From a2f086ceca204de6abeb4310b1614a5c77beab19 Mon Sep 17 00:00:00 2001 From: "aravind.est" Date: Fri, 20 Oct 2023 15:22:31 +0100 Subject: [PATCH] Add DME Participant 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 Change-Id: I4093678f80714cc7b481109e1861f67050fb9523 --- participants/participant-impl-dme/Dockerfile | 58 ++++ participants/participant-impl-dme/pom.xml | 193 ++++++++++++++ .../org/oransc/participant/dme/Application.java | 36 +++ .../oransc/participant/dme/BeanConfiguration.java | 59 +++++ .../participant/dme/config/MicrometerConfig.java | 43 +++ .../participant/dme/config/SecurityConfig.java | 38 +++ .../participant/dme/exception/DmeException.java | 39 +++ .../AutomationCompositionElementHandler.java | 218 +++++++++++++++ .../dme/models/ConfigurationEntity.java | 40 +++ .../participant/dme/models/DataConsumerEntity.java | 46 ++++ .../participant/dme/models/DataProducerEntity.java | 46 ++++ .../participant/dme/models/InfoTypeEntity.java | 46 ++++ .../participant/dme/parameters/DmeParameters.java | 35 +++ .../dme/parameters/DmeParticipantParameters.java | 41 +++ .../participant/dme/restclient/AcDmeClient.java | 107 ++++++++ .../src/main/resources/application.yaml | 49 ++++ .../dme/handler/AcElementHandlerTest.java | 294 +++++++++++++++++++++ .../dme/rest/ActuatorControllerTest.java | 91 +++++++ .../dme/restclient/AcA1PmsClientTest.java | 173 ++++++++++++ .../dme/utils/CommonActuatorController.java | 75 ++++++ .../participant/dme/utils/CommonTestData.java | 55 ++++ .../oransc/participant/dme/utils/ToscaUtils.java | 50 ++++ .../src/test/resources/participant-dme.yaml | 199 ++++++++++++++ participants/pom.xml | 89 +++++++ 24 files changed, 2120 insertions(+) create mode 100755 participants/participant-impl-dme/Dockerfile create mode 100755 participants/participant-impl-dme/pom.xml create mode 100755 participants/participant-impl-dme/src/main/java/org/oransc/participant/dme/Application.java create mode 100755 participants/participant-impl-dme/src/main/java/org/oransc/participant/dme/BeanConfiguration.java create mode 100755 participants/participant-impl-dme/src/main/java/org/oransc/participant/dme/config/MicrometerConfig.java create mode 100755 participants/participant-impl-dme/src/main/java/org/oransc/participant/dme/config/SecurityConfig.java create mode 100755 participants/participant-impl-dme/src/main/java/org/oransc/participant/dme/exception/DmeException.java create mode 100755 participants/participant-impl-dme/src/main/java/org/oransc/participant/dme/handler/AutomationCompositionElementHandler.java create mode 100755 participants/participant-impl-dme/src/main/java/org/oransc/participant/dme/models/ConfigurationEntity.java create mode 100755 participants/participant-impl-dme/src/main/java/org/oransc/participant/dme/models/DataConsumerEntity.java create mode 100755 participants/participant-impl-dme/src/main/java/org/oransc/participant/dme/models/DataProducerEntity.java create mode 100755 participants/participant-impl-dme/src/main/java/org/oransc/participant/dme/models/InfoTypeEntity.java create mode 100755 participants/participant-impl-dme/src/main/java/org/oransc/participant/dme/parameters/DmeParameters.java create mode 100755 participants/participant-impl-dme/src/main/java/org/oransc/participant/dme/parameters/DmeParticipantParameters.java create mode 100755 participants/participant-impl-dme/src/main/java/org/oransc/participant/dme/restclient/AcDmeClient.java create mode 100755 participants/participant-impl-dme/src/main/resources/application.yaml create mode 100755 participants/participant-impl-dme/src/test/java/org/oransc/participant/dme/handler/AcElementHandlerTest.java create mode 100755 participants/participant-impl-dme/src/test/java/org/oransc/participant/dme/rest/ActuatorControllerTest.java create mode 100755 participants/participant-impl-dme/src/test/java/org/oransc/participant/dme/restclient/AcA1PmsClientTest.java create mode 100755 participants/participant-impl-dme/src/test/java/org/oransc/participant/dme/utils/CommonActuatorController.java create mode 100755 participants/participant-impl-dme/src/test/java/org/oransc/participant/dme/utils/CommonTestData.java create mode 100755 participants/participant-impl-dme/src/test/java/org/oransc/participant/dme/utils/ToscaUtils.java create mode 100755 participants/participant-impl-dme/src/test/resources/participant-dme.yaml create mode 100755 participants/pom.xml diff --git a/participants/participant-impl-dme/Dockerfile b/participants/participant-impl-dme/Dockerfile new file mode 100755 index 0000000..7f95151 --- /dev/null +++ b/participants/participant-impl-dme/Dockerfile @@ -0,0 +1,58 @@ +# +# ============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"] diff --git a/participants/participant-impl-dme/pom.xml b/participants/participant-impl-dme/pom.xml new file mode 100755 index 0000000..a856bd2 --- /dev/null +++ b/participants/participant-impl-dme/pom.xml @@ -0,0 +1,193 @@ + + + + 4.0.0 + + org.o-ran-sc.nonrtric.plt + participants + 0.0.1-SNAPSHOT + + + org.o-ran-sc.nonrtric.plt.participants + participant-impl-dme + + + 17 + 17 + UTF-8 + + + + + org.onap.policy.clamp.participant + policy-clamp-participant-intermediary + ${onap.acm.models.version} + + + org.onap.policy.clamp + policy-clamp-models + ${onap.acm.models.version} + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-security + + + io.micrometer + micrometer-registry-prometheus + + + org.projectlombok + lombok + true + + + org.openapitools + jackson-databind-nullable + ${openapi.jackson.databind.nullable.version} + + + org.springframework.boot + spring-boot-starter-test + test + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + repackage + + package + + + + + org.openapitools + openapi-generator-maven-plugin + ${openapi.maven.version} + + + dme-participant-spec-generator + + generate + + + ${project.parent.basedir}/../openapi/dme/ics-api.yaml + java + resttemplate + false + false + false + false + true + + apiNameSuffix=ApiClient + + + src/main/java + true + com.oransc.participant.dme + com.oransc.participant.dme.rest + com.oransc.participant.dme.data + false + + + + + + + io.fabric8 + docker-maven-plugin + ${docker-maven-plugin} + false + + + generate-nonrtric-plt-participant-impl-dme-image + package + + build + + + ${env.CONTAINER_PULL_REGISTRY} + + + + o-ran-sc/nonrtric-plt-participant-impl-dme:${project.version} + + + try + ${project.basedir} + Dockerfile + + ${project.build.finalName}.jar + + + ${project.version} + + + + + + + + push-nonrtric-plt-participant-impl-dme-image + + push + + + ${env.CONTAINER_PUSH_REGISTRY} + + + + o-ran-sc/nonrtric-plt-participant-impl-dme:${project.version} + + + ${project.basedir} + Dockerfile + + ${project.build.finalName}.jar + + + ${project.version} + latest + + + + + + + + + + + diff --git a/participants/participant-impl-dme/src/main/java/org/oransc/participant/dme/Application.java b/participants/participant-impl-dme/src/main/java/org/oransc/participant/dme/Application.java new file mode 100755 index 0000000..73fd5a6 --- /dev/null +++ b/participants/participant-impl-dme/src/main/java/org/oransc/participant/dme/Application.java @@ -0,0 +1,36 @@ +/*- + * ============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); + } +} diff --git a/participants/participant-impl-dme/src/main/java/org/oransc/participant/dme/BeanConfiguration.java b/participants/participant-impl-dme/src/main/java/org/oransc/participant/dme/BeanConfiguration.java new file mode 100755 index 0000000..ac8296c --- /dev/null +++ b/participants/participant-impl-dme/src/main/java/org/oransc/participant/dme/BeanConfiguration.java @@ -0,0 +1,59 @@ +/*- + * ============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); + } +} diff --git a/participants/participant-impl-dme/src/main/java/org/oransc/participant/dme/config/MicrometerConfig.java b/participants/participant-impl-dme/src/main/java/org/oransc/participant/dme/config/MicrometerConfig.java new file mode 100755 index 0000000..77f7da0 --- /dev/null +++ b/participants/participant-impl-dme/src/main/java/org/oransc/participant/dme/config/MicrometerConfig.java @@ -0,0 +1,43 @@ +/*- + * ============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); + } +} diff --git a/participants/participant-impl-dme/src/main/java/org/oransc/participant/dme/config/SecurityConfig.java b/participants/participant-impl-dme/src/main/java/org/oransc/participant/dme/config/SecurityConfig.java new file mode 100755 index 0000000..53df1d0 --- /dev/null +++ b/participants/participant-impl-dme/src/main/java/org/oransc/participant/dme/config/SecurityConfig.java @@ -0,0 +1,38 @@ +/*- + * ========================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(); + } +} diff --git a/participants/participant-impl-dme/src/main/java/org/oransc/participant/dme/exception/DmeException.java b/participants/participant-impl-dme/src/main/java/org/oransc/participant/dme/exception/DmeException.java new file mode 100755 index 0000000..5a7861e --- /dev/null +++ b/participants/participant-impl-dme/src/main/java/org/oransc/participant/dme/exception/DmeException.java @@ -0,0 +1,39 @@ +/*- + * ============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); + } +} diff --git a/participants/participant-impl-dme/src/main/java/org/oransc/participant/dme/handler/AutomationCompositionElementHandler.java b/participants/participant-impl-dme/src/main/java/org/oransc/participant/dme/handler/AutomationCompositionElementHandler.java new file mode 100755 index 0000000..612295e --- /dev/null +++ b/participants/participant-impl-dme/src/main/java/org/oransc/participant/dme/handler/AutomationCompositionElementHandler.java @@ -0,0 +1,218 @@ +/*- + * ============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 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 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 properties) { + intermediaryApi.updateAutomationCompositionElementState(instanceId, element.getId(), DeployState.DEPLOYED, null, + StateChangeResult.NO_ERROR, "Update not supported"); + } + + @Override + public void prime(UUID compositionId, List 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 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 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 properties) { + intermediaryApi.updateAutomationCompositionElementState(automationCompositionId, element.getId(), + DeployState.DEPLOYED, null, StateChangeResult.NO_ERROR, "Migrated"); + } +} diff --git a/participants/participant-impl-dme/src/main/java/org/oransc/participant/dme/models/ConfigurationEntity.java b/participants/participant-impl-dme/src/main/java/org/oransc/participant/dme/models/ConfigurationEntity.java new file mode 100755 index 0000000..a312226 --- /dev/null +++ b/participants/participant-impl-dme/src/main/java/org/oransc/participant/dme/models/ConfigurationEntity.java @@ -0,0 +1,40 @@ +/*- + * ============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 infoTypeEntities; + + @Valid + private List dataProducerEntities; + + @Valid + private List dataConsumerEntities; +} diff --git a/participants/participant-impl-dme/src/main/java/org/oransc/participant/dme/models/DataConsumerEntity.java b/participants/participant-impl-dme/src/main/java/org/oransc/participant/dme/models/DataConsumerEntity.java new file mode 100755 index 0000000..381e0ff --- /dev/null +++ b/participants/participant-impl-dme/src/main/java/org/oransc/participant/dme/models/DataConsumerEntity.java @@ -0,0 +1,46 @@ +/*- + * ============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; + +} diff --git a/participants/participant-impl-dme/src/main/java/org/oransc/participant/dme/models/DataProducerEntity.java b/participants/participant-impl-dme/src/main/java/org/oransc/participant/dme/models/DataProducerEntity.java new file mode 100755 index 0000000..ab9b734 --- /dev/null +++ b/participants/participant-impl-dme/src/main/java/org/oransc/participant/dme/models/DataProducerEntity.java @@ -0,0 +1,46 @@ +/*- + * ============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; + +} diff --git a/participants/participant-impl-dme/src/main/java/org/oransc/participant/dme/models/InfoTypeEntity.java b/participants/participant-impl-dme/src/main/java/org/oransc/participant/dme/models/InfoTypeEntity.java new file mode 100755 index 0000000..07d9735 --- /dev/null +++ b/participants/participant-impl-dme/src/main/java/org/oransc/participant/dme/models/InfoTypeEntity.java @@ -0,0 +1,46 @@ +/*- + * ============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; + +} diff --git a/participants/participant-impl-dme/src/main/java/org/oransc/participant/dme/parameters/DmeParameters.java b/participants/participant-impl-dme/src/main/java/org/oransc/participant/dme/parameters/DmeParameters.java new file mode 100755 index 0000000..76581dc --- /dev/null +++ b/participants/participant-impl-dme/src/main/java/org/oransc/participant/dme/parameters/DmeParameters.java @@ -0,0 +1,35 @@ +/*- + * ============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; +} diff --git a/participants/participant-impl-dme/src/main/java/org/oransc/participant/dme/parameters/DmeParticipantParameters.java b/participants/participant-impl-dme/src/main/java/org/oransc/participant/dme/parameters/DmeParticipantParameters.java new file mode 100755 index 0000000..bfc6b0a --- /dev/null +++ b/participants/participant-impl-dme/src/main/java/org/oransc/participant/dme/parameters/DmeParticipantParameters.java @@ -0,0 +1,41 @@ +/*- + * ============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; +} diff --git a/participants/participant-impl-dme/src/main/java/org/oransc/participant/dme/restclient/AcDmeClient.java b/participants/participant-impl-dme/src/main/java/org/oransc/participant/dme/restclient/AcDmeClient.java new file mode 100755 index 0000000..ab963e5 --- /dev/null +++ b/participants/participant-impl-dme/src/main/java/org/oransc/participant/dme/restclient/AcDmeClient.java @@ -0,0 +1,107 @@ +/*- + * ============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 infoTypeMap) throws DmeException, JsonProcessingException { + for (Map.Entry entry : infoTypeMap.entrySet()) { + String infoTypeName = entry.getKey(); + ProducerInfoTypeInfo infoTypeInfo = objectMapper.readValue(entry.getValue(), ProducerInfoTypeInfo.class); + ResponseEntity objectResponseEntity = + dataProducerRegistrationApiClient.putInfoTypeWithHttpInfo(infoTypeName, infoTypeInfo); + if (!objectResponseEntity.getStatusCode().is2xxSuccessful()) { + throw new DmeException(objectResponseEntity.getStatusCode().value(), "Error in creating info types"); + } + } + } + + public void createDataProducer(Map dataProducerMap) throws DmeException, JsonProcessingException { + for (Map.Entry entry : dataProducerMap.entrySet()) { + String infoProducerName = entry.getKey(); + ProducerRegistrationInfo producerRegistrationInfo = + objectMapper.readValue(entry.getValue(), ProducerRegistrationInfo.class); + ResponseEntity objectResponseEntity = + dataProducerRegistrationApiClient.putInfoProducerWithHttpInfo(infoProducerName, + producerRegistrationInfo); + if (!objectResponseEntity.getStatusCode().is2xxSuccessful()) { + throw new DmeException(objectResponseEntity.getStatusCode().value(), "Error in creating data producer"); + } + } + } + + public void createDataConsumer(Map dataConsumerMap) throws DmeException, JsonProcessingException { + for (Map.Entry entry : dataConsumerMap.entrySet()) { + String infoProducerName = entry.getKey(); + ConsumerJob consumerJob = objectMapper.readValue(entry.getValue(), ConsumerJob.class); + ResponseEntity objectResponseEntity = + dataConsumerApiClient.putIndividualInfoJobWithHttpInfo(infoProducerName, consumerJob); + if (!objectResponseEntity.getStatusCode().is2xxSuccessful()) { + throw new DmeException(objectResponseEntity.getStatusCode().value(), "Error in creating data consumer"); + } + } + } + + public void deleteDataProducer(Set dataProducerList) throws DmeException { + for (String dataProducer : dataProducerList) { + ResponseEntity objectResponseEntity = + dataProducerRegistrationApiClient.deleteInfoProducerWithHttpInfo(dataProducer); + if (!objectResponseEntity.getStatusCode().is2xxSuccessful()) { + throw new DmeException(objectResponseEntity.getStatusCode().value(), "Error in deleting data producer"); + } + } + } + + public void deleteDataConsumer(Set dataConsumerList) throws DmeException { + for (String dataConsumer : dataConsumerList) { + ResponseEntity objectResponseEntity = + dataConsumerApiClient.deleteIndividualInfoJobWithHttpInfo(dataConsumer); + if (!objectResponseEntity.getStatusCode().is2xxSuccessful()) { + throw new DmeException(objectResponseEntity.getStatusCode().value(), "Error in deleting data consumer"); + } + } + } + +} diff --git a/participants/participant-impl-dme/src/main/resources/application.yaml b/participants/participant-impl-dme/src/main/resources/application.yaml new file mode 100755 index 0000000..e1f60e1 --- /dev/null +++ b/participants/participant-impl-dme/src/main/resources/application.yaml @@ -0,0 +1,49 @@ +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 diff --git a/participants/participant-impl-dme/src/test/java/org/oransc/participant/dme/handler/AcElementHandlerTest.java b/participants/participant-impl-dme/src/test/java/org/oransc/participant/dme/handler/AcElementHandlerTest.java new file mode 100755 index 0000000..fd4cc94 --- /dev/null +++ b/participants/participant-impl-dme/src/test/java/org/oransc/participant/dme/handler/AcElementHandlerTest.java @@ -0,0 +1,294 @@ +/*- + * ============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"); + } +} diff --git a/participants/participant-impl-dme/src/test/java/org/oransc/participant/dme/rest/ActuatorControllerTest.java b/participants/participant-impl-dme/src/test/java/org/oransc/participant/dme/rest/ActuatorControllerTest.java new file mode 100755 index 0000000..bdcd3ed --- /dev/null +++ b/participants/participant-impl-dme/src/test/java/org/oransc/participant/dme/rest/ActuatorControllerTest.java @@ -0,0 +1,91 @@ +/*- + * ============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()); + } + +} diff --git a/participants/participant-impl-dme/src/test/java/org/oransc/participant/dme/restclient/AcA1PmsClientTest.java b/participants/participant-impl-dme/src/test/java/org/oransc/participant/dme/restclient/AcA1PmsClientTest.java new file mode 100755 index 0000000..f7489d9 --- /dev/null +++ b/participants/participant-impl-dme/src/test/java/org/oransc/participant/dme/restclient/AcA1PmsClientTest.java @@ -0,0 +1,173 @@ +/*- + * ============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 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 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 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 getDeleteDataProducers() { + return Stream.of(Arguments.of(Set.of("producer1")), Arguments.of(Set.of())); + } + + private static Stream getDeleteDataConsumers() { + return Stream.of(Arguments.of(Set.of("consumer1")), Arguments.of(Set.of())); + } + private static Stream getInfoTypes() { + return Stream.of(Arguments.of(Map.of("infotype1", "{}")), Arguments.of(Map.of())); + } + + private static Stream getDataProducers() { + return Stream.of(Arguments.of(Map.of("dataproducers", "{}")), Arguments.of(Map.of())); + } + + private static Stream getDataConsumers() { + return Stream.of(Arguments.of(Map.of("dataconsumer", "{}")), Arguments.of(Map.of())); + } +} diff --git a/participants/participant-impl-dme/src/test/java/org/oransc/participant/dme/utils/CommonActuatorController.java b/participants/participant-impl-dme/src/test/java/org/oransc/participant/dme/utils/CommonActuatorController.java new file mode 100755 index 0000000..894087a --- /dev/null +++ b/participants/participant-impl-dme/src/test/java/org/oransc/participant/dme/utils/CommonActuatorController.java @@ -0,0 +1,75 @@ +/*- + * ============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 + "/"; + } + +} diff --git a/participants/participant-impl-dme/src/test/java/org/oransc/participant/dme/utils/CommonTestData.java b/participants/participant-impl-dme/src/test/java/org/oransc/participant/dme/utils/CommonTestData.java new file mode 100755 index 0000000..3cb897f --- /dev/null +++ b/participants/participant-impl-dme/src/test/java/org/oransc/participant/dme/utils/CommonTestData.java @@ -0,0 +1,55 @@ +/*- + * ============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 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); + } + +} diff --git a/participants/participant-impl-dme/src/test/java/org/oransc/participant/dme/utils/ToscaUtils.java b/participants/participant-impl-dme/src/test/java/org/oransc/participant/dme/utils/ToscaUtils.java new file mode 100755 index 0000000..99cedc1 --- /dev/null +++ b/participants/participant-impl-dme/src/test/java/org/oransc/participant/dme/utils/ToscaUtils.java @@ -0,0 +1,50 @@ +/*- + * ============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()); + } +} diff --git a/participants/participant-impl-dme/src/test/resources/participant-dme.yaml b/participants/participant-impl-dme/src/test/resources/participant-dme.yaml new file mode 100755 index 0000000..c72c8c7 --- /dev/null +++ b/participants/participant-impl-dme/src/test/resources/participant-dme.yaml @@ -0,0 +1,199 @@ +# ============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 diff --git a/participants/pom.xml b/participants/pom.xml new file mode 100755 index 0000000..8eee1f5 --- /dev/null +++ b/participants/pom.xml @@ -0,0 +1,89 @@ + + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 3.1.5 + + + org.o-ran-sc.nonrtric.plt + participants + 0.0.1-SNAPSHOT + pom + NONRTRIC ACM Participants + O-RAN SC ACM Participants. + + participant-impl-dme + + + + onap-releases + onap-releases + https://nexus.onap.org/content/repositories/releases/ + + + + 17 + 7.0.1 + 0.30.0 + 0.8.10 + 7.0.1-SNAPSHOT + 0.2.6 + + + + + org.apache.maven.plugins + maven-surefire-plugin + + false + + + + org.jacoco + jacoco-maven-plugin + ${jacoco-maven-plugin.version} + + + default-prepare-agent + + prepare-agent + + + + default-report + prepare-package + + report + + + + + + + + JIRA + https://jira.o-ran-sc.org/ + + -- 2.16.6