-
Notifications
You must be signed in to change notification settings - Fork 323
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
New Option for JNLP: Pass Slave Connection Arguments to Entrypoint #596
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,7 +4,6 @@ | |
import com.github.dockerjava.api.command.CreateContainerCmd; | ||
import com.github.dockerjava.api.command.PullImageCmd; | ||
import com.github.dockerjava.api.exception.DockerClientException; | ||
import com.github.dockerjava.api.exception.DockerException; | ||
import com.github.dockerjava.api.exception.NotFoundException; | ||
import com.github.dockerjava.api.model.PortBinding; | ||
import com.github.dockerjava.api.model.PullResponseItem; | ||
|
@@ -15,19 +14,13 @@ | |
import com.nirima.jenkins.plugins.docker.strategy.DockerOnceRetentionStrategy; | ||
import hudson.Extension; | ||
import hudson.Util; | ||
import hudson.model.Describable; | ||
import hudson.model.Descriptor; | ||
import hudson.model.DescriptorVisibilityFilter; | ||
import hudson.model.Label; | ||
import hudson.model.Node; | ||
import hudson.model.TaskListener; | ||
import hudson.model.*; | ||
import hudson.model.labels.LabelAtom; | ||
import hudson.slaves.ComputerLauncher; | ||
import hudson.slaves.NodeProperty; | ||
import hudson.slaves.NodePropertyDescriptor; | ||
import hudson.slaves.RetentionStrategy; | ||
import hudson.util.DescribableList; | ||
import hudson.util.FormValidation; | ||
import io.jenkins.docker.DockerTransientNode; | ||
import io.jenkins.docker.client.DockerAPI; | ||
import io.jenkins.docker.connector.DockerComputerConnector; | ||
|
@@ -37,19 +30,14 @@ | |
import org.kohsuke.accmod.restrictions.NoExternalUse; | ||
import org.kohsuke.stapler.DataBoundConstructor; | ||
import org.kohsuke.stapler.DataBoundSetter; | ||
import org.kohsuke.stapler.QueryParameter; | ||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
|
||
import javax.annotation.CheckForNull; | ||
import javax.annotation.Nonnull; | ||
import java.io.IOException; | ||
import java.util.ArrayList; | ||
import java.util.Collection; | ||
import java.util.Collections; | ||
import java.util.Iterator; | ||
import java.util.List; | ||
import java.util.Set; | ||
import java.io.Serializable; | ||
import java.util.*; | ||
|
||
|
||
public class DockerTemplate implements Describable<DockerTemplate> { | ||
|
@@ -412,35 +400,40 @@ public void onNext(PullResponseItem item) { | |
|
||
} | ||
|
||
@Restricted(NoExternalUse.class) | ||
public DockerTransientNode provisionNode(DockerAPI api, TaskListener listener) throws IOException, Descriptor.FormException, InterruptedException { | ||
public class ContainerCommandCreator implements Serializable{ | ||
private final String containerUniqueName; | ||
|
||
final DockerClient client = api.getClient(); | ||
final DockerComputerConnector connector = getConnector(); | ||
pullImage(api, listener); | ||
ContainerCommandCreator(){ | ||
// Since container can now be launched during slave launch, we need an alternative unique node name, which will be also the container name | ||
this.containerUniqueName = Long.toHexString(System.nanoTime()); | ||
} | ||
|
||
LOGGER.info("Trying to run container for {}", getImage()); | ||
CreateContainerCmd cmd = client.createContainerCmd(getImage()); | ||
fillContainerConfig(cmd); | ||
public String getContainerUniqueName() { | ||
return containerUniqueName; | ||
} | ||
|
||
connector.beforeContainerCreated(api, remoteFs, cmd); | ||
public CreateContainerCmd createContainerCmd(DockerAPI api){ | ||
final DockerClient client = api.getClient(); | ||
CreateContainerCmd cmd = client.createContainerCmd(getImage()); | ||
fillContainerConfig(cmd); | ||
cmd.withName(containerUniqueName); | ||
return cmd; | ||
} | ||
|
||
String containerId = cmd.exec().getId(); | ||
} | ||
|
||
try { | ||
connector.beforeContainerStarted(api, remoteFs, containerId); | ||
@Restricted(NoExternalUse.class) | ||
public DockerTransientNode provisionNode(DockerAPI api, TaskListener listener) throws IOException, Descriptor.FormException, InterruptedException { | ||
|
||
client.startContainerCmd(containerId).exec(); | ||
final DockerComputerConnector connector = getConnector(); | ||
pullImage(api, listener); | ||
|
||
connector.afterContainerStarted(api, remoteFs, containerId); | ||
} catch (DockerException e) { | ||
// if something went wrong, cleanup aborted container | ||
client.removeContainerCmd(containerId).withForce(true).exec(); | ||
throw e; | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You don't need to move this code away and introduce There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I moved this code to the DockerComputerConnector, since it must be called from the launcher itself and cannot run before the launcher is being created. In this iteration, I tried to keep the original code as it was when I could (sorry for the many refactoring - did not try to make your review hard, it was just multiple iterations). |
||
LOGGER.info("Trying to run container for {}", getImage()); | ||
ContainerCommandCreator containerCommandCreator = new ContainerCommandCreator(); | ||
LOGGER.info("Trying to run container for image: {}, with unique name: {}", getImage(), containerCommandCreator.getContainerUniqueName()); | ||
final ComputerLauncher launcher = connector.createLauncher(api, containerCommandCreator, remoteFs, listener); | ||
|
||
final ComputerLauncher launcher = connector.createLauncher(api, containerId, remoteFs, listener); | ||
DockerTransientNode node = new DockerTransientNode(containerId, remoteFs, launcher); | ||
DockerTransientNode node = new DockerTransientNode(containerCommandCreator.getContainerUniqueName(), remoteFs, launcher); | ||
node.setNodeDescription("Docker Agent [" + getImage() + " on "+ api.getDockerHost().getUri() + "]"); | ||
node.setMode(mode); | ||
node.setLabelString(labelString); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,44 +7,50 @@ | |
import com.nirima.jenkins.plugins.docker.strategy.DockerOnceRetentionStrategy; | ||
import hudson.model.Computer; | ||
import hudson.model.Descriptor; | ||
import hudson.model.Queue; | ||
import hudson.model.Slave; | ||
import hudson.model.TaskListener; | ||
import hudson.slaves.Cloud; | ||
import hudson.slaves.ComputerLauncher; | ||
import io.jenkins.docker.client.DockerAPI; | ||
import jenkins.model.Jenkins; | ||
|
||
import javax.annotation.CheckForNull; | ||
import javax.annotation.Nonnull; | ||
import java.io.IOException; | ||
import java.io.Serializable; | ||
|
||
/** | ||
* A {@link Slave} node designed to be used only once for a build. | ||
* | ||
* @author <a href="mailto:[email protected]">Nicolas De Loof</a> | ||
*/ | ||
public class DockerTransientNode extends Slave { | ||
|
||
private final String containerId; | ||
|
||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. please do not remove this useful information. Just make this non-final and assign as container has been created There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Restored. |
||
//Keeping real containerId information, but using containerUniqueName as containerId | ||
private String containerId; | ||
|
||
private String containerUniqueName; | ||
|
||
private DockerAPI dockerAPI; | ||
|
||
private boolean removeVolumes; | ||
|
||
private String cloudId; | ||
|
||
public DockerTransientNode(@Nonnull String containerId, String remoteFS, ComputerLauncher launcher) throws Descriptor.FormException, IOException { | ||
super("docker-" + containerId.substring(0,12), remoteFS, launcher); | ||
|
||
public DockerTransientNode(@Nonnull String uniqueName, String workdir, ComputerLauncher launcher) throws Descriptor.FormException, IOException { | ||
super("docker-" + uniqueName, workdir, launcher); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. wouldn't hurt to also store containerName as an attribute There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done. |
||
this.containerUniqueName = uniqueName; | ||
setNumExecutors(1); | ||
setMode(Mode.EXCLUSIVE); | ||
setRetentionStrategy(new DockerOnceRetentionStrategy(10)); | ||
} | ||
|
||
public void setRealContainerId(String containerId){ | ||
this.containerId = containerId; | ||
} | ||
|
||
public String getContainerId() { | ||
return containerId; | ||
public String getContainerId(){ | ||
// For old sake. If the containerUniqueName was not introduced yet, use the containerId | ||
return containerUniqueName == null ? containerId : containerUniqueName; | ||
} | ||
|
||
public void setDockerAPI(DockerAPI dockerAPI) { | ||
|
@@ -92,7 +98,7 @@ public void terminate(TaskListener listener) { | |
} | ||
|
||
Computer.threadPoolForRemoting.submit(() -> { | ||
|
||
final String containerId = getContainerId(); | ||
DockerClient client = dockerAPI.getClient(); | ||
|
||
try { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @ndeloof, I had to add this
ContainerCommandCreator
, since the CreateContainerCmd is not Serializable and therefore when passing it to the anonymousDelegatingComputerLauncher(new JNLPLauncher()))
through thecreateLauncher
method, Jenkins will fail serialization.So the trick was to do it lazily using the
DockerTemplate
which is serializable. So this class is a holder for the uniqueContainerName and when needed, the it creates the CreateContainerCmd and fills it will all the required data from the DockerTemplate instance.