Skip to content

Commit 23dc9fa

Browse files
authored
Refresh Kubernetes instances before creating agents (#13)
* Refresh KubernetesInstances on each create-agent call * At the time of the pod creation, the state of pod will always be pending as it goes through a series of kubernetes queues before its running. * Refresh the state of KubernetesInstance as the pod state has changed since it has been scheduled. * Before each create-agent-request, refresh the state of all pods, and based on the refreshed pending/running state information, make a decision for scheduling a new pod. * Use created Kubernetes Pod for KubernetesInstance creation instead of using the reference pod * Once the pod has been created by the library, it returns the current state of the newly created pod, use newly created pod object for any future references
1 parent ba6333f commit 23dc9fa

File tree

7 files changed

+45
-26
lines changed

7 files changed

+45
-26
lines changed

src/main/java/cd/go/contrib/elasticagent/KubernetesAgentInstances.java

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@
3838
public class KubernetesAgentInstances implements AgentInstances<KubernetesInstance> {
3939
private final ConcurrentHashMap<String, KubernetesInstance> instances = new ConcurrentHashMap<>();
4040
public Clock clock = Clock.DEFAULT;
41-
private boolean refreshed;
4241
final Semaphore semaphore = new Semaphore(0, true);
4342

4443
private KubernetesClientFactory factory;
@@ -149,22 +148,17 @@ public Agents instancesCreatedAfterTimeout(PluginSettings settings, Agents agent
149148

150149
@Override
151150
public void refreshAll(PluginRequest pluginRequest) throws Exception {
152-
LOG.debug("Refreshing Elastic agents.");
151+
LOG.debug("[Refresh Instances]. Syncing k8s elastic agent pod information");
153152
KubernetesClient client = factory.kubernetes(pluginRequest.getPluginSettings());
154153
PodList list = client.pods().inNamespace(Constants.KUBERNETES_NAMESPACE_KEY).list();
155154

156-
if (!refreshed) {
157-
LOG.debug("Syncing k8s elastic agent pod information");
158-
for (Pod pod : list.getItems()) {
159-
Map<String, String> podLabels = pod.getMetadata().getLabels();
160-
if (podLabels != null) {
161-
if (StringUtils.equals(Constants.KUBERNETES_POD_KIND_LABEL_VALUE, podLabels.get(Constants.KUBERNETES_POD_KIND_LABEL_KEY))) {
162-
register(kubernetesInstanceFactory.fromKubernetesPod(pod));
163-
}
155+
for (Pod pod : list.getItems()) {
156+
Map<String, String> podLabels = pod.getMetadata().getLabels();
157+
if (podLabels != null) {
158+
if (StringUtils.equals(Constants.KUBERNETES_POD_KIND_LABEL_VALUE, podLabels.get(Constants.KUBERNETES_POD_KIND_LABEL_KEY))) {
159+
register(kubernetesInstanceFactory.fromKubernetesPod(pod));
164160
}
165161
}
166-
167-
refreshed = true;
168162
}
169163
}
170164

src/main/java/cd/go/contrib/elasticagent/KubernetesInstanceFactory.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,8 +112,8 @@ private static void setAnnotations(Pod pod, CreateAgentRequest request) {
112112

113113
private KubernetesInstance createKubernetesPod(KubernetesClient client, Pod elasticAgentPod) {
114114
LOG.info(String.format("[Create Agent] Creating K8s pod with spec:%s", elasticAgentPod.toString()));
115-
client.pods().inNamespace(Constants.KUBERNETES_NAMESPACE_KEY).create(elasticAgentPod);
116-
return fromKubernetesPod(elasticAgentPod);
115+
Pod pod = client.pods().inNamespace(Constants.KUBERNETES_NAMESPACE_KEY).create(elasticAgentPod);
116+
return fromKubernetesPod(pod);
117117
}
118118

119119
public KubernetesInstance fromKubernetesPod(Pod elasticAgentPod) {

src/main/java/cd/go/contrib/elasticagent/KubernetesPlugin.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,6 @@ public GoPluginApiResponse handle(GoPluginApiRequest request) throws UnhandledRe
7070
refreshInstances();
7171
return CreateAgentRequest.fromJSON(request.requestBody()).executor(agentInstances, pluginRequest).execute();
7272
case REQUEST_SHOULD_ASSIGN_WORK:
73-
refreshInstances();
7473
return ShouldAssignWorkRequest.fromJSON(request.requestBody()).executor(agentInstances).execute();
7574
case REQUEST_SERVER_PING:
7675
refreshInstances();

src/main/java/cd/go/contrib/elasticagent/PodState.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,18 +17,20 @@
1717
package cd.go.contrib.elasticagent;
1818

1919
import io.fabric8.kubernetes.api.model.Pod;
20-
import io.fabric8.kubernetes.api.model.PodStatus;
2120

2221
public enum PodState {
2322
Running,
2423
Pending;
2524

2625
public static PodState fromPod(Pod pod) {
27-
PodStatus status = pod.getStatus();
28-
if (status == null) {
26+
if (pod.getStatus() == null) {
2927
return Pending;
3028
}
3129

32-
return (status.getPhase() != null && status.getPhase().equals("Running")) ? Running : Pending;
30+
if ("Running".equals(pod.getStatus().getPhase())) {
31+
return Running;
32+
}
33+
34+
return Pending;
3335
}
3436
}

src/test/java/cd/go/contrib/elasticagent/KubernetesAgentInstancesIntegrationTest.java

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,13 @@
2020
import com.google.gson.Gson;
2121
import io.fabric8.kubernetes.api.model.*;
2222
import io.fabric8.kubernetes.client.KubernetesClient;
23-
import io.fabric8.kubernetes.client.dsl.internal.NodeOperationsImpl;
2423
import io.fabric8.kubernetes.client.dsl.internal.PodOperationsImpl;
2524
import org.junit.Before;
2625
import org.junit.Test;
2726
import org.mockito.ArgumentCaptor;
2827
import org.mockito.Mock;
28+
import org.mockito.invocation.InvocationOnMock;
29+
import org.mockito.stubbing.Answer;
2930

3031
import java.util.ArrayList;
3132
import java.util.HashMap;
@@ -54,9 +55,6 @@ public class KubernetesAgentInstancesIntegrationTest {
5455
@Mock
5556
private KubernetesClient mockKubernetesClient;
5657

57-
@Mock
58-
private NodeOperationsImpl nodes;
59-
6058
@Mock
6159
private PodOperationsImpl pods;
6260

@@ -67,6 +65,15 @@ public void setUp() throws Exception {
6765
when(mockedKubernetesClientFactory.kubernetes(any())).thenReturn(mockKubernetesClient);
6866

6967
when(pods.inNamespace(Constants.KUBERNETES_NAMESPACE_KEY)).thenReturn(pods);
68+
69+
when(pods.create(any())).thenAnswer(new Answer<Pod>() {
70+
@Override
71+
public Pod answer(InvocationOnMock invocation) throws Throwable {
72+
Object[] args = invocation.getArguments();
73+
return (Pod) args[0];
74+
}
75+
});
76+
7077
when(pods.list()).thenReturn(new PodList());
7178
when(mockKubernetesClient.pods()).thenReturn(pods);
7279

src/test/java/cd/go/contrib/elasticagent/executors/ServerPingRequestExecutorTest.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@
3232
import org.junit.Test;
3333
import org.mockito.ArgumentMatcher;
3434
import org.mockito.Mock;
35+
import org.mockito.invocation.InvocationOnMock;
36+
import org.mockito.stubbing.Answer;
3537

3638
import java.util.*;
3739

@@ -62,12 +64,20 @@ public void setUp() throws Exception {
6264
when(mockedClient.pods()).thenReturn(mockedOperation);
6365
when(mockedOperation.inNamespace(Constants.KUBERNETES_NAMESPACE_KEY)).thenReturn(mockedNamespaceOperation);
6466

65-
when(mockedNamespaceOperation.create(any(Pod.class))).thenReturn(mockedPod);
67+
when(mockedNamespaceOperation.create(any(Pod.class))).thenAnswer(new Answer<Pod>() {
68+
@Override
69+
public Pod answer(InvocationOnMock invocation) throws Throwable {
70+
Object[] args = invocation.getArguments();
71+
return (Pod) args[0];
72+
}
73+
});
74+
6675
when(mockedNamespaceOperation.withName(anyString())).thenReturn(podResource);
6776
when(podResource.get()).thenReturn(mockedPod);
6877

6978
objectMetadata = new ObjectMeta();
7079
objectMetadata.setCreationTimestamp(getSimpleDateFormat().format(new Date()));
80+
7181
when(mockedPod.getMetadata()).thenReturn(objectMetadata);
7282
}
7383

src/test/java/cd/go/contrib/elasticagent/executors/ShouldAssignWorkRequestExecutorTest.java

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@
3131
import org.junit.Before;
3232
import org.junit.Test;
3333
import org.mockito.Mock;
34+
import org.mockito.invocation.InvocationOnMock;
35+
import org.mockito.stubbing.Answer;
3436

3537
import java.util.HashMap;
3638
import java.util.Map;
@@ -40,7 +42,6 @@
4042
import static org.hamcrest.Matchers.is;
4143
import static org.junit.Assert.assertThat;
4244
import static org.mockito.ArgumentMatchers.any;
43-
import static org.mockito.Mockito.mock;
4445
import static org.mockito.Mockito.when;
4546
import static org.mockito.MockitoAnnotations.initMocks;
4647

@@ -64,7 +65,13 @@ public void setUp() throws Exception {
6465
when(factory.kubernetes(any(PluginSettings.class))).thenReturn(mockedClient);
6566
when(mockedClient.pods()).thenReturn(mockedOperation);
6667
when(mockedOperation.inNamespace(KUBERNETES_NAMESPACE_KEY)).thenReturn(mockedNamespaceOperation);
67-
when(mockedNamespaceOperation.create(any(Pod.class))).thenReturn(mock(Pod.class));
68+
when(mockedNamespaceOperation.create(any(Pod.class))).thenAnswer(new Answer<Pod>() {
69+
@Override
70+
public Pod answer(InvocationOnMock invocation) throws Throwable {
71+
Object[] args = invocation.getArguments();
72+
return (Pod) args[0];
73+
}
74+
});
6875

6976
agentInstances = new KubernetesAgentInstances(factory);
7077
properties.put("foo", "bar");

0 commit comments

Comments
 (0)