diff --git a/src/main/java/eu/dissco/orchestration/backend/service/MachineAnnotationServiceService.java b/src/main/java/eu/dissco/orchestration/backend/service/MachineAnnotationServiceService.java index d420bab..7ed4744 100644 --- a/src/main/java/eu/dissco/orchestration/backend/service/MachineAnnotationServiceService.java +++ b/src/main/java/eu/dissco/orchestration/backend/service/MachineAnnotationServiceService.java @@ -104,7 +104,7 @@ public JsonApiWrapper createMachineAnnotationService( var mas = buildMachineAnnotationService(masRequest, 1, userId, handle, Instant.now()); repository.createMachineAnnotationService(mas); - createDeployment(mas, masRequest); + createDeployment(mas); publishCreateEvent(mas); return wrapSingleResponse(mas, path); } catch (PidException e) { @@ -166,12 +166,11 @@ private void setDefaultMas(MachineAnnotationServiceRequest mas, String handle) { } } - private void createDeployment(MachineAnnotationService mas, - MachineAnnotationServiceRequest masRequest) + private void createDeployment(MachineAnnotationService mas) throws ProcessingFailedException { var successfulDeployment = false; try { - successfulDeployment = deployMasToCluster(mas, true, masRequest); + successfulDeployment = deployMasToCluster(mas, true); deployKedaToCluster(mas); } catch (KubernetesFailedException e) { rollbackMasCreation(mas, successfulDeployment, false); @@ -198,17 +197,12 @@ private void deployKedaToCluster(MachineAnnotationService mas) } private boolean deployMasToCluster(MachineAnnotationService mas, - boolean create, MachineAnnotationServiceRequest masRequest) + boolean create) throws KubernetesFailedException { var shortPid = getName(mas.getId()); try { V1Deployment deployment; - if (masRequest == null) { // Null only when we're deploying a previous version - deployment = appsV1Api.readNamespacedDeployment(properties.getNamespace(), - getName((mas.getId()) + DEPLOYMENT)).execute(); - } else { - deployment = getV1Deployment(mas, shortPid, masRequest); - } + deployment = getV1Deployment(mas, shortPid); if (create) { appsV1Api.createNamespacedDeployment(properties.getNamespace(), deployment).execute(); } else { @@ -226,11 +220,10 @@ private boolean deployMasToCluster(MachineAnnotationService mas, return true; } - private V1Deployment getV1Deployment(MachineAnnotationService mas, String shortPid, - MachineAnnotationServiceRequest masRequest) + private V1Deployment getV1Deployment(MachineAnnotationService mas, String shortPid) throws IOException, TemplateException { var templateProperties = getDeploymentTemplateProperties(mas, shortPid); - var deploymentString = fillDeploymentTemplate(templateProperties, masRequest); + var deploymentString = fillDeploymentTemplate(templateProperties, mas); return mapper.readValue(deploymentString, V1Deployment.class); } @@ -271,13 +264,13 @@ private Map getDeploymentTemplateProperties(MachineAnnotationSer return map; } - private List addMasKeys(MachineAnnotationServiceRequest masRequest) { + private List addMasKeys(MachineAnnotationService mas) { var keyNode = new ArrayList(); - if (masRequest == null) { + if (mas == null) { return List.of(mapper.createObjectNode()); } - if (masRequest.getOdsHasEnvironment() != null) { - masRequest.getOdsHasEnvironment().forEach(env -> { + if (mas.getOdsHasEnvironment() != null) { + mas.getOdsHasEnvironment().forEach(env -> { if (env.getValue() instanceof String stringVal) { keyNode.add(mapper.createObjectNode() .put(NAME, env.getName()) @@ -295,8 +288,8 @@ private List addMasKeys(MachineAnnotationServiceRequest masRequest) { } }); } - if (masRequest.getOdsHasSecret() != null) { - masRequest.getOdsHasSecret().forEach(secret -> keyNode.add(mapper.createObjectNode() + if (mas.getOdsHasSecret() != null) { + mas.getOdsHasSecret().forEach(secret -> keyNode.add(mapper.createObjectNode() .put(NAME, secret.getSecretName()) .set("valueFrom", mapper.createObjectNode() .set("secretKeyRef", mapper.createObjectNode() @@ -307,14 +300,14 @@ private List addMasKeys(MachineAnnotationServiceRequest masRequest) { } private String fillDeploymentTemplate(Map templateProperties, - MachineAnnotationServiceRequest masRequest) + MachineAnnotationService mas) throws IOException, TemplateException { var writer = new StringWriter(); deploymentTemplate.process(templateProperties, writer); var templateAsNode = (ObjectNode) mapper.readTree(writer.toString()); var defaultKeyNode = (ArrayNode) templateAsNode.get("spec").get("template").get("spec") .get("containers").get(0).get("env"); - defaultKeyNode.addAll(addMasKeys(masRequest)); + defaultKeyNode.addAll(addMasKeys(mas)); return mapper.writeValueAsString(templateAsNode); } @@ -378,8 +371,8 @@ public JsonApiWrapper updateMachineAnnotationService(String id, return null; } else { repository.updateMachineAnnotationService(machineAnnotationService); - updateDeployment(machineAnnotationService, currentMas, masRequest); - publishUpdateEvent(machineAnnotationService, currentMas, masRequest); + updateDeployment(machineAnnotationService, currentMas); + publishUpdateEvent(machineAnnotationService, currentMas); return wrapSingleResponse(machineAnnotationService, path); } } else { @@ -412,14 +405,14 @@ private boolean isEqual(MachineAnnotationService mas, MachineAnnotationService c } private void updateDeployment(MachineAnnotationService mas, - MachineAnnotationService currentMas, MachineAnnotationServiceRequest masRequest) + MachineAnnotationService currentMas) throws ProcessingFailedException { var successfulDeployment = false; try { - successfulDeployment = deployMasToCluster(mas, false, masRequest); + successfulDeployment = deployMasToCluster(mas, false); updateKedaResource(mas, currentMas); } catch (KubernetesFailedException e) { - rollbackToPreviousVersion(currentMas, successfulDeployment, false, masRequest); + rollbackToPreviousVersion(currentMas, successfulDeployment, false); throw new ProcessingFailedException("Failed to update kubernetes resources", e); } } @@ -463,28 +456,27 @@ private void updateKedaResource(MachineAnnotationService mas, } private void publishUpdateEvent(MachineAnnotationService mas, - MachineAnnotationService currentMas, MachineAnnotationServiceRequest masRequest) + MachineAnnotationService currentMas) throws ProcessingFailedException { try { kafkaPublisherService.publishUpdateEvent(mapper.valueToTree(mas), mapper.valueToTree(currentMas)); } catch (JsonProcessingException e) { log.error("Unable to publish message to Kafka", e); - rollbackToPreviousVersion(currentMas, true, true, masRequest); + rollbackToPreviousVersion(currentMas, true, true); throw new ProcessingFailedException("Failed to create new machine annotation service", e); } } private void rollbackToPreviousVersion(MachineAnnotationService currentMas, - boolean rollbackDeployment, boolean rollbackKeda, - MachineAnnotationServiceRequest masRequest) + boolean rollbackDeployment, boolean rollbackKeda) throws ProcessingFailedException { repository.updateMachineAnnotationService(currentMas); if (rollbackDeployment) { try { log.warn( "Rolling back to previous version of kubernetes deployment with environmental variables provided in update request. Environment may be out of sync with deployment"); - deployMasToCluster(currentMas, false, masRequest); + deployMasToCluster(currentMas, false); } catch (KubernetesFailedException e) { log.error( "Fatal exception, unable to rollback kubernetes deployment for: {} ", @@ -513,10 +505,12 @@ public void tombstoneMachineAnnotationService(String id, Agent agent) var tombstoneMas = buildTombstoneMachineAnnotationService(mas, agent, timestamp); repository.tombstoneMachineAnnotationService(tombstoneMas, timestamp); try { - kafkaPublisherService.publishTombstoneEvent(mapper.valueToTree(tombstoneMas), mapper.valueToTree(mas)); - } catch (JsonProcessingException e){ + kafkaPublisherService.publishTombstoneEvent(mapper.valueToTree(tombstoneMas), + mapper.valueToTree(mas)); + } catch (JsonProcessingException e) { log.error("Unable to publish tombstone event to provenance service", e); - throw new ProcessingFailedException("Unable to publish tombstone event to provenance service", e); + throw new ProcessingFailedException( + "Unable to publish tombstone event to provenance service", e); } } else { throw new NotFoundException("Requested machine annotation system: " + id + "does not exist"); @@ -527,7 +521,7 @@ private void tombstoneHandle(String handle) throws ProcessingFailedException { var request = fdoRecordService.buildTombstoneRequest(ObjectType.MAS, handle); try { handleComponent.tombstoneHandle(request, handle); - } catch (PidException e){ + } catch (PidException e) { log.error("Unable to tombstone handle {}", handle, e); throw new ProcessingFailedException("Unable to tombstone handle", e); } @@ -591,7 +585,7 @@ private void deleteDeployment(MachineAnnotationService currentMas) "Deletion of kubernetes keda failed for record: {}, with code: {} and message: {}", currentMas, e.getCode(), e.getResponseBody()); try { - deployMasToCluster(currentMas, true, null); + deployMasToCluster(currentMas, true); } catch (KubernetesFailedException ex) { log.error("Failed error, unable to create deployment after failed keda deletion"); } diff --git a/src/main/resources/templates/mas-template.ftl b/src/main/resources/templates/mas-template.ftl index aa81610..ab67326 100644 --- a/src/main/resources/templates/mas-template.ftl +++ b/src/main/resources/templates/mas-template.ftl @@ -21,6 +21,8 @@ } }, "spec": { + "serviceAccountName":"mas-secret-manager", + "automountServiceAccountToken": true, "containers": [ { "name": "${pid}", diff --git a/src/test/java/eu/dissco/orchestration/backend/service/MachineAnnotationServiceServiceTest.java b/src/test/java/eu/dissco/orchestration/backend/service/MachineAnnotationServiceServiceTest.java index 8441210..ccdccf9 100644 --- a/src/test/java/eu/dissco/orchestration/backend/service/MachineAnnotationServiceServiceTest.java +++ b/src/test/java/eu/dissco/orchestration/backend/service/MachineAnnotationServiceServiceTest.java @@ -55,7 +55,6 @@ import io.kubernetes.client.openapi.apis.AppsV1Api; import io.kubernetes.client.openapi.apis.AppsV1Api.APIcreateNamespacedDeploymentRequest; import io.kubernetes.client.openapi.apis.AppsV1Api.APIdeleteNamespacedDeploymentRequest; -import io.kubernetes.client.openapi.apis.AppsV1Api.APIreadNamespacedDeploymentRequest; import io.kubernetes.client.openapi.apis.AppsV1Api.APIreplaceNamespacedDeploymentRequest; import io.kubernetes.client.openapi.apis.CustomObjectsApi; import io.kubernetes.client.openapi.apis.CustomObjectsApi.APIcreateNamespacedCustomObjectRequest; @@ -660,11 +659,14 @@ void testTombstoneMasKafkaFailed() throws Exception { var deleteCustom = mock(APIdeleteNamespacedCustomObjectRequest.class); given(customObjectsApi.deleteNamespacedCustomObject("keda.sh", "v1alpha1", "namespace", "scaledobjects", "gw0-pop-xsl-scaled-object")).willReturn(deleteCustom); - doThrow(JsonProcessingException.class).when(kafkaPublisherService).publishTombstoneEvent(any(), any()); - given(fdoRecordService.buildTombstoneRequest(ObjectType.MAS, BARE_HANDLE)).willReturn(givenTombstoneRequestMas()); + doThrow(JsonProcessingException.class).when(kafkaPublisherService) + .publishTombstoneEvent(any(), any()); + given(fdoRecordService.buildTombstoneRequest(ObjectType.MAS, BARE_HANDLE)).willReturn( + givenTombstoneRequestMas()); // When - assertThrowsExactly(ProcessingFailedException.class, () -> service.tombstoneMachineAnnotationService(BARE_HANDLE, givenAgent())); + assertThrowsExactly(ProcessingFailedException.class, + () -> service.tombstoneMachineAnnotationService(BARE_HANDLE, givenAgent())); // Then then(repository).should().tombstoneMachineAnnotationService(any(), any()); @@ -701,15 +703,13 @@ void testDeleteKedaFails() throws ApiException { given(repository.getActiveMachineAnnotationService(BARE_HANDLE)).willReturn( Optional.of(givenMas())); given(properties.getNamespace()).willReturn("namespace"); + given(properties.getKafkaHost()).willReturn("kafka.svc.cluster.local:9092"); var createDeploy = mock(APIcreateNamespacedDeploymentRequest.class); given(appsV1Api.createNamespacedDeployment(eq("namespace"), any(V1Deployment.class))) .willReturn(createDeploy); var deleteDeploy = mock(APIdeleteNamespacedDeploymentRequest.class); given(appsV1Api.deleteNamespacedDeployment(SUFFIX.toLowerCase() + "-deployment", "namespace")).willReturn(deleteDeploy); - var deleteRead = mock(APIreadNamespacedDeploymentRequest.class); - given(appsV1Api.readNamespacedDeployment(any(), anyString())).willReturn(deleteRead); - given(deleteRead.execute()).willReturn(mock(V1Deployment.class)); var deleteCustom = mock(APIdeleteNamespacedCustomObjectRequest.class); given(customObjectsApi.deleteNamespacedCustomObject("keda.sh", "v1alpha1", "namespace", "scaledobjects", "gw0-pop-xsl-scaled-object")).willReturn(deleteCustom); @@ -735,8 +735,10 @@ private static Stream masKeys() { return Stream.of( Arguments.of(null, null), Arguments.of(givenMasEnvironment(), givenMasSecrets()), - Arguments.of(List.of(new MachineAnnotationServiceEnvironment("name", 1)), givenMasSecrets()), - Arguments.of(List.of(new MachineAnnotationServiceEnvironment("name", true)), givenMasSecrets()) + Arguments.of(List.of(new MachineAnnotationServiceEnvironment("name", 1)), + givenMasSecrets()), + Arguments.of(List.of(new MachineAnnotationServiceEnvironment("name", true)), + givenMasSecrets()) ); }