Skip to content

Commit c5d98c5

Browse files
committed
[JENKINS-67256] Integrate with Cloud Statistics plugin
Implement TrackedItem on KubernetesComputer and KubernetesSlave. StandardPlannedNodeBuilder now returns a TrackedPlannedNode.
1 parent cfd9c5a commit c5d98c5

File tree

6 files changed

+97
-9
lines changed

6 files changed

+97
-9
lines changed

pom.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,10 @@
8484
<groupId>org.jenkins-ci.plugins</groupId>
8585
<artifactId>bouncycastle-api</artifactId>
8686
</dependency>
87+
<dependency>
88+
<groupId>org.jenkins-ci.plugins</groupId>
89+
<artifactId>cloud-stats</artifactId>
90+
</dependency>
8791

8892
<dependency>
8993
<!-- Requires Permission -->
@@ -144,6 +148,8 @@
144148
<groupId>org.jenkins-ci.plugins.workflow</groupId>
145149
<artifactId>workflow-durable-task-step</artifactId>
146150
</dependency>
151+
152+
<!-- for testing -->
147153
<dependency>
148154
<groupId>org.jenkins-ci.plugins.workflow</groupId>
149155
<artifactId>workflow-step-api</artifactId>

src/main/java/org/csanchez/jenkins/plugins/kubernetes/KubernetesComputer.java

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package org.csanchez.jenkins.plugins.kubernetes;
22

3+
import edu.umd.cs.findbugs.annotations.CheckForNull;
34
import edu.umd.cs.findbugs.annotations.NonNull;
45
import hudson.model.Computer;
56
import hudson.model.Executor;
@@ -30,6 +31,8 @@
3031
import jenkins.model.Jenkins;
3132
import org.acegisecurity.Authentication;
3233
import org.apache.commons.lang.StringUtils;
34+
import org.jenkinsci.plugins.cloudstats.ProvisioningActivity;
35+
import org.jenkinsci.plugins.cloudstats.TrackedItem;
3336
import org.jenkinsci.plugins.kubernetes.auth.KubernetesAuthException;
3437
import org.kohsuke.stapler.QueryParameter;
3538
import org.kohsuke.stapler.StaplerRequest2;
@@ -41,7 +44,7 @@
4144
/**
4245
* @author Carlos Sanchez [email protected]
4346
*/
44-
public class KubernetesComputer extends AbstractCloudComputer<KubernetesSlave> {
47+
public class KubernetesComputer extends AbstractCloudComputer<KubernetesSlave> implements TrackedItem {
4548
private static final Logger LOGGER = Logger.getLogger(KubernetesComputer.class.getName());
4649

4750
private boolean launching;
@@ -244,4 +247,15 @@ public void setAcceptingTasks(boolean acceptingTasks) {
244247
launching = false;
245248
}
246249
}
250+
251+
@CheckForNull
252+
@Override
253+
public ProvisioningActivity.Id getId() {
254+
KubernetesSlave slave = getNode();
255+
if (slave != null) {
256+
return slave.getId();
257+
}
258+
259+
return null;
260+
}
247261
}

