From cba5dd1c03a3132ee68ca3130532d38e4d9c97df Mon Sep 17 00:00:00 2001 From: BenjaminDecreusefond Date: Fri, 8 Nov 2024 14:05:09 +0100 Subject: [PATCH] feat: add possibility to mount config map on ephemeral job agent (#1505) * feat: add possibility to mount config map on ephemeral job agent --- .../ephemeral/EphemeralExecutorService.java | 42 +++++++++++++++---- ui/src/domain/Workspaces/Create.jsx | 2 +- ui/src/domain/Workspaces/Details.jsx | 2 +- 3 files changed, 37 insertions(+), 9 deletions(-) diff --git a/api/src/main/java/org/terrakube/api/plugin/scheduler/job/tcl/executor/ephemeral/EphemeralExecutorService.java b/api/src/main/java/org/terrakube/api/plugin/scheduler/job/tcl/executor/ephemeral/EphemeralExecutorService.java index 614650326..291f21790 100644 --- a/api/src/main/java/org/terrakube/api/plugin/scheduler/job/tcl/executor/ephemeral/EphemeralExecutorService.java +++ b/api/src/main/java/org/terrakube/api/plugin/scheduler/job/tcl/executor/ephemeral/EphemeralExecutorService.java @@ -1,9 +1,7 @@ package org.terrakube.api.plugin.scheduler.job.tcl.executor.ephemeral; import com.fasterxml.jackson.databind.ObjectMapper; -import io.fabric8.kubernetes.api.model.EnvFromSource; -import io.fabric8.kubernetes.api.model.EnvVar; -import io.fabric8.kubernetes.api.model.SecretEnvSource; +import io.fabric8.kubernetes.api.model.*; import io.fabric8.kubernetes.api.model.batch.v1.JobBuilder; import io.fabric8.kubernetes.client.KubernetesClient; import lombok.AllArgsConstructor; @@ -22,6 +20,9 @@ public class EphemeralExecutorService { private static final String NODE_SELECTOR = "EPHEMERAL_CONFIG_NODE_SELECTOR_TAGS"; private static final String SERVICE_ACCOUNT = "EPHEMERAL_CONFIG_SERVICE_ACCOUNT"; private static final String ANNOTATIONS = "EPHEMERAL_CONFIG_ANNOTATIONS"; + private static final String CONFIG_MAP_NAME = "EPHEMERAL_CONFIG_MAP_NAME"; + private static final String CONFIG_MAP_PATH = "EPHEMERAL_CONFIG_MAP_MOUNT_PATH"; + KubernetesClient kubernetesClient; EphemeralConfiguration ephemeralConfiguration; @@ -52,7 +53,7 @@ public boolean sendToEphemeralExecutor(Job job, ExecutorContext executorContext) final List executorEnvVarFlags = Arrays.asList(executorFlagBatch, executorFlagBatchJsonContent); - Optional nodeSelector = Optional.ofNullable(executorContext.getEnvironmentVariables().containsKey(NODE_SELECTOR) ? executorContext.getEnvironmentVariables().get(NODE_SELECTOR) : null); + Optional nodeSelector = Optional.ofNullable(executorContext.getEnvironmentVariables().getOrDefault(NODE_SELECTOR, null)); Map nodeSelectorInfo = new HashMap(); log.info("Custom Node selector: {} {}", nodeSelector.isPresent(), nodeSelector.isEmpty()); if(nodeSelector.isPresent()) { @@ -66,7 +67,7 @@ public boolean sendToEphemeralExecutor(Job job, ExecutorContext executorContext) nodeSelectorInfo = ephemeralConfiguration.getNodeSelector(); } - Optional annotationsInfo = Optional.ofNullable(executorContext.getEnvironmentVariables().containsKey(ANNOTATIONS) ? executorContext.getEnvironmentVariables().get(ANNOTATIONS) : null); + Optional annotationsInfo = Optional.ofNullable(executorContext.getEnvironmentVariables().getOrDefault(ANNOTATIONS, null)); Map annotations = new HashMap(); log.info("Custom Annotations: {}", annotationsInfo.isPresent()); if(annotationsInfo.isPresent()) { @@ -77,8 +78,33 @@ public boolean sendToEphemeralExecutor(Job job, ExecutorContext executorContext) } Optional serviceAccountInfo = Optional.ofNullable( - executorContext.getEnvironmentVariables().containsKey(SERVICE_ACCOUNT) ? executorContext.getEnvironmentVariables().get(SERVICE_ACCOUNT) : null); - String serviceAccount = serviceAccountInfo.isPresent() ? serviceAccountInfo.get() : null; + executorContext.getEnvironmentVariables().getOrDefault(SERVICE_ACCOUNT, null)); + String serviceAccount = serviceAccountInfo.orElse(null); + + // Volume and VolumeMount for ConfigMap if specified + List volumes = new ArrayList<>(); + List volumeMounts = new ArrayList<>(); + + Optional configMapNameOpt = Optional.ofNullable(executorContext.getEnvironmentVariables().get(CONFIG_MAP_NAME)); + Optional configMapMountPathOpt = Optional.ofNullable(executorContext.getEnvironmentVariables().get(CONFIG_MAP_PATH)); + if (configMapNameOpt.isPresent()) { + String configMapName = configMapNameOpt.get(); + String mountPath = configMapMountPathOpt.orElse("/tmp"); // Default mount path if not specified + + // Define ConfigMap volume + Volume configMapVolume = new Volume(); + configMapVolume.setName("config-volume"); + ConfigMapVolumeSource configMapVolumeSource = new ConfigMapVolumeSource(); + configMapVolumeSource.setName(configMapName); + configMapVolume.setConfigMap(configMapVolumeSource); + volumes.add(configMapVolume); + + // Define VolumeMount for the container + VolumeMount configMapMount = new VolumeMount(); + configMapMount.setName("config-volume"); + configMapMount.setMountPath(mountPath); + volumeMounts.add(configMapMount); + } io.fabric8.kubernetes.api.model.batch.v1.Job k8sJob = new JobBuilder() .withApiVersion("batch/v1") @@ -95,11 +121,13 @@ public boolean sendToEphemeralExecutor(Job job, ExecutorContext executorContext) .withNewSpec() .withNodeSelector(nodeSelectorInfo) .withServiceAccountName(serviceAccount) + .withVolumes(volumes) .addNewContainer() .withName(jobName) .withEnvFrom(executorEnvVarFromSecret) .withImage(ephemeralConfiguration.getImage()) .withEnv(executorEnvVarFlags) + .withVolumeMounts(volumeMounts) .endContainer() .withRestartPolicy("Never") .endSpec() diff --git a/ui/src/domain/Workspaces/Create.jsx b/ui/src/domain/Workspaces/Create.jsx index ab03183d3..7e6a9db18 100644 --- a/ui/src/domain/Workspaces/Create.jsx +++ b/ui/src/domain/Workspaces/Create.jsx @@ -799,7 +799,7 @@ export const CreateWorkspace = () => { name="webhookBranch" label="Webhook Branch" tooltip="A list of branch prefixes that will trigger a run." - extra="A list of brach prefixes besides the default VCS branch that will trigger a run, for example 'feat,fix'. Values are separated by comma." + extra="A list of branch regex besides the default VCS branch that will trigger a run, for example 'feat,fix'. Values are separated by comma." rules={[{ required: false }]} > diff --git a/ui/src/domain/Workspaces/Details.jsx b/ui/src/domain/Workspaces/Details.jsx index 94cfbd533..17d355c89 100644 --- a/ui/src/domain/Workspaces/Details.jsx +++ b/ui/src/domain/Workspaces/Details.jsx @@ -1520,7 +1520,7 @@ export const WorkspaceDetails = ({ setOrganizationName, selectedTab }) => { name="pushWebhookBranch" label="Webhook Branch" tooltip="A list of branch prefixes that will trigger a run." - extra="A list of brach prefixes besides the default VCS branch that will trigger a run, for example 'feat,fix'. Values are separated by comma." + extra="A list of branch regex besides the default VCS branch that will trigger a run, for example 'feat,fix'. Values are separated by comma." rules={[{ required: false }]} >