DME participant interacts with ICS to lifecycle manage ICS entities.
Dockerfile added for creating docker images.
Issue-ID: NONRTRIC-952
Signed-off-by: aravind.est <aravindhan.a@est.tech>
Change-Id: I4093678f80714cc7b481109e1861f67050fb9523
--- /dev/null
+#
+# ============LICENSE_START=======================================================
+# 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.
+#
+# SPDX-License-Identifier: Apache-2.0
+# ============LICENSE_END=========================================================
+#
+FROM openjdk:17-jdk as jre-build
+
+RUN $JAVA_HOME/bin/jlink \
+--verbose \
+--add-modules ALL-MODULE-PATH \
+--strip-debug \
+--no-man-pages \
+--no-header-files \
+--compress=2 \
+--output /customjre
+
+# Use debian base image (same as openjdk uses)
+FROM debian:11-slim
+
+ENV JAVA_HOME=/jre
+ENV PATH="${JAVA_HOME}/bin:${PATH}"
+
+#copy JRE from the base image
+COPY --from=jre-build /customjre $JAVA_HOME
+
+ARG JAR
+
+WORKDIR /opt/app/participant/dme
+
+EXPOSE 8080
+
+ADD src/main/resources/application.yaml /opt/app/participant/dme/application.yaml
+ADD target/${JAR} /opt/app/participant/dme/participant-impl-dme.jar
+
+ARG user=nonrtric
+ARG group=nonrtric
+
+RUN groupadd $user && \
+ useradd -r -g $group $user
+RUN chown -R $user:$group /opt/app/participant/dme
+
+USER ${user}
+
+CMD ["/jre/bin/java", "-jar", "/opt/app/participant/dme/participant-impl-dme.jar"]
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+* ========================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===================================
+-->
+<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>org.o-ran-sc.nonrtric.plt</groupId>
+ <artifactId>participants</artifactId>
+ <version>0.0.1-SNAPSHOT</version>
+ </parent>
+
+ <groupId>org.o-ran-sc.nonrtric.plt.participants</groupId>
+ <artifactId>participant-impl-dme</artifactId>
+
+ <properties>
+ <maven.compiler.source>17</maven.compiler.source>
+ <maven.compiler.target>17</maven.compiler.target>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.onap.policy.clamp.participant</groupId>
+ <artifactId>policy-clamp-participant-intermediary</artifactId>
+ <version>${onap.acm.models.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.onap.policy.clamp</groupId>
+ <artifactId>policy-clamp-models</artifactId>
+ <version>${onap.acm.models.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-web</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-security</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>io.micrometer</groupId>
+ <artifactId>micrometer-registry-prometheus</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>${openapi.jackson.databind.nullable.version}</version>
+ </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>
+ <executions>
+ <execution>
+ <goals>
+ <goal>repackage</goal>
+ </goals>
+ <phase>package</phase>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.openapitools</groupId>
+ <artifactId>openapi-generator-maven-plugin</artifactId>
+ <version>${openapi.maven.version}</version>
+ <executions>
+ <execution>
+ <id>dme-participant-spec-generator</id>
+ <goals>
+ <goal>generate</goal>
+ </goals>
+ <configuration>
+ <inputSpec>${project.parent.basedir}/../openapi/dme/ics-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.participant.dme</invokerPackage>
+ <apiPackage>com.oransc.participant.dme.rest</apiPackage>
+ <modelPackage>com.oransc.participant.dme.data</modelPackage>
+ <generateClientAsBean>false</generateClientAsBean>
+ </configOptions>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>io.fabric8</groupId>
+ <artifactId>docker-maven-plugin</artifactId>
+ <version>${docker-maven-plugin}</version>
+ <inherited>false</inherited>
+ <executions>
+ <execution>
+ <id>generate-nonrtric-plt-participant-impl-dme-image</id>
+ <phase>package</phase>
+ <goals>
+ <goal>build</goal>
+ </goals>
+ <configuration>
+ <pullRegistry>${env.CONTAINER_PULL_REGISTRY}</pullRegistry>
+ <images>
+ <image>
+ <name>
+ o-ran-sc/nonrtric-plt-participant-impl-dme:${project.version}
+ </name>
+ <build>
+ <cleanup>try</cleanup>
+ <contextDir>${project.basedir}</contextDir>
+ <dockerFile>Dockerfile</dockerFile>
+ <args>
+ <JAR>${project.build.finalName}.jar</JAR>
+ </args>
+ <tags>
+ <tag>${project.version}</tag>
+ </tags>
+ </build>
+ </image>
+ </images>
+ </configuration>
+ </execution>
+ <execution>
+ <id>push-nonrtric-plt-participant-impl-dme-image</id>
+ <goals>
+ <goal>push</goal>
+ </goals>
+ <configuration>
+ <pushRegistry>${env.CONTAINER_PUSH_REGISTRY}</pushRegistry>
+ <images>
+ <image>
+ <name>
+ o-ran-sc/nonrtric-plt-participant-impl-dme:${project.version}
+ </name>
+ <build>
+ <contextDir>${project.basedir}</contextDir>
+ <dockerFile>Dockerfile</dockerFile>
+ <args>
+ <JAR>${project.build.finalName}.jar</JAR>
+ </args>
+ <tags>
+ <tag>${project.version}</tag>
+ <tag>latest</tag>
+ </tags>
+ </build>
+ </image>
+ </images>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+</project>
--- /dev/null
+/*-
+ * ============LICENSE_START=======================================================
+ * 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.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.oransc.participant.dme;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.context.properties.ConfigurationPropertiesScan;
+import org.springframework.context.annotation.ComponentScan;
+
+@SpringBootApplication
+@ComponentScan({"org.oransc.participant.dme", "org.onap.policy.clamp.acm.participant.intermediary"})
+@ConfigurationPropertiesScan("org.oransc.participant.dme.parameters")
+public class Application {
+
+ public static void main(String[] args) {
+ SpringApplication.run(Application.class, args);
+ }
+}
--- /dev/null
+/*-
+ * ============LICENSE_START=======================================================
+ * 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.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.oransc.participant.dme;
+
+import com.oransc.participant.dme.rest.DataConsumerApiClient;
+import com.oransc.participant.dme.rest.DataProducerRegistrationApiClient;
+import lombok.RequiredArgsConstructor;
+import org.oransc.participant.dme.parameters.DmeParameters;
+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 DmeParameters dmeParameters;
+
+ @Bean
+ public RestTemplate restTemplate(RestTemplateBuilder builder) {
+ return builder.build();
+ }
+
+ @Bean
+ public com.oransc.participant.dme.ApiClient dmeApiClient(RestTemplate restTemplate) {
+ com.oransc.participant.dme.ApiClient apiClient = new com.oransc.participant.dme.ApiClient(restTemplate);
+ return apiClient.setBasePath(dmeParameters.getBaseUrl());
+ }
+
+ @Bean
+ public DataProducerRegistrationApiClient dataProducerRegistrationApiClient(
+ com.oransc.participant.dme.ApiClient apiClient) {
+ return new DataProducerRegistrationApiClient(apiClient);
+ }
+
+ @Bean
+ public DataConsumerApiClient dataConsumerApiClient(com.oransc.participant.dme.ApiClient apiClient) {
+ return new DataConsumerApiClient(apiClient);
+ }
+}
--- /dev/null
+/*-
+ * ============LICENSE_START=======================================================
+ * 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.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.oransc.participant.dme.config;
+
+import io.micrometer.core.aop.TimedAspect;
+import io.micrometer.core.instrument.MeterRegistry;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.beans.factory.config.BeanPostProcessor;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class MicrometerConfig {
+
+ @Bean
+ public InitializingBean forcePrometheusPostProcessor(BeanPostProcessor meterRegistryPostProcessor,
+ MeterRegistry registry) {
+ return () -> meterRegistryPostProcessor.postProcessAfterInitialization(registry, "");
+ }
+
+ @Bean
+ public TimedAspect timedAspect(MeterRegistry registry) {
+ return new TimedAspect(registry);
+ }
+}
--- /dev/null
+/*-
+ * ========================LICENSE_START=================================
+ * 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 org.oransc.participant.dme.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.config.Customizer;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
+import org.springframework.security.web.SecurityFilterChain;
+
+@Configuration
+public class SecurityConfig {
+ @Bean
+ public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
+ http
+ .httpBasic(Customizer.withDefaults())
+ .authorizeHttpRequests(authorize -> authorize.anyRequest().authenticated())
+ .csrf(AbstractHttpConfigurer::disable);
+ return http.build();
+ }
+}
--- /dev/null
+/*-
+ * ============LICENSE_START=======================================================
+ * 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.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.oransc.participant.dme.exception;
+
+import jakarta.ws.rs.core.Response;
+import java.io.Serial;
+import org.onap.policy.models.base.PfModelException;
+
+public class DmeException extends PfModelException {
+
+ @Serial
+ private static final long serialVersionUID = 6438746904567105054L;
+
+ public DmeException(int statusCode, String message) {
+ super(Response.Status.fromStatusCode(statusCode), message);
+ }
+
+ public DmeException(int statusCode, String message, Exception e) {
+ super(Response.Status.fromStatusCode(statusCode), message, e);
+ }
+}
--- /dev/null
+/*-
+ * ============LICENSE_START=======================================================
+ * 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.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.oransc.participant.dme.handler;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import jakarta.validation.Validation;
+import jakarta.validation.ValidationException;
+import java.lang.invoke.MethodHandles;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.stream.Collectors;
+import lombok.AccessLevel;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+import org.apache.http.HttpStatus;
+import org.onap.policy.clamp.acm.participant.intermediary.api.AutomationCompositionElementListener;
+import org.onap.policy.clamp.acm.participant.intermediary.api.ParticipantIntermediaryApi;
+import org.onap.policy.clamp.models.acm.concepts.AcElementDeploy;
+import org.onap.policy.clamp.models.acm.concepts.AcTypeState;
+import org.onap.policy.clamp.models.acm.concepts.AutomationCompositionElementDefinition;
+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.StateChangeResult;
+import org.onap.policy.clamp.models.acm.utils.AcmUtils;
+import org.onap.policy.common.utils.coder.Coder;
+import org.onap.policy.common.utils.coder.CoderException;
+import org.onap.policy.common.utils.coder.StandardCoder;
+import org.onap.policy.models.base.PfModelException;
+import org.oransc.participant.dme.exception.DmeException;
+import org.oransc.participant.dme.models.ConfigurationEntity;
+import org.oransc.participant.dme.models.DataConsumerEntity;
+import org.oransc.participant.dme.models.DataProducerEntity;
+import org.oransc.participant.dme.models.InfoTypeEntity;
+import org.oransc.participant.dme.restclient.AcDmeClient;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
+
+@Component
+@RequiredArgsConstructor
+public class AutomationCompositionElementHandler implements AutomationCompositionElementListener {
+
+ private static final Coder CODER = new StandardCoder();
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
+
+ private final ParticipantIntermediaryApi intermediaryApi;
+
+ private final AcDmeClient acDmeClient;
+
+ // Map of acElement Id and DME services
+ @Getter(AccessLevel.PACKAGE)
+ private final Map<UUID, ConfigurationEntity> configRequestMap = new ConcurrentHashMap<>();
+
+ @Override
+ public void undeploy(UUID automationCompositionId, UUID automationCompositionElementId) throws DmeException {
+ var configurationEntity = configRequestMap.get(automationCompositionElementId);
+ if (configurationEntity != null && acDmeClient.isDmeHealthy()) {
+ if (configurationEntity.getDataConsumerEntities() != null) {
+ acDmeClient.deleteDataConsumer(configurationEntity.getDataConsumerEntities().stream()
+ .map(DataConsumerEntity::getDataConsumerId)
+ .collect(Collectors.toSet()));
+ }
+ if (configurationEntity.getDataProducerEntities() != null) {
+ acDmeClient.deleteDataProducer(configurationEntity.getDataProducerEntities().stream()
+ .map(DataProducerEntity::getDataProducerId)
+ .collect(Collectors.toSet()));
+ }
+ configRequestMap.remove(automationCompositionElementId);
+ intermediaryApi.updateAutomationCompositionElementState(automationCompositionId,
+ automationCompositionElementId, DeployState.UNDEPLOYED, null, StateChangeResult.NO_ERROR,
+ "Undeployed");
+ } else {
+ LOGGER.warn("Failed to connect with DME. Service configuration is: {}", configurationEntity);
+ throw new DmeException(HttpStatus.SC_SERVICE_UNAVAILABLE, "Unable to connect with DME");
+ }
+ }
+
+ @Override
+ public void deploy(UUID automationCompositionId, AcElementDeploy element, Map<String, Object> properties)
+ throws DmeException {
+ try {
+ var configurationEntity = CODER.convert(properties, ConfigurationEntity.class);
+ var violations = Validation.buildDefaultValidatorFactory().getValidator().validate(configurationEntity);
+ if (violations.isEmpty()) {
+ if ((configurationEntity.getInfoTypeEntities() != null
+ || configurationEntity.getDataProducerEntities() != null
+ || configurationEntity.getDataConsumerEntities() != null) && acDmeClient.isDmeHealthy()) {
+ if (configurationEntity.getInfoTypeEntities() != null) {
+ acDmeClient.createInfoType(configurationEntity.getInfoTypeEntities().stream().collect(
+ Collectors.toMap(InfoTypeEntity::getInfoTypeId, InfoTypeEntity::getPayload)));
+ }
+ if (configurationEntity.getDataProducerEntities() != null) {
+ acDmeClient.createDataProducer(configurationEntity.getDataProducerEntities().stream().collect(
+ Collectors.toMap(DataProducerEntity::getDataProducerId,
+ DataProducerEntity::getPayload)));
+ }
+ if (configurationEntity.getDataConsumerEntities() != null) {
+ acDmeClient.createDataConsumer(configurationEntity.getDataConsumerEntities().stream().collect(
+ Collectors.toMap(DataConsumerEntity::getDataConsumerId,
+ DataConsumerEntity::getPayload)));
+ }
+
+ configRequestMap.put(element.getId(), configurationEntity);
+ intermediaryApi.updateAutomationCompositionElementState(automationCompositionId, element.getId(),
+ DeployState.DEPLOYED, null, StateChangeResult.NO_ERROR, "Deployed");
+ } else {
+ intermediaryApi.updateAutomationCompositionElementState(automationCompositionId, element.getId(),
+ DeployState.UNDEPLOYED, null, StateChangeResult.FAILED, "Unable to connect with DME ");
+ throw new DmeException(HttpStatus.SC_SERVICE_UNAVAILABLE, "Unable to connect with DME");
+ }
+ } else {
+ LOGGER.error("Violations found in the config request parameters: {}", violations);
+ throw new ValidationException("Constraint violations in the config request");
+ }
+ } catch (JsonProcessingException | ValidationException | CoderException | DmeException e) {
+ intermediaryApi.updateAutomationCompositionElementState(automationCompositionId, element.getId(),
+ DeployState.UNDEPLOYED, null, StateChangeResult.FAILED, e.getMessage());
+ throw new DmeException(HttpStatus.SC_BAD_REQUEST, "Invalid Configuration", e);
+ }
+ }
+
+ @Override
+ public void lock(UUID instanceId, UUID elementId) {
+ intermediaryApi.updateAutomationCompositionElementState(instanceId, elementId, null, LockState.LOCKED,
+ StateChangeResult.NO_ERROR, "Locked");
+ }
+
+ @Override
+ public void unlock(UUID instanceId, UUID elementId) {
+ intermediaryApi.updateAutomationCompositionElementState(instanceId, elementId, null, LockState.UNLOCKED,
+ StateChangeResult.NO_ERROR, "Unlocked");
+ }
+
+ @Override
+ public void delete(UUID instanceId, UUID elementId) {
+ intermediaryApi.updateAutomationCompositionElementState(instanceId, elementId, DeployState.DELETED, null,
+ StateChangeResult.NO_ERROR, "Deleted");
+ }
+
+ @Override
+ public void update(UUID instanceId, AcElementDeploy element, Map<String, Object> properties) {
+ intermediaryApi.updateAutomationCompositionElementState(instanceId, element.getId(), DeployState.DEPLOYED, null,
+ StateChangeResult.NO_ERROR, "Update not supported");
+ }
+
+ @Override
+ public void prime(UUID compositionId, List<AutomationCompositionElementDefinition> elementDefinitionList) {
+ intermediaryApi.updateCompositionState(compositionId, AcTypeState.PRIMED, StateChangeResult.NO_ERROR, "Primed");
+ }
+
+ @Override
+ public void deprime(UUID compositionId) {
+ intermediaryApi.updateCompositionState(compositionId, AcTypeState.COMMISSIONED, StateChangeResult.NO_ERROR,
+ "Deprimed");
+ }
+
+ @Override
+ public void handleRestartComposition(UUID compositionId,
+ List<AutomationCompositionElementDefinition> elementDefinitionList, AcTypeState state) {
+ var finalState = AcTypeState.PRIMED.equals(state) || AcTypeState.PRIMING.equals(state) ? AcTypeState.PRIMED
+ : AcTypeState.COMMISSIONED;
+ intermediaryApi.updateCompositionState(compositionId, finalState, StateChangeResult.NO_ERROR, "Restarted");
+ }
+
+ @Override
+ public void handleRestartInstance(UUID automationCompositionId, AcElementDeploy element,
+ Map<String, Object> properties, DeployState deployState, LockState lockState) throws PfModelException {
+ if (DeployState.DEPLOYING.equals(deployState)) {
+ deploy(automationCompositionId, element, properties);
+ return;
+ }
+ if (DeployState.UNDEPLOYING.equals(deployState) || DeployState.DEPLOYED.equals(deployState)
+ || DeployState.UPDATING.equals(deployState)) {
+ try {
+ var configurationEntity = CODER.convert(properties, ConfigurationEntity.class);
+ configRequestMap.put(element.getId(), configurationEntity);
+ } catch (ValidationException | CoderException e) {
+ throw new DmeException(HttpStatus.SC_BAD_REQUEST, "Invalid Configuration", e);
+ }
+ }
+ if (DeployState.UNDEPLOYING.equals(deployState)) {
+ undeploy(automationCompositionId, element.getId());
+ return;
+ }
+ deployState = AcmUtils.deployCompleted(deployState);
+ lockState = AcmUtils.lockCompleted(deployState, lockState);
+ intermediaryApi.updateAutomationCompositionElementState(automationCompositionId, element.getId(), deployState,
+ lockState, StateChangeResult.NO_ERROR, "Restarted");
+ }
+
+ @Override
+ public void migrate(UUID automationCompositionId, AcElementDeploy element, UUID compositionTargetId,
+ Map<String, Object> properties) {
+ intermediaryApi.updateAutomationCompositionElementState(automationCompositionId, element.getId(),
+ DeployState.DEPLOYED, null, StateChangeResult.NO_ERROR, "Migrated");
+ }
+}
--- /dev/null
+/*-
+ * ============LICENSE_START=======================================================
+ * 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.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.oransc.participant.dme.models;
+
+import jakarta.validation.Valid;
+import java.util.List;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+
+@Data
+@AllArgsConstructor
+public class ConfigurationEntity {
+
+ @Valid
+ private List<InfoTypeEntity> infoTypeEntities;
+
+ @Valid
+ private List<DataProducerEntity> dataProducerEntities;
+
+ @Valid
+ private List<DataConsumerEntity> dataConsumerEntities;
+}
--- /dev/null
+/*-
+ * ============LICENSE_START=======================================================
+ * 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.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.oransc.participant.dme.models;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.databind.PropertyNamingStrategies;
+import com.fasterxml.jackson.databind.annotation.JsonNaming;
+import jakarta.validation.constraints.NotNull;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier;
+
+@Data
+@AllArgsConstructor
+@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class)
+public class DataConsumerEntity {
+
+ @NotNull
+ @JsonIgnore
+ private ToscaConceptIdentifier dataConsumerEntityId;
+
+ @NotNull
+ private String dataConsumerId;
+
+ @NotNull
+ private String payload;
+
+}
--- /dev/null
+/*-
+ * ============LICENSE_START=======================================================
+ * 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.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.oransc.participant.dme.models;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.databind.PropertyNamingStrategies;
+import com.fasterxml.jackson.databind.annotation.JsonNaming;
+import jakarta.validation.constraints.NotNull;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier;
+
+@Data
+@AllArgsConstructor
+@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class)
+public class DataProducerEntity {
+
+ @NotNull
+ @JsonIgnore
+ private ToscaConceptIdentifier dataProducerEntityId;
+
+ @NotNull
+ private String dataProducerId;
+
+ @NotNull
+ private String payload;
+
+}
--- /dev/null
+/*-
+ * ============LICENSE_START=======================================================
+ * 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.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.oransc.participant.dme.models;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.databind.PropertyNamingStrategies;
+import com.fasterxml.jackson.databind.annotation.JsonNaming;
+import jakarta.validation.constraints.NotNull;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier;
+
+@Data
+@AllArgsConstructor
+@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class)
+public class InfoTypeEntity {
+
+ @NotNull
+ @JsonIgnore
+ private ToscaConceptIdentifier infoTypeEntityId;
+
+ @NotNull
+ private String infoTypeId;
+
+ @NotNull
+ private String payload;
+
+}
--- /dev/null
+/*-
+ * ============LICENSE_START=======================================================
+ * 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.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.oransc.participant.dme.parameters;
+
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.validation.annotation.Validated;
+
+@Validated
+@Data
+@ConfigurationProperties(prefix = "dme")
+public class DmeParameters {
+
+ @NotNull
+ private String baseUrl;
+}
--- /dev/null
+/*-
+ * ============LICENSE_START=======================================================
+ * 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.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.oransc.participant.dme.parameters;
+
+import jakarta.validation.Valid;
+import jakarta.validation.constraints.NotNull;
+import lombok.Getter;
+import lombok.Setter;
+import org.onap.policy.clamp.acm.participant.intermediary.parameters.ParticipantIntermediaryParameters;
+import org.onap.policy.clamp.acm.participant.intermediary.parameters.ParticipantParameters;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.validation.annotation.Validated;
+
+@Validated
+@Getter
+@Setter
+@ConfigurationProperties(prefix = "participant")
+public class DmeParticipantParameters implements ParticipantParameters {
+
+ @NotNull
+ @Valid
+ private ParticipantIntermediaryParameters intermediaryParameters;
+}
--- /dev/null
+/*-
+ * ============LICENSE_START=======================================================
+ * 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.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.oransc.participant.dme.restclient;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.oransc.participant.dme.data.ConsumerJob;
+import com.oransc.participant.dme.data.ProducerInfoTypeInfo;
+import com.oransc.participant.dme.data.ProducerRegistrationInfo;
+import com.oransc.participant.dme.rest.DataConsumerApiClient;
+import com.oransc.participant.dme.rest.DataProducerRegistrationApiClient;
+import java.util.Map;
+import java.util.Set;
+import lombok.RequiredArgsConstructor;
+import org.oransc.participant.dme.exception.DmeException;
+import org.springframework.http.ResponseEntity;
+import org.springframework.stereotype.Component;
+
+@Component
+@RequiredArgsConstructor
+public class AcDmeClient {
+
+ private final DataProducerRegistrationApiClient dataProducerRegistrationApiClient;
+ private final DataConsumerApiClient dataConsumerApiClient;
+ private final ObjectMapper objectMapper;
+
+ public boolean isDmeHealthy() {
+ return dataProducerRegistrationApiClient.getInfoTypdentifiersWithHttpInfo().getStatusCode().is2xxSuccessful();
+ }
+
+ public void createInfoType(Map<String, String> infoTypeMap) throws DmeException, JsonProcessingException {
+ for (Map.Entry<String, String> entry : infoTypeMap.entrySet()) {
+ String infoTypeName = entry.getKey();
+ ProducerInfoTypeInfo infoTypeInfo = objectMapper.readValue(entry.getValue(), ProducerInfoTypeInfo.class);
+ ResponseEntity<Object> objectResponseEntity =
+ dataProducerRegistrationApiClient.putInfoTypeWithHttpInfo(infoTypeName, infoTypeInfo);
+ if (!objectResponseEntity.getStatusCode().is2xxSuccessful()) {
+ throw new DmeException(objectResponseEntity.getStatusCode().value(), "Error in creating info types");
+ }
+ }
+ }
+
+ public void createDataProducer(Map<String, String> dataProducerMap) throws DmeException, JsonProcessingException {
+ for (Map.Entry<String, String> entry : dataProducerMap.entrySet()) {
+ String infoProducerName = entry.getKey();
+ ProducerRegistrationInfo producerRegistrationInfo =
+ objectMapper.readValue(entry.getValue(), ProducerRegistrationInfo.class);
+ ResponseEntity<Object> objectResponseEntity =
+ dataProducerRegistrationApiClient.putInfoProducerWithHttpInfo(infoProducerName,
+ producerRegistrationInfo);
+ if (!objectResponseEntity.getStatusCode().is2xxSuccessful()) {
+ throw new DmeException(objectResponseEntity.getStatusCode().value(), "Error in creating data producer");
+ }
+ }
+ }
+
+ public void createDataConsumer(Map<String, String> dataConsumerMap) throws DmeException, JsonProcessingException {
+ for (Map.Entry<String, String> entry : dataConsumerMap.entrySet()) {
+ String infoProducerName = entry.getKey();
+ ConsumerJob consumerJob = objectMapper.readValue(entry.getValue(), ConsumerJob.class);
+ ResponseEntity<Object> objectResponseEntity =
+ dataConsumerApiClient.putIndividualInfoJobWithHttpInfo(infoProducerName, consumerJob);
+ if (!objectResponseEntity.getStatusCode().is2xxSuccessful()) {
+ throw new DmeException(objectResponseEntity.getStatusCode().value(), "Error in creating data consumer");
+ }
+ }
+ }
+
+ public void deleteDataProducer(Set<String> dataProducerList) throws DmeException {
+ for (String dataProducer : dataProducerList) {
+ ResponseEntity<Object> objectResponseEntity =
+ dataProducerRegistrationApiClient.deleteInfoProducerWithHttpInfo(dataProducer);
+ if (!objectResponseEntity.getStatusCode().is2xxSuccessful()) {
+ throw new DmeException(objectResponseEntity.getStatusCode().value(), "Error in deleting data producer");
+ }
+ }
+ }
+
+ public void deleteDataConsumer(Set<String> dataConsumerList) throws DmeException {
+ for (String dataConsumer : dataConsumerList) {
+ ResponseEntity<Object> objectResponseEntity =
+ dataConsumerApiClient.deleteIndividualInfoJobWithHttpInfo(dataConsumer);
+ if (!objectResponseEntity.getStatusCode().is2xxSuccessful()) {
+ throw new DmeException(objectResponseEntity.getStatusCode().value(), "Error in deleting data consumer");
+ }
+ }
+ }
+
+}
--- /dev/null
+spring:
+ security:
+ user:
+ name: participantUser
+ password: zb!XztG34
+ autoconfigure:
+ exclude:
+ - org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration
+ - org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
+ - org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration
+ - org.springframework.boot.autoconfigure.data.web.SpringDataWebAutoConfiguration
+security:
+ enable-csrf: false
+
+dme:
+ baseUrl: http://localhost:63475
+
+participant:
+ intermediaryParameters:
+ reportingTimeIntervalMs: 120000
+ description: Participant Description
+ participantId: 101c62b3-8918-41b9-a747-d21eb79c6c08
+ clampAutomationCompositionTopics:
+ topicSources:
+ - topic: POLICY-ACRUNTIME-PARTICIPANT
+ servers:
+ - ${topicServer:localhost}
+ topicCommInfrastructure: dmaap
+ fetchTimeout: 15000
+ topicSinks:
+ - topic: POLICY-ACRUNTIME-PARTICIPANT
+ servers:
+ - ${topicServer:localhost}
+ topicCommInfrastructure: dmaap
+ participantSupportedElementTypes:
+ -
+ typeName: org.onap.policy.clamp.acm.DMEAutomationCompositionElement
+ typeVersion: 1.0.1
+
+management:
+ endpoints:
+ web:
+ base-path: /
+ exposure:
+ include: health, metrics, prometheus
+server:
+ port: 8080
+ servlet:
+ context-path: /nonrtric/dmeparticipant
--- /dev/null
+/*-
+ * ============LICENSE_START=======================================================
+ * 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.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.oransc.participant.dme.handler;
+
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.onap.policy.clamp.acm.participant.intermediary.api.ParticipantIntermediaryApi;
+import org.onap.policy.clamp.models.acm.concepts.AcTypeState;
+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.StateChangeResult;
+import org.onap.policy.models.base.PfModelException;
+import org.onap.policy.models.tosca.authorative.concepts.ToscaServiceTemplate;
+import org.oransc.participant.dme.exception.DmeException;
+import org.oransc.participant.dme.restclient.AcDmeClient;
+import org.oransc.participant.dme.utils.CommonTestData;
+import org.oransc.participant.dme.utils.ToscaUtils;
+
+class AcElementHandlerTest {
+
+ private final AcDmeClient acDmeClient = mock(AcDmeClient.class);
+
+ private final CommonTestData commonTestData = new CommonTestData();
+
+ private static ToscaServiceTemplate serviceTemplate;
+ private static final String DME_AUTOMATION_COMPOSITION_ELEMENT =
+ "onap.policy.clamp.ac.element.DMEAutomationCompositionElement";
+
+ @BeforeAll
+ static void init() {
+ serviceTemplate = ToscaUtils.readAutomationCompositionFromTosca();
+ }
+
+ @BeforeEach
+ void startMocks() throws DmeException, JsonProcessingException {
+ when(acDmeClient.isDmeHealthy()).thenReturn(Boolean.TRUE);
+ doNothing().when(acDmeClient).createInfoType(any());
+ }
+
+ @Test
+ void test_automationCompositionElementStateChange() throws DmeException {
+ var participantIntermediaryApi = mock(ParticipantIntermediaryApi.class);
+ var automationCompositionElementHandler =
+ new AutomationCompositionElementHandler(participantIntermediaryApi, acDmeClient);
+
+ var automationCompositionId = commonTestData.getAutomationCompositionId();
+ var element = commonTestData.getAutomationCompositionElement();
+ var automationCompositionElementId = element.getId();
+
+ var nodeTemplatesMap = serviceTemplate.getToscaTopologyTemplate().getNodeTemplates();
+ automationCompositionElementHandler.deploy(commonTestData.getAutomationCompositionId(), element,
+ nodeTemplatesMap.get(DME_AUTOMATION_COMPOSITION_ELEMENT).getProperties());
+ verify(participantIntermediaryApi).updateAutomationCompositionElementState(automationCompositionId,
+ automationCompositionElementId, DeployState.DEPLOYED, null, StateChangeResult.NO_ERROR, "Deployed");
+
+ automationCompositionElementHandler.undeploy(automationCompositionId, automationCompositionElementId);
+ verify(participantIntermediaryApi).updateAutomationCompositionElementState(automationCompositionId,
+ automationCompositionElementId, DeployState.UNDEPLOYED, null, StateChangeResult.NO_ERROR, "Undeployed");
+
+ when(acDmeClient.isDmeHealthy()).thenReturn(Boolean.FALSE);
+ assertThrows(DmeException.class, () -> automationCompositionElementHandler
+ .undeploy(automationCompositionId, automationCompositionElementId));
+ }
+
+ @Test
+ void test_AutomationCompositionElementUpdate() throws DmeException {
+ var participantIntermediaryApi = mock(ParticipantIntermediaryApi.class);
+ var automationCompositionElementHandler =
+ new AutomationCompositionElementHandler(participantIntermediaryApi, acDmeClient);
+
+ var element = commonTestData.getAutomationCompositionElement();
+ var nodeTemplatesMap = serviceTemplate.getToscaTopologyTemplate().getNodeTemplates();
+ automationCompositionElementHandler.deploy(commonTestData.getAutomationCompositionId(), element,
+ nodeTemplatesMap.get(DME_AUTOMATION_COMPOSITION_ELEMENT).getProperties());
+ verify(participantIntermediaryApi).updateAutomationCompositionElementState(
+ commonTestData.getAutomationCompositionId(), element.getId(), DeployState.DEPLOYED, null,
+ StateChangeResult.NO_ERROR, "Deployed");
+ }
+
+ @Test
+ void test_AutomationCompositionElementUpdateWithUnhealthyA1pms() {
+ var participantIntermediaryApi = mock(ParticipantIntermediaryApi.class);
+ var automationCompositionElementHandler =
+ new AutomationCompositionElementHandler(participantIntermediaryApi, acDmeClient);
+
+ var element = commonTestData.getAutomationCompositionElement();
+ when(acDmeClient.isDmeHealthy()).thenReturn(Boolean.FALSE);
+
+ var nodeTemplatesMap = serviceTemplate.getToscaTopologyTemplate().getNodeTemplates();
+ assertThrows(DmeException.class,
+ () -> automationCompositionElementHandler.deploy(commonTestData.getAutomationCompositionId(), element,
+ nodeTemplatesMap.get(DME_AUTOMATION_COMPOSITION_ELEMENT).getProperties()));
+ }
+
+ @Test
+ void test_AutomationCompositionElementUpdateWithInvalidConfiguration() {
+ var participantIntermediaryApi = mock(ParticipantIntermediaryApi.class);
+ var automationCompositionElementHandler =
+ new AutomationCompositionElementHandler(participantIntermediaryApi, acDmeClient);
+
+ var element = commonTestData.getAutomationCompositionElement();
+ assertThrows(DmeException.class, () -> automationCompositionElementHandler
+ .deploy(commonTestData.getAutomationCompositionId(), element, Map.of()));
+ }
+
+ @Test
+ void testLock() {
+ var participantIntermediaryApi = mock(ParticipantIntermediaryApi.class);
+ var automationCompositionElementHandler =
+ new AutomationCompositionElementHandler(participantIntermediaryApi, acDmeClient);
+
+ var automationCompositionId = UUID.randomUUID();
+ var elementId = UUID.randomUUID();
+ automationCompositionElementHandler.lock(automationCompositionId, elementId);
+
+ verify(participantIntermediaryApi).updateAutomationCompositionElementState(automationCompositionId, elementId,
+ null, LockState.LOCKED, StateChangeResult.NO_ERROR, "Locked");
+ }
+
+ @Test
+ void testUnlock() {
+ var participantIntermediaryApi = mock(ParticipantIntermediaryApi.class);
+ var automationCompositionElementHandler =
+ new AutomationCompositionElementHandler(participantIntermediaryApi, acDmeClient);
+
+ var automationCompositionId = UUID.randomUUID();
+ var elementId = UUID.randomUUID();
+ automationCompositionElementHandler.unlock(automationCompositionId, elementId);
+
+ verify(participantIntermediaryApi).updateAutomationCompositionElementState(automationCompositionId, elementId,
+ null, LockState.UNLOCKED, StateChangeResult.NO_ERROR, "Unlocked");
+ }
+
+ @Test
+ void testUpdate() {
+ var participantIntermediaryApi = mock(ParticipantIntermediaryApi.class);
+ var automationCompositionElementHandler =
+ new AutomationCompositionElementHandler(participantIntermediaryApi, acDmeClient);
+
+ var automationCompositionId = UUID.randomUUID();
+ var element = commonTestData.getAutomationCompositionElement();
+ automationCompositionElementHandler.update(automationCompositionId, element, Map.of());
+
+ verify(participantIntermediaryApi).updateAutomationCompositionElementState(automationCompositionId,
+ element.getId(), DeployState.DEPLOYED, null, StateChangeResult.NO_ERROR, "Update not supported");
+ }
+
+ @Test
+ void testDelete() {
+ var participantIntermediaryApi = mock(ParticipantIntermediaryApi.class);
+ var automationCompositionElementHandler =
+ new AutomationCompositionElementHandler(participantIntermediaryApi, acDmeClient);
+
+ var automationCompositionId = UUID.randomUUID();
+ var elementId = UUID.randomUUID();
+ automationCompositionElementHandler.delete(automationCompositionId, elementId);
+
+ verify(participantIntermediaryApi).updateAutomationCompositionElementState(automationCompositionId, elementId,
+ DeployState.DELETED, null, StateChangeResult.NO_ERROR, "Deleted");
+ }
+
+ @Test
+ void testPrime() {
+ var participantIntermediaryApi = mock(ParticipantIntermediaryApi.class);
+ var automationCompositionElementHandler =
+ new AutomationCompositionElementHandler(participantIntermediaryApi, acDmeClient);
+
+ var compositionId = UUID.randomUUID();
+ automationCompositionElementHandler.prime(compositionId, List.of());
+
+ verify(participantIntermediaryApi).updateCompositionState(compositionId, AcTypeState.PRIMED,
+ StateChangeResult.NO_ERROR, "Primed");
+ }
+
+ @Test
+ void testDeprime() {
+ var participantIntermediaryApi = mock(ParticipantIntermediaryApi.class);
+ var automationCompositionElementHandler =
+ new AutomationCompositionElementHandler(participantIntermediaryApi, acDmeClient);
+
+ var compositionId = UUID.randomUUID();
+ automationCompositionElementHandler.deprime(compositionId);
+
+ verify(participantIntermediaryApi).updateCompositionState(compositionId, AcTypeState.COMMISSIONED,
+ StateChangeResult.NO_ERROR, "Deprimed");
+ }
+
+ @Test
+ void testHandleRestartComposition() {
+ var participantIntermediaryApi = mock(ParticipantIntermediaryApi.class);
+ var automationCompositionElementHandler =
+ new AutomationCompositionElementHandler(participantIntermediaryApi, acDmeClient);
+
+ var compositionId = UUID.randomUUID();
+ automationCompositionElementHandler.handleRestartComposition(compositionId, List.of(), AcTypeState.PRIMED);
+
+ verify(participantIntermediaryApi).updateCompositionState(compositionId, AcTypeState.PRIMED,
+ StateChangeResult.NO_ERROR, "Restarted");
+ }
+
+ @Test
+ void testHandleRestartInstanceDeploying() throws PfModelException {
+ var participantIntermediaryApi = mock(ParticipantIntermediaryApi.class);
+ var automationCompositionElementHandler =
+ new AutomationCompositionElementHandler(participantIntermediaryApi, acDmeClient);
+
+ var automationCompositionId = UUID.randomUUID();
+ var element = commonTestData.getAutomationCompositionElement();
+ var automationCompositionElementId = element.getId();
+ var nodeTemplatesMap = serviceTemplate.getToscaTopologyTemplate().getNodeTemplates();
+ automationCompositionElementHandler.handleRestartInstance(automationCompositionId, element,
+ nodeTemplatesMap.get(DME_AUTOMATION_COMPOSITION_ELEMENT).getProperties(), DeployState.DEPLOYING,
+ LockState.NONE);
+ verify(participantIntermediaryApi).updateAutomationCompositionElementState(automationCompositionId,
+ automationCompositionElementId, DeployState.DEPLOYED, null, StateChangeResult.NO_ERROR, "Deployed");
+ }
+
+ @Test
+ void testHandleRestartInstanceDeployed() throws PfModelException {
+ var intermediaryApi = mock(ParticipantIntermediaryApi.class);
+ var automationCompositionElementHandler =
+ new AutomationCompositionElementHandler(intermediaryApi, acDmeClient);
+
+ var automationCompositionId = UUID.randomUUID();
+ var element = commonTestData.getAutomationCompositionElement();
+ var nodeTemplatesMap = serviceTemplate.getToscaTopologyTemplate().getNodeTemplates();
+ automationCompositionElementHandler.handleRestartInstance(automationCompositionId, element,
+ nodeTemplatesMap.get(DME_AUTOMATION_COMPOSITION_ELEMENT).getProperties(), DeployState.DEPLOYED,
+ LockState.LOCKED);
+ verify(intermediaryApi).updateAutomationCompositionElementState(automationCompositionId, element.getId(),
+ DeployState.DEPLOYED, LockState.LOCKED, StateChangeResult.NO_ERROR, "Restarted");
+ }
+
+ @Test
+ void testHandleRestartInstanceUndeployed() throws PfModelException {
+ var intermediaryApi = mock(ParticipantIntermediaryApi.class);
+ var automationCompositionElementHandler =
+ new AutomationCompositionElementHandler(intermediaryApi, acDmeClient);
+
+ var automationCompositionId = UUID.randomUUID();
+ var element = commonTestData.getAutomationCompositionElement();
+ var automationCompositionElementId = element.getId();
+ var nodeTemplatesMap = serviceTemplate.getToscaTopologyTemplate().getNodeTemplates();
+ automationCompositionElementHandler.handleRestartInstance(automationCompositionId, element,
+ nodeTemplatesMap.get(DME_AUTOMATION_COMPOSITION_ELEMENT).getProperties(), DeployState.UNDEPLOYING,
+ LockState.LOCKED);
+ verify(intermediaryApi).updateAutomationCompositionElementState(automationCompositionId,
+ automationCompositionElementId, DeployState.UNDEPLOYED, null, StateChangeResult.NO_ERROR, "Undeployed");
+ }
+
+ @Test
+ void testMigrate() {
+ var participantIntermediaryApi = mock(ParticipantIntermediaryApi.class);
+ var automationCompositionElementHandler =
+ new AutomationCompositionElementHandler(participantIntermediaryApi, acDmeClient);
+
+ var automationCompositionId = UUID.randomUUID();
+ var element = commonTestData.getAutomationCompositionElement();
+ automationCompositionElementHandler.migrate(automationCompositionId, element, UUID.randomUUID(), Map.of());
+
+ verify(participantIntermediaryApi).updateAutomationCompositionElementState(automationCompositionId,
+ element.getId(), DeployState.DEPLOYED, null, StateChangeResult.NO_ERROR, "Migrated");
+ }
+}
--- /dev/null
+/*-
+ * ============LICENSE_START=======================================================
+ * 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.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.oransc.participant.dme.rest;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import jakarta.ws.rs.core.Response;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.oransc.participant.dme.utils.CommonActuatorController;
+import org.springframework.boot.test.autoconfigure.actuate.observability.AutoConfigureObservability;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
+import org.springframework.boot.test.web.server.LocalServerPort;
+import org.springframework.test.context.ActiveProfiles;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
+
+@AutoConfigureObservability(tracing = false)
+@ExtendWith(SpringExtension.class)
+@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
+@ActiveProfiles("test")
+class ActuatorControllerTest extends CommonActuatorController {
+
+ private static final String HEALTH_ENDPOINT = "health";
+ private static final String METRICS_ENDPOINT = "metrics";
+ private static final String PROMETHEUS_ENDPOINT = "prometheus";
+
+ @LocalServerPort
+ private int randomServerPort;
+
+ @BeforeEach
+ public void setUpPort() {
+ super.setHttpPrefix(randomServerPort);
+ }
+
+ @Test
+ void testGetHealth_Unauthorized() {
+ assertUnauthorizedActGet(HEALTH_ENDPOINT);
+ }
+
+ @Test
+ void testGetMetrics_Unauthorized() {
+ assertUnauthorizedActGet(METRICS_ENDPOINT);
+ }
+
+ @Test
+ void testGetPrometheus_Unauthorized() {
+ assertUnauthorizedActGet(PROMETHEUS_ENDPOINT);
+ }
+
+ @Test
+ void testGetHealth() {
+ var invocationBuilder = super.sendActRequest(HEALTH_ENDPOINT);
+ var rawresp = invocationBuilder.buildGet().invoke();
+ assertEquals(Response.Status.OK.getStatusCode(), rawresp.getStatus());
+ }
+
+ @Test
+ void testGetMetrics() {
+ var invocationBuilder = super.sendActRequest(METRICS_ENDPOINT);
+ var rawresp = invocationBuilder.buildGet().invoke();
+ assertEquals(Response.Status.OK.getStatusCode(), rawresp.getStatus());
+ }
+
+ @Test
+ void testGePrometheus() {
+ var invocationBuilder = super.sendActRequest(PROMETHEUS_ENDPOINT);
+ var rawresp = invocationBuilder.buildGet().invoke();
+ assertEquals(Response.Status.OK.getStatusCode(), rawresp.getStatus());
+ }
+
+}
--- /dev/null
+/*-
+ * ============LICENSE_START=======================================================
+ * 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.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.oransc.participant.dme.restclient;
+
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.when;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.oransc.participant.dme.rest.DataConsumerApiClient;
+import com.oransc.participant.dme.rest.DataProducerRegistrationApiClient;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Stream;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+import org.oransc.participant.dme.exception.DmeException;
+import org.springframework.boot.test.mock.mockito.MockBean;
+import org.springframework.http.ResponseEntity;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
+
+@ExtendWith(SpringExtension.class)
+class AcA1PmsClientTest {
+
+ @MockBean
+ DataProducerRegistrationApiClient dataProducerRegistrationApiClient;
+
+ @MockBean
+ DataConsumerApiClient dataConsumerApiClient;
+
+ @MockBean
+ AcDmeClient acDmeClient;
+
+ ObjectMapper objectMapper = new ObjectMapper();
+
+ @BeforeEach
+ void initialize() {
+ acDmeClient = new AcDmeClient(dataProducerRegistrationApiClient, dataConsumerApiClient, objectMapper);
+ }
+
+ @Test
+ void testHealthyDme() {
+ when(dataProducerRegistrationApiClient.getInfoTypdentifiersWithHttpInfo()).thenReturn(
+ ResponseEntity.ok().build());
+ assertTrue(acDmeClient.isDmeHealthy());
+ }
+
+ @Test
+ void testUnhealthyDme() {
+ when(dataProducerRegistrationApiClient.getInfoTypdentifiersWithHttpInfo()).thenReturn(
+ ResponseEntity.internalServerError().build());
+ assertFalse(acDmeClient.isDmeHealthy());
+ }
+
+ @ParameterizedTest
+ @MethodSource("getInfoTypes")
+ void testcreateInfoTypeSuccess(Map<String, String> infoTypeMap) {
+ when(dataProducerRegistrationApiClient.putInfoTypeWithHttpInfo(any(), any())).thenReturn(
+ ResponseEntity.ok().build());
+ assertDoesNotThrow(() -> acDmeClient.createInfoType(infoTypeMap));
+ }
+
+ @Test
+ void testcreateInfoTypeFailure() {
+ when(dataProducerRegistrationApiClient.putInfoTypeWithHttpInfo(any(), any())).thenReturn(
+ ResponseEntity.internalServerError().build());
+ assertThrows(DmeException.class, () -> acDmeClient.createInfoType(Map.of("infotype1", "{}")));
+ }
+
+ @ParameterizedTest
+ @MethodSource("getDataProducers")
+ void testcreateDataProducerSuccess(Map<String, String> dataProducerMap) {
+ when(dataProducerRegistrationApiClient.putInfoProducerWithHttpInfo(any(), any())).thenReturn(
+ ResponseEntity.ok().build());
+ assertDoesNotThrow(() -> acDmeClient.createDataProducer(dataProducerMap));
+ }
+
+
+ @Test
+ void testcreateDataProducerFailure() {
+ when(dataProducerRegistrationApiClient.putInfoProducerWithHttpInfo(any(), any())).thenReturn(
+ ResponseEntity.internalServerError().build());
+ assertThrows(DmeException.class, () -> acDmeClient.createDataProducer(Map.of("producer1", "{}")));
+ }
+
+ @ParameterizedTest
+ @MethodSource("getDataConsumers")
+ void testcreateDataConsumerSuccess(Map<String, String> dataConsumerMap) {
+ when(dataConsumerApiClient.putIndividualInfoJobWithHttpInfo(any(), any())).thenReturn(
+ ResponseEntity.ok().build());
+ assertDoesNotThrow(() -> acDmeClient.createDataConsumer(dataConsumerMap));
+ }
+
+ @Test
+ void testcreateDataConsumerFailure() {
+ when(dataConsumerApiClient.putIndividualInfoJobWithHttpInfo(any(), any())).thenReturn(
+ ResponseEntity.internalServerError().build());
+ assertThrows(DmeException.class, () -> acDmeClient.createDataConsumer(Map.of("consumer1", "{}")));
+ }
+
+ @ParameterizedTest
+ @MethodSource("getDeleteDataProducers")
+ void testDeleteDataProducerSuccess() {
+ when(dataProducerRegistrationApiClient.deleteInfoProducerWithHttpInfo(any())).thenReturn(
+ ResponseEntity.ok().build());
+ assertDoesNotThrow(() -> acDmeClient.deleteDataProducer(Set.of("producer1")));
+ }
+
+ @Test
+ void testDeleteDataProducerFailure() {
+ when(dataProducerRegistrationApiClient.deleteInfoProducerWithHttpInfo(any())).thenReturn(
+ ResponseEntity.internalServerError().build());
+ assertThrows(DmeException.class, () -> acDmeClient.deleteDataProducer(Set.of("producer1")));
+ }
+
+ @ParameterizedTest
+ @MethodSource("getDeleteDataConsumers")
+ void testDeleteDataConsumerSuccess() {
+ when(dataConsumerApiClient.deleteIndividualInfoJobWithHttpInfo(any())).thenReturn(ResponseEntity.ok().build());
+ assertDoesNotThrow(() -> acDmeClient.deleteDataConsumer(Set.of("consumer1")));
+ }
+
+ @Test
+ void testDeleteDataConsumerFailure() {
+ when(dataConsumerApiClient.deleteIndividualInfoJobWithHttpInfo(any())).thenReturn(
+ ResponseEntity.internalServerError().build());
+ assertThrows(DmeException.class, () -> acDmeClient.deleteDataConsumer(Set.of("consumer1")));
+ }
+
+ private static Stream<Arguments> getDeleteDataProducers() {
+ return Stream.of(Arguments.of(Set.of("producer1")), Arguments.of(Set.of()));
+ }
+
+ private static Stream<Arguments> getDeleteDataConsumers() {
+ return Stream.of(Arguments.of(Set.of("consumer1")), Arguments.of(Set.of()));
+ }
+ private static Stream<Arguments> getInfoTypes() {
+ return Stream.of(Arguments.of(Map.of("infotype1", "{}")), Arguments.of(Map.of()));
+ }
+
+ private static Stream<Arguments> getDataProducers() {
+ return Stream.of(Arguments.of(Map.of("dataproducers", "{}")), Arguments.of(Map.of()));
+ }
+
+ private static Stream<Arguments> getDataConsumers() {
+ return Stream.of(Arguments.of(Map.of("dataconsumer", "{}")), Arguments.of(Map.of()));
+ }
+}
--- /dev/null
+/*-
+ * ============LICENSE_START=======================================================
+ * 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.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.oransc.participant.dme.utils;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import jakarta.ws.rs.client.Client;
+import jakarta.ws.rs.client.ClientBuilder;
+import jakarta.ws.rs.client.Invocation;
+import jakarta.ws.rs.client.WebTarget;
+import jakarta.ws.rs.core.MediaType;
+import jakarta.ws.rs.core.Response;
+import org.glassfish.jersey.client.ClientProperties;
+import org.glassfish.jersey.client.authentication.HttpAuthenticationFeature;
+import org.onap.policy.common.gson.GsonMessageBodyHandler;
+import org.onap.policy.common.utils.network.NetworkUtil;
+
+public class CommonActuatorController {
+
+ public static final String SELF = NetworkUtil.getHostname();
+ public static final String CONTEXT_PATH = "nonrtric/dmeparticipant/";
+
+ private static String httpPrefix;
+
+ protected Invocation.Builder sendActRequest(final String endpoint) {
+ return sendFqeRequest(httpPrefix + CONTEXT_PATH + endpoint, true);
+ }
+
+ protected Invocation.Builder sendNoAuthActRequest(final String endpoint) {
+ return sendFqeRequest(httpPrefix + CONTEXT_PATH + endpoint, false);
+ }
+
+ protected Invocation.Builder sendFqeRequest(final String fullyQualifiedEndpoint, boolean includeAuth) {
+ final Client client = ClientBuilder.newBuilder().build();
+
+ client.property(ClientProperties.METAINF_SERVICES_LOOKUP_DISABLE, "true");
+ client.register(GsonMessageBodyHandler.class);
+
+ if (includeAuth) {
+ client.register(HttpAuthenticationFeature.basic("participantUser", "zb!XztG34"));
+ }
+
+ final WebTarget webTarget = client.target(fullyQualifiedEndpoint);
+
+ return webTarget.request(MediaType.APPLICATION_JSON, MediaType.TEXT_PLAIN);
+ }
+
+ protected void assertUnauthorizedActGet(final String endPoint) {
+ Response rawresp = sendNoAuthActRequest(endPoint).buildGet().invoke();
+ assertEquals(Response.Status.UNAUTHORIZED.getStatusCode(), rawresp.getStatus());
+ }
+
+ protected void setHttpPrefix(int port) {
+ httpPrefix = "http://" + SELF + ":" + port + "/";
+ }
+
+}
--- /dev/null
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2022-2023 Nordix Foundation.
+ * Modifications Copyright (C) 2022 AT&T Intellectual Property. 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.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.oransc.participant.dme.utils;
+
+import java.util.List;
+import java.util.UUID;
+import org.onap.policy.clamp.models.acm.concepts.AcElementDeploy;
+import org.onap.policy.clamp.models.acm.messages.rest.instantiation.DeployOrder;
+import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier;
+
+public class CommonTestData {
+
+ private static final String TEST_KEY_NAME = "onap.policy.clamp.ac.element.DmeAutomationCompositionElement";
+ private static final List<UUID> AC_ID_LIST = List.of(UUID.randomUUID(), UUID.randomUUID());
+
+ public AcElementDeploy getAutomationCompositionElement() {
+ var element = new AcElementDeploy();
+ element.setId(UUID.randomUUID());
+ element.setDefinition(new ToscaConceptIdentifier(TEST_KEY_NAME, "1.0.1"));
+ element.setOrderedState(DeployOrder.DEPLOY);
+ return element;
+ }
+
+ public ToscaConceptIdentifier getDmeIdentifier(int instanceNo) {
+ return new ToscaConceptIdentifier("DmeInstance" + instanceNo, "1.0.0");
+ }
+
+ public UUID getAutomationCompositionId() {
+ return getAutomationCompositionId(0);
+ }
+
+ public UUID getAutomationCompositionId(int instanceNo) {
+ return AC_ID_LIST.get(instanceNo);
+ }
+
+}
--- /dev/null
+/*-
+ * ============LICENSE_START=======================================================
+ * 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.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.oransc.participant.dme.utils;
+
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+import org.onap.policy.common.utils.coder.YamlJsonTranslator;
+import org.onap.policy.common.utils.resources.ResourceUtils;
+import org.onap.policy.models.tosca.authorative.concepts.ToscaServiceTemplate;
+
+/**
+ * Util class for Test scope.
+ */
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public final class ToscaUtils {
+
+ private static final YamlJsonTranslator yamlTranslator = new YamlJsonTranslator();
+ private static final String TOSCA_TEMPLATE_YAML = "participant-dme.yaml";
+
+ public static ToscaServiceTemplate readAutomationCompositionFromTosca() {
+ return serializeAutomationCompositionYaml();
+ }
+
+ private static ToscaServiceTemplate serializeAutomationCompositionYaml() {
+ String automationCompositionString = ResourceUtils.getResourceAsString(ToscaUtils.TOSCA_TEMPLATE_YAML);
+ return yamlTranslator.fromYaml(automationCompositionString, ToscaServiceTemplate.class);
+ }
+
+ public static void main(String[] args) {
+ System.out.println(serializeAutomationCompositionYaml());
+ }
+}
--- /dev/null
+# ============LICENSE_START=======================================================
+# 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.
+#
+# SPDX-License-Identifier: Apache-2.0
+# ============LICENSE_END=========================================================
+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.DMEAutomationCompositionElement.InfoTypeEntity:
+ version: 1.0.0
+ derived_from: tosca.datatypes.Root
+ properties:
+ infoTypeEntityId:
+ type: onap.datatypes.ToscaConceptIdentifier
+ required: true
+ description: The name and version of a Configuration Entity to be handled by
+ the DME Automation Composition Element
+ infoTypeId:
+ type: string
+ required: true
+ description: Id of the info type
+ payload:
+ type: string
+ required: true
+ description: Json payload of info type
+ org.onap.datatypes.policy.clamp.acm.DMEAutomationCompositionElement.DataProducerEntity:
+ version: 1.0.0
+ derived_from: tosca.datatypes.Root
+ properties:
+ dataProducerEntityId:
+ type: onap.datatypes.ToscaConceptIdentifier
+ required: true
+ description: The name and version of a Configuration Entity to be handled by
+ the DME Automation Composition Element
+ dataProducerId:
+ type: string
+ required: true
+ description: Id of the info type
+ payload:
+ type: string
+ required: true
+ description: Json payload of info type
+ org.onap.datatypes.policy.clamp.acm.DMEAutomationCompositionElement.DataConsumerEntity:
+ version: 1.0.0
+ derived_from: tosca.datatypes.Root
+ properties:
+ dataConsumerEntityId:
+ type: onap.datatypes.ToscaConceptIdentifier
+ required: true
+ description: The name and version of a Configuration Entity to be handled by
+ the DME Automation Composition Element
+ dataConsumerId:
+ type: string
+ required: true
+ description: Id of the info type
+ payload:
+ type: string
+ required: true
+ description: Json payload of info type
+
+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
+ 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
+ org.onap.policy.clamp.acm.AutomationComposition:
+ version: 1.0.1
+ derived_from: tosca.nodetypes.Root
+ properties:
+ provider:
+ type: string
+ required: false
+ elements:
+ type: list
+ required: true
+ entry_schema:
+ type: onap.datatypes.ToscaConceptIdentifier
+ org.onap.policy.clamp.acm.DMEAutomationCompositionElement:
+ version: 1.0.1
+ derived_from: org.onap.policy.clamp.acm.AutomationCompositionElement
+ properties:
+ infoTypeEntities:
+ type: list
+ required: true
+ entry_schema:
+ type: org.onap.datatypes.policy.clamp.acm.DMEAutomationCompositionElement.InfoTypeEntity
+ type_version: 1.0.0
+ description: The configuration entities of DME
+ dataProducerEntities:
+ type: list
+ required: true
+ entry_schema:
+ type: org.onap.datatypes.policy.clamp.acm.DMEAutomationCompositionElement.DataProducerEntity
+ type_version: 1.0.0
+ description: The configuration entities of DME
+ dataConsumerEntities:
+ type: list
+ required: true
+ entry_schema:
+ type: org.onap.datatypes.policy.clamp.acm.DMEAutomationCompositionElement.DataConsumerEntity
+ type_version: 1.0.0
+ description: The configuration entities of DME
+topology_template:
+ node_templates:
+ org.onap.policy.clamp.acm.DMEAutomationCompositionParticipant:
+ version: 2.3.4
+ type: org.onap.policy.clamp.acm.Participant
+ type_version: 1.0.1
+ description: Participant for DME
+ properties:
+ provider: ONAP
+
+ onap.policy.clamp.ac.element.DMEAutomationCompositionElement:
+ version: 1.2.3
+ type: org.onap.policy.clamp.acm.DMEAutomationCompositionElement
+ type_version: 1.0.1
+ description: Automation composition element for the DME Requests
+ properties:
+ provider: ONAP
+ participantType:
+ name: org.onap.policy.clamp.acm.DMEParticipant
+ version: 2.3.4
+ infoTypeEntities:
+ - infoTypeEntityId:
+ name: infoType1
+ version: 1.0.1
+ infoTypeId: json-file-data-from-filestore
+ payload: '{"info_job_data_schema": {"schema": "http://json-schema.org/draft-07/schema#","title":
+ "json-file-data-from-filestore","description": "json-file-data-from-filestore","type":
+ "object"}}'
+ dataProducerEntities:
+ - dataProducerEntityId:
+ name: producerType1
+ version: 1.0.1
+ dataProducerId: json-file-data-producer
+ payload: '{"info_job_callback_url": "http://localhost/jsonproducerjobcallback","info_producer_supervision_callback_url":
+ "http://localhost/jsonproducersupervisioncallback","supported_info_types": ["json-file-data-from-filestore"]}'
+ dataConsumerEntities:
+ - dataConsumerEntityId:
+ name: consumerType1
+ version: 1.0.1
+ dataConsumerId: json-file-consumer
+ payload: '{"info_type_id": "json-file-data-from-filestore","job_owner": "console","status_notification_uri":
+ "http://callback.nonrtric:80/post","job_definition": {"db-url": "http://influxdb2.nonrtric:8086","db-org":
+ "est","db-bucket": "pm-bucket","db-token": "token","filterType": "pmdata","filter":
+ {}}}'
+
+
+ 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 DME request
+ properties:
+ provider: ONAP
+ elements:
+ - name: onap.policy.clamp.ac.element.DMEAutomationCompositionElement
+ version: 1.2.3
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+* ========================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===================================
+-->
+<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.1.5</version>
+ <relativePath/>
+ </parent>
+ <groupId>org.o-ran-sc.nonrtric.plt</groupId>
+ <artifactId>participants</artifactId>
+ <version>0.0.1-SNAPSHOT</version>
+ <packaging>pom</packaging>
+ <name>NONRTRIC ACM Participants</name>
+ <description>O-RAN SC ACM Participants.</description>
+ <modules>
+ <module>participant-impl-dme</module>
+ </modules>
+ <repositories>
+ <repository>
+ <id>onap-releases</id>
+ <name>onap-releases</name>
+ <url>https://nexus.onap.org/content/repositories/releases/</url>
+ </repository>
+ </repositories>
+ <properties>
+ <java.version>17</java.version>
+ <openapi.maven.version>7.0.1</openapi.maven.version>
+ <docker-maven-plugin>0.30.0</docker-maven-plugin>
+ <jacoco-maven-plugin.version>0.8.10</jacoco-maven-plugin.version>
+ <onap.acm.models.version>7.0.1-SNAPSHOT</onap.acm.models.version>
+ <openapi.jackson.databind.nullable.version>0.2.6</openapi.jackson.databind.nullable.version>
+ </properties>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <configuration>
+ <skipTests>false</skipTests>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.jacoco</groupId>
+ <artifactId>jacoco-maven-plugin</artifactId>
+ <version>${jacoco-maven-plugin.version}</version>
+ <executions>
+ <execution>
+ <id>default-prepare-agent</id>
+ <goals>
+ <goal>prepare-agent</goal>
+ </goals>
+ </execution>
+ <execution>
+ <id>default-report</id>
+ <phase>prepare-package</phase>
+ <goals>
+ <goal>report</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ <issueManagement>
+ <system>JIRA</system>
+ <url>https://jira.o-ran-sc.org/</url>
+ </issueManagement>
+</project>