diff options
19 files changed, 890 insertions, 13 deletions
diff --git a/controlloop/common/controller-usecases/pom.xml b/controlloop/common/controller-usecases/pom.xml index cac01b838..63c9243fe 100644 --- a/controlloop/common/controller-usecases/pom.xml +++ b/controlloop/common/controller-usecases/pom.xml @@ -5,6 +5,7 @@ ================================================================================ Copyright (C) 2018-2019 AT&T Intellectual Property. All rights reserved. Modifications Copyright (C) 2019 Nordix Foundation. + Modifications Copyright (C) 2019 Bell Canada. ================================================================================ Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -107,6 +108,12 @@ <scope>provided</scope> </dependency> <dependency> + <groupId>org.onap.policy.models.policy-models-interactions.model-impl</groupId> + <artifactId>cds</artifactId> + <version>${policy.models.version}</version> + <scope>provided</scope> + </dependency> + <dependency> <groupId>org.onap.policy.drools-applications.controlloop.common</groupId> <artifactId>eventmanager</artifactId> <version>${project.version}</version> @@ -161,6 +168,11 @@ <scope>provided</scope> </dependency> <dependency> + <groupId>org.onap.policy.models.policy-models-interactions.model-actors</groupId> + <artifactId>actor.cds</artifactId> + <version>${policy.models.version}</version> + </dependency> + <dependency> <groupId>org.onap.policy.models.policy-models-interactions</groupId> <artifactId>model-yaml</artifactId> <version>${policy.models.version}</version> @@ -173,6 +185,11 @@ <scope>provided</scope> <optional>true</optional> </dependency> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <scope>test</scope> + </dependency> </dependencies> <profiles> diff --git a/controlloop/common/controller-usecases/src/main/resources/usecases.drl b/controlloop/common/controller-usecases/src/main/resources/usecases.drl index 02161b8c3..4adf74064 100644 --- a/controlloop/common/controller-usecases/src/main/resources/usecases.drl +++ b/controlloop/common/controller-usecases/src/main/resources/usecases.drl @@ -3,6 +3,7 @@ * ONAP * ================================================================================ * Copyright (C) 2018-2019 AT&T Intellectual Property. All rights reserved. + * Modifications Copyright (C) 2019 Bell Canada. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,6 +21,7 @@ package org.onap.policy.controlloop; +import org.onap.ccsdk.cds.controllerblueprints.processing.api.ExecutionServiceInput; import org.onap.policy.controlloop.params.ControlLoopParams; import org.onap.policy.controlloop.VirtualControlLoopEvent; import org.onap.policy.controlloop.VirtualControlLoopNotification; @@ -35,6 +37,9 @@ import org.onap.policy.controlloop.eventmanager.ControlLoopEventManager.NewEvent import org.onap.policy.controlloop.eventmanager.ControlLoopOperationManager; import org.onap.policy.controlloop.utils.ControlLoopUtils; import org.onap.policy.controlloop.actor.so.SoActorServiceProvider; +import org.onap.policy.controlloop.actor.cds.CdsActorServiceProvider; +import org.onap.policy.controlloop.actor.cds.CdsActorServiceProvider.CdsActorServiceManager; +import org.onap.policy.controlloop.actor.cds.constants.CdsActorConstants; import org.onap.policy.aai.AaiNqResponseWrapper; import org.onap.policy.aai.AaiCqResponse; import org.onap.policy.appc.Request; @@ -45,6 +50,9 @@ import org.onap.policy.appclcm.LcmResponseWrapper; import org.onap.policy.appclcm.LcmRequest; import org.onap.policy.appclcm.LcmResponse; import org.onap.policy.appclcm.LcmCommonHeader; +import org.onap.policy.cds.CdsResponse; +import org.onap.policy.cds.client.CdsProcessorGrpcClient; +import org.onap.policy.cds.properties.CdsServerProperties; import org.onap.policy.sdnr.PciRequestWrapper; import org.onap.policy.sdnr.PciResponseWrapper; import org.onap.policy.sdnr.PciRequest; @@ -78,6 +86,7 @@ import java.time.Instant; import java.util.LinkedList; import java.util.Iterator; + import org.onap.policy.drools.system.PolicyEngineConstants; /* @@ -621,6 +630,33 @@ rule "EVENT.MANAGER.OPERATION.LOCKED.GUARD_PERMITTED" t.start(); } break; + + case "CDS": + + if(request instanceof ExecutionServiceInput) { + + // Instantiate cds actor, service manager and grpc properties + + CdsActorServiceProvider cdsActor = new CdsActorServiceProvider(); + CdsActorServiceProvider.CdsActorServiceManager cdsActorServiceManager = cdsActor.new CdsActorServiceManager(); + + CdsServerProperties props = new CdsServerProperties(); + props.setHost(PolicyEngineConstants.getManager().getEnvironmentProperty("cds.grpcHost")); + props.setPort(Integer.parseInt(PolicyEngineConstants.getManager().getEnvironmentProperty("cds.grpcPort"))); + props.setUsername(PolicyEngineConstants.getManager().getEnvironmentProperty("cds.grpcUsername")); + props.setPassword(PolicyEngineConstants.getManager().getEnvironmentProperty("cds.grpcPassword")); + props.setTimeout(Integer.parseInt(PolicyEngineConstants.getManager().getEnvironmentProperty("cds.grpcTimeout"))); + + // Send cds grpc request + try (CdsProcessorGrpcClient client = new CdsProcessorGrpcClient(cdsActorServiceManager, props)) { + CdsResponse response = + cdsActorServiceManager.sendRequestToCds(client, props, (ExecutionServiceInput) request); + logger.info("CDS response: {}", response); + insert(response); + } + } + break; + } } else { // @@ -1302,6 +1338,87 @@ rule "SDNC.RESPONSE" end + +/** + * This rule responds to CDS Response Events + */ +rule "${policyName}.CDS.RESPONSE" + when + $params : ControlLoopParams( $clName : getClosedLoopControlName() ) + $event : VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName(), + closedLoopEventStatus == ControlLoopEventStatus.ONSET ) + $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(), + requestId == $event.getRequestId() ) + $operation : ControlLoopOperationManager( onset.closedLoopControlName == $event.getClosedLoopControlName(), + onset.getRequestId() == $event.getRequestId() ) + $opTimer : ControlLoopTimer( closedLoopControlName == $event.getClosedLoopControlName(), + requestId == $event.getRequestId().toString(), timerType == "Operation", !expired ) + $lock : TargetLock (requestId == $event.getRequestId()) + $response : CdsResponse( requestId == $event.getRequestId().toString() ) + + then + + Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage()); + logger.info("{}: {}", $params.getClosedLoopControlName(), drools.getRule().getName()); + logger.debug("{}: {}: event={} manager={} operation={} lock={} opTimer={} response={}", + $params.getClosedLoopControlName(), drools.getRule().getName(), + $event, $manager, $operation, $lock, $operation, $opTimer, $response); + + // Get the result of the operation + PolicyResult policyResult = $operation.onResponse($response); + + if (policyResult != null) { + logger.debug("{}: {}: operation finished - result={}", + $params.getClosedLoopControlName(), drools.getRule().getName(), + policyResult); + + // The operation has completed, construct a notification showing our results + VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event); + notification.setFrom("policy"); + notification.setPolicyName(drools.getRule().getName()); + notification.setPolicyScope($params.getPolicyScope()); + notification.setPolicyVersion($params.getPolicyVersion()); + notification.setMessage($operation.getOperationHistory()); + notification.setHistory($operation.getHistory()); + notification.setNotification( + ($response != null && CdsActorConstants.SUCCESS.equals($response.getStatus())) + ? ControlLoopNotificationType.OPERATION_SUCCESS : ControlLoopNotificationType.OPERATION_FAILURE); + + // Send the notification + PolicyEngineConstants.getManager().deliver("POLICY-CL-MGT", notification); + + // Ensure the operation is complete + if ($operation.isOperationComplete()) { + + // It is complete, remove it from memory + retract($operation); + + // We must also retract the timer object + // NOTE: We could write a Rule to do this + retract($opTimer); + + // Complete the operation + modify($manager) {finishOperation($operation)}; + + } else { + // Just doing this will kick off the LOCKED rule again + modify($operation) {}; + } + } else { + // Its not finished yet (i.e. expecting more Response objects) + // Or possibly it is a leftover response that we timed the request out previously + logger.info( + "policyResult is null" + + "\nIt's not finished yet (i.e. expecting more Response objects)" + + "\nOr possibly it is a leftover response that we timed the request out previously"); + } + + // We are going to retract these objects from memory + retract($response); + +end + +/* /* * * This manages a single timer. diff --git a/controlloop/common/eventmanager/pom.xml b/controlloop/common/eventmanager/pom.xml index a7cb753d1..a020e5e5d 100644 --- a/controlloop/common/eventmanager/pom.xml +++ b/controlloop/common/eventmanager/pom.xml @@ -4,6 +4,7 @@ ================================================================================ Copyright (C) 2017-2019 AT&T Intellectual Property. All rights reserved. Modifications Copyright (C) 2019 Nordix Foundation. + Modifications Copyright (C) 2019 Bell Canada. ================================================================================ Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -85,6 +86,12 @@ <scope>provided</scope> </dependency> <dependency> + <groupId>org.onap.policy.models.policy-models-interactions.model-actors</groupId> + <artifactId>actor.cds</artifactId> + <version>${policy.models.version}</version> + <scope>provided</scope> + </dependency> + <dependency> <groupId>org.onap.policy.drools-applications.controlloop.common</groupId> <artifactId>database</artifactId> <version>${project.version}</version> @@ -132,6 +139,16 @@ <scope>provided</scope> </dependency> <dependency> + <groupId>org.onap.policy.models.policy-models-interactions.model-impl</groupId> + <artifactId>cds</artifactId> + <version>${policy.models.version}</version> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>org.onap.ccsdk.cds.components</groupId> + <artifactId>proto-definition</artifactId> + </dependency> + <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <scope>test</scope> diff --git a/controlloop/common/eventmanager/src/main/java/org/onap/policy/controlloop/eventmanager/ControlLoopEventManager.java b/controlloop/common/eventmanager/src/main/java/org/onap/policy/controlloop/eventmanager/ControlLoopEventManager.java index aaccef60b..f6cfe5594 100644 --- a/controlloop/common/eventmanager/src/main/java/org/onap/policy/controlloop/eventmanager/ControlLoopEventManager.java +++ b/controlloop/common/eventmanager/src/main/java/org/onap/policy/controlloop/eventmanager/ControlLoopEventManager.java @@ -1056,7 +1056,7 @@ public class ControlLoopEventManager implements LockCallback, Serializable { * This function calls Aai Custom Query and responds with the AaiCqResponse. * * @param event input event - * @return AaiCqResponse Response from Aai for custom query + * @return AaiCqResponse Response from Aai for custom query. Can not be null. * @throws AaiException if error occurs */ public AaiCqResponse getCqResponse(VirtualControlLoopEvent event) throws AaiException { @@ -1088,6 +1088,11 @@ public class ControlLoopEventManager implements LockCallback, Serializable { response = new AaiManager(new RestManager()).getCustomQueryResponse(aaiHostUrl, aaiUser, aaiPassword, reqId, vserverId); + + if (response == null) { + throw new AaiException("Aai response is undefined"); + } + return response; } diff --git a/controlloop/common/eventmanager/src/main/java/org/onap/policy/controlloop/eventmanager/ControlLoopOperationManager.java b/controlloop/common/eventmanager/src/main/java/org/onap/policy/controlloop/eventmanager/ControlLoopOperationManager.java index 293fa43aa..eb1901937 100644 --- a/controlloop/common/eventmanager/src/main/java/org/onap/policy/controlloop/eventmanager/ControlLoopOperationManager.java +++ b/controlloop/common/eventmanager/src/main/java/org/onap/policy/controlloop/eventmanager/ControlLoopOperationManager.java @@ -5,6 +5,7 @@ * Copyright (C) 2017-2019 AT&T Intellectual Property. All rights reserved. * Modifications Copyright (C) 2019 Huawei Technologies Co., Ltd. All rights reserved. * Modifications Copyright (C) 2019 Tech Mahindra + * Modifications Copyright (C) 2019 Bell Canada. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -26,18 +27,26 @@ import java.io.Serializable; import java.sql.Timestamp; import java.time.Instant; import java.util.AbstractMap; +import java.util.HashMap; import java.util.LinkedList; import java.util.List; +import java.util.Map; import java.util.NoSuchElementException; +import java.util.Optional; import java.util.Properties; import javax.persistence.EntityManager; import javax.persistence.Persistence; + import org.eclipse.persistence.config.PersistenceUnitProperties; import org.onap.aai.domain.yang.GenericVnf; +import org.onap.aai.domain.yang.ServiceInstance; +import org.onap.ccsdk.cds.controllerblueprints.processing.api.ExecutionServiceInput; +import org.onap.policy.aai.AaiCqResponse; import org.onap.policy.aai.util.AaiException; import org.onap.policy.appc.Response; import org.onap.policy.appc.ResponseCode; import org.onap.policy.appclcm.LcmResponseWrapper; +import org.onap.policy.cds.CdsResponse; import org.onap.policy.controlloop.ControlLoopEvent; import org.onap.policy.controlloop.ControlLoopException; import org.onap.policy.controlloop.ControlLoopOperation; @@ -45,12 +54,15 @@ import org.onap.policy.controlloop.ControlLoopResponse; import org.onap.policy.controlloop.VirtualControlLoopEvent; import org.onap.policy.controlloop.actor.appc.AppcActorServiceProvider; import org.onap.policy.controlloop.actor.appclcm.AppcLcmActorServiceProvider; +import org.onap.policy.controlloop.actor.cds.CdsActorServiceProvider; +import org.onap.policy.controlloop.actor.cds.constants.CdsActorConstants; import org.onap.policy.controlloop.actor.sdnc.SdncActorServiceProvider; import org.onap.policy.controlloop.actor.sdnr.SdnrActorServiceProvider; import org.onap.policy.controlloop.actor.so.SoActorServiceProvider; import org.onap.policy.controlloop.actor.vfc.VfcActorServiceProvider; import org.onap.policy.controlloop.policy.Policy; import org.onap.policy.controlloop.policy.PolicyResult; +import org.onap.policy.controlloop.policy.TargetType; import org.onap.policy.database.operationshistory.Dbao; import org.onap.policy.drools.system.PolicyEngineConstants; import org.onap.policy.guard.Util; @@ -72,6 +84,8 @@ public class ControlLoopOperationManager implements Serializable { private static final String GENERIC_VNF_VNF_NAME = "generic-vnf.vnf-name"; private static final String GENERIC_VNF_VNF_ID = "generic-vnf.vnf-id"; + private static final String AAI_SERVICE_INSTANCE_ID_KEY = "service-instance.service-instance-id"; + // // These properties are not changeable, but accessible // for Drools Rule statements. @@ -89,6 +103,7 @@ public class ControlLoopOperationManager implements Serializable { private ControlLoopEventManager eventManager = null; private String targetEntity; private String guardApprovalStatus = "NONE";// "NONE", "PERMIT", "DENY" + private AaiCqResponse aaiCqResponse; private transient Object operationRequest; /** @@ -106,10 +121,15 @@ public class ControlLoopOperationManager implements Serializable { this.policy = policy; this.guardApprovalStatus = "NONE"; this.eventManager = em; - this.targetEntity = getTarget(policy); try { + if (Boolean.valueOf(PolicyEngineConstants.getManager().getEnvironmentProperty(AAI_CUSTOM_QUERY))) { + this.aaiCqResponse = this.eventManager.getCqResponse((VirtualControlLoopEvent) onset); + } + + this.targetEntity = getTarget(policy); + // // Let's make a sanity check // @@ -125,6 +145,8 @@ public class ControlLoopOperationManager implements Serializable { break; case "SDNC": break; + case "CDS": + break; default: throw new ControlLoopException("ControlLoopEventManager: policy has an unknown actor."); } @@ -142,8 +164,8 @@ public class ControlLoopOperationManager implements Serializable { * vnf-id is retrieved by a named query to A&AI. */ if (Boolean.valueOf(PolicyEngineConstants.getManager().getEnvironmentProperty(AAI_CUSTOM_QUERY))) { - GenericVnf genvnf = this.eventManager.getCqResponse((VirtualControlLoopEvent) onset) - .getGenericVnfByModelInvariantId(policy.getTarget().getResourceID()); + GenericVnf genvnf = + this.aaiCqResponse.getGenericVnfByModelInvariantId(policy.getTarget().getResourceID()); if (genvnf == null) { logger.info("Target entity could not be found"); throw new AaiException("Target vnf-id could not be found"); @@ -261,8 +283,7 @@ public class ControlLoopOperationManager implements Serializable { try { String vnfId; if (Boolean.valueOf(PolicyEngineConstants.getManager().getEnvironmentProperty(AAI_CUSTOM_QUERY))) { - vnfId = this.eventManager.getCqResponse((VirtualControlLoopEvent) onset).getDefaultGenericVnf() - .getVnfId(); + vnfId = this.aaiCqResponse.getDefaultGenericVnf().getVnfId(); } else { vnfId = this.eventManager.getVnfResponse().getVnfId(); } @@ -314,6 +335,8 @@ public class ControlLoopOperationManager implements Serializable { return startSdnrOperation(onset, operation); case "SDNC": return startSdncOperation(onset, operation); + case "CDS": + return startCdsOperation(onset, operation); default: throw new ControlLoopException("invalid actor " + policy.getActor() + " on policy"); } @@ -350,7 +373,7 @@ public class ControlLoopOperationManager implements Serializable { if (Boolean.valueOf(PolicyEngineConstants.getManager().getEnvironmentProperty(AAI_CUSTOM_QUERY))) { this.operationRequest = soActorSp.constructRequestCq((VirtualControlLoopEvent) onset, operation.clOperation, - this.policy, eventManager.getCqResponse((VirtualControlLoopEvent) onset)); + this.policy, this.aaiCqResponse); } else { this.operationRequest = soActorSp.constructRequest((VirtualControlLoopEvent) onset, operation.clOperation, this.policy, eventManager.getNqVserverFromAai()); @@ -370,8 +393,7 @@ public class ControlLoopOperationManager implements Serializable { private Object startVfcOperation(ControlLoopEvent onset, Operation operation) throws AaiException { if (Boolean.valueOf(PolicyEngineConstants.getManager().getEnvironmentProperty(AAI_CUSTOM_QUERY))) { this.operationRequest = VfcActorServiceProvider.constructRequestCq((VirtualControlLoopEvent) onset, - operation.clOperation, this.policy, - eventManager.getCqResponse((VirtualControlLoopEvent) onset)); + operation.clOperation, this.policy, this.aaiCqResponse); } else { this.operationRequest = VfcActorServiceProvider.constructRequest((VirtualControlLoopEvent) onset, operation.clOperation, this.policy, this.eventManager.getVnfResponse(), @@ -416,6 +438,60 @@ public class ControlLoopOperationManager implements Serializable { return operationRequest; } + private Object startCdsOperation(ControlLoopEvent onset, Operation operation) throws AaiException { + + CdsActorServiceProvider provider = new CdsActorServiceProvider(); + Optional<ExecutionServiceInput> optionalRequest = provider.constructRequest( + (VirtualControlLoopEvent) onset, operation.clOperation, this.policy, this.buildAaiParams()); + + this.currentOperation = operation; + if (optionalRequest.isPresent()) { + this.operationRequest = optionalRequest.get(); + } else { + this.operationRequest = null; + this.policyResult = PolicyResult.FAILURE; + } + + return this.operationRequest; + } + + /** + * Build AAI parameters for CDS operation. + * @return a map containing vnf id key and value for the vnf to apply the action to. + * @throws AaiException if the vnf can not be found. + */ + private Map<String, String> buildAaiParams() throws AaiException { + + Map<String, String> result = new HashMap<>(); + + if (TargetType.VNF.equals(policy.getTarget().getType()) + || TargetType.VFMODULE.equals(policy.getTarget().getType())) { + + if (Boolean.valueOf(PolicyEngineConstants.getManager().getEnvironmentProperty(AAI_CUSTOM_QUERY))) { + + ServiceInstance serviceInstance = this.aaiCqResponse.getServiceInstance(); + if (serviceInstance == null) { + logger.info("Target entity service instance could not be found"); + throw new AaiException("Target service instance could not be found"); + } + + GenericVnf genericVnf = + this.aaiCqResponse.getGenericVnfByModelInvariantId(policy.getTarget().getResourceID()); + if (genericVnf == null) { + logger.info("Target entity generic vnf could not be found"); + throw new AaiException("Target generic vnf could not be found"); + } + + result.put(AAI_SERVICE_INSTANCE_ID_KEY, serviceInstance.getServiceInstanceId()); + result.put(GENERIC_VNF_VNF_ID, genericVnf.getVnfId()); + } + + } + + return result; + + } + /** * Handle a response. * @@ -456,6 +532,11 @@ public class ControlLoopOperationManager implements Serializable { // Cast SDNC response and handle it // return onResponse((SdncResponse) response); + } else if (response instanceof CdsResponse) { + // + // Cast CDS response and handle it + // + return onResponse((CdsResponse) response); } else { return null; } @@ -694,6 +775,33 @@ public class ControlLoopOperationManager implements Serializable { } } + /** + * This method handles operation responses from CDS. + * + * @param response the CDS response + * @return The result of the response handling + */ + private PolicyResult onResponse(CdsResponse response) { + if (response != null && CdsActorConstants.SUCCESS.equals(response.getStatus())) { + // + // Consider it as success + // + this.completeOperation(this.attempts, SUCCESS_MSG, PolicyResult.SUCCESS); + return getTimeoutResult(PolicyResult.SUCCESS); + } else { + // + // Consider it as failure + // + this.completeOperation(this.attempts, FAILED_MSG, PolicyResult.FAILURE); + if (PolicyResult.FAILURE_TIMEOUT.equals(this.policyResult)) { + return null; + } + // increment operation attempts for retries + this.attempts += 1; + return PolicyResult.FAILURE; + } + } + private PolicyResult getTimeoutResult(PolicyResult result) { return (PolicyResult.FAILURE_TIMEOUT.equals(this.policyResult) ? null : result); } diff --git a/controlloop/common/eventmanager/src/test/java/org/onap/policy/controlloop/eventmanager/ControlLoopOperationManagerTest.java b/controlloop/common/eventmanager/src/test/java/org/onap/policy/controlloop/eventmanager/ControlLoopOperationManagerTest.java index 9b1633521..914eb7664 100644 --- a/controlloop/common/eventmanager/src/test/java/org/onap/policy/controlloop/eventmanager/ControlLoopOperationManagerTest.java +++ b/controlloop/common/eventmanager/src/test/java/org/onap/policy/controlloop/eventmanager/ControlLoopOperationManagerTest.java @@ -3,6 +3,7 @@ * unit test * ================================================================================ * Copyright (C) 2017-2019 AT&T Intellectual Property. All rights reserved. + * Modifications Copyright (C) 2019 Bell Canada. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -43,6 +44,7 @@ import org.apache.commons.io.IOUtils; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; +import org.onap.ccsdk.cds.controllerblueprints.processing.api.ExecutionServiceInput; import org.onap.policy.aai.util.AaiException; import org.onap.policy.appc.CommonHeader; import org.onap.policy.appc.Response; @@ -79,6 +81,7 @@ import org.slf4j.LoggerFactory; public class ControlLoopOperationManagerTest { private static final String VSERVER_NAME = "vserver.vserver-name"; private static final String TEST_YAML = "src/test/resources/test.yaml"; + private static final String TEST_CDS_YAML = "src/test/resources/test-cds.yaml"; private static final String ONSET_ONE = "onsetOne"; private static final String VNF_NAME = "generic-vnf.vnf-name"; private static final String VNF_ID = "generic-vnf.vnf-id"; @@ -746,6 +749,46 @@ public class ControlLoopOperationManagerTest { } @Test + public void testStartCdsOperation() throws ControlLoopException, IOException { + + // Prepare + String yamlString; + try (InputStream is = new FileInputStream(new File(TEST_CDS_YAML))) { + yamlString = IOUtils.toString(is, StandardCharsets.UTF_8); + } + + UUID requestId = UUID.randomUUID(); + VirtualControlLoopEvent event = new VirtualControlLoopEvent(); + event.setClosedLoopControlName(TWO_ONSET_TEST); + event.setRequestId(requestId); + event.setTarget(VNF_ID); + event.setClosedLoopAlarmStart(Instant.now()); + event.setClosedLoopEventStatus(ControlLoopEventStatus.ONSET); + event.setAai(new HashMap<>()); + event.getAai().put(VNF_NAME, ONSET_ONE); + event.getAai().put(VSERVER_NAME, "OzVServer"); + + ControlLoopEventManager eventManager = + new ControlLoopEventManager(event.getClosedLoopControlName(), event.getRequestId()); + VirtualControlLoopNotification notification = eventManager.activate(yamlString, event); + assertNotNull(notification); + assertEquals(ControlLoopNotificationType.ACTIVE, notification.getNotification()); + + Policy policy = eventManager.getProcessor().getCurrentPolicy(); + ControlLoopOperationManager operationManager = new ControlLoopOperationManager(event, policy, eventManager); + + // Run + Object result = operationManager.startOperation(event); + + // Verify + assertNotNull(result); + assertTrue(result instanceof ExecutionServiceInput); + ExecutionServiceInput request = (ExecutionServiceInput) result; + logger.debug("request: " + request); + + } + + @Test public void testCommitAbatement() throws Exception { String yamlString = null; diff --git a/controlloop/common/eventmanager/src/test/resources/test-cds.yaml b/controlloop/common/eventmanager/src/test/resources/test-cds.yaml new file mode 100644 index 000000000..332c724b2 --- /dev/null +++ b/controlloop/common/eventmanager/src/test/resources/test-cds.yaml @@ -0,0 +1,46 @@ +# Copyright (C) 2019 Bell Canada. +# +# 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. +controlLoop: + version: 2.0.0 + controlLoopName: ControlLoop-vFirewall-d0a1dfc6-94f5-4fd4-a5b5-4630b438850a + services: + - serviceInvariantUUID: 5cfe6f4a-41bc-4247-8674-ebd4b98e35cc + serviceUUID: 0f40bba5-986e-4b3c-803f-ddd1b7b25f24 + serviceName: 57e66ea7-0ed6-45c7-970f + trigger_policy: unique-policy-id-1-modifyConfig + timeout: 60 + abatement: true + +policies: + - id: unique-policy-id-1-modifyConfig + name: modify packet gen config + description: + actor: CDS + recipe: ModifyConfig + target: + resourceID: bbb3cefd-01c8-413c-9bdd-2b92f9ca3d38 + type: VNF + payload: + artifact_name: vfw-cds + artifact_version: 1.0.0 + mode: async + data: '{"mapInfo":{"key":"val"},"arrayInfo":["one","two"],"paramInfo":"val"}' + retry: 0 + timeout: 30 + success: final_success + failure: final_failure + failure_timeout: final_failure_timeout + failure_retries: final_failure_retries + failure_exception: final_failure_exception + failure_guard: final_failure_guard
\ No newline at end of file diff --git a/controlloop/common/feature-controlloop-management/pom.xml b/controlloop/common/feature-controlloop-management/pom.xml index bf43f20dc..24f7a1792 100644 --- a/controlloop/common/feature-controlloop-management/pom.xml +++ b/controlloop/common/feature-controlloop-management/pom.xml @@ -245,6 +245,17 @@ </exclusions> </dependency> <dependency> + <groupId>org.onap.policy.models.policy-models-interactions.model-actors</groupId> + <artifactId>actor.cds</artifactId> + <version>${policy.models.version}</version> + <exclusions> + <exclusion> + <artifactId>guava</artifactId> + <groupId>com.google.guava</groupId> + </exclusion> + </exclusions> + </dependency> + <dependency> <groupId>org.onap.policy.models.policy-models-interactions</groupId> <artifactId>model-yaml</artifactId> <version>${policy.models.version}</version> @@ -266,6 +277,11 @@ <scope>provided</scope> </dependency> <dependency> + <groupId>org.onap.policy.models.policy-models-interactions.model-impl</groupId> + <artifactId>cds</artifactId> + <version>${policy.models.version}</version> + </dependency> + <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <scope>test</scope> diff --git a/controlloop/common/feature-controlloop-management/src/main/feature/config/controlloop.properties.environment b/controlloop/common/feature-controlloop-management/src/main/feature/config/controlloop.properties.environment index 84bef12f9..4a0916895 100644 --- a/controlloop/common/feature-controlloop-management/src/main/feature/config/controlloop.properties.environment +++ b/controlloop/common/feature-controlloop-management/src/main/feature/config/controlloop.properties.environment @@ -3,6 +3,7 @@ # ONAP # ================================================================================ # Copyright (C) 2017-2019 AT&T Intellectual Property. All rights reserved. +# Modifications Copyright (C) 2019 Bell Canada. # ================================================================================ # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -51,3 +52,9 @@ sdnc.username=${env:SDNC_USERNAME} sdnc.password=${env:SDNC_PASSWORD} aai.customQuery=true + +cds.grpcHost=${env:CDS_GRPC_HOST} +cds.grpcPort=${env:CDS_GRPC_PORT} +cds.grpcUsername=${env:CDS_GRPC_USERNAME} +cds.grpcPassword=${env:CDS_GRPC_PASSWORD} +cds.grpcTimeout=10 diff --git a/controlloop/common/feature-controlloop-utils/src/main/java/org/onap/policy/drools/apps/controlloop/feature/utils/ControlLoopUtilsFeature.java b/controlloop/common/feature-controlloop-utils/src/main/java/org/onap/policy/drools/apps/controlloop/feature/utils/ControlLoopUtilsFeature.java index 2cf643096..c2e78029b 100644 --- a/controlloop/common/feature-controlloop-utils/src/main/java/org/onap/policy/drools/apps/controlloop/feature/utils/ControlLoopUtilsFeature.java +++ b/controlloop/common/feature-controlloop-utils/src/main/java/org/onap/policy/drools/apps/controlloop/feature/utils/ControlLoopUtilsFeature.java @@ -47,9 +47,6 @@ public class ControlLoopUtilsFeature implements PolicyEngineFeatureApi { } catch (final InterruptedException e) { logger.error("{}: initialization aborted", ControlLoopUtilsFeature.class.getName(), e); Thread.currentThread().interrupt(); - } catch (final IOException e) { - logger.error("{}: a simulator cannot be built because of {}", ControlLoopUtilsFeature.class.getName(), - e.getMessage(), e); } return false; } diff --git a/controlloop/pom.xml b/controlloop/pom.xml index 377c9f6be..dff61c171 100644 --- a/controlloop/pom.xml +++ b/controlloop/pom.xml @@ -31,6 +31,21 @@ <groupId>org.onap.policy.drools-applications.controlloop</groupId> <artifactId>controlloop</artifactId> + <properties> + <ccsdk.version>0.4.4</ccsdk.version> + </properties> + + <dependencyManagement> + <dependencies> + <dependency> + <groupId>org.onap.ccsdk.cds.components</groupId> + <artifactId>proto-definition</artifactId> + <version>${ccsdk.version}</version> + </dependency> + </dependencies> + </dependencyManagement> + + <modules> <module>common</module> <module>templates</module> diff --git a/controlloop/templates/archetype-cl-amsterdam/src/main/resources/archetype-resources/src/main/resources/__closedLoopControlName__.drl b/controlloop/templates/archetype-cl-amsterdam/src/main/resources/archetype-resources/src/main/resources/__closedLoopControlName__.drl index 57ebd7089..4cbdd49e5 100644 --- a/controlloop/templates/archetype-cl-amsterdam/src/main/resources/archetype-resources/src/main/resources/__closedLoopControlName__.drl +++ b/controlloop/templates/archetype-cl-amsterdam/src/main/resources/archetype-resources/src/main/resources/__closedLoopControlName__.drl @@ -3,6 +3,7 @@ * ONAP * ================================================================================ * Copyright (C) 2017-2019 AT&T Intellectual Property. All rights reserved. + * Modifications Copyright (C) 2019 Bell Canada. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,6 +21,8 @@ package org.onap.policy.controlloop; +import org.onap.ccsdk.cds.controllerblueprints.processing.api.ExecutionServiceInput; + import org.onap.policy.controlloop.VirtualControlLoopEvent; import org.onap.policy.controlloop.VirtualControlLoopNotification; import org.onap.policy.controlloop.ControlLoopEventStatus; @@ -32,6 +35,9 @@ import org.onap.policy.controlloop.eventmanager.ControlLoopEventManager; import org.onap.policy.controlloop.eventmanager.ControlLoopEventManager.NewEventStatus; import org.onap.policy.controlloop.eventmanager.ControlLoopOperationManager; import org.onap.policy.controlloop.actor.so.SoActorServiceProvider; +import org.onap.policy.controlloop.actor.cds.CdsActorServiceProvider; +import org.onap.policy.controlloop.actor.cds.CdsActorServiceProvider.CdsActorServiceManager; +import org.onap.policy.controlloop.actor.cds.constants.CdsActorConstants; import org.onap.policy.aai.AaiNqResponseWrapper; import org.onap.policy.aai.AaiCqResponse; import org.onap.policy.appc.Request; @@ -42,6 +48,9 @@ import org.onap.policy.appclcm.LcmResponseWrapper; import org.onap.policy.appclcm.LcmRequest; import org.onap.policy.appclcm.LcmResponse; import org.onap.policy.appclcm.LcmCommonHeader; +import org.onap.policy.cds.CdsResponse; +import org.onap.policy.cds.client.CdsProcessorGrpcClient; +import org.onap.policy.cds.properties.CdsServerProperties; import org.onap.policy.sdnr.PciRequestWrapper; import org.onap.policy.sdnr.PciResponseWrapper; import org.onap.policy.sdnr.PciRequest; @@ -636,6 +645,34 @@ rule "${policyName}.EVENT.MANAGER.OPERATION.LOCKED.GUARD_PERMITTED" PolicyEngineConstants.getManager().deliver("SDNR-CL", request); } break; + + case "CDS": + + if(request instanceof ExecutionServiceInput) { + + // Instantiate cds actor, service manager and grpc properties + + CdsActorServiceProvider cdsActor = new CdsActorServiceProvider(); + CdsActorServiceProvider.CdsActorServiceManager cdsActorServiceManager = cdsActor.new CdsActorServiceManager(); + + CdsServerProperties props = new CdsServerProperties(); + props.setHost(PolicyEngineConstants.getManager().getEnvironmentProperty("cds.grpcHost")); + props.setPort(Integer.parseInt(PolicyEngineConstants.getManager().getEnvironmentProperty("cds.grpcPort"))); + props.setUsername(PolicyEngineConstants.getManager().getEnvironmentProperty("cds.grpcUsername")); + props.setPassword(PolicyEngineConstants.getManager().getEnvironmentProperty("cds.grpcPassword")); + props.setTimeout(Integer.parseInt(PolicyEngineConstants.getManager().getEnvironmentProperty("cds.grpcTimeout"))); + + // Send cds grpc request + try (CdsProcessorGrpcClient client = new CdsProcessorGrpcClient(cdsActorServiceManager, props)) { + CdsResponse response = + cdsActorServiceManager.sendRequestToCds(client, props, (ExecutionServiceInput) request); + logger.info("CDS response: {}", response); + insert(response); + } + + } + break; + } } else { // @@ -1429,6 +1466,86 @@ rule "${policyName}.SDNC.RESPONSE" end + +/** + * This rule responds to CDS Response Events + */ +rule "${policyName}.CDS.RESPONSE" + when + $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" ) + $event : VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName(), + closedLoopEventStatus == ControlLoopEventStatus.ONSET ) + $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(), + requestId == $event.getRequestId() ) + $operation : ControlLoopOperationManager( onset.closedLoopControlName == $event.getClosedLoopControlName(), + onset.getRequestId() == $event.getRequestId() ) + $opTimer : ControlLoopTimer( closedLoopControlName == $event.getClosedLoopControlName(), + requestId == $event.getRequestId().toString(), timerType == "Operation", !expired ) + $lock : TargetLock (requestId == $event.getRequestId()) + $response : CdsResponse( requestId == $event.getRequestId().toString() ) + + then + + Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage()); + logger.info("{}: {}", $params.getClosedLoopControlName(), drools.getRule().getName()); + logger.debug("{}: {}: event={} manager={} operation={} lock={} opTimer={} response={}", + $params.getClosedLoopControlName(), drools.getRule().getName(), + $event, $manager, $operation, $lock, $operation, $opTimer, $response); + + // Get the result of the operation + PolicyResult policyResult = $operation.onResponse($response); + + if (policyResult != null) { + logger.debug("{}: {}: operation finished - result={}", + $params.getClosedLoopControlName(), drools.getRule().getName(), + policyResult); + + // The operation has completed, construct a notification showing our results + VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event); + notification.setFrom("policy"); + notification.setPolicyName(drools.getRule().getName()); + notification.setPolicyScope("${policyScope}"); + notification.setPolicyVersion("${policyVersion}"); + notification.setMessage($operation.getOperationHistory()); + notification.setHistory($operation.getHistory()); + notification.setNotification( + ($response != null && CdsActorConstants.SUCCESS.equals($response.getStatus())) + ? ControlLoopNotificationType.OPERATION_SUCCESS : ControlLoopNotificationType.OPERATION_FAILURE); + + // Send the notification + PolicyEngineConstants.getManager().deliver("POLICY-CL-MGT", notification); + + // Ensure the operation is complete + if ($operation.isOperationComplete()) { + + // It is complete, remove it from memory + retract($operation); + + // We must also retract the timer object + // NOTE: We could write a Rule to do this + retract($opTimer); + + // Complete the operation + modify($manager) {finishOperation($operation)}; + + } else { + // Just doing this will kick off the LOCKED rule again + modify($operation) {}; + } + } else { + // Its not finished yet (i.e. expecting more Response objects) + // Or possibly it is a leftover response that we timed the request out previously + logger.info( + "policyResult is null" + + "\nIt's not finished yet (i.e. expecting more Response objects)" + + "\nOr possibly it is a leftover response that we timed the request out previously"); + } + + // We are going to retract these objects from memory + retract($response); + +end + /* * * This manages a single timer. diff --git a/controlloop/templates/template.demo/pom.xml b/controlloop/templates/template.demo/pom.xml index 548bb76b3..57edba6f0 100644 --- a/controlloop/templates/template.demo/pom.xml +++ b/controlloop/templates/template.demo/pom.xml @@ -4,6 +4,7 @@ ================================================================================ Copyright (C) 2017-2019 AT&T Intellectual Property. All rights reserved. Modifications Copyright (C) 2019 Nordix Foundation. + Modifications Copyright (C) 2019 Bell Canada. ================================================================================ Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -30,6 +31,11 @@ <artifactId>template.demo</artifactId> + <properties> + <protobuf.version>3.6.1</protobuf.version> + <grpc.version>1.17.1</grpc.version> + </properties> + <dependencies> <dependency> <groupId>org.eclipse.persistence</groupId> @@ -185,6 +191,28 @@ <scope>provided</scope> </dependency> <dependency> + <groupId>org.onap.policy.models.policy-models-interactions.model-actors</groupId> + <artifactId>actor.cds</artifactId> + <version>${policy.models.version}</version> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>org.onap.ccsdk.cds.components</groupId> + <artifactId>proto-definition</artifactId> + </dependency> + <dependency> + <groupId>org.onap.policy.models.policy-models-interactions.model-impl</groupId> + <artifactId>cds</artifactId> + <version>${policy.models.version}</version> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>com.google.protobuf</groupId> + <artifactId>protobuf-java</artifactId> + <version>${protobuf.version}</version> + <scope>provided</scope> + </dependency> + <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <scope>test</scope> @@ -207,6 +235,12 @@ <scope>test</scope> </dependency> <dependency> + <groupId>io.grpc</groupId> + <artifactId>grpc-testing</artifactId> + <version>${grpc.version}</version> + <scope>test</scope> + </dependency> + <dependency> <groupId>org.onap.policy.drools-pdp</groupId> <artifactId>policy-management</artifactId> <version>${version.policy.drools-pdp}</version> diff --git a/controlloop/templates/template.demo/src/test/java/org/onap/policy/template/demo/ControlLoopBase.java b/controlloop/templates/template.demo/src/test/java/org/onap/policy/template/demo/ControlLoopBase.java index ab6ec5a3a..5817dc930 100644 --- a/controlloop/templates/template.demo/src/test/java/org/onap/policy/template/demo/ControlLoopBase.java +++ b/controlloop/templates/template.demo/src/test/java/org/onap/policy/template/demo/ControlLoopBase.java @@ -3,6 +3,7 @@ * demo * ================================================================================ * Copyright (C) 2019 AT&T Intellectual Property. All rights reserved. + * Modifications Copyright (C) 2019 Bell Canada. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -84,6 +85,7 @@ public class ControlLoopBase { SupportUtil.setSoProps(); SupportUtil.setVfcProps(); SupportUtil.setPuProp(); + SupportUtil.setCdsProps(); LoggerUtil.setLevel(LoggerUtil.ROOT_LOGGER, "INFO"); diff --git a/controlloop/templates/template.demo/src/test/java/org/onap/policy/template/demo/ControlLoopFailureTest.java b/controlloop/templates/template.demo/src/test/java/org/onap/policy/template/demo/ControlLoopFailureTest.java index bc5a9828b..0793b8825 100644 --- a/controlloop/templates/template.demo/src/test/java/org/onap/policy/template/demo/ControlLoopFailureTest.java +++ b/controlloop/templates/template.demo/src/test/java/org/onap/policy/template/demo/ControlLoopFailureTest.java @@ -252,6 +252,7 @@ public class ControlLoopFailureTest extends ControlLoopBase implements TopicList event.setClosedLoopAlarmStart(Instant.now()); event.setAai(new HashMap<>()); event.getAai().put("generic-vnf.vnf-id", target); + event.getAai().put("vserver.vserver-name", "OzVServer"); event.setClosedLoopEventStatus(status); kieSession.insert(event); } diff --git a/controlloop/templates/template.demo/src/test/java/org/onap/policy/template/demo/SupportUtil.java b/controlloop/templates/template.demo/src/test/java/org/onap/policy/template/demo/SupportUtil.java index ab57fdf86..878f94be1 100644 --- a/controlloop/templates/template.demo/src/test/java/org/onap/policy/template/demo/SupportUtil.java +++ b/controlloop/templates/template.demo/src/test/java/org/onap/policy/template/demo/SupportUtil.java @@ -3,6 +3,7 @@ * demo * ================================================================================ * Copyright (C) 2017-2019 AT&T Intellectual Property. All rights reserved. + * Modifications Copyright (C) 2019 Bell Canada. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -44,6 +45,7 @@ import org.kie.api.builder.Results; import org.kie.api.runtime.KieContainer; import org.kie.api.runtime.KieSession; import org.onap.policy.common.endpoints.http.server.HttpServletServer; +import org.onap.policy.common.utils.network.NetworkUtil; import org.onap.policy.controlloop.policy.ControlLoopPolicy; import org.onap.policy.controlloop.policy.guard.ControlLoopGuard; import org.onap.policy.drools.system.PolicyEngineConstants; @@ -58,6 +60,16 @@ public final class SupportUtil { private static final String OPSHISTPUPROP = "OperationsHistoryPU"; private static final Logger logger = LoggerFactory.getLogger(SupportUtil.class); + static final int GRPC_SERVER_PORT; + + static { + try { + GRPC_SERVER_PORT = NetworkUtil.allocPort(); + } catch (IOException e) { + throw new RuntimeException("Socket cannot be created for grpc server port", e); + } + } + public static class Pair<A, B> { public final A first; public final B second; @@ -370,6 +382,17 @@ public final class SupportUtil { } /** + * Set cds properties. + */ + public static void setCdsProps() { + PolicyEngineConstants.getManager().setEnvironmentProperty("cds.grpcHost", "localhost"); + PolicyEngineConstants.getManager().setEnvironmentProperty("cds.grpcPort", Integer.toString(GRPC_SERVER_PORT)); + PolicyEngineConstants.getManager().setEnvironmentProperty("cds.grpcUsername", "grpc-username"); + PolicyEngineConstants.getManager().setEnvironmentProperty("cds.grpcPassword", "grpc-password"); + PolicyEngineConstants.getManager().setEnvironmentProperty("cds.grpcTimeout", "5"); + } + + /** * Rule specification. */ public static class RuleSpec { diff --git a/controlloop/templates/template.demo/src/test/java/org/onap/policy/template/demo/VcpeControlLoopTest.java b/controlloop/templates/template.demo/src/test/java/org/onap/policy/template/demo/VcpeControlLoopTest.java index 1cd431f50..25bef2ebb 100644 --- a/controlloop/templates/template.demo/src/test/java/org/onap/policy/template/demo/VcpeControlLoopTest.java +++ b/controlloop/templates/template.demo/src/test/java/org/onap/policy/template/demo/VcpeControlLoopTest.java @@ -58,6 +58,7 @@ public class VcpeControlLoopTest extends ControlLoopBase implements TopicListene "service=ServiceDemo;resource=Res1Demo;type=operational", "CL_vCPE", "org.onap.closed_loop.ServiceDemo:VNFS:1.0.0"); + SupportUtil.setCustomQuery("false"); } @Test @@ -122,7 +123,6 @@ public class VcpeControlLoopTest extends ControlLoopBase implements TopicListene */ sendEvent(pair.first, requestId, ControlLoopEventStatus.ONSET, "getFail", false); - kieSession.fireUntilHalt(); // allow object clean-up diff --git a/controlloop/templates/template.demo/src/test/java/org/onap/policy/template/demo/VfwControlLoopCdsTest.java b/controlloop/templates/template.demo/src/test/java/org/onap/policy/template/demo/VfwControlLoopCdsTest.java new file mode 100644 index 000000000..435faf25d --- /dev/null +++ b/controlloop/templates/template.demo/src/test/java/org/onap/policy/template/demo/VfwControlLoopCdsTest.java @@ -0,0 +1,266 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2019 Bell Canada. + * ================================================================================ + * 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.template.demo; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import io.grpc.Server; +import io.grpc.ServerBuilder; +import io.grpc.stub.StreamObserver; + +import java.io.IOException; +import java.time.Instant; +import java.util.HashMap; +import java.util.UUID; +import java.util.concurrent.atomic.AtomicReference; + +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.onap.ccsdk.cds.controllerblueprints.common.api.CommonHeader; +import org.onap.ccsdk.cds.controllerblueprints.common.api.EventType; +import org.onap.ccsdk.cds.controllerblueprints.common.api.Status; +import org.onap.ccsdk.cds.controllerblueprints.processing.api.BluePrintProcessingServiceGrpc; +import org.onap.ccsdk.cds.controllerblueprints.processing.api.ExecutionServiceInput; +import org.onap.ccsdk.cds.controllerblueprints.processing.api.ExecutionServiceOutput; +import org.onap.policy.common.endpoints.event.comm.Topic.CommInfrastructure; +import org.onap.policy.common.endpoints.event.comm.TopicListener; +import org.onap.policy.common.endpoints.event.comm.TopicSink; +import org.onap.policy.controlloop.ControlLoopEventStatus; +import org.onap.policy.controlloop.ControlLoopNotificationType; +import org.onap.policy.controlloop.VirtualControlLoopEvent; +import org.onap.policy.controlloop.VirtualControlLoopNotification; +import org.onap.policy.controlloop.policy.ControlLoopPolicy; +import org.onap.policy.controlloop.util.Serialization; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Test class for vfirewall use case using CDS actor. + */ +public class VfwControlLoopCdsTest extends ControlLoopBase implements TopicListener { + + private static final Logger LOGGER = LoggerFactory.getLogger(VfwControlLoopCdsTest.class); + + private final AtomicReference<StreamObserver<ExecutionServiceOutput>> responseObserverRef = new AtomicReference<>(); + private Server server; + + /** + * Setup the simulator. + */ + @BeforeClass + public static void setUpBeforeClass() { + ControlLoopBase.setUpBeforeClass("../archetype-cl-amsterdam/src/main/resources/archetype-resources/src/" + + "main/resources/__closedLoopControlName__.drl", + "src/test/resources/yaml/policy_ControlLoop_vFW_CDS.yaml", + "service=ServiceDemo;resource=Res1Demo;type=operational", "CL_vFW", + "org.onap.closed_loop.ServiceDemo:VNFS:1.0.0"); + SupportUtil.setCustomQuery("true"); + } + + @Before + public void setUp() throws IOException { + this.startGrpcServer(); + } + + @After + public void tearDown() { + this.stopGrpcServer(); + } + + private void startGrpcServer() throws IOException { + + BluePrintProcessingServiceGrpc.BluePrintProcessingServiceImplBase cdsBlueprintServerImpl = + + new BluePrintProcessingServiceGrpc.BluePrintProcessingServiceImplBase() { + + @Override + public StreamObserver<ExecutionServiceInput> process( + final StreamObserver<ExecutionServiceOutput> responseObserver) { + + responseObserverRef.set(responseObserver); + + return new StreamObserver<ExecutionServiceInput>() { + @Override + public void onNext(final ExecutionServiceInput input) { + LOGGER.info("gRPC server onNext() for input: {} ...", input); + ExecutionServiceOutput output = + ExecutionServiceOutput.newBuilder() + .setCommonHeader( + CommonHeader.newBuilder().setRequestId( + input.getCommonHeader().getRequestId()).build()) + .setStatus( + Status.newBuilder().setEventType( + EventType.EVENT_COMPONENT_EXECUTED).build()) + .build(); + responseObserver.onNext(output); + } + + @Override + public void onError(final Throwable throwable) { + LOGGER.error("gRPC server onError() for throwable: {} ...", throwable); + } + + @Override + public void onCompleted() { + LOGGER.info("gRPC server onCompleted() ..."); + responseObserver.onCompleted(); + } + }; + } + }; + + server = ServerBuilder.forPort(SupportUtil.GRPC_SERVER_PORT).addService(cdsBlueprintServerImpl).build().start(); + LOGGER.info("gRPC server is listening for CDS requests on port {}", SupportUtil.GRPC_SERVER_PORT); + + } + + private void stopGrpcServer() { + if (server != null) { + this.server.shutdown(); + LOGGER.info("gRPC server handling CDS requests has been successfully shut down."); + } + } + + @Test + public void successTest() { + + /* + * Allows the PolicyEngine to callback to this object to notify that there is an event ready + * to be pulled from the queue + */ + for (TopicSink sink : noopTopics) { + assertTrue(sink.start()); + sink.register(this); + } + + /* + * Create a unique requestId + */ + requestId = UUID.randomUUID(); + + /* + * Simulate an onset event the policy engine will receive from DCAE to kick off processing + * through the rules + */ + sendEvent(pair.first, requestId, ControlLoopEventStatus.ONSET); + + kieSession.fireUntilHalt(); + kieSession.fireAllRules(); + + /* + * The only fact in memory should be Params + */ + assertEquals(1, kieSession.getFactCount()); + + /* + * Print what's left in memory + */ + dumpFacts(kieSession); + } + + + /* + * @see org.onap.policy.drools.PolicyEngineListener#newEventNotification(java.lang.String) + */ + @Override + public void onTopicEvent(CommInfrastructure commType, String topic, String event) { + /* + * Pull the object that was sent out to DMAAP and make sure it is a ControlLoopNotification + * of type active + */ + assertEquals("POLICY-CL-MGT", topic); + VirtualControlLoopNotification notification = + Serialization.gsonJunit.fromJson(event, VirtualControlLoopNotification.class); + assertNotNull(notification); + String policyName = notification.getPolicyName(); + if (policyName.endsWith("EVENT")) { + logger.debug("Rule Fired: " + notification.getPolicyName()); + assertEquals(ControlLoopNotificationType.ACTIVE, notification.getNotification()); + } else if (policyName.endsWith("GUARD_NOT_YET_QUERIED")) { + logger.debug("Rule Fired: " + notification.getPolicyName()); + assertEquals(ControlLoopNotificationType.OPERATION, notification.getNotification()); + assertNotNull(notification.getMessage()); + assertTrue(notification.getMessage().startsWith("Sending guard query")); + } else if (policyName.endsWith("GUARD.RESPONSE")) { + logger.debug("Rule Fired: " + notification.getPolicyName()); + assertEquals(ControlLoopNotificationType.OPERATION, notification.getNotification()); + assertNotNull(notification.getMessage()); + assertTrue(notification.getMessage().toLowerCase().endsWith("permit")); + } else if (policyName.endsWith("GUARD_PERMITTED")) { + logger.debug("Rule Fired: " + notification.getPolicyName()); + assertEquals(ControlLoopNotificationType.OPERATION, notification.getNotification()); + assertNotNull(notification.getMessage()); + assertTrue(notification.getMessage().startsWith("actor=CDS")); + } else if (policyName.endsWith("OPERATION.TIMEOUT")) { + logger.debug("Rule Fired: " + notification.getPolicyName()); + kieSession.halt(); + logger.debug("The operation timed out"); + fail("Operation Timed Out"); + } else if (policyName.endsWith("CDS.RESPONSE")) { + logger.debug("Rule Fired: " + notification.getPolicyName()); + assertEquals(ControlLoopNotificationType.OPERATION_SUCCESS, notification.getNotification()); + assertNotNull(notification.getMessage()); + assertTrue(notification.getMessage().startsWith("actor=CDS")); + sendEvent(pair.first, requestId, ControlLoopEventStatus.ABATED); + } else if (policyName.endsWith("EVENT.MANAGER")) { + logger.debug("Rule Fired: " + notification.getPolicyName()); + if ("error".equals(notification.getAai().get("generic-vnf.vnf-name"))) { + assertEquals(ControlLoopNotificationType.FINAL_FAILURE, notification.getNotification()); + assertEquals("Target vnf-id could not be found", notification.getMessage()); + } else if ("getFail".equals(notification.getAai().get("generic-vnf.vnf-name"))) { + assertEquals(ControlLoopNotificationType.FINAL_FAILURE, notification.getNotification()); + } else { + assertEquals(ControlLoopNotificationType.FINAL_SUCCESS, notification.getNotification()); + } + kieSession.halt(); + } else if (policyName.endsWith("EVENT.MANAGER.TIMEOUT")) { + logger.debug("Rule Fired: " + notification.getPolicyName()); + kieSession.halt(); + logger.debug("The control loop timed out"); + fail("Control Loop Timed Out"); + } + } + + /** + * This method is used to simulate event messages from DCAE that start the control loop (onset + * message) or end the control loop (abatement message). + * + * @param policy the controlLoopName comes from the policy + * @param requestId the requestId for this event + * @param status could be onset or abated + */ + private void sendEvent(ControlLoopPolicy policy, UUID requestId, ControlLoopEventStatus status) { + VirtualControlLoopEvent event = new VirtualControlLoopEvent(); + event.setClosedLoopControlName(policy.getControlLoop().getControlLoopName()); + event.setRequestId(requestId); + event.setTarget("generic-vnf.vnf-name"); + event.setClosedLoopAlarmStart(Instant.now()); + event.setAai(new HashMap<>()); + event.getAai().put("generic-vnf.vnf-name", "testGenericVnfID"); + event.getAai().put("vserver.vserver-name", "OzVServer"); + event.setClosedLoopEventStatus(status); + kieSession.insert(event); + } + +} diff --git a/controlloop/templates/template.demo/src/test/resources/yaml/policy_ControlLoop_vFW_CDS.yaml b/controlloop/templates/template.demo/src/test/resources/yaml/policy_ControlLoop_vFW_CDS.yaml new file mode 100644 index 000000000..511a9694b --- /dev/null +++ b/controlloop/templates/template.demo/src/test/resources/yaml/policy_ControlLoop_vFW_CDS.yaml @@ -0,0 +1,46 @@ +# Copyright (C) 2019 Bell Canada. +# +# 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. +controlLoop: + version: 2.0.0 + controlLoopName: ControlLoop-vFirewall-d0a1dfc6-94f5-4fd4-a5b5-4630b438850a + services: + - serviceInvariantUUID: 5cfe6f4a-41bc-4247-8674-ebd4b98e35cc + serviceUUID: 0f40bba5-986e-4b3c-803f-ddd1b7b25f24 + serviceName: 57e66ea7-0ed6-45c7-970f + trigger_policy: unique-policy-id-1-modifyConfig + timeout: 60 + abatement: true + +policies: + - id: unique-policy-id-1-modifyConfig + name: modify packet gen config + description: + actor: CDS + recipe: ModifyConfig + target: + resourceID: bbb3cefd-01c8-413c-9bdd-2b92f9ca3d38 + type: VNF + payload: + artifact_name: vfw-cds + artifact_version: 1.0.0 + mode: async + data: '{"mapInfo":{"key":"val"},"arrayInfo":["one","two"],"paramInfo":"val"}' + retry: 0 + timeout: 30 + success: final_success + failure: final_failure + failure_timeout: final_failure_timeout + failure_retries: final_failure_retries + failure_exception: final_failure_exception + failure_guard: final_failure_guard |