Add initial version of code
Initial version of rapp manager code added.
Issue-ID: NONRTRIC-872
Signed-off-by: aravind.est <aravindhan.a@est.tech>
Change-Id: I124b20a0790ba701d32089b66f81fc8b4e647e79
diff --git a/.gitignore b/.gitignore
new file mode 100755
index 0000000..549e00a
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,33 @@
+HELP.md
+target/
+!.mvn/wrapper/maven-wrapper.jar
+!**/src/main/**/target/
+!**/src/test/**/target/
+
+### STS ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
+
+### IntelliJ IDEA ###
+.idea
+*.iws
+*.iml
+*.ipr
+
+### NetBeans ###
+/nbproject/private/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
+build/
+!**/src/main/**/build/
+!**/src/test/**/build/
+
+### VS Code ###
+.vscode/
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..343a972
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,4 @@
+[submodule "sme"]
+ path = sme
+ url = https://gerrit.o-ran-sc.org/r/nonrtric/plt/sme
+ branch = master
diff --git a/README.md b/README.md
new file mode 100755
index 0000000..ce1339b
--- /dev/null
+++ b/README.md
@@ -0,0 +1,10 @@
+# Rapp Manager (This is a prototype)
+Rapp manager is an application which lifecycle manages the Rapp.
+
+<mark>**Rapp packaging model used here is purely a prototype**</mark>
+
+# Integration of ONAP ACM
+
+ONAP ACM is used here as a backend of Rapp manager to lifecycle manage the deployment items as part of Rapp.
+
+ONAP ACM related details can be found [here](https://docs.onap.org/projects/onap-policy-parent/en/london/clamp/clamp.html).
diff --git a/pom.xml b/pom.xml
new file mode 100755
index 0000000..d1f051e
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-parent</artifactId>
+ <version>3.0.6</version>
+ </parent>
+ <groupId>com.oransc</groupId>
+ <artifactId>rappmanager</artifactId>
+ <version>0.0.1-SNAPSHOT</version>
+ <packaging>pom</packaging>
+ <name>rappmanager</name>
+ <description>Rapp Manager(ACM) in ORANSC</description>
+ <modules>
+ <module>rapp-manager-models</module>
+ <module>rapp-manager-acm</module>
+ <module>rapp-manager-sme</module>
+ <module>rapp-manager-application</module>
+ </modules>
+ <properties>
+ <java.version>17</java.version>
+ <openapi.maven.version>6.6.0</openapi.maven.version>
+ </properties>
+</project>
diff --git a/rapp-manager-acm/pom.xml b/rapp-manager-acm/pom.xml
new file mode 100755
index 0000000..9740db8
--- /dev/null
+++ b/rapp-manager-acm/pom.xml
@@ -0,0 +1,123 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>com.oransc</groupId>
+ <artifactId>rappmanager</artifactId>
+ <version>0.0.1-SNAPSHOT</version>
+ </parent>
+
+ <groupId>com.oransc.rappmanager</groupId>
+ <artifactId>rapp-manager-acm</artifactId>
+
+ <properties>
+ <maven.compiler.source>${java.version}</maven.compiler.source>
+ <maven.compiler.target>${java.version}</maven.compiler.target>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>com.oransc.rappmanager</groupId>
+ <artifactId>rapp-manager-models</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.onap.policy.clamp</groupId>
+ <artifactId>policy-clamp-models</artifactId>
+ <version>6.4.2</version>
+ <exclusions>
+ <exclusion>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-data-jpa</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-aop</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-security</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-validation</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-webflux</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ <dependency>
+ <groupId>org.openapitools</groupId>
+ <artifactId>jackson-databind-nullable</artifactId>
+ <version>0.2.6</version>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-test</artifactId>
+ <scope>test</scope>
+ </dependency>
+
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.openapitools</groupId>
+ <artifactId>openapi-generator-maven-plugin</artifactId>
+ <version>${openapi.maven.version}</version>
+ <executions>
+ <execution>
+ <id>acm-spec-generator</id>
+ <goals>
+ <goal>generate</goal>
+ </goals>
+ <configuration>
+ <inputSpec>rapp-manager-acm/src/main/resources/openapi/acm-spec.yaml</inputSpec>
+ <generatorName>java</generatorName>
+ <library>resttemplate</library>
+ <generateApiTests>false</generateApiTests>
+ <generateModelTests>false</generateModelTests>
+ <generateApiDocumentation>false</generateApiDocumentation>
+ <generateModelDocumentation>false</generateModelDocumentation>
+ <generateModels>true</generateModels>
+ <schemaMappings>
+ ToscaServiceTemplates=org.onap.policy.models.tosca.authorative.concepts.ToscaServiceTemplates,
+ ToscaServiceTemplate=org.onap.policy.models.tosca.authorative.concepts.ToscaServiceTemplate,
+ ToscaNodeTemplate=org.onap.policy.models.tosca.authorative.concepts.ToscaNodeTemplate,
+ AutomationCompositions=org.onap.policy.clamp.models.acm.concepts.AutomationCompositions,
+ AutomationComposition=org.onap.policy.clamp.models.acm.concepts.AutomationComposition,
+ <!-- AutomationCompositionDefinition=org.onap.policy.clamp.models.acm.concepts.AutomationCompositionDefinition,-->
+ SimpleResponse=org.onap.policy.clamp.models.acm.messages.rest.SimpleResponse,
+ AcTypeStateUpdate=org.onap.policy.clamp.models.acm.messages.rest.commissioning.AcTypeStateUpdate,
+ AcInstanceStateUpdate=org.onap.policy.clamp.models.acm.messages.rest.instantiation.AcInstanceStateUpdate,
+ InstancePropertiesResponse=org.onap.policy.clamp.models.acm.messages.rest.instantiation.InstancePropertiesResponse,
+ CommissioningResponse=org.onap.policy.clamp.models.acm.messages.rest.commissioning.CommissioningResponse,
+ InstantiationCommand=org.onap.policy.clamp.models.acm.messages.rest.instantiation.InstantiationCommand,
+ InstantiationResponse=org.onap.policy.clamp.models.acm.messages.rest.instantiation.InstantiationResponse,
+ InstantiationUpdate=org.onap.policy.clamp.models.acm.messages.rest.instantiation.InstantiationUpdate,
+ ParticipantInformation=org.onap.policy.clamp.models.acm.concepts.ParticipantInformation
+ </schemaMappings>
+ <additionalProperties>
+ <additionalProperty>apiNameSuffix=ApiClient</additionalProperty>
+ </additionalProperties>
+ <configOptions>
+ <sourceFolder>src/main/java</sourceFolder>
+ <useJakartaEe>true</useJakartaEe>
+ <invokerPackage>com.oransc.rappmanager.acm</invokerPackage>
+ <apiPackage>com.oransc.rappmanager.acm.rest</apiPackage>
+ <modelPackage>com.oransc.rappmanager.acm.data</modelPackage>
+ <generateClientAsBean>false</generateClientAsBean>
+ </configOptions>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+
+</project>
\ No newline at end of file
diff --git a/rapp-manager-acm/src/main/java/com/oransc/rappmanager/acm/configuration/ACMConfiguration.java b/rapp-manager-acm/src/main/java/com/oransc/rappmanager/acm/configuration/ACMConfiguration.java
new file mode 100755
index 0000000..6582775
--- /dev/null
+++ b/rapp-manager-acm/src/main/java/com/oransc/rappmanager/acm/configuration/ACMConfiguration.java
@@ -0,0 +1,36 @@
+/*-
+ * ============LICENSE_START======================================================================
+ * Copyright (C) 2023 Nordix Foundation. 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END========================================================================
+ */
+
+package com.oransc.rappmanager.acm.configuration;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+@ConfigurationProperties(prefix = "rappmanager.acm")
+@Data
+public class ACMConfiguration {
+
+ String baseUrl;
+ String username;
+ String password;
+ String compositionDefinitionLocation;
+ int maxRetries;
+ int retryInterval;
+}
diff --git a/rapp-manager-acm/src/main/java/com/oransc/rappmanager/acm/service/AcmDeployer.java b/rapp-manager-acm/src/main/java/com/oransc/rappmanager/acm/service/AcmDeployer.java
new file mode 100755
index 0000000..def268b
--- /dev/null
+++ b/rapp-manager-acm/src/main/java/com/oransc/rappmanager/acm/service/AcmDeployer.java
@@ -0,0 +1,201 @@
+/*-
+ * ============LICENSE_START======================================================================
+ * Copyright (C) 2023 Nordix Foundation. 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END========================================================================
+ */
+
+package com.oransc.rappmanager.acm.service;
+
+import com.oransc.rappmanager.acm.configuration.ACMConfiguration;
+import com.oransc.rappmanager.acm.rest.AutomationCompositionDefinitionApiClient;
+import com.oransc.rappmanager.acm.rest.AutomationCompositionInstanceApiClient;
+import com.oransc.rappmanager.acm.rest.ParticipantMonitoringApiClient;
+import com.oransc.rappmanager.models.Rapp;
+import com.oransc.rappmanager.models.RappCsarConfigurationHandler;
+import com.oransc.rappmanager.models.RappDeployer;
+import com.oransc.rappmanager.models.RappEvent;
+import com.oransc.rappmanager.models.RappState;
+import com.oransc.rappmanager.models.cache.RappCacheService;
+import com.oransc.rappmanager.models.statemachine.RappStateMachine;
+import java.util.List;
+import java.util.UUID;
+import java.util.concurrent.TimeUnit;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+import org.onap.policy.clamp.models.acm.concepts.AcTypeState;
+import org.onap.policy.clamp.models.acm.concepts.AutomationComposition;
+import org.onap.policy.clamp.models.acm.concepts.DeployState;
+import org.onap.policy.clamp.models.acm.concepts.LockState;
+import org.onap.policy.clamp.models.acm.concepts.ParticipantInformation;
+import org.onap.policy.clamp.models.acm.messages.rest.commissioning.AcTypeStateUpdate;
+import org.onap.policy.clamp.models.acm.messages.rest.commissioning.CommissioningResponse;
+import org.onap.policy.clamp.models.acm.messages.rest.commissioning.PrimeOrder;
+import org.onap.policy.clamp.models.acm.messages.rest.instantiation.AcInstanceStateUpdate;
+import org.onap.policy.clamp.models.acm.messages.rest.instantiation.DeployOrder;
+import org.onap.policy.clamp.models.acm.messages.rest.instantiation.InstantiationResponse;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Service;
+import org.springframework.web.client.RestClientException;
+
+@Service
+@RequiredArgsConstructor
+public class AcmDeployer implements RappDeployer {
+
+ Logger logger = LoggerFactory.getLogger(AcmDeployer.class);
+
+ private final ParticipantMonitoringApiClient participantMonitoringApiClient;
+ private final AutomationCompositionDefinitionApiClient automationCompositionDefinitionApiClient;
+ private final AutomationCompositionInstanceApiClient automationCompositionInstanceApiClient;
+ private final RappCsarConfigurationHandler rappCsarConfigurationHandler;
+ private final RappCacheService rappCacheService;
+ private final RappStateMachine rappStateMachine;
+ private final ACMConfiguration acmConfiguration;
+ @Getter
+ private UUID compositionId;
+
+ public List<ParticipantInformation> getAllParticipants() {
+ return participantMonitoringApiClient.queryParticipants(null, null, UUID.randomUUID());
+ }
+
+
+ void updateACMInstanceState(Rapp rapp, DeployOrder deployOrder) {
+ AcInstanceStateUpdate acInstanceStateUpdate = new AcInstanceStateUpdate();
+ acInstanceStateUpdate.setDeployOrder(deployOrder);
+ automationCompositionInstanceApiClient.compositionInstanceState(rapp.getCompositionId(),
+ rapp.getCompositionInstanceId(), acInstanceStateUpdate, UUID.randomUUID());
+ }
+
+ public void primeACMComposition(UUID compositionId, PrimeOrder primeOrder) {
+ AcTypeStateUpdate acTypeStateUpdate = new AcTypeStateUpdate();
+ acTypeStateUpdate.setPrimeOrder(primeOrder);
+ automationCompositionDefinitionApiClient.compositionDefinitionPriming(compositionId, UUID.randomUUID(),
+ acTypeStateUpdate);
+ }
+
+ public CommissioningResponse createComposition(String compositionPayload) {
+ CommissioningResponse commissioningResponse = null;
+ try {
+ commissioningResponse =
+ automationCompositionDefinitionApiClient.createCompositionDefinitions(compositionPayload,
+ UUID.randomUUID());
+ compositionId = commissioningResponse.getCompositionId();
+ } catch (Exception e) {
+ logger.warn("Error in creating composition", e);
+ }
+ return commissioningResponse;
+ }
+
+ public CommissioningResponse deleteComposition(UUID compositionId) {
+ return automationCompositionDefinitionApiClient.deleteCompositionDefinition(compositionId, UUID.randomUUID());
+ }
+
+ public boolean isCompositionStateEquals(UUID compositionId, AcTypeState acTypeState) {
+ //automationCompositionDefinitionApiClient.getCompositionDefinition(compositionId, UUID.randomUUID()).getState().equals(acTypeState);
+ //TODO httpmessage converter doesn't map AutomationCompositionDefinition properly, Fix that and check the response
+ return true;
+ }
+
+ boolean isCompositionInstanceStateEquals(UUID compositionId, UUID compositionIntanceId, DeployState deployState) {
+ return automationCompositionInstanceApiClient.getCompositionInstance(compositionId, compositionIntanceId,
+ UUID.randomUUID()).getDeployState().equals(deployState);
+ }
+
+ boolean waitForCompositionInstanceTargetState(Rapp rapp, DeployState deployState) {
+ boolean targetInstanceStateTransition = false;
+ try {
+ for (int i = 0; i < acmConfiguration.getMaxRetries(); i++) {
+ logger.debug("Composition instance state check {}", i + 1);
+ if (isCompositionInstanceStateEquals(rapp.getCompositionId(), rapp.getCompositionInstanceId(),
+ deployState)) {
+ sendRappStateEvent(rapp, deployState);
+ logger.info("Composition instance {} state is {}", rapp.getCompositionInstanceId(), deployState);
+ targetInstanceStateTransition = true;
+ break;
+ } else {
+ TimeUnit.SECONDS.sleep(acmConfiguration.getRetryInterval());
+ }
+ }
+ } catch (Exception e) {
+ logger.warn("Unable to get composition instance state for composition {}", rapp.getCompositionId());
+ }
+ return targetInstanceStateTransition;
+ }
+
+ @Override
+ public boolean deployRapp(Rapp rapp) {
+ try {
+ rapp.setCompositionId(getCompositionId());
+ String instantiationPayload =
+ rappCsarConfigurationHandler.getInstantiationPayload(rapp, getCompositionId());
+ InstantiationResponse instantiationResponse =
+ automationCompositionInstanceApiClient.createCompositionInstance(getCompositionId(),
+ instantiationPayload, UUID.randomUUID());
+ if (instantiationResponse.getInstanceId() != null) {
+ rapp.setCompositionInstanceId(instantiationResponse.getInstanceId());
+ updateACMInstanceState(rapp, DeployOrder.DEPLOY);
+ return true;
+ }
+ } catch (Exception e) {
+ logger.warn("Error in deploying Rapp", e);
+ }
+ return false;
+ }
+
+ @Override
+ public boolean undeployRapp(Rapp rapp) {
+ AutomationComposition automationComposition =
+ automationCompositionInstanceApiClient.getCompositionInstance(rapp.getCompositionId(),
+ rapp.getCompositionInstanceId(), UUID.randomUUID());
+ if (automationComposition.getDeployState().equals(DeployState.DEPLOYED) && automationComposition.getLockState()
+ .equals(LockState.LOCKED)) {
+ updateACMInstanceState(rapp, DeployOrder.UNDEPLOY);
+ if (waitForCompositionInstanceTargetState(rapp, DeployState.UNDEPLOYED)) {
+ automationCompositionInstanceApiClient.deleteCompositionInstance(
+ automationComposition.getCompositionId(), automationComposition.getInstanceId(),
+ UUID.randomUUID());
+ rappStateMachine.sendRappEvent(rapp, RappEvent.ACMUNDEPLOYED);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public void syncRappStatus(Rapp rapp) {
+ if (rapp.getCompositionId() != null && rapp.getCompositionInstanceId() != null) {
+ try {
+ AutomationComposition compositionInstance =
+ automationCompositionInstanceApiClient.getCompositionInstance(rapp.getCompositionId(),
+ rapp.getCompositionInstanceId(), UUID.randomUUID());
+ logger.info("ACM details are " + compositionInstance.toString());
+ sendRappStateEvent(rapp, compositionInstance.getDeployState());
+ } catch (RestClientException exception) {
+ logger.warn("Unable to get the ACM details for rapp {}", rapp.getName());
+ }
+ }
+ }
+
+ void sendRappStateEvent(Rapp rapp, DeployState deployState) {
+ if (deployState.equals(DeployState.DEPLOYED)) {
+ rappStateMachine.sendRappEvent(rapp, RappEvent.ACMDEPLOYED);
+ } else if (deployState.equals(DeployState.UNDEPLOYED)) {
+ rappStateMachine.sendRappEvent(rapp, RappEvent.ACMUNDEPLOYED);
+ } else if (deployState.equals(DeployState.DEPLOYING)) {
+ rappStateMachine.sendRappEvent(rapp, RappEvent.DEPLOYING);
+ } else if (deployState.equals(DeployState.UNDEPLOYING)) {
+ rappStateMachine.sendRappEvent(rapp, RappEvent.UNDEPLOYING);
+ }
+ }
+}
diff --git a/rapp-manager-acm/src/main/java/com/oransc/rappmanager/acm/service/AutomationCompositionLifeCycleManager.java b/rapp-manager-acm/src/main/java/com/oransc/rappmanager/acm/service/AutomationCompositionLifeCycleManager.java
new file mode 100755
index 0000000..8498bdf
--- /dev/null
+++ b/rapp-manager-acm/src/main/java/com/oransc/rappmanager/acm/service/AutomationCompositionLifeCycleManager.java
@@ -0,0 +1,104 @@
+/*-
+ * ============LICENSE_START======================================================================
+ * Copyright (C) 2023 Nordix Foundation. 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END========================================================================
+ */
+
+package com.oransc.rappmanager.acm.service;
+
+
+import com.oransc.rappmanager.acm.configuration.ACMConfiguration;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.concurrent.TimeUnit;
+import lombok.RequiredArgsConstructor;
+import org.onap.policy.clamp.models.acm.concepts.AcTypeState;
+import org.onap.policy.clamp.models.acm.messages.rest.commissioning.CommissioningResponse;
+import org.onap.policy.clamp.models.acm.messages.rest.commissioning.PrimeOrder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.context.SmartLifecycle;
+import org.springframework.stereotype.Service;
+
+@Service
+@RequiredArgsConstructor
+public class AutomationCompositionLifeCycleManager implements SmartLifecycle {
+
+ Logger logger = LoggerFactory.getLogger(AutomationCompositionLifeCycleManager.class);
+ private final ACMConfiguration acmConfiguration;
+ private final AcmDeployer acmDeployer;
+ private boolean running;
+
+ @Override
+ public void start() {
+ logger.info("Initializing automation Composition");
+ try {
+ String compositionPayload = Files.readString(Path.of(acmConfiguration.getCompositionDefinitionLocation()));
+ CommissioningResponse commissioningResponse =
+ acmDeployer.createComposition(compositionPayload);
+ if (commissioningResponse != null && commissioningResponse.getCompositionId() != null) {
+ logger.info("Priming automation Composition");
+ acmDeployer.primeACMComposition(commissioningResponse.getCompositionId(),
+ PrimeOrder.PRIME);
+ for (int i = 0; i < acmConfiguration.getMaxRetries(); i++) {
+ logger.debug("Composition priming check {}", i + 1);
+ if (acmDeployer.isCompositionStateEquals(commissioningResponse.getCompositionId(),
+ AcTypeState.PRIMED)) {
+ logger.info("Composition {} is primed", commissioningResponse.getCompositionId());
+ running = true;
+ break;
+ } else {
+ TimeUnit.SECONDS.sleep(acmConfiguration.getRetryInterval());
+ }
+ }
+ } else {
+ logger.error("Failed to create automation composition");
+ }
+ } catch (Exception e) {
+ logger.error("Failed to create automation composition", e);
+ }
+ }
+
+ @Override
+ public void stop() {
+ logger.info("Depriming automation Composition");
+ if (running) {
+ try {
+ acmDeployer.primeACMComposition(acmDeployer.getCompositionId(),
+ PrimeOrder.DEPRIME);
+ for (int i = 0; i < acmConfiguration.getMaxRetries(); i++) {
+ logger.debug("Composition depriming check {}", i + 1);
+ if (acmDeployer.isCompositionStateEquals(
+ acmDeployer.getCompositionId(), AcTypeState.COMMISSIONED)) {
+ logger.info("Composition {} is deprimed", acmDeployer.getCompositionId());
+ logger.info("Deleting automation Composition");
+ acmDeployer.deleteComposition(acmDeployer.getCompositionId());
+ running = false;
+ break;
+ } else {
+ TimeUnit.SECONDS.sleep(acmConfiguration.getRetryInterval());
+ }
+ }
+ } catch (Exception e) {
+ logger.error("Failed to cleanup automation composition");
+ }
+ }
+ }
+
+ @Override
+ public boolean isRunning() {
+ return running;
+ }
+}
diff --git a/rapp-manager-acm/src/main/resources/openapi/acm-spec.yaml b/rapp-manager-acm/src/main/resources/openapi/acm-spec.yaml
new file mode 100755
index 0000000..6eae87b
--- /dev/null
+++ b/rapp-manager-acm/src/main/resources/openapi/acm-spec.yaml
@@ -0,0 +1,1388 @@
+# ============LICENSE_START=======================================================
+# Copyright (C) 2022-2023 Nordix Foundation
+# ================================================================================
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+# ============LICENSE_END=========================================================
+openapi: 3.0.1
+info:
+ title: Api Documentation
+ description: Api Documentation
+ termsOfService: urn:tos
+ contact: {}
+ license:
+ name: Apache 2.0
+ url: http://www.apache.org/licenses/LICENSE-2.0
+ version: "1.0"
+servers:
+ - url: https://{server}
+ variables:
+ server:
+ default: onap/policy/clamp/acm/v2
+ description: This value is assigned by the service provider
+tags:
+ - name: Participant Monitoring
+ description: Pariticipant Monitoring Controller, for monitoring of and requesting information from participants
+ - name: Automation Composition Definition
+ description: Automation Composition Definition Controller, for definition and management of Automation Composition Types
+ - name: Automation Composition Instance
+ description: Automation Composition Instance Controller, for definition and management of Automation Composition Instances
+
+paths:
+ /participants:
+ get:
+ tags:
+ - Participant Monitoring
+ summary: Query Particicpants
+ description: Query the participants that are registered on the ACM runtime
+ operationId: queryParticipants
+ parameters:
+ - name: name
+ in: query
+ required: false
+ description: Automation composition definition name. Regular expressions are supported for filtering. If
+ this parameter is not specified, all automation composition definitions are returned.
+ schema:
+ type: string
+ - name: version
+ in: query
+ required: false
+ description: Automation composition definition version. Regular expressions are supported for filtering. If this
+ parameter is not specified, all automation composition definitions that match the "name" filter are are returned.
+ schema:
+ type: string
+ - name: X-onap-RequestId
+ in: header
+ description: RequestID for http transaction
+ schema:
+ type: string
+ format: uuid
+ responses:
+ 200:
+ description: OK, serialised array of instances of
+ [ParticipantInformation](https://github.com/onap/policy-clamp/blob/master/models/src/main/java/org/onap/policy/clamp/models/acm/concepts/ParticipantInformation.java)
+ that contains information on participants with their information and status. Each participant entry contains
+ a list of AC Element types on the participant. Each AC Element type entry contains a list of AC Element
+ instances on the Participant.
+ headers:
+ X-LatestVersion:
+ $ref: '#/components/headers/X-LatestVersion'
+ X-PatchVersion:
+ $ref: '#/components/headers/X-PatchVersion'
+ X-MinorVersion:
+ $ref: '#/components/headers/X-MinorVersion'
+ X-onap-RequestId:
+ $ref: '#/components/headers/X-onap-RequestId'
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/ParticipantInformation'
+ example:
+ externalValue: 'https://raw.githubusercontent.com/onap/policy-clamp/master/runtime-acm/src/main/resources/openapi/examples/getMultiParticipantResponse.json'
+ application/yaml:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/ParticipantInformation'
+ example:
+ externalValue: 'https://raw.githubusercontent.com/onap/policy-clamp/master/runtime-acm/src/main/resources/openapi/examples/getMultiParticipantResponse.yaml'
+ 401:
+ description: Authentication Error, returns an instance of
+ [SimpleResponse](https://github.com/onap/policy-clamp/blob/master/models/src/main/java/org/onap/policy/clamp/models/acm/messages/rest/SimpleResponse.java)
+ headers:
+ X-LatestVersion:
+ $ref: '#/components/headers/X-LatestVersion'
+ X-PatchVersion:
+ $ref: '#/components/headers/X-PatchVersion'
+ X-MinorVersion:
+ $ref: '#/components/headers/X-MinorVersion'
+ X-onap-RequestId:
+ $ref: '#/components/headers/X-onap-RequestId'
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/SimpleResponse'
+ security:
+ - basicAuth: []
+ x-interface info:
+ api-version: 1.0.0
+ last-mod-release: London
+ put:
+ tags:
+ - Participant Monitoring
+ summary: Order an immendiate Participant Report from all participants
+ description: Requests all participants to immediately generate a heartbeat report with their information and status
+ and the information and status of all their AC Element Types and Instances. The results are published on subsequent
+ GET REST requests on the "participants" endpoint.
+ operationId: orderAllParticipantsReport
+ parameters:
+ - name: X-onap-RequestId
+ in: header
+ description: RequestID for http transaction
+ schema:
+ type: string
+ format: uuid
+ responses:
+ 202:
+ description: Accepted, the request has been accepted and forwarded to participants
+ headers:
+ X-LatestVersion:
+ $ref: '#/components/headers/X-LatestVersion'
+ X-PatchVersion:
+ $ref: '#/components/headers/X-PatchVersion'
+ X-MinorVersion:
+ $ref: '#/components/headers/X-MinorVersion'
+ X-onap-RequestId:
+ $ref: '#/components/headers/X-onap-RequestId'
+ 400:
+ description: Bad Request, returns an instance of
+ [SimpleResponse](https://github.com/onap/policy-clamp/blob/master/models/src/main/java/org/onap/policy/clamp/models/acm/messages/rest/SimpleResponse.java)
+ headers:
+ X-LatestVersion:
+ $ref: '#/components/headers/X-LatestVersion'
+ X-PatchVersion:
+ $ref: '#/components/headers/X-PatchVersion'
+ X-MinorVersion:
+ $ref: '#/components/headers/X-MinorVersion'
+ X-onap-RequestId:
+ $ref: '#/components/headers/X-onap-RequestId'
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/SimpleResponse'
+ 401:
+ description: Authentication Error, returns an instance of
+ [SimpleResponse](https://github.com/onap/policy-clamp/blob/master/models/src/main/java/org/onap/policy/clamp/models/acm/messages/rest/SimpleResponse.java)
+ headers:
+ X-LatestVersion:
+ $ref: '#/components/headers/X-LatestVersion'
+ X-PatchVersion:
+ $ref: '#/components/headers/X-PatchVersion'
+ X-MinorVersion:
+ $ref: '#/components/headers/X-MinorVersion'
+ X-onap-RequestId:
+ $ref: '#/components/headers/X-onap-RequestId'
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/SimpleResponse'
+ security:
+ - basicAuth: []
+ x-interface info:
+ api-version: 1.0.0
+ last-mod-release: London
+ x-codegen-request-body-name: body
+ /participants/{participantId}:
+ get:
+ tags:
+ - Participant Monitoring
+ summary: Get details of the requested participant
+ definitions
+ description: Get details of the requested commissioned participant, returning all pariticipant details
+ operationId: getParticipant
+ parameters:
+ - name : participantId
+ in: path
+ description: The UUID of the participant to get
+ required: true
+ schema:
+ type: string
+ format: uuid
+ - name: X-onap-RequestId
+ in: header
+ description: RequestID for http transaction
+ schema:
+ type: string
+ format: uuid
+ responses:
+ 200:
+ description: Serialised instance of
+ [ParticipantInformation](https://github.com/onap/policy-clamp/blob/master/models/src/main/java/org/onap/policy/clamp/models/acm/concepts/ParticipantInformation.java)
+ that information on the participant with its information and status. The participant entry contains
+ a list of AC Element types on the participant. Each AC Element type entry contains a list of AC Element
+ instances on the Participant.
+ headers:
+ X-LatestVersion:
+ $ref: '#/components/headers/X-LatestVersion'
+ X-PatchVersion:
+ $ref: '#/components/headers/X-PatchVersion'
+ X-MinorVersion:
+ $ref: '#/components/headers/X-MinorVersion'
+ X-onap-RequestId:
+ $ref: '#/components/headers/X-onap-RequestId'
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ParticipantInformation'
+ example:
+ externalValue: 'https://raw.githubusercontent.com/onap/policy-clamp/master/runtime-acm/src/main/resources/openapi/examples/getSingleParticipantResponse.json'
+ application/yaml:
+ schema:
+ $ref: '#/components/schemas/ToscaServiceTemplate'
+ example:
+ externalValue: 'https://raw.githubusercontent.com/onap/policy-clamp/master/runtime-acm/src/main/resources/openapi/examples/getParticipantResponse.yaml'
+ 401:
+ description: Authentication Error, returns an instance of
+ [SimpleResponse](https://github.com/onap/policy-clamp/blob/master/models/src/main/java/org/onap/policy/clamp/models/acm/messages/rest/SimpleResponse.java)
+ headers:
+ X-LatestVersion:
+ $ref: '#/components/headers/X-LatestVersion'
+ X-PatchVersion:
+ $ref: '#/components/headers/X-PatchVersion'
+ X-MinorVersion:
+ $ref: '#/components/headers/X-MinorVersion'
+ X-onap-RequestId:
+ $ref: '#/components/headers/X-onap-RequestId'
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/SimpleResponse'
+ 404:
+ description: Specified participant not found, returns an instance of
+ [SimpleResponse](https://github.com/onap/policy-clamp/blob/master/models/src/main/java/org/onap/policy/clamp/models/acm/messages/rest/SimpleResponse.java)
+ headers:
+ X-LatestVersion:
+ $ref: '#/components/headers/X-LatestVersion'
+ X-PatchVersion:
+ $ref: '#/components/headers/X-PatchVersion'
+ X-MinorVersion:
+ $ref: '#/components/headers/X-MinorVersion'
+ X-onap-RequestId:
+ $ref: '#/components/headers/X-onap-RequestId'
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/SimpleResponse'
+ security:
+ - basicAuth: []
+ x-interface info:
+ api-version: 1.0.0
+ last-mod-release: London
+ put:
+ tags:
+ - Participant Monitoring
+ summary: Order an immendiate Participant Report from a participant
+ description: Requests the participants to immediately generate a heartbeat report with its information and status
+ and the information and status of all its AC Element Types and Instances. The results are published on subsequent
+ GET REST requests on the "participants" endpoint.
+ operationId: orderParticipantReport
+ parameters:
+ - name : participantId
+ in: path
+ description: The UUID of the participant to get
+ required: true
+ schema:
+ type: string
+ format: uuid
+ - name: X-onap-RequestId
+ in: header
+ description: RequestID for http transaction
+ schema:
+ type: string
+ format: uuid
+ responses:
+ 202:
+ description: Accepted, the request has been accepted and forwarded to participants
+ headers:
+ X-LatestVersion:
+ $ref: '#/components/headers/X-LatestVersion'
+ X-PatchVersion:
+ $ref: '#/components/headers/X-PatchVersion'
+ X-MinorVersion:
+ $ref: '#/components/headers/X-MinorVersion'
+ X-onap-RequestId:
+ $ref: '#/components/headers/X-onap-RequestId'
+ 400:
+ description: Bad Request, returns an instance of
+ [SimpleResponse](https://github.com/onap/policy-clamp/blob/master/models/src/main/java/org/onap/policy/clamp/models/acm/messages/rest/SimpleResponse.java)
+ headers:
+ X-LatestVersion:
+ $ref: '#/components/headers/X-LatestVersion'
+ X-PatchVersion:
+ $ref: '#/components/headers/X-PatchVersion'
+ X-MinorVersion:
+ $ref: '#/components/headers/X-MinorVersion'
+ X-onap-RequestId:
+ $ref: '#/components/headers/X-onap-RequestId'
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/SimpleResponse'
+ 401:
+ description: Authentication Error, returns an instance of
+ [SimpleResponse](https://github.com/onap/policy-clamp/blob/master/models/src/main/java/org/onap/policy/clamp/models/acm/messages/rest/SimpleResponse.java)
+ headers:
+ X-LatestVersion:
+ $ref: '#/components/headers/X-LatestVersion'
+ X-PatchVersion:
+ $ref: '#/components/headers/X-PatchVersion'
+ X-MinorVersion:
+ $ref: '#/components/headers/X-MinorVersion'
+ X-onap-RequestId:
+ $ref: '#/components/headers/X-onap-RequestId'
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/SimpleResponse'
+ 404:
+ description: Specified participant not found, returns an instance of
+ [SimpleResponse](https://github.com/onap/policy-clamp/blob/master/models/src/main/java/org/onap/policy/clamp/models/acm/messages/rest/SimpleResponse.java)
+ headers:
+ X-LatestVersion:
+ $ref: '#/components/headers/X-LatestVersion'
+ X-PatchVersion:
+ $ref: '#/components/headers/X-PatchVersion'
+ X-MinorVersion:
+ $ref: '#/components/headers/X-MinorVersion'
+ X-onap-RequestId:
+ $ref: '#/components/headers/X-onap-RequestId'
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/SimpleResponse'
+ security:
+ - basicAuth: []
+ x-interface info:
+ api-version: 1.0.0
+ last-mod-release: London
+ x-codegen-request-body-name: body
+ /compositions:
+ get:
+ tags:
+ - Automation Composition Definition
+ summary: Query the commissioned automation composition definitions
+ definitions
+ description: Query the commissioned automation composition
+ definitions, returning the automation composition details
+ operationId: queryCompositionDefinitions
+ parameters:
+ - name: name
+ in: query
+ required: false
+ description: Automation composition definition name. Regular expressions are supported for filtering. If
+ this parameter is not specified, all automation composition definitions are returned.
+ schema:
+ type: string
+ - name: version
+ in: query
+ required: false
+ description: Automation composition definition version. Regular expressions are supported for filtering. If this
+ parameter is not specified, all automation composition definitions that match the "name" filter are are returned.
+ schema:
+ type: string
+ - name: X-onap-RequestId
+ in: header
+ description: RequestID for http transaction
+ schema:
+ type: string
+ format: uuid
+ responses:
+ 200:
+ description: Serialised instance of
+ [ToscaServiceTemplates](https://github.com/onap/policy-models/blob/master/models-tosca/src/main/java/org/onap/policy/models/tosca/authorative/concepts/ToscaServiceTemplates.java)
+ that contains the automation composition definitions that match the requested filters.
+ headers:
+ X-LatestVersion:
+ $ref: '#/components/headers/X-LatestVersion'
+ X-PatchVersion:
+ $ref: '#/components/headers/X-PatchVersion'
+ X-MinorVersion:
+ $ref: '#/components/headers/X-MinorVersion'
+ X-onap-RequestId:
+ $ref: '#/components/headers/X-onap-RequestId'
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ToscaServiceTemplates'
+ example:
+ externalValue: 'https://raw.githubusercontent.com/onap/policy-clamp/master/runtime-acm/src/main/resources/openapi/examples/getAllCompositionDefinitions.json'
+ application/yaml:
+ schema:
+ $ref: '#/components/schemas/ToscaServiceTemplates'
+ example:
+ externalValue: 'https://raw.githubusercontent.com/onap/policy-clamp/master/runtime-acm/src/main/resources/openapi/examples/getAllCompositionDefinitions.yaml'
+ 401:
+ description: Authentication Error, returns an instance of
+ [SimpleResponse](https://github.com/onap/policy-clamp/blob/master/models/src/main/java/org/onap/policy/clamp/models/acm/messages/rest/SimpleResponse.java)
+ headers:
+ X-LatestVersion:
+ $ref: '#/components/headers/X-LatestVersion'
+ X-PatchVersion:
+ $ref: '#/components/headers/X-PatchVersion'
+ X-MinorVersion:
+ $ref: '#/components/headers/X-MinorVersion'
+ X-onap-RequestId:
+ $ref: '#/components/headers/X-onap-RequestId'
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/SimpleResponse'
+ security:
+ - basicAuth: []
+ x-interface info:
+ api-version: 1.0.0
+ last-mod-release: London
+ post:
+ tags:
+ - Automation Composition Definition
+ summary: Commissions automation composition definitions
+ description: Commissions automation composition definitions, returning the UUIDs of
+ automation composition definitions commissioned by this request.
+ operationId: createCompositionDefinitions
+ parameters:
+ - name: X-onap-RequestId
+ in: header
+ description: RequestID for http transaction
+ schema:
+ type: string
+ format: uuid
+ requestBody:
+ description: Serialised instance of
+ [ToscaServiceTemplate](https://github.com/onap/policy-models/blob/master/models-tosca/src/main/java/org/onap/policy/models/tosca/authorative/concepts/ToscaServiceTemplate.java)
+ containing the automation composition definitions to be commissioned.
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ToscaServiceTemplate'
+ example:
+ externalValue: 'https://raw.githubusercontent.com/onap/policy-clamp/master/runtime-acm/src/main/resources/openapi/examples/postCompositionDefinitions.json'
+ application/yaml:
+ schema:
+ $ref: '#/components/schemas/ToscaServiceTemplate'
+ example:
+ externalValue: 'https://raw.githubusercontent.com/onap/policy-clamp/master/runtime-acm/src/main/resources/openapi/examples/postCompositionDefinitions.yaml'
+ required: true
+ responses:
+ 201:
+ description: Serialised instance of
+ [CommissioningResponse](https://github.com/onap/policy-clamp/blob/master/models/src/main/java/org/onap/policy/clamp/models/acm/messages/rest/commissioning/CommissioningResponse.java)
+ containing the UUIDs of automation composition definitions created by this request
+ headers:
+ X-LatestVersion:
+ $ref: '#/components/headers/X-LatestVersion'
+ X-PatchVersion:
+ $ref: '#/components/headers/X-PatchVersion'
+ X-MinorVersion:
+ $ref: '#/components/headers/X-MinorVersion'
+ X-onap-RequestId:
+ $ref: '#/components/headers/X-onap-RequestId'
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/CommissioningResponse'
+ example:
+ externalValue: 'https://raw.githubusercontent.com/onap/policy-clamp/master/runtime-acm/src/main/resources/openapi/examples/postCommissionCompositionDefinitionsResponse.json'
+ application/yaml:
+ schema:
+ $ref: '#/components/schemas/CommissioningResponse'
+ example:
+ externalValue: 'https://raw.githubusercontent.com/onap/policy-clamp/master/runtime-acm/src/main/resources/openapi/examples/postCommissionCompositionDefinitionsResponse.yaml'
+ 401:
+ description: Authentication Error, returns an instance of
+ [SimpleResponse](https://github.com/onap/policy-clamp/blob/master/models/src/main/java/org/onap/policy/clamp/models/acm/messages/rest/SimpleResponse.java)
+ headers:
+ X-LatestVersion:
+ $ref: '#/components/headers/X-LatestVersion'
+ X-PatchVersion:
+ $ref: '#/components/headers/X-PatchVersion'
+ X-MinorVersion:
+ $ref: '#/components/headers/X-MinorVersion'
+ X-onap-RequestId:
+ $ref: '#/components/headers/X-onap-RequestId'
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/SimpleResponse'
+ 400:
+ description: Bad Request, returns an instance of
+ [SimpleResponse](https://github.com/onap/policy-clamp/blob/master/models/src/main/java/org/onap/policy/clamp/models/acm/messages/rest/SimpleResponse.java)
+ headers:
+ X-LatestVersion:
+ $ref: '#/components/headers/X-LatestVersion'
+ X-PatchVersion:
+ $ref: '#/components/headers/X-PatchVersion'
+ X-MinorVersion:
+ $ref: '#/components/headers/X-MinorVersion'
+ X-onap-RequestId:
+ $ref: '#/components/headers/X-onap-RequestId'
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/SimpleResponse'
+ security:
+ - basicAuth: []
+ x-interface info:
+ api-version: 1.0.0
+ last-mod-release: London
+ x-codegen-request-body-name: body
+ /compositions/{compositionId}:
+ get:
+ tags:
+ - Automation Composition Definition
+ summary: Get details of the requested commissioned automation composition
+ definitions
+ description: Get details of the requested commissioned automation composition
+ definitions, returning all automation composition details
+ operationId: getCompositionDefinition
+ parameters:
+ - name : compositionId
+ in: path
+ description: The UUID of the automation composition definition to get
+ required: true
+ schema:
+ type: string
+ format: uuid
+ - name: X-onap-RequestId
+ in: header
+ description: RequestID for http transaction
+ schema:
+ type: string
+ format: uuid
+ responses:
+ 200:
+ description:
+ Serialised instance of
+ [AutomationCompositionDefinition](https://github.com/onap/policy-clamp/blob/master/models/src/main/java/org/onap/policy/clamp/models/acm/concepts/AutomationCompositionDefinition.java)
+ containing the requested automation composition definition.
+ headers:
+ X-LatestVersion:
+ $ref: '#/components/headers/X-LatestVersion'
+ X-PatchVersion:
+ $ref: '#/components/headers/X-PatchVersion'
+ X-MinorVersion:
+ $ref: '#/components/headers/X-MinorVersion'
+ X-onap-RequestId:
+ $ref: '#/components/headers/X-onap-RequestId'
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/AutomationCompositionDefinition'
+ example:
+ externalValue: 'https://raw.githubusercontent.com/onap/policy-clamp/master/runtime-acm/src/main/resources/openapi/examples/getSingleCompositionDefinition.json'
+ application/yaml:
+ schema:
+ $ref: '#/components/schemas/AutomationCompositionDefinition'
+ example:
+ externalValue: 'https://raw.githubusercontent.com/onap/policy-clamp/master/runtime-acm/src/main/resources/openapi/examples/getSingleCompositionDefinition.yaml'
+ 401:
+ description: Authentication Error, returns an instance of
+ [SimpleResponse](https://github.com/onap/policy-clamp/blob/master/models/src/main/java/org/onap/policy/clamp/models/acm/messages/rest/SimpleResponse.java)
+ headers:
+ X-LatestVersion:
+ $ref: '#/components/headers/X-LatestVersion'
+ X-PatchVersion:
+ $ref: '#/components/headers/X-PatchVersion'
+ X-MinorVersion:
+ $ref: '#/components/headers/X-MinorVersion'
+ X-onap-RequestId:
+ $ref: '#/components/headers/X-onap-RequestId'
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/SimpleResponse'
+ 404:
+ description: Specified automation composition definition not found, returns an instance of
+ [SimpleResponse](https://github.com/onap/policy-clamp/blob/master/models/src/main/java/org/onap/policy/clamp/models/acm/messages/rest/SimpleResponse.java)
+ headers:
+ X-LatestVersion:
+ $ref: '#/components/headers/X-LatestVersion'
+ X-PatchVersion:
+ $ref: '#/components/headers/X-PatchVersion'
+ X-MinorVersion:
+ $ref: '#/components/headers/X-MinorVersion'
+ X-onap-RequestId:
+ $ref: '#/components/headers/X-onap-RequestId'
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/SimpleResponse'
+ security:
+ - basicAuth: []
+ x-interface info:
+ api-version: 1.0.0
+ last-mod-release: London
+ put:
+ tags:
+ - Automation Composition Definition
+ summary: Primes or deprimes an automation composition definition
+ description: Primes or deprimes an automation composition definition by sending the AC Element Types to participants and
+ getting participants to take responsibility for AC Element Types in this AC Type.
+ operationId: compositionDefinitionPriming
+ parameters:
+ - name : compositionId
+ in: path
+ description: The UUID of the automation composition definition to update
+ required: true
+ schema:
+ type: string
+ format: uuid
+ - name: X-onap-RequestId
+ in: header
+ description: RequestID for http transaction
+ schema:
+ type: string
+ format: uuid
+ requestBody:
+ description: Serialised instance of
+ [AcTypeStateUpdate](https://github.com/onap/policy-clamp/blob/master/models/src/main/java/org/onap/policy/clamp/models/acm/messages/rest/commissioning/AcTypeStateUpdate.java)
+ which specifies the requested state change on the automation concept instance
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/AcTypeStateUpdate'
+ example:
+ externalValue: 'https://raw.githubusercontent.com/onap/policy-clamp/master/runtime-acm/src/main/resources/openapi/examples/putAcTypeStateUpdate.json'
+ application/yaml:
+ schema:
+ $ref: '#/components/schemas/AcTypeStateUpdate'
+ example:
+ externalValue: 'https://raw.githubusercontent.com/onap/policy-clamp/master/runtime-acm/src/main/resources/openapi/examples/putAcTypeStateUpdate.yaml'
+ responses:
+ 202:
+ description: Accepted, the request has been accepted and forwarded to participants
+ headers:
+ X-LatestVersion:
+ $ref: '#/components/headers/X-LatestVersion'
+ X-PatchVersion:
+ $ref: '#/components/headers/X-PatchVersion'
+ X-MinorVersion:
+ $ref: '#/components/headers/X-MinorVersion'
+ X-onap-RequestId:
+ $ref: '#/components/headers/X-onap-RequestId'
+ 400:
+ description: Bad Request, returns an instance of
+ [SimpleResponse](https://github.com/onap/policy-clamp/blob/master/models/src/main/java/org/onap/policy/clamp/models/acm/messages/rest/SimpleResponse.java)
+ headers:
+ X-LatestVersion:
+ $ref: '#/components/headers/X-LatestVersion'
+ X-PatchVersion:
+ $ref: '#/components/headers/X-PatchVersion'
+ X-MinorVersion:
+ $ref: '#/components/headers/X-MinorVersion'
+ X-onap-RequestId:
+ $ref: '#/components/headers/X-onap-RequestId'
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/SimpleResponse'
+ 401:
+ description: Authentication Error, returns an instance of
+ [SimpleResponse](https://github.com/onap/policy-clamp/blob/master/models/src/main/java/org/onap/policy/clamp/models/acm/messages/rest/SimpleResponse.java)
+ headers:
+ X-LatestVersion:
+ $ref: '#/components/headers/X-LatestVersion'
+ X-PatchVersion:
+ $ref: '#/components/headers/X-PatchVersion'
+ X-MinorVersion:
+ $ref: '#/components/headers/X-MinorVersion'
+ X-onap-RequestId:
+ $ref: '#/components/headers/X-onap-RequestId'
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/SimpleResponse'
+ 404:
+ description: Specified automation composition definition not found, returns an instance of
+ [SimpleResponse](https://github.com/onap/policy-clamp/blob/master/models/src/main/java/org/onap/policy/clamp/models/acm/messages/rest/SimpleResponse.java)
+ headers:
+ X-LatestVersion:
+ $ref: '#/components/headers/X-LatestVersion'
+ X-PatchVersion:
+ $ref: '#/components/headers/X-PatchVersion'
+ X-MinorVersion:
+ $ref: '#/components/headers/X-MinorVersion'
+ X-onap-RequestId:
+ $ref: '#/components/headers/X-onap-RequestId'
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/SimpleResponse'
+ security:
+ - basicAuth: []
+ x-interface info:
+ api-version: 1.0.0
+ last-mod-release: London
+ x-codegen-request-body-name: body
+ delete:
+ tags:
+ - Automation Composition Definition
+ summary: Delete a commissioned automation composition definition
+ description: Deletes a commissioned automation composition definition,returning the UUID of the automation composition definition deleted by this request
+ operationId: deleteCompositionDefinition
+ parameters:
+ - name : compositionId
+ in: path
+ description: The UUID of the automation composition definition to delete
+ required: true
+ schema:
+ type: string
+ format: uuid
+ - name: X-onap-RequestId
+ in: header
+ description: RequestID for http transaction
+ schema:
+ type: string
+ format: uuid
+ responses:
+ 200:
+ description: Serialised instance of
+ [CommissioningResponse](https://github.com/onap/policy-clamp/blob/master/models/src/main/java/org/onap/policy/clamp/models/acm/messages/rest/commissioning/CommissioningResponse.java)
+ containing the UUID of the automation composition deleted by this request
+ headers:
+ X-LatestVersion:
+ $ref: '#/components/headers/X-LatestVersion'
+ X-PatchVersion:
+ $ref: '#/components/headers/X-PatchVersion'
+ X-MinorVersion:
+ $ref: '#/components/headers/X-MinorVersion'
+ X-onap-RequestId:
+ $ref: '#/components/headers/X-onap-RequestId'
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/CommissioningResponse'
+ example:
+ externalValue: 'https://raw.githubusercontent.com/onap/policy-clamp/master/runtime-acm/src/main/resources/openapi/examples/deleteCompositionDefinitionResponse.json'
+ application/yaml:
+ schema:
+ $ref: '#/components/schemas/CommissioningResponse'
+ example:
+ externalValue: 'https://raw.githubusercontent.com/onap/policy-clamp/master/runtime-acm/src/main/resources/openapi/examples/deleteCompositionDefinitionResponse.yaml'
+ 401:
+ description: Authentication Error, returns an instance of
+ [SimpleResponse](https://github.com/onap/policy-clamp/blob/master/models/src/main/java/org/onap/policy/clamp/models/acm/messages/rest/SimpleResponse.java)
+ headers:
+ X-LatestVersion:
+ $ref: '#/components/headers/X-LatestVersion'
+ X-PatchVersion:
+ $ref: '#/components/headers/X-PatchVersion'
+ X-MinorVersion:
+ $ref: '#/components/headers/X-MinorVersion'
+ X-onap-RequestId:
+ $ref: '#/components/headers/X-onap-RequestId'
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/SimpleResponse'
+ 404:
+ description: Specified automation composition definition not found, returns an instance of
+ [SimpleResponse](https://github.com/onap/policy-clamp/blob/master/models/src/main/java/org/onap/policy/clamp/models/acm/messages/rest/SimpleResponse.java)
+ headers:
+ X-LatestVersion:
+ $ref: '#/components/headers/X-LatestVersion'
+ X-PatchVersion:
+ $ref: '#/components/headers/X-PatchVersion'
+ X-MinorVersion:
+ $ref: '#/components/headers/X-MinorVersion'
+ X-onap-RequestId:
+ $ref: '#/components/headers/X-onap-RequestId'
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/SimpleResponse'
+ 400:
+ description: Bad Request, returns an instance of
+ [SimpleResponse](https://github.com/onap/policy-clamp/blob/master/models/src/main/java/org/onap/policy/clamp/models/acm/messages/rest/SimpleResponse.java)
+ headers:
+ X-LatestVersion:
+ $ref: '#/components/headers/X-LatestVersion'
+ X-PatchVersion:
+ $ref: '#/components/headers/X-PatchVersion'
+ X-MinorVersion:
+ $ref: '#/components/headers/X-MinorVersion'
+ X-onap-RequestId:
+ $ref: '#/components/headers/X-onap-RequestId'
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/SimpleResponse'
+ security:
+ - basicAuth: []
+ x-interface info:
+ api-version: 1.0.0
+ last-mod-release: London
+ /compositions/{compositionId}/instances:
+ get:
+ tags:
+ - Automation Composition Instance
+ summary: Query details of the requested automation composition instances
+ description: Query details of the requested automation composition instances for the given automation composition definition ID, returning
+ details of all its automation composition instances
+ operationId: queryCompositionInstances
+ parameters:
+ - name : compositionId
+ in: path
+ description: The UUID of the automation composition definition for which to return instances
+ required: true
+ schema:
+ type: string
+ format: uuid
+ - name: name
+ in: query
+ description: Automation composition instance name. Regular expressions are supported for filtering. If
+ this parameter is not specified, all automation composition instances for the specified definition are returned.
+ schema:
+ type: string
+ - name: version
+ in: query
+ description: Automation composition instance version. Regular expressions are supported for filtering. If this
+ parameter is not specified, all automation composition instances for the specified definition that match the "name" filter are are returned.
+ schema:
+ type: string
+ - name: X-onap-RequestId
+ in: header
+ description: RequestID for http transaction
+ schema:
+ type: string
+ format: uuid
+ responses:
+ 200:
+ description: Serialised instance of
+ [AutomationCompositions](https://github.com/onap/policy-clamp/blob/master/models/src/main/java/org/onap/policy/clamp/models/acm/concepts/AutomationCompositions.java)
+ containing a list of automation composition instances found
+ headers:
+ X-LatestVersion:
+ $ref: '#/components/headers/X-LatestVersion'
+ X-PatchVersion:
+ $ref: '#/components/headers/X-PatchVersion'
+ X-MinorVersion:
+ $ref: '#/components/headers/X-MinorVersion'
+ X-onap-RequestId:
+ $ref: '#/components/headers/X-onap-RequestId'
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/AutomationCompositions'
+ example:
+ externalValue: 'https://raw.githubusercontent.com/onap/policy-clamp/master/runtime-acm/src/main/resources/openapi/examples/getCompositionInstancesResponse.json'
+ application/yaml:
+ schema:
+ $ref: '#/components/schemas/AutomationCompositions'
+ example:
+ externalValue: 'https://raw.githubusercontent.com/onap/policy-clamp/master/runtime-acm/src/main/resources/openapi/examples/getCompositionInstancesResponse.yaml'
+ 401:
+ description: Authentication Error, returns an instance of
+ [SimpleResponse](https://github.com/onap/policy-clamp/blob/master/models/src/main/java/org/onap/policy/clamp/models/acm/messages/rest/SimpleResponse.java)
+ headers:
+ X-LatestVersion:
+ $ref: '#/components/headers/X-LatestVersion'
+ X-PatchVersion:
+ $ref: '#/components/headers/X-PatchVersion'
+ X-MinorVersion:
+ $ref: '#/components/headers/X-MinorVersion'
+ X-onap-RequestId:
+ $ref: '#/components/headers/X-onap-RequestId'
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/SimpleResponse'
+ 404:
+ description: The specified automation composition definition was not found, returns an instance of
+ [SimpleResponse](https://github.com/onap/policy-clamp/blob/master/models/src/main/java/org/onap/policy/clamp/models/acm/messages/rest/SimpleResponse.java)
+ headers:
+ X-LatestVersion:
+ $ref: '#/components/headers/X-LatestVersion'
+ X-PatchVersion:
+ $ref: '#/components/headers/X-PatchVersion'
+ X-MinorVersion:
+ $ref: '#/components/headers/X-MinorVersion'
+ X-onap-RequestId:
+ $ref: '#/components/headers/X-onap-RequestId'
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/SimpleResponse'
+ security:
+ - basicAuth: []
+ x-interface info:
+ api-version: 1.0.0
+ last-mod-release: London
+ post:
+ tags:
+ - Automation Composition Instance
+ summary: Create automation composition instance
+ description: Creates automation composition instance that use the sepcified automation composition definition. The ID of the created
+ automation composition instance is returned.
+ operationId: createCompositionInstance
+ parameters:
+ - name : compositionId
+ in: path
+ description: The UUID of the automation composition definition on which to create instance
+ required: true
+ schema:
+ type: string
+ format: uuid
+ - name: X-onap-RequestId
+ in: header
+ description: RequestID for http transaction
+ schema:
+ type: string
+ format: uuid
+ requestBody:
+ description: Serialised instance of
+ [AutomationComposition](https://github.com/onap/policy-clamp/blob/master/models/src/main/java/org/onap/policy/clamp/models/acm/concepts/AutomationComposition.java)
+ containing a automation composition instance to create
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/AutomationComposition'
+ example:
+ externalValue: 'https://raw.githubusercontent.com/onap/policy-clamp/master/runtime-acm/src/main/resources/openapi/examples/postCompositionInstance.json'
+ application/yaml:
+ schema:
+ $ref: '#/components/schemas/AutomationComposition'
+ example:
+ externalValue: 'https://raw.githubusercontent.com/onap/policy-clamp/master/runtime-acm/src/main/resources/openapi/examples/postCompositionInstance.yaml'
+ required: true
+ responses:
+ 201:
+ description: Serialised instance of
+ [InstantiationResponse](https://github.com/onap/policy-clamp/blob/master/models/src/main/java/org/onap/policy/clamp/models/acm/messages/rest/instantiation/InstantiationResponse.java)
+ containing the UUID of the created automation composition instance
+ headers:
+ X-LatestVersion:
+ $ref: '#/components/headers/X-LatestVersion'
+ X-PatchVersion:
+ $ref: '#/components/headers/X-PatchVersion'
+ X-MinorVersion:
+ $ref: '#/components/headers/X-MinorVersion'
+ X-onap-RequestId:
+ $ref: '#/components/headers/X-onap-RequestId'
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/InstantiationResponse'
+ example:
+ externalValue: 'https://raw.githubusercontent.com/onap/policy-clamp/master/runtime-acm/src/main/resources/openapi/examples/postCompositionInstancesResponse.json'
+ application/yaml:
+ schema:
+ $ref: '#/components/schemas/InstantiationResponse'
+ example:
+ externalValue: 'https://raw.githubusercontent.com/onap/policy-clamp/master/runtime-acm/src/main/resources/openapi/examples/postCompositionInstancesResponse.yaml'
+ 401:
+ description: Authentication Error, returns an instance of
+ [SimpleResponse](https://github.com/onap/policy-clamp/blob/master/models/src/main/java/org/onap/policy/clamp/models/acm/messages/rest/SimpleResponse.java)
+ headers:
+ X-LatestVersion:
+ $ref: '#/components/headers/X-LatestVersion'
+ X-PatchVersion:
+ $ref: '#/components/headers/X-PatchVersion'
+ X-MinorVersion:
+ $ref: '#/components/headers/X-MinorVersion'
+ X-onap-RequestId:
+ $ref: '#/components/headers/X-onap-RequestId'
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/SimpleResponse'
+ 404:
+ description: The specified automation composition definition was not found, returns an instance of
+ [SimpleResponse](https://github.com/onap/policy-clamp/blob/master/models/src/main/java/org/onap/policy/clamp/models/acm/messages/rest/SimpleResponse.java)
+ headers:
+ X-LatestVersion:
+ $ref: '#/components/headers/X-LatestVersion'
+ X-PatchVersion:
+ $ref: '#/components/headers/X-PatchVersion'
+ X-MinorVersion:
+ $ref: '#/components/headers/X-MinorVersion'
+ X-onap-RequestId:
+ $ref: '#/components/headers/X-onap-RequestId'
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/SimpleResponse'
+ 400:
+ description: Bad Request, returns an instance of
+ [SimpleResponse](https://github.com/onap/policy-clamp/blob/master/models/src/main/java/org/onap/policy/clamp/models/acm/messages/rest/SimpleResponse.java)
+ headers:
+ X-LatestVersion:
+ $ref: '#/components/headers/X-LatestVersion'
+ X-PatchVersion:
+ $ref: '#/components/headers/X-PatchVersion'
+ X-MinorVersion:
+ $ref: '#/components/headers/X-MinorVersion'
+ X-onap-RequestId:
+ $ref: '#/components/headers/X-onap-RequestId'
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/SimpleResponse'
+ security:
+ - basicAuth: []
+ x-interface info:
+ api-version: 1.0.0
+ last-mod-release: London
+ x-codegen-request-body-name: body
+ /compositions/{compositionId}/instances/{instanceId}:
+ get:
+ tags:
+ - Automation Composition Instance
+ summary: Get automation composition instance details.
+ description: Get details of the requested automation composition instance.
+ operationId: getCompositionInstance
+ parameters:
+ - name : compositionId
+ in: path
+ description: The UUID of the automation composition definition on which to get an instance
+ required: true
+ schema:
+ type: string
+ format: uuid
+ - name : instanceId
+ in: path
+ description: The UUID of the automation composition instance to get
+ required: true
+ schema:
+ type: string
+ format: uuid
+ - name: X-onap-RequestId
+ in: header
+ description: RequestID for http transaction
+ schema:
+ type: string
+ format: uuid
+ responses:
+ 200:
+ description: Serialised instance of
+ [AutomationComposition](https://github.com/onap/policy-clamp/blob/master/models/src/main/java/org/onap/policy/clamp/models/acm/concepts/AutomationComposition.java)
+ containing the automation composition instance
+ headers:
+ X-LatestVersion:
+ $ref: '#/components/headers/X-LatestVersion'
+ X-PatchVersion:
+ $ref: '#/components/headers/X-PatchVersion'
+ X-MinorVersion:
+ $ref: '#/components/headers/X-MinorVersion'
+ X-onap-RequestId:
+ $ref: '#/components/headers/X-onap-RequestId'
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/AutomationComposition'
+ example:
+ externalValue: 'https://raw.githubusercontent.com/onap/policy-clamp/master/runtime-acm/src/main/resources/openapi/examples/getCompositionInstanceResponse.json'
+ application/yaml:
+ schema:
+ $ref: '#/components/schemas/AutomationComposition'
+ example:
+ externalValue: 'https://raw.githubusercontent.com/onap/policy-clamp/master/runtime-acm/src/main/resources/openapi/examples/getCompositionInstanceResponse.yaml'
+ 401:
+ description: Authentication Error, returns an instance of
+ [SimpleResponse](https://github.com/onap/policy-clamp/blob/master/models/src/main/java/org/onap/policy/clamp/models/acm/messages/rest/SimpleResponse.java)
+ headers:
+ X-LatestVersion:
+ $ref: '#/components/headers/X-LatestVersion'
+ X-PatchVersion:
+ $ref: '#/components/headers/X-PatchVersion'
+ X-MinorVersion:
+ $ref: '#/components/headers/X-MinorVersion'
+ X-onap-RequestId:
+ $ref: '#/components/headers/X-onap-RequestId'
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/SimpleResponse'
+ 404:
+ description: The automation composition instance was not found, returns an instance of
+ [SimpleResponse](https://github.com/onap/policy-clamp/blob/master/models/src/main/java/org/onap/policy/clamp/models/acm/messages/rest/SimpleResponse.java)
+ headers:
+ X-LatestVersion:
+ $ref: '#/components/headers/X-LatestVersion'
+ X-PatchVersion:
+ $ref: '#/components/headers/X-PatchVersion'
+ X-MinorVersion:
+ $ref: '#/components/headers/X-MinorVersion'
+ X-onap-RequestId:
+ $ref: '#/components/headers/X-onap-RequestId'
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/SimpleResponse'
+ security:
+ - basicAuth: []
+ x-interface info:
+ api-version: 1.0.0
+ last-mod-release: London
+ put:
+ tags:
+ - Automation Composition Instance
+ summary: Manage deployment and locking of an automation composition instance
+ description: This request manages deployment and locking of an automation composition instance. This endpoint can
+ order deployment and undeployment of an AC Instance to participants and order unlocking and locking of AC instances
+ on participants
+ operationId: compositionInstanceState
+ parameters:
+ - name : compositionId
+ in: path
+ description: The UUID of the automation composition definition on which to update an instance
+ required: true
+ schema:
+ type: string
+ format: uuid
+ - name : instanceId
+ in: path
+ description: The UUID of the automation composition instance to update
+ required: true
+ schema:
+ type: string
+ format: uuid
+ - name: X-onap-RequestId
+ in: header
+ description: RequestID for http transaction
+ schema:
+ type: string
+ format: uuid
+ requestBody:
+ description: Serialised instance of
+ [AcInstanceStateUpdate](https://github.com/onap/policy-clamp/blob/master/models/src/main/java/org/onap/policy/clamp/models/acm/messages/rest/instantiation/AcInstanceStateUpdate.java)
+ which specifies the requested state change on the automation concept instance
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/AcInstanceStateUpdate'
+ example:
+ externalValue: 'https://raw.githubusercontent.com/onap/policy-clamp/master/runtime-acm/src/main/resources/openapi/examples/putAcInstanceStateUpdate.json'
+ application/yaml:
+ schema:
+ $ref: '#/components/schemas/AcInstanceStateUpdate'
+ example:
+ externalValue: 'https://raw.githubusercontent.com/onap/policy-clamp/master/runtime-acm/src/main/resources/openapi/examples/putAcInstanceStateUpdate.yaml'
+ required: true
+ responses:
+ 202:
+ description: Accepted, the request has been accepted and forwarded to participants
+ headers:
+ X-LatestVersion:
+ $ref: '#/components/headers/X-LatestVersion'
+ X-PatchVersion:
+ $ref: '#/components/headers/X-PatchVersion'
+ X-MinorVersion:
+ $ref: '#/components/headers/X-MinorVersion'
+ X-onap-RequestId:
+ $ref: '#/components/headers/X-onap-RequestId'
+ 400:
+ description: Bad Request, returns an instance of
+ [SimpleResponse](https://github.com/onap/policy-clamp/blob/master/models/src/main/java/org/onap/policy/clamp/models/acm/messages/rest/SimpleResponse.java)
+ headers:
+ X-LatestVersion:
+ $ref: '#/components/headers/X-LatestVersion'
+ X-PatchVersion:
+ $ref: '#/components/headers/X-PatchVersion'
+ X-MinorVersion:
+ $ref: '#/components/headers/X-MinorVersion'
+ X-onap-RequestId:
+ $ref: '#/components/headers/X-onap-RequestId'
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/SimpleResponse'
+ 401:
+ description: Authentication Error, returns an instance of
+ [SimpleResponse](https://github.com/onap/policy-clamp/blob/master/models/src/main/java/org/onap/policy/clamp/models/acm/messages/rest/SimpleResponse.java)
+ headers:
+ X-LatestVersion:
+ $ref: '#/components/headers/X-LatestVersion'
+ X-PatchVersion:
+ $ref: '#/components/headers/X-PatchVersion'
+ X-MinorVersion:
+ $ref: '#/components/headers/X-MinorVersion'
+ X-onap-RequestId:
+ $ref: '#/components/headers/X-onap-RequestId'
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/SimpleResponse'
+ 404:
+ description: The specified automation composition instance was not found, returns an instance of
+ [SimpleResponse](https://github.com/onap/policy-clamp/blob/master/models/src/main/java/org/onap/policy/clamp/models/acm/messages/rest/SimpleResponse.java)
+ headers:
+ X-LatestVersion:
+ $ref: '#/components/headers/X-LatestVersion'
+ X-PatchVersion:
+ $ref: '#/components/headers/X-PatchVersion'
+ X-MinorVersion:
+ $ref: '#/components/headers/X-MinorVersion'
+ X-onap-RequestId:
+ $ref: '#/components/headers/X-onap-RequestId'
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/SimpleResponse'
+ security:
+ - basicAuth: []
+ x-interface info:
+ api-version: 1.0.0
+ last-mod-release: London
+ x-codegen-request-body-name: body
+ delete:
+ tags:
+ - Automation Composition Instance
+ summary: Delete an automation composition instance
+ description: Deletes a automation composition instance, returning the UUID of the deleted automation composition instance
+ operationId: deleteCompositionInstance
+ parameters:
+ - name : compositionId
+ in: path
+ description: The UUID of the automation composition definition on which to delete an instance
+ required: true
+ schema:
+ type: string
+ format: uuid
+ - name : instanceId
+ in: path
+ description: The UUID of the automation composition instance to delete
+ required: true
+ schema:
+ type: string
+ format: uuid
+ - name: X-onap-RequestId
+ in: header
+ description: RequestID for http transaction
+ schema:
+ type: string
+ format: uuid
+ responses:
+ 200:
+ description: Serialised instance of
+ [InstantiationResponse](https://github.com/onap/policy-clamp/blob/master/models/src/main/java/org/onap/policy/clamp/models/acm/messages/rest/instantiation/InstantiationResponse.java)
+ containing the UUID of the deleted automation composition instance
+ headers:
+ X-LatestVersion:
+ $ref: '#/components/headers/X-LatestVersion'
+ X-PatchVersion:
+ $ref: '#/components/headers/X-PatchVersion'
+ X-MinorVersion:
+ $ref: '#/components/headers/X-MinorVersion'
+ X-onap-RequestId:
+ $ref: '#/components/headers/X-onap-RequestId'
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/InstantiationResponse'
+ example:
+ externalValue: 'https://raw.githubusercontent.com/onap/policy-clamp/master/runtime-acm/src/main/resources/openapi/examples/deleteCompositionInstanceResponse.json'
+ application/yaml:
+ schema:
+ $ref: '#/components/schemas/InstantiationResponse'
+ example:
+ externalValue: 'https://raw.githubusercontent.com/onap/policy-clamp/master/runtime-acm/src/main/resources/openapi/examples/deleteCompositionInstanceResponse.yaml'
+ 401:
+ description: Authentication Error, returns an instance of
+ [SimpleResponse](https://github.com/onap/policy-clamp/blob/master/models/src/main/java/org/onap/policy/clamp/models/acm/messages/rest/SimpleResponse.java)
+ headers:
+ X-LatestVersion:
+ $ref: '#/components/headers/X-LatestVersion'
+ X-PatchVersion:
+ $ref: '#/components/headers/X-PatchVersion'
+ X-MinorVersion:
+ $ref: '#/components/headers/X-MinorVersion'
+ X-onap-RequestId:
+ $ref: '#/components/headers/X-onap-RequestId'
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/SimpleResponse'
+ 404:
+ description: The specified automation composition instance was not found, returns an instance of
+ [SimpleResponse](https://github.com/onap/policy-clamp/blob/master/models/src/main/java/org/onap/policy/clamp/models/acm/messages/rest/SimpleResponse.java)
+ headers:
+ X-LatestVersion:
+ $ref: '#/components/headers/X-LatestVersion'
+ X-PatchVersion:
+ $ref: '#/components/headers/X-PatchVersion'
+ X-MinorVersion:
+ $ref: '#/components/headers/X-MinorVersion'
+ X-onap-RequestId:
+ $ref: '#/components/headers/X-onap-RequestId'
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/SimpleResponse'
+ 400:
+ description: Bad Request, returns an instance of
+ [SimpleResponse](https://github.com/onap/policy-clamp/blob/master/models/src/main/java/org/onap/policy/clamp/models/acm/messages/rest/SimpleResponse.java)
+ headers:
+ X-LatestVersion:
+ $ref: '#/components/headers/X-LatestVersion'
+ X-PatchVersion:
+ $ref: '#/components/headers/X-PatchVersion'
+ X-MinorVersion:
+ $ref: '#/components/headers/X-MinorVersion'
+ X-onap-RequestId:
+ $ref: '#/components/headers/X-onap-RequestId'
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/SimpleResponse'
+ security:
+ - basicAuth: []
+ x-interface info:
+ api-version: 1.0.0
+ last-mod-release: London
+
+components:
+ securitySchemes:
+ basicAuth:
+ type: http
+ scheme: basic
+ schemas:
+ ParticipantInformation:
+ title: ParticipantInformation
+ type: object
+ ToscaServiceTemplates:
+ title: ToscaServiceTemplates
+ type: object
+ ToscaServiceTemplate:
+ title: ToscaServiceTemplate
+ type: object
+ AutomationCompositionDefinition:
+ title: AutomationCompositionDefinition
+ type: object
+ AutomationComposition:
+ title: AutomationComposition
+ type: object
+ AutomationCompositions:
+ title: AutomationCompositions
+ type: object
+ SimpleResponse:
+ title: SimpleResponse
+ type: object
+ CommissioningResponse:
+ title: CommissioningResponse
+ type: object
+ AcTypeStateUpdate:
+ title: AcTypeStateUpdate
+ type: object
+ AcInstanceStateUpdate:
+ title: AcInstanceStateUpdate
+ type: object
+ InstantiationResponse:
+ title: InstantiationResponse
+ type: object
+ headers:
+ X-LatestVersion:
+ schema:
+ type: string
+ X-PatchVersion:
+ schema:
+ type: string
+ X-MinorVersion:
+ schema:
+ type: string
+ X-onap-RequestId:
+ schema:
+ type: string
+ format: uuid
diff --git a/rapp-manager-application/pom.xml b/rapp-manager-application/pom.xml
new file mode 100755
index 0000000..c88f1fe
--- /dev/null
+++ b/rapp-manager-application/pom.xml
@@ -0,0 +1,162 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>com.oransc</groupId>
+ <artifactId>rappmanager</artifactId>
+ <version>0.0.1-SNAPSHOT</version>
+ </parent>
+
+ <artifactId>rapp-manager-application</artifactId>
+
+ <properties>
+ <maven.compiler.source>${java.version}</maven.compiler.source>
+ <maven.compiler.target>${java.version}</maven.compiler.target>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>com.oransc.rappmanager</groupId>
+ <artifactId>rapp-manager-models</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>com.oransc.rappmanager</groupId>
+ <artifactId>rapp-manager-acm</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>com.oransc.rappmanager</groupId>
+ <artifactId>rapp-manager-sme</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.onap.policy.clamp</groupId>
+ <artifactId>policy-clamp-models</artifactId>
+ <version>6.4.2</version>
+ <exclusions>
+ <exclusion>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-data-jpa</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-aop</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-security</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-validation</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-webflux</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-actuator</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-web</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-cache</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-configuration-processor</artifactId>
+ <optional>true</optional>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework.retry</groupId>
+ <artifactId>spring-retry</artifactId>
+ <version>2.0.1</version>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework.statemachine</groupId>
+ <artifactId>spring-statemachine-core</artifactId>
+ <version>3.2.1</version>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework.statemachine</groupId>
+ <artifactId>spring-statemachine-test</artifactId>
+ <version>3.2.1</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.aspectj</groupId>
+ <artifactId>aspectjweaver</artifactId>
+ <scope>compile</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.projectlombok</groupId>
+ <artifactId>lombok</artifactId>
+ <optional>true</optional>
+ </dependency>
+ <dependency>
+ <groupId>org.openapitools</groupId>
+ <artifactId>jackson-databind-nullable</artifactId>
+ <version>0.2.6</version>
+ </dependency>
+ <!-- Bean Validation API support -->
+ <dependency>
+ <groupId>javax.validation</groupId>
+ <artifactId>validation-api</artifactId>
+ <version>2.0.1.Final</version>
+ </dependency>
+ <dependency>
+ <groupId>javax.annotation</groupId>
+ <artifactId>javax.annotation-api</artifactId>
+ <version>1.3.2</version>
+ </dependency>
+ <dependency>
+ <groupId>io.swagger.core.v3</groupId>
+ <artifactId>swagger-annotations</artifactId>
+ <version>2.2.9</version>
+ </dependency>
+ <dependency>
+ <groupId>io.swagger.core.v3</groupId>
+ <artifactId>swagger-models</artifactId>
+ <version>2.2.9</version>
+ </dependency>
+ <dependency>
+ <groupId>javax.servlet</groupId>
+ <artifactId>servlet-api</artifactId>
+ <version>2.5</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-test</artifactId>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-maven-plugin</artifactId>
+ <configuration>
+ <excludes>
+ <exclude>
+ <groupId>org.projectlombok</groupId>
+ <artifactId>lombok</artifactId>
+ </exclude>
+ </excludes>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+</project>
\ No newline at end of file
diff --git a/rapp-manager-application/src/main/java/com/oransc/rappmanager/BeanConfiguration.java b/rapp-manager-application/src/main/java/com/oransc/rappmanager/BeanConfiguration.java
new file mode 100755
index 0000000..0fd2dfa
--- /dev/null
+++ b/rapp-manager-application/src/main/java/com/oransc/rappmanager/BeanConfiguration.java
@@ -0,0 +1,110 @@
+/*-
+ * ============LICENSE_START======================================================================
+ * Copyright (C) 2023 Nordix Foundation. 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END========================================================================
+ */
+
+package com.oransc.rappmanager;
+
+import com.oransc.rappmanager.acm.ApiClient;
+import com.oransc.rappmanager.acm.configuration.ACMConfiguration;
+import com.oransc.rappmanager.acm.rest.AutomationCompositionDefinitionApiClient;
+import com.oransc.rappmanager.acm.rest.AutomationCompositionInstanceApiClient;
+import com.oransc.rappmanager.acm.rest.ParticipantMonitoringApiClient;
+import com.oransc.rappmanager.sme.configuration.SmeConfiguration;
+import com.oransc.rappmanager.sme.provider.rest.DefaultApiClient;
+import lombok.RequiredArgsConstructor;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.boot.web.client.RestTemplateBuilder;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.client.RestTemplate;
+
+@Configuration
+@RequiredArgsConstructor
+public class BeanConfiguration {
+
+ private final ACMConfiguration acmConfiguration;
+ private final SmeConfiguration smeConfiguration;
+
+ @Bean
+ public RestTemplate restTemplate(RestTemplateBuilder builder) {
+ return builder.build();
+ }
+
+ @Bean("acmApiClient")
+ public ApiClient acmApiClient(RestTemplate restTemplate) {
+ ApiClient apiClient = new ApiClient(restTemplate);
+ // apiClient.setDebugging(true);
+ apiClient.setUsername(acmConfiguration.getUsername());
+ apiClient.setPassword(acmConfiguration.getPassword());
+ return apiClient.setBasePath(acmConfiguration.getBaseUrl());
+ }
+
+ @Bean("smeProviderApiClient")
+ public com.oransc.rappmanager.sme.provider.ApiClient smeProviderApiClient(RestTemplate restTemplate) {
+ return new com.oransc.rappmanager.sme.provider.ApiClient(restTemplate);
+ }
+
+ @Bean("smePublishServiceApiClient")
+ public com.oransc.rappmanager.sme.publishservice.ApiClient smePublishServiceApiClient(RestTemplate restTemplate) {
+ return new com.oransc.rappmanager.sme.publishservice.ApiClient(restTemplate);
+ }
+
+ @Bean("smeInvokerApiClient")
+ public com.oransc.rappmanager.sme.invoker.ApiClient smeInvokerApiClient(RestTemplate restTemplate) {
+ return new com.oransc.rappmanager.sme.invoker.ApiClient(restTemplate);
+ }
+
+ @Bean
+ public ParticipantMonitoringApiClient participantMonitoringApiClient(
+ @Qualifier("acmApiClient") ApiClient apiClient) {
+ return new ParticipantMonitoringApiClient(apiClient);
+ }
+
+ @Bean
+ public AutomationCompositionDefinitionApiClient automationCompositionDefinitionApiClient(
+ @Qualifier("acmApiClient") ApiClient apiClient) {
+ return new AutomationCompositionDefinitionApiClient(apiClient);
+ }
+
+ @Bean
+ public AutomationCompositionInstanceApiClient automationCompositionInstanceApiClient(
+ @Qualifier("acmApiClient") ApiClient apiClient) {
+ return new AutomationCompositionInstanceApiClient(apiClient);
+ }
+
+ @Bean
+ public DefaultApiClient defaultProviderApiClient(
+ @Qualifier("smeProviderApiClient") com.oransc.rappmanager.sme.provider.ApiClient apiClient) {
+ apiClient.setBasePath(smeConfiguration.getBaseUrl() + smeConfiguration.getProviderBasePath());
+ return new DefaultApiClient(apiClient);
+ }
+
+ @Bean
+ public com.oransc.rappmanager.sme.publishservice.rest.DefaultApiClient defaultPublishServiceApiClient(
+ @Qualifier("smePublishServiceApiClient") com.oransc.rappmanager.sme.publishservice.ApiClient apiClient) {
+ apiClient.setBasePath(smeConfiguration.getBaseUrl() + smeConfiguration.getPublishApiBasePath());
+ return new com.oransc.rappmanager.sme.publishservice.rest.DefaultApiClient(apiClient);
+ }
+
+ @Bean
+ public com.oransc.rappmanager.sme.invoker.rest.DefaultApiClient defaultInvokerApiClient(
+ @Qualifier("smeInvokerApiClient") com.oransc.rappmanager.sme.invoker.ApiClient apiClient) {
+ apiClient.setBasePath(smeConfiguration.getBaseUrl() + smeConfiguration.getInvokerBasePath());
+ return new com.oransc.rappmanager.sme.invoker.rest.DefaultApiClient(apiClient);
+ }
+
+}
diff --git a/rapp-manager-application/src/main/java/com/oransc/rappmanager/RappManagerApplication.java b/rapp-manager-application/src/main/java/com/oransc/rappmanager/RappManagerApplication.java
new file mode 100755
index 0000000..94f865a
--- /dev/null
+++ b/rapp-manager-application/src/main/java/com/oransc/rappmanager/RappManagerApplication.java
@@ -0,0 +1,37 @@
+/*-
+ * ============LICENSE_START======================================================================
+ * Copyright (C) 2023 Nordix Foundation. 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END========================================================================
+ */
+
+package com.oransc.rappmanager;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.cache.annotation.EnableCaching;
+import org.springframework.retry.annotation.EnableRetry;
+
+@SpringBootApplication
+@EnableConfigurationProperties
+@EnableCaching
+@EnableRetry
+public class RappManagerApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(RappManagerApplication.class, args);
+ }
+
+}
diff --git a/rapp-manager-application/src/main/java/com/oransc/rappmanager/WriteCsarFile.java b/rapp-manager-application/src/main/java/com/oransc/rappmanager/WriteCsarFile.java
new file mode 100755
index 0000000..c421486
--- /dev/null
+++ b/rapp-manager-application/src/main/java/com/oransc/rappmanager/WriteCsarFile.java
@@ -0,0 +1,95 @@
+/*-
+ * ============LICENSE_START======================================================================
+ * Copyright (C) 2023 Nordix Foundation. 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END========================================================================
+ */
+
+package com.oransc.rappmanager;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipOutputStream;
+
+public class WriteCsarFile {
+
+ public static void main(String[] args) {
+ String zipFileName =
+ "rapp-manager-application\\src\\main\\resources\\resource-csar\\rapp.csar";
+ String csarPath =
+ "rapp-manager-application\\src\\main\\resources\\resource-csar";
+
+ try {
+ FileOutputStream fos = new FileOutputStream(zipFileName);
+ ZipOutputStream zos = new ZipOutputStream(fos);
+
+ File directory = new File(csarPath);
+ System.out.println("Is directory " + directory.isDirectory());
+ List<File> fileList = new ArrayList<>();
+ getFiles(directory, directory, fileList);
+ File[] files = fileList.toArray(new File[0]);
+ System.out.println("File size :" + files.length);
+ Arrays.sort(files, Collections.reverseOrder());
+
+
+ for (File file : files) {
+ System.out.println("Processing " + file.getPath());
+ if (!file.isDirectory()) {
+ System.out.println("Processing " + file.getPath());
+ FileInputStream fis = new FileInputStream(csarPath + File.separator + file.getPath());
+
+ ZipEntry zipEntry = new ZipEntry(file.getPath().replaceAll("\\\\", "/"));
+ zos.putNextEntry(zipEntry);
+
+ byte[] bytes = new byte[1024];
+ int length;
+ while ((length = fis.read(bytes)) >= 0) {
+ zos.write(bytes, 0, length);
+ }
+ fis.close();
+ } else {
+ System.out.println("Not a file: " + file.getPath());
+ }
+ }
+
+ zos.close();
+ fos.close();
+
+ System.out.println("Zip file created successfully!");
+
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ private static void getFiles(File baseDirectory, File directory, List<File> fileList) {
+ File[] files = directory.listFiles();
+ if (files != null) {
+ for (File file : files) {
+ if (file.isDirectory()) {
+ getFiles(baseDirectory, file, fileList);
+ } else {
+ fileList.add(new File(file.getPath().replace(baseDirectory.getPath() + File.separator, "")));
+ }
+ }
+ }
+ }
+}
diff --git a/rapp-manager-application/src/main/java/com/oransc/rappmanager/configuration/RappManagerConfiguration.java b/rapp-manager-application/src/main/java/com/oransc/rappmanager/configuration/RappManagerConfiguration.java
new file mode 100755
index 0000000..85d3498
--- /dev/null
+++ b/rapp-manager-application/src/main/java/com/oransc/rappmanager/configuration/RappManagerConfiguration.java
@@ -0,0 +1,31 @@
+/*-
+ * ============LICENSE_START======================================================================
+ * Copyright (C) 2023 Nordix Foundation. 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END========================================================================
+ */
+
+package com.oransc.rappmanager.configuration;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+@ConfigurationProperties(prefix = "rappmanager")
+@Data
+public class RappManagerConfiguration {
+
+ String csarLocation;
+}
diff --git a/rapp-manager-application/src/main/java/com/oransc/rappmanager/exception/ACMInvalidStateTransitionException.java b/rapp-manager-application/src/main/java/com/oransc/rappmanager/exception/ACMInvalidStateTransitionException.java
new file mode 100755
index 0000000..efc7175
--- /dev/null
+++ b/rapp-manager-application/src/main/java/com/oransc/rappmanager/exception/ACMInvalidStateTransitionException.java
@@ -0,0 +1,29 @@
+/*-
+ * ============LICENSE_START======================================================================
+ * Copyright (C) 2023 Nordix Foundation. 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END========================================================================
+ */
+
+package com.oransc.rappmanager.exception;
+
+public class ACMInvalidStateTransitionException extends RuntimeException {
+ public ACMInvalidStateTransitionException() {
+ super();
+ }
+
+ public ACMInvalidStateTransitionException(String targetState, String actualState) {
+ super();
+ }
+}
diff --git a/rapp-manager-application/src/main/java/com/oransc/rappmanager/rest/OnboardingController.java b/rapp-manager-application/src/main/java/com/oransc/rappmanager/rest/OnboardingController.java
new file mode 100755
index 0000000..6742686
--- /dev/null
+++ b/rapp-manager-application/src/main/java/com/oransc/rappmanager/rest/OnboardingController.java
@@ -0,0 +1,131 @@
+/*-
+ * ============LICENSE_START======================================================================
+ * Copyright (C) 2023 Nordix Foundation. 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END========================================================================
+ */
+
+package com.oransc.rappmanager.rest;
+
+import com.oransc.rappmanager.acm.service.AcmDeployer;
+import com.oransc.rappmanager.configuration.RappManagerConfiguration;
+import com.oransc.rappmanager.models.Rapp;
+import com.oransc.rappmanager.models.RappCsarConfigurationHandler;
+import com.oransc.rappmanager.models.RappEvent;
+import com.oransc.rappmanager.models.RappState;
+import com.oransc.rappmanager.models.cache.RappCacheService;
+import com.oransc.rappmanager.models.statemachine.RappStateMachine;
+import com.oransc.rappmanager.sme.service.SmeDeployer;
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.StandardCopyOption;
+import java.util.Optional;
+import lombok.RequiredArgsConstructor;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.cache.Cache;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestPart;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.multipart.MultipartFile;
+
+@RestController
+@RequestMapping(path = "rapps")
+@RequiredArgsConstructor
+public class OnboardingController {
+
+ Logger logger = LoggerFactory.getLogger(OnboardingController.class);
+ private final RappCsarConfigurationHandler rappCsarConfigurationHandler;
+ private final AcmDeployer acmDeployer;
+ private final SmeDeployer smeDeployer;
+ private final RappManagerConfiguration rappManagerConfiguration;
+ private final RappStateMachine rappStateMachine;
+ private final RappCacheService rappCacheService;
+
+
+ @GetMapping
+ public ResponseEntity<Cache> getRapps() {
+ return ResponseEntity.ok(rappCacheService.getAllRapp());
+ }
+
+ @GetMapping("{rapp_id}")
+ public ResponseEntity<Rapp> getRapps(@PathVariable("rapp_id") String rappId) {
+ Optional<Rapp> rappOptional = rappCacheService.getRapp(rappId);
+ if (rappOptional.isPresent()) {
+ acmDeployer.syncRappStatus(rappOptional.get());
+ return ResponseEntity.ok(rappCacheService.getRapp(rappId).get());
+ }
+ return ResponseEntity.badRequest().build();
+ }
+
+ @PostMapping("{rapp_id}/onboard")
+ public ResponseEntity<Object> uploadRappCsarFile(@PathVariable("rapp_id") String rappId,
+ @RequestPart("file") MultipartFile csarFilePart) throws IOException {
+ if (rappCsarConfigurationHandler.isValidRappPackage(csarFilePart)) {
+ File csarFile = new File(
+ rappCsarConfigurationHandler.getRappPackageLocation(rappManagerConfiguration.getCsarLocation(),
+ rappId, csarFilePart.getOriginalFilename()).toUri());
+ csarFile.getParentFile().mkdirs();
+ Files.copy(csarFilePart.getInputStream(), csarFile.getAbsoluteFile().toPath(),
+ StandardCopyOption.REPLACE_EXISTING);
+ Rapp rapp = Rapp.builder().name(rappId).packageLocation(rappManagerConfiguration.getCsarLocation())
+ .packageName(csarFile.getName()).state(RappState.ONBOARDED).build();
+ rappCacheService.putRapp(rapp);
+ rappStateMachine.onboardRapp(rapp.getRappId());
+ return ResponseEntity.accepted().build();
+ } else {
+ logger.info("Invalid Rapp package for {}", rappId);
+ return ResponseEntity.badRequest().build();
+ }
+ }
+
+ @PostMapping("{rapp_id}/deploy")
+ public ResponseEntity<?> deployRapp(@PathVariable("rapp_id") String rappId) {
+ Optional<Rapp> rappOptional = rappCacheService.getRapp(rappId);
+ rappOptional.ifPresent(rapp -> {
+ rappStateMachine.sendRappEvent(rapp, RappEvent.DEPLOYING);
+ });
+ if (rappOptional.isPresent() && acmDeployer.deployRapp(rappOptional.get()) && smeDeployer.deployRapp(
+ rappOptional.get())) {
+ return ResponseEntity.accepted().build();
+ }
+ return ResponseEntity.internalServerError().build();
+ }
+
+ @PostMapping("{rapp_id}/undeploy")
+ public ResponseEntity<?> undeployRapp(@PathVariable("rapp_id") String rappId) {
+ Optional<Rapp> rappOptional = rappCacheService.getRapp(rappId);
+ rappOptional.ifPresent(rapp -> {
+ rappStateMachine.sendRappEvent(rapp, RappEvent.UNDEPLOYING);
+ });
+ if (rappOptional.isPresent() && acmDeployer.undeployRapp(rappOptional.get()) && smeDeployer.undeployRapp(
+ rappOptional.get())) {
+ rappCacheService.deleteRapp(rappOptional.get());
+ rappStateMachine.deleteRapp(rappOptional.get());
+ return ResponseEntity.accepted().build();
+ }
+ return ResponseEntity.internalServerError().build();
+ }
+
+ @GetMapping("info")
+ public ResponseEntity<Object> getInfo() {
+ return ResponseEntity.ok(acmDeployer.getAllParticipants());
+ }
+
+}
diff --git a/rapp-manager-application/src/main/resources/application.yaml b/rapp-manager-application/src/main/resources/application.yaml
new file mode 100755
index 0000000..445297a
--- /dev/null
+++ b/rapp-manager-application/src/main/resources/application.yaml
@@ -0,0 +1,30 @@
+rappmanager:
+ csarlocation: src/main/resources/csar
+ acm:
+ baseurl: http://10.101.2.254:30442/onap/policy/clamp/acm/v2/
+ username: runtimeUser
+ password: zb!XztG34
+ compositionDefinitionLocation: src/main/resources/compositiondefinition.json
+ maxRetries: 3
+ retryInterval: 2 #seconds
+ sme:
+ baseurl: http://10.101.2.254:30232
+ providerBasePath: /api-provider-management/v1/
+ invokerBasePath: /api-invoker-management/v1/
+ publishApiBasePath: /published-apis/v1/
+ maxRetries: 3
+ retryInterval: 2 #seconds
+
+logging:
+ level:
+ root: INFO
+ com.oransc.rapps: DEBUG
+ org.apache.http: DEBUG
+ httpclient.wire: DEBUG
+ org.springframework.web.client.RestTemplate: TRACE
+
+management:
+ endpoints:
+ web:
+ exposure:
+ include: "*"
\ No newline at end of file
diff --git a/rapp-manager-application/src/main/resources/compositiondefinition.json b/rapp-manager-application/src/main/resources/compositiondefinition.json
new file mode 100755
index 0000000..bc568ad
--- /dev/null
+++ b/rapp-manager-application/src/main/resources/compositiondefinition.json
@@ -0,0 +1,320 @@
+{
+ "tosca_definitions_version": "tosca_simple_yaml_1_3",
+ "data_types": {
+ "onap.datatypes.ToscaConceptIdentifier": {
+ "derived_from": "tosca.datatypes.Root",
+ "properties": {
+ "name": {
+ "type": "string",
+ "required": true
+ },
+ "version": {
+ "type": "string",
+ "required": true
+ }
+ }
+ },
+ "org.onap.datatypes.policy.clamp.acm.kserveAutomationCompositionElement.KserveInferenceEntity": {
+ "version": "1.0.0",
+ "derived_from": "tosca.datatypes.Root",
+ "properties": {
+ "kserveEntityId": {
+ "type": "onap.datatypes.ToscaConceptIdentifier",
+ "required": true,
+ "description": "The name and version of a Configuration Entity to be handled by the Kserve Automation Composition Element"
+ },
+ "name": {
+ "type": "string",
+ "required": true,
+ "description": "Inference service name to be created"
+ },
+ "payload": {
+ "type": "string",
+ "required": true,
+ "description": "Inference Service payload"
+ }
+ }
+ },
+ "org.onap.datatypes.policy.clamp.acm.a1pmsAutomationCompositionElement.A1PolicyServiceEntity": {
+ "version": "1.0.0",
+ "derived_from": "tosca.datatypes.Root",
+ "properties": {
+ "a1PolicyServiceEntityId": {
+ "type": "onap.datatypes.ToscaConceptIdentifier",
+ "required": true,
+ "description": "The name and version of a Configuration Entity to be handled by the A1 PMS Automation Composition Element"
+ },
+ "clientId": {
+ "type": "string",
+ "required": true,
+ "description": "Client Id to be created"
+ },
+ "callbackUrl": {
+ "type": "string",
+ "required": true,
+ "description": "The callback URL to get registered"
+ },
+ "keepAliveIntervalSeconds": {
+ "type": "integer",
+ "required": true,
+ "description": "Keep alive interval time for the callback URL"
+ }
+ }
+ }
+ },
+ "node_types": {
+ "org.onap.policy.clamp.acm.Participant": {
+ "version": "1.0.1",
+ "derived_from": "tosca.nodetypes.Root",
+ "properties": {
+ "provider": {
+ "type": "string",
+ "required": false
+ }
+ }
+ },
+ "org.onap.policy.clamp.acm.AutomationCompositionElement": {
+ "version": "1.0.1",
+ "derived_from": "tosca.nodetypes.Root",
+ "properties": {
+ "provider": {
+ "type": "string",
+ "required": false
+ },
+ "participantType": {
+ "type": "onap.datatypes.ToscaConceptIdentifier",
+ "required": true
+ },
+ "startPhase": {
+ "type": "integer",
+ "required": false,
+ "constraints": [
+ {
+ "greater-or-equal": 0
+ }
+ ],
+ "metadata": {
+ "common": true
+ },
+ "description": "A value indicating the start phase in which this automation composition element will be started, the first start phase is zero. Automation Composition Elements are started in their start_phase order and stopped in reverse start phase order. Automation Composition Elements with the same start phase are started and stopped simultaneously"
+ },
+ "passiveToRunningTimeout": {
+ "type": "integer",
+ "required": false,
+ "constraints": [
+ {
+ "greater_or_equal": 0
+ }
+ ],
+ "default": 60,
+ "metadata": {
+ "common": true
+ },
+ "description": "The maximum time in seconds to wait for a state chage from passive to running"
+ },
+ "runningToPassiveTimeout": {
+ "type": "integer",
+ "required": false,
+ "constraints": [
+ {
+ "greater_or_equal": 0
+ }
+ ],
+ "default": 60,
+ "metadata": {
+ "common": true
+ },
+ "description": "The maximum time in seconds to wait for a state chage from running to passive"
+ },
+ "passiveToUninitializedTimeout": {
+ "type": "integer",
+ "required": false,
+ "constraints": [
+ {
+ "greater_or_equal": 0
+ }
+ ],
+ "default": 60,
+ "metadata": {
+ "common": true
+ },
+ "description": "The maximum time in seconds to wait for a state chage from passive to uninitialized"
+ }
+ }
+ },
+ "org.onap.policy.clamp.acm.AutomationComposition": {
+ "version": "1.0.1",
+ "derived_from": "tosca.nodetypes.Root",
+ "properties": {
+ "provider": {
+ "type": "string",
+ "required": false,
+ "metadata": {
+ "common": true
+ }
+ },
+ "elements": {
+ "type": "list",
+ "required": true,
+ "metadata": {
+ "common": true
+ },
+ "entry_schema": {
+ "type": "onap.datatypes.ToscaConceptIdentifier"
+ }
+ }
+ }
+ },
+ "org.onap.policy.clamp.acm.KserveAutomationCompositionElement": {
+ "version": "1.0.1",
+ "derived_from": "org.onap.policy.clamp.acm.AutomationCompositionElement",
+ "properties": {
+ "kserveInferenceEntities": {
+ "type": "list",
+ "required": true,
+ "entry_schema": {
+ "type": "org.onap.datatypes.policy.clamp.acm.kserveAutomationCompositionElement.KserveInferenceEntity",
+ "type_version": "1.0.0"
+ },
+ "description": "The configuration entities of Kserve inference service"
+ }
+ }
+ },
+ "org.onap.policy.clamp.acm.A1PMSAutomationCompositionElement": {
+ "version": "1.0.1",
+ "derived_from": "org.onap.policy.clamp.acm.AutomationCompositionElement",
+ "properties": {
+ "policyServiceEntities": {
+ "type": "list",
+ "required": true,
+ "entry_schema": {
+ "type": "org.onap.datatypes.policy.clamp.acm.a1pmsAutomationCompositionElement.A1PolicyServiceEntity",
+ "type_version": "1.0.0"
+ },
+ "description": "The configuration entities of A1 policy services"
+ }
+ }
+ },
+ "org.onap.policy.clamp.acm.K8SMicroserviceAutomationCompositionElement": {
+ "version": "1.0.0",
+ "derived_from": "org.onap.policy.clamp.acm.AutomationCompositionElement",
+ "properties": {
+ "chart": {
+ "type": "string",
+ "required": true
+ },
+ "configs": {
+ "type": "list",
+ "required": false
+ },
+ "requirements": {
+ "type": "string",
+ "required": false
+ },
+ "templates": {
+ "type": "list",
+ "required": false,
+ "entry_schema": null
+ },
+ "values": {
+ "type": "string",
+ "required": true
+ }
+ }
+ }
+ },
+ "topology_template": {
+ "node_templates": {
+ "org.onap.policy.clamp.acm.KserveParticipant": {
+ "version": "2.3.4",
+ "type": "org.onap.policy.clamp.acm.Participant",
+ "type_version": "1.0.1",
+ "description": "Participant for Kserve requests",
+ "properties": {
+ "provider": "ONAP"
+ }
+ },
+ "org.onap.policy.clamp.acm.A1PMSAutomationCompositionParticipant": {
+ "version": "2.3.4",
+ "type": "org.onap.policy.clamp.acm.Participant",
+ "type_version": "1.0.1",
+ "description": "Participant for A1 PMS requests",
+ "properties": {
+ "provider": "ONAP"
+ }
+ },
+ "org.onap.k8s.acm.K8SAutomationCompositionParticipant": {
+ "version": "2.3.4",
+ "type": "org.onap.policy.clamp.acm.Participant",
+ "type_version": "1.0.1",
+ "description": "Participant for K8S",
+ "properties": {
+ "provider": "ONAP"
+ }
+ },
+ "onap.policy.clamp.ac.element.KserveAutomationCompositionElement": {
+ "version": "1.2.3",
+ "type": "org.onap.policy.clamp.acm.KserveAutomationCompositionElement",
+ "type_version": "1.0.1",
+ "description": "Automation composition element for the Kserve Requests",
+ "properties": {
+ "provider": "ONAP",
+ "participantType": {
+ "name": "org.onap.policy.clamp.acm.KserveParticipant",
+ "version": "2.3.4"
+ },
+ "uninitializedToPassiveTimeout": 60,
+ "statusCheckInterval": 30
+ }
+ },
+ "onap.policy.clamp.ac.element.A1PMSAutomationCompositionElement": {
+ "version": "1.2.3",
+ "type": "org.onap.policy.clamp.acm.A1PMSAutomationCompositionElement",
+ "type_version": "1.0.1",
+ "description": "Automation composition element for the A1 PMS Requests",
+ "properties": {
+ "provider": "ONAP",
+ "participantType": {
+ "name": "org.onap.policy.clamp.acm.A1PMSParticipant",
+ "version": "2.3.4"
+ }
+ }
+ },
+ "onap.policy.clamp.ac.element.K8S_StarterAutomationCompositionElement": {
+ "version": "1.2.3",
+ "type": "org.onap.policy.clamp.acm.K8SMicroserviceAutomationCompositionElement",
+ "type_version": "1.0.0",
+ "description": "Automation composition element for the K8S microservice for AC Element Starter",
+ "properties": {
+ "provider": "ONAP",
+ "startPhase": 0,
+ "uninitializedToPassiveTimeout": 300,
+ "podStatusCheckInterval": 30
+ }
+ },
+ "onap.policy.clamp.ac.element.AutomationCompositionDefinition": {
+ "version": "1.2.3",
+ "type": "org.onap.policy.clamp.acm.AutomationComposition",
+ "type_version": "1.0.1",
+ "description": "Automation composition for rapp deployment",
+ "properties": {
+ "provider": "ONAP",
+ "elements": [
+ {
+ "name": "onap.policy.clamp.ac.element.KserveAutomationCompositionElement",
+ "version": "1.2.3"
+ },
+ {
+ "name": "onap.policy.clamp.ac.element.A1PMSAutomationCompositionElement",
+ "version": "1.2.3"
+ },
+ {
+ "name": "onap.policy.clamp.ac.element.K8S_StarterAutomationCompositionElement",
+ "version": "1.2.3"
+ }
+ ]
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/rapp-manager-application/src/main/resources/resource-csar/Artifacts/Deployment/HELM/free5gc-1.1.3.tgz b/rapp-manager-application/src/main/resources/resource-csar/Artifacts/Deployment/HELM/free5gc-1.1.3.tgz
new file mode 100755
index 0000000..df0a584
--- /dev/null
+++ b/rapp-manager-application/src/main/resources/resource-csar/Artifacts/Deployment/HELM/free5gc-1.1.3.tgz
Binary files differ
diff --git a/rapp-manager-application/src/main/resources/resource-csar/Artifacts/Deployment/HELM/ueransim-2.0.14.tgz b/rapp-manager-application/src/main/resources/resource-csar/Artifacts/Deployment/HELM/ueransim-2.0.14.tgz
new file mode 100755
index 0000000..bc9dec2
--- /dev/null
+++ b/rapp-manager-application/src/main/resources/resource-csar/Artifacts/Deployment/HELM/ueransim-2.0.14.tgz
Binary files differ
diff --git a/rapp-manager-application/src/main/resources/resource-csar/Definitions/asd.yaml b/rapp-manager-application/src/main/resources/resource-csar/Definitions/asd.yaml
new file mode 100755
index 0000000..39ce4ed
--- /dev/null
+++ b/rapp-manager-application/src/main/resources/resource-csar/Definitions/asd.yaml
@@ -0,0 +1,112 @@
+tosca_definitions_version: tosca_simple_yaml_1_2
+
+description: First drop of free5gc and ueransim ASD
+
+imports:
+ - asd_types.yaml
+
+topology_template:
+ node_templates:
+ applicationServiceDescriptor:
+ type: tosca.nodes.asd
+ description: "Free5gc"
+ properties:
+ descriptor_id: 123e4567-e89b-12d3-a456-426614174000
+ descriptor_invariant_id: 123e4yyy-e89b-12d3-a456-426614174abc
+ descriptor_version: 1.0
+ schema_version: 2.0
+ function_description: free5gc description
+ provider: EST
+ application_name: free5gc-app
+ application_version: 2.3
+ ext_cpds:
+ - id: 1
+ description: webpage-service
+ virtual_link_requirement: endUser
+ network_interface_realization_requirements:
+ trunk_mode: false
+ ipam: orchestrated
+ interface_type: direct.userdriver
+ interface_option:
+ - virtio
+ - memif
+ interface_redundancy: actPassBond
+ nic_options:
+ - nic id1
+ - nic id2
+ input_param_mappings:
+ loadbalancer_IP: 1.2.3.4
+ external_IPs:
+ - 5.6.7.8
+ - 10.11.12.13
+ nad_names:
+ - nad name 1
+ - nad name 2
+ nad_namespace: myNamespace
+ resource_mapping: my resource manifest
+ - id: 2
+ description: transactionAPI
+ virtual_link_requirement: backhaul
+ network_interface_realization_requirements:
+ trunk_mode: true
+ ipam: orchestrated
+ interface_type: direct.userdriver
+ interface_option:
+ - virtio
+ interface_redundancy: actPassBond
+ nic_options:
+ - nic id3
+ - nic id4
+ input_param_mappings:
+ loadbalancer_IP: 192.168.1.0
+ external_IPs:
+ - 192.168.1.1
+ - 192.168.1.2
+ nad_names:
+ - nad name 3
+ - nad name 4
+ nad_namespace: myNamespace2
+ resource_mapping: my resource manifest
+ enhanced_cluster_capabilities:
+ min_kernel_version: 1.2.3
+ required_kernel_modules:
+ - ip6_tables
+ - cryptd
+ conflicting_kernel_modules:
+ - nf_nat
+ required_custom_resources:
+ - kind: myKind
+ api_version: myVersion
+ - kind: mySecondKind
+ api_version: mySecondVersion
+ cluster_labels:
+ - label 1
+ - label 2
+ required_plugin:
+ - name: plugin1Name
+ version: 1.2.3
+ - name: plugin2Name
+ version: 4.5.6
+ artifacts:
+ free5gc:
+ type: tosca.artifacts.asd.deploymentItem
+ file: "Artifacts/Deployment/HELM/free5gc-1.1.3.tgz"
+ properties:
+ artifact_type: "helm_chart"
+ itemId: 1
+ deployment_order: 1
+ lifecycle_parameters:
+ - ".Values.global.n2network.masterIf"
+ - ".Values.global.n3network.masterIf"
+ - ".Values.global.n4network.masterIf"
+ - ".Values.global.n6network.masterIf"
+ ueransim-free5gc:
+ type: tosca.artifacts.asd.deploymentItem
+ file: "Artifacts/Deployment/HELM/ueransim-2.0.14.tgz"
+ properties:
+ artifact_type: "helm_chart"
+ itemId: 2
+ deployment_order: 2
+ lifecycle_parameters:
+ - ".Values.global.n2network.masterIf"
+ - ".Values.global.n3network.masterIf"
diff --git a/rapp-manager-application/src/main/resources/resource-csar/Definitions/asd_types.yaml b/rapp-manager-application/src/main/resources/resource-csar/Definitions/asd_types.yaml
new file mode 100755
index 0000000..b004aa2
--- /dev/null
+++ b/rapp-manager-application/src/main/resources/resource-csar/Definitions/asd_types.yaml
@@ -0,0 +1,448 @@
+tosca_definitions_version: tosca_simple_yaml_1_2
+description: ASD types definitions version 0.1
+data_types:
+tosca.datatypes.asd.networkInterfaceRequirements:
+ derived_from: tosca.datatypes.Root
+ version: 0.1
+ description: "Describes the datatype for network interface requirements"
+ properties:
+ trunk_mode:
+ description: >
+ Information about whether the CP instantiated from this Cp is
+ in Trunk mode (802.1Q or other). When operating in "trunk mode",
+ the Cp is capable of carrying traffic for several VLANs.
+ Absence of this property implies that trunkMode is not configured
+ for the Cp i.e. It is equivalent to boolean value "false".
+ required: true
+ type: boolean
+ default: false
+ ipam:
+ description: >
+ Identifies whether application expects IP address assignment to be
+ managed by the cluster infrastructure (CNI IPAM plugin), or
+ configured by orchestrator via for example helm input parameter,
+ or if IP assignment is handled by the application itself.
+ required: true
+ type: string
+ constraints:
+ - valid_values: ["infraProvided", "orchestrated", "userManaged"]
+ default: "infraProvided"
+ interface_type:
+ description: >
+ Indicates what type of network interface the application expects.
+ Kernel based virtual netdev based on CNIs such as ovs | bridge |
+ macvlan | ipvlan, or PCIe dev directly visible in application
+ namespace with kernel or userspace driver or bonded with the Bond
+ CNI, or userspace-CNI based network interface
+ (requires DPDK-OVS/VPP vSwitch).
+ required: true
+ type: string
+ constraints:
+ - valid_values: ["kernel.netdev", "direct.userdriver", "direct.kerneldriver", "direct.bond", "userspace"]
+ default: "kernel.netdev"
+ interface_option:
+ description: >
+ This attribute describes verified realization options for the
+ network interface in question. Currently listed options
+ (virtio and memif) are applicable for the interfaceType “userspace”.
+ required: false
+ type: list
+ entry_schema:
+ type: string
+ constraints:
+ - valid_values: ["virtio", "memif"]
+ interface_redundancy:
+ description: >
+ Identifies switch-plane redundancy method the application uses,
+ and that node infrastructure is required to comply with.
+ "infraProvided", “left” and “right”: The container sees a
+ single vNIC that a) the infrastructure bonds over both switchplanes
+ or b) that is connected to the network via only left or
+ right the switchplane.
+ The other cases are for a mated pair of vnics connecting to
+ same network, but where one vNIC connects
+ via left switch plane and the other via right switch plane,
+ and where the application manages the redundancy.
+ "activePassiveBond": the application bonds with move of MAC address.
+ "activeActiveBond“: bonded left/right links must be part of a multi-chassis LAG
+ "activePassiveL3": application will move application IP address between the vNICs.
+ "activeActiveL3": the application uses anycast/ECMP.
+ required: true
+ type: string
+ constraints:
+ - valid_values: ["infraProvided", "actPassBond", "actActBond", "actPassL3", "actActL3", "Left", "Right"]
+ default: "infraProvided"
+ nic_options:
+ description: >
+ Identifies for the direct.userdriver interface type, the physical
+ nics the driver is verified to work with.
+ Allowed values for nic types must be handled via a registry or be standardized.
+ required: false
+ type: list
+ entry_schema:
+ type: string
+
+tosca.datatypes.asd.paramMappings:
+ version: 0.1
+ derived_from: tosca.datatypes.Root
+ description: "Describes the datatype for parameter mapping"
+ properties:
+ loadbalancer_IP:
+ description: >
+ When present, this attribute specifies the name of the deployment
+ artifact input parameter through which the orchestrator can
+ configure the loadbalancerIP parameter of the K8s service
+ or ingress controller that the extCpdData represents.
+ Note: The format of the Content strings is specific for each different
+ orchestration templating technology used (Helm, Teraform, etc.).
+ Currently only a format for use with Helm charts is suggested:
+ "<helmchartname>:[<subchartname>.]^(0..N)[<parentparamname>.]^(0..N)<paramname>".
+ Whether the optional parts of the format are present depends on how the
+ parameter is declared in the helm chart. An example is:
+ "chartName:subChart1.subChart2.subChart3.Parent1.Parent2.Parent3.LBIP".
+ required: false
+ type: string
+ external_IPs:
+ description: >
+ When present, this attribute specifies the name of the deployment
+ artifact input parameter through which the orchestrator can
+ configure the extermalIPs parameter of the K8s service or ingress
+ controller, or the pod network interface annotation, that the
+ extCpdData represents.
+ Note: The format of the Content strings is specific for each different
+ orchestration templating technology used (Helm, Teraform, etc.).
+ Currently only a format for use with Helm charts is suggested:
+ "<helmchartname>:[<subchartname>.]^(0..N)[<parentparamname>.]^(0..N)<paramname>".
+ Whether the optional parts of the format are present depends on how the
+ parameter is declared in the helm chart. An example is:
+ "chartName:subChart1.subChart2.subChart3.Parent1.Parent2.Parent3.extIP".
+ required: false
+ type: list
+ entry_schema:
+ type: string
+ nad_names:
+ description: >
+ Specifies, for an extCpdData respesenting a secondary network interface,
+ the name(s) of the deployment artifact input parameter(s) through which
+ the orchestrator can provide the names of the network attachment
+ definitions (NADs) the orchestrator has created as base for the network
+ interface the extCpdData represents.
+ Note 1: When the extCpdData represent a networkRedundant/mated-pair of
+ sriov interfaces, there are references to 2 or 3 related NADs needed
+ to be passed, while for other interface types only one NAD reference
+ is needed to be passed.
+ Note 2: The format of the Content strings is specific for each different
+ orchestration templating technology used (Helm, Teraform, etc.).
+ Currently only a format for use with Helm charts is suggested:
+ "<helmchartname>:[<subchartname>.]^(0..N)[<parentparamname>.]^(0..N)<paramname>".
+ Whether the optional parts of the format are present depends on how the
+ parameter is declared in the helm chart. An example is:
+ chartName:"subChart1.subChart2.subChart3.Parent1.Parent2.Parent3.nadName".
+ Note 3: A direct attached (passthrough) network interface, such as an sriov
+ interface, attaches to a network via only one of the two switch planes
+ in the infrastructure.
+ When using a direct attached network interface one therefore commonly in a
+ pod uses a mated pair of sriov network attachments, where each interface
+ attaches same network but via different switchplane.
+ The application uses the mated pair of network interfaces as a single
+ logical “swith-path-redundant” network interface – and this is represented
+ by a single extCpdData.
+ Also there is a case where a third “bond” attachment interface is used in
+ the pod, bonding the two direct interfaces so that the application do not
+ need to handle the redundancy issues – application just uses the bond interface.
+ In this case, all three attachments are together making up a logical
+ “switch-path-redundant” network interface represented by a single extCpdData.
+ When three NADs are used in the extCpdData the NAD implementing the bond attachment
+ interface is provided through the parameter indicated in the third place in
+ the nadNames attribute.
+ required: false
+ type: list
+ entry_schema:
+ type: string
+ nad_namespace:
+ description: >
+ Specifies, for an extCpdData respesenting a secondary network interface,
+ the name of the deployment artifact input parameter through which the orchestrator
+ can provide the namespace where the NetworkAttachmentDefinitions (NADs) are located.
+ Attribute may be omitted if the namespace is same as the application
+ namespace.
+ Note: The format of the Content strings is specific for each different
+ orchestration templating technology used (Helm, Teraform, etc.).
+ Currently only a format for use with Helm charts is suggested:
+ "<helmchartname>:[<subchartname>.]^(0..N)[<parentparamname>.]^(0..N)<paramname>".
+ Whether the optional parts of the format are present depends on how the
+ parameter is declared in the helm chart. An example is:
+ "chartName:subChart1.subChart2.subChart3.Parent1.Parent2.Parent3.NameSpace".
+ required: false
+ type: string
+
+tosca.datatypes.asd.extCpdData:
+ version: 0.1
+ derived_from: tosca.datatypes.Root
+ description: "Describes the datatype for external connection point definition data"
+ properties:
+ id:
+ description: "The identifier of this extCpdData"
+ required: true
+ type: string
+ description:
+ description: >
+ This property describes for a particular ExtCpd instance
+ what service it exposes.
+ required: true
+ type: string
+ virtual_link_requirement:
+ description: >
+ Refers in an abstract way to the network or multiple networks that
+ the ExtCpd shall be exposed on (ex: OAM, EndUser, backhaul, LI, etc)
+ required: true
+ type: string
+ network_interface_realization_requirements:
+ description: >
+ Details container implementation specific requirements on
+ the NetworkAttachmentDefinition
+ required: false
+ type: tosca.datatypes.asd.networkInterfaceRequirements
+ input_param_mappings:
+ description: >
+ Information on what helm chart input parameters that
+ are required to be configured for this extCpd
+ required: false
+ type: tosca.datatypes.asd.paramMappings
+ resource_mapping:
+ description: >
+ Kubernetes API resource name for the resource manifest for the service,
+ ingress controller or pod
+ required: false
+ type: string
+
+tosca.datatypes.asd.enhancedClusterCapabilities:
+ version: 0.1
+ derived_from: tosca.datatypes.Root
+ description: "Describes the datatype for parameter mapping"
+ properties:
+ min_kernel_version:
+ description: >
+ Describes the minimal required Kernel version, e.g. 4.15.0.
+ Coded as displayed by linux command uname –r
+ required: true
+ type: string
+ required_kernel_modules:
+ description: >
+ Required kernel modules are coded as listed by linux lsmod command,
+ e.g. ip6_tables, cryptd, nf_nat etc.
+ required: false
+ type: list
+ entry_schema:
+ type: string
+ conflicting_kernel_modules:
+ description: >
+ Kernel modules, which must not be present in the target environment.
+ The kernel modules are coded as listed by linux lsmod command,
+ e.g., ip6_tables, cryptd, nf_nat etc.
+ Example: Linux kernel SCTP module, which would conflict with use of
+ proprietary user space SCTP stack provided by the application.
+ required: false
+ type: list
+ entry_schema:
+ type: string
+ required_custom_resources:
+ description: >
+ List the custom resource kinds required to be supported in the target
+ environment. The list shall include those custom resource kinds which
+ are not delivered with the application.
+ required: false
+ type: list
+ entry_schema:
+ type: tosca.datatypes.asd.customResourceRequirement
+ cluster_labels:
+ description: >
+ This attribute allows to associate arbitrary labels to clusters.
+ These can indicate special infrastructure capabilities (e.g., NW acceleration,
+ GPU compute, etc.). The intent of these labels is to serve as a set of
+ values that can help in application placement decisions.
+ clusterLabels follow the Kubernetes label key-value-nomenclature
+ (https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/).
+ It is recommended that labels follow a standardized meaning e.g. for node
+ features (https://kubernetes-sigs.github.io/node-feature-discovery/v0.9/get-started/features.html#table-of-contents).
+ Example:
+ ClusterLabels
+ - feature.node.kubernetes.io/cpu-cpuid.AESNI: true
+ required: false
+ type: list
+ entry_schema:
+ type: string
+ required_plugin:
+ description: a list of the name of the required K8s plugin
+ required: false
+ type: list
+ entry_schema:
+ type: tosca.datatypes.asd.requiredPlugin
+
+tosca.datatypes.asd.customResourceRequirement:
+ version: 0.1
+ derived_from: tosca.datatypes.Root
+ description: >
+ kind: "Redis", apiVersion: "kubedb.com/v1alpha1"
+ properties:
+ kind:
+ description: "the name of the custom resource requirement"
+ type: string
+ required: true
+ api_version:
+ description: "the api version of the custom resource requirement"
+ type: string
+ required: true
+
+tosca.datatypes.asd.requiredPlugin:
+ version: 0.1
+ derived_from: tosca.datatypes.Root
+ description: "the required K8s plugin"
+ properties:
+ name:
+ description: "the name of the required K8s plugin"
+ type: string
+ required: true
+ version:
+ description: "the version of the required K8s plugin"
+ type: string
+ required: true
+
+node_types:
+ tosca.nodes.asd:
+ derived_from: tosca.nodes.Root
+ description: "The ASD node type"
+ version: 0.1
+ properties:
+ descriptor_id:
+ type: string # UUID
+ required: true
+ description: Identifier of this ASD. It is in UUID format as specified in RFC 4122
+ descriptor_invariant_id:
+ type: string # UUID
+ required: true
+ description: >
+ Identifier of this descriptor in a version independent manner. This attribute
+ is invariant across versions of ASD. It is in UUID format as specified in RFC 4122
+ descriptor_version:
+ type: string
+ required: true
+ description: Identifies the version of the ASD.
+ schema_version:
+ type: string
+ required: true
+ description: Identifies the Identifies the version of this ASD’s schema.
+ function_description:
+ type: string
+ required: false
+ description: Description of the application service described by this ASD.
+ provider:
+ type: string
+ required: true
+ description: Identifies the provider of the ASD.
+ application_name:
+ type: string
+ required: true
+ description: Name to identify the application service described by this ASD
+ application_version:
+ type: string
+ required: true
+ description: Identifies the version of the application service described by this ASD.
+ ext_cpds:
+ type: list
+ required: false
+ entry_schema:
+ type: tosca.datatypes.asd.extCpdData
+ description: >
+ Describes the externally exposed connection points of the application
+ service described by this ASD
+ enhanced_cluster_capabilities:
+ type: tosca.datatypes.asd.enhancedClusterCapabilities
+ required: false
+ description: >
+ A list of expected capabilities of the target Kubernetes cluster to aid
+ placement of the application service on a suitable cluster.
+ tosca.nodes.asdInNsd:
+ derived_from: tosca.nodes.nfv.VNF
+ description: "The generic ASD node types for NS requirements. Optional properties are not list here."
+ version: 0.1
+ properties:
+ descriptor_id:
+ type: string # UUID
+ description: Identifier of an ASD. It is in UUID format as specified in RFC 4122
+ required: true
+ descriptor_version:
+ type: string
+ description: Identifies the version of the ASD.
+ required: true
+ default: ""
+ provider:
+ type: string
+ description: Identifies the provider of the ASD
+ required: true
+ default: ""
+ product_name:
+ type: string
+ description: Please use the application_name property
+ required: true
+ default: ""
+ software_version:
+ type: string
+ description: Please use the application_version property
+ required: true
+ default: ""
+ flavour_id:
+ type: string
+ required: true
+ constraints: [ equal: "simple" ]
+ default: "simple"
+ flavour_description:
+ type: string
+ required: true
+ default: ""
+ vnfm_info:
+ type: list
+ required: true
+ entry_schema:
+ type: list
+ requirements:
+ - virtual_link:
+ capability: tosca.capabilities.nfv.VirtualLinkable
+ relationship: tosca.relationships.nfv.VirtualLinkableTo
+ occurrences: [ 0,0 ]
+ - virtual_links:
+ capability: tosca.capabilities.nfv.VirtualLinkable
+ relationship: tosca.relationships.nfv.VirtualLinkableTo
+ occurrences: [ 0,UNBOUNDED ]
+artifact_types:
+tosca.artifacts.asd.deploymentItem:
+ version: 0.1
+ derived_from: tosca.artifacts.Root
+ description: "Describes the artifact type of asd deployment item"
+ file: "URI or path of the artifact"
+ properties:
+ item_id:
+ description: "The identifier of this asd deployment item"
+ required: true
+ type: string
+ artifact_type:
+ description: >
+ Specify artifact type.
+ required: true
+ type: string
+ constraints:
+ - valid_values: ["helm_chart", "helmfile", "crd", "terraform" ]
+ deployment_order:
+ description: >
+ Specifies the deployment stage that the DeploymentArtifact belongs to.
+ A lower value specifies that the DeploymentArtifact belongs to an earlier
+ deployment stage. When this value is omitted, the deployment order
+ will be decided by the orchestrator.
+ required: false
+ type: integer
+ lifecycle_parameters:
+ description: "list of parameters that can be overridden at deployment time "
+ required: false
+ type: list
+ entry_schema:
+ type: string
diff --git a/rapp-manager-application/src/main/resources/resource-csar/Files/Acm/instantiation.json b/rapp-manager-application/src/main/resources/resource-csar/Files/Acm/instantiation.json
new file mode 100755
index 0000000..c17f49b
--- /dev/null
+++ b/rapp-manager-application/src/main/resources/resource-csar/Files/Acm/instantiation.json
@@ -0,0 +1,72 @@
+{
+ "name": "RappInstance0",
+ "version": "1.0.1",
+ "compositionId": "COMPOSITIONID",
+ "description": "Demo automation composition instance 0",
+ "elements": {
+ "709c62b3-8918-41b9-a747-d21eb79c6c20": {
+ "id": "709c62b3-8918-41b9-a747-d21eb79c6c20",
+ "definition": {
+ "name": "onap.policy.clamp.ac.element.KserveAutomationCompositionElement",
+ "version": "1.2.3"
+ },
+ "description": "Starter Automation Composition Element for the Demo",
+ "properties": {
+ "kserveInferenceEntities": [
+ {
+ "kserveInferenceEntityId": {
+ "name": "entity1",
+ "version": "1.0.1"
+ },
+ "name": "sklearn-iris",
+ "namespace": "rapps",
+ "payload": "{\"apiVersion\": \"serving.kserve.io/v1beta1\",\"kind\": \"InferenceService\",\"metadata\": {\"name\": \"sklearn-iris\"},\"spec\": {\"predictor\": {\"model\":{\"modelFormat\": {\"name\": \"sklearn\"},\"storageUri\": \"gs://kfserving-examples/models/sklearn/1.0/model\"}}}}"
+ }
+ ]
+ }
+ },
+ "709c62b3-8918-41b9-a747-d21eb79c6c12": {
+ "id": "709c62b3-8918-41b9-a747-d21eb79c6c12",
+ "definition": {
+ "name": "onap.policy.clamp.ac.element.A1PMSAutomationCompositionElement",
+ "version": "1.2.3"
+ },
+ "description": "Starter Automation Composition Element for the Demo",
+ "properties": {
+ "policyServiceEntities": [
+ {
+ "a1PolicyServiceEntityId": {
+ "name": "entity1",
+ "version": "1.0.1"
+ },
+ "clientId": "firstService",
+ "callbackUrl": "http:\\localhost"
+ }
+ ]
+ }
+ },
+ "709c62b3-8918-41b9-a747-d21eb79c6c21": {
+ "id": "709c62b3-8918-41b9-a747-d21eb79c6c21",
+ "definition": {
+ "name": "onap.policy.clamp.ac.element.K8S_StarterAutomationCompositionElement",
+ "version": "1.2.3"
+ },
+ "description": "Starter Automation Composition Element for the Demo",
+ "properties": {
+ "chart": {
+ "chartId": {
+ "name": "ransliceassurance",
+ "version": "1.0.0"
+ },
+ "namespace": "nonrtric",
+ "releaseName": "ransliceassurance",
+ "podName": "ransliceassurance",
+ "repository": {
+ "repoName": "local",
+ "address": "http://10.101.2.254:8879/charts"
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/rapp-manager-application/src/main/resources/resource-csar/Files/ChangeLog.txt b/rapp-manager-application/src/main/resources/resource-csar/Files/ChangeLog.txt
new file mode 100755
index 0000000..bdcfb02
--- /dev/null
+++ b/rapp-manager-application/src/main/resources/resource-csar/Files/ChangeLog.txt
@@ -0,0 +1 @@
+This is the first version of My ASD node.
\ No newline at end of file
diff --git a/rapp-manager-application/src/main/resources/resource-csar/Files/Events/MyASD_v1.yaml b/rapp-manager-application/src/main/resources/resource-csar/Files/Events/MyASD_v1.yaml
new file mode 100755
index 0000000..90144cf
--- /dev/null
+++ b/rapp-manager-application/src/main/resources/resource-csar/Files/Events/MyASD_v1.yaml
@@ -0,0 +1,213 @@
+---
+event:
+ presence: required
+ structure:
+ commonEventHeader:
+ presence: required
+ structure:
+ domain: {presence: required, value: notification}
+ eventName: {presence: required, value: Noti_MyPnf-Acme_FileReady}
+ priority: {presence: required, value: Normal}
+ eventId: {presence: required}
+ reportingEntityId: {presence: required}
+ reportingEntityName: {presence: required}
+ sequence: {presence: required, value: 0}
+ sourceId: {presence: required}
+ sourceName: {presence: required}
+ version: {presence: required, value: 4.0.1}
+ vesEventListenerVersion: {presence: required, value: 7.0.1}
+ startEpochMicrosec: {presence: required}
+ lastEpochMicrosec: {presence: required}
+ notificationFields:
+ presence: required
+ structure:
+ changeIdentifier: {presence: required, value: PM_MEAS_FILES}
+ changeType: {presence: required, value: fileReady}
+ notificationFieldsVersion: {presence: required, value: 2.0}
+ arrayOfNamedHashMap:
+ presence: required
+ array:
+ - name: {presence: required}
+ hashMap: {presence: required, structure: {
+ keyValuePair: {presence: required, structure: {key: {presence: required, value: location}, value: {presence: required}}},
+ keyValuePair: {presence: required, structure: {key: {presence: required, value: compression}, value: {presence: required, value: gzip}}},
+ keyValuePair: {presence: required, structure: {key: {presence: required, value: fileFormatType}, value: {presence: required, value: org.3GPP.32.435}}},
+ keyValuePair: {presence: required, structure: {key: {presence: required, value: fileFormatVersion}, value: {presence: required, value: V10}}}}
+ }
+...
+---
+event:
+ presence: required
+ structure:
+ commonEventHeader:
+ presence: required
+ structure:
+ domain: {presence: required, value: pnfRegistration}
+ eventId: {presence: required}
+ eventName: {presence: required, value: PnfReg_MyPnf-Acme_pnfRegistration}
+ lastEpochMicrosec: {presence: required}
+ priority: {presence: required, value: Normal}
+ reportingEntityName: {presence: required}
+ sequence: {presence: required, value: 0}
+ sourceName: {presence: required}
+ startEpochMicrosec: {presence: required}
+ timeZoneOffset: {presence: required}
+ version: {presence: required, value: 4.0.1}
+ vesEventListenerVersion: {presence: required, value: 7.0.1}
+ pnfRegistrationFields:
+ presence: required
+ structure:
+ modelNumber: {presence: required}
+ oamV4IpAddress: {presence: optional}
+ oamV6IpAddress: {presence: optional}
+ pnfRegistrationFieldsVersion: {presence: required, value: 2.0}
+ serialNumber: {presence: required}
+ softwareVersion: {presence: required}
+ unitFamily: {presence: required, value: BBU}
+ unitType: {presence: required}
+ vendorName: {presence: required, value: Acme}
+...
+---
+event:
+ presence: required
+ action: [ any, any, null, null, null ]
+ comment: "
+ ALARM NAME: CertMAutomaticEnrollmentFailed,
+ ALARM DESCRIPTION: ‘See alarm OPI x/1111-ABC 123 4567/1 Uen’,
+ ALARM EFFECT: 'See alarm OPI x/2222-ABC 123 4567/1 Uen',
+ MANAGED OBJECT CLASSES: NodeCredential,
+ EVENT TYPE: 'PROCESSINGERRORALARM',
+ PROBABLE CAUSE: 'ConfigurationOrCustomizationError',
+ PROPOSED REPAIR ACTIONS: 'See alarm OPI x/3333-ABC 123 4567/1 Uen',
+ CLEARING TYPE: Automatic
+ "
+ structure:
+ commonEventHeader:
+ presence: required
+ structure:
+ version: {presence: required, value: 4.0.1}
+ vesEventListenerVersion: {presence: required, value: 7.0.1}
+ domain: {presence: required, value: fault}
+ eventName: {presence: required, value: Fault_MyPnf-Acme_CertMAutomaticEnrollmentFailed}
+ eventId: {presence: required}
+ sequence: {presence: required}
+ priority: {presence: required, value: Normal}
+ reportingEntityName: {presence: required}
+ sourceName: {presence: required}
+ nfVendorName: {presence: required, value: Acme}
+ startEpochMicrosec: {presence: required}
+ lastEpochMicrosec: {presence: required}
+ timeZoneOffset: {presence: required}
+ faultFields:
+ presence: required
+ structure:
+ faultFieldsVersion: {presence: required, value: 4.0}
+ alarmCondition: {presence: required, value: 'CertMAutomaticEnrollmentFailed'}
+ eventCategory: {presence: required, value: 'PROCESSINGERRORALARM'}
+ eventSourceType: {presence: required}
+ specificProblem: {presence: required, value: 'Certificate Management Automatic Enrollment Failed'}
+ eventSeverity: {presence: required}
+ vfStatus: {presence: required, value: Active}
+ alarmAdditionalInformation: {presence: required, structure: {
+ keyValuePair: {presence: required, structure: {key: {presence: required, value: source}, value: {presence: required}}},
+ keyValuePair: {presence: required, structure: {key: {presence: required, value: probableCause}, value: {presence: required, value: 'ConfigurationOrCustomizationError'}}},
+ keyValuePair: {presence: required, structure: {key: {presence: required, value: additionalText}, value: {presence: optional}}},
+ keyValuePair: {presence: required, structure: {key: {presence: required, value: additionalInfo}, value: {presence: optional}}}}
+ }
+...
+---
+event:
+ presence: required
+ action: [ any, any, null, null, null ]
+ comment: "
+ ALARM NAME: PowerLoss,
+ ALARM DESCRIPTION: 'PNF is losing power',
+ ALARM EFFECT: 'PNF will shutdown if battery is drained',
+ MANAGED OBJECT CLASSES: 'BatteryBackup;BatteryUnit',
+ EVENT TYPE: 'EQUIPMENTALARM',
+ PROBABLE CAUSE: 'Power Supply Failure',
+ PROPOSED REPAIR ACTIONS: 'Repair Power Supply',
+ CLEARING TYPE: Automatic
+ "
+ structure:
+ commonEventHeader:
+ presence: required
+ structure:
+ version: {presence: required, value: 4.0.1}
+ vesEventListenerVersion: {presence: required, value: 7.0.1}
+ domain: {presence: required, value: fault}
+ eventName: {presence: required, value: Fault_MyPnf-Acme_PowerLoss}
+ eventId: {presence: required}
+ sequence: {presence: required}
+ priority: {presence: required, value: Normal}
+ reportingEntityName: {presence: required}
+ sourceName: {presence: required}
+ nfVendorName: {presence: required, value: Acme}
+ startEpochMicrosec: {presence: required}
+ lastEpochMicrosec: {presence: required}
+ timeZoneOffset: {presence: required}
+ faultFields:
+ presence: required
+ structure:
+ faultFieldsVersion: {presence: required, value: 4.0}
+ alarmCondition: {presence: required, value: 'PowerLoss'}
+ eventCategory: {presence: required, value: 'EQUIPMENTALARM'}
+ eventSourceType: {presence: required}
+ specificProblem: {presence: required, value: 'Power Supply Failure'}
+ eventSeverity: {presence: required}
+ vfStatus: {presence: required, value: Active}
+ alarmAdditionalInformation: {presence: required, structure: {
+ keyValuePair: {presence: required, structure: {key: {presence: required, value: source}, value: {presence: required}}},
+ keyValuePair: {presence: required, structure: {key: {presence: required, value: probableCause}, value: {presence: required, value: 'Power Supply Failure'}}},
+ keyValuePair: {presence: required, structure: {key: {presence: required, value: additionalText}, value: {presence: optional}}},
+ keyValuePair: {presence: required, structure: {key: {presence: required, value: additionalInfo}, value: {presence: optional}}}}
+ }
+...
+---
+event:
+ presence: required
+ action: [ any, any, null, null, null ]
+ comment: "
+ ALARM NAME: LogHasReachedFullCapacity,
+ ALARM DESCRIPTION: 'Log Has Reached Full Capacity',
+ ALARM EFFECT: 'See alarm OPI x/2223-ABC 123 4567/1 Uen',
+ MANAGED OBJECT CLASSES: Log,
+ EVENT TYPE: 'PROCESSINGERRORALARM',
+ PROBABLE CAUSE: 'FileError',
+ PROPOSED REPAIR ACTIONS: 'See alarm OPI x/3334-ABC 123 4567/1 Uen',
+ CLEARING TYPE: Automatic
+ "
+ structure:
+ commonEventHeader:
+ presence: required
+ structure:
+ version: {presence: required, value: 4.0.1}
+ vesEventListenerVersion: {presence: required, value: 7.0.1}
+ domain: {presence: required, value: fault}
+ eventName: {presence: required, value: Fault_MyPnf-Acme_LogHasReachedFullCapacity}
+ eventId: {presence: required}
+ sequence: {presence: required}
+ priority: {presence: required, value: Normal}
+ reportingEntityName: {presence: required}
+ sourceName: {presence: required}
+ nfVendorName: {presence: required, value: Acme}
+ startEpochMicrosec: {presence: required}
+ lastEpochMicrosec: {presence: required}
+ timeZoneOffset: {presence: required}
+ faultFields:
+ presence: required
+ structure:
+ faultFieldsVersion: {presence: required, value: 4.0}
+ alarmCondition: {presence: required, value: 'LogHasReachedFullCapacity'}
+ eventCategory: {presence: required, value: 'PROCESSINGERRORALARM'}
+ eventSourceType: {presence: required}
+ specificProblem: {presence: required, value: 'Log Has Reached Full Capacity'}
+ eventSeverity: {presence: required}
+ vfStatus: {presence: required, value: Active}
+ alarmAdditionalInformation: {presence: required, structure: {
+ keyValuePair: {presence: required, structure: {key: {presence: required, value: source},value: {presence: required}}},
+ keyValuePair: {presence: required, structure: {key: {presence: required, value: probableCause},value: {presence: required, value: 'FileError'}}},
+ keyValuePair: {presence: required, structure: {key: {presence: required, value: additionalText},value: {presence: optional}}},
+ keyValuePair: {presence: required, structure: {key: {presence: required, value: additionalInfo},value: {presence: optional}}}}
+ }
+...
\ No newline at end of file
diff --git a/rapp-manager-application/src/main/resources/resource-csar/Files/Guides/user_guide.txt b/rapp-manager-application/src/main/resources/resource-csar/Files/Guides/user_guide.txt
new file mode 100755
index 0000000..6792e54
--- /dev/null
+++ b/rapp-manager-application/src/main/resources/resource-csar/Files/Guides/user_guide.txt
@@ -0,0 +1 @@
+This is a sample user guide file.
\ No newline at end of file
diff --git a/rapp-manager-application/src/main/resources/resource-csar/Files/Measurements/PM_Dictionary.yaml b/rapp-manager-application/src/main/resources/resource-csar/Files/Measurements/PM_Dictionary.yaml
new file mode 100755
index 0000000..858951f
--- /dev/null
+++ b/rapp-manager-application/src/main/resources/resource-csar/Files/Measurements/PM_Dictionary.yaml
@@ -0,0 +1,186 @@
+pmDictionary:
+ presence: required
+ structure:
+ pmDictionaryHeader:
+ presence: required
+ structure:
+ pmDefVsn: { presence: required, comment: "Version of the PM Dictionary. Version is vendor defined."}
+ pmDefSchemaVsn: { presence: required, comment: "Version of the PM Dictionary Schema used for this PM Dictionary. Schema versions are specified in the VES Specifications."}
+ nfType: { presence: required, comment: "NF type to whom this PM Dictionary applies. nfType is vendor defined and should match the string used in eventName."}
+ vendor: { presence: required, value: Acme, comment: "Vendor of the NF type to whom this PM Dictionary applies."}
+ pmDictionaryMeasurements:
+ presence: required
+ array:
+ - measType: { presence: required, comment: "Measurement name used in PM file, in 3GPP format where specified, else vendor defined. Names for 3GPP-defined 4G measurements are specified in 3GPP TS 32.425 item e). Names for 3GPP-defined 5G measurements are specified in 3GPP TS 28.552 item e). Vendor defined names are preceded with VS."}
+ measDescription: { presence: required, comment: "Text description of the purpose of the measurement, what information does the measurement provide. Descriptions for 3GPP-defined 4G measurements are specified in 3GPP TS 32.425 item a). Descriptions for 3GPP-defined 5G measurements are specified in 3GPP TS 28.552 item a). Vendors are free to augment or modify the 3GPP-provided descriptions to more accurately describe their measurements as needed."}
+ measCondition: { presence: required, comment: "Text description of the condition that causes the measurement to be updated. Conditions for 3GPP-defined 4G measurements are specified in 3GPP TS 32.425 item c). Conditions for 3GPP-defined 5G measurements are specified in 3GPP TS 28.552 item c). Vendors are free to augment or modify the 3GPP-provided conditions to more accurately describe their measurements as needed."}
+ measResultType: { presence: required, value: [integer], comment: "Data type of the measurement result. Result data types for 3GPP-defined 4G measurements are specified in 3GPP TS 32.425 item d). Result data types for 3GPP-defined 5G measurements are specified in 3GPP TS 28.552 item d). The measResultType values supported by a vendor are specified in the PM Dictionary YAML using the 'value' attribute and may include vendor-defined data types not specified by 3GPP; for example boolean."}
+ measResultRange: { presence: optional, comment: "Range for the measurement result. The range is specified as a comma separated list of discrete values or a range of values specified as minimum value-maximum value with no spaces. Result ranges for 3GPP-defined 4G measurements are specified in 3GPP TS 32.425 item d) if applicable. Result ranges for 3GPP-defined 5G measurements are specified in 3GPP TS 28.552 item d) if applicable. "}
+ measResultUnits: { presence: required, value: [seconds, minutes, nanoseconds, microseconds, kbps], comment: "Unit of measure for the result; e.g. milliseconds, bytes, kilobytes, packets, number. Unit of measure for 3GPP-defined 4G measurements are specified in 3GPP TS 32.425 item d) if applicable. Unit of measure for 3GPP-defined 5G measurements are specified in 3GPP TS 28.552 item d) if applicable. The measResultsUnits values supported by a vendor are specified in the PM Dictionary YAML using the 'value' attribute and may include vendor-defined units of measure not specified by 3GPP; for example ethernet frames."}
+ measObjClass: { presence: required, value: [NRCellCU, NRCellDU, NRBTS, IPNO, ETHIF], comment: "Measurement Object Class. Object classes for 3GPP-defined 4G measurements are specified in 3GPP TS 32.425 item f). Object classes for 3GPP-defined 5G measurements are specified in 3GPP TS 28.552 item f). The measObjClass values supported by a vendor are specified in the PM Dictionary YAML using the “value” attribute and may include vendor-defined objects not specified by 3GPP; for example IPSEC."}
+ measCollectionMethod: { presence: required, value: [CC, GUAGE, DER, SI], comment: "Collection Method for the measurement. 3GPP-defined collection methods are CC, SI, DER and Gauge. Collection Methods for 3GPP-defined 4G measurements are specified in 3GPP TS 32.425 item b). Collection Methods for 3GPP-defined 5G measurements are specified in 3GPP TS 28.552 item c). The measCollectionMethod values supported by a vendor are specified in the PM Dictionary YAML using the 'value' attribute and may include vendor-defined collection methods not specified by 3GPP; for example Average."}
+ measLastChange: { presence: required, comment: "PM Dictionary version the last time this measurement was changed, added or deleted."}
+ measChangeType: { presence: required, value: [added, modified, deleted], comment: "For the measLastChange, indicates the type of change made for this measurement. Valid values are added, modified or deleted. Deleted measurements may be kept in the PM Dictionary for one release or more or permanently for historical purposes, if desired."}
+ measInfoId: { presence: required, comment: "Name for a group of related measurements, in 3GPP format where specified, else vendor defined. Family names for 3GPP-defined 4G measurements are specified in 3GPP TS 32.425 Section 3.1. Family names for 3GPP-defined 5G measurements are specified in 3GPP TS 28.552 Section 3.4."}
+ measFamily: { presence: required, comment: "Abbreviation for a family of measurements, in 3GPP format where specified, else vendor defined. Family name abbreviations for 3GPP-defined 4G measurements are specified in 3GPP TS 32.425 Section 3.1. Family name abbreviations for 3GPP-defined 5G measurements are specified in 3GPP TS 28.552 Section 3.4. "}
+ measAdditionalFields: { presence: required, comment: "Hashmap of vendor specific PM Dictionary fields in key value pair format.", structure: {
+ keyValuePair: { presence: required, structure: { key: { presence: required, value: measurementStatus, comment: "Contains the status of the measurement."}, value: { presence: required, value: [USED, DEPRECATED, OBSOLETE, PRELIMINARY] }}},
+ keyValuePair: { presence: required, structure: { key: { presence: required, value: initialValue, comment: "The initial value to which the Measurement Type is set at the beginning of a new granularity period."}, value: { presence: required }}},
+ keyValuePair: { presence: required, structure: { key: { presence: required, value: acmeParameter1, comment: "Extra vendor specific parameter 1."}, value: { presence: required }}},
+ keyValuePair: { presence: optional, structure: { key: { presence: required, value: acmeParameter2, comment: "Extra vendor specific parameter 2."}, value: { presence: required, value: [true, false] }}},
+ keyValuePair: { presence: optional, structure: { key: { presence: required, value: acmeParameter3, comment: "Extra vendor specific parameter 3."}, value: { presence: required }}}}
+ }
+---
+pmDictionary:
+ pmDictionaryHeader:
+ pmDefVsn: AcmeNumber.1.0
+ pmDefSchemaVsn: 1.0
+ nfType: myPnf
+ vendor: Acme
+ pmDictionaryMeasurements:
+
+ - measType: DRB.UEThpDl
+ measDescription: Average DL UE throughput in gNB
+ measCondition: See 3GPP TS 28.552
+ measResultType: integer
+ measResultRange: 0-4294967295
+ measResultUnits: kbps
+ measObjClass: NRCellDU
+ measCollectionMethod: DER
+ measLastChange: 1.0
+ measChangeType: added
+ measInfoId: "Data Radio Bearer"
+ measFamily: DRB
+ measAdditionalFields: {
+ "measurementStatus": "USED",
+ "initialValue": 0,
+ "acmeParameter1": 0,
+ "acmeParameter2": true,
+ "acmeParameter3": "acmeParameterValue3"}
+
+ - measType: VS.ifInDiscards
+ measDescription: The number of inbound packets which were chosen to be discarded
+ measCondition: The number of inbound packets which were chosen to be
+ discarded even though no errors had been detected to prevent
+ their being deliverable to a higher-layer protocol. One
+ possible reason for discarding such a packet could be to
+ free up buffer space.
+ Discontinuities in the value of this counter can occur at
+ re-initialization of the management system, and at other
+ times as indicated by the value of
+ ifCounterDiscontinuityTime.
+ measResultType: integer
+ measResultRange: 0-4294967295
+ measResultUnits: number
+ measObjClass: EthernetPort
+ measCollectionMethod: CC
+ measLastChange: 1.0
+ measChangeType: added
+ measInfoId: "IP Management"
+ measFamily: IP
+ measAdditionalFields: {
+ "measurementStatus": "USED",
+ "initialValue": 0,
+ "acmeParameter1": 0,
+ "acmeParameter2": true,
+ "acmeParameter3": "acmeParameterValue3"}
+
+ - measType: VS.ifInErrors
+ measDescription: Number of inbound packets that contained errors
+ measCondition: For packet-oriented interfaces, the number of inbound
+ packets that contained errors preventing them from being
+ deliverable to a higher-layer protocol. For character-
+ oriented or fixed-length interfaces, the number of inbound
+ transmission units that contained errors preventing them
+ from being deliverable to a higher-layer protocol.
+ measResultType: integer
+ measResultRange: 0-4294967295
+ measResultUnits: number
+ measObjClass: EthernetPort
+ measCollectionMethod: Gauge
+ measLastChange: 1.0
+ measChangeType: added
+ measInfoId: "IP Management"
+ measFamily: IP
+ measAdditionalFields: {
+ "measurementStatus": "USED",
+ "initialValue": 0,
+ "acmeParameter1": 0,
+ "acmeParameter3": "acmeParameterValue3"}
+
+ - measType: VS.ifInUnknownProtos
+ measDescription: Number of inbound packets received via an unknown or usupported protocol
+ measCondition: For packet-oriented interfaces, the number of packets
+ received via the interface which were discarded because of
+ an unknown or unsupported protocol. For character-oriented
+ or fixed-length interfaces that support protocol
+ multiplexing the number of transmission units received via
+ the interface which were discarded because of an unknown or
+ unsupported protocol. For any interface that does not
+ support protocol multiplexing, this counter will always be
+ 0.
+ measResultType: integer
+ measResultRange: 0-4294967295
+ measResultUnits: number
+ measObjClass: EthernetPort
+ measCollectionMethod: CC
+ measLastChange: 1.0
+ measChangeType: added
+ measInfoId: "IP Management"
+ measFamily: IP
+ measAdditionalFields: {
+ "measurementStatus": "USED",
+ "initialValue": 0,
+ "acmeParameter1": 0,
+ "acmeParameter2": true}
+
+ - measType: VS.ifHCInBroadcastPkts
+ measDescription: Number of the broadcasted inbound packets delivered to the higher (sub-)layer
+ measCondition: The number of packets, delivered by this sub-layer to a
+ higher (sub-)layer, which were addressed to a broadcast
+ address at this sub-layer. This object is a 64-bit version
+ of ifInBroadcastPkts.
+ Discontinuities in the value of this counter can occur at
+ re-initialization of the management system, and at other
+ times as indicated by the value of
+ ifCounterDiscontinuityTime.
+ measResultType: integer
+ measResultRange: 0-4294967295
+ measResultUnits: number
+ measObjClass: EthernetPort
+ measCollectionMethod: CC
+ measLastChange: 1.0
+ measChangeType: added
+ measInfoId: "IP Management"
+ measFamily: IP
+ measAdditionalFields: {
+ "measurementStatus": "USED",
+ "initialValue": 0,
+ "acmeParameter1": 0}
+
+ - measType: VS.ifHCOutBroadcastPkts
+ measDescription: Number of the broadcasted outsbound packets delivered to the higher (sub-)layer
+ measCondition: The total number of packets that higher-level protocols
+ requested be transmitted, and which were addressed to a
+ broadcast address at this sub-layer, including those that
+ were discarded or not sent. This object is a 64-bit version
+ of ifOutBroadcastPkts.
+ Discontinuities in the value of this counter can occur at
+ re-initialization of the management system, and at other
+ times as indicated by the value of
+ ifCounterDiscontinuityTime.
+ measResultType: integer
+ measResultRange: 0-4294967295
+ measResultUnits: number
+ measObjClass: EthernetPort
+ measCollectionMethod: CC
+ measLastChange: 1.0
+ measChangeType: added
+ measInfoId: "IP Management"
+ measFamily: IP
+ measAdditionalFields: {
+ "measurementStatus": "USED",
+ "initialValue": 0,
+ "acmeParameter1": 0,
+ "acmeParameter2": true,
+ "acmeParameter3": "acmeParameterValue3"}
diff --git a/rapp-manager-application/src/main/resources/resource-csar/Files/Scripts/my_script.sh b/rapp-manager-application/src/main/resources/resource-csar/Files/Scripts/my_script.sh
new file mode 100755
index 0000000..79b3155
--- /dev/null
+++ b/rapp-manager-application/src/main/resources/resource-csar/Files/Scripts/my_script.sh
@@ -0,0 +1,2 @@
+#!/bin/bash
+echo "I'm simply an example script file in the package that doesn't do anything!"
\ No newline at end of file
diff --git a/rapp-manager-application/src/main/resources/resource-csar/Files/Sme/invoker.json b/rapp-manager-application/src/main/resources/resource-csar/Files/Sme/invoker.json
new file mode 100755
index 0000000..141a860
--- /dev/null
+++ b/rapp-manager-application/src/main/resources/resource-csar/Files/Sme/invoker.json
@@ -0,0 +1,14 @@
+[
+ {
+ "apiInvokerInformation": "rApp as invoker 1",
+ "apiList": [
+ {}
+ ],
+ "notificationDestination": "http://invoker-app:8086/callback",
+ "onboardingInformation": {
+ "apiInvokerPublicKey": "{PUBLIC_KEY_INVOKER_1}",
+ "apiInvokerCertificate": "apiInvokerCertificate"
+ },
+ "requestTestNotification": true
+ }
+]
\ No newline at end of file
diff --git a/rapp-manager-application/src/main/resources/resource-csar/Files/Sme/provider-api.json b/rapp-manager-application/src/main/resources/resource-csar/Files/Sme/provider-api.json
new file mode 100755
index 0000000..7c58c9c
--- /dev/null
+++ b/rapp-manager-application/src/main/resources/resource-csar/Files/Sme/provider-api.json
@@ -0,0 +1,45 @@
+{
+ "apiName": "Rapp API",
+ "description": "Example A API of rApp",
+ "aefProfiles": [
+ {
+ "aefId": "rApp as AEF",
+ "description": "Example A rApp as AEF",
+ "versions": [
+ {
+ "apiVersion": "v1",
+ "resources": [
+ {
+ "resourceName": "exampleA",
+ "commType": "REQUEST_RESPONSE",
+ "uri": "/exampleA/subscription/subscription_id_1",
+ "operations": [
+ "GET"
+ ]
+ }
+ ]
+ }
+ ],
+ "protocol": "HTTP_1_1",
+ "securityMethods": [
+ "PSK"
+ ],
+ "interfaceDescriptions": [
+ {
+ "ipv4Addr": "string",
+ "port": 65535,
+ "securityMethods": [
+ "PKI"
+ ]
+ },
+ {
+ "ipv4Addr": "string",
+ "port": 65535,
+ "securityMethods": [
+ "PKI"
+ ]
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/rapp-manager-application/src/main/resources/resource-csar/Files/Sme/provider-domain.json b/rapp-manager-application/src/main/resources/resource-csar/Files/Sme/provider-domain.json
new file mode 100755
index 0000000..644819c
--- /dev/null
+++ b/rapp-manager-application/src/main/resources/resource-csar/Files/Sme/provider-domain.json
@@ -0,0 +1,34 @@
+{
+ "apiProvDomInfo": "Provider domain",
+ "apiProvFuncs": [
+ {
+ "apiProvFuncInfo": "rApp as APF",
+ "apiProvFuncRole": "APF",
+ "regInfo": {
+ "apiProvPubKey": "APF-PublicKey"
+ }
+ },
+ {
+ "apiProvFuncInfo": "rApp as AEF",
+ "apiProvFuncRole": "AEF",
+ "regInfo": {
+ "apiProvPubKey": "AEF-PublicKey"
+ }
+ },
+ {
+ "apiProvFuncInfo": "rApp as AMF",
+ "apiProvFuncRole": "AMF",
+ "regInfo": {
+ "apiProvPubKey": "AMF-PublicKey"
+ }
+ },
+ {
+ "apiProvFuncInfo": "Gateway as entrypoint AEF",
+ "apiProvFuncRole": "AEF",
+ "regInfo": {
+ "apiProvPubKey": "AEF-Gateway-PublicKey"
+ }
+ }
+ ],
+ "regSec": "PSK"
+}
\ No newline at end of file
diff --git a/rapp-manager-application/src/main/resources/resource-csar/Files/Yang_module/mynetconf.yang b/rapp-manager-application/src/main/resources/resource-csar/Files/Yang_module/mynetconf.yang
new file mode 100755
index 0000000..56501e8
--- /dev/null
+++ b/rapp-manager-application/src/main/resources/resource-csar/Files/Yang_module/mynetconf.yang
@@ -0,0 +1,26 @@
+module mynetconf {
+ yang-version 1.1;
+ namespace "urn:mynetconf:test";
+
+ prefix nft;
+
+ organization "mynetconf";
+ contact "my netconf address";
+ description "yang model for mynetconf";
+ revision "2019-03-01"{
+ description "initial version";
+ }
+
+ container netconflist{
+ list netconf{
+ key netconf-id;
+ leaf netconf-id{
+ type uint16;
+ }
+ leaf netconf-param {
+ type uint32;
+ }
+ }
+
+ }
+}
diff --git a/rapp-manager-application/src/main/resources/resource-csar/Files/rapp1/rapp.zip b/rapp-manager-application/src/main/resources/resource-csar/Files/rapp1/rapp.zip
new file mode 100755
index 0000000..6409765
--- /dev/null
+++ b/rapp-manager-application/src/main/resources/resource-csar/Files/rapp1/rapp.zip
Binary files differ
diff --git a/rapp-manager-application/src/main/resources/resource-csar/TOSCA-Metadata/TOSCA.meta b/rapp-manager-application/src/main/resources/resource-csar/TOSCA-Metadata/TOSCA.meta
new file mode 100755
index 0000000..3325e34
--- /dev/null
+++ b/rapp-manager-application/src/main/resources/resource-csar/TOSCA-Metadata/TOSCA.meta
@@ -0,0 +1,5 @@
+TOSCA-Meta-File-Version: 1.0
+CSAR-Version: 1.0
+Created-By: Ericsson (Zu Qiang 2021-10-21)
+Entry-Definitions: Definitions/asd.yaml
+ETSI-Entry-Manifest: asd.mf
\ No newline at end of file
diff --git a/rapp-manager-application/src/main/resources/resource-csar/asd.mf b/rapp-manager-application/src/main/resources/resource-csar/asd.mf
new file mode 100755
index 0000000..39218a5
--- /dev/null
+++ b/rapp-manager-application/src/main/resources/resource-csar/asd.mf
@@ -0,0 +1,35 @@
+metadata:
+ application_name: Free5gc-APP
+ application_provider: MyCompany
+ release_date_time: 2021-10-21T11:30:00+05:00
+ entry_definition_type: asd
+
+Source: asd.mf
+Source: Definitions/asd.yaml
+Source: Definitions/asd_types.yaml
+Source: Files/ChangeLog.txt
+Source: Files/Events/MyASD_v1.yaml
+Source: Files/Guides/user_guide.txt
+Source: Files/Measurements/PM_Dictionary.yaml
+Source: Files/Scripts/my_script.sh
+Source: Files/Yang_module/mynetconf.yang
+Source: TOSCA-Metadata/TOSCA.meta
+Source: Artifacts/Deployment/HELM/free5gc-1.1.3.tgz
+Source: Artifacts/Deployment/HELM/ueransim-2.0.14.tgz
+Source: Files/rapp1/rapp.zip
+Source: Files/Acm/instantiation.yaml
+
+non_mano_artifact_sets:
+ onap_ves_events:
+ Source: Files/Events/MyASD_v1.yaml
+ onap_pm_dictionary:
+ Source: Files/Measurements/PM_Dictionary.yaml
+ onap_yang_modules:
+ Source: Files/Yang_module/mynetconf.yang
+ onap_others:
+ Source: Files/Guides/user_guide.txt
+ onap_vendor_artifacts:
+ vendor_name: Ericsson
+ artifact_type: rApp_name1
+ source:Files/rapp1/rapp.zip
+
diff --git a/rapp-manager-application/src/test/java/com/oransc/rappmanager/rest/OnboardingControllerTest.java b/rapp-manager-application/src/test/java/com/oransc/rappmanager/rest/OnboardingControllerTest.java
new file mode 100755
index 0000000..c64e999
--- /dev/null
+++ b/rapp-manager-application/src/test/java/com/oransc/rappmanager/rest/OnboardingControllerTest.java
@@ -0,0 +1,149 @@
+/*-
+ * ============LICENSE_START======================================================================
+ * Copyright (C) 2023 Nordix Foundation. 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END========================================================================
+ */
+
+package com.oransc.rappmanager.rest;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.when;
+import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+import com.oransc.rappmanager.acm.service.AcmDeployer;
+import com.oransc.rappmanager.configuration.RappManagerConfiguration;
+import com.oransc.rappmanager.models.RappState;
+import com.oransc.rappmanager.sme.service.SmeDeployer;
+import java.io.File;
+import java.io.FileInputStream;
+import java.util.UUID;
+import org.apache.http.entity.ContentType;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.mock.mockito.MockBean;
+import org.springframework.mock.web.MockMultipartFile;
+import org.springframework.test.context.TestPropertySource;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
+
+@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
+@TestPropertySource(properties = "rappmanager.csarlocation=src/test/resources")
+@AutoConfigureMockMvc
+public class OnboardingControllerTest {
+
+ @Autowired
+ private MockMvc mockMvc;
+
+ @Autowired
+ RappManagerConfiguration rappManagerConfiguration;
+
+ @MockBean
+ AcmDeployer acmDeployer;
+
+ @MockBean
+ SmeDeployer smeDeployer;
+
+ private final String validRappFile = "valid-rapp-package.csar";
+
+ private final String invalidRappFile = "invalid-rapp-package.csar";
+
+ @Test
+ void testOnboardCsarPackage() throws Exception {
+ String rappCsarPath = rappManagerConfiguration.getCsarLocation() + File.separator + validRappFile;
+ MockMultipartFile multipartFile =
+ new MockMultipartFile("file", validRappFile, ContentType.MULTIPART_FORM_DATA.getMimeType(),
+ new FileInputStream(rappCsarPath));
+ mockMvc.perform(
+ MockMvcRequestBuilders.multipart("/rapps/{rapp_id}/onboard", UUID.randomUUID()).file(multipartFile))
+ .andExpect(status().isAccepted());
+ }
+
+ @Test
+ void testOnboardCsarPackageFailure() throws Exception {
+ String rappCsarPath = rappManagerConfiguration.getCsarLocation() + File.separator + invalidRappFile;
+ MockMultipartFile multipartFile =
+ new MockMultipartFile("file", invalidRappFile, ContentType.MULTIPART_FORM_DATA.getMimeType(),
+ new FileInputStream(rappCsarPath));
+ mockMvc.perform(
+ MockMvcRequestBuilders.multipart("/rapps/{rapp_id}/onboard", UUID.randomUUID()).file(multipartFile))
+ .andExpect(status().isBadRequest());
+ }
+
+ @Test
+ void testGetRapp() throws Exception {
+ UUID rappId = UUID.randomUUID();
+ this.onBoardRappCsar(rappId);
+ this.mockMvc.perform(MockMvcRequestBuilders.get("/rapps/{rapp_id}", rappId)).andExpect(status().isOk())
+ .andExpect(jsonPath("$.name").value(rappId.toString()))
+ .andExpect(jsonPath("$.state").value(RappState.ONBOARDED.name()));
+ }
+
+ @Test
+ void testGetInvalidRapp() throws Exception {
+ UUID rappId = UUID.randomUUID();
+ this.mockMvc.perform(MockMvcRequestBuilders.get("/rapps/{rapp_id}", rappId)).andDo(print())
+ .andExpect(status().isBadRequest());
+ }
+
+ @Test
+ void testRappDeploy() throws Exception {
+ UUID rappId = UUID.randomUUID();
+ this.onBoardRappCsar(rappId);
+ when(acmDeployer.deployRapp(any())).thenReturn(true);
+ when(smeDeployer.deployRapp(any())).thenReturn(true);
+ mockMvc.perform(MockMvcRequestBuilders.multipart("/rapps/{rapp_id}/deploy", rappId))
+ .andExpect(status().isAccepted());
+ }
+
+ @Test
+ void testInvalidRappDeploy() throws Exception {
+ UUID rappId = UUID.randomUUID();
+ when(acmDeployer.deployRapp(any())).thenReturn(false);
+ mockMvc.perform(MockMvcRequestBuilders.multipart("/rapps/{rapp_id}/deploy", rappId))
+ .andExpect(status().isInternalServerError());
+ }
+
+ @Test
+ void testRappUndeploy() throws Exception {
+ UUID rappId = UUID.randomUUID();
+ this.onBoardRappCsar(rappId);
+ when(acmDeployer.undeployRapp(any())).thenReturn(true);
+ when(smeDeployer.undeployRapp(any())).thenReturn(true);
+ mockMvc.perform(MockMvcRequestBuilders.multipart("/rapps/{rapp_id}/undeploy", rappId))
+ .andExpect(status().isAccepted());
+ }
+
+ @Test
+ void testInvalidRappUndeploy() throws Exception {
+ UUID rappId = UUID.randomUUID();
+ when(acmDeployer.undeployRapp(any())).thenReturn(false);
+ mockMvc.perform(MockMvcRequestBuilders.multipart("/rapps/{rapp_id}/undeploy", rappId))
+ .andExpect(status().isInternalServerError());
+ }
+
+ void onBoardRappCsar(UUID rappId) throws Exception {
+ String rappCsarPath = rappManagerConfiguration.getCsarLocation() + File.separator + validRappFile;
+ MockMultipartFile multipartFile =
+ new MockMultipartFile("file", validRappFile, ContentType.MULTIPART_FORM_DATA.getMimeType(),
+ new FileInputStream(rappCsarPath));
+ mockMvc.perform(MockMvcRequestBuilders.multipart("/rapps/{rapp_id}/onboard", rappId).file(multipartFile))
+ .andExpect(status().isAccepted());
+ }
+
+}
diff --git a/rapp-manager-application/src/test/java/com/oransc/rappmanager/service/AcmDeployerTest.java b/rapp-manager-application/src/test/java/com/oransc/rappmanager/service/AcmDeployerTest.java
new file mode 100755
index 0000000..5682ca0
--- /dev/null
+++ b/rapp-manager-application/src/test/java/com/oransc/rappmanager/service/AcmDeployerTest.java
@@ -0,0 +1,313 @@
+/*-
+ * ============LICENSE_START======================================================================
+ * Copyright (C) 2023 Nordix Foundation. 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END========================================================================
+ */
+
+package com.oransc.rappmanager.service;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.springframework.test.web.client.match.MockRestRequestMatchers.method;
+import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo;
+import static org.springframework.test.web.client.response.MockRestResponseCreators.withStatus;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.oransc.rappmanager.acm.configuration.ACMConfiguration;
+import com.oransc.rappmanager.acm.service.AcmDeployer;
+import com.oransc.rappmanager.configuration.RappManagerConfiguration;
+import com.oransc.rappmanager.models.Rapp;
+import com.oransc.rappmanager.models.RappEvent;
+import com.oransc.rappmanager.models.RappState;
+import com.oransc.rappmanager.models.cache.RappCacheService;
+import com.oransc.rappmanager.models.statemachine.RappStateMachine;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.UUID;
+import org.apache.http.entity.ContentType;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestInstance;
+import org.onap.policy.clamp.models.acm.concepts.AutomationComposition;
+import org.onap.policy.clamp.models.acm.concepts.DeployState;
+import org.onap.policy.clamp.models.acm.concepts.LockState;
+import org.onap.policy.clamp.models.acm.messages.rest.commissioning.CommissioningResponse;
+import org.onap.policy.clamp.models.acm.messages.rest.commissioning.PrimeOrder;
+import org.onap.policy.clamp.models.acm.messages.rest.instantiation.InstantiationResponse;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.mock.mockito.SpyBean;
+import org.springframework.http.HttpMethod;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.MediaType;
+import org.springframework.mock.web.MockMultipartFile;
+import org.springframework.test.context.TestPropertySource;
+import org.springframework.test.web.client.ExpectedCount;
+import org.springframework.test.web.client.MockRestServiceServer;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
+import org.springframework.web.client.RestTemplate;
+
+@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
+@TestPropertySource(properties = "rappmanager.csarlocation=src/test/resources")
+@TestInstance(TestInstance.Lifecycle.PER_CLASS)
+@AutoConfigureMockMvc
+public class AcmDeployerTest {
+
+ MockRestServiceServer mockServer;
+ @SpyBean
+ AcmDeployer acmDeployer;
+ @Autowired
+ RestTemplate restTemplate;
+ @Autowired
+ ACMConfiguration acmConfiguration;
+ @Autowired
+ RappManagerConfiguration rappManagerConfiguration;
+ @Autowired
+ private MockMvc mockMvc;
+ @Autowired
+ RappCacheService rappCacheService;
+ @SpyBean
+ RappStateMachine rappStateMachine;
+ private final String validRappFile = "valid-rapp-package.csar";
+ ObjectMapper objectMapper = new ObjectMapper();
+ String URI_ACM_COMPOSITIONS, URI_ACM_COMPOSITION, URI_ACM_INSTANCES, URI_ACM_INSTANCE;
+
+ @BeforeAll
+ void initACMURI() {
+ URI_ACM_COMPOSITIONS = acmConfiguration.getBaseUrl() + "compositions";
+ URI_ACM_COMPOSITION = acmConfiguration.getBaseUrl() + "compositions/%s";
+ URI_ACM_INSTANCES = acmConfiguration.getBaseUrl() + "compositions/%s/instances";
+ URI_ACM_INSTANCE = acmConfiguration.getBaseUrl() + "compositions/%s/instances/%s";
+ }
+
+
+ @BeforeEach
+ public void init() {
+ mockServer = MockRestServiceServer.createServer(restTemplate);
+ }
+
+ @Test
+ void testCreateComposition() throws IOException {
+ String compositionPayload = Files.readString(Path.of(acmConfiguration.getCompositionDefinitionLocation()));
+ CommissioningResponse commissioningResponseExpected = new CommissioningResponse();
+ commissioningResponseExpected.setCompositionId(UUID.randomUUID());
+ mockServer.expect(ExpectedCount.once(), requestTo(URI_ACM_COMPOSITIONS)).andExpect(method(HttpMethod.POST))
+ .andRespond(withStatus(HttpStatus.OK).contentType(MediaType.APPLICATION_JSON)
+ .body(objectMapper.writeValueAsString(commissioningResponseExpected)));
+ CommissioningResponse commissioningResponseActual = acmDeployer.createComposition(compositionPayload);
+ mockServer.verify();
+ assertEquals(commissioningResponseActual.getCompositionId(), commissioningResponseExpected.getCompositionId());
+ }
+
+ @Test
+ void testCreateCompositionFailure() throws IOException {
+ String compositionPayload = Files.readString(Path.of(acmConfiguration.getCompositionDefinitionLocation()));
+ mockServer.expect(ExpectedCount.once(), requestTo(URI_ACM_COMPOSITIONS)).andExpect(method(HttpMethod.POST))
+ .andRespond(withStatus(HttpStatus.BAD_GATEWAY));
+ CommissioningResponse commissioningResponseActual = acmDeployer.createComposition(compositionPayload);
+ mockServer.verify();
+ assertNull(commissioningResponseActual);
+ }
+
+ @Test
+ void testCompositionPriming() {
+ UUID compositionId = UUID.randomUUID();
+ mockServer.expect(ExpectedCount.once(), requestTo(String.format(URI_ACM_COMPOSITION, compositionId)))
+ .andExpect(method(HttpMethod.PUT)).andRespond(withStatus(HttpStatus.ACCEPTED));
+
+ acmDeployer.primeACMComposition(compositionId, PrimeOrder.PRIME);
+ mockServer.verify();
+ }
+
+ @Test
+ void testDeployRapp() throws Exception {
+
+ UUID compositionId = UUID.randomUUID();
+ when(acmDeployer.getCompositionId()).thenReturn(compositionId);
+ UUID rappId = UUID.randomUUID();
+ UUID instanceId = UUID.randomUUID();
+ Rapp rapp = Rapp.builder().name(rappId.toString()).packageName(validRappFile).compositionId(compositionId)
+ .packageLocation(rappManagerConfiguration.getCsarLocation()).state(RappState.ONBOARDED)
+ .build();
+ onBoardRappCsar(rappId);
+ InstantiationResponse instantiationResponse = new InstantiationResponse();
+ instantiationResponse.setInstanceId(instanceId);
+ mockServer.expect(ExpectedCount.once(), requestTo(String.format(URI_ACM_INSTANCES, compositionId)))
+ .andExpect(method(HttpMethod.POST)).andRespond(
+ withStatus(HttpStatus.ACCEPTED).contentType(MediaType.APPLICATION_JSON)
+ .body(objectMapper.writeValueAsString(instantiationResponse)));
+
+ mockServer.expect(ExpectedCount.once(),
+ requestTo(acmConfiguration.getBaseUrl() + "compositions/" + compositionId + "/instances/" + instanceId))
+ .andExpect(method(HttpMethod.PUT)).andRespond(withStatus(HttpStatus.ACCEPTED));
+
+
+ boolean rappDeployStateActual = acmDeployer.deployRapp(rapp);
+ assertTrue(rappDeployStateActual);
+ mockServer.verify();
+ }
+
+ @Test
+ void testDeployRappFailure() throws Exception {
+ UUID compositionId = UUID.randomUUID();
+ when(acmDeployer.getCompositionId()).thenReturn(compositionId);
+ UUID rappId = UUID.randomUUID();
+ UUID instanceId = UUID.randomUUID();
+ Rapp rapp = Rapp.builder().name(rappId.toString()).packageName(validRappFile).compositionId(compositionId)
+ .packageLocation(rappManagerConfiguration.getCsarLocation()).state(RappState.ONBOARDED)
+ .build();
+ onBoardRappCsar(rappId);
+ InstantiationResponse instantiationResponse = new InstantiationResponse();
+ instantiationResponse.setInstanceId(instanceId);
+ mockServer.expect(ExpectedCount.once(), requestTo(String.format(URI_ACM_INSTANCES, compositionId)))
+ .andExpect(method(HttpMethod.POST)).andRespond(withStatus(HttpStatus.BAD_GATEWAY));
+
+ boolean rappDeployStateActual = acmDeployer.deployRapp(rapp);
+ mockServer.verify();
+ assertFalse(rappDeployStateActual);
+ }
+
+ @Test
+ void testUndeployRapp() throws JsonProcessingException {
+ UUID compositionId = UUID.randomUUID();
+ when(acmDeployer.getCompositionId()).thenReturn(compositionId);
+ UUID rappId = UUID.randomUUID();
+ UUID instanceId = UUID.randomUUID();
+ Rapp rapp = Rapp.builder().rappId(rappId).name(rappId.toString()).packageName(validRappFile)
+ .compositionId(compositionId).compositionInstanceId(instanceId).state(RappState.DEPLOYED)
+ .build();
+ rappCacheService.putRapp(rapp);
+ rappStateMachine.onboardRapp(rappId);
+
+ expectAcmGetInstanceToReturnDeployedState(compositionId, instanceId, DeployState.DEPLOYED, LockState.LOCKED,
+ ExpectedCount.once());
+
+ mockServer.expect(ExpectedCount.once(), requestTo(String.format(URI_ACM_INSTANCE, compositionId, instanceId)))
+ .andExpect(method(HttpMethod.PUT)).andRespond(withStatus(HttpStatus.ACCEPTED));
+
+ expectAcmGetInstanceToReturnDeployedState(compositionId, instanceId, DeployState.UNDEPLOYED, LockState.UNLOCKED,
+ ExpectedCount.once());
+
+ mockServer.expect(ExpectedCount.once(), requestTo(String.format(URI_ACM_INSTANCE, compositionId, instanceId)))
+ .andExpect(method(HttpMethod.DELETE)).andRespond(withStatus(HttpStatus.NO_CONTENT));
+
+
+ boolean rappUndeployStateActual = acmDeployer.undeployRapp(rapp);
+ mockServer.verify();
+ assertTrue(rappUndeployStateActual);
+ }
+
+ @Test
+ void testUndeployRappFailure() throws JsonProcessingException {
+ UUID compositionId = UUID.randomUUID();
+ when(acmDeployer.getCompositionId()).thenReturn(compositionId);
+ UUID rappId = UUID.randomUUID();
+ UUID instanceId = UUID.randomUUID();
+ Rapp rapp = Rapp.builder().name(rappId.toString()).packageName(validRappFile).compositionId(compositionId)
+ .compositionInstanceId(instanceId).state(RappState.DEPLOYED).build();
+ rappCacheService.putRapp(rapp);
+
+ expectAcmGetInstanceToReturnDeployedState(compositionId, instanceId, DeployState.DEPLOYED, LockState.LOCKED,
+ ExpectedCount.once());
+
+ mockServer.expect(ExpectedCount.once(), requestTo(String.format(URI_ACM_INSTANCE, compositionId, instanceId)))
+ .andExpect(method(HttpMethod.PUT)).andRespond(withStatus(HttpStatus.ACCEPTED));
+
+ expectAcmGetInstanceToReturnDeployedState(compositionId, instanceId, DeployState.UNDEPLOYING,
+ LockState.UNLOCKING, ExpectedCount.manyTimes());
+
+ boolean rappUndeployStateActual = acmDeployer.undeployRapp(rapp);
+ mockServer.verify();
+ assertFalse(rappUndeployStateActual);
+ }
+
+ @Test
+ void testSyncRappStatus() throws JsonProcessingException {
+ UUID compositionId = UUID.randomUUID();
+ when(acmDeployer.getCompositionId()).thenReturn(compositionId);
+ UUID rappId = UUID.randomUUID();
+ UUID instanceId = UUID.randomUUID();
+ Rapp rapp = Rapp.builder().rappId(rappId).name(rappId.toString()).packageName(validRappFile)
+ .compositionId(compositionId).compositionInstanceId(instanceId).state(RappState.DEPLOYED)
+ .build();
+ rappCacheService.putRapp(rapp);
+ rappStateMachine.onboardRapp(rappId);
+
+ expectAcmGetInstanceToReturnDeployedState(compositionId, instanceId, DeployState.UNDEPLOYING,
+ LockState.UNLOCKING, ExpectedCount.once());
+
+ acmDeployer.syncRappStatus(rapp);
+ mockServer.verify();
+ verify(rappStateMachine, times(1)).sendRappEvent(rapp, RappEvent.UNDEPLOYING);
+ }
+
+ @Test
+ void testSyncRappStatusFailure() {
+ UUID compositionId = UUID.randomUUID();
+ when(acmDeployer.getCompositionId()).thenReturn(compositionId);
+ UUID rappId = UUID.randomUUID();
+ UUID instanceId = UUID.randomUUID();
+ Rapp rapp = Rapp.builder().name(rappId.toString()).packageName(validRappFile).compositionId(compositionId)
+ .compositionInstanceId(instanceId).state(RappState.DEPLOYED).build();
+ rappCacheService.putRapp(rapp);
+
+ mockServer.expect(ExpectedCount.once(), requestTo(String.format(URI_ACM_INSTANCE, compositionId, instanceId)))
+ .andExpect(method(HttpMethod.GET)).andRespond(withStatus(HttpStatus.BAD_GATEWAY));
+
+ acmDeployer.syncRappStatus(rapp);
+ mockServer.verify();
+ verify(rappStateMachine, never()).sendRappEvent(any(), any());
+ }
+
+ void expectAcmGetInstanceToReturnDeployedState(UUID compositionId, UUID instanceId, DeployState deployState,
+ LockState lockState, ExpectedCount expectedCount) throws JsonProcessingException {
+ AutomationComposition automationCompositionDeployed = new AutomationComposition();
+ automationCompositionDeployed.setCompositionId(compositionId);
+ automationCompositionDeployed.setInstanceId(instanceId);
+ automationCompositionDeployed.setDeployState(deployState);
+ automationCompositionDeployed.setLockState(lockState);
+
+ mockServer.expect(expectedCount, requestTo(String.format(URI_ACM_INSTANCE, compositionId, instanceId)))
+ .andExpect(method(HttpMethod.GET)).andRespond(
+ withStatus(HttpStatus.OK).contentType(MediaType.APPLICATION_JSON)
+ .body(objectMapper.writeValueAsString(automationCompositionDeployed)));
+ }
+
+ void onBoardRappCsar(UUID rappId) throws Exception {
+ String rappCsarPath = rappManagerConfiguration.getCsarLocation() + File.separator + validRappFile;
+ MockMultipartFile multipartFile =
+ new MockMultipartFile("file", validRappFile, ContentType.MULTIPART_FORM_DATA.getMimeType(),
+ new FileInputStream(rappCsarPath));
+ mockMvc.perform(MockMvcRequestBuilders.multipart("/rapps/{rapp_id}/onboard", rappId).file(multipartFile))
+ .andExpect(status().isAccepted());
+ }
+
+
+}
diff --git a/rapp-manager-application/src/test/java/com/oransc/rappmanager/service/RappCsarConfigurationHandlerTest.java b/rapp-manager-application/src/test/java/com/oransc/rappmanager/service/RappCsarConfigurationHandlerTest.java
new file mode 100755
index 0000000..f92becb
--- /dev/null
+++ b/rapp-manager-application/src/test/java/com/oransc/rappmanager/service/RappCsarConfigurationHandlerTest.java
@@ -0,0 +1,87 @@
+/*-
+ * ============LICENSE_START======================================================================
+ * Copyright (C) 2023 Nordix Foundation. 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END========================================================================
+ */
+
+package com.oransc.rappmanager.service;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.oransc.rappmanager.configuration.RappManagerConfiguration;
+
+import com.oransc.rappmanager.models.Rapp;
+import com.oransc.rappmanager.models.RappCsarConfigurationHandler;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.util.UUID;
+import org.apache.http.entity.ContentType;
+import org.junit.jupiter.api.Test;
+import org.onap.policy.clamp.models.acm.concepts.AutomationComposition;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.mock.web.MockMultipartFile;
+import org.springframework.test.context.TestPropertySource;
+import org.springframework.web.multipart.MultipartFile;
+
+@SpringBootTest
+@TestPropertySource(properties = "rappmanager.csarlocation=src/test/resources")
+public class RappCsarConfigurationHandlerTest {
+
+ @Autowired
+ RappCsarConfigurationHandler rappCsarConfigurationHandler;
+
+ @Autowired
+ RappManagerConfiguration rappManagerConfiguration;
+
+ ObjectMapper objectMapper = new ObjectMapper();
+
+
+ private final String validRappFile = "valid-rapp-package.csar";
+
+ private final String invalidRappFile = "invalid-rapp-package.csar";
+
+ @Test
+ void testCsarPackageValidationSuccess() throws IOException {
+ String rappCsarPath = rappManagerConfiguration.getCsarLocation() + File.separator + validRappFile;
+ MultipartFile multipartFile =
+ new MockMultipartFile(rappCsarPath, rappCsarPath, ContentType.MULTIPART_FORM_DATA.getMimeType(),
+ new FileInputStream(rappCsarPath));
+ assertEquals(Boolean.TRUE, rappCsarConfigurationHandler.isValidRappPackage(multipartFile));
+ }
+
+ @Test
+ void testCsarPackageValidationFailure() throws IOException {
+ String rappCsarPath = rappManagerConfiguration.getCsarLocation() + File.separator + invalidRappFile;
+ MultipartFile multipartFile =
+ new MockMultipartFile(rappCsarPath, rappCsarPath, ContentType.MULTIPART_FORM_DATA.getMimeType(),
+ new FileInputStream(rappCsarPath));
+ assertEquals(Boolean.FALSE, rappCsarConfigurationHandler.isValidRappPackage(multipartFile));
+ }
+
+ @Test
+ void testCsarInstantiationPayload() throws JsonProcessingException {
+ Rapp rapp = Rapp.builder().name("").packageName(validRappFile)
+ .packageLocation(rappManagerConfiguration.getCsarLocation()).build();
+ UUID compositionId = UUID.randomUUID();
+ AutomationComposition automationComposition =
+ objectMapper.readValue(rappCsarConfigurationHandler.getInstantiationPayload(rapp, compositionId),
+ AutomationComposition.class);
+ assertEquals(automationComposition.getCompositionId(), compositionId);
+ }
+}
diff --git a/rapp-manager-application/src/test/java/com/oransc/rappmanager/sme/service/SmeDeployerTest.java b/rapp-manager-application/src/test/java/com/oransc/rappmanager/sme/service/SmeDeployerTest.java
new file mode 100755
index 0000000..b45d855
--- /dev/null
+++ b/rapp-manager-application/src/test/java/com/oransc/rappmanager/sme/service/SmeDeployerTest.java
@@ -0,0 +1,440 @@
+/*-
+ * ============LICENSE_START======================================================================
+ * Copyright (C) 2023 Nordix Foundation. 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END========================================================================
+ */
+
+package com.oransc.rappmanager.sme.service;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.springframework.test.web.client.match.MockRestRequestMatchers.method;
+import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo;
+import static org.springframework.test.web.client.response.MockRestResponseCreators.withStatus;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.oransc.rappmanager.configuration.RappManagerConfiguration;
+import com.oransc.rappmanager.models.Rapp;
+import com.oransc.rappmanager.models.RappState;
+import com.oransc.rappmanager.models.cache.RappCacheService;
+import com.oransc.rappmanager.models.statemachine.RappStateMachine;
+import com.oransc.rappmanager.sme.configuration.SmeConfiguration;
+import com.oransc.rappmanager.sme.invoker.data.APIInvokerEnrolmentDetails;
+import com.oransc.rappmanager.sme.provider.data.APIProviderEnrolmentDetails;
+import com.oransc.rappmanager.sme.provider.data.APIProviderFunctionDetails;
+import com.oransc.rappmanager.sme.provider.data.ApiProviderFuncRole;
+import com.oransc.rappmanager.sme.publishservice.data.AefProfile;
+import com.oransc.rappmanager.sme.publishservice.data.ServiceAPIDescription;
+import java.io.File;
+import java.io.FileInputStream;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+import org.apache.http.entity.ContentType;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestInstance;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.mock.mockito.SpyBean;
+import org.springframework.http.HttpMethod;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.MediaType;
+import org.springframework.mock.web.MockMultipartFile;
+import org.springframework.test.context.TestPropertySource;
+import org.springframework.test.web.client.ExpectedCount;
+import org.springframework.test.web.client.MockRestServiceServer;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
+import org.springframework.web.client.RestTemplate;
+
+@SpringBootTest
+@TestPropertySource(properties = "rappmanager.csarlocation=src/test/resources")
+@TestInstance(TestInstance.Lifecycle.PER_CLASS)
+@AutoConfigureMockMvc
+public class SmeDeployerTest {
+
+ MockRestServiceServer mockServer;
+ @SpyBean
+ SmeDeployer smeDeployer;
+ @Autowired
+ RestTemplate restTemplate;
+ @Autowired
+ SmeConfiguration smeConfiguration;
+ @Autowired
+ RappManagerConfiguration rappManagerConfiguration;
+ @Autowired
+ private MockMvc mockMvc;
+ @Autowired
+ RappCacheService rappCacheService;
+ @SpyBean
+ RappStateMachine rappStateMachine;
+ private final String validRappFile = "valid-rapp-package.csar";
+ ObjectMapper objectMapper = new ObjectMapper();
+ String URI_PROVIDER_REGISTRATIONS, URI_PROVIDER_REGISTRATION, URI_PUBLISH_APIS, URI_PUBLISH_API, URI_INVOKERS,
+ URI_INVOKER;
+
+ @BeforeAll
+ void initSmeUri() {
+ URI_PROVIDER_REGISTRATIONS =
+ smeConfiguration.getBaseUrl() + smeConfiguration.getProviderBasePath() + "registrations";
+ URI_PROVIDER_REGISTRATION =
+ smeConfiguration.getBaseUrl() + smeConfiguration.getProviderBasePath() + "registrations/%s";
+ URI_PUBLISH_APIS = smeConfiguration.getBaseUrl() + smeConfiguration.getPublishApiBasePath() + "%s/service-apis";
+ URI_PUBLISH_API =
+ smeConfiguration.getBaseUrl() + smeConfiguration.getPublishApiBasePath() + "%s/service-apis/%s";
+ URI_INVOKERS = smeConfiguration.getBaseUrl() + smeConfiguration.getInvokerBasePath() + "onboardedInvokers";
+ URI_INVOKER = smeConfiguration.getBaseUrl() + smeConfiguration.getInvokerBasePath() + "onboardedInvokers/%s";
+ }
+
+ @BeforeEach
+ public void init() {
+ mockServer = MockRestServiceServer.createServer(restTemplate);
+ }
+
+ @Test
+ void testCreateAMF() throws JsonProcessingException {
+ String apiProvDomId = UUID.randomUUID().toString();
+ APIProviderEnrolmentDetails apiProviderEnrolmentDetails = new APIProviderEnrolmentDetails(apiProvDomId);
+ mockServer.expect(ExpectedCount.once(), requestTo(URI_PROVIDER_REGISTRATIONS))
+ .andExpect(method(HttpMethod.POST)).andRespond(
+ withStatus(HttpStatus.OK).contentType(MediaType.APPLICATION_JSON)
+ .body(objectMapper.writeValueAsString(apiProviderEnrolmentDetails)));
+ APIProviderEnrolmentDetails apiProviderEnrolmentResponse = smeDeployer.createAMF();
+ mockServer.verify();
+ assertEquals(apiProvDomId, apiProviderEnrolmentResponse.getApiProvDomId());
+ }
+
+ @Test
+ void testCreateAMFFailure() {
+ mockServer.expect(ExpectedCount.once(), requestTo(URI_PROVIDER_REGISTRATIONS))
+ .andExpect(method(HttpMethod.POST)).andRespond(withStatus(HttpStatus.INTERNAL_SERVER_ERROR));
+ APIProviderEnrolmentDetails apiProviderEnrolmentResponse = smeDeployer.createAMF();
+ mockServer.verify();
+ assertNull(apiProviderEnrolmentResponse);
+ }
+
+ @Test
+ void testDeleteAMF() throws JsonProcessingException {
+ String apiProvDomId = UUID.randomUUID().toString();
+ APIProviderEnrolmentDetails apiProviderEnrolmentDetails = new APIProviderEnrolmentDetails(apiProvDomId);
+ mockServer.expect(ExpectedCount.once(), requestTo(URI_PROVIDER_REGISTRATIONS))
+ .andExpect(method(HttpMethod.POST)).andRespond(
+ withStatus(HttpStatus.OK).contentType(MediaType.APPLICATION_JSON)
+ .body(objectMapper.writeValueAsString(apiProviderEnrolmentDetails)));
+ mockServer.expect(ExpectedCount.once(), requestTo(String.format(URI_PROVIDER_REGISTRATION, apiProvDomId)))
+ .andExpect(method(HttpMethod.DELETE)).andRespond(withStatus(HttpStatus.NO_CONTENT));
+ smeDeployer.createAMF();
+ smeDeployer.deleteAMF();
+ mockServer.verify();
+ }
+
+ @Test
+ void testCreateProviderDomain() throws Exception {
+ UUID rappId = UUID.randomUUID();
+ Rapp rapp = Rapp.builder().rappId(rappId).name(rappId.toString()).packageName(validRappFile)
+ .packageLocation(rappManagerConfiguration.getCsarLocation()).state(RappState.ONBOARDED)
+ .build();
+ onBoardRappCsar(rappId);
+ APIProviderEnrolmentDetails apiProviderEnrolmentDetails = getProviderDomainApiEnrollmentDetails();
+ mockServer.expect(ExpectedCount.once(), requestTo(URI_PROVIDER_REGISTRATIONS))
+ .andExpect(method(HttpMethod.POST)).andRespond(
+ withStatus(HttpStatus.OK).contentType(MediaType.APPLICATION_JSON)
+ .body(objectMapper.writeValueAsString(apiProviderEnrolmentDetails)));
+ boolean createProviderDomain = smeDeployer.createProviderDomain(rapp);
+ mockServer.verify();
+ assertTrue(createProviderDomain);
+ }
+
+ @Test
+ void testCreateProviderDomainFailure() throws Exception {
+ UUID rappId = UUID.randomUUID();
+ Rapp rapp = Rapp.builder().rappId(rappId).name(rappId.toString()).packageName(validRappFile)
+ .packageLocation(rappManagerConfiguration.getCsarLocation()).state(RappState.ONBOARDED)
+ .build();
+ onBoardRappCsar(rappId);
+ mockServer.expect(ExpectedCount.once(), requestTo(URI_PROVIDER_REGISTRATIONS))
+ .andExpect(method(HttpMethod.POST)).andRespond(withStatus(HttpStatus.INTERNAL_SERVER_ERROR));
+ boolean createProviderDomain = smeDeployer.createProviderDomain(rapp);
+ mockServer.verify();
+ assertFalse(createProviderDomain);
+ }
+
+ @Test
+ void testDeleteProviderFunc() {
+ UUID registrationId = UUID.randomUUID();
+ mockServer.expect(ExpectedCount.once(), requestTo(String.format(URI_PROVIDER_REGISTRATION, registrationId)))
+ .andExpect(method(HttpMethod.DELETE)).andRespond(withStatus(HttpStatus.NO_CONTENT));
+ smeDeployer.deleteProviderFunc(String.valueOf(registrationId));
+ mockServer.verify();
+ }
+
+ @Test
+ void testCreatePublishApi() throws Exception {
+ UUID rappId = UUID.randomUUID();
+ UUID apfId = UUID.randomUUID();
+ Rapp rapp = Rapp.builder().rappId(rappId).name(rappId.toString()).packageName(validRappFile)
+ .packageLocation(rappManagerConfiguration.getCsarLocation()).state(RappState.ONBOARDED)
+ .smeApfId(String.valueOf(apfId)).build();
+ onBoardRappCsar(rappId);
+ ServiceAPIDescription serviceAPIDescription = getServiceApiDescription();
+ mockServer.expect(ExpectedCount.once(), requestTo(String.format(URI_PUBLISH_APIS, apfId)))
+ .andExpect(method(HttpMethod.POST)).andRespond(
+ withStatus(HttpStatus.OK).contentType(MediaType.APPLICATION_JSON)
+ .body(objectMapper.writeValueAsString(serviceAPIDescription)));
+ boolean publishApi = smeDeployer.createPublishApi(rapp);
+ mockServer.verify();
+ assertTrue(publishApi);
+ }
+
+
+ @Test
+ void testCreatePublishApiFailure() throws Exception {
+ UUID rappId = UUID.randomUUID();
+ UUID apfId = UUID.randomUUID();
+ Rapp rapp = Rapp.builder().rappId(rappId).name(rappId.toString()).packageName(validRappFile)
+ .packageLocation(rappManagerConfiguration.getCsarLocation()).state(RappState.ONBOARDED)
+ .smeApfId(String.valueOf(apfId)).build();
+ onBoardRappCsar(rappId);
+ mockServer.expect(ExpectedCount.once(), requestTo(String.format(URI_PUBLISH_APIS, apfId)))
+ .andExpect(method(HttpMethod.POST)).andRespond(withStatus(HttpStatus.INTERNAL_SERVER_ERROR));
+ boolean publishApi = smeDeployer.createPublishApi(rapp);
+ mockServer.verify();
+ assertFalse(publishApi);
+ }
+
+ @Test
+ void testDeletePublishApi() {
+ String serviceApiId = String.valueOf(UUID.randomUUID());
+ String apfId = String.valueOf(UUID.randomUUID());
+ mockServer.expect(ExpectedCount.once(), requestTo(String.format(URI_PUBLISH_API, apfId, serviceApiId)))
+ .andExpect(method(HttpMethod.DELETE)).andRespond(withStatus(HttpStatus.NO_CONTENT));
+ smeDeployer.deletePublishApi(serviceApiId, apfId);
+ mockServer.verify();
+ }
+
+ @Test
+ void testCreateInvoker() throws Exception {
+ UUID rappId = UUID.randomUUID();
+ UUID apfId = UUID.randomUUID();
+ Rapp rapp = Rapp.builder().rappId(rappId).name(rappId.toString()).packageName(validRappFile)
+ .packageLocation(rappManagerConfiguration.getCsarLocation()).state(RappState.ONBOARDED)
+ .smeApfId(String.valueOf(apfId)).build();
+ onBoardRappCsar(rappId);
+ APIInvokerEnrolmentDetails apiInvokerEnrolmentDetails = getApiInvokerEnrollmentDetails();
+ mockServer.expect(ExpectedCount.once(), requestTo(URI_INVOKERS)).andExpect(method(HttpMethod.POST)).andRespond(
+ withStatus(HttpStatus.OK).contentType(MediaType.APPLICATION_JSON)
+ .body(objectMapper.writeValueAsString(apiInvokerEnrolmentDetails)));
+ boolean createInvoker = smeDeployer.createInvoker(rapp);
+ mockServer.verify();
+ assertTrue(createInvoker);
+ }
+
+ @Test
+ void testCreateInvokerFailure() throws Exception {
+ UUID rappId = UUID.randomUUID();
+ UUID apfId = UUID.randomUUID();
+ Rapp rapp = Rapp.builder().rappId(rappId).name(rappId.toString()).packageName(validRappFile)
+ .packageLocation(rappManagerConfiguration.getCsarLocation()).state(RappState.ONBOARDED)
+ .smeApfId(String.valueOf(apfId)).build();
+ onBoardRappCsar(rappId);
+ mockServer.expect(ExpectedCount.once(), requestTo(URI_INVOKERS)).andExpect(method(HttpMethod.POST))
+ .andRespond(withStatus(HttpStatus.INTERNAL_SERVER_ERROR));
+ boolean createInvoker = smeDeployer.createInvoker(rapp);
+ mockServer.verify();
+ assertFalse(createInvoker);
+ }
+
+ @Test
+ void testDeleteInvoker() {
+ String invokerId = String.valueOf(UUID.randomUUID());
+ mockServer.expect(ExpectedCount.once(), requestTo(String.format(URI_INVOKER, invokerId)))
+ .andExpect(method(HttpMethod.DELETE)).andRespond(withStatus(HttpStatus.NO_CONTENT));
+ smeDeployer.deleteInvoker(invokerId);
+ mockServer.verify();
+ }
+
+ @Test
+ void testDeployRapp() throws Exception {
+ UUID rappId = UUID.randomUUID();
+ APIProviderEnrolmentDetails apiProviderEnrolmentDetails = getProviderDomainApiEnrollmentDetails();
+ APIProviderFunctionDetails apfProviderFunctionDetails = apiProviderEnrolmentDetails.getApiProvFuncs().stream()
+ .filter(apiProviderFunctionDetails -> apiProviderFunctionDetails.getApiProvFuncRole()
+ .equals(ApiProviderFuncRole.APF))
+ .findFirst().get();
+ onBoardRappCsar(rappId);
+ Rapp rapp = rappCacheService.getRapp(String.valueOf(rappId)).get();
+ mockServer.expect(ExpectedCount.once(), requestTo(URI_PROVIDER_REGISTRATIONS))
+ .andExpect(method(HttpMethod.POST)).andRespond(
+ withStatus(HttpStatus.OK).contentType(MediaType.APPLICATION_JSON)
+ .body(objectMapper.writeValueAsString(apiProviderEnrolmentDetails)));
+ ServiceAPIDescription serviceAPIDescription = getServiceApiDescription();
+ mockServer.expect(ExpectedCount.once(),
+ requestTo(String.format(URI_PUBLISH_APIS, apfProviderFunctionDetails.getApiProvFuncId())))
+ .andExpect(method(HttpMethod.POST)).andRespond(
+ withStatus(HttpStatus.OK).contentType(MediaType.APPLICATION_JSON)
+ .body(objectMapper.writeValueAsString(serviceAPIDescription)));
+ APIInvokerEnrolmentDetails apiInvokerEnrolmentDetails = getApiInvokerEnrollmentDetails();
+ mockServer.expect(ExpectedCount.once(), requestTo(URI_INVOKERS)).andExpect(method(HttpMethod.POST)).andRespond(
+ withStatus(HttpStatus.OK).contentType(MediaType.APPLICATION_JSON)
+ .body(objectMapper.writeValueAsString(apiInvokerEnrolmentDetails)));
+ boolean deployRapp = smeDeployer.deployRapp(rapp);
+ mockServer.verify();
+ assertTrue(deployRapp);
+ }
+
+ @Test
+ void testDeployRappFailure() throws Exception {
+ UUID rappId = UUID.randomUUID();
+ APIProviderEnrolmentDetails apiProviderEnrolmentDetails = getProviderDomainApiEnrollmentDetails();
+ APIProviderFunctionDetails apfProviderFunctionDetails = apiProviderEnrolmentDetails.getApiProvFuncs().stream()
+ .filter(apiProviderFunctionDetails -> apiProviderFunctionDetails.getApiProvFuncRole()
+ .equals(ApiProviderFuncRole.APF))
+ .findFirst().get();
+ onBoardRappCsar(rappId);
+ Rapp rapp = rappCacheService.getRapp(String.valueOf(rappId)).get();
+ mockServer.expect(ExpectedCount.once(), requestTo(URI_PROVIDER_REGISTRATIONS))
+ .andExpect(method(HttpMethod.POST)).andRespond(
+ withStatus(HttpStatus.OK).contentType(MediaType.APPLICATION_JSON)
+ .body(objectMapper.writeValueAsString(apiProviderEnrolmentDetails)));
+ ServiceAPIDescription serviceAPIDescription = getServiceApiDescription();
+ mockServer.expect(ExpectedCount.once(),
+ requestTo(String.format(URI_PUBLISH_APIS, apfProviderFunctionDetails.getApiProvFuncId())))
+ .andExpect(method(HttpMethod.POST)).andRespond(
+ withStatus(HttpStatus.OK).contentType(MediaType.APPLICATION_JSON)
+ .body(objectMapper.writeValueAsString(serviceAPIDescription)));
+ mockServer.expect(ExpectedCount.once(), requestTo(URI_INVOKERS)).andExpect(method(HttpMethod.POST))
+ .andRespond(withStatus(HttpStatus.INTERNAL_SERVER_ERROR));
+ boolean deployRapp = smeDeployer.deployRapp(rapp);
+ mockServer.verify();
+ assertFalse(deployRapp);
+ }
+
+ @Test
+ void testUndeployRapp() throws Exception {
+ UUID rappId = UUID.randomUUID();
+ UUID apfId = UUID.randomUUID();
+ List<String> invokers = List.of(String.valueOf(UUID.randomUUID()), String.valueOf(UUID.randomUUID()));
+ List<String> serviceApis = List.of(String.valueOf(UUID.randomUUID()), String.valueOf(UUID.randomUUID()));
+ Map<String, String> providerFuncs = Map.of(String.valueOf(UUID.randomUUID()), String.valueOf(UUID.randomUUID()),
+ String.valueOf(UUID.randomUUID()), String.valueOf(UUID.randomUUID()));
+ Rapp rapp = Rapp.builder().rappId(rappId).name(rappId.toString()).packageName(validRappFile)
+ .packageLocation(rappManagerConfiguration.getCsarLocation()).state(RappState.ONBOARDED)
+ .smeApfId(String.valueOf(apfId)).smeInvokers(invokers).smeServiceApis(serviceApis)
+ .smeProviderFunctions(providerFuncs).build();
+ onBoardRappCsar(rappId);
+ rapp.setRappId(rappCacheService.getRapp(String.valueOf(rappId)).get().getRappId());
+ mockServer.expect(ExpectedCount.once(), requestTo(String.format(URI_INVOKER, invokers.get(0))))
+ .andExpect(method(HttpMethod.DELETE)).andRespond(withStatus(HttpStatus.NO_CONTENT));
+ mockServer.expect(ExpectedCount.once(), requestTo(String.format(URI_INVOKER, invokers.get(1))))
+ .andExpect(method(HttpMethod.DELETE)).andRespond(withStatus(HttpStatus.NO_CONTENT));
+ mockServer.expect(ExpectedCount.once(), requestTo(String.format(URI_PUBLISH_API, apfId, serviceApis.get(0))))
+ .andExpect(method(HttpMethod.DELETE)).andRespond(withStatus(HttpStatus.NO_CONTENT));
+ mockServer.expect(ExpectedCount.once(), requestTo(String.format(URI_PUBLISH_API, apfId, serviceApis.get(1))))
+ .andExpect(method(HttpMethod.DELETE)).andRespond(withStatus(HttpStatus.NO_CONTENT));
+ mockServer.expect(ExpectedCount.once(),
+ requestTo(String.format(URI_PROVIDER_REGISTRATION, providerFuncs.values().toArray()[0])))
+ .andExpect(method(HttpMethod.DELETE)).andRespond(withStatus(HttpStatus.NO_CONTENT));
+ mockServer.expect(ExpectedCount.once(),
+ requestTo(String.format(URI_PROVIDER_REGISTRATION, providerFuncs.values().toArray()[1])))
+ .andExpect(method(HttpMethod.DELETE)).andRespond(withStatus(HttpStatus.NO_CONTENT));
+
+ boolean undeployRapp = smeDeployer.undeployRapp(rapp);
+ mockServer.verify();
+ assertTrue(undeployRapp);
+ }
+
+ @Test
+ void testUndeployRappFailure() throws Exception {
+ UUID rappId = UUID.randomUUID();
+ UUID apfId = UUID.randomUUID();
+ List<String> invokers = List.of(String.valueOf(UUID.randomUUID()), String.valueOf(UUID.randomUUID()));
+ List<String> serviceApis = List.of(String.valueOf(UUID.randomUUID()), String.valueOf(UUID.randomUUID()));
+ Map<String, String> providerFuncs = Map.of(String.valueOf(UUID.randomUUID()), String.valueOf(UUID.randomUUID()),
+ String.valueOf(UUID.randomUUID()), String.valueOf(UUID.randomUUID()));
+ Rapp rapp = Rapp.builder().rappId(rappId).name(rappId.toString()).packageName(validRappFile)
+ .packageLocation(rappManagerConfiguration.getCsarLocation()).state(RappState.ONBOARDED)
+ .smeApfId(String.valueOf(apfId)).smeInvokers(invokers).smeServiceApis(serviceApis)
+ .smeProviderFunctions(providerFuncs).build();
+ onBoardRappCsar(rappId);
+ mockServer.expect(ExpectedCount.once(), requestTo(String.format(URI_INVOKER, invokers.get(0))))
+ .andExpect(method(HttpMethod.DELETE)).andRespond(withStatus(HttpStatus.NO_CONTENT));
+ mockServer.expect(ExpectedCount.once(), requestTo(String.format(URI_INVOKER, invokers.get(1))))
+ .andExpect(method(HttpMethod.DELETE)).andRespond(withStatus(HttpStatus.NO_CONTENT));
+ mockServer.expect(ExpectedCount.once(), requestTo(String.format(URI_PUBLISH_API, apfId, serviceApis.get(0))))
+ .andExpect(method(HttpMethod.DELETE)).andRespond(withStatus(HttpStatus.NO_CONTENT));
+ mockServer.expect(ExpectedCount.once(), requestTo(String.format(URI_PUBLISH_API, apfId, serviceApis.get(1))))
+ .andExpect(method(HttpMethod.DELETE)).andRespond(withStatus(HttpStatus.NO_CONTENT));
+ mockServer.expect(ExpectedCount.once(),
+ requestTo(String.format(URI_PROVIDER_REGISTRATION, providerFuncs.values().toArray()[0])))
+ .andExpect(method(HttpMethod.DELETE)).andRespond(withStatus(HttpStatus.NO_CONTENT));
+ mockServer.expect(ExpectedCount.once(),
+ requestTo(String.format(URI_PROVIDER_REGISTRATION, providerFuncs.values().toArray()[1])))
+ .andExpect(method(HttpMethod.DELETE)).andRespond(withStatus(HttpStatus.INTERNAL_SERVER_ERROR));
+
+ boolean undeployRapp = smeDeployer.undeployRapp(rapp);
+ mockServer.verify();
+ assertFalse(undeployRapp);
+ }
+
+ APIProviderEnrolmentDetails getProviderDomainApiEnrollmentDetails() {
+ APIProviderEnrolmentDetails apiProviderEnrolmentDetails =
+ new APIProviderEnrolmentDetails(UUID.randomUUID().toString());
+ APIProviderFunctionDetails apiProviderFunctionDetailsAEF = new APIProviderFunctionDetails();
+ apiProviderFunctionDetailsAEF.setApiProvFuncInfo("AEF");
+ apiProviderFunctionDetailsAEF.setApiProvFuncRole(ApiProviderFuncRole.AEF);
+ apiProviderFunctionDetailsAEF.setApiProvFuncId(String.valueOf(UUID.randomUUID()));
+ APIProviderFunctionDetails apiProviderFunctionDetailsAPF = new APIProviderFunctionDetails();
+ apiProviderFunctionDetailsAPF.setApiProvFuncInfo("APF");
+ apiProviderFunctionDetailsAPF.setApiProvFuncRole(ApiProviderFuncRole.APF);
+ apiProviderFunctionDetailsAPF.setApiProvFuncId(String.valueOf(UUID.randomUUID()));
+ apiProviderEnrolmentDetails.setApiProvFuncs(
+ List.of(apiProviderFunctionDetailsAEF, apiProviderFunctionDetailsAPF));
+ return apiProviderEnrolmentDetails;
+ }
+
+
+ ServiceAPIDescription getServiceApiDescription() {
+ ServiceAPIDescription serviceAPIDescription = new ServiceAPIDescription();
+ AefProfile aefProfile = new AefProfile();
+ aefProfile.setAefId(String.valueOf(UUID.randomUUID()));
+ serviceAPIDescription.setAefProfiles(List.of(aefProfile));
+ return serviceAPIDescription;
+ }
+
+ APIInvokerEnrolmentDetails getApiInvokerEnrollmentDetails() {
+ APIInvokerEnrolmentDetails apiInvokerEnrolmentDetails = new APIInvokerEnrolmentDetails();
+ com.oransc.rappmanager.sme.invoker.data.ServiceAPIDescription serviceAPIDescription =
+ new com.oransc.rappmanager.sme.invoker.data.ServiceAPIDescription();
+ serviceAPIDescription.setApiId(String.valueOf(UUID.randomUUID()));
+ apiInvokerEnrolmentDetails.setApiList(List.of(serviceAPIDescription));
+ return apiInvokerEnrolmentDetails;
+ }
+
+ void onBoardRappCsar(UUID rappId) throws Exception {
+ String rappCsarPath = rappManagerConfiguration.getCsarLocation() + File.separator + validRappFile;
+ MockMultipartFile multipartFile =
+ new MockMultipartFile("file", validRappFile, ContentType.MULTIPART_FORM_DATA.getMimeType(),
+ new FileInputStream(rappCsarPath));
+ mockMvc.perform(MockMvcRequestBuilders.multipart("/rapps/{rapp_id}/onboard", rappId).file(multipartFile))
+ .andExpect(status().isAccepted());
+ }
+}
diff --git a/rapp-manager-application/src/test/java/com/oransc/rappmanager/statemachine/RappStateMachineTest.java b/rapp-manager-application/src/test/java/com/oransc/rappmanager/statemachine/RappStateMachineTest.java
new file mode 100755
index 0000000..6deb839
--- /dev/null
+++ b/rapp-manager-application/src/test/java/com/oransc/rappmanager/statemachine/RappStateMachineTest.java
@@ -0,0 +1,166 @@
+/*-
+ * ============LICENSE_START======================================================================
+ * Copyright (C) 2023 Nordix Foundation. 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END========================================================================
+ */
+
+package com.oransc.rappmanager.statemachine;
+
+import com.oransc.rappmanager.models.RappEvent;
+import com.oransc.rappmanager.models.RappState;
+import java.util.UUID;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.EnumSource;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.statemachine.StateMachine;
+import org.springframework.statemachine.config.StateMachineFactory;
+import org.springframework.statemachine.test.StateMachineTestPlan;
+import org.springframework.statemachine.test.StateMachineTestPlanBuilder;
+
+@SpringBootTest
+public class RappStateMachineTest {
+
+ @Autowired
+ StateMachineFactory<RappState, RappEvent> stateMachineFactory;
+
+ StateMachine<RappState, RappEvent> stateMachine;
+
+ @BeforeEach
+ void getStateMachine() {
+ stateMachine = stateMachineFactory.getStateMachine(UUID.randomUUID());
+ stateMachine.startReactively().subscribe();
+ }
+
+ @AfterEach
+ void stopStateMachine() {
+ stateMachine.stopReactively().subscribe();
+ }
+
+ @Test
+ void testOnboardedState() throws Exception {
+ StateMachineTestPlan plan =
+ StateMachineTestPlanBuilder.<RappState, RappEvent>builder().stateMachine(stateMachine).step()
+ .expectState(RappState.ONBOARDED).and().build();
+ plan.test();
+ }
+
+ @Test
+ void testDeployingState() throws Exception {
+ StateMachineTestPlan plan =
+ StateMachineTestPlanBuilder.<RappState, RappEvent>builder().stateMachine(stateMachine).step()
+ .expectState(RappState.ONBOARDED).and().step().sendEvent(RappEvent.DEPLOYING)
+ .expectState(RappState.DEPLOYING).expectStateChanged(1).and().build();
+ plan.test();
+ }
+
+ @ParameterizedTest
+ @EnumSource(value = RappEvent.class, names = {"ACMDEPLOYED", "SMEDEPLOYED"})
+ void testIndividualDeployedState(RappEvent rappEvent) throws Exception {
+ StateMachineTestPlan plan =
+ StateMachineTestPlanBuilder.<RappState, RappEvent>builder().stateMachine(stateMachine).step()
+ .expectState(RappState.ONBOARDED).and().step().sendEvent(RappEvent.DEPLOYING)
+ .expectState(RappState.DEPLOYING).expectStateChanged(1).and().step().sendEvent(rappEvent)
+ .expectState(RappState.DEPLOYING).and().build();
+ plan.test();
+ }
+
+ @Test
+ void testDeployedState() throws Exception {
+ StateMachineTestPlan plan =
+ StateMachineTestPlanBuilder.<RappState, RappEvent>builder().stateMachine(stateMachine).step()
+ .expectState(RappState.ONBOARDED).and().step().sendEvent(RappEvent.DEPLOYING)
+ .expectState(RappState.DEPLOYING).expectStateChanged(1).and().step()
+ .sendEvent(RappEvent.ACMDEPLOYED).expectState(RappState.DEPLOYING).and().step()
+ .sendEvent(RappEvent.SMEDEPLOYED).expectState(RappState.DEPLOYED).expectStateChanged(1).and()
+ .build();
+ plan.test();
+ }
+
+ @Test
+ void testDeployFailedState() throws Exception {
+ StateMachineTestPlan plan =
+ StateMachineTestPlanBuilder.<RappState, RappEvent>builder().stateMachine(stateMachine).step()
+ .expectState(RappState.ONBOARDED).and().step().sendEvent(RappEvent.DEPLOYING)
+ .expectState(RappState.DEPLOYING).expectStateChanged(1).and().step()
+ .sendEvent(RappEvent.ACMDEPLOYED).expectState(RappState.DEPLOYING).and().step()
+ .sendEvent(RappEvent.SMEDEPLOYFAILED).expectState(RappState.FAILED).expectStateChanged(1).and()
+ .build();
+ plan.test();
+ }
+
+ @Test
+ void testUndeployingState() throws Exception {
+ StateMachineTestPlan plan =
+ StateMachineTestPlanBuilder.<RappState, RappEvent>builder().stateMachine(stateMachine).step()
+ .expectState(RappState.ONBOARDED).and().step().sendEvent(RappEvent.DEPLOYING)
+ .expectState(RappState.DEPLOYING).expectStateChanged(1).and().step()
+ .sendEvent(RappEvent.ACMDEPLOYED).expectState(RappState.DEPLOYING).and().step()
+ .sendEvent(RappEvent.SMEDEPLOYED).expectState(RappState.DEPLOYED).expectStateChanged(1).and()
+ .step().sendEvent(RappEvent.UNDEPLOYING).expectState(RappState.UNDEPLOYING)
+ .expectStateChanged(1).and().build();
+ plan.test();
+ }
+
+ @ParameterizedTest
+ @EnumSource(value = RappEvent.class, names = {"ACMUNDEPLOYED", "SMEUNDEPLOYED"})
+ void testIndividualUndeployedState(RappEvent rappEvent) throws Exception {
+ StateMachineTestPlan plan =
+ StateMachineTestPlanBuilder.<RappState, RappEvent>builder().stateMachine(stateMachine).step()
+ .expectState(RappState.ONBOARDED).and().step().sendEvent(RappEvent.DEPLOYING)
+ .expectState(RappState.DEPLOYING).expectStateChanged(1).and().step()
+ .sendEvent(RappEvent.ACMDEPLOYED).expectState(RappState.DEPLOYING).and().step()
+ .sendEvent(RappEvent.SMEDEPLOYED).expectState(RappState.DEPLOYED).expectStateChanged(1).and()
+ .step().sendEvent(RappEvent.UNDEPLOYING).expectState(RappState.UNDEPLOYING)
+ .expectStateChanged(1).and().step().sendEvent(rappEvent).expectState(RappState.UNDEPLOYING)
+ .and().build();
+ plan.test();
+ }
+
+ @Test
+ void testUndeployedState() throws Exception {
+ StateMachineTestPlan plan =
+ StateMachineTestPlanBuilder.<RappState, RappEvent>builder().stateMachine(stateMachine).step()
+ .expectState(RappState.ONBOARDED).and().step().sendEvent(RappEvent.DEPLOYING)
+ .expectState(RappState.DEPLOYING).expectStateChanged(1).and().step()
+ .sendEvent(RappEvent.ACMDEPLOYED).expectState(RappState.DEPLOYING).and().step()
+ .sendEvent(RappEvent.SMEDEPLOYED).expectState(RappState.DEPLOYED).expectStateChanged(1).and()
+ .step().sendEvent(RappEvent.UNDEPLOYING).expectState(RappState.UNDEPLOYING)
+ .expectStateChanged(1).and().step().sendEvent(RappEvent.ACMUNDEPLOYED)
+ .expectState(RappState.UNDEPLOYING).and().step().sendEvent(RappEvent.SMEUNDEPLOYED)
+ .expectState(RappState.UNDEPLOYED).expectStateChanged(1).and().build();
+ plan.test();
+ }
+
+ @Test
+ void testUndeployFailedState() throws Exception {
+ StateMachineTestPlan plan =
+ StateMachineTestPlanBuilder.<RappState, RappEvent>builder().stateMachine(stateMachine).step()
+ .expectState(RappState.ONBOARDED).and().step().sendEvent(RappEvent.DEPLOYING)
+ .expectState(RappState.DEPLOYING).expectStateChanged(1).and().step()
+ .sendEvent(RappEvent.ACMDEPLOYED).expectState(RappState.DEPLOYING).and().step()
+ .sendEvent(RappEvent.SMEDEPLOYED).expectState(RappState.DEPLOYED).expectStateChanged(1).and()
+ .step().sendEvent(RappEvent.UNDEPLOYING).expectState(RappState.UNDEPLOYING)
+ .expectStateChanged(1).and().step().sendEvent(RappEvent.ACMUNDEPLOYED)
+ .expectState(RappState.UNDEPLOYING).and().step().sendEvent(RappEvent.SMEUNDEPLOYFAILED)
+ .expectState(RappState.FAILED).expectStateChanged(1).and().build();
+ plan.test();
+ }
+
+
+}
diff --git a/rapp-manager-application/src/test/resources/invalid-rapp-package.csar b/rapp-manager-application/src/test/resources/invalid-rapp-package.csar
new file mode 100755
index 0000000..c9150f0
--- /dev/null
+++ b/rapp-manager-application/src/test/resources/invalid-rapp-package.csar
Binary files differ
diff --git a/rapp-manager-application/src/test/resources/valid-rapp-package.csar b/rapp-manager-application/src/test/resources/valid-rapp-package.csar
new file mode 100755
index 0000000..205094e
--- /dev/null
+++ b/rapp-manager-application/src/test/resources/valid-rapp-package.csar
Binary files differ
diff --git a/rapp-manager-models/pom.xml b/rapp-manager-models/pom.xml
new file mode 100755
index 0000000..918d936
--- /dev/null
+++ b/rapp-manager-models/pom.xml
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>com.oransc</groupId>
+ <artifactId>rappmanager</artifactId>
+ <version>0.0.1-SNAPSHOT</version>
+ </parent>
+
+ <groupId>com.oransc.rappmanager</groupId>
+ <artifactId>rapp-manager-models</artifactId>
+
+ <properties>
+ <maven.compiler.source>${java.version}</maven.compiler.source>
+ <maven.compiler.target>${java.version}</maven.compiler.target>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.springframework</groupId>
+ <artifactId>spring-context</artifactId>
+ <version>6.0.8</version>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework</groupId>
+ <artifactId>spring-web</artifactId>
+ <version>6.0.8</version>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework.statemachine</groupId>
+ <artifactId>spring-statemachine-core</artifactId>
+ <version>3.2.1</version>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ <version>2.0.7</version>
+ </dependency>
+ <dependency>
+ <groupId>org.projectlombok</groupId>
+ <artifactId>lombok</artifactId>
+ <optional>true</optional>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-test</artifactId>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+</project>
\ No newline at end of file
diff --git a/rapp-manager-models/src/main/java/com/oransc/rappmanager/models/Rapp.java b/rapp-manager-models/src/main/java/com/oransc/rappmanager/models/Rapp.java
new file mode 100755
index 0000000..c8b4f6d
--- /dev/null
+++ b/rapp-manager-models/src/main/java/com/oransc/rappmanager/models/Rapp.java
@@ -0,0 +1,51 @@
+/*-
+ * ============LICENSE_START======================================================================
+ * Copyright (C) 2023 Nordix Foundation. 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END========================================================================
+ */
+
+package com.oransc.rappmanager.models;
+
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+import lombok.Builder;
+import lombok.Data;
+import lombok.Getter;
+
+@Data
+@Builder(toBuilder = true)
+public class Rapp {
+
+ @Builder.Default
+ UUID rappId = UUID.randomUUID();
+ String name;
+ RappState state;
+ String packageLocation;
+ String packageName;
+ UUID compositionId;
+ UUID compositionInstanceId;
+ String smeApfId;
+ String smeAefId;
+ @Builder.Default
+ Map<String, String> smeProviderFunctions = new HashMap<>();
+ @Builder.Default
+ List<String> smeServiceApis = new ArrayList<>();
+ @Builder.Default
+ List<String> smeInvokers = new ArrayList<>();
+}
diff --git a/rapp-manager-models/src/main/java/com/oransc/rappmanager/models/RappCsarConfigurationHandler.java b/rapp-manager-models/src/main/java/com/oransc/rappmanager/models/RappCsarConfigurationHandler.java
new file mode 100755
index 0000000..5574f38
--- /dev/null
+++ b/rapp-manager-models/src/main/java/com/oransc/rappmanager/models/RappCsarConfigurationHandler.java
@@ -0,0 +1,115 @@
+/*-
+ * ============LICENSE_START======================================================================
+ * Copyright (C) 2023 Nordix Foundation. 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END========================================================================
+ */
+
+package com.oransc.rappmanager.models;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.nio.file.Path;
+import java.util.UUID;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Service;
+import org.springframework.web.multipart.MultipartFile;
+
+@Service
+public class RappCsarConfigurationHandler {
+
+ Logger logger = LoggerFactory.getLogger(RappCsarConfigurationHandler.class);
+ private final String acmInstantiationJsonLocation = "Files/Acm/instantiation.json";
+
+ private final String smeProviderDomainLocation = "Files/Sme/provider-domain.json";
+
+ private final String smeProviderApiLocation = "Files/Sme/provider-api.json";
+
+ private final String smeInvokerLocation = "Files/Sme/invoker.json";
+
+
+ public boolean isValidRappPackage(MultipartFile multipartFile) {
+ return multipartFile.getOriginalFilename() != null && multipartFile.getOriginalFilename().endsWith(".csar")
+ && isFileExistsInCsar(multipartFile, acmInstantiationJsonLocation);
+ }
+
+ boolean isFileExistsInCsar(MultipartFile multipartFile, String fileLocation) {
+ try (ZipInputStream zipInputStream = new ZipInputStream(multipartFile.getInputStream())) {
+ ZipEntry zipEntry;
+ while ((zipEntry = zipInputStream.getNextEntry()) != null) {
+ if (zipEntry.getName().matches(fileLocation)) {
+ return Boolean.TRUE;
+ }
+ }
+ return Boolean.FALSE;
+ } catch (IOException e) {
+ logger.error("Unable to find the CSAR file", e);
+ return Boolean.FALSE;
+ }
+ }
+
+ public Path getRappPackageLocation(String csarLocation, String rappId, String fileName) {
+ return Path.of(csarLocation, rappId, fileName);
+ }
+
+ public String getInstantiationPayload(Rapp rapp, UUID compositionId) {
+ return getPayload(rapp, acmInstantiationJsonLocation).replaceAll("COMPOSITIONID",
+ String.valueOf(compositionId));
+ }
+
+ String getPayload(Rapp rapp, String location) {
+ File csarFile = new File(
+ getRappPackageLocation(rapp.getPackageLocation(), rapp.getName(), rapp.getPackageName()).toUri());
+ return getFileFromCsar(csarFile, location).toString();
+ }
+
+ ByteArrayOutputStream getFileFromCsar(File csarFile, String fileLocation) {
+ ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
+ try (FileInputStream fileInputStream = new FileInputStream(csarFile);
+ ZipInputStream zipInputStream = new ZipInputStream(fileInputStream)) {
+ ZipEntry entry;
+ while ((entry = zipInputStream.getNextEntry()) != null) {
+ if (!entry.isDirectory() && entry.getName().equals(fileLocation)) {
+ byte[] buffer = new byte[1024];
+ int bytesRead;
+ while ((bytesRead = zipInputStream.read(buffer)) != -1) {
+ byteArrayOutputStream.write(buffer, 0, bytesRead);
+ }
+ }
+ }
+ } catch (IOException e) {
+ logger.error("Unable to find the CSAR file", e);
+ }
+ return byteArrayOutputStream;
+ }
+
+
+ public String getSmeProviderDomainPayload(Rapp rapp) {
+ return getPayload(rapp, smeProviderDomainLocation);
+ }
+
+ public String getSmeProviderApiPayload(Rapp rapp) {
+ return getPayload(rapp, smeProviderApiLocation);
+ }
+
+ public String getSmeInvokerPayload(Rapp rapp) {
+ return getPayload(rapp, smeInvokerLocation);
+ }
+
+}
diff --git a/rapp-manager-models/src/main/java/com/oransc/rappmanager/models/RappDeployer.java b/rapp-manager-models/src/main/java/com/oransc/rappmanager/models/RappDeployer.java
new file mode 100755
index 0000000..9c6a410
--- /dev/null
+++ b/rapp-manager-models/src/main/java/com/oransc/rappmanager/models/RappDeployer.java
@@ -0,0 +1,6 @@
+package com.oransc.rappmanager.models;
+
+public interface RappDeployer {
+ boolean deployRapp(Rapp rapp);
+ boolean undeployRapp(Rapp rapp);
+}
diff --git a/rapp-manager-models/src/main/java/com/oransc/rappmanager/models/RappEvent.java b/rapp-manager-models/src/main/java/com/oransc/rappmanager/models/RappEvent.java
new file mode 100755
index 0000000..0f64e55
--- /dev/null
+++ b/rapp-manager-models/src/main/java/com/oransc/rappmanager/models/RappEvent.java
@@ -0,0 +1,6 @@
+package com.oransc.rappmanager.models;
+
+public enum RappEvent {
+ ONBOARDED, DEPLOYING, ACMDEPLOYED, SMEDEPLOYED, ACMDEPLOYFAILED, SMEDEPLOYFAILED, DEPLOYED, UNDEPLOYING, UNDEPLOYED,
+ ACMUNDEPLOYED, SMEUNDEPLOYED, ACMUNDEPLOYFAILED, SMEUNDEPLOYFAILED
+}
diff --git a/rapp-manager-models/src/main/java/com/oransc/rappmanager/models/RappState.java b/rapp-manager-models/src/main/java/com/oransc/rappmanager/models/RappState.java
new file mode 100755
index 0000000..6198c47
--- /dev/null
+++ b/rapp-manager-models/src/main/java/com/oransc/rappmanager/models/RappState.java
@@ -0,0 +1,23 @@
+/*-
+ * ============LICENSE_START======================================================================
+ * Copyright (C) 2023 Nordix Foundation. 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END========================================================================
+ */
+
+package com.oransc.rappmanager.models;
+
+public enum RappState {
+ ONBOARDED, DEPLOYING, DEPLOYED, UNDEPLOYING, UNDEPLOYED, FAILED
+}
diff --git a/rapp-manager-models/src/main/java/com/oransc/rappmanager/models/cache/RappCacheService.java b/rapp-manager-models/src/main/java/com/oransc/rappmanager/models/cache/RappCacheService.java
new file mode 100755
index 0000000..d2b273c
--- /dev/null
+++ b/rapp-manager-models/src/main/java/com/oransc/rappmanager/models/cache/RappCacheService.java
@@ -0,0 +1,61 @@
+/*-
+ * ============LICENSE_START======================================================================
+ * Copyright (C) 2023 Nordix Foundation. 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END========================================================================
+ */
+
+package com.oransc.rappmanager.models.cache;
+
+import com.oransc.rappmanager.models.Rapp;
+import com.oransc.rappmanager.models.statemachine.RappStateMachine;
+import java.util.Optional;
+import lombok.RequiredArgsConstructor;
+import org.springframework.cache.Cache;
+import org.springframework.cache.CacheManager;
+import org.springframework.stereotype.Service;
+
+@Service
+@RequiredArgsConstructor
+public class RappCacheService {
+
+ private final String RAPP_CACHE = "rapp-cache";
+ private final CacheManager cacheManager;
+ private final RappStateMachine rappStateMachine;
+
+ public Cache getAllRapp() {
+ return cacheManager.getCache(RAPP_CACHE);
+ }
+
+ public Optional<Rapp> getRapp(String rappId) {
+ final Cache cache = cacheManager.getCache(RAPP_CACHE);
+ Optional<Rapp> rappOptional = Optional.ofNullable(cache.get(rappId, Rapp.class));
+ rappOptional.ifPresent(rapp -> rapp.setState(rappStateMachine.getRappState(rapp.getRappId())));
+ return rappOptional;
+ }
+
+ public void putRapp(Rapp rapp) {
+ final Cache cache = cacheManager.getCache(RAPP_CACHE);
+ if (cache != null) {
+ cache.put(rapp.getName(), rapp);
+ }
+ }
+
+ public void deleteRapp(Rapp rapp) {
+ final Cache cache = cacheManager.getCache(RAPP_CACHE);
+ if (cache != null) {
+ cache.evict(rapp.getName());
+ }
+ }
+}
diff --git a/rapp-manager-models/src/main/java/com/oransc/rappmanager/models/statemachine/RappStateMachine.java b/rapp-manager-models/src/main/java/com/oransc/rappmanager/models/statemachine/RappStateMachine.java
new file mode 100755
index 0000000..fcd6ed3
--- /dev/null
+++ b/rapp-manager-models/src/main/java/com/oransc/rappmanager/models/statemachine/RappStateMachine.java
@@ -0,0 +1,44 @@
+package com.oransc.rappmanager.models.statemachine;
+
+import com.oransc.rappmanager.models.Rapp;
+import com.oransc.rappmanager.models.RappEvent;
+import com.oransc.rappmanager.models.RappState;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+import lombok.RequiredArgsConstructor;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.statemachine.StateMachine;
+import org.springframework.statemachine.config.StateMachineFactory;
+import org.springframework.stereotype.Service;
+
+@Service
+@RequiredArgsConstructor
+public class RappStateMachine {
+
+ Logger logger = LoggerFactory.getLogger(RappStateMachine.class);
+
+ private final StateMachineFactory<RappState, RappEvent> stateMachineFactory;
+ private Map<UUID, StateMachine<RappState, RappEvent>> stateMachineMap = new HashMap<>();
+
+ public void onboardRapp(UUID rappId) {
+ StateMachine<RappState, RappEvent> stateMachine = stateMachineFactory.getStateMachine(rappId);
+ stateMachineMap.put(rappId, stateMachine);
+ stateMachine.start();
+ }
+
+ public void sendRappEvent(Rapp rapp, RappEvent rappEvent) {
+ logger.info("Sending rapp event {} for {}", rappEvent.name(), rapp.getRappId());
+ logger.info("State machine map is {}", stateMachineMap);
+ stateMachineMap.get(rapp.getRappId()).sendEvent(rappEvent);
+ }
+
+ public RappState getRappState(UUID rappId) {
+ return stateMachineMap.get(rappId).getState().getId();
+ }
+
+ public void deleteRapp(Rapp rapp) {
+ stateMachineMap.get(rapp.getRappId()).stop();
+ }
+}
diff --git a/rapp-manager-models/src/main/java/com/oransc/rappmanager/models/statemachine/RappStateMachineConfig.java b/rapp-manager-models/src/main/java/com/oransc/rappmanager/models/statemachine/RappStateMachineConfig.java
new file mode 100755
index 0000000..4d7e486
--- /dev/null
+++ b/rapp-manager-models/src/main/java/com/oransc/rappmanager/models/statemachine/RappStateMachineConfig.java
@@ -0,0 +1,87 @@
+package com.oransc.rappmanager.models.statemachine;
+
+import com.oransc.rappmanager.models.RappEvent;
+import com.oransc.rappmanager.models.RappState;
+import java.util.EnumSet;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.statemachine.config.EnableStateMachineFactory;
+import org.springframework.statemachine.config.EnumStateMachineConfigurerAdapter;
+import org.springframework.statemachine.config.builders.StateMachineConfigurationConfigurer;
+import org.springframework.statemachine.config.builders.StateMachineStateConfigurer;
+import org.springframework.statemachine.config.builders.StateMachineTransitionConfigurer;
+import org.springframework.statemachine.guard.Guard;
+
+@Configuration
+@EnableStateMachineFactory
+public class RappStateMachineConfig extends EnumStateMachineConfigurerAdapter<RappState, RappEvent> {
+
+ @Override
+ public void configure(StateMachineStateConfigurer<RappState, RappEvent> states) throws Exception {
+ states.withStates().initial(RappState.ONBOARDED).states(EnumSet.allOf(RappState.class));
+ }
+
+ @Override
+ public void configure(StateMachineConfigurationConfigurer<RappState, RappEvent> config) throws Exception {
+ config.withConfiguration();
+ }
+
+ // @formatter:off
+ @Override
+ public void configure(StateMachineTransitionConfigurer<RappState, RappEvent> transitions) throws Exception {
+ transitions
+ .withExternal()
+ .source(RappState.ONBOARDED).target(RappState.DEPLOYING).event(RappEvent.DEPLOYING)
+ .and()
+ .withExternal()
+ .source(RappState.DEPLOYING).target(RappState.FAILED).event(RappEvent.ACMDEPLOYFAILED)
+ .and()
+ .withExternal()
+ .source(RappState.DEPLOYING).target(RappState.FAILED).event(RappEvent.SMEDEPLOYFAILED)
+ .and()
+ .withExternal()
+ .source(RappState.UNDEPLOYING).target(RappState.FAILED).event(RappEvent.ACMUNDEPLOYFAILED)
+ .and()
+ .withExternal()
+ .source(RappState.UNDEPLOYING).target(RappState.FAILED).event(RappEvent.SMEUNDEPLOYFAILED)
+ .and()
+ .withExternal()
+ .source(RappState.DEPLOYED).target(RappState.UNDEPLOYING).event(RappEvent.UNDEPLOYING)
+ .and()
+ .withExternal()
+ .source(RappState.DEPLOYING).target(RappState.DEPLOYED).event(RappEvent.ACMDEPLOYED)
+ .guard(deployedGuard())
+ .and()
+ .withExternal()
+ .source(RappState.DEPLOYING).target(RappState.DEPLOYED).event(RappEvent.SMEDEPLOYED)
+ .guard(deployedGuard())
+ .and()
+ .withExternal()
+ .source(RappState.UNDEPLOYING).target(RappState.UNDEPLOYED).event(RappEvent.ACMUNDEPLOYED)
+ .guard(undeployedGuard())
+ .and()
+ .withExternal()
+ .source(RappState.UNDEPLOYING).target(RappState.UNDEPLOYED).event(RappEvent.SMEUNDEPLOYED)
+ .guard(undeployedGuard());
+
+ }
+ // @formatter:on
+
+ @Bean
+ public Guard<RappState, RappEvent> deployedGuard() {
+ return stateContext -> {
+ stateContext.getExtendedState().getVariables().put(stateContext.getEvent(), true);
+ return stateContext.getExtendedState().getVariables().get(RappEvent.ACMDEPLOYED) != null
+ && stateContext.getExtendedState().getVariables().get(RappEvent.SMEDEPLOYED) != null;
+ };
+ }
+
+ @Bean
+ public Guard<RappState, RappEvent> undeployedGuard() {
+ return stateContext -> {
+ stateContext.getExtendedState().getVariables().put(stateContext.getEvent(), true);
+ return stateContext.getExtendedState().getVariables().get(RappEvent.ACMUNDEPLOYED) != null
+ && stateContext.getExtendedState().getVariables().get(RappEvent.SMEUNDEPLOYED) != null;
+ };
+ }
+}
diff --git a/rapp-manager-sme/pom.xml b/rapp-manager-sme/pom.xml
new file mode 100755
index 0000000..cc607b2
--- /dev/null
+++ b/rapp-manager-sme/pom.xml
@@ -0,0 +1,178 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>com.oransc</groupId>
+ <artifactId>rappmanager</artifactId>
+ <version>0.0.1-SNAPSHOT</version>
+ </parent>
+
+ <groupId>com.oransc.rappmanager</groupId>
+ <artifactId>rapp-manager-sme</artifactId>
+
+ <properties>
+ <maven.compiler.source>17</maven.compiler.source>
+ <maven.compiler.target>17</maven.compiler.target>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ <exec-maven-plugin.version>3.1.0</exec-maven-plugin.version>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>com.oransc.rappmanager</groupId>
+ <artifactId>rapp-manager-models</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-web</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.projectlombok</groupId>
+ <artifactId>lombok</artifactId>
+ <optional>true</optional>
+ </dependency>
+ <dependency>
+ <groupId>org.openapitools</groupId>
+ <artifactId>jackson-databind-nullable</artifactId>
+ <version>0.2.6</version>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>exec-maven-plugin</artifactId>
+ <version>${exec-maven-plugin.version}</version>
+ <executions>
+ <execution>
+ <id>git submodule update</id>
+ <phase>initialize</phase>
+ <configuration>
+ <executable>git</executable>
+ <arguments>
+ <argument>submodule</argument>
+ <argument>update</argument>
+ <argument>--init</argument>
+ <argument>--recursive</argument>
+ </arguments>
+ </configuration>
+ <goals>
+ <goal>exec</goal>
+ </goals>
+ </execution>
+ <execution>
+ <id>initialize-sme-openapi-specs</id>
+ <phase>initialize</phase>
+ <goals>
+ <goal>exec</goal>
+ </goals>
+ <configuration>
+ <executable>bash</executable>
+ <arguments>
+ <argument>../scripts/init/init-sme-spec.sh</argument>
+ </arguments>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.openapitools</groupId>
+ <artifactId>openapi-generator-maven-plugin</artifactId>
+ <version>${openapi.maven.version}</version>
+ <executions>
+ <execution>
+ <id>provider-spec-generator</id>
+ <goals>
+ <goal>generate</goal>
+ </goals>
+ <configuration>
+ <inputSpec>
+ rapp-manager-sme/src/main/resources/openapi/TS29222_CAPIF_API_Provider_Management_API.yaml
+ </inputSpec>
+ <generatorName>java</generatorName>
+ <library>resttemplate</library>
+ <generateApiTests>false</generateApiTests>
+ <generateModelTests>false</generateModelTests>
+ <generateApiDocumentation>false</generateApiDocumentation>
+ <generateModelDocumentation>false</generateModelDocumentation>
+ <generateModels>true</generateModels>
+ <additionalProperties>
+ <additionalProperty>apiNameSuffix=ApiClient</additionalProperty>
+ </additionalProperties>
+ <configOptions>
+ <sourceFolder>src/main/java</sourceFolder>
+ <useJakartaEe>true</useJakartaEe>
+ <invokerPackage>com.oransc.rappmanager.sme.provider</invokerPackage>
+ <apiPackage>com.oransc.rappmanager.sme.provider.rest</apiPackage>
+ <modelPackage>com.oransc.rappmanager.sme.provider.data</modelPackage>
+ <generateClientAsBean>false</generateClientAsBean>
+ </configOptions>
+ </configuration>
+ </execution>
+ <execution>
+ <id>publish-service-spec-generator</id>
+ <goals>
+ <goal>generate</goal>
+ </goals>
+ <configuration>
+ <inputSpec>
+ rapp-manager-sme/src/main/resources/openapi/TS29222_CAPIF_Publish_Service_API.yaml
+ </inputSpec>
+ <generatorName>java</generatorName>
+ <library>resttemplate</library>
+ <generateApiTests>false</generateApiTests>
+ <generateModelTests>false</generateModelTests>
+ <generateApiDocumentation>false</generateApiDocumentation>
+ <generateModelDocumentation>false</generateModelDocumentation>
+ <generateModels>true</generateModels>
+ <additionalProperties>
+ <additionalProperty>apiNameSuffix=ApiClient</additionalProperty>
+ </additionalProperties>
+ <configOptions>
+ <sourceFolder>src/main/java</sourceFolder>
+ <useJakartaEe>true</useJakartaEe>
+ <invokerPackage>com.oransc.rappmanager.sme.publishservice</invokerPackage>
+ <apiPackage>com.oransc.rappmanager.sme.publishservice.rest</apiPackage>
+ <modelPackage>com.oransc.rappmanager.sme.publishservice.data</modelPackage>
+ <generateClientAsBean>false</generateClientAsBean>
+ </configOptions>
+ </configuration>
+ </execution>
+ <execution>
+ <id>invoker-spec-generator</id>
+ <goals>
+ <goal>generate</goal>
+ </goals>
+ <configuration>
+ <inputSpec>
+ rapp-manager-sme/src/main/resources/openapi/TS29222_CAPIF_API_Invoker_Management_API.yaml
+ </inputSpec>
+ <generatorName>java</generatorName>
+ <library>resttemplate</library>
+ <generateApiTests>false</generateApiTests>
+ <generateModelTests>false</generateModelTests>
+ <generateApiDocumentation>false</generateApiDocumentation>
+ <generateModelDocumentation>false</generateModelDocumentation>
+ <generateModels>true</generateModels>
+ <additionalProperties>
+ <additionalProperty>apiNameSuffix=ApiClient</additionalProperty>
+ </additionalProperties>
+ <configOptions>
+ <sourceFolder>src/main/java</sourceFolder>
+ <useJakartaEe>true</useJakartaEe>
+ <invokerPackage>com.oransc.rappmanager.sme.invoker</invokerPackage>
+ <apiPackage>com.oransc.rappmanager.sme.invoker.rest</apiPackage>
+ <modelPackage>com.oransc.rappmanager.sme.invoker.data</modelPackage>
+ <generateClientAsBean>false</generateClientAsBean>
+ </configOptions>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+</project>
\ No newline at end of file
diff --git a/rapp-manager-sme/src/main/java/com/oransc/rappmanager/sme/configuration/SmeConfiguration.java b/rapp-manager-sme/src/main/java/com/oransc/rappmanager/sme/configuration/SmeConfiguration.java
new file mode 100755
index 0000000..2a1f0ce
--- /dev/null
+++ b/rapp-manager-sme/src/main/java/com/oransc/rappmanager/sme/configuration/SmeConfiguration.java
@@ -0,0 +1,36 @@
+/*-
+ * ============LICENSE_START======================================================================
+ * Copyright (C) 2023 Nordix Foundation. 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END========================================================================
+ */
+
+package com.oransc.rappmanager.sme.configuration;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+@ConfigurationProperties(prefix = "rappmanager.sme")
+@Data
+public class SmeConfiguration {
+
+ String baseUrl;
+ String providerBasePath;
+ String invokerBasePath;
+ String publishApiBasePath;
+ int maxRetries;
+ int retryInterval;
+}
diff --git a/rapp-manager-sme/src/main/java/com/oransc/rappmanager/sme/service/SmeDeployer.java b/rapp-manager-sme/src/main/java/com/oransc/rappmanager/sme/service/SmeDeployer.java
new file mode 100755
index 0000000..5901417
--- /dev/null
+++ b/rapp-manager-sme/src/main/java/com/oransc/rappmanager/sme/service/SmeDeployer.java
@@ -0,0 +1,225 @@
+/*-
+ * ============LICENSE_START======================================================================
+ * Copyright (C) 2023 Nordix Foundation. 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END========================================================================
+ */
+
+package com.oransc.rappmanager.sme.service;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.oransc.rappmanager.models.Rapp;
+import com.oransc.rappmanager.models.RappCsarConfigurationHandler;
+import com.oransc.rappmanager.models.RappDeployer;
+import com.oransc.rappmanager.models.RappEvent;
+import com.oransc.rappmanager.models.cache.RappCacheService;
+import com.oransc.rappmanager.models.statemachine.RappStateMachine;
+import com.oransc.rappmanager.sme.invoker.data.APIInvokerEnrolmentDetails;
+import com.oransc.rappmanager.sme.provider.data.APIProviderEnrolmentDetails;
+import com.oransc.rappmanager.sme.provider.data.APIProviderFunctionDetails;
+import com.oransc.rappmanager.sme.provider.data.ApiProviderFuncRole;
+import com.oransc.rappmanager.sme.provider.data.RegistrationInformation;
+import com.oransc.rappmanager.sme.publishservice.data.AefProfile;
+import com.oransc.rappmanager.sme.publishservice.data.ServiceAPIDescription;
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Collectors;
+import lombok.RequiredArgsConstructor;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Service;
+
+@Service
+@RequiredArgsConstructor
+public class SmeDeployer implements RappDeployer {
+
+ Logger logger = LoggerFactory.getLogger(SmeDeployer.class);
+
+ private final com.oransc.rappmanager.sme.provider.rest.DefaultApiClient providerDefaultApiClient;
+
+ private final com.oransc.rappmanager.sme.publishservice.rest.DefaultApiClient publishServiceDefaultApiClient;
+
+ private final com.oransc.rappmanager.sme.invoker.rest.DefaultApiClient invokerDefaultApiClient;
+
+ private final RappCsarConfigurationHandler rappCsarConfigurationHandler;
+
+ private final ObjectMapper objectMapper;
+
+ private final RappCacheService rappCacheService;
+
+ private final RappStateMachine rappStateMachine;
+
+ private String amfRegistrationId;
+
+
+ APIProviderEnrolmentDetails createAMF() {
+ APIProviderEnrolmentDetails responseApiEnrollmentDetails = null;
+ try {
+ APIProviderFunctionDetails apiProviderFunctionDetails = new APIProviderFunctionDetails();
+ apiProviderFunctionDetails.setApiProvFuncRole(ApiProviderFuncRole.AMF);
+ apiProviderFunctionDetails.setApiProvFuncInfo("Rapp Manager as AMF");
+ apiProviderFunctionDetails.setRegInfo(new RegistrationInformation().apiProvPubKey("asd"));
+
+ APIProviderEnrolmentDetails apiProviderEnrolmentDetails = new APIProviderEnrolmentDetails();
+ apiProviderEnrolmentDetails.setRegSec("PSK");
+ apiProviderEnrolmentDetails.setApiProvDomInfo("Rapp Manager as AMF");
+ apiProviderEnrolmentDetails.setApiProvFuncs(List.of(apiProviderFunctionDetails));
+ responseApiEnrollmentDetails = providerDefaultApiClient.postRegistrations(apiProviderEnrolmentDetails);
+ amfRegistrationId = responseApiEnrollmentDetails.getApiProvDomId();
+ } catch (Exception e) {
+ logger.warn("Error in creating AMF", e);
+ }
+ return responseApiEnrollmentDetails;
+ }
+
+ void deleteAMF() {
+ deleteProviderFunc(amfRegistrationId);
+ }
+
+
+ @Override
+ public boolean deployRapp(Rapp rapp) {
+ logger.debug("Deploying SME functions for Rapp {}", rapp.getName());
+ try {
+ boolean deployState = createProviderDomain(rapp) && createPublishApi(rapp) && createInvoker(rapp);
+ if (deployState) {
+ rappStateMachine.sendRappEvent(rapp, RappEvent.SMEDEPLOYED);
+ } else {
+ rappStateMachine.sendRappEvent(rapp, RappEvent.SMEDEPLOYFAILED);
+ }
+ return deployState;
+ } catch (JsonProcessingException e) {
+ logger.warn("Failed to deploy SME functions for Rapp {}", rapp.getName(), e);
+ }
+ return false;
+ }
+
+ @Override
+ public boolean undeployRapp(Rapp rapp) {
+ logger.debug("Undeploying SME functions for Rapp {}", rapp.getName());
+ try {
+ rapp.getSmeInvokers().forEach(this::deleteInvoker);
+ rapp.getSmeServiceApis().forEach(s -> deletePublishApi(s, rapp.getSmeApfId()));
+ rapp.getSmeProviderFunctions().values().forEach(this::deleteProviderFunc);
+ rappStateMachine.sendRappEvent(rapp, RappEvent.SMEUNDEPLOYED);
+ return true;
+ } catch (Exception e) {
+ logger.warn("Failed to Undeploy SME functions for Rapp {}", rapp.getName());
+ }
+ return false;
+ }
+
+ boolean createProviderDomain(Rapp rapp) throws JsonProcessingException {
+ logger.debug("Creating provider domain for Rapp {}", rapp.getName());
+ try {
+ String providerDomainPayload = rappCsarConfigurationHandler.getSmeProviderDomainPayload(rapp);
+ if (providerDomainPayload != null) {
+ APIProviderEnrolmentDetails apiProviderEnrolmentDetails =
+ objectMapper.readValue(providerDomainPayload, APIProviderEnrolmentDetails.class);
+ APIProviderEnrolmentDetails responseApiEnrollmentDetails =
+ providerDefaultApiClient.postRegistrations(apiProviderEnrolmentDetails);
+ if (responseApiEnrollmentDetails.getApiProvFuncs() != null) {
+ getProviderFuncId(responseApiEnrollmentDetails.getApiProvFuncs(),
+ ApiProviderFuncRole.APF).ifPresent(apiProviderFunctionDetails -> rapp.setSmeApfId(
+ apiProviderFunctionDetails.getApiProvFuncId()));
+ getProviderFuncId(responseApiEnrollmentDetails.getApiProvFuncs(),
+ ApiProviderFuncRole.AEF).ifPresent(apiProviderFunctionDetails -> rapp.setSmeAefId(
+ apiProviderFunctionDetails.getApiProvFuncId()));
+ rapp.setSmeProviderFunctions(responseApiEnrollmentDetails.getApiProvFuncs().stream().collect(
+ Collectors.toMap(APIProviderFunctionDetails::getApiProvFuncInfo,
+ APIProviderFunctionDetails::getApiProvFuncId)));
+ rappCacheService.putRapp(rapp);
+ return true;
+ }
+ }
+ } catch (Exception e) {
+ logger.warn("Error in creating provider domain", e);
+ }
+ return false;
+ }
+
+ Optional<APIProviderFunctionDetails> getProviderFuncId(List<APIProviderFunctionDetails> apiProviderFunctionDetails,
+ ApiProviderFuncRole apiProviderFuncRole) {
+ return apiProviderFunctionDetails.stream()
+ .filter(apiProviderFunctionDetail -> apiProviderFunctionDetail.getApiProvFuncRole()
+ .equals(apiProviderFuncRole)).findFirst();
+ }
+
+ void deleteProviderFunc(String registrationId) {
+ providerDefaultApiClient.deleteRegistrationsRegistrationId(registrationId);
+ }
+
+
+ boolean createPublishApi(Rapp rapp) throws JsonProcessingException {
+ logger.debug("Creating publish api for Rapp {}", rapp.getName());
+ try {
+ String providerApiPayload = rappCsarConfigurationHandler.getSmeProviderApiPayload(rapp);
+ if (providerApiPayload != null) {
+ ServiceAPIDescription serviceAPIDescription =
+ objectMapper.readValue(providerApiPayload, ServiceAPIDescription.class);
+ serviceAPIDescription.getAefProfiles().forEach(aefProfile -> {
+ aefProfile.setAefId(rapp.getSmeProviderFunctions().get(aefProfile.getAefId()));
+ });
+ ServiceAPIDescription serviceAPIDescriptionResponse =
+ publishServiceDefaultApiClient.postApfIdServiceApis(rapp.getSmeApfId(), serviceAPIDescription);
+
+ if (serviceAPIDescriptionResponse.getAefProfiles() != null) {
+ rapp.setSmeServiceApis(
+ serviceAPIDescriptionResponse.getAefProfiles().stream().map(AefProfile::getAefId)
+ .collect(Collectors.toList()));
+ rappCacheService.putRapp(rapp);
+ return true;
+ }
+ }
+ } catch (Exception e) {
+ logger.warn("Error in creating publish api", e);
+ }
+ return false;
+ }
+
+ void deletePublishApi(String serviceApiId, String apfId) {
+ publishServiceDefaultApiClient.deleteApfIdServiceApisServiceApiId(serviceApiId, apfId);
+ }
+
+ boolean createInvoker(Rapp rapp) throws JsonProcessingException {
+ logger.debug("Creating provider domain for Rapp {}", rapp.getName());
+ try {
+ String invokerPayload = rappCsarConfigurationHandler.getSmeInvokerPayload(rapp);
+ if (invokerPayload != null) {
+ List<APIInvokerEnrolmentDetails> apiInvokerEnrolmentDetails =
+ objectMapper.readValue(invokerPayload, new TypeReference<>() { });
+ apiInvokerEnrolmentDetails.forEach(apiInvokerEnrolmentDetail -> {
+ APIInvokerEnrolmentDetails apiInvokerEnrolmentDetailsResponse =
+ invokerDefaultApiClient.postOnboardedInvokers(apiInvokerEnrolmentDetail);
+ if (apiInvokerEnrolmentDetailsResponse.getApiList() != null) {
+ rapp.getSmeInvokers().addAll(apiInvokerEnrolmentDetailsResponse.getApiList().stream()
+ .map(com.oransc.rappmanager.sme.invoker.data.ServiceAPIDescription::getApiId)
+ .toList());
+ rappCacheService.putRapp(rapp);
+ }
+ });
+ return true;
+ }
+ } catch (Exception e) {
+ logger.warn("Error in creating invoker", e);
+ }
+ return false;
+ }
+
+ void deleteInvoker(String invokerId) {
+ invokerDefaultApiClient.deleteOnboardedInvokersOnboardingId(invokerId);
+ }
+}
diff --git a/rapp-manager-sme/src/main/java/com/oransc/rappmanager/sme/service/SmeLifecycleManager.java b/rapp-manager-sme/src/main/java/com/oransc/rappmanager/sme/service/SmeLifecycleManager.java
new file mode 100755
index 0000000..0c21c1b
--- /dev/null
+++ b/rapp-manager-sme/src/main/java/com/oransc/rappmanager/sme/service/SmeLifecycleManager.java
@@ -0,0 +1,63 @@
+/*-
+ * ============LICENSE_START======================================================================
+ * Copyright (C) 2023 Nordix Foundation. 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END========================================================================
+ */
+
+package com.oransc.rappmanager.sme.service;
+
+import com.oransc.rappmanager.sme.provider.data.APIProviderEnrolmentDetails;
+import lombok.RequiredArgsConstructor;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.context.SmartLifecycle;
+import org.springframework.stereotype.Service;
+
+@Service
+@RequiredArgsConstructor
+public class SmeLifecycleManager implements SmartLifecycle {
+
+ Logger logger = LoggerFactory.getLogger(SmeLifecycleManager.class);
+
+ private final SmeDeployer smeDeployer;
+ private boolean running;
+
+ @Override
+ public void start() {
+ try {
+ logger.info("Registering Rapp Manager as AMF");
+ APIProviderEnrolmentDetails providerServiceAMF = smeDeployer.createAMF();
+ logger.info("Rapp Manager AMF Registration Id: " + providerServiceAMF.getApiProvDomId());
+ running = true;
+ }catch (Exception e){
+ logger.warn("Error in initializing AMF", e);
+ running = false;
+ }
+ }
+
+ @Override
+ public void stop() {
+ if (isRunning()) {
+ logger.info("Deleting Rapp Manager as AMF");
+ smeDeployer.deleteAMF();
+ running = false;
+ }
+ }
+
+ @Override
+ public boolean isRunning() {
+ return running;
+ }
+}
diff --git a/scripts/init/getsmeswagger.go b/scripts/init/getsmeswagger.go
new file mode 100755
index 0000000..65826a2
--- /dev/null
+++ b/scripts/init/getsmeswagger.go
@@ -0,0 +1,95 @@
+// -
+// ========================LICENSE_START=================================
+// O-RAN-SC
+// %%
+// Copyright (C) 2023: Nordix Foundation
+// %%
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================LICENSE_END===================================
+//
+
+package main
+
+
+import (
+ "github.com/getkin/kin-openapi/openapi3"
+ log "github.com/sirupsen/logrus"
+ "gopkg.in/yaml.v3"
+ "encoding/json"
+ "io/ioutil"
+
+ "oransc.org/nonrtric/capifcore/internal/invokermanagementapi"
+ "oransc.org/nonrtric/capifcore/internal/providermanagementapi"
+ "oransc.org/nonrtric/capifcore/internal/publishserviceapi"
+ "oransc.org/nonrtric/capifcore/internal/common"
+ "oransc.org/nonrtric/capifcore/internal/common29122"
+ "oransc.org/nonrtric/capifcore/internal/common29571"
+)
+
+func main() {
+ var swagger *openapi3.T
+ var err error
+
+ swagger,err = providermanagementapi.GetSwagger()
+ if err == nil {
+ generateSwaggerYaml(swagger, "TS29222_CAPIF_API_Provider_Management_API.yaml")
+ }
+
+ swagger,err = publishserviceapi.GetSwagger()
+ if err == nil {
+ generateSwaggerYaml(swagger, "TS29222_CAPIF_Publish_Service_API.yaml")
+ }
+
+ swagger,err = invokermanagementapi.GetSwagger()
+ if err == nil {
+ generateSwaggerYaml(swagger, "TS29222_CAPIF_API_Invoker_Management_API.yaml")
+ }
+
+ swagger,err = common.GetSwagger()
+ if err == nil {
+ generateSwaggerYaml(swagger, "CommonData.yaml")
+ }
+
+ swagger,err = common29122.GetSwagger()
+ if err == nil {
+ generateSwaggerYaml(swagger, "TS29122_CommonData.yaml")
+ }
+
+ swagger,err = common29571.GetSwagger()
+ if err == nil {
+ generateSwaggerYaml(swagger, "TS29571_CommonData.yaml")
+ }
+}
+
+func generateSwaggerYaml(swagger *openapi3.T, filename string) {
+ jsondataarr, jsondataarrerr := json.Marshal(&swagger)
+ if jsondataarrerr != nil {
+ log.Fatalf("Error loading json data from swagger \n: %s", jsondataarrerr)
+ }
+
+ var data map[string]interface{}
+ if err := json.Unmarshal(jsondataarr, &data); err != nil {
+ log.Fatalf("Error loading json data to map \n: %s", jsondataarrerr)
+ log.Fatal(err)
+ }
+
+ yamldataarr, yamldataarrerr := yaml.Marshal(&data)
+ if yamldataarrerr != nil {
+ log.Fatalf("Error loading json data map to array \n: %s", yamldataarrerr)
+ }
+
+ err2 := ioutil.WriteFile(filename, yamldataarr, 0755)
+ if err2 != nil {
+ log.Fatalf("Error writing provider yaml \n: %s", err2)
+ }
+}
\ No newline at end of file
diff --git a/scripts/init/init-sme-spec.sh b/scripts/init/init-sme-spec.sh
new file mode 100755
index 0000000..da4a3cd
--- /dev/null
+++ b/scripts/init/init-sme-spec.sh
@@ -0,0 +1,46 @@
+#!/bin/bash
+
+# ============LICENSE_START===============================================
+# Copyright (C) 2023 Nordix Foundation. 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.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ============LICENSE_END=================================================
+#
+
+SME_LOCATION="../sme/capifcore"
+cp ../scripts/init/getsmeswagger.go $SME_LOCATION
+cd $SME_LOCATION
+
+echo "Generating SME openapi spec..."
+
+if [ -f "getsmeswagger.go" ]; then
+ echo "Generating..."
+ go run getsmeswagger.go
+
+ echo "Copying generated specs..."
+ mkdir -p ../../rapp-manager-sme/src/main/resources/openapi
+ echo "Copying CommonData.yaml"
+ mv CommonData.yaml ../../rapp-manager-sme/src/main/resources/openapi
+ echo "Copying TS29122_CommonData.yaml"
+ mv TS29122_CommonData.yaml ../../rapp-manager-sme/src/main/resources/openapi
+ echo "Copying TS29571_CommonData.yaml"
+ mv TS29571_CommonData.yaml ../../rapp-manager-sme/src/main/resources/openapi
+ echo "Copying TS29222_CAPIF_API_Invoker_Management_API.yaml"
+ mv TS29222_CAPIF_API_Invoker_Management_API.yaml ../../rapp-manager-sme/src/main/resources/openapi
+ echo "Copying TS29222_CAPIF_API_Provider_Management_API.yaml"
+ mv TS29222_CAPIF_API_Provider_Management_API.yaml ../../rapp-manager-sme/src/main/resources/openapi
+ echo "Copying TS29222_CAPIF_Publish_Service_API.yaml"
+ mv TS29222_CAPIF_Publish_Service_API.yaml ../../rapp-manager-sme/src/main/resources/openapi
+else
+ echo "Unable to find the openapi spec generator."
+fi
diff --git a/sme b/sme
new file mode 160000
index 0000000..82a6094
--- /dev/null
+++ b/sme
@@ -0,0 +1 @@
+Subproject commit 82a60949ea3507b00313bb627d91c9169c0a37c7