diff options
Diffstat (limited to 'participant')
61 files changed, 3042 insertions, 1630 deletions
diff --git a/participant/participant-impl/participant-impl-kubernetes/pom.xml b/participant/participant-impl/participant-impl-kubernetes/pom.xml index a85c5fdbf..504d91d78 100644 --- a/participant/participant-impl/participant-impl-kubernetes/pom.xml +++ b/participant/participant-impl/participant-impl-kubernetes/pom.xml @@ -19,7 +19,7 @@ --> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> @@ -30,5 +30,116 @@ <artifactId>policy-clamp-participant-impl-kubernetes</artifactId> <name>${project.artifactId}</name> - <description>Kubernetes participant, that allows microservices running in Kubernetes to partake in control loops</description> + <description>Kubernetes participant, that allows k8s pods to partake in control loops</description> + + <properties> + <springboot.version>2.5.0</springboot.version> + <immutable.version>2.8.8</immutable.version> + <springfox.version>3.0.0</springfox.version> + </properties> + + <dependencyManagement> + <dependencies> + <!-- Spring Boot BOM --> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-dependencies</artifactId> + <version>${springboot.version}</version> + <type>pom</type> + <scope>import</scope> + </dependency> + </dependencies> + </dependencyManagement> + + <dependencies> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-web</artifactId> + </dependency> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-webflux</artifactId> + </dependency> + <dependency> + <groupId>org.apache.tomcat.embed</groupId> + <artifactId>tomcat-embed-core</artifactId> + </dependency> + <dependency> + <groupId>org.immutables</groupId> + <artifactId>value</artifactId> + <version>${immutable.version}</version> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>org.immutables</groupId> + <artifactId>gson</artifactId> + <version>${immutable.version}</version> + </dependency> + <dependency> + <groupId>org.json</groupId> + <artifactId>json</artifactId> + </dependency> + <dependency> + <groupId>org.projectlombok</groupId> + <artifactId>lombok</artifactId> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>io.springfox</groupId> + <artifactId>springfox-swagger2</artifactId> + <version>${springfox.version}</version> + </dependency> + <dependency> + <groupId>io.springfox</groupId> + <artifactId>springfox-swagger-ui</artifactId> + <version>${springfox.version}</version> + <scope>runtime</scope> + </dependency> + <dependency> + <groupId>commons-fileupload</groupId> + <artifactId>commons-fileupload</artifactId> + <version>1.4</version> + </dependency> + <dependency> + <groupId>org.onap.policy.clamp.participant</groupId> + <artifactId>policy-clamp-participant-intermediary</artifactId> + <version>${project.version}</version> + </dependency> + + </dependencies> + + <build> + <resources> + <!-- Output the version of the control loop system --> + <resource> + <directory>src/main/resources</directory> + <filtering>true</filtering> + <includes> + <include>**/version.txt</include> + </includes> + </resource> + <resource> + <directory>src/main/resources</directory> + <filtering>false</filtering> + <excludes> + <exclude>**/version.txt</exclude> + </excludes> + </resource> + </resources> + <plugins> + <plugin> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-maven-plugin</artifactId> + <version>${springboot.version}</version> + <executions> + <execution> + <goals> + <goal>repackage</goal> + </goals> + <phase>package</phase> + </execution> + </executions> + </plugin> + </plugins> + </build> </project> diff --git a/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/controlloop/participant/kubernetes/Application.java b/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/controlloop/participant/kubernetes/Application.java new file mode 100644 index 000000000..ffa0bceb9 --- /dev/null +++ b/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/controlloop/participant/kubernetes/Application.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.participant.kubernetes; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +/** + * Starter. + * + */ +@SpringBootApplication +public class Application { + /** + * Main class. + * @param args args + */ + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } +} + diff --git a/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/controlloop/participant/kubernetes/configurations/BeanFactory.java b/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/controlloop/participant/kubernetes/configurations/BeanFactory.java new file mode 100644 index 000000000..3199d0cd9 --- /dev/null +++ b/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/controlloop/participant/kubernetes/configurations/BeanFactory.java @@ -0,0 +1,71 @@ +/*- + * ========================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.apache.catalina.connector.Connector; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory; +import org.springframework.boot.web.servlet.server.ServletWebServerFactory; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.multipart.MultipartResolver; +import org.springframework.web.multipart.commons.CommonsMultipartResolver; + +/** + * Bean Factory class for helm client. + */ +@Configuration +public class BeanFactory { + + @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 + */ + @Bean(name = "multipartResolver") + public MultipartResolver multipartResolver() { + var multipartResolver = new CommonsMultipartResolver(); + 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/ParametersConfig.java b/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/controlloop/participant/kubernetes/configurations/ParametersConfig.java new file mode 100644 index 000000000..5f2a4e4ad --- /dev/null +++ b/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/controlloop/participant/kubernetes/configurations/ParametersConfig.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.kubernetes.configurations; + +import org.onap.policy.clamp.controlloop.common.exception.ControlLoopException; +import org.onap.policy.clamp.controlloop.participant.kubernetes.parameters.ParticipantK8sParameterHandler; +import org.onap.policy.clamp.controlloop.participant.kubernetes.parameters.ParticipantK8sParameters; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class ParametersConfig { + + @Value("${participant.file}") + private String file; + + @Bean + public ParticipantK8sParameters participantK8sParameters() throws ControlLoopException { + return new ParticipantK8sParameterHandler().toParticipantK8sParameters(file); + } +} + diff --git a/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/controlloop/participant/kubernetes/configurations/ParticipantIntermediaryConfig.java b/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/controlloop/participant/kubernetes/configurations/ParticipantIntermediaryConfig.java new file mode 100644 index 000000000..d8c39925b --- /dev/null +++ b/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/controlloop/participant/kubernetes/configurations/ParticipantIntermediaryConfig.java @@ -0,0 +1,48 @@ +/*- + * ============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.configurations; + +import org.onap.policy.clamp.controlloop.participant.intermediary.api.ParticipantIntermediaryApi; +import org.onap.policy.clamp.controlloop.participant.intermediary.api.ParticipantIntermediaryFactory; +import org.onap.policy.clamp.controlloop.participant.kubernetes.handler.ControlLoopElementHandler; +import org.onap.policy.clamp.controlloop.participant.kubernetes.parameters.ParticipantK8sParameters; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class ParticipantIntermediaryConfig { + + /** + * Create ParticipantIntermediaryApi. + * + * @param parameters the K8s Participant Parameters + * @param clElementHandler the ControlLoop Element Handler + * @return ParticipantIntermediaryApi + */ + @Bean + public ParticipantIntermediaryApi participantIntermediaryApi(ParticipantK8sParameters parameters, + ControlLoopElementHandler clElementHandler) { + ParticipantIntermediaryApi intermediaryApi = new ParticipantIntermediaryFactory().createApiImplementation(); + intermediaryApi.init(parameters.getIntermediaryParameters()); + intermediaryApi.registerControlLoopElementListener(clElementHandler); + return intermediaryApi; + } +} diff --git a/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/controlloop/participant/kubernetes/controller/ChartController.java b/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/controlloop/participant/kubernetes/controller/ChartController.java new file mode 100644 index 000000000..427b06fc5 --- /dev/null +++ b/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/controlloop/participant/kubernetes/controller/ChartController.java @@ -0,0 +1,166 @@ +/*- + * ========================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.controller; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiResponse; +import io.swagger.annotations.ApiResponses; +import java.io.IOException; +import java.util.ArrayList; +import org.onap.policy.clamp.controlloop.participant.kubernetes.exception.ServiceException; +import org.onap.policy.clamp.controlloop.participant.kubernetes.models.ChartInfo; +import org.onap.policy.clamp.controlloop.participant.kubernetes.models.ChartList; +import org.onap.policy.clamp.controlloop.participant.kubernetes.models.InstallationInfo; +import org.onap.policy.clamp.controlloop.participant.kubernetes.service.ChartService; +import org.onap.policy.common.utils.coder.CoderException; +import org.onap.policy.common.utils.coder.StandardCoder; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RequestPart; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.multipart.MultipartFile; + +@RestController("chartController") +@RequestMapping("helm") +@Api(tags = {"chart"}) +public class ChartController { + + @Autowired + private ChartService chartService; + + private static final StandardCoder CODER = new StandardCoder(); + + /** + * REST endpoint to get all the charts. + * + * @return List of charts installed + */ + @GetMapping(path = "/charts", produces = MediaType.APPLICATION_JSON_VALUE) + @ApiOperation(value = "Return all Charts") + @ApiResponses(value = {@ApiResponse(code = 200, message = "chart List")}) + public ResponseEntity<ChartList> getAllCharts() { + return new ResponseEntity<>(ChartList.builder().charts(new ArrayList<>(chartService.getAllCharts())).build(), + HttpStatus.OK); + } + + /** + * REST endpoint to install a helm chart. + * + * @param info Info of the chart to be installed + * @return Status of the install operation + * @throws ServiceException incase of error + */ + @PostMapping(path = "/install", consumes = MediaType.APPLICATION_JSON_VALUE, + produces = MediaType.APPLICATION_JSON_VALUE) + @ApiOperation(value = "Install the chart") + @ApiResponses(value = {@ApiResponse(code = 201, message = "chart Installed")}) + public ResponseEntity<Object> installChart(@RequestBody InstallationInfo info) + throws ServiceException, IOException { + ChartInfo chart = chartService.getChart(info.getName(), info.getVersion()); + if (chart == null) { + return new ResponseEntity<>(HttpStatus.NOT_FOUND); + } + + chartService.installChart(chart); + return new ResponseEntity<>(HttpStatus.CREATED); + } + + /** + * REST endpoint to uninstall a specific chart. + * + * @param name name of the chart + * @param version version of the chart + * @return Status of operation + * @throws ServiceException incase of error. + */ + @DeleteMapping(path = "/uninstall/{name}/{version}", produces = MediaType.APPLICATION_JSON_VALUE) + @ApiOperation(value = "Uninstall the Chart") + @ApiResponses(value = {@ApiResponse(code = 201, message = "chart Uninstalled")}) + public ResponseEntity<Object> uninstallChart(@PathVariable("name") String name, + @PathVariable("version") String version) throws ServiceException { + ChartInfo chart = chartService.getChart(name, version); + if (chart == null) { + return new ResponseEntity<>(HttpStatus.NOT_FOUND); + } + + chartService.uninstallChart(chart); + return new ResponseEntity<>(HttpStatus.NO_CONTENT); + } + + /** + * REST endpoint to onboard a chart. + * + * @param chartFile Multipart file for the helm chart + * @param infoJson AppInfo of the chart + * @return Status of onboard operation + * @throws ServiceException incase of error + * @throws IOException incase of IO error + */ + @PostMapping(path = "/charts", consumes = MediaType.MULTIPART_FORM_DATA_VALUE, + produces = MediaType.APPLICATION_JSON_VALUE) + @ApiOperation(value = "Onboard the Chart") + @ApiResponses(value = {@ApiResponse(code = 201, message = "Chart Onboarded")}) + public ResponseEntity<String> onboardChart(@RequestPart("chart") MultipartFile chartFile, + @RequestParam(name = "values", required = false) MultipartFile overrideFile, + @RequestParam("info") String infoJson) throws ServiceException, IOException { + + ChartInfo info; + try { + info = CODER.decode(infoJson, ChartInfo.class); + } catch (CoderException e) { + throw new ServiceException("Error parsing the chart information", e); + } + + chartService.saveChart(info, chartFile, overrideFile); + return new ResponseEntity<>(HttpStatus.OK); + } + + /** + * REST endpoint to delete a specific helm chart. + * + * @param name name of the chart + * @param version version of the chart + * @return Status of operation + * @throws ServiceException incase of error. + */ + @DeleteMapping(path = "/charts/{name}/{version}") + @ApiOperation(value = "Delete the chart") + @ApiResponses(value = {@ApiResponse(code = 204, message = "Chart Deleted")}) + public ResponseEntity<Object> deleteChart(@PathVariable("name") String name, + @PathVariable("version") String version) throws ServiceException { + + ChartInfo chart = chartService.getChart(name, version); + if (chart == null) { + return new ResponseEntity<>(HttpStatus.NOT_FOUND); + } + + chartService.deleteChart(chart); + return new ResponseEntity<>(HttpStatus.NO_CONTENT); + } +} diff --git a/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/controlloop/participant/kubernetes/exception/ServiceException.java b/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/controlloop/participant/kubernetes/exception/ServiceException.java new file mode 100644 index 000000000..9a825cf75 --- /dev/null +++ b/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/controlloop/participant/kubernetes/exception/ServiceException.java @@ -0,0 +1,32 @@ +/*- + * ========================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.exception; + +public class ServiceException extends Exception { + + private static final long serialVersionUID = 6810785674716590648L; + + public ServiceException(String message) { + super(message); + } + + public ServiceException(String message, Exception originalException) { + super(message, originalException); + } +} 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 new file mode 100644 index 000000000..5f1dcb8d4 --- /dev/null +++ b/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/controlloop/participant/kubernetes/handler/ControlLoopElementHandler.java @@ -0,0 +1,147 @@ +/*- + * ============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.handler; + + +import java.io.IOException; +import java.lang.invoke.MethodHandles; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; +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; +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.models.ChartInfo; +import org.onap.policy.clamp.controlloop.participant.kubernetes.service.ChartService; +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; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +/** + * This class handles implementation of controlLoopElement updates. + */ +@Component +public class ControlLoopElementHandler implements ControlLoopElementListener { + private static final Logger LOGGER = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); + + @Autowired + private ChartService chartService; + + @Autowired + private ParticipantIntermediaryApi intermediaryApi; + + // Map of CLElement Id and installed Helm charts + private final Map<UUID, ChartInfo> chartMap = new HashMap<>(); + + /** + * Callback method to handle a control loop element state change. + * + * @param controlLoopElementId the ID of the control loop element + * @param currentState the current state of the control loop element + * @param newState the state to which the control loop element is changing to + */ + @Override + public synchronized void controlLoopElementStateChange(UUID controlLoopElementId, ControlLoopState currentState, + ControlLoopOrderedState newState) { + switch (newState) { + case UNINITIALISED: + ChartInfo chart = chartMap.get(controlLoopElementId); + if (chart != null) { + LOGGER.info("Helm deployment to be deleted {} ", chart.getReleaseName()); + try { + chartService.uninstallChart(chart); + intermediaryApi.updateControlLoopElementState(controlLoopElementId, newState, + ControlLoopState.UNINITIALISED); + } catch (ServiceException se) { + LOGGER.warn("deletion of Helm deployment failed", se); + } + } + break; + case PASSIVE: + intermediaryApi.updateControlLoopElementState(controlLoopElementId, newState, ControlLoopState.PASSIVE); + break; + case RUNNING: + intermediaryApi.updateControlLoopElementState(controlLoopElementId, newState, ControlLoopState.RUNNING); + break; + default: + LOGGER.warn("cannot transition from state {} to state {}", currentState, newState); + break; + } + } + + + /** + * Callback method to handle an update on a control loop element. + * + * @param element the information on the control loop element + * @param controlLoopDefinition toscaServiceTemplate + * @throws PfModelException in case of an exception + */ + @Override + public synchronized void controlLoopElementUpdate(ControlLoopElement element, + ToscaServiceTemplate controlLoopDefinition) throws PfModelException { + + for (Map.Entry<String, ToscaNodeTemplate> nodeTemplate : controlLoopDefinition.getToscaTopologyTemplate() + .getNodeTemplates().entrySet()) { + + // Fetching the node template of corresponding CL element + if (element.getDefinition().getName().equals(nodeTemplate.getKey()) + && nodeTemplate.getValue().getProperties().containsKey("chart")) { + @SuppressWarnings("unchecked") + Map<String, Object> chartData = + (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 repositoryValue = chartData.get("repository"); + if (repositoryValue != null) { + chart.setRepository(String.valueOf(repositoryValue)); + } + chartService.installChart(chart); + chartMap.put(element.getId(), chart); + } catch (IOException | ServiceException ise) { + LOGGER.warn("installation of Helm chart failed", ise); + } + } + } + } + + /** + * Overridden method. + * + * @param controlLoopElementId controlLoopElement id + * @throws PfModelException incase of error + */ + @Override + public synchronized void handleStatistics(UUID controlLoopElementId) throws PfModelException { + // TODO Implement statistics functionality + } +} 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 new file mode 100644 index 000000000..456122f3d --- /dev/null +++ b/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/controlloop/participant/kubernetes/helm/HelmClient.java @@ -0,0 +1,201 @@ +/*- + * ========================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.ArrayList; +import java.util.Arrays; +import java.util.List; +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; +import org.onap.policy.clamp.controlloop.participant.kubernetes.service.ChartStore; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +/** + * Client to talk with Helm cli. Supports helm3 + version + */ +@Component +public class HelmClient { + + @Autowired + private ChartStore chartStore; + + private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); + + + /** + * Install a chart. + * + * @param chart name and version. + * @throws ServiceException incase of error + */ + public void installChart(ChartInfo chart) throws ServiceException { + var processBuilder = prepareCreateNamespaceCommand(chart.getNamespace()); + try { + executeCommand(processBuilder); + } catch (ServiceException e) { + logger.warn("Namespace not created", e); + } + processBuilder = prepareInstallCommand(chart); + logger.info("Installing helm chart {} from the repository {} ", chart.getChartName(), chart.getRepository()); + executeCommand(processBuilder); + logger.info("Chart {} installed successfully", chart.getChartName()); + } + + /** + * Finds helm chart repository for the chart. + * + * @param chart ChartInfo. + * @throws ServiceException incase of error + */ + public String findChartRepository(ChartInfo chart) throws ServiceException, IOException { + updateHelmRepo(); + logger.info("Looking for helm chart {} in all the configured helm repositories", chart.getChartName()); + String repository = null; + + var process = helmRepoVerifyCommand(chart.getChartName()).start(); + + try (var reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) { + String line = reader.readLine(); + while (line != null) { + if (line.contains(chart.getChartName())) { + repository = line.split("/")[0]; + logger.info("Helm chart located in the repository {} ", repository); + return repository; + } + line = reader.readLine(); + } + } + + var localHelmChartDir = chartStore.getAppPath(chart.getChartName(), chart.getVersion()).toString(); + logger.info("Chart not found in helm repositories, verifying local repo {} ", localHelmChartDir); + if (verifyLocalHelmRepo(localHelmChartDir + "/" + chart.getChartName())) { + repository = localHelmChartDir; + } + + return repository; + } + + /** + * Uninstall a chart. + * + * @param chart name and version. + * @throws ServiceException incase of error + */ + public void uninstallChart(ChartInfo chart) throws ServiceException { + executeCommand(prepareUnInstallCommand(chart)); + } + + static String executeCommand(ProcessBuilder processBuilder) throws ServiceException { + var commandStr = toString(processBuilder); + + processBuilder.redirectInput(ProcessBuilder.Redirect.DISCARD); + + try { + var process = processBuilder.start(); + process.waitFor(); + int exitValue = process.exitValue(); + + if (exitValue != 0) { + var error = IOUtils.toString(process.getErrorStream(), StandardCharsets.UTF_8); + throw new ServiceException("Command execution failed: " + commandStr + " " + error); + } + var output = IOUtils.toString(process.getInputStream(), StandardCharsets.UTF_8); + logger.debug("Command <{}> execution, output: {}", commandStr, output); + return output; + } catch (InterruptedException ie) { + Thread.currentThread().interrupt(); + throw new ServiceException( + "Failed to execute the Command: " + commandStr + ", the command was interrupted", ie); + } catch (Exception exc) { + throw new ServiceException("Failed to execute the Command: " + commandStr, exc); + } + } + + private ProcessBuilder prepareInstallCommand(ChartInfo chart) { + + // @formatter:off + List<String> helmArguments = new ArrayList<>( + Arrays.asList( + "helm", + "install", chart.getReleaseName(), chart.getRepository() + "/" + chart.getChartName(), + "--version", chart.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)); + } + + return new ProcessBuilder().command(helmArguments); + } + + private ProcessBuilder prepareUnInstallCommand(ChartInfo chart) { + return new ProcessBuilder("helm", "delete", chart.getReleaseName(), "--namespace", chart.getNamespace()); + } + + private ProcessBuilder prepareCreateNamespaceCommand(String namespace) { + return new ProcessBuilder().command("kubectl", "create", "namespace", namespace); + } + + private ProcessBuilder helmRepoVerifyCommand(String chartName) { + return new ProcessBuilder().command("bash", "-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"); + List<String> helmArguments = Arrays.asList("helm", "repo", "update"); + + executeCommand(new ProcessBuilder().command(helmArguments)); + 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; + } + + protected static String toString(ProcessBuilder processBuilder) { + return String.join(" ", processBuilder.command()); + } +} 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 new file mode 100644 index 000000000..6bfb7aed5 --- /dev/null +++ b/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/controlloop/participant/kubernetes/models/ChartInfo.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.models; + +import lombok.Data; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import org.immutables.gson.Gson; + +@Data +@RequiredArgsConstructor +@Gson.TypeAdapters +public class ChartInfo { + + @NonNull + private String releaseName; + + @NonNull + private String chartName; + + @NonNull + private String version; + + @NonNull + private String namespace; + + private String repository; + +} diff --git a/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/controlloop/participant/kubernetes/models/ChartList.java b/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/controlloop/participant/kubernetes/models/ChartList.java new file mode 100644 index 000000000..c86bff58a --- /dev/null +++ b/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/controlloop/participant/kubernetes/models/ChartList.java @@ -0,0 +1,31 @@ +/*- + * ========================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.models; + +import java.util.Collection; +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +@Builder +public class ChartList { + private Collection<ChartInfo> charts; +} diff --git a/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/controlloop/participant/kubernetes/models/InstallationInfo.java b/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/controlloop/participant/kubernetes/models/InstallationInfo.java new file mode 100644 index 000000000..b21e93a01 --- /dev/null +++ b/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/controlloop/participant/kubernetes/models/InstallationInfo.java @@ -0,0 +1,29 @@ +/*- + * ========================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.models; + +import lombok.Getter; +import org.immutables.gson.Gson; + +@Getter +@Gson.TypeAdapters +public class InstallationInfo { + private String name; + private String version; +} diff --git a/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/controlloop/participant/kubernetes/parameters/ParticipantK8sParameterHandler.java b/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/controlloop/participant/kubernetes/parameters/ParticipantK8sParameterHandler.java new file mode 100644 index 000000000..1a7dc35e8 --- /dev/null +++ b/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/controlloop/participant/kubernetes/parameters/ParticipantK8sParameterHandler.java @@ -0,0 +1,73 @@ +/*- + * ============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.parameters; + +import java.io.File; +import javax.ws.rs.core.Response; +import org.onap.policy.clamp.controlloop.common.exception.ControlLoopException; +import org.onap.policy.common.parameters.BeanValidationResult; +import org.onap.policy.common.utils.coder.Coder; +import org.onap.policy.common.utils.coder.CoderException; +import org.onap.policy.common.utils.coder.StandardCoder; + +/** + * This class handles reading, parsing and validating of control loop participant parameters from JSON files. + */ +public class ParticipantK8sParameterHandler { + private static final Coder CODER = new StandardCoder(); + + /** + * Read the parameters from the path of the file. + * + * @param path path of the config file. + * @return the parameters read from the configuration file + * @throws ControlLoopException on parameter exceptions + */ + public ParticipantK8sParameters toParticipantK8sParameters(String path) throws ControlLoopException { + ParticipantK8sParameters parameters = null; + // Read the parameters + try { + // Read the parameters from JSON + var file = new File(path); + parameters = CODER.decode(file, ParticipantK8sParameters.class); + } catch (final CoderException e) { + final String errorMessage = + "error reading parameters from \"" + path + "\"\n" + "(" + e.getClass().getSimpleName() + ")"; + throw new ControlLoopException(Response.Status.NOT_ACCEPTABLE, errorMessage, e); + } + + // The JSON processing returns null if there is an empty file + if (parameters == null) { + final String errorMessage = "no parameters found in \"" + path + "\""; + throw new ControlLoopException(Response.Status.NOT_ACCEPTABLE, errorMessage); + } + + // validate the parameters + final BeanValidationResult validationResult = parameters.validate(); + if (!validationResult.isValid()) { + String returnMessage = + "validation error(s) on parameters from \"" + path + "\"\n" + validationResult.getResult(); + throw new ControlLoopException(Response.Status.NOT_ACCEPTABLE, returnMessage); + } + + return parameters; + } +} diff --git a/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/controlloop/participant/kubernetes/parameters/ParticipantK8sParameters.java b/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/controlloop/participant/kubernetes/parameters/ParticipantK8sParameters.java new file mode 100644 index 000000000..65b32433c --- /dev/null +++ b/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/controlloop/participant/kubernetes/parameters/ParticipantK8sParameters.java @@ -0,0 +1,59 @@ +/*- + * ============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.parameters; + +import javax.validation.constraints.NotBlank; +import lombok.Getter; +import org.onap.policy.clamp.controlloop.participant.intermediary.parameters.ParticipantIntermediaryParameters; +import org.onap.policy.common.parameters.ParameterGroupImpl; +import org.onap.policy.common.parameters.annotations.NotNull; +import org.onap.policy.common.parameters.annotations.Valid; +import org.onap.policy.models.provider.PolicyModelsProviderParameters; + +/** + * Class to hold all parameters needed for the kubernetes participant. + * + */ +@NotNull +@NotBlank +@Getter +public class ParticipantK8sParameters extends ParameterGroupImpl { + public static final String DEFAULT_LOCAL_CHART_DIR = "/var/helm-manager/local-charts"; + public static final String DEFAULT_INFO_FILE_NAME = "CHART_INFO.json"; + + @Valid + private ParticipantIntermediaryParameters intermediaryParameters; + @Valid + private PolicyModelsProviderParameters databaseProviderParameters; + + + private String localChartDirectory = DEFAULT_LOCAL_CHART_DIR; + private String infoFileName = DEFAULT_INFO_FILE_NAME; + + /** + * Create the kubernetes participant parameter group. + * + * @param name the parameter group name + */ + public ParticipantK8sParameters(final String name) { + super(name); + } +} 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 new file mode 100644 index 000000000..6accac339 --- /dev/null +++ b/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/controlloop/participant/kubernetes/service/ChartService.java @@ -0,0 +1,122 @@ +/*- + * ========================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.service; + +import java.io.IOException; +import java.lang.invoke.MethodHandles; +import java.util.Collection; +import org.onap.policy.clamp.controlloop.participant.kubernetes.exception.ServiceException; +import org.onap.policy.clamp.controlloop.participant.kubernetes.helm.HelmClient; +import org.onap.policy.clamp.controlloop.participant.kubernetes.models.ChartInfo; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; + +@Service +public class ChartService { + private final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); + + @Autowired + private ChartStore chartStore; + + @Autowired + private HelmClient helmClient; + + /** + * Get all the installed charts. + * @return list of charts. + */ + public Collection<ChartInfo> getAllCharts() { + return chartStore.getAllCharts(); + } + + /** + * Get specific chart info. + * @param name name of the app + * @param version version of the app + * @return chart + * @throws ServiceException incase of error. + */ + public ChartInfo getChart(String name, String version) throws ServiceException { + return chartStore.getChart(name, version); + } + + /** + * Save a helm chart. + * @param chartInfo name and version of the app. + * @param chartFile Helm chart file + * @return chart details of the helm chart + * @throws IOException incase of IO error + * @throws ServiceException incase of error + */ + public ChartInfo saveChart(ChartInfo chartInfo, MultipartFile chartFile, MultipartFile overrideFile) + throws IOException, ServiceException { + return chartStore.saveChart(chartInfo, chartFile, overrideFile); + } + + /** + * Delete a helm chart. + * @param chart name and version of the chart. + */ + public void deleteChart(ChartInfo chart) { + chartStore.deleteChart(chart); + } + + /** + * Install a helm chart. + * @param chart name and version. + * @throws ServiceException incase of error + */ + public void installChart(ChartInfo chart) throws ServiceException, IOException { + if (chart.getRepository() == null) { + String repository = findChartRepo(chart); + if (repository == null) { + logger.error("Chart repository could not be found. Skipping chart Installation " + + "for the chart {} ", chart.getChartName()); + return; + } else { + chart.setRepository(repository); + } + } + helmClient.installChart(chart); + } + + /** + * Finds helm chart repository for a given chart. + * @param chart chartInfo. + * @throws ServiceException incase of error + */ + public String findChartRepo(ChartInfo chart) throws ServiceException, IOException { + logger.info("Fetching helm chart repository for the given chart {} ", chart.getChartName()); + return helmClient.findChartRepository(chart); + } + + /** + * Uninstall a helm chart. + * @param chart name and version + * @throws ServiceException incase of error. + */ + public void uninstallChart(ChartInfo chart) throws ServiceException { + 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 new file mode 100644 index 000000000..2d0ce7a83 --- /dev/null +++ b/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/controlloop/participant/kubernetes/service/ChartStore.java @@ -0,0 +1,215 @@ +/*- + * ========================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.service; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import java.lang.invoke.MethodHandles; +import java.nio.file.FileVisitResult; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.SimpleFileVisitor; +import java.nio.file.attribute.BasicFileAttributes; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import org.onap.policy.clamp.controlloop.participant.kubernetes.exception.ServiceException; +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.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.util.FileSystemUtils; +import org.springframework.web.multipart.MultipartFile; + +@Component +public class ChartStore { + private static final Logger LOGGER = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); + + private static final StandardCoder STANDARD_CODER = new StandardCoder(); + + @Autowired + private ParticipantK8sParameters participantK8sParameters; + + /** + * The chartStore map contains chart name as key & ChartInfo as value. + */ + private Map<String, ChartInfo> localChartMap = new ConcurrentHashMap<>(); + + /** + * Constructor method. + */ + public ChartStore() { + this.restoreFromLocalFileSystem(); + } + + /** + * Get local helm chart file. + * + * @param chart ChartInfo + * @return the chart file. + */ + public File getHelmChartFile(ChartInfo chart) { + var appPath = getAppPath(chart.getChartName(), chart.getVersion()); + return new File(appPath.toFile(), chart.getChartName()); + } + + /** + * Get the override yaml file. + * + * @param chart ChartInfo + * @return the override yaml file + */ + public File getOverrideFile(ChartInfo chart) { + var appPath = getAppPath(chart.getChartName(), chart.getVersion()); + return new File(appPath.toFile(), "values.yaml"); + } + + + /** + * Saves the helm chart. + * + * @param chartInfo chartInfo + * @param chartFile helm chart file. + * @return chart + * @throws IOException incase of IO error + * @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()))) { + throw new ServiceException("Chart already exist"); + } + var appPath = getAppPath(chartInfo.getChartName(), chartInfo.getVersion()); + Files.createDirectories(appPath); + + chartFile.transferTo(getHelmChartFile(chartInfo)); + if (overrideFile != null) { + overrideFile.transferTo(getOverrideFile(chartInfo)); + } + + localChartMap.put(key(chartInfo), chartInfo); + storeChartInFile(chartInfo); + return chartInfo; + } + + /** + * Get the chart info. + * + * @param name name of the chart + * @param version version of the chart + * @return chart + */ + public synchronized ChartInfo getChart(String name, String version) { + return localChartMap.get(key(name, version)); + } + + /** + * Get all the charts installed. + * + * @return list of charts. + */ + public synchronized List<ChartInfo> getAllCharts() { + return new ArrayList<>(localChartMap.values()); + } + + /** + * Delete a chart. + * + * @param chart chart info + */ + public synchronized void deleteChart(ChartInfo chart) { + var appPath = getAppPath(chart.getChartName(), chart.getVersion()); + try { + FileSystemUtils.deleteRecursively(appPath); + } catch (IOException exc) { + LOGGER.warn("Could not delete chart from local file system : {}", appPath, exc); + } + + localChartMap.remove(key(chart)); + } + + /** + * Fetch the local chart directory of specific chart. + * + * @param chartName name of the chart + * @param chartVersion version of the chart + * @return path + */ + public Path getAppPath(String chartName, String chartVersion) { + return Path.of(participantK8sParameters.getLocalChartDirectory(), chartName, chartVersion); + } + + 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); + } + } + + private File getFile(ChartInfo chart) { + var appPath = getAppPath(chart.getChartName(), chart.getVersion()).toString(); + return Path.of(appPath, participantK8sParameters.getInfoFileName()).toFile(); + } + + private synchronized void restoreFromLocalFileSystem() { + Path localChartDirectoryPath = Paths.get(participantK8sParameters.getLocalChartDirectory()); + + try { + Files.createDirectories(localChartDirectoryPath); + restoreFromLocalFileSystem(localChartDirectoryPath); + } catch (IOException ioe) { + LOGGER.warn("Could not restore charts from local file system: {}", ioe); + } + } + + private synchronized void restoreFromLocalFileSystem(Path localChartDirectoryPath) + throws IOException { + + Files.walkFileTree(localChartDirectoryPath, new SimpleFileVisitor<Path>() { + @Override + public FileVisitResult visitFile(Path localChartFile, BasicFileAttributes attrs) throws IOException { + try { + ChartInfo chart = STANDARD_CODER.decode(localChartFile.toFile(), ChartInfo.class); + localChartMap.put(key(chart), chart); + return FileVisitResult.CONTINUE; + } catch (CoderException ce) { + throw new IOException("Error decoding chart file", ce); + } + } + }); + } + + private String key(ChartInfo chart) { + return key(chart.getChartName(), chart.getVersion()); + } + + private String key(String chartName, String chartVersion) { + return chartName + "_" + chartVersion; + } + +} diff --git a/participant/participant-impl/participant-impl-kubernetes/src/main/resources/config/KubernetesParticipantConfig.json b/participant/participant-impl/participant-impl-kubernetes/src/main/resources/config/KubernetesParticipantConfig.json new file mode 100644 index 000000000..620e05552 --- /dev/null +++ b/participant/participant-impl/participant-impl-kubernetes/src/main/resources/config/KubernetesParticipantConfig.json @@ -0,0 +1,56 @@ +{ + "name": "ControlLoopParticipantK8s", + "localChartDirectory": "/var/helm-manager/local-charts", + "infoFileName": "CHART_INFO.json", + + "intermediaryParameters":{ + "name":"Participant parameters", + "reportingTimeInterval":120000, + "description":"Participant Description", + "participantId":{ + "name":"K8sParticipant0", + "version":"1.0.0" + }, + "participantType":{ + "name":"org.onap.k8s.controlloop.K8SControlLoopParticipant", + "version":"2.3.4" + }, + "clampControlLoopTopics":{ + "topicSources":[ + { + "topic":"POLICY-CLRUNTIME-PARTICIPANT", + "servers":[ + "localhost" + ], + "topicCommInfrastructure":"dmaap", + "fetchTimeout":15000 + } + ], + "topicSinks":[ + { + "topic":"POLICY-CLRUNTIME-PARTICIPANT", + "servers":[ + "localhost" + ], + "topicCommInfrastructure":"dmaap" + }, + { + "topic":"POLICY-NOTIFICATION", + "servers":[ + "localhost" + ], + "topicCommInfrastructure":"dmaap" + } + ] + } + }, + "databaseProviderParameters":{ + "name":"PolicyProviderParameterGroup", + "implementation":"org.onap.policy.models.provider.impl.DatabasePolicyModelsProviderImpl", + "databaseDriver":"org.mariadb.jdbc.Driver", + "databaseUrl":"jdbc:mariadb://localhost:3306/controlloop", + "databaseUser":"admin", + "databasePassword":"passme", + "persistenceUnit":"ToscaConceptTest" + } +} 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 new file mode 100644 index 000000000..b4240036b --- /dev/null +++ b/participant/participant-impl/participant-impl-kubernetes/src/main/resources/config/application.yaml @@ -0,0 +1,25 @@ +spring: + profiles: + active: prod + +participant: + file: src/main/resources/config/KubernetesParticipantConfig.json +management: + endpoints: + web: + exposure: + include: "loggers,logfile,health,info,metrics,threaddump,heapdump" +server: + # Configuration of the HTTP/REST server. The parameters are defined and handled by the springboot framework. + # See springboot documentation. + http-port : 8083 + +logging: + # Configuration of logging + level: + ROOT: INFO + org.springframework: ERROR + org.springframework.data: ERROR + org.springframework.web.reactive.function.client.ExchangeFunctions: ERROR + file: + name: /var/log/helm-manager/application.log diff --git a/participant/participant-impl/participant-impl-kubernetes/src/test/resources/KubernetesHelm.yaml b/participant/participant-impl/participant-impl-kubernetes/src/test/resources/KubernetesHelm.yaml new file mode 100644 index 000000000..3212b5ad2 --- /dev/null +++ b/participant/participant-impl/participant-impl-kubernetes/src/test/resources/KubernetesHelm.yaml @@ -0,0 +1,154 @@ +# ============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========================================================= +tosca_definitions_version: tosca_simple_yaml_1_3 +data_types: + onap.datatypes.ToscaConceptIdentifier: + derived_from: tosca.datatypes.Root + properties: + name: + type: string + required: true + version: + type: string + required: true +node_types: + org.onap.policy.clamp.controlloop.Participant: + version: 1.0.1 + derived_from: tosca.nodetypes.Root + properties: + provider: + type: string + requred: false + org.onap.policy.clamp.controlloop.ControlLoopElement: + version: 1.0.1 + derived_from: tosca.nodetypes.Root + properties: + provider: + type: string + requred: false + participant_id: + type: onap.datatypes.ToscaConceptIdentifier + requred: true + org.onap.policy.clamp.controlloop.ControlLoop: + version: 1.0.1 + derived_from: tosca.nodetypes.Root + properties: + provider: + type: string + requred: false + elements: + type: list + required: true + entry_schema: + type: onap.datatypes.ToscaConceptIdentifier + org.onap.policy.clamp.controlloop.K8SMicroserviceControlLoopElement: + version: 1.0.1 + derived_from: org.onap.policy.clamp.controlloop.ControlLoopElement + properties: + chart: + type: string + required: true + configs: + type: list + required: false + requirements: + type: string + requred: false + templates: + type: list + required: false + entry_schema: + values: + type: string + requred: true +topology_template: + node_templates: + org.onap.k8s.controlloop.K8SControlLoopParticipant: + version: 2.3.4 + type: org.onap.policy.clamp.controlloop.Participant + type_version: 1.0.1 + description: Participant for K8S + properties: + provider: ONAP + + org.onap.domain.database.HelloWorld_K8SMicroserviceControlLoopElement: + # Chart from any chart repository configured on helm client. + version: 1.2.3 + type: org.onap.policy.clamp.controlloop.K8SMicroserviceControlLoopElement + type_version: 1.0.0 + description: Control loop element for the K8S microservice for Hello World + properties: + provider: ONAP + participant_id: + name: org.onap.k8s.controlloop.K8SControlLoopParticipant + version: 2.3.4 + chart: + release_name: helloworld + chart_name: hello + version: 0.1.0 + repository: chartMuseum + namespace: onap + + org.onap.domain.database.PMSH_K8SMicroserviceControlLoopElement: + # Chart from local file system + version: 1.2.3 + type: org.onap.policy.clamp.controlloop.K8SMicroserviceControlLoopElement + type_version: 1.0.0 + description: Control loop element for the K8S microservice for PMSH + properties: + provider: ONAP + participant_id: + name: org.onap.k8s.controlloop.K8SControlLoopParticipant + version: 2.3.4 + chart: + release_name: pmshmicroservice + chart_name: test + version: 1.0.1 + namespace: onap + + org.onap.domain.database.Local_K8SMicroserviceControlLoopElement: + # Chart installation without passing repository name + version: 1.2.3 + type: org.onap.policy.clamp.controlloop.K8SMicroserviceControlLoopElement + type_version: 1.0.0 + description: Control loop element for the K8S microservice for local chart + properties: + provider: ONAP + participant_id: + name: org.onap.k8s.controlloop.K8SControlLoopParticipant + version: 2.3.4 + chart: + release_name: nginxms + chart_name: nginx-ingress + version: 0.9.1 + namespace: onap + + org.onap.domain.sample.GenericK8s_ControlLoopDefinition: + version: 1.2.3 + type: org.onap.policy.clamp.controlloop.ControlLoop + type_version: 1.0.0 + description: Control loop for Hello World + properties: + provider: ONAP + elements: + - name: org.onap.domain.database.HelloWorld_K8SMicroserviceControlLoopElement + version: 1.2.3 + - name: org.onap.domain.database.PMSH_K8SMicroserviceControlLoopElement + version: 1.2.3 + - name: org.onap.domain.database.Local_K8SMicroserviceControlLoopElement + version: 1.2.3 diff --git a/participant/participant-impl/participant-impl-policy/src/main/java/org/onap/policy/clamp/controlloop/participant/policy/client/AbstractHttpClient.java b/participant/participant-impl/participant-impl-policy/src/main/java/org/onap/policy/clamp/controlloop/participant/policy/client/AbstractHttpClient.java new file mode 100644 index 000000000..4b6686156 --- /dev/null +++ b/participant/participant-impl/participant-impl-policy/src/main/java/org/onap/policy/clamp/controlloop/participant/policy/client/AbstractHttpClient.java @@ -0,0 +1,75 @@ +/*- + * ============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.client; + +import java.io.Closeable; +import java.io.IOException; +import java.util.Collections; +import java.util.Map; +import javax.ws.rs.client.Entity; +import javax.ws.rs.core.HttpHeaders; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.Status; +import org.onap.policy.clamp.controlloop.common.exception.ControlLoopRuntimeException; +import org.onap.policy.common.endpoints.event.comm.bus.internal.BusTopicParams; +import org.onap.policy.common.endpoints.http.client.HttpClient; +import org.onap.policy.common.endpoints.http.client.HttpClientFactoryInstance; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public abstract class AbstractHttpClient implements Closeable { + + private static final Logger LOGGER = LoggerFactory.getLogger(AbstractHttpClient.class); + private final HttpClient httpclient; + + + /** + * Constructor. + */ + protected AbstractHttpClient(BusTopicParams policyApiParameters) { + try { + httpclient = HttpClientFactoryInstance.getClientFactory().build(policyApiParameters); + } catch (final Exception e) { + throw new ControlLoopRuntimeException(Status.INTERNAL_SERVER_ERROR, " Client failed to start", e); + } + } + + protected Response executePost(String path, final Entity<?> entity) { + Response response = httpclient.post(path, entity, Map.of(HttpHeaders.ACCEPT, + MediaType.APPLICATION_JSON, HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON)); + if (response.getStatus() / 100 != 2) { + LOGGER.error( + "Invocation of path {} failed for entity {}. Response status: {}, Response status info: {}", + path, entity, response.getStatus(), response.getStatusInfo()); + } + return response; + } + + protected Response executeDelete(String path) { + return httpclient.delete(path, Collections.emptyMap()); + } + + @Override + public void close() throws IOException { + httpclient.shutdown(); + } +}
\ No newline at end of file diff --git a/participant/participant-impl/participant-impl-policy/src/main/java/org/onap/policy/clamp/controlloop/participant/policy/client/PolicyApiHttpClient.java b/participant/participant-impl/participant-impl-policy/src/main/java/org/onap/policy/clamp/controlloop/participant/policy/client/PolicyApiHttpClient.java new file mode 100644 index 000000000..3d1047ce4 --- /dev/null +++ b/participant/participant-impl/participant-impl-policy/src/main/java/org/onap/policy/clamp/controlloop/participant/policy/client/PolicyApiHttpClient.java @@ -0,0 +1,84 @@ +/*- + * ============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.client; + +import javax.ws.rs.client.Entity; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import org.onap.policy.clamp.controlloop.participant.policy.main.parameters.ParticipantPolicyParameters; +import org.onap.policy.models.base.PfModelException; +import org.onap.policy.models.tosca.authorative.concepts.ToscaServiceTemplate; +import org.springframework.stereotype.Component; + +@Component +public class PolicyApiHttpClient extends AbstractHttpClient { + + private static final String POLICY_URI = "/policy/api/v1/"; + + /** + * Constructor. + */ + public PolicyApiHttpClient(ParticipantPolicyParameters parameters) { + super(parameters.getPolicyApiParameters()); + } + + /** + * Create Policy Types. + * + * @param toscaServiceTemplate the whole ToscaServiceTemplate + * @return Response + */ + public Response createPolicyType(ToscaServiceTemplate toscaServiceTemplate) throws PfModelException { + return executePost(POLICY_URI + "policytypes", Entity.entity(toscaServiceTemplate, MediaType.APPLICATION_JSON)); + } + + /** + * Create Policies. + * + * @param toscaServiceTemplate the whole ToscaServiceTemplate + * @return Response + */ + public Response createPolicy(final ToscaServiceTemplate toscaServiceTemplate) { + return executePost(POLICY_URI + "policies", Entity.entity(toscaServiceTemplate, MediaType.APPLICATION_JSON)); + } + + /** + * Delete Policies. + * + * @param policyName the name of the policy to be deleted + * @param policyVersion the version of the policy to be deleted + * @return Response + */ + public Response deletePolicy(final String policyName, final String policyVersion) { + return executeDelete(POLICY_URI + "policies/" + policyName + "/versions/" + policyVersion); + } + + /** + * Delete Policy types. + * + * @param policyTypeName the name of the policy to be deleted + * @param policyTypeVersion the version of the policy to be deleted + * @return Response + */ + public Response deletePolicyType(final String policyTypeName, final String policyTypeVersion) { + return executeDelete(POLICY_URI + "policytypes/" + policyTypeName + "/versions/" + policyTypeVersion); + } +} diff --git a/participant/participant-impl/participant-impl-policy/src/main/java/org/onap/policy/clamp/controlloop/participant/policy/config/ParticipantConfig.java b/participant/participant-impl/participant-impl-policy/src/main/java/org/onap/policy/clamp/controlloop/participant/policy/config/ParticipantConfig.java index afef1a5d2..3b8324151 100644 --- a/participant/participant-impl/participant-impl-policy/src/main/java/org/onap/policy/clamp/controlloop/participant/policy/config/ParticipantConfig.java +++ b/participant/participant-impl/participant-impl-policy/src/main/java/org/onap/policy/clamp/controlloop/participant/policy/config/ParticipantConfig.java @@ -24,9 +24,6 @@ import org.onap.policy.clamp.controlloop.participant.intermediary.api.Participan import org.onap.policy.clamp.controlloop.participant.intermediary.api.ParticipantIntermediaryFactory; import org.onap.policy.clamp.controlloop.participant.policy.main.handler.ControlLoopElementHandler; import org.onap.policy.clamp.controlloop.participant.policy.main.parameters.ParticipantPolicyParameters; -import org.onap.policy.models.base.PfModelException; -import org.onap.policy.models.provider.PolicyModelsProvider; -import org.onap.policy.models.provider.PolicyModelsProviderFactory; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -49,17 +46,4 @@ public class ParticipantConfig { controlLoopElementHandler.setIntermediaryApi(intermediaryApi); return intermediaryApi; } - - /** - * Create PolicyModelsProvider. - * - * @param parameters the Participant Policy Parameters - * @return PolicyModelsProvider - * @throws PfModelException in case of an exception - */ - @Bean - public PolicyModelsProvider databaseProvider(ParticipantPolicyParameters parameters) throws PfModelException { - return new PolicyModelsProviderFactory().createPolicyModelsProvider(parameters.getDatabaseProviderParameters()); - } - } diff --git a/participant/participant-impl/participant-impl-policy/src/main/java/org/onap/policy/clamp/controlloop/participant/policy/main/handler/ControlLoopElementHandler.java b/participant/participant-impl/participant-impl-policy/src/main/java/org/onap/policy/clamp/controlloop/participant/policy/main/handler/ControlLoopElementHandler.java index 5b07568da..1b176f076 100644 --- a/participant/participant-impl/participant-impl-policy/src/main/java/org/onap/policy/clamp/controlloop/participant/policy/main/handler/ControlLoopElementHandler.java +++ b/participant/participant-impl/participant-impl-policy/src/main/java/org/onap/policy/clamp/controlloop/participant/policy/main/handler/ControlLoopElementHandler.java @@ -32,9 +32,9 @@ 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.participant.intermediary.api.ControlLoopElementListener; import org.onap.policy.clamp.controlloop.participant.intermediary.api.ParticipantIntermediaryApi; +import org.onap.policy.clamp.controlloop.participant.policy.client.PolicyApiHttpClient; 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.tosca.authorative.concepts.ToscaPolicy; import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicyType; import org.onap.policy.models.tosca.authorative.concepts.ToscaServiceTemplate; @@ -52,7 +52,7 @@ public class ControlLoopElementHandler implements ControlLoopElementListener { private final Map<String, String> policyTypeMap = new LinkedHashMap<>(); private final Map<String, String> policyMap = new LinkedHashMap<>(); - private final PolicyModelsProvider databaseProvider; + private final PolicyApiHttpClient apiHttpClient; @Setter private ParticipantIntermediaryApi intermediaryApi; @@ -60,10 +60,10 @@ public class ControlLoopElementHandler implements ControlLoopElementListener { /** * constructor. * - * @param databaseProvider the Policy Models Provider + * @param apiHttpClient the Policy Api Http Client */ - public ControlLoopElementHandler(PolicyModelsProvider databaseProvider) { - this.databaseProvider = databaseProvider; + public ControlLoopElementHandler(PolicyApiHttpClient apiHttpClient) { + this.apiHttpClient = apiHttpClient; } /** @@ -82,7 +82,7 @@ public class ControlLoopElementHandler implements ControlLoopElementListener { try { deletePolicyData(controlLoopElementId, newState); } catch (PfModelRuntimeException e) { - LOGGER.debug("Delete policytpes failed", e); + LOGGER.debug("Deleting policy data failed", e); } break; case PASSIVE: @@ -100,12 +100,12 @@ public class ControlLoopElementHandler implements ControlLoopElementListener { private void deletePolicyData(UUID controlLoopElementId, ControlLoopOrderedState newState) throws PfModelException { // Delete all policies of this controlLoop from policy framework for (Entry<String, String> policy : policyMap.entrySet()) { - databaseProvider.deletePolicy(policy.getKey(), policy.getValue()); + apiHttpClient.deletePolicy(policy.getKey(), policy.getValue()); } policyMap.clear(); // Delete all policy types of this control loop from policy framework for (Entry<String, String> policyType : policyTypeMap.entrySet()) { - databaseProvider.deletePolicyType(policyType.getKey(), policyType.getValue()); + apiHttpClient.deletePolicyType(policyType.getKey(), policyType.getValue()); } policyTypeMap.clear(); intermediaryApi.updateControlLoopElementState(controlLoopElementId, newState, ControlLoopState.UNINITIALISED); @@ -127,17 +127,20 @@ public class ControlLoopElementHandler implements ControlLoopElementListener { for (ToscaPolicyType policyType : controlLoopDefinition.getPolicyTypes().values()) { policyTypeMap.put(policyType.getName(), policyType.getVersion()); } - databaseProvider.createPolicyTypes(controlLoopDefinition); + LOGGER.debug("Found Policy Types in control loop definition: {} , Creating Policy Types", + controlLoopDefinition.getName()); + apiHttpClient.createPolicyType(controlLoopDefinition); } if (controlLoopDefinition.getToscaTopologyTemplate().getPolicies() != null) { for (Map<String, ToscaPolicy> foundPolicyMap : controlLoopDefinition.getToscaTopologyTemplate() .getPolicies()) { - for (Entry<String, ToscaPolicy> policyEntry : foundPolicyMap.entrySet()) { - ToscaPolicy policy = policyEntry.getValue(); + for (ToscaPolicy policy : foundPolicyMap.values()) { policyMap.put(policy.getName(), policy.getVersion()); } } - databaseProvider.createPolicies(controlLoopDefinition); + LOGGER.debug("Found Policies in control loop definition: {} , Creating Policies", + controlLoopDefinition.getName()); + apiHttpClient.createPolicy(controlLoopDefinition); } } diff --git a/participant/participant-impl/participant-impl-policy/src/main/java/org/onap/policy/clamp/controlloop/participant/policy/main/parameters/ParticipantPolicyParameters.java b/participant/participant-impl/participant-impl-policy/src/main/java/org/onap/policy/clamp/controlloop/participant/policy/main/parameters/ParticipantPolicyParameters.java index 13d89faba..490722a45 100644 --- a/participant/participant-impl/participant-impl-policy/src/main/java/org/onap/policy/clamp/controlloop/participant/policy/main/parameters/ParticipantPolicyParameters.java +++ b/participant/participant-impl/participant-impl-policy/src/main/java/org/onap/policy/clamp/controlloop/participant/policy/main/parameters/ParticipantPolicyParameters.java @@ -23,9 +23,9 @@ package org.onap.policy.clamp.controlloop.participant.policy.main.parameters; import javax.validation.constraints.NotBlank; import lombok.Getter; import org.onap.policy.clamp.controlloop.participant.intermediary.parameters.ParticipantIntermediaryParameters; +import org.onap.policy.common.endpoints.event.comm.bus.internal.BusTopicParams; import org.onap.policy.common.parameters.ParameterGroupImpl; import org.onap.policy.common.parameters.annotations.NotNull; -import org.onap.policy.models.provider.PolicyModelsProviderParameters; /** * Class to hold all parameters needed for the policy participant. @@ -36,7 +36,7 @@ import org.onap.policy.models.provider.PolicyModelsProviderParameters; @Getter public class ParticipantPolicyParameters extends ParameterGroupImpl { private ParticipantIntermediaryParameters intermediaryParameters; - private PolicyModelsProviderParameters databaseProviderParameters; + private BusTopicParams policyApiParameters; /** * Create the policy participant parameter group. diff --git a/participant/participant-impl/participant-impl-policy/src/main/resources/config/PolicyParticipantConfig.json b/participant/participant-impl/participant-impl-policy/src/main/resources/config/PolicyParticipantConfig.json index e6b3c8eb1..bf458fae9 100644 --- a/participant/participant-impl/participant-impl-policy/src/main/resources/config/PolicyParticipantConfig.json +++ b/participant/participant-impl/participant-impl-policy/src/main/resources/config/PolicyParticipantConfig.json @@ -1,31 +1,53 @@ { - "name":"ParticipantParameterGroup", - "participantStatusParameters":{ - "timeIntervalMs":10000, - "description":"Participant Status", - "participantId":{ - "name": "PolicyParticipant0", - "version":"1.0.0" - }, + "name": "ControlLoopParticipantGroup", + "intermediaryParameters": { + "name": "Participant parameters", + "reportingTimeInterval": 120000, + "description": "Participant Description", "participantType":{ "name": "org.onap.policy.controlloop.PolicyControlLoopParticipant", "version":"2.3.1" }, - "participantDefinition":{ - "name": "org.onap.policy.controlloop.PolicyControlLoopParticipant", - "version":"2.3.1" + "participantId": { + "name": "org.onap.PM_Policy", + "version": "1.0.0" + }, + "clampControlLoopTopics": { + "topicSources": [ + { + "topic": "POLICY-CLRUNTIME-PARTICIPANT", + "servers": [ + "message-router" + ], + "topicCommInfrastructure": "dmaap", + "fetchTimeout": 15000 + } + ], + "topicSinks": [ + { + "topic": "POLICY-CLRUNTIME-PARTICIPANT", + "servers": [ + "message-router" + ], + "topicCommInfrastructure": "dmaap" + }, + { + "topic": "POLICY-NOTIFICATION", + "servers": [ + "message-router" + ], + "topicCommInfrastructure": "dmaap" + } + ] } }, - "topicParameterGroup": { - "topicSources" : [{ - "topic" : "POLICY-CLRUNTIME-PARTICIPANT", - "servers" : [ "127.0.0.1:3904" ], - "topicCommInfrastructure" : "dmaap" - }], - "topicSinks" : [{ - "topic" : "POLICY-CLRUNTIME-PARTICIPANT", - "servers" : [ "127.0.0.1:3904" ], - "topicCommInfrastructure" : "dmaap" - }] + "policyApiParameters": { + "clientName": "api", + "hostname": "policy-api", + "port": "6969", + "userName": "healthcheck", + "password": "zb!XztG34", + "https": true, + "allowSelfSignedCerts": true } } diff --git a/participant/participant-impl/participant-impl-policy/src/test/resources/parameters/TestParameters.json b/participant/participant-impl/participant-impl-policy/src/test/resources/parameters/TestParameters.json index 30250be68..024f72d6d 100644 --- a/participant/participant-impl/participant-impl-policy/src/test/resources/parameters/TestParameters.json +++ b/participant/participant-impl/participant-impl-policy/src/test/resources/parameters/TestParameters.json @@ -41,13 +41,13 @@ ] } }, - "databaseProviderParameters": { - "name": "PolicyProviderParameterGroup", - "implementation": "org.onap.policy.models.provider.impl.DatabasePolicyModelsProviderImpl", - "databaseDriver": "org.h2.Driver", - "databaseUrl": "jdbc:h2:mem:testdb", - "databaseUser": "policy", - "databasePassword": "P01icY", - "persistenceUnit": "ToscaConceptTest" + "policyApiParameters": { + "clientName": "api", + "hostname": "localhost", + "port": "6969", + "userName": "healthcheck", + "password": "zb!XztG34", + "https": false, + "allowSelfSignedCerts": true } } diff --git a/participant/participant-impl/participant-impl-simulator/pom.xml b/participant/participant-impl/participant-impl-simulator/pom.xml index d54a23e53..bb8317380 100644 --- a/participant/participant-impl/participant-impl-simulator/pom.xml +++ b/participant/participant-impl/participant-impl-simulator/pom.xml @@ -31,4 +31,71 @@ <artifactId>policy-clamp-participant-impl-simulator</artifactId> <name>${project.artifactId}</name> <description>Participant simulator, used to test control loops</description> + + <properties> + <springboot.version>2.4.4</springboot.version> + <springfox.version>3.0.0</springfox.version> + </properties> + + <dependencyManagement> + <dependencies> + <!-- Spring Boot BOM --> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-dependencies</artifactId> + <version>${springboot.version}</version> + <type>pom</type> + <scope>import</scope> + </dependency> + </dependencies> + </dependencyManagement> + + <dependencies> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-web</artifactId> + </dependency> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-security</artifactId> + </dependency> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-validation</artifactId> + </dependency> + <dependency> + <groupId>io.springfox</groupId> + <artifactId>springfox-boot-starter</artifactId> + <version>${springfox.version}</version> + </dependency> + <dependency> + <groupId>io.springfox</groupId> + <artifactId>springfox-swagger-ui</artifactId> + <version>${springfox.version}</version> + <scope>runtime</scope> + </dependency> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-test</artifactId> + <scope>test</scope> + </dependency> + </dependencies> + + <build> + <plugins> + <plugin> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-maven-plugin</artifactId> + <version>${springboot.version}</version> + <executions> + <execution> + <goals> + <goal>repackage</goal> + </goals> + <phase>package</phase> + </execution> + </executions> + </plugin> + </plugins> + </build> </project> diff --git a/participant/participant-impl/participant-impl-simulator/src/main/java/org/onap/policy/clamp/controlloop/participant/simulator/ParticipantSimulatorApplication.java b/participant/participant-impl/participant-impl-simulator/src/main/java/org/onap/policy/clamp/controlloop/participant/simulator/ParticipantSimulatorApplication.java new file mode 100644 index 000000000..3aa1c36db --- /dev/null +++ b/participant/participant-impl/participant-impl-simulator/src/main/java/org/onap/policy/clamp/controlloop/participant/simulator/ParticipantSimulatorApplication.java @@ -0,0 +1,36 @@ +/*-
+ * ============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.simulator;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+/**
+ * Starter.
+ *
+ */
+@SpringBootApplication
+public class ParticipantSimulatorApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(ParticipantSimulatorApplication.class, args);
+ }
+}
diff --git a/participant/participant-impl/participant-impl-simulator/src/main/java/org/onap/policy/clamp/controlloop/participant/simulator/config/AafConfiguration.java b/participant/participant-impl/participant-impl-simulator/src/main/java/org/onap/policy/clamp/controlloop/participant/simulator/config/AafConfiguration.java new file mode 100644 index 000000000..c8922a1f5 --- /dev/null +++ b/participant/participant-impl/participant-impl-simulator/src/main/java/org/onap/policy/clamp/controlloop/participant/simulator/config/AafConfiguration.java @@ -0,0 +1,46 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights + * reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END============================================ + * =================================================================== + * + */ + +package org.onap.policy.clamp.controlloop.participant.simulator.config; + +import javax.servlet.Filter; +import org.onap.policy.clamp.controlloop.participant.simulator.main.rest.ParticipantSimulatorAafFilter; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; + +@Configuration +@Profile("clamp-aaf-authentication") +public class AafConfiguration { + + /** + * Method to return Aaf filter. + * + * @return Filter + */ + @Bean + public Filter aafFilter() { + return new ParticipantSimulatorAafFilter(); + } + +} diff --git a/participant/participant-impl/participant-impl-simulator/src/main/java/org/onap/policy/clamp/controlloop/participant/simulator/config/ParametersConfig.java b/participant/participant-impl/participant-impl-simulator/src/main/java/org/onap/policy/clamp/controlloop/participant/simulator/config/ParametersConfig.java new file mode 100644 index 000000000..936df2c57 --- /dev/null +++ b/participant/participant-impl/participant-impl-simulator/src/main/java/org/onap/policy/clamp/controlloop/participant/simulator/config/ParametersConfig.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.participant.simulator.config; + +import org.onap.policy.clamp.controlloop.common.exception.ControlLoopException; +import org.onap.policy.clamp.controlloop.participant.simulator.main.parameters.ParticipantSimulatorParameterHandler; +import org.onap.policy.clamp.controlloop.participant.simulator.main.parameters.ParticipantSimulatorParameters; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class ParametersConfig { + + @Value("${participant.file}") + private String file; + + @Bean + public ParticipantSimulatorParameters participantSimulatorParameters() throws ControlLoopException { + return new ParticipantSimulatorParameterHandler().toParticipantSimulatorParameters(file); + } +} diff --git a/participant/participant-impl/participant-impl-simulator/src/main/java/org/onap/policy/clamp/controlloop/participant/simulator/config/ParticipantConfig.java b/participant/participant-impl/participant-impl-simulator/src/main/java/org/onap/policy/clamp/controlloop/participant/simulator/config/ParticipantConfig.java new file mode 100644 index 000000000..f4e6791ec --- /dev/null +++ b/participant/participant-impl/participant-impl-simulator/src/main/java/org/onap/policy/clamp/controlloop/participant/simulator/config/ParticipantConfig.java @@ -0,0 +1,61 @@ +/*- + * ============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.simulator.config; + +import org.onap.policy.clamp.controlloop.participant.intermediary.api.ParticipantIntermediaryApi; +import org.onap.policy.clamp.controlloop.participant.intermediary.api.ParticipantIntermediaryFactory; +import org.onap.policy.clamp.controlloop.participant.simulator.main.parameters.ParticipantSimulatorParameters; +import org.onap.policy.clamp.controlloop.participant.simulator.main.rest.RequestResponseLoggingFilter; +import org.springframework.boot.web.servlet.FilterRegistrationBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class ParticipantConfig { + + /** + * Create ParticipantIntermediaryApi. + * + * @param parameters the Participant Dcae Parameters + * @return ParticipantIntermediaryApi + */ + @Bean + public ParticipantIntermediaryApi participantIntermediaryApi(ParticipantSimulatorParameters parameters) { + ParticipantIntermediaryApi intermediaryApi = new ParticipantIntermediaryFactory().createApiImplementation(); + intermediaryApi.init(parameters.getIntermediaryParameters()); + return intermediaryApi; + } + + /** + * logging Filter configuration. + * + * @return FilterRegistrationBean + */ + @Bean + public FilterRegistrationBean<RequestResponseLoggingFilter> loggingFilter() { + FilterRegistrationBean<RequestResponseLoggingFilter> registrationBean = new FilterRegistrationBean<>(); + + registrationBean.setFilter(new RequestResponseLoggingFilter()); + registrationBean.addUrlPatterns("/onap/participantsim/v2/*"); + + return registrationBean; + } +} diff --git a/participant/participant-impl/participant-impl-simulator/src/main/java/org/onap/policy/clamp/controlloop/participant/simulator/config/SecurityConfig.java b/participant/participant-impl/participant-impl-simulator/src/main/java/org/onap/policy/clamp/controlloop/participant/simulator/config/SecurityConfig.java new file mode 100644 index 000000000..cdfd5eac3 --- /dev/null +++ b/participant/participant-impl/participant-impl-simulator/src/main/java/org/onap/policy/clamp/controlloop/participant/simulator/config/SecurityConfig.java @@ -0,0 +1,39 @@ +/*- + * ============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.simulator.config; + +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 { + + @Override + protected void configure(HttpSecurity http) throws Exception { + // @formatter:off + http.authorizeRequests() + .antMatchers().authenticated() + .anyRequest().authenticated() + .and().httpBasic().and().csrf().disable(); + // @formatter:on + } +} diff --git a/participant/participant-impl/participant-impl-simulator/src/main/java/org/onap/policy/clamp/controlloop/participant/simulator/config/SpringFoxConfig.java b/participant/participant-impl/participant-impl-simulator/src/main/java/org/onap/policy/clamp/controlloop/participant/simulator/config/SpringFoxConfig.java new file mode 100644 index 000000000..bf776140b --- /dev/null +++ b/participant/participant-impl/participant-impl-simulator/src/main/java/org/onap/policy/clamp/controlloop/participant/simulator/config/SpringFoxConfig.java @@ -0,0 +1,45 @@ +/*- + * ============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.simulator.config; + +import org.onap.policy.clamp.controlloop.participant.simulator.simulation.rest.SimulationElementController; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import springfox.documentation.builders.PathSelectors; +import springfox.documentation.builders.RequestHandlerSelectors; +import springfox.documentation.spi.DocumentationType; +import springfox.documentation.spring.web.plugins.Docket; + +@Configuration +public class SpringFoxConfig { + + /** + * Docket Spring Fox Config. + * + * @return Docket + */ + @Bean + public Docket api() { + return new Docket(DocumentationType.SWAGGER_2).select() + .apis(RequestHandlerSelectors.basePackage(SimulationElementController.class.getPackageName())) + .paths(PathSelectors.any()).build(); + } +} diff --git a/participant/participant-impl/participant-impl-simulator/src/main/java/org/onap/policy/clamp/controlloop/participant/simulator/config/YamlConfiguration.java b/participant/participant-impl/participant-impl-simulator/src/main/java/org/onap/policy/clamp/controlloop/participant/simulator/config/YamlConfiguration.java new file mode 100644 index 000000000..e84a7fc0a --- /dev/null +++ b/participant/participant-impl/participant-impl-simulator/src/main/java/org/onap/policy/clamp/controlloop/participant/simulator/config/YamlConfiguration.java @@ -0,0 +1,35 @@ +/*- + * ============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.simulator.config; + +import java.util.List; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.converter.HttpMessageConverter; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +@Configuration +public class YamlConfiguration implements WebMvcConfigurer { + + @Override + public void extendMessageConverters(List<HttpMessageConverter<?>> converters) { + converters.add(new YamlHttpMessageConverter<>()); + } +} diff --git a/participant/participant-impl/participant-impl-simulator/src/main/java/org/onap/policy/clamp/controlloop/participant/simulator/config/YamlHttpMessageConverter.java b/participant/participant-impl/participant-impl-simulator/src/main/java/org/onap/policy/clamp/controlloop/participant/simulator/config/YamlHttpMessageConverter.java new file mode 100644 index 000000000..4c8d324c6 --- /dev/null +++ b/participant/participant-impl/participant-impl-simulator/src/main/java/org/onap/policy/clamp/controlloop/participant/simulator/config/YamlHttpMessageConverter.java @@ -0,0 +1,60 @@ +/*- + * ============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.simulator.config; + +import java.io.IOException; +import java.io.OutputStreamWriter; +import java.nio.charset.StandardCharsets; +import org.springframework.http.HttpInputMessage; +import org.springframework.http.HttpOutputMessage; +import org.springframework.http.MediaType; +import org.springframework.http.converter.AbstractHttpMessageConverter; +import org.springframework.http.converter.HttpMessageNotReadableException; +import org.springframework.http.converter.HttpMessageNotWritableException; +import org.yaml.snakeyaml.Yaml; + +public class YamlHttpMessageConverter<T> extends AbstractHttpMessageConverter<T> { + + public YamlHttpMessageConverter() { + super(new MediaType("application", "yaml")); + } + + @Override + protected boolean supports(Class<?> clazz) { + return true; + } + + @Override + protected T readInternal(Class<? extends T> clazz, HttpInputMessage inputMessage) + throws IOException, HttpMessageNotReadableException { + Yaml yaml = new Yaml(); + return yaml.loadAs(inputMessage.getBody(), clazz); + } + + @Override + protected void writeInternal(T t, HttpOutputMessage outputMessage) + throws IOException, HttpMessageNotWritableException { + Yaml yaml = new Yaml(); + try (OutputStreamWriter writer = new OutputStreamWriter(outputMessage.getBody(), StandardCharsets.UTF_8)) { + yaml.dump(t, writer); + } + } +} diff --git a/participant/participant-impl/participant-impl-simulator/src/main/java/org/onap/policy/clamp/controlloop/participant/simulator/main/parameters/ParticipantSimulatorParameterHandler.java b/participant/participant-impl/participant-impl-simulator/src/main/java/org/onap/policy/clamp/controlloop/participant/simulator/main/parameters/ParticipantSimulatorParameterHandler.java index 42f458602..178d08794 100644 --- a/participant/participant-impl/participant-impl-simulator/src/main/java/org/onap/policy/clamp/controlloop/participant/simulator/main/parameters/ParticipantSimulatorParameterHandler.java +++ b/participant/participant-impl/participant-impl-simulator/src/main/java/org/onap/policy/clamp/controlloop/participant/simulator/main/parameters/ParticipantSimulatorParameterHandler.java @@ -23,8 +23,7 @@ package org.onap.policy.clamp.controlloop.participant.simulator.main.parameters; import java.io.File; import javax.ws.rs.core.Response; import org.onap.policy.clamp.controlloop.common.exception.ControlLoopException; -import org.onap.policy.clamp.controlloop.participant.simulator.main.startstop.ParticipantSimulatorCommandLineArguments; -import org.onap.policy.common.parameters.ValidationResult; +import org.onap.policy.common.parameters.BeanValidationResult; import org.onap.policy.common.utils.coder.Coder; import org.onap.policy.common.utils.coder.CoderException; import org.onap.policy.common.utils.coder.StandardCoder; @@ -37,42 +36,41 @@ public class ParticipantSimulatorParameterHandler { private static final Coder CODER = new StandardCoder(); /** - * Read the parameters from the parameter file. + * Read the parameters from the path of the file. * - * @param arguments the arguments passed to simulator + * @param path path of the config file. * @return the parameters read from the configuration file * @throws ControlLoopException on parameter exceptions */ - public ParticipantSimulatorParameters getParameters(final ParticipantSimulatorCommandLineArguments arguments) - throws ControlLoopException { + public ParticipantSimulatorParameters toParticipantSimulatorParameters(String path) throws ControlLoopException { ParticipantSimulatorParameters parameters = null; - // Read the parameters try { // Read the parameters from JSON - File file = new File(arguments.getFullConfigurationFilePath()); + File file = new File(path); parameters = CODER.decode(file, ParticipantSimulatorParameters.class); } catch (final CoderException e) { - final String errorMessage = "error reading parameters from \"" + arguments.getConfigurationFilePath() - + "\"\n" + "(" + e.getClass().getSimpleName() + ")"; + final String errorMessage = "error reading parameters from \"" + path + "\"" + System.lineSeparator() + "(" + + e.getClass().getSimpleName() + ")"; throw new ControlLoopException(Response.Status.NOT_ACCEPTABLE, errorMessage, e); } // The JSON processing returns null if there is an empty file if (parameters == null) { - final String errorMessage = "no parameters found in \"" + arguments.getConfigurationFilePath() + "\""; + final String errorMessage = "no parameters found in \"" + path + "\""; throw new ControlLoopException(Response.Status.NOT_ACCEPTABLE, errorMessage); } // validate the parameters - final ValidationResult validationResult = parameters.validate(); + final BeanValidationResult validationResult = parameters.validate(); if (!validationResult.isValid()) { - String returnMessage = - "validation error(s) on parameters from \"" + arguments.getConfigurationFilePath() + "\"\n"; - returnMessage += validationResult.getResult(); + final String returnMessage = "validation error(s) on parameters from \"" + path + "\"" + + System.lineSeparator() + validationResult.getResult(); + throw new ControlLoopException(Response.Status.NOT_ACCEPTABLE, returnMessage); } return parameters; } + } diff --git a/participant/participant-impl/participant-impl-simulator/src/main/java/org/onap/policy/clamp/controlloop/participant/simulator/main/rest/RestController.java b/participant/participant-impl/participant-impl-simulator/src/main/java/org/onap/policy/clamp/controlloop/participant/simulator/main/rest/AbstractRestController.java index 444f37889..b872ec0c6 100644 --- a/participant/participant-impl/participant-impl-simulator/src/main/java/org/onap/policy/clamp/controlloop/participant/simulator/main/rest/RestController.java +++ b/participant/participant-impl/participant-impl-simulator/src/main/java/org/onap/policy/clamp/controlloop/participant/simulator/main/rest/AbstractRestController.java @@ -27,34 +27,29 @@ import io.swagger.annotations.SecurityDefinition; import io.swagger.annotations.SwaggerDefinition; import io.swagger.annotations.Tag; import java.net.HttpURLConnection; -import java.util.UUID; -import javax.ws.rs.Path; -import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response.ResponseBuilder; import lombok.AccessLevel; import lombok.Getter; -import org.onap.policy.clamp.controlloop.participant.simulator.simulation.SimulationHandler; import org.onap.policy.clamp.controlloop.participant.simulator.simulation.SimulationProvider; +import org.springframework.web.bind.annotation.RequestMapping; /** * Common superclass to provide REST endpoints for the participant simulator. */ // @formatter:off -@Path("/onap/participantsim/v2") +@RequestMapping(value = "/v2", produces = {MediaType.APPLICATION_JSON, AbstractRestController.APPLICATION_YAML}) @Api(value = "Participant Simulator API") -@Produces({MediaType.APPLICATION_JSON, RestController.APPLICATION_YAML}) @SwaggerDefinition( info = @Info(description = "Participant Simulator", version = "v1.0", title = "Participant Simulator"), - consumes = {MediaType.APPLICATION_JSON, RestController.APPLICATION_YAML}, - produces = {MediaType.APPLICATION_JSON, RestController.APPLICATION_YAML}, + consumes = {MediaType.APPLICATION_JSON, AbstractRestController.APPLICATION_YAML}, + produces = {MediaType.APPLICATION_JSON, AbstractRestController.APPLICATION_YAML}, schemes = {SwaggerDefinition.Scheme.HTTP, SwaggerDefinition.Scheme.HTTPS}, tags = {@Tag(name = "participantsim", description = "Participant Simulator")}, securityDefinition = @SecurityDefinition(basicAuthDefinitions = {@BasicAuthDefinition(key = "basicAuth")})) // @formatter:on -public class RestController { +public abstract class AbstractRestController { public static final String APPLICATION_YAML = "application/yaml"; public static final String EXTENSION_NAME = "interface info"; @@ -90,41 +85,16 @@ public class RestController { public static final String AUTHENTICATION_ERROR_MESSAGE = "Authentication Error"; public static final String AUTHORIZATION_ERROR_MESSAGE = "Authorization Error"; public static final String SERVER_ERROR_MESSAGE = "Internal Server Error"; + @Getter(AccessLevel.PROTECTED) // The provider for simulation requests private SimulationProvider simulationProvider; - /** * create a Rest Controller. */ - public RestController() { - simulationProvider = SimulationHandler.getInstance().getSimulationProvider(); - } - - /** - * Adds version headers to the response. - * - * @param respBuilder response builder - * @return the response builder, with version headers - */ - public ResponseBuilder addVersionControlHeaders(ResponseBuilder respBuilder) { - return respBuilder.header(VERSION_MINOR_NAME, "0").header(VERSION_PATCH_NAME, "0").header(VERSION_LATEST_NAME, - API_VERSION); + protected AbstractRestController(SimulationProvider simulationProvider) { + this.simulationProvider = simulationProvider; } - /** - * Adds logging headers to the response. - * - * @param respBuilder response builder - * @return the response builder, with version logging - */ - public ResponseBuilder addLoggingHeaders(ResponseBuilder respBuilder, UUID requestId) { - if (requestId == null) { - // Generate a random uuid if client does not embed requestId in rest request - return respBuilder.header(REQUEST_ID_NAME, UUID.randomUUID()); - } - - return respBuilder.header(REQUEST_ID_NAME, requestId); - } } diff --git a/participant/participant-impl/participant-impl-simulator/src/main/java/org/onap/policy/clamp/controlloop/participant/simulator/main/rest/GlobalControllerExceptionHandler.java b/participant/participant-impl/participant-impl-simulator/src/main/java/org/onap/policy/clamp/controlloop/participant/simulator/main/rest/GlobalControllerExceptionHandler.java new file mode 100644 index 000000000..562bbd13e --- /dev/null +++ b/participant/participant-impl/participant-impl-simulator/src/main/java/org/onap/policy/clamp/controlloop/participant/simulator/main/rest/GlobalControllerExceptionHandler.java @@ -0,0 +1,49 @@ +/*- + * ============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.simulator.main.rest; + +import org.onap.policy.clamp.controlloop.common.exception.ControlLoopException; +import org.onap.policy.clamp.controlloop.models.messages.rest.commissioning.CommissioningResponse; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.bind.annotation.RestControllerAdvice; + +@RestControllerAdvice +public class GlobalControllerExceptionHandler { + + /** + * Handle ControlLoopException. + * + * @param ex ControlLoopException + * @return ResponseEntity + */ + @ExceptionHandler(ControlLoopException.class) + @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) + public ResponseEntity<CommissioningResponse> handleBadRequest(ControlLoopException ex) { + + CommissioningResponse resp = new CommissioningResponse(); + resp.setErrorDetails(ex.getErrorResponse().getErrorMessage()); + + return ResponseEntity.status(ex.getErrorResponse().getResponseCode().getStatusCode()).body(resp); + } +} diff --git a/participant/participant-impl/participant-impl-simulator/src/main/java/org/onap/policy/clamp/controlloop/participant/simulator/main/rest/ParticipantErrorController.java b/participant/participant-impl/participant-impl-simulator/src/main/java/org/onap/policy/clamp/controlloop/participant/simulator/main/rest/ParticipantErrorController.java new file mode 100644 index 000000000..6607377bb --- /dev/null +++ b/participant/participant-impl/participant-impl-simulator/src/main/java/org/onap/policy/clamp/controlloop/participant/simulator/main/rest/ParticipantErrorController.java @@ -0,0 +1,102 @@ +/*- + * ============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.simulator.main.rest; + +import io.swagger.v3.oas.annotations.Hidden; +import java.util.Map; +import javax.servlet.RequestDispatcher; +import javax.servlet.http.HttpServletRequest; +import org.onap.policy.clamp.controlloop.models.messages.rest.SimpleResponse; +import org.onap.policy.clamp.controlloop.models.messages.rest.TypedSimpleResponse; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.web.error.ErrorAttributeOptions; +import org.springframework.boot.web.servlet.error.ErrorAttributes; +import org.springframework.boot.web.servlet.error.ErrorController; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.context.request.ServletWebRequest; + +@Controller +@Hidden +public class ParticipantErrorController implements ErrorController { + + private final ErrorAttributes errorAttributes; + + @Value("${server.error.path}") + private String path; + + /** + * Constructor. + * + * @param errorAttributes ErrorAttributes + */ + public ParticipantErrorController(ErrorAttributes errorAttributes) { + this.errorAttributes = errorAttributes; + } + + protected HttpStatus getStatus(HttpServletRequest request) { + Integer statusCode = (Integer) request.getAttribute(RequestDispatcher.ERROR_STATUS_CODE); + if (statusCode == null) { + return HttpStatus.INTERNAL_SERVER_ERROR; + } + try { + return HttpStatus.valueOf(statusCode); + } catch (Exception ex) { + return HttpStatus.INTERNAL_SERVER_ERROR; + } + } + + /** + * Handle Errors not handled to GlobalControllerExceptionHandler. + * + * @param request HttpServletRequest + * @return ResponseEntity + */ + @RequestMapping(value = "${server.error.path}", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity<TypedSimpleResponse<SimpleResponse>> handleError(HttpServletRequest request) { + Map<String, Object> map = this.errorAttributes.getErrorAttributes(new ServletWebRequest(request), + ErrorAttributeOptions.defaults()); + + StringBuilder sb = new StringBuilder(); + final Object error = map.get("error"); + if (error != null) { + sb.append(error.toString() + " "); + } + final Object message = map.get("message"); + if (message != null) { + sb.append(message.toString()); + } + + TypedSimpleResponse<SimpleResponse> resp = new TypedSimpleResponse<>(); + resp.setErrorDetails(sb.toString()); + + return ResponseEntity.status(getStatus(request)).body(resp); + + } + + @Override + public String getErrorPath() { + return path; + } +} diff --git a/participant/participant-impl/participant-impl-simulator/src/main/java/org/onap/policy/clamp/controlloop/participant/simulator/main/rest/RequestResponseLoggingFilter.java b/participant/participant-impl/participant-impl-simulator/src/main/java/org/onap/policy/clamp/controlloop/participant/simulator/main/rest/RequestResponseLoggingFilter.java new file mode 100644 index 000000000..3aaeeaf72 --- /dev/null +++ b/participant/participant-impl/participant-impl-simulator/src/main/java/org/onap/policy/clamp/controlloop/participant/simulator/main/rest/RequestResponseLoggingFilter.java @@ -0,0 +1,63 @@ +/*- + * ============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.simulator.main.rest; + +import java.io.IOException; +import java.util.UUID; +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +@Component +@Order(2) +public class RequestResponseLoggingFilter implements Filter { + + private static final String VERSION_MINOR_NAME = "X-MinorVersion"; + private static final String VERSION_PATCH_NAME = "X-PatchVersion"; + private static final String VERSION_LATEST_NAME = "X-LatestVersion"; + public static final String API_VERSION = "1.0.0"; + public static final String REQUEST_ID_NAME = "X-ONAP-RequestID"; + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) + throws IOException, ServletException { + + + HttpServletResponse res = (HttpServletResponse) response; + HttpServletRequest req = (HttpServletRequest) request; + + String requestId = req.getHeader(REQUEST_ID_NAME); + res.addHeader(REQUEST_ID_NAME, requestId != null ? requestId : UUID.randomUUID().toString()); + + res.addHeader(VERSION_MINOR_NAME, "0"); + res.addHeader(VERSION_PATCH_NAME, "0"); + res.addHeader(VERSION_LATEST_NAME, API_VERSION); + + chain.doFilter(request, response); + } + +} diff --git a/participant/participant-impl/participant-impl-simulator/src/main/java/org/onap/policy/clamp/controlloop/participant/simulator/main/startstop/Main.java b/participant/participant-impl/participant-impl-simulator/src/main/java/org/onap/policy/clamp/controlloop/participant/simulator/main/startstop/Main.java deleted file mode 100644 index e6c93d55d..000000000 --- a/participant/participant-impl/participant-impl-simulator/src/main/java/org/onap/policy/clamp/controlloop/participant/simulator/main/startstop/Main.java +++ /dev/null @@ -1,141 +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.participant.simulator.main.startstop; - -import java.util.Arrays; -import javax.ws.rs.core.Response; -import lombok.Getter; -import org.onap.policy.clamp.controlloop.common.exception.ControlLoopException; -import org.onap.policy.clamp.controlloop.common.exception.ControlLoopRuntimeException; -import org.onap.policy.clamp.controlloop.participant.simulator.main.parameters.ParticipantSimulatorParameterHandler; -import org.onap.policy.clamp.controlloop.participant.simulator.main.parameters.ParticipantSimulatorParameters; -import org.onap.policy.common.utils.resources.MessageConstants; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * This class initiates participant simulator. - */ -public class Main { - - private static final Logger LOGGER = LoggerFactory.getLogger(Main.class); - - private ParticipantSimulatorActivator activator; - - @Getter - private ParticipantSimulatorParameters parameterGroup; - - /** - * Instantiates the control loop participant service. - * - * @param args the command line arguments - */ - public Main(final String[] args) { - final String argumentString = Arrays.toString(args); - LOGGER.info("Starting the participant service with arguments - {}", argumentString); - - // Check the arguments - final ParticipantSimulatorCommandLineArguments arguments = new ParticipantSimulatorCommandLineArguments(); - try { - // The arguments return a string if there is a message to print and we should exit - final String argumentMessage = arguments.parse(args); - if (argumentMessage != null) { - LOGGER.info(argumentMessage); - return; - } - // Validate that the arguments are sane - arguments.validate(); - - // Read the parameters - parameterGroup = new ParticipantSimulatorParameterHandler().getParameters(arguments); - - // Now, create the activator for the service - activator = new ParticipantSimulatorActivator(parameterGroup); - - // Start the activator - activator.start(); - } catch (Exception exp) { - throw new ControlLoopRuntimeException(Response.Status.BAD_REQUEST, - String.format(MessageConstants.START_FAILURE_MSG, MessageConstants.POLICY_CLAMP), exp); - } - - // Add a shutdown hook to shut everything down in an orderly manner - Runtime.getRuntime().addShutdownHook(new ClParticipantSimulatorShutdownHookClass()); - String successMsg = String.format(MessageConstants.START_SUCCESS_MSG, MessageConstants.POLICY_CLAMP); - LOGGER.info(successMsg); - } - - /** - * Check if main is running. - */ - public boolean isRunning() { - return activator != null && activator.isAlive(); - } - - /** - * Shut down Execution. - * - * @throws ControlLoopException on shutdown errors - */ - public void shutdown() throws ControlLoopException { - // clear the parameterGroup variable - parameterGroup = null; - - // clear the cl participant activator - if (activator != null) { - activator.stop(); - } - } - - /** - * The Class ClParticipantSimulatorShutdownHookClass terminates the control loop participant service - * when its run method is called. - */ - private class ClParticipantSimulatorShutdownHookClass extends Thread { - /* - * (non-Javadoc) - * - * @see java.lang.Runnable#run() - */ - @Override - public void run() { - try { - // Shutdown the participant simulator and wait for everything to stop - shutdown(); - } catch (final RuntimeException | ControlLoopException e) { - LOGGER.warn("error occured during shut down of the participant simulator", e); - } - } - } - - /** - * The main method. - * - * @param args the arguments - */ - public static void main(final String[] args) { // NOSONAR - /* - * NOTE: arguments are validated by the constructor, thus sonar is disabled. - */ - - new Main(args); - } -} diff --git a/participant/participant-impl/participant-impl-simulator/src/main/java/org/onap/policy/clamp/controlloop/participant/simulator/main/startstop/ParticipantSimulatorActivator.java b/participant/participant-impl/participant-impl-simulator/src/main/java/org/onap/policy/clamp/controlloop/participant/simulator/main/startstop/ParticipantSimulatorActivator.java deleted file mode 100644 index 4daa0393f..000000000 --- a/participant/participant-impl/participant-impl-simulator/src/main/java/org/onap/policy/clamp/controlloop/participant/simulator/main/startstop/ParticipantSimulatorActivator.java +++ /dev/null @@ -1,75 +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.participant.simulator.main.startstop; - -import java.util.Set; -import java.util.concurrent.atomic.AtomicReference; -import lombok.Getter; -import org.onap.policy.clamp.controlloop.participant.simulator.main.parameters.ParticipantSimulatorParameters; -import org.onap.policy.clamp.controlloop.participant.simulator.main.rest.ParticipantSimulatorAafFilter; -import org.onap.policy.clamp.controlloop.participant.simulator.simulation.SimulationHandler; -import org.onap.policy.common.endpoints.http.server.RestServer; -import org.onap.policy.common.utils.services.ServiceManagerContainer; - -/** - * This class activates the participant simulator component as a complete service together with all its controllers, - * listeners and handlers. - */ -public class ParticipantSimulatorActivator extends ServiceManagerContainer { - @Getter - private final ParticipantSimulatorParameters parameters; - - /** - * Instantiate the activator for the simulator as a complete service. - * - * @param parameters the parameters for the participant service - */ - public ParticipantSimulatorActivator(final ParticipantSimulatorParameters parameters) { - this.parameters = parameters; - - final AtomicReference<SimulationHandler> simulationHandler = new AtomicReference<>(); - final AtomicReference<RestServer> restServer = new AtomicReference<>(); - - // @formatter:off - addAction("Simulation Handler", - () -> simulationHandler.set(new SimulationHandler(parameters)), - () -> simulationHandler.get().close()); - - addAction("Simulation Providers", - () -> simulationHandler.get().startProviders(), - () -> simulationHandler.get().stopProviders()); - - parameters.getRestServerParameters().setName(parameters.getName()); - - addAction("REST server", - () -> { - Set<Class<?>> providerClasses = simulationHandler.get().getProviderClasses(); - - RestServer server = new RestServer(parameters.getRestServerParameters(), - ParticipantSimulatorAafFilter.class, - providerClasses.toArray(new Class<?>[providerClasses.size()])); - restServer.set(server); - restServer.get().start(); - }, - () -> restServer.get().stop()); - // @formatter:on - } -} diff --git a/participant/participant-impl/participant-impl-simulator/src/main/java/org/onap/policy/clamp/controlloop/participant/simulator/main/startstop/ParticipantSimulatorCommandLineArguments.java b/participant/participant-impl/participant-impl-simulator/src/main/java/org/onap/policy/clamp/controlloop/participant/simulator/main/startstop/ParticipantSimulatorCommandLineArguments.java deleted file mode 100644 index 51ac3a4d5..000000000 --- a/participant/participant-impl/participant-impl-simulator/src/main/java/org/onap/policy/clamp/controlloop/participant/simulator/main/startstop/ParticipantSimulatorCommandLineArguments.java +++ /dev/null @@ -1,151 +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.participant.simulator.main.startstop; - -import java.io.File; -import java.io.PrintWriter; -import java.io.StringWriter; -import java.net.URL; -import java.util.Arrays; -import javax.ws.rs.core.Response; -import lombok.Getter; -import lombok.Setter; -import org.apache.commons.cli.CommandLine; -import org.apache.commons.cli.DefaultParser; -import org.apache.commons.cli.HelpFormatter; -import org.apache.commons.cli.Option; -import org.apache.commons.cli.Options; -import org.apache.commons.cli.ParseException; -import org.apache.commons.lang3.StringUtils; -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.startstop.CommonCommandLineArguments; -import org.onap.policy.common.utils.resources.ResourceUtils; - -/** - * This class reads and handles command line parameters for the participant simulator service. - * - */ -public class ParticipantSimulatorCommandLineArguments { - private static final String FILE_MESSAGE_PREAMBLE = " file \""; - private static final int HELP_LINE_LENGTH = 120; - - private final Options options; - private final CommonCommandLineArguments commonCommandLineArguments; - - @Getter() - @Setter() - private String configurationFilePath = null; - - /** - * Construct the options for the participant component. - */ - public ParticipantSimulatorCommandLineArguments() { - options = new Options(); - commonCommandLineArguments = new CommonCommandLineArguments(options); - } - - /** - * Construct the options for the participant component and parse in the given arguments. - * - * @param args The command line arguments - */ - public ParticipantSimulatorCommandLineArguments(final String[] args) { - // Set up the options with the default constructor - this(); - - // Parse the arguments - try { - parse(args); - } catch (final ControlLoopException e) { - throw new ControlLoopRuntimeException(Response.Status.NOT_ACCEPTABLE, - "parse error on participant parameters", e); - } - } - - /** - * Parse the command line options. - * - * @param args The command line arguments - * @return a string with a message for help and version, or null if there is no message - * @throws ControlLoopException on command argument errors - */ - public String parse(final String[] args) throws ControlLoopException { - // Clear all our arguments - setConfigurationFilePath(null); - CommandLine commandLine = null; - try { - commandLine = new DefaultParser().parse(options, args); - } catch (final ParseException e) { - throw new ControlLoopException(Response.Status.NOT_ACCEPTABLE, - "invalid command line arguments specified : " + e.getMessage()); - } - - // Arguments left over after Commons CLI does its stuff - final String[] remainingArgs = commandLine.getArgs(); - - if (remainingArgs.length > 0) { - throw new ControlLoopException(Response.Status.NOT_ACCEPTABLE, - "too many command line arguments specified : " + Arrays.toString(args)); - } - - if (commandLine.hasOption('h')) { - return commonCommandLineArguments.help(Main.class.getName(), options); - } - - if (commandLine.hasOption('v')) { - return commonCommandLineArguments.version(); - } - - if (commandLine.hasOption('c')) { - setConfigurationFilePath(commandLine.getOptionValue('c')); - } - - return null; - } - - /** - * Validate the command line options. - * - * @throws ControlLoopException on command argument validation errors - */ - public void validate() throws ControlLoopException { - commonCommandLineArguments.validate(configurationFilePath); - } - - /** - * Gets the full expanded configuration file path. - * - * @return the configuration file path - */ - public String getFullConfigurationFilePath() { - return ResourceUtils.getFilePath4Resource(getConfigurationFilePath()); - } - - /** - * Check set configuration file path. - * - * @return true, if check set configuration file path - */ - public boolean checkSetConfigurationFilePath() { - return !StringUtils.isEmpty(configurationFilePath); - } -} diff --git a/participant/participant-impl/participant-impl-simulator/src/main/java/org/onap/policy/clamp/controlloop/participant/simulator/simulation/SimulationHandler.java b/participant/participant-impl/participant-impl-simulator/src/main/java/org/onap/policy/clamp/controlloop/participant/simulator/simulation/SimulationHandler.java deleted file mode 100644 index df7f2a611..000000000 --- a/participant/participant-impl/participant-impl-simulator/src/main/java/org/onap/policy/clamp/controlloop/participant/simulator/simulation/SimulationHandler.java +++ /dev/null @@ -1,81 +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.participant.simulator.simulation; - -import java.io.IOException; -import java.util.List; -import java.util.Set; -import javax.ws.rs.core.Response; -import lombok.Getter; -import org.onap.policy.clamp.controlloop.common.handler.ControlLoopHandler; -import org.onap.policy.clamp.controlloop.participant.intermediary.parameters.ParticipantIntermediaryParameters; -import org.onap.policy.clamp.controlloop.participant.simulator.main.parameters.ParticipantSimulatorParameters; -import org.onap.policy.clamp.controlloop.participant.simulator.simulation.rest.SimulationElementController; -import org.onap.policy.clamp.controlloop.participant.simulator.simulation.rest.SimulationParticipantController; -import org.onap.policy.common.endpoints.event.comm.TopicSink; -import org.onap.policy.common.endpoints.listeners.MessageTypeDispatcher; -import org.onap.policy.common.utils.services.Registry; -import org.onap.policy.models.base.PfModelRuntimeException; - -/** - * This class handles simulation of participants and control loop elements. - * - * <p/>It is effectively a singleton that is started at system start. - */ -public class SimulationHandler extends ControlLoopHandler { - private final ParticipantIntermediaryParameters participantParameters; - - @Getter - private SimulationProvider simulationProvider; - - /** - * Create a handler. - * - * @param parameters the parameters for access to the database - */ - public SimulationHandler(ParticipantSimulatorParameters parameters) { - super(parameters.getDatabaseProviderParameters()); - participantParameters = parameters.getIntermediaryParameters(); - } - - public static SimulationHandler getInstance() { - return Registry.get(SimulationHandler.class.getName()); - } - - @Override - public Set<Class<?>> getProviderClasses() { - return Set.of(SimulationElementController.class, SimulationParticipantController.class); - } - - @Override - public void startProviders() { - simulationProvider = new SimulationProvider(participantParameters); - } - - @Override - public void stopProviders() { - try { - simulationProvider.close(); - } catch (IOException e) { - throw new PfModelRuntimeException(Response.Status.INTERNAL_SERVER_ERROR, "Stop providers failed ", e); - } - } -} diff --git a/participant/participant-impl/participant-impl-simulator/src/main/java/org/onap/policy/clamp/controlloop/participant/simulator/simulation/SimulationProvider.java b/participant/participant-impl/participant-impl-simulator/src/main/java/org/onap/policy/clamp/controlloop/participant/simulator/simulation/SimulationProvider.java index 1fcbba3af..6ee4eac3e 100644 --- a/participant/participant-impl/participant-impl-simulator/src/main/java/org/onap/policy/clamp/controlloop/participant/simulator/simulation/SimulationProvider.java +++ b/participant/participant-impl/participant-impl-simulator/src/main/java/org/onap/policy/clamp/controlloop/participant/simulator/simulation/SimulationProvider.java @@ -20,44 +20,30 @@ package org.onap.policy.clamp.controlloop.participant.simulator.simulation; -import java.io.Closeable; -import java.io.IOException; import java.util.List; import java.util.Map; import java.util.UUID; -import lombok.Getter; import org.onap.policy.clamp.controlloop.common.exception.ControlLoopException; -import org.onap.policy.clamp.controlloop.common.exception.ControlLoopRuntimeException; -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.Participant; import org.onap.policy.clamp.controlloop.models.messages.rest.TypedSimpleResponse; import org.onap.policy.clamp.controlloop.participant.intermediary.api.ParticipantIntermediaryApi; -import org.onap.policy.clamp.controlloop.participant.intermediary.api.ParticipantIntermediaryFactory; -import org.onap.policy.clamp.controlloop.participant.intermediary.parameters.ParticipantIntermediaryParameters; +import org.springframework.stereotype.Service; /** * This provider class simulation of participants and control loop elements. */ -public class SimulationProvider implements Closeable { - @Getter +@Service +public class SimulationProvider { + private final ParticipantIntermediaryApi intermediaryApi; /** * Create a participant simulation provider. - * - * @throws ControlLoopRuntimeException on errors creating the provider */ - public SimulationProvider(ParticipantIntermediaryParameters participantParameters) - throws ControlLoopRuntimeException { - intermediaryApi = new ParticipantIntermediaryFactory().createApiImplementation(); - intermediaryApi.init(participantParameters); - } - - @Override - public void close() throws IOException { - intermediaryApi.close(); + public SimulationProvider(ParticipantIntermediaryApi intermediaryApi) { + this.intermediaryApi = intermediaryApi; } /** @@ -78,10 +64,8 @@ public class SimulationProvider implements Closeable { * @param name the controlLoopElement, null to get all * @param version the controlLoopElement, null to get all * @return the control loop elements - * @throws ControlLoopException on errors getting the control loop elements */ - public Map<UUID, ControlLoopElement> getControlLoopElements(String name, String version) - throws ControlLoopException { + public Map<UUID, ControlLoopElement> getControlLoopElements(String name, String version) { return intermediaryApi.getControlLoopElements(name, version); } @@ -90,13 +74,11 @@ public class SimulationProvider implements Closeable { * * @param element the control loop element to update * @return response simple response returned - * @throws ControlLoopException on errors updating the control loop element */ - public TypedSimpleResponse<ControlLoopElement> updateControlLoopElement(ControlLoopElement element) - throws ControlLoopException { + public TypedSimpleResponse<ControlLoopElement> updateControlLoopElement(ControlLoopElement element) { TypedSimpleResponse<ControlLoopElement> response = new TypedSimpleResponse<>(); - response.setResponse(intermediaryApi.updateControlLoopElementState( - element.getId(), element.getOrderedState(), element.getState())); + response.setResponse(intermediaryApi.updateControlLoopElementState(element.getId(), element.getOrderedState(), + element.getState())); return response; } @@ -106,9 +88,8 @@ public class SimulationProvider implements Closeable { * @param name the participant, null to get all * @param version the participant, null to get all * @return the list of participants - * @throws ControlLoopException on errors getting the participants */ - public List<Participant> getParticipants(String name, String version) throws ControlLoopException { + public List<Participant> getParticipants(String name, String version) { return intermediaryApi.getParticipants(name, version); } @@ -117,13 +98,11 @@ public class SimulationProvider implements Closeable { * * @param participant the participant to update * @return TypedSimpleResponse simple response - * @throws ControlLoopException on errors updating the participant */ - - public TypedSimpleResponse<Participant> updateParticipant(Participant participant) throws ControlLoopException { + public TypedSimpleResponse<Participant> updateParticipant(Participant participant) { TypedSimpleResponse<Participant> response = new TypedSimpleResponse<>(); - response.setResponse(intermediaryApi.updateParticipantState( - participant.getDefinition(), participant.getParticipantState())); + response.setResponse( + intermediaryApi.updateParticipantState(participant.getDefinition(), participant.getParticipantState())); return response; } } diff --git a/participant/participant-impl/participant-impl-simulator/src/main/java/org/onap/policy/clamp/controlloop/participant/simulator/simulation/rest/SimulationElementController.java b/participant/participant-impl/participant-impl-simulator/src/main/java/org/onap/policy/clamp/controlloop/participant/simulator/simulation/rest/SimulationElementController.java index 1869047c9..de2a06223 100644 --- a/participant/participant-impl/participant-impl-simulator/src/main/java/org/onap/policy/clamp/controlloop/participant/simulator/simulation/rest/SimulationElementController.java +++ b/participant/participant-impl/participant-impl-simulator/src/main/java/org/onap/policy/clamp/controlloop/participant/simulator/simulation/rest/SimulationElementController.java @@ -28,30 +28,35 @@ import io.swagger.annotations.Authorization; import io.swagger.annotations.Extension; import io.swagger.annotations.ExtensionProperty; import io.swagger.annotations.ResponseHeader; -import java.util.List; import java.util.Map; import java.util.UUID; -import javax.ws.rs.GET; -import javax.ws.rs.HeaderParam; -import javax.ws.rs.PUT; -import javax.ws.rs.Path; -import javax.ws.rs.PathParam; -import javax.ws.rs.core.Response; -import javax.ws.rs.core.Response.Status; -import org.onap.policy.clamp.controlloop.common.exception.ControlLoopException; 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.messages.rest.SimpleResponse; import org.onap.policy.clamp.controlloop.models.messages.rest.TypedSimpleResponse; -import org.onap.policy.clamp.controlloop.participant.simulator.main.rest.RestController; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import org.onap.policy.clamp.controlloop.participant.simulator.main.rest.AbstractRestController; +import org.onap.policy.clamp.controlloop.participant.simulator.simulation.SimulationProvider; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RestController; /** * Class to provide REST end points for participant simulator to query/update details of controlLoopElements. */ -public class SimulationElementController extends RestController { - private static final Logger LOGGER = LoggerFactory.getLogger(SimulationElementController.class); +@RestController +public class SimulationElementController extends AbstractRestController { + + /** + * Constructor. + * + * @param simulationProvider the Simulation Provider + */ + public SimulationElementController(SimulationProvider simulationProvider) { + super(simulationProvider); + } /** * Queries details of all control loop element within the simulator. @@ -62,8 +67,7 @@ public class SimulationElementController extends RestController { * @return the control loop elements */ // @formatter:off - @GET - @Path("/elements/{name}/{version}") + @GetMapping("/elements/{name}/{version}") @ApiOperation(value = "Query details of the requested simulated control loop elements", notes = "Queries details of the requested simulated control loop elements, " + "returning all control loop element details", @@ -100,24 +104,16 @@ public class SimulationElementController extends RestController { } ) // @formatter:on - public Response elements(@HeaderParam(REQUEST_ID_NAME) @ApiParam(REQUEST_ID_PARAM_DESCRIPTION) UUID requestId, - @ApiParam(value = "Control loop element name", required = true) @PathParam("name") String name, - @ApiParam(value = "Control loop element version", required = true) @PathParam("version") String version) { - - try { - Map<UUID, ControlLoopElement> response = getSimulationProvider().getControlLoopElements(name, version); - return addLoggingHeaders(addVersionControlHeaders(Response.status(Status.OK)), requestId).entity(response) - .build(); - - } catch (ControlLoopException cle) { - LOGGER.warn("get of control loop elements failed", cle); - SimpleResponse resp = new SimpleResponse(); - resp.setErrorDetails(cle.getErrorResponse().getErrorMessage()); - return addLoggingHeaders( - addVersionControlHeaders(Response.status(cle.getErrorResponse().getResponseCode())), requestId) - .entity(resp).build(); - } + public ResponseEntity<Map<UUID, ControlLoopElement>> elements( + @RequestHeader( + name = REQUEST_ID_NAME, + required = false) @ApiParam(REQUEST_ID_PARAM_DESCRIPTION) UUID requestId, + @ApiParam(value = "Control loop element name", required = true) @PathVariable("name") String name, + @ApiParam( + value = "Control loop element version", + required = true) @PathVariable("version") String version) { + return ResponseEntity.ok().body(getSimulationProvider().getControlLoopElements(name, version)); } /** @@ -128,8 +124,7 @@ public class SimulationElementController extends RestController { * @return a response */ // @formatter:off - @PUT - @Path("/elements") + @PutMapping("/elements") @ApiOperation( value = "Updates simulated control loop elements", notes = "Updates simulated control loop elements, returning the updated control loop definition IDs", @@ -174,22 +169,12 @@ public class SimulationElementController extends RestController { } ) // @formatter:on - public Response update(@HeaderParam(REQUEST_ID_NAME) @ApiParam(REQUEST_ID_PARAM_DESCRIPTION) UUID requestId, - @ApiParam(value = "Body of a control loop element", required = true) ControlLoopElement body) { - - try { - TypedSimpleResponse<ControlLoopElement> response = - getSimulationProvider().updateControlLoopElement(body); - return addLoggingHeaders(addVersionControlHeaders(Response.status(Status.OK)), requestId).entity(response) - .build(); + public ResponseEntity<TypedSimpleResponse<ControlLoopElement>> update( + @RequestHeader( + name = REQUEST_ID_NAME, + required = false) @ApiParam(REQUEST_ID_PARAM_DESCRIPTION) UUID requestId, + @ApiParam(value = "Body of a control loop element", required = true) @RequestBody ControlLoopElement body) { - } catch (ControlLoopException cle) { - LOGGER.warn("update of control loop element failed", cle); - TypedSimpleResponse<ControlLoopElement> resp = new TypedSimpleResponse<>(); - resp.setErrorDetails(cle.getErrorResponse().getErrorMessage()); - return addLoggingHeaders( - addVersionControlHeaders(Response.status(cle.getErrorResponse().getResponseCode())), requestId) - .entity(resp).build(); - } + return ResponseEntity.ok().body(getSimulationProvider().updateControlLoopElement(body)); } } diff --git a/participant/participant-impl/participant-impl-simulator/src/main/java/org/onap/policy/clamp/controlloop/participant/simulator/simulation/rest/SimulationParticipantController.java b/participant/participant-impl/participant-impl-simulator/src/main/java/org/onap/policy/clamp/controlloop/participant/simulator/simulation/rest/SimulationParticipantController.java index d6ca6d0d1..715ec3410 100644 --- a/participant/participant-impl/participant-impl-simulator/src/main/java/org/onap/policy/clamp/controlloop/participant/simulator/simulation/rest/SimulationParticipantController.java +++ b/participant/participant-impl/participant-impl-simulator/src/main/java/org/onap/policy/clamp/controlloop/participant/simulator/simulation/rest/SimulationParticipantController.java @@ -30,26 +30,32 @@ import io.swagger.annotations.ExtensionProperty; import io.swagger.annotations.ResponseHeader; import java.util.List; import java.util.UUID; -import javax.ws.rs.GET; -import javax.ws.rs.HeaderParam; -import javax.ws.rs.PUT; -import javax.ws.rs.Path; -import javax.ws.rs.PathParam; -import javax.ws.rs.core.Response; -import javax.ws.rs.core.Response.Status; -import org.onap.policy.clamp.controlloop.common.exception.ControlLoopException; import org.onap.policy.clamp.controlloop.models.controlloop.concepts.Participant; -import org.onap.policy.clamp.controlloop.models.messages.rest.SimpleResponse; import org.onap.policy.clamp.controlloop.models.messages.rest.TypedSimpleResponse; -import org.onap.policy.clamp.controlloop.participant.simulator.main.rest.RestController; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import org.onap.policy.clamp.controlloop.participant.simulator.main.rest.AbstractRestController; +import org.onap.policy.clamp.controlloop.participant.simulator.simulation.SimulationProvider; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RestController; /** * Class to provide REST end points for participant simulator to query/update details of all participants. */ -public class SimulationParticipantController extends RestController { - private static final Logger LOGGER = LoggerFactory.getLogger(SimulationParticipantController.class); +@RestController +public class SimulationParticipantController extends AbstractRestController { + + /** + * Constructor. + * + * @param simulationProvider the Simulation Provider + */ + public SimulationParticipantController(SimulationProvider simulationProvider) { + super(simulationProvider); + } /** * Queries details of all participants within the simulator. @@ -60,8 +66,7 @@ public class SimulationParticipantController extends RestController { * @return the participants */ // @formatter:off - @GET - @Path("/participants/{name}/{version}") + @GetMapping("/participants/{name}/{version}") @ApiOperation(value = "Query details of the requested simulated participants", notes = "Queries details of the requested simulated participants, " + "returning all participant details", @@ -98,24 +103,14 @@ public class SimulationParticipantController extends RestController { } ) // @formatter:on - public Response participants(@HeaderParam(REQUEST_ID_NAME) @ApiParam(REQUEST_ID_PARAM_DESCRIPTION) UUID requestId, - @ApiParam(value = "Participant name", required = true) @PathParam("name") String name, - @ApiParam(value = "Participant version", required = true) @PathParam("version") String version) { - - try { - List<Participant> response = getSimulationProvider().getParticipants(name, version); - return addLoggingHeaders(addVersionControlHeaders(Response.status(Status.OK)), requestId).entity(response) - .build(); - - } catch (ControlLoopException cle) { - LOGGER.warn("get of participants failed", cle); - SimpleResponse resp = new SimpleResponse(); - resp.setErrorDetails(cle.getErrorResponse().getErrorMessage()); - return addLoggingHeaders( - addVersionControlHeaders(Response.status(cle.getErrorResponse().getResponseCode())), requestId) - .entity(resp).build(); - } + public ResponseEntity<List<Participant>> participants( + @RequestHeader( + name = REQUEST_ID_NAME, + required = false) @ApiParam(REQUEST_ID_PARAM_DESCRIPTION) UUID requestId, + @ApiParam(value = "Participant name", required = true) @PathVariable("name") String name, + @ApiParam(value = "Participant version", required = true) @PathVariable("version") String version) { + return ResponseEntity.ok().body(getSimulationProvider().getParticipants(name, version)); } /** @@ -126,8 +121,7 @@ public class SimulationParticipantController extends RestController { * @return a response */ // @formatter:off - @PUT - @Path("/participants") + @PutMapping("/participants") @ApiOperation( value = "Updates simulated participants", notes = "Updates simulated participants, returning the updated control loop definition IDs", @@ -172,21 +166,12 @@ public class SimulationParticipantController extends RestController { } ) // @formatter:on - public Response update(@HeaderParam(REQUEST_ID_NAME) @ApiParam(REQUEST_ID_PARAM_DESCRIPTION) UUID requestId, - @ApiParam(value = "Body of a participant", required = true) Participant body) { - - try { - TypedSimpleResponse<Participant> response = getSimulationProvider().updateParticipant(body); - return addLoggingHeaders(addVersionControlHeaders(Response.status(Status.OK)), requestId).entity(response) - .build(); + public ResponseEntity<TypedSimpleResponse<Participant>> update( + @RequestHeader( + name = REQUEST_ID_NAME, + required = false) @ApiParam(REQUEST_ID_PARAM_DESCRIPTION) UUID requestId, + @ApiParam(value = "Body of a participant", required = true) @RequestBody Participant body) { - } catch (ControlLoopException cle) { - LOGGER.warn("update of participant failed", cle); - TypedSimpleResponse<Participant> resp = new TypedSimpleResponse<>(); - resp.setErrorDetails(cle.getErrorResponse().getErrorMessage()); - return addLoggingHeaders( - addVersionControlHeaders(Response.status(cle.getErrorResponse().getResponseCode())), requestId) - .entity(resp).build(); - } + return ResponseEntity.ok().body(getSimulationProvider().updateParticipant(body)); } } diff --git a/participant/participant-impl/participant-impl-simulator/src/main/resources/config/CDSParticipantConfig.json b/participant/participant-impl/participant-impl-simulator/src/main/resources/config/CDSParticipantConfig.json index 3eca87678..544edb1ff 100644 --- a/participant/participant-impl/participant-impl-simulator/src/main/resources/config/CDSParticipantConfig.json +++ b/participant/participant-impl/participant-impl-simulator/src/main/resources/config/CDSParticipantConfig.json @@ -1,31 +1,61 @@ { - "name":"ParticipantParameterGroup", - "participantStatusParameters":{ - "timeIntervalMs": 10000, - "description":"Participant Status", - "participantType":{ - "name": "org.onap.ccsdk.cds.controlloop.CdsControlLoopParticipant", - "version":"2.2.1" + "name": "ControlLoopParticipantGroup", + "restServerParameters": { + "host": "0.0.0.0", + "port": 6969, + "userName": "healthcheck", + "password": "zb!XztG34", + "https": false, + "aaf": false + }, + "intermediaryParameters": { + "name": "Participant parameters", + "reportingTimeInterval": 120000, + "description": "Participant Description", + "participantId": { + "name": "org.onap.PM_CDS_Blueprint", + "version": "1.0.0" }, - "participantId":{ - "name": "CDSParticipant0", - "version":"1.0.0" + "participantType": { + "name": "org.onap.PM_CDS_Blueprint", + "version": "1.0.0" }, - "participantDefinition":{ - "name": "org.onap.ccsdk.cds.controlloop.CdsControlLoopParticipant", - "version":"3.2.1" + "clampControlLoopTopics": { + "topicSources": [ + { + "topic": "POLICY-CLRUNTIME-PARTICIPANT", + "servers": [ + "message-router" + ], + "topicCommInfrastructure": "dmaap", + "fetchTimeout": 15000 + } + ], + "topicSinks": [ + { + "topic": "POLICY-CLRUNTIME-PARTICIPANT", + "servers": [ + "message-router" + ], + "topicCommInfrastructure": "dmaap" + }, + { + "topic": "POLICY-NOTIFICATION", + "servers": [ + "message-router" + ], + "topicCommInfrastructure": "dmaap" + } + ] } }, - "topicParameterGroup": { - "topicSources" : [{ - "topic" : "POLICY-CLRUNTIME-PARTICIPANT", - "servers" : [ "127.0.0.1:3904" ], - "topicCommInfrastructure" : "dmaap" - }], - "topicSinks" : [{ - "topic" : "POLICY-CLRUNTIME-PARTICIPANT", - "servers" : [ "127.0.0.1:3904" ], - "topicCommInfrastructure" : "dmaap" - }] + "databaseProviderParameters": { + "name": "PolicyProviderParameterGroup", + "implementation": "org.onap.policy.models.provider.impl.DatabasePolicyModelsProviderImpl", + "databaseDriver": "org.mariadb.jdbc.Driver", + "databaseUrl": "jdbc:mariadb://mariadb:3306/cdsparticipantsim", + "databaseUser": "policy", + "databasePassword": "P01icY", + "persistenceUnit": "ToscaConceptTest" } } 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 new file mode 100644 index 000000000..b1fc135a5 --- /dev/null +++ b/participant/participant-impl/participant-impl-simulator/src/main/resources/config/application.yaml @@ -0,0 +1,15 @@ +spring: + security: + user: + name: healthcheck + password: zb!XztG34 + +server: + port: 6969 + servlet: + context-path: /onap/participantsim + error: + path: /error + +participant: + file: src/main/resources/config/CDSParticipantConfig.json diff --git a/participant/participant-impl/participant-impl-simulator/src/test/java/org/onap/policy/clamp/controlloop/participant/simulator/endtoend/ParticipantSimulatorTest.java b/participant/participant-impl/participant-impl-simulator/src/test/java/org/onap/policy/clamp/controlloop/participant/simulator/endtoend/ParticipantSimulatorTest.java new file mode 100644 index 000000000..832399660 --- /dev/null +++ b/participant/participant-impl/participant-impl-simulator/src/test/java/org/onap/policy/clamp/controlloop/participant/simulator/endtoend/ParticipantSimulatorTest.java @@ -0,0 +1,291 @@ +/*- + * ============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.simulator.endtoend; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +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.ControlLoopOrderedState; +import org.onap.policy.clamp.controlloop.models.controlloop.concepts.Participant; +import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ParticipantState; +import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantControlLoopUpdate; +import org.onap.policy.clamp.controlloop.models.messages.rest.TypedSimpleResponse; +import org.onap.policy.clamp.controlloop.participant.intermediary.api.ParticipantIntermediaryApi; +import org.onap.policy.clamp.controlloop.participant.intermediary.comm.ControlLoopUpdateListener; +import org.onap.policy.clamp.controlloop.participant.simulator.main.parameters.CommonTestData; +import org.onap.policy.clamp.controlloop.participant.simulator.main.rest.AbstractRestController; +import org.onap.policy.clamp.controlloop.participant.simulator.main.rest.TestListenerUtils; +import org.onap.policy.common.endpoints.event.comm.Topic.CommInfrastructure; +import org.onap.policy.common.utils.coder.Coder; +import org.onap.policy.common.utils.coder.StandardCoder; +import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; +import org.springframework.boot.test.web.client.TestRestTemplate; +import org.springframework.boot.web.server.LocalServerPort; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +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 ParticipantSimulatorTest { + + private static final String PARTICIPANTS_ENDPOINT = "participants"; + private static final String ELEMENTS_ENDPOINT = "elements"; + private static final CommInfrastructure INFRA = CommInfrastructure.NOOP; + private static final String TOPIC = "my-topic"; + + public static final Coder coder = new StandardCoder(); + + @Value("${spring.security.user.name}") + private String user; + + @Value("${spring.security.user.password}") + private String password; + + @LocalServerPort + private int randomServerPort; + + @Autowired + private TestRestTemplate restTemplate; + + @Autowired + private ParticipantIntermediaryApi participantIntermediaryApi; + + private static final Object lockit = new Object(); + private boolean check = false; + + private void setUp() throws Exception { + synchronized (lockit) { + if (!check) { + check = true; + ControlLoopUpdateListener clUpdateListener = + new ControlLoopUpdateListener(participantIntermediaryApi.getParticipantHandler()); + + ParticipantControlLoopUpdate participantControlLoopUpdateMsg = + TestListenerUtils.createControlLoopUpdateMsg(); + participantControlLoopUpdateMsg.getControlLoop().setOrderedState(ControlLoopOrderedState.PASSIVE); + clUpdateListener.onTopicEvent(INFRA, TOPIC, null, participantControlLoopUpdateMsg); + + } + } + } + + private String getPath(String path) { + return "http://localhost:" + randomServerPort + "/onap/participantsim/v2/" + path; + } + + void testSwagger(String endPoint) { + HttpEntity<Void> request = new HttpEntity<>(null, createHttpHeaders()); + ResponseEntity<String> response = + restTemplate.exchange(getPath("api-docs"), HttpMethod.GET, request, String.class); + assertThat(response.getStatusCodeValue()).isEqualTo(200); + assertTrue(response.getBody().contains("/onap/participantsim/v2/" + endPoint)); + } + + @Test + void testEndParticipatsSwagger() { + testSwagger(PARTICIPANTS_ENDPOINT); + } + + @Test + void testElementsSwagger() { + testSwagger(ELEMENTS_ENDPOINT); + } + + @Test + void testProducerYaml() { + MediaType yamlMediaType = new MediaType("application", "yaml"); + HttpHeaders headers = createHttpHeaders(); + headers.setAccept(Collections.singletonList(yamlMediaType)); + HttpEntity<Void> request = new HttpEntity<>(null, headers); + String path = getPath(PARTICIPANTS_ENDPOINT + "/org.onap.PM_CDS_Blueprint/1"); + + ResponseEntity<String> response = restTemplate.exchange(path, HttpMethod.GET, request, String.class); + + assertThat(response.getStatusCodeValue()).isEqualTo(200); + assertTrue(response.getHeaders().getContentType().isCompatibleWith(yamlMediaType)); + } + + @Test + void testQuery_Unauthorized() throws Exception { + String path = getPath(PARTICIPANTS_ENDPOINT + "/org.onap.PM_CDS_Blueprint/1"); + + // authorized call + ResponseEntity<String> response = + restTemplate.exchange(path, HttpMethod.GET, new HttpEntity<>(null, createHttpHeaders()), String.class); + assertThat(response.getStatusCodeValue()).isEqualTo(200); + + // unauthorized call + response = restTemplate.exchange(path, HttpMethod.GET, new HttpEntity<>(null, new HttpHeaders()), String.class); + assertThat(response.getStatusCodeValue()).isEqualTo(401); + } + + private HttpHeaders createHttpHeaders() { + HttpHeaders headers = new HttpHeaders(); + headers.setBasicAuth(user, password); + return headers; + } + + protected <T> ResponseEntity<T> performGet(String endpoint, Class<T> responseType, UUID uuid) throws Exception { + HttpHeaders httpHeaders = createHttpHeaders(); + if (uuid != null) { + httpHeaders.add(AbstractRestController.REQUEST_ID_NAME, uuid.toString()); + } + HttpEntity<Void> request = new HttpEntity<>(null, httpHeaders); + return restTemplate.exchange(getPath(endpoint), HttpMethod.GET, request, responseType); + } + + protected <T> ResponseEntity<T> performGet(String endpoint, Class<T> responseType) throws Exception { + return performGet(endpoint, responseType, null); + } + + protected <T, R> ResponseEntity<R> performPut(String path, T body, ParameterizedTypeReference<R> responseType, + UUID uuid) throws Exception { + HttpHeaders httpHeaders = createHttpHeaders(); + if (uuid != null) { + httpHeaders.add(AbstractRestController.REQUEST_ID_NAME, uuid.toString()); + } + HttpEntity<T> request = new HttpEntity<>(body, httpHeaders); + return restTemplate.exchange(getPath(path), HttpMethod.PUT, request, responseType); + } + + @Test + void testQueryParticipants() throws Exception { + Participant participant = new Participant(); + ToscaConceptIdentifier participantId = CommonTestData.getParticipantId(); + participant.setDefinition(participantId); + participant.setName(participantId.getName()); + participant.setVersion(participantId.getVersion()); + UUID uuid = UUID.randomUUID(); + + // GET REST call for querying the participants + ResponseEntity<String> response = performGet( + PARTICIPANTS_ENDPOINT + "/" + participant.getKey().getName() + "/" + participant.getKey().getVersion(), + String.class, uuid); + checkResponseEntity(response, 200, uuid); + + Participant[] returnValue = coder.decode(response.getBody(), Participant[].class); + assertThat(returnValue).hasSize(1); + // Verify the result of GET participants with what is stored + assertEquals(participant.getDefinition(), returnValue[0].getDefinition()); + } + + private <T> void checkResponseEntity(ResponseEntity<T> response, int status, UUID uuid) { + assertThat(response.getStatusCodeValue()).isEqualTo(status); + assertThat(getHeader(response.getHeaders(), AbstractRestController.VERSION_MINOR_NAME)).isEqualTo("0"); + assertThat(getHeader(response.getHeaders(), AbstractRestController.VERSION_PATCH_NAME)).isEqualTo("0"); + assertThat(getHeader(response.getHeaders(), AbstractRestController.VERSION_LATEST_NAME)).isEqualTo("1.0.0"); + assertThat(getHeader(response.getHeaders(), AbstractRestController.REQUEST_ID_NAME)).isEqualTo(uuid.toString()); + } + + private String getHeader(HttpHeaders httpHeaders, String param) { + List<String> list = httpHeaders.get(param); + assertThat(list).hasSize(1); + return list.get(0); + } + + @Test + void testQueryControlLoopElements() throws Exception { + setUp(); + UUID uuid = UUID.randomUUID(); + ToscaConceptIdentifier participantId = CommonTestData.getParticipantId(); + + // GET REST call for querying the controlLoop elements + ResponseEntity<String> response = + performGet(ELEMENTS_ENDPOINT + "/" + participantId.getName() + "/" + participantId.getVersion(), + String.class, uuid); + checkResponseEntity(response, 200, uuid); + + Map returnValue = coder.decode(response.getBody(), Map.class); + // Verify the result of GET controlloop elements with what is stored + assertThat(returnValue).isEmpty(); + } + + @Test + void testUpdateParticipant() throws Exception { + setUp(); + List<Participant> participants = participantIntermediaryApi.getParticipants( + CommonTestData.getParticipantId().getName(), CommonTestData.getParticipantId().getVersion()); + assertEquals(ParticipantState.UNKNOWN, participants.get(0).getParticipantState()); + // Change the state of the participant to PASSIVE from UNKNOWN + participants.get(0).setParticipantState(ParticipantState.PASSIVE); + UUID uuid = UUID.randomUUID(); + + // PUT REST call for updating Participant + ResponseEntity<TypedSimpleResponse<Participant>> response = performPut(PARTICIPANTS_ENDPOINT, + participants.get(0), new ParameterizedTypeReference<TypedSimpleResponse<Participant>>() {}, uuid); + checkResponseEntity(response, 200, uuid); + + TypedSimpleResponse<Participant> resp = response.getBody(); + assertNotNull(resp.getResponse()); + // Verify the response and state returned by PUT REST call for updating participants + assertEquals(participants.get(0).getDefinition(), resp.getResponse().getDefinition()); + assertEquals(ParticipantState.PASSIVE, resp.getResponse().getParticipantState()); + } + + @Test + void testUpdateControlLoopElement() throws Exception { + setUp(); + ControlLoop controlLoop = TestListenerUtils.createControlLoop(); + Map<UUID, ControlLoopElement> controlLoopElements = participantIntermediaryApi.getControlLoopElements( + controlLoop.getDefinition().getName(), controlLoop.getDefinition().getVersion()); + + UUID uuid = controlLoopElements.keySet().iterator().next(); + ControlLoopElement controlLoopElement = controlLoopElements.get(uuid); + + // Check the initial state on the ControlLoopElement, which is UNINITIALISED + assertEquals(ControlLoopOrderedState.UNINITIALISED, controlLoopElement.getOrderedState()); + + // Change the state of the ControlLoopElement to PASSIVE from UNINITIALISED + controlLoopElement.setOrderedState(ControlLoopOrderedState.PASSIVE); + + // PUT REST call for updating ControlLoopElement + ResponseEntity<TypedSimpleResponse<ControlLoopElement>> response = performPut(ELEMENTS_ENDPOINT, + controlLoopElement, new ParameterizedTypeReference<TypedSimpleResponse<ControlLoopElement>>() {}, uuid); + checkResponseEntity(response, 200, uuid); + + TypedSimpleResponse<ControlLoopElement> resp = response.getBody(); + assertNotNull(resp.getResponse()); + // Verify the response and state returned by PUT REST call for updating participants + assertEquals(controlLoopElement.getDefinition(), resp.getResponse().getDefinition()); + assertEquals(ControlLoopOrderedState.PASSIVE, resp.getResponse().getOrderedState()); + } +} diff --git a/participant/participant-impl/participant-impl-simulator/src/test/java/org/onap/policy/clamp/controlloop/participant/simulator/main/intermediary/TestControlLoopUpdateListener.java b/participant/participant-impl/participant-impl-simulator/src/test/java/org/onap/policy/clamp/controlloop/participant/simulator/main/intermediary/TestControlLoopUpdateListener.java deleted file mode 100644 index a307d3457..000000000 --- a/participant/participant-impl/participant-impl-simulator/src/test/java/org/onap/policy/clamp/controlloop/participant/simulator/main/intermediary/TestControlLoopUpdateListener.java +++ /dev/null @@ -1,91 +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.participant.simulator.main.intermediary; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotEquals; - -import java.io.FileNotFoundException; -import java.io.IOException; -import org.junit.BeforeClass; -import org.junit.Test; -import org.onap.policy.clamp.controlloop.common.exception.ControlLoopException; -import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoopOrderedState; -import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantControlLoopUpdate; -import org.onap.policy.clamp.controlloop.participant.intermediary.comm.ControlLoopUpdateListener; -import org.onap.policy.clamp.controlloop.participant.simulator.main.parameters.CommonTestData; -import org.onap.policy.clamp.controlloop.participant.simulator.main.rest.TestListenerUtils; -import org.onap.policy.common.endpoints.event.comm.Topic.CommInfrastructure; -import org.onap.policy.common.utils.coder.CoderException; - -/** - * Class to perform unit test of {@link ControlLoopUpdateListener}. - */ -public class TestControlLoopUpdateListener { - private static ControlLoopUpdateListener clUpdateListener; - private static final CommInfrastructure INFRA = CommInfrastructure.NOOP; - private static final String TOPIC = "my-topic"; - static CommonTestData commonTestData = new CommonTestData(); - - /** - * Method for setup. - * - * @throws ParticipantException if some error occurs while starting up the participant - * @throws FileNotFoundException if the file is missing - * @throws IOException if IO exception occurs - */ - @BeforeClass - public static void setUp() throws ControlLoopException, FileNotFoundException, IOException { - TestListenerUtils.initParticipantHandler(); - clUpdateListener = new ControlLoopUpdateListener(TestListenerUtils.getParticipantHandler()); - } - - @Test - public void testControlLoopUpdateListener_ParticipantIdNoMatch() throws CoderException { - ParticipantControlLoopUpdate participantControlLoopUpdateMsg = prepareMsg("DummyName"); - clUpdateListener.onTopicEvent(INFRA, TOPIC, null, participantControlLoopUpdateMsg); - - // Verify the content in participantHandler - assertNotEquals(participantControlLoopUpdateMsg.getParticipantId().getName(), - TestListenerUtils.getParticipantHandler().getParticipantId().getName()); - } - - @Test - public void testControlLoopUpdateListener() throws CoderException { - ParticipantControlLoopUpdate participantControlLoopUpdateMsg = prepareMsg("org.onap.PM_CDS_Blueprint"); - clUpdateListener.onTopicEvent(INFRA, TOPIC, null, participantControlLoopUpdateMsg); - - // Verify the content in participantHandler - assertEquals(TestListenerUtils.getParticipantHandler().getParticipantId(), - participantControlLoopUpdateMsg.getParticipantId()); - assertThat(TestListenerUtils.getParticipantHandler().getControlLoopHandler().getControlLoops() - .getControlLoopList()).hasSize(1); - } - - private ParticipantControlLoopUpdate prepareMsg(final String participantName) { - ParticipantControlLoopUpdate participantControlLoopUpdateMsg; - participantControlLoopUpdateMsg = TestListenerUtils.createControlLoopUpdateMsg(); - participantControlLoopUpdateMsg.getParticipantId().setName(participantName); - participantControlLoopUpdateMsg.getControlLoop().setOrderedState(ControlLoopOrderedState.PASSIVE); - return participantControlLoopUpdateMsg; - } -} diff --git a/participant/participant-impl/participant-impl-simulator/src/test/java/org/onap/policy/clamp/controlloop/participant/simulator/main/parameters/CommonTestData.java b/participant/participant-impl/participant-impl-simulator/src/test/java/org/onap/policy/clamp/controlloop/participant/simulator/main/parameters/CommonTestData.java index 0a8754256..8ca139bcd 100644 --- a/participant/participant-impl/participant-impl-simulator/src/test/java/org/onap/policy/clamp/controlloop/participant/simulator/main/parameters/CommonTestData.java +++ b/participant/participant-impl/participant-impl-simulator/src/test/java/org/onap/policy/clamp/controlloop/participant/simulator/main/parameters/CommonTestData.java @@ -48,7 +48,7 @@ public class CommonTestData { private static final String REST_SERVER_PASSWORD = "zb!XztG34"; private static final String REST_SERVER_USER = "healthcheck"; private static final int REST_SERVER_PORT = 6969; - private static final String REST_SERVER_HOST = "0.0.0.0"; + public static final String REST_SERVER_HOST = "0.0.0.0"; private static final boolean REST_SERVER_HTTPS = true; private static final boolean REST_SERVER_AAF = false; @@ -197,8 +197,8 @@ public class CommonTestData { return coder.decode(getParticipantParameterGroupAsString(port), ParticipantSimulatorParameters.class); } catch (CoderException e) { - throw new ControlLoopRuntimeException(Response.Status.NOT_ACCEPTABLE, - "cannot read participant parameters", e); + throw new ControlLoopRuntimeException(Response.Status.NOT_ACCEPTABLE, "cannot read participant parameters", + e); } } @@ -220,8 +220,8 @@ public class CommonTestData { return json; } catch (IOException e) { - throw new ControlLoopRuntimeException(Response.Status.NOT_ACCEPTABLE, - "cannot read participant parameters", e); + throw new ControlLoopRuntimeException(Response.Status.NOT_ACCEPTABLE, "cannot read participant parameters", + e); } } @@ -239,6 +239,7 @@ public class CommonTestData { /** * Nulls out a field within a JSON string. + * * @param json JSON string * @param field field to be nulled out * @return a new JSON string with the field nulled out diff --git a/participant/participant-impl/participant-impl-simulator/src/test/java/org/onap/policy/clamp/controlloop/participant/simulator/main/parameters/TestParticipantSimulatorParameterHandler.java b/participant/participant-impl/participant-impl-simulator/src/test/java/org/onap/policy/clamp/controlloop/participant/simulator/main/parameters/TestParticipantSimulatorParameterHandler.java index e94939af8..44b49f355 100644 --- a/participant/participant-impl/participant-impl-simulator/src/test/java/org/onap/policy/clamp/controlloop/participant/simulator/main/parameters/TestParticipantSimulatorParameterHandler.java +++ b/participant/participant-impl/participant-impl-simulator/src/test/java/org/onap/policy/clamp/controlloop/participant/simulator/main/parameters/TestParticipantSimulatorParameterHandler.java @@ -20,101 +20,52 @@ package org.onap.policy.clamp.controlloop.participant.simulator.main.parameters; -import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; import java.io.FileNotFoundException; import org.apache.commons.io.DirectoryWalker.CancelException; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.onap.policy.clamp.controlloop.common.exception.ControlLoopException; -import org.onap.policy.clamp.controlloop.participant.simulator.main.startstop.ParticipantSimulatorCommandLineArguments; import org.onap.policy.common.utils.coder.CoderException; /** * Class to perform unit test of {@link ParticipantParameterHandler}. */ -public class TestParticipantSimulatorParameterHandler { +class TestParticipantSimulatorParameterHandler { @Test - public void testParameterHandlerNoParameterFile() throws ControlLoopException { - final String[] emptyArgumentString = { "-c", "src/test/resources/parameters/NoParametersFile.json" }; + void testParameterHandlerNoParameterFile() throws ControlLoopException { + final String path = "src/test/resources/parameters/NoParametersFile.json"; - final ParticipantSimulatorCommandLineArguments emptyArguments = new ParticipantSimulatorCommandLineArguments(); - emptyArguments.parse(emptyArgumentString); - - assertThatThrownBy(() -> new ParticipantSimulatorParameterHandler().getParameters(emptyArguments)) + assertThatThrownBy(() -> new ParticipantSimulatorParameterHandler().toParticipantSimulatorParameters(path)) .hasCauseInstanceOf(CoderException.class) .hasRootCauseInstanceOf(FileNotFoundException.class); } @Test - public void testParameterHandlerInvalidParameters() throws ControlLoopException { - final String[] invalidArgumentString = { "-c", "src/test/resources/parameters/InvalidParameters.json" }; - - final ParticipantSimulatorCommandLineArguments invalidArguments = - new ParticipantSimulatorCommandLineArguments(); - invalidArguments.parse(invalidArgumentString); + void testParameterHandlerInvalidParameters() throws ControlLoopException { + final String path = "src/test/resources/parameters/InvalidParameters.json"; - assertThatThrownBy(() -> new ParticipantSimulatorParameterHandler().getParameters(invalidArguments)) + assertThatThrownBy(() -> new ParticipantSimulatorParameterHandler().toParticipantSimulatorParameters(path)) .hasMessageStartingWith("error reading parameters from") .hasCauseInstanceOf(CoderException.class); } @Test - public void testParameterHandlerNoParameters() throws CancelException, ControlLoopException { - final String[] noArgumentString = { "-c", "src/test/resources/parameters/EmptyParameters.json" }; + void testParameterHandlerNoParameters() throws CancelException, ControlLoopException { + final String path = "src/test/resources/parameters/EmptyParameters.json"; - final ParticipantSimulatorCommandLineArguments noArguments = new ParticipantSimulatorCommandLineArguments(); - noArguments.parse(noArgumentString); - - assertThatThrownBy(() -> new ParticipantSimulatorParameterHandler().getParameters(noArguments)) + assertThatThrownBy(() -> new ParticipantSimulatorParameterHandler().toParticipantSimulatorParameters(path)) .hasMessageContaining("no parameters found"); } @Test - public void testParticipantParameterGroup() throws ControlLoopException { - final String[] participantConfigParameters = { "-c", "src/test/resources/parameters/TestParameters.json"}; - - final ParticipantSimulatorCommandLineArguments arguments = new ParticipantSimulatorCommandLineArguments(); - arguments.parse(participantConfigParameters); + void testParticipantParameterGroup() throws ControlLoopException { + final String path = "src/test/resources/parameters/TestParameters.json"; final ParticipantSimulatorParameters parGroup = new ParticipantSimulatorParameterHandler() - .getParameters(arguments); - assertTrue(arguments.checkSetConfigurationFilePath()); + .toParticipantSimulatorParameters(path); assertEquals(CommonTestData.PARTICIPANT_GROUP_NAME, parGroup.getName()); } - - @Test - public void testParticipantVersion() throws ControlLoopException { - final String[] participantConfigParameters = { "-v" }; - final ParticipantSimulatorCommandLineArguments arguments = new ParticipantSimulatorCommandLineArguments(); - assertThat(arguments.parse(participantConfigParameters)).startsWith( - "ONAP Tosca defined control loop Participant"); - } - - @Test - public void testParticipantHelp() throws ControlLoopException { - final String[] participantConfigParameters = { "-h" }; - final ParticipantSimulatorCommandLineArguments arguments = new ParticipantSimulatorCommandLineArguments(); - assertThat(arguments.parse(participantConfigParameters)).startsWith("usage:"); - } - - @Test - public void testParticipant_TooManyArguments() throws ControlLoopException { - final String[] participantConfigParameters = { "-c", "src/test/resources/parameters/TestParameters.json", - "TooMany"}; - final ParticipantSimulatorCommandLineArguments arguments = new ParticipantSimulatorCommandLineArguments(); - assertThatThrownBy(() -> arguments.parse(participantConfigParameters)) - .hasMessageStartingWith("too many command line arguments specified"); - } - - @Test - public void testParticipantInvalidOption() throws ControlLoopException { - final String[] participantConfigParameters = { "-d" }; - final ParticipantSimulatorCommandLineArguments arguments = new ParticipantSimulatorCommandLineArguments(); - assertThatThrownBy(() -> arguments.parse(participantConfigParameters)) - .hasMessageStartingWith("invalid command line arguments specified"); - } } diff --git a/participant/participant-impl/participant-impl-simulator/src/test/java/org/onap/policy/clamp/controlloop/participant/simulator/main/parameters/TestParticipantSimulatorParameters.java b/participant/participant-impl/participant-impl-simulator/src/test/java/org/onap/policy/clamp/controlloop/participant/simulator/main/parameters/TestParticipantSimulatorParameters.java index 8027d6f08..41c5b09b0 100644 --- a/participant/participant-impl/participant-impl-simulator/src/test/java/org/onap/policy/clamp/controlloop/participant/simulator/main/parameters/TestParticipantSimulatorParameters.java +++ b/participant/participant-impl/participant-impl-simulator/src/test/java/org/onap/policy/clamp/controlloop/participant/simulator/main/parameters/TestParticipantSimulatorParameters.java @@ -26,23 +26,23 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; import java.util.Map; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.onap.policy.common.parameters.ValidationResult; /** * Class to perform unit test of {@link ParticipantParameterGroup}. */ -public class TestParticipantSimulatorParameters { +class TestParticipantSimulatorParameters { CommonTestData commonTestData = new CommonTestData(); @Test - public void testParticipantParameterGroup_Named() { + void testParticipantParameterGroup_Named() { final ParticipantSimulatorParameters participantParameters = new ParticipantSimulatorParameters("my-name"); assertEquals("my-name", participantParameters.getName()); } @Test - public void testParticipantParameterGroup() { + void testParticipantParameterGroup() { final ParticipantSimulatorParameters participantParameters = commonTestData.toObject( commonTestData.getParticipantParameterGroupMap(CommonTestData.PARTICIPANT_GROUP_NAME), ParticipantSimulatorParameters.class); @@ -51,7 +51,7 @@ public class TestParticipantSimulatorParameters { } @Test - public void testParticipantParameterGroup_NullName() { + void testParticipantParameterGroup_NullName() { final ParticipantSimulatorParameters participantParameters = commonTestData .toObject(commonTestData.getParticipantParameterGroupMap(null), ParticipantSimulatorParameters.class); @@ -62,7 +62,7 @@ public class TestParticipantSimulatorParameters { } @Test - public void testParticipantParameterGroup_EmptyName() { + void testParticipantParameterGroup_EmptyName() { final ParticipantSimulatorParameters participantParameters = commonTestData .toObject(commonTestData.getParticipantParameterGroupMap(""), ParticipantSimulatorParameters.class); @@ -74,7 +74,7 @@ public class TestParticipantSimulatorParameters { } @Test - public void testParticipantParameterGroup_SetName() { + void testParticipantParameterGroup_SetName() { final ParticipantSimulatorParameters participantParameters = commonTestData.toObject( commonTestData.getParticipantParameterGroupMap(CommonTestData.PARTICIPANT_GROUP_NAME), ParticipantSimulatorParameters.class); @@ -84,7 +84,7 @@ public class TestParticipantSimulatorParameters { } @Test - public void testParticipantParameterGroup_EmptyParticipantIntermediaryParameters() { + void testParticipantParameterGroup_EmptyParticipantIntermediaryParameters() { final Map<String, Object> map = commonTestData.getParticipantParameterGroupMap(CommonTestData.PARTICIPANT_GROUP_NAME); map.replace("intermediaryParameters", commonTestData.getIntermediaryParametersMap(true)); @@ -95,7 +95,7 @@ public class TestParticipantSimulatorParameters { } @Test - public void testParticipantParameterGroupp_EmptyTopicParameters() { + void testParticipantParameterGroupp_EmptyTopicParameters() { final Map<String, Object> map = commonTestData.getParticipantParameterGroupMap(CommonTestData.PARTICIPANT_GROUP_NAME); final Map<String, Object> intermediaryParametersMap = commonTestData.getIntermediaryParametersMap(false); diff --git a/participant/participant-impl/participant-impl-simulator/src/test/java/org/onap/policy/clamp/controlloop/participant/simulator/main/rest/CommonParticipantRestServer.java b/participant/participant-impl/participant-impl-simulator/src/test/java/org/onap/policy/clamp/controlloop/participant/simulator/main/rest/CommonParticipantRestServer.java deleted file mode 100644 index ae004de49..000000000 --- a/participant/participant-impl/participant-impl-simulator/src/test/java/org/onap/policy/clamp/controlloop/participant/simulator/main/rest/CommonParticipantRestServer.java +++ /dev/null @@ -1,227 +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.participant.simulator.main.rest; - -import static org.assertj.core.api.Assertions.assertThat; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import javax.ws.rs.client.Client; -import javax.ws.rs.client.ClientBuilder; -import javax.ws.rs.client.Invocation; -import javax.ws.rs.client.WebTarget; -import javax.ws.rs.core.MediaType; -import org.glassfish.jersey.client.ClientProperties; -import org.glassfish.jersey.client.authentication.HttpAuthenticationFeature; -import org.junit.AfterClass; -import org.junit.Before; -import org.junit.BeforeClass; -import org.onap.policy.clamp.controlloop.common.exception.ControlLoopException; -import org.onap.policy.clamp.controlloop.participant.simulator.main.parameters.CommonTestData; -import org.onap.policy.clamp.controlloop.participant.simulator.main.startstop.Main; -import org.onap.policy.common.endpoints.event.comm.TopicEndpointManager; -import org.onap.policy.common.endpoints.http.server.HttpServletServerFactoryInstance; -import org.onap.policy.common.gson.GsonMessageBodyHandler; -import org.onap.policy.common.utils.network.NetworkUtil; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Class to perform Rest unit tests. - * - */ - -public class CommonParticipantRestServer { - - private static final String CONFIG_FILE = "src/test/resources/parameters/TestConfigParameters.json"; - private static final Logger LOGGER = LoggerFactory.getLogger(CommonParticipantRestServer.class); - public static final String SELF = NetworkUtil.getHostname(); - public static final String ENDPOINT_PREFIX = "onap/participantsim/v2/"; - private static int port; - private static String httpPrefix; - private static Main main; - - /** - * Allocates a port for the server, writes a config file, and then starts Main. - * - * @throws Exception if an error occurs - */ - @BeforeClass - public static void setUpBeforeClass() throws Exception { - setUpBeforeClass(true); - } - - /** - * Allocates a port for the server, writes a config file, and then starts Main, if - * specified. - * - * @param shouldStart {@code true} if Main should be started, {@code false} otherwise - * @throws Exception if an error occurs - */ - public static void setUpBeforeClass(boolean shouldStart) throws Exception { - port = NetworkUtil.allocPort(); - httpPrefix = "http://localhost:" + port + "/"; - - makeConfigFile(); - HttpServletServerFactoryInstance.getServerFactory().destroy(); - TopicEndpointManager.getManager().shutdown(); - - if (shouldStart) { - startMain(); - } - } - - /** - * Stops Main. - */ - @AfterClass - public static void teardownAfterClass() { - try { - stopMain(); - - } catch (ControlLoopException exp) { - LOGGER.error("cannot stop main", exp); - } - } - - /** - * Set up. - * - * @throws Exception if an error occurs - */ - @Before - public void setUp() throws Exception { - // restart, if not currently running - if (main == null) { - startMain(); - } - } - - /** - * Verifies that an endpoint appears within the swagger response. - * - * @param endpoint the endpoint of interest - * @throws Exception if an error occurs - */ - protected void testSwagger(final String endpoint) throws Exception { - final Invocation.Builder invocationBuilder = sendFqeRequest(httpPrefix + "swagger.yaml", true); - assertThat(invocationBuilder.get(String.class)).contains(ENDPOINT_PREFIX + endpoint + ":"); - } - - /** - * Makes a parameter configuration file. - * - * @throws IOException if an error occurs writing the configuration file - * @throws FileNotFoundException if an error occurs writing the configuration file - * - * @throws Exception if an error occurs - */ - private static void makeConfigFile() throws FileNotFoundException, IOException { - String json = CommonTestData.getParticipantParameterGroupAsString(port); - File file = new File(String.format(CONFIG_FILE, port)); - file.deleteOnExit(); - try (FileOutputStream output = new FileOutputStream(file)) { - output.write(json.getBytes(StandardCharsets.UTF_8)); - } - } - - /** - * Starts the "Main". - * - * @throws InterruptedException - * - * @throws Exception if an error occurs - */ - protected static void startMain() throws InterruptedException { - // make sure port is available - if (NetworkUtil.isTcpPortOpen("localhost", port, 1, 1L)) { - throw new IllegalStateException("port " + port + " is still in use"); - } - - final String[] configParameters = { "-c", CONFIG_FILE }; - - main = new Main(configParameters); - - if (!NetworkUtil.isTcpPortOpen("localhost", port, 40, 250L)) { - throw new IllegalStateException("server is not listening on port " + port); - } - } - - /** - * Stops the "Main". - * - * @throws ControlLoopException - * - * @throws Exception if an error occurs - */ - private static void stopMain() throws ControlLoopException { - if (main != null) { - main.shutdown(); - main = null; - } - } - - /** - * Sends a request to an endpoint. - * - * @param endpoint the target endpoint - * @return a request builder - * @throws Exception if an error occurs - */ - protected Invocation.Builder sendRequest(final String endpoint) throws Exception { - return sendFqeRequest(httpPrefix + ENDPOINT_PREFIX + endpoint, true); - } - - /** - * Sends a request to an endpoint, without any authorization header. - * - * @param endpoint the target endpoint - * @return a request builder - * @throws Exception if an error occurs - */ - protected Invocation.Builder sendNoAuthRequest(final String endpoint) throws Exception { - return sendFqeRequest(httpPrefix + ENDPOINT_PREFIX + endpoint, false); - } - - /** - * Sends a request to a fully qualified endpoint. - * - * @param fullyQualifiedEndpoint the fully qualified target endpoint - * @param includeAuth if authorization header should be included - * @return a request builder - * @throws Exception if an error occurs - */ - protected Invocation.Builder sendFqeRequest(final String fullyQualifiedEndpoint, boolean includeAuth) - throws Exception { - final Client client = ClientBuilder.newBuilder().build(); - client.property(ClientProperties.METAINF_SERVICES_LOOKUP_DISABLE, "true"); - client.register(GsonMessageBodyHandler.class); - if (includeAuth) { - client.register(HttpAuthenticationFeature.basic("healthcheck", "zb!XztG34")); - } - final WebTarget webTarget = client.target(fullyQualifiedEndpoint); - return webTarget.request(MediaType.APPLICATION_JSON); - } -} diff --git a/participant/participant-impl/participant-impl-simulator/src/test/java/org/onap/policy/clamp/controlloop/participant/simulator/main/rest/RestControllerTest.java b/participant/participant-impl/participant-impl-simulator/src/test/java/org/onap/policy/clamp/controlloop/participant/simulator/main/rest/RestControllerTest.java deleted file mode 100644 index 1311eee35..000000000 --- a/participant/participant-impl/participant-impl-simulator/src/test/java/org/onap/policy/clamp/controlloop/participant/simulator/main/rest/RestControllerTest.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. - * ============LICENSE_END========================================================= - */ - -package org.onap.policy.clamp.controlloop.participant.simulator.main.rest; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; - -import java.util.UUID; -import javax.ws.rs.Produces; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; -import javax.ws.rs.core.Response.ResponseBuilder; -import org.junit.AfterClass; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Test; -import org.mockito.Mockito; -import org.onap.policy.clamp.controlloop.participant.simulator.simulation.SimulationHandler; -import org.onap.policy.common.utils.services.Registry; - -public class RestControllerTest { - - private RestController ctlr; - private ResponseBuilder bldr; - - /** - * Setup before class, instantiate SimulationHandler. - * - */ - @BeforeClass - public static void setUpBeforeClass() throws Exception { - Registry.newRegistry(); - Registry.register(SimulationHandler.class.getName(), Mockito.mock(SimulationHandler.class)); - } - - @AfterClass - public static void teardownAfterClass() throws Exception { - Registry.unregister(SimulationHandler.class.getName()); - } - - /** - * set Up. - */ - @Before - public void setUp() { - ctlr = new RestController(); - bldr = Response.status(Response.Status.OK); - } - - @Test - public void testProduces() { - Produces annotation = RestController.class.getAnnotation(Produces.class); - assertNotNull(annotation); - assertThat(annotation.value()).contains(MediaType.APPLICATION_JSON) - .contains(RestController.APPLICATION_YAML); - } - - @Test - public void testAddVersionControlHeaders() { - Response resp = ctlr.addVersionControlHeaders(bldr).build(); - assertEquals("0", resp.getHeaderString(RestController.VERSION_MINOR_NAME)); - assertEquals("0", resp.getHeaderString(RestController.VERSION_PATCH_NAME)); - assertEquals("1.0.0", resp.getHeaderString(RestController.VERSION_LATEST_NAME)); - } - - @Test - public void testAddLoggingHeaders_Null() { - Response resp = ctlr.addLoggingHeaders(bldr, null).build(); - assertNotNull(resp.getHeaderString(RestController.REQUEST_ID_NAME)); - } - - @Test - public void testAddLoggingHeaders_NonNull() { - UUID uuid = UUID.randomUUID(); - Response resp = ctlr.addLoggingHeaders(bldr, uuid).build(); - assertEquals(uuid.toString(), resp.getHeaderString(RestController.REQUEST_ID_NAME)); - } -} diff --git a/participant/participant-impl/participant-impl-simulator/src/test/java/org/onap/policy/clamp/controlloop/participant/simulator/main/rest/TestListenerUtils.java b/participant/participant-impl/participant-impl-simulator/src/test/java/org/onap/policy/clamp/controlloop/participant/simulator/main/rest/TestListenerUtils.java index 9c20ffe22..8aa40cbd5 100644 --- a/participant/participant-impl/participant-impl-simulator/src/test/java/org/onap/policy/clamp/controlloop/participant/simulator/main/rest/TestListenerUtils.java +++ b/participant/participant-impl/participant-impl-simulator/src/test/java/org/onap/policy/clamp/controlloop/participant/simulator/main/rest/TestListenerUtils.java @@ -25,13 +25,10 @@ import static org.junit.Assert.assertTrue; import java.io.File; import java.io.FileNotFoundException; import java.time.Instant; -import java.util.ArrayList; import java.util.LinkedHashMap; -import java.util.List; import java.util.Map; import java.util.Set; import java.util.UUID; -import lombok.Getter; 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.ControlLoopOrderedState; @@ -40,10 +37,7 @@ import org.onap.policy.clamp.controlloop.models.controlloop.concepts.Participant 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.ParticipantStateChange; -import org.onap.policy.clamp.controlloop.participant.intermediary.handler.ParticipantHandler; import org.onap.policy.clamp.controlloop.participant.simulator.main.parameters.CommonTestData; -import org.onap.policy.clamp.controlloop.participant.simulator.main.parameters.ParticipantSimulatorParameters; -import org.onap.policy.clamp.controlloop.participant.simulator.simulation.SimulationProvider; import org.onap.policy.common.utils.coder.Coder; import org.onap.policy.common.utils.coder.CoderException; import org.onap.policy.common.utils.coder.StandardCoder; @@ -64,24 +58,6 @@ public class TestListenerUtils { private TestListenerUtils() {} - @Getter - private static ParticipantHandler participantHandler; - - /** - * Method to initialize participantHandler. - */ - public static void initParticipantHandler() { - - final ParticipantSimulatorParameters participantParameters = commonTestData.toObject( - commonTestData.getParticipantParameterGroupMap(CommonTestData.PARTICIPANT_GROUP_NAME), - ParticipantSimulatorParameters.class); - - SimulationProvider simulationProvider = - new SimulationProvider(participantParameters.getIntermediaryParameters()); - - participantHandler = simulationProvider.getIntermediaryApi().getParticipantHandler(); - } - /** * Method to create a controlLoop from a yaml file. * diff --git a/participant/participant-impl/participant-impl-simulator/src/test/java/org/onap/policy/clamp/controlloop/participant/simulator/main/rest/TestSimulationRestController.java b/participant/participant-impl/participant-impl-simulator/src/test/java/org/onap/policy/clamp/controlloop/participant/simulator/main/rest/TestSimulationRestController.java deleted file mode 100644 index 472b4beee..000000000 --- a/participant/participant-impl/participant-impl-simulator/src/test/java/org/onap/policy/clamp/controlloop/participant/simulator/main/rest/TestSimulationRestController.java +++ /dev/null @@ -1,186 +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.participant.simulator.main.rest; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; - -import java.util.Collection; -import java.util.List; -import java.util.Map; -import java.util.UUID; -import javax.ws.rs.client.Entity; -import javax.ws.rs.client.Invocation; -import javax.ws.rs.core.GenericType; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; -import org.junit.AfterClass; -import org.junit.BeforeClass; -import org.junit.Test; -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.ControlLoopOrderedState; -import org.onap.policy.clamp.controlloop.models.controlloop.concepts.Participant; -import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ParticipantState; -import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantControlLoopUpdate; -import org.onap.policy.clamp.controlloop.models.messages.rest.TypedSimpleResponse; -import org.onap.policy.clamp.controlloop.participant.intermediary.comm.ControlLoopUpdateListener; -import org.onap.policy.clamp.controlloop.participant.simulator.main.parameters.CommonTestData; -import org.onap.policy.clamp.controlloop.participant.simulator.simulation.SimulationHandler; -import org.onap.policy.clamp.controlloop.participant.simulator.simulation.SimulationProvider; -import org.onap.policy.common.endpoints.event.comm.Topic.CommInfrastructure; -import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier; -import org.onap.policy.models.tosca.authorative.concepts.ToscaNodeTemplate; - -/** - * Class to perform unit test of {@link TestSimulationRestController}. - */ -public class TestSimulationRestController extends CommonParticipantRestServer { - - private static ControlLoopUpdateListener clUpdateListener; - private static final String PARTICIPANTS_ENDPOINT = "participants"; - private static final String ELEMENTS_ENDPOINT = "elements"; - private static final CommInfrastructure INFRA = CommInfrastructure.NOOP; - private static final String TOPIC = "my-topic"; - static CommonTestData commonTestData = new CommonTestData(); - - /** - * Setup before class. - * - */ - @BeforeClass - public static void setUpBeforeClass() throws Exception { - CommonParticipantRestServer.setUpBeforeClass(); - clUpdateListener = new ControlLoopUpdateListener( - SimulationHandler.getInstance() - .getSimulationProvider() - .getIntermediaryApi() - .getParticipantHandler()); - ParticipantControlLoopUpdate participantControlLoopUpdateMsg = - TestListenerUtils.createControlLoopUpdateMsg(); - participantControlLoopUpdateMsg.getControlLoop().setOrderedState(ControlLoopOrderedState.PASSIVE); - clUpdateListener.onTopicEvent(INFRA, TOPIC, null, participantControlLoopUpdateMsg); - } - - @AfterClass - public static void teardownAfterClass() { - CommonParticipantRestServer.teardownAfterClass(); - } - - @Test - public void testSwagger() throws Exception { - super.testSwagger(ELEMENTS_ENDPOINT); - } - - @Test - public void testQuery_Unauthorized() throws Exception { - Invocation.Builder invocationBuilder = super.sendNoAuthRequest(ELEMENTS_ENDPOINT); - Response rawresp = invocationBuilder.buildGet().invoke(); - assertEquals(Response.Status.UNAUTHORIZED.getStatusCode(), rawresp.getStatus()); - } - - @Test - public void testQueryParticipants() throws Exception { - Participant participant = new Participant(); - ToscaConceptIdentifier participantId = CommonTestData.getParticipantId(); - participant.setDefinition(participantId); - participant.setName(participantId.getName()); - participant.setVersion(participantId.getVersion()); - - // GET REST call for querying the participants - Invocation.Builder invocationBuilder = - super.sendRequest(PARTICIPANTS_ENDPOINT + "/" + participant.getKey().getName() - + "/" + participant.getVersion()); - - Response rawresp = invocationBuilder.buildGet().invoke(); - assertEquals(Response.Status.OK.getStatusCode(), rawresp.getStatus()); - List<Participant> returnValue = rawresp.readEntity(new GenericType<List<Participant>>() {}); - assertNotNull(returnValue); - assertThat(returnValue).hasSize(1); - // Verify the result of GET participants with what is stored - assertEquals(participant.getDefinition(), returnValue.get(0).getDefinition()); - } - - @Test - public void testQueryControlLoopElements() throws Exception { - // GET REST call for querying the controlLoop elements - Invocation.Builder invocationBuilder = super.sendRequest(ELEMENTS_ENDPOINT + "/" - + "PMSHInstance0" + "/" + "1.0.0"); - - Response rawresp = invocationBuilder.buildGet().invoke(); - assertEquals(Response.Status.OK.getStatusCode(), rawresp.getStatus()); - Map<UUID, ControlLoopElement> returnValue = - rawresp.readEntity(new GenericType<Map<UUID, ControlLoopElement>>() {}); - assertNotNull(returnValue); - // Verify the result of GET controlloop elements with what is stored - assertThat(returnValue).hasSize(1); - returnValue.values().forEach(element -> assertEquals("org.onap.PM_CDS_Blueprint", - element.getDefinition().getName())); - } - - @Test - public void testUpdateParticipant() throws Exception { - SimulationProvider provider = SimulationHandler.getInstance().getSimulationProvider(); - List<Participant> participants = provider.getParticipants(CommonTestData.getParticipantId().getName(), - CommonTestData.getParticipantId().getVersion()); - assertEquals(ParticipantState.UNKNOWN, participants.get(0).getParticipantState()); - // Change the state of the participant to PASSIVE from UNKNOWN - participants.get(0).setParticipantState(ParticipantState.PASSIVE); - Entity<Participant> entParticipant = Entity.entity(participants.get(0), MediaType.APPLICATION_JSON); - - // PUT REST call for updating Participant - Invocation.Builder invocationBuilder = sendRequest(PARTICIPANTS_ENDPOINT); - Response rawresp = invocationBuilder.put(entParticipant); - TypedSimpleResponse<Participant> resp = rawresp.readEntity(TypedSimpleResponse.class); - assertEquals(Response.Status.OK.getStatusCode(), rawresp.getStatus()); - assertNotNull(resp.getResponse()); - // Verify the response and state returned by PUT REST call for updating participants - assertThat(resp.toString()).contains("definition={name=org.onap.PM_CDS_Blueprint, version=1.0.0}"); - assertThat(resp.toString()).contains("participantState=PASSIVE"); - } - - @Test - public void testUpdateControlLoopElement() throws Exception { - ControlLoop controlLoop = TestListenerUtils.createControlLoop(); - SimulationProvider provider = SimulationHandler.getInstance().getSimulationProvider(); - Map<UUID, ControlLoopElement> controlLoopElements = provider.getControlLoopElements( - controlLoop.getDefinition().getName(), controlLoop.getDefinition().getVersion()); - - for (Map.Entry<UUID, ControlLoopElement> clElement : controlLoopElements.entrySet()) { - // Check the initial state on the ControlLoopElement, which is UNINITIALISED - assertEquals(ControlLoopOrderedState.UNINITIALISED, clElement.getValue().getOrderedState()); - // Change the state of the ControlLoopElement to PASSIVE from UNINITIALISED - clElement.getValue().setOrderedState(ControlLoopOrderedState.PASSIVE); - Entity<ControlLoopElement> entClElement = Entity.entity(clElement.getValue(), MediaType.APPLICATION_JSON); - - // PUT REST call for updating ControlLoopElement - Invocation.Builder invocationBuilder = sendRequest(ELEMENTS_ENDPOINT); - Response rawresp = invocationBuilder.put(entClElement); - TypedSimpleResponse<ControlLoopElement> resp = rawresp.readEntity(TypedSimpleResponse.class); - assertEquals(Response.Status.OK.getStatusCode(), rawresp.getStatus()); - assertNotNull(resp.getResponse()); - // Verify the response and state returned by PUT REST call for updating participants - assertThat(resp.toString()).contains("definition={name=org.onap.PM_CDS_Blueprint, version=1.0.0}"); - assertThat(resp.toString()).contains("orderedState=PASSIVE"); - } - } -} diff --git a/participant/participant-impl/participant-impl-simulator/src/test/java/org/onap/policy/clamp/controlloop/participant/simulator/main/startstop/TestMain.java b/participant/participant-impl/participant-impl-simulator/src/test/java/org/onap/policy/clamp/controlloop/participant/simulator/main/startstop/TestMain.java deleted file mode 100644 index 5a5ad8931..000000000 --- a/participant/participant-impl/participant-impl-simulator/src/test/java/org/onap/policy/clamp/controlloop/participant/simulator/main/startstop/TestMain.java +++ /dev/null @@ -1,117 +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.participant.simulator.main.startstop; - -import static org.assertj.core.api.Assertions.assertThatCode; -import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -import org.junit.Test; -import org.onap.policy.clamp.controlloop.common.exception.ControlLoopRuntimeException; -import org.onap.policy.common.utils.resources.MessageConstants; - -/** - * Class to perform unit test of {@link Main}}. - */ -public class TestMain { - - @Test - public void testMain_Help() { - final String[] configParameters = {"-h"}; - Main main = new Main(configParameters); - assertFalse(main.isRunning()); - } - - @Test - public void testMain_Version() { - final String[] configParameters = {"-v"}; - Main main = new Main(configParameters); - assertFalse(main.isRunning()); - } - - @Test - public void testMain_Valid() { - final String[] configParameters = {"-c", "src/test/resources/parameters/TestParameters.json"}; - Main main = new Main(configParameters); - assertTrue(main.isRunning()); - - assertThatCode(() -> main.shutdown()).doesNotThrowAnyException(); - - assertFalse(main.isRunning()); - } - - @Test - public void testMain_NoParameter() { - assertThatConfigParameterThrownException(new String[] {}); - } - - @Test - public void testMain_FilePathNotDefined() { - assertThatConfigParameterThrownException(new String[] {"-c"}); - } - - @Test - public void testMain_TooManyCommand() { - assertThatConfigParameterThrownException(new String[] {"-h", "d"}); - } - - @Test - public void testMain_WrongParameter() { - assertThatConfigParameterThrownException(new String[] {"-d"}); - } - - private void assertThatConfigParameterThrownException(final String[] configParameters) { - assertThatThrownBy(() -> Main.main(configParameters)).isInstanceOf(ControlLoopRuntimeException.class) - .hasMessage(String.format(MessageConstants.START_FAILURE_MSG, MessageConstants.POLICY_CLAMP)); - } - - @Test - public void testParticipant_NoFileWithThisName() { - assertThatConfigFileThrownException("src/test/resources/parameters/NoFileWithThisName.json"); - } - - @Test - public void testParticipant_NotValidFile() { - assertThatConfigFileThrownException("src/test/resources/parameters"); - } - - @Test - public void testParticipant_FileEmpty() { - assertThatConfigFileThrownException("src/test/resources/parameters/EmptyParameters.json"); - } - - @Test - public void testParticipant_NoParameters() { - assertThatConfigFileThrownException("src/test/resources/parameters/NoParameters.json"); - } - - @Test - public void testParticipant_InvalidParameters() { - assertThatConfigFileThrownException("src/test/resources/parameters/InvalidParameters.json"); - } - - private void assertThatConfigFileThrownException(final String configFilePath) { - final String[] configParameters = new String[] {"-c", configFilePath}; - assertThatThrownBy(() -> new Main(configParameters)).isInstanceOf(ControlLoopRuntimeException.class) - .hasMessage(String.format(MessageConstants.START_FAILURE_MSG, MessageConstants.POLICY_CLAMP)); - } -} diff --git a/participant/participant-impl/participant-impl-simulator/src/test/java/org/onap/policy/clamp/controlloop/participant/simulator/main/startstop/TestParticipantSimulatorActivator.java b/participant/participant-impl/participant-impl-simulator/src/test/java/org/onap/policy/clamp/controlloop/participant/simulator/main/startstop/TestParticipantSimulatorActivator.java deleted file mode 100644 index c695d5f24..000000000 --- a/participant/participant-impl/participant-impl-simulator/src/test/java/org/onap/policy/clamp/controlloop/participant/simulator/main/startstop/TestParticipantSimulatorActivator.java +++ /dev/null @@ -1,89 +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.participant.simulator.main.startstop; - -import static org.assertj.core.api.Assertions.assertThatIllegalStateException; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -import org.junit.AfterClass; -import org.junit.BeforeClass; -import org.junit.Test; -import org.onap.policy.clamp.controlloop.participant.simulator.main.parameters.CommonTestData; -import org.onap.policy.clamp.controlloop.participant.simulator.main.parameters.ParticipantSimulatorParameterHandler; -import org.onap.policy.clamp.controlloop.participant.simulator.main.parameters.ParticipantSimulatorParameters; - -/** - * Class to perform unit test of {@link ParticipantActivator}}. - */ -public class TestParticipantSimulatorActivator { - - private static ParticipantSimulatorActivator activator; - - /** - * Initializes an activator. - * - * @throws Exception if an error occurs - */ - @BeforeClass - public static void setUp() throws Exception { - final String[] participantConfigParameters = { "-c", "src/test/resources/parameters/TestParameters.json"}; - final ParticipantSimulatorCommandLineArguments arguments = - new ParticipantSimulatorCommandLineArguments(participantConfigParameters); - final ParticipantSimulatorParameters parGroup = - new ParticipantSimulatorParameterHandler().getParameters(arguments); - activator = new ParticipantSimulatorActivator(parGroup); - } - - /** - * Method for cleanup after each test. - * - * @throws Exception if an error occurs - */ - @AfterClass - public static void teardown() throws Exception { - // shut down activator - if (activator != null && activator.isAlive()) { - activator.shutdown(); - } - } - - @Test - public void testParticipantActivator() { - activator.start(); - assertTrue(activator.isAlive()); - assertTrue(activator.getParameters().isValid()); - assertEquals(CommonTestData.PARTICIPANT_GROUP_NAME, activator.getParameters().getName()); - - // repeat - should throw an exception - assertThatIllegalStateException().isThrownBy(() -> activator.start()); - assertTrue(activator.isAlive()); - assertTrue(activator.getParameters().isValid()); - - activator.shutdown(); - assertFalse(activator.isAlive()); - - // repeat - should throw an exception - assertThatIllegalStateException().isThrownBy(() -> activator.shutdown()); - assertFalse(activator.isAlive()); - } -} 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 new file mode 100644 index 000000000..c31bb9d6b --- /dev/null +++ b/participant/participant-impl/participant-impl-simulator/src/test/resources/application_test.properties @@ -0,0 +1,7 @@ +spring.security.user.name=healthcheck +spring.security.user.password=zb!XztG34 + +server.servlet.context-path=/onap/participantsim +server.error.path=/error + +participant.file=src/test/resources/parameters/TestParameters.json |