Skip to content

Commit 8fe8f2b

Browse files
authored
Make KubernetesNodeContext public (#1700)
1 parent cb42cbb commit 8fe8f2b

File tree

4 files changed

+127
-29
lines changed

4 files changed

+127
-29
lines changed

src/main/java/org/csanchez/jenkins/plugins/kubernetes/pipeline/ContainerExecDecorator.java

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@
5959
import org.csanchez.jenkins.plugins.kubernetes.ContainerTemplate;
6060
import org.csanchez.jenkins.plugins.kubernetes.KubernetesSlave;
6161
import org.csanchez.jenkins.plugins.kubernetes.PodContainerSource;
62+
import org.jenkinsci.plugins.kubernetes.auth.KubernetesAuthException;
6263
import org.jenkinsci.plugins.workflow.steps.EnvironmentExpander;
6364

6465
/**
@@ -462,10 +463,8 @@ private Proc doLaunch(
462463
final CountDownLatch finished = new CountDownLatch(1);
463464
final AtomicLong startAlive = new AtomicLong();
464465

465-
ExecWatch watch = getClient()
466-
.pods()
467-
.inNamespace(getNamespace())
468-
.withName(getPodName())
466+
ExecWatch watch = nodeContext
467+
.getPodResource()
469468
.inContainer(containerName)
470469
.redirectingInput(STDIN_BUFFER_SIZE) // JENKINS-50429
471470
.writingOutput(stream)
@@ -527,10 +526,15 @@ public void onClose(int i, String s) {
527526
throw e;
528527
}
529528

529+
} catch (KubernetesAuthException e) {
530+
launcher.getListener().getLogger().print("Failed to authenticate with Kubernetes cluster: ");
531+
e.printStackTrace(launcher.getListener().getLogger());
532+
throw new AbortException("Failed to authenticate with Kubernetes cluster");
530533
} catch (KubernetesClientException e) {
531534
launcher.getListener().getLogger().print("Failed to start websocket connection: ");
532535
String message = e.getMessage();
533536
if (message != null && message.startsWith("container " + containerName + " not found in pod")) {
537+
launcher.getListener().getLogger().print(message);
534538
// Don't even retry if the container is invalid.
535539
throw e;
536540
}

src/main/java/org/csanchez/jenkins/plugins/kubernetes/pipeline/ContainerLogStepExecution.java

Lines changed: 5 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818

1919
import hudson.model.TaskListener;
2020
import hudson.util.LogTaskListener;
21-
import io.fabric8.kubernetes.client.KubernetesClient;
21+
import io.fabric8.kubernetes.client.dsl.ContainerResource;
2222
import io.fabric8.kubernetes.client.dsl.TailPrettyLoggable;
2323
import io.fabric8.kubernetes.client.dsl.TimeTailPrettyLoggable;
2424
import java.io.IOException;
@@ -30,10 +30,9 @@
3030

3131
public class ContainerLogStepExecution extends SynchronousNonBlockingStepExecution<String> {
3232
private static final long serialVersionUID = 5588861066775717487L;
33-
private static final transient Logger LOGGER = Logger.getLogger(ContainerLogStepExecution.class.getName());
33+
private static final Logger LOGGER = Logger.getLogger(ContainerLogStepExecution.class.getName());
3434

3535
private final ContainerLogStep step;
36-
private transient KubernetesClient client;
3736

3837
ContainerLogStepExecution(ContainerLogStep step, StepContext context) {
3938
super(context);
@@ -67,20 +66,11 @@ protected String run() throws Exception {
6766
LOGGER.log(Level.FINE, "Starting containerLog step.");
6867

6968
KubernetesNodeContext nodeContext = new KubernetesNodeContext(getContext());
70-
client = nodeContext.connectToCloud();
7169

7270
String podName = nodeContext.getPodName();
73-
74-
TimeTailPrettyLoggable limited = limitBytes > 0
75-
? client.pods() //
76-
.inNamespace(nodeContext.getNamespace()) //
77-
.withName(podName)
78-
.inContainer(containerName)
79-
.limitBytes(limitBytes)
80-
: client.pods() //
81-
.inNamespace(nodeContext.getNamespace()) //
82-
.withName(podName)
83-
.inContainer(containerName);
71+
ContainerResource containerResource = nodeContext.getPodResource().inContainer(containerName);
72+
TimeTailPrettyLoggable limited =
73+
limitBytes > 0 ? containerResource.limitBytes(limitBytes) : containerResource;
8474

8575
TailPrettyLoggable since = sinceSeconds > 0 ? limited.sinceSeconds(sinceSeconds) : limited;
8676

src/main/java/org/csanchez/jenkins/plugins/kubernetes/pipeline/KubernetesNodeContext.java

Lines changed: 51 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,48 +16,89 @@
1616

1717
package org.csanchez.jenkins.plugins.kubernetes.pipeline;
1818

19+
import edu.umd.cs.findbugs.annotations.CheckForNull;
20+
import edu.umd.cs.findbugs.annotations.NonNull;
21+
import edu.umd.cs.findbugs.annotations.Nullable;
1922
import hudson.AbortException;
2023
import hudson.model.Node;
2124
import io.fabric8.kubernetes.client.KubernetesClient;
25+
import io.fabric8.kubernetes.client.dsl.PodResource;
2226
import java.io.IOException;
2327
import java.io.Serializable;
2428
import org.csanchez.jenkins.plugins.kubernetes.KubernetesSlave;
29+
import org.jenkinsci.plugins.kubernetes.auth.KubernetesAuthException;
2530
import org.jenkinsci.plugins.workflow.steps.StepContext;
2631

2732
/**
2833
* helper class for steps running in a kubernetes `node` context
2934
*/
30-
class KubernetesNodeContext implements Serializable {
35+
public class KubernetesNodeContext implements Serializable {
3136

3237
private static final long serialVersionUID = 1L;
3338

34-
private StepContext context;
39+
private final StepContext context;
40+
private final String podName;
3541

36-
private String podName;
37-
private String namespace;
42+
@CheckForNull
43+
private final String namespace;
3844

39-
KubernetesNodeContext(StepContext context) throws Exception {
45+
/**
46+
* Create new Kubernetes context
47+
* @param context step context, not null
48+
* @throws Exception if {@link Node} context not instance of {@link KubernetesSlave} or interrupted.
49+
*/
50+
public KubernetesNodeContext(@NonNull StepContext context) throws Exception {
4051
this.context = context;
4152
KubernetesSlave agent = getKubernetesSlave();
4253
this.podName = agent.getPodName();
4354
this.namespace = agent.getNamespace();
4455
}
4556

46-
// TODO remove the Exception thrown
47-
String getPodName() throws Exception {
57+
/**
58+
* Kubernetes Pod name.
59+
* @return pod name, never {@code null}
60+
*/
61+
@NonNull
62+
public String getPodName() {
4863
return podName;
4964
}
5065

51-
// TODO remove the Exception thrown
52-
public String getNamespace() throws Exception {
66+
/**
67+
* Kubernetes namespace Pod is running in.
68+
* @return kubernetes namespace or {@code null}
69+
*/
70+
@Nullable
71+
public String getNamespace() {
5372
return namespace;
5473
}
5574

75+
/**
76+
* Get node {@link PodResource}.
77+
* @return client pod resource, never {@code null}
78+
* @throws IOException if IO exception
79+
* @throws InterruptedException if interrupted
80+
* @throws KubernetesAuthException if authentication failure
81+
* @see org.csanchez.jenkins.plugins.kubernetes.KubernetesCloud#getPodResource(String, String)
82+
*/
83+
@NonNull
84+
public PodResource getPodResource() throws IOException, InterruptedException, KubernetesAuthException {
85+
return getKubernetesSlave().getKubernetesCloud().getPodResource(namespace, podName);
86+
}
87+
5688
KubernetesClient connectToCloud() throws Exception {
5789
return getKubernetesSlave().getKubernetesCloud().connect();
5890
}
5991

60-
private KubernetesSlave getKubernetesSlave() throws IOException, InterruptedException {
92+
/**
93+
* Get {@link Node} from the {@link StepContext}. If the context instance is instance of
94+
* {@link KubernetesSlave} it will be returned otherwise an exception is thrown.
95+
* @return kubernetes slave node context, never {@code null}
96+
* @throws IOException if IO exception
97+
* @throws InterruptedException if interrupted
98+
* @throws AbortException if {@link Node} context is not instance of {@link KubernetesSlave}
99+
*/
100+
@NonNull
101+
public final KubernetesSlave getKubernetesSlave() throws IOException, InterruptedException {
61102
Node node = context.get(Node.class);
62103
if (!(node instanceof KubernetesSlave)) {
63104
throw new AbortException(
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
package org.csanchez.jenkins.plugins.kubernetes.pipeline;
2+
3+
import static org.junit.Assert.*;
4+
import static org.mockito.Mockito.mock;
5+
import static org.mockito.Mockito.when;
6+
7+
import hudson.AbortException;
8+
import hudson.model.Node;
9+
import io.fabric8.kubernetes.client.dsl.PodResource;
10+
import org.csanchez.jenkins.plugins.kubernetes.KubernetesCloud;
11+
import org.csanchez.jenkins.plugins.kubernetes.KubernetesSlave;
12+
import org.jenkinsci.plugins.workflow.steps.StepContext;
13+
import org.junit.Before;
14+
import org.junit.Test;
15+
import org.junit.runner.RunWith;
16+
import org.mockito.Mock;
17+
import org.mockito.junit.MockitoJUnitRunner;
18+
19+
@RunWith(MockitoJUnitRunner.class)
20+
public class KubernetesNodeContextTest {
21+
22+
@Mock
23+
private StepContext context;
24+
25+
@Mock
26+
private KubernetesSlave slave;
27+
28+
@Mock
29+
private KubernetesCloud cloud;
30+
31+
@Mock
32+
private PodResource podResource;
33+
34+
@Before
35+
public void setup() {
36+
when(slave.getKubernetesCloud()).thenReturn(cloud);
37+
when(slave.getPodName()).thenReturn("foo");
38+
when(slave.getNamespace()).thenReturn("bar");
39+
}
40+
41+
@Test
42+
public void createContext() throws Exception {
43+
when(cloud.getPodResource("bar", "foo")).thenReturn(podResource);
44+
when(context.get(Node.class)).thenReturn(slave);
45+
KubernetesNodeContext knc = new KubernetesNodeContext(context);
46+
assertEquals("foo", knc.getPodName());
47+
assertEquals("bar", knc.getNamespace());
48+
assertSame(slave, knc.getKubernetesSlave());
49+
assertSame(podResource, knc.getPodResource());
50+
}
51+
52+
@Test
53+
public void notKubernetesSlaveInstance() throws Exception {
54+
Node node = mock(Node.class);
55+
when(context.get(Node.class)).thenReturn(node);
56+
try {
57+
new KubernetesNodeContext(context);
58+
fail("expected abort exception");
59+
} catch (AbortException ae) {
60+
assertTrue(ae.getMessage().startsWith("Node is not a Kubernetes node"));
61+
}
62+
}
63+
}

0 commit comments

Comments
 (0)