src/main/java/org/csanchez/jenkins/plugins/kubernetes/KubernetesSlave.java

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@
4949
import org.apache.commons.lang.StringUtils;
5050
import org.apache.commons.lang.Validate;
5151
import org.csanchez.jenkins.plugins.kubernetes.pod.retention.PodRetention;
52+
import org.jenkinsci.plugins.cloudstats.ProvisioningActivity;
53+
import org.jenkinsci.plugins.cloudstats.TrackedItem;
5254
import org.jenkinsci.plugins.durabletask.executors.OnceRetentionStrategy;
5355
import org.jenkinsci.plugins.kubernetes.auth.KubernetesAuthException;
5456
import org.jenkinsci.plugins.workflow.flow.FlowExecutionOwner;
@@ -58,7 +60,7 @@
5860
/**
5961
* @author Carlos Sanchez [email protected]
6062
*/
61-
public class KubernetesSlave extends AbstractCloudSlave {
63+
public class KubernetesSlave extends AbstractCloudSlave implements TrackedItem {
6264

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

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

90+
@NonNull
91+
private final ProvisioningActivity.Id id;
92+
8893
@NonNull
8994
public PodTemplate getTemplate() throws IllegalStateException {
9095
// Look up updated pod template after a restart
@@ -210,6 +215,7 @@ protected KubernetesSlave(
210215
this.cloudName = cloudName;
211216
this.template = template;
212217
this.podTemplateId = template.getId();
218+
this.id = new ProvisioningActivity.Id(cloudName, template.getName(), name);
213219
}
214220

215221
public String getCloudName() {
@@ -478,6 +484,12 @@ private void deleteSlavePod(TaskListener listener, KubernetesClient client) {
478484
listener.getLogger().println(msg);
479485
}
480486

487+
@CheckForNull
488+
@Override
489+
public ProvisioningActivity.Id getId() {
490+
return id;
491+
}
492+
481493
@Override
482494
public boolean equals(Object o) {
483495
if (this == o) return true;
Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
package org.csanchez.jenkins.plugins.kubernetes;
22

3-
import hudson.Util;
43
import hudson.model.Descriptor;
4+
import hudson.model.Node;
55
import hudson.slaves.NodeProvisioner;
66
import java.io.IOException;
77
import java.util.concurrent.CompletableFuture;
8+
import org.jenkinsci.plugins.cloudstats.ProvisioningActivity;
9+
import org.jenkinsci.plugins.cloudstats.TrackedPlannedNode;
810

911
/**
1012
* The default {@link PlannedNodeBuilder} implementation, in case there is other registered.
@@ -14,20 +16,25 @@ public class StandardPlannedNodeBuilder extends PlannedNodeBuilder {
1416
public NodeProvisioner.PlannedNode build() {
1517
KubernetesCloud cloud = getCloud();
1618
PodTemplate t = getTemplate();
17-
CompletableFuture f;
18-
String displayName;
19+
CompletableFuture<Node> f;
20+
ProvisioningActivity.Id id = null;
1921
try {
2022
KubernetesSlave agent = KubernetesSlave.builder()
2123
.podTemplate(t.isUnwrapped() ? t : cloud.getUnwrappedTemplate(t))
2224
.cloud(cloud)
2325
.build();
24-
displayName = agent.getDisplayName();
26+
id = agent.getId(); // always use one sourced from the slave we are provisioning so the identity is
27+
// maintained
2528
f = CompletableFuture.completedFuture(agent);
2629
} catch (IOException | Descriptor.FormException e) {
27-
displayName = null;
28-
f = new CompletableFuture();
30+
f = new CompletableFuture<>();
2931
f.completeExceptionally(e);
3032
}
31-
return new NodeProvisioner.PlannedNode(Util.fixNull(displayName), f, getNumExecutors());
33+
34+
if (id == null) {
35+
id = new ProvisioningActivity.Id(cloud.name, t.getName());
36+
}
37+
38+
return new TrackedPlannedNode(id, getNumExecutors(), f);
3239
}
3340
}

src/test/java/org/csanchez/jenkins/plugins/kubernetes/KubernetesSlaveTest.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
import org.csanchez.jenkins.plugins.kubernetes.pod.retention.PodRetention;
4747
import org.csanchez.jenkins.plugins.kubernetes.volumes.PodVolume;
4848
import org.jenkinsci.plugins.kubernetes.auth.KubernetesAuthException;
49+
import org.jenkinsci.plugins.cloudstats.ProvisioningActivity;
4950
import org.junit.Rule;
5051
import org.junit.Test;
5152
import org.jvnet.hudson.test.JenkinsRule;
@@ -164,6 +165,18 @@ private interface GetPodTestCase {
164165
void test(KubernetesCloud cloud, KubernetesSlave slave, PodResource podResource) throws Exception;
165166
}
166167

168+
@Test
169+
public void testProvisioningActivityId() throws Descriptor.FormException, IOException {
170+
PodTemplate pt = new PodTemplate("x");
171+
pt.setName("Template");
172+
KubernetesSlave slave = new KubernetesSlave("Node", pt, "bar", "Cloud", "", null, null);
173+
ProvisioningActivity.Id id = slave.getId();
174+
assertNotNull(id);
175+
assertEquals(id.getCloudName(), "Cloud");
176+
assertEquals(id.getTemplateName(), "Template");
177+
assertEquals(id.getNodeName(), "Node");
178+
}
179+
167180
@Test
168181
public void testGetPodRetention() {
169182
try {
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package org.csanchez.jenkins.plugins.kubernetes;
2+
3+
import static org.csanchez.jenkins.plugins.kubernetes.KubernetesTestUtil.assertRegex;
4+
import static org.junit.Assert.assertEquals;
5+
import static org.junit.Assert.assertTrue;
6+
7+
import hudson.slaves.NodeProvisioner;
8+
import org.jenkinsci.plugins.cloudstats.ProvisioningActivity;
9+
import org.jenkinsci.plugins.cloudstats.TrackedPlannedNode;
10+
import org.junit.Rule;
11+
import org.junit.Test;
12+
import org.jvnet.hudson.test.JenkinsRule;
13+
14+
public class StandardPlannedNodeBuilderTest {
15+
16+
@Rule
17+
public JenkinsRule r = new JenkinsRule();
18+
19+
@Test
20+
public void testBuild() {
21+
KubernetesCloud cloud = new KubernetesCloud("Cloud");
22+
PodTemplate template = new PodTemplate("t");
23+
template.setName("Template");
24+
StandardPlannedNodeBuilder builder = new StandardPlannedNodeBuilder();
25+
builder.cloud(cloud);
26+
builder.template(template);
27+
builder.numExecutors(1);
28+
29+
NodeProvisioner.PlannedNode plannedNode = builder.build();
30+
assertTrue(plannedNode instanceof TrackedPlannedNode);
31+
ProvisioningActivity.Id id = ((TrackedPlannedNode) plannedNode).getId();
32+
assertEquals(id.getCloudName(), "Cloud");
33+
assertEquals(id.getTemplateName(), "Template");
34+
assertRegex(id.getNodeName(), "template-\\w{5}");
35+
}
36+
}

0 commit comments

Comments
 (0)