Skip to content
Permalink
Browse files
Merge pull request #31 from jenkinsci/dockerlabel
[JENKINS-39109] Add a configuration option for what label to use for docker agents
  • Loading branch information
abayer committed Oct 20, 2016
2 parents 55b7014 + 10ffeca commit abbde740b9b603f5fd9d56302c300ab5db6c22cf
Showing with 792 additions and 17 deletions.
  1. +5 −0 ...odel-definition/src/main/groovy/org/jenkinsci/plugins/pipeline/modeldefinition/model/Agent.groovy
  2. +45 −0 ...tion/src/main/java/org/jenkinsci/plugins/pipeline/modeldefinition/config/DockerLabelProvider.java
  3. +111 −0 ...-definition/src/main/java/org/jenkinsci/plugins/pipeline/modeldefinition/config/FolderConfig.java
  4. +78 −0 ...-definition/src/main/java/org/jenkinsci/plugins/pipeline/modeldefinition/config/GlobalConfig.java
  5. +87 −0 ...efinition/src/main/java/org/jenkinsci/plugins/pipeline/modeldefinition/steps/DockerLabelStep.java
  6. +26 −0 ...-definition/src/main/resources/org/jenkinsci/plugins/pipeline/modeldefinition/Messages.properties
  7. +10 −0 ...inition/src/main/resources/org/jenkinsci/plugins/pipeline/modeldefinition/ModelInterpreter.groovy
  8. +35 −0 ...c/main/resources/org/jenkinsci/plugins/pipeline/modeldefinition/config/FolderConfig/config.groovy
  9. +30 −0 ...esources/org/jenkinsci/plugins/pipeline/modeldefinition/config/FolderConfig/help-dockerLabel.html
  10. +35 −0 ...c/main/resources/org/jenkinsci/plugins/pipeline/modeldefinition/config/GlobalConfig/config.groovy
  11. +30 −0 ...esources/org/jenkinsci/plugins/pipeline/modeldefinition/config/GlobalConfig/help-dockerLabel.html
  12. +50 −17 ...definition/src/test/java/org/jenkinsci/plugins/pipeline/modeldefinition/AbstractModelDefTest.java
  13. +127 −0 ...ition/src/test/java/org/jenkinsci/plugins/pipeline/modeldefinition/steps/DockerLabelStepTest.java
  14. +47 −0 pipeline-model-definition/src/test/resources/agentDockerEnvSpecLabel.groovy
  15. +47 −0 pipeline-model-definition/src/test/resources/agentDockerEnvTest.groovy
  16. +29 −0 pipeline-model-definition/src/test/resources/dockerLabel.groovy
@@ -74,6 +74,11 @@ public class Agent implements Serializable {
return any || docker != null || label != null
}

@Whitelisted
public boolean hasDocker() {
return docker != null
}

// TODO: Rewrite as an extension point and get this by extension discovery, but we knew that already.
public static List<String> agentConfigKeys() {
return ["docker", "label", "dockerArgs"]
@@ -0,0 +1,45 @@
/*
* The MIT License
*
* Copyright (c) 2016, CloudBees, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/

package org.jenkinsci.plugins.pipeline.modeldefinition.config;

import hudson.ExtensionList;
import hudson.ExtensionPoint;
import hudson.model.Run;

import javax.annotation.CheckForNull;

/**
* Provider of label expressions to use for {@code agent: docker} when no other label is provided.
*/
public abstract class DockerLabelProvider implements ExtensionPoint {

@CheckForNull
public abstract String getLabel(Run run);

public static ExtensionList<DockerLabelProvider> all() {
return ExtensionList.lookup(DockerLabelProvider.class);
}
}
@@ -0,0 +1,111 @@
/*
* The MIT License
*
* Copyright (c) 2016, CloudBees, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/

package org.jenkinsci.plugins.pipeline.modeldefinition.config;

import com.cloudbees.hudson.plugins.folder.AbstractFolder;
import com.cloudbees.hudson.plugins.folder.AbstractFolderProperty;
import com.cloudbees.hudson.plugins.folder.AbstractFolderPropertyDescriptor;
import hudson.Extension;
import hudson.model.Item;
import hudson.model.ItemGroup;
import hudson.model.Job;
import hudson.model.Run;
import org.apache.commons.lang.StringUtils;
import org.jenkinsci.Symbol;
import org.jenkinsci.plugins.pipeline.modeldefinition.Messages;
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.DataBoundSetter;

import javax.annotation.Nonnull;

/**
* Provides folder level configuration.
*/
public class FolderConfig extends AbstractFolderProperty<AbstractFolder<?>> {
private String dockerLabel;

@DataBoundConstructor
public FolderConfig() {
}

/**
* For testing
*
* @param dockerLabel the docker label to use
*/
public FolderConfig(String dockerLabel) {
this.dockerLabel = dockerLabel;
}

public String getDockerLabel() {
return dockerLabel;
}

@DataBoundSetter
public void setDockerLabel(String dockerLabel) {
this.dockerLabel = dockerLabel;
}

@Extension @Symbol("pipeline-model")
public static class DescriptorImpl extends AbstractFolderPropertyDescriptor {

@Nonnull
@Override
public String getDisplayName() {
return Messages.PipelineModelDefinition_DisplayName();
}
}

@Extension(ordinal = 10000) //First to be asked
public static class FolderDockerLabelProvider extends DockerLabelProvider {

@Override
public String getLabel(Run run) {
Job job = run.getParent();
ItemGroup parent = job.getParent();
while(parent != null) {

if (parent instanceof AbstractFolder) {
AbstractFolder folder = (AbstractFolder)parent;
FolderConfig config = (FolderConfig)folder.getProperties().get(FolderConfig.class);
if (config != null) {
String label = config.getDockerLabel();
if (!StringUtils.isBlank(label)) {
return label;
}
}
}

if (parent instanceof Item) {
parent = ((Item)parent).getParent();
} else {
parent = null;
}
}
return null;
}
}
}
@@ -0,0 +1,78 @@
/*
* The MIT License
*
* Copyright (c) 2016, CloudBees, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/

package org.jenkinsci.plugins.pipeline.modeldefinition.config;

import com.google.inject.Inject;
import hudson.Extension;
import hudson.ExtensionList;
import hudson.Util;
import hudson.model.Run;
import jenkins.model.GlobalConfiguration;
import net.sf.json.JSONObject;
import org.jenkinsci.Symbol;
import org.kohsuke.stapler.DataBoundSetter;
import org.kohsuke.stapler.StaplerRequest;

/**
* The system config.
*
* For example the system level {@link DockerLabelProvider}.
*/
@Extension @Symbol("pipeline-model")
public class GlobalConfig extends GlobalConfiguration {
private String dockerLabel;

public String getDockerLabel() {
return Util.fixEmpty(dockerLabel);
}

@DataBoundSetter
public void setDockerLabel(String dockerLabel) {
this.dockerLabel = dockerLabel;
}

@Override
public boolean configure(StaplerRequest req, JSONObject json) throws FormException {
req.bindJSON(this, json);
save();
return true;
}

public static GlobalConfig get() {
return ExtensionList.lookup(GlobalConfiguration.class).get(GlobalConfig.class);
}

@Extension(ordinal = -10000) //Last one to be asked
public static final class GlobalConfigDockerLabelProvider extends DockerLabelProvider {
@Inject
GlobalConfig config;

@Override
public String getLabel(Run run) {
return config.getDockerLabel();
}
}
}
@@ -0,0 +1,87 @@
/*
* The MIT License
*
* Copyright (c) 2016, CloudBees, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/

package org.jenkinsci.plugins.pipeline.modeldefinition.steps;

import hudson.Extension;
import hudson.model.TaskListener;
import org.apache.commons.lang.StringUtils;
import org.jenkinsci.plugins.pipeline.modeldefinition.config.DockerLabelProvider;
import org.jenkinsci.plugins.workflow.job.WorkflowRun;
import org.jenkinsci.plugins.workflow.steps.AbstractStepDescriptorImpl;
import org.jenkinsci.plugins.workflow.steps.AbstractStepImpl;
import org.jenkinsci.plugins.workflow.steps.AbstractSynchronousNonBlockingStepExecution;
import org.jenkinsci.plugins.workflow.steps.StepContextParameter;
import org.kohsuke.stapler.DataBoundConstructor;

import java.io.Serializable;

/**
* The node label expression to use for running docker.
*
* @see org.jenkinsci.plugins.pipeline.modeldefinition.config.DockerLabelProvider
*/
public class DockerLabelStep extends AbstractStepImpl implements Serializable {
private static final long serialVersionUID = 1L;

@DataBoundConstructor
public DockerLabelStep() {
}

@Extension
public static final class DescriptorImpl extends AbstractStepDescriptorImpl {

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

@Override
public String getFunctionName() {
return "dockerLabel";
}
}


public static class StepExecutionImpl extends AbstractSynchronousNonBlockingStepExecution<String> {
private static final long serialVersionUID = 1L;

@StepContextParameter
transient TaskListener listener;

@StepContextParameter
transient WorkflowRun run;

@Override
protected String run() throws Exception {
for (DockerLabelProvider provider : DockerLabelProvider.all()) {
String label = provider.getLabel(run);
if (!StringUtils.isBlank(label)) {
return label;
}
}
return null;
}
}
}
@@ -0,0 +1,26 @@
#
# The MIT License
#
# Copyright (c) 2016, CloudBees, Inc.
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
#

PipelineModelDefinition.DisplayName=Pipeline Model Definition
@@ -270,6 +270,16 @@ public class ModelInterpreter implements Serializable {
}
}
} else {
if (agent?.hasDocker()) {
String dl = script.dockerLabel()?.trim()
if (dl) {
return {
script.node(dl) {
body.call()
}
}
}
}
return {
script.node {
body.call()

0 comments on commit abbde74

Please sign in to comment.