From bf6cc68f7f6c58f57ca8a384bbe71f4061a9285c Mon Sep 17 00:00:00 2001 From: "aravind.est" Date: Mon, 21 Nov 2022 15:26:58 +0000 Subject: Add A1 PMS participant Issue-ID: CCSDK-3816 Signed-off-by: aravind.est Change-Id: I00c04542f5ec4672b1c3a29ca32477bf5d2ca336 --- .../clamp/acm/test/participant-a1pms.yaml | 146 +++++++++++++++++++ packages/policy-clamp-docker/pom.xml | 40 ++++++ .../main/docker/A1pmsParticipant-Suse.Dockerfile | 64 +++++++++ .../src/main/docker/A1pmsParticipant.Dockerfile | 58 ++++++++ .../src/main/docker/a1pms-participant.sh | 59 ++++++++ packages/policy-clamp-tarball/pom.xml | 5 + .../resources/etc/A1pmsParticipantParameters.yaml | 57 ++++++++ packages/pom.xml | 1 + .../participant-impl-a1pms/pom.xml | 50 +++++++ .../clamp/acm/participant/a1pms/Application.java | 48 +++++++ .../participant/a1pms/config/MicrometerConfig.java | 46 ++++++ .../a1pms/config/ParticipantConfig.java | 43 ++++++ .../participant/a1pms/config/SecurityConfig.java | 45 ++++++ .../a1pms/exception/A1PolicyServiceException.java | 35 +++++ .../AutomationCompositionElementHandler.java | 156 +++++++++++++++++++++ .../a1pms/models/A1PolicyServiceEntity.java | 54 +++++++ .../a1pms/models/ConfigurationEntity.java | 37 +++++ .../a1pms/parameters/A1PmsParameters.java | 55 ++++++++ .../parameters/A1PmsParticipantParameters.java | 44 ++++++ .../participant/a1pms/webclient/AcA1PmsClient.java | 129 +++++++++++++++++ .../src/main/resources/config/application.yaml | 59 ++++++++ .../a1pms/handler/AcElementHandlerTest.java | 110 +++++++++++++++ .../a1pms/rest/ActuatorControllerTest.java | 92 ++++++++++++ .../a1pms/utils/CommonActuatorController.java | 107 ++++++++++++++ .../participant/a1pms/utils/CommonTestData.java | 78 +++++++++++ .../participant/a1pms/utils/MockRestEndpoint.java | 83 +++++++++++ .../participant/a1pms/utils/MockServerRest.java | 65 +++++++++ .../acm/participant/a1pms/utils/ToscaUtils.java | 51 +++++++ .../a1pms/webclient/AcA1PmsClientTest.java | 148 +++++++++++++++++++ .../src/test/resources/application-test.yaml | 24 ++++ participant/participant-impl/pom.xml | 1 + pom.xml | 1 + 32 files changed, 1991 insertions(+) create mode 100755 examples/src/main/resources/clamp/acm/test/participant-a1pms.yaml create mode 100755 packages/policy-clamp-docker/src/main/docker/A1pmsParticipant-Suse.Dockerfile create mode 100755 packages/policy-clamp-docker/src/main/docker/A1pmsParticipant.Dockerfile create mode 100755 packages/policy-clamp-docker/src/main/docker/a1pms-participant.sh create mode 100755 packages/policy-clamp-tarball/src/main/resources/etc/A1pmsParticipantParameters.yaml create mode 100755 participant/participant-impl/participant-impl-a1pms/pom.xml create mode 100755 participant/participant-impl/participant-impl-a1pms/src/main/java/org/onap/policy/clamp/acm/participant/a1pms/Application.java create mode 100755 participant/participant-impl/participant-impl-a1pms/src/main/java/org/onap/policy/clamp/acm/participant/a1pms/config/MicrometerConfig.java create mode 100755 participant/participant-impl/participant-impl-a1pms/src/main/java/org/onap/policy/clamp/acm/participant/a1pms/config/ParticipantConfig.java create mode 100755 participant/participant-impl/participant-impl-a1pms/src/main/java/org/onap/policy/clamp/acm/participant/a1pms/config/SecurityConfig.java create mode 100755 participant/participant-impl/participant-impl-a1pms/src/main/java/org/onap/policy/clamp/acm/participant/a1pms/exception/A1PolicyServiceException.java create mode 100755 participant/participant-impl/participant-impl-a1pms/src/main/java/org/onap/policy/clamp/acm/participant/a1pms/handler/AutomationCompositionElementHandler.java create mode 100755 participant/participant-impl/participant-impl-a1pms/src/main/java/org/onap/policy/clamp/acm/participant/a1pms/models/A1PolicyServiceEntity.java create mode 100755 participant/participant-impl/participant-impl-a1pms/src/main/java/org/onap/policy/clamp/acm/participant/a1pms/models/ConfigurationEntity.java create mode 100755 participant/participant-impl/participant-impl-a1pms/src/main/java/org/onap/policy/clamp/acm/participant/a1pms/parameters/A1PmsParameters.java create mode 100755 participant/participant-impl/participant-impl-a1pms/src/main/java/org/onap/policy/clamp/acm/participant/a1pms/parameters/A1PmsParticipantParameters.java create mode 100755 participant/participant-impl/participant-impl-a1pms/src/main/java/org/onap/policy/clamp/acm/participant/a1pms/webclient/AcA1PmsClient.java create mode 100755 participant/participant-impl/participant-impl-a1pms/src/main/resources/config/application.yaml create mode 100755 participant/participant-impl/participant-impl-a1pms/src/test/java/org/onap/policy/clamp/acm/participant/a1pms/handler/AcElementHandlerTest.java create mode 100755 participant/participant-impl/participant-impl-a1pms/src/test/java/org/onap/policy/clamp/acm/participant/a1pms/rest/ActuatorControllerTest.java create mode 100755 participant/participant-impl/participant-impl-a1pms/src/test/java/org/onap/policy/clamp/acm/participant/a1pms/utils/CommonActuatorController.java create mode 100755 participant/participant-impl/participant-impl-a1pms/src/test/java/org/onap/policy/clamp/acm/participant/a1pms/utils/CommonTestData.java create mode 100755 participant/participant-impl/participant-impl-a1pms/src/test/java/org/onap/policy/clamp/acm/participant/a1pms/utils/MockRestEndpoint.java create mode 100755 participant/participant-impl/participant-impl-a1pms/src/test/java/org/onap/policy/clamp/acm/participant/a1pms/utils/MockServerRest.java create mode 100755 participant/participant-impl/participant-impl-a1pms/src/test/java/org/onap/policy/clamp/acm/participant/a1pms/utils/ToscaUtils.java create mode 100755 participant/participant-impl/participant-impl-a1pms/src/test/java/org/onap/policy/clamp/acm/participant/a1pms/webclient/AcA1PmsClientTest.java create mode 100755 participant/participant-impl/participant-impl-a1pms/src/test/resources/application-test.yaml diff --git a/examples/src/main/resources/clamp/acm/test/participant-a1pms.yaml b/examples/src/main/resources/clamp/acm/test/participant-a1pms.yaml new file mode 100755 index 000000000..9e3f20c34 --- /dev/null +++ b/examples/src/main/resources/clamp/acm/test/participant-a1pms.yaml @@ -0,0 +1,146 @@ +# ============LICENSE_START======================================================= +# Copyright (C) 2022 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.a1PmsAutomationCompositionElement.A1PolicyServiceEntity: + version: 1.0.0 + derived_from: tosca.datatypes.Root + properties: + a1PolicyServiceEntityId: + type: onap.datatypes.ToscaConceptIdentifier + type_version: 0.0.0 + required: true + description: The name and version of a Configuration Entity to be handled by the A1 PMS Automation Composition Element + clientId: + type: string + required: true + description: Client Id to be created + callbackUrl: + type: string + required: true + description: The callback URL to get registered + keepAliveIntervalSeconds: + type: integer + required: true + description: Keep alive interval time for the callback URL + +node_types: + org.onap.policy.clamp.acm.Participant: + version: 1.0.1 + derived_from: tosca.nodetypes.Root + properties: + provider: + type: string + required: false + org.onap.policy.clamp.acm.AutomationCompositionElement: + version: 1.0.1 + derived_from: tosca.nodetypes.Root + properties: + provider: + type: string + required: false + participantType: + type: onap.datatypes.ToscaConceptIdentifier + required: true + startPhase: + type: integer + required: false + constraints: + - greater-or-equal: 0 + metadata: + common: true + description: A value indicating the start phase in which this automation composition element will be started, the + first start phase is zero. Automation Composition Elements are started in their start_phase order and stopped + in reverse start phase order. Automation Composition Elements with the same start phase are started and + stopped simultaneously + 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.A1PMSAutomationCompositionElement: + version: 1.0.1 + derived_from: org.onap.policy.clamp.acm.AutomationCompositionElement + properties: + policyServiceEntities: + type: list + required: true + entry_schema: + type: org.onap.datatypes.policy.clamp.acm.a1pmsAutomationCompositionElement.A1PolicyServiceEntity + type_version: 1.0.0 + description: The configuration entities of A1 policy services +topology_template: + node_templates: + org.onap.k8s.acm.A1PMSAutomationCompositionParticipant: + version: 2.3.4 + type: org.onap.policy.clamp.acm.Participant + type_version: 1.0.1 + description: Participant for A1 PMS requests + properties: + provider: ONAP + + org.onap.domain.database.A1PMSAutomationCompositionElement: + version: 1.2.3 + type: org.onap.policy.clamp.acm.A1PMSAutomationCompositionElement + type_version: 1.0.1 + description: Automation composition element for the A1 PMS Requests + properties: + provider: ONAP + participantType: + name: org.onap.policy.clamp.acm.A1PMSParticipant + version: 2.3.4 + policyServiceEntities: + - a1PolicyServiceEntityId: + name: entity1 + version: 1.0.1 + clientId: firstService + callbackUrl: http://localhost + keepAliveIntervalSeconds: 0 + - a1PolicyServiceEntityId: + name: entity2 + version: 1.0.1 + clientId: secondService + callbackUrl: http://127.0.0.1 + keepAliveIntervalSeconds: 0 + + org.onap.domain.sample.A1PMSAutomationCompositionDefinition: + version: 1.2.3 + type: org.onap.policy.clamp.acm.AutomationComposition + type_version: 1.0.0 + description: Automation composition for A1PMS request + properties: + provider: ONAP + elements: + - name: org.onap.domain.database.A1PMSAutomationCompositionElement + version: 1.2.3 diff --git a/packages/policy-clamp-docker/pom.xml b/packages/policy-clamp-docker/pom.xml index 57fe51bc5..f4e863d77 100644 --- a/packages/policy-clamp-docker/pom.xml +++ b/packages/policy-clamp-docker/pom.xml @@ -51,6 +51,8 @@ ${project.basedir}/src/main/docker HttpParticipant.Dockerfile ${project.basedir}/src/main/docker + A1pmsParticipant.Dockerfile + ${project.basedir}/src/main/docker ElementParticipant.Dockerfile ${project.basedir}/src/main/docker yyyyMMdd'T'HHmm @@ -79,6 +81,11 @@ policy-clamp-participant-impl-http ${project.version} + + org.onap.policy.clamp.participant + policy-clamp-participant-impl-a1pms + ${project.version} + org.onap.policy.clamp.participant policy-clamp-acm-element-impl @@ -272,6 +279,39 @@ + + onap/policy-clamp-ac-a1pms-ppnt + onap-policy-clamp-ac-a1pms-ppnt + + try + ${docker.clamp-ac-a1pms-ppnt.dockerFile} + ${docker.clamp-ac-a1pms-ppnt.contextDir} + + ${project.version} + ${project.version}-${maven.build.timestamp} + ${project.docker.latest.minmax.tag.version} + + + + + + + org.onap.policy.clamp:policy-clamp-tarball + + /lib + a1pms-participant.tar.gz + + + + org.onap.policy.clamp.participant:policy-clamp-participant-impl-a1pms + + policy-clamp-participant-impl-a1pms.jar + + + + + + onap/policy-clamp-acm-element-impl onap-policy-clamp-acm-element-impl diff --git a/packages/policy-clamp-docker/src/main/docker/A1pmsParticipant-Suse.Dockerfile b/packages/policy-clamp-docker/src/main/docker/A1pmsParticipant-Suse.Dockerfile new file mode 100755 index 000000000..33d66da46 --- /dev/null +++ b/packages/policy-clamp-docker/src/main/docker/A1pmsParticipant-Suse.Dockerfile @@ -0,0 +1,64 @@ +#------------------------------------------------------------------------------- +# ============LICENSE_START======================================================= +# Copyright (C) 2022 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 busybox AS tarball +RUN mkdir /packages /extracted +COPY /maven/lib/a1pms-participant.tar.gz /packages/ +RUN tar xvzf /packages/a1pms-participant.tar.gz --directory /extracted/ + +FROM opensuse/leap:15.4 + +LABEL maintainer="Policy Team" +LABEL org.opencontainers.image.title="Policy CLAMP ACM A1 PMS Participant" +LABEL org.opencontainers.image.description="Policy CLAMP ACM A1 PMS Participant image based on OpenSuse" +LABEL org.opencontainers.image.url="https://github.com/onap/policy-clamp" +LABEL org.opencontainers.image.vendor="ONAP Policy Team" +LABEL org.opencontainers.image.licenses="Apache-2.0" +LABEL org.opencontainers.image.created="${git.build.time}" +LABEL org.opencontainers.image.version="${git.build.version}" +LABEL org.opencontainers.image.revision="${git.commit.id.abbrev}" + +ARG POLICY_LOGS=/var/log/onap/policy/a1pms-participant + +ENV POLICY_LOGS=$POLICY_LOGS +ENV POLICY_HOME=/opt/app/policy/clamp +ENV LANG=en_US.UTF-8 LANGUAGE=en_US:en LC_ALL=en_US.UTF-8 +ENV JAVA_HOME=/usr/lib64/jvm/java-11-openjdk-11 + +RUN zypper -n -q install --no-recommends java-11-openjdk-headless netcat-openbsd && \ + zypper -n -q update && zypper -n -q clean --all && \ + groupadd --system policy && \ + useradd --system --shell /bin/sh -G policy policy && \ + mkdir -p $POLICY_HOME $POLICY_LOGS && \ + chown -R policy:policy $POLICY_HOME $POLICY_LOGS + +COPY --chown=policy:policy --from=tarball /extracted $POLICY_HOME + +WORKDIR $POLICY_HOME +COPY --chown=policy:policy a1pms-participant.sh bin/ +COPY --chown=policy:policy /maven/policy-clamp-participant-impl-a1.jar /app/app.jar + +RUN chmod 755 bin/*.sh + +EXPOSE 8086 + +USER policy +WORKDIR $POLICY_HOME/bin +ENTRYPOINT [ "./a1pms-participant.sh" ] diff --git a/packages/policy-clamp-docker/src/main/docker/A1pmsParticipant.Dockerfile b/packages/policy-clamp-docker/src/main/docker/A1pmsParticipant.Dockerfile new file mode 100755 index 000000000..fc2ef78f0 --- /dev/null +++ b/packages/policy-clamp-docker/src/main/docker/A1pmsParticipant.Dockerfile @@ -0,0 +1,58 @@ +#------------------------------------------------------------------------------- +# ============LICENSE_START======================================================= +# Copyright (C) 2021-2022 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 busybox AS tarball +RUN mkdir /packages /extracted +COPY /maven/lib/a1pms-participant.tar.gz /packages/ +RUN tar xvzf /packages/a1pms-participant.tar.gz --directory /extracted/ + +FROM onap/policy-jre-alpine:2.6.0-SNAPSHOT + +LABEL maintainer="Policy Team" +LABEL org.opencontainers.image.title="Policy CLAMP ACM A1 PMS Participant" +LABEL org.opencontainers.image.description="Policy CLAMP ACM A1 PMS Participant image based on Alpine" +LABEL org.opencontainers.image.url="https://github.com/onap/policy-clamp" +LABEL org.opencontainers.image.vendor="ONAP Policy Team" +LABEL org.opencontainers.image.licenses="Apache-2.0" +LABEL org.opencontainers.image.created="${git.build.time}" +LABEL org.opencontainers.image.version="${git.build.version}" +LABEL org.opencontainers.image.revision="${git.commit.id.abbrev}" + +ARG POLICY_LOGS=/var/log/onap/policy/a1pms-participant + +ENV POLICY_LOGS=$POLICY_LOGS +ENV POLICY_HOME=$POLICY_HOME/clamp + +RUN mkdir -p $POLICY_LOGS $POLICY_HOME && \ + chown -R policy:policy $POLICY_HOME $POLICY_LOGS + +COPY --chown=policy:policy --from=tarball /extracted $POLICY_HOME + +WORKDIR $POLICY_HOME +COPY --chown=policy:policy a1pms-participant.sh bin/ +COPY --chown=policy:policy /maven/policy-clamp-participant-impl-a1pms.jar /app/app.jar + +RUN chmod 755 bin/*.sh + +EXPOSE 8086 + +USER policy +WORKDIR $POLICY_HOME/bin +ENTRYPOINT [ "./a1pms-participant.sh" ] diff --git a/packages/policy-clamp-docker/src/main/docker/a1pms-participant.sh b/packages/policy-clamp-docker/src/main/docker/a1pms-participant.sh new file mode 100755 index 000000000..72aae5e9e --- /dev/null +++ b/packages/policy-clamp-docker/src/main/docker/a1pms-participant.sh @@ -0,0 +1,59 @@ +#!/usr/bin/env sh +# +# ============LICENSE_START======================================================= +# Copyright (C) 2021-2022 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========================================================= +# + +KEYSTORE="${KEYSTORE:-$POLICY_HOME/etc/ssl/policy-keystore}" +TRUSTSTORE="${TRUSTSTORE:-$POLICY_HOME/etc/ssl/policy-truststore}" +KEYSTORE_PASSWD="${KEYSTORE_PASSWD:-Pol1cy_0nap}" +TRUSTSTORE_PASSWD="${TRUSTSTORE_PASSWD:-Pol1cy_0nap}" + +if [ "$#" -eq 1 ]; then + CONFIG_FILE=$1 +fi + +if [ -z "$CONFIG_FILE" ]; then + CONFIG_FILE="${POLICY_HOME}/etc/A1pmsParticipantParameters.yaml" +fi + +echo "Policy clamp A1 Pms participant config file: $CONFIG_FILE" + +if [ -f "${POLICY_HOME}/etc/mounted/policy-truststore" ]; then + echo "overriding policy-truststore" + cp -f "${POLICY_HOME}"/etc/mounted/policy-truststore "${TRUSTSTORE}" +fi + +if [ -f "${POLICY_HOME}/etc/mounted/policy-keystore" ]; then + echo "overriding policy-keystore" + cp -f "${POLICY_HOME}"/etc/mounted/policy-keystore "${KEYSTORE}" +fi + +if [ -f "${POLICY_HOME}/etc/mounted/logback.xml" ]; then + echo "overriding logback xml file" + cp -f "${POLICY_HOME}"/etc/mounted/logback.xml "${POLICY_HOME}"/etc/ +fi + +$JAVA_HOME/bin/java \ + -Dlogging.config="${POLICY_HOME}/etc/logback.xml" \ + -Dserver.ssl.keyStore="${KEYSTORE}" \ + -Dserver.ssl.keyStorePassword="${KEYSTORE_PASSWD}" \ + -Djavax.net.ssl.trustStore="${TRUSTSTORE}" \ + -Djavax.net.ssl.trustStorePassword="${TRUSTSTORE_PASSWD}" \ + -jar /app/app.jar \ + --spring.config.location="${CONFIG_FILE}" diff --git a/packages/policy-clamp-tarball/pom.xml b/packages/policy-clamp-tarball/pom.xml index 1d3c67f54..769813a23 100644 --- a/packages/policy-clamp-tarball/pom.xml +++ b/packages/policy-clamp-tarball/pom.xml @@ -52,6 +52,11 @@ policy-clamp-participant-impl-http ${project.version} + + org.onap.policy.clamp.participant + policy-clamp-participant-impl-a1pms + ${project.version} + org.onap.policy.clamp.participant policy-clamp-acm-element-impl diff --git a/packages/policy-clamp-tarball/src/main/resources/etc/A1pmsParticipantParameters.yaml b/packages/policy-clamp-tarball/src/main/resources/etc/A1pmsParticipantParameters.yaml new file mode 100755 index 000000000..54a592484 --- /dev/null +++ b/packages/policy-clamp-tarball/src/main/resources/etc/A1pmsParticipantParameters.yaml @@ -0,0 +1,57 @@ +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 + +a1pms: + baseUrl: http://a1policymanagement.onap:8081 + headers: + content-type: application/json + endpoints: + health: /a1-policy/v2/rics + services: /a1-policy/v2/services + service: /a1-policy/v2/services/{service_id} + +participant: + intermediaryParameters: + reportingTimeIntervalMs: 120000 + description: Participant Description + participantId: + name: A1PMSParticipant0 + version: 1.0.0 + participantType: + name: org.onap.policy.clamp.acm.A1PMSParticipant + version: 2.3.4 + clampAutomationCompositionTopics: + topicSources: + - topic: POLICY-ACRUNTIME-PARTICIPANT + servers: + - ${topicServer:localhost} + topicCommInfrastructure: dmaap + fetchTimeout: 15000 + topicSinks: + - topic: POLICY-ACRUNTIME-PARTICIPANT + servers: + - ${topicServer:localhost} + topicCommInfrastructure: dmaap + + +management: + endpoints: + web: + base-path: / + exposure: + include: health, metrics, prometheus +server: + port: 8086 + servlet: + context-path: /onap/policy/clamp/acm/a1pmsparticipant \ No newline at end of file diff --git a/packages/pom.xml b/packages/pom.xml index 847b5bc72..56f997455 100644 --- a/packages/pom.xml +++ b/packages/pom.xml @@ -68,6 +68,7 @@ PolicyParticipant-Suse.Dockerfile KubernetesParticipant-Suse.Dockerfile HttpParticipant-Suse.Dockerfile + A1pmsParticipant-Suse.Dockerfile ElementParticipant-Suse.Dockerfile diff --git a/participant/participant-impl/participant-impl-a1pms/pom.xml b/participant/participant-impl/participant-impl-a1pms/pom.xml new file mode 100755 index 000000000..c8566a13e --- /dev/null +++ b/participant/participant-impl/participant-impl-a1pms/pom.xml @@ -0,0 +1,50 @@ + + + + 4.0.0 + + + org.onap.policy.clamp.participant + policy-clamp-participant-impl + 6.4.0-SNAPSHOT + + + policy-clamp-participant-impl-a1pms + ${project.artifactId} + A1 PMS participant, that performs operations related to access the A1 Policy Management Service to perform A1 Policy Operations + + + + org.springframework.boot + spring-boot-maven-plugin + + + + repackage + + package + + + + + + diff --git a/participant/participant-impl/participant-impl-a1pms/src/main/java/org/onap/policy/clamp/acm/participant/a1pms/Application.java b/participant/participant-impl/participant-impl-a1pms/src/main/java/org/onap/policy/clamp/acm/participant/a1pms/Application.java new file mode 100755 index 000000000..1adf5cdb1 --- /dev/null +++ b/participant/participant-impl/participant-impl-a1pms/src/main/java/org/onap/policy/clamp/acm/participant/a1pms/Application.java @@ -0,0 +1,48 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2022 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.onap.policy.clamp.acm.participant.a1pms; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.context.properties.ConfigurationPropertiesScan; +import org.springframework.context.annotation.ComponentScan; + +/** + * Starter. + */ +// @formatter:off +@SpringBootApplication +@ComponentScan({ + "org.onap.policy.clamp.acm.participant.a1pms", + "org.onap.policy.clamp.acm.participant.intermediary" +}) +@ConfigurationPropertiesScan("org.onap.policy.clamp.acm.participant.a1pms.parameters") +//@formatter:on +public class Application { + /** + * Main class. + * + * @param args args + */ + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } +} diff --git a/participant/participant-impl/participant-impl-a1pms/src/main/java/org/onap/policy/clamp/acm/participant/a1pms/config/MicrometerConfig.java b/participant/participant-impl/participant-impl-a1pms/src/main/java/org/onap/policy/clamp/acm/participant/a1pms/config/MicrometerConfig.java new file mode 100755 index 000000000..5e3441d82 --- /dev/null +++ b/participant/participant-impl/participant-impl-a1pms/src/main/java/org/onap/policy/clamp/acm/participant/a1pms/config/MicrometerConfig.java @@ -0,0 +1,46 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2022 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.onap.policy.clamp.acm.participant.a1pms.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 { + + /** + * Load up the metrics registry. + */ + @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/participant/participant-impl/participant-impl-a1pms/src/main/java/org/onap/policy/clamp/acm/participant/a1pms/config/ParticipantConfig.java b/participant/participant-impl/participant-impl-a1pms/src/main/java/org/onap/policy/clamp/acm/participant/a1pms/config/ParticipantConfig.java new file mode 100755 index 000000000..7158b5d53 --- /dev/null +++ b/participant/participant-impl/participant-impl-a1pms/src/main/java/org/onap/policy/clamp/acm/participant/a1pms/config/ParticipantConfig.java @@ -0,0 +1,43 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2022 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.onap.policy.clamp.acm.participant.a1pms.config; + +import org.onap.policy.clamp.acm.participant.a1pms.handler.AutomationCompositionElementHandler; +import org.onap.policy.clamp.acm.participant.intermediary.api.ParticipantIntermediaryApi; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class ParticipantConfig { + + /** + * Register AutomationCompositionElementListener. + * + * @param intermediaryApi the ParticipantIntermediaryApi + * @param acElementHandler the AutomationComposition Element Handler + */ + @Autowired + public void registerAutomationCompositionElementListener(ParticipantIntermediaryApi intermediaryApi, + AutomationCompositionElementHandler acElementHandler) { + intermediaryApi.registerAutomationCompositionElementListener(acElementHandler); + acElementHandler.setIntermediaryApi(intermediaryApi); + } +} diff --git a/participant/participant-impl/participant-impl-a1pms/src/main/java/org/onap/policy/clamp/acm/participant/a1pms/config/SecurityConfig.java b/participant/participant-impl/participant-impl-a1pms/src/main/java/org/onap/policy/clamp/acm/participant/a1pms/config/SecurityConfig.java new file mode 100755 index 000000000..fdbbc4558 --- /dev/null +++ b/participant/participant-impl/participant-impl-a1pms/src/main/java/org/onap/policy/clamp/acm/participant/a1pms/config/SecurityConfig.java @@ -0,0 +1,45 @@ +/*- + * ========================LICENSE_START================================= + * Copyright (C) 2022 Nordix Foundation. All rights reserved. + * ====================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ========================LICENSE_END=================================== + */ + +package org.onap.policy.clamp.acm.participant.a1pms.config; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; + +@Configuration +public class SecurityConfig extends WebSecurityConfigurerAdapter { + + @Value("${security.enable-csrf:true}") + private boolean csrfEnabled = true; + + @Override + protected void configure(HttpSecurity http) throws Exception { + // @formatter:off + http.authorizeRequests() + .antMatchers().authenticated() + .anyRequest().authenticated() + .and().httpBasic(); + // @formatter:on + + if (!csrfEnabled) { + http.csrf().disable(); + } + } +} diff --git a/participant/participant-impl/participant-impl-a1pms/src/main/java/org/onap/policy/clamp/acm/participant/a1pms/exception/A1PolicyServiceException.java b/participant/participant-impl/participant-impl-a1pms/src/main/java/org/onap/policy/clamp/acm/participant/a1pms/exception/A1PolicyServiceException.java new file mode 100755 index 000000000..3a7ac7d9f --- /dev/null +++ b/participant/participant-impl/participant-impl-a1pms/src/main/java/org/onap/policy/clamp/acm/participant/a1pms/exception/A1PolicyServiceException.java @@ -0,0 +1,35 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2022 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.onap.policy.clamp.acm.participant.a1pms.exception; + +import javax.ws.rs.core.Response; +import org.onap.policy.models.base.PfModelException; + +public class A1PolicyServiceException extends PfModelException { + + public A1PolicyServiceException(int statusCode, String message) { + super(Response.Status.fromStatusCode(statusCode), message); + } + + public A1PolicyServiceException(int statusCode, String message, Exception e) { + super(Response.Status.fromStatusCode(statusCode), message, e); + } +} diff --git a/participant/participant-impl/participant-impl-a1pms/src/main/java/org/onap/policy/clamp/acm/participant/a1pms/handler/AutomationCompositionElementHandler.java b/participant/participant-impl/participant-impl-a1pms/src/main/java/org/onap/policy/clamp/acm/participant/a1pms/handler/AutomationCompositionElementHandler.java new file mode 100755 index 000000000..072d14475 --- /dev/null +++ b/participant/participant-impl/participant-impl-a1pms/src/main/java/org/onap/policy/clamp/acm/participant/a1pms/handler/AutomationCompositionElementHandler.java @@ -0,0 +1,156 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2022 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.onap.policy.clamp.acm.participant.a1pms.handler; + +import java.lang.invoke.MethodHandles; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import java.util.UUID; +import javax.validation.ConstraintViolation; +import javax.validation.Validation; +import javax.validation.ValidationException; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import lombok.Setter; +import org.apache.http.HttpStatus; +import org.onap.policy.clamp.acm.participant.a1pms.exception.A1PolicyServiceException; +import org.onap.policy.clamp.acm.participant.a1pms.models.ConfigurationEntity; +import org.onap.policy.clamp.acm.participant.a1pms.webclient.AcA1PmsClient; +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.AutomationCompositionElement; +import org.onap.policy.clamp.models.acm.concepts.AutomationCompositionOrderedState; +import org.onap.policy.clamp.models.acm.concepts.AutomationCompositionState; +import org.onap.policy.clamp.models.acm.messages.dmaap.participant.ParticipantMessageType; +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.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier; +import org.onap.policy.models.tosca.authorative.concepts.ToscaNodeTemplate; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +/** + * This class handles implementation of automationCompositionElement updates. + */ +@Component +@RequiredArgsConstructor +public class AutomationCompositionElementHandler implements AutomationCompositionElementListener { + + private static final Coder CODER = new StandardCoder(); + + private static final Logger LOGGER = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); + + @Setter + private ParticipantIntermediaryApi intermediaryApi; + + private final AcA1PmsClient acA1PmsClient; + + // Map of acElement Id and A1PMS services + @Getter(AccessLevel.PACKAGE) + private final Map configRequestMap = new HashMap<>(); + + /** + * Handle a automation composition element state change. + * + * @param automationCompositionElementId the ID of the automation composition element + * @param currentState the current state of the automation composition element + * @param newState the state to which the automation composition element is changing to + * @throws PfModelException in case of a model exception + */ + @Override + public void automationCompositionElementStateChange(ToscaConceptIdentifier automationCompositionId, + UUID automationCompositionElementId, AutomationCompositionState currentState, + AutomationCompositionOrderedState newState) throws A1PolicyServiceException { + switch (newState) { + case UNINITIALISED: + ConfigurationEntity configurationEntity = configRequestMap.get(automationCompositionElementId); + if (configurationEntity != null && acA1PmsClient.isPmsHealthy()) { + acA1PmsClient.deleteService(configurationEntity.getPolicyServiceEntities()); + configRequestMap.remove(automationCompositionElementId); + intermediaryApi.updateAutomationCompositionElementState(automationCompositionId, + automationCompositionElementId, newState, AutomationCompositionState.UNINITIALISED, + ParticipantMessageType.AUTOMATION_COMPOSITION_STATE_CHANGE); + } else { + LOGGER.warn("Failed to connect with A1PMS. Service configuration is: {}", configurationEntity); + throw new A1PolicyServiceException(HttpStatus.SC_SERVICE_UNAVAILABLE, + "Unable to connect with A1PMS"); + } + break; + case PASSIVE: + intermediaryApi.updateAutomationCompositionElementState(automationCompositionId, + automationCompositionElementId, newState, AutomationCompositionState.PASSIVE, + ParticipantMessageType.AUTOMATION_COMPOSITION_STATE_CHANGE); + break; + case RUNNING: + intermediaryApi.updateAutomationCompositionElementState(automationCompositionId, + automationCompositionElementId, newState, AutomationCompositionState.RUNNING, + ParticipantMessageType.AUTOMATION_COMPOSITION_STATE_CHANGE); + break; + default: + LOGGER.warn("Cannot transition from state {} to state {}", currentState, newState); + break; + } + } + + /** + * Callback method to handle an update on an automation composition element. + * + * @param element the information on the automation composition element + * @param nodeTemplate toscaNodeTemplate + */ + @Override + public void automationCompositionElementUpdate(ToscaConceptIdentifier automationCompositionId, + AutomationCompositionElement element, ToscaNodeTemplate nodeTemplate) throws A1PolicyServiceException { + try { + var configurationEntity = CODER.convert(nodeTemplate.getProperties(), ConfigurationEntity.class); + Set> violations = + Validation.buildDefaultValidatorFactory().getValidator().validate(configurationEntity); + if (violations.isEmpty()) { + if (acA1PmsClient.isPmsHealthy()) { + acA1PmsClient.createService(configurationEntity.getPolicyServiceEntities()); + configRequestMap.put(element.getId(), configurationEntity); + + intermediaryApi.updateAutomationCompositionElementState(automationCompositionId, element.getId(), + AutomationCompositionOrderedState.PASSIVE, AutomationCompositionState.PASSIVE, + ParticipantMessageType.AUTOMATION_COMPOSITION_STATE_CHANGE); + } else { + LOGGER.error("Failed to connect with A1PMS"); + throw new A1PolicyServiceException(HttpStatus.SC_SERVICE_UNAVAILABLE, + "Unable to connect with A1PMS"); + } + } else { + LOGGER.error("Violations found in the config request parameters: {}", violations); + throw new ValidationException("Constraint violations in the config request"); + } + } catch (ValidationException | CoderException e) { + LOGGER.error("Error invoking the A1PMS request for the config ", e); + throw new A1PolicyServiceException(HttpStatus.SC_BAD_REQUEST, "Invalid Configuration", e); + } catch (A1PolicyServiceException e) { + LOGGER.error("Error invoking the A1PMS request for the config ", e); + throw e; + } + } +} diff --git a/participant/participant-impl/participant-impl-a1pms/src/main/java/org/onap/policy/clamp/acm/participant/a1pms/models/A1PolicyServiceEntity.java b/participant/participant-impl/participant-impl-a1pms/src/main/java/org/onap/policy/clamp/acm/participant/a1pms/models/A1PolicyServiceEntity.java new file mode 100755 index 000000000..991cb926f --- /dev/null +++ b/participant/participant-impl/participant-impl-a1pms/src/main/java/org/onap/policy/clamp/acm/participant/a1pms/models/A1PolicyServiceEntity.java @@ -0,0 +1,54 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2022 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.onap.policy.clamp.acm.participant.a1pms.models; + +import com.fasterxml.jackson.annotation.JsonGetter; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.databind.PropertyNamingStrategies; +import com.fasterxml.jackson.databind.annotation.JsonNaming; +import javax.validation.constraints.NotNull; +import javax.ws.rs.DefaultValue; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.Getter; +import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier; + +@Data +@AllArgsConstructor +@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class) +public class A1PolicyServiceEntity { + + @NotNull + @JsonIgnore + private ToscaConceptIdentifier a1PolicyServiceEntityId; + + @NotNull + @Getter(onMethod_ = {@JsonGetter(value = "service_id")}) + private String clientId; + + @NotNull + private String callbackUrl; + + @NotNull + @DefaultValue("0") + private int keepAliveIntervalSeconds; + +} diff --git a/participant/participant-impl/participant-impl-a1pms/src/main/java/org/onap/policy/clamp/acm/participant/a1pms/models/ConfigurationEntity.java b/participant/participant-impl/participant-impl-a1pms/src/main/java/org/onap/policy/clamp/acm/participant/a1pms/models/ConfigurationEntity.java new file mode 100755 index 000000000..80715c27c --- /dev/null +++ b/participant/participant-impl/participant-impl-a1pms/src/main/java/org/onap/policy/clamp/acm/participant/a1pms/models/ConfigurationEntity.java @@ -0,0 +1,37 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2022 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.onap.policy.clamp.acm.participant.a1pms.models; + +import java.util.List; +import javax.validation.Valid; +import javax.validation.constraints.NotNull; +import lombok.AllArgsConstructor; +import lombok.Data; + +@Data +@AllArgsConstructor +public class ConfigurationEntity { + + @NotNull + @Valid + private List policyServiceEntities; + +} diff --git a/participant/participant-impl/participant-impl-a1pms/src/main/java/org/onap/policy/clamp/acm/participant/a1pms/parameters/A1PmsParameters.java b/participant/participant-impl/participant-impl-a1pms/src/main/java/org/onap/policy/clamp/acm/participant/a1pms/parameters/A1PmsParameters.java new file mode 100755 index 000000000..704ef4153 --- /dev/null +++ b/participant/participant-impl/participant-impl-a1pms/src/main/java/org/onap/policy/clamp/acm/participant/a1pms/parameters/A1PmsParameters.java @@ -0,0 +1,55 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2022 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.onap.policy.clamp.acm.participant.a1pms.parameters; + +import java.util.Map; +import javax.validation.constraints.NotNull; +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.validation.annotation.Validated; + +/** + * Class to hold all parameters needed for the A1PMS participant. + */ +@Validated +@Data +@ConfigurationProperties(prefix = "a1pms") +public class A1PmsParameters { + + @NotNull + private String baseUrl; + + @NotNull + private Endpoints endpoints; + + @NotNull + private Map headers; + + @Data + public static class Endpoints { + + String health; + + String services; + + String service; + } +} diff --git a/participant/participant-impl/participant-impl-a1pms/src/main/java/org/onap/policy/clamp/acm/participant/a1pms/parameters/A1PmsParticipantParameters.java b/participant/participant-impl/participant-impl-a1pms/src/main/java/org/onap/policy/clamp/acm/participant/a1pms/parameters/A1PmsParticipantParameters.java new file mode 100755 index 000000000..b3e036041 --- /dev/null +++ b/participant/participant-impl/participant-impl-a1pms/src/main/java/org/onap/policy/clamp/acm/participant/a1pms/parameters/A1PmsParticipantParameters.java @@ -0,0 +1,44 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2022 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.onap.policy.clamp.acm.participant.a1pms.parameters; + +import javax.validation.Valid; +import javax.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; + +/** + * Class to hold all parameters needed for the A1PMS participant. + */ +@Validated +@Getter +@Setter +@ConfigurationProperties(prefix = "participant") +public class A1PmsParticipantParameters implements ParticipantParameters { + + @NotNull + @Valid + private ParticipantIntermediaryParameters intermediaryParameters; +} diff --git a/participant/participant-impl/participant-impl-a1pms/src/main/java/org/onap/policy/clamp/acm/participant/a1pms/webclient/AcA1PmsClient.java b/participant/participant-impl/participant-impl-a1pms/src/main/java/org/onap/policy/clamp/acm/participant/a1pms/webclient/AcA1PmsClient.java new file mode 100755 index 000000000..25fb67fb7 --- /dev/null +++ b/participant/participant-impl/participant-impl-a1pms/src/main/java/org/onap/policy/clamp/acm/participant/a1pms/webclient/AcA1PmsClient.java @@ -0,0 +1,129 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2022 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.onap.policy.clamp.acm.participant.a1pms.webclient; + +import java.lang.invoke.MethodHandles; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.function.Predicate; +import lombok.RequiredArgsConstructor; +import org.onap.policy.clamp.acm.participant.a1pms.exception.A1PolicyServiceException; +import org.onap.policy.clamp.acm.participant.a1pms.models.A1PolicyServiceEntity; +import org.onap.policy.clamp.acm.participant.a1pms.parameters.A1PmsParameters; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.HttpStatus; +import org.springframework.stereotype.Component; +import org.springframework.web.reactive.function.client.WebClient; +import reactor.core.publisher.Mono; + +@Component +@RequiredArgsConstructor +public class AcA1PmsClient { + + private final A1PmsParameters a1PmsParameters; + + private static final Logger LOGGER = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); + + /** + * Get webclient for A1PMS. + * + * @return webClient + */ + private WebClient getPmsClient() { + return WebClient.builder().baseUrl(a1PmsParameters.getBaseUrl()) + .defaultHeaders(httpHeaders -> httpHeaders.addAll(createHeaders())).build(); + } + + /** + * Get A1PMS health status. + * + * @return whether A1PMS is healthy + */ + public boolean isPmsHealthy() { + return Objects.equals(Boolean.TRUE, + getPmsClient().method(HttpMethod.GET).uri(a1PmsParameters.getEndpoints().getHealth()) + .exchangeToMono(clientResponse -> Mono.just(clientResponse.statusCode().is2xxSuccessful())) + .block()); + } + + + /** + * Create service in A1PMS. + * @param policyServiceEntities List of service entities + * @throws A1PolicyServiceException Exception on creating service + */ + public void createService(List policyServiceEntities) throws A1PolicyServiceException { + policyServiceEntities.forEach( + a1PolicyServiceEntity -> getPmsClient().method(HttpMethod.PUT) + .uri(a1PmsParameters.getEndpoints().getServices()) + .bodyValue(a1PolicyServiceEntity).retrieve() + .onStatus(HttpStatus::isError, + clientResponse -> Mono.error(new A1PolicyServiceException( + clientResponse.statusCode().value(), + "Error in creating policy service"))) + .onStatus(Predicate.isEqual(HttpStatus.OK), + clientResponse -> { + LOGGER.warn("Client {} already exists and the configuration " + + "is updated", + a1PolicyServiceEntity.getClientId()); + return Mono.empty(); + }) + .toBodilessEntity() + .block()); + } + + /** + * Delete service in A1PMS. + * @param policyServiceEntities List of service entities + * @throws A1PolicyServiceException Exception on deleting service + */ + public void deleteService(List policyServiceEntities) throws A1PolicyServiceException { + policyServiceEntities.forEach( + a1PolicyServiceEntity -> getPmsClient().method(HttpMethod.DELETE) + .uri(a1PmsParameters.getEndpoints().getService(), + a1PolicyServiceEntity.getClientId()) + .bodyValue(a1PolicyServiceEntity).retrieve() + .onStatus(HttpStatus::isError, + clientResponse -> Mono.error( + new A1PolicyServiceException( + clientResponse.statusCode().value(), + "Error in deleting policy service"))) + .toBodilessEntity() + .block()); + } + + /** + * Prepare the Http headers to call A1PMS. + * + * @return httpHeaders + */ + private HttpHeaders createHeaders() { + var headers = new HttpHeaders(); + for (Map.Entry entry : a1PmsParameters.getHeaders().entrySet()) { + headers.add(entry.getKey(), entry.getValue()); + } + return headers; + } +} diff --git a/participant/participant-impl/participant-impl-a1pms/src/main/resources/config/application.yaml b/participant/participant-impl/participant-impl-a1pms/src/main/resources/config/application.yaml new file mode 100755 index 000000000..fcc2057b2 --- /dev/null +++ b/participant/participant-impl/participant-impl-a1pms/src/main/resources/config/application.yaml @@ -0,0 +1,59 @@ +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 + +a1pms: + baseUrl: http://a1policymanagement.onap:8081 + headers: + content-type: application/json + endpoints: + health: /a1-policy/v2/rics + services: /a1-policy/v2/services + service: /a1-policy/v2/services/{service_id} + +participant: + intermediaryParameters: + reportingTimeIntervalMs: 120000 + description: Participant Description + participantId: + name: A1PMSParticipant0 + version: 1.0.0 + participantType: + name: org.onap.policy.clamp.acm.A1PMSParticipant + version: 2.3.4 + clampAutomationCompositionTopics: + topicSources: + - topic: POLICY-ACRUNTIME-PARTICIPANT + servers: + - ${topicServer:localhost} + topicCommInfrastructure: dmaap + fetchTimeout: 15000 + topicSinks: + - topic: POLICY-ACRUNTIME-PARTICIPANT + servers: + - ${topicServer:localhost} + topicCommInfrastructure: dmaap + + +management: + endpoints: + web: + base-path: / + exposure: + include: health, metrics, prometheus +server: + port: 8086 + servlet: + context-path: /onap/policy/clamp/acm/a1pmsparticipant + + diff --git a/participant/participant-impl/participant-impl-a1pms/src/test/java/org/onap/policy/clamp/acm/participant/a1pms/handler/AcElementHandlerTest.java b/participant/participant-impl/participant-impl-a1pms/src/test/java/org/onap/policy/clamp/acm/participant/a1pms/handler/AcElementHandlerTest.java new file mode 100755 index 000000000..690f5f2f4 --- /dev/null +++ b/participant/participant-impl/participant-impl-a1pms/src/test/java/org/onap/policy/clamp/acm/participant/a1pms/handler/AcElementHandlerTest.java @@ -0,0 +1,110 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2022 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.onap.policy.clamp.acm.participant.a1pms.handler; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.util.Map; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Spy; +import org.onap.policy.clamp.acm.participant.a1pms.exception.A1PolicyServiceException; +import org.onap.policy.clamp.acm.participant.a1pms.utils.CommonTestData; +import org.onap.policy.clamp.acm.participant.a1pms.utils.ToscaUtils; +import org.onap.policy.clamp.acm.participant.a1pms.webclient.AcA1PmsClient; +import org.onap.policy.clamp.acm.participant.intermediary.api.ParticipantIntermediaryApi; +import org.onap.policy.clamp.models.acm.concepts.AutomationCompositionElement; +import org.onap.policy.clamp.models.acm.concepts.AutomationCompositionOrderedState; +import org.onap.policy.clamp.models.acm.concepts.AutomationCompositionState; +import org.onap.policy.models.tosca.authorative.concepts.ToscaNodeTemplate; +import org.onap.policy.models.tosca.authorative.concepts.ToscaServiceTemplate; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +@ExtendWith(SpringExtension.class) +class AcElementHandlerTest { + + private final AcA1PmsClient acA1PmsClient = mock(AcA1PmsClient.class); + + @InjectMocks + @Spy + private AutomationCompositionElementHandler automationCompositionElementHandler = + new AutomationCompositionElementHandler(acA1PmsClient); + + + private final CommonTestData commonTestData = new CommonTestData(); + + private static ToscaServiceTemplate serviceTemplate; + private static final String A1_AUTOMATION_COMPOSITION_ELEMENT = + "org.onap.domain.database.A1PMSAutomationCompositionElement"; + + @BeforeAll + static void init() { + serviceTemplate = ToscaUtils.readAutomationCompositionFromTosca(); + } + + @BeforeEach + void startMocks() throws A1PolicyServiceException { + automationCompositionElementHandler.setIntermediaryApi(mock(ParticipantIntermediaryApi.class)); + when(acA1PmsClient.isPmsHealthy()).thenReturn(Boolean.TRUE); + doNothing().when(acA1PmsClient).createService(any()); + } + + @Test + void test_automationCompositionElementStateChange() throws A1PolicyServiceException { + var automationCompositionId = commonTestData.getAutomationCompositionId(); + var element = commonTestData.getAutomationCompositionElement(); + var automationCompositionElementId = element.getId(); + + Map nodeTemplatesMap = serviceTemplate.getToscaTopologyTemplate().getNodeTemplates(); + automationCompositionElementHandler.automationCompositionElementUpdate( + commonTestData.getAutomationCompositionId(), element, + nodeTemplatesMap.get(A1_AUTOMATION_COMPOSITION_ELEMENT)); + + assertDoesNotThrow(() -> automationCompositionElementHandler.automationCompositionElementStateChange( + automationCompositionId, automationCompositionElementId, AutomationCompositionState.PASSIVE, + AutomationCompositionOrderedState.PASSIVE)); + + assertDoesNotThrow(() -> automationCompositionElementHandler.automationCompositionElementStateChange( + automationCompositionId, automationCompositionElementId, AutomationCompositionState.PASSIVE, + AutomationCompositionOrderedState.UNINITIALISED)); + + assertDoesNotThrow(() -> automationCompositionElementHandler.automationCompositionElementStateChange( + automationCompositionId, automationCompositionElementId, AutomationCompositionState.PASSIVE, + AutomationCompositionOrderedState.RUNNING)); + } + + @Test + void test_AutomationCompositionElementUpdate() { + AutomationCompositionElement element = commonTestData.getAutomationCompositionElement(); + + Map nodeTemplatesMap = serviceTemplate.getToscaTopologyTemplate().getNodeTemplates(); + assertDoesNotThrow(() -> automationCompositionElementHandler.automationCompositionElementUpdate( + commonTestData.getAutomationCompositionId(), element, + nodeTemplatesMap.get(A1_AUTOMATION_COMPOSITION_ELEMENT))); + } +} diff --git a/participant/participant-impl/participant-impl-a1pms/src/test/java/org/onap/policy/clamp/acm/participant/a1pms/rest/ActuatorControllerTest.java b/participant/participant-impl/participant-impl-a1pms/src/test/java/org/onap/policy/clamp/acm/participant/a1pms/rest/ActuatorControllerTest.java new file mode 100755 index 000000000..831dc5e77 --- /dev/null +++ b/participant/participant-impl/participant-impl-a1pms/src/test/java/org/onap/policy/clamp/acm/participant/a1pms/rest/ActuatorControllerTest.java @@ -0,0 +1,92 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2022 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.onap.policy.clamp.acm.participant.a1pms.rest; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import javax.ws.rs.client.Invocation; +import javax.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.onap.policy.clamp.acm.participant.a1pms.utils.CommonActuatorController; +import org.springframework.boot.test.autoconfigure.actuate.metrics.AutoConfigureMetrics; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; +import org.springframework.boot.web.server.LocalServerPort; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +@AutoConfigureMetrics +@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() { + Invocation.Builder invocationBuilder = super.sendActRequest(HEALTH_ENDPOINT); + Response rawresp = invocationBuilder.buildGet().invoke(); + assertEquals(Response.Status.OK.getStatusCode(), rawresp.getStatus()); + } + + @Test + void testGetMetrics() { + Invocation.Builder invocationBuilder = super.sendActRequest(METRICS_ENDPOINT); + Response rawresp = invocationBuilder.buildGet().invoke(); + assertEquals(Response.Status.OK.getStatusCode(), rawresp.getStatus()); + } + + @Test + void testGePrometheus() { + Invocation.Builder invocationBuilder = super.sendActRequest(PROMETHEUS_ENDPOINT); + Response rawresp = invocationBuilder.buildGet().invoke(); + assertEquals(Response.Status.OK.getStatusCode(), rawresp.getStatus()); + } + +} diff --git a/participant/participant-impl/participant-impl-a1pms/src/test/java/org/onap/policy/clamp/acm/participant/a1pms/utils/CommonActuatorController.java b/participant/participant-impl/participant-impl-a1pms/src/test/java/org/onap/policy/clamp/acm/participant/a1pms/utils/CommonActuatorController.java new file mode 100755 index 000000000..fc00f66b8 --- /dev/null +++ b/participant/participant-impl/participant-impl-a1pms/src/test/java/org/onap/policy/clamp/acm/participant/a1pms/utils/CommonActuatorController.java @@ -0,0 +1,107 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2022 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.onap.policy.clamp.acm.participant.a1pms.utils; + +import static org.junit.Assert.assertEquals; + +import javax.ws.rs.client.Client; +import javax.ws.rs.client.ClientBuilder; +import javax.ws.rs.client.Invocation; +import javax.ws.rs.client.WebTarget; +import javax.ws.rs.core.MediaType; +import javax.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; + +/** + * Class to perform Rest unit tests. + */ +public class CommonActuatorController { + + public static final String SELF = NetworkUtil.getHostname(); + public static final String CONTEXT_PATH = "onap/policy/clamp/acm/a1pmsparticipant/"; + + private static String httpPrefix; + + /** + * Sends a request to an actuator endpoint. + * + * @param endpoint the target endpoint + * @return a request builder + */ + protected Invocation.Builder sendActRequest(final String endpoint) { + return sendFqeRequest(httpPrefix + CONTEXT_PATH + endpoint, true); + } + + /** + * Sends a request to an actuator endpoint, without any authorization header. + * + * @param endpoint the target endpoint + * @return a request builder + */ + protected Invocation.Builder sendNoAuthActRequest(final String endpoint) { + return sendFqeRequest(httpPrefix + CONTEXT_PATH + endpoint, false); + } + + /** + * Sends a request to a fully qualified endpoint. + * + * @param fullyQualifiedEndpoint the fully qualified target endpoint + * @param includeAuth if authorization header should be included + * @return a request builder + */ + 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); + } + + /** + * Assert that GET call to actuator endpoint is Unauthorized. + * + * @param endPoint the endpoint + */ + protected void assertUnauthorizedActGet(final String endPoint) { + Response rawresp = sendNoAuthActRequest(endPoint).buildGet().invoke(); + assertEquals(Response.Status.UNAUTHORIZED.getStatusCode(), rawresp.getStatus()); + } + + /** + * Set Up httpPrefix. + * + * @param port the port + */ + protected void setHttpPrefix(int port) { + httpPrefix = "http://" + SELF + ":" + port + "/"; + } + +} diff --git a/participant/participant-impl/participant-impl-a1pms/src/test/java/org/onap/policy/clamp/acm/participant/a1pms/utils/CommonTestData.java b/participant/participant-impl/participant-impl-a1pms/src/test/java/org/onap/policy/clamp/acm/participant/a1pms/utils/CommonTestData.java new file mode 100755 index 000000000..be573cb37 --- /dev/null +++ b/participant/participant-impl/participant-impl-a1pms/src/test/java/org/onap/policy/clamp/acm/participant/a1pms/utils/CommonTestData.java @@ -0,0 +1,78 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2022 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.onap.policy.clamp.acm.participant.a1pms.utils; + +import java.util.List; +import java.util.UUID; +import org.onap.policy.clamp.acm.participant.a1pms.models.A1PolicyServiceEntity; +import org.onap.policy.clamp.models.acm.concepts.AutomationCompositionElement; +import org.onap.policy.clamp.models.acm.concepts.AutomationCompositionOrderedState; +import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier; + +public class CommonTestData { + + private static final String TEST_KEY_NAME = "org.onap.domain.database.A1PMSAutomationCompositionElement"; + + /** + * Get a automationComposition Element. + * + * @return automationCompositionElement object + */ + public AutomationCompositionElement getAutomationCompositionElement() { + AutomationCompositionElement element = new AutomationCompositionElement(); + element.setId(UUID.randomUUID()); + element.setDefinition(new ToscaConceptIdentifier(TEST_KEY_NAME, "1.0.1")); + element.setOrderedState(AutomationCompositionOrderedState.PASSIVE); + return element; + } + + /** + * Get automation composition id. + * + * @return ToscaConceptIdentifier automationCompositionId + */ + public ToscaConceptIdentifier getAutomationCompositionId() { + return getAutomationCompositionId(0); + } + + /** + * Get automation composition id. + * @param instanceNo Identifier instance no + * @return ToscaConceptIdentifier automationCompositionId + */ + public ToscaConceptIdentifier getAutomationCompositionId(int instanceNo) { + return new ToscaConceptIdentifier("A1PMSInstance" + instanceNo, "1.0.0"); + } + + + /** + * Get valid policy entities. + * @return List of policy entities + */ + public List getValidPolicyEntities() { + A1PolicyServiceEntity a1PolicyServiceEntity1 = new A1PolicyServiceEntity(getAutomationCompositionId(0), + "testService1", "http://localhost", 0); + A1PolicyServiceEntity a1PolicyServiceEntity2 = new A1PolicyServiceEntity(getAutomationCompositionId(1), + "testService2", "http://127.0.0.1", 0); + return List.of(a1PolicyServiceEntity1, a1PolicyServiceEntity2); + } +} diff --git a/participant/participant-impl/participant-impl-a1pms/src/test/java/org/onap/policy/clamp/acm/participant/a1pms/utils/MockRestEndpoint.java b/participant/participant-impl/participant-impl-a1pms/src/test/java/org/onap/policy/clamp/acm/participant/a1pms/utils/MockRestEndpoint.java new file mode 100755 index 000000000..9f8a28193 --- /dev/null +++ b/participant/participant-impl/participant-impl-a1pms/src/test/java/org/onap/policy/clamp/acm/participant/a1pms/utils/MockRestEndpoint.java @@ -0,0 +1,83 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2022 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.onap.policy.clamp.acm.participant.a1pms.utils; + +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.core.Response; + +/** + * The Class MockRestEndpoint creates rest server endpoints for simulating Rest calls. + */ +@Path("/") +@Produces("application/json") +public class MockRestEndpoint { + + /** + * Get dummy health endpoint. + * + * @return the response + */ + @Path("/healthy") + @GET + public Response getApplicationHealthy() { + return Response.status(200).entity("{}").build(); + } + + /** + * Get dummy health endpoint. + * + * @return the response + */ + @Path("/unhealthy") + @GET + public Response getApplicationUnHealthy() { + return Response.status(500).entity("{}").build(); + } + + @Path("/services/success") + @PUT + public Response createServiceSuccess() { + return Response.status(200).entity("{}").build(); + } + + @Path("/services/failure") + @PUT + public Response createServiceFailure() { + return Response.status(500).entity("{}").build(); + } + + @Path("/service/success/{clientId}") + @DELETE + public Response deleteServiceSuccess(@PathParam("clientId") String clientId) { + return Response.status(204).entity("{}").build(); + } + + @Path("/service/failure/{clientId}") + @DELETE + public Response deleteServiceFailure(@PathParam("clientId") String clientId) { + return Response.status(500).entity("{}").build(); + } +} diff --git a/participant/participant-impl/participant-impl-a1pms/src/test/java/org/onap/policy/clamp/acm/participant/a1pms/utils/MockServerRest.java b/participant/participant-impl/participant-impl-a1pms/src/test/java/org/onap/policy/clamp/acm/participant/a1pms/utils/MockServerRest.java new file mode 100755 index 000000000..dc0ed4a01 --- /dev/null +++ b/participant/participant-impl/participant-impl-a1pms/src/test/java/org/onap/policy/clamp/acm/participant/a1pms/utils/MockServerRest.java @@ -0,0 +1,65 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2022 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.onap.policy.clamp.acm.participant.a1pms.utils; + +import org.onap.policy.common.endpoints.http.server.HttpServletServer; +import org.onap.policy.common.endpoints.http.server.HttpServletServerFactoryInstance; +import org.onap.policy.common.gson.GsonMessageBodyHandler; +import org.onap.policy.common.utils.network.NetworkUtil; + +/** + * The Class MockServerRest that manages test servers for REST requests for the test. + */ +public class MockServerRest implements AutoCloseable { + private static final String HOST = "localhost"; + private HttpServletServer restServer; + private int restServerPort = 0; + + /** + * Instantiates a new REST simulator. + */ + public MockServerRest(int restServerPort) { + this.restServerPort = restServerPort; + restServer = HttpServletServerFactoryInstance.getServerFactory().build("MockRestEndpoint", false, HOST, + restServerPort, "/", false, false); + restServer.addServletClass(null, MockRestEndpoint.class.getName()); + restServer.setSerializationProvider(GsonMessageBodyHandler.class.getName()); + restServer.start(); + } + + /** + * Validate the Rest server. + * @throws InterruptedException if is not alive + */ + public void validate() throws InterruptedException { + if (!NetworkUtil.isTcpPortOpen(HOST, restServerPort, 50, 200L)) { + throw new IllegalStateException("port " + restServerPort + " is still not in use"); + } + } + + @Override + public void close() throws Exception { + if (restServer != null) { + restServer.stop(); + restServer = null; + } + } +} diff --git a/participant/participant-impl/participant-impl-a1pms/src/test/java/org/onap/policy/clamp/acm/participant/a1pms/utils/ToscaUtils.java b/participant/participant-impl/participant-impl-a1pms/src/test/java/org/onap/policy/clamp/acm/participant/a1pms/utils/ToscaUtils.java new file mode 100755 index 000000000..19471c016 --- /dev/null +++ b/participant/participant-impl/participant-impl-a1pms/src/test/java/org/onap/policy/clamp/acm/participant/a1pms/utils/ToscaUtils.java @@ -0,0 +1,51 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2022 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.onap.policy.clamp.acm.participant.a1pms.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 = "clamp/acm/test/participant-a1pms.yaml"; + + + /** + * Read a service template yaml. + * @return ToscaServiceTemplate + */ + public static ToscaServiceTemplate readAutomationCompositionFromTosca() { + return serializeAutomationCompositionYaml(); + } + + private static ToscaServiceTemplate serializeAutomationCompositionYaml() { + String automationCompositionString = ResourceUtils.getResourceAsString(ToscaUtils.TOSCA_TEMPLATE_YAML); + return yamlTranslator.fromYaml(automationCompositionString, ToscaServiceTemplate.class); + } +} diff --git a/participant/participant-impl/participant-impl-a1pms/src/test/java/org/onap/policy/clamp/acm/participant/a1pms/webclient/AcA1PmsClientTest.java b/participant/participant-impl/participant-impl-a1pms/src/test/java/org/onap/policy/clamp/acm/participant/a1pms/webclient/AcA1PmsClientTest.java new file mode 100755 index 000000000..0c4eabc21 --- /dev/null +++ b/participant/participant-impl/participant-impl-a1pms/src/test/java/org/onap/policy/clamp/acm/participant/a1pms/webclient/AcA1PmsClientTest.java @@ -0,0 +1,148 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2022 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.onap.policy.clamp.acm.participant.a1pms.webclient; + +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.Mockito.when; + +import java.io.IOException; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.onap.policy.clamp.acm.participant.a1pms.parameters.A1PmsParameters; +import org.onap.policy.clamp.acm.participant.a1pms.utils.CommonTestData; +import org.onap.policy.clamp.acm.participant.a1pms.utils.MockServerRest; +import org.onap.policy.common.utils.network.NetworkUtil; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +@ExtendWith(SpringExtension.class) +class AcA1PmsClientTest { + + private static int mockServerPort; + + private static MockServerRest mockServer; + + private static CommonTestData commonTestData; + + @Mock + private A1PmsParameters a1PmsParameters; + + + private final String healthyUrl = "/healthy"; + + private final String servicesUrl = "/services/success"; + + private final String serviceUrl = "/service/success/{serviceId}"; + + /** + * Set up Mock server. + */ + @BeforeAll + static void setUpMockServer() throws IOException, InterruptedException { + mockServerPort = NetworkUtil.allocPort(); + mockServer = new MockServerRest(mockServerPort); + mockServer.validate(); + commonTestData = new CommonTestData(); + } + + @AfterAll + static void stopServer() throws Exception { + mockServer.close(); + mockServer = null; + } + + void initializePmsHealthParameters(String healthUrl) { + String testMockUrl = "http://localhost"; + when(a1PmsParameters.getBaseUrl()).thenReturn(testMockUrl + ":" + mockServerPort); + var endpoints = new A1PmsParameters.Endpoints(); + endpoints.setHealth(healthUrl); + when(a1PmsParameters.getEndpoints()).thenReturn(endpoints); + } + + void initializePmsServicesParameters(String servicesUrl) { + initializePmsHealthParameters(healthyUrl); + var endpoints = a1PmsParameters.getEndpoints(); + endpoints.setServices(servicesUrl); + when(a1PmsParameters.getEndpoints()).thenReturn(endpoints); + } + + void initializePmsServiceParameters(String serviceUrl) { + initializePmsServicesParameters(servicesUrl); + var endpoints = a1PmsParameters.getEndpoints(); + endpoints.setService(serviceUrl); + when(a1PmsParameters.getEndpoints()).thenReturn(endpoints); + } + + + @Test + void test_healthyPms() { + initializePmsHealthParameters(healthyUrl); + var client = new AcA1PmsClient(a1PmsParameters); + assertTrue(client.isPmsHealthy()); + } + + @Test + void test_unhealthyPms() { + String unhealthyUrl = "/unhealthy"; + initializePmsHealthParameters(unhealthyUrl); + var client = new AcA1PmsClient(a1PmsParameters); + assertFalse(client.isPmsHealthy()); + } + + @Test + void test_createServicesSuccess() { + initializePmsServicesParameters(servicesUrl); + var client = new AcA1PmsClient(a1PmsParameters); + assertDoesNotThrow(() -> client.createService(commonTestData.getValidPolicyEntities())); + } + + @Test + void test_createServicesFailure() { + String createServiceFailureUrl = "services/failure"; + initializePmsServicesParameters(createServiceFailureUrl); + var client = new AcA1PmsClient(a1PmsParameters); + String expectedMessage = "Error in creating policy service"; + assertThrows(Exception.class, + () -> client.createService(commonTestData.getValidPolicyEntities()), expectedMessage); + } + + @Test + void test_deleteServicesSuccess() { + initializePmsServiceParameters(serviceUrl); + var client = new AcA1PmsClient(a1PmsParameters); + assertDoesNotThrow(() -> client.deleteService(commonTestData.getValidPolicyEntities())); + } + + @Test + void test_deleteServicesFailure() { + String deleteServiceFailureUrl = "services/failure/{serviceId}"; + initializePmsServiceParameters(deleteServiceFailureUrl); + var client = new AcA1PmsClient(a1PmsParameters); + String expectedMessage = "Error in deleting policy service"; + assertThrows(Exception.class, + () -> client.deleteService(commonTestData.getValidPolicyEntities()), expectedMessage); + } +} diff --git a/participant/participant-impl/participant-impl-a1pms/src/test/resources/application-test.yaml b/participant/participant-impl/participant-impl-a1pms/src/test/resources/application-test.yaml new file mode 100755 index 000000000..be33b5249 --- /dev/null +++ b/participant/participant-impl/participant-impl-a1pms/src/test/resources/application-test.yaml @@ -0,0 +1,24 @@ +participant: + intermediaryParameters: + reportingTimeInterval: 120000 + description: Participant Description + participantId: + name: A1PMSParticipant0 + version: 1.0.0 + participantType: + name: org.onap.policy.clamp.acm.A1PMSParticipant + version: 2.3.4 + clampAutomationCompositionTopics: + topicSources: + - + topic: POLICY-ACRUNTIME-PARTICIPANT + servers: + - localhost + topicCommInfrastructure: dmaap + fetchTimeout: 15000 + topicSinks: + - + topicCommInfrastructure: dmaap + servers: + - localhost + topic: POLICY-ACRUNTIME-PARTICIPANT \ No newline at end of file diff --git a/participant/participant-impl/pom.xml b/participant/participant-impl/pom.xml index 7837f1da9..bfbbf08ff 100644 --- a/participant/participant-impl/pom.xml +++ b/participant/participant-impl/pom.xml @@ -40,6 +40,7 @@ participant-impl-cds participant-impl-kubernetes participant-impl-http + participant-impl-a1pms diff --git a/pom.xml b/pom.xml index fc3755e58..550919413 100644 --- a/pom.xml +++ b/pom.xml @@ -49,6 +49,7 @@ o policy-clamp-participant-impl-policy: A standard participant for handling polcies for Policy Framework o policy-clamp-acm-element-impl: ACM element implementation for integration testing o policy-clamp-participant-impl-http: A standard participant for http configurations + o policy-clamp-participant-impl-a1: A standard participant for accessing A1-Policy Management Service -- cgit 1.2.3-korg