From 560fd0351b10decd54656a30c7c9fad471a85d9d Mon Sep 17 00:00:00 2001 From: xhejtman Date: Tue, 24 Jan 2023 09:52:30 +0100 Subject: [PATCH] Configmap (#47) * Use configmap for JSON_INPUT Signed-off-by: Lukas Hejtmanek * Fix basic tests Signed-off-by: Lukas Hejtmanek * Fix integration tests Signed-off-by: Lukas Hejtmanek Signed-off-by: Lukas Hejtmanek --- .../java/uk/ac/ebi/tsc/tesk/AuthIT.java | 20 ++++++ .../java/uk/ac/ebi/tsc/tesk/NoAuthIT.java | 4 ++ .../k8s/convert/TesKubernetesConverter.java | 59 +++++++++++++++--- .../k8s/service/KubernetesClientWrapper.java | 9 +++ .../tsc/tesk/tes/service/TesServiceImpl.java | 3 + src/main/resources/taskmaster.json | 14 +++-- .../TesKubernetesConverterMinimalTest.java | 55 ++++++++++++----- .../convert/TesKubernetesConverterTest.java | 61 +++++++++++++------ src/test/resources/fromTesToK8s/job.json | 20 ++++-- .../resources/fromTesToK8s_minimal/job.json | 20 +++--- 10 files changed, 203 insertions(+), 62 deletions(-) diff --git a/src/integration-test/java/uk/ac/ebi/tsc/tesk/AuthIT.java b/src/integration-test/java/uk/ac/ebi/tsc/tesk/AuthIT.java index 4fb4a35..5f52942 100644 --- a/src/integration-test/java/uk/ac/ebi/tsc/tesk/AuthIT.java +++ b/src/integration-test/java/uk/ac/ebi/tsc/tesk/AuthIT.java @@ -76,6 +76,10 @@ public void admin_createTask() throws Exception { .withRequestBody(matchingJsonPath("$.metadata.labels[?(@.creator-user-id == '123')]")) .willReturn(okJson("{\"metadata\":{\"name\":\"task-fe99716a\"}}"))); + mockKubernetes.givenThat( + WireMock.post("/api/v1/namespaces/default/configmaps") + .willReturn(okJson("{\"metadata\":{\"name\":\"task-fe99716a\"}}"))); + String path = "fromTesToK8s_minimal/task.json"; this.mvc.perform(post(TASK_URL) .content(getFileContentFromResources(path)) @@ -97,6 +101,10 @@ public void adminAndMember_createTask() throws Exception { .withRequestBody(matchingJsonPath("$.metadata.labels[?(@.creator-user-id == '123')]")) .willReturn(okJson("{\"metadata\":{\"name\":\"task-fe99716a\"}}"))); + mockKubernetes.givenThat( + WireMock.post("/api/v1/namespaces/default/configmaps") + .willReturn(okJson("{\"metadata\":{\"name\":\"task-fe99716a\"}}"))); + String path = "fromTesToK8s_minimal/task.json"; this.mvc.perform(post(TASK_URL) .content(getFileContentFromResources(path)) @@ -133,6 +141,10 @@ public void authorizedUser_createTask() throws Exception { .withRequestBody(matchingJsonPath("$.metadata.labels[?(@.creator-user-id == '123')]")) .willReturn(okJson("{\"metadata\":{\"name\":\"task-fe99716a\"}}"))); + mockKubernetes.givenThat( + WireMock.post("/api/v1/namespaces/default/configmaps") + .willReturn(okJson("{\"metadata\":{\"name\":\"task-fe99716a\"}}"))); + String path = "fromTesToK8s_minimal/task.json"; this.mvc.perform(post(TASK_URL) .content(getFileContentFromResources(path)) @@ -153,6 +165,10 @@ public void multiGroups_createTask() throws Exception { .withRequestBody(matchingJsonPath("$.metadata.labels[?(@.creator-user-id == '123')]")) .willReturn(okJson("{\"metadata\":{\"name\":\"task-fe99716a\"}}"))); + mockKubernetes.givenThat( + WireMock.post("/api/v1/namespaces/default/configmaps") + .willReturn(okJson("{\"metadata\":{\"name\":\"task-fe99716a\"}}"))); + String path = "fromTesToK8s_minimal/task.json"; this.mvc.perform(post(TASK_URL) .content(getFileContentFromResources(path)) @@ -174,6 +190,10 @@ public void chosenGroup_createTask() throws Exception { .withRequestBody(matchingJsonPath("$.metadata.labels[?(@.creator-group-name == 'ABC')]")) .willReturn(okJson("{\"metadata\":{\"name\":\"task-fe99716a\"}}"))); + mockKubernetes.givenThat( + WireMock.post("/api/v1/namespaces/default/configmaps") + .willReturn(okJson("{\"metadata\":{\"name\":\"task-fe99716a\"}}"))); + mockKubernetes.givenThat( WireMock.get("/api/v1/namespaces/default/limitranges") .willReturn(okJson("{\"metadata\":{\"name\":\"core-resource-limits\"}}"))); diff --git a/src/integration-test/java/uk/ac/ebi/tsc/tesk/NoAuthIT.java b/src/integration-test/java/uk/ac/ebi/tsc/tesk/NoAuthIT.java index 82370d6..4d8b7a9 100644 --- a/src/integration-test/java/uk/ac/ebi/tsc/tesk/NoAuthIT.java +++ b/src/integration-test/java/uk/ac/ebi/tsc/tesk/NoAuthIT.java @@ -69,6 +69,10 @@ public void createTask() throws Exception { .withRequestBody(matchingJsonPath("$.metadata.labels[?(@.creator-user-id == 'anonymousUser')]")) .willReturn(okJson("{\"metadata\":{\"name\":\"task-fe99716a\"}}"))); + mockKubernetes.givenThat( + WireMock.post("/api/v1/namespaces/default/configmaps") + .willReturn(okJson("{\"metadata\":{\"name\":\"task-fe99716a\"}}"))); + String path = "fromTesToK8s_minimal/task.json"; this.mvc.perform(post(TASK_URL) .content(getFileContentFromResources(path)) diff --git a/src/main/java/uk/ac/ebi/tsc/tesk/k8s/convert/TesKubernetesConverter.java b/src/main/java/uk/ac/ebi/tsc/tesk/k8s/convert/TesKubernetesConverter.java index bc8442b..8df57a4 100644 --- a/src/main/java/uk/ac/ebi/tsc/tesk/k8s/convert/TesKubernetesConverter.java +++ b/src/main/java/uk/ac/ebi/tsc/tesk/k8s/convert/TesKubernetesConverter.java @@ -27,6 +27,9 @@ import java.util.stream.Collectors; import java.util.stream.IntStream; +import java.io.ByteArrayOutputStream; +import java.util.zip.GZIPOutputStream; + import static uk.ac.ebi.tsc.tesk.k8s.constant.Constants.*; import static uk.ac.ebi.tsc.tesk.k8s.constant.K8sConstants.*; @@ -89,31 +92,67 @@ public V1Job fromTesTaskToK8sJob(TesTask task, User user) { } catch (JsonProcessingException ex) { logger.info(String.format("Serializing task %s to JSON failed", taskMasterJob.getMetadata().getName()), ex); } - //Converting executors to Kubernetes Job Objects + + V1Volume volume = new V1Volume(); + volume.setName("jsoninput"); + V1ConfigMapVolumeSource src = new V1ConfigMapVolumeSource(); + src.setName(taskMasterJob.getMetadata().getName()); + volume.setConfigMap(src); + taskMasterJob.getSpec().getTemplate().getSpec().addVolumesItem(volume); + + return taskMasterJob; + } + + + /** + * Converts TES task to new K8s ConfigMap object with random generated name + * + * @param task - TES Task input object + * @return K8s Job Object + */ + @SuppressWarnings("unchecked") + public V1ConfigMap fromTesTaskToK8sConfigMap(TesTask task, User user, V1Job job) { + //get new Job template with random generated name; + V1ConfigMap taskMasterConfigMap = new V1ConfigMap(); + taskMasterConfigMap.setMetadata(new V1ObjectMeta()); + taskMasterConfigMap.getMetadata().setName(job.getMetadata().getName()); + //put input task name as annotation + taskMasterConfigMap.getMetadata().putAnnotationsItem(ANN_TESTASK_NAME_KEY, task.getName()); + //creating user and owning group + taskMasterConfigMap.getMetadata().putLabelsItem(LABEL_USERID_KEY, user.getUsername()); + if (task.getTags() != null && task.getTags().containsKey("GROUP_NAME")) { + taskMasterConfigMap.getMetadata().putLabelsItem(LABEL_GROUPNAME_KEY, task.getTags().get("GROUP_NAME")); + } else if (user.isMember()) { + taskMasterConfigMap.getMetadata().putLabelsItem(LABEL_GROUPNAME_KEY, user.getAnyGroup()); + } List executorsAsJobs = IntStream.range(0, task.getExecutors().size()). - mapToObj(i -> this.fromTesExecutorToK8sJob(taskMasterJob.getMetadata().getName(), task.getName(), task.getExecutors().get(i), i, task.getResources(), user)). + mapToObj(i -> this.fromTesExecutorToK8sJob(taskMasterConfigMap.getMetadata().getName(), task.getName(), task.getExecutors().get(i), i, task.getResources(), user)). collect(Collectors.toList()); Map taskMasterInput = new HashMap<>(); try { - //converting original inputs, outputs, volumes and disk size back again to JSON (will be part of taskMaster's input parameter) - //Jackson - for TES objects List inputs = task.getInputs() == null ? new ArrayList<>() : task.getInputs(); List outputs = task.getOutputs() == null ? new ArrayList<>() : task.getOutputs(); List volumes = task.getVolumes() == null ? new ArrayList<>() : task.getVolumes(); String jobAsJson = this.objectMapper.writeValueAsString(new TesTask().inputs(inputs).outputs(outputs).volumes(volumes). resources(new TesResources().diskGb(Optional.ofNullable(task.getResources()).map(TesResources::getDiskGb).orElse(RESOURCE_DISK_DEFAULT)))); - //merging 2 JSONs together into one map Map jobAsMap = gson.fromJson(jobAsJson, Map.class); taskMasterInput.putAll(jobAsMap); } catch (JsonProcessingException e) { - logger.info(String.format("Serializing copy of task %s to JSON failed", taskMasterJob.getMetadata().getName()), e); - //TODO throw + logger.info(String.format("Serializing copy of task %s to JSON failed", taskMasterConfigMap.getMetadata().getName()), e); } taskMasterInput.put(TASKMASTER_INPUT_EXEC_KEY, executorsAsJobs); String taskMasterInputAsJSON = this.gson.toJson(taskMasterInput); - //placing taskmaster's parameter (JSONed map of: inputs, outputs, volumes, executors (as jobs) into ENV variable in taskmaster spec - taskMasterJob.getSpec().getTemplate().getSpec().getContainers().get(0).getEnv().stream().filter(x -> x.getName().equals(TASKMASTER_INPUT)).forEach(x -> x.setValue(taskMasterInputAsJSON)); - return taskMasterJob; + + try { + ByteArrayOutputStream obj=new ByteArrayOutputStream(); + GZIPOutputStream gzip = new GZIPOutputStream(obj); + gzip.write(taskMasterInputAsJSON.getBytes("UTF-8")); + gzip.close(); + taskMasterConfigMap.putBinaryDataItem(TASKMASTER_INPUT+".gz", obj.toByteArray()); + } catch (Exception e) { + logger.info(String.format("Compression of task %s JSON configmap failed", taskMasterConfigMap.getMetadata().getName()), e); + } + return taskMasterConfigMap; } /** diff --git a/src/main/java/uk/ac/ebi/tsc/tesk/k8s/service/KubernetesClientWrapper.java b/src/main/java/uk/ac/ebi/tsc/tesk/k8s/service/KubernetesClientWrapper.java index a5a12cf..38b1834 100644 --- a/src/main/java/uk/ac/ebi/tsc/tesk/k8s/service/KubernetesClientWrapper.java +++ b/src/main/java/uk/ac/ebi/tsc/tesk/k8s/service/KubernetesClientWrapper.java @@ -5,6 +5,7 @@ import io.kubernetes.client.openapi.apis.CoreV1Api; import io.kubernetes.client.openapi.models.V1Job; +import io.kubernetes.client.openapi.models.V1ConfigMap; import io.kubernetes.client.openapi.models.V1JobList; import io.kubernetes.client.openapi.models.V1PodList; import io.kubernetes.client.openapi.models.V1LimitRangeList; @@ -68,6 +69,14 @@ public V1Job createJob(V1Job job) { } } + public V1ConfigMap createConfigMap(V1ConfigMap map) { + try { + return this.coreApi.createNamespacedConfigMap(namespace, map, null, null, null); + } catch (ApiException e) { + throw KubernetesException.fromApiException(e); + } + } + public V1Job readTaskmasterJob(String taskId) { try { V1Job job = this.batchApi.readNamespacedJob(taskId, namespace, null, null, null); diff --git a/src/main/java/uk/ac/ebi/tsc/tesk/tes/service/TesServiceImpl.java b/src/main/java/uk/ac/ebi/tsc/tesk/tes/service/TesServiceImpl.java index ce7139f..fbed1ba 100644 --- a/src/main/java/uk/ac/ebi/tsc/tesk/tes/service/TesServiceImpl.java +++ b/src/main/java/uk/ac/ebi/tsc/tesk/tes/service/TesServiceImpl.java @@ -1,6 +1,7 @@ package uk.ac.ebi.tsc.tesk.tes.service; import io.kubernetes.client.openapi.models.V1Job; +import io.kubernetes.client.openapi.models.V1ConfigMap; import io.kubernetes.client.openapi.models.V1JobList; import io.kubernetes.client.openapi.models.V1PodList; import org.springframework.stereotype.Service; @@ -65,6 +66,8 @@ public TesCreateTaskResponse createTask(TesTask task, User user) { } V1Job taskMasterJob = this.converter.fromTesTaskToK8sJob(task, user); + V1ConfigMap taskMasterConfigMap = this.converter.fromTesTaskToK8sConfigMap(task, user, taskMasterJob); + V1ConfigMap createdConfigMap = this.kubernetesClientWrapper.createConfigMap(taskMasterConfigMap); V1Job createdJob = this.kubernetesClientWrapper.createJob(taskMasterJob); return this.converter.fromK8sJobToTesCreateTaskResponse(createdJob); } catch (KubernetesException e) { diff --git a/src/main/resources/taskmaster.json b/src/main/resources/taskmaster.json index 7c7b204..8230aae 100644 --- a/src/main/resources/taskmaster.json +++ b/src/main/resources/taskmaster.json @@ -16,13 +16,10 @@ "name": "taskmaster", "image": "eu.gcr.io/tes-wes/taskmaster:v0.0.5.2", "args": [ - "$(JSON_INPUT)" + "-f", + "/jsoninput/JSON_INPUT.gz" ], "env": [ - { - "name": "JSON_INPUT", - "value": "" - }, { "name": "TESK_FTP_USERNAME", "valueFrom": { @@ -49,7 +46,12 @@ "name": "podinfo", "mountPath": "/podinfo", "readOnly": true - } + }, + { + "name": "jsoninput", + "mountPath": "/jsoninput", + "readOnly": true + } ] } ], diff --git a/src/test/java/uk/ac/ebi/tsc/tesk/k8s/convert/TesKubernetesConverterMinimalTest.java b/src/test/java/uk/ac/ebi/tsc/tesk/k8s/convert/TesKubernetesConverterMinimalTest.java index 0b990fd..1feae06 100644 --- a/src/test/java/uk/ac/ebi/tsc/tesk/k8s/convert/TesKubernetesConverterMinimalTest.java +++ b/src/test/java/uk/ac/ebi/tsc/tesk/k8s/convert/TesKubernetesConverterMinimalTest.java @@ -6,6 +6,7 @@ import io.kubernetes.client.openapi.models.V1JobStatus; import io.kubernetes.client.openapi.models.V1ObjectMeta; import io.kubernetes.client.openapi.models.V1PodList; +import io.kubernetes.client.openapi.models.V1ConfigMap; import org.hamcrest.CoreMatchers; import org.junit.Before; import org.junit.Test; @@ -38,6 +39,7 @@ import java.io.*; import java.util.function.Supplier; +import java.util.Map; import static org.assertj.core.api.Assertions.assertThat; import static org.hamcrest.Matchers.is; @@ -52,6 +54,8 @@ import static uk.ac.ebi.tsc.tesk.k8s.constant.Constants.LABEL_TASKSTATE_KEY; import static uk.ac.ebi.tsc.tesk.k8s.constant.Constants.LABEL_TASKSTATE_VALUE_CANC; +import java.io.ByteArrayInputStream; +import java.util.zip.GZIPInputStream; /** * @author Ania Niewielska @@ -125,10 +129,43 @@ public void fromTesTaskToK8sJob_minimal() throws IOException { assertThat(outputJob.getMetadata().getLabels().get("creator-user-id"), is("test-user-id")); assertThat(outputJob.getMetadata().getLabels().get("creator-group-name"), is("ABC")); - assertThat(outputJob.getSpec().getTemplate().getSpec().getContainers().get(0).getArgs().get(0), is("$(JSON_INPUT)")); + Resource outputJobFile = new ClassPathResource("fromTesToK8s_minimal/job.json"); + V1Job expectedJob; + try (InputStream inputStream = outputJobFile.getInputStream(); + Reader reader = new BufferedReader(new InputStreamReader(inputStream))) { + expectedJob = this.gson.fromJson(reader, V1Job.class); + } + expectedJob.getMetadata().setAnnotations(null); + outputJob.getMetadata().setAnnotations(null); + expectedJob.getSpec().getTemplate().getSpec().getContainers().get(0).getEnv().stream().filter(env -> env.getName().equals(Constants.TASKMASTER_INPUT)).forEach(env -> env.setValue("")); + outputJob.getSpec().getTemplate().getSpec().getContainers().get(0).getEnv().stream().filter(env -> env.getName().equals(Constants.TASKMASTER_INPUT)).forEach(env -> env.setValue("")); + //comparing fields of resulting Job object and pattern Job objects other those with JSON values, which were cleared in previous lines (JSON strings do not have to be exactly equal to pattern). + assertEquals(expectedJob, outputJob); + } + + @Test + public void fromTesTaskToK8sConfigMap() throws IOException { + + given(this.jobNameGenerator.getTaskMasterName()).willReturn("task-98605447"); + Resource inputTaskFile = new ClassPathResource("fromTesToK8s_minimal/task.json"); + TesTask inputTask; + try (InputStream inputStream = inputTaskFile.getInputStream(); + Reader reader = new BufferedReader(new InputStreamReader(inputStream))) { + inputTask = this.objectMapper.readValue(reader, TesTask.class); + } + V1Job outputJob = this.converter.fromTesTaskToK8sJob(inputTask, User.builder("test-user-id").teskMemberedGroups(StringUtils.commaDelimitedListToSet("ABC,CDE")).build()); + + V1ConfigMap outputConfigMap = this.converter.fromTesTaskToK8sConfigMap(inputTask, User.builder("test-user-id").teskMemberedGroups(StringUtils.commaDelimitedListToSet("ABC,CDE")).build(), outputJob); + Map binaryDataMap = outputConfigMap.getBinaryData(); + GZIPInputStream gis = new GZIPInputStream(new ByteArrayInputStream(binaryDataMap.get("JSON_INPUT.gz"))); + BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(gis, "UTF-8")); + String line; + String jsonString=""; + while ((line = bufferedReader.readLine()) != null) { + jsonString = jsonString + line; + } - JsonContentAssert taskMasterInputJson = new JsonContentAssert(this.getClass(), outputJob.getSpec().getTemplate().getSpec(). - getContainers().get(0).getEnv().stream().filter(env -> env.getName().equals("JSON_INPUT")).findAny().get().getValue()); + JsonContentAssert taskMasterInputJson = new JsonContentAssert(this.getClass(), jsonString); taskMasterInputJson.hasJsonPathValue("outputs"); taskMasterInputJson.extractingJsonPathNumberValue("outputs.size()").isEqualTo(0); taskMasterInputJson.extractingJsonPathNumberValue("inputs.size()").isEqualTo(0); @@ -149,18 +186,6 @@ public void fromTesTaskToK8sJob_minimal() throws IOException { taskMasterInputJson.isEqualToJson(new ClassPathResource("fromTesToK8s_minimal/taskmaster_param.json"), JSONCompareMode.NON_EXTENSIBLE); - Resource outputJobFile = new ClassPathResource("fromTesToK8s_minimal/job.json"); - V1Job expectedJob; - try (InputStream inputStream = outputJobFile.getInputStream(); - Reader reader = new BufferedReader(new InputStreamReader(inputStream))) { - expectedJob = this.gson.fromJson(reader, V1Job.class); - } - expectedJob.getMetadata().setAnnotations(null); - outputJob.getMetadata().setAnnotations(null); - expectedJob.getSpec().getTemplate().getSpec().getContainers().get(0).getEnv().stream().filter(env -> env.getName().equals(Constants.TASKMASTER_INPUT)).forEach(env -> env.setValue("")); - outputJob.getSpec().getTemplate().getSpec().getContainers().get(0).getEnv().stream().filter(env -> env.getName().equals(Constants.TASKMASTER_INPUT)).forEach(env -> env.setValue("")); - //comparing fields of resulting Job object and pattern Job objects other those with JSON values, which were cleared in previous lines (JSON strings do not have to be exactly equal to pattern). - assertEquals(expectedJob, outputJob); } private TaskBuilder prepareBaseTaskBuider(boolean withExecutors, boolean withPods) throws IOException { diff --git a/src/test/java/uk/ac/ebi/tsc/tesk/k8s/convert/TesKubernetesConverterTest.java b/src/test/java/uk/ac/ebi/tsc/tesk/k8s/convert/TesKubernetesConverterTest.java index 316be7f..2d7fa95 100644 --- a/src/test/java/uk/ac/ebi/tsc/tesk/k8s/convert/TesKubernetesConverterTest.java +++ b/src/test/java/uk/ac/ebi/tsc/tesk/k8s/convert/TesKubernetesConverterTest.java @@ -50,6 +50,8 @@ import static uk.ac.ebi.tsc.tesk.k8s.constant.Constants.LABEL_TASKSTATE_KEY; import static uk.ac.ebi.tsc.tesk.k8s.constant.Constants.LABEL_TASKSTATE_VALUE_CANC; +import java.io.ByteArrayInputStream; +import java.util.zip.GZIPInputStream; /** * @author Ania Niewielska @@ -172,15 +174,50 @@ public void fromTesTaskToK8sJob() throws IOException { assertEquals(outputJob.getSpec().getTemplate().getSpec().getContainers().get(0).getName(), "task-35605447"); assertEquals(outputJob.getSpec().getTemplate().getSpec().getServiceAccountName(), "custom-service-account"); - assertEquals(outputJob.getSpec().getTemplate().getSpec().getContainers().get(0).getArgs().get(0), "$(JSON_INPUT)"); - assertEquals(outputJob.getSpec().getTemplate().getSpec().getContainers().get(0).getArgs().get(2), "test-namespace"); - assertEquals(outputJob.getSpec().getTemplate().getSpec().getContainers().get(0).getArgs().get(4), "task-full-filer-image-name"); - assertEquals(outputJob.getSpec().getTemplate().getSpec().getContainers().get(0).getArgs().get(6), "task-full-filer-image-version"); + assertEquals(outputJob.getSpec().getTemplate().getSpec().getContainers().get(0).getArgs().get(0), "-f"); + assertEquals(outputJob.getSpec().getTemplate().getSpec().getContainers().get(0).getArgs().get(1), "/jsoninput/JSON_INPUT.gz"); + assertEquals(outputJob.getSpec().getTemplate().getSpec().getContainers().get(0).getArgs().get(3), "test-namespace"); + assertEquals(outputJob.getSpec().getTemplate().getSpec().getContainers().get(0).getArgs().get(5), "task-full-filer-image-name"); + assertEquals(outputJob.getSpec().getTemplate().getSpec().getContainers().get(0).getArgs().get(7), "task-full-filer-image-version"); assertEquals(outputJob.getSpec().getTemplate().getSpec().getContainers().get(0).getImage(), "task-full-image-name:task-full-image-version"); assertEquals(outputJob.getSpec().getTemplate().getSpec().getRestartPolicy(), "Never"); - JsonContentAssert taskMasterInputJson = new JsonContentAssert(this.getClass(), outputJob.getSpec().getTemplate().getSpec(). - getContainers().get(0).getEnv().stream().filter(env -> env.getName().equals("JSON_INPUT")).findAny().get().getValue()); + Resource outputJobFile = new ClassPathResource("fromTesToK8s/job.json"); + V1Job expectedJob; + try (InputStream inputStream = outputJobFile.getInputStream(); + Reader reader = new BufferedReader(new InputStreamReader(inputStream))) { + expectedJob = this.gson.fromJson(reader, V1Job.class); + } + expectedJob.getMetadata().setAnnotations(null); + outputJob.getMetadata().setAnnotations(null); + expectedJob.getSpec().getTemplate().getSpec().getContainers().get(0).getEnv().stream().filter(env -> env.getName().equals(Constants.TASKMASTER_INPUT)).forEach(env -> env.setValue("")); + outputJob.getSpec().getTemplate().getSpec().getContainers().get(0).getEnv().stream().filter(env -> env.getName().equals(Constants.TASKMASTER_INPUT)).forEach(env -> env.setValue("")); + //comparing fields of resulting Job object and pattern Job objects other those with JSON values, which were cleared in previous lines (JSON strings do not have to be exactly equal to pattern). + assertEquals(expectedJob, outputJob); + } + + @Test + public void fromTesTaskToK8sConfigMap() throws IOException { + + given(this.jobNameGenerator.getTaskMasterName()).willReturn("task-35605447"); + Resource inputTaskFile = new ClassPathResource("fromTesToK8s/task.json"); + TesTask inputTask; + try (InputStream inputStream = inputTaskFile.getInputStream(); + Reader reader = new BufferedReader(new InputStreamReader(inputStream))) { + inputTask = this.objectMapper.readValue(reader, TesTask.class); + } + V1Job outputJob = this.converter.fromTesTaskToK8sJob(inputTask, User.builder("test-user-id").teskMemberedGroups(StringUtils.commaDelimitedListToSet("ABC,CDE")).build()); + + V1ConfigMap outputConfigMap = this.converter.fromTesTaskToK8sConfigMap(inputTask, User.builder("test-user-id").teskMemberedGroups(StringUtils.commaDelimitedListToSet("ABC,CDE")).build(), outputJob); + Map binaryDataMap = outputConfigMap.getBinaryData(); + GZIPInputStream gis = new GZIPInputStream(new ByteArrayInputStream(binaryDataMap.get("JSON_INPUT.gz"))); + BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(gis, "UTF-8")); + String line; + String jsonString=""; + while ((line = bufferedReader.readLine()) != null) { + jsonString = jsonString + line; + } + JsonContentAssert taskMasterInputJson = new JsonContentAssert(this.getClass(), jsonString); taskMasterInputJson.hasJsonPathValue("outputs[?(@.type == 'FILE')]"); //JSONPath filter expressions sadly return array ;/ taskMasterInputJson.extractingJsonPathArrayValue("outputs[?(@.type == 'FILE')].url").containsExactly("/path/to/output_file.txt"); @@ -221,18 +258,6 @@ public void fromTesTaskToK8sJob() throws IOException { taskMasterInputJson.isEqualToJson(new ClassPathResource("fromTesToK8s/taskmaster_param.json"), JSONCompareMode.NON_EXTENSIBLE); - Resource outputJobFile = new ClassPathResource("fromTesToK8s/job.json"); - V1Job expectedJob; - try (InputStream inputStream = outputJobFile.getInputStream(); - Reader reader = new BufferedReader(new InputStreamReader(inputStream))) { - expectedJob = this.gson.fromJson(reader, V1Job.class); - } - expectedJob.getMetadata().setAnnotations(null); - outputJob.getMetadata().setAnnotations(null); - expectedJob.getSpec().getTemplate().getSpec().getContainers().get(0).getEnv().stream().filter(env -> env.getName().equals(Constants.TASKMASTER_INPUT)).forEach(env -> env.setValue("")); - outputJob.getSpec().getTemplate().getSpec().getContainers().get(0).getEnv().stream().filter(env -> env.getName().equals(Constants.TASKMASTER_INPUT)).forEach(env -> env.setValue("")); - //comparing fields of resulting Job object and pattern Job objects other those with JSON values, which were cleared in previous lines (JSON strings do not have to be exactly equal to pattern). - assertEquals(expectedJob, outputJob); } private TaskBuilder prepareBaseTaskBuider(boolean withExecutor) throws IOException { diff --git a/src/test/resources/fromTesToK8s/job.json b/src/test/resources/fromTesToK8s/job.json index cf6a1bc..8b45c13 100644 --- a/src/test/resources/fromTesToK8s/job.json +++ b/src/test/resources/fromTesToK8s/job.json @@ -23,7 +23,8 @@ "containers": [ { "args": [ - "$(JSON_INPUT)", + "-f", + "/jsoninput/JSON_INPUT.gz", "-n", "test-namespace", "-fn", @@ -33,10 +34,6 @@ "-d" ], "env": [ - { - "name": "JSON_INPUT", - "value": "{\"outputs\":[{\"url\":\"/path/to/output_file.txt\",\"path\":\"/tes/output.txt\",\"type\":\"FILE\"},{\"url\":\"/path/to/output\",\"path\":\"/outputs/output\",\"type\":\"DIRECTORY\"}],\"inputs\":[{\"name\":\"infile1\",\"description\":\"aa bbb\",\"url\":\"/path1/to/input_file.json\",\"path\":\"/tes/volumes/input.json\",\"type\":\"FILE\"},{\"url\":\"/path2/to/input\",\"path\":\"/tes/volumes/input\",\"type\":\"DIRECTORY\"},{\"path\":\"/container/input/other.txt\",\"type\":\"FILE\",\"content\":\"aaabbbcccddd\"}],\"volumes\":[\"/tmp/tmp1\",\"/tmp/tmp2\"],\"executors\":[{\"apiVersion\":\"batch/v1\",\"kind\":\"Job\",\"metadata\":{\"annotations\":{\"tes-task-name\":\"taskFull\"},\"labels\":{\"job-type\":\"executor\",\"taskmaster-name\":\"task-35605447\",\"executor-no\":\"0\"},\"name\":\"task-35605447-ex-00\"},\"spec\":{\"template\":{\"metadata\":{\"name\":\"task-35605447-ex-00\"},\"spec\":{\"containers\":[{\"args\":[\"echo\",\"hello world\"],\"command\":[],\"image\":\"alpine\",\"name\":\"task-35605447-ex-00\",\"resources\":{\"requests\":{\"cpu\":\"4\"}}}],\"restartPolicy\":\"Never\"}}}},{\"apiVersion\":\"batch/v1\",\"kind\":\"Job\",\"metadata\":{\"annotations\":{\"tes-task-name\":\"taskFull\"},\"labels\":{\"job-type\":\"executor\",\"taskmaster-name\":\"task-35605447\",\"executor-no\":\"1\"},\"name\":\"task-35605447-ex-01\"},\"spec\":{\"template\":{\"metadata\":{\"name\":\"task-35605447-ex-01\"},\"spec\":{\"containers\":[{\"args\":[\"sh\",\"-c\",\"md5sum $src\"],\"command\":[],\"env\":[{\"name\":\"src\",\"value\":\"/container/input/other.txt\"},{\"name\":\"sth\",\"value\":\"sthElse\"}],\"image\":\"alpine\",\"name\":\"task-35605447-ex-01\",\"resources\":{\"requests\":{\"cpu\":\"4\"}},\"workingDir\":\"/starthere\"}],\"restartPolicy\":\"Never\"}}}}],\"resources\":{}}" - }, { "name": "TESK_FTP_USERNAME", "valueFrom": { @@ -71,7 +68,12 @@ "name": "podinfo", "mountPath": "/podinfo", "readOnly": true - } + }, + { + "name": "jsoninput", + "mountPath": "/jsoninput", + "readOnly": true + } ], "image": "task-full-image-name:task-full-image-version", "name": "task-35605447", @@ -91,6 +93,12 @@ } ] } + }, + { + "name": "jsoninput", + "configMap": { + "name": "task-35605447" + } } ], "restartPolicy": "Never" diff --git a/src/test/resources/fromTesToK8s_minimal/job.json b/src/test/resources/fromTesToK8s_minimal/job.json index 30535e7..9b352de 100644 --- a/src/test/resources/fromTesToK8s_minimal/job.json +++ b/src/test/resources/fromTesToK8s_minimal/job.json @@ -22,21 +22,21 @@ "containers": [ { "args": [ - "$(JSON_INPUT)", "-n", "default", "-fn", "eu.gcr.io/tes-wes/filer", "-fv", "v0.10.0" - ], - "env": [ - { - "name": "JSON_INPUT", - "value": "{\"outputs\":[{\"url\":\"/path/to/output_file.txt\",\"path\":\"/tes/output.txt\",\"type\":\"FILE\"},{\"url\":\"/path/to/output\",\"path\":\"/outputs/output\",\"type\":\"DIRECTORY\"}],\"inputs\":[{\"name\":\"infile1\",\"description\":\"aa bbb\",\"url\":\"/path1/to/input_file.json\",\"path\":\"/tes/volumes/input.json\",\"type\":\"FILE\"},{\"url\":\"/path2/to/input\",\"path\":\"/tes/volumes/input\",\"type\":\"DIRECTORY\"},{\"path\":\"/container/input/other.txt\",\"type\":\"FILE\",\"content\":\"aaabbbcccddd\"}],\"volumes\":[\"/tmp/tmp1\",\"/tmp/tmp2\"],\"executors\":[{\"apiVersion\":\"batch/v1\",\"kind\":\"Job\",\"metadata\":{\"annotations\":{\"tes-task-name\":\"taskFull\"},\"labels\":{\"job-type\":\"executor\",\"taskmaster-name\":\"task-35605447\",\"executor-no\":\"0\"},\"name\":\"task-35605447-ex-00\"},\"spec\":{\"template\":{\"metadata\":{\"name\":\"task-35605447-ex-00\"},\"spec\":{\"containers\":[{\"args\":[\"echo\",\"hello world\"],\"command\":[],\"image\":\"alpine\",\"name\":\"task-35605447-ex-00\",\"resources\":{\"requests\":{\"cpu\":\"4\"}}}],\"restartPolicy\":\"Never\"}}}},{\"apiVersion\":\"batch/v1\",\"kind\":\"Job\",\"metadata\":{\"annotations\":{\"tes-task-name\":\"taskFull\"},\"labels\":{\"job-type\":\"executor\",\"taskmaster-name\":\"task-35605447\",\"executor-no\":\"1\"},\"name\":\"task-35605447-ex-01\"},\"spec\":{\"template\":{\"metadata\":{\"name\":\"task-35605447-ex-01\"},\"spec\":{\"containers\":[{\"args\":[\"sh\",\"-c\",\"md5sum $src\"],\"command\":[],\"env\":[{\"name\":\"src\",\"value\":\"/container/input/other.txt\"},{\"name\":\"sth\",\"value\":\"sthElse\"}],\"image\":\"alpine\",\"name\":\"task-35605447-ex-01\",\"resources\":{\"requests\":{\"cpu\":\"4\"}},\"workingDir\":\"/starthere\"}],\"restartPolicy\":\"Never\"}}}}],\"resources\":{}}" - } + "-f", "/jsoninput/JSON_INPUT.gz", "-n", "default", "-fn", "eu.gcr.io/tes-wes/filer", "-fv", "v0.10.0" ], "image": "eu.gcr.io/tes-wes/taskmaster:v0.10.0", "name": "task-98605447", + "env": [], "volumeMounts": [ { "name": "podinfo", "mountPath": "/podinfo", "readOnly": true + }, + { + "name": "jsoninput", + "mountPath": "/jsoninput", + "readOnly": true } ] } @@ -54,6 +54,12 @@ } ] } + }, + { + "name": "jsoninput", + "configMap": { + "name": "task-98605447" + } } ], "restartPolicy": "Never"