Skip to content

Commit

Permalink
Merge pull request #298 from Vlatombe/planned_node_builder
Browse files Browse the repository at this point in the history
Allow customization of NodeProvisioner.PlannedNode using extension point
  • Loading branch information
carlossg authored Mar 21, 2018
2 parents d76e72d + 28d9597 commit 2cbbd30
Show file tree
Hide file tree
Showing 6 changed files with 291 additions and 30 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@
import hudson.Util;
import hudson.init.InitMilestone;
import hudson.init.Initializer;
import hudson.model.Computer;
import hudson.model.Descriptor;
import hudson.model.Label;
import hudson.model.Node;
Expand Down Expand Up @@ -405,9 +404,7 @@ public synchronized Collection<NodeProvisioner.PlannedNode> provision(@CheckForN
if (!addProvisionedSlave(t, label)) {
break;
}

r.add(new NodeProvisioner.PlannedNode(t.getDisplayName(), Computer.threadPoolForRemoting
.submit(new ProvisioningCallback(this, t, label)), 1));
r.add(PlannedNodeBuilderFactory.createInstance().cloud(this).template(t).label(label).build());
}
if (r.size() > 0) {
// Already found a matching template
Expand Down Expand Up @@ -487,6 +484,15 @@ public PodTemplate getTemplate(@CheckForNull Label label) {
return PodTemplateUtils.getTemplateByLabel(label, getAllTemplates());
}

/**
* Unwraps the given pod template.
* @param podTemplate the pod template to unwrap.
* @return the unwrapped pod template
*/
public PodTemplate getUnwrappedTemplate(PodTemplate podTemplate) {
return PodTemplateUtils.unwrap(podTemplate, getDefaultsProviderTemplate(), getAllTemplates());
}

/**
* Gets all PodTemplates that have the matching {@link Label}.
* @param label label to look for in templates
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

import org.apache.commons.lang.RandomStringUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.Validate;
import org.jenkinsci.plugins.durabletask.executors.Messages;
import org.jenkinsci.plugins.durabletask.executors.OnceRetentionStrategy;
import org.jvnet.localizer.Localizable;
Expand All @@ -29,6 +30,8 @@
import hudson.model.TaskListener;
import hudson.slaves.AbstractCloudSlave;
import hudson.slaves.Cloud;
import hudson.slaves.CloudRetentionStrategy;
import hudson.slaves.ComputerLauncher;
import hudson.slaves.OfflineCause;
import hudson.slaves.RetentionStrategy;
import io.fabric8.kubernetes.client.KubernetesClient;
Expand Down Expand Up @@ -62,7 +65,7 @@ public PodTemplate getTemplate() {
}

/**
* @deprecated Use {@link #KubernetesSlave(PodTemplate, String, String, String, RetentionStrategy)} instead.
* @deprecated Use {@link Builder} instead.
*/
@Deprecated
public KubernetesSlave(PodTemplate template, String nodeDescription, KubernetesCloud cloud, String labelStr)
Expand All @@ -72,7 +75,7 @@ public KubernetesSlave(PodTemplate template, String nodeDescription, KubernetesC
}

/**
* @deprecated Use {@link #KubernetesSlave(PodTemplate, String, String, String, RetentionStrategy)} instead.
* @deprecated Use {@link Builder} instead.
*/
@Deprecated
public KubernetesSlave(PodTemplate template, String nodeDescription, KubernetesCloud cloud, Label label)
Expand All @@ -81,7 +84,7 @@ public KubernetesSlave(PodTemplate template, String nodeDescription, KubernetesC
}

/**
* @deprecated Use {@link #KubernetesSlave(PodTemplate, String, String, String, RetentionStrategy)} instead.
* @deprecated Use {@link Builder} instead.
*/
@Deprecated
public KubernetesSlave(PodTemplate template, String nodeDescription, KubernetesCloud cloud, String labelStr,
Expand All @@ -90,18 +93,27 @@ public KubernetesSlave(PodTemplate template, String nodeDescription, KubernetesC
this(template, nodeDescription, cloud.name, labelStr, rs);
}

@DataBoundConstructor
/**
* @deprecated Use {@link Builder} instead.
*/
@Deprecated
@DataBoundConstructor // make stapler happy. Not actually used.
public KubernetesSlave(PodTemplate template, String nodeDescription, String cloudName, String labelStr,
RetentionStrategy rs)
throws Descriptor.FormException, IOException {
this(getSlaveName(template), template, nodeDescription, cloudName, labelStr, new KubernetesLauncher(), rs);
}

super(getSlaveName(template),
protected KubernetesSlave(String name, PodTemplate template, String nodeDescription, String cloudName, String labelStr,
ComputerLauncher computerLauncher, RetentionStrategy rs)
throws Descriptor.FormException, IOException {
super(name,
nodeDescription,
template.getRemoteFs(),
1,
template.getNodeUsageMode() != null ? template.getNodeUsageMode() : Node.Mode.NORMAL,
labelStr == null ? null : labelStr,
new KubernetesLauncher(),
computerLauncher,
rs,
template.getNodeProperties());

Expand Down Expand Up @@ -257,6 +269,118 @@ public int hashCode() {
return result;
}

/**
* Returns a new {@link Builder} instance.
* @return a new {@link Builder} instance.
*/
public static Builder builder() {
return new Builder();
}

/**
* Builds a {@link KubernetesSlave} instance.
*/
public static class Builder {
private String name;
private String nodeDescription;
private PodTemplate podTemplate;
private KubernetesCloud cloud;
private String label;
private ComputerLauncher computerLauncher;
private RetentionStrategy retentionStrategy;

/**
* @param name The name of the future {@link KubernetesSlave}
* @return the current instance for method chaining
*/
public Builder name(String name) {
this.name = name;
return this;
}

/**
* @param nodeDescription The node description of the future {@link KubernetesSlave}
* @return the current instance for method chaining
*/
public Builder nodeDescription(String nodeDescription) {
this.nodeDescription = nodeDescription;
return this;
}

/**
* @param podTemplate The pod template the future {@link KubernetesSlave} has been created from
* @return the current instance for method chaining
*/
public Builder podTemplate(PodTemplate podTemplate) {
this.podTemplate = podTemplate;
return this;
}

/**
* @param cloud The cloud that is provisioning the {@link KubernetesSlave} instance.
* @return the current instance for method chaining
*/
public Builder cloud(KubernetesCloud cloud) {
this.cloud = cloud;
return this;
}

/**
* @param label The label the {@link KubernetesSlave} has.
* @return the current instance for method chaining
*/
public Builder label(String label) {
this.label = label;
return this;
}

/**
* @param computerLauncher The computer launcher to use to launch the {@link KubernetesSlave} instance.
* @return the current instance for method chaining
*/
public Builder computerLauncher(ComputerLauncher computerLauncher) {
this.computerLauncher = computerLauncher;
return this;
}

/**
* @param retentionStrategy The retention strategy to use for the {@link KubernetesSlave} instance.
* @return the current instance for method chaining
*/
public Builder retentionStrategy(RetentionStrategy retentionStrategy) {
this.retentionStrategy = retentionStrategy;
return this;
}

private RetentionStrategy determineRetentionStrategy() {
if (podTemplate.getIdleMinutes() == 0) {
return new OnceRetentionStrategy(cloud.getRetentionTimeout());
} else {
return new CloudRetentionStrategy(podTemplate.getIdleMinutes());
}
}

/**
* Builds the resulting {@link KubernetesSlave} instance.
* @return an initialized {@link KubernetesSlave} instance.
* @throws IOException
* @throws Descriptor.FormException
*/
public KubernetesSlave build() throws IOException, Descriptor.FormException {
Validate.notNull(podTemplate);
Validate.notNull(cloud);
return new KubernetesSlave(
name == null ? getSlaveName(podTemplate) : name,
podTemplate,
nodeDescription == null ? podTemplate.getName() : nodeDescription,
cloud.name,
label == null ? podTemplate.getLabel() : label,
computerLauncher == null ? new KubernetesLauncher() : computerLauncher,
retentionStrategy == null ? determineRetentionStrategy() : retentionStrategy);
}
}


@Extension
public static final class DescriptorImpl extends SlaveDescriptor {

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package org.csanchez.jenkins.plugins.kubernetes;

import hudson.model.Label;
import hudson.slaves.NodeProvisioner;

/**
* A builder of {@link hudson.slaves.NodeProvisioner.PlannedNode} implementations for Kubernetes.
* Can be subclassed to provide alternative implementations of {@link hudson.slaves.NodeProvisioner.PlannedNode}.
*/
public abstract class PlannedNodeBuilder {
private KubernetesCloud cloud;
private PodTemplate template;
private Label label;
private int numExecutors = 1;

/**
* Returns the {@link KubernetesCloud}.
* @return the {@link KubernetesCloud}.
*/
public KubernetesCloud getCloud() {
return cloud;
}

/**
* Returns the {@link PodTemplate}.
* @return
*/
public PodTemplate getTemplate() {
return template;
}

public Label getLabel() {
return label;
}

public int getNumExecutors() {
return numExecutors;
}

/**
* @param cloud the {@link KubernetesCloud} instance to use.
* @return the current builder.
*/
public PlannedNodeBuilder cloud(KubernetesCloud cloud) {
this.cloud = cloud;
return this;
}

/**
* @param template the {@link PodTemplate} instance to use.
* @return the current builder.
*/
public PlannedNodeBuilder template(PodTemplate template) {
this.template = template;
return this;
}

/**
* @param label the {@link Label} to use.
* @return the current builder.
*/
public PlannedNodeBuilder label(Label label) {
this.label = label;
return this;
}

/**
* @param numExecutors the number of executors.
* @return the current builder.
*/
public PlannedNodeBuilder numExecutors(int numExecutors) {
this.numExecutors = numExecutors;
return this;
}

/**
* Builds the {@link hudson.slaves.NodeProvisioner.PlannedNode} instance based on the given inputs.
* @return a {@link hudson.slaves.NodeProvisioner.PlannedNode} configured from this builder.
*/
public abstract NodeProvisioner.PlannedNode build();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package org.csanchez.jenkins.plugins.kubernetes;

import hudson.ExtensionList;
import hudson.ExtensionPoint;

/**
* A factory of {@link PlannedNodeBuilder} instances.
*/
public abstract class PlannedNodeBuilderFactory implements ExtensionPoint {
/**
* Returns all registered implementations of {@link PlannedNodeBuilderFactory}.
* @return all registered implementations of {@link PlannedNodeBuilderFactory}.
*/
public static ExtensionList<PlannedNodeBuilderFactory> all() {
return ExtensionList.lookup(PlannedNodeBuilderFactory.class);
}

/**
* Returns a new instance of {@link PlannedNodeBuilder}.
* @return a new instance of {@link PlannedNodeBuilder}.
*/
public static PlannedNodeBuilder createInstance() {
for (PlannedNodeBuilderFactory factory: all()) {
PlannedNodeBuilder plannedNodeBuilder = factory.newInstance();
if (plannedNodeBuilder != null) {
return plannedNodeBuilder;
}
}
return new StandardPlannedNodeBuilder();
}

/**
* Creates a new instance of {@link PlannedNodeBuilder}.
* @return a new instance of {@link PlannedNodeBuilder}.
*/
public abstract PlannedNodeBuilder newInstance();
}
Loading

0 comments on commit 2cbbd30

Please sign in to comment.