Skip to content

Commit

Permalink
container step always uses cloud named 'kubernetes'
Browse files Browse the repository at this point in the history
Fixes #104
Use the cloud defined in podTemplate step

Remove deprecations in step and step execution classes
  • Loading branch information
carlossg committed Jan 30, 2017
1 parent 8078e12 commit 04175e2
Show file tree
Hide file tree
Showing 5 changed files with 92 additions and 90 deletions.
Original file line number Diff line number Diff line change
@@ -1,24 +1,26 @@
package org.csanchez.jenkins.plugins.kubernetes.pipeline;

import hudson.Extension;
import org.jenkinsci.plugins.workflow.steps.AbstractStepDescriptorImpl;
import org.jenkinsci.plugins.workflow.steps.AbstractStepImpl;
import java.io.Serializable;
import java.util.Set;

import org.jenkinsci.plugins.workflow.steps.Step;
import org.jenkinsci.plugins.workflow.steps.StepContext;
import org.jenkinsci.plugins.workflow.steps.StepDescriptor;
import org.jenkinsci.plugins.workflow.steps.StepExecution;
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.DataBoundSetter;

import java.io.Serializable;
import com.google.common.collect.ImmutableSet;

public class ContainerStep extends AbstractStepImpl implements Serializable {
import hudson.Extension;
import hudson.FilePath;
import hudson.model.TaskListener;

public class ContainerStep extends Step implements Serializable {

private static final long serialVersionUID = 5588861066775717487L;

private final String name;

private static final String DEFAULT_CLOUD = "kubernetes";

private String cloud = DEFAULT_CLOUD;

@DataBoundConstructor
public ContainerStep(String name) {
this.name = name;
Expand All @@ -28,25 +30,13 @@ public String getName() {
return name;
}

public String getCloud() {
return cloud;
}

@DataBoundSetter
public void setCloud(String cloud) {
this.cloud = cloud;
@Override
public StepExecution start(StepContext context) throws Exception {
return new ContainerStepExecution(this, context);
}

@Extension
public static class DescriptorImpl extends AbstractStepDescriptorImpl {

public DescriptorImpl() {
super(ContainerStepExecution.class);
}

public DescriptorImpl(Class<? extends StepExecution> executionType) {
super(executionType);
}
public static class DescriptorImpl extends StepDescriptor {

@Override
public String getFunctionName() {
Expand All @@ -67,5 +57,10 @@ public boolean takesImplicitBlockArgument() {
public boolean isAdvanced() {
return true;
}

@Override
public Set<? extends Class<?>> getRequiredContext() {
return ImmutableSet.of(PodTemplateStep.class, FilePath.class, TaskListener.class);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,25 +1,24 @@
package org.csanchez.jenkins.plugins.kubernetes.pipeline;

import hudson.AbortException;
import hudson.FilePath;
import hudson.LauncherDecorator;
import hudson.model.TaskListener;
import io.fabric8.kubernetes.client.KubernetesClient;
import jenkins.model.Jenkins;
import java.io.Closeable;
import java.io.IOException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.csanchez.jenkins.plugins.kubernetes.KubernetesCloud;
import org.jenkinsci.plugins.workflow.steps.AbstractStepExecutionImpl;
import org.jenkinsci.plugins.workflow.steps.BodyExecutionCallback;
import org.jenkinsci.plugins.workflow.steps.BodyInvoker;
import org.jenkinsci.plugins.workflow.steps.StepContext;
import org.jenkinsci.plugins.workflow.steps.StepContextParameter;

import javax.inject.Inject;
import java.io.Closeable;
import java.io.IOException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Logger;
import java.util.logging.Level;
import hudson.AbortException;
import hudson.FilePath;
import hudson.LauncherDecorator;
import hudson.model.TaskListener;
import io.fabric8.kubernetes.client.KubernetesClient;
import jenkins.model.Jenkins;

public class ContainerStepExecution extends AbstractStepExecutionImpl {

Expand All @@ -28,33 +27,36 @@ public class ContainerStepExecution extends AbstractStepExecutionImpl {
private static final transient Logger LOGGER = Logger.getLogger(ContainerStepExecution.class.getName());
private static final transient String HOSTNAME_FILE = "/etc/hostname";

@Inject
private ContainerStep step;
@StepContextParameter private transient FilePath workspace;
@StepContextParameter private transient TaskListener listener;
private transient final ContainerStep step;

private transient KubernetesClient client;
private transient ContainerExecDecorator decorator;

ContainerStepExecution(ContainerStep step, StepContext context) {
super(context);
this.step = step;
}

@Override
public boolean start() throws Exception {
LOGGER.log(Level.FINE, "Starting container step.");
StepContext context = getContext();
FilePath workspace = getContext().get(FilePath.class);
String podName = workspace.child(HOSTNAME_FILE).readToString().trim();
String containerName = step.getName();

final AtomicBoolean podAlive = new AtomicBoolean(false);
final CountDownLatch podStarted = new CountDownLatch(1);
final CountDownLatch podFinished = new CountDownLatch(1);

KubernetesCloud cloud = (KubernetesCloud) Jenkins.getInstance().getCloud(step.getCloud());
String cloudName = getContext().get(PodTemplateStep.class).getCloud();
KubernetesCloud cloud = (KubernetesCloud) Jenkins.getInstance().getCloud(cloudName);
if (cloud == null) {
throw new AbortException(String.format("Cloud does not exist: %s", step.getCloud()));
throw new AbortException(String.format("Cloud does not exist: %s", cloudName));
}
client = cloud.connect();

decorator = new ContainerExecDecorator(client, podName, containerName, workspace.getRemote(), podAlive, podStarted, podFinished);
context.newBodyInvoker()
getContext().newBodyInvoker()
.withContext(BodyInvoker
.mergeLauncherDecorators(getContext().get(LauncherDecorator.class), decorator))
.withCallback(new ContainerExecCallback())
Expand All @@ -68,13 +70,17 @@ public void stop(Throwable cause) throws Exception {
closeQuietly(client, decorator);
}

private void closeQuietly(Closeable... closeables) {
private void closeQuietly(Closeable... closeables) {
for (Closeable c : closeables) {
if (c != null) {
try {
c.close();
} catch (IOException e) {
listener.error("Error while closing: [" + c + "]");
try {
getContext().get(TaskListener.class).error("Error while closing: [" + c + "]");
} catch (IOException | InterruptedException e1) {
LOGGER.log(Level.WARNING, "Error writing to task listener", e);
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,25 @@
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import org.csanchez.jenkins.plugins.kubernetes.ContainerTemplate;
import org.csanchez.jenkins.plugins.kubernetes.volumes.PodVolume;
import org.csanchez.jenkins.plugins.kubernetes.volumes.workspace.WorkspaceVolume;
import org.jenkinsci.plugins.workflow.steps.AbstractStepDescriptorImpl;
import org.jenkinsci.plugins.workflow.steps.AbstractStepImpl;
import org.jenkinsci.plugins.workflow.steps.StepContextParameter;
import org.jenkinsci.plugins.workflow.steps.Step;
import org.jenkinsci.plugins.workflow.steps.StepContext;
import org.jenkinsci.plugins.workflow.steps.StepDescriptor;
import org.jenkinsci.plugins.workflow.steps.StepExecution;
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.DataBoundSetter;

import com.google.common.collect.ImmutableSet;

import hudson.Extension;
import hudson.model.Run;
import hudson.model.TaskListener;

public class PodTemplateStep extends AbstractStepImpl implements Serializable {
public class PodTemplateStep extends Step implements Serializable {

private static final long serialVersionUID = 5588861066775717487L;

Expand All @@ -38,13 +42,6 @@ public class PodTemplateStep extends AbstractStepImpl implements Serializable {
private String nodeSelector;
private String workingDir = ContainerTemplate.DEFAULT_WORKING_DIR;

@StepContextParameter
private transient Run run;

public Run getRun() {
return run;
}

@DataBoundConstructor
public PodTemplateStep(String label, String name) {
this.label = label;
Expand Down Expand Up @@ -140,16 +137,13 @@ public void setWorkingDir(String workingDir) {
this.workingDir = workingDir;
}

@Extension
public static class DescriptorImpl extends AbstractStepDescriptorImpl {

public DescriptorImpl() {
super(PodTemplateStepExecution.class);
}
@Override
public StepExecution start(StepContext context) throws Exception {
return new PodTemplateStepExecution(this, context);
}

public DescriptorImpl(Class<? extends StepExecution> executionType) {
super(executionType);
}
@Extension
public static class DescriptorImpl extends StepDescriptor {

@Override
public String getFunctionName() {
Expand All @@ -170,5 +164,10 @@ public boolean takesImplicitBlockArgument() {
public boolean isAdvanced() {
return true;
}

@Override
public Set<? extends Class<?>> getRequiredContext() {
return ImmutableSet.of(Run.class, TaskListener.class);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.inject.Inject;

import org.csanchez.jenkins.plugins.kubernetes.KubernetesCloud;
import org.csanchez.jenkins.plugins.kubernetes.PodTemplate;
import org.jenkinsci.plugins.workflow.steps.AbstractStepExecutionImpl;
Expand All @@ -15,6 +13,7 @@
import com.google.common.base.Strings;

import hudson.AbortException;
import hudson.model.Run;
import hudson.slaves.Cloud;
import jenkins.model.Jenkins;

Expand All @@ -26,13 +25,17 @@ public class PodTemplateStepExecution extends AbstractStepExecutionImpl {

private static final transient String NAME_FORMAT = "kubernetes-%s";

@Inject
private PodTemplateStep step;
private transient final PodTemplateStep step;

PodTemplateStepExecution(PodTemplateStep step, StepContext context) {
super(context);
this.step = step;
}

@Override
public boolean start() throws Exception {

Cloud cloud = Jenkins.getActiveInstance().getCloud(step.getCloud());
Cloud cloud = Jenkins.getInstance().getCloud(step.getCloud());
if (cloud == null) {
throw new AbortException(String.format("Cloud does not exist: %s", step.getCloud()));
}
Expand All @@ -43,7 +46,7 @@ public boolean start() throws Exception {
KubernetesCloud kubernetesCloud = (KubernetesCloud) cloud;
String name = String.format(NAME_FORMAT, UUID.randomUUID().toString().replaceAll("-", ""));

PodTemplateAction action = new PodTemplateAction(step.getRun());
PodTemplateAction action = new PodTemplateAction(getContext().get(Run.class));

PodTemplate newTemplate = new PodTemplate();
newTemplate.setName(name);
Expand All @@ -58,9 +61,7 @@ public boolean start() throws Exception {
newTemplate.setServiceAccount(step.getServiceAccount());

kubernetesCloud.addTemplate(newTemplate);
getContext().newBodyInvoker()
.withCallback(new PodTemplateCallback(newTemplate))
.start();
getContext().newBodyInvoker().withContext(step).withCallback(new PodTemplateCallback(newTemplate)).start();


action.push(step.getLabel());
Expand All @@ -69,7 +70,7 @@ public boolean start() throws Exception {

@Override
public void stop(Throwable cause) throws Exception {
new PodTemplateAction(step.getRun()).pop();
new PodTemplateAction(getContext().get(Run.class)).pop();
}

private class PodTemplateCallback extends BodyExecutionCallback.TailCall {
Expand All @@ -87,7 +88,7 @@ private PodTemplateCallback(PodTemplate podTemplate) {
* Remove the template after step is done
*/
protected void finished(StepContext context) throws Exception {
Cloud cloud = Jenkins.getActiveInstance().getCloud(step.getCloud());
Cloud cloud = Jenkins.getInstance().getCloud(step.getCloud());
if (cloud == null) {
LOGGER.log(Level.FINE, "Cloud {0} no longer exists, cannot delete pod template {1}",
new Object[] { step.getCloud(), podTemplate.getName() });
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ public class KubernetesPipelineTest {
@Rule
public TemporaryFolder tmp = new TemporaryFolder();

private static KubernetesCloud cloud = new KubernetesCloud("kubernetes");
private static KubernetesCloud cloud = new KubernetesCloud("minikube");

@BeforeClass
public static void configureCloud() throws Exception {
Expand Down Expand Up @@ -116,7 +116,7 @@ public void runInPod() throws Exception {

WorkflowJob p = r.jenkins.createProject(WorkflowJob.class, "p");
p.setDefinition(new CpsFlowDefinition("" //
+ "podTemplate(label: 'mypod', volumes: [emptyDirVolume(mountPath: '/my-mount')], containers: [\n" //
+ "podTemplate(cloud: 'minikube', label: 'mypod', volumes: [emptyDirVolume(mountPath: '/my-mount')], containers: [\n" //
+ " containerTemplate(name: 'jnlp', image: 'jenkinsci/jnlp-slave:2.62-alpine', args: '${computer.jnlpmac} ${computer.name}'),\n" //
+ " containerTemplate(name: 'maven', image: 'maven:3.3.9-jdk-8-alpine', ttyEnabled: true, command: 'cat'),\n" //
+ " containerTemplate(name: 'golang', image: 'golang:1.6.3-alpine', ttyEnabled: true, command: 'cat')\n" //
Expand All @@ -125,13 +125,13 @@ public void runInPod() throws Exception {
+ " node ('mypod') {\n" //
+ " sh \"echo My Kubernetes Pipeline\" \n" //
+ " sh \"ls /\" \n" //
// + " stage 'Get a Maven project'\n" //
// + " git 'https://github.com/jenkinsci/kubernetes-plugin.git'\n" //
// + " container('maven') {\n" //
// + " stage 'Build a Maven project'\n" //
// + " sh 'mvn clean install'\n" //
// + " }\n" //
// + "\n" //
+ "\n" //
+ " stage('Run maven') {\n" //
+ " container('maven') {\n" //
+ " sh 'mvn -version'\n" //
+ " }\n" //
+ " }\n" //
+ "\n" //
// + " stage 'Get a Golang project'\n" //
// + " git url: 'https://github.com/hashicorp/terraform.git'\n" //
// + " container('golang') {\n" //
Expand All @@ -151,6 +151,7 @@ public void runInPod() throws Exception {
r.assertBuildStatusSuccess(r.waitForCompletion(b));
r.assertLogContains("My Kubernetes Pipeline", b);
r.assertLogContains("my-mount", b);
r.assertLogContains("Apache Maven 3.3.9", b);
}

// @Test
Expand Down

0 comments on commit 04175e2

Please sign in to comment.