diff options
86 files changed, 2782 insertions, 1199 deletions
diff --git a/common/src/main/java/org/onap/policy/clamp/controlloop/common/handler/ControlLoopHandler.java b/common/src/main/java/org/onap/policy/clamp/controlloop/common/handler/ControlLoopHandler.java deleted file mode 100644 index 18297da42..000000000 --- a/common/src/main/java/org/onap/policy/clamp/controlloop/common/handler/ControlLoopHandler.java +++ /dev/null @@ -1,95 +0,0 @@ -/*- - * ============LICENSE_START======================================================= - * Copyright (C) 2021 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.controlloop.common.handler; - -import java.util.List; -import lombok.Getter; -import lombok.NonNull; -import org.onap.policy.common.endpoints.event.comm.TopicSink; -import org.onap.policy.common.endpoints.listeners.MessageTypeDispatcher; -import org.onap.policy.models.provider.PolicyModelsProviderParameters; - -/** - * Abstract class for handlers for sub components in the control loop system - * - * <p>Instances are effectively singletons that are started at system start. - */ -public abstract class ControlLoopHandler { - @Getter - private final PolicyModelsProviderParameters databaseProviderParameters; - - /** - * Create a handler. - * - * @param databaseProviderParameters the parameters for access to the database - */ - protected ControlLoopHandler(@NonNull PolicyModelsProviderParameters databaseProviderParameters) { - this.databaseProviderParameters = databaseProviderParameters; - - } - - public void close() { - } - - /** - * Start any topic message listeners for this handler. - * - * @param msgDispatcher the message dispatcher with which to register the listener - */ - public void startAndRegisterListeners(MessageTypeDispatcher msgDispatcher) { - // Start and register listeners - } - - /** - * Start any topic message publishers for this handler. - * - * @param topicSinks the topic sinks on which the publisher can publish - */ - public void startAndRegisterPublishers(List<TopicSink> topicSinks) { - // Start and register publishers - } - - /** - * Stop any topic message publishers for this handler. - */ - public void stopAndUnregisterPublishers() { - // Stop and unregister publishers - } - - /** - * Stop any topic message listeners for this handler. - * - * @param msgDispatcher the message dispatcher from which to unregister the listener - */ - public void stopAndUnregisterListeners(MessageTypeDispatcher msgDispatcher) { - // Stop and unregister listeners - } - - /** - * Start any providers for this handler. - */ - public abstract void startProviders(); - - /** - * Stop any providers for this handler. - */ - public abstract void stopProviders(); -} diff --git a/common/src/test/java/org/onap/policy/clamp/controlloop/common/handler/DummyControlLoopHandler.java b/common/src/test/java/org/onap/policy/clamp/controlloop/common/handler/DummyControlLoopHandler.java deleted file mode 100644 index 1602fb6eb..000000000 --- a/common/src/test/java/org/onap/policy/clamp/controlloop/common/handler/DummyControlLoopHandler.java +++ /dev/null @@ -1,63 +0,0 @@ -/*- - * ============LICENSE_START======================================================= - * Copyright (C) 2021 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.controlloop.common.handler; - -import java.util.List; -import org.onap.policy.common.endpoints.event.comm.TopicSink; -import org.onap.policy.common.endpoints.listeners.MessageTypeDispatcher; -import org.onap.policy.models.provider.PolicyModelsProviderParameters; - -public class DummyControlLoopHandler extends ControlLoopHandler { - - public DummyControlLoopHandler(PolicyModelsProviderParameters databaseProviderParameters) { - super(databaseProviderParameters); - } - - @Override - public void startAndRegisterListeners(MessageTypeDispatcher msgDispatcher) { - // Do nothing on this dummy class - } - - @Override - public void startAndRegisterPublishers(List<TopicSink> topicSinks) { - // Do nothing on this dummy class - } - - @Override - public void stopAndUnregisterPublishers() { - // Do nothing on this dummy class - } - - @Override - public void stopAndUnregisterListeners(MessageTypeDispatcher msgDispatcher) { - // Do nothing on this dummy class - } - - @Override - public void startProviders() { - // Do nothing on this dummy class - } - - @Override - public void stopProviders() { - // Do nothing on this dummy class - } -} diff --git a/models/src/main/java/org/onap/policy/clamp/controlloop/models/controlloop/persistence/provider/ClElementStatisticsProvider.java b/models/src/main/java/org/onap/policy/clamp/controlloop/models/controlloop/persistence/provider/ClElementStatisticsProvider.java index f8f1f4145..e5b062bc1 100644 --- a/models/src/main/java/org/onap/policy/clamp/controlloop/models/controlloop/persistence/provider/ClElementStatisticsProvider.java +++ b/models/src/main/java/org/onap/policy/clamp/controlloop/models/controlloop/persistence/provider/ClElementStatisticsProvider.java @@ -33,12 +33,14 @@ import org.onap.policy.models.base.PfReferenceTimestampKey; import org.onap.policy.models.dao.PfFilterParameters; import org.onap.policy.models.provider.PolicyModelsProviderParameters; import org.onap.policy.models.provider.impl.AbstractModelsProvider; +import org.springframework.stereotype.Component; /** * This class provides the provision of information on control loop element statistics in the database to callers. * * @author Ramesh Murugan Iyer (ramesh.murugan.iyer@est.tech) */ +@Component public class ClElementStatisticsProvider extends AbstractModelsProvider { /** diff --git a/models/src/main/java/org/onap/policy/clamp/controlloop/models/controlloop/persistence/provider/ControlLoopProvider.java b/models/src/main/java/org/onap/policy/clamp/controlloop/models/controlloop/persistence/provider/ControlLoopProvider.java index 7c34a6654..4e502c64c 100644 --- a/models/src/main/java/org/onap/policy/clamp/controlloop/models/controlloop/persistence/provider/ControlLoopProvider.java +++ b/models/src/main/java/org/onap/policy/clamp/controlloop/models/controlloop/persistence/provider/ControlLoopProvider.java @@ -40,10 +40,12 @@ import org.onap.policy.models.tosca.authorative.concepts.ToscaEntity; import org.onap.policy.models.tosca.authorative.concepts.ToscaNodeTemplate; import org.onap.policy.models.tosca.authorative.concepts.ToscaTypedEntityFilter; import org.onap.policy.models.tosca.simple.concepts.JpaToscaNodeTemplate; +import org.springframework.stereotype.Component; /** * This class provides information on control loop concepts in the database to callers. */ +@Component public class ControlLoopProvider extends AbstractModelsProvider { /** diff --git a/models/src/main/java/org/onap/policy/clamp/controlloop/models/controlloop/persistence/provider/ParticipantProvider.java b/models/src/main/java/org/onap/policy/clamp/controlloop/models/controlloop/persistence/provider/ParticipantProvider.java index 2ccc5d3c1..dd669a6d8 100644 --- a/models/src/main/java/org/onap/policy/clamp/controlloop/models/controlloop/persistence/provider/ParticipantProvider.java +++ b/models/src/main/java/org/onap/policy/clamp/controlloop/models/controlloop/persistence/provider/ParticipantProvider.java @@ -33,10 +33,12 @@ import org.onap.policy.models.base.PfModelRuntimeException; import org.onap.policy.models.provider.PolicyModelsProviderParameters; import org.onap.policy.models.provider.impl.AbstractModelsProvider; import org.onap.policy.models.tosca.authorative.concepts.ToscaTypedEntityFilter; +import org.springframework.stereotype.Component; /** * This class provides information on participant concepts in the database to callers. */ +@Component public class ParticipantProvider extends AbstractModelsProvider { /** * Create a provider for participants. diff --git a/models/src/main/java/org/onap/policy/clamp/controlloop/models/controlloop/persistence/provider/ParticipantStatisticsProvider.java b/models/src/main/java/org/onap/policy/clamp/controlloop/models/controlloop/persistence/provider/ParticipantStatisticsProvider.java index 272333b88..fa27a41c2 100644 --- a/models/src/main/java/org/onap/policy/clamp/controlloop/models/controlloop/persistence/provider/ParticipantStatisticsProvider.java +++ b/models/src/main/java/org/onap/policy/clamp/controlloop/models/controlloop/persistence/provider/ParticipantStatisticsProvider.java @@ -33,10 +33,12 @@ import org.onap.policy.models.base.PfTimestampKey; import org.onap.policy.models.dao.PfFilterParameters; import org.onap.policy.models.provider.PolicyModelsProviderParameters; import org.onap.policy.models.provider.impl.AbstractModelsProvider; +import org.springframework.stereotype.Component; /** * This class provides the provision of information on participant statistics in the database to callers. */ +@Component public class ParticipantStatisticsProvider extends AbstractModelsProvider { /** diff --git a/packages/policy-clamp-docker/src/main/docker/KubernetesParticipantDockerfile b/packages/policy-clamp-docker/src/main/docker/KubernetesParticipantDockerfile index 40532c002..63209d75f 100644 --- a/packages/policy-clamp-docker/src/main/docker/KubernetesParticipantDockerfile +++ b/packages/policy-clamp-docker/src/main/docker/KubernetesParticipantDockerfile @@ -57,7 +57,7 @@ RUN chown -R policy:policy * && \ chmod +x kubectl && \ mv kubectl /usr/local/bin/kubectl -EXPOSE 8080 +EXPOSE 8083 USER policy WORKDIR $POLICY_HOME/bin diff --git a/packages/policy-clamp-docker/src/main/docker/kubernetes-participant.sh b/packages/policy-clamp-docker/src/main/docker/kubernetes-participant.sh index 195639ad3..50995de3b 100644 --- a/packages/policy-clamp-docker/src/main/docker/kubernetes-participant.sh +++ b/packages/policy-clamp-docker/src/main/docker/kubernetes-participant.sh @@ -42,8 +42,8 @@ if [ -f "${POLICY_HOME}/etc/mounted/logback.xml" ]; then cp -f "${POLICY_HOME}"/etc/mounted/logback*.xml "${POLICY_HOME}"/etc/ fi -$JAVA_HOME/bin/java -Djavax.net.ssl.keyStore="${KEYSTORE}" \ - -Djavax.net.ssl.keyStorePassword="${KEYSTORE_PASSWD}" \ - -Djavax.net.ssl.trustStore="${TRUSTSTORE}" \ - -Djavax.net.ssl.trustStorePassword="${TRUSTSTORE_PASSWD}" \ +$JAVA_HOME/bin/java -Dserver.ssl.keyStore="${KEYSTORE}" \ + -Dserver.ssl.keyStorePassword="${KEYSTORE_PASSWD}" \ + -Dserver.ssl.trustStore="${TRUSTSTORE}" \ + -Dserver.ssl.trustStorePassword="${TRUSTSTORE_PASSWD}" \ -jar /app/app.jar diff --git a/participant/participant-impl/participant-impl-dcae/src/main/resources/config/application.yaml b/participant/participant-impl/participant-impl-dcae/src/main/resources/config/application.yaml index 36b9f846a..44ba5b3e8 100644 --- a/participant/participant-impl/participant-impl-dcae/src/main/resources/config/application.yaml +++ b/participant/participant-impl/participant-impl-dcae/src/main/resources/config/application.yaml @@ -46,10 +46,6 @@ participant: topic: POLICY-CLRUNTIME-PARTICIPANT servers[0]: ${topicServer:message-router} topicCommInfrastructure: dmaap - topicSinks[1]: - topic: POLICY-NOTIFICATION - servers[0]: ${topicServer:message-router} - topicCommInfrastructure: dmaap checkCount: 10 secCount: 10 jsonBodyConsulPath: src/main/resources/parameters/consul.json diff --git a/participant/participant-impl/participant-impl-dcae/src/test/resources/application_test.properties b/participant/participant-impl/participant-impl-dcae/src/test/resources/application_test.properties index d585dd3c9..2c775c28d 100644 --- a/participant/participant-impl/participant-impl-dcae/src/test/resources/application_test.properties +++ b/participant/participant-impl/participant-impl-dcae/src/test/resources/application_test.properties @@ -34,8 +34,5 @@ participant.intermediaryParameters.clampControlLoopTopics.topicSources[0].fetchT participant.intermediaryParameters.clampControlLoopTopics.topicSinks[0].topic=POLICY-CLRUNTIME-PARTICIPANT participant.intermediaryParameters.clampControlLoopTopics.topicSinks[0].servers[0]=localhost participant.intermediaryParameters.clampControlLoopTopics.topicSinks[0].topicCommInfrastructure=dmaap -participant.intermediaryParameters.clampControlLoopTopics.topicSinks[1].topic=POLICY-NOTIFICATION -participant.intermediaryParameters.clampControlLoopTopics.topicSinks[1].servers[0]=localhost -participant.intermediaryParameters.clampControlLoopTopics.topicSinks[1].topicCommInfrastructure=dmaap participant.checkCount=10 diff --git a/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/controlloop/participant/kubernetes/configurations/ParticipantConfig.java b/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/controlloop/participant/kubernetes/configurations/ParticipantConfig.java index 94789a74f..97adfde88 100644 --- a/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/controlloop/participant/kubernetes/configurations/ParticipantConfig.java +++ b/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/controlloop/participant/kubernetes/configurations/ParticipantConfig.java @@ -33,30 +33,6 @@ import org.springframework.web.multipart.commons.CommonsMultipartResolver; @Configuration public class ParticipantConfig { - @Value("${server.http-port}") - private int httpPort = 0; - - /** - * Method to create servlet container bean. - * @return webserver factory - */ - @Bean - public ServletWebServerFactory servletContainer() { - var tomcat = new TomcatServletWebServerFactory(); - if (httpPort > 0) { - tomcat.addAdditionalTomcatConnectors(getHttpConnector(httpPort)); - } - return tomcat; - } - - private static Connector getHttpConnector(int httpPort) { - var connector = new Connector(TomcatServletWebServerFactory.DEFAULT_PROTOCOL); - connector.setScheme("http"); - connector.setPort(httpPort); - connector.setSecure(false); - return connector; - } - /** * Method to create multipartResolver bean. * @return MultipartResolver @@ -67,5 +43,4 @@ public class ParticipantConfig { multipartResolver.setMaxUploadSize(100000); return multipartResolver; } - } diff --git a/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/controlloop/participant/kubernetes/configurations/SecurityConfig.java b/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/controlloop/participant/kubernetes/configurations/SecurityConfig.java new file mode 100644 index 000000000..6b4fb0a75 --- /dev/null +++ b/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/controlloop/participant/kubernetes/configurations/SecurityConfig.java @@ -0,0 +1,45 @@ +/*- + * ========================LICENSE_START================================= + * Copyright (C) 2021 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.controlloop.participant.kubernetes.configurations; + +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-kubernetes/src/main/java/org/onap/policy/clamp/controlloop/participant/kubernetes/handler/ControlLoopElementHandler.java b/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/controlloop/participant/kubernetes/handler/ControlLoopElementHandler.java index 4f654832d..20a23ca32 100644 --- a/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/controlloop/participant/kubernetes/handler/ControlLoopElementHandler.java +++ b/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/controlloop/participant/kubernetes/handler/ControlLoopElementHandler.java @@ -26,6 +26,7 @@ import java.lang.invoke.MethodHandles; import java.util.HashMap; import java.util.Map; import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; import lombok.AccessLevel; import lombok.Getter; import lombok.Setter; @@ -35,8 +36,12 @@ import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoop import org.onap.policy.clamp.controlloop.participant.intermediary.api.ControlLoopElementListener; import org.onap.policy.clamp.controlloop.participant.intermediary.api.ParticipantIntermediaryApi; import org.onap.policy.clamp.controlloop.participant.kubernetes.exception.ServiceException; +import org.onap.policy.clamp.controlloop.participant.kubernetes.helm.PodStatusValidator; import org.onap.policy.clamp.controlloop.participant.kubernetes.models.ChartInfo; import org.onap.policy.clamp.controlloop.participant.kubernetes.service.ChartService; +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.ToscaNodeTemplate; import org.onap.policy.models.tosca.authorative.concepts.ToscaServiceTemplate; @@ -45,6 +50,7 @@ import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; + /** * This class handles implementation of controlLoopElement updates. */ @@ -52,6 +58,11 @@ import org.springframework.stereotype.Component; public class ControlLoopElementHandler implements ControlLoopElementListener { private static final Logger LOGGER = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); + // Map of helm installation and the status of corresponding pods + @Getter + private static Map<String, Map<String, String>> podStatusMap = new ConcurrentHashMap<>(); + private static final Coder CODER = new StandardCoder(); + @Autowired private ChartService chartService; @@ -62,6 +73,12 @@ public class ControlLoopElementHandler implements ControlLoopElementListener { @Getter(AccessLevel.PACKAGE) private final Map<UUID, ChartInfo> chartMap = new HashMap<>(); + // Default thread config values + private static class ThreadConfig { + private int uninitializedToPassiveTimeout = 60; + private int podStatusCheckInterval = 30; + } + /** * Callback method to handle a control loop element state change. * @@ -71,7 +88,7 @@ public class ControlLoopElementHandler implements ControlLoopElementListener { */ @Override public synchronized void controlLoopElementStateChange(UUID controlLoopElementId, ControlLoopState currentState, - ControlLoopOrderedState newState) { + ControlLoopOrderedState newState) { switch (newState) { case UNINITIALISED: ChartInfo chart = chartMap.get(controlLoopElementId); @@ -80,7 +97,9 @@ public class ControlLoopElementHandler implements ControlLoopElementListener { try { chartService.uninstallChart(chart); intermediaryApi.updateControlLoopElementState(controlLoopElementId, newState, - ControlLoopState.UNINITIALISED); + ControlLoopState.UNINITIALISED); + chartMap.remove(controlLoopElementId); + podStatusMap.remove(chart.getReleaseName()); } catch (ServiceException se) { LOGGER.warn("deletion of Helm deployment failed", se); } @@ -108,37 +127,50 @@ public class ControlLoopElementHandler implements ControlLoopElementListener { */ @Override public synchronized void controlLoopElementUpdate(ControlLoopElement element, - ToscaServiceTemplate controlLoopDefinition) throws PfModelException { + ToscaServiceTemplate controlLoopDefinition) + throws PfModelException { for (Map.Entry<String, ToscaNodeTemplate> nodeTemplate : controlLoopDefinition.getToscaTopologyTemplate() - .getNodeTemplates().entrySet()) { + .getNodeTemplates().entrySet()) { // Fetching the node template of corresponding CL element if (element.getDefinition().getName().equals(nodeTemplate.getKey()) - && nodeTemplate.getValue().getProperties().containsKey("chart")) { + && nodeTemplate.getValue().getProperties().containsKey("chart")) { @SuppressWarnings("unchecked") Map<String, Object> chartData = - (Map<String, Object>) nodeTemplate.getValue().getProperties().get("chart"); + (Map<String, Object>) nodeTemplate.getValue().getProperties().get("chart"); LOGGER.info("Installation request received for the Helm Chart {} ", chartData); - var chart = new ChartInfo(String.valueOf(chartData.get("release_name")), - String.valueOf(chartData.get("chart_name")), String.valueOf(chartData.get("version")), - String.valueOf(chartData.get("namespace"))); try { + var chartInfo = CODER.decode(String.valueOf(chartData), ChartInfo.class); var repositoryValue = chartData.get("repository"); if (repositoryValue != null) { - chart.setRepository(String.valueOf(repositoryValue)); + chartInfo.setRepository(repositoryValue.toString()); } - chartService.installChart(chart); - chartMap.put(element.getId(), chart); - } catch (IOException | ServiceException ise) { - LOGGER.warn("installation of Helm chart failed", ise); + chartService.installChart(chartInfo); + chartMap.put(element.getId(), chartInfo); + + var config = CODER.convert(nodeTemplate.getValue().getProperties(), ThreadConfig.class); + checkPodStatus(chartInfo, config.uninitializedToPassiveTimeout, config.podStatusCheckInterval); + + } catch (ServiceException | CoderException | IOException e) { + LOGGER.warn("Installation of Helm chart failed", e); } } } } /** + * Invoke a new thread to check the status of deployed pods. + * @param chart ChartInfo + */ + public void checkPodStatus(ChartInfo chart, int timeout, int podStatusCheckInterval) { + // Invoke runnable thread to check pod status + var runnableThread = new Thread(new PodStatusValidator(chart, timeout, podStatusCheckInterval)); + runnableThread.start(); + } + + /** * Overridden method. * * @param controlLoopElementId controlLoopElement id diff --git a/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/controlloop/participant/kubernetes/helm/HelmClient.java b/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/controlloop/participant/kubernetes/helm/HelmClient.java index 90d7218da..b38fbeb81 100644 --- a/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/controlloop/participant/kubernetes/helm/HelmClient.java +++ b/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/controlloop/participant/kubernetes/helm/HelmClient.java @@ -19,6 +19,7 @@ package org.onap.policy.clamp.controlloop.participant.kubernetes.helm; import java.io.BufferedReader; +import java.io.File; import java.io.IOException; import java.io.InputStreamReader; import java.lang.invoke.MethodHandles; @@ -26,6 +27,7 @@ import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.Map; import org.apache.commons.io.IOUtils; import org.onap.policy.clamp.controlloop.participant.kubernetes.exception.ServiceException; import org.onap.policy.clamp.controlloop.participant.kubernetes.models.ChartInfo; @@ -60,9 +62,10 @@ public class HelmClient { logger.warn("Namespace not created", e); } processBuilder = prepareInstallCommand(chart); - logger.info("Installing helm chart {} from the repository {} ", chart.getChartName(), chart.getRepository()); + logger.info("Installing helm chart {} from the repository {} ", chart.getChartId().getName(), + chart.getRepository()); executeCommand(processBuilder); - logger.info("Chart {} installed successfully", chart.getChartName()); + logger.info("Chart {} installed successfully", chart.getChartId().getName()); } /** @@ -79,9 +82,9 @@ public class HelmClient { if (repository != null) { return repository; } - var localHelmChartDir = chartStore.getAppPath(chart.getChartName(), chart.getVersion()).toString(); + var localHelmChartDir = chartStore.getAppPath(chart.getChartId()).toString(); logger.info("Chart not found in helm repositories, verifying local repo {} ", localHelmChartDir); - if (verifyLocalHelmRepo(localHelmChartDir + "/" + chart.getChartName())) { + if (verifyLocalHelmRepo(new File(localHelmChartDir + "/" + chart.getChartId().getName()))) { repository = localHelmChartDir; } @@ -96,15 +99,15 @@ public class HelmClient { * @throws ServiceException incase of error */ public String verifyConfiguredRepo(ChartInfo chart) throws IOException, ServiceException { - logger.info("Looking for helm chart {} in all the configured helm repositories", chart.getChartName()); + logger.info("Looking for helm chart {} in all the configured helm repositories", chart.getChartId().getName()); String repository = null; - var builder = helmRepoVerifyCommand(chart.getChartName()); + var builder = helmRepoVerifyCommand(chart.getChartId().getName()); String output = executeCommand(builder); try (var reader = new BufferedReader(new InputStreamReader(IOUtils.toInputStream(output, - StandardCharsets.UTF_8)))) { + StandardCharsets.UTF_8)))) { String line = reader.readLine(); while (line != null) { - if (line.contains(chart.getChartName())) { + if (line.contains(chart.getChartId().getName())) { repository = line.split("/")[0]; logger.info("Helm chart located in the repository {} ", repository); return repository; @@ -125,6 +128,7 @@ public class HelmClient { executeCommand(prepareUnInstallCommand(chart)); } + /** * Execute helm cli bash commands . * @param processBuilder processbuilder @@ -141,7 +145,9 @@ public class HelmClient { if (exitValue != 0) { var error = IOUtils.toString(process.getErrorStream(), StandardCharsets.UTF_8); - throw new ServiceException("Command execution failed: " + commandStr + " " + error); + if (! error.isEmpty()) { + throw new ServiceException("Command execution failed: " + commandStr + " " + error); + } } var output = IOUtils.toString(process.getInputStream(), StandardCharsets.UTF_8); @@ -151,7 +157,7 @@ public class HelmClient { } catch (InterruptedException ie) { Thread.currentThread().interrupt(); throw new ServiceException("Failed to execute the Command: " + commandStr + ", the command was interrupted", - ie); + ie); } catch (Exception exc) { throw new ServiceException("Failed to execute the Command: " + commandStr, exc); } @@ -161,27 +167,34 @@ public class HelmClient { // @formatter:off List<String> helmArguments = new ArrayList<>( - Arrays.asList( - "helm", - "install", chart.getReleaseName(), chart.getRepository() + "/" + chart.getChartName(), - "--version", chart.getVersion(), - "--namespace", chart.getNamespace() - ) + List.of( + "helm", + "install", chart.getReleaseName(), chart.getRepository() + "/" + chart.getChartId().getName(), + "--version", chart.getChartId().getVersion(), + "--namespace", chart.getNamespace() + ) ); // @formatter:on - // Verify if values.yaml available for the chart - var overrideFile = chartStore.getOverrideFile(chart).getPath(); - if (verifyLocalHelmRepo(overrideFile)) { - logger.info("Override yaml file available for the helm chart"); - helmArguments.addAll(Arrays.asList("--values", overrideFile)); + // Verify if values.yaml/override parameters available for the chart + var localOverrideYaml = chartStore.getOverrideFile(chart); + + if (verifyLocalHelmRepo(localOverrideYaml)) { + logger.info("Override yaml available for the helm chart"); + helmArguments.addAll(List.of("--values", localOverrideYaml.getPath())); } + if (chart.getOverrideParams() != null) { + for (Map.Entry<String, String> entry : chart.getOverrideParams().entrySet()) { + helmArguments.addAll(List.of("--set", entry.getKey() + "=" + entry.getValue())); + } + } return new ProcessBuilder().command(helmArguments); } private ProcessBuilder prepareUnInstallCommand(ChartInfo chart) { - return new ProcessBuilder("helm", "delete", chart.getReleaseName(), "--namespace", chart.getNamespace()); + return new ProcessBuilder("helm", "delete", chart.getReleaseName(), "--namespace", + chart.getNamespace()); } private ProcessBuilder prepareCreateNamespaceCommand(String namespace) { @@ -189,12 +202,9 @@ public class HelmClient { } private ProcessBuilder helmRepoVerifyCommand(String chartName) { - return new ProcessBuilder().command("bash", "-c", "helm search repo | grep " + chartName); + return new ProcessBuilder().command("sh", "-c", "helm search repo | grep " + chartName); } - private ProcessBuilder localRepoVerifyCommand(String localFile) { - return new ProcessBuilder().command("bash", "-c", "ls " + localFile); - } private void updateHelmRepo() throws ServiceException { logger.info("Updating local helm repositories before verifying the chart"); @@ -202,16 +212,8 @@ public class HelmClient { logger.debug("Helm repositories updated successfully"); } - private boolean verifyLocalHelmRepo(String localFile) { - var isVerified = false; - var processBuilder = localRepoVerifyCommand(localFile); - try { - executeCommand(processBuilder); - isVerified = true; - } catch (ServiceException e) { - logger.error("Unable to verify file in local repository", e); - } - return isVerified; + private boolean verifyLocalHelmRepo(File localFile) { + return localFile.exists(); } protected static String toString(ProcessBuilder processBuilder) { diff --git a/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/controlloop/participant/kubernetes/helm/PodStatusValidator.java b/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/controlloop/participant/kubernetes/helm/PodStatusValidator.java new file mode 100644 index 000000000..d55fd6658 --- /dev/null +++ b/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/controlloop/participant/kubernetes/helm/PodStatusValidator.java @@ -0,0 +1,119 @@ +/*- + * ========================LICENSE_START================================= + * Copyright (C) 2021 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.controlloop.participant.kubernetes.helm; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.lang.invoke.MethodHandles; +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.Map; +import lombok.SneakyThrows; +import org.apache.commons.io.IOUtils; +import org.onap.policy.clamp.controlloop.participant.kubernetes.exception.ServiceException; +import org.onap.policy.clamp.controlloop.participant.kubernetes.handler.ControlLoopElementHandler; +import org.onap.policy.clamp.controlloop.participant.kubernetes.models.ChartInfo; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +public class PodStatusValidator implements Runnable { + + private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); + + private final int statusCheckInterval; + + //Timeout for the thread to exit. + private final int timeout; + + private ChartInfo chart; + + /** + * Constructor for PodStatusValidator. + * @param chart chartInfo + * @param timeout timeout for the thread to exit + * @param statusCheckInterval Interval to check pod status + */ + public PodStatusValidator(ChartInfo chart, int timeout, int statusCheckInterval) { + this.chart = chart; + this.timeout = timeout; + this.statusCheckInterval = statusCheckInterval; + } + + + @SneakyThrows + @Override + public void run() { + logger.info("Polling the status of deployed pods for the chart {}", chart.getChartId().getName()); + Map<String, String> podStatusMap; + String output = null; + var isVerified = false; + long endTime = System.currentTimeMillis() + (timeout * 1000L); + + while (!isVerified && System.currentTimeMillis() < endTime) { + try { + output = HelmClient.executeCommand(verifyPodStatusCommand(chart)); + podStatusMap = mapPodStatus(output); + isVerified = podStatusMap.values() + .stream() + .allMatch("Running"::equals); + if (! isVerified) { + logger.info("Waiting for the pods to be active for the chart {}", chart.getChartId().getName()); + podStatusMap.forEach((key, value) -> logger.info("Pod: {} , state: {}", key, value)); + ControlLoopElementHandler.getPodStatusMap().put(chart.getReleaseName(), podStatusMap); + // Recheck status of pods in specific intervals. + Thread.sleep(statusCheckInterval * 1000L); + } else { + logger.info("All pods are in running state for the helm chart {}", chart.getChartId().getName()); + ControlLoopElementHandler.getPodStatusMap().put(chart.getReleaseName(), podStatusMap); + } + } catch (ServiceException | IOException e) { + throw new ServiceException("Error verifying the status of the pod. Exiting", e); + } + } + } + + private ProcessBuilder verifyPodStatusCommand(ChartInfo chart) { + String podName = chart.getReleaseName() + "-" + chart.getChartId().getName(); + String cmd = "kubectl get pods --namespace " + chart.getNamespace() + " | grep " + podName; + return new ProcessBuilder("sh", "-c", cmd); + } + + + private Map<String, String> mapPodStatus(String output) throws IOException, ServiceException { + Map<String, String> podStatusMap = new HashMap<>(); + try (var reader = new BufferedReader(new InputStreamReader(IOUtils.toInputStream(output, + StandardCharsets.UTF_8)))) { + var line = reader.readLine(); + while (line != null) { + if (line.contains(chart.getChartId().getName())) { + var result = line.split("\\s+"); + podStatusMap.put(result[0], result[2]); + } + line = reader.readLine(); + } + } + if (!podStatusMap.isEmpty()) { + return podStatusMap; + } else { + throw new ServiceException("Status of Pod is empty"); + } + } +} diff --git a/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/controlloop/participant/kubernetes/models/ChartInfo.java b/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/controlloop/participant/kubernetes/models/ChartInfo.java index 6bfb7aed5..b53f2075a 100644 --- a/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/controlloop/participant/kubernetes/models/ChartInfo.java +++ b/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/controlloop/participant/kubernetes/models/ChartInfo.java @@ -18,28 +18,27 @@ package org.onap.policy.clamp.controlloop.participant.kubernetes.models; +import java.util.Map; import lombok.Data; import lombok.NonNull; import lombok.RequiredArgsConstructor; -import org.immutables.gson.Gson; +import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier; @Data @RequiredArgsConstructor -@Gson.TypeAdapters public class ChartInfo { @NonNull private String releaseName; @NonNull - private String chartName; - - @NonNull - private String version; + private ToscaConceptIdentifier chartId; @NonNull private String namespace; private String repository; + private Map<String, String> overrideParams; + } diff --git a/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/controlloop/participant/kubernetes/service/ChartService.java b/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/controlloop/participant/kubernetes/service/ChartService.java index adb6cf0d1..a1522188d 100644 --- a/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/controlloop/participant/kubernetes/service/ChartService.java +++ b/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/controlloop/participant/kubernetes/service/ChartService.java @@ -68,7 +68,7 @@ public class ChartService { * @throws ServiceException in case of error */ public ChartInfo saveChart(ChartInfo chartInfo, MultipartFile chartFile, MultipartFile overrideFile) - throws IOException, ServiceException { + throws IOException, ServiceException { return chartStore.saveChart(chartInfo, chartFile, overrideFile); } @@ -91,7 +91,7 @@ public class ChartService { String repository = findChartRepo(chart); if (repository == null) { logger.error("Chart repository could not be found. Skipping chart Installation " - + "for the chart {} ", chart.getChartName()); + + "for the chart {} ", chart.getChartId().getName()); return; } else { chart.setRepository(repository); @@ -108,7 +108,7 @@ public class ChartService { * @throws IOException in case of IO errors */ public String findChartRepo(ChartInfo chart) throws ServiceException, IOException { - logger.info("Fetching helm chart repository for the given chart {} ", chart.getChartName()); + logger.info("Fetching helm chart repository for the given chart {} ", chart.getChartId().getName()); return helmClient.findChartRepository(chart); } @@ -121,5 +121,4 @@ public class ChartService { logger.info("Uninstalling helm deployment {}", chart.getReleaseName()); helmClient.uninstallChart(chart); } - } diff --git a/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/controlloop/participant/kubernetes/service/ChartStore.java b/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/controlloop/participant/kubernetes/service/ChartStore.java index 03b35161d..975671705 100644 --- a/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/controlloop/participant/kubernetes/service/ChartStore.java +++ b/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/controlloop/participant/kubernetes/service/ChartStore.java @@ -40,6 +40,7 @@ import org.onap.policy.clamp.controlloop.participant.kubernetes.models.ChartInfo import org.onap.policy.clamp.controlloop.participant.kubernetes.parameters.ParticipantK8sParameters; import org.onap.policy.common.utils.coder.CoderException; import org.onap.policy.common.utils.coder.StandardCoder; +import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; @@ -73,8 +74,8 @@ public class ChartStore { * @return the chart file. */ public File getHelmChartFile(ChartInfo chart) { - var appPath = getAppPath(chart.getChartName(), chart.getVersion()); - return new File(appPath.toFile(), chart.getChartName()); + var appPath = getAppPath(chart.getChartId()); + return new File(appPath.toFile(), chart.getChartId().getName()); } /** @@ -84,7 +85,7 @@ public class ChartStore { * @return the override yaml file */ public File getOverrideFile(ChartInfo chart) { - var appPath = getAppPath(chart.getChartName(), chart.getVersion()); + var appPath = getAppPath(chart.getChartId()); return new File(appPath.toFile(), "values.yaml"); } @@ -100,11 +101,11 @@ public class ChartStore { * @throws ServiceException incase of error. */ public synchronized ChartInfo saveChart(ChartInfo chartInfo, MultipartFile chartFile, MultipartFile overrideFile) - throws IOException, ServiceException { - if (localChartMap.containsKey(key(chartInfo.getChartName(), chartInfo.getVersion()))) { + throws IOException, ServiceException { + if (localChartMap.containsKey(key(chartInfo))) { throw new ServiceException("Chart already exist"); } - var appPath = getAppPath(chartInfo.getChartName(), chartInfo.getVersion()); + var appPath = getAppPath(chartInfo.getChartId()); Files.createDirectories(appPath); chartFile.transferTo(getHelmChartFile(chartInfo)); @@ -143,7 +144,7 @@ public class ChartStore { * @param chart chart info */ public synchronized void deleteChart(ChartInfo chart) { - var appPath = getAppPath(chart.getChartName(), chart.getVersion()); + var appPath = getAppPath(chart.getChartId()); try { FileSystemUtils.deleteRecursively(appPath); } catch (IOException exc) { @@ -156,24 +157,23 @@ public class ChartStore { /** * Fetch the local chart directory of specific chart. * - * @param chartName name of the chart - * @param chartVersion version of the chart + * @param chartId Id of the chart * @return path */ - public Path getAppPath(String chartName, String chartVersion) { - return Path.of(participantK8sParameters.getLocalChartDirectory(), chartName, chartVersion); + public Path getAppPath(ToscaConceptIdentifier chartId) { + return Path.of(participantK8sParameters.getLocalChartDirectory(), chartId.getName(), chartId.getVersion()); } private void storeChartInFile(ChartInfo chart) { try (var out = new PrintStream(new FileOutputStream(getFile(chart)))) { out.print(STANDARD_CODER.encode(chart)); } catch (Exception exc) { - LOGGER.warn("Could not store chart: {} {}", chart.getChartName(), exc); + LOGGER.warn("Could not store chart: {} {}", chart.getChartId(), exc); } } private File getFile(ChartInfo chart) { - var appPath = getAppPath(chart.getChartName(), chart.getVersion()).toString(); + var appPath = getAppPath(chart.getChartId()).toString(); return Path.of(appPath, participantK8sParameters.getInfoFileName()).toFile(); } @@ -188,7 +188,7 @@ public class ChartStore { } private synchronized void restoreFromLocalFileSystem(Path localChartDirectoryPath) - throws IOException { + throws IOException { Files.walkFileTree(localChartDirectoryPath, new SimpleFileVisitor<Path>() { @Override @@ -208,11 +208,10 @@ public class ChartStore { } private String key(ChartInfo chart) { - return key(chart.getChartName(), chart.getVersion()); + return key(chart.getChartId().getName(), chart.getChartId().getVersion()); } private String key(String chartName, String chartVersion) { return chartName + "_" + chartVersion; } - } diff --git a/participant/participant-impl/participant-impl-kubernetes/src/main/resources/config/application.yaml b/participant/participant-impl/participant-impl-kubernetes/src/main/resources/config/application.yaml index 63ec8a295..9d3523737 100644 --- a/participant/participant-impl/participant-impl-kubernetes/src/main/resources/config/application.yaml +++ b/participant/participant-impl/participant-impl-kubernetes/src/main/resources/config/application.yaml @@ -1,6 +1,10 @@ spring: - profiles: - active: prod + security: + user: + name: healthcheck + password: zb!XztG34 +security: + enable-csrf: false participant: localChartDirectory: /var/helm-manager/local-charts @@ -24,10 +28,6 @@ participant: topic: POLICY-CLRUNTIME-PARTICIPANT servers[0]: ${topicServer:message-router} topicCommInfrastructure: dmaap - topicSinks[1]: - topic: POLICY-NOTIFICATION - servers[0]: ${topicServer:message-router} - topicCommInfrastructure: dmaap management: endpoints: @@ -37,7 +37,7 @@ management: server: # Configuration of the HTTP/REST server. The parameters are defined and handled by the springboot framework. # See springboot documentation. - http-port : 8083 + port: 8083 logging: # Configuration of logging diff --git a/participant/participant-impl/participant-impl-kubernetes/src/test/java/org.onap.policy.clamp.controlloop.participant.kubernetes/handler/ControlLoopElementHandlerTest.java b/participant/participant-impl/participant-impl-kubernetes/src/test/java/org.onap.policy.clamp.controlloop.participant.kubernetes/handler/ControlLoopElementHandlerTest.java index f3d27a63c..f8381ee7f 100644 --- a/participant/participant-impl/participant-impl-kubernetes/src/test/java/org.onap.policy.clamp.controlloop.participant.kubernetes/handler/ControlLoopElementHandlerTest.java +++ b/participant/participant-impl/participant-impl-kubernetes/src/test/java/org.onap.policy.clamp.controlloop.participant.kubernetes/handler/ControlLoopElementHandlerTest.java @@ -22,6 +22,8 @@ package org.onap.policy.clamp.controlloop.participant.kubernetes.handler; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doThrow; @@ -35,6 +37,7 @@ import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.Mockito; +import org.mockito.Spy; import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoopElement; import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoopOrderedState; import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoopState; @@ -64,6 +67,7 @@ class ControlLoopElementHandlerTest { @InjectMocks + @Spy private ControlLoopElementHandler controlLoopElementHandler = new ControlLoopElementHandler(); @Mock @@ -107,7 +111,7 @@ class ControlLoopElementHandlerTest { @Test void test_ControlLoopElementUpdate() throws PfModelException, IOException, ServiceException { - + doNothing().when(controlLoopElementHandler).checkPodStatus(any(), anyInt(), anyInt()); UUID elementId1 = UUID.randomUUID(); ControlLoopElement element = new ControlLoopElement(); element.setId(elementId1); diff --git a/participant/participant-impl/participant-impl-kubernetes/src/test/java/org.onap.policy.clamp.controlloop.participant.kubernetes/helm/HelmClientTest.java b/participant/participant-impl/participant-impl-kubernetes/src/test/java/org.onap.policy.clamp.controlloop.participant.kubernetes/helm/HelmClientTest.java index 5f8b7dc78..370bfa6ce 100644 --- a/participant/participant-impl/participant-impl-kubernetes/src/test/java/org.onap.policy.clamp.controlloop.participant.kubernetes/helm/HelmClientTest.java +++ b/participant/participant-impl/participant-impl-kubernetes/src/test/java/org.onap.policy.clamp.controlloop.participant.kubernetes/helm/HelmClientTest.java @@ -33,6 +33,7 @@ import java.io.File; import java.io.IOException; import java.nio.file.Path; import java.util.List; +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; @@ -49,6 +50,7 @@ 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.springframework.test.context.junit.jupiter.SpringExtension; +import org.springframework.util.FileSystemUtils; @ExtendWith(SpringExtension.class) @@ -74,6 +76,12 @@ class HelmClientTest { mockedClient = mockStatic(HelmClient.class); } + @AfterAll + public static void close() throws IOException { + mockedClient.close(); + FileSystemUtils.deleteRecursively(Path.of("target/tmp")); + } + @Test void test_installChart() throws IOException { mockedClient.when(() -> HelmClient.executeCommand(any())) @@ -85,21 +93,22 @@ class HelmClientTest { @Test void test_findChartRepository() throws IOException, ServiceException { + String tmpPath = "target/tmp/dummyChart/1.0/"; mockedClient.when(() -> HelmClient.executeCommand(Mockito.any())) .thenReturn("nginx-stable/nginx-ingress\t0.9.3\t1.11.3" + " \tNGINX Ingress Controller"); String configuredRepo = helmClient.findChartRepository(charts.get(1)); - assertThat(configuredRepo).isEqualTo("nginx-stable"); - doReturn(Path.of("/target/tmp/dummyChart/1.0")).when(chartStore).getAppPath(charts.get(1).getChartName(), - charts.get(1).getVersion()); + File tmpFile = new File(tmpPath + charts.get(1).getChartId().getName()); + tmpFile.mkdirs(); + doReturn(Path.of(tmpPath)).when(chartStore).getAppPath(charts.get(1).getChartId()); doReturn(null).when(helmClient).verifyConfiguredRepo(charts.get(1)); String localRepoName = helmClient.findChartRepository(charts.get(1)); assertNotNull(localRepoName); - assertThat(localRepoName).endsWith(charts.get(0).getVersion()); + assertThat(localRepoName).endsWith(charts.get(0).getChartId().getVersion()); } @Test diff --git a/participant/participant-impl/participant-impl-kubernetes/src/test/java/org.onap.policy.clamp.controlloop.participant.kubernetes/helm/PodStatusValidatorTest.java b/participant/participant-impl/participant-impl-kubernetes/src/test/java/org.onap.policy.clamp.controlloop.participant.kubernetes/helm/PodStatusValidatorTest.java new file mode 100644 index 000000000..f72a53403 --- /dev/null +++ b/participant/participant-impl/participant-impl-kubernetes/src/test/java/org.onap.policy.clamp.controlloop.participant.kubernetes/helm/PodStatusValidatorTest.java @@ -0,0 +1,108 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2021 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.controlloop.participant.kubernetes.helm; + + + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mockStatic; + +import java.io.File; +import java.util.List; +import java.util.Map; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.MockedStatic; +import org.onap.policy.clamp.controlloop.participant.kubernetes.exception.ServiceException; +import org.onap.policy.clamp.controlloop.participant.kubernetes.handler.ControlLoopElementHandler; +import org.onap.policy.clamp.controlloop.participant.kubernetes.models.ChartInfo; +import org.onap.policy.clamp.controlloop.participant.kubernetes.models.ChartList; +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.springframework.test.context.junit.jupiter.SpringExtension; + +@ExtendWith(SpringExtension.class) +class PodStatusValidatorTest { + + + private static final Coder CODER = new StandardCoder(); + private static final String CHART_INFO_YAML = "src/test/resources/ChartList.json"; + private static List<ChartInfo> charts; + private static int timeout = 60; + private static int statusCheckInterval = 30; + + + @InjectMocks + private static PodStatusValidator podStatusValidator; + + private static MockedStatic<HelmClient> mockedClient; + + + @BeforeAll + static void init() throws CoderException { + charts = CODER.decode(new File(CHART_INFO_YAML), ChartList.class).getCharts(); + mockedClient = mockStatic(HelmClient.class); + podStatusValidator = new PodStatusValidator(charts.get(0), timeout, statusCheckInterval); + } + + @AfterEach + void clearPodStatusMap() { + ControlLoopElementHandler.getPodStatusMap().clear(); + } + + @AfterAll + public static void close() { + mockedClient.close(); + } + + + @Test + void test_RunningPodState() { + String runningPod = "NAME\tREADY\tSTATUS\tRESTARTS\tAGE\r\nHelloWorld-54777df9f8-qpzqr\t1/1\tRunning\t0\t9h"; + mockedClient.when(() -> HelmClient.executeCommand(any())) + .thenReturn(runningPod); + assertDoesNotThrow(() -> podStatusValidator.run()); + assertThat(ControlLoopElementHandler.getPodStatusMap()).hasSize(1); + assertThat(ControlLoopElementHandler.getPodStatusMap()).containsKey(charts.get(0).getReleaseName()); + assertThat(ControlLoopElementHandler.getPodStatusMap()) + .containsValue(Map.of("HelloWorld-54777df9f8-qpzqr", "Running")); + } + + + @Test + void test_InvalidPodState() { + String invalidPod = "NAME\tREADY\tSTATUS\tRESTARTS\tAGE\nhellofromdocker-54777df9f8-qpzqr\t1/1\tInit\t0\t9h"; + mockedClient.when(() -> HelmClient.executeCommand(any())) + .thenReturn(invalidPod); + assertThatThrownBy(() -> podStatusValidator.run()) + .isInstanceOf(ServiceException.class).hasMessage("Error verifying the status of the pod. Exiting"); + assertThat(ControlLoopElementHandler.getPodStatusMap()).isEmpty(); + } + +} diff --git a/participant/participant-impl/participant-impl-kubernetes/src/test/java/org.onap.policy.clamp.controlloop.participant.kubernetes/rest/ChartControllerTest.java b/participant/participant-impl/participant-impl-kubernetes/src/test/java/org.onap.policy.clamp.controlloop.participant.kubernetes/rest/ChartControllerTest.java index 1a1bdae5b..a28fd9ebe 100644 --- a/participant/participant-impl/participant-impl-kubernetes/src/test/java/org.onap.policy.clamp.controlloop.participant.kubernetes/rest/ChartControllerTest.java +++ b/participant/participant-impl/participant-impl-kubernetes/src/test/java/org.onap.policy.clamp.controlloop.participant.kubernetes/rest/ChartControllerTest.java @@ -93,7 +93,7 @@ class ChartControllerTest { @BeforeEach void mockServiceClass() { when(chartService.getAllCharts()).thenReturn(charts); - when(chartService.getChart(charts.get(0).getChartName(), charts.get(0).getVersion())) + when(chartService.getChart(charts.get(0).getChartId().getName(), charts.get(0).getChartId().getVersion())) .thenReturn(charts.get(0)); this.mockMvc = MockMvcBuilders.webAppContextSetup(this.context).build(); @@ -110,7 +110,7 @@ class ChartControllerTest { mockMvc.perform(requestBuilder).andExpect(status().isOk()) .andExpect(content().contentTypeCompatibleWith(MediaType.APPLICATION_JSON)) - .andExpect(jsonPath("$.charts.[0].chartName", is("HelloWorld"))); + .andExpect(jsonPath("$.charts.[0].chartId.name", is("HelloWorld"))); } /** @@ -125,7 +125,7 @@ class ChartControllerTest { doNothing().when(chartService).installChart(charts.get(0)); requestBuilder = MockMvcRequestBuilders.post(INSTALL_CHART_URL).accept(MediaType.APPLICATION_JSON_VALUE) - .content(getInstallationJson(charts.get(0).getChartName(), charts.get(0).getVersion())) + .content(getInstallationJson(charts.get(0).getChartId().getName(), charts.get(0).getChartId().getVersion())) .contentType(MediaType.APPLICATION_JSON_VALUE); mockMvc.perform(requestBuilder).andExpect(status().isCreated()); @@ -149,9 +149,9 @@ class ChartControllerTest { //Mocking successful scenario for void uninstall method doNothing().when(chartService).uninstallChart(charts.get(0)); - requestBuilder = MockMvcRequestBuilders.delete(UNINSTALL_CHART_URL + charts.get(0).getChartName() - + "/" + charts.get(0).getVersion()).accept(MediaType.APPLICATION_JSON_VALUE) - .contentType(MediaType.APPLICATION_JSON_VALUE); + requestBuilder = MockMvcRequestBuilders.delete(UNINSTALL_CHART_URL + charts.get(0) + .getChartId().getName() + "/" + charts.get(0).getChartId().getVersion()) + .accept(MediaType.APPLICATION_JSON_VALUE).contentType(MediaType.APPLICATION_JSON_VALUE); mockMvc.perform(requestBuilder).andExpect(status().isNoContent()); @@ -196,8 +196,9 @@ class ChartControllerTest { //Mocking successful scenario for void uninstall method doNothing().when(chartService).deleteChart(charts.get(0)); - requestBuilder = MockMvcRequestBuilders.delete(DEFAULT_CHART_URL + "/" + charts.get(0).getChartName() - + "/" + charts.get(0).getVersion()).accept(MediaType.APPLICATION_JSON_VALUE) + requestBuilder = MockMvcRequestBuilders.delete(DEFAULT_CHART_URL + "/" + charts.get(0) + .getChartId().getName() + "/" + charts.get(0).getChartId().getVersion()) + .accept(MediaType.APPLICATION_JSON_VALUE) .contentType(MediaType.APPLICATION_JSON_VALUE); mockMvc.perform(requestBuilder).andExpect(status().isNoContent()); @@ -219,8 +220,8 @@ class ChartControllerTest { private String getChartInfoJson() { JSONObject jsonObj = new JSONObject(); - jsonObj.put("chartName", charts.get(0).getChartName()); - jsonObj.put("version", charts.get(0).getVersion()); + jsonObj.put("chartName", charts.get(0).getChartId().getName()); + jsonObj.put("version", charts.get(0).getChartId().getVersion()); jsonObj.put("namespace", charts.get(0).getNamespace()); jsonObj.put("repository", charts.get(0).getRepository()); jsonObj.put("releaseName", charts.get(0).getReleaseName()); diff --git a/participant/participant-impl/participant-impl-kubernetes/src/test/java/org.onap.policy.clamp.controlloop.participant.kubernetes/service/ChartServiceTest.java b/participant/participant-impl/participant-impl-kubernetes/src/test/java/org.onap.policy.clamp.controlloop.participant.kubernetes/service/ChartServiceTest.java index 957a69a08..8e7943410 100644 --- a/participant/participant-impl/participant-impl-kubernetes/src/test/java/org.onap.policy.clamp.controlloop.participant.kubernetes/service/ChartServiceTest.java +++ b/participant/participant-impl/participant-impl-kubernetes/src/test/java/org.onap.policy.clamp.controlloop.participant.kubernetes/service/ChartServiceTest.java @@ -88,8 +88,8 @@ class ChartServiceTest { assertNull(chartService.getChart("dummyName", "dummyversion")); doReturn(charts.get(0)).when(chartStore).getChart(any(), any()); - ChartInfo chart = chartService.getChart(charts.get(0).getChartName(), - charts.get(0).getVersion()); + ChartInfo chart = chartService.getChart(charts.get(0).getChartId().getName(), + charts.get(0).getChartId().getVersion()); assertNotNull(chart); assertThat(chart.getNamespace()).isEqualTo(charts.get(0).getNamespace()); } @@ -107,7 +107,7 @@ class ChartServiceTest { ChartInfo chart = chartService.saveChart(charts.get(0), mockChartFile, mockOverrideFile); assertNotNull(chart); - assertThat(chart.getChartName()).isEqualTo(charts.get(0).getChartName()); + assertThat(chart.getChartId().getName()).isEqualTo(charts.get(0).getChartId().getName()); } diff --git a/participant/participant-impl/participant-impl-kubernetes/src/test/java/org.onap.policy.clamp.controlloop.participant.kubernetes/service/ChartStoreTest.java b/participant/participant-impl/participant-impl-kubernetes/src/test/java/org.onap.policy.clamp.controlloop.participant.kubernetes/service/ChartStoreTest.java index 2d05a7a0e..eb4e7a173 100644 --- a/participant/participant-impl/participant-impl-kubernetes/src/test/java/org.onap.policy.clamp.controlloop.participant.kubernetes/service/ChartStoreTest.java +++ b/participant/participant-impl/participant-impl-kubernetes/src/test/java/org.onap.policy.clamp.controlloop.participant.kubernetes/service/ChartStoreTest.java @@ -46,6 +46,7 @@ import org.onap.policy.clamp.controlloop.participant.kubernetes.parameters.Parti 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.tosca.authorative.concepts.ToscaConceptIdentifier; import org.springframework.mock.web.MockMultipartFile; import org.springframework.util.FileSystemUtils; @@ -88,7 +89,7 @@ class ChartStoreTest { void test_getHelmChartFile() { File file = chartStore.getHelmChartFile(charts.get(0)); assertNotNull(file); - assertThat(file.getPath()).endsWith(charts.get(0).getChartName()); + assertThat(file.getPath()).endsWith(charts.get(0).getChartId().getName()); } @Test @@ -103,10 +104,10 @@ class ChartStoreTest { MockMultipartFile mockChartFile = new MockMultipartFile("chart", "dummy".getBytes()); MockMultipartFile mockOverrideFile = new MockMultipartFile("override", "dummy".getBytes()); ChartInfo testChart = charts.get(0); - testChart.setChartName("testChart"); + testChart.setChartId(new ToscaConceptIdentifier("testChart", "1.0.0")); ChartInfo result = chartStore.saveChart(charts.get(0), mockChartFile, mockOverrideFile); - assertThat(result.getChartName()).isEqualTo("testChart"); + assertThat(result.getChartId().getName()).isEqualTo("testChart"); assertThat(chartStore.getLocalChartMap()).hasSize(1); assertThatThrownBy(() -> chartStore.saveChart(charts.get(0), mockChartFile, mockOverrideFile)) @@ -116,11 +117,12 @@ class ChartStoreTest { @Test void test_getChart() { - assertNull(chartStore.getChart(charts.get(0).getChartName(), charts.get(0).getVersion())); - chartStore.getLocalChartMap().put(charts.get(0).getChartName() + "_" + charts.get(0).getVersion(), - charts.get(0)); - ChartInfo chart = chartStore.getChart(charts.get(0).getChartName(), charts.get(0).getVersion()); - assertThat(chart.getChartName()).isEqualTo(charts.get(0).getChartName()); + assertNull(chartStore.getChart(charts.get(0).getChartId().getName(), charts.get(0).getChartId().getVersion())); + chartStore.getLocalChartMap().put(charts.get(0).getChartId().getName() + "_" + charts.get(0).getChartId() + .getVersion(), charts.get(0)); + ChartInfo chart = chartStore.getChart(charts.get(0).getChartId().getName(), + charts.get(0).getChartId().getVersion()); + assertThat(chart.getChartId().getName()).isEqualTo(charts.get(0).getChartId().getName()); } @Test @@ -129,7 +131,8 @@ class ChartStoreTest { assertThat(chartStore.getAllCharts()).isEmpty(); for (ChartInfo chart : charts) { - chartStore.getLocalChartMap().put(chart.getChartName() + "_" + chart.getVersion(), chart); + chartStore.getLocalChartMap().put(chart.getChartId().getName() + "_" + chart.getChartId().getVersion(), + chart); } List<ChartInfo> retrievedChartList = chartStore.getAllCharts(); assertThat(retrievedChartList).isNotEmpty(); @@ -138,8 +141,8 @@ class ChartStoreTest { @Test void test_deleteChart() { - chartStore.getLocalChartMap().put(charts.get(0).getChartName() + "_" + charts.get(0).getVersion(), - charts.get(0)); + chartStore.getLocalChartMap().put(charts.get(0).getChartId().getName() + "_" + charts.get(0).getChartId() + .getVersion(), charts.get(0)); assertThat(chartStore.getLocalChartMap()).hasSize(1); chartStore.deleteChart(charts.get(0)); assertThat(chartStore.getLocalChartMap()).isEmpty(); @@ -147,9 +150,9 @@ class ChartStoreTest { @Test void test_getAppPath() { - Path path = chartStore.getAppPath(charts.get(0).getChartName(), charts.get(0).getVersion()); + Path path = chartStore.getAppPath(charts.get(0).getChartId()); assertNotNull(path); - assertThat(path.toString()).endsWith(charts.get(0).getVersion()); + assertThat(path.toString()).endsWith(charts.get(0).getChartId().getVersion()); assertThat(path.toString()).startsWith("target"); } @@ -158,13 +161,14 @@ class ChartStoreTest { MockMultipartFile mockChartFile = new MockMultipartFile("HelmChartFile", "dummyData".getBytes()); MockMultipartFile mockOverrideFile = new MockMultipartFile("overrideFile.yaml", "dummyData".getBytes()); ChartInfo testChart = charts.get(0); - testChart.setChartName("dummyChart"); + testChart.setChartId(new ToscaConceptIdentifier("dummyChart", "1.0.0")); //Creating a dummy chart in local dir. chartStore.saveChart(charts.get(0), mockChartFile, mockOverrideFile); //Instantiating a new chartStore object with pre available chart in local. ChartStore chartStore2 = new ChartStore(parameters); - assertThat(chartStore2.getLocalChartMap()).hasSize(1).containsKey("dummyChart_" + charts.get(0).getVersion()); + assertThat(chartStore2.getLocalChartMap()).hasSize(1).containsKey("dummyChart_" + charts.get(0).getChartId() + .getVersion()); } } diff --git a/participant/participant-impl/participant-impl-kubernetes/src/test/resources/ChartList.json b/participant/participant-impl/participant-impl-kubernetes/src/test/resources/ChartList.json index 4e355c38e..2f4ec2827 100644 --- a/participant/participant-impl/participant-impl-kubernetes/src/test/resources/ChartList.json +++ b/participant/participant-impl/participant-impl-kubernetes/src/test/resources/ChartList.json @@ -1,15 +1,21 @@ { "charts" : [ { - "chartName" : "HelloWorld", - "version" : "1.0", + "chartId" : { + "name" : "HelloWorld", + "version" : "1.0" + }, "namespace" : "onap", - "repository" : "chartMuseum" + "repository" : "chartMuseum", + "releaseName" : "helloworld" }, { - "chartName" : "nginx", - "version" : "1.1", - "namespace" : "onap" + "chartId" : { + "name" : "nginx", + "version" : "1.1" + }, + "namespace" : "onap", + "releaseName" : "nginxapp" } ] } diff --git a/participant/participant-impl/participant-impl-kubernetes/src/test/resources/application_test.properties b/participant/participant-impl/participant-impl-kubernetes/src/test/resources/application_test.properties index 188623af0..5c61535a7 100644 --- a/participant/participant-impl/participant-impl-kubernetes/src/test/resources/application_test.properties +++ b/participant/participant-impl/participant-impl-kubernetes/src/test/resources/application_test.properties @@ -21,6 +21,3 @@ participant.intermediaryParameters.clampControlLoopTopics.topicSources[0].fetchT participant.intermediaryParameters.clampControlLoopTopics.topicSinks[0].topic=POLICY-CLRUNTIME-PARTICIPANT participant.intermediaryParameters.clampControlLoopTopics.topicSinks[0].servers[0]=localhost participant.intermediaryParameters.clampControlLoopTopics.topicSinks[0].topicCommInfrastructure=dmaap -participant.intermediaryParameters.clampControlLoopTopics.topicSinks[1].topic=POLICY-NOTIFICATION -participant.intermediaryParameters.clampControlLoopTopics.topicSinks[1].servers[0]=localhost -participant.intermediaryParameters.clampControlLoopTopics.topicSinks[1].topicCommInfrastructure=dmaap diff --git a/participant/participant-impl/participant-impl-kubernetes/src/test/resources/servicetemplates/KubernetesHelm.yaml b/participant/participant-impl/participant-impl-kubernetes/src/test/resources/servicetemplates/KubernetesHelm.yaml index 3212b5ad2..69886cdb1 100644 --- a/participant/participant-impl/participant-impl-kubernetes/src/test/resources/servicetemplates/KubernetesHelm.yaml +++ b/participant/participant-impl/participant-impl-kubernetes/src/test/resources/servicetemplates/KubernetesHelm.yaml @@ -97,12 +97,15 @@ topology_template: participant_id: name: org.onap.k8s.controlloop.K8SControlLoopParticipant version: 2.3.4 + uninitializedToPassiveTimeout: 180 + podStatusCheckInterval: 30 chart: - release_name: helloworld - chart_name: hello - version: 0.1.0 - repository: chartMuseum + chartId: + name: hello + version: 0.1.0 + releaseName: helloworld namespace: onap + repository: chartMuseum org.onap.domain.database.PMSH_K8SMicroserviceControlLoopElement: # Chart from local file system @@ -115,11 +118,16 @@ topology_template: participant_id: name: org.onap.k8s.controlloop.K8SControlLoopParticipant version: 2.3.4 + uninitializedToPassiveTimeout: 180 + podStatusCheckInterval: 30 chart: - release_name: pmshmicroservice - chart_name: test - version: 1.0.1 + chartId: + name: dcae-pmsh + version: 8.0.0 namespace: onap + releaseName: pmshms + overrideParams: + global.masterPassword: test org.onap.domain.database.Local_K8SMicroserviceControlLoopElement: # Chart installation without passing repository name @@ -132,10 +140,13 @@ topology_template: participant_id: name: org.onap.k8s.controlloop.K8SControlLoopParticipant version: 2.3.4 + uninitializedToPassiveTimeout: 180 + podStatusCheckInterval: 30 chart: - release_name: nginxms - chart_name: nginx-ingress - version: 0.9.1 + chartId: + name: nginx-ingress + version: 0.9.1 + releaseName: nginxms namespace: onap org.onap.domain.sample.GenericK8s_ControlLoopDefinition: diff --git a/participant/participant-impl/participant-impl-policy/src/main/resources/config/application.yaml b/participant/participant-impl/participant-impl-policy/src/main/resources/config/application.yaml index 7bf4f623a..d4c7d7561 100644 --- a/participant/participant-impl/participant-impl-policy/src/main/resources/config/application.yaml +++ b/participant/participant-impl/participant-impl-policy/src/main/resources/config/application.yaml @@ -27,7 +27,3 @@ participant: topic: POLICY-CLRUNTIME-PARTICIPANT servers[0]: ${topicServer:message-router} topicCommInfrastructure: dmaap - topicSinks[1]: - topic: POLICY-NOTIFICATION - servers[0]: ${topicServer:message-router} - topicCommInfrastructure: dmaap diff --git a/participant/participant-impl/participant-impl-policy/src/test/java/org/onap/policy/clamp/controlloop/participant/policy/endtoend/ParticipantMessagesTest.java b/participant/participant-impl/participant-impl-policy/src/test/java/org/onap/policy/clamp/controlloop/participant/policy/endtoend/ParticipantMessagesTest.java new file mode 100644 index 000000000..4b4558b89 --- /dev/null +++ b/participant/participant-impl/participant-impl-policy/src/test/java/org/onap/policy/clamp/controlloop/participant/policy/endtoend/ParticipantMessagesTest.java @@ -0,0 +1,149 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2021 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.controlloop.participant.policy.endtoend; + +import java.time.Instant; +import java.util.Collections; +import java.util.UUID; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mockito; +import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantDeregister; +import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantDeregisterAck; +import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantRegister; +import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantRegisterAck; +import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantUpdate; +import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantUpdateAck; +import org.onap.policy.clamp.controlloop.participant.intermediary.comm.ParticipantDeregisterAckListener; +import org.onap.policy.clamp.controlloop.participant.intermediary.comm.ParticipantMessagePublisher; +import org.onap.policy.clamp.controlloop.participant.intermediary.comm.ParticipantRegisterAckListener; +import org.onap.policy.clamp.controlloop.participant.intermediary.comm.ParticipantUpdateListener; +import org.onap.policy.clamp.controlloop.participant.intermediary.handler.ParticipantHandler; +import org.onap.policy.clamp.controlloop.participant.policy.main.utils.TestListenerUtils; +import org.onap.policy.common.endpoints.event.comm.Topic.CommInfrastructure; +import org.onap.policy.common.endpoints.event.comm.TopicSink; +import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; +import org.springframework.test.context.TestPropertySource; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +@ExtendWith(SpringExtension.class) +@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) +@TestPropertySource(locations = {"classpath:application_test.properties"}) +class ParticipantMessagesTest { + + private static final Object lockit = new Object(); + private static final CommInfrastructure INFRA = CommInfrastructure.NOOP; + private static final String TOPIC = "my-topic"; + + @Autowired + private ParticipantHandler participantHandler; + + @Test + void testSendParticipantRegisterMessage() throws Exception { + final ParticipantRegister participantRegisterMsg = new ParticipantRegister(); + participantRegisterMsg.setParticipantId(getParticipantId()); + participantRegisterMsg.setTimestamp(Instant.now()); + participantRegisterMsg.setParticipantType(getParticipantType()); + + synchronized (lockit) { + ParticipantMessagePublisher participantMessagePublisher = + new ParticipantMessagePublisher(Collections.singletonList(Mockito.mock(TopicSink.class))); + participantMessagePublisher.sendParticipantRegister(participantRegisterMsg); + } + } + + @Test + void testReceiveParticipantRegisterAckMessage() throws Exception { + final ParticipantRegisterAck participantRegisterAckMsg = new ParticipantRegisterAck(); + participantRegisterAckMsg.setMessage("ParticipantRegisterAck message"); + participantRegisterAckMsg.setResponseTo(UUID.randomUUID()); + participantRegisterAckMsg.setResult(true); + + synchronized (lockit) { + ParticipantRegisterAckListener participantRegisterAckListener = + new ParticipantRegisterAckListener(participantHandler); + participantRegisterAckListener.onTopicEvent(INFRA, TOPIC, null, participantRegisterAckMsg); + } + } + + @Test + void testSendParticipantDeregisterMessage() throws Exception { + final ParticipantDeregister participantDeregisterMsg = new ParticipantDeregister(); + participantDeregisterMsg.setParticipantId(getParticipantId()); + participantDeregisterMsg.setTimestamp(Instant.now()); + participantDeregisterMsg.setParticipantType(getParticipantType()); + + synchronized (lockit) { + ParticipantMessagePublisher participantMessagePublisher = + new ParticipantMessagePublisher(Collections.singletonList(Mockito.mock(TopicSink.class))); + participantMessagePublisher.sendParticipantDeregister(participantDeregisterMsg); + } + } + + @Test + void testReceiveParticipantDeregisterAckMessage() throws Exception { + final ParticipantDeregisterAck participantDeregisterAckMsg = new ParticipantDeregisterAck(); + participantDeregisterAckMsg.setMessage("ParticipantDeregisterAck message"); + participantDeregisterAckMsg.setResponseTo(UUID.randomUUID()); + participantDeregisterAckMsg.setResult(true); + + synchronized (lockit) { + ParticipantDeregisterAckListener participantDeregisterAckListener = + new ParticipantDeregisterAckListener(participantHandler); + participantDeregisterAckListener.onTopicEvent(INFRA, TOPIC, null, participantDeregisterAckMsg); + } + } + + @Test + void testReceiveParticipantUpdateMessage() throws Exception { + ParticipantUpdate participantUpdateMsg = TestListenerUtils.createParticipantUpdateMsg(); + + synchronized (lockit) { + ParticipantUpdateListener participantUpdateListener = new ParticipantUpdateListener(participantHandler); + participantUpdateListener.onTopicEvent(INFRA, TOPIC, null, participantUpdateMsg); + } + } + + @Test + void testSendParticipantUpdateAckMessage() throws Exception { + final ParticipantUpdateAck participantUpdateAckMsg = new ParticipantUpdateAck(); + participantUpdateAckMsg.setMessage("ParticipantUpdateAck message"); + participantUpdateAckMsg.setResponseTo(UUID.randomUUID()); + participantUpdateAckMsg.setResult(true); + + synchronized (lockit) { + ParticipantMessagePublisher participantMessagePublisher = + new ParticipantMessagePublisher(Collections.singletonList(Mockito.mock(TopicSink.class))); + participantMessagePublisher.sendParticipantUpdateAck(participantUpdateAckMsg); + } + } + + private ToscaConceptIdentifier getParticipantId() { + return new ToscaConceptIdentifier("org.onap.PM_Policy", "1.0.0"); + } + + private ToscaConceptIdentifier getParticipantType() { + return new ToscaConceptIdentifier("org.onap.policy.controlloop.PolicyControlLoopParticipant", "2.3.1"); + } +} diff --git a/participant/participant-impl/participant-impl-policy/src/test/java/org/onap/policy/clamp/controlloop/participant/policy/endtoend/ParticipantPolicyTest.java b/participant/participant-impl/participant-impl-policy/src/test/java/org/onap/policy/clamp/controlloop/participant/policy/endtoend/ParticipantPolicyTest.java index 6b8323971..45674f4c8 100644 --- a/participant/participant-impl/participant-impl-policy/src/test/java/org/onap/policy/clamp/controlloop/participant/policy/endtoend/ParticipantPolicyTest.java +++ b/participant/participant-impl/participant-impl-policy/src/test/java/org/onap/policy/clamp/controlloop/participant/policy/endtoend/ParticipantPolicyTest.java @@ -28,8 +28,10 @@ import org.junit.jupiter.api.extension.ExtendWith; import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoopOrderedState; import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantControlLoopStateChange; import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantControlLoopUpdate; +import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantUpdate; import org.onap.policy.clamp.controlloop.participant.intermediary.comm.ControlLoopStateChangeListener; import org.onap.policy.clamp.controlloop.participant.intermediary.comm.ControlLoopUpdateListener; +import org.onap.policy.clamp.controlloop.participant.intermediary.comm.ParticipantUpdateListener; import org.onap.policy.clamp.controlloop.participant.intermediary.handler.ParticipantHandler; import org.onap.policy.clamp.controlloop.participant.policy.main.utils.TestListenerUtils; import org.onap.policy.common.endpoints.event.comm.Topic.CommInfrastructure; diff --git a/participant/participant-impl/participant-impl-policy/src/test/java/org/onap/policy/clamp/controlloop/participant/policy/main/utils/TestListenerUtils.java b/participant/participant-impl/participant-impl-policy/src/test/java/org/onap/policy/clamp/controlloop/participant/policy/main/utils/TestListenerUtils.java index 794b9ff69..d439c9daf 100644 --- a/participant/participant-impl/participant-impl-policy/src/test/java/org/onap/policy/clamp/controlloop/participant/policy/main/utils/TestListenerUtils.java +++ b/participant/participant-impl/participant-impl-policy/src/test/java/org/onap/policy/clamp/controlloop/participant/policy/main/utils/TestListenerUtils.java @@ -31,6 +31,7 @@ import java.util.Set; import java.util.UUID; import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoop; import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoopElement; +import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoopElementDefinition; import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoopOrderedState; import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoopState; import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ParticipantState; @@ -38,6 +39,7 @@ import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.Parti import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantControlLoopUpdate; import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantHealthCheck; import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantStateChange; +import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantUpdate; import org.onap.policy.clamp.controlloop.participant.policy.main.parameters.CommonTestData; import org.onap.policy.common.utils.coder.Coder; import org.onap.policy.common.utils.coder.CoderException; @@ -193,6 +195,45 @@ public class TestListenerUtils { } /** + * Method to create participantUpdateMsg. + * + * @return ParticipantUpdate message + */ + public static ParticipantUpdate createParticipantUpdateMsg() { + final ParticipantUpdate participantUpdateMsg = new ParticipantUpdate(); + ToscaConceptIdentifier participantId = new ToscaConceptIdentifier("org.onap.PM_Policy", "1.0.0"); + ToscaConceptIdentifier participantType = new ToscaConceptIdentifier( + "org.onap.policy.controlloop.PolicyControlLoopParticipant", "2.3.1"); + + participantUpdateMsg.setParticipantId(participantId); + participantUpdateMsg.setTimestamp(Instant.now()); + participantUpdateMsg.setParticipantType(participantType); + participantUpdateMsg.setTimestamp(Instant.ofEpochMilli(3000)); + participantUpdateMsg.setMessageId(UUID.randomUUID()); + + ToscaServiceTemplate toscaServiceTemplate = new ToscaServiceTemplate(); + toscaServiceTemplate.setName("serviceTemplate"); + toscaServiceTemplate.setDerivedFrom("parentServiceTemplate"); + toscaServiceTemplate.setDescription("Description of serviceTemplate"); + toscaServiceTemplate.setVersion("1.2.3"); + + ControlLoopElementDefinition clDefinition = new ControlLoopElementDefinition(); + clDefinition.setId(UUID.randomUUID()); + clDefinition.setControlLoopElementToscaServiceTemplate(toscaServiceTemplate); + Map<String, String> commonPropertiesMap = Map.of("Prop1", "PropValue"); + clDefinition.setCommonPropertiesMap(commonPropertiesMap); + + Map<UUID, ControlLoopElementDefinition> controlLoopElementDefinitionMap = + Map.of(UUID.randomUUID(), clDefinition); + + Map<ToscaConceptIdentifier, Map<UUID, ControlLoopElementDefinition>> + participantDefinitionUpdateMap = Map.of(participantId, controlLoopElementDefinitionMap); + participantUpdateMsg.setParticipantDefinitionUpdateMap(participantDefinitionUpdateMap); + + return participantUpdateMsg; + } + + /** * Method to create ParticipantHealthCheck message. * * @return ParticipantHealthCheck message diff --git a/participant/participant-impl/participant-impl-policy/src/test/resources/application_test.properties b/participant/participant-impl/participant-impl-policy/src/test/resources/application_test.properties index 2f260825b..70d52b413 100644 --- a/participant/participant-impl/participant-impl-policy/src/test/resources/application_test.properties +++ b/participant/participant-impl/participant-impl-policy/src/test/resources/application_test.properties @@ -22,6 +22,3 @@ participant.intermediaryParameters.clampControlLoopTopics.topicSources[0].fetchT participant.intermediaryParameters.clampControlLoopTopics.topicSinks[0].topic=POLICY-CLRUNTIME-PARTICIPANT participant.intermediaryParameters.clampControlLoopTopics.topicSinks[0].servers[0]=localhost participant.intermediaryParameters.clampControlLoopTopics.topicSinks[0].topicCommInfrastructure=dmaap -participant.intermediaryParameters.clampControlLoopTopics.topicSinks[1].topic=POLICY-NOTIFICATION -participant.intermediaryParameters.clampControlLoopTopics.topicSinks[1].servers[0]=localhost -participant.intermediaryParameters.clampControlLoopTopics.topicSinks[1].topicCommInfrastructure=dmaap diff --git a/participant/participant-impl/participant-impl-simulator/src/main/resources/config/application.yaml b/participant/participant-impl/participant-impl-simulator/src/main/resources/config/application.yaml index 82e3b89f1..5a9cf1497 100644 --- a/participant/participant-impl/participant-impl-simulator/src/main/resources/config/application.yaml +++ b/participant/participant-impl/participant-impl-simulator/src/main/resources/config/application.yaml @@ -31,7 +31,3 @@ participant: topic: POLICY-CLRUNTIME-PARTICIPANT servers[0]: ${topicServer:message-router} topicCommInfrastructure: dmaap - topicSinks[1]: - topic: POLICY-NOTIFICATION - servers[0]: ${topicServer:message-router} - topicCommInfrastructure: dmaap diff --git a/participant/participant-impl/participant-impl-simulator/src/test/resources/application_test.properties b/participant/participant-impl/participant-impl-simulator/src/test/resources/application_test.properties index 2b30c4ffd..f162367f8 100644 --- a/participant/participant-impl/participant-impl-simulator/src/test/resources/application_test.properties +++ b/participant/participant-impl/participant-impl-simulator/src/test/resources/application_test.properties @@ -23,6 +23,3 @@ participant.intermediaryParameters.clampControlLoopTopics.topicSources[0].fetchT participant.intermediaryParameters.clampControlLoopTopics.topicSinks[0].topic=POLICY-CLRUNTIME-PARTICIPANT participant.intermediaryParameters.clampControlLoopTopics.topicSinks[0].servers[0]=localhost participant.intermediaryParameters.clampControlLoopTopics.topicSinks[0].topicCommInfrastructure=dmaap -participant.intermediaryParameters.clampControlLoopTopics.topicSinks[1].topic=POLICY-NOTIFICATION -participant.intermediaryParameters.clampControlLoopTopics.topicSinks[1].servers[0]=localhost -participant.intermediaryParameters.clampControlLoopTopics.topicSinks[1].topicCommInfrastructure=dmaap diff --git a/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/controlloop/participant/intermediary/api/ParticipantIntermediaryApi.java b/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/controlloop/participant/intermediary/api/ParticipantIntermediaryApi.java index a87299bdc..7e448dc15 100644 --- a/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/controlloop/participant/intermediary/api/ParticipantIntermediaryApi.java +++ b/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/controlloop/participant/intermediary/api/ParticipantIntermediaryApi.java @@ -46,6 +46,16 @@ public interface ParticipantIntermediaryApi { void registerControlLoopElementListener(ControlLoopElementListener controlLoopElementListener); /** + * Send participant register message to controlloop runtime. + */ + void sendParticipantRegister(); + + /** + * Send participant deregister message to controlloop runtime. + */ + void sendParticipantDeregister(); + + /** * Get participants loops from the intermediary API. * * @param name the participant name, null for all @@ -114,5 +124,4 @@ public interface ParticipantIntermediaryApi { * @param elementStatistics the updated statistics */ void updateControlLoopElementStatistics(UUID id, ClElementStatistics elementStatistics); - } diff --git a/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/controlloop/participant/intermediary/api/impl/ParticipantIntermediaryApiImpl.java b/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/controlloop/participant/intermediary/api/impl/ParticipantIntermediaryApiImpl.java index 838f47544..9652f1a8d 100644 --- a/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/controlloop/participant/intermediary/api/impl/ParticipantIntermediaryApiImpl.java +++ b/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/controlloop/participant/intermediary/api/impl/ParticipantIntermediaryApiImpl.java @@ -63,6 +63,16 @@ public class ParticipantIntermediaryApiImpl implements ParticipantIntermediaryAp } @Override + public void sendParticipantRegister() { + participantHandler.sendParticipantRegister(); + } + + @Override + public void sendParticipantDeregister() { + participantHandler.sendParticipantDeregister(); + } + + @Override public List<Participant> getParticipants(String name, String version) { return List.of(participantHandler.getParticipant(name, version)); } diff --git a/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/controlloop/participant/intermediary/comm/MessageSender.java b/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/controlloop/participant/intermediary/comm/MessageSender.java index 6926bc30b..1bfce1374 100644 --- a/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/controlloop/participant/intermediary/comm/MessageSender.java +++ b/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/controlloop/participant/intermediary/comm/MessageSender.java @@ -30,9 +30,12 @@ import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoop import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoopElement; import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoops; import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ParticipantStatistics; +import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantDeregister; +import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantRegister; import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantResponseDetails; import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantResponseStatus; import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantStatus; +import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantUpdateAck; import org.onap.policy.clamp.controlloop.participant.intermediary.api.ControlLoopElementListener; import org.onap.policy.clamp.controlloop.participant.intermediary.handler.ParticipantHandler; import org.onap.policy.models.base.PfModelException; @@ -47,7 +50,7 @@ public class MessageSender extends TimerTask implements Closeable { private static final Logger LOGGER = LoggerFactory.getLogger(MessageSender.class); private final ParticipantHandler participantHandler; - private final ParticipantStatusPublisher publisher; + private final ParticipantMessagePublisher publisher; private ScheduledExecutorService timerPool; /** @@ -57,7 +60,7 @@ public class MessageSender extends TimerTask implements Closeable { * @param publisher the publisher to use for sending messages * @param interval time interval to send Participant Status periodic messages */ - public MessageSender(ParticipantHandler participantHandler, ParticipantStatusPublisher publisher, + public MessageSender(ParticipantHandler participantHandler, ParticipantMessagePublisher publisher, long interval) { this.participantHandler = participantHandler; this.publisher = publisher; @@ -127,11 +130,38 @@ public class MessageSender extends TimerTask implements Closeable { status.setControlLoops(controlLoops); - publisher.send(status); + publisher.sendParticipantStatus(status); } /** - * Update ControlLoopElement statistics. The control loop elements listening will be + * Send a ParticipantRegister message for this participant. + * + * @param message the participantRegister message + */ + public void sendParticipantRegister(ParticipantRegister message) { + publisher.sendParticipantRegister(message); + } + + /** + * Send a ParticipantDeregister message for this participant. + * + * @param message the participantDeRegister message + */ + public void sendParticipantDeregister(ParticipantDeregister message) { + publisher.sendParticipantDeregister(message); + } + + /** + * Send a ParticipantUpdateAck message for this participant update. + * + * @param message the participantUpdateAck message + */ + public void sendParticipantUpdateAck(ParticipantUpdateAck message) { + publisher.sendParticipantUpdateAck(message); + } + + /** + * Update ControlLoopElement statistics. The control loop elements listening will be * notified to retrieve statistics from respective controlloop elements, and controlloopelements * data on the handler will be updated. * diff --git a/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/controlloop/participant/intermediary/comm/ParticipantAckListener.java b/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/controlloop/participant/intermediary/comm/ParticipantAckListener.java new file mode 100644 index 000000000..262b21630 --- /dev/null +++ b/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/controlloop/participant/intermediary/comm/ParticipantAckListener.java @@ -0,0 +1,57 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2021 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.controlloop.participant.intermediary.comm; + +import java.util.function.Consumer; +import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantAckMessage; +import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantMessage; +import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantRegisterAck; +import org.onap.policy.clamp.controlloop.participant.intermediary.handler.ParticipantHandler; +import org.onap.policy.common.endpoints.event.comm.Topic.CommInfrastructure; +import org.onap.policy.common.endpoints.listeners.ScoListener; +import org.onap.policy.common.utils.coder.StandardCoderObject; + +/** + * Abstract Listener for Participant Ack messages sent by runtime. + */ +public abstract class ParticipantAckListener<T extends ParticipantAckMessage> extends ScoListener<T> { + + private final ParticipantHandler participantHandler; + private final Consumer<T> consumer; + + /** + * Constructs the object. + * + * @param clazz class of message this handles + * @param participantHandler ParticipantHandler + * @param consumer function that handles the message + */ + protected ParticipantAckListener(Class<T> clazz, ParticipantHandler participantHandler, Consumer<T> consumer) { + super(clazz); + this.participantHandler = participantHandler; + this.consumer = consumer; + } + + @Override + public void onTopicEvent(CommInfrastructure infra, String topic, StandardCoderObject sco, T message) { + consumer.accept(message); + } +} diff --git a/common/src/test/java/org/onap/policy/clamp/controlloop/common/handler/ControlLoopHandlerTest.java b/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/controlloop/participant/intermediary/comm/ParticipantDeregisterAckListener.java index 7def2873a..e20f481f8 100644 --- a/common/src/test/java/org/onap/policy/clamp/controlloop/common/handler/ControlLoopHandlerTest.java +++ b/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/controlloop/participant/intermediary/comm/ParticipantDeregisterAckListener.java @@ -18,30 +18,25 @@ * ============LICENSE_END========================================================= */ -package org.onap.policy.clamp.controlloop.common.handler; +package org.onap.policy.clamp.controlloop.participant.intermediary.comm; -import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; +import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantDeregisterAck; +import org.onap.policy.clamp.controlloop.participant.intermediary.handler.ParticipantHandler; +import org.springframework.stereotype.Component; -import org.junit.jupiter.api.Test; -import org.onap.policy.models.provider.PolicyModelsProviderParameters; - -class ControlLoopHandlerTest { - - @Test - void testControlLoopHandler() { - assertThatThrownBy(() -> new DummyControlLoopHandler(null)).isInstanceOf(NullPointerException.class); - - assertNotNull(new DummyControlLoopHandler(new PolicyModelsProviderParameters())); - - PolicyModelsProviderParameters pars = new PolicyModelsProviderParameters(); - - DummyControlLoopHandler dclh = new DummyControlLoopHandler(pars); - assertNotNull(dclh); - - assertEquals(pars, dclh.getDatabaseProviderParameters()); - - dclh.close(); +/** + * Listener for Participant Deregister Ack messages sent by runtime. + * + */ +@Component +public class ParticipantDeregisterAckListener extends ParticipantAckListener<ParticipantDeregisterAck> { + + /** + * Constructs the object. + * + * @param participantHandler the handler for managing the state of the participant + */ + public ParticipantDeregisterAckListener(final ParticipantHandler participantHandler) { + super(ParticipantDeregisterAck.class, participantHandler, participantHandler::handleParticipantDeregisterAck); } } diff --git a/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/controlloop/participant/intermediary/comm/ParticipantMessagePublisher.java b/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/controlloop/participant/intermediary/comm/ParticipantMessagePublisher.java new file mode 100644 index 000000000..9e1b84620 --- /dev/null +++ b/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/controlloop/participant/intermediary/comm/ParticipantMessagePublisher.java @@ -0,0 +1,93 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2021 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.controlloop.participant.intermediary.comm; + +import java.util.List; +import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantDeregister; +import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantRegister; +import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantStatus; +import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantUpdateAck; +import org.onap.policy.common.endpoints.event.comm.TopicSink; +import org.onap.policy.common.endpoints.event.comm.client.TopicSinkClient; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * This class is used to send Participant Status messages to clamp using TopicSinkClient. + * + */ +public class ParticipantMessagePublisher { + private static final Logger LOGGER = LoggerFactory.getLogger(ParticipantMessagePublisher.class); + + private final TopicSinkClient topicSinkClient; + + /** + * Constructor for instantiating ParticipantMessagePublisher. + * + * @param topicSinks the topic sinks + */ + public ParticipantMessagePublisher(List<TopicSink> topicSinks) { + if (topicSinks.size() != 1) { + throw new IllegalArgumentException("Configuration unsupported, Topic sinks greater than 1"); + } + this.topicSinkClient = new TopicSinkClient(topicSinks.get(0)); + } + + /** + * Method to send Participant Status message to clamp on demand. + * + * @param participantStatus the Participant Status + */ + public void sendParticipantStatus(final ParticipantStatus participantStatus) { + topicSinkClient.send(participantStatus); + LOGGER.debug("Sent Participant Status message to CLAMP - {}", participantStatus); + } + + /** + * Method to send Participant Status message to clamp on demand. + * + * @param participantRegister the Participant Status + */ + public void sendParticipantRegister(final ParticipantRegister participantRegister) { + topicSinkClient.send(participantRegister); + LOGGER.debug("Sent Participant Register message to CLAMP - {}", participantRegister); + } + + /** + * Method to send Participant Status message to clamp on demand. + * + * @param participantDeregister the Participant Status + */ + public void sendParticipantDeregister(final ParticipantDeregister participantDeregister) { + topicSinkClient.send(participantDeregister); + LOGGER.debug("Sent Participant Deregister message to CLAMP - {}", participantDeregister); + } + + /** + * Method to send Participant Update Ack message to runtime. + * + * @param participantUpdateAck the Participant Update Ack + */ + public void sendParticipantUpdateAck(final ParticipantUpdateAck participantUpdateAck) { + topicSinkClient.send(participantUpdateAck); + LOGGER.debug("Sent Participant Update Ack message to CLAMP - {}", participantUpdateAck); + } +} diff --git a/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/controlloop/participant/intermediary/comm/ParticipantRegisterAckListener.java b/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/controlloop/participant/intermediary/comm/ParticipantRegisterAckListener.java new file mode 100644 index 000000000..a15a2a850 --- /dev/null +++ b/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/controlloop/participant/intermediary/comm/ParticipantRegisterAckListener.java @@ -0,0 +1,42 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2021 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.controlloop.participant.intermediary.comm; + +import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantRegisterAck; +import org.onap.policy.clamp.controlloop.participant.intermediary.handler.ParticipantHandler; +import org.springframework.stereotype.Component; + +/** + * Listener for Participant Register Ack messages sent by runtime. + * + */ +@Component +public class ParticipantRegisterAckListener extends ParticipantAckListener<ParticipantRegisterAck> { + + /** + * Constructs the object. + * + * @param participantHandler the handler for managing the state of the participant + */ + public ParticipantRegisterAckListener(final ParticipantHandler participantHandler) { + super(ParticipantRegisterAck.class, participantHandler, participantHandler::handleParticipantRegisterAck); + } +} diff --git a/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/controlloop/participant/intermediary/comm/ParticipantUpdateListener.java b/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/controlloop/participant/intermediary/comm/ParticipantUpdateListener.java new file mode 100644 index 000000000..42bd52d9a --- /dev/null +++ b/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/controlloop/participant/intermediary/comm/ParticipantUpdateListener.java @@ -0,0 +1,41 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2021 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.controlloop.participant.intermediary.comm; + +import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantUpdate; +import org.onap.policy.clamp.controlloop.participant.intermediary.handler.ParticipantHandler; +import org.springframework.stereotype.Component; + +/** + * Listener for Participant Update messages sent by runtime. + */ +@Component +public class ParticipantUpdateListener extends ParticipantListener<ParticipantUpdate> { + + /** + * Constructs the object. + * + * @param participantHandler the handler for managing the state of the participant + */ + public ParticipantUpdateListener(final ParticipantHandler participantHandler) { + super(ParticipantUpdate.class, participantHandler, participantHandler::handleParticipantUpdate); + } +} diff --git a/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/controlloop/participant/intermediary/config/BeanFactory.java b/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/controlloop/participant/intermediary/config/BeanFactory.java index dc7d87eec..e363504a5 100644 --- a/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/controlloop/participant/intermediary/config/BeanFactory.java +++ b/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/controlloop/participant/intermediary/config/BeanFactory.java @@ -21,7 +21,7 @@ package org.onap.policy.clamp.controlloop.participant.intermediary.config; import java.util.List; -import org.onap.policy.clamp.controlloop.participant.intermediary.comm.ParticipantStatusPublisher; +import org.onap.policy.clamp.controlloop.participant.intermediary.comm.ParticipantMessagePublisher; import org.onap.policy.clamp.controlloop.participant.intermediary.parameters.ParticipantParameters; import org.onap.policy.common.endpoints.event.comm.TopicEndpointManager; import org.onap.policy.common.endpoints.event.comm.TopicSink; @@ -36,16 +36,16 @@ public class BeanFactory { private static final String[] MSG_TYPE_NAMES = {"messageType"}; /** - * create ParticipantStatusPublisher. + * create ParticipantMessagePublisher. * * @param parameters the ParticipantParameters - * @return ParticipantStatusPublisher + * @return ParticipantMessagePublisher */ @Bean - public ParticipantStatusPublisher publisher(final ParticipantParameters parameters) { + public ParticipantMessagePublisher publisher(final ParticipantParameters parameters) { List<TopicSink> topicSinks = TopicEndpointManager.getManager() .addTopicSinks(parameters.getIntermediaryParameters().getClampControlLoopTopics().getTopicSinks()); - return new ParticipantStatusPublisher(topicSinks); + return new ParticipantMessagePublisher(topicSinks); } @Bean diff --git a/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/controlloop/participant/intermediary/handler/IntermediaryActivator.java b/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/controlloop/participant/intermediary/handler/IntermediaryActivator.java index 2d789d40d..0aa536746 100644 --- a/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/controlloop/participant/intermediary/handler/IntermediaryActivator.java +++ b/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/controlloop/participant/intermediary/handler/IntermediaryActivator.java @@ -24,10 +24,14 @@ import java.io.Closeable; import java.io.IOException; import java.util.List; import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantMessageType; +import org.onap.policy.clamp.controlloop.participant.intermediary.api.ParticipantIntermediaryApi; import org.onap.policy.clamp.controlloop.participant.intermediary.comm.ControlLoopStateChangeListener; import org.onap.policy.clamp.controlloop.participant.intermediary.comm.ControlLoopUpdateListener; +import org.onap.policy.clamp.controlloop.participant.intermediary.comm.ParticipantDeregisterAckListener; import org.onap.policy.clamp.controlloop.participant.intermediary.comm.ParticipantHealthCheckListener; +import org.onap.policy.clamp.controlloop.participant.intermediary.comm.ParticipantRegisterAckListener; import org.onap.policy.clamp.controlloop.participant.intermediary.comm.ParticipantStateChangeListener; +import org.onap.policy.clamp.controlloop.participant.intermediary.comm.ParticipantUpdateListener; import org.onap.policy.clamp.controlloop.participant.intermediary.parameters.ParticipantParameters; import org.onap.policy.common.endpoints.event.comm.TopicEndpointManager; import org.onap.policy.common.endpoints.event.comm.TopicSource; @@ -50,14 +54,18 @@ public class IntermediaryActivator extends ServiceManagerContainer implements Cl // Topics from which the participant receives and to which the participant sends messages private List<TopicSource> topicSources; + ParticipantIntermediaryApi participantIntermediaryApi; + /** * Instantiate the activator for participant. * * @param applicationContext ApplicationContext * @param parameters the ParticipantParameters */ - public IntermediaryActivator(final ApplicationContext applicationContext, final ParticipantParameters parameters) { + public IntermediaryActivator(final ApplicationContext applicationContext, final ParticipantParameters parameters, + ParticipantIntermediaryApi participantIntermediaryApi) { this.applicationContext = applicationContext; + this.participantIntermediaryApi = participantIntermediaryApi; topicSources = TopicEndpointManager.getManager() .addTopicSources(parameters.getIntermediaryParameters().getClampControlLoopTopics().getTopicSources()); @@ -81,6 +89,7 @@ public class IntermediaryActivator extends ServiceManagerContainer implements Cl public void handleContextRefreshEvent(ContextRefreshedEvent ctxRefreshedEvent) { if (!isAlive()) { start(); + sendParticipantRegister(); } } @@ -92,10 +101,19 @@ public class IntermediaryActivator extends ServiceManagerContainer implements Cl @EventListener public void handleContextClosedEvent(ContextClosedEvent ctxClosedEvent) { if (isAlive()) { + sendParticipantDeregister(); stop(); } } + private void sendParticipantRegister() { + participantIntermediaryApi.sendParticipantRegister(); + } + + private void sendParticipantDeregister() { + participantIntermediaryApi.sendParticipantDeregister(); + } + /** * Registers the dispatcher with the topic source(s). */ @@ -114,6 +132,15 @@ public class IntermediaryActivator extends ServiceManagerContainer implements Cl msgDispatcher.register(ParticipantMessageType.PARTICIPANT_CONTROL_LOOP_UPDATE.name(), applicationContext.getBean(ControlLoopUpdateListener.class)); + msgDispatcher.register(ParticipantMessageType.PARTICIPANT_REGISTER_ACK.name(), + applicationContext.getBean(ParticipantRegisterAckListener.class)); + + msgDispatcher.register(ParticipantMessageType.PARTICIPANT_DEREGISTER_ACK.name(), + applicationContext.getBean(ParticipantDeregisterAckListener.class)); + + msgDispatcher.register(ParticipantMessageType.PARTICIPANT_UPDATE.name(), + applicationContext.getBean(ParticipantUpdateListener.class)); + for (final TopicSource source : topicSources) { source.register(msgDispatcher); } diff --git a/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/controlloop/participant/intermediary/handler/ParticipantHandler.java b/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/controlloop/participant/intermediary/handler/ParticipantHandler.java index 1c54658fa..a8913c1f0 100644 --- a/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/controlloop/participant/intermediary/handler/ParticipantHandler.java +++ b/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/controlloop/participant/intermediary/handler/ParticipantHandler.java @@ -21,22 +21,32 @@ package org.onap.policy.clamp.controlloop.participant.intermediary.handler; import java.io.Closeable; +import java.util.LinkedHashMap; +import java.util.Map; import java.util.Objects; +import java.util.UUID; import lombok.Getter; import lombok.Setter; +import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoopElementDefinition; import org.onap.policy.clamp.controlloop.models.controlloop.concepts.Participant; import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ParticipantHealthStatus; import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ParticipantState; import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ParticipantStatistics; import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantControlLoopStateChange; import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantControlLoopUpdate; +import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantDeregister; +import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantDeregisterAck; import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantHealthCheck; import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantMessage; +import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantRegister; +import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantRegisterAck; import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantResponseDetails; import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantResponseStatus; import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantStateChange; +import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantUpdate; +import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantUpdateAck; import org.onap.policy.clamp.controlloop.participant.intermediary.comm.MessageSender; -import org.onap.policy.clamp.controlloop.participant.intermediary.comm.ParticipantStatusPublisher; +import org.onap.policy.clamp.controlloop.participant.intermediary.comm.ParticipantMessagePublisher; import org.onap.policy.clamp.controlloop.participant.intermediary.parameters.ParticipantParameters; import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier; import org.slf4j.Logger; @@ -63,13 +73,15 @@ public class ParticipantHandler implements Closeable { @Setter private ParticipantHealthStatus healthStatus = ParticipantHealthStatus.UNKNOWN; + private final Map<UUID, ControlLoopElementDefinition> clElementDefsOnThisParticipant = new LinkedHashMap<>(); + /** * Constructor, set the participant ID and sender. * * @param parameters the parameters of the participant * @param publisher the publisher for sending responses to messages */ - public ParticipantHandler(ParticipantParameters parameters, ParticipantStatusPublisher publisher) { + public ParticipantHandler(ParticipantParameters parameters, ParticipantMessagePublisher publisher) { this.participantType = parameters.getIntermediaryParameters().getParticipantType(); this.participantId = parameters.getIntermediaryParameters().getParticipantId(); this.sender = @@ -249,20 +261,87 @@ public class ParticipantHandler implements Closeable { /** * Check if a participant message applies to this participant handler. * - * @param partipantMsg the message to check + * @param participantMsg the message to check * @return true if it applies, false otherwise */ - public boolean canHandle(ParticipantMessage partipantMsg) { - return partipantMsg.appliesTo(participantType, participantId); + public boolean appliesTo(ParticipantMessage participantMsg) { + return participantMsg.appliesTo(participantType, participantId); } /** - * Check if a participant message applies to this participant handler. + * Method to send ParticipantRegister message to controlloop runtime. + */ + public void sendParticipantRegister() { + var participantRegister = new ParticipantRegister(); + participantRegister.setParticipantId(participantId); + participantRegister.setParticipantType(participantType); + + sender.sendParticipantRegister(participantRegister); + } + + /** + * Handle a participantRegister Ack message. * - * @param partipantMsg the message to check - * @return true if it applies, false otherwise + * @param participantRegisterAckMsg the participantRegisterAck message + */ + public void handleParticipantRegisterAck(ParticipantRegisterAck participantRegisterAckMsg) { + LOGGER.debug("ParticipantRegisterAck message received as responseTo {}", + participantRegisterAckMsg.getResponseTo()); + } + + /** + * Method to send ParticipantDeregister message to controlloop runtime. + */ + public void sendParticipantDeregister() { + var participantDeregister = new ParticipantDeregister(); + participantDeregister.setParticipantId(participantId); + participantDeregister.setParticipantType(participantType); + + sender.sendParticipantDeregister(participantDeregister); + } + + /** + * Handle a participantDeregister Ack message. + * + * @param participantDeregisterAckMsg the participantDeregisterAck message */ - public boolean appliesTo(ParticipantMessage partipantMsg) { - return partipantMsg.appliesTo(participantType, participantId); + public void handleParticipantDeregisterAck(ParticipantDeregisterAck participantDeregisterAckMsg) { + LOGGER.debug("ParticipantDeregisterAck message received as responseTo {}", + participantDeregisterAckMsg.getResponseTo()); + } + + /** + * Handle a ParticipantUpdate message. + * + * @param participantUpdateMsg the ParticipantUpdate message + */ + public void handleParticipantUpdate(ParticipantUpdate participantUpdateMsg) { + LOGGER.debug("ParticipantUpdate message received for participantId {}", + participantUpdateMsg.getParticipantId()); + + if (!participantUpdateMsg.appliesTo(participantType, participantId)) { + return; + } + + Map<UUID, ControlLoopElementDefinition> clDefinitionMap = + participantUpdateMsg.getParticipantDefinitionUpdateMap().get(participantUpdateMsg.getParticipantId()); + + for (ControlLoopElementDefinition element : clDefinitionMap.values()) { + clElementDefsOnThisParticipant.put(element.getId(), element); + } + + sendParticipantUpdateAck(participantUpdateMsg.getMessageId()); + } + + /** + * Method to send ParticipantUpdateAck message to controlloop runtime. + */ + public void sendParticipantUpdateAck(UUID messageId) { + var participantUpdateAck = new ParticipantUpdateAck(); + participantUpdateAck.setResponseTo(messageId); + participantUpdateAck.setMessage("Participant Update Ack message"); + participantUpdateAck.setResult(true); + + sender.sendParticipantUpdateAck(participantUpdateAck); } } diff --git a/participant/participant-intermediary/src/test/java/org/onap/policy/clamp/controlloop/participant/intermediary/main/parameters/CommonTestData.java b/participant/participant-intermediary/src/test/java/org/onap/policy/clamp/controlloop/participant/intermediary/main/parameters/CommonTestData.java new file mode 100644 index 000000000..93ba15846 --- /dev/null +++ b/participant/participant-intermediary/src/test/java/org/onap/policy/clamp/controlloop/participant/intermediary/main/parameters/CommonTestData.java @@ -0,0 +1,113 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2021 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.controlloop.participant.intermediary.main.parameters; + +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; +import org.onap.policy.clamp.controlloop.participant.intermediary.parameters.ParticipantIntermediaryParameters; +import org.onap.policy.common.endpoints.parameters.TopicParameters; +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.tosca.authorative.concepts.ToscaConceptIdentifier; + +/** + * Class to hold/create all parameters for test cases. + */ +public class CommonTestData { + public static final String PARTICIPANT_GROUP_NAME = "ControlLoopParticipantGroup"; + public static final String DESCRIPTION = "Participant description"; + public static final long TIME_INTERVAL = 2000; + public static final List<TopicParameters> TOPIC_PARAMS = Arrays.asList(getTopicParams()); + + public static final Coder CODER = new StandardCoder(); + + /** + * Get ParticipantIntermediaryParameters. + * + * @return ParticipantIntermediaryParameters + */ + public ParticipantIntermediaryParameters getParticipantIntermediaryParameters() { + try { + return CODER.convert(getIntermediaryParametersMap(PARTICIPANT_GROUP_NAME), + ParticipantIntermediaryParameters.class); + } catch (final CoderException e) { + throw new RuntimeException("cannot create ParticipantSimulatorParameters from map", e); + } + } + + /** + * Returns a property map for a intermediaryParameters map for test cases. + * + * @param name name of the parameters + * @return a property map suitable for constructing an object + */ + public Map<String, Object> getIntermediaryParametersMap(final String name) { + final Map<String, Object> map = new TreeMap<>(); + map.put("name", name); + map.put("participantId", getParticipantId()); + map.put("description", DESCRIPTION); + map.put("participantType", getParticipantId()); + map.put("reportingTimeInterval", TIME_INTERVAL); + map.put("clampControlLoopTopics", getTopicParametersMap(false)); + + return map; + } + + /** + * Returns a property map for a TopicParameters map for test cases. + * + * @param isEmpty boolean value to represent that object created should be empty or not + * @return a property map suitable for constructing an object + */ + public Map<String, Object> getTopicParametersMap(final boolean isEmpty) { + final Map<String, Object> map = new TreeMap<>(); + if (!isEmpty) { + map.put("topicSources", TOPIC_PARAMS); + map.put("topicSinks", TOPIC_PARAMS); + } + return map; + } + + /** + * Returns topic parameters for test cases. + * + * @return topic parameters + */ + public static TopicParameters getTopicParams() { + final TopicParameters topicParams = new TopicParameters(); + topicParams.setTopic("POLICY-CLRUNTIME-PARTICIPANT"); + topicParams.setTopicCommInfrastructure("dmaap"); + topicParams.setServers(Arrays.asList("localhost")); + return topicParams; + } + + /** + * Returns participantId for test cases. + * + * @return participant Id + */ + public static ToscaConceptIdentifier getParticipantId() { + return new ToscaConceptIdentifier("org.onap.PM_CDS_Blueprint", "1.0.1"); + } +} diff --git a/participant/participant-intermediary/src/test/java/org/onap/policy/clamp/controlloop/participant/intermediary/main/parameters/TestParticipantIntermediaryParameters.java b/participant/participant-intermediary/src/test/java/org/onap/policy/clamp/controlloop/participant/intermediary/main/parameters/TestParticipantIntermediaryParameters.java new file mode 100644 index 000000000..d554a55b6 --- /dev/null +++ b/participant/participant-intermediary/src/test/java/org/onap/policy/clamp/controlloop/participant/intermediary/main/parameters/TestParticipantIntermediaryParameters.java @@ -0,0 +1,67 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2021 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.controlloop.participant.intermediary.main.parameters; + +import static org.assertj.core.api.Assertions.assertThat; + +import javax.validation.Validation; +import javax.validation.ValidatorFactory; +import org.junit.jupiter.api.Test; +import org.onap.policy.clamp.controlloop.participant.intermediary.parameters.ParticipantIntermediaryParameters; + +/** + * Class to perform unit test of {@link ParticipantParameterGroup}. + */ +class TestParticipantIntermediaryParameters { + private CommonTestData commonTestData = new CommonTestData(); + private ValidatorFactory validatorFactory = Validation.buildDefaultValidatorFactory(); + + @Test + void testParticipantIntermediaryParameterGroup() { + final ParticipantIntermediaryParameters participantParameters = + commonTestData.getParticipantIntermediaryParameters(); + assertThat(validatorFactory.getValidator().validate(participantParameters)).isEmpty(); + } + + @Test + void testParticipantIntermediaryParameterGroup_EmptyParameter() { + final ParticipantIntermediaryParameters participantParameters = + commonTestData.getParticipantIntermediaryParameters(); + participantParameters.setClampControlLoopTopics(null); + assertThat(validatorFactory.getValidator().validate(participantParameters)).isNotEmpty(); + } + + @Test + void testParticipantIntermediaryParameters_NullTopicSinks() { + final ParticipantIntermediaryParameters participantParameters = + commonTestData.getParticipantIntermediaryParameters(); + participantParameters.getClampControlLoopTopics().setTopicSinks(null); + assertThat(validatorFactory.getValidator().validate(participantParameters)).isNotEmpty(); + } + + @Test + void testParticipantIntermediaryParameters_NullTopicSources() { + final ParticipantIntermediaryParameters participantParameters = + commonTestData.getParticipantIntermediaryParameters(); + participantParameters.getClampControlLoopTopics().setTopicSources(null); + assertThat(validatorFactory.getValidator().validate(participantParameters)).isNotEmpty(); + } +} @@ -57,6 +57,7 @@ <modules> <module>common</module> <module>models</module> + <module>packages</module> <module>runtime</module> <module>runtime-controlloop</module> <module>participant</module> diff --git a/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/Application.java b/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/Application.java index a2b6f62d4..6b772513c 100644 --- a/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/Application.java +++ b/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/Application.java @@ -22,8 +22,11 @@ package org.onap.policy.clamp.controlloop.runtime; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.ComponentScan; @SpringBootApplication +@ComponentScan({"org.onap.policy.clamp.controlloop.models.controlloop.persistence.provider", + "org.onap.policy.clamp.controlloop.runtime"}) public class Application { public static void main(String[] args) { diff --git a/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/commissioning/CommissioningProvider.java b/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/commissioning/CommissioningProvider.java index e5dccde7b..d9dee50bc 100644 --- a/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/commissioning/CommissioningProvider.java +++ b/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/commissioning/CommissioningProvider.java @@ -25,8 +25,6 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.PropertyNamingStrategies; import com.fasterxml.jackson.module.jsonSchema.JsonSchema; import com.fasterxml.jackson.module.jsonSchema.factories.SchemaFactoryWrapper; -import java.io.Closeable; -import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -36,11 +34,8 @@ import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.collections4.MapUtils; import org.onap.policy.clamp.controlloop.models.controlloop.persistence.provider.ControlLoopProvider; import org.onap.policy.clamp.controlloop.models.messages.rest.commissioning.CommissioningResponse; -import org.onap.policy.clamp.controlloop.runtime.main.parameters.ClRuntimeParameterGroup; import org.onap.policy.models.base.PfModelException; -import org.onap.policy.models.base.PfModelRuntimeException; import org.onap.policy.models.provider.PolicyModelsProvider; -import org.onap.policy.models.provider.PolicyModelsProviderFactory; import org.onap.policy.models.tosca.authorative.concepts.ToscaCapabilityType; import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier; import org.onap.policy.models.tosca.authorative.concepts.ToscaDataType; @@ -59,7 +54,7 @@ import org.springframework.stereotype.Component; * the callers. */ @Component -public class CommissioningProvider implements Closeable { +public class CommissioningProvider { public static final String CONTROL_LOOP_NODE_TYPE = "org.onap.policy.clamp.controlloop.ControlLoop"; private final PolicyModelsProvider modelsProvider; @@ -70,32 +65,12 @@ public class CommissioningProvider implements Closeable { /** * Create a commissioning provider. * - * @param controlLoopParameters the parameters for access to the database - * @throws PfModelRuntimeException on errors creating the database provider + * @param modelsProvider the PolicyModelsProvider + * @param clProvider the ControlLoopProvider */ - public CommissioningProvider(ClRuntimeParameterGroup controlLoopParameters) { - try { - modelsProvider = new PolicyModelsProviderFactory() - .createPolicyModelsProvider(controlLoopParameters.getDatabaseProviderParameters()); - } catch (PfModelException e) { - throw new PfModelRuntimeException(e); - } - - try { - clProvider = new ControlLoopProvider(controlLoopParameters.getDatabaseProviderParameters()); - } catch (PfModelException e) { - throw new PfModelRuntimeException(e); - } - } - - @Override - public void close() throws IOException { - try { - modelsProvider.close(); - clProvider.close(); - } catch (PfModelException e) { - throw new IOException("error closing modelsProvider", e); - } + public CommissioningProvider(PolicyModelsProvider modelsProvider, ControlLoopProvider clProvider) { + this.modelsProvider = modelsProvider; + this.clProvider = clProvider; } /** diff --git a/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/config/ActivatorConfig.java b/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/config/PolicyModelConfig.java index 1d6b92e77..8a151d886 100644 --- a/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/config/ActivatorConfig.java +++ b/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/config/PolicyModelConfig.java @@ -21,26 +21,25 @@ package org.onap.policy.clamp.controlloop.runtime.config; import org.onap.policy.clamp.controlloop.runtime.main.parameters.ClRuntimeParameterGroup; -import org.onap.policy.clamp.controlloop.runtime.main.startstop.ClRuntimeActivator; -import org.onap.policy.clamp.controlloop.runtime.supervision.SupervisionHandler; +import org.onap.policy.models.base.PfModelException; +import org.onap.policy.models.provider.PolicyModelsProvider; +import org.onap.policy.models.provider.PolicyModelsProviderFactory; +import org.onap.policy.models.provider.PolicyModelsProviderParameters; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration -public class ActivatorConfig { +public class PolicyModelConfig { - /** - * Create and start ClRuntimeActivator. - * - * @param clRuntimeParameterGroup the parameters for the control loop runtime service - * @param supervisionHandler the SupervisionHandler - * @return ClRuntimeActivator - */ @Bean - public ClRuntimeActivator clRuntimeActivator(ClRuntimeParameterGroup clRuntimeParameterGroup, - SupervisionHandler supervisionHandler) { - var clRuntimeActivator = new ClRuntimeActivator(clRuntimeParameterGroup, supervisionHandler); - clRuntimeActivator.start(); - return clRuntimeActivator; + public PolicyModelsProviderParameters policyModelsProviderParameters( + ClRuntimeParameterGroup clRuntimeParameterGroup) { + return clRuntimeParameterGroup.getDatabaseProviderParameters(); + } + + @Bean + public PolicyModelsProvider policyModelsProvider(PolicyModelsProviderParameters policyModelsProviderParameters) + throws PfModelException { + return new PolicyModelsProviderFactory().createPolicyModelsProvider(policyModelsProviderParameters); } } diff --git a/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/config/messaging/Listener.java b/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/config/messaging/Listener.java new file mode 100644 index 000000000..b67ddf2a7 --- /dev/null +++ b/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/config/messaging/Listener.java @@ -0,0 +1,40 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2021 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.controlloop.runtime.config.messaging; + +import org.onap.policy.common.endpoints.listeners.ScoListener; + +public interface Listener { + + /** + * Get the type of message of interest to the listener. + * + * @return type of message of interest to the listener + */ + String getType(); + + /** + * Get listener to register. + * + * @return listener to register + */ + <T> ScoListener<T> getScoListener(); +} diff --git a/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/main/startstop/ClRuntimeActivator.java b/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/config/messaging/MessageDispatcherActivator.java index 323f76178..891dab9ae 100644 --- a/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/main/startstop/ClRuntimeActivator.java +++ b/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/config/messaging/MessageDispatcherActivator.java @@ -18,53 +18,47 @@ * ============LICENSE_END========================================================= */ -package org.onap.policy.clamp.controlloop.runtime.main.startstop; +package org.onap.policy.clamp.controlloop.runtime.config.messaging; import java.io.Closeable; import java.io.IOException; import java.util.List; +import java.util.stream.Stream; import javax.ws.rs.core.Response.Status; import lombok.Getter; import org.onap.policy.clamp.controlloop.common.exception.ControlLoopRuntimeException; import org.onap.policy.clamp.controlloop.runtime.main.parameters.ClRuntimeParameterGroup; -import org.onap.policy.clamp.controlloop.runtime.supervision.SupervisionHandler; import org.onap.policy.common.endpoints.event.comm.TopicEndpointManager; import org.onap.policy.common.endpoints.event.comm.TopicSink; import org.onap.policy.common.endpoints.event.comm.TopicSource; import org.onap.policy.common.endpoints.listeners.MessageTypeDispatcher; import org.onap.policy.common.utils.services.ServiceManagerContainer; +import org.springframework.context.event.ContextRefreshedEvent; +import org.springframework.context.event.EventListener; +import org.springframework.stereotype.Component; -/** - * This class activates the control loop runtime component as a complete service together with all its controllers, - * listeners & handlers. - */ -public class ClRuntimeActivator extends ServiceManagerContainer implements Closeable { - // Name of the message type for messages on topics - private static final String[] MSG_TYPE_NAMES = {"messageType"}; +@Component +public class MessageDispatcherActivator extends ServiceManagerContainer implements Closeable { - @Getter - private final ClRuntimeParameterGroup parameterGroup; + private static final String[] MSG_TYPE_NAMES = {"messageType"}; // Topics from which the application receives and to which the application sends messages private List<TopicSink> topicSinks; private List<TopicSource> topicSources; - /** - * Listens for messages on the topic, decodes them into a message, and then dispatches them. - */ + @Getter private final MessageTypeDispatcher msgDispatcher; /** - * Instantiate the activator for the control loop runtime as a complete service. + * Constructor. * * @param clRuntimeParameterGroup the parameters for the control loop runtime service - * @param supervisionHandler SupervisionHandler + * @param publishers array of Publishers + * @param listeners array of Listeners * @throws ControlLoopRuntimeException if the activator does not start */ - public ClRuntimeActivator(final ClRuntimeParameterGroup clRuntimeParameterGroup, - SupervisionHandler supervisionHandler) { - this.parameterGroup = clRuntimeParameterGroup; - + public MessageDispatcherActivator(final ClRuntimeParameterGroup clRuntimeParameterGroup, Publisher[] publishers, + Listener[] listeners) { topicSinks = TopicEndpointManager.getManager() .addTopicSinks(clRuntimeParameterGroup.getTopicParameterGroup().getTopicSinks()); @@ -80,15 +74,18 @@ public class ClRuntimeActivator extends ServiceManagerContainer implements Close // @formatter:off addAction("Topic endpoint management", - () -> TopicEndpointManager.getManager().start(), - () -> TopicEndpointManager.getManager().shutdown()); + () -> TopicEndpointManager.getManager().start(), + () -> TopicEndpointManager.getManager().shutdown()); - addAction("Supervision Providers", () -> supervisionHandler.startProviders(), - () -> supervisionHandler.stopProviders()); - addAction("Supervision Listeners", () -> supervisionHandler.startAndRegisterListeners(msgDispatcher), - () -> supervisionHandler.stopAndUnregisterListeners(msgDispatcher)); - addAction("Supervision Publishers", () -> supervisionHandler.startAndRegisterPublishers(topicSinks), - () -> supervisionHandler.stopAndUnregisterPublishers()); + Stream.of(publishers).forEach(publisher -> + addAction("Publisher " + publisher.getClass().getSimpleName(), + () -> publisher.active(topicSinks), + () -> publisher.stop())); + + Stream.of(listeners).forEach(listener -> + addAction("Listener " + listener.getClass().getSimpleName(), + () -> msgDispatcher.register(listener.getType(), listener.getScoListener()), + () -> msgDispatcher.unregister(listener.getType()))); addAction("Topic Message Dispatcher", this::registerMsgDispatcher, this::unregisterMsgDispatcher); // @formatter:on @@ -112,6 +109,18 @@ public class ClRuntimeActivator extends ServiceManagerContainer implements Close } } + /** + * Start Manager after the application is Started. + * + * @param cre Refreshed Event + */ + @EventListener + public void handleContextStart(ContextRefreshedEvent cre) { + if (!isAlive()) { + start(); + } + } + @Override public void close() throws IOException { if (isAlive()) { diff --git a/common/src/main/java/org/onap/policy/clamp/controlloop/common/ControlLoopConstants.java b/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/config/messaging/Publisher.java index aa8b720bc..3cd4dff85 100644 --- a/common/src/main/java/org/onap/policy/clamp/controlloop/common/ControlLoopConstants.java +++ b/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/config/messaging/Publisher.java @@ -1,6 +1,6 @@ -/* +/*- * ============LICENSE_START======================================================= - * Copyright (C) 2021 Nordix Foundation. + * Copyright (C) 2021 Nordix Foundation. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,20 +13,22 @@ * 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.controlloop.common; +package org.onap.policy.clamp.controlloop.runtime.config.messaging; + +import java.util.List; +import org.onap.policy.common.endpoints.event.comm.TopicSink; /** - * Names of various items contained in the Registry. + * Publisher. */ -public class ControlLoopConstants { +public interface Publisher { - // Registry keys - public static final String REG_CLRUNTIME_ACTIVATOR = "object:activator/clruntime"; + void active(List<TopicSink> topicSinks); - private ControlLoopConstants() { - super(); - } + void stop(); } diff --git a/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/instantiation/ControlLoopInstantiationProvider.java b/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/instantiation/ControlLoopInstantiationProvider.java index c01a0b989..1011f620c 100644 --- a/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/instantiation/ControlLoopInstantiationProvider.java +++ b/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/instantiation/ControlLoopInstantiationProvider.java @@ -20,8 +20,6 @@ package org.onap.policy.clamp.controlloop.runtime.instantiation; -import java.io.Closeable; -import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -30,6 +28,7 @@ import java.util.function.UnaryOperator; import java.util.stream.Collectors; import javax.ws.rs.core.Response; import javax.ws.rs.core.Response.Status; +import lombok.AllArgsConstructor; import org.onap.policy.clamp.controlloop.common.exception.ControlLoopException; import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoop; import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoopElement; @@ -39,14 +38,12 @@ import org.onap.policy.clamp.controlloop.models.controlloop.persistence.provider import org.onap.policy.clamp.controlloop.models.messages.rest.instantiation.InstantiationCommand; import org.onap.policy.clamp.controlloop.models.messages.rest.instantiation.InstantiationResponse; import org.onap.policy.clamp.controlloop.runtime.commissioning.CommissioningProvider; -import org.onap.policy.clamp.controlloop.runtime.main.parameters.ClRuntimeParameterGroup; import org.onap.policy.clamp.controlloop.runtime.supervision.SupervisionHandler; import org.onap.policy.common.parameters.BeanValidationResult; import org.onap.policy.common.parameters.ObjectValidationResult; import org.onap.policy.common.parameters.ValidationResult; import org.onap.policy.common.parameters.ValidationStatus; import org.onap.policy.models.base.PfModelException; -import org.onap.policy.models.base.PfModelRuntimeException; import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier; import org.onap.policy.models.tosca.authorative.concepts.ToscaNodeTemplate; import org.springframework.stereotype.Component; @@ -55,7 +52,8 @@ import org.springframework.stereotype.Component; * This class is dedicated to the Instantiation of Commissioned control loop. */ @Component -public class ControlLoopInstantiationProvider implements Closeable { +@AllArgsConstructor +public class ControlLoopInstantiationProvider { private final ControlLoopProvider controlLoopProvider; private final CommissioningProvider commissioningProvider; private final SupervisionHandler supervisionHandler; @@ -63,30 +61,6 @@ public class ControlLoopInstantiationProvider implements Closeable { private static final Object lockit = new Object(); /** - * Create a instantiation provider. - * - * @param controlLoopParameters the parameters for access to the database - * @param commissioningProvider CommissioningProvider - * @param supervisionHandler SupervisionHandler - * @throws PfModelRuntimeException on errors creating a provider - */ - public ControlLoopInstantiationProvider(ClRuntimeParameterGroup controlLoopParameters, - CommissioningProvider commissioningProvider, SupervisionHandler supervisionHandler) { - this.commissioningProvider = commissioningProvider; - this.supervisionHandler = supervisionHandler; - try { - controlLoopProvider = new ControlLoopProvider(controlLoopParameters.getDatabaseProviderParameters()); - } catch (PfModelException e) { - throw new PfModelRuntimeException(e); - } - } - - @Override - public void close() throws IOException { - controlLoopProvider.close(); - } - - /** * Create control loops. * * @param controlLoops the control loop diff --git a/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/main/parameters/ClRuntimeParameterGroup.java b/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/main/parameters/ClRuntimeParameterGroup.java index d1fa31261..433eeeebb 100644 --- a/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/main/parameters/ClRuntimeParameterGroup.java +++ b/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/main/parameters/ClRuntimeParameterGroup.java @@ -45,6 +45,9 @@ public class ClRuntimeParameterGroup extends ParameterGroupImpl { private long participantStateChangeIntervalSec; private long participantClUpdateIntervalSec; private long participantClStateChangeIntervalSec; + private long participantRegisterAckIntervalSec; + private long participantDeregisterAckIntervalSec; + private long participantUpdateIntervalSec; /** * Create the Control Loop parameter group. diff --git a/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/monitoring/MonitoringProvider.java b/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/monitoring/MonitoringProvider.java index a68505877..1f6246bd6 100644 --- a/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/monitoring/MonitoringProvider.java +++ b/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/monitoring/MonitoringProvider.java @@ -20,13 +20,12 @@ package org.onap.policy.clamp.controlloop.runtime.monitoring; -import java.io.Closeable; -import java.io.IOException; import java.time.Instant; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import lombok.AllArgsConstructor; import lombok.NonNull; import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ClElementStatistics; import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ClElementStatisticsList; @@ -36,7 +35,6 @@ import org.onap.policy.clamp.controlloop.models.controlloop.concepts.Participant import org.onap.policy.clamp.controlloop.models.controlloop.persistence.provider.ClElementStatisticsProvider; import org.onap.policy.clamp.controlloop.models.controlloop.persistence.provider.ControlLoopProvider; import org.onap.policy.clamp.controlloop.models.controlloop.persistence.provider.ParticipantStatisticsProvider; -import org.onap.policy.clamp.controlloop.runtime.main.parameters.ClRuntimeParameterGroup; import org.onap.policy.models.base.PfModelException; import org.onap.policy.models.base.PfModelRuntimeException; import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier; @@ -46,7 +44,8 @@ import org.springframework.stereotype.Component; * This class provides information about statistics data of CL elements and CL Participants in database to callers. */ @Component -public class MonitoringProvider implements Closeable { +@AllArgsConstructor +public class MonitoringProvider { private static final String DESC_ORDER = "DESC"; private final ParticipantStatisticsProvider participantStatisticsProvider; @@ -54,32 +53,6 @@ public class MonitoringProvider implements Closeable { private final ControlLoopProvider controlLoopProvider; /** - * Create a Monitoring provider. - * - * @param controlLoopParameters the parameters for access to the database - * @throws PfModelRuntimeException on errors creating the provider - */ - public MonitoringProvider(ClRuntimeParameterGroup controlLoopParameters) { - - try { - participantStatisticsProvider = - new ParticipantStatisticsProvider(controlLoopParameters.getDatabaseProviderParameters()); - clElementStatisticsProvider = - new ClElementStatisticsProvider(controlLoopParameters.getDatabaseProviderParameters()); - controlLoopProvider = new ControlLoopProvider(controlLoopParameters.getDatabaseProviderParameters()); - } catch (PfModelException e) { - throw new PfModelRuntimeException(e); - } - } - - @Override - public void close() throws IOException { - controlLoopProvider.close(); - clElementStatisticsProvider.close(); - participantStatisticsProvider.close(); - } - - /** * Create participant statistics. * * @param participantStatistics the participant statistics diff --git a/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/supervision/SupervisionHandler.java b/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/supervision/SupervisionHandler.java index e1b4be48b..5e94d293e 100644 --- a/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/supervision/SupervisionHandler.java +++ b/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/supervision/SupervisionHandler.java @@ -20,31 +20,42 @@ package org.onap.policy.clamp.controlloop.runtime.supervision; +import java.time.Instant; +import java.util.LinkedHashMap; import java.util.List; +import java.util.Map; import java.util.UUID; import javax.ws.rs.core.Response; -import javax.ws.rs.core.Response.Status; +import lombok.AllArgsConstructor; import org.apache.commons.collections4.CollectionUtils; import org.onap.policy.clamp.controlloop.common.exception.ControlLoopException; -import org.onap.policy.clamp.controlloop.common.exception.ControlLoopRuntimeException; -import org.onap.policy.clamp.controlloop.common.handler.ControlLoopHandler; import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoop; import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoopElement; +import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoopElementDefinition; import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoopState; import org.onap.policy.clamp.controlloop.models.controlloop.concepts.Participant; import org.onap.policy.clamp.controlloop.models.controlloop.persistence.provider.ControlLoopProvider; import org.onap.policy.clamp.controlloop.models.controlloop.persistence.provider.ParticipantProvider; import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantControlLoopStateChange; import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantControlLoopUpdate; +import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantDeregister; +import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantDeregisterAck; import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantMessageType; +import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantRegister; +import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantRegisterAck; import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantStatus; +import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantUpdate; +import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantUpdateAck; import org.onap.policy.clamp.controlloop.runtime.commissioning.CommissioningProvider; import org.onap.policy.clamp.controlloop.runtime.main.parameters.ClRuntimeParameterGroup; import org.onap.policy.clamp.controlloop.runtime.monitoring.MonitoringProvider; import org.onap.policy.clamp.controlloop.runtime.supervision.comm.ParticipantControlLoopStateChangePublisher; import org.onap.policy.clamp.controlloop.runtime.supervision.comm.ParticipantControlLoopUpdatePublisher; +import org.onap.policy.clamp.controlloop.runtime.supervision.comm.ParticipantDeregisterAckPublisher; +import org.onap.policy.clamp.controlloop.runtime.supervision.comm.ParticipantRegisterAckPublisher; import org.onap.policy.clamp.controlloop.runtime.supervision.comm.ParticipantStateChangePublisher; import org.onap.policy.clamp.controlloop.runtime.supervision.comm.ParticipantStatusListener; +import org.onap.policy.clamp.controlloop.runtime.supervision.comm.ParticipantUpdatePublisher; import org.onap.policy.common.endpoints.event.comm.TopicSink; import org.onap.policy.common.endpoints.listeners.MessageTypeDispatcher; import org.onap.policy.common.utils.services.ServiceManager; @@ -58,10 +69,12 @@ import org.springframework.stereotype.Component; /** * This class handles supervision of control loop instances, so only one object of this type should be built at a time. * - * <p/> It is effectively a singleton that is started at system start. + * <p/> + * It is effectively a singleton that is started at system start. */ @Component -public class SupervisionHandler extends ControlLoopHandler { +@AllArgsConstructor +public class SupervisionHandler { private static final Logger LOGGER = LoggerFactory.getLogger(SupervisionHandler.class); private static final String CONTROL_LOOP_CANNOT_TRANSITION_FROM_STATE = "Control loop can't transition from state "; @@ -69,59 +82,17 @@ public class SupervisionHandler extends ControlLoopHandler { private static final String TO_STATE = " to state "; private static final String AND_TRANSITIONING_TO_STATE = " and transitioning to state "; - private ControlLoopProvider controlLoopProvider; - private ParticipantProvider participantProvider; + private final ControlLoopProvider controlLoopProvider; + private final ParticipantProvider participantProvider; private final MonitoringProvider monitoringProvider; private final CommissioningProvider commissioningProvider; // Publishers for participant communication - private ParticipantStateChangePublisher stateChangePublisher; - private ParticipantControlLoopUpdatePublisher controlLoopUpdatePublisher; - private ParticipantControlLoopStateChangePublisher controlLoopStateChangePublisher; - - private long supervisionScannerIntervalSec; - private long participantStateChangeIntervalSec; - private long participantClUpdateIntervalSec; - private long participantClStateChangeIntervalSec; - - // Database scanner - private SupervisionScanner scanner; - - /** - * Used to manage the services. - */ - private ServiceManager manager; - private ServiceManager publisherManager; - - /** - * Create a handler. - * - * @param clRuntimeParameterGroup the parameters for the control loop runtime - * @param monitoringProvider the MonitoringProvider - * @param commissioningProvider the CommissioningProvider - */ - public SupervisionHandler(ClRuntimeParameterGroup clRuntimeParameterGroup, MonitoringProvider monitoringProvider, - CommissioningProvider commissioningProvider) { - super(clRuntimeParameterGroup.getDatabaseProviderParameters()); - this.monitoringProvider = monitoringProvider; - this.commissioningProvider = commissioningProvider; - - // @formatter:off - this.manager = new ServiceManager() - .addAction("ControlLoop Provider", - () -> controlLoopProvider = new ControlLoopProvider(getDatabaseProviderParameters()), - () -> controlLoopProvider = null) - .addAction("Participant Provider", - () -> participantProvider = new ParticipantProvider(getDatabaseProviderParameters()), - () -> participantProvider = null); - // @formatter:on - - supervisionScannerIntervalSec = clRuntimeParameterGroup.getSupervisionScannerIntervalSec(); - participantStateChangeIntervalSec = clRuntimeParameterGroup.getParticipantClStateChangeIntervalSec(); - participantClUpdateIntervalSec = clRuntimeParameterGroup.getParticipantClUpdateIntervalSec(); - participantClStateChangeIntervalSec = clRuntimeParameterGroup.getParticipantClStateChangeIntervalSec(); - - } + private final ParticipantControlLoopUpdatePublisher controlLoopUpdatePublisher; + private final ParticipantControlLoopStateChangePublisher controlLoopStateChangePublisher; + private final ParticipantRegisterAckPublisher participantRegisterAckPublisher; + private final ParticipantDeregisterAckPublisher participantDeregisterAckPublisher; + private final ParticipantUpdatePublisher participantUpdatePublisher; /** * Supervision trigger called when a command is issued on control loops. @@ -155,63 +126,13 @@ public class SupervisionHandler extends ControlLoopHandler { } } - @Override - public void startAndRegisterListeners(MessageTypeDispatcher msgDispatcher) { - msgDispatcher.register(ParticipantMessageType.PARTICIPANT_STATUS.name(), new ParticipantStatusListener(this)); - } - - @Override - public void startAndRegisterPublishers(List<TopicSink> topicSinks) { - // @formatter:off - this.publisherManager = new ServiceManager() - .addAction("Supervision scanner", - () -> scanner = - new SupervisionScanner(controlLoopProvider, supervisionScannerIntervalSec), - () -> scanner.close()) - .addAction("ControlLoopUpdate publisher", - () -> controlLoopUpdatePublisher = - new ParticipantControlLoopUpdatePublisher(topicSinks, participantClUpdateIntervalSec), - () -> controlLoopUpdatePublisher.terminate()) - .addAction("StateChange Publisher", - () -> stateChangePublisher = - new ParticipantStateChangePublisher(topicSinks, participantStateChangeIntervalSec), - () -> stateChangePublisher.terminate()) - .addAction("ControlLoopStateChange Publisher", - () -> controlLoopStateChangePublisher = - new ParticipantControlLoopStateChangePublisher(topicSinks, participantClStateChangeIntervalSec), - () -> controlLoopStateChangePublisher.terminate()); - // @formatter:on - try { - publisherManager.start(); - } catch (final ServiceManagerException exp) { - throw new ControlLoopRuntimeException(Status.INTERNAL_SERVER_ERROR, - "Supervision handler start of publishers or scanner failed", exp); - } - } - - @Override - public void stopAndUnregisterPublishers() { - try { - publisherManager.stop(); - } catch (final ServiceManagerException exp) { - throw new ControlLoopRuntimeException(Status.INTERNAL_SERVER_ERROR, - "Supervision handler stop of publishers or scanner failed", exp); - } - } - - @Override - public void stopAndUnregisterListeners(MessageTypeDispatcher msgDispatcher) { - msgDispatcher.unregister(ParticipantMessageType.PARTICIPANT_STATUS.name()); - } - /** * Handle a ParticipantStatus message from a participant. * * @param participantStatusMessage the ParticipantStatus message received from a participant */ - public void handleParticipantStatusMessage(ParticipantStatus participantStatusMessage) { + public void handleParticipantMessage(ParticipantStatus participantStatusMessage) { LOGGER.debug("Participant Status received {}", participantStatusMessage); - try { superviseParticipant(participantStatusMessage); } catch (PfModelException | ControlLoopException svExc) { @@ -227,6 +148,36 @@ public class SupervisionHandler extends ControlLoopHandler { } /** + * Handle a ParticipantRegister message from a participant. + * + * @param participantRegisterMessage the ParticipantRegister message received from a participant + */ + public void handleParticipantMessage(ParticipantRegister participantRegisterMessage) { + LOGGER.debug("Participant Register received {}", participantRegisterMessage); + sendParticipantAckMessage(participantRegisterMessage); + sendParticipantUpdate(participantRegisterMessage); + } + + /** + * Handle a ParticipantDeregister message from a participant. + * + * @param participantDeregisterMessage the ParticipantDeregister message received from a participant + */ + public void handleParticipantMessage(ParticipantDeregister participantDeregisterMessage) { + LOGGER.debug("Participant Deregister received {}", participantDeregisterMessage); + sendParticipantAckMessage(participantDeregisterMessage); + } + + /** + * Handle a ParticipantUpdateAck message from a participant. + * + * @param participantUpdateAckMessage the ParticipantUpdateAck message received from a participant + */ + public void handleParticipantMessage(ParticipantUpdateAck participantUpdateAckMessage) { + LOGGER.debug("Participant Update Ack received {}", participantUpdateAckMessage); + } + + /** * Supervise a control loop, performing whatever actions need to be performed on the control loop. * * @param controlLoop the control loop to supervises @@ -270,7 +221,7 @@ public class SupervisionHandler extends ControlLoopHandler { case UNINITIALISED2PASSIVE: case PASSIVE: controlLoop.setState(ControlLoopState.PASSIVE2UNINITIALISED); - sendControlLoopStateChange(controlLoop); + controlLoopStateChangePublisher.send(controlLoop); break; case PASSIVE2UNINITIALISED: @@ -294,7 +245,7 @@ public class SupervisionHandler extends ControlLoopHandler { break; case UNINITIALISED: controlLoop.setState(ControlLoopState.UNINITIALISED2PASSIVE); - sendControlLoopUpdate(controlLoop); + controlLoopUpdatePublisher.send(controlLoop); break; case UNINITIALISED2PASSIVE: @@ -305,7 +256,7 @@ public class SupervisionHandler extends ControlLoopHandler { case RUNNING: controlLoop.setState(ControlLoopState.RUNNING2PASSIVE); - sendControlLoopStateChange(controlLoop); + controlLoopStateChangePublisher.send(controlLoop); break; default: @@ -329,7 +280,7 @@ public class SupervisionHandler extends ControlLoopHandler { case PASSIVE: controlLoop.setState(ControlLoopState.PASSIVE2RUNNING); - sendControlLoopStateChange(controlLoop); + controlLoopStateChangePublisher.send(controlLoop); break; default: @@ -354,10 +305,55 @@ public class SupervisionHandler extends ControlLoopHandler { clsc.setControlLoopId(controlLoop.getKey().asIdentifier()); clsc.setMessageId(UUID.randomUUID()); clsc.setOrderedState(controlLoop.getOrderedState()); - controlLoopStateChangePublisher.send(clsc); } + private void sendParticipantUpdate(ParticipantRegister participantRegisterMessage) { + var message = new ParticipantUpdate(); + message.setParticipantId(participantRegisterMessage.getParticipantId()); + message.setParticipantType(participantRegisterMessage.getParticipantType()); + message.setTimestamp(Instant.now()); + + ControlLoopElementDefinition clDefinition = new ControlLoopElementDefinition(); + clDefinition.setId(UUID.randomUUID()); + + try { + clDefinition.setControlLoopElementToscaServiceTemplate(commissioningProvider + .getToscaServiceTemplate(null, null)); + } catch (PfModelException pfme) { + LOGGER.warn("Get of tosca service template failed, cannot send participantupdate", pfme); + return; + } + + Map<UUID, ControlLoopElementDefinition> controlLoopElementDefinitionMap = new LinkedHashMap<>(); + controlLoopElementDefinitionMap.put(UUID.randomUUID(), clDefinition); + + Map<ToscaConceptIdentifier, Map<UUID, ControlLoopElementDefinition>> + participantDefinitionUpdateMap = new LinkedHashMap<>(); + participantDefinitionUpdateMap.put(participantRegisterMessage.getParticipantId(), + controlLoopElementDefinitionMap); + message.setParticipantDefinitionUpdateMap(participantDefinitionUpdateMap); + + LOGGER.debug("Participant Update sent", message); + participantUpdatePublisher.send(message); + } + + private void sendParticipantAckMessage(ParticipantRegister participantRegisterMessage) { + var message = new ParticipantRegisterAck(); + message.setResponseTo(participantRegisterMessage.getMessageId()); + message.setMessage("Participant Register Ack"); + message.setResult(true); + participantRegisterAckPublisher.send(message); + } + + private void sendParticipantAckMessage(ParticipantDeregister participantDeregisterMessage) { + var message = new ParticipantDeregisterAck(); + message.setResponseTo(participantDeregisterMessage.getMessageId()); + message.setMessage("Participant Deregister Ack"); + message.setResult(true); + participantDeregisterAckPublisher.send(message); + } + private void superviseParticipant(ParticipantStatus participantStatusMessage) throws PfModelException, ControlLoopException { if (participantStatusMessage.getParticipantId() == null) { @@ -427,26 +423,6 @@ public class SupervisionHandler extends ControlLoopHandler { } } - @Override - public void startProviders() { - try { - manager.start(); - } catch (final ServiceManagerException exp) { - throw new ControlLoopRuntimeException(Status.INTERNAL_SERVER_ERROR, - "Supervision handler start of providers failed", exp); - } - } - - @Override - public void stopProviders() { - try { - manager.stop(); - } catch (final ServiceManagerException exp) { - throw new ControlLoopRuntimeException(Status.INTERNAL_SERVER_ERROR, - "Supervision handler stop of providers failed", exp); - } - } - private void exceptionOccured(Response.Status status, String reason) throws ControlLoopException { throw new ControlLoopException(status, reason); } diff --git a/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/supervision/SupervisionScanner.java b/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/supervision/SupervisionScanner.java index 4f3faf8af..68f5830c0 100644 --- a/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/supervision/SupervisionScanner.java +++ b/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/supervision/SupervisionScanner.java @@ -27,13 +27,16 @@ import java.util.concurrent.TimeUnit; import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoop; import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoopElement; import org.onap.policy.clamp.controlloop.models.controlloop.persistence.provider.ControlLoopProvider; +import org.onap.policy.clamp.controlloop.runtime.main.parameters.ClRuntimeParameterGroup; import org.onap.policy.models.base.PfModelException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; /** * This class is used to scan the control loops in the database and check if they are in the correct state. */ +@Component public class SupervisionScanner implements Runnable, Closeable { private static final Logger LOGGER = LoggerFactory.getLogger(SupervisionScanner.class); @@ -43,15 +46,17 @@ public class SupervisionScanner implements Runnable, Closeable { /** * Constructor for instantiating SupervisionScanner. * + * @param clRuntimeParameterGroup the parameters for the control loop runtime * @param controlLoopProvider the provider to use to read control loops from the database - * @param interval time interval to perform scans */ - public SupervisionScanner(final ControlLoopProvider controlLoopProvider, final long interval) { + public SupervisionScanner(final ControlLoopProvider controlLoopProvider, + ClRuntimeParameterGroup clRuntimeParameterGroup) { this.controlLoopProvider = controlLoopProvider; // Kick off the timer timerPool = makeTimerPool(); - timerPool.scheduleAtFixedRate(this, 0, interval, TimeUnit.SECONDS); + timerPool.scheduleAtFixedRate(this, 0, clRuntimeParameterGroup.getSupervisionScannerIntervalSec(), + TimeUnit.SECONDS); } @Override diff --git a/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/controlloop/participant/intermediary/comm/ParticipantStatusPublisher.java b/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/supervision/comm/AbstractParticipantAckPublisher.java index 78b998453..4b4ca9915 100644 --- a/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/controlloop/participant/intermediary/comm/ParticipantStatusPublisher.java +++ b/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/supervision/comm/AbstractParticipantAckPublisher.java @@ -18,40 +18,45 @@ * ============LICENSE_END========================================================= */ -package org.onap.policy.clamp.controlloop.participant.intermediary.comm; +package org.onap.policy.clamp.controlloop.runtime.supervision.comm; import java.util.List; -import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantStatus; +import javax.ws.rs.core.Response.Status; +import org.onap.policy.clamp.controlloop.common.exception.ControlLoopRuntimeException; +import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantAckMessage; +import org.onap.policy.clamp.controlloop.runtime.config.messaging.Publisher; import org.onap.policy.common.endpoints.event.comm.TopicSink; import org.onap.policy.common.endpoints.event.comm.client.TopicSinkClient; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -/** - * This class is used to send Participant Status messages to clamp using TopicSinkClient. - * - */ -public class ParticipantStatusPublisher { - private static final Logger LOGGER = LoggerFactory.getLogger(ParticipantStatusPublisher.class); +public abstract class AbstractParticipantAckPublisher<E extends ParticipantAckMessage> implements Publisher { - private final TopicSinkClient topicSinkClient; + private TopicSinkClient topicSinkClient; + private boolean active = false; /** - * Constructor for instantiating ParticipantStatusPublisher. + * Method to send Participant message to participants on demand. * - * @param topicSinks the topic sinks + * @param participantMessage the Participant message */ - public ParticipantStatusPublisher(List<TopicSink> topicSinks) { + public void send(final E participantMessage) { + if (!active) { + throw new ControlLoopRuntimeException(Status.NOT_ACCEPTABLE, "Not Active!"); + } + topicSinkClient.send(participantMessage); + } + + + @Override + public void active(List<TopicSink> topicSinks) { + if (topicSinks.size() != 1) { + throw new IllegalArgumentException("Topic Sink must be one"); + } this.topicSinkClient = new TopicSinkClient(topicSinks.get(0)); + active = true; } - /** - * Method to send Participant Status message to clamp on demand. - * - * @param participantStatus the Participant Status - */ - public void send(final ParticipantStatus participantStatus) { - topicSinkClient.send(participantStatus); - LOGGER.debug("Sent Participant Status message to CLAMP - {}", participantStatus); + @Override + public void stop() { + active = false; } } diff --git a/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/supervision/comm/AbstractParticipantPublisher.java b/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/supervision/comm/AbstractParticipantPublisher.java index c54856101..3c87b05b4 100644 --- a/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/supervision/comm/AbstractParticipantPublisher.java +++ b/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/supervision/comm/AbstractParticipantPublisher.java @@ -21,35 +21,17 @@ package org.onap.policy.clamp.controlloop.runtime.supervision.comm; import java.util.List; -import lombok.Getter; +import javax.ws.rs.core.Response.Status; +import org.onap.policy.clamp.controlloop.common.exception.ControlLoopRuntimeException; import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantMessage; +import org.onap.policy.clamp.controlloop.runtime.config.messaging.Publisher; import org.onap.policy.common.endpoints.event.comm.TopicSink; import org.onap.policy.common.endpoints.event.comm.client.TopicSinkClient; -public abstract class AbstractParticipantPublisher<E extends ParticipantMessage> { +public abstract class AbstractParticipantPublisher<E extends ParticipantMessage> implements Publisher { - private final TopicSinkClient topicSinkClient; - - @Getter - private final long intervalSec; - - /** - * Constructor. - * - * @param topicSinks the topic sinks - * @param intervalSec time interval to send ParticipantStateChange messages - */ - protected AbstractParticipantPublisher(final List<TopicSink> topicSinks, long intervalSec) { - this.topicSinkClient = new TopicSinkClient(topicSinks.get(0)); - this.intervalSec = intervalSec; - } - - /** - * Terminates the current timer. - */ - public void terminate() { - // Nothing to terminate, this publisher does not have a timer - } + private TopicSinkClient topicSinkClient; + private boolean active = false; /** * Method to send Participant message to participants on demand. @@ -57,6 +39,24 @@ public abstract class AbstractParticipantPublisher<E extends ParticipantMessage> * @param participantMessage the Participant message */ public void send(final E participantMessage) { + if (!active) { + throw new ControlLoopRuntimeException(Status.NOT_ACCEPTABLE, "Not Active!"); + } topicSinkClient.send(participantMessage); } + + + @Override + public void active(List<TopicSink> topicSinks) { + if (topicSinks.size() != 1) { + throw new IllegalArgumentException("Topic Sink must be one"); + } + this.topicSinkClient = new TopicSinkClient(topicSinks.get(0)); + active = true; + } + + @Override + public void stop() { + active = false; + } } diff --git a/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/supervision/comm/ParticipantControlLoopStateChangePublisher.java b/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/supervision/comm/ParticipantControlLoopStateChangePublisher.java index c9d0a4fe4..734ccb842 100644 --- a/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/supervision/comm/ParticipantControlLoopStateChangePublisher.java +++ b/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/supervision/comm/ParticipantControlLoopStateChangePublisher.java @@ -20,23 +20,29 @@ package org.onap.policy.clamp.controlloop.runtime.supervision.comm; -import java.util.List; +import java.util.UUID; +import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoop; import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantControlLoopStateChange; -import org.onap.policy.common.endpoints.event.comm.TopicSink; +import org.springframework.stereotype.Component; /** * This class is used to send ParticipantControlLoopStateChangePublisher messages to participants on DMaaP. */ +@Component public class ParticipantControlLoopStateChangePublisher extends AbstractParticipantPublisher<ParticipantControlLoopStateChange> { /** - * Constructor for instantiating ParticipantControlLoopStateChangePublisherPublisher. + * Send ControlLoopStateChange to Participant. * - * @param topicSinks the topic sinks - * @param interval time interval to send ParticipantControlLoopStateChangePublisher messages + * @param controlLoop the ControlLoop */ - public ParticipantControlLoopStateChangePublisher(final List<TopicSink> topicSinks, final long interval) { - super(topicSinks, interval); + public void send(ControlLoop controlLoop) { + var clsc = new ParticipantControlLoopStateChange(); + clsc.setControlLoopId(controlLoop.getKey().asIdentifier()); + clsc.setMessageId(UUID.randomUUID()); + clsc.setOrderedState(controlLoop.getOrderedState()); + + super.send(clsc); } } diff --git a/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/supervision/comm/ParticipantControlLoopUpdatePublisher.java b/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/supervision/comm/ParticipantControlLoopUpdatePublisher.java index fbbd95fbc..8d40c5e69 100644 --- a/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/supervision/comm/ParticipantControlLoopUpdatePublisher.java +++ b/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/supervision/comm/ParticipantControlLoopUpdatePublisher.java @@ -20,22 +20,42 @@ package org.onap.policy.clamp.controlloop.runtime.supervision.comm; -import java.util.List; +import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoop; import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantControlLoopUpdate; -import org.onap.policy.common.endpoints.event.comm.TopicSink; +import org.onap.policy.clamp.controlloop.runtime.commissioning.CommissioningProvider; +import org.onap.policy.models.base.PfModelException; +import org.springframework.stereotype.Component; /** * This class is used to send ParticipantControlLoopUpdate messages to participants on DMaaP. */ +@Component public class ParticipantControlLoopUpdatePublisher extends AbstractParticipantPublisher<ParticipantControlLoopUpdate> { + private final CommissioningProvider commissioningProvider; + + /** + * Constructor. + * + * @param commissioningProvider the CommissioningProvider + */ + public ParticipantControlLoopUpdatePublisher(CommissioningProvider commissioningProvider) { + this.commissioningProvider = commissioningProvider; + } + /** - * Constructor for instantiating ParticipantUpdatePublisher. + * Send ControlLoopUpdate to Participant. * - * @param topicSinks the topic sinks - * @param interval time interval to send ParticipantControlLoopUpdate messages + * @param controlLoop the ControlLoop + * @throws PfModelException on errors getting the Control Loop Definition */ - public ParticipantControlLoopUpdatePublisher(final List<TopicSink> topicSinks, final long interval) { - super(topicSinks, interval); + public void send(ControlLoop controlLoop) throws PfModelException { + var pclu = new ParticipantControlLoopUpdate(); + pclu.setControlLoopId(controlLoop.getKey().asIdentifier()); + pclu.setControlLoop(controlLoop); + // TODO: We should look up the correct TOSCA node template here for the control loop + // Tiny hack implemented to return the tosca service template entry from the database and be passed onto dmaap + pclu.setControlLoopDefinition(commissioningProvider.getToscaServiceTemplate(null, null)); + super.send(pclu); } } diff --git a/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/supervision/comm/ParticipantDeregisterAckPublisher.java b/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/supervision/comm/ParticipantDeregisterAckPublisher.java new file mode 100644 index 000000000..c0fcb3e7d --- /dev/null +++ b/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/supervision/comm/ParticipantDeregisterAckPublisher.java @@ -0,0 +1,32 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2021 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.controlloop.runtime.supervision.comm; + +import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantDeregisterAck; +import org.springframework.stereotype.Component; + +/** + * This class is used to send ParticipantDeregisterAck messages to participants on DMaaP. + */ +@Component +public class ParticipantDeregisterAckPublisher extends AbstractParticipantAckPublisher<ParticipantDeregisterAck> { + +} diff --git a/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/supervision/comm/ParticipantDeregisterListener.java b/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/supervision/comm/ParticipantDeregisterListener.java new file mode 100644 index 000000000..a03ff0a63 --- /dev/null +++ b/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/supervision/comm/ParticipantDeregisterListener.java @@ -0,0 +1,67 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2021 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.controlloop.runtime.supervision.comm; + +import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantDeregister; +import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantMessageType; +import org.onap.policy.clamp.controlloop.runtime.config.messaging.Listener; +import org.onap.policy.clamp.controlloop.runtime.supervision.SupervisionHandler; +import org.onap.policy.common.endpoints.event.comm.Topic.CommInfrastructure; +import org.onap.policy.common.endpoints.listeners.ScoListener; +import org.onap.policy.common.utils.coder.StandardCoderObject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +/** + * Listener for ParticipantDeregister messages sent by participants. + */ +@Component +public class ParticipantDeregisterListener extends ScoListener<ParticipantDeregister> implements Listener { + private static final Logger LOGGER = LoggerFactory.getLogger(ParticipantDeregisterListener.class); + + private final SupervisionHandler supervisionHandler; + + /** + * Constructs the object. + */ + public ParticipantDeregisterListener(SupervisionHandler supervisionHandler) { + super(ParticipantDeregister.class); + this.supervisionHandler = supervisionHandler; + } + + @Override + public void onTopicEvent(final CommInfrastructure infra, final String topic, final StandardCoderObject sco, + final ParticipantDeregister participantDeregisterMessage) { + LOGGER.debug("ParticipantDeregister message received from participant - {}", participantDeregisterMessage); + supervisionHandler.handleParticipantMessage(participantDeregisterMessage); + } + + @Override + public String getType() { + return ParticipantMessageType.PARTICIPANT_DEREGISTER.name(); + } + + @Override + public ScoListener<ParticipantDeregister> getScoListener() { + return this; + } +} diff --git a/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/supervision/comm/ParticipantRegisterAckPublisher.java b/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/supervision/comm/ParticipantRegisterAckPublisher.java new file mode 100644 index 000000000..2c0c4b393 --- /dev/null +++ b/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/supervision/comm/ParticipantRegisterAckPublisher.java @@ -0,0 +1,32 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2021 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.controlloop.runtime.supervision.comm; + +import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantRegisterAck; +import org.springframework.stereotype.Component; + +/** + * This class is used to send ParticipantRegisterAck messages to participants on DMaaP. + */ +@Component +public class ParticipantRegisterAckPublisher extends AbstractParticipantAckPublisher<ParticipantRegisterAck> { + +} diff --git a/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/supervision/comm/ParticipantRegisterListener.java b/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/supervision/comm/ParticipantRegisterListener.java new file mode 100644 index 000000000..a4d8c7697 --- /dev/null +++ b/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/supervision/comm/ParticipantRegisterListener.java @@ -0,0 +1,67 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2021 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.controlloop.runtime.supervision.comm; + +import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantMessageType; +import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantRegister; +import org.onap.policy.clamp.controlloop.runtime.config.messaging.Listener; +import org.onap.policy.clamp.controlloop.runtime.supervision.SupervisionHandler; +import org.onap.policy.common.endpoints.event.comm.Topic.CommInfrastructure; +import org.onap.policy.common.endpoints.listeners.ScoListener; +import org.onap.policy.common.utils.coder.StandardCoderObject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +/** + * Listener for ParticipantRegister messages sent by participants. + */ +@Component +public class ParticipantRegisterListener extends ScoListener<ParticipantRegister> implements Listener { + private static final Logger LOGGER = LoggerFactory.getLogger(ParticipantRegisterListener.class); + + private final SupervisionHandler supervisionHandler; + + /** + * Constructs the object. + */ + public ParticipantRegisterListener(SupervisionHandler supervisionHandler) { + super(ParticipantRegister.class); + this.supervisionHandler = supervisionHandler; + } + + @Override + public void onTopicEvent(final CommInfrastructure infra, final String topic, final StandardCoderObject sco, + final ParticipantRegister participantRegisterMessage) { + LOGGER.debug("ParticipantRegister message received from participant - {}", participantRegisterMessage); + supervisionHandler.handleParticipantMessage(participantRegisterMessage); + } + + @Override + public String getType() { + return ParticipantMessageType.PARTICIPANT_REGISTER.name(); + } + + @Override + public ScoListener<ParticipantRegister> getScoListener() { + return this; + } +} diff --git a/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/supervision/comm/ParticipantStateChangePublisher.java b/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/supervision/comm/ParticipantStateChangePublisher.java index 20cdea6f4..b63cbdf03 100644 --- a/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/supervision/comm/ParticipantStateChangePublisher.java +++ b/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/supervision/comm/ParticipantStateChangePublisher.java @@ -20,22 +20,13 @@ package org.onap.policy.clamp.controlloop.runtime.supervision.comm; -import java.util.List; import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantStateChange; -import org.onap.policy.common.endpoints.event.comm.TopicSink; +import org.springframework.stereotype.Component; /** * This class is used to send ParticipantStateChange messages to participants on DMaaP. */ +@Component public class ParticipantStateChangePublisher extends AbstractParticipantPublisher<ParticipantStateChange> { - /** - * Constructor for instantiating ParticipantStateChangePublisher. - * - * @param topicSinks the topic sinks - * @param interval time interval to send ParticipantStateChange messages - */ - public ParticipantStateChangePublisher(List<TopicSink> topicSinks, long interval) { - super(topicSinks, interval); - } } diff --git a/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/supervision/comm/ParticipantStatusListener.java b/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/supervision/comm/ParticipantStatusListener.java index 88b838613..9da886026 100644 --- a/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/supervision/comm/ParticipantStatusListener.java +++ b/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/supervision/comm/ParticipantStatusListener.java @@ -20,18 +20,22 @@ package org.onap.policy.clamp.controlloop.runtime.supervision.comm; +import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantMessageType; import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantStatus; +import org.onap.policy.clamp.controlloop.runtime.config.messaging.Listener; import org.onap.policy.clamp.controlloop.runtime.supervision.SupervisionHandler; import org.onap.policy.common.endpoints.event.comm.Topic.CommInfrastructure; import org.onap.policy.common.endpoints.listeners.ScoListener; import org.onap.policy.common.utils.coder.StandardCoderObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; /** * Listener for ParticipantStatus messages sent by participants. */ -public class ParticipantStatusListener extends ScoListener<ParticipantStatus> { +@Component +public class ParticipantStatusListener extends ScoListener<ParticipantStatus> implements Listener { private static final Logger LOGGER = LoggerFactory.getLogger(ParticipantStatusListener.class); private final SupervisionHandler supervisionHandler; @@ -48,6 +52,16 @@ public class ParticipantStatusListener extends ScoListener<ParticipantStatus> { public void onTopicEvent(final CommInfrastructure infra, final String topic, final StandardCoderObject sco, final ParticipantStatus participantStatusMessage) { LOGGER.debug("ParticipantStatus message received from participant - {}", participantStatusMessage); - supervisionHandler.handleParticipantStatusMessage(participantStatusMessage); + supervisionHandler.handleParticipantMessage(participantStatusMessage); + } + + @Override + public String getType() { + return ParticipantMessageType.PARTICIPANT_STATUS.name(); + } + + @Override + public ScoListener<ParticipantStatus> getScoListener() { + return this; } } diff --git a/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/supervision/comm/ParticipantUpdateAckListener.java b/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/supervision/comm/ParticipantUpdateAckListener.java new file mode 100644 index 000000000..b8538b1f7 --- /dev/null +++ b/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/supervision/comm/ParticipantUpdateAckListener.java @@ -0,0 +1,68 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2021 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.controlloop.runtime.supervision.comm; + +import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantMessageType; +import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantRegister; +import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantUpdateAck; +import org.onap.policy.clamp.controlloop.runtime.config.messaging.Listener; +import org.onap.policy.clamp.controlloop.runtime.supervision.SupervisionHandler; +import org.onap.policy.common.endpoints.event.comm.Topic.CommInfrastructure; +import org.onap.policy.common.endpoints.listeners.ScoListener; +import org.onap.policy.common.utils.coder.StandardCoderObject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +/** + * Listener for ParticipantUpdateAck messages sent by participants. + */ +@Component +public class ParticipantUpdateAckListener extends ScoListener<ParticipantUpdateAck> implements Listener { + private static final Logger LOGGER = LoggerFactory.getLogger(ParticipantUpdateAckListener.class); + + private final SupervisionHandler supervisionHandler; + + /** + * Constructs the object. + */ + public ParticipantUpdateAckListener(SupervisionHandler supervisionHandler) { + super(ParticipantUpdateAck.class); + this.supervisionHandler = supervisionHandler; + } + + @Override + public void onTopicEvent(final CommInfrastructure infra, final String topic, final StandardCoderObject sco, + final ParticipantUpdateAck participantUpdateAckMessage) { + LOGGER.debug("ParticipantUpdateAck message received from participant - {}", participantUpdateAckMessage); + supervisionHandler.handleParticipantMessage(participantUpdateAckMessage); + } + + @Override + public String getType() { + return ParticipantMessageType.PARTICIPANT_UPDATE_ACK.name(); + } + + @Override + public ScoListener<ParticipantUpdateAck> getScoListener() { + return this; + } +} diff --git a/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/supervision/comm/ParticipantUpdatePublisher.java b/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/supervision/comm/ParticipantUpdatePublisher.java new file mode 100644 index 000000000..5af5f1f54 --- /dev/null +++ b/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/supervision/comm/ParticipantUpdatePublisher.java @@ -0,0 +1,32 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2021 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.controlloop.runtime.supervision.comm; + +import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantUpdate; +import org.springframework.stereotype.Component; + +/** + * This class is used to send ParticipantUpdate messages to participants on DMaaP. + */ +@Component +public class ParticipantUpdatePublisher extends AbstractParticipantPublisher<ParticipantUpdate> { + +} diff --git a/runtime-controlloop/src/main/resources/parameters/ClRuntimeParameters.json b/runtime-controlloop/src/main/resources/parameters/ClRuntimeParameters.json index a6c19837e..00ca7f9a6 100644 --- a/runtime-controlloop/src/main/resources/parameters/ClRuntimeParameters.json +++ b/runtime-controlloop/src/main/resources/parameters/ClRuntimeParameters.json @@ -50,13 +50,6 @@ "message-router" ], "topicCommInfrastructure": "dmaap" - }, - { - "topic": "POLICY-NOTIFICATION", - "servers": [ - "message-router" - ], - "topicCommInfrastructure": "dmaap" } ] } diff --git a/runtime-controlloop/src/test/java/org/onap/policy/clamp/controlloop/runtime/commissioning/CommissioningProviderTest.java b/runtime-controlloop/src/test/java/org/onap/policy/clamp/controlloop/runtime/commissioning/CommissioningProviderTest.java index fdddcf996..440380781 100644 --- a/runtime-controlloop/src/test/java/org/onap/policy/clamp/controlloop/runtime/commissioning/CommissioningProviderTest.java +++ b/runtime-controlloop/src/test/java/org/onap/policy/clamp/controlloop/runtime/commissioning/CommissioningProviderTest.java @@ -26,13 +26,17 @@ import static org.junit.jupiter.api.Assertions.assertTrue; import java.util.ArrayList; import java.util.List; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; +import org.onap.policy.clamp.controlloop.models.controlloop.persistence.provider.ControlLoopProvider; import org.onap.policy.clamp.controlloop.runtime.main.parameters.ClRuntimeParameterGroup; +import org.onap.policy.clamp.controlloop.runtime.util.CommonTestData; 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.common.utils.coder.YamlJsonTranslator; import org.onap.policy.common.utils.resources.ResourceUtils; +import org.onap.policy.models.provider.PolicyModelsProvider; import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier; import org.onap.policy.models.tosca.authorative.concepts.ToscaNodeTemplate; import org.onap.policy.models.tosca.authorative.concepts.ToscaNodeType; @@ -47,6 +51,9 @@ class CommissioningProviderTest { private static int dbNum = 0; private static final Object lockit = new Object(); + private PolicyModelsProvider modelsProvider = null; + private ControlLoopProvider clProvider = null; + private static String getParameterGroupAsString() { dbNum++; return ResourceUtils.getResourceAsString("src/test/resources/parameters/TestParameters.json") @@ -64,6 +71,16 @@ class CommissioningProviderTest { } } + @AfterEach + void close() throws Exception { + if (modelsProvider != null) { + modelsProvider.close(); + } + if (clProvider != null) { + clProvider.close(); + } + } + /** * Test the fetching of control loop definitions (ToscaServiceTemplates). * @@ -71,33 +88,34 @@ class CommissioningProviderTest { */ @Test void testGetControlLoopDefinitions() throws Exception { - List<ToscaNodeTemplate> listOfTemplates; ClRuntimeParameterGroup clRuntimeParameterGroup = getClRuntimeParameterGroup(); + modelsProvider = + CommonTestData.getPolicyModelsProvider(clRuntimeParameterGroup.getDatabaseProviderParameters()); + clProvider = new ControlLoopProvider(clRuntimeParameterGroup.getDatabaseProviderParameters()); + + CommissioningProvider provider = new CommissioningProvider(modelsProvider, clProvider); + ToscaServiceTemplate serviceTemplate = yamlTranslator + .fromYaml(ResourceUtils.getResourceAsString(TOSCA_SERVICE_TEMPLATE_YAML), ToscaServiceTemplate.class); + + List<ToscaNodeTemplate> listOfTemplates = provider.getControlLoopDefinitions(null, null); + assertThat(listOfTemplates).isEmpty(); + + provider.createControlLoopDefinitions(serviceTemplate); + listOfTemplates = provider.getControlLoopDefinitions(null, null); + assertThat(listOfTemplates).hasSize(2); + + // Test Filtering + listOfTemplates = provider.getControlLoopDefinitions("org.onap.domain.pmsh.PMSHControlLoopDefinition", "1.2.3"); + assertThat(listOfTemplates).hasSize(1); + for (ToscaNodeTemplate template : listOfTemplates) { + // Other CL elements contain PMSD instead of PMSH in their name + assertThat(template.getName()).doesNotContain("PMSD"); + } - try (var provider = new CommissioningProvider(clRuntimeParameterGroup)) { - ToscaServiceTemplate serviceTemplate = yamlTranslator.fromYaml( - ResourceUtils.getResourceAsString(TOSCA_SERVICE_TEMPLATE_YAML), ToscaServiceTemplate.class); - - listOfTemplates = provider.getControlLoopDefinitions(null, null); - assertThat(listOfTemplates).isEmpty(); - - provider.createControlLoopDefinitions(serviceTemplate); - listOfTemplates = provider.getControlLoopDefinitions(null, null); - assertThat(listOfTemplates).hasSize(2); - - // Test Filtering - listOfTemplates = - provider.getControlLoopDefinitions("org.onap.domain.pmsh.PMSHControlLoopDefinition", "1.2.3"); - assertThat(listOfTemplates).hasSize(1); - for (ToscaNodeTemplate template : listOfTemplates) { - // Other CL elements contain PMSD instead of PMSH in their name - assertThat(template.getName()).doesNotContain("PMSD"); - } + // Test Wrong Name + listOfTemplates = provider.getControlLoopDefinitions("WrongControlLoopName", "0.0.0"); + assertThat(listOfTemplates).isEmpty(); - // Test Wrong Name - listOfTemplates = provider.getControlLoopDefinitions("WrongControlLoopName", "0.0.0"); - assertThat(listOfTemplates).isEmpty(); - } } /** @@ -107,25 +125,26 @@ class CommissioningProviderTest { */ @Test void testCreateControlLoopDefinitions() throws Exception { - List<ToscaNodeTemplate> listOfTemplates; ClRuntimeParameterGroup clRuntimeParameterGroup = getClRuntimeParameterGroup(); - - try (var provider = new CommissioningProvider(clRuntimeParameterGroup)) { - // Test Service template is null - assertThatThrownBy(() -> provider.createControlLoopDefinitions(null)).hasMessageMatching(TEMPLATE_IS_NULL); - listOfTemplates = provider.getControlLoopDefinitions(null, null); - assertThat(listOfTemplates).isEmpty(); - - ToscaServiceTemplate serviceTemplate = yamlTranslator.fromYaml( - ResourceUtils.getResourceAsString(TOSCA_SERVICE_TEMPLATE_YAML), ToscaServiceTemplate.class); - - // Response should return the number of node templates present in the service template - List<ToscaConceptIdentifier> affectedDefinitions = - provider.createControlLoopDefinitions(serviceTemplate).getAffectedControlLoopDefinitions(); - assertThat(affectedDefinitions).hasSize(13); - listOfTemplates = provider.getControlLoopDefinitions(null, null); - assertThat(listOfTemplates).hasSize(2); - } + modelsProvider = + CommonTestData.getPolicyModelsProvider(clRuntimeParameterGroup.getDatabaseProviderParameters()); + clProvider = new ControlLoopProvider(clRuntimeParameterGroup.getDatabaseProviderParameters()); + + CommissioningProvider provider = new CommissioningProvider(modelsProvider, clProvider); + // Test Service template is null + assertThatThrownBy(() -> provider.createControlLoopDefinitions(null)).hasMessageMatching(TEMPLATE_IS_NULL); + List<ToscaNodeTemplate> listOfTemplates = provider.getControlLoopDefinitions(null, null); + assertThat(listOfTemplates).isEmpty(); + + ToscaServiceTemplate serviceTemplate = yamlTranslator + .fromYaml(ResourceUtils.getResourceAsString(TOSCA_SERVICE_TEMPLATE_YAML), ToscaServiceTemplate.class); + + // Response should return the number of node templates present in the service template + List<ToscaConceptIdentifier> affectedDefinitions = + provider.createControlLoopDefinitions(serviceTemplate).getAffectedControlLoopDefinitions(); + assertThat(affectedDefinitions).hasSize(13); + listOfTemplates = provider.getControlLoopDefinitions(null, null); + assertThat(listOfTemplates).hasSize(2); } /** @@ -135,24 +154,25 @@ class CommissioningProviderTest { */ @Test void testDeleteControlLoopDefinitions() throws Exception { - List<ToscaNodeTemplate> listOfTemplates; ClRuntimeParameterGroup clRuntimeParameterGroup = getClRuntimeParameterGroup(); + modelsProvider = + CommonTestData.getPolicyModelsProvider(clRuntimeParameterGroup.getDatabaseProviderParameters()); + clProvider = new ControlLoopProvider(clRuntimeParameterGroup.getDatabaseProviderParameters()); - try (var provider = new CommissioningProvider(clRuntimeParameterGroup)) { - ToscaServiceTemplate serviceTemplate = yamlTranslator.fromYaml( - ResourceUtils.getResourceAsString(TOSCA_SERVICE_TEMPLATE_YAML), ToscaServiceTemplate.class); + CommissioningProvider provider = new CommissioningProvider(modelsProvider, clProvider); + ToscaServiceTemplate serviceTemplate = yamlTranslator + .fromYaml(ResourceUtils.getResourceAsString(TOSCA_SERVICE_TEMPLATE_YAML), ToscaServiceTemplate.class); - listOfTemplates = provider.getControlLoopDefinitions(null, null); - assertThat(listOfTemplates).isEmpty(); + List<ToscaNodeTemplate> listOfTemplates = provider.getControlLoopDefinitions(null, null); + assertThat(listOfTemplates).isEmpty(); - provider.createControlLoopDefinitions(serviceTemplate); - listOfTemplates = provider.getControlLoopDefinitions(null, null); - assertThat(listOfTemplates).hasSize(2); + provider.createControlLoopDefinitions(serviceTemplate); + listOfTemplates = provider.getControlLoopDefinitions(null, null); + assertThat(listOfTemplates).hasSize(2); - provider.deleteControlLoopDefinition(serviceTemplate.getName(), serviceTemplate.getVersion()); - listOfTemplates = provider.getControlLoopDefinitions(null, null); - assertThat(listOfTemplates).isEmpty(); - } + provider.deleteControlLoopDefinition(serviceTemplate.getName(), serviceTemplate.getVersion()); + listOfTemplates = provider.getControlLoopDefinitions(null, null); + assertThat(listOfTemplates).isEmpty(); } /** @@ -163,26 +183,29 @@ class CommissioningProviderTest { @Test void testGetControlLoopElementDefinitions() throws Exception { ClRuntimeParameterGroup clRuntimeParameterGroup = getClRuntimeParameterGroup(); - try (var provider = new CommissioningProvider(clRuntimeParameterGroup)) { - ToscaServiceTemplate serviceTemplate = yamlTranslator.fromYaml( - ResourceUtils.getResourceAsString(TOSCA_SERVICE_TEMPLATE_YAML), ToscaServiceTemplate.class); + modelsProvider = + CommonTestData.getPolicyModelsProvider(clRuntimeParameterGroup.getDatabaseProviderParameters()); + clProvider = new ControlLoopProvider(clRuntimeParameterGroup.getDatabaseProviderParameters()); - provider.getControlLoopDefinitions(null, null); + CommissioningProvider provider = new CommissioningProvider(modelsProvider, clProvider); + ToscaServiceTemplate serviceTemplate = yamlTranslator + .fromYaml(ResourceUtils.getResourceAsString(TOSCA_SERVICE_TEMPLATE_YAML), ToscaServiceTemplate.class); - provider.createControlLoopDefinitions(serviceTemplate); - List<ToscaNodeTemplate> controlLoopDefinitionList = - provider.getControlLoopDefinitions("org.onap.domain.pmsh.PMSHControlLoopDefinition", "1.2.3"); + provider.getControlLoopDefinitions(null, null); - List<ToscaNodeTemplate> controlLoopElementNodeTemplates = - provider.getControlLoopElementDefinitions(controlLoopDefinitionList.get(0)); + provider.createControlLoopDefinitions(serviceTemplate); + List<ToscaNodeTemplate> controlLoopDefinitionList = + provider.getControlLoopDefinitions("org.onap.domain.pmsh.PMSHControlLoopDefinition", "1.2.3"); - // 4 PMSH control loop elements definitions. - assertThat(controlLoopElementNodeTemplates).hasSize(4); + List<ToscaNodeTemplate> controlLoopElementNodeTemplates = + provider.getControlLoopElementDefinitions(controlLoopDefinitionList.get(0)); - List<ToscaNodeType> derivedTypes = getDerivedNodeTypes(serviceTemplate); - for (ToscaNodeTemplate template : controlLoopElementNodeTemplates) { - assertTrue(checkNodeType(template, derivedTypes)); - } + // 4 PMSH control loop elements definitions. + assertThat(controlLoopElementNodeTemplates).hasSize(4); + + List<ToscaNodeType> derivedTypes = getDerivedNodeTypes(serviceTemplate); + for (ToscaNodeTemplate template : controlLoopElementNodeTemplates) { + assertTrue(checkNodeType(template, derivedTypes)); } } diff --git a/runtime-controlloop/src/test/java/org/onap/policy/clamp/controlloop/runtime/config/messaging/MessageDispatcherActivatorTest.java b/runtime-controlloop/src/test/java/org/onap/policy/clamp/controlloop/runtime/config/messaging/MessageDispatcherActivatorTest.java new file mode 100644 index 000000000..2b4abaa3b --- /dev/null +++ b/runtime-controlloop/src/test/java/org/onap/policy/clamp/controlloop/runtime/config/messaging/MessageDispatcherActivatorTest.java @@ -0,0 +1,100 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2021 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.controlloop.runtime.config.messaging; + +import static org.assertj.core.api.Assertions.assertThatIllegalStateException; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyList; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import org.junit.jupiter.api.Test; +import org.onap.policy.clamp.controlloop.runtime.main.parameters.ClRuntimeParameterGroup; +import org.onap.policy.clamp.controlloop.runtime.main.parameters.ClRuntimeParameterHandler; +import org.onap.policy.clamp.controlloop.runtime.supervision.comm.ParticipantStatusListener; +import org.onap.policy.common.utils.coder.Coder; +import org.onap.policy.common.utils.coder.StandardCoder; +import org.onap.policy.common.utils.coder.StandardCoderObject; + +/** + * Class to perform unit test of {@link MessageDispatcherActivator}}. + * + */ +class MessageDispatcherActivatorTest { + + private static final Coder CODER = new StandardCoder(); + + private static final String TOPIC_FIRST = "TOPIC1"; + private static final String TOPIC_SECOND = "TOPIC2"; + + @Test + void testStartAndStop() throws Exception { + final String path = "src/test/resources/parameters/TestParameters.json"; + ClRuntimeParameterGroup parameterGroup = new ClRuntimeParameterHandler().getParameters(path); + + var publisherFirst = spy(mock(Publisher.class)); + var publisherSecond = spy(mock(Publisher.class)); + var publishers = new Publisher[] {publisherFirst, publisherSecond}; + + var listenerFirst = spy(mock(ParticipantStatusListener.class)); + when(listenerFirst.getType()).thenReturn(TOPIC_FIRST); + when(listenerFirst.getScoListener()).thenReturn(listenerFirst); + + var listenerSecond = spy(mock(ParticipantStatusListener.class)); + when(listenerSecond.getType()).thenReturn(TOPIC_SECOND); + when(listenerSecond.getScoListener()).thenReturn(listenerSecond); + + var listeners = new Listener[] {listenerFirst, listenerSecond}; + + try (var activator = new MessageDispatcherActivator(parameterGroup, publishers, listeners)) { + + assertFalse(activator.isAlive()); + activator.start(); + assertTrue(activator.isAlive()); + + // repeat start - should throw an exception + assertThatIllegalStateException().isThrownBy(() -> activator.start()); + assertTrue(activator.isAlive()); + verify(publisherFirst, times(1)).active(anyList()); + verify(publisherSecond, times(1)).active(anyList()); + + StandardCoderObject sco = CODER.decode("{messageType:" + TOPIC_FIRST + "}", StandardCoderObject.class); + activator.getMsgDispatcher().onTopicEvent(null, "msg", sco); + verify(listenerFirst, times(1)).onTopicEvent(any(), any(), any()); + + sco = CODER.decode("{messageType:" + TOPIC_SECOND + "}", StandardCoderObject.class); + activator.getMsgDispatcher().onTopicEvent(null, "msg", sco); + verify(listenerSecond, times(1)).onTopicEvent(any(), any(), any()); + + activator.stop(); + assertFalse(activator.isAlive()); + + // repeat stop - should throw an exception + assertThatIllegalStateException().isThrownBy(() -> activator.stop()); + assertFalse(activator.isAlive()); + } + } +} diff --git a/runtime-controlloop/src/test/java/org/onap/policy/clamp/controlloop/runtime/instantiation/ControlLoopInstantiationProviderTest.java b/runtime-controlloop/src/test/java/org/onap/policy/clamp/controlloop/runtime/instantiation/ControlLoopInstantiationProviderTest.java index b93bd0f0e..b92f341eb 100644 --- a/runtime-controlloop/src/test/java/org/onap/policy/clamp/controlloop/runtime/instantiation/ControlLoopInstantiationProviderTest.java +++ b/runtime-controlloop/src/test/java/org/onap/policy/clamp/controlloop/runtime/instantiation/ControlLoopInstantiationProviderTest.java @@ -25,7 +25,7 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy; import java.io.IOException; import java.util.ArrayList; -import java.util.Collections; +import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.mockito.Mockito; @@ -33,15 +33,24 @@ import org.onap.policy.clamp.controlloop.common.exception.ControlLoopRuntimeExce import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoop; import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoopState; import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoops; +import org.onap.policy.clamp.controlloop.models.controlloop.persistence.provider.ClElementStatisticsProvider; +import org.onap.policy.clamp.controlloop.models.controlloop.persistence.provider.ControlLoopProvider; +import org.onap.policy.clamp.controlloop.models.controlloop.persistence.provider.ParticipantProvider; +import org.onap.policy.clamp.controlloop.models.controlloop.persistence.provider.ParticipantStatisticsProvider; import org.onap.policy.clamp.controlloop.models.messages.rest.instantiation.InstantiationCommand; import org.onap.policy.clamp.controlloop.models.messages.rest.instantiation.InstantiationResponse; import org.onap.policy.clamp.controlloop.runtime.commissioning.CommissioningProvider; import org.onap.policy.clamp.controlloop.runtime.main.parameters.ClRuntimeParameterGroup; import org.onap.policy.clamp.controlloop.runtime.monitoring.MonitoringProvider; import org.onap.policy.clamp.controlloop.runtime.supervision.SupervisionHandler; +import org.onap.policy.clamp.controlloop.runtime.supervision.comm.ParticipantControlLoopStateChangePublisher; +import org.onap.policy.clamp.controlloop.runtime.supervision.comm.ParticipantControlLoopUpdatePublisher; +import org.onap.policy.clamp.controlloop.runtime.supervision.comm.ParticipantDeregisterAckPublisher; +import org.onap.policy.clamp.controlloop.runtime.supervision.comm.ParticipantRegisterAckPublisher; +import org.onap.policy.clamp.controlloop.runtime.supervision.comm.ParticipantUpdatePublisher; import org.onap.policy.clamp.controlloop.runtime.util.CommonTestData; -import org.onap.policy.common.endpoints.event.comm.TopicSink; import org.onap.policy.models.base.PfModelException; +import org.onap.policy.models.provider.PolicyModelsProvider; import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier; /** @@ -79,9 +88,10 @@ class ControlLoopInstantiationProviderTest { + " item \"ControlLoop\" value \"org.onap.domain.PMSHControlLoopDefinition\" INVALID," + " Commissioned control loop definition not FOUND\n"; - private static ClRuntimeParameterGroup controlLoopParameters; private static SupervisionHandler supervisionHandler; private static CommissioningProvider commissioningProvider; + private static ControlLoopProvider clProvider; + private static PolicyModelsProvider modelsProvider; /** * setup Db Provider Parameters. @@ -90,12 +100,33 @@ class ControlLoopInstantiationProviderTest { */ @BeforeAll public static void setupDbProviderParameters() throws PfModelException { - controlLoopParameters = CommonTestData.geParameterGroup(0, "instantproviderdb"); - commissioningProvider = new CommissioningProvider(controlLoopParameters); - var monitoringProvider = new MonitoringProvider(controlLoopParameters); - supervisionHandler = new SupervisionHandler(controlLoopParameters, monitoringProvider, commissioningProvider); - supervisionHandler.startProviders(); - supervisionHandler.startAndRegisterPublishers(Collections.singletonList(Mockito.mock(TopicSink.class))); + ClRuntimeParameterGroup controlLoopParameters = CommonTestData.geParameterGroup(0, "instantproviderdb"); + + modelsProvider = + CommonTestData.getPolicyModelsProvider(controlLoopParameters.getDatabaseProviderParameters()); + clProvider = new ControlLoopProvider(controlLoopParameters.getDatabaseProviderParameters()); + var participantStatisticsProvider = + new ParticipantStatisticsProvider(controlLoopParameters.getDatabaseProviderParameters()); + var clElementStatisticsProvider = + new ClElementStatisticsProvider(controlLoopParameters.getDatabaseProviderParameters()); + commissioningProvider = new CommissioningProvider(modelsProvider, clProvider); + var monitoringProvider = + new MonitoringProvider(participantStatisticsProvider, clElementStatisticsProvider, clProvider); + var participantProvider = new ParticipantProvider(controlLoopParameters.getDatabaseProviderParameters()); + var controlLoopUpdatePublisher = Mockito.mock(ParticipantControlLoopUpdatePublisher.class); + var controlLoopStateChangePublisher = Mockito.mock(ParticipantControlLoopStateChangePublisher.class); + var participantRegisterAckPublisher = Mockito.mock(ParticipantRegisterAckPublisher.class); + var participantDeregisterAckPublisher = Mockito.mock(ParticipantDeregisterAckPublisher.class); + var participantUpdatePublisher = Mockito.mock(ParticipantUpdatePublisher.class); + supervisionHandler = new SupervisionHandler(clProvider, participantProvider, monitoringProvider, + commissioningProvider, controlLoopUpdatePublisher, controlLoopStateChangePublisher, + participantRegisterAckPublisher, participantDeregisterAckPublisher, participantUpdatePublisher); + } + + @AfterAll + public static void closeDbProvider() throws PfModelException { + clProvider.close(); + modelsProvider.close(); } @Test @@ -104,77 +135,75 @@ class ControlLoopInstantiationProviderTest { InstantiationUtils.getControlLoopsFromResource(CL_INSTANTIATION_CREATE_JSON, "Crud"); ControlLoops controlLoopsDb = getControlLoopsFromDb(controlLoopsCreate); assertThat(controlLoopsDb.getControlLoopList()).isEmpty(); - try (ControlLoopInstantiationProvider instantiationProvider = new ControlLoopInstantiationProvider( - controlLoopParameters, commissioningProvider, supervisionHandler)) { + var instantiationProvider = + new ControlLoopInstantiationProvider(clProvider, commissioningProvider, supervisionHandler); - // to validate control Loop, it needs to define ToscaServiceTemplate - InstantiationUtils.storeToscaServiceTemplate(TOSCA_TEMPLATE_YAML, commissioningProvider); + // to validate control Loop, it needs to define ToscaServiceTemplate + InstantiationUtils.storeToscaServiceTemplate(TOSCA_TEMPLATE_YAML, commissioningProvider); - InstantiationResponse instantiationResponse = instantiationProvider.createControlLoops(controlLoopsCreate); - InstantiationUtils.assertInstantiationResponse(instantiationResponse, controlLoopsCreate); + InstantiationResponse instantiationResponse = instantiationProvider.createControlLoops(controlLoopsCreate); + InstantiationUtils.assertInstantiationResponse(instantiationResponse, controlLoopsCreate); - controlLoopsDb = getControlLoopsFromDb(controlLoopsCreate); - assertThat(controlLoopsDb.getControlLoopList()).isNotEmpty(); - assertThat(controlLoopsCreate).isEqualTo(controlLoopsDb); - - for (ControlLoop controlLoop : controlLoopsCreate.getControlLoopList()) { - ControlLoops controlLoopsGet = - instantiationProvider.getControlLoops(controlLoop.getName(), controlLoop.getVersion()); - assertThat(controlLoopsGet.getControlLoopList()).hasSize(1); - assertThat(controlLoop).isEqualTo(controlLoopsGet.getControlLoopList().get(0)); - } + controlLoopsDb = getControlLoopsFromDb(controlLoopsCreate); + assertThat(controlLoopsDb.getControlLoopList()).isNotEmpty(); + assertThat(controlLoopsCreate).isEqualTo(controlLoopsDb); - ControlLoops controlLoopsUpdate = - InstantiationUtils.getControlLoopsFromResource(CL_INSTANTIATION_UPDATE_JSON, "Crud"); - assertThat(controlLoopsUpdate).isNotEqualTo(controlLoopsDb); + for (ControlLoop controlLoop : controlLoopsCreate.getControlLoopList()) { + ControlLoops controlLoopsGet = + instantiationProvider.getControlLoops(controlLoop.getName(), controlLoop.getVersion()); + assertThat(controlLoopsGet.getControlLoopList()).hasSize(1); + assertThat(controlLoop).isEqualTo(controlLoopsGet.getControlLoopList().get(0)); + } - instantiationResponse = instantiationProvider.updateControlLoops(controlLoopsUpdate); - InstantiationUtils.assertInstantiationResponse(instantiationResponse, controlLoopsUpdate); + ControlLoops controlLoopsUpdate = + InstantiationUtils.getControlLoopsFromResource(CL_INSTANTIATION_UPDATE_JSON, "Crud"); + assertThat(controlLoopsUpdate).isNotEqualTo(controlLoopsDb); - controlLoopsDb = getControlLoopsFromDb(controlLoopsCreate); - assertThat(controlLoopsDb.getControlLoopList()).isNotEmpty(); - assertThat(controlLoopsUpdate).isEqualTo(controlLoopsDb); + instantiationResponse = instantiationProvider.updateControlLoops(controlLoopsUpdate); + InstantiationUtils.assertInstantiationResponse(instantiationResponse, controlLoopsUpdate); - InstantiationCommand instantiationCommand = - InstantiationUtils.getInstantiationCommandFromResource(CL_INSTANTIATION_CHANGE_STATE_JSON, "Crud"); - instantiationResponse = instantiationProvider.issueControlLoopCommand(instantiationCommand); - InstantiationUtils.assertInstantiationResponse(instantiationResponse, instantiationCommand); + controlLoopsDb = getControlLoopsFromDb(controlLoopsCreate); + assertThat(controlLoopsDb.getControlLoopList()).isNotEmpty(); + assertThat(controlLoopsUpdate).isEqualTo(controlLoopsDb); - for (ToscaConceptIdentifier toscaConceptIdentifier : instantiationCommand.getControlLoopIdentifierList()) { - ControlLoops controlLoopsGet = instantiationProvider.getControlLoops(toscaConceptIdentifier.getName(), - toscaConceptIdentifier.getVersion()); - assertThat(controlLoopsGet.getControlLoopList()).hasSize(1); - assertThat(instantiationCommand.getOrderedState()) - .isEqualTo(controlLoopsGet.getControlLoopList().get(0).getOrderedState()); - } + InstantiationCommand instantiationCommand = + InstantiationUtils.getInstantiationCommandFromResource(CL_INSTANTIATION_CHANGE_STATE_JSON, "Crud"); + instantiationResponse = instantiationProvider.issueControlLoopCommand(instantiationCommand); + InstantiationUtils.assertInstantiationResponse(instantiationResponse, instantiationCommand); - // in order to delete a controlLoop the state must be UNINITIALISED - controlLoopsCreate.getControlLoopList().forEach(cl -> cl.setState(ControlLoopState.UNINITIALISED)); - instantiationProvider.updateControlLoops(controlLoopsCreate); + for (ToscaConceptIdentifier toscaConceptIdentifier : instantiationCommand.getControlLoopIdentifierList()) { + ControlLoops controlLoopsGet = instantiationProvider.getControlLoops(toscaConceptIdentifier.getName(), + toscaConceptIdentifier.getVersion()); + assertThat(controlLoopsGet.getControlLoopList()).hasSize(1); + assertThat(instantiationCommand.getOrderedState()) + .isEqualTo(controlLoopsGet.getControlLoopList().get(0).getOrderedState()); + } - for (ControlLoop controlLoop : controlLoopsCreate.getControlLoopList()) { - instantiationProvider.deleteControlLoop(controlLoop.getName(), controlLoop.getVersion()); - } + // in order to delete a controlLoop the state must be UNINITIALISED + controlLoopsCreate.getControlLoopList().forEach(cl -> cl.setState(ControlLoopState.UNINITIALISED)); + instantiationProvider.updateControlLoops(controlLoopsCreate); - controlLoopsDb = getControlLoopsFromDb(controlLoopsCreate); - assertThat(controlLoopsDb.getControlLoopList()).isEmpty(); + for (ControlLoop controlLoop : controlLoopsCreate.getControlLoopList()) { + instantiationProvider.deleteControlLoop(controlLoop.getName(), controlLoop.getVersion()); } + + controlLoopsDb = getControlLoopsFromDb(controlLoopsCreate); + assertThat(controlLoopsDb.getControlLoopList()).isEmpty(); } private ControlLoops getControlLoopsFromDb(ControlLoops controlLoopsSource) throws Exception { ControlLoops controlLoopsDb = new ControlLoops(); controlLoopsDb.setControlLoopList(new ArrayList<>()); - try (ControlLoopInstantiationProvider instantiationProvider = new ControlLoopInstantiationProvider( - controlLoopParameters, commissioningProvider, supervisionHandler)) { + var instantiationProvider = + new ControlLoopInstantiationProvider(clProvider, commissioningProvider, supervisionHandler); - for (ControlLoop controlLoop : controlLoopsSource.getControlLoopList()) { - ControlLoops controlLoopsFromDb = - instantiationProvider.getControlLoops(controlLoop.getName(), controlLoop.getVersion()); - controlLoopsDb.getControlLoopList().addAll(controlLoopsFromDb.getControlLoopList()); - } - return controlLoopsDb; + for (ControlLoop controlLoop : controlLoopsSource.getControlLoopList()) { + ControlLoops controlLoopsFromDb = + instantiationProvider.getControlLoops(controlLoop.getName(), controlLoop.getVersion()); + controlLoopsDb.getControlLoopList().addAll(controlLoopsFromDb.getControlLoopList()); } + return controlLoopsDb; } @Test @@ -185,37 +214,36 @@ class ControlLoopInstantiationProviderTest { ControlLoop controlLoop0 = controlLoops.getControlLoopList().get(0); - try (ControlLoopInstantiationProvider instantiationProvider = new ControlLoopInstantiationProvider( - controlLoopParameters, commissioningProvider, supervisionHandler)) { + var instantiationProvider = + new ControlLoopInstantiationProvider(clProvider, commissioningProvider, supervisionHandler); - // to validate control Loop, it needs to define ToscaServiceTemplate - InstantiationUtils.storeToscaServiceTemplate(TOSCA_TEMPLATE_YAML, commissioningProvider); + // to validate control Loop, it needs to define ToscaServiceTemplate + InstantiationUtils.storeToscaServiceTemplate(TOSCA_TEMPLATE_YAML, commissioningProvider); - assertThatThrownBy( - () -> instantiationProvider.deleteControlLoop(controlLoop0.getName(), controlLoop0.getVersion())) - .hasMessageMatching(CONTROL_LOOP_NOT_FOUND); + assertThatThrownBy( + () -> instantiationProvider.deleteControlLoop(controlLoop0.getName(), controlLoop0.getVersion())) + .hasMessageMatching(CONTROL_LOOP_NOT_FOUND); - InstantiationUtils.assertInstantiationResponse(instantiationProvider.createControlLoops(controlLoops), - controlLoops); + InstantiationUtils.assertInstantiationResponse(instantiationProvider.createControlLoops(controlLoops), + controlLoops); - for (ControlLoopState state : ControlLoopState.values()) { - if (!ControlLoopState.UNINITIALISED.equals(state)) { - assertThatDeleteThrownBy(controlLoops, state); - } + for (ControlLoopState state : ControlLoopState.values()) { + if (!ControlLoopState.UNINITIALISED.equals(state)) { + assertThatDeleteThrownBy(controlLoops, state); } + } - controlLoop0.setState(ControlLoopState.UNINITIALISED); - instantiationProvider.updateControlLoops(controlLoops); + controlLoop0.setState(ControlLoopState.UNINITIALISED); + instantiationProvider.updateControlLoops(controlLoops); - for (ControlLoop controlLoop : controlLoops.getControlLoopList()) { - instantiationProvider.deleteControlLoop(controlLoop.getName(), controlLoop.getVersion()); - } + for (ControlLoop controlLoop : controlLoops.getControlLoopList()) { + instantiationProvider.deleteControlLoop(controlLoop.getName(), controlLoop.getVersion()); + } - for (ControlLoop controlLoop : controlLoops.getControlLoopList()) { - ControlLoops controlLoopsGet = - instantiationProvider.getControlLoops(controlLoop.getName(), controlLoop.getVersion()); - assertThat(controlLoopsGet.getControlLoopList()).isEmpty(); - } + for (ControlLoop controlLoop : controlLoops.getControlLoopList()) { + ControlLoops controlLoopsGet = + instantiationProvider.getControlLoops(controlLoop.getName(), controlLoop.getVersion()); + assertThat(controlLoopsGet.getControlLoopList()).isEmpty(); } } @@ -224,14 +252,13 @@ class ControlLoopInstantiationProviderTest { controlLoop.setState(state); - try (ControlLoopInstantiationProvider instantiationProvider = new ControlLoopInstantiationProvider( - controlLoopParameters, commissioningProvider, supervisionHandler)) { + var instantiationProvider = + new ControlLoopInstantiationProvider(clProvider, commissioningProvider, supervisionHandler); - instantiationProvider.updateControlLoops(controlLoops); - assertThatThrownBy( - () -> instantiationProvider.deleteControlLoop(controlLoop.getName(), controlLoop.getVersion())) - .hasMessageMatching(String.format(DELETE_BAD_REQUEST, state)); - } + instantiationProvider.updateControlLoops(controlLoops); + assertThatThrownBy( + () -> instantiationProvider.deleteControlLoop(controlLoop.getName(), controlLoop.getVersion())) + .hasMessageMatching(String.format(DELETE_BAD_REQUEST, state)); } @Test @@ -242,21 +269,20 @@ class ControlLoopInstantiationProviderTest { ControlLoops controlLoopsDb = getControlLoopsFromDb(controlLoopsCreate); assertThat(controlLoopsDb.getControlLoopList()).isEmpty(); - try (ControlLoopInstantiationProvider instantiationProvider = new ControlLoopInstantiationProvider( - controlLoopParameters, commissioningProvider, supervisionHandler)) { + var instantiationProvider = + new ControlLoopInstantiationProvider(clProvider, commissioningProvider, supervisionHandler); - // to validate control Loop, it needs to define ToscaServiceTemplate - InstantiationUtils.storeToscaServiceTemplate(TOSCA_TEMPLATE_YAML, commissioningProvider); + // to validate control Loop, it needs to define ToscaServiceTemplate + InstantiationUtils.storeToscaServiceTemplate(TOSCA_TEMPLATE_YAML, commissioningProvider); - InstantiationResponse instantiationResponse = instantiationProvider.createControlLoops(controlLoopsCreate); - InstantiationUtils.assertInstantiationResponse(instantiationResponse, controlLoopsCreate); + InstantiationResponse instantiationResponse = instantiationProvider.createControlLoops(controlLoopsCreate); + InstantiationUtils.assertInstantiationResponse(instantiationResponse, controlLoopsCreate); - assertThatThrownBy(() -> instantiationProvider.createControlLoops(controlLoopsCreate)).hasMessageMatching( - controlLoopsCreate.getControlLoopList().get(0).getKey().asIdentifier() + " already defined"); + assertThatThrownBy(() -> instantiationProvider.createControlLoops(controlLoopsCreate)).hasMessageMatching( + controlLoopsCreate.getControlLoopList().get(0).getKey().asIdentifier() + " already defined"); - for (ControlLoop controlLoop : controlLoopsCreate.getControlLoopList()) { - instantiationProvider.deleteControlLoop(controlLoop.getName(), controlLoop.getVersion()); - } + for (ControlLoop controlLoop : controlLoopsCreate.getControlLoopList()) { + instantiationProvider.deleteControlLoop(controlLoop.getName(), controlLoop.getVersion()); } } @@ -265,17 +291,15 @@ class ControlLoopInstantiationProviderTest { ControlLoops controlLoops = InstantiationUtils .getControlLoopsFromResource(CL_INSTANTIATION_DEFINITION_NAME_NOT_FOUND_JSON, "ClElementNotFound"); - try (ControlLoopInstantiationProvider provider = new ControlLoopInstantiationProvider(controlLoopParameters, - commissioningProvider, supervisionHandler)) { + var provider = new ControlLoopInstantiationProvider(clProvider, commissioningProvider, supervisionHandler); - // to validate control Loop, it needs to define ToscaServiceTemplate - InstantiationUtils.storeToscaServiceTemplate(TOSCA_TEMPLATE_YAML, commissioningProvider); + // to validate control Loop, it needs to define ToscaServiceTemplate + InstantiationUtils.storeToscaServiceTemplate(TOSCA_TEMPLATE_YAML, commissioningProvider); - assertThat(getControlLoopsFromDb(controlLoops).getControlLoopList()).isEmpty(); + assertThat(getControlLoopsFromDb(controlLoops).getControlLoopList()).isEmpty(); - assertThatThrownBy(() -> provider.createControlLoops(controlLoops)) - .hasMessageMatching(CONTROLLOOP_ELEMENT_NAME_NOT_FOUND); - } + assertThatThrownBy(() -> provider.createControlLoops(controlLoops)) + .hasMessageMatching(CONTROLLOOP_ELEMENT_NAME_NOT_FOUND); } @Test @@ -285,20 +309,17 @@ class ControlLoopInstantiationProviderTest { assertThat(getControlLoopsFromDb(controlLoops).getControlLoopList()).isEmpty(); - try (ControlLoopInstantiationProvider provider = new ControlLoopInstantiationProvider(controlLoopParameters, - commissioningProvider, supervisionHandler)) { - assertThatThrownBy(() -> provider.createControlLoops(controlLoops)) - .hasMessageMatching(CONTROLLOOP_DEFINITION_NOT_FOUND); - } + var provider = new ControlLoopInstantiationProvider(clProvider, commissioningProvider, supervisionHandler); + assertThatThrownBy(() -> provider.createControlLoops(controlLoops)) + .hasMessageMatching(CONTROLLOOP_DEFINITION_NOT_FOUND); } @Test void testIssueControlLoopCommand_OrderedStateInvalid() throws ControlLoopRuntimeException, IOException { - try (ControlLoopInstantiationProvider instantiationProvider = new ControlLoopInstantiationProvider( - controlLoopParameters, commissioningProvider, supervisionHandler)) { - assertThatThrownBy(() -> instantiationProvider.issueControlLoopCommand(new InstantiationCommand())) - .hasMessageMatching(ORDERED_STATE_INVALID); - } + var instantiationProvider = + new ControlLoopInstantiationProvider(clProvider, commissioningProvider, supervisionHandler); + assertThatThrownBy(() -> instantiationProvider.issueControlLoopCommand(new InstantiationCommand())) + .hasMessageMatching(ORDERED_STATE_INVALID); } @Test @@ -309,61 +330,60 @@ class ControlLoopInstantiationProviderTest { InstantiationUtils.getControlLoopsFromResource(CL_INSTANTIATION_CREATE_JSON, "V1"); assertThat(getControlLoopsFromDb(controlLoopsV1).getControlLoopList()).isEmpty(); - try (ControlLoopInstantiationProvider instantiationProvider = new ControlLoopInstantiationProvider( - controlLoopParameters, commissioningProvider, supervisionHandler)) { + var instantiationProvider = + new ControlLoopInstantiationProvider(clProvider, commissioningProvider, supervisionHandler); - // to validate control Loop, it needs to define ToscaServiceTemplate - InstantiationUtils.storeToscaServiceTemplate(TOSCA_TEMPLATE_YAML, commissioningProvider); + // to validate control Loop, it needs to define ToscaServiceTemplate + InstantiationUtils.storeToscaServiceTemplate(TOSCA_TEMPLATE_YAML, commissioningProvider); - InstantiationUtils.assertInstantiationResponse(instantiationProvider.createControlLoops(controlLoopsV1), - controlLoopsV1); + InstantiationUtils.assertInstantiationResponse(instantiationProvider.createControlLoops(controlLoopsV1), + controlLoopsV1); - // create controlLoops V2 - ControlLoops controlLoopsV2 = - InstantiationUtils.getControlLoopsFromResource(CL_INSTANTIATION_CREATE_JSON, "V2"); - assertThat(getControlLoopsFromDb(controlLoopsV2).getControlLoopList()).isEmpty(); - InstantiationUtils.assertInstantiationResponse(instantiationProvider.createControlLoops(controlLoopsV2), - controlLoopsV2); + // create controlLoops V2 + ControlLoops controlLoopsV2 = + InstantiationUtils.getControlLoopsFromResource(CL_INSTANTIATION_CREATE_JSON, "V2"); + assertThat(getControlLoopsFromDb(controlLoopsV2).getControlLoopList()).isEmpty(); + InstantiationUtils.assertInstantiationResponse(instantiationProvider.createControlLoops(controlLoopsV2), + controlLoopsV2); - // GET controlLoops V2 - for (ControlLoop controlLoop : controlLoopsV2.getControlLoopList()) { - ControlLoops controlLoopsGet = - instantiationProvider.getControlLoops(controlLoop.getName(), controlLoop.getVersion()); - assertThat(controlLoopsGet.getControlLoopList()).hasSize(1); - assertThat(controlLoop).isEqualTo(controlLoopsGet.getControlLoopList().get(0)); - } + // GET controlLoops V2 + for (ControlLoop controlLoop : controlLoopsV2.getControlLoopList()) { + ControlLoops controlLoopsGet = + instantiationProvider.getControlLoops(controlLoop.getName(), controlLoop.getVersion()); + assertThat(controlLoopsGet.getControlLoopList()).hasSize(1); + assertThat(controlLoop).isEqualTo(controlLoopsGet.getControlLoopList().get(0)); + } - // DELETE controlLoops V1 - for (ControlLoop controlLoop : controlLoopsV1.getControlLoopList()) { - instantiationProvider.deleteControlLoop(controlLoop.getName(), controlLoop.getVersion()); - } + // DELETE controlLoops V1 + for (ControlLoop controlLoop : controlLoopsV1.getControlLoopList()) { + instantiationProvider.deleteControlLoop(controlLoop.getName(), controlLoop.getVersion()); + } - // GET controlLoops V1 is not available - for (ControlLoop controlLoop : controlLoopsV1.getControlLoopList()) { - ControlLoops controlLoopsGet = - instantiationProvider.getControlLoops(controlLoop.getName(), controlLoop.getVersion()); - assertThat(controlLoopsGet.getControlLoopList()).isEmpty(); - } + // GET controlLoops V1 is not available + for (ControlLoop controlLoop : controlLoopsV1.getControlLoopList()) { + ControlLoops controlLoopsGet = + instantiationProvider.getControlLoops(controlLoop.getName(), controlLoop.getVersion()); + assertThat(controlLoopsGet.getControlLoopList()).isEmpty(); + } - // GET controlLoops V2 is still available - for (ControlLoop controlLoop : controlLoopsV2.getControlLoopList()) { - ControlLoops controlLoopsGet = - instantiationProvider.getControlLoops(controlLoop.getName(), controlLoop.getVersion()); - assertThat(controlLoopsGet.getControlLoopList()).hasSize(1); - assertThat(controlLoop).isEqualTo(controlLoopsGet.getControlLoopList().get(0)); - } + // GET controlLoops V2 is still available + for (ControlLoop controlLoop : controlLoopsV2.getControlLoopList()) { + ControlLoops controlLoopsGet = + instantiationProvider.getControlLoops(controlLoop.getName(), controlLoop.getVersion()); + assertThat(controlLoopsGet.getControlLoopList()).hasSize(1); + assertThat(controlLoop).isEqualTo(controlLoopsGet.getControlLoopList().get(0)); + } - // DELETE controlLoops V2 - for (ControlLoop controlLoop : controlLoopsV2.getControlLoopList()) { - instantiationProvider.deleteControlLoop(controlLoop.getName(), controlLoop.getVersion()); - } + // DELETE controlLoops V2 + for (ControlLoop controlLoop : controlLoopsV2.getControlLoopList()) { + instantiationProvider.deleteControlLoop(controlLoop.getName(), controlLoop.getVersion()); + } - // GET controlLoops V2 is not available - for (ControlLoop controlLoop : controlLoopsV2.getControlLoopList()) { - ControlLoops controlLoopsGet = - instantiationProvider.getControlLoops(controlLoop.getName(), controlLoop.getVersion()); - assertThat(controlLoopsGet.getControlLoopList()).isEmpty(); - } + // GET controlLoops V2 is not available + for (ControlLoop controlLoop : controlLoopsV2.getControlLoopList()) { + ControlLoops controlLoopsGet = + instantiationProvider.getControlLoops(controlLoop.getName(), controlLoop.getVersion()); + assertThat(controlLoopsGet.getControlLoopList()).isEmpty(); } } } diff --git a/runtime-controlloop/src/test/java/org/onap/policy/clamp/controlloop/runtime/main/startstop/ClRuntimeActivatorTest.java b/runtime-controlloop/src/test/java/org/onap/policy/clamp/controlloop/runtime/main/startstop/ClRuntimeActivatorTest.java deleted file mode 100644 index 7eb567259..000000000 --- a/runtime-controlloop/src/test/java/org/onap/policy/clamp/controlloop/runtime/main/startstop/ClRuntimeActivatorTest.java +++ /dev/null @@ -1,65 +0,0 @@ -/*- - * ============LICENSE_START======================================================= - * Copyright (C) 2021 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.controlloop.runtime.main.startstop; - -import static org.assertj.core.api.Assertions.assertThatIllegalStateException; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import org.junit.jupiter.api.Test; -import org.mockito.Mockito; -import org.onap.policy.clamp.controlloop.runtime.main.parameters.ClRuntimeParameterGroup; -import org.onap.policy.clamp.controlloop.runtime.main.parameters.ClRuntimeParameterHandler; -import org.onap.policy.clamp.controlloop.runtime.supervision.SupervisionHandler; - -/** - * Class to perform unit test of {@link ClRuntimeActivator}}. - * - */ -class ClRuntimeActivatorTest { - - @Test - void testStartAndStop() throws Exception { - final String path = "src/test/resources/parameters/TestParameters.json"; - ClRuntimeParameterGroup parameterGroup = new ClRuntimeParameterHandler().getParameters(path); - var supervisionHandler = Mockito.mock(SupervisionHandler.class); - - try (var activator = new ClRuntimeActivator(parameterGroup, supervisionHandler)) { - - assertFalse(activator.isAlive()); - activator.start(); - assertTrue(activator.isAlive()); - assertTrue(activator.getParameterGroup().isValid()); - - // repeat start - should throw an exception - assertThatIllegalStateException().isThrownBy(() -> activator.start()); - assertTrue(activator.isAlive()); - assertTrue(activator.getParameterGroup().isValid()); - - activator.stop(); - assertFalse(activator.isAlive()); - - // repeat stop - should throw an exception - assertThatIllegalStateException().isThrownBy(() -> activator.stop()); - assertFalse(activator.isAlive()); - } - } -} diff --git a/runtime-controlloop/src/test/java/org/onap/policy/clamp/controlloop/runtime/monitoring/TestMonitoringProvider.java b/runtime-controlloop/src/test/java/org/onap/policy/clamp/controlloop/runtime/monitoring/TestMonitoringProvider.java index 580b30f9e..c47211a2d 100644 --- a/runtime-controlloop/src/test/java/org/onap/policy/clamp/controlloop/runtime/monitoring/TestMonitoringProvider.java +++ b/runtime-controlloop/src/test/java/org/onap/policy/clamp/controlloop/runtime/monitoring/TestMonitoringProvider.java @@ -23,15 +23,15 @@ package org.onap.policy.clamp.controlloop.runtime.monitoring; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.when; import java.io.File; -import java.lang.reflect.Field; import java.time.Instant; -import java.util.ArrayList; import java.util.LinkedHashMap; -import java.util.List; import java.util.Map; +import java.util.UUID; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.mockito.Mockito; @@ -39,7 +39,9 @@ import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ClElementSt import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoop; import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoopElement; import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ParticipantStatisticsList; +import org.onap.policy.clamp.controlloop.models.controlloop.persistence.provider.ClElementStatisticsProvider; import org.onap.policy.clamp.controlloop.models.controlloop.persistence.provider.ControlLoopProvider; +import org.onap.policy.clamp.controlloop.models.controlloop.persistence.provider.ParticipantStatisticsProvider; import org.onap.policy.clamp.controlloop.runtime.main.parameters.ClRuntimeParameterGroup; import org.onap.policy.clamp.controlloop.runtime.util.CommonTestData; import org.onap.policy.common.utils.coder.Coder; @@ -59,14 +61,16 @@ class TestMonitoringProvider { "src/test/resources/rest/monitoring/TestClElementStatistics_Invalid.json"; private static final Coder CODER = new StandardCoder(); - private static final String CL_PROVIDER_FIELD = "controlLoopProvider"; - private static final String LIST_IS_NULL = ".*StatisticsList is marked .*ull but is null"; private static ParticipantStatisticsList inputParticipantStatistics; private static ParticipantStatisticsList invalidParticipantInput; private static ClElementStatisticsList inputClElementStatistics; private static ClElementStatisticsList invalidClElementInput; + private ParticipantStatisticsProvider participantStatisticsProvider = null; + private ClElementStatisticsProvider clElementStatisticsProvider = null; + private ControlLoopProvider clProvider = null; + @BeforeAll public static void beforeSetupStatistics() throws CoderException { // Reading input json for statistics data @@ -78,141 +82,167 @@ class TestMonitoringProvider { invalidClElementInput = CODER.decode(new File(INVALID_CL_ELEMENT_JSON_INPUT), ClElementStatisticsList.class); } + @AfterEach + void close() throws Exception { + if (participantStatisticsProvider != null) { + participantStatisticsProvider.close(); + } + if (clElementStatisticsProvider != null) { + clElementStatisticsProvider.close(); + } + if (clProvider != null) { + clProvider.close(); + } + } + @Test void testCreateParticipantStatistics() throws Exception { ClRuntimeParameterGroup parameters = CommonTestData.geParameterGroup(0, "createparStat"); - - try (MonitoringProvider provider = new MonitoringProvider(parameters)) { - // Creating statistics data in db with null input - assertThatThrownBy(() -> { - provider.createParticipantStatistics(null); - }).hasMessageMatching(LIST_IS_NULL); - - assertThatThrownBy(() -> { - provider.createParticipantStatistics(invalidParticipantInput.getStatisticsList()); - }).hasMessageMatching("participantStatisticsList is marked .*null but is null"); - - // Creating statistics data from input json - ParticipantStatisticsList createResponse = - provider.createParticipantStatistics(inputParticipantStatistics.getStatisticsList()); - - assertThat(createResponse.getStatisticsList()).hasSize(3); - assertEquals(createResponse.getStatisticsList().toString().replaceAll("\\s+", ""), - inputParticipantStatistics.getStatisticsList().toString().replaceAll("\\s+", "")); - } + participantStatisticsProvider = new ParticipantStatisticsProvider(parameters.getDatabaseProviderParameters()); + clElementStatisticsProvider = new ClElementStatisticsProvider(parameters.getDatabaseProviderParameters()); + clProvider = new ControlLoopProvider(parameters.getDatabaseProviderParameters()); + MonitoringProvider provider = + new MonitoringProvider(participantStatisticsProvider, clElementStatisticsProvider, clProvider); + // Creating statistics data in db with null input + assertThatThrownBy(() -> { + provider.createParticipantStatistics(null); + }).hasMessageMatching(LIST_IS_NULL); + + assertThatThrownBy(() -> { + provider.createParticipantStatistics(invalidParticipantInput.getStatisticsList()); + }).hasMessageMatching("participantStatisticsList is marked .*null but is null"); + + // Creating statistics data from input json + ParticipantStatisticsList createResponse = + provider.createParticipantStatistics(inputParticipantStatistics.getStatisticsList()); + + assertThat(createResponse.getStatisticsList()).hasSize(3); + assertEquals(createResponse.getStatisticsList().toString().replaceAll("\\s+", ""), + inputParticipantStatistics.getStatisticsList().toString().replaceAll("\\s+", "")); } @Test void testGetParticipantStatistics() throws Exception { ClRuntimeParameterGroup parameters = CommonTestData.geParameterGroup(0, "getparStat"); - try (MonitoringProvider provider = new MonitoringProvider(parameters)) { - ParticipantStatisticsList getResponse; - - provider.createParticipantStatistics(inputParticipantStatistics.getStatisticsList()); - - assertThatThrownBy(() -> { - provider.fetchFilteredParticipantStatistics(null, null, 0, null, null); - }).hasMessageMatching("name is marked .*null but is null"); - - // Fetch specific statistics record with name, version and record count - getResponse = provider.fetchFilteredParticipantStatistics("name2", "1.001", 1, null, null); - assertThat(getResponse.getStatisticsList()).hasSize(1); - assertEquals(getResponse.getStatisticsList().get(0).toString().replaceAll("\\s+", ""), - inputParticipantStatistics.getStatisticsList().get(2).toString().replaceAll("\\s+", "")); - - // Fetch statistics using timestamp - getResponse = provider.fetchFilteredParticipantStatistics("name1", "1.001", 0, null, - Instant.parse("2021-01-10T15:00:00.000Z")); - assertThat(getResponse.getStatisticsList()).hasSize(1); - - getResponse = provider.fetchFilteredParticipantStatistics("name1", "1.001", 0, - Instant.parse("2021-01-11T12:00:00.000Z"), Instant.parse("2021-01-11T16:00:00.000Z")); - - assertThat(getResponse.getStatisticsList()).isEmpty(); - } + participantStatisticsProvider = new ParticipantStatisticsProvider(parameters.getDatabaseProviderParameters()); + clElementStatisticsProvider = new ClElementStatisticsProvider(parameters.getDatabaseProviderParameters()); + clProvider = new ControlLoopProvider(parameters.getDatabaseProviderParameters()); + MonitoringProvider provider = + new MonitoringProvider(participantStatisticsProvider, clElementStatisticsProvider, clProvider); + + provider.createParticipantStatistics(inputParticipantStatistics.getStatisticsList()); + + assertThatThrownBy(() -> { + provider.fetchFilteredParticipantStatistics(null, null, 0, null, null); + }).hasMessageMatching("name is marked .*null but is null"); + + // Fetch specific statistics record with name, version and record count + ParticipantStatisticsList getResponse = + provider.fetchFilteredParticipantStatistics("name2", "1.001", 1, null, null); + assertThat(getResponse.getStatisticsList()).hasSize(1); + assertEquals(getResponse.getStatisticsList().get(0).toString().replaceAll("\\s+", ""), + inputParticipantStatistics.getStatisticsList().get(2).toString().replaceAll("\\s+", "")); + + // Fetch statistics using timestamp + getResponse = provider.fetchFilteredParticipantStatistics("name1", "1.001", 0, null, + Instant.parse("2021-01-10T15:00:00.000Z")); + assertThat(getResponse.getStatisticsList()).hasSize(1); + + getResponse = provider.fetchFilteredParticipantStatistics("name1", "1.001", 0, + Instant.parse("2021-01-11T12:00:00.000Z"), Instant.parse("2021-01-11T16:00:00.000Z")); + + assertThat(getResponse.getStatisticsList()).isEmpty(); } @Test void testCreateClElementStatistics() throws Exception { ClRuntimeParameterGroup parameters = CommonTestData.geParameterGroup(0, "createelemstat"); - - try (MonitoringProvider provider = new MonitoringProvider(parameters)) { - // Creating statistics data in db with null input - assertThatThrownBy(() -> { - provider.createClElementStatistics(null); - }).hasMessageMatching(LIST_IS_NULL); - - assertThatThrownBy(() -> { - provider.createClElementStatistics(invalidClElementInput.getClElementStatistics()); - }).hasMessageMatching("clElementStatisticsList is marked .*null but is null"); - - // Creating clElement statistics data from input json - ClElementStatisticsList createResponse = - provider.createClElementStatistics(inputClElementStatistics.getClElementStatistics()); - - assertThat(createResponse.getClElementStatistics()).hasSize(4); - assertEquals(createResponse.getClElementStatistics().toString().replaceAll("\\s+", ""), - inputClElementStatistics.getClElementStatistics().toString().replaceAll("\\s+", "")); - } + participantStatisticsProvider = new ParticipantStatisticsProvider(parameters.getDatabaseProviderParameters()); + clElementStatisticsProvider = new ClElementStatisticsProvider(parameters.getDatabaseProviderParameters()); + clProvider = new ControlLoopProvider(parameters.getDatabaseProviderParameters()); + + MonitoringProvider provider = + new MonitoringProvider(participantStatisticsProvider, clElementStatisticsProvider, clProvider); + // Creating statistics data in db with null input + assertThatThrownBy(() -> { + provider.createClElementStatistics(null); + }).hasMessageMatching(LIST_IS_NULL); + + assertThatThrownBy(() -> { + provider.createClElementStatistics(invalidClElementInput.getClElementStatistics()); + }).hasMessageMatching("clElementStatisticsList is marked .*null but is null"); + + // Creating clElement statistics data from input json + ClElementStatisticsList createResponse = + provider.createClElementStatistics(inputClElementStatistics.getClElementStatistics()); + + assertThat(createResponse.getClElementStatistics()).hasSize(4); + assertEquals(createResponse.getClElementStatistics().toString().replaceAll("\\s+", ""), + inputClElementStatistics.getClElementStatistics().toString().replaceAll("\\s+", "")); } @Test void testGetClElementStatistics() throws Exception { ClRuntimeParameterGroup parameters = CommonTestData.geParameterGroup(0, "getelemstat"); + participantStatisticsProvider = new ParticipantStatisticsProvider(parameters.getDatabaseProviderParameters()); + clElementStatisticsProvider = new ClElementStatisticsProvider(parameters.getDatabaseProviderParameters()); + clProvider = new ControlLoopProvider(parameters.getDatabaseProviderParameters()); - try (MonitoringProvider provider = new MonitoringProvider(parameters)) { - ClElementStatisticsList getResponse; + MonitoringProvider provider = + new MonitoringProvider(participantStatisticsProvider, clElementStatisticsProvider, clProvider); - assertThatThrownBy(() -> { - provider.fetchFilteredClElementStatistics(null, null, null, null, null, 0); - }).hasMessageMatching("name is marked .*null but is null"); + assertThatThrownBy(() -> { + provider.fetchFilteredClElementStatistics(null, null, null, null, null, 0); + }).hasMessageMatching("name is marked .*null but is null"); - provider.createClElementStatistics(inputClElementStatistics.getClElementStatistics()); + provider.createClElementStatistics(inputClElementStatistics.getClElementStatistics()); - getResponse = provider.fetchFilteredClElementStatistics("name1", null, null, null, null, 0); + ClElementStatisticsList getResponse = + provider.fetchFilteredClElementStatistics("name1", null, null, null, null, 0); - assertThat(getResponse.getClElementStatistics()).hasSize(2); - assertEquals(getResponse.getClElementStatistics().get(0).toString().replaceAll("\\s+", ""), - inputClElementStatistics.getClElementStatistics().get(0).toString().replaceAll("\\s+", "")); + assertThat(getResponse.getClElementStatistics()).hasSize(2); + assertEquals(getResponse.getClElementStatistics().get(0).toString().replaceAll("\\s+", ""), + inputClElementStatistics.getClElementStatistics().get(0).toString().replaceAll("\\s+", "")); - // Fetch specific statistics record with name, id and record count - getResponse = provider.fetchFilteredClElementStatistics("name1", "1.001", - "709c62b3-8918-41b9-a747-d21eb79c6c20", null, null, 0); - assertThat(getResponse.getClElementStatistics()).hasSize(2); + // Fetch specific statistics record with name, id and record count + getResponse = provider.fetchFilteredClElementStatistics("name1", "1.001", + "709c62b3-8918-41b9-a747-d21eb79c6c20", null, null, 0); + assertThat(getResponse.getClElementStatistics()).hasSize(2); - // Fetch statistics using timestamp - getResponse = provider.fetchFilteredClElementStatistics("name1", "1.001", null, - Instant.parse("2021-01-10T13:45:00.000Z"), null, 0); - assertThat(getResponse.getClElementStatistics()).hasSize(2); - } + // Fetch statistics using timestamp + getResponse = provider.fetchFilteredClElementStatistics("name1", "1.001", null, + Instant.parse("2021-01-10T13:45:00.000Z"), null, 0); + assertThat(getResponse.getClElementStatistics()).hasSize(2); } @Test void testGetParticipantStatsPerCL() throws Exception { ClRuntimeParameterGroup parameters = CommonTestData.geParameterGroup(0, "getparStatCL"); - - try (MonitoringProvider provider = Mockito.spy(new MonitoringProvider(parameters))) { - - provider.createParticipantStatistics(inputParticipantStatistics.getStatisticsList()); - // Mock the response for fetching participant conceptIdentifiers per control loop - List<ToscaConceptIdentifier> conceptIdentifiers = new ArrayList<>(); - conceptIdentifiers.add(new ToscaConceptIdentifier("name1", "1.001")); - when(provider.getAllParticipantIdsPerControlLoop("testName", "1.001")).thenReturn(conceptIdentifiers); - ParticipantStatisticsList getResponse; - getResponse = provider.fetchParticipantStatsPerControlLoop("testName", "1.001"); - assertThat(getResponse.getStatisticsList()).hasSize(2); - assertEquals(getResponse.getStatisticsList().get(0).toString().replaceAll("\\s+", ""), - inputParticipantStatistics.getStatisticsList().get(0).toString().replaceAll("\\s+", "")); - assertThat(provider.fetchParticipantStatsPerControlLoop("invalidCLName", "1.002").getStatisticsList()) - .isEmpty(); - } - + participantStatisticsProvider = new ParticipantStatisticsProvider(parameters.getDatabaseProviderParameters()); + clElementStatisticsProvider = new ClElementStatisticsProvider(parameters.getDatabaseProviderParameters()); + var mockClProvider = Mockito.mock(ControlLoopProvider.class); + var provider = + new MonitoringProvider(participantStatisticsProvider, clElementStatisticsProvider, mockClProvider); + + provider.createParticipantStatistics(inputParticipantStatistics.getStatisticsList()); + + var controlLoop = new ControlLoop(); + var element = new ControlLoopElement(); + element.setParticipantId(new ToscaConceptIdentifier("name1", "1.001")); + controlLoop.setElements(Map.of(UUID.randomUUID(), element)); + when(mockClProvider.getControlLoop(eq(new ToscaConceptIdentifier("testName", "1.001")))) + .thenReturn(controlLoop); + + ParticipantStatisticsList getResponse = provider.fetchParticipantStatsPerControlLoop("testName", "1.001"); + assertThat(getResponse.getStatisticsList()).hasSize(2); + assertEquals(getResponse.getStatisticsList().get(0).toString().replaceAll("\\s+", ""), + inputParticipantStatistics.getStatisticsList().get(0).toString().replaceAll("\\s+", "")); + assertThat(provider.fetchParticipantStatsPerControlLoop("invalidCLName", "1.002").getStatisticsList()) + .isEmpty(); } @Test void testClElementStatsPerCL() throws Exception { - ClRuntimeParameterGroup parameters = CommonTestData.geParameterGroup(0, "getelemstatPerCL"); - // Setup a dummy Control loop data ControlLoopElement mockClElement = new ControlLoopElement(); mockClElement.setId(inputClElementStatistics.getClElementStatistics().get(0).getId()); @@ -223,30 +253,32 @@ class TestMonitoringProvider { mockCL.setElements(new LinkedHashMap<>()); mockCL.getElements().put(mockClElement.getId(), mockClElement); - // Mock controlloop data to be returned for the given CL Id + ClRuntimeParameterGroup parameters = CommonTestData.geParameterGroup(0, "getelemstatPerCL"); + participantStatisticsProvider = new ParticipantStatisticsProvider(parameters.getDatabaseProviderParameters()); + clElementStatisticsProvider = new ClElementStatisticsProvider(parameters.getDatabaseProviderParameters()); ControlLoopProvider mockClProvider = Mockito.mock(ControlLoopProvider.class); + var monitoringProvider = + new MonitoringProvider(participantStatisticsProvider, clElementStatisticsProvider, mockClProvider); + + // Mock controlloop data to be returned for the given CL Id when(mockClProvider.getControlLoop(new ToscaConceptIdentifier("testCLName", "1.001"))).thenReturn(mockCL); - try (MonitoringProvider monitoringProvider = new MonitoringProvider(parameters)) { - monitoringProvider.createClElementStatistics(inputClElementStatistics.getClElementStatistics()); - Field controlLoopProviderField = monitoringProvider.getClass().getDeclaredField(CL_PROVIDER_FIELD); - controlLoopProviderField.setAccessible(true); - controlLoopProviderField.set(monitoringProvider, mockClProvider); + monitoringProvider.createClElementStatistics(inputClElementStatistics.getClElementStatistics()); - ClElementStatisticsList getResponse; - getResponse = monitoringProvider.fetchClElementStatsPerControlLoop("testCLName", "1.001"); + ClElementStatisticsList getResponse; + getResponse = monitoringProvider.fetchClElementStatsPerControlLoop("testCLName", "1.001"); - assertThat(getResponse.getClElementStatistics()).hasSize(2); - assertEquals(getResponse.getClElementStatistics().get(1).toString().replaceAll("\\s+", ""), - inputClElementStatistics.getClElementStatistics().get(1).toString().replaceAll("\\s+", "")); + assertThat(getResponse.getClElementStatistics()).hasSize(2); + assertEquals(getResponse.getClElementStatistics().get(1).toString().replaceAll("\\s+", ""), + inputClElementStatistics.getClElementStatistics().get(1).toString().replaceAll("\\s+", "")); - assertThat(monitoringProvider.fetchClElementStatsPerControlLoop("invalidCLName", "1.002") - .getClElementStatistics()).isEmpty(); + assertThat( + monitoringProvider.fetchClElementStatsPerControlLoop("invalidCLName", "1.002").getClElementStatistics()) + .isEmpty(); - Map<String, ToscaConceptIdentifier> clElementIds = - monitoringProvider.getAllClElementsIdPerControlLoop("testCLName", "1.001"); - assertThat(clElementIds) - .containsKey(inputClElementStatistics.getClElementStatistics().get(0).getId().toString()); - } + Map<String, ToscaConceptIdentifier> clElementIds = + monitoringProvider.getAllClElementsIdPerControlLoop("testCLName", "1.001"); + assertThat(clElementIds) + .containsKey(inputClElementStatistics.getClElementStatistics().get(0).getId().toString()); } } diff --git a/runtime-controlloop/src/test/java/org/onap/policy/clamp/controlloop/runtime/monitoring/rest/MonitoringQueryControllerTest.java b/runtime-controlloop/src/test/java/org/onap/policy/clamp/controlloop/runtime/monitoring/rest/MonitoringQueryControllerTest.java index 95b2113cd..77742aea9 100644 --- a/runtime-controlloop/src/test/java/org/onap/policy/clamp/controlloop/runtime/monitoring/rest/MonitoringQueryControllerTest.java +++ b/runtime-controlloop/src/test/java/org/onap/policy/clamp/controlloop/runtime/monitoring/rest/MonitoringQueryControllerTest.java @@ -34,7 +34,6 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ClElementStatisticsList; import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ParticipantStatisticsList; -import org.onap.policy.clamp.controlloop.runtime.main.parameters.ClRuntimeParameterGroup; import org.onap.policy.clamp.controlloop.runtime.monitoring.MonitoringProvider; import org.onap.policy.clamp.controlloop.runtime.util.rest.CommonRestController; import org.onap.policy.common.utils.coder.Coder; @@ -70,7 +69,7 @@ class MonitoringQueryControllerTest extends CommonRestController { private static final String CLELEMENT_STATS_PER_CL_ENDPOINT = "monitoring/clelements/controlloop"; @Autowired - private ClRuntimeParameterGroup clRuntimeParameterGroup; + private MonitoringProvider monitoringProvider; @LocalServerPort private int randomServerPort; @@ -92,14 +91,12 @@ class MonitoringQueryControllerTest extends CommonRestController { public void setUpBeforeEach() throws Exception { super.setHttpPrefix(randomServerPort); - try (var monitoringProvider = new MonitoringProvider(clRuntimeParameterGroup)) { - // Insert Participant statistics to DB - participantStatisticsList = - monitoringProvider.createParticipantStatistics(inputParticipantStatistics.getStatisticsList()); - // Insert CL Element statistics to DB - clElementStatisticsList = - monitoringProvider.createClElementStatistics(inputClElementStatistics.getClElementStatistics()); - } + // Insert Participant statistics to DB + participantStatisticsList = + monitoringProvider.createParticipantStatistics(inputParticipantStatistics.getStatisticsList()); + // Insert CL Element statistics to DB + clElementStatisticsList = + monitoringProvider.createClElementStatistics(inputClElementStatistics.getClElementStatistics()); } @Test diff --git a/runtime-controlloop/src/test/java/org/onap/policy/clamp/controlloop/runtime/supervision/comm/SupervisionMessagesTest.java b/runtime-controlloop/src/test/java/org/onap/policy/clamp/controlloop/runtime/supervision/comm/SupervisionMessagesTest.java new file mode 100644 index 000000000..f08cda12b --- /dev/null +++ b/runtime-controlloop/src/test/java/org/onap/policy/clamp/controlloop/runtime/supervision/comm/SupervisionMessagesTest.java @@ -0,0 +1,228 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2021 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.controlloop.runtime.supervision.comm; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.time.Instant; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoopElementDefinition; +import org.onap.policy.clamp.controlloop.models.controlloop.persistence.provider.ClElementStatisticsProvider; +import org.onap.policy.clamp.controlloop.models.controlloop.persistence.provider.ControlLoopProvider; +import org.onap.policy.clamp.controlloop.models.controlloop.persistence.provider.ParticipantProvider; +import org.onap.policy.clamp.controlloop.models.controlloop.persistence.provider.ParticipantStatisticsProvider; +import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantDeregister; +import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantDeregisterAck; +import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantRegister; +import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantRegisterAck; +import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantUpdate; +import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantUpdateAck; +import org.onap.policy.clamp.controlloop.runtime.commissioning.CommissioningProvider; +import org.onap.policy.clamp.controlloop.runtime.main.parameters.ClRuntimeParameterGroup; +import org.onap.policy.clamp.controlloop.runtime.monitoring.MonitoringProvider; +import org.onap.policy.clamp.controlloop.runtime.supervision.SupervisionHandler; +import org.onap.policy.clamp.controlloop.runtime.util.CommonTestData; +import org.onap.policy.clamp.controlloop.runtime.util.rest.CommonRestController; +import org.onap.policy.common.endpoints.event.comm.Topic.CommInfrastructure; +import org.onap.policy.common.endpoints.event.comm.TopicSink; +import org.onap.policy.common.utils.coder.YamlJsonTranslator; +import org.onap.policy.common.utils.resources.ResourceUtils; +import org.onap.policy.models.base.PfModelException; +import org.onap.policy.models.provider.PolicyModelsProvider; +import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier; +import org.onap.policy.models.tosca.authorative.concepts.ToscaNodeTemplate; +import org.onap.policy.models.tosca.authorative.concepts.ToscaServiceTemplate; + +class SupervisionMessagesTest extends CommonRestController { + + private static final String TOSCA_SERVICE_TEMPLATE_YAML = + "src/test/resources/rest/servicetemplates/pmsh_multiple_cl_tosca.yaml"; + private static final Object lockit = new Object(); + private static final CommInfrastructure INFRA = CommInfrastructure.NOOP; + private static final String TOPIC = "my-topic"; + private static final long interval = 1000; + private static SupervisionHandler supervisionHandler; + private static CommissioningProvider commissioningProvider; + private static ControlLoopProvider clProvider; + private static PolicyModelsProvider modelsProvider; + private static final YamlJsonTranslator yamlTranslator = new YamlJsonTranslator(); + + /** + * setup Db Provider Parameters. + * + * @throws PfModelException if an error occurs + */ + @BeforeAll + public static void setupDbProviderParameters() throws PfModelException { + ClRuntimeParameterGroup controlLoopParameters = CommonTestData.geParameterGroup(0, "instantproviderdb"); + + modelsProvider = + CommonTestData.getPolicyModelsProvider(controlLoopParameters.getDatabaseProviderParameters()); + clProvider = new ControlLoopProvider(controlLoopParameters.getDatabaseProviderParameters()); + var participantStatisticsProvider = + new ParticipantStatisticsProvider(controlLoopParameters.getDatabaseProviderParameters()); + var clElementStatisticsProvider = + new ClElementStatisticsProvider(controlLoopParameters.getDatabaseProviderParameters()); + commissioningProvider = new CommissioningProvider(modelsProvider, clProvider); + var monitoringProvider = + new MonitoringProvider(participantStatisticsProvider, clElementStatisticsProvider, clProvider); + var participantProvider = new ParticipantProvider(controlLoopParameters.getDatabaseProviderParameters()); + var controlLoopUpdatePublisher = Mockito.mock(ParticipantControlLoopUpdatePublisher.class); + var controlLoopStateChangePublisher = Mockito.mock(ParticipantControlLoopStateChangePublisher.class); + var participantRegisterAckPublisher = Mockito.mock(ParticipantRegisterAckPublisher.class); + var participantDeregisterAckPublisher = Mockito.mock(ParticipantDeregisterAckPublisher.class); + var participantUpdatePublisher = Mockito.mock(ParticipantUpdatePublisher.class); + supervisionHandler = new SupervisionHandler(clProvider, participantProvider, monitoringProvider, + commissioningProvider, controlLoopUpdatePublisher, controlLoopStateChangePublisher, + participantRegisterAckPublisher, participantDeregisterAckPublisher, participantUpdatePublisher); + } + + @AfterAll + public static void closeDbProvider() throws PfModelException { + clProvider.close(); + modelsProvider.close(); + } + + @Test + void testReceiveParticipantRegister() throws Exception { + final ParticipantRegister participantRegisterMsg = new ParticipantRegister(); + participantRegisterMsg.setParticipantId(getParticipantId()); + participantRegisterMsg.setTimestamp(Instant.now()); + participantRegisterMsg.setParticipantType(getParticipantType()); + + synchronized (lockit) { + ParticipantRegisterListener participantRegisterListener = + new ParticipantRegisterListener(supervisionHandler); + ToscaServiceTemplate serviceTemplate = yamlTranslator + .fromYaml(ResourceUtils.getResourceAsString(TOSCA_SERVICE_TEMPLATE_YAML), ToscaServiceTemplate.class); + + List<ToscaNodeTemplate> listOfTemplates = commissioningProvider.getControlLoopDefinitions(null, null); + commissioningProvider.createControlLoopDefinitions(serviceTemplate); + participantRegisterListener.onTopicEvent(INFRA, TOPIC, null, participantRegisterMsg); + } + } + + @Test + void testSendParticipantRegisterAck() throws Exception { + final ParticipantRegisterAck participantRegisterAckMsg = new ParticipantRegisterAck(); + participantRegisterAckMsg.setMessage("ParticipantRegisterAck message"); + participantRegisterAckMsg.setResponseTo(UUID.randomUUID()); + participantRegisterAckMsg.setResult(true); + + synchronized (lockit) { + ParticipantRegisterAckPublisher clRegisterAckPublisher = new ParticipantRegisterAckPublisher(); + clRegisterAckPublisher.active(Collections.singletonList(Mockito.mock(TopicSink.class))); + clRegisterAckPublisher.send(participantRegisterAckMsg); + } + } + + @Test + void testReceiveParticipantDeregister() throws Exception { + final ParticipantDeregister participantDeregisterMsg = new ParticipantDeregister(); + participantDeregisterMsg.setParticipantId(getParticipantId()); + participantDeregisterMsg.setTimestamp(Instant.now()); + participantDeregisterMsg.setParticipantType(getParticipantType()); + + synchronized (lockit) { + ParticipantDeregisterListener participantDeregisterListener = + new ParticipantDeregisterListener(supervisionHandler); + participantDeregisterListener.onTopicEvent(INFRA, TOPIC, null, participantDeregisterMsg); + } + } + + @Test + void testSendParticipantDeregisterAck() throws Exception { + final ParticipantDeregisterAck participantDeregisterAckMsg = new ParticipantDeregisterAck(); + participantDeregisterAckMsg.setMessage("ParticipantDeregisterAck message"); + participantDeregisterAckMsg.setResponseTo(UUID.randomUUID()); + participantDeregisterAckMsg.setResult(true); + + synchronized (lockit) { + ParticipantDeregisterAckPublisher clDeregisterAckPublisher = new ParticipantDeregisterAckPublisher(); + clDeregisterAckPublisher.active(Collections.singletonList(Mockito.mock(TopicSink.class))); + clDeregisterAckPublisher.send(participantDeregisterAckMsg); + } + } + + @Test + void testSendParticipantUpdate() throws Exception { + final ParticipantUpdate participantUpdateMsg = new ParticipantUpdate(); + participantUpdateMsg.setParticipantId(getParticipantId()); + participantUpdateMsg.setTimestamp(Instant.now()); + participantUpdateMsg.setParticipantType(getParticipantType()); + participantUpdateMsg.setTimestamp(Instant.ofEpochMilli(3000)); + participantUpdateMsg.setMessageId(UUID.randomUUID()); + + ToscaServiceTemplate toscaServiceTemplate = new ToscaServiceTemplate(); + toscaServiceTemplate.setName("serviceTemplate"); + toscaServiceTemplate.setDerivedFrom("parentServiceTemplate"); + toscaServiceTemplate.setDescription("Description of serviceTemplate"); + toscaServiceTemplate.setVersion("1.2.3"); + + ControlLoopElementDefinition clDefinition = new ControlLoopElementDefinition(); + clDefinition.setId(UUID.randomUUID()); + clDefinition.setControlLoopElementToscaServiceTemplate(toscaServiceTemplate); + Map<String, String> commonPropertiesMap = Map.of("Prop1", "PropValue"); + clDefinition.setCommonPropertiesMap(commonPropertiesMap); + + Map<UUID, ControlLoopElementDefinition> controlLoopElementDefinitionMap = + Map.of(UUID.randomUUID(), clDefinition); + + Map<ToscaConceptIdentifier, Map<UUID, ControlLoopElementDefinition>> + participantDefinitionUpdateMap = Map.of(getParticipantId(), controlLoopElementDefinitionMap); + participantUpdateMsg.setParticipantDefinitionUpdateMap(participantDefinitionUpdateMap); + + synchronized (lockit) { + ParticipantUpdatePublisher clUpdatePublisher = new ParticipantUpdatePublisher(); + clUpdatePublisher.active(Collections.singletonList(Mockito.mock(TopicSink.class))); + clUpdatePublisher.send(participantUpdateMsg); + } + } + + @Test + void testReceiveParticipantUpdateAckMessage() throws Exception { + final ParticipantUpdateAck participantUpdateAckMsg = new ParticipantUpdateAck(); + participantUpdateAckMsg.setMessage("ParticipantUpdateAck message"); + participantUpdateAckMsg.setResponseTo(UUID.randomUUID()); + participantUpdateAckMsg.setResult(true); + + synchronized (lockit) { + ParticipantUpdateAckListener participantUpdateAckListener = + new ParticipantUpdateAckListener(supervisionHandler); + participantUpdateAckListener.onTopicEvent(INFRA, TOPIC, null, participantUpdateAckMsg); + } + } + + private ToscaConceptIdentifier getParticipantId() { + return new ToscaConceptIdentifier("org.onap.PM_Policy", "1.0.0"); + } + + private ToscaConceptIdentifier getParticipantType() { + return new ToscaConceptIdentifier("org.onap.policy.controlloop.PolicyControlLoopParticipant", "2.3.1"); + } +} diff --git a/runtime-controlloop/src/test/java/org/onap/policy/clamp/controlloop/runtime/util/CommonTestData.java b/runtime-controlloop/src/test/java/org/onap/policy/clamp/controlloop/runtime/util/CommonTestData.java index aa17e9c4f..464c14354 100644 --- a/runtime-controlloop/src/test/java/org/onap/policy/clamp/controlloop/runtime/util/CommonTestData.java +++ b/runtime-controlloop/src/test/java/org/onap/policy/clamp/controlloop/runtime/util/CommonTestData.java @@ -27,6 +27,11 @@ 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.common.utils.resources.ResourceUtils; +import org.onap.policy.models.base.PfModelException; +import org.onap.policy.models.base.PfModelRuntimeException; +import org.onap.policy.models.provider.PolicyModelsProvider; +import org.onap.policy.models.provider.PolicyModelsProviderFactory; +import org.onap.policy.models.provider.PolicyModelsProviderParameters; /** * Class to hold/create all parameters for test cases. @@ -63,4 +68,19 @@ public class CommonTestData { return ResourceUtils.getResourceAsString("src/test/resources/parameters/InstantiationConfigParametersStd.json") .replace("${port}", String.valueOf(port)).replace("${dbName}", "jdbc:h2:mem:" + dbName); } + + /** + * Create a new PolicyModelsProvider. + * + * @param databaseProviderParameters the database Provider Parameters + * @return a new PolicyModelsProvider + */ + public static PolicyModelsProvider getPolicyModelsProvider( + PolicyModelsProviderParameters databaseProviderParameters) { + try { + return new PolicyModelsProviderFactory().createPolicyModelsProvider(databaseProviderParameters); + } catch (PfModelException e) { + throw new PfModelRuntimeException(e); + } + } } diff --git a/runtime-controlloop/src/test/resources/parameters/InstantiationConfigParametersStd.json b/runtime-controlloop/src/test/resources/parameters/InstantiationConfigParametersStd.json index 06f4370e8..71df254e2 100644 --- a/runtime-controlloop/src/test/resources/parameters/InstantiationConfigParametersStd.json +++ b/runtime-controlloop/src/test/resources/parameters/InstantiationConfigParametersStd.json @@ -50,13 +50,6 @@ "localhost" ], "topicCommInfrastructure": "dmaap" - }, - { - "topic": "POLICY-NOTIFICATION", - "servers": [ - "localhost" - ], - "topicCommInfrastructure": "dmaap" } ] } diff --git a/runtime-controlloop/src/test/resources/parameters/TestParameters.json b/runtime-controlloop/src/test/resources/parameters/TestParameters.json index 9bcd764cb..680e070f2 100644 --- a/runtime-controlloop/src/test/resources/parameters/TestParameters.json +++ b/runtime-controlloop/src/test/resources/parameters/TestParameters.json @@ -50,13 +50,6 @@ "localhost" ], "topicCommInfrastructure": "dmaap" - }, - { - "topic": "POLICY-NOTIFICATION", - "servers": [ - "localhost" - ], - "topicCommInfrastructure": "dmaap" } ] } diff --git a/runtime-controlloop/src/test/resources/parameters/Unreadable.json b/runtime-controlloop/src/test/resources/parameters/Unreadable.json index 0ea56eb5d..ddd04edc7 100644 --- a/runtime-controlloop/src/test/resources/parameters/Unreadable.json +++ b/runtime-controlloop/src/test/resources/parameters/Unreadable.json @@ -50,13 +50,6 @@ "localhost" ], "topicCommInfrastructure": "dmaap" - }, - { - "topic": "POLICY-NOTIFICATION", - "servers": [ - "localhost" - ], - "topicCommInfrastructure": "dmaap" } ] } diff --git a/runtime/src/main/resources/clds/camel/rest/clamp-api-v2.xml b/runtime/src/main/resources/clds/camel/rest/clamp-api-v2.xml index 3addb55f8..01ee071ee 100644 --- a/runtime/src/main/resources/clds/camel/rest/clamp-api-v2.xml +++ b/runtime/src/main/resources/clds/camel/rest/clamp-api-v2.xml @@ -1767,6 +1767,49 @@ </route> </post> + <put uri="/v2/toscaControlLoop/putToscaInstantiationStateChange" + type="java.lang.String" + consumes="plain/text" + outType="java.lang.String" + produces="application/json" + bindingMode="off"> + <route> + <removeHeaders pattern="*"/> + <setProperty name="raiseHttpExceptionFlag"> + <simple resultType="java.lang.Boolean">true</simple> + </setProperty> + <setHeader name="Content-Type"> + <constant>application/json</constant> + </setHeader> + <doTry> + <to + uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=startLog(*, 'Update the global properties')"/> + <to + uri="bean:org.onap.policy.clamp.authorization.AuthorizationController?method=authorize(*,'cl','','update')"/> + <to uri="direct:put-tosca-instantiation"/> + <to + uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=endLog()"/> + <doCatch> + <exception>java.lang.Exception</exception> + <handled> + <constant>true</constant> + </handled> + <to + uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=errorLog()"/> + <log loggingLevel="ERROR" + message="Tosca Instantiation State Change Service FAILED"/> + + <setHeader name="CamelHttpResponseCode"> + <constant>500</constant> + </setHeader> + <setBody> + <simple>Tosca Instantiation State Change Service FAILED</simple> + </setBody> + </doCatch> + </doTry> + </route> + </put> + <get uri="/v2/clampInformation" outType="org.onap.policy.clamp.clds.model.ClampInformation" produces="application/json"> <route> diff --git a/runtime/src/main/resources/clds/camel/routes/controlloop-flows.xml b/runtime/src/main/resources/clds/camel/routes/controlloop-flows.xml index c33aa5924..2c063f105 100644 --- a/runtime/src/main/resources/clds/camel/routes/controlloop-flows.xml +++ b/runtime/src/main/resources/clds/camel/routes/controlloop-flows.xml @@ -135,6 +135,31 @@ </doFinally> </doTry> </route> + <route id="put-tosca-instantiation"> + <from uri="direct:put-tosca-instantiation"/> + <doTry> + <log loggingLevel="INFO" + message="Change the tosca instantiation state service"/> + <to + uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=invokeLog('Controlloop', 'Change the tosca instantiation state service')"/> + <setHeader name="CamelHttpMethod"> + <constant>PUT</constant> + </setHeader> + <setHeader name="Content-Type"> + <constant>application/json</constant> + </setHeader> + <log loggingLevel="INFO" + message="Endpoint to send Tosca Instantiation state change Service: {{clamp.config.controlloop.runtime.url}}/onap/controlloop/v2/instantiation/command"></log> + <toD + uri="{{clamp.config.controlloop.runtime.url}}/onap/controlloop/v2/instantiation/command?bridgeEndpoint=true&useSystemProperties=true&throwExceptionOnFailure=${exchangeProperty[raiseHttpExceptionFlag]}&authMethod=Basic&authUsername={{clamp.config.controlloop.runtime.userName}}&authPassword={{clamp.config.controlloop.runtime.password}}&authenticationPreemptive=true&connectionClose=true"/> + <convertBodyTo type="java.lang.String"/> + <doFinally> + <to uri="direct:reset-raise-http-exception-flag"/> + <to + uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=invokeReturnLog()"/> + </doFinally> + </doTry> + </route> <route id="get-json-schema"> <from uri="direct:get-json-schema"/> <doTry> |