From: aravind.est Date: Thu, 28 Aug 2025 12:57:32 +0000 (+0100) Subject: rApp instance status sync on all rApp GET request X-Git-Url: https://gerrit.o-ran-sc.org/r/gitweb?a=commitdiff_plain;h=e729e2b2e0a8031a697a70eb4018ae7096479927;p=nonrtric%2Fplt%2Frappmanager.git rApp instance status sync on all rApp GET request rApp instance status is synchronized on all the rApp/rApp instance get requests Issue-ID: NONRTRIC-1087 Change-Id: Ib538666f428f876b14bf0f5092e8872c7308bdab Signed-off-by: aravind.est --- diff --git a/rapp-manager-acm/src/main/java/org/oransc/rappmanager/acm/service/AcmDeployer.java b/rapp-manager-acm/src/main/java/org/oransc/rappmanager/acm/service/AcmDeployer.java index 9016aae..2eb230d 100644 --- a/rapp-manager-acm/src/main/java/org/oransc/rappmanager/acm/service/AcmDeployer.java +++ b/rapp-manager-acm/src/main/java/org/oransc/rappmanager/acm/service/AcmDeployer.java @@ -1,7 +1,7 @@ /*- * ============LICENSE_START====================================================================== * Copyright (C) 2023 Nordix Foundation. All rights reserved. - * Copyright (C) 2023-2024 OpenInfra Foundation Europe. All rights reserved. + * Copyright (C) 2023-2025 OpenInfra Foundation Europe. All rights reserved. * =============================================================================================== * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -170,6 +170,7 @@ public class AcmDeployer implements RappDeployer { automationComposition.getCompositionId(), automationComposition.getInstanceId(), UUID.randomUUID()); rappInstanceStateMachine.sendRappInstanceEvent(rappInstance, RappEvent.ACMUNDEPLOYED); + rappInstance.getAcm().setAcmInstanceId(null); return true; } } @@ -243,7 +244,7 @@ public class AcmDeployer implements RappDeployer { } public void syncRappInstanceStatus(UUID compositionId, RappInstance rappInstance) { - if (rappInstance.getAcm().getAcmInstanceId() != null) { + if (rappInstance.getAcm() != null && rappInstance.getAcm().getAcmInstanceId() != null) { try { AutomationComposition compositionInstance = automationCompositionInstanceApiClient.getCompositionInstance(compositionId, diff --git a/rapp-manager-acm/src/test/java/org/oransc/rappmanager/acm/service/AcmDeployerTest.java b/rapp-manager-acm/src/test/java/org/oransc/rappmanager/acm/service/AcmDeployerTest.java index 99f9302..f6a405d 100644 --- a/rapp-manager-acm/src/test/java/org/oransc/rappmanager/acm/service/AcmDeployerTest.java +++ b/rapp-manager-acm/src/test/java/org/oransc/rappmanager/acm/service/AcmDeployerTest.java @@ -267,6 +267,7 @@ class AcmDeployerTest { boolean rappUndeployStateActual = acmDeployer.undeployRappInstance(rapp, rappInstance); mockServer.verify(); assertTrue(rappUndeployStateActual); + assertNull(rappInstance.getAcm().getAcmInstanceId()); } @Test @@ -354,6 +355,26 @@ class AcmDeployerTest { verify(rappInstanceStateMachine, never()).sendRappInstanceEvent(any(), any()); } + @Test + void testSyncRappStatusFailureAcmNull() { + UUID compositionId = UUID.randomUUID(); + RappInstance rappInstance = rappResourceBuilder.getRappInstance(); + rappInstance.setAcm(null); + rappInstanceStateMachine.onboardRappInstance(rappInstance.getRappInstanceId()); + acmDeployer.syncRappInstanceStatus(compositionId, rappInstance); + verify(rappInstanceStateMachine, never()).sendRappInstanceEvent(any(), any()); + } + + @Test + void testSyncRappStatusFailureAcmInstanceIdNull() { + UUID compositionId = UUID.randomUUID(); + RappInstance rappInstance = rappResourceBuilder.getRappInstance(); + rappInstance.getAcm().setAcmInstanceId(null); + rappInstanceStateMachine.onboardRappInstance(rappInstance.getRappInstanceId()); + acmDeployer.syncRappInstanceStatus(compositionId, rappInstance); + verify(rappInstanceStateMachine, never()).sendRappInstanceEvent(any(), any()); + } + @Test void testPrimeRapp() throws JsonProcessingException { UUID compositionId = UUID.randomUUID(); diff --git a/rapp-manager-application/src/main/java/org/oransc/rappmanager/rest/RappController.java b/rapp-manager-application/src/main/java/org/oransc/rappmanager/rest/RappController.java index 3af2bd9..44d3083 100644 --- a/rapp-manager-application/src/main/java/org/oransc/rappmanager/rest/RappController.java +++ b/rapp-manager-application/src/main/java/org/oransc/rappmanager/rest/RappController.java @@ -37,8 +37,6 @@ import org.oransc.rappmanager.models.rapp.Rapp; import org.oransc.rappmanager.models.rapp.RappPrimeOrder; import org.oransc.rappmanager.models.rapp.RappState; import org.oransc.rappmanager.service.RappService; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.DeleteMapping; @@ -57,7 +55,6 @@ import org.springframework.web.multipart.MultipartFile; @RequiredArgsConstructor public class RappController { - Logger logger = LoggerFactory.getLogger(RappController.class); private final RappCsarConfigurationHandler rappCsarConfigurationHandler; private final RappValidationHandler rappValidationHandler; private final RappManagerConfiguration rappManagerConfiguration; @@ -67,12 +64,12 @@ public class RappController { @GetMapping public ResponseEntity> getRapps() { - return ResponseEntity.ok(rappCacheService.getAllRapp()); + return ResponseEntity.ok(rappService.syncRappStates(rappCacheService.getAllRapp())); } @GetMapping("{rapp_id}") public ResponseEntity getRapp(@PathVariable("rapp_id") String rappId) { - return rappCacheService.getRapp(rappId).map(ResponseEntity::ok).orElseThrow( + return rappCacheService.getRapp(rappId).map(rappService::syncRappState).map(ResponseEntity::ok).orElseThrow( () -> new RappHandlerException(HttpStatus.NOT_FOUND, String.format(RAPP_NOT_FOUND, rappId))); } diff --git a/rapp-manager-application/src/main/java/org/oransc/rappmanager/rest/RappInstanceController.java b/rapp-manager-application/src/main/java/org/oransc/rappmanager/rest/RappInstanceController.java index c2fc36f..54002ed 100644 --- a/rapp-manager-application/src/main/java/org/oransc/rappmanager/rest/RappInstanceController.java +++ b/rapp-manager-application/src/main/java/org/oransc/rappmanager/rest/RappInstanceController.java @@ -58,8 +58,9 @@ public class RappInstanceController { @GetMapping public ResponseEntity> getAllRappInstances(@PathVariable("rapp_id") String rappId) { - return rappCacheService.getRapp(rappId).map(Rapp::getRappInstances).map(ResponseEntity::ok).orElseThrow( - () -> new RappHandlerException(HttpStatus.NOT_FOUND, "No instance found for rApp '" + rappId + "'.")); + return rappCacheService.getRapp(rappId).map(rappService::syncRappState).map(Rapp::getRappInstances) + .map(ResponseEntity::ok).orElseThrow(() -> new RappHandlerException(HttpStatus.NOT_FOUND, + "No instance found for rApp '" + rappId + "'.")); } @PostMapping diff --git a/rapp-manager-application/src/main/java/org/oransc/rappmanager/service/RappService.java b/rapp-manager-application/src/main/java/org/oransc/rappmanager/service/RappService.java index 241c95d..8ce68b5 100644 --- a/rapp-manager-application/src/main/java/org/oransc/rappmanager/service/RappService.java +++ b/rapp-manager-application/src/main/java/org/oransc/rappmanager/service/RappService.java @@ -1,7 +1,7 @@ /*- * ============LICENSE_START====================================================================== * Copyright (C) 2023 Nordix Foundation. All rights reserved. - * Copyright (C) 2023-2024 OpenInfra Foundation Europe. All rights reserved. + * Copyright (C) 2023-2025 OpenInfra Foundation Europe. All rights reserved. * =============================================================================================== * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,6 +19,7 @@ package org.oransc.rappmanager.service; +import java.util.Collection; import java.util.List; import java.util.UUID; import lombok.RequiredArgsConstructor; @@ -145,6 +146,7 @@ public class RappService { if (rApp.getRappInstances().get(rappInstanceId).getState().equals(RappInstanceState.UNDEPLOYED)) { rappInstanceStateMachine.deleteRappInstance(rApp.getRappInstances().get(rappInstanceId)); rApp.getRappInstances().remove(rappInstanceId); + rappCacheService.putRapp(rApp); return ResponseEntity.noContent().build(); } throw new RappHandlerException(HttpStatus.BAD_REQUEST, @@ -154,4 +156,17 @@ public class RappService { public void updateRappInstanceState(Rapp rapp, RappInstance rappInstance) { acmDeployer.syncRappInstanceStatus(rapp.getCompositionId(), rappInstance); } + + public Collection syncRappStates(Collection rapps) { + rapps.forEach(this::syncRappState); + return rapps; + } + + public Rapp syncRappState(Rapp rapp) { + rapp.getRappInstances().forEach((instanceId, instance) -> { + updateRappInstanceState(rapp, instance); + instance.setState(rappInstanceStateMachine.getRappInstanceState(instanceId)); + }); + return rapp; + } } diff --git a/rapp-manager-application/src/test/java/org/oransc/rappmanager/rest/RappControllerTest.java b/rapp-manager-application/src/test/java/org/oransc/rappmanager/rest/RappControllerTest.java index 0cd6de1..c5de92e 100644 --- a/rapp-manager-application/src/test/java/org/oransc/rappmanager/rest/RappControllerTest.java +++ b/rapp-manager-application/src/test/java/org/oransc/rappmanager/rest/RappControllerTest.java @@ -28,6 +28,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import java.io.File; import java.io.FileInputStream; import java.util.List; +import java.util.Map; import java.util.UUID; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; @@ -41,6 +42,9 @@ import org.oransc.rappmanager.models.rapp.PrimeOrder; import org.oransc.rappmanager.models.rapp.Rapp; import org.oransc.rappmanager.models.rapp.RappPrimeOrder; import org.oransc.rappmanager.models.rapp.RappState; +import org.oransc.rappmanager.models.rappinstance.RappInstance; +import org.oransc.rappmanager.models.rappinstance.RappInstanceState; +import org.oransc.rappmanager.models.statemachine.RappInstanceStateMachine; import org.oransc.rappmanager.sme.service.SmeLifecycleManager; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; @@ -61,6 +65,9 @@ class RappControllerTest { @Autowired private RappCacheService rappCacheService; + @Autowired + RappInstanceStateMachine rappInstanceStateMachine; + @MockitoBean AcmDeployer acmDeployer; @@ -80,32 +87,48 @@ class RappControllerTest { mockMvc.perform(MockMvcRequestBuilders.get("/rapps")).andExpect(status().isOk()) .andExpect(jsonPath("$", hasSize(0))); UUID rappId = UUID.randomUUID(); + UUID instanceId = UUID.randomUUID(); + RappInstance instance = new RappInstance(); + instance.setRappInstanceId(instanceId); + instance.setState(RappInstanceState.UNDEPLOYED); + Map instances = Map.of(instanceId, instance); Rapp rapp = Rapp.builder().rappId(rappId).name(String.valueOf(rappId)).packageName(validRappFile) - .packageLocation(validCsarFileLocation).state(RappState.COMMISSIONED).build(); + .packageLocation(validCsarFileLocation).state(RappState.COMMISSIONED).rappInstances(instances).build(); AsdMetadata asdMetadata = new AsdMetadata(); asdMetadata.setDescriptorId(UUID.randomUUID().toString()); asdMetadata.setDescriptorInvariantId(UUID.randomUUID().toString()); asdMetadata.setDeploymentItems(List.of()); rapp.setAsdMetadata(asdMetadata); rappCacheService.putRapp(rapp); + rappInstanceStateMachine.onboardRappInstance(instanceId); mockMvc.perform(MockMvcRequestBuilders.get("/rapps")).andExpect(status().isOk()) - .andExpect(jsonPath("$", hasSize(1))); + .andExpect(jsonPath("$", hasSize(1))) + .andExpect(jsonPath("$[0].rappInstances." + instanceId + ".rappInstanceId").value(instanceId.toString())) + .andExpect(jsonPath("$[0].rappInstances." + instanceId + ".state").value(instance.getState().name())); } @Test void testGetRapp() throws Exception { UUID rappId = UUID.randomUUID(); + UUID instanceId = UUID.randomUUID(); + RappInstance instance = new RappInstance(); + instance.setRappInstanceId(instanceId); + instance.setState(RappInstanceState.UNDEPLOYED); + Map instances = Map.of(instanceId, instance); Rapp rapp = Rapp.builder().rappId(rappId).name(String.valueOf(rappId)).packageName(validRappFile) - .packageLocation(validCsarFileLocation).state(RappState.COMMISSIONED).build(); + .packageLocation(validCsarFileLocation).state(RappState.COMMISSIONED).rappInstances(instances).build(); AsdMetadata asdMetadata = new AsdMetadata(); asdMetadata.setDescriptorId(UUID.randomUUID().toString()); asdMetadata.setDescriptorInvariantId(UUID.randomUUID().toString()); asdMetadata.setDeploymentItems(List.of()); rapp.setAsdMetadata(asdMetadata); rappCacheService.putRapp(rapp); + rappInstanceStateMachine.onboardRappInstance(instanceId); mockMvc.perform(MockMvcRequestBuilders.get("/rapps/{rapp_id}", rappId)).andExpect(status().isOk()) .andExpect(jsonPath("$.rappId").value(rappId.toString())) - .andExpect(jsonPath("$.state").value(RappState.COMMISSIONED.name())); + .andExpect(jsonPath("$.state").value(RappState.COMMISSIONED.name())) + .andExpect(jsonPath("$.rappInstances." + instanceId + ".rappInstanceId").value(instanceId.toString())) + .andExpect(jsonPath("$.rappInstances." + instanceId + ".state").value(instance.getState().name())); } @Test diff --git a/rapp-manager-application/src/test/java/org/oransc/rappmanager/rest/RappInstanceControllerTest.java b/rapp-manager-application/src/test/java/org/oransc/rappmanager/rest/RappInstanceControllerTest.java index 0ef098f..474fd09 100644 --- a/rapp-manager-application/src/test/java/org/oransc/rappmanager/rest/RappInstanceControllerTest.java +++ b/rapp-manager-application/src/test/java/org/oransc/rappmanager/rest/RappInstanceControllerTest.java @@ -91,6 +91,7 @@ class RappInstanceControllerTest { UUID rappInstanceId = UUID.randomUUID(); Rapp rapp = getRapp(rappId, rappInstanceId); rappCacheService.putRapp(rapp); + rappInstanceStateMachine.onboardRappInstance(rappInstanceId); mockMvc.perform(MockMvcRequestBuilders.get("/rapps/{rapp_id}/instance", rappId)).andExpect(status().isOk()) .andExpect( jsonPath("$." + rappInstanceId.toString() + ".rappInstanceId").value(rappInstanceId.toString())) diff --git a/sample-rapp-generator/rapp-sample-ics-consumer/Files/Acm/instances/k8s-instance.json b/sample-rapp-generator/rapp-sample-ics-consumer/Files/Acm/instances/k8s-instance.json index 6748b29..87116cd 100644 --- a/sample-rapp-generator/rapp-sample-ics-consumer/Files/Acm/instances/k8s-instance.json +++ b/sample-rapp-generator/rapp-sample-ics-consumer/Files/Acm/instances/k8s-instance.json @@ -19,7 +19,7 @@ }, "namespace": "nonrtric", "releaseName": "ics-consumer", - "podName": "ics-consumer", + "podName": "kafka-consumer", "repository": { "repoName": "local", "address": "UPDATE_THIS_CHART_MUSEUM_GET_CHARTS_URI" diff --git a/sample-rapp-generator/rapp-sample-ics-producer/Files/Acm/instances/k8s-instance.json b/sample-rapp-generator/rapp-sample-ics-producer/Files/Acm/instances/k8s-instance.json index c04f816..ef9338e 100644 --- a/sample-rapp-generator/rapp-sample-ics-producer/Files/Acm/instances/k8s-instance.json +++ b/sample-rapp-generator/rapp-sample-ics-producer/Files/Acm/instances/k8s-instance.json @@ -19,7 +19,7 @@ }, "namespace": "nonrtric", "releaseName": "ics-producer", - "podName": "ics-producer", + "podName": "kafka-producer", "repository": { "repoName": "local", "address": "UPDATE_THIS_CHART_MUSEUM_GET_CHARTS_URI"