Skip to content
Open
20 changes: 14 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,18 @@ template, it can be configured on cloud level and leave the filed blank
in the templates.

<a href="https://raw.githubusercontent.com/jenkinsci/openstack-cloud-plugin/master/docs/options.png"><img align="right" width="300" src="https://raw.githubusercontent.com/jenkinsci/openstack-cloud-plugin/master/docs/options.png"></a>
Aside from machine/node attributes, every template require name and
labels to be configured. Name will serve both as an identifier of the
Aside from machine/node attributes, every template requires name, labels and
usage mode to be configured. Name will serve both as an identifier of the
template as well as a name prefix for Jenkins node and OpenStack machine
(that is why some limitations apply here). Labels field expects a set of
Jenkins labels that will be assigned to all nodes that the template
provisions. It will also be used to determine which cloud and template to
use to process Jenkins load. When there is a build with no label
requirements, any
template can be used to provision the node. Build with label restriction
provisions. The Usage field specifies whether nodes will be provisioned for
builds that have no label requirement (_Use this node as much as possible_)
or only if a build's label is present (_Only build jobs with label expressions matching this node_).
The combination of the Labels and Usage fields will be used to determine
which cloud and template to use to process Jenkins load. When there is a build with no label
requirements, any template where the Usage mode is '_Use this node as much as possible_'
can be used to provision the node. Builds with label restrictions
can trigger provisioning only on templates with matching label set. The
attributes at template level will inherit all global values (the value
in effect is printed under the field on hte config page). In case required
Expand Down Expand Up @@ -107,19 +110,24 @@ jenkins:
templates:
- name: "empty"
labels: "linux"
slaveOptions:
mode: EXCLUSIVE
- name: "jnlp"
labels: "jnlp"
slaveOptions:
mode: NORMAL
launcherFactory: "jnlp"
- name: "volumeSnapshot"
labels: "volume"
slaveOptions:
mode: NORMAL
bootSource:
volumeSnapshot:
name: "Volume name"
- name: "volumeFromImage"
labels: "volume from image"
slaveOptions:
mode: NORMAL
bootSource:
volumeFromImage:
name: "Volume name"
Expand Down
Binary file modified docs/config.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/options.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ public JCloudsSlave(
this.cache = makeCache();

setNumExecutors(slaveOptions.getNumExecutors());
setMode(Mode.NORMAL);
setMode(slaveOptions.getMode() != null ? slaveOptions.getMode() : Node.Mode.NORMAL);
setLabelString(labelString);
setRetentionStrategy(new JCloudsRetentionStrategy());
setNodeProperties(mkNodeProperties(Openstack.getAccessIpAddress(metadata), slaveOptions.getNodeProperties()));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@
import com.google.common.annotations.VisibleForTesting;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import hudson.Extension;
import hudson.RelativePath;
import hudson.Util;
import hudson.model.Describable;
import hudson.model.Descriptor;
import hudson.model.Failure;
import hudson.model.Label;
import hudson.model.Node;
import hudson.model.TaskListener;
import hudson.model.labels.LabelAtom;
import hudson.util.FormValidation;
Expand Down Expand Up @@ -91,7 +93,6 @@ public class JCloudsSlaveTemplate implements Describable<JCloudsSlaveTemplate>,
public JCloudsSlaveTemplate(final @Nonnull String name, final @Nonnull String labels, final @CheckForNull SlaveOptions slaveOptions) {
this.name = Util.fixNull(name).trim();
this.labelString = Util.fixNull(labels).trim();

this.slaveOptions = slaveOptions == null ? SlaveOptions.empty() : slaveOptions;

readResolve();
Expand Down Expand Up @@ -195,7 +196,9 @@ public Set<LabelAtom> getLabelSet() {
}

public boolean canProvision(final Label label) {
return label == null || label.matches(labelSet);
return label == null
? slaveOptions.getMode() == null || slaveOptions.getMode() == Node.Mode.NORMAL
: label.matches(labelSet);
}

/*package*/ boolean hasProvisioned(@Nonnull Server server) {
Expand Down Expand Up @@ -535,5 +538,14 @@ public FormValidation doCheckName(@QueryParameter String value) {
return FormValidation.error(ex.getMessage());
}
}

@Restricted(DoNotUse.class)
@RequirePOST
public FormValidation doCheckLabels(@QueryParameter String value, @RelativePath("slaveOptions") @QueryParameter Node.Mode mode) {
if ((value == null || value.trim().isEmpty()) && mode == Node.Mode.EXCLUSIVE) {
return FormValidation.warning("Nodes without any labels and running in exclusive mode will never be provisioned");
}
return FormValidation.ok();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import hudson.Util;
import hudson.model.Describable;
import hudson.model.Node;
import hudson.slaves.NodeProperty;
import jenkins.model.Jenkins;
import jenkins.plugins.openstack.compute.slaveopts.BootSource;
Expand Down Expand Up @@ -54,7 +55,7 @@
*/
public class SlaveOptions implements Describable<SlaveOptions>, Serializable {
private static final long serialVersionUID = -1L;
private static final SlaveOptions EMPTY = new SlaveOptions(null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null);
private static final SlaveOptions EMPTY = new SlaveOptions(null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null);

// Provisioning attributes
private /*final*/ @CheckForNull BootSource bootSource;
Expand All @@ -70,6 +71,7 @@ public class SlaveOptions implements Describable<SlaveOptions>, Serializable {
private final @CheckForNull String keyPairName;

// Slave launch attributes
private final @Nonnull Node.Mode mode;
private final Integer numExecutors;
private final @CheckForNull String jvmOptions;
private final String fsRoot;
Expand Down Expand Up @@ -138,6 +140,10 @@ public Integer getStartTimeout() {
return keyPairName;
}

public @Nonnull Node.Mode getMode() {
return mode;
}

public Integer getNumExecutors() {
return numExecutors;
}
Expand Down Expand Up @@ -173,6 +179,7 @@ public SlaveOptions(Builder b) {
b.availabilityZone,
b.startTimeout,
b.keyPairName,
b.mode,
b.numExecutors,
b.jvmOptions,
b.fsRoot,
Expand All @@ -196,6 +203,7 @@ public SlaveOptions(
String availabilityZone,
Integer startTimeout,
String keyPairName,
Node.Mode mode,
Integer numExecutors,
String jvmOptions,
String fsRoot,
Expand All @@ -215,6 +223,7 @@ public SlaveOptions(
this.availabilityZone = Util.fixEmpty(availabilityZone);
this.startTimeout = startTimeout;
this.keyPairName = Util.fixEmpty(keyPairName);
this.mode = mode;
this.numExecutors = numExecutors;
this.jvmOptions = Util.fixEmpty(jvmOptions);
this.fsRoot = Util.fixEmpty(fsRoot);
Expand Down Expand Up @@ -252,6 +261,7 @@ private Object readResolve() {
.availabilityZone(_override(this.availabilityZone, o.availabilityZone))
.startTimeout(_override(this.startTimeout, o.startTimeout))
.keyPairName(_override(this.keyPairName, o.keyPairName))
.mode(_override(this.mode, o.mode))
.numExecutors(_override(this.numExecutors, o.numExecutors))
.jvmOptions(_override(this.jvmOptions, o.jvmOptions))
.fsRoot(_override(this.fsRoot, o.fsRoot))
Expand Down Expand Up @@ -283,6 +293,7 @@ private Object readResolve() {
.availabilityZone(_erase(this.availabilityZone, defaults.availabilityZone))
.startTimeout(_erase(this.startTimeout, defaults.startTimeout))
.keyPairName(_erase(this.keyPairName, defaults.keyPairName))
.mode(_erase(this.mode, defaults.mode))
.numExecutors(_erase(this.numExecutors, defaults.numExecutors))
.jvmOptions(_erase(this.jvmOptions, defaults.jvmOptions))
.fsRoot(_erase(this.fsRoot, defaults.fsRoot))
Expand Down Expand Up @@ -315,6 +326,7 @@ public String toString() {
.append("availabilityZone", availabilityZone)
.append("startTimeout", startTimeout)
.append("keyPairName", keyPairName)
.append("mode", mode)
.append("numExecutors", numExecutors)
.append("jvmOptions", jvmOptions)
.append("fsRoot", fsRoot)
Expand Down Expand Up @@ -344,6 +356,7 @@ public boolean equals(Object o) {
if (!Objects.equals(availabilityZone, that.availabilityZone)) return false;
if (!Objects.equals(startTimeout, that.startTimeout)) return false;
if (!Objects.equals(keyPairName, that.keyPairName)) return false;
if (!Objects.equals(mode, that.mode)) return false;
if (!Objects.equals(numExecutors, that.numExecutors)) return false;
if (!Objects.equals(jvmOptions, that.jvmOptions)) return false;
if (!Objects.equals(fsRoot, that.fsRoot)) return false;
Expand All @@ -366,6 +379,7 @@ public int hashCode() {
result = 31 * result + (availabilityZone != null ? availabilityZone.hashCode() : 0);
result = 31 * result + (startTimeout != null ? startTimeout.hashCode() : 0);
result = 31 * result + (keyPairName != null ? keyPairName.hashCode() : 0);
result = 31 * result + (mode != null ? mode.hashCode() : 0);
result = 31 * result + (numExecutors != null ? numExecutors.hashCode() : 0);
result = 31 * result + (jvmOptions != null ? jvmOptions.hashCode() : 0);
result = 31 * result + (fsRoot != null ? fsRoot.hashCode() : 0);
Expand All @@ -392,6 +406,7 @@ public Builder getBuilder() {
.availabilityZone(availabilityZone)
.startTimeout(startTimeout)
.keyPairName(keyPairName)
.mode(mode)
.numExecutors(numExecutors)
.jvmOptions(jvmOptions)
.fsRoot(fsRoot)
Expand Down Expand Up @@ -426,6 +441,7 @@ public static final class Builder {
private @CheckForNull Integer startTimeout;
private @CheckForNull String keyPairName;

private @CheckForNull Node.Mode mode;
private @CheckForNull Integer numExecutors;
private @CheckForNull String jvmOptions;
private @CheckForNull String fsRoot;
Expand Down Expand Up @@ -496,6 +512,11 @@ public Builder() {}
return this;
}

public @Nonnull Builder mode(Node.Mode mode) {
this.mode = mode;
return this;
}

public @Nonnull Builder numExecutors(Integer numExecutors) {
this.numExecutors = numExecutors;
return this;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
<div name="slaveOptions" descriptorid="${descriptor.id}">
<rh:blockWrapper>
<f:section title="Cloud Server Options">
<f:slave-mode name="mode" node="${instance}"/>
<f:dropdownDescriptorSelector field="bootSource" title="Boot Source"/>
<f:entry title="Hardware" field="hardwareId">
<f:select checkMethod="post"/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ public static SlaveOptions dummySlaveOptions() {
dummyUserData("dummyUserDataId");
}
return new SlaveOptions(
new BootSource.VolumeSnapshot("id"), "hw", "nw1,mw2", "dummyUserDataId", 1, 2, "pool", "sg", "az", 1, null, 10,
new BootSource.VolumeSnapshot("id"), "hw", "nw1,mw2", "dummyUserDataId", 1, 2, "pool", "sg", "az", 1, null, Node.Mode.NORMAL, 10,
"jvmo", "fsRoot", LauncherFactory.JNLP.JNLP, mkListOfNodeProperties(1, 2), 1, null
);
}
Expand Down Expand Up @@ -185,6 +185,7 @@ public SlaveOptions defaultSlaveOptions() {
.keyPairName("dummyKeyPairName")
.jvmOptions("dummyJvmOptions")
.fsRoot("/tmp/jenkins")
.mode(Node.Mode.NORMAL)
.launcherFactory(LauncherFactory.JNLP.JNLP)
.build()
;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import hudson.ExtensionList;
import hudson.model.Item;
import hudson.model.Label;
import hudson.model.Node;
import hudson.model.UnprotectedRootAction;
import hudson.model.User;
import hudson.security.ACL;
Expand Down Expand Up @@ -133,10 +134,10 @@ public void presentUIDefaults() throws Exception {
String openstackAuth = j.dummyCredentials();

JCloudsSlaveTemplate template = new JCloudsSlaveTemplate("template", "label", new SlaveOptions(
new BootSource.Image("iid"), "hw", "nw", "ud", 1, 0, "public", "sg", "az", 2, "kp", 3, "jvmo", "fsRoot", LauncherFactory.JNLP.JNLP, null, 4, false
new BootSource.Image("iid"), "hw", "nw", "ud", 1, 0, "public", "sg", "az", 2, "kp", Node.Mode.NORMAL, 3, "jvmo", "fsRoot", LauncherFactory.JNLP.JNLP, null, 4, false
));
JCloudsCloud cloud = new JCloudsCloud("openstack", "endPointUrl", false,"zone", new SlaveOptions(
new BootSource.VolumeSnapshot("vsid"), "HW", "NW", "UD", 6, 4, null, "SG", "AZ", 7, "KP", 8, "JVMO", "FSrOOT", new LauncherFactory.SSH("cid"), null, 9, false
new BootSource.VolumeSnapshot("vsid"), "HW", "NW", "UD", 6, 4, null, "SG", "AZ", 7, "KP", Node.Mode.NORMAL, 8, "JVMO", "FSrOOT", new LauncherFactory.SSH("cid"), null, 9, false
), Collections.singletonList(template),openstackAuth);
j.jenkins.clouds.add(cloud);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ public void defaultOverrides() {
assertEquals("sg", unmodified.getSecurityGroups());
assertEquals("az", unmodified.getAvailabilityZone());
assertEquals(1, (int) unmodified.getStartTimeout());
assertEquals(Node.Mode.NORMAL, unmodified.getMode());
assertEquals(10, (int) unmodified.getNumExecutors());
assertEquals("jvmo", unmodified.getJvmOptions());
assertEquals("fsRoot", unmodified.getFsRoot());
Expand All @@ -53,6 +54,7 @@ public void defaultOverrides() {
.securityGroups("SG")
.availabilityZone("AZ")
.startTimeout(4)
.mode(Node.Mode.NORMAL)
.numExecutors(2)
.jvmOptions("JVMO")
.fsRoot("FSROOT")
Expand All @@ -74,6 +76,7 @@ public void defaultOverrides() {
assertEquals("SG", overridden.getSecurityGroups());
assertEquals("AZ", overridden.getAvailabilityZone());
assertEquals(4, (int) overridden.getStartTimeout());
assertEquals(Node.Mode.NORMAL, overridden.getMode());
assertEquals(2, (int) overridden.getNumExecutors());
assertEquals("JVMO", overridden.getJvmOptions());
assertEquals("FSROOT", overridden.getFsRoot());
Expand All @@ -99,7 +102,7 @@ public void eraseDefaults() {
public void emptyStrings() {
SlaveOptions nulls = SlaveOptions.empty();
SlaveOptions emptyStrings = new SlaveOptions(
null, "", "", "", null, null, "", "", "", null, "", null, "", "", null, null, null, null
null, "", "", "", null, null, "", "", "", null, "", null, null, "", "", null, null, null, null
);
SlaveOptions emptyBuilt = SlaveOptions.builder()
.hardwareId("")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,28 +37,33 @@ jenkins:
- name: "jnlp"
labels: "jnlp"
slaveOptions:
mode: NORMAL
launcherFactory: "jnlp"
- name: "volumeSnapshot"
labels: "volume"
slaveOptions:
mode: NORMAL
bootSource:
volumeSnapshot:
name: "Volume name"
- name: "volumeFromImage"
labels: "volume from image"
slaveOptions:
mode: NORMAL
bootSource:
volumeFromImage:
name: "Volume name"
volumeSize: 15
- name: "customNodeProperties"
labels: "templateWithItsOwnNodeProperties"
slaveOptions:
mode: NORMAL
nodeProperties:
- nodePropertyTwo
- name: "noNodeProperties"
labels: "templateWithNoNodePropertiesInsteadOfDefaults"
slaveOptions:
mode: NORMAL
nodeProperties: []

unclassified:
Expand Down