Skip to content

Commit fb4bdd0

Browse files
kubernetes deployment component added
1 parent 23186f9 commit fb4bdd0

File tree

1 file changed

+196
-0
lines changed

1 file changed

+196
-0
lines changed
Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
package com.trendyol.kubernetesoperatorapi.adapter.kubernetes.component;
2+
3+
import com.trendyol.kubernetesoperatorapi.domain.enumtype.RollBackLevel;
4+
import com.trendyol.kubernetesoperatorapi.domain.exception.RollBackBusinessException;
5+
import com.trendyol.kubernetesoperatorapi.infra.annotation.RetryOperation;
6+
import io.kubernetes.client.openapi.ApiClient;
7+
import io.kubernetes.client.openapi.ApiException;
8+
import io.kubernetes.client.openapi.apis.AppsV1Api;
9+
import io.kubernetes.client.openapi.apis.CoreV1Api;
10+
import io.kubernetes.client.openapi.models.*;
11+
import lombok.RequiredArgsConstructor;
12+
import lombok.extern.slf4j.Slf4j;
13+
import org.springframework.stereotype.Component;
14+
15+
import java.util.ArrayList;
16+
import java.util.Map;
17+
import java.util.Objects;
18+
import java.util.Optional;
19+
20+
import static com.trendyol.kubernetesoperatorapi.infra.constant.Constant.*;
21+
22+
@Slf4j
23+
@Component
24+
@RequiredArgsConstructor
25+
public class KubernetesDeploymentComponent {
26+
27+
private final KubernetesYamlConverterComponent kubernetesYamlConverterComponent;
28+
29+
@RetryOperation(retryCount = 3, waitSeconds = 1)
30+
public String deployMaster(ApiClient apiClient, Map<String, String> variables) {
31+
AppsV1Api appsV1Api = new AppsV1Api(apiClient);
32+
String runId = variables.get("RUN_ID");
33+
String deploymentName = MASTER_DEPLOYMENT_NAME_PREFIX + runId;
34+
35+
V1Deployment deployment = (V1Deployment) kubernetesYamlConverterComponent.convertKubernetesYml(variables, MASTER_DEPLOYMENT_YAML_PATH, V1Deployment.class);
36+
37+
try {
38+
appsV1Api.createNamespacedDeployment(NAMESPACE, deployment, null, null, null, null);
39+
} catch (ApiException e) {
40+
log.error("Encountered an exception while consuming create name spaced deployment by deploymentName: {} , exceptionMessage: {}", deploymentName, e.getResponseBody());
41+
throw new RollBackBusinessException("Encountered an exception while consuming create name spaced deployment for master", RollBackLevel.BEFORE_MASTER_DEPLOYMENT);
42+
}
43+
return deploymentName;
44+
}
45+
46+
@RetryOperation(retryCount = 3, waitSeconds = 1)
47+
public String deployWorker(ApiClient apiClient, Map<String, String> variables, int workerCount) {
48+
AppsV1Api appsV1Api = new AppsV1Api(apiClient);
49+
String runId = variables.get("RUN_ID");
50+
String deploymentName = WORKER_DEPLOYMENT_NAME_PREFIX + runId;
51+
52+
V1Deployment deployment = (V1Deployment) kubernetesYamlConverterComponent.convertKubernetesYml(variables, WORKER_DEPLOYMENT_YAML_PATH, V1Deployment.class);
53+
deployment.getSpec().replicas(workerCount);
54+
55+
try {
56+
appsV1Api.createNamespacedDeployment(NAMESPACE, deployment, null, null, null, null);
57+
} catch (ApiException e) {
58+
log.error("Encountered an exception while consuming create name spaced deployment by deploymentName: {} , exceptionMessage: {}", deploymentName, e.getMessage(), e);
59+
throw new RollBackBusinessException("Encountered an exception while consuming create name spaced deployment for worker", RollBackLevel.BEFORE_WORKER_DEPLOYMENT);
60+
}
61+
return deploymentName;
62+
}
63+
64+
@RetryOperation(retryCount = 3, waitSeconds = 1)
65+
public boolean rollOutStatus(String runId, ApiClient apiClient, String deploymentName, String appName, int replicaCount) {
66+
AppsV1Api appsV1Api = new AppsV1Api(apiClient);
67+
CoreV1Api coreV1Api = new CoreV1Api(apiClient);
68+
69+
long start = System.currentTimeMillis();
70+
boolean deploymentReady = false;
71+
while (!deploymentReady) {
72+
if (System.currentTimeMillis() - start > TIMEOUT_VALUE_FOR_ROLLOUT) {
73+
break;
74+
}
75+
try {
76+
V1DeploymentStatus status = appsV1Api.readNamespacedDeployment(deploymentName, NAMESPACE, null).getStatus();
77+
78+
int readyReplicas = Objects.nonNull(status) ? Optional.ofNullable(status.getReadyReplicas()).orElse(0) : 0;
79+
80+
String labelSelector = String.format("id=%s,app=%s", runId, appName);
81+
V1PodList list = coreV1Api.listNamespacedPod(NAMESPACE, null, null, null, "status.phase=Running", labelSelector, Integer.MAX_VALUE, null, null, null, Boolean.FALSE);
82+
83+
log.info("Waiting for deployment {} to finish. {}/{} replicas are available. {}/{} pods are running", deploymentName, readyReplicas, replicaCount, list.getItems().size(), replicaCount);
84+
deploymentReady = readyReplicas >= replicaCount && list.getItems().size() >= replicaCount;
85+
86+
if (!deploymentReady) {
87+
Thread.sleep(INTERVAL_VALUE_FOR_ROLLOUT);
88+
}
89+
} catch (Exception ignored) {
90+
//This exception ignored, this method will try again without waiting.
91+
}
92+
}
93+
94+
if (deploymentReady) {
95+
log.info("Created deployment successfully: {}", deploymentName);
96+
return true;
97+
} else {
98+
log.error("An error occurred while creating deployment: {}", deploymentName);
99+
return false;
100+
}
101+
}
102+
103+
@RetryOperation(retryCount = 5, waitSeconds = 1)
104+
public void createService(ApiClient apiClient, String runId) {
105+
Map<String, String> variables = Map.of("RUN_ID", runId);
106+
107+
CoreV1Api coreV1Api = new CoreV1Api(apiClient);
108+
V1Service masterService = (V1Service) kubernetesYamlConverterComponent.convertKubernetesYml(variables, MASTER_SERVICE_YAML_PATH, V1Service.class);
109+
110+
try {
111+
coreV1Api.createNamespacedService(NAMESPACE, masterService, null, null, null, null);
112+
} catch (ApiException e) {
113+
log.error("Encountered an exception while consuming create name spaced component by serviceName: {} , exceptionMessage: {}", MASTER_SERVICE, e.getResponseBody());
114+
throw new RollBackBusinessException("Encountered an exception while consuming create name spaced component for " + MASTER_SERVICE, RollBackLevel.BEFORE_SERVICE);
115+
}
116+
log.info("component/{}-{} created", MASTER_SERVICE, runId);
117+
}
118+
119+
@RetryOperation(retryCount = 5, waitSeconds = 1)
120+
public void createServiceUi(ApiClient apiClient, String runId) {
121+
Map<String, String> variables = Map.of("RUN_ID", runId);
122+
123+
CoreV1Api coreV1Api = new CoreV1Api(apiClient);
124+
V1Service masterService = (V1Service) kubernetesYamlConverterComponent.convertKubernetesYml(variables, MASTER_SERVICE_UI_YAML_PATH, V1Service.class);
125+
126+
try {
127+
coreV1Api.createNamespacedService(NAMESPACE, masterService, null, null, null, null);
128+
} catch (ApiException e) {
129+
log.error("Encountered an exception while consuming create name spaced component by serviceName: {} , exceptionMessage: {}", MASTER_SERVICE_UI, e.getResponseBody());
130+
throw new RollBackBusinessException("Encountered an exception while consuming create name spaced component for " + MASTER_SERVICE_UI, RollBackLevel.BEFORE_SERVICE_UI);
131+
}
132+
log.info("component/{}-{} created", MASTER_SERVICE_UI, runId);
133+
}
134+
135+
public void printPodStatus(ApiClient apiClient, String runId) {
136+
CoreV1Api coreV1Api = new CoreV1Api(apiClient);
137+
try {
138+
V1PodList list = coreV1Api.listNamespacedPod(NAMESPACE, null, null, null, null, "id=" + runId, Integer.MAX_VALUE, null, null, null, Boolean.FALSE);
139+
var podInfos = new ArrayList<Object[]>();
140+
podInfos.add(new String[]{"NAME", "STATUS", "AGE"});
141+
long nowAsSecond = System.currentTimeMillis() / 1000;
142+
for (V1Pod pod : list.getItems()) {
143+
final long age = nowAsSecond - pod.getStatus().getStartTime().toEpochSecond();
144+
podInfos.add(new Object[]{pod.getMetadata().getName(), pod.getStatus().getPhase(), age + "s"});
145+
}
146+
147+
for (Object[] row : podInfos) {
148+
System.out.format("%-55s%-15s%-15s%n", row);
149+
}
150+
} catch (ApiException ignored) {
151+
//This exception ignored.
152+
}
153+
}
154+
155+
@RetryOperation(retryCount = 5, waitSeconds = 1)
156+
public V1ServiceList retrieveNamespacedServiceList(ApiClient apiClient, String runId) {
157+
CoreV1Api coreV1Api = new CoreV1Api(apiClient);
158+
V1ServiceList serviceList;
159+
try {
160+
serviceList = coreV1Api.listNamespacedService(NAMESPACE, null, null, null, null, "id=" + runId, Integer.MAX_VALUE, null, null, null, Boolean.FALSE);
161+
} catch (ApiException e) {
162+
log.error("Encountered an exception while listing name spaced service by exceptionMessage: {}", e.getResponseBody());
163+
throw new RollBackBusinessException("Encountered an exception while listing name spaced service by runId: {}" + runId, RollBackLevel.ALL_FLOW);
164+
}
165+
166+
return serviceList;
167+
}
168+
169+
public void printServiceStatus(V1ServiceList list) {
170+
var serviceInfos = new ArrayList<Object[]>();
171+
serviceInfos.add(new String[]{"NAME", "TYPE", "CLUSTER-IP", "PORT(S)", "AGE"});
172+
long nowAsSecond = System.currentTimeMillis() / 1000;
173+
for (V1Service service : list.getItems()) {
174+
175+
var ports = service.getSpec().getPorts();
176+
StringBuilder sb = new StringBuilder();
177+
for (int i = 0; i < ports.size(); i++) {
178+
sb.append(ports.get(i).getPort());
179+
sb.append(Objects.nonNull(ports.get(i).getNodePort()) ? ":" + ports.get(i).getNodePort() : "");
180+
sb.append("/");
181+
sb.append(ports.get(i).getProtocol());
182+
183+
if (i + 1 < ports.size()) {
184+
sb.append(",");
185+
}
186+
}
187+
188+
long age = nowAsSecond - service.getMetadata().getCreationTimestamp().toEpochSecond();
189+
serviceInfos.add(new Object[]{service.getMetadata().getName(), service.getSpec().getType(), service.getSpec().getClusterIP(), sb.toString(), age + "s"});
190+
}
191+
192+
for (Object[] row : serviceInfos) {
193+
System.out.format("%-40s%-15s%-15s%-25s%-15s%n", row);
194+
}
195+
}
196+
}

0 commit comments

Comments
 (0)