Skip to content

Commit

Permalink
[JENKINS-67256] Integrate with Cloud Statistics plugin
Browse files Browse the repository at this point in the history
Implement TrackedItem on KubernetesComputer and KubernetesSlave.
StandardPlannedNodeBuilder now returns a TrackedPlannedNode.
  • Loading branch information
cronik committed Apr 17, 2024
1 parent 1dd44f5 commit 669a7bb
Show file tree
Hide file tree
Showing 6 changed files with 98 additions and 9 deletions.
7 changes: 7 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,11 @@
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>authentication-tokens</artifactId>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>cloud-stats</artifactId>
<version>302.v45b_647b_90608</version>
</dependency>

<dependency>
<!-- Requires Permission -->
Expand Down Expand Up @@ -140,6 +145,8 @@
<groupId>org.jenkins-ci.plugins.workflow</groupId>
<artifactId>workflow-durable-task-step</artifactId>
</dependency>

<!-- for testing -->
<dependency>
<groupId>org.jenkins-ci.plugins.workflow</groupId>
<artifactId>workflow-step-api</artifactId>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.csanchez.jenkins.plugins.kubernetes;

import edu.umd.cs.findbugs.annotations.CheckForNull;
import edu.umd.cs.findbugs.annotations.NonNull;
import hudson.model.Computer;
import hudson.model.Executor;
Expand All @@ -23,6 +24,8 @@
import jenkins.model.Jenkins;
import org.acegisecurity.Authentication;
import org.apache.commons.lang.StringUtils;
import org.jenkinsci.plugins.cloudstats.ProvisioningActivity;
import org.jenkinsci.plugins.cloudstats.TrackedItem;
import org.jenkinsci.plugins.kubernetes.auth.KubernetesAuthException;
import org.kohsuke.stapler.QueryParameter;
import org.kohsuke.stapler.StaplerRequest;
Expand All @@ -34,7 +37,7 @@
/**
* @author Carlos Sanchez carlos@apache.org
*/
public class KubernetesComputer extends AbstractCloudComputer<KubernetesSlave> {
public class KubernetesComputer extends AbstractCloudComputer<KubernetesSlave> implements TrackedItem {
private static final Logger LOGGER = Logger.getLogger(KubernetesComputer.class.getName());

private boolean launching;
Expand Down Expand Up @@ -203,4 +206,15 @@ public void setAcceptingTasks(boolean acceptingTasks) {
launching = false;
}
}

@CheckForNull
@Override
public ProvisioningActivity.Id getId() {
KubernetesSlave slave = getNode();
if (slave != null) {
return slave.getId();
}

return null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.Validate;
import org.csanchez.jenkins.plugins.kubernetes.pod.retention.PodRetention;
import org.jenkinsci.plugins.cloudstats.ProvisioningActivity;
import org.jenkinsci.plugins.cloudstats.TrackedItem;
import org.jenkinsci.plugins.durabletask.executors.OnceRetentionStrategy;
import org.jenkinsci.plugins.kubernetes.auth.KubernetesAuthException;
import org.jenkinsci.plugins.workflow.flow.FlowExecutionOwner;
Expand All @@ -58,7 +60,7 @@
/**
* @author Carlos Sanchez carlos@apache.org
*/
public class KubernetesSlave extends AbstractCloudSlave {
public class KubernetesSlave extends AbstractCloudSlave implements TrackedItem {

private static final Logger LOGGER = Logger.getLogger(KubernetesSlave.class.getName());

Expand All @@ -85,6 +87,9 @@ public class KubernetesSlave extends AbstractCloudSlave {
@CheckForNull
private transient Pod pod;

@NonNull
private final ProvisioningActivity.Id id;

@NonNull
public PodTemplate getTemplate() throws IllegalStateException {
// Look up updated pod template after a restart
Expand Down Expand Up @@ -210,6 +215,7 @@ protected KubernetesSlave(
this.cloudName = cloudName;
this.template = template;
this.podTemplateId = template.getId();
this.id = new ProvisioningActivity.Id(cloudName, template.getName(), name);
}

public String getCloudName() {
Expand Down Expand Up @@ -450,6 +456,12 @@ private void deleteSlavePod(TaskListener listener, KubernetesClient client) thro
listener.getLogger().println(msg);
}

@CheckForNull
@Override
public ProvisioningActivity.Id getId() {
return id;
}

@Override
public String toString() {
return String.format("KubernetesSlave name: %s", name);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package org.csanchez.jenkins.plugins.kubernetes;

import hudson.Util;
import hudson.model.Descriptor;
import hudson.model.Node;
import hudson.slaves.NodeProvisioner;
import java.io.IOException;
import java.util.concurrent.CompletableFuture;
import org.jenkinsci.plugins.cloudstats.ProvisioningActivity;
import org.jenkinsci.plugins.cloudstats.TrackedPlannedNode;

/**
* The default {@link PlannedNodeBuilder} implementation, in case there is other registered.
Expand All @@ -14,20 +16,25 @@ public class StandardPlannedNodeBuilder extends PlannedNodeBuilder {
public NodeProvisioner.PlannedNode build() {
KubernetesCloud cloud = getCloud();
PodTemplate t = getTemplate();
CompletableFuture f;
String displayName;
CompletableFuture<Node> f;
ProvisioningActivity.Id id = null;
try {
KubernetesSlave agent = KubernetesSlave.builder()
.podTemplate(t.isUnwrapped() ? t : cloud.getUnwrappedTemplate(t))
.cloud(cloud)
.build();
displayName = agent.getDisplayName();
id = agent.getId(); // always use one sourced from the slave we are provisioning so the identity is
// maintained
f = CompletableFuture.completedFuture(agent);
} catch (IOException | Descriptor.FormException e) {
displayName = null;
f = new CompletableFuture();
f = new CompletableFuture<>();
f.completeExceptionally(e);
}
return new NodeProvisioner.PlannedNode(Util.fixNull(displayName), f, getNumExecutors());

if (id == null) {
id = new ProvisioningActivity.Id(cloud.name, t.getName());
}

return new TrackedPlannedNode(id, getNumExecutors(), f);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
import org.csanchez.jenkins.plugins.kubernetes.pod.retention.OnFailure;
import org.csanchez.jenkins.plugins.kubernetes.pod.retention.PodRetention;
import org.csanchez.jenkins.plugins.kubernetes.volumes.PodVolume;
import org.jenkinsci.plugins.cloudstats.ProvisioningActivity;
import org.junit.Rule;
import org.junit.Test;
import org.jvnet.hudson.test.JenkinsRule;
Expand Down Expand Up @@ -70,6 +71,18 @@ public void testGetSlaveName() {
("jenkins-agent-[0-9a-z]{5}"));
}

@Test
public void testProvisioningActivityId() throws Descriptor.FormException, IOException {
PodTemplate pt = new PodTemplate("x");
pt.setName("Template");
KubernetesSlave slave = new KubernetesSlave("Node", pt, "bar", "Cloud", "", null, null);
ProvisioningActivity.Id id = slave.getId();
assertNotNull(id);
assertEquals(id.getCloudName(), "Cloud");
assertEquals(id.getTemplateName(), "Template");
assertEquals(id.getNodeName(), "Node");
}

@Test
public void testGetPodRetention() {
try {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package org.csanchez.jenkins.plugins.kubernetes;

import static org.csanchez.jenkins.plugins.kubernetes.KubernetesTestUtil.assertRegex;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

import hudson.slaves.NodeProvisioner;
import org.jenkinsci.plugins.cloudstats.ProvisioningActivity;
import org.jenkinsci.plugins.cloudstats.TrackedPlannedNode;
import org.junit.Rule;
import org.junit.Test;
import org.jvnet.hudson.test.JenkinsRule;

public class StandardPlannedNodeBuilderTest {

@Rule
public JenkinsRule r = new JenkinsRule();

@Test
public void testBuild() {
KubernetesCloud cloud = new KubernetesCloud("Cloud");
PodTemplate template = new PodTemplate("t");
template.setName("Template");
StandardPlannedNodeBuilder builder = new StandardPlannedNodeBuilder();
builder.cloud(cloud);
builder.template(template);
builder.numExecutors(1);

NodeProvisioner.PlannedNode plannedNode = builder.build();
assertTrue(plannedNode instanceof TrackedPlannedNode);
ProvisioningActivity.Id id = ((TrackedPlannedNode) plannedNode).getId();
assertEquals(id.getCloudName(), "Cloud");
assertEquals(id.getTemplateName(), "Template");
assertRegex(id.getNodeName(), "template-\\w{5}");
}
}

0 comments on commit 669a7bb

Please sign in to comment.