diff options
22 files changed, 2130 insertions, 81 deletions
diff --git a/main/src/test/resources/parameters/TestConfigParams.json b/main/src/test/resources/parameters/TestConfigParams.json new file mode 100644 index 00000000..0bb50d65 --- /dev/null +++ b/main/src/test/resources/parameters/TestConfigParams.json @@ -0,0 +1,64 @@ +{ + "name":"SDCDistributionGroup", + "restServerParameters":{ + "host":"0.0.0.0", + "port":54290, + "userName":"healthcheck", + "password":"zb!XztG34" + }, + "receptionHandlerParameters":{ + "DummyReceptionHandler":{ + "receptionHandlerType":"DummyReceptionHandler", + "receptionHandlerClassName":"org.onap.policy.distribution.main.testclasses.DummyReceptionHandler", + "receptionHandlerConfigurationName":"dummyReceptionHandlerConfiguration", + "pluginHandlerParameters":{ + "policyDecoders":{ + "DummyDecoder":{ + "decoderType":"DummyDecoder", + "decoderClassName":"org.onap.policy.distribution.main.testclasses.DummyDecoder", + "decoderConfigurationParameters": "dummyDecoderConfiguration" + } + }, + "policyForwarders":{ + "DummyForwarder":{ + "forwarderType":"DummyForwarder", + "forwarderClassName":"org.onap.policy.distribution.main.testclasses.DummyPolicyForwarder", + "forwarderConfigurationParameters": "dummyConfiguration" + } + } + } + } + }, + "receptionHandlerConfigurationParameters":{ + "dummyReceptionHandlerConfiguration":{ + "parameterClassName":"org.onap.policy.distribution.main.testclasses.DummyReceptionHandlerParameterGroup", + "parameters":{ + "myStringParameter": "stringValue", + "myIntegerParameter":20, + "myBooleanParameter": true + } + } + }, + "policyForwarderConfigurationParameters":{ + "dummyConfiguration":{ + "parameterClassName":"org.onap.policy.distribution.main.testclasses.DummyPolicyForwarderParameterGroup", + "parameters":{ + "useHttps": false, + "hostname": "192.168.99.100", + "port": 8081, + "userName": "user", + "password": "pw123", + "isManaged": true + } + } + }, + "policyDecoderConfigurationParameters":{ + "dummyDecoderConfiguration":{ + "parameterClassName":"org.onap.policy.distribution.main.testclasses.DummyPolicyDecoderParameterGroup", + "parameters":{ + "policyName": "SamplePolicy", + "policyType": "DUMMY" + } + } + } +} diff --git a/packages/policy-distribution-tarball/src/main/resources/etc/defaultConfig.json b/packages/policy-distribution-tarball/src/main/resources/etc/defaultConfig.json index bda3b11f..4c14f75b 100644 --- a/packages/policy-distribution-tarball/src/main/resources/etc/defaultConfig.json +++ b/packages/policy-distribution-tarball/src/main/resources/etc/defaultConfig.json @@ -19,13 +19,23 @@ "decoderType": "ToscaPolicyDecoder", "decoderClassName": "org.onap.policy.distribution.reception.decoding.policy.file.PolicyDecoderFileInCsarToPolicy", "decoderConfigurationName": "toscaPolicyDecoderConfiguration" + }, + "ToscaControlLoopDecoder": { + "decoderType": "ToscaControlLoopDecoder", + "decoderClassName": "org.onap.policy.distribution.reception.decoding.policy.file.ControlLoopDecoderFileInCsar", + "decoderConfigurationName": "toscaControlLoopDecoderConfiguration" } }, "policyForwarders": { - "LifeCycleApiForwarder": { - "forwarderType": "LifeCycleAPI", + "LifeCycleApiPolicyForwarder": { + "forwarderType": "LifeCyclePolicyAPI", "forwarderClassName": "org.onap.policy.distribution.forwarding.lifecycle.api.LifecycleApiPolicyForwarder", - "forwarderConfigurationName": "lifecycleApiConfiguration" + "forwarderConfigurationName": "lifecycleApiPolicyConfiguration" + }, + "LifeCycleApiControlLoopForwarder": { + "forwarderType": "LifeCycleControlLoopAPI", + "forwarderClassName": "org.onap.policy.distribution.forwarding.lifecycle.api.LifecycleApiControlLoopForwarder", + "forwarderConfigurationName": "lifecycleApiControlLoopConfiguration" } } } @@ -65,10 +75,16 @@ "policyFileName": "tosca_policy", "policyTypeFileName": "tosca_policy_type" } + }, + "toscaControlLoopDecoderConfiguration": { + "parameterClassName": "org.onap.policy.distribution.reception.decoding.policy.file.ControlLoopDecoderFileInCsarParameterGroup", + "parameters": { + "controlLoopType": "controlloop" + } } }, "policyForwarderConfigurationParameters": { - "lifecycleApiConfiguration": { + "lifecycleApiPolicyConfiguration": { "parameterClassName": "org.onap.policy.distribution.forwarding.lifecycle.api.LifecycleApiForwarderParameters", "parameters": { "apiParameters": { @@ -89,6 +105,19 @@ }, "deployPolicies": true } + }, + "lifecycleApiControlLoopConfiguration": { + "parameterClassName": "org.onap.policy.distribution.forwarding.lifecycle.api.LifecycleApiControlLoopForwarderParameters", + "parameters": { + "controlLoopRuntimeParameters": { + "clientName": "policy-clamp-cl-runtime", + "hostname": "policy-clamp-cl-runtime", + "port": 6969, + "useHttps": true, + "userName": "policyadmin", + "password": "zb!XztG34" + } + } } } } diff --git a/packages/policy-distribution-tarball/src/main/resources/etc/s3pConfig.json b/packages/policy-distribution-tarball/src/main/resources/etc/s3pConfig.json index 7059f5b4..cea48547 100644 --- a/packages/policy-distribution-tarball/src/main/resources/etc/s3pConfig.json +++ b/packages/policy-distribution-tarball/src/main/resources/etc/s3pConfig.json @@ -17,13 +17,23 @@ "decoderType": "ToscaPolicyDecoder", "decoderClassName": "org.onap.policy.distribution.reception.decoding.policy.file.PolicyDecoderFileInCsarToPolicy", "decoderConfigurationName": "toscaPolicyDecoderConfiguration" + }, + "ToscaControlLoopDecoder": { + "decoderType": "ToscaControlLoopDecoder", + "decoderClassName": "org.onap.policy.distribution.reception.decoding.policy.file.ControlLoopDecoderFileInCsar", + "decoderConfigurationName": "toscaControlLoopDecoderConfiguration" } }, "policyForwarders": { - "LifeCycleApiForwarder": { - "forwarderType": "LifeCycleAPI", + "LifeCycleApiPolicyForwarder": { + "forwarderType": "LifeCyclePolicyAPI", "forwarderClassName": "org.onap.policy.distribution.forwarding.lifecycle.api.LifecycleApiPolicyForwarder", - "forwarderConfigurationName": "lifecycleApiConfiguration" + "forwarderConfigurationName": "lifecycleApiPolicyConfiguration" + }, + "LifeCycleApiControlLoopForwarder": { + "forwarderType": "LifeCycleControlLoopAPI", + "forwarderClassName": "org.onap.policy.distribution.forwarding.lifecycle.api.LifecycleApiControlLoopForwarder", + "forwarderConfigurationName": "lifecycleApiControlLoopConfiguration" } } } @@ -44,10 +54,16 @@ "policyFileName": "tosca_policy", "policyTypeFileName": "tosca_policy_type" } + }, + "toscaControlLoopDecoderConfiguration": { + "parameterClassName": "org.onap.policy.distribution.reception.decoding.policy.file.ControlLoopDecoderFileInCsarParameterGroup", + "parameters": { + "controlLoopType": "controlloop" + } } }, "policyForwarderConfigurationParameters": { - "lifecycleApiConfiguration": { + "lifecycleApiPolicyConfiguration": { "parameterClassName": "org.onap.policy.distribution.forwarding.lifecycle.api.LifecycleApiForwarderParameters", "parameters": { "apiParameters": { @@ -68,6 +84,19 @@ }, "deployPolicies": true } + }, + "lifecycleApiControlLoopConfiguration": { + "parameterClassName": "org.onap.policy.distribution.forwarding.lifecycle.api.LifecycleApiControlLoopForwarderParameters", + "parameters": { + "controlLoopRuntimeParameters": { + "clientName": "policy-clamp-cl-runtime", + "hostname": "policy-clamp-cl-runtime", + "port": 6969, + "useHttps": true, + "userName": "policyadmin", + "password": "zb!XztG34" + } + } } } } diff --git a/plugins/forwarding-plugins/src/main/java/org/onap/policy/distribution/forwarding/lifecycle/api/LifecycleApiControlLoopForwarder.java b/plugins/forwarding-plugins/src/main/java/org/onap/policy/distribution/forwarding/lifecycle/api/LifecycleApiControlLoopForwarder.java new file mode 100644 index 00000000..605c68cd --- /dev/null +++ b/plugins/forwarding-plugins/src/main/java/org/onap/policy/distribution/forwarding/lifecycle/api/LifecycleApiControlLoopForwarder.java @@ -0,0 +1,121 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2022 Nordix Foundation. + * Modifications Copyright (C) 2022 Nordix Foundation. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.distribution.forwarding.lifecycle.api; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +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 org.onap.policy.common.endpoints.http.client.HttpClient; +import org.onap.policy.common.endpoints.http.client.HttpClientConfigException; +import org.onap.policy.common.endpoints.http.client.HttpClientFactoryInstance; +import org.onap.policy.common.parameters.ParameterService; +import org.onap.policy.distribution.forwarding.PolicyForwarder; +import org.onap.policy.distribution.forwarding.PolicyForwardingException; +import org.onap.policy.models.tosca.authorative.concepts.ToscaEntity; +import org.onap.policy.models.tosca.authorative.concepts.ToscaServiceTemplate; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * This class provides an implementation of {@link PolicyForwarder} interface for forwarding the + * controlloop design template to the life cycle api's of controlloop components. + * + * @author Sirisha Manchikanti (sirisha.manchikanti@est.tech) + */ +public class LifecycleApiControlLoopForwarder implements PolicyForwarder { + + private static final String COMMISSION_CONTROLLOOP_URI = "/onap/controlloop/v2/commission"; + private static final Logger LOGGER = LoggerFactory.getLogger(LifecycleApiControlLoopForwarder.class); + + private LifecycleApiControlLoopForwarderParameters forwarderParameters; + private HttpClient controlLoopClient; + + /** + * {@inheritDoc}. + */ + @Override + public void configure(final String parameterGroupName) throws HttpClientConfigException { + forwarderParameters = ParameterService.get(parameterGroupName); + + controlLoopClient = HttpClientFactoryInstance.getClientFactory().build( + forwarderParameters.getControlLoopRuntimeParameters()); + } + + /** + * {@inheritDoc}. + */ + @Override + public void forward(final Collection<ToscaEntity> entities) throws PolicyForwardingException { + final List<ToscaEntity> failedEntities = new ArrayList<>(); + for (final ToscaEntity entity : entities) { + forwardSingleEntity(failedEntities, entity); + } + if (!failedEntities.isEmpty()) { + throw new PolicyForwardingException( + "Failed forwarding the following entities: " + Arrays.toString(failedEntities.toArray())); + } + } + + private void forwardSingleEntity(final List<ToscaEntity> failedEntities, final ToscaEntity entity) { + try { + if (entity instanceof ToscaServiceTemplate) { + final var toscaServiceTemplate = (ToscaServiceTemplate) entity; + if (null != toscaServiceTemplate.getToscaTopologyTemplate() + && null != toscaServiceTemplate.getNodeTypes() + && null != toscaServiceTemplate.getDataTypes()) { + commissionControlLoop(toscaServiceTemplate); + } + } else { + throw new PolicyForwardingException("The entity is not of type ToscaServiceTemplate - " + entity); + } + } catch (final Exception exp) { + LOGGER.error(exp.getMessage(), exp); + failedEntities.add(entity); + } + } + + private Response commissionControlLoop(final ToscaServiceTemplate toscaServiceTemplate) + throws PolicyForwardingException { + return invokeHttpClient(Entity.entity(toscaServiceTemplate, MediaType.APPLICATION_JSON), + COMMISSION_CONTROLLOOP_URI); + } + + private Response invokeHttpClient(final Entity<?> entity, final String path) + throws PolicyForwardingException { + var response = controlLoopClient.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()); + throw new PolicyForwardingException("Failed creating the entity - " + entity); + } + return response; + } +} + diff --git a/plugins/forwarding-plugins/src/main/java/org/onap/policy/distribution/forwarding/lifecycle/api/LifecycleApiControlLoopForwarderParameters.java b/plugins/forwarding-plugins/src/main/java/org/onap/policy/distribution/forwarding/lifecycle/api/LifecycleApiControlLoopForwarderParameters.java new file mode 100644 index 00000000..d1abce71 --- /dev/null +++ b/plugins/forwarding-plugins/src/main/java/org/onap/policy/distribution/forwarding/lifecycle/api/LifecycleApiControlLoopForwarderParameters.java @@ -0,0 +1,47 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2022 Nordix Foundation. + * Modifications Copyright (C) 2022 Nordix Foundation. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.distribution.forwarding.lifecycle.api; + +import lombok.Getter; +import org.onap.policy.common.endpoints.parameters.RestClientParameters; +import org.onap.policy.common.parameters.annotations.NotBlank; +import org.onap.policy.common.parameters.annotations.NotNull; +import org.onap.policy.common.parameters.annotations.Valid; +import org.onap.policy.distribution.main.parameters.PolicyForwarderConfigurationParameterGroup; + +/** + * Holds the parameters for the {@link LifecycleApiControlLoopForwarder}. + * + * @author Sirisha Manchikanti (sirisha.manchikanti@est.tech) + */ +@Getter +@NotNull +@NotBlank +public class LifecycleApiControlLoopForwarderParameters extends PolicyForwarderConfigurationParameterGroup { + public static final String CONTROLLOOP_FORWARDER_PLUGIN_CLASS = LifecycleApiControlLoopForwarder.class.getName(); + + private @Valid RestClientParameters controlLoopRuntimeParameters; + + public LifecycleApiControlLoopForwarderParameters() { + super(LifecycleApiControlLoopForwarderParameters.class.getSimpleName()); + } +} diff --git a/plugins/forwarding-plugins/src/test/java/org/onap/policy/distribution/forwarding/lifecycle/api/LifecycleApiControlLoopForwarderParametersTest.java b/plugins/forwarding-plugins/src/test/java/org/onap/policy/distribution/forwarding/lifecycle/api/LifecycleApiControlLoopForwarderParametersTest.java new file mode 100644 index 00000000..ba8d9bfb --- /dev/null +++ b/plugins/forwarding-plugins/src/test/java/org/onap/policy/distribution/forwarding/lifecycle/api/LifecycleApiControlLoopForwarderParametersTest.java @@ -0,0 +1,88 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2022 Nordix Foundation. + * Modifications Copyright (C) 2022 Nordix Foundation. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.distribution.forwarding.lifecycle.api; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; +import org.onap.policy.common.parameters.ValidationStatus; +import org.onap.policy.distribution.forwarding.testclasses.CommonTestData; + +/** + * Class to perform unit test of {@link LifecycleApiControlLoopForwarderParameters}. + * + * @author Sirisha Manchikanti (sirisha.manchikanti@est.tech) + */ +public class LifecycleApiControlLoopForwarderParametersTest { + + private static final String CONTROLLOOP_RUNTIME_HOST_NAME = "0.0.0.0"; + private static final int CONTROLLOOP_RUNTIME_PORT = 6969; + private static final String CONTROLLOOP_RUNTIME_USER = "policyadmin"; + private static final String CONTROLLOOP_RUNTIME_PASSWORD = "zb!XztG34"; + + + @Test + public void testValidParameters() { + final LifecycleApiControlLoopForwarderParameters configurationParameters = + CommonTestData.getPolicyForwarderParameters( + "src/test/resources/parameters/LifecycleApiControlLoopForwarderParameters.json", + LifecycleApiControlLoopForwarderParameters.class); + + assertEquals(LifecycleApiControlLoopForwarderParameters.class.getSimpleName(), + configurationParameters.getName()); + + assertEquals(CONTROLLOOP_RUNTIME_HOST_NAME, + configurationParameters.getControlLoopRuntimeParameters().getHostname()); + assertEquals(CONTROLLOOP_RUNTIME_PORT, + configurationParameters.getControlLoopRuntimeParameters().getPort()); + assertFalse(configurationParameters.getControlLoopRuntimeParameters().isUseHttps()); + assertEquals(CONTROLLOOP_RUNTIME_USER, + configurationParameters.getControlLoopRuntimeParameters().getUserName()); + assertEquals(CONTROLLOOP_RUNTIME_PASSWORD, + configurationParameters.getControlLoopRuntimeParameters().getPassword()); + + assertThat(configurationParameters.validate().getResult()).isNull(); + assertEquals(ValidationStatus.CLEAN, configurationParameters.validate().getStatus()); + } + + @Test + public void testInvalidParameters() { + final LifecycleApiForwarderParameters configurationParameters = + CommonTestData.getPolicyForwarderParameters( + "src/test/resources/parameters/LifecycleApiPolicyForwarderParametersInvalid.json", + LifecycleApiForwarderParameters.class); + + assertEquals(ValidationStatus.INVALID, configurationParameters.validate().getStatus()); + } + + @Test + public void testEmptyParameters() { + final LifecycleApiForwarderParameters configurationParameters = + CommonTestData.getPolicyForwarderParameters("src/test/resources/parameters/EmptyParameters.json", + LifecycleApiForwarderParameters.class); + + assertEquals(ValidationStatus.INVALID, configurationParameters.validate().getStatus()); + } +} diff --git a/plugins/forwarding-plugins/src/test/java/org/onap/policy/distribution/forwarding/lifecycle/api/LifecycleApiControlLoopForwarderTest.java b/plugins/forwarding-plugins/src/test/java/org/onap/policy/distribution/forwarding/lifecycle/api/LifecycleApiControlLoopForwarderTest.java new file mode 100644 index 00000000..047482ef --- /dev/null +++ b/plugins/forwarding-plugins/src/test/java/org/onap/policy/distribution/forwarding/lifecycle/api/LifecycleApiControlLoopForwarderTest.java @@ -0,0 +1,115 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2022 Nordix Foundation. + * Modifications Copyright (C) 2022 Nordix Foundation. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.distribution.forwarding.lifecycle.api; + +import static org.assertj.core.api.Assertions.assertThatCode; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import java.util.ArrayList; +import java.util.Collection; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; +import org.onap.policy.common.parameters.ParameterGroup; +import org.onap.policy.common.parameters.ParameterService; +import org.onap.policy.common.utils.coder.CoderException; +import org.onap.policy.common.utils.coder.StandardCoder; +import org.onap.policy.common.utils.network.NetworkUtil; +import org.onap.policy.common.utils.resources.ResourceUtils; +import org.onap.policy.distribution.forwarding.PolicyForwardingException; +import org.onap.policy.distribution.forwarding.testclasses.CommonTestData; +import org.onap.policy.distribution.forwarding.testclasses.LifecycleApiControlLoopSimulatorMain; +import org.onap.policy.models.tosca.authorative.concepts.ToscaEntity; +import org.onap.policy.models.tosca.authorative.concepts.ToscaServiceTemplate; + +/** + * Class to perform unit test of {@link LifecycleApiControlLoopForwarder}. + * + * @author Sirisha Manchikanti (sirisha.manchikanti@est.tech) + */ +public class LifecycleApiControlLoopForwarderTest { + + private static final String CONTROL_LOOP = "src/test/resources/parameters/sample_control_loop.json"; + private final StandardCoder standardCoder = new StandardCoder(); + private static final LifecycleApiControlLoopSimulatorMain simulator = new LifecycleApiControlLoopSimulatorMain(); + + /** + * Set up. + * + * @throws CoderException if any error occurs + * @throws PolicyForwardingException if any error occurs + * @throws InterruptedException if any error occurs + */ + @BeforeClass + public static void setUp() throws PolicyForwardingException, CoderException, InterruptedException { + final ParameterGroup parameterGroup = CommonTestData.getPolicyForwarderParameters( + "src/test/resources/parameters/LifecycleApiControlLoopForwarderParameters.json", + LifecycleApiControlLoopForwarderParameters.class); + ParameterService.register(parameterGroup); + simulator.startLifecycycleApiSimulator(); + if (!NetworkUtil.isTcpPortOpen("0.0.0.0", 6969, 50, 200L)) { + throw new IllegalStateException("cannot connect to port 6969"); + } + } + + /** + * Tear down. + */ + @AfterClass + public static void tearDown() { + ParameterService.deregister(LifecycleApiControlLoopForwarderParameters.class.getSimpleName()); + simulator.stopLifecycycleApiSimulator(); + } + + @Test + public void testForwardControlLoopUsingSimulator() throws Exception { + assertThatCode(() -> { + final ToscaServiceTemplate toscaServiceTemplate = + standardCoder.decode(ResourceUtils.getResourceAsString(CONTROL_LOOP), ToscaServiceTemplate.class); + + final LifecycleApiControlLoopForwarder forwarder = new LifecycleApiControlLoopForwarder(); + forwarder.configure(LifecycleApiControlLoopForwarderParameters.class.getSimpleName()); + + final Collection<ToscaEntity> controlLoopList = new ArrayList<>(); + controlLoopList.add(toscaServiceTemplate); + + forwarder.forward(controlLoopList); + + }).doesNotThrowAnyException(); + } + + @Test + public void testForwardControlLoopFailureUsingSimulator() throws Exception { + + final ToscaEntity toscaEntity = new ToscaEntity(); + toscaEntity.setName("FailureCase"); + + final LifecycleApiControlLoopForwarder forwarder = new LifecycleApiControlLoopForwarder(); + forwarder.configure(LifecycleApiControlLoopForwarderParameters.class.getSimpleName()); + + final Collection<ToscaEntity> controlLoopList = new ArrayList<>(); + controlLoopList.add(toscaEntity); + + assertThatThrownBy(() -> forwarder.forward(controlLoopList)).isInstanceOf(PolicyForwardingException.class) + .hasMessageContaining("Failed forwarding the following entities:"); + } +} diff --git a/plugins/forwarding-plugins/src/test/java/org/onap/policy/distribution/forwarding/testclasses/LifecycleApiControlLoopSimulatorEndpoint.java b/plugins/forwarding-plugins/src/test/java/org/onap/policy/distribution/forwarding/testclasses/LifecycleApiControlLoopSimulatorEndpoint.java new file mode 100644 index 00000000..d361d166 --- /dev/null +++ b/plugins/forwarding-plugins/src/test/java/org/onap/policy/distribution/forwarding/testclasses/LifecycleApiControlLoopSimulatorEndpoint.java @@ -0,0 +1,54 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2022 Nordix Foundation. + * Modifications Copyright (C) 2022 Nordix Foundation. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.distribution.forwarding.testclasses; + +import javax.ws.rs.Consumes; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import org.onap.policy.models.tosca.authorative.concepts.ToscaServiceTemplate; + +/** + * Class to provide rest end points for LifecycleApiControlLoopSimulator. + * + * @author Sirisha Manchikanti (sirisha.manchikanti@est.tech) + */ +@Path("/onap") +@Produces(MediaType.APPLICATION_JSON) +public class LifecycleApiControlLoopSimulatorEndpoint { + + /** + * ControlLoop commissioning end-point. + * + * @param body the post body + * @return the response object + */ + @POST + @Path("/controlloop/v2/commission") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + public Response commissionControlLoop(final ToscaServiceTemplate body) { + return Response.status(Response.Status.OK).entity(body).build(); + } +} diff --git a/plugins/forwarding-plugins/src/test/java/org/onap/policy/distribution/forwarding/testclasses/LifecycleApiControlLoopSimulatorMain.java b/plugins/forwarding-plugins/src/test/java/org/onap/policy/distribution/forwarding/testclasses/LifecycleApiControlLoopSimulatorMain.java new file mode 100644 index 00000000..a60fda1d --- /dev/null +++ b/plugins/forwarding-plugins/src/test/java/org/onap/policy/distribution/forwarding/testclasses/LifecycleApiControlLoopSimulatorMain.java @@ -0,0 +1,67 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2022 Nordix Foundation. + * Modifications Copyright (C) 2022 Nordix Foundation. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.distribution.forwarding.testclasses; + +import org.onap.policy.common.endpoints.http.server.RestServer; +import org.onap.policy.common.endpoints.parameters.RestServerParameters; +import org.onap.policy.common.utils.coder.CoderException; +import org.onap.policy.common.utils.coder.StandardCoder; +import org.onap.policy.common.utils.resources.ResourceUtils; +import org.onap.policy.distribution.forwarding.PolicyForwardingException; +import org.onap.policy.distribution.forwarding.lifecycle.api.LifecycleApiControlLoopForwarder; +import org.onap.policy.distribution.main.rest.aaf.AafDistributionFilter; + +/** + * The class for starting/stopping simulator for testing {@link LifecycleApiControlLoopForwarder} . + * + * @author Sirisha Manchikanti (sirisha.manchikanti@est.tech) + */ +public class LifecycleApiControlLoopSimulatorMain { + private RestServer restServer; + + /** + * Starts the simulator. + * + * @throws PolicyForwardingException if error occurs + * @throws CoderException if error occurs + */ + public void startLifecycycleApiSimulator() throws PolicyForwardingException, CoderException { + final StandardCoder standardCoder = new StandardCoder(); + final RestServerParameters restServerParameters = standardCoder.decode( + ResourceUtils.getResourceAsString("src/test/resources/parameters/RestServerParameters.json"), + RestServerParameters.class); + restServer = new RestServer(restServerParameters, AafDistributionFilter.class, + LifecycleApiControlLoopSimulatorEndpoint.class); + if (!restServer.start()) { + throw new PolicyForwardingException("Failed to start rest simulator. Check log for more details..."); + } + } + + /** + * Shut down Execution. + */ + public void stopLifecycycleApiSimulator() { + if (restServer != null) { + restServer.stop(); + } + } +} diff --git a/plugins/forwarding-plugins/src/test/resources/parameters/LifecycleApiControlLoopForwarderParameters.json b/plugins/forwarding-plugins/src/test/resources/parameters/LifecycleApiControlLoopForwarderParameters.json new file mode 100644 index 00000000..1eef9773 --- /dev/null +++ b/plugins/forwarding-plugins/src/test/resources/parameters/LifecycleApiControlLoopForwarderParameters.json @@ -0,0 +1,10 @@ +{ + "controlLoopRuntimeParameters": { + "clientName": "policy-clamp-cl-runtime", + "hostname": "0.0.0.0", + "port": 6969, + "useHttps": false, + "userName": "policyadmin", + "password": "zb!XztG34" + } +} diff --git a/plugins/forwarding-plugins/src/test/resources/parameters/LifecycleApiControlLoopForwarderParametersInvalid.json b/plugins/forwarding-plugins/src/test/resources/parameters/LifecycleApiControlLoopForwarderParametersInvalid.json new file mode 100644 index 00000000..5ac0c4ee --- /dev/null +++ b/plugins/forwarding-plugins/src/test/resources/parameters/LifecycleApiControlLoopForwarderParametersInvalid.json @@ -0,0 +1,10 @@ +{ + "controlLoopRuntimeParameters": { + "clientName": "policy-clamp-cl-runtime", + "hostname": "", + "port": 6969, + "useHttps": false, + "userName": "policyadmin", + "password": "zb!XztG34" + } +} diff --git a/plugins/forwarding-plugins/src/test/resources/parameters/sample_control_loop.json b/plugins/forwarding-plugins/src/test/resources/parameters/sample_control_loop.json new file mode 100644 index 00000000..20dedc50 --- /dev/null +++ b/plugins/forwarding-plugins/src/test/resources/parameters/sample_control_loop.json @@ -0,0 +1,1022 @@ +{ + "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 + } + } + }, + "onap.datatype.controlloop.Target": { + "derived_from": "tosca.datatypes.Root", + "description": "Definition for a entity in A&AI to perform a control loop operation on", + "properties": { + "targetType": { + "type": "string", + "description": "Category for the target type", + "required": true, + "constraints": [ + { + "valid_values": [ + "VNF", + "VM", + "VFMODULE", + "PNF" + ] + } + ] + }, + "entityIds": { + "type": "map", + "description": "Map of values that identify the resource. If none are provided, it is assumed that the\nentity that generated the ONSET event will be the target.\n", + "required": false, + "metadata": { + "clamp_possible_values": "ClampExecution:CSAR_RESOURCES" + }, + "entry_schema": { + "type": "string" + } + } + } + }, + "onap.datatype.controlloop.Actor": { + "derived_from": "tosca.datatypes.Root", + "description": "An actor/operation/target definition", + "properties": { + "actor": { + "type": "string", + "description": "The actor performing the operation.", + "required": true, + "metadata": { + "clamp_possible_values": "Dictionary:DefaultActors,ClampExecution:CDS/actor" + } + }, + "operation": { + "type": "string", + "description": "The operation the actor is performing.", + "metadata": { + "clamp_possible_values": "Dictionary:DefaultOperations,ClampExecution:CDS/operation" + }, + "required": true + }, + "target": { + "type": "onap.datatype.controlloop.Target", + "description": "The resource the operation should be performed on.", + "required": true + }, + "payload": { + "type": "map", + "description": "Name/value pairs of payload information passed by Policy to the actor", + "required": false, + "metadata": { + "clamp_possible_values": "ClampExecution:CDS/payload" + }, + "entry_schema": { + "type": "string" + } + } + } + }, + "onap.datatype.controlloop.Operation": { + "derived_from": "tosca.datatypes.Root", + "description": "An operation supported by an actor", + "properties": { + "id": { + "type": "string", + "description": "Unique identifier for the operation", + "required": true + }, + "description": { + "type": "string", + "description": "A user-friendly description of the intent for the operation", + "required": false + }, + "operation": { + "type": "onap.datatype.controlloop.Actor", + "description": "The definition of the operation to be performed.", + "required": true + }, + "timeout": { + "type": "integer", + "description": "The amount of time for the actor to perform the operation.", + "required": true + }, + "retries": { + "type": "integer", + "description": "The number of retries the actor should attempt to perform the operation.", + "required": true, + "default": 0 + }, + "success": { + "type": "string", + "description": "Points to the operation to invoke on success. A value of \"final_success\" indicates and end to the operation.", + "required": false, + "default": "final_success" + }, + "failure": { + "type": "string", + "description": "Points to the operation to invoke on Actor operation failure.", + "required": false, + "default": "final_failure" + }, + "failure_timeout": { + "type": "string", + "description": "Points to the operation to invoke when the time out for the operation occurs.", + "required": false, + "default": "final_failure_timeout" + }, + "failure_retries": { + "type": "string", + "description": "Points to the operation to invoke when the current operation has exceeded its max retries.", + "required": false, + "default": "final_failure_retries" + }, + "failure_exception": { + "type": "string", + "description": "Points to the operation to invoke when the current operation causes an exception.", + "required": false, + "default": "final_failure_exception" + }, + "failure_guard": { + "type": "string", + "description": "Points to the operation to invoke when the current operation is blocked due to guard policy enforcement.", + "required": false, + "default": "final_failure_guard" + } + } + }, + "onap.datatypes.monitoring.managedObjectDNsBasic": { + "constraints": [], + "properties": { + "DN": { + "name": "DN", + "type": "string", + "typeVersion": "0.0.0", + "description": "Managed object distinguished name", + "required": true, + "constraints": [], + "metadata": {} + } + }, + "name": "onap.datatypes.monitoring.managedObjectDNsBasic", + "version": "0.0.0", + "derived_from": "tosca.datatypes.Root", + "metadata": {} + }, + "onap.datatypes.monitoring.managedObjectDNsBasics": { + "constraints": [], + "properties": { + "managedObjectDNsBasic": { + "name": "managedObjectDNsBasic", + "type": "map", + "typeVersion": "0.0.0", + "description": "Managed object distinguished name object", + "required": true, + "constraints": [], + "entry_schema": { + "type": "onap.datatypes.monitoring.managedObjectDNsBasic", + "typeVersion": "0.0.0", + "constraints": [] + }, + "metadata": {} + } + }, + "name": "onap.datatypes.monitoring.managedObjectDNsBasics", + "version": "0.0.0", + "derived_from": "tosca.datatypes.Root", + "metadata": {} + }, + "onap.datatypes.monitoring.measurementGroup": { + "constraints": [], + "properties": { + "measurementTypes": { + "name": "measurementTypes", + "type": "list", + "typeVersion": "0.0.0", + "description": "List of measurement types", + "required": true, + "constraints": [], + "entry_schema": { + "type": "onap.datatypes.monitoring.measurementTypes", + "typeVersion": "0.0.0", + "constraints": [] + }, + "metadata": {} + }, + "managedObjectDNsBasic": { + "name": "managedObjectDNsBasic", + "type": "list", + "typeVersion": "0.0.0", + "description": "List of managed object distinguished names", + "required": true, + "constraints": [], + "entry_schema": { + "type": "onap.datatypes.monitoring.managedObjectDNsBasics", + "typeVersion": "0.0.0", + "constraints": [] + }, + "metadata": {} + } + }, + "name": "onap.datatypes.monitoring.measurementGroup", + "version": "0.0.0", + "derived_from": "tosca.datatypes.Root", + "metadata": {} + }, + "onap.datatypes.monitoring.measurementGroups": { + "constraints": [], + "properties": { + "measurementGroup": { + "name": "measurementGroup", + "type": "map", + "typeVersion": "0.0.0", + "description": "Measurement Group", + "required": true, + "constraints": [], + "entry_schema": { + "type": "onap.datatypes.monitoring.measurementGroup", + "typeVersion": "0.0.0", + "constraints": [] + }, + "metadata": {} + } + }, + "name": "onap.datatypes.monitoring.measurementGroups", + "version": "0.0.0", + "derived_from": "tosca.datatypes.Root", + "metadata": {} + }, + "onap.datatypes.monitoring.measurementType": { + "constraints": [], + "properties": { + "measurementType": { + "name": "measurementType", + "type": "string", + "typeVersion": "0.0.0", + "description": "Measurement type", + "required": true, + "constraints": [], + "metadata": {} + } + }, + "name": "onap.datatypes.monitoring.measurementType", + "version": "0.0.0", + "derived_from": "tosca.datatypes.Root", + "metadata": {} + }, + "onap.datatypes.monitoring.measurementTypes": { + "constraints": [], + "properties": { + "measurementType": { + "name": "measurementType", + "type": "map", + "typeVersion": "0.0.0", + "description": "Measurement type object", + "required": true, + "constraints": [], + "entry_schema": { + "type": "onap.datatypes.monitoring.measurementType", + "typeVersion": "0.0.0", + "constraints": [] + }, + "metadata": {} + } + }, + "name": "onap.datatypes.monitoring.measurementTypes", + "version": "0.0.0", + "derived_from": "tosca.datatypes.Root", + "metadata": {} + }, + "onap.datatypes.monitoring.nfFilter": { + "constraints": [], + "properties": { + "modelNames": { + "name": "modelNames", + "type": "list", + "typeVersion": "0.0.0", + "description": "List of model names", + "required": true, + "constraints": [], + "entry_schema": { + "type": "string", + "typeVersion": "0.0.0", + "constraints": [] + }, + "metadata": {} + }, + "modelInvariantIDs": { + "name": "modelInvariantIDs", + "type": "list", + "typeVersion": "0.0.0", + "description": "List of model invariant IDs", + "required": true, + "constraints": [], + "entry_schema": { + "type": "string", + "typeVersion": "0.0.0", + "constraints": [] + }, + "metadata": {} + }, + "modelVersionIDs": { + "name": "modelVersionIDs", + "type": "list", + "typeVersion": "0.0.0", + "description": "List of model version IDs", + "required": true, + "constraints": [], + "entry_schema": { + "type": "string", + "typeVersion": "0.0.0", + "constraints": [] + }, + "metadata": {} + }, + "nfNames": { + "name": "nfNames", + "type": "list", + "typeVersion": "0.0.0", + "description": "List of network functions", + "required": true, + "constraints": [], + "entry_schema": { + "type": "string", + "typeVersion": "0.0.0", + "constraints": [] + }, + "metadata": {} + } + }, + "name": "onap.datatypes.monitoring.nfFilter", + "version": "0.0.0", + "derived_from": "tosca.datatypes.Root", + "metadata": {} + }, + "onap.datatypes.monitoring.subscription": { + "constraints": [], + "properties": { + "measurementGroups": { + "name": "measurementGroups", + "type": "list", + "typeVersion": "0.0.0", + "description": "Measurement Groups", + "required": true, + "constraints": [], + "entry_schema": { + "type": "onap.datatypes.monitoring.measurementGroups", + "typeVersion": "0.0.0", + "constraints": [] + }, + "metadata": {} + }, + "fileBasedGP": { + "name": "fileBasedGP", + "type": "integer", + "typeVersion": "0.0.0", + "description": "File based granularity period", + "required": true, + "constraints": [], + "metadata": {} + }, + "fileLocation": { + "name": "fileLocation", + "type": "string", + "typeVersion": "0.0.0", + "description": "ROP file location", + "required": true, + "constraints": [], + "metadata": {} + }, + "subscriptionName": { + "name": "subscriptionName", + "type": "string", + "typeVersion": "0.0.0", + "description": "Name of the subscription", + "required": true, + "constraints": [], + "metadata": {} + }, + "administrativeState": { + "name": "administrativeState", + "type": "string", + "typeVersion": "0.0.0", + "description": "State of the subscription", + "required": true, + "constraints": [ + { + "valid_values": [ + "LOCKED", + "UNLOCKED" + ] + } + ], + "metadata": {} + }, + "nfFilter": { + "name": "nfFilter", + "type": "map", + "typeVersion": "0.0.0", + "description": "Network function filter", + "required": true, + "constraints": [], + "entry_schema": { + "type": "onap.datatypes.monitoring.nfFilter", + "typeVersion": "0.0.0", + "constraints": [] + }, + "metadata": {} + } + }, + "name": "onap.datatypes.monitoring.subscription", + "version": "0.0.0", + "derived_from": "tosca.datatypes.Root", + "metadata": {} + }, + "org.onap.datatypes.policy.clamp.controlloop.httpControlLoopElement.RestRequest": { + "version": "1.0.0", + "derived_from": "tosca.datatypes.Root", + "properties": { + "restRequestId": { + "type": "onap.datatypes.ToscaConceptIdentifier", + "typeVersion": "1.0.0", + "required": true, + "description": "The name and version of a REST request to be sent to a REST endpoint" + }, + "httpMethod": { + "type": "string", + "required": true, + "constraints": [ + { + "valid_values": [ + "POST", + "PUT", + "GET", + "DELETE" + ] + } + ], + "description": "The REST method to use" + }, + "path": { + "type": "string", + "required": true, + "description": "The path of the REST request relative to the base URL" + }, + "body": { + "type": "string", + "required": false, + "description": "The body of the REST request for PUT and POST requests" + }, + "expectedResponse": { + "type": "integer", + "required": true, + "constraints": [], + "description": "THe expected HTTP status code for the REST request" + } + }, + "org.onap.datatypes.policy.clamp.controlloop.httpControlLoopElement.ConfigurationEntity": { + "version": "1.0.0", + "derived_from": "tosca.datatypes.Root", + "properties": { + "configurationEntityId": { + "type": "onap.datatypes.ToscaConceptIdentifier", + "typeVersion": "1.0.0", + "required": true, + "description": "The name and version of a Configuration Entity to be handled by the HTTP Control Loop Element" + }, + "restSequence": { + "type": "list", + "entry_schema": { + "type": "org.onap.datatypes.policy.clamp.controlloop.httpControlLoopElement.RestRequest", + "typeVersion": "1.0.0" + }, + "description": "A sequence of REST commands to send to the REST endpoint" + } + } + } + } + }, + "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", + "required": false, + "metadata": { + "common": true + }, + "description": "Specifies the organization that provides the control loop element" + }, + "participant_id": { + "type": "onap.datatypes.ToscaConceptIdentifier", + "requred": true, + "metadata": { + "common": true + } + }, + "participantType": { + "type": "onap.datatypes.ToscaConceptIdentifier", + "required": true, + "metadata": { + "common": true + }, + "description": "The identity of the participant type that hosts this type of Control Loop Element" + }, + "startPhase": { + "type": "integer", + "required": false, + "constraints": [ + { + "greater_or_equal": 0 + } + ], + "metadata": { + "common": true + }, + "description": "A value indicating the start phase in which this control loop element will be started, the first start phase is zero. Control Loop Elements are started in their start_phase order and stopped in reverse start phase order. Control Loop Elements with the same start phase are started and stopped simultaneously" + }, + "uninitializedToPassiveTimeout": { + "type": "integer", + "required": false, + "constraints": [ + { + "greater_or_equal": 0 + } + ], + "default": 60, + "metadata": { + "common": true + }, + "description": "The maximum time in seconds to wait for a state chage from uninitialized to passive" + }, + "passiveToRunningTimeout": { + "type": "integer", + "required": false, + "constraints": [ + { + "greater_or_equal": 0 + } + ], + "default": 60, + "metadata": { + "common": true + }, + "description": "The maximum time in seconds to wait for a state chage from passive to running" + }, + "runningToPassiveTimeout": { + "type": "integer", + "required": false, + "constraints": [ + { + "greater_or_equal": 0 + } + ], + "default": 60, + "metadata": { + "common": true + }, + "description": "The maximum time in seconds to wait for a state chage from running to passive" + }, + "passiveToUninitializedTimeout": { + "type": "integer", + "required": false, + "constraints": [ + { + "greater_or_equal": 0 + } + ], + "default": 60, + "metadata": { + "common": true + }, + "description": "The maximum time in seconds to wait for a state chage from passive to uninitialized" + } + } + }, + "org.onap.policy.clamp.controlloop.ControlLoop": { + "version": "1.0.1", + "derived_from": "tosca.nodetypes.Root", + "properties": { + "provider": { + "type": "string", + "required": false, + "metadata": { + "common": true + }, + "description": "Specifies the organization that provides the control loop element" + }, + "elements": { + "type": "list", + "required": true, + "metadata": { + "common": true + }, + "entry_schema": { + "type": "onap.datatypes.ToscaConceptIdentifier" + }, + "description": "Specifies a list of control loop element definitions that make up this control loop definition" + } + } + }, + "org.onap.policy.clamp.controlloop.PolicyControlLoopElement": { + "version": "1.0.1", + "derived_from": "org.onap.policy.clamp.controlloop.ControlLoopElement", + "properties": { + "policy_type_id": { + "type": "onap.datatypes.ToscaConceptIdentifier", + "requred": true + }, + "policy_id": { + "type": "onap.datatypes.ToscaConceptIdentifier", + "requred": false + } + } + }, + "org.onap.policy.clamp.controlloop.DerivedPolicyControlLoopElement": { + "version": "1.0.1", + "derived_from": "org.onap.policy.clamp.controlloop.PolicyControlLoopElement", + "properties": { + "policy_type_id": { + "type": "onap.datatypes.ToscaConceptIdentifier", + "requred": true + }, + "policy_id": { + "type": "onap.datatypes.ToscaConceptIdentifier", + "requred": false + } + } + }, + "org.onap.policy.clamp.controlloop.DerivedDerivedPolicyControlLoopElement": { + "version": "1.0.1", + "derived_from": "org.onap.policy.clamp.controlloop.DerivedPolicyControlLoopElement", + "properties": { + "policy_type_id": { + "type": "onap.datatypes.ToscaConceptIdentifier", + "requred": true + }, + "policy_id": { + "type": "onap.datatypes.ToscaConceptIdentifier", + "requred": false + } + } + }, + "org.onap.policy.clamp.controlloop.CDSControlLoopElement": { + "version": "1.0.1", + "derived_from": "org.onap.policy.clamp.controlloop.ControlLoopElement", + "properties": { + "cds_blueprint_id": { + "type": "onap.datatypes.ToscaConceptIdentifier", + "requred": true + } + } + }, + "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": null + }, + "values": { + "type": "string", + "requred": true + } + } + }, + "org.onap.policy.clamp.controlloop.HttpControlLoopElement": { + "version": "1.0.1", + "derived_from": "org.onap.policy.clamp.controlloop.ControlLoopElement", + "properties": { + "baseUrl": { + "type": "string", + "required": true, + "description": "The base URL to be prepended to each path, identifies the host for the REST endpoints." + }, + "httpHeaders": { + "type": "map", + "required": false, + "entry_schema": { + "type": "string" + }, + "description": "HTTP headers to send on REST requests" + }, + "configurationEntities": { + "type": "map", + "required": true, + "entry_schema": { + "type": "org.onap.datatypes.policy.clamp.controlloop.httpControlLoopElement.ConfigurationEntity", + "typeVersion": "1.0.0" + }, + "description": "The connfiguration entities the Control Loop Element is managing and their associated REST requests" + } + } + } + }, + "topology_template": { + "inputs": { + "pmsh_monitoring_policy": { + "type": "onap.datatypes.ToscaConceptIdentifier", + "description": "The ID of the PMSH monitoring policy to use", + "default": { + "name": "MICROSERVICE_vLoadBalancerMS_v1_0_dcae-pm-subscription-handler_1_0_0test", + "version": "1.0.0" + } + }, + "pmsh_operational_policy": { + "type": "onap.datatypes.ToscaConceptIdentifier", + "description": "The ID of the PMSH operational policy to use", + "default": { + "name": "operational.apex.pmcontrol", + "version": "1.0.0" + } + } + }, + "node_templates": { + "org.onap.policy.controlloop.PolicyControlLoopParticipant": { + "version": "2.3.1", + "type": "org.onap.policy.clamp.controlloop.Participant", + "type_version": "1.0.1", + "description": "Participant for DCAE microservices", + "properties": { + "provider": "ONAP" + } + }, + "org.onap.domain.pmsh.PMSH_MonitoringPolicyControlLoopElement": { + "version": "1.2.3", + "type": "org.onap.policy.clamp.controlloop.PolicyControlLoopElement", + "type_version": "1.0.0", + "description": "Control loop element for the monitoring policy for Performance Management Subscription Handling", + "properties": { + "provider": "Ericsson", + "participant_id": { + "name": "org.onap.PM_Policy", + "version": "1.0.0" + }, + "participantType": { + "name": "org.onap.policy.controlloop.PolicyControlLoopParticipant", + "version": "2.3.1" + }, + "policy_type_id": { + "name": "onap.policies.monitoring.pm-subscription-handler", + "version": "1.0.0" + }, + "policy_id": { + "get_input": "pmsh_monitoring_policy" + } + } + }, + "org.onap.domain.pmsh.PMSH_OperationalPolicyControlLoopElement": { + "version": "1.2.3", + "type": "org.onap.policy.clamp.controlloop.PolicyControlLoopElement", + "type_version": "1.0.0", + "description": "Control loop element for the operational policy for Performance Management Subscription Handling", + "properties": { + "provider": "Ericsson", + "participant_id": { + "name": "org.onap.PM_Policy", + "version": "1.0.0" + }, + "participantType": { + "name": "org.onap.policy.controlloop.PolicyControlLoopParticipant", + "version": "2.3.1" + }, + "policy_type_id": { + "name": "onap.policies.operational.pm-subscription-handler", + "version": "1.0.0" + }, + "policy_id": { + "get_input": "pmsh_operational_policy" + } + } + }, + "org.onap.domain.pmsh.DerivedPolicyControlLoopElement": { + "version": "1.2.3", + "type": "org.onap.policy.clamp.controlloop.DerivedPolicyControlLoopElement", + "type_version": "1.0.0", + "description": "Control loop for Performance Management Subscription Handling", + "properties": { + "provider": "Ericsson", + "participantType": { + "name": "org.onap.policy.controlloop.PolicyControlLoopParticipant", + "version": "2.3.1" + }, + "participant_id": { + "name": "org.onap.PM_Policy", + "version": "1.0.0" + } + } + }, + "org.onap.domain.pmsh.DerivedDerivedPolicyControlLoopElement": { + "version": "1.2.3", + "type": "org.onap.policy.clamp.controlloop.DerivedDerivedPolicyControlLoopElement", + "type_version": "1.0.0", + "description": "Control loop for Performance Management Subscription Handling", + "properties": { + "provider": "Ericsson", + "participantType": { + "name": "org.onap.policy.controlloop.PolicyControlLoopParticipant", + "version": "2.3.1" + }, + "participant_id": { + "name": "org.onap.PM_Policy", + "version": "1.0.0" + } + } + }, + "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.PMSH_K8SMicroserviceControlLoopElement": { + "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": "K8sParticipant0", + "version": "1.0.0" + }, + "participantType": { + "name": "org.onap.k8s.controlloop.K8SControlLoopParticipant", + "version": "2.3.4" + }, + "chart": { + "chartId": { + "name": "dcae-pmsh", + "version": "8.0.0" + }, + "namespace": "onap", + "releaseName": "pmshms", + "repository": { + "repoName": "chartmuseum", + "protocol": "http", + "address": "10.152.183.120", + "port": 80, + "userName": "onapinitializer", + "password": "demo123456!" + }, + "overrideParams": { + "global.masterPassword": "test" + } + } + } + }, + "org.onap.domain.database.Local_K8SMicroserviceControlLoopElement": { + "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": "K8sParticipant0", + "version": "1.0.0" + }, + "participantType": { + "name": "org.onap.k8s.controlloop.K8SControlLoopParticipant", + "version": "2.3.4" + }, + "chart": { + "chartId": { + "name": "nginx-ingress", + "version": "0.9.1" + }, + "releaseName": "nginxms", + "namespace": "test" + } + } + }, + "org.onap.controlloop.HttpControlLoopParticipant": { + "version": "2.3.4", + "type": "org.onap.policy.clamp.controlloop.Participant", + "type_version": "1.0.1", + "description": "Participant for Http requests", + "properties": { + "provider": "ONAP" + } + }, + "org.onap.domain.database.Http_PMSHMicroserviceControlLoopElement": { + "version": "1.2.3", + "type": "org.onap.policy.clamp.controlloop.HttpControlLoopElement", + "type_version": "1.0.1", + "description": "Control loop element for the http requests of PMSH microservice", + "properties": { + "provider": "ONAP", + "participant_id": { + "name": "HttpParticipant0", + "version": "1.0.0" + }, + "participantType": { + "name": "org.onap.k8s.controlloop.HttpControlLoopParticipant", + "version": "2.3.4" + }, + "uninitializedToPassiveTimeout": 180, + "startPhase": 1, + "baseUrl": "http://10.152.183.51:8500", + "httpHeaders": { + "Content-Type": "application/json" + }, + "configurationEntities": [ + { + "configurationEntityId": { + "name": "entity1", + "version": "1.0.1" + }, + "restSequence": [ + { + "restRequestId": { + "name": "request1", + "version": "1.0.1" + }, + "httpMethod": "PUT", + "path": "v1/kv/dcae-pmsh2", + "body": "{ \"control_loop_name\":\"pmsh-control-loop\", \"operational_policy_name\":\"pmsh-operational-policy\", \"aaf_password\":\"demo123456!\", \"aaf_identity\":\"dcae@dcae.onap.org\", \"cert_path\":\"/opt/app/pmsh/etc/certs/cert.pem\", \"key_path\":\"/opt/app/pmsh/etc/certs/key.pem\", \"ca_cert_path\":\"/opt/app/pmsh/etc/certs/cacert.pem\", \"enable_tls\":\"true\", \"pmsh_policy\":{ \"subscription\":{ \"subscriptionName\":\"ExtraPM-All-gNB-R2B\", \"administrativeState\":\"UNLOCKED\", \"fileBasedGP\":15, \"fileLocation\":\"\\/pm\\/pm.xml\", \"nfFilter\":{ \"nfNames\":[ \"^pnf.*\", \"^vnf.*\" ], \"modelInvariantIDs\":[ ], \"modelVersionIDs\":[ ], \"modelNames\":[ ] }, \"measurementGroups\":[ { \"measurementGroup\":{ \"measurementTypes\":[ { \"measurementType\":\"countera\" }, { \"measurementType\":\"counterb\" } ], \"managedObjectDNsBasic\":[ { \"DN\":\"dna\" }, { \"DN\":\"dnb\" } ] } }, { \"measurementGroup\":{ \"measurementTypes\":[ { \"measurementType\":\"counterc\" }, { \"measurementType\":\"counterd\" } ], \"managedObjectDNsBasic\":[ { \"DN\":\"dnc\" }, { \"DN\":\"dnd\" } ] } } ] } }, \"streams_subscribes\":{ \"aai_subscriber\":{ \"type\":\"message_router\", \"dmaap_info\":{ \"topic_url\":\"https://10.152.183.151:3905/events/AAI_EVENT\", \"client_role\":\"org.onap.dcae.aaiSub\", \"location\":\"san-francisco\", \"client_id\":\"1575976809466\" } }, \"policy_pm_subscriber\":{ \"type\":\"message_router\", \"dmaap_info\":{ \"topic_url\":\"https://10.152.183.151:3905/events/org.onap.dmaap.mr.PM_SUBSCRIPTIONS\", \"client_role\":\"org.onap.dcae.pmSubscriber\", \"location\":\"san-francisco\", \"client_id\":\"1575876809456\" } } }, \"streams_publishes\":{ \"policy_pm_publisher\":{ \"type\":\"message_router\", \"dmaap_info\":{ \"topic_url\":\"https://10.152.183.151:3905/events/org.onap.dmaap.mr.PM_SUBSCRIPTIONS\", \"client_role\":\"org.onap.dcae.pmPublisher\", \"location\":\"san-francisco\", \"client_id\":\"1475976809466\" } }, \"other_publisher\":{ \"type\":\"message_router\", \"dmaap_info\":{ \"topic_url\":\"https://10.152.183.151:3905/events/org.onap.dmaap.mr.SOME_OTHER_TOPIC\", \"client_role\":\"org.onap.dcae.pmControlPub\", \"location\":\"san-francisco\", \"client_id\":\"1875976809466\" } } } }", + "expectedResponse": 200 + } + ] + } + ] + } + }, + "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.PMSH_K8SMicroserviceControlLoopElement", + "version": "1.2.3" + }, + { + "name": "org.onap.domain.database.Local_K8SMicroserviceControlLoopElement", + "version": "1.2.3" + }, + { + "name": "org.onap.domain.database.Http_PMSHMicroserviceControlLoopElement", + "version": "1.2.3" + }, + { + "name": "org.onap.domain.pmsh.DerivedPolicyControlLoopElement", + "version": "1.2.3" + }, + { + "name": "org.onap.domain.pmsh.DerivedDerivedPolicyControlLoopElement", + "version": "1.2.3" + }, + { + "name": "org.onap.domain.pmsh.PMSH_MonitoringPolicyControlLoopElement", + "version": "1.2.3" + }, + { + "name": "org.onap.domain.pmsh.PMSH_OperationalPolicyControlLoopElement", + "version": "1.2.3" + } + ] + } + } + } + } +} diff --git a/plugins/reception-plugins/src/main/java/org/onap/policy/distribution/reception/decoding/policy/file/ControlLoopDecoderFileInCsar.java b/plugins/reception-plugins/src/main/java/org/onap/policy/distribution/reception/decoding/policy/file/ControlLoopDecoderFileInCsar.java new file mode 100644 index 00000000..96db632c --- /dev/null +++ b/plugins/reception-plugins/src/main/java/org/onap/policy/distribution/reception/decoding/policy/file/ControlLoopDecoderFileInCsar.java @@ -0,0 +1,117 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2022 Nordix Foundation. + * Modifications Copyright (C) 2022 Nordix Foundation. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.distribution.reception.decoding.policy.file; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Enumeration; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; +import org.onap.policy.common.parameters.ParameterService; +import org.onap.policy.common.utils.coder.CoderException; +import org.onap.policy.distribution.model.Csar; +import org.onap.policy.distribution.model.PolicyInput; +import org.onap.policy.distribution.reception.decoding.PolicyDecoder; +import org.onap.policy.distribution.reception.decoding.PolicyDecodingException; +import org.onap.policy.distribution.reception.util.ReceptionUtil; +import org.onap.policy.models.tosca.authorative.concepts.ToscaEntity; +import org.onap.policy.models.tosca.authorative.concepts.ToscaServiceTemplate; + +/** + * This class extracts controlloop information from a CSAR file. + * + * @author Sirisha Manchikanti (sirisha.manchikanti@est.tech) + */ +public class ControlLoopDecoderFileInCsar implements PolicyDecoder<Csar, ToscaEntity> { + + private ControlLoopDecoderFileInCsarParameterGroup decoderParameters; + private static final String NODE_TYPES = "nodes.yml"; + private static final String DATA_TYPES = "data.yml"; + + /** + * {@inheritDoc}. + */ + @Override + public void configure(final String parameterGroupName) { + decoderParameters = ParameterService.get(parameterGroupName); + } + + /** + * {@inheritDoc}. + */ + @Override + public boolean canHandle(final PolicyInput policyInput) { + return policyInput.getClass().isAssignableFrom(Csar.class); + } + + /** + * {@inheritDoc}. + */ + @Override + public Collection<ToscaEntity> decode(final Csar csar) throws PolicyDecodingException { + final Collection<ToscaEntity> controlLoopList = new ArrayList<>(); + ToscaServiceTemplate nodeTypes = null; + ToscaServiceTemplate dataTypes = null; + + try (var zipFile = new ZipFile(csar.getCsarFilePath())) { + final Enumeration<? extends ZipEntry> entries = zipFile.entries(); + while (entries.hasMoreElements()) { + // + // Sonar will flag this as a Security Hotspot + // "Expanding archive files is security-sensitive" + // isZipEntryValid ensures the file being read exists in the archive + // + final ZipEntry entry = entries.nextElement(); // NOSONAR + final String entryName = entry.getName(); + + // Store node_types + if (entryName.contains(NODE_TYPES)) { + nodeTypes = ReceptionUtil.decodeFile(zipFile, entry); + } + + // Store data_types + if (entryName.contains(DATA_TYPES)) { + dataTypes = ReceptionUtil.decodeFile(zipFile, entry); + } + + if (entryName.contains(decoderParameters.getControlLoopType())) { + ReceptionUtil.validateZipEntry(entryName, csar.getCsarFilePath(), entry.getSize()); + final ToscaServiceTemplate controlLoop = ReceptionUtil.decodeFile(zipFile, entry); + if (null != controlLoop.getToscaTopologyTemplate()) { + if (null != nodeTypes) { + controlLoop.setNodeTypes(nodeTypes.getNodeTypes()); + } + if (null != dataTypes) { + controlLoop.setDataTypes(dataTypes.getDataTypes()); + } + controlLoopList.add(controlLoop); + } + } + } + } catch (final IOException | CoderException exp) { + throw new PolicyDecodingException("Failed decoding the controlloop", exp); + } + + return controlLoopList; + } +} diff --git a/plugins/reception-plugins/src/main/java/org/onap/policy/distribution/reception/decoding/policy/file/ControlLoopDecoderFileInCsarParameterGroup.java b/plugins/reception-plugins/src/main/java/org/onap/policy/distribution/reception/decoding/policy/file/ControlLoopDecoderFileInCsarParameterGroup.java new file mode 100644 index 00000000..358b1f87 --- /dev/null +++ b/plugins/reception-plugins/src/main/java/org/onap/policy/distribution/reception/decoding/policy/file/ControlLoopDecoderFileInCsarParameterGroup.java @@ -0,0 +1,44 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2022 Nordix Foundation. + * Modifications Copyright (C) 2022 Nordix Foundation. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.distribution.reception.decoding.policy.file; + +import lombok.Getter; +import org.onap.policy.common.parameters.annotations.NotBlank; +import org.onap.policy.common.parameters.annotations.NotNull; +import org.onap.policy.distribution.reception.parameters.PolicyDecoderConfigurationParameterGroup; + +/** + * Holds the parameters for the{@link ControlLoopDecoderFileInCsar}. + * + * @author Sirisha Manchikanti (sirisha.manchikanti@est.tech) + */ +@Getter +@NotNull +@NotBlank +public class ControlLoopDecoderFileInCsarParameterGroup extends PolicyDecoderConfigurationParameterGroup { + + private String controlLoopType; + + public ControlLoopDecoderFileInCsarParameterGroup() { + super(ControlLoopDecoderFileInCsarParameterGroup.class.getSimpleName()); + } +} diff --git a/plugins/reception-plugins/src/main/java/org/onap/policy/distribution/reception/decoding/policy/file/PolicyDecoderFileInCsarToPolicy.java b/plugins/reception-plugins/src/main/java/org/onap/policy/distribution/reception/decoding/policy/file/PolicyDecoderFileInCsarToPolicy.java index 72316f28..c4ba21fe 100644 --- a/plugins/reception-plugins/src/main/java/org/onap/policy/distribution/reception/decoding/policy/file/PolicyDecoderFileInCsarToPolicy.java +++ b/plugins/reception-plugins/src/main/java/org/onap/policy/distribution/reception/decoding/policy/file/PolicyDecoderFileInCsarToPolicy.java @@ -1,7 +1,7 @@ /*- * ============LICENSE_START======================================================= * Copyright (C) 2018 Ericsson. All rights reserved. - * Copyright (C) 2019 Nordix Foundation. + * Copyright (C) 2022 Nordix Foundation. * Modifications Copyright (C) 2020-2021 AT&T Intellectual Property. All rights reserved. * Modifications Copyright (C) 2021 Bell Canada. All rights reserved. * ================================================================================ @@ -24,7 +24,6 @@ package org.onap.policy.distribution.reception.decoding.policy.file; import java.io.IOException; -import java.nio.file.Path; import java.util.ArrayList; import java.util.Collection; import java.util.Enumeration; @@ -32,12 +31,11 @@ import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import org.onap.policy.common.parameters.ParameterService; import org.onap.policy.common.utils.coder.CoderException; -import org.onap.policy.common.utils.coder.StandardCoder; -import org.onap.policy.common.utils.coder.StandardYamlCoder; import org.onap.policy.distribution.model.Csar; import org.onap.policy.distribution.model.PolicyInput; import org.onap.policy.distribution.reception.decoding.PolicyDecoder; import org.onap.policy.distribution.reception.decoding.PolicyDecodingException; +import org.onap.policy.distribution.reception.util.ReceptionUtil; import org.onap.policy.models.tosca.authorative.concepts.ToscaEntity; import org.onap.policy.models.tosca.authorative.concepts.ToscaServiceTemplate; @@ -49,9 +47,6 @@ import org.onap.policy.models.tosca.authorative.concepts.ToscaServiceTemplate; public class PolicyDecoderFileInCsarToPolicy implements PolicyDecoder<Csar, ToscaEntity> { private PolicyDecoderFileInCsarToPolicyParameterGroup decoderParameters; - private StandardCoder coder; - private StandardYamlCoder yamlCoder; - private static final long MAX_FILE_SIZE = 512L * 1024; /** * {@inheritDoc}. @@ -59,8 +54,6 @@ public class PolicyDecoderFileInCsarToPolicy implements PolicyDecoder<Csar, Tosc @Override public void configure(final String parameterGroupName) { decoderParameters = ParameterService.get(parameterGroupName); - coder = new StandardCoder(); - yamlCoder = new StandardYamlCoder(); } /** @@ -87,9 +80,15 @@ public class PolicyDecoderFileInCsarToPolicy implements PolicyDecoder<Csar, Tosc // isZipEntryValid ensures the file being read exists in the archive // final ZipEntry entry = entries.nextElement(); // NOSONAR - if (isZipEntryValid(entry.getName(), csar.getCsarFilePath(), entry.getSize())) { - final ToscaServiceTemplate policy = - decodeFile(zipFile, entry); + final String entryName = entry.getName(); + + // + // We only care about policy types and policies + // + if (entryName.contains(decoderParameters.getPolicyTypeFileName()) + || entryName.contains(decoderParameters.getPolicyFileName())) { + ReceptionUtil.validateZipEntry(entryName, csar.getCsarFilePath(), entry.getSize()); + final ToscaServiceTemplate policy = ReceptionUtil.decodeFile(zipFile, entry); policyList.add(policy); } } @@ -99,61 +98,4 @@ public class PolicyDecoderFileInCsarToPolicy implements PolicyDecoder<Csar, Tosc return policyList; } - - /** - * Method to filter out Policy type and Policy files. In addition, - * ensures validation of entries in the Zipfile. Attempts to solve path - * injection java security issues. - * - * @param entryName name of the ZipEntry to check - * @param csarPath Absolute path to the csar the ZipEntry is in - * @param entrySize size of the ZipEntry - * @return true if no injection detected, and it is a policy type or policy file. - * @throws PolicyDecodingException if the file size is too large - */ - private boolean isZipEntryValid(String entryName, String csarPath, long entrySize) throws PolicyDecodingException { - // - // We only care about policy types and policies - // - if (entryName.contains(decoderParameters.getPolicyTypeFileName()) - || entryName.contains(decoderParameters.getPolicyFileName())) { - // - // Check file size - // - if (entrySize > MAX_FILE_SIZE) { - throw new PolicyDecodingException("Zip entry for " + entryName + " is too large " + entrySize); - } - // - // Now ensure that there is no path injection - // - var path = Path.of(csarPath, entryName).normalize(); - // - // Throw an exception if path is outside the csar - // - if (! path.startsWith(csarPath)) { - throw new PolicyDecodingException("Potential path injection for zip entry " + entryName); - } - return true; - } - - return false; - } - - /** - * Method to decode either a json or yaml file into an object. - * - * @param zipFile the zip file - * @param entry the entry to read in the zip file. - * @return the decoded ToscaServiceTemplate object. - * @throws CoderException IOException if the file decoding fails. - */ - private ToscaServiceTemplate decodeFile(ZipFile zipFile, final ZipEntry entry) throws IOException, CoderException { - ToscaServiceTemplate policy = null; - if (entry.getName().endsWith(".json")) { - policy = coder.decode(zipFile.getInputStream(entry), ToscaServiceTemplate.class); - } else if (entry.getName().endsWith(".yaml")) { - policy = yamlCoder.decode(zipFile.getInputStream(entry), ToscaServiceTemplate.class); - } - return policy; - } } diff --git a/plugins/reception-plugins/src/main/java/org/onap/policy/distribution/reception/util/ReceptionUtil.java b/plugins/reception-plugins/src/main/java/org/onap/policy/distribution/reception/util/ReceptionUtil.java new file mode 100644 index 00000000..9c0bab43 --- /dev/null +++ b/plugins/reception-plugins/src/main/java/org/onap/policy/distribution/reception/util/ReceptionUtil.java @@ -0,0 +1,92 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2022 Nordix Foundation. + * Modifications Copyright (C) 2022 Nordix Foundation. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.distribution.reception.util; + +import java.io.IOException; +import java.nio.file.Path; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; +import org.onap.policy.common.utils.coder.CoderException; +import org.onap.policy.common.utils.coder.StandardCoder; +import org.onap.policy.common.utils.coder.StandardYamlCoder; +import org.onap.policy.distribution.reception.decoding.PolicyDecodingException; +import org.onap.policy.models.tosca.authorative.concepts.ToscaServiceTemplate; + +/** + * This class extracts and validates information from a CSAR file. + * + * @author Sirisha Manchikanti (sirisha.manchikanti@est.tech) + */ +public class ReceptionUtil { + + private static StandardCoder coder = new StandardCoder(); + private static StandardYamlCoder yamlCoder = new StandardYamlCoder(); + private static final long MAX_FILE_SIZE = 512L * 1024; + + /** + * Method to ensure validation of entries in the Zipfile. Attempts to solve path + * injection java security issues. + * + * @param entryName name of the ZipEntry to check + * @param csarPath Absolute path to the csar the ZipEntry is in + * @param entrySize size of the ZipEntry + * @throws PolicyDecodingException if the file size is too large + */ + public static void validateZipEntry(String entryName, String csarPath, long entrySize) + throws PolicyDecodingException { + // + // Check file size + // + if (entrySize > MAX_FILE_SIZE) { + throw new PolicyDecodingException("Zip entry for " + entryName + " is too large " + entrySize); + } + // + // Now ensure that there is no path injection + // + var path = Path.of(csarPath, entryName).normalize(); + // + // Throw an exception if path is outside the csar + // + if (! path.startsWith(csarPath)) { + throw new PolicyDecodingException("Potential path injection for zip entry " + entryName); + } + } + + /** + * Method to decode either a json or yaml file into an object. + * + * @param zipFile the zip file + * @param entry the entry to read in the zip file. + * @return the decoded ToscaServiceTemplate object. + * @throws CoderException IOException if the file decoding fails. + */ + public static ToscaServiceTemplate decodeFile(ZipFile zipFile, final ZipEntry entry) + throws IOException, CoderException { + ToscaServiceTemplate toscaServiceTemplate = null; + if (entry.getName().endsWith(".json")) { + toscaServiceTemplate = coder.decode(zipFile.getInputStream(entry), ToscaServiceTemplate.class); + } else if (entry.getName().endsWith(".yml")) { + toscaServiceTemplate = yamlCoder.decode(zipFile.getInputStream(entry), ToscaServiceTemplate.class); + } + return toscaServiceTemplate; + } +} diff --git a/plugins/reception-plugins/src/test/java/org/onap/policy/distribution/reception/decoding/policy/file/ControlLoopDecoderFileInCsarParameterGroupTest.java b/plugins/reception-plugins/src/test/java/org/onap/policy/distribution/reception/decoding/policy/file/ControlLoopDecoderFileInCsarParameterGroupTest.java new file mode 100644 index 00000000..16f80096 --- /dev/null +++ b/plugins/reception-plugins/src/test/java/org/onap/policy/distribution/reception/decoding/policy/file/ControlLoopDecoderFileInCsarParameterGroupTest.java @@ -0,0 +1,67 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2022 Nordix Foundation. + * Modifications Copyright (C) 2022 Nordix Foundation. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.distribution.reception.decoding.policy.file; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; +import org.onap.policy.common.parameters.ValidationStatus; +import org.onap.policy.distribution.reception.handling.sdc.CommonTestData; + +/** + * Class to perform unit test of {@link ControlLoopDecoderFileInCsarParameterGroup}. + * + * @author Sirisha Manchikanti (sirisha.manchikanti@est.tech) + */ +public class ControlLoopDecoderFileInCsarParameterGroupTest { + + @Test + public void testValidParameters() { + final ControlLoopDecoderFileInCsarParameterGroup configurationParameters = CommonTestData + .getPolicyDecoderParameters("src/test/resources/parameters/FileInCsarControlLoopDecoderParameters.json", + ControlLoopDecoderFileInCsarParameterGroup.class); + + assertEquals(ControlLoopDecoderFileInCsarParameterGroup.class.getSimpleName(), + configurationParameters.getName()); + assertEquals("controlloop", configurationParameters.getControlLoopType()); + assertEquals(ValidationStatus.CLEAN, configurationParameters.validate().getStatus()); + } + + @Test + public void testInvalidParameters() { + final ControlLoopDecoderFileInCsarParameterGroup configurationParameters = + CommonTestData.getPolicyDecoderParameters( + "src/test/resources/parameters/FileInCsarControlLoopDecoderParametersInvalid.json", + ControlLoopDecoderFileInCsarParameterGroup.class); + + assertEquals(ValidationStatus.INVALID, configurationParameters.validate().getStatus()); + } + + @Test + public void testEmptyParameters() { + final ControlLoopDecoderFileInCsarParameterGroup configurationParameters = + CommonTestData.getPolicyDecoderParameters("src/test/resources/parameters/EmptyParameters.json", + ControlLoopDecoderFileInCsarParameterGroup.class); + + assertEquals(ValidationStatus.INVALID, configurationParameters.validate().getStatus()); + } +} diff --git a/plugins/reception-plugins/src/test/java/org/onap/policy/distribution/reception/decoding/policy/file/ControlLoopDecoderFileInCsarTest.java b/plugins/reception-plugins/src/test/java/org/onap/policy/distribution/reception/decoding/policy/file/ControlLoopDecoderFileInCsarTest.java new file mode 100644 index 00000000..e452a7ce --- /dev/null +++ b/plugins/reception-plugins/src/test/java/org/onap/policy/distribution/reception/decoding/policy/file/ControlLoopDecoderFileInCsarTest.java @@ -0,0 +1,96 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2022 Nordix Foundation. + * Modifications Copyright (C) 2022 Nordix Foundation. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.distribution.reception.decoding.policy.file; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.io.File; +import java.util.Collection; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.runners.MockitoJUnitRunner; +import org.onap.policy.common.parameters.ParameterService; +import org.onap.policy.distribution.model.Csar; +import org.onap.policy.distribution.reception.decoding.PolicyDecodingException; +import org.onap.policy.distribution.reception.handling.sdc.CommonTestData; +import org.onap.policy.models.tosca.authorative.concepts.ToscaEntity; + +/** + * Class to perform unit test of {@link ControlLoopDecoderFileInCsar}. + * + * @author Sirisha Manchikanti (sirisha.manchikanti@est.tech) + */ +@RunWith(MockitoJUnitRunner.class) +public class ControlLoopDecoderFileInCsarTest { + + /** + * Set up. + */ + @BeforeClass + public static void setUp() { + final ControlLoopDecoderFileInCsarParameterGroup configurationParameters = CommonTestData + .getPolicyDecoderParameters("src/test/resources/parameters/FileInCsarControlLoopDecoderParameters.json", + ControlLoopDecoderFileInCsarParameterGroup.class); + configurationParameters.setName(ControlLoopDecoderFileInCsarParameterGroup.class.getSimpleName()); + ParameterService.register(configurationParameters); + } + + /** + * Tear down. + */ + @AfterClass + public static void tearDown() { + ParameterService.deregister(ControlLoopDecoderFileInCsarParameterGroup.class.getSimpleName()); + } + + @Test + public void testDecodeControlLoop() throws PolicyDecodingException { + + final ControlLoopDecoderFileInCsar decoder = new ControlLoopDecoderFileInCsar(); + decoder.configure(ControlLoopDecoderFileInCsarParameterGroup.class.getSimpleName()); + + final File file = new File("src/test/resources/service-Sampleservice-controlloop.csar"); + final Csar csar = new Csar(file.getAbsolutePath()); + + assertTrue(decoder.canHandle(csar)); + final Collection<ToscaEntity> controlLoopHolders = decoder.decode(csar); + assertEquals(1, controlLoopHolders.size()); + } + + @Test + public void testDecodeControlLoopZipError() { + + final ControlLoopDecoderFileInCsar decoder = new ControlLoopDecoderFileInCsar(); + decoder.configure(ControlLoopDecoderFileInCsarParameterGroup.class.getSimpleName()); + + final File file = new File("unknown.csar"); + final Csar csar = new Csar(file.getAbsolutePath()); + + assertTrue(decoder.canHandle(csar)); + assertThatThrownBy(() -> decoder.decode(csar)).isInstanceOf(PolicyDecodingException.class) + .hasMessageContaining("Failed decoding the controlloop"); + } +} diff --git a/plugins/reception-plugins/src/test/resources/parameters/FileInCsarControlLoopDecoderParameters.json b/plugins/reception-plugins/src/test/resources/parameters/FileInCsarControlLoopDecoderParameters.json new file mode 100644 index 00000000..ca112388 --- /dev/null +++ b/plugins/reception-plugins/src/test/resources/parameters/FileInCsarControlLoopDecoderParameters.json @@ -0,0 +1,3 @@ +{ + "controlLoopType": "controlloop" +} diff --git a/plugins/reception-plugins/src/test/resources/parameters/FileInCsarControlLoopDecoderParametersInvalid.json b/plugins/reception-plugins/src/test/resources/parameters/FileInCsarControlLoopDecoderParametersInvalid.json new file mode 100644 index 00000000..9d33896e --- /dev/null +++ b/plugins/reception-plugins/src/test/resources/parameters/FileInCsarControlLoopDecoderParametersInvalid.json @@ -0,0 +1,3 @@ +{ + "controlLoop": "" +} diff --git a/plugins/reception-plugins/src/test/resources/service-Sampleservice-controlloop.csar b/plugins/reception-plugins/src/test/resources/service-Sampleservice-controlloop.csar Binary files differnew file mode 100644 index 00000000..03e29366 --- /dev/null +++ b/plugins/reception-plugins/src/test/resources/service-Sampleservice-controlloop.csar diff --git a/testsuites/stability/src/main/resources/setup/distribution/etc/defaultConfig.json b/testsuites/stability/src/main/resources/setup/distribution/etc/defaultConfig.json index a4cf85a8..2b3078ac 100644 --- a/testsuites/stability/src/main/resources/setup/distribution/etc/defaultConfig.json +++ b/testsuites/stability/src/main/resources/setup/distribution/etc/defaultConfig.json @@ -17,13 +17,23 @@ "decoderType":"ToscaPolicyDecoder", "decoderClassName":"org.onap.policy.distribution.reception.decoding.policy.file.PolicyDecoderFileInCsarToPolicy", "decoderConfigurationName": "toscaPolicyDecoderConfiguration" + }, + "ToscaControlLoopDecoder": { + "decoderType": "ToscaControlLoopDecoder", + "decoderClassName": "org.onap.policy.distribution.reception.decoding.policy.file.ControlLoopDecoderFileInCsar", + "decoderConfigurationName": "toscaControlLoopDecoderConfiguration" } }, "policyForwarders": { - "LifeCycleApiForwarder": { - "forwarderType": "LifeCycleAPI", + "LifeCycleApiPolicyForwarder": { + "forwarderType": "LifeCyclePolicyAPI", "forwarderClassName": "org.onap.policy.distribution.forwarding.lifecycle.api.LifecycleApiPolicyForwarder", - "forwarderConfigurationName": "lifecycleApiConfiguration" + "forwarderConfigurationName": "lifecycleApiPolicyConfiguration" + }, + "LifeCycleApiControlLoopForwarder": { + "forwarderType": "LifeCycleControlLoopAPI", + "forwarderClassName": "org.onap.policy.distribution.forwarding.lifecycle.api.LifecycleApiControlLoopForwarder", + "forwarderConfigurationName": "lifecycleApiControlLoopConfiguration" } } } @@ -45,11 +55,17 @@ "policyFileName": "tosca_policy", "policyTypeFileName": "tosca_policy_type" } + }, + "toscaControlLoopDecoderConfiguration": { + "parameterClassName": "org.onap.policy.distribution.reception.decoding.policy.file.ControlLoopDecoderFileInCsarParameterGroup", + "parameters": { + "controlLoopType": "controlloop" + } } }, "policyForwarderConfigurationParameters": { - "lifecycleApiConfiguration": { + "lifecycleApiPolicyConfiguration": { "parameterClassName": "org.onap.policy.distribution.forwarding.lifecycle.api.LifecycleApiForwarderParameters", "parameters": { "apiParameters": { @@ -70,6 +86,19 @@ }, "deployPolicies": true } + }, + "lifecycleApiControlLoopConfiguration": { + "parameterClassName": "org.onap.policy.distribution.forwarding.lifecycle.api.LifecycleApiControlLoopForwarderParameters", + "parameters": { + "controlLoopRuntimeParameters": { + "clientName": "policy-clamp-cl-runtime", + "hostname": "policy-clamp-cl-runtime", + "port": 6969, + "useHttps": true, + "userName": "policyadmin", + "password": "zb!XztG34" + } + } } } } |