diff options
40 files changed, 3683 insertions, 101 deletions
diff --git a/controlloop/common/actors/actor.appc/pom.xml b/controlloop/common/actors/actor.appc/pom.xml index 5f6519a47..2d39ca849 100644 --- a/controlloop/common/actors/actor.appc/pom.xml +++ b/controlloop/common/actors/actor.appc/pom.xml @@ -18,15 +18,45 @@ </dependency> <dependency> <groupId>org.onap.policy.drools-applications</groupId> + <artifactId>actor.appclcm</artifactId> + <version>1.1.0-SNAPSHOT</version> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>org.onap.policy.drools-applications</groupId> + <artifactId>aai</artifactId> + <version>1.1.0-SNAPSHOT</version> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>org.onap.policy.drools-applications</groupId> <artifactId>appc</artifactId> <version>1.1.0-SNAPSHOT</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.onap.policy.drools-applications</groupId> + <artifactId>trafficgenerator</artifactId> + <version>1.1.0-SNAPSHOT</version> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>org.onap.policy.drools-applications</groupId> <artifactId>events</artifactId> <version>1.1.0-SNAPSHOT</version> <scope>provided</scope> </dependency> + <dependency> + <groupId>com.google.code.gson</groupId> + <artifactId>gson</artifactId> + <version>2.5</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <version>4.12</version> + <scope>test</scope> + </dependency> </dependencies> </project> diff --git a/controlloop/common/actors/actor.appc/src/main/java/org/onap/policy/controlloop/actor/appc/APPCActorServiceProvider.java b/controlloop/common/actors/actor.appc/src/main/java/org/onap/policy/controlloop/actor/appc/APPCActorServiceProvider.java index 7cdf99625..e7b7d2371 100644 --- a/controlloop/common/actors/actor.appc/src/main/java/org/onap/policy/controlloop/actor/appc/APPCActorServiceProvider.java +++ b/controlloop/common/actors/actor.appc/src/main/java/org/onap/policy/controlloop/actor/appc/APPCActorServiceProvider.java @@ -21,16 +21,17 @@ package org.onap.policy.controlloop.actor.appc; import java.util.Collections; -import java.util.HashMap; import java.util.List; -import java.util.Map; import org.onap.policy.controlloop.VirtualControlLoopEvent; +import org.onap.policy.controlloop.actor.appclcm.AppcLcmActorServiceProvider; import org.onap.policy.appc.CommonHeader; import org.onap.policy.appc.Request; import org.onap.policy.controlloop.ControlLoopOperation; import org.onap.policy.controlloop.policy.Policy; - +import org.onap.policy.vnf.trafficgenerator.PGRequest; +import org.onap.policy.vnf.trafficgenerator.PGStream; +import org.onap.policy.vnf.trafficgenerator.PGStreams; import org.onap.policy.controlloop.actorServiceProvider.spi.Actor; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; @@ -43,7 +44,7 @@ public class APPCActorServiceProvider implements Actor { .put("Restart", ImmutableList.of("VM")) .put("Rebuild", ImmutableList.of("VM")) .put("Migrate", ImmutableList.of("VM")) - .put("ModifyConfig", ImmutableList.of("VFC")) + .put("ModifyConfig", ImmutableList.of("VNF")) .build(); private static final ImmutableMap<String, List<String>> payloads = new ImmutableMap.Builder<String, List<String>>() .put("ModifyConfig", ImmutableList.of("generic-vnf.vnf-id")) @@ -69,43 +70,63 @@ public class APPCActorServiceProvider implements Actor { return ImmutableList.copyOf(payloads.getOrDefault(recipe, Collections.emptyList())); } - + /** + * Constructs an APPC request conforming to the legacy API. + * The legacy API will be deprecated in future releases as + * all legacy functionality is moved into the LCM API. + * + * @param onset + * the event that is reporting the alert for policy + * to perform an action + * @param operation + * the control loop operation specifying the actor, + * operation, target, etc. + * @param policy + * the policy the was specified from the yaml generated + * by CLAMP or through the Policy GUI/API + * @return an APPC request conforming to the legacy API + */ public static Request constructRequest(VirtualControlLoopEvent onset, ControlLoopOperation operation, Policy policy) { - // - // Construct an APPC request - // + /* + * Construct an APPC request + */ Request request = new Request(); request.CommonHeader = new CommonHeader(); request.CommonHeader.RequestID = onset.requestID; request.CommonHeader.SubRequestID = operation.subRequestId; request.Action = policy.getRecipe(); - // - // TODO: do we need to take care of the target - // + /* + * The target vnf-id may not be the same as the source vnf-id + * specified in the yaml, the target vnf-id is retrieved by + * a named query to A&AI. + */ + String resourceId = policy.getTarget().getResourceID(); + String sourceVnfId = onset.AAI.get("generic-vnf.vnf-id"); + String vnfId = "test"; //AppcLcmActorServiceProvider.vnfNamedQuery(resourceId, sourceVnfId); + + /* + * For now Policy generates the PG Streams as a demo, in the + * future the payload can be provided by CLAMP + */ + request.Payload.put("generic-vnf.vnf-id", vnfId); + + PGRequest pgRequest = new PGRequest(); + pgRequest.pgStreams = new PGStreams(); - // - // Handle the payload - // - if (policy.getPayload() != null && !policy.getPayload().isEmpty()) { - request.Payload = new HashMap<String, Object>(); - // - // Add each payload entry - // - for (Map.Entry<String, String> entry : policy.getPayload().entrySet()) { - // - // TODO: entry key has ref$, value has {xxxx} - // - request.Payload.put(entry.getKey(), entry.getValue()); - } + PGStream pgStream; + for (int i = 0; i < 5; i++) { + pgStream = new PGStream(); + pgStream.streamId = "fw_udp"+(i+1); + pgStream.isEnabled = "true"; + pgRequest.pgStreams.pgStream.add(pgStream); } + request.Payload.put("pg-streams", pgRequest.pgStreams); + /* + * Return the request + */ - request.Payload.put("AICVServerSelfLink", onset.AAI.get("vserver.selflink"));//.AICVServerSelfLink); - request.Payload.put("AICIdentity", onset.AAI.get("cloud-region.identity-url"));//AICIdentity); - // - // Return the request - // return request; } diff --git a/controlloop/common/actors/actor.appc/src/test/java/org/onap/policy/controlloop/actor/appc/AppcServiceProviderTest.java b/controlloop/common/actors/actor.appc/src/test/java/org/onap/policy/controlloop/actor/appc/AppcServiceProviderTest.java new file mode 100644 index 000000000..c8179992c --- /dev/null +++ b/controlloop/common/actors/actor.appc/src/test/java/org/onap/policy/controlloop/actor/appc/AppcServiceProviderTest.java @@ -0,0 +1,124 @@ +/*- + * ============LICENSE_START======================================================= + * AppcServiceProviderTest + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.controlloop.actor.appc; + +import static org.junit.Assert.*; + +import java.time.Instant; +import java.util.HashMap; +import java.util.UUID; + +import org.junit.Test; +import org.onap.policy.appc.Request; +import org.onap.policy.appc.util.Serialization; +import org.onap.policy.controlloop.ControlLoopEventStatus; +import org.onap.policy.controlloop.ControlLoopOperation; +import org.onap.policy.controlloop.ControlLoopTargetType; +import org.onap.policy.controlloop.VirtualControlLoopEvent; +import org.onap.policy.controlloop.policy.Policy; +import org.onap.policy.controlloop.policy.Target; +import org.onap.policy.controlloop.policy.TargetType; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class AppcServiceProviderTest { + + private static final Logger logger = LoggerFactory.getLogger(AppcServiceProviderTest.class); + + private static VirtualControlLoopEvent onsetEvent; + private static ControlLoopOperation operation; + private static Policy policy; + + static { + /* + * Construct an onset with an AAI subtag containing + * generic-vnf.vnf-id and a target type of VM. + */ + onsetEvent = new VirtualControlLoopEvent(); + onsetEvent.closedLoopControlName = "closedLoopControlName-Test"; + onsetEvent.requestID = UUID.randomUUID(); + onsetEvent.closedLoopEventClient = "tca.instance00001"; + onsetEvent.target_type = ControlLoopTargetType.VF; + onsetEvent.target = "generic-vnf.vnf-id"; + onsetEvent.from = "DCAE"; + onsetEvent.closedLoopAlarmStart = Instant.now(); + onsetEvent.AAI = new HashMap<>(); + onsetEvent.AAI.put("generic-vnf.vnf-id", "fw0001vm001fw001"); + onsetEvent.closedLoopEventStatus = ControlLoopEventStatus.ONSET; + + /* Construct an operation with an APPC actor and ModifyConfig operation. */ + operation = new ControlLoopOperation(); + operation.actor = "APPC"; + operation.operation = "ModifyConfig"; + operation.target = "VM"; + operation.end = Instant.now(); + operation.subRequestId = "1"; + + /* Construct a policy specifying to modify configuration. */ + policy = new Policy(); + policy.setName("Modify Packet Generation Config"); + policy.setDescription("Upon getting the trigger event, modify packet gen config"); + policy.setActor("APPC"); + policy.setTarget(new Target(TargetType.VM)); + policy.setRecipe("ModifyConfig"); + policy.setPayload(null); + policy.setRetry(2); + policy.setTimeout(300); + + } + + @Test + public void constructModifyConfigRequestTest() { + + Request appcRequest = APPCActorServiceProvider.constructRequest(onsetEvent, operation, policy); + + /* The service provider must return a non null APPC request */ + assertNotNull(appcRequest); + + /* A common header is required and cannot be null */ + assertNotNull(appcRequest.getCommonHeader()); + assertEquals(appcRequest.getCommonHeader().RequestID, onsetEvent.requestID); + + /* An action is required and cannot be null */ + assertNotNull(appcRequest.Action); + assertEquals(appcRequest.Action, "ModifyConfig"); + + /* A payload is required and cannot be null */ + assertNotNull(appcRequest.getPayload()); + assertTrue(appcRequest.getPayload().containsKey("generic-vnf.vnf-id")); + assertTrue(appcRequest.getPayload().containsKey("pg-streams")); + + logger.debug("APPC Request: \n" + appcRequest.toString()); + + /* Print out request as json to make sure serialization works */ + String jsonRequest = Serialization.gsonPretty.toJson(appcRequest); + logger.debug("JSON Output: \n" + jsonRequest); + + /* The JSON string must contain the following fields */ + assertTrue(jsonRequest.contains("CommonHeader")); + assertTrue(jsonRequest.contains("Action")); + assertTrue(jsonRequest.contains("ModifyConfig")); + assertTrue(jsonRequest.contains("Payload")); + assertTrue(jsonRequest.contains("generic-vnf.vnf-id")); + assertTrue(jsonRequest.contains("pg-streams")); + } + +} diff --git a/controlloop/common/actors/actor.appclcm/pom.xml b/controlloop/common/actors/actor.appclcm/pom.xml new file mode 100644 index 000000000..6aa5f6439 --- /dev/null +++ b/controlloop/common/actors/actor.appclcm/pom.xml @@ -0,0 +1,50 @@ +<?xml version="1.0"?> +<project + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" + xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>org.onap.policy.drools-applications</groupId> + <artifactId>actors</artifactId> + <version>1.1.0-SNAPSHOT</version> + </parent> + <artifactId>actor.appclcm</artifactId> + <dependencies> + <dependency> + <groupId>org.onap.policy.drools-applications</groupId> + <artifactId>actorServiceProvider</artifactId> + <version>1.1.0-SNAPSHOT</version> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>org.onap.policy.drools-applications</groupId> + <artifactId>appclcm</artifactId> + <version>1.1.0-SNAPSHOT</version> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>org.onap.policy.drools-applications</groupId> + <artifactId>aai</artifactId> + <version>1.1.0-SNAPSHOT</version> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>com.google.code.gson</groupId> + <artifactId>gson</artifactId> + <version>2.5</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.onap.policy.drools-applications</groupId> + <artifactId>events</artifactId> + <version>1.1.0-SNAPSHOT</version> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <version>4.12</version> + <scope>test</scope> + </dependency> + </dependencies> +</project> diff --git a/controlloop/common/actors/actor.appclcm/src/main/java/org/onap/policy/controlloop/actor/appclcm/AppcLcmActorServiceProvider.java b/controlloop/common/actors/actor.appclcm/src/main/java/org/onap/policy/controlloop/actor/appclcm/AppcLcmActorServiceProvider.java new file mode 100644 index 000000000..c52a7f08e --- /dev/null +++ b/controlloop/common/actors/actor.appclcm/src/main/java/org/onap/policy/controlloop/actor/appclcm/AppcLcmActorServiceProvider.java @@ -0,0 +1,293 @@ +/*- + * ============LICENSE_START======================================================= + * AppcLcmActorServiceProvider + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.controlloop.actor.appclcm; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; + +import java.util.AbstractMap; +import java.util.AbstractMap.SimpleEntry; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +import org.onap.policy.aai.AAINQF199.AAINQF199InventoryResponseItem; +import org.onap.policy.aai.AAINQF199.AAINQF199Manager; +import org.onap.policy.aai.AAINQF199.AAINQF199Request; +import org.onap.policy.aai.AAINQF199.AAINQF199Response; +import org.onap.policy.appclcm.LCMCommonHeader; +import org.onap.policy.appclcm.LCMRequest; +import org.onap.policy.appclcm.LCMRequestWrapper; +import org.onap.policy.appclcm.LCMResponse; +import org.onap.policy.appclcm.LCMResponseCode; +import org.onap.policy.appclcm.LCMResponseWrapper; +import org.onap.policy.controlloop.ControlLoopOperation; +import org.onap.policy.controlloop.VirtualControlLoopEvent; +import org.onap.policy.controlloop.actorServiceProvider.spi.Actor; +import org.onap.policy.controlloop.policy.Policy; +import org.onap.policy.controlloop.policy.PolicyResult; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class AppcLcmActorServiceProvider implements Actor { + + private static final Logger logger = LoggerFactory.getLogger(AppcLcmActorServiceProvider.class); + + /* The source vnf-id provided from the DCAE onset */ + private static final String DCAE_VNF_ID = "generic-vnf.vnf-id"; + + /* To be used in future releases to restart a single vm */ + private static final String APPC_VM_ID = "vm-id"; + + /* To be used in future releases when LCM ConfigModify is used */ + private static final String APPC_REQUEST_PARAMS = "request-parameters"; + private static final String APPC_CONFIG_PARAMS = "configuration-parameters"; + + private static final ImmutableList<String> recipes = ImmutableList.of("Restart", "Rebuild", "Migrate", + "ConfigModify"); + private static final ImmutableMap<String, List<String>> targets = new ImmutableMap.Builder<String, List<String>>() + .put("Restart", ImmutableList.of("VM")).put("Rebuild", ImmutableList.of("VM")) + .put("Migrate", ImmutableList.of("VM")).put("ConfigModify", ImmutableList.of("VNF")).build(); + private static final ImmutableMap<String, List<String>> payloads = new ImmutableMap.Builder<String, List<String>>() + .put("Restart", ImmutableList.of(APPC_VM_ID)) + .put("ConfigModify", ImmutableList.of(APPC_REQUEST_PARAMS, APPC_CONFIG_PARAMS)).build(); + + @Override + public String actor() { + return "APPC"; + } + + @Override + public List<String> recipes() { + return ImmutableList.copyOf(recipes); + } + + @Override + public List<String> recipeTargets(String recipe) { + return ImmutableList.copyOf(targets.getOrDefault(recipe, Collections.emptyList())); + } + + @Override + public List<String> recipePayloads(String recipe) { + return ImmutableList.copyOf(payloads.getOrDefault(recipe, Collections.emptyList())); + } + + /** + * Constructs an A&AI Named Query using a source vnf-id to determine + * the vnf-id of the target entity specified in the policy to act upon. + * + * @param resourceId + * the id of the target from the sdc catalog + * + * @param sourceVnfId + * the vnf id of the source entity reporting the alert + * + * @return the target entities vnf id to act upon + */ + public static String vnfNamedQuery(String resourceId, String sourceVnfId) { + String targetVnfId = ""; + AAINQF199Request aaiRequest = new AAINQF199Request(); + UUID requestId = UUID.randomUUID(); + + aaiRequest.queryParameters.namedQuery.namedQueryUUID = requestId; + + Map<String, Map<String, String>> filter = new HashMap<String, Map<String, String>>(); + + Map<String, String> filterItem = new HashMap<String, String>(); + filterItem.put("vnf-id", sourceVnfId); + + filter.put("generic-vnf", filterItem); + + aaiRequest.instanceFilters.instanceFilter.add(filter); + + //TODO: What is the url to use? + AAINQF199Response aaiResponse = AAINQF199Manager.postQuery("http://localhost:6666", "policy", "policy", aaiRequest, requestId); + + //TODO: What if the resourceId never matches? + for (AAINQF199InventoryResponseItem item: aaiResponse.inventoryResponseItems) { + if (item.genericVNF.modelInvariantId.equals(resourceId)) { + targetVnfId = item.genericVNF.vnfID; + } + } + + return targetVnfId; + } + + /** + * Constructs an APPC request conforming to the lcm API. + * The actual request is constructed and then placed in a + * wrapper object used to send through DMAAP. + * + * @param onset + * the event that is reporting the alert for policy + * to perform an action + * @param operation + * the control loop operation specifying the actor, + * operation, target, etc. + * @param policy + * the policy the was specified from the yaml generated + * by CLAMP or through the Policy GUI/API + * @return an APPC request conforming to the lcm API using the DMAAP wrapper + */ + public static LCMRequestWrapper constructRequest(VirtualControlLoopEvent onset, ControlLoopOperation operation, + Policy policy) { + + /* Construct an APPC request using LCM Model */ + + /* + * The actual LCM request is placed in a wrapper used to send + * through dmaap. The current version is 2.0 as of R1. + */ + LCMRequestWrapper dmaapRequest = new LCMRequestWrapper(); + dmaapRequest.setVersion("2.0"); + dmaapRequest.setCorrelationId(onset.requestID + "-" + operation.subRequestId); + dmaapRequest.setRpcName(policy.getRecipe().toLowerCase()); + dmaapRequest.setType("request"); + + /* This is the actual request that is placed in the dmaap wrapper. */ + LCMRequest appcRequest = new LCMRequest(); + + /* The common header is a required field for all APPC requests. */ + LCMCommonHeader requestCommonHeader = new LCMCommonHeader(); + requestCommonHeader.setOriginatorId(onset.requestID.toString()); + requestCommonHeader.setRequestId(onset.requestID); + requestCommonHeader.setSubRequestId(operation.subRequestId); + + appcRequest.setCommonHeader(requestCommonHeader); + + /* + * Action Identifiers are required for APPC LCM requests. + * For R1, the recipes supported by Policy only require + * a vnf-id. + */ + HashMap<String, String> requestActionIdentifiers = new HashMap<>(); + requestActionIdentifiers.put("vnf-id", onset.AAI.get(DCAE_VNF_ID)); + appcRequest.setActionIdentifiers(requestActionIdentifiers); + + /* + * An action is required for all APPC requests, this will + * be the recipe specified in the policy. + */ + appcRequest.setAction(policy.getRecipe().toLowerCase()); + + /* + * For R1, the payloads will not be required for the Restart, + * Rebuild, or Migrate recipes. APPC will populate the payload + * based on A&AI look up of the vnd-id provided in the action + * identifiers. + */ + if ("Restart".equalsIgnoreCase(policy.getRecipe()) || "Rebuild".equalsIgnoreCase(policy.getRecipe()) + || "Migrate".equalsIgnoreCase(policy.getRecipe())) { + appcRequest.setPayload(null); + } + + /* + * Once the LCM request is constructed, add it into the + * body of the dmaap wrapper. + */ + dmaapRequest.setBody(appcRequest); + + /* Return the request to be sent through dmaap. */ + return dmaapRequest; + } + + /** + * Parses the operation attempt using the subRequestId + * of APPC response. + * + * @param subRequestId + * the sub id used to send to APPC, Policy sets + * this using the operation attempt + * + * @return the current operation attempt + */ + public static Integer parseOperationAttempt(String subRequestId) { + Integer operationAttempt; + try { + operationAttempt = Integer.parseInt(subRequestId); + } catch (NumberFormatException e) { + logger.debug("A NumberFormatException was thrown due to error in parsing the operation attempt"); + return null; + } + return operationAttempt; + } + + /** + * Processes the APPC LCM response sent from APPC. Determines + * if the APPC operation was successful/unsuccessful and maps + * this to the corresponding Policy result. + * + * @param dmaapResponse + * the dmaap wrapper message that contains the + * actual APPC reponse inside the body field + * + * @return an key-value pair that contains the Policy result + * and APPC response message + */ + public static SimpleEntry<PolicyResult, String> processResponse(LCMResponseWrapper dmaapResponse) { + /* The actual APPC response is inside the wrapper's body field. */ + LCMResponse appcResponse = dmaapResponse.getBody(); + + /* The message returned in the APPC response. */ + String message; + + /* The Policy result determined from the APPC Response. */ + PolicyResult result; + + /* If there is no status, Policy cannot determine if the request was successful. */ + if (appcResponse.getStatus() == null) { + message = "Policy was unable to parse APP-C response status field (it was null)."; + return new AbstractMap.SimpleEntry<>(PolicyResult.FAILURE_EXCEPTION, message); + } + + /* If there is no code, Policy cannot determine if the request was successful. */ + String responseValue = LCMResponseCode.toResponseValue(appcResponse.getStatus().getCode()); + if (responseValue == null) { + message = "Policy was unable to parse APP-C response status code field."; + return new AbstractMap.SimpleEntry<>(PolicyResult.FAILURE_EXCEPTION, message); + } + + /* Save the APPC response's message for Policy noticiation message. */ + message = appcResponse.getStatus().getMessage(); + + /* Maps the APPC response result to a Policy result. */ + switch (responseValue) { + case LCMResponseCode.ACCEPTED: + /* Nothing to do if code is accept, continue processing */ + result = null; + break; + case LCMResponseCode.SUCCESS: + result = PolicyResult.SUCCESS; + break; + case LCMResponseCode.FAILURE: + result = PolicyResult.FAILURE; + break; + case LCMResponseCode.REJECT: + case LCMResponseCode.ERROR: + default: + result = PolicyResult.FAILURE_EXCEPTION; + } + return new AbstractMap.SimpleEntry<>(result, message); + } + +} diff --git a/controlloop/common/actors/actor.appclcm/src/main/resources/META-INF/services/org.onap.policy.controlloop.actorServiceProvider.spi.Actor b/controlloop/common/actors/actor.appclcm/src/main/resources/META-INF/services/org.onap.policy.controlloop.actorServiceProvider.spi.Actor new file mode 100644 index 000000000..403ad9859 --- /dev/null +++ b/controlloop/common/actors/actor.appclcm/src/main/resources/META-INF/services/org.onap.policy.controlloop.actorServiceProvider.spi.Actor @@ -0,0 +1 @@ +org.onap.policy.controlloop.actor.appclcm.AppcLcmActorServiceProvider
\ No newline at end of file diff --git a/controlloop/common/actors/actor.appclcm/src/test/java/org/onap/policy/controlloop/actor/appclcm/AppcLcmServiceProviderTest.java b/controlloop/common/actors/actor.appclcm/src/test/java/org/onap/policy/controlloop/actor/appclcm/AppcLcmServiceProviderTest.java new file mode 100644 index 000000000..f1df440a8 --- /dev/null +++ b/controlloop/common/actors/actor.appclcm/src/test/java/org/onap/policy/controlloop/actor/appclcm/AppcLcmServiceProviderTest.java @@ -0,0 +1,271 @@ +/*- + * ============LICENSE_START======================================================= + * AppcServiceProviderTest + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.controlloop.actor.appclcm; + +import static org.junit.Assert.*; + +import java.time.Instant; +import java.util.AbstractMap; +import java.util.HashMap; +import java.util.UUID; + +import org.junit.Test; +import org.onap.policy.appclcm.LCMCommonHeader; +import org.onap.policy.appclcm.LCMRequest; +import org.onap.policy.appclcm.LCMRequestWrapper; +import org.onap.policy.appclcm.LCMResponse; +import org.onap.policy.appclcm.LCMResponseWrapper; +import org.onap.policy.controlloop.ControlLoopEventStatus; +import org.onap.policy.controlloop.ControlLoopOperation; +import org.onap.policy.controlloop.ControlLoopTargetType; +import org.onap.policy.controlloop.VirtualControlLoopEvent; +import org.onap.policy.controlloop.policy.Policy; +import org.onap.policy.controlloop.policy.PolicyResult; +import org.onap.policy.controlloop.policy.Target; +import org.onap.policy.controlloop.policy.TargetType; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class AppcLcmServiceProviderTest { + + private static final Logger logger = LoggerFactory.getLogger(AppcLcmServiceProviderTest.class); + + private static VirtualControlLoopEvent onsetEvent; + private static ControlLoopOperation operation; + private static Policy policy; + private static LCMRequestWrapper dmaapRequest; + private static LCMResponseWrapper dmaapResponse; + + static { + /* + * Construct an onset with an AAI subtag containing + * generic-vnf.vnf-id and a target type of VM. + */ + onsetEvent = new VirtualControlLoopEvent(); + onsetEvent.closedLoopControlName = "closedLoopControlName-Test"; + onsetEvent.requestID = UUID.randomUUID(); + onsetEvent.closedLoopEventClient = "tca.instance00001"; + onsetEvent.target_type = ControlLoopTargetType.VM; + onsetEvent.target = "generic-vnf.vnf-id"; + onsetEvent.from = "DCAE"; + onsetEvent.closedLoopAlarmStart = Instant.now(); + onsetEvent.AAI = new HashMap<>(); + onsetEvent.AAI.put("generic-vnf.vnf-id", "fw0001vm001fw001"); + onsetEvent.closedLoopEventStatus = ControlLoopEventStatus.ONSET; + + /* Construct an operation with an APPC actor and restart operation. */ + operation = new ControlLoopOperation(); + operation.actor = "APPC"; + operation.operation = "Restart"; + operation.target = "VM"; + operation.end = Instant.now(); + operation.subRequestId = "1"; + + /* Construct a policy specifying to restart vm. */ + policy = new Policy(); + policy.setName("Restart the VM"); + policy.setDescription("Upon getting the trigger event, restart the VM"); + policy.setActor("APPC"); + policy.setTarget(new Target(TargetType.VM)); + policy.setRecipe("Restart"); + policy.setPayload(null); + policy.setRetry(2); + policy.setTimeout(300); + + /* A sample DMAAP request wrapper. */ + dmaapRequest = new LCMRequestWrapper(); + dmaapRequest.setCorrelationId(onsetEvent.requestID.toString() + "-" + "1"); + dmaapRequest.setRpcName(policy.getRecipe().toLowerCase()); + dmaapRequest.setType("request"); + + /* A sample DMAAP response wrapper */ + dmaapResponse = new LCMResponseWrapper(); + dmaapResponse.setCorrelationId(onsetEvent.requestID.toString() + "-" + "1"); + dmaapResponse.setRpcName(policy.getRecipe().toLowerCase()); + dmaapResponse.setType("response"); + + /* A sample APPC LCM request. */ + LCMRequest appcRequest = new LCMRequest(); + + /* The following code constructs a sample APPC LCM Request */ + appcRequest.setAction("restart"); + + HashMap<String, String> actionIdentifiers = new HashMap<>(); + actionIdentifiers.put("vnf-id", "trial-vnf-003"); + + appcRequest.setActionIdentifiers(actionIdentifiers); + + LCMCommonHeader commonHeader = new LCMCommonHeader(); + commonHeader.setRequestId(onsetEvent.requestID); + commonHeader.setSubRequestId("1"); + commonHeader.setOriginatorId(onsetEvent.requestID.toString()); + + appcRequest.setCommonHeader(commonHeader); + + appcRequest.setPayload(null); + + dmaapRequest.setBody(appcRequest); + + /* The following code constructs a sample APPC LCM Response */ + LCMResponse appcResponse = new LCMResponse(appcRequest); + appcResponse.getStatus().setCode(400); + appcResponse.getStatus().setMessage("Restart Successful"); + + dmaapResponse.setBody(appcResponse); + } + + /** + * A test to construct an APPC LCM restart request. + */ + @Test + public void constructRestartRequestTest() { + + LCMRequestWrapper dmaapRequest = AppcLcmActorServiceProvider.constructRequest(onsetEvent, operation, policy); + + /* The service provider must return a non null DMAAP request wrapper */ + assertNotNull(dmaapRequest); + + /* The DMAAP wrapper's type field must be request */ + assertEquals(dmaapRequest.getType(), "request"); + + /* The DMAAP wrapper's body field cannot be null */ + assertNotNull(dmaapRequest.getBody()); + + LCMRequest appcRequest = dmaapRequest.getBody(); + + /* A common header is required and cannot be null */ + assertNotNull(appcRequest.getCommonHeader()); + assertEquals(appcRequest.getCommonHeader().getRequestId(), onsetEvent.requestID); + + /* An action is required and cannot be null */ + assertNotNull(appcRequest.getAction()); + assertEquals(appcRequest.getAction(), "restart"); + + /* Action Identifiers are required and cannot be null */ + assertNotNull(appcRequest.getActionIdentifiers()); + assertNotNull(appcRequest.getActionIdentifiers().get("vnf-id")); + + logger.debug("APPC Request: \n" + appcRequest.toString()); + } + + /** + * A test to process a successful APPC restart response. + */ + @Test + public void processRestartResponseSuccessTest() { + AbstractMap.SimpleEntry<PolicyResult, String> result = AppcLcmActorServiceProvider + .processResponse(dmaapResponse); + assertEquals(result.getKey(), PolicyResult.SUCCESS); + assertEquals(result.getValue(), "Restart Successful"); + } + + /** + * A test to map APPC response results to corresponding Policy results + */ + @Test + public void appcToPolicyResultTest() { + + AbstractMap.SimpleEntry<PolicyResult, String> result; + + /* If APPC accepts, PolicyResult is null */ + dmaapResponse.getBody().getStatus().setCode(100); + dmaapResponse.getBody().getStatus().setMessage("ACCEPTED"); + result = AppcLcmActorServiceProvider.processResponse(dmaapResponse); + assertEquals(result.getKey(), null); + + /* If APPC is successful, PolicyResult is success */ + dmaapResponse.getBody().getStatus().setCode(400); + dmaapResponse.getBody().getStatus().setMessage("SUCCESS"); + result = AppcLcmActorServiceProvider.processResponse(dmaapResponse); + assertEquals(result.getKey(), PolicyResult.SUCCESS); + + /* If APPC returns an error, PolicyResult is failure exception */ + dmaapResponse.getBody().getStatus().setCode(200); + dmaapResponse.getBody().getStatus().setMessage("ERROR"); + result = AppcLcmActorServiceProvider.processResponse(dmaapResponse); + assertEquals(result.getKey(), PolicyResult.FAILURE_EXCEPTION); + + /* If APPC rejects, PolicyResult is failure exception */ + dmaapResponse.getBody().getStatus().setCode(300); + dmaapResponse.getBody().getStatus().setMessage("REJECT"); + result = AppcLcmActorServiceProvider.processResponse(dmaapResponse); + assertEquals(result.getKey(), PolicyResult.FAILURE_EXCEPTION); + + /* Test multiple reject codes */ + dmaapResponse.getBody().getStatus().setCode(306); + dmaapResponse.getBody().getStatus().setMessage("REJECT"); + result = AppcLcmActorServiceProvider.processResponse(dmaapResponse); + assertEquals(result.getKey(), PolicyResult.FAILURE_EXCEPTION); + + dmaapResponse.getBody().getStatus().setCode(313); + dmaapResponse.getBody().getStatus().setMessage("REJECT"); + result = AppcLcmActorServiceProvider.processResponse(dmaapResponse); + assertEquals(result.getKey(), PolicyResult.FAILURE_EXCEPTION); + + /* If APPC returns failure, PolicyResult is failure */ + dmaapResponse.getBody().getStatus().setCode(401); + dmaapResponse.getBody().getStatus().setMessage("FAILURE"); + result = AppcLcmActorServiceProvider.processResponse(dmaapResponse); + assertEquals(result.getKey(), PolicyResult.FAILURE); + + /* Test multiple failure codes */ + dmaapResponse.getBody().getStatus().setCode(406); + dmaapResponse.getBody().getStatus().setMessage("FAILURE"); + result = AppcLcmActorServiceProvider.processResponse(dmaapResponse); + assertEquals(result.getKey(), PolicyResult.FAILURE); + + dmaapResponse.getBody().getStatus().setCode(450); + dmaapResponse.getBody().getStatus().setMessage("FAILURE"); + result = AppcLcmActorServiceProvider.processResponse(dmaapResponse); + assertEquals(result.getKey(), PolicyResult.FAILURE); + + /* If APPC returns partial success, PolicyResult is failure exception */ + dmaapResponse.getBody().getStatus().setCode(500); + dmaapResponse.getBody().getStatus().setMessage("PARTIAL SUCCESS"); + result = AppcLcmActorServiceProvider.processResponse(dmaapResponse); + assertEquals(result.getKey(), PolicyResult.FAILURE_EXCEPTION); + + /* If APPC returns partial failure, PolicyResult is failure exception */ + dmaapResponse.getBody().getStatus().setCode(501); + dmaapResponse.getBody().getStatus().setMessage("PARTIAL FAILURE"); + result = AppcLcmActorServiceProvider.processResponse(dmaapResponse); + assertEquals(result.getKey(), PolicyResult.FAILURE_EXCEPTION); + + /* Test multiple partial failure codes */ + dmaapResponse.getBody().getStatus().setCode(599); + dmaapResponse.getBody().getStatus().setMessage("PARTIAL FAILURE"); + result = AppcLcmActorServiceProvider.processResponse(dmaapResponse); + assertEquals(result.getKey(), PolicyResult.FAILURE_EXCEPTION); + + dmaapResponse.getBody().getStatus().setCode(550); + dmaapResponse.getBody().getStatus().setMessage("PARTIAL FAILURE"); + result = AppcLcmActorServiceProvider.processResponse(dmaapResponse); + assertEquals(result.getKey(), PolicyResult.FAILURE_EXCEPTION); + + /* If APPC code is unknown to Policy, PolicyResult is failure exception */ + dmaapResponse.getBody().getStatus().setCode(700); + dmaapResponse.getBody().getStatus().setMessage("UNKNOWN"); + result = AppcLcmActorServiceProvider.processResponse(dmaapResponse); + assertEquals(result.getKey(), PolicyResult.FAILURE_EXCEPTION); + } + + +} diff --git a/controlloop/common/actors/pom.xml b/controlloop/common/actors/pom.xml index e99fbb09f..1f38e90b1 100644 --- a/controlloop/common/actors/pom.xml +++ b/controlloop/common/actors/pom.xml @@ -15,6 +15,7 @@ <module>actorServiceProvider</module> <module>actor.appc</module> <module>actor.vfc</module> + <module>actor.appclcm</module> <module>actor.mso</module> <module>actor.test</module> </modules> diff --git a/controlloop/common/eventmanager/pom.xml b/controlloop/common/eventmanager/pom.xml index 8447ff74d..318d39fbc 100644 --- a/controlloop/common/eventmanager/pom.xml +++ b/controlloop/common/eventmanager/pom.xml @@ -60,6 +60,12 @@ </dependency> <dependency> <groupId>org.onap.policy.drools-applications</groupId> + <artifactId>actor.appclcm</artifactId> + <version>1.1.0-SNAPSHOT</version> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>org.onap.policy.drools-applications</groupId> <artifactId>guard</artifactId> <version>1.1.0-SNAPSHOT</version> <scope>provided</scope> @@ -83,6 +89,18 @@ <scope>provided</scope> </dependency> <dependency> + <groupId>org.onap.policy.drools-applications</groupId> + <artifactId>appclcm</artifactId> + <version>1.1.0-SNAPSHOT</version> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>org.onap.policy.drools-applications</groupId> + <artifactId>trafficgenerator</artifactId> + <version>1.1.0-SNAPSHOT</version> + <scope>provided</scope> + </dependency> + <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> 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 09f69fb0b..94b6e1618 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 @@ -23,6 +23,7 @@ package org.onap.policy.controlloop.eventmanager; import java.io.Serializable; import java.sql.Timestamp; import java.time.Instant; +import java.util.AbstractMap; import java.util.LinkedList; import javax.persistence.EntityManager; @@ -30,6 +31,7 @@ import javax.persistence.Persistence; import org.onap.policy.appc.Response; import org.onap.policy.appc.ResponseCode; +import org.onap.policy.appclcm.LCMResponseWrapper; import org.onap.policy.controlloop.ControlLoopEvent; import org.onap.policy.controlloop.ControlLoopOperation; import org.onap.policy.controlloop.VirtualControlLoopEvent; @@ -40,7 +42,7 @@ import org.onap.policy.controlloop.actor.appc.APPCActorServiceProvider; import org.onap.policy.controlloop.actor.vfc.VFCActorServiceProvider; import org.slf4j.Logger; import org.slf4j.LoggerFactory; - +import org.onap.policy.controlloop.actor.appclcm.AppcLcmActorServiceProvider; public class ControlLoopOperationManager implements Serializable { @@ -196,16 +198,22 @@ public class ControlLoopOperationManager implements Serializable { // switch (policy.getActor()) { case "APPC": - //Request request = APPCActorServiceProvider.constructRequest(onset, operation.operation, this.policy); - this.operationRequest = APPCActorServiceProvider.constructRequest((VirtualControlLoopEvent)onset, operation.operation, this.policy); + /* + * If the recipe is ModifyConfig, a legacy APPC + * request is constructed. Otherwise an LCMRequest + * is constructed. + */ + if ("ModifyConfig".equalsIgnoreCase(policy.getRecipe())) { + + this.operationRequest = APPCActorServiceProvider.constructRequest((VirtualControlLoopEvent)onset, operation.operation, this.policy); + } + else { + this.operationRequest = AppcLcmActorServiceProvider.constructRequest((VirtualControlLoopEvent) onset, operation.operation, this.policy); + } // // Save the operation // this.currentOperation = operation; - //System.out.print("************* BEFORE STORING....."); - //this.storeOperationInDataBase("startOperation"); - //System.out.print("************* AFTER STORING....."); - // return operationRequest; case "MSO": // @@ -306,7 +314,34 @@ public class ControlLoopOperationManager implements Serializable { } return PolicyResult.FAILURE; } - } + } + else if (response instanceof LCMResponseWrapper) { + + LCMResponseWrapper dmaapResponse = (LCMResponseWrapper) response; + + /* + * Parse out the operation attempt using the subrequestid + */ + Integer operationAttempt = AppcLcmActorServiceProvider.parseOperationAttempt(dmaapResponse.getBody().getCommonHeader().getSubRequestId()); + if (operationAttempt == null) { + this.completeOperation(operationAttempt, "Policy was unable to parse APP-C SubRequestID (it was null).", PolicyResult.FAILURE_EXCEPTION); + } + + /* + * Process the APPCLCM response to see what PolicyResult + * should be returned + */ + AbstractMap.SimpleEntry<PolicyResult, String> result = AppcLcmActorServiceProvider.processResponse(dmaapResponse); + + if (result.getKey() != null) { + this.completeOperation(operationAttempt, result.getValue(), result.getKey()); + if (PolicyResult.FAILURE_TIMEOUT.equals(this.policyResult)) { + return null; + } + return result.getKey(); + } + return null; + } return null; } diff --git a/controlloop/common/eventmanager/src/main/java/org/onap/policy/drools/impl/PolicyEngineJUnitImpl.java b/controlloop/common/eventmanager/src/main/java/org/onap/policy/drools/impl/PolicyEngineJUnitImpl.java index bb5cec8da..aed72815c 100644 --- a/controlloop/common/eventmanager/src/main/java/org/onap/policy/drools/impl/PolicyEngineJUnitImpl.java +++ b/controlloop/common/eventmanager/src/main/java/org/onap/policy/drools/impl/PolicyEngineJUnitImpl.java @@ -26,6 +26,7 @@ import java.util.Map; import java.util.Queue; import org.onap.policy.appc.Request; +import org.onap.policy.appclcm.LCMRequestWrapper; import org.onap.policy.controlloop.ControlLoopNotification; import org.onap.policy.controlloop.util.Serialization; import org.slf4j.Logger; @@ -49,6 +50,10 @@ public class PolicyEngineJUnitImpl implements PolicyEngine { Request request = (Request) obj; logger.debug("Request: {} subrequst {}", request.Action, request.CommonHeader.SubRequestID); } + else if (obj instanceof LCMRequestWrapper) { + LCMRequestWrapper dmaapRequest = (LCMRequestWrapper) obj; + logger.debug("Request: {} subrequest {}", dmaapRequest.getBody().getAction(), dmaapRequest.getBody().getCommonHeader().getSubRequestId()); + } // // Does the bus exist? // @@ -57,7 +62,7 @@ public class PolicyEngineJUnitImpl implements PolicyEngine { // // Create the bus // - busMap.put(busType, new HashMap<String, Queue<Object>>()); + busMap.put(busType, new HashMap<>()); } // // Get the bus @@ -71,7 +76,7 @@ public class PolicyEngineJUnitImpl implements PolicyEngine { // // Create the topic // - topicMap.put(topic, new LinkedList<Object>()); + topicMap.put(topic, new LinkedList<>()); } // // Get the topic queue 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 6116d987e..90f61e0c9 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 @@ -30,10 +30,10 @@ import java.util.HashMap; import java.util.UUID; import org.junit.Test; -import org.onap.policy.appc.Request; -import org.onap.policy.appc.Response; -import org.onap.policy.appc.ResponseCode; -import org.onap.policy.appc.ResponseValue; +import org.onap.policy.appclcm.LCMRequest; +import org.onap.policy.appclcm.LCMRequestWrapper; +import org.onap.policy.appclcm.LCMResponse; +import org.onap.policy.appclcm.LCMResponseWrapper; import org.onap.policy.controlloop.ControlLoopEventStatus; import org.onap.policy.controlloop.VirtualControlLoopEvent; @@ -53,7 +53,7 @@ public class ControlLoopOperationManagerTest { onset.requestID = UUID.randomUUID(); onset.target = "vserver.selflink"; onset.closedLoopAlarmStart = Instant.now(); - onset.AAI = new HashMap<String, String>(); + onset.AAI = new HashMap<>(); onset.AAI.put("cloud-region.identity-url", "foo"); onset.AAI.put("vserver.selflink", "bar"); onset.AAI.put("vserver.is-closed-loop-disabled", "false"); @@ -91,20 +91,24 @@ public class ControlLoopOperationManagerTest { Object request = manager.startOperation(onset); logger.debug("{}",manager); assertNotNull(request); - assertTrue(request instanceof Request); - assertTrue(((Request)request).CommonHeader.SubRequestID.contentEquals("1")); + assertTrue(request instanceof LCMRequestWrapper); + LCMRequestWrapper dmaapRequest = (LCMRequestWrapper) request; + LCMRequest appcRequest = dmaapRequest.getBody(); + assertTrue(appcRequest.getCommonHeader().getSubRequestId().contentEquals("1")); assertFalse(manager.isOperationComplete()); assertTrue(manager.isOperationRunning()); // // Accept // - Response response = new Response((Request) request); - response.Status.Code = ResponseCode.ACCEPT.getValue(); - response.Status.Value = ResponseValue.ACCEPT.toString(); + LCMResponseWrapper dmaapResponse = new LCMResponseWrapper(); + LCMResponse appcResponse = new LCMResponse((LCMRequest) appcRequest); + appcResponse.getStatus().setCode(100); + appcResponse.getStatus().setMessage("ACCEPT"); + dmaapResponse.setBody(appcResponse); // // // - PolicyResult result = manager.onResponse(response); + PolicyResult result = manager.onResponse(dmaapResponse); logger.debug("{}",manager); assertTrue(result == null); assertFalse(manager.isOperationComplete()); @@ -112,11 +116,11 @@ public class ControlLoopOperationManagerTest { // // Now we are going to Fail it // - response = new Response((Request) request); - response.Status.Code = ResponseCode.FAILURE.getValue(); - response.Status.Value = ResponseValue.FAILURE.toString(); - response.Status.Description = "AppC failed for some reason"; - result = manager.onResponse(response); + appcResponse = new LCMResponse(appcRequest); + appcResponse.getStatus().setCode(401); + appcResponse.getStatus().setMessage("AppC failed for some reason"); + dmaapResponse.setBody(appcResponse); + result = manager.onResponse(dmaapResponse); logger.debug("{}",manager); assertTrue(result.equals(PolicyResult.FAILURE)); assertFalse(manager.isOperationComplete()); @@ -127,21 +131,24 @@ public class ControlLoopOperationManagerTest { request = manager.startOperation(onset); logger.debug("{}",manager); assertNotNull(request); - assertTrue(request instanceof Request); - assertTrue(((Request)request).CommonHeader.SubRequestID.contentEquals("2")); + assertTrue(request instanceof LCMRequestWrapper); + dmaapRequest = (LCMRequestWrapper) request; + appcRequest = dmaapRequest.getBody(); + assertTrue(appcRequest.getCommonHeader().getSubRequestId().contentEquals("2")); assertFalse(manager.isOperationComplete()); assertTrue(manager.isOperationRunning()); // // // - response = new Response((Request) request); + appcResponse = new LCMResponse((LCMRequest) appcRequest); logger.debug("{}",manager); - response.Status.Code = ResponseCode.ACCEPT.getValue(); - response.Status.Value = ResponseValue.ACCEPT.toString(); + appcResponse.getStatus().setCode(100); + appcResponse.getStatus().setMessage("ACCEPT"); + dmaapResponse.setBody(appcResponse); // // // - result = manager.onResponse(response); + result = manager.onResponse(dmaapResponse); logger.debug("{}",manager); assertTrue(result == null); assertFalse(manager.isOperationComplete()); @@ -149,11 +156,11 @@ public class ControlLoopOperationManagerTest { // // Now we are going to Fail it // - response = new Response((Request) request); - response.Status.Code = ResponseCode.FAILURE.getValue(); - response.Status.Value = ResponseValue.FAILURE.toString(); - response.Status.Description = "AppC failed for some reason"; - result = manager.onResponse(response); + appcResponse = new LCMResponse((LCMRequest) appcRequest); + appcResponse.getStatus().setCode(401); + appcResponse.getStatus().setMessage("AppC failed for some reason"); + dmaapResponse.setBody(appcResponse); + result = manager.onResponse(dmaapResponse); logger.debug("{}",manager); assertTrue(result.equals(PolicyResult.FAILURE)); // @@ -199,20 +206,24 @@ public class ControlLoopOperationManagerTest { Object request = manager.startOperation(onset); logger.debug("{}",manager); assertNotNull(request); - assertTrue(request instanceof Request); - assertTrue(((Request)request).CommonHeader.SubRequestID.contentEquals("1")); + assertTrue((request) instanceof LCMRequestWrapper); + LCMRequestWrapper dmaapRequest = (LCMRequestWrapper) request; + LCMRequest appcRequest = dmaapRequest.getBody(); + assertTrue((appcRequest).getCommonHeader().getSubRequestId().contentEquals("1")); assertFalse(manager.isOperationComplete()); assertTrue(manager.isOperationRunning()); // // Accept // - Response response = new Response((Request) request); - response.Status.Code = ResponseCode.ACCEPT.getValue(); - response.Status.Value = ResponseValue.ACCEPT.toString(); + LCMResponseWrapper dmaapResponse = new LCMResponseWrapper(); + LCMResponse appcResponse = new LCMResponse(appcRequest); + dmaapResponse.setBody(appcResponse); + appcResponse.getStatus().setCode(100); + appcResponse.getStatus().setMessage("ACCEPT"); // // // - PolicyResult result = manager.onResponse(response); + PolicyResult result = manager.onResponse(dmaapResponse); logger.debug("{}",manager); assertTrue(result == null); assertFalse(manager.isOperationComplete()); @@ -229,11 +240,11 @@ public class ControlLoopOperationManagerTest { // // Now we are going to Fail the previous request // - response = new Response((Request) request); - response.Status.Code = ResponseCode.FAILURE.getValue(); - response.Status.Value = ResponseValue.FAILURE.toString(); - response.Status.Description = "AppC failed for some reason"; - result = manager.onResponse(response); + appcResponse = new LCMResponse(appcRequest); + appcResponse.getStatus().setCode(401); + appcResponse.getStatus().setMessage("AppC failed for some reason"); + dmaapResponse.setBody(appcResponse); + result = manager.onResponse(dmaapResponse); logger.debug("{}",manager); // // diff --git a/controlloop/common/model-impl/aai/src/main/java/org/onap/policy/aai/AAINQF199/AAINQF199GenericVNF.java b/controlloop/common/model-impl/aai/src/main/java/org/onap/policy/aai/AAINQF199/AAINQF199GenericVNF.java index 8d667bb75..eb19ad95e 100644 --- a/controlloop/common/model-impl/aai/src/main/java/org/onap/policy/aai/AAINQF199/AAINQF199GenericVNF.java +++ b/controlloop/common/model-impl/aai/src/main/java/org/onap/policy/aai/AAINQF199/AAINQF199GenericVNF.java @@ -75,6 +75,9 @@ public class AAINQF199GenericVNF implements Serializable { @SerializedName("persona-model-version") public String personaModelVersion; + + @SerializedName("model-invariant-id") + public String modelInvariantId; public AAINQF199GenericVNF() { } diff --git a/controlloop/common/model-impl/appc/pom.xml b/controlloop/common/model-impl/appc/pom.xml index ae6ff0f5f..fc99a19ed 100644 --- a/controlloop/common/model-impl/appc/pom.xml +++ b/controlloop/common/model-impl/appc/pom.xml @@ -33,7 +33,7 @@ <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> - <scope>provided</scope> + <scope>test</scope> </dependency> <dependency> <groupId>com.google.code.gson</groupId> diff --git a/controlloop/common/model-impl/appc/src/main/java/org/onap/policy/appc/CommonHeader.java b/controlloop/common/model-impl/appc/src/main/java/org/onap/policy/appc/CommonHeader.java index 4df25ecc5..1e92744ef 100644 --- a/controlloop/common/model-impl/appc/src/main/java/org/onap/policy/appc/CommonHeader.java +++ b/controlloop/common/model-impl/appc/src/main/java/org/onap/policy/appc/CommonHeader.java @@ -36,8 +36,8 @@ public class CommonHeader implements Serializable { public String OriginatorID; public UUID RequestID; public String SubRequestID; - public Collection<String> RequestTrack = new ArrayList<String>(); - public Collection<Map<String, String>> Flags = new ArrayList<Map<String, String>>(); + public Collection<String> RequestTrack = new ArrayList<>(); + public Collection<Map<String, String>> Flags = new ArrayList<>(); public CommonHeader() { diff --git a/controlloop/common/model-impl/appc/src/main/java/org/onap/policy/appc/Request.java b/controlloop/common/model-impl/appc/src/main/java/org/onap/policy/appc/Request.java index fbf0d8ee5..a9634a7b2 100644 --- a/controlloop/common/model-impl/appc/src/main/java/org/onap/policy/appc/Request.java +++ b/controlloop/common/model-impl/appc/src/main/java/org/onap/policy/appc/Request.java @@ -32,7 +32,7 @@ public class Request implements Serializable{ public String Action; public String TargetID; public String ObjectID; - public Map<String, Object> Payload = new HashMap<String, Object>(); + public Map<String, Object> Payload = new HashMap<>(); public Request() { diff --git a/controlloop/common/model-impl/appc/src/main/java/org/onap/policy/appc/Response.java b/controlloop/common/model-impl/appc/src/main/java/org/onap/policy/appc/Response.java index f9f494625..0aeb1d483 100644 --- a/controlloop/common/model-impl/appc/src/main/java/org/onap/policy/appc/Response.java +++ b/controlloop/common/model-impl/appc/src/main/java/org/onap/policy/appc/Response.java @@ -30,7 +30,7 @@ public class Response implements Serializable { public CommonHeader CommonHeader; public ResponseStatus Status = new ResponseStatus(); - public Map<String, Object> Payload = new HashMap<String, Object>(); + public Map<String, Object> Payload = new HashMap<>(); public Response() { diff --git a/controlloop/common/model-impl/appclcm/pom.xml b/controlloop/common/model-impl/appclcm/pom.xml new file mode 100644 index 000000000..a882cb46c --- /dev/null +++ b/controlloop/common/model-impl/appclcm/pom.xml @@ -0,0 +1,45 @@ +<!-- + ============LICENSE_START======================================================= + Drools PDP Application Models + ================================================================================ + Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + ================================================================================ + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + ============LICENSE_END========================================================= + --> + +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + <artifactId>appclcm</artifactId> + + <parent> + <groupId>org.onap.policy.drools-applications</groupId> + <artifactId>model-impl</artifactId> + <version>1.1.0-SNAPSHOT</version> + </parent> + + <dependencies> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <version>4.12</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>com.google.code.gson</groupId> + <artifactId>gson</artifactId> + <version>2.5</version> + <scope>provided</scope> + </dependency> + </dependencies> +</project> diff --git a/controlloop/common/model-impl/appclcm/src/main/java/org/onap/policy/appclcm/LCMCommonHeader.java b/controlloop/common/model-impl/appclcm/src/main/java/org/onap/policy/appclcm/LCMCommonHeader.java new file mode 100644 index 000000000..e2f520ad8 --- /dev/null +++ b/controlloop/common/model-impl/appclcm/src/main/java/org/onap/policy/appclcm/LCMCommonHeader.java @@ -0,0 +1,233 @@ +/*- + * ============LICENSE_START======================================================= + * appclcm + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.appclcm; + +import java.io.Serializable; +import java.time.Instant; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +import com.google.gson.annotations.SerializedName; + +public class LCMCommonHeader implements Serializable { + + private static final long serialVersionUID = 6581963539127062114L; + + @SerializedName(value="timestamp") + private Instant timeStamp = Instant.now(); + + @SerializedName(value="api-ver") + private String apiVer="5.00"; + + @SerializedName(value="originator-id") + private String originatorId; + + @SerializedName(value="request-id") + private UUID requestId; + + @SerializedName(value="sub-request-id") + private String subRequestId; + + @SerializedName(value="flags") + private Map<String, String> flags = new HashMap<>(); + + public LCMCommonHeader() { + + } + + /** + * Used to copy a common header. + * + * @param commonHeader + * a header that is defined by the lcm api guide that contains + * information about the request (requestId, flags, etc.) + */ + public LCMCommonHeader(LCMCommonHeader commonHeader) { + this.originatorId = commonHeader.originatorId; + this.requestId = commonHeader.requestId; + this.subRequestId = commonHeader.subRequestId; + if (commonHeader.flags != null) { + this.flags.putAll(commonHeader.flags); + } + } + + /** + * @return the timeStamp + */ + public Instant getTimeStamp() { + return timeStamp; + } + + /** + * @param timeStamp the timeStamp to set + */ + public void setTimeStamp(Instant timeStamp) { + this.timeStamp = timeStamp; + } + + /** + * @return the apiVer + */ + public String getApiVer() { + return apiVer; + } + + /** + * @param apiVer the apiVer to set + */ + public void setApiVer(String apiVer) { + this.apiVer = apiVer; + } + + /** + * @return the originatorId + */ + public String getOriginatorId() { + return originatorId; + } + + /** + * @param originatorId the originatorId to set + */ + public void setOriginatorId(String originatorId) { + this.originatorId = originatorId; + } + + /** + * @return the requestId + */ + public UUID getRequestId() { + return requestId; + } + + /** + * @param requestId the requestId to set + */ + public void setRequestId(UUID requestId) { + this.requestId = requestId; + } + + /** + * @return the subRequestId + */ + public String getSubRequestId() { + return subRequestId; + } + + /** + * @param subRequestId the subRequestId to set + */ + public void setSubRequestId(String subRequestId) { + this.subRequestId = subRequestId; + } + + /** + * @return the flags + */ + public Map<String, String> getFlags() { + return flags; + } + + /** + * @param flags the flags to set + */ + public void setFlags(Map<String, String> flags) { + this.flags = flags; + } + + @Override + public String toString() { + return "CommonHeader [timeStamp=" + timeStamp + ", apiVer=" + apiVer + ", originatorId=" + originatorId + + ", requestId=" + requestId + ", subRequestId=" + subRequestId + ", flags=" + flags + "]"; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((apiVer == null) ? 0 : apiVer.hashCode()); + result = prime * result + ((flags == null) ? 0 : flags.hashCode()); + result = prime * result + ((originatorId == null) ? 0 : originatorId.hashCode()); + result = prime * result + ((requestId == null) ? 0 : requestId.hashCode()); + result = prime * result + ((subRequestId == null) ? 0 : subRequestId.hashCode()); + result = prime * result + ((timeStamp == null) ? 0 : timeStamp.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + LCMCommonHeader other = (LCMCommonHeader) obj; + if (apiVer == null) { + if (other.apiVer != null) { + return false; + } + } else if (!apiVer.equals(other.apiVer)) { + return false; + } + if (flags == null) { + if (other.flags != null) { + return false; + } + } else if (!flags.equals(other.flags)) { + return false; + } + if (originatorId == null) { + if (other.originatorId != null) { + return false; + } + } else if (!originatorId.equals(other.originatorId)) { + return false; + } + if (requestId == null) { + if (other.requestId != null) { + return false; + } + } else if (!requestId.equals(other.requestId)) { + return false; + } + if (subRequestId == null) { + if (other.subRequestId != null) { + return false; + } + } else if (!subRequestId.equals(other.subRequestId)) { + return false; + } + if (timeStamp == null) { + if (other.timeStamp != null) { + return false; + } + } else if (!timeStamp.equals(other.timeStamp)) { + return false; + } + return true; + } + +} diff --git a/controlloop/common/model-impl/appclcm/src/main/java/org/onap/policy/appclcm/LCMRequest.java b/controlloop/common/model-impl/appclcm/src/main/java/org/onap/policy/appclcm/LCMRequest.java new file mode 100644 index 000000000..51db7fef0 --- /dev/null +++ b/controlloop/common/model-impl/appclcm/src/main/java/org/onap/policy/appclcm/LCMRequest.java @@ -0,0 +1,161 @@ +/*- + * ============LICENSE_START======================================================= + * appclcm + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.appclcm; + +import java.io.Serializable; +import java.util.Map; + +import com.google.gson.annotations.SerializedName; + +public class LCMRequest implements Serializable { + + private static final long serialVersionUID = 219375564922846624L; + + @SerializedName(value="common-header") + private LCMCommonHeader commonHeader; + + @SerializedName(value="action") + private String action; + + @SerializedName(value="action-identifiers") + private Map<String, String> actionIdentifiers; + + @SerializedName(value="payload") + private String payload; + + public LCMRequest() { + + } + + public LCMCommonHeader getCommonHeader() { + return commonHeader; + } + + /** + * @return the action + */ + public String getAction() { + return action; + } + + /** + * @param action the action to set + */ + public void setAction(String action) { + this.action = action; + } + + /** + * @return the actionIdentifiers + */ + public Map<String, String> getActionIdentifiers() { + return actionIdentifiers; + } + + /** + * @param actionIdentifiers the actionIdentifiers to set + */ + public void setActionIdentifiers(Map<String, String> actionIdentifiers) { + this.actionIdentifiers = actionIdentifiers; + } + + /** + * @return the payload + */ + public String getPayload() { + return payload; + } + + /** + * @param payload the payload to set + */ + public void setPayload(String payload) { + this.payload = payload; + } + + /** + * @param commonHeader the commonHeader to set + */ + public void setCommonHeader(LCMCommonHeader commonHeader) { + this.commonHeader = commonHeader; + } + + @Override + public String toString() { + return "Request [commonHeader=" + commonHeader + ", action=" + action + ", actionIdentifiers=" + + actionIdentifiers + ", payload=" + payload + "]"; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((commonHeader == null) ? 0 : commonHeader.hashCode()); + result = prime * result + ((action == null) ? 0 : action.hashCode()); + result = prime * result + ((actionIdentifiers == null) ? 0 : actionIdentifiers.hashCode()); + result = prime * result + ((payload == null) ? 0 : payload.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + LCMRequest other = (LCMRequest) obj; + if (commonHeader == null) { + if (other.commonHeader != null) { + return false; + } + } else if (!commonHeader.equals(other.commonHeader)) { + return false; + } + if (action == null) { + if (other.action != null) { + return false; + } + } else if (!action.equals(other.action)) { + return false; + } + if (actionIdentifiers == null) { + if (other.actionIdentifiers != null) { + return false; + } + } else if (!actionIdentifiers.equals(other.actionIdentifiers)) { + return false; + } + if (payload == null) { + if (other.payload != null) { + return false; + } + } else if (!payload.equals(other.payload)) { + return false; + } + return true; + } + +} diff --git a/controlloop/common/model-impl/appclcm/src/main/java/org/onap/policy/appclcm/LCMRequestWrapper.java b/controlloop/common/model-impl/appclcm/src/main/java/org/onap/policy/appclcm/LCMRequestWrapper.java new file mode 100644 index 000000000..ea7e6762f --- /dev/null +++ b/controlloop/common/model-impl/appclcm/src/main/java/org/onap/policy/appclcm/LCMRequestWrapper.java @@ -0,0 +1,90 @@ +/*- + * ============LICENSE_START======================================================= + * appclcm + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.appclcm; + +import com.google.gson.annotations.SerializedName; +import java.io.Serializable; + +public class LCMRequestWrapper extends LCMWrapper implements Serializable { + + private static final long serialVersionUID = 424866914715980798L; + + @SerializedName(value="body") + private LCMRequest body; + + public LCMRequestWrapper() { + super(); + } + + public LCMRequestWrapper(LCMRequest request) { + body = request; + } + + /** + * @return the body + */ + public LCMRequest getBody() { + return body; + } + + /** + * @param body the body to set + */ + public void setBody(LCMRequest body) { + this.body = body; + } + + @Override + public String toString() { + return "RequestWrapper [body=" + body + ", toString()=" + super.toString() + "]"; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = super.hashCode(); + result = prime * result + ((body == null) ? 0 : body.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!super.equals(obj)) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + LCMRequestWrapper other = (LCMRequestWrapper) obj; + if (body == null) { + if (other.body != null) { + return false; + } + } else if (!body.equals(other.body)) { + return false; + } + return true; + } + +} diff --git a/controlloop/common/model-impl/appclcm/src/main/java/org/onap/policy/appclcm/LCMResponse.java b/controlloop/common/model-impl/appclcm/src/main/java/org/onap/policy/appclcm/LCMResponse.java new file mode 100644 index 000000000..003dc573b --- /dev/null +++ b/controlloop/common/model-impl/appclcm/src/main/java/org/onap/policy/appclcm/LCMResponse.java @@ -0,0 +1,151 @@ +/*- + * ============LICENSE_START======================================================= + * appclcm + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.appclcm; + +import com.google.gson.annotations.SerializedName; +import java.io.Serializable; + +public class LCMResponse implements Serializable { + + private static final long serialVersionUID = 6332508597287669750L; + + @SerializedName(value = "common-header") + private LCMCommonHeader commonHeader; + + @SerializedName(value = "status") + private LCMResponseStatus status = new LCMResponseStatus(); + + @SerializedName(value = "payload") + private String payload; + + public LCMResponse() { + + } + + /** + * Constructs a response using the common header of the request since they + * will be the same. + * + * @param request + * an appc lcm request object specified by the lcm api guide + */ + public LCMResponse(LCMRequest request) { + this.commonHeader = new LCMCommonHeader(request.getCommonHeader()); + String requestPayload = request.getPayload(); + if (requestPayload != null) { + // this.payload.putAll(request.payload); + this.payload = requestPayload; + } + } + + /** + * @return the commonHeader + */ + public LCMCommonHeader getCommonHeader() { + return commonHeader; + } + + /** + * @param commonHeader the commonHeader to set + */ + public void setCommonHeader(LCMCommonHeader commonHeader) { + this.commonHeader = commonHeader; + } + + /** + * @return the status + */ + public LCMResponseStatus getStatus() { + return status; + } + + /** + * @param status the status to set + */ + public void setStatus(LCMResponseStatus status) { + this.status = status; + } + + /** + * @return the payload + */ + public String getPayload() { + return payload; + } + + /** + * @param payload the payload to set + */ + public void setPayload(String payload) { + this.payload = payload; + } + + @Override + public String toString() { + return "Response [commonHeader=" + commonHeader + ", status=" + status + ", payload=" + payload + "]"; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((commonHeader == null) ? 0 : commonHeader.hashCode()); + result = prime * result + ((payload == null) ? 0 : payload.hashCode()); + result = prime * result + ((status == null) ? 0 : status.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + LCMResponse other = (LCMResponse) obj; + if (commonHeader == null) { + if (other.commonHeader != null) { + return false; + } + } else if (!commonHeader.equals(other.commonHeader)) { + return false; + } + if (payload == null) { + if (other.payload != null) { + return false; + } + } else if (!payload.equals(other.payload)) { + return false; + } + if (status == null) { + if (other.status != null) { + return false; + } + } else if (!status.equals(other.status)) { + return false; + } + return true; + } +} diff --git a/controlloop/common/model-impl/appclcm/src/main/java/org/onap/policy/appclcm/LCMResponseCode.java b/controlloop/common/model-impl/appclcm/src/main/java/org/onap/policy/appclcm/LCMResponseCode.java new file mode 100644 index 000000000..484e793e2 --- /dev/null +++ b/controlloop/common/model-impl/appclcm/src/main/java/org/onap/policy/appclcm/LCMResponseCode.java @@ -0,0 +1,80 @@ +/*- + * ============LICENSE_START======================================================= + * appclcm + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.appclcm; + +public class LCMResponseCode { + + /* These fields define the key to the response code value. */ + public static final String ACCEPTED = "ACCEPTED"; + public static final String ERROR = "ERROR"; + public static final String REJECT = "REJECT"; + public static final String SUCCESS = "SUCCESS"; + public static final String FAILURE = "FAILURE"; + public static final String PARTIAL_SUCCESS = "PARTIAL SUCCESS"; + public static final String PARTIAL_FAILURE = "PARTIAL FAILURE"; + + private Integer code; + + private LCMResponseCode(int code) { + this.code = code; + } + + public int getCode() { + return this.code; + } + + public String toString() { + return Integer.toString(this.code); + } + + /** + * Translates the code to a string value that represents the meaning of the code. + * + * @param code + * the numeric value that is returned by APPC based on success, + * failure, etc. of the action requested + * @return the string value equivalent of the APPC response code + */ + public static String toResponseValue(int code) { + if (code == 100) { + return ACCEPTED; + } + else if (code == 200) { + return ERROR; + } + else if (code >= 300 && code <= 313) { + return REJECT; + } + else if (code == 400) { + return SUCCESS; + } + else if (code == 450 || (code >= 401 && code <= 406)) { + return FAILURE; + } + else if (code == 500) { + return PARTIAL_SUCCESS; + } + else if (code >= 501 && code <= 599) { + return PARTIAL_FAILURE; + } + return null; + } +} diff --git a/controlloop/common/model-impl/appclcm/src/main/java/org/onap/policy/appclcm/LCMResponseStatus.java b/controlloop/common/model-impl/appclcm/src/main/java/org/onap/policy/appclcm/LCMResponseStatus.java new file mode 100644 index 000000000..131e331bf --- /dev/null +++ b/controlloop/common/model-impl/appclcm/src/main/java/org/onap/policy/appclcm/LCMResponseStatus.java @@ -0,0 +1,107 @@ +/*- + * ============LICENSE_START======================================================= + * appclcm + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.appclcm; + +import com.google.gson.annotations.SerializedName; +import java.io.Serializable; + +public class LCMResponseStatus implements Serializable { + + private static final long serialVersionUID = 974891505135467199L; + + @SerializedName(value="code") + private int code; + + @SerializedName(value="message") + private String message; + + public LCMResponseStatus() { + + } + + /** + * @return the code + */ + public int getCode() { + return code; + } + + /** + * @param code the code to set + */ + public void setCode(int code) { + this.code = code; + } + + /** + * @return the message + */ + public String getMessage() { + return message; + } + + /** + * @param message the message to set + */ + public void setMessage(String message) { + this.message = message; + } + + @Override + public String toString() { + return "ResponseStatus [code=" + code + ", message=" + message + "]"; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + code; + result = prime * result + ((message == null) ? 0 : message.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + LCMResponseStatus other = (LCMResponseStatus) obj; + if (code != other.code) { + return false; + } + if (message == null) { + if (other.message != null) { + return false; + } + } else if (!message.equals(other.message)) { + return false; + } + return true; + } + +} diff --git a/controlloop/common/model-impl/appclcm/src/main/java/org/onap/policy/appclcm/LCMResponseWrapper.java b/controlloop/common/model-impl/appclcm/src/main/java/org/onap/policy/appclcm/LCMResponseWrapper.java new file mode 100644 index 000000000..7d9062979 --- /dev/null +++ b/controlloop/common/model-impl/appclcm/src/main/java/org/onap/policy/appclcm/LCMResponseWrapper.java @@ -0,0 +1,85 @@ +/*- + * ============LICENSE_START======================================================= + * appclcm + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.appclcm; + +import com.google.gson.annotations.SerializedName; +import java.io.Serializable; + +public class LCMResponseWrapper extends LCMWrapper implements Serializable { + + private static final long serialVersionUID = 463937813781086802L; + + @SerializedName(value="body") + private LCMResponse body; + + public LCMResponseWrapper() { + super(); + } + + /** + * @return the body + */ + public LCMResponse getBody() { + return body; + } + + /** + * @param body the body to set + */ + public void setBody(LCMResponse body) { + this.body = body; + } + + @Override + public String toString() { + return "ResponseWrapper [body=" + body + ", toString()=" + super.toString() + "]"; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = super.hashCode(); + result = prime * result + ((body == null) ? 0 : body.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!super.equals(obj)) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + LCMResponseWrapper other = (LCMResponseWrapper) obj; + if (body == null) { + if (other.body != null) { + return false; + } + } else if (!body.equals(other.body)) { + return false; + } + return true; + } +} diff --git a/controlloop/common/model-impl/appclcm/src/main/java/org/onap/policy/appclcm/LCMWrapper.java b/controlloop/common/model-impl/appclcm/src/main/java/org/onap/policy/appclcm/LCMWrapper.java new file mode 100644 index 000000000..c9f72c2e2 --- /dev/null +++ b/controlloop/common/model-impl/appclcm/src/main/java/org/onap/policy/appclcm/LCMWrapper.java @@ -0,0 +1,187 @@ +/*- + * ============LICENSE_START======================================================= + * appclcm + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.appclcm; + +import com.google.gson.annotations.SerializedName; +import java.io.Serializable; + +public class LCMWrapper implements Serializable { + + private static final long serialVersionUID = 753005805432396532L; + + @SerializedName(value="version") + private String version; + + @SerializedName(value="cambria-partition") + private String cambriaPartition; + + @SerializedName(value="rpc-name") + private String rpcName; + + @SerializedName(value="correlation-id") + private String correlationId; + + @SerializedName(value="type") + private String type; + + public LCMWrapper() { + + } + + /** + * @return the version + */ + public String getVersion() { + return version; + } + + /** + * @param version the version to set + */ + public void setVersion(String version) { + this.version = version; + } + + /** + * @return the cambriaPartition + */ + public String getCambriaPartition() { + return cambriaPartition; + } + + /** + * @param cambriaPartition the cambriaPartition to set + */ + public void setCambriaPartition(String cambriaPartition) { + this.cambriaPartition = cambriaPartition; + } + + /** + * @return the rpcName + */ + public String getRpcName() { + return rpcName; + } + + /** + * @param rpcName the rpcName to set + */ + public void setRpcName(String rpcName) { + this.rpcName = rpcName; + } + + /** + * @return the correlationId + */ + public String getCorrelationId() { + return correlationId; + } + + /** + * @param correlationId the correlationId to set + */ + public void setCorrelationId(String correlationId) { + this.correlationId = correlationId; + } + + /** + * @return the type + */ + public String getType() { + return type; + } + + /** + * @param type the type to set + */ + public void setType(String type) { + this.type = type; + } + + @Override + public String toString() { + return "Wrapper [version=" + version + ", cambriaPartition=" + cambriaPartition + ", rpcName=" + rpcName + + ", correlationId=" + correlationId + ", type=" + type + "]"; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((cambriaPartition == null) ? 0 : cambriaPartition.hashCode()); + result = prime * result + ((correlationId == null) ? 0 : correlationId.hashCode()); + result = prime * result + ((rpcName == null) ? 0 : rpcName.hashCode()); + result = prime * result + ((type == null) ? 0 : type.hashCode()); + result = prime * result + ((version == null) ? 0 : version.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + LCMWrapper other = (LCMWrapper) obj; + if (cambriaPartition == null) { + if (other.cambriaPartition != null) { + return false; + } + } else if (!cambriaPartition.equals(other.cambriaPartition)) { + return false; + } + if (correlationId == null) { + if (other.correlationId != null) { + return false; + } + } else if (!correlationId.equals(other.correlationId)) { + return false; + } + if (rpcName == null) { + if (other.rpcName != null) { + return false; + } + } else if (!rpcName.equals(other.rpcName)) { + return false; + } + if (type == null) { + if (other.type != null) { + return false; + } + } else if (!type.equals(other.type)) { + return false; + } + if (version == null) { + if (other.version != null) { + return false; + } + } else if (!version.equals(other.version)) { + return false; + } + return true; + } + +} diff --git a/controlloop/common/model-impl/appclcm/src/main/java/org/onap/policy/appclcm/util/Serialization.java b/controlloop/common/model-impl/appclcm/src/main/java/org/onap/policy/appclcm/util/Serialization.java new file mode 100644 index 000000000..7187ab1e7 --- /dev/null +++ b/controlloop/common/model-impl/appclcm/src/main/java/org/onap/policy/appclcm/util/Serialization.java @@ -0,0 +1,101 @@ +/*- + * ============LICENSE_START======================================================= + * appc + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.appclcm.util; + +import java.lang.reflect.Type; +import java.time.Instant; + +import org.onap.policy.appclcm.LCMRequest; +import org.onap.policy.appclcm.LCMResponse; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; +import com.google.gson.JsonPrimitive; +import com.google.gson.JsonSerializationContext; +import com.google.gson.JsonSerializer; + +public final class Serialization { + + public static class RequestAdapter implements JsonSerializer<LCMRequest>, JsonDeserializer<LCMRequest> { + + @Override + public JsonElement serialize(LCMRequest src, Type typeOfSrc, JsonSerializationContext context) { + JsonElement requestJson = gsonPretty.toJsonTree(src, LCMRequest.class); + JsonObject input = new JsonObject(); + input.add("input", requestJson); + + return input; + } + + @Override + public LCMRequest deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) + throws JsonParseException { + LCMRequest request = gsonPretty.fromJson(json.getAsJsonObject().get("input"), LCMRequest.class); + return request; + } + } + + public static class ResponseAdapter implements JsonSerializer<LCMResponse>, JsonDeserializer<LCMResponse> { + + @Override + public JsonElement serialize(LCMResponse src, Type typeOfSrc, JsonSerializationContext context) { + JsonElement responseJson = gsonPretty.toJsonTree(src, LCMResponse.class); + JsonObject output = new JsonObject(); + output.add("output", responseJson); + return output; + } + + @Override + public LCMResponse deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) + throws JsonParseException { + LCMResponse response = gsonPretty.fromJson(json.getAsJsonObject().get("output"), LCMResponse.class); + return response; + } + } + + public static class InstantAdapter implements JsonSerializer<Instant>, JsonDeserializer<Instant> { + + @Override + public Instant deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) + throws JsonParseException { + return Instant.parse(json.getAsString()); + } + + @Override + public JsonElement serialize(Instant src, Type typeOfSrc, JsonSerializationContext context) { + return new JsonPrimitive(src.toString()); + } + + } + + public static final Gson gsonPretty = new GsonBuilder().disableHtmlEscaping().setPrettyPrinting() + .registerTypeAdapter(Instant.class, new InstantAdapter()).create(); + + public static final Gson gson = new GsonBuilder().disableHtmlEscaping().setPrettyPrinting() + .registerTypeAdapter(LCMRequest.class, new RequestAdapter()) + .registerTypeAdapter(LCMResponse.class, new ResponseAdapter()).create(); + +} diff --git a/controlloop/common/model-impl/appclcm/src/main/resources/definitions.yaml b/controlloop/common/model-impl/appclcm/src/main/resources/definitions.yaml new file mode 100644 index 000000000..680a9929c --- /dev/null +++ b/controlloop/common/model-impl/appclcm/src/main/resources/definitions.yaml @@ -0,0 +1,118 @@ +### +# ============LICENSE_START======================================================= +# appc +# ================================================================================ +# Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. +# ================================================================================ +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============LICENSE_END========================================================= +### + +Request: + type: object + properties: + CommonHeader: + type: object + properties: + TimeStamp: + type: string + APIver: + type: string + value: '1.01' + OriginatorID: + type: string + RequestID: + type: string + pattern: "^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$" + SubRequestID: + type: string + Flags: + type: object + required: + - TimeStamp + - APIver + - OriginatorID + - RequestID + Action: + type: string + enum: + - Audit + - ActionStatus + - BlockAudits + - Configure + - HealthCheck + - Install + - LiveUpgrade + - Migrate + - ModifyConfig + - Query + - Rebuild + - Reconfigure + - Restart + - Rollback + - Scale + - Start + - Stop + - Sync + - Terminate + - Test + - Upgrade + TargetID: + type: string + ObjectID: + type: string + Payload: + type: object + required: + - CommonHeader + - Action + - TargetID +Response: + type: object + properties: + CommonHeader: + type: object + properties: + TimeStamp: + type: string + APIver: + type: string + OriginatorID: + type: string + RequestID: + type: string + SubRequestID: + type: string + Flags: + type: object + required: + - TimeStamp + - APIver + - OriginatorID + - RequestID + Status: + type: object + properties: + Code: + type: integer + Value: + type: string + required: + - Code + - Value + Payload: + type: object + required: + - CommonHeader + - Status + diff --git a/controlloop/common/model-impl/appclcm/src/test/java/org/onap/policy/appclcm/AppcLcmTest.java b/controlloop/common/model-impl/appclcm/src/test/java/org/onap/policy/appclcm/AppcLcmTest.java new file mode 100644 index 000000000..41bafe498 --- /dev/null +++ b/controlloop/common/model-impl/appclcm/src/test/java/org/onap/policy/appclcm/AppcLcmTest.java @@ -0,0 +1,244 @@ +/*- + * ============LICENSE_START======================================================= + * appclcm + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.appclcm; + +import static org.junit.Assert.*; + +import java.util.HashMap; +import java.util.UUID; + +import org.junit.Test; +import org.onap.policy.appclcm.util.Serialization; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class AppcLcmTest { + + private static final Logger logger = LoggerFactory.getLogger(AppcLcmTest.class); + + private static LCMRequestWrapper dmaapRequest; + private static LCMResponseWrapper dmaapResponse; + + static { + /* + * Construct an APPCLCM Request to be Serialized + */ + dmaapRequest = new LCMRequestWrapper(); + dmaapRequest.setCorrelationId("664be3d2-6c12-4f4b-a3e7-c349acced200" + "-" + "1"); + dmaapRequest.setRpcName("restart"); + dmaapRequest.setType("request"); + + dmaapResponse = new LCMResponseWrapper(); + dmaapResponse.setCorrelationId("664be3d2-6c12-4f4b-a3e7-c349acced200" + "-" + "1"); + dmaapResponse.setRpcName("restart"); + dmaapResponse.setType("response"); + + LCMRequest appcRequest = new LCMRequest(); + + appcRequest.setAction("restart"); + + HashMap<String, String> actionIdentifiers = new HashMap<>(); + actionIdentifiers.put("vnf-id", "trial-vnf-003"); + actionIdentifiers.put("vserver-id", "08f6c1f9-99e7-49f3-a662-c62b9f200d79"); + + appcRequest.setActionIdentifiers(actionIdentifiers); + + LCMCommonHeader commonHeader = new LCMCommonHeader(); + commonHeader.setRequestId(UUID.fromString("664be3d2-6c12-4f4b-a3e7-c349acced200")); + commonHeader.setSubRequestId("1"); + commonHeader.setOriginatorId("664be3d2-6c12-4f4b-a3e7-c349acced200"); + + appcRequest.setCommonHeader(commonHeader); + + appcRequest.setPayload(null); + + dmaapRequest.setBody(appcRequest); + + /* + * Construct an APPCLCM Response to be Serialized + */ + LCMResponse appcResponse = new LCMResponse(appcRequest); + appcResponse.getStatus().setCode(400); + appcResponse.getStatus().setMessage("Restart Successful"); + appcResponse.setPayload(null); + + dmaapResponse.setBody(appcResponse); + } + + @Test + public void testRequestSerialization() { + + /* + * Use the gson serializer to obtain json + */ + String jsonRequest = Serialization.gson.toJson(dmaapRequest, LCMRequestWrapper.class); + assertNotNull(jsonRequest); + + /* + * The serializer should have added an extra + * sub-tag called "input" that wraps the request + */ + assertTrue(jsonRequest.contains("input")); + + /* + * The common-header, request-id, and + * sub-request-id should exist + */ + assertTrue(jsonRequest.contains("common-header")); + assertTrue(jsonRequest.contains("request-id")); + assertTrue(jsonRequest.contains("sub-request-id")); + + /* + * action-identifiers should exist and contain + * a vnf-id + */ + assertTrue(jsonRequest.contains("action-identifiers")); + assertTrue(jsonRequest.contains("vnf-id")); + + /* + * The action sub-tag should exist + */ + assertTrue(jsonRequest.contains("action")); + + logger.debug("Request as JSON: " + jsonRequest + "\n\n"); + } + + @Test + public void testRequestDeserialization() { + + /* + * Convert the LCM request object into json + * so we have a string of json to use for testing + */ + String jsonRequest = Serialization.gson.toJson(dmaapRequest, LCMRequestWrapper.class); + + /* + * Use the serializer to convert the json string + * into a java object + */ + LCMRequestWrapper dmaapRequest = Serialization.gson.fromJson(jsonRequest, LCMRequestWrapper.class); + assertNotNull(dmaapRequest); + + /* + * The type of the DMAAP wrapper should be request + */ + assertEquals(dmaapRequest.getType(), "request"); + + /* + * The DMAAP wrapper must have a body as that is + * the true APPC request + */ + assertNotNull(dmaapRequest.getBody()); + LCMRequest appcRequest = dmaapRequest.getBody(); + assertNotNull(appcRequest); + + /* + * The common header should not be null + */ + assertNotNull(appcRequest.getCommonHeader()); + + /* + * The action should not be null and should be + * set to restart + */ + assertNotNull(appcRequest.getAction()); + assertEquals(appcRequest.getAction(), "restart"); + + /* + * The action-identifiers should not be null + * and should contain a vnf-id + */ + assertNotNull(appcRequest.getActionIdentifiers()); + assertNotNull(appcRequest.getActionIdentifiers().get("vnf-id")); + + logger.debug("Request as a Java Object: \n" + appcRequest.toString() + "\n\n"); + } + + @Test + public void testResponseSerialization() { + + /* + * Use the serializer to convert the object into json + */ + String jsonResponse = Serialization.gson.toJson(dmaapResponse, LCMResponseWrapper.class); + assertNotNull(jsonResponse); + + /* + * The serializer should have added an extra + * sub-tag called "input" that wraps the request + */ + assertTrue(jsonResponse.contains("output")); + + /* + * The response should contain a common-header, + * request-id, sub-request-id, and status + */ + assertTrue(jsonResponse.contains("common-header")); + assertTrue(jsonResponse.contains("request-id")); + assertTrue(jsonResponse.contains("sub-request-id")); + assertTrue(jsonResponse.contains("status")); + + logger.debug("Response as JSON: " + jsonResponse + "\n\n"); + } + + @Test + public void testResponseDeserialization() { + /* + * Convert the LCM response object into json + * so we have a string of json to use for testing + */ + String jsonResponse = Serialization.gson.toJson(dmaapResponse, LCMResponseWrapper.class); + + /* + * Use the serializer to convert the json string + * into a java object + */ + LCMResponseWrapper dmaapResponse = Serialization.gson.fromJson(jsonResponse, LCMResponseWrapper.class); + assertNotNull(dmaapResponse); + + /* + * The type of the DMAAP wrapper should be response + */ + assertEquals(dmaapResponse.getType(), "response"); + + /* + * The DMAAP wrapper must have a body as that is + * the true APPC response + */ + assertNotNull(dmaapResponse.getBody()); + LCMResponse appcResponse = dmaapResponse.getBody(); + assertNotNull(appcResponse); + + /* + * The common header should not be null + */ + assertNotNull(appcResponse.getCommonHeader()); + + /* + * The status should not be null and the + * status code should be 400 + */ + assertNotNull(appcResponse.getStatus()); + assertEquals(appcResponse.getStatus().getCode(), 400); + + logger.debug("Response as a Java Object: \n" + appcResponse.toString() + "\n\n"); + } +} diff --git a/controlloop/common/model-impl/pom.xml b/controlloop/common/model-impl/pom.xml index 5d18e4916..e96befbf7 100644 --- a/controlloop/common/model-impl/pom.xml +++ b/controlloop/common/model-impl/pom.xml @@ -35,6 +35,7 @@ <modules> <module>aai</module> <module>appc</module> + <module>appclcm</module> <module>events</module> <module>mso</module> <module>rest</module> diff --git a/controlloop/templates/template.demo/pom.xml b/controlloop/templates/template.demo/pom.xml index c0aef2074..5436b5ebd 100644 --- a/controlloop/templates/template.demo/pom.xml +++ b/controlloop/templates/template.demo/pom.xml @@ -67,6 +67,18 @@ </dependency> <dependency> <groupId>org.onap.policy.drools-applications</groupId> + <artifactId>appclcm</artifactId> + <version>${project.version}</version> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>org.onap.policy.drools-applications</groupId> + <artifactId>trafficgenerator</artifactId> + <version>${project.version}</version> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>org.onap.policy.drools-applications</groupId> <artifactId>vfc</artifactId> <version>${project.version}</version> <scope>provided</scope> @@ -151,6 +163,12 @@ </dependency> <dependency> <groupId>org.onap.policy.drools-applications</groupId> + <artifactId>actor.appclcm</artifactId> + <version>${project.version}</version> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>org.onap.policy.drools-applications</groupId> <artifactId>actor.vfc</artifactId> <version>${project.version}</version> <scope>provided</scope> diff --git a/controlloop/templates/template.demo/src/main/resources/ControlLoop_Template_xacml_guard.drl b/controlloop/templates/template.demo/src/main/resources/ControlLoop_Template_xacml_guard.drl index 276e64b7d..aa1f1e977 100644 --- a/controlloop/templates/template.demo/src/main/resources/ControlLoop_Template_xacml_guard.drl +++ b/controlloop/templates/template.demo/src/main/resources/ControlLoop_Template_xacml_guard.drl @@ -32,6 +32,11 @@ import org.onap.policy.controlloop.eventmanager.ControlLoopOperationManager; import org.onap.policy.appc.Request; import org.onap.policy.appc.Response; import org.onap.policy.appc.CommonHeader; +import org.onap.policy.appclcm.LCMRequestWrapper; +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.vfc.VFCRequest; import org.onap.policy.vfc.VFCManager; import org.onap.policy.guard.PolicyGuard; @@ -490,7 +495,7 @@ rule "${policyName}.EVENT.MANAGER.OPERATION.LOCKED.GUARD_PERMITTED" case "APPC": - if (request instanceof Request) { + if (request instanceof Request || request instanceof LCMRequestWrapper) { Engine.deliver("UEB", "APPC-CL", request); } break; @@ -771,6 +776,122 @@ rule "${policyName}.APPC.RESPONSE.CLEANUP" // retract($response); end + +/* +* +* This rule responds to APPC Response Events using the new LCM interface provided by appc +* +*/ +rule "${policyName}.APPC.LCM.RESPONSE" + when + $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" ) + $event : VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName(), closedLoopEventStatus == ControlLoopEventStatus.ONSET ) + $manager : ControlLoopEventManager( closedLoopControlName == $event.closedLoopControlName, requestID == $event.requestID ) + $operation : ControlLoopOperationManager( onset.closedLoopControlName == $event.closedLoopControlName, onset.requestID == $event.requestID ) + $opTimer : OperationTimer( closedLoopControlName == $event.closedLoopControlName, requestID == $event.requestID.toString() ) + $lock : TargetLock (requestID == $event.requestID) + $response : LCMResponseWrapper( getBody().getCommonHeader().getRequestId() == $event.requestID ) + then + // + // Logging + // + Logger.info("------------------------------------------------------------------------------------------------"); + Logger.metrics(Instant.now() + " " + drools.getRule().getName() + " " + drools.getRule().getPackage()); + Logger.metrics($params); + Logger.metrics($event); + Logger.metrics($manager); + Logger.metrics($operation); + Logger.metrics($opTimer); + Logger.metrics($lock); + Logger.metrics($response); + // + // Get the result of the operation + // + PolicyResult policyResult = $operation.onResponse($response); + if (policyResult != null) { + Logger.info("operation finished with result: " + policyResult); + // + // This Operation has completed, construct a notification showing our results. (DB write - end operation) + // + VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event); + notification.from = "policy"; + notification.policyName = drools.getRule().getName(); + notification.policyScope = "${policyScope}"; + notification.policyVersion = "${policyVersion}"; + notification.message = $operation.getOperationHistory(); + notification.history = $operation.getHistory(); + if (policyResult.equals(PolicyResult.SUCCESS)) { + notification.notification = ControlLoopNotificationType.OPERATION_SUCCESS; + // + // Let interested parties know + // + Engine.deliver("UEB", "POLICY-CL-MGT", notification); + } else { + notification.notification = ControlLoopNotificationType.OPERATION_FAILURE; + // + // Let interested parties know + // + Engine.deliver("UEB", "POLICY-CL-MGT", notification); + } + // + // Ensure the operation is complete + // + if ($operation.isOperationComplete() == true) { + // + // 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 + // + } + // + // We are going to retract these objects from memory + // + retract($response); +end + +/* +* +* Clean Up any lingering LCM reponses +* +*/ +rule "${policyName}.APPC.LCM.RESPONSE.CLEANUP" + when + $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" ) + $response : LCMResponseWrapper($id : getBody().getCommonHeader().getRequestId ) + not ( VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName(), requestID == $id, closedLoopEventStatus == ControlLoopEventStatus.ONSET ) ) + then + // + // Logging + // + Logger.info("------------------------------------------------------------------------------------------------"); + Logger.metrics(Instant.now() + " " + drools.getRule().getName() + " " + drools.getRule().getPackage()); + Logger.metrics($params); + // + // Retract it + // + retract($response); +end + /* * * This is the timer that manages the timeout for an individual operation. diff --git a/controlloop/templates/template.demo/src/test/java/org/onap/policy/template/demo/AaiSimulatorTest.java b/controlloop/templates/template.demo/src/test/java/org/onap/policy/template/demo/AaiSimulatorTest.java index 3bdeca1fc..71c6e3a29 100644 --- a/controlloop/templates/template.demo/src/test/java/org/onap/policy/template/demo/AaiSimulatorTest.java +++ b/controlloop/templates/template.demo/src/test/java/org/onap/policy/template/demo/AaiSimulatorTest.java @@ -27,7 +27,6 @@ import java.util.UUID; import org.junit.AfterClass; import org.junit.BeforeClass; -import org.junit.Ignore; import org.junit.Test; import org.onap.policy.aai.AAIGETResponse; import org.onap.policy.aai.AAINQF199.AAINQF199Manager; diff --git a/controlloop/templates/template.demo/src/test/java/org/onap/policy/template/demo/ControlLoopXacmlGuardTest.java b/controlloop/templates/template.demo/src/test/java/org/onap/policy/template/demo/ControlLoopXacmlGuardTest.java index 23f03f7e8..8c0b99462 100644 --- a/controlloop/templates/template.demo/src/test/java/org/onap/policy/template/demo/ControlLoopXacmlGuardTest.java +++ b/controlloop/templates/template.demo/src/test/java/org/onap/policy/template/demo/ControlLoopXacmlGuardTest.java @@ -32,14 +32,16 @@ import java.time.Instant; import java.util.HashMap; import java.util.UUID; +import org.junit.AfterClass; +import org.junit.BeforeClass; import org.junit.Ignore; import org.junit.Test; import org.kie.api.runtime.KieSession; import org.kie.api.runtime.rule.FactHandle; -import org.onap.policy.appc.Request; -import org.onap.policy.appc.Response; -import org.onap.policy.appc.ResponseCode; -import org.onap.policy.appc.ResponseValue; +import org.onap.policy.appclcm.LCMRequest; +import org.onap.policy.appclcm.LCMRequestWrapper; +import org.onap.policy.appclcm.LCMResponse; +import org.onap.policy.appclcm.LCMResponseWrapper; import org.onap.policy.controlloop.ControlLoopEventStatus; import org.onap.policy.controlloop.ControlLoopNotificationType; @@ -47,6 +49,7 @@ import org.onap.policy.controlloop.VirtualControlLoopEvent; import org.onap.policy.controlloop.VirtualControlLoopNotification; import org.onap.policy.controlloop.policy.ControlLoopPolicy; import org.onap.policy.controlloop.policy.TargetType; +import org.onap.policy.drools.http.server.HttpServletServer; import org.onap.policy.drools.impl.PolicyEngineJUnitImpl; import org.onap.policy.guard.PolicyGuard; import org.slf4j.Logger; @@ -55,8 +58,22 @@ import org.slf4j.LoggerFactory; public class ControlLoopXacmlGuardTest { + @BeforeClass + public static void setUpSimulator() { + try { + Util.buildAaiSim(); + } catch (InterruptedException e) { + fail(e.getMessage()); + } + } + + @AfterClass + public static void tearDownSimulator() { + HttpServletServer.factory.destroy(); + } + private static final Logger logger = LoggerFactory.getLogger(ControlLoopXacmlGuardTest.class); - + @Test public void test() { try { @@ -216,8 +233,10 @@ public class ControlLoopXacmlGuardTest { obj = engine.subscribe("UEB", "APPC-CL"); assertNotNull(obj); - assertTrue(obj instanceof Request); - assertTrue(((Request)obj).CommonHeader.SubRequestID.equals("1")); + assertTrue(obj instanceof LCMRequestWrapper); + LCMRequestWrapper dmaapRequest = (LCMRequestWrapper) obj; + LCMRequest appcRequest = dmaapRequest.getBody(); + assertTrue(appcRequest.getCommonHeader().getSubRequestId().equals("1")); logger.debug("\n============ APP-C Got request!!! ===========\n"); // @@ -232,11 +251,12 @@ public class ControlLoopXacmlGuardTest { // // Now we are going to success it // - Response response = new Response((Request) obj); - response.Status.Code = ResponseCode.SUCCESS.getValue(); - response.Status.Value = ResponseValue.SUCCESS.toString(); - response.Status.Description = "AppC success"; - kieSession.insert(response); + LCMResponseWrapper dmaapResponse = new LCMResponseWrapper(); + LCMResponse appcResponse = new LCMResponse(appcRequest); + appcResponse.getStatus().setCode(400); + appcResponse.getStatus().setMessage("AppC success"); + dmaapResponse.setBody(appcResponse); + kieSession.insert(dmaapResponse); // // Give it some time to process // @@ -248,7 +268,7 @@ public class ControlLoopXacmlGuardTest { // // now wait for it to finish // - Thread.sleep(5000); + Thread.sleep(15000); // // Ensure they released the lock // @@ -288,6 +308,7 @@ public class ControlLoopXacmlGuardTest { Object fact = kieSession.getObject(handle); assertEquals("", "org.onap.policy.controlloop.Params", fact.getClass().getName()); } + kieSession.dispose(); } @@ -307,7 +328,7 @@ public class ControlLoopXacmlGuardTest { event.target = "vserver.vserver-name"; event.closedLoopAlarmStart = Instant.now().minusSeconds(5); event.closedLoopAlarmEnd = Instant.now(); - event.AAI = new HashMap<String, String>(); + event.AAI = new HashMap<>(); event.AAI.put("cloud-region.identity-url", "foo"); event.AAI.put("vserver.selflink", "bar"); event.AAI.put("vserver.is-closed-loop-disabled", "false"); @@ -322,7 +343,7 @@ public class ControlLoopXacmlGuardTest { event.requestID = requestID; event.target = "vserver.vserver-name"; event.closedLoopAlarmStart = Instant.now(); - event.AAI = new HashMap<String, String>(); + event.AAI = new HashMap<>(); event.AAI.put("cloud-region.identity-url", "foo"); event.AAI.put("vserver.selflink", "bar"); event.AAI.put("vserver.is-closed-loop-disabled", "false"); @@ -350,7 +371,7 @@ public class ControlLoopXacmlGuardTest { // // add some aai // - event.AAI = new HashMap<String, String>(); + event.AAI = new HashMap<>(); event.AAI.put("cloud-region.identity-url", "foo"); event.AAI.put("vserver.selflink", "bar"); event.AAI.put("vserver.vserver-name", "vmfoo"); diff --git a/controlloop/templates/template.demo/src/test/java/org/onap/policy/template/demo/Util.java b/controlloop/templates/template.demo/src/test/java/org/onap/policy/template/demo/Util.java index 61be1535e..502ef7c1d 100644 --- a/controlloop/templates/template.demo/src/test/java/org/onap/policy/template/demo/Util.java +++ b/controlloop/templates/template.demo/src/test/java/org/onap/policy/template/demo/Util.java @@ -239,6 +239,10 @@ public final class Util { "src/main/resources/frequency_limiter_template.xml", "src/test/resources/xacml/autogenerated_frequency_limiter_migrate.xml"); + PolicyGuardYamlToXacml.fromYamlToXacml("src/test/resources/yaml/policy_guard_appc_modifyconfig.yaml", + "src/main/resources/frequency_limiter_template.xml", + "src/test/resources/xacml/autogenerated_frequency_limiter_modifyconfig.xml"); + PolicyGuardYamlToXacml.fromYamlToXacmlBlacklist("src/test/resources/yaml/policy_guard_appc_restart_blacklist.yaml", "src/main/resources/blacklist_template.xml", "src/test/resources/xacml/autogenerated_blacklist.xml"); 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 new file mode 100644 index 000000000..a34ee6cd1 --- /dev/null +++ b/controlloop/templates/template.demo/src/test/java/org/onap/policy/template/demo/VCPEControlLoopTest.java @@ -0,0 +1,441 @@ +/*- + * ============LICENSE_START======================================================= + * demo + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.template.demo; + +import static org.junit.Assert.*; + +import java.io.IOException; +import java.net.URLEncoder; +import java.time.Instant; +import java.util.HashMap; +import java.util.UUID; + +import org.junit.Test; +import org.kie.api.runtime.KieSession; +import org.kie.api.runtime.rule.FactHandle; +import org.onap.policy.appclcm.LCMRequest; +import org.onap.policy.appclcm.LCMRequestWrapper; +import org.onap.policy.appclcm.LCMResponse; +import org.onap.policy.appclcm.LCMResponseWrapper; +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.policy.TargetType; +import org.onap.policy.drools.impl.PolicyEngineJUnitImpl; +import org.onap.policy.guard.PolicyGuard; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class VCPEControlLoopTest { + + private static final Logger logger = LoggerFactory.getLogger(VCPEControlLoopTest.class); + + private KieSession kieSession; + private Util.Pair<ControlLoopPolicy, String> pair; + private PolicyEngineJUnitImpl engine; + + @Test + public void successTest() { + + /* + * Start the kie session + */ + try { + kieSession = startSession("src/main/resources/ControlLoop_Template_xacml_guard.drl", + "src/test/resources/yaml/policy_ControlLoop_vCPE.yaml", + "service=ServiceTest;resource=ResourceTest;type=operational", + "CL_vCPE", + "org.onap.closed_loop.ServiceTest:VNFS:1.0.0"); + } catch (IOException e) { + e.printStackTrace(); + logger.debug("Could not create kieSession"); + fail("Could not create kieSession"); + } + + /* + * Create a thread to continuously fire rules + * until main thread calls halt + */ + new Thread( new Runnable() { + @Override + public void run() { + kieSession.fireUntilHalt(); + } + } ).start(); + + /* + * Create a unique requestId and a unique trigger source + */ + UUID requestID = UUID.randomUUID(); + String triggerSourceName = "foobartriggersource36"; + + /* + * This will be the object returned from the PolicyEngine + */ + Object obj = null; + + /* + * Simulate an onset event the policy engine will + * receive from DCAE to kick off processing through + * the rules. + */ + try { + sendOnset(pair.a, requestID, triggerSourceName); + } catch (InterruptedException e) { + e.printStackTrace(); + logger.debug("Unable to send onset event"); + fail("Unable to send onset event"); + } + + /* + * Pull the object that was sent out to DMAAP and make + * sure it is a ControlLoopNoticiation of type active + */ + obj = engine.subscribe("UEB", "POLICY-CL-MGT"); + assertNotNull(obj); + assertTrue(obj instanceof VirtualControlLoopNotification); + assertTrue(((VirtualControlLoopNotification)obj).notification.equals(ControlLoopNotificationType.ACTIVE)); + + /* + * Give the control loop time to acquire a lock + */ + try { + Thread.sleep(4000); + } catch (InterruptedException e) { + e.printStackTrace(); + logger.debug("An interrupt Exception was thrown"); + fail("An interrupt Exception was thrown"); + } + + /* + * The fact should be ready to query guard now to see + * if a ModifyConfig recipe is allowed + */ + obj = engine.subscribe("UEB", "POLICY-CL-MGT"); + assertNotNull(obj); + logger.debug("\n\n####################### GOING TO QUERY GUARD about Restart!!!!!!"); + logger.debug("Rule: {} Message {}", ((VirtualControlLoopNotification)obj).policyName, ((VirtualControlLoopNotification)obj).message); + + /* + * Make sure the object is an instance of a ControlLoopNotification + * and is of type operation + */ + assertTrue(obj instanceof VirtualControlLoopNotification); + assertTrue(((VirtualControlLoopNotification)obj).notification.equals(ControlLoopNotificationType.OPERATION)); + + try { + Thread.sleep(4000); + } catch (InterruptedException e) { + e.printStackTrace(); + logger.debug("An interrupt Exception was thrown"); + fail("An interrupt Exception was thrown"); + } + + /* + * The guard response should be received at this point + */ + obj = engine.subscribe("UEB", "POLICY-CL-MGT"); + assertNotNull(obj); + logger.debug("Rule: {} Message {}", ((VirtualControlLoopNotification)obj).policyName, ((VirtualControlLoopNotification)obj).message); + + /* + * The object should be a ControlLoopNotification with type operation + */ + assertTrue(obj instanceof VirtualControlLoopNotification); + assertTrue(((VirtualControlLoopNotification)obj).notification.equals(ControlLoopNotificationType.OPERATION)); + + /* + * See if Guard permits this action, if it does + * not then the test should fail + */ + if (((VirtualControlLoopNotification)obj).message.contains("Guard result: Permit")) { + + /* + * A notification should be sent out of the Policy + * Engine at this point, it will be of type operation + */ + obj = engine.subscribe("UEB", "POLICY-CL-MGT"); + assertNotNull(obj); + logger.debug("Rule: {} Message {}", ((VirtualControlLoopNotification)obj).policyName, ((VirtualControlLoopNotification)obj).message); + + /* A notification should be sent out of the Policy + * Engine at this point, it will be of type operation + */ + assertTrue(obj instanceof VirtualControlLoopNotification); + assertTrue(((VirtualControlLoopNotification)obj).notification.equals(ControlLoopNotificationType.OPERATION)); + + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + e.printStackTrace(); + logger.debug("An interrupt Exception was thrown"); + fail("An interrupt Exception was thrown"); + } + + /* + * Obtain the request sent from the Policy Engine + */ + obj = engine.subscribe("UEB", "APPC-CL"); + assertNotNull(obj); + + /* + * The request should be of type LCMRequestWrapper + * and the subrequestid should be 1 + */ + assertTrue(obj instanceof LCMRequestWrapper); + LCMRequestWrapper dmaapRequest = (LCMRequestWrapper) obj; + LCMRequest appcRequest = dmaapRequest.getBody(); + assertTrue(appcRequest.getCommonHeader().getSubRequestId().equals("1")); + + logger.debug("\n============ APPC received the request!!! ===========\n"); + + /* + * Give some time for processing + */ + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + e.printStackTrace(); + logger.debug("An interrupt Exception was thrown"); + fail("An interrupt Exception was thrown"); + } + + /* + * Simulate a success response from APPC and insert + * the response into the working memory + */ + LCMResponseWrapper dmaapResponse = new LCMResponseWrapper(); + LCMResponse appcResponse = new LCMResponse(appcRequest); + appcResponse.getStatus().setCode(400); + appcResponse.getStatus().setMessage("AppC success"); + dmaapResponse.setBody(appcResponse); + kieSession.insert(dmaapResponse); + + /* + * Give time for processing + */ + try { + Thread.sleep(4000); + } catch (InterruptedException e) { + e.printStackTrace(); + logger.debug("An interrupt Exception was thrown"); + fail("An interrupt Exception was thrown"); + } + + /* + * Make sure the next notification is delivered + */ + obj = engine.subscribe("UEB", "POLICY-CL-MGT"); + assertNotNull(obj); + logger.debug("Rule: {} Message {}", ((VirtualControlLoopNotification)obj).policyName, ((VirtualControlLoopNotification)obj).message); + + /* + * The ControlLoopNotification should be + * an OPERATION_SUCCESS + */ + assertTrue(obj instanceof VirtualControlLoopNotification); + assertTrue(((VirtualControlLoopNotification)obj).notification.equals(ControlLoopNotificationType.OPERATION_SUCCESS)); + + /* + * Now simulate the abatement sent from DCAE + */ + try { + sendAbatement(pair.a, requestID, triggerSourceName); + } catch (InterruptedException e1) { + e1.printStackTrace(); + logger.debug("Abatement could not be sent"); + fail("Abatement could not be sent"); + } + + /* + * Give time to finish processing + */ + try { + Thread.sleep(20000); + } catch (InterruptedException e) { + e.printStackTrace(); + logger.debug("An interrupt Exception was thrown"); + fail("An interrupt Exception was thrown"); + } + + /* + * This should be the final notification from the Policy Engine + */ + obj = engine.subscribe("UEB", "POLICY-CL-MGT"); + assertNotNull(obj); + logger.debug("Rule: {} Message {}", ((VirtualControlLoopNotification)obj).policyName, ((VirtualControlLoopNotification)obj).message); + + /* + * The ControlLoopNotification should be of type FINAL_SUCCESS + */ + assertTrue(obj instanceof VirtualControlLoopNotification); + assertTrue(((VirtualControlLoopNotification)obj).notification.equals(ControlLoopNotificationType.FINAL_SUCCESS)); + + /* + * One final check to make sure the lock is released + */ + assertFalse(PolicyGuard.isLocked(TargetType.VM, triggerSourceName, requestID)); + } + else { + fail("Operation Denied by Guard"); + } + + /* + * This will stop the thread that is firing the rules + */ + kieSession.halt(); + + /* + * The only fact in memory should be Params + */ + assertEquals(1, kieSession.getFactCount()); + + /* + * Print what's left in memory + */ + dumpFacts(kieSession); + + /* + * Gracefully shut down the kie session + */ + kieSession.dispose(); + } + + /** + * This method will start a kie session and instantiate + * the Policy Engine. + * + * @param droolsTemplate + * the DRL rules file + * @param yamlFile + * the yaml file containing the policies + * @param policyScope + * scope for policy + * @param policyName + * name of the policy + * @param policyVersion + * version of the policy + * @return the kieSession to be used to insert facts + * @throws IOException + */ + private KieSession startSession(String droolsTemplate, + String yamlFile, + String policyScope, + String policyName, + String policyVersion) throws IOException { + + /* + * Load policies from yaml + */ + pair = Util.loadYaml(yamlFile); + assertNotNull(pair); + assertNotNull(pair.a); + assertNotNull(pair.a.getControlLoop()); + assertNotNull(pair.a.getControlLoop().getControlLoopName()); + assertTrue(pair.a.getControlLoop().getControlLoopName().length() > 0); + + /* + * Construct a kie session + */ + final KieSession kieSession = Util.buildContainer(droolsTemplate, + pair.a.getControlLoop().getControlLoopName(), + policyScope, + policyName, + policyVersion, + URLEncoder.encode(pair.b, "UTF-8")); + + /* + * Retrieve the Policy Engine + */ + engine = (PolicyEngineJUnitImpl) kieSession.getGlobal("Engine"); + + logger.debug("============"); + logger.debug(URLEncoder.encode(pair.b, "UTF-8")); + logger.debug("============"); + + return kieSession; + } + + /** + * This method is used to simulate event messages from DCAE + * that start the control loop (onset message). + * + * @param policy the controlLoopName comes from the policy + * @param requestID the requestId for this event + * @param triggerSourceName + * @throws InterruptedException + */ + protected void sendOnset(ControlLoopPolicy policy, UUID requestID, String triggerSourceName) throws InterruptedException { + VirtualControlLoopEvent event = new VirtualControlLoopEvent(); + event.closedLoopControlName = policy.getControlLoop().getControlLoopName(); + event.requestID = requestID; + event.target = "vserver.vserver-name"; + event.closedLoopAlarmStart = Instant.now(); + event.AAI = new HashMap<>(); + event.AAI.put("cloud-region.identity-url", "foo"); + event.AAI.put("vserver.selflink", "bar"); + event.AAI.put("vserver.is-closed-loop-disabled", "false"); + event.AAI.put("vserver.vserver-name", "testGenericVnfName"); + event.AAI.put("generic-vnf.vnf-id", "testGenericVnfId"); + event.closedLoopEventStatus = ControlLoopEventStatus.ONSET; + kieSession.insert(event); + Thread.sleep(1000); + } + + /** + * This method is used to simulate event messages from DCAE + * that end the control loop (abatement message). + * + * @param policy the controlLoopName comes from the policy + * @param requestID the requestId for this event + * @param triggerSourceName + * @throws InterruptedException + */ + protected void sendAbatement(ControlLoopPolicy policy, UUID requestID, String triggerSourceName) throws InterruptedException { + VirtualControlLoopEvent event = new VirtualControlLoopEvent(); + event.closedLoopControlName = policy.getControlLoop().getControlLoopName(); + event.requestID = requestID; + event.target = "vserver.vserver-name"; + event.closedLoopAlarmStart = Instant.now().minusSeconds(5); + event.closedLoopAlarmEnd = Instant.now(); + event.AAI = new HashMap<>(); + event.AAI.put("cloud-region.identity-url", "foo"); + event.AAI.put("vserver.selflink", "bar"); + event.AAI.put("vserver.is-closed-loop-disabled", "false"); + event.AAI.put("generic-vnf.vnf-name", "testGenericVnfName"); + event.closedLoopEventStatus = ControlLoopEventStatus.ABATED; + kieSession.insert(event); + } + + /** + * This method will dump all the facts in the working memory. + * + * @param kieSession the session containing the facts + */ + public void dumpFacts(KieSession kieSession) { + logger.debug("Fact Count: {}", kieSession.getFactCount()); + for (FactHandle handle : kieSession.getFactHandles()) { + logger.debug("FACT: {}", handle); + } + } +} diff --git a/controlloop/templates/template.demo/src/test/java/org/onap/policy/template/demo/VFWControlLoopTest.java b/controlloop/templates/template.demo/src/test/java/org/onap/policy/template/demo/VFWControlLoopTest.java new file mode 100644 index 000000000..25920e8b5 --- /dev/null +++ b/controlloop/templates/template.demo/src/test/java/org/onap/policy/template/demo/VFWControlLoopTest.java @@ -0,0 +1,435 @@ +/*- + * ============LICENSE_START======================================================= + * demo + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.template.demo; + +import static org.junit.Assert.*; + +import java.io.IOException; +import java.net.URLEncoder; +import java.time.Instant; +import java.util.HashMap; +import java.util.UUID; + +import org.junit.Test; +import org.kie.api.runtime.KieSession; +import org.kie.api.runtime.rule.FactHandle; +import org.onap.policy.appc.Request; +import org.onap.policy.appc.Response; +import org.onap.policy.appc.ResponseCode; +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.policy.TargetType; +import org.onap.policy.drools.impl.PolicyEngineJUnitImpl; +import org.onap.policy.guard.PolicyGuard; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class VFWControlLoopTest { + + private static final Logger logger = LoggerFactory.getLogger(VFWControlLoopTest.class); + + private KieSession kieSession; + private Util.Pair<ControlLoopPolicy, String> pair; + private PolicyEngineJUnitImpl engine; + + @Test + public void successTest() { + + /* + * Start the kie session + */ + try { + kieSession = startSession("src/main/resources/ControlLoop_Template_xacml_guard.drl", + "src/test/resources/yaml/policy_ControlLoop_vFW.yaml", + "service=ServiceDemo;resource=Res1Demo;type=operational", + "CL_vFW", + "org.onap.closed_loop.ServiceDemo:VNFS:1.0.0"); + } catch (IOException e) { + e.printStackTrace(); + logger.debug("Could not create kieSession"); + fail("Could not create kieSession"); + } + + /* + * Create a thread to continuously fire rules + * until main thread calls halt + */ + new Thread( new Runnable() { + @Override + public void run() { + kieSession.fireUntilHalt(); + } + } ).start(); + + /* + * Create a unique requestId and a unique trigger source + */ + UUID requestID = UUID.randomUUID(); + String triggerSourceName = "foobartriggersource36"; + + /* + * This will be the object returned from the PolicyEngine + */ + Object obj = null; + + /* + * Simulate an onset event the policy engine will + * receive from DCAE to kick off processing through + * the rules + */ + try { + sendOnset(pair.a, requestID, triggerSourceName); + } catch (InterruptedException e) { + e.printStackTrace(); + logger.debug("Unable to send onset event"); + fail("Unable to send onset event"); + } + + /* + * Pull the object that was sent out to DMAAP and make + * sure it is a ControlLoopNoticiation of type active + */ + obj = engine.subscribe("UEB", "POLICY-CL-MGT"); + assertNotNull(obj); + assertTrue(obj instanceof VirtualControlLoopNotification); + assertTrue(((VirtualControlLoopNotification)obj).notification.equals(ControlLoopNotificationType.ACTIVE)); + + /* + * Give the control loop time to acquire a lock + */ + try { + Thread.sleep(4000); + } catch (InterruptedException e) { + e.printStackTrace(); + logger.debug("An interrupt Exception was thrown"); + fail("An interrupt Exception was thrown"); + } + + /* + * The fact should be ready to query guard now to see + * if a ModifyConfig recipe is allowed + */ + obj = engine.subscribe("UEB", "POLICY-CL-MGT"); + assertNotNull(obj); + logger.debug("\n\n####################### GOING TO QUERY GUARD about ModifyConfig!!!!!!"); + logger.debug("Rule: {} Message {}", ((VirtualControlLoopNotification)obj).policyName, ((VirtualControlLoopNotification)obj).message); + + /* + * Make sure the object is an instance of a ControlLoopNotification + * and is of type operation + */ + assertTrue(obj instanceof VirtualControlLoopNotification); + assertTrue(((VirtualControlLoopNotification)obj).notification.equals(ControlLoopNotificationType.OPERATION)); + + try { + Thread.sleep(4000); + } catch (InterruptedException e) { + e.printStackTrace(); + logger.debug("An interrupt Exception was thrown"); + fail("An interrupt Exception was thrown"); + } + + /* + * The guard response should be received at this point + */ + obj = engine.subscribe("UEB", "POLICY-CL-MGT"); + assertNotNull(obj); + logger.debug("Rule: {} Message {}", ((VirtualControlLoopNotification)obj).policyName, ((VirtualControlLoopNotification)obj).message); + + /* + * The object should be a ControlLoopNotification with type operation + */ + assertTrue(obj instanceof VirtualControlLoopNotification); + assertTrue(((VirtualControlLoopNotification)obj).notification.equals(ControlLoopNotificationType.OPERATION)); + + /* + * See if Guard permits this action, if it does + * not then the test should fail + */ + if (((VirtualControlLoopNotification)obj).message.contains("Guard result: Permit")) { + + /* + * Obtain the ControlLoopNoticiation, it should be of type operation + */ + obj = engine.subscribe("UEB", "POLICY-CL-MGT"); + assertNotNull(obj); + logger.debug("Rule: {} Message {}", ((VirtualControlLoopNotification)obj).policyName, ((VirtualControlLoopNotification)obj).message); + + /* + * A notification should be sent out of the Policy + * Engine at this point, it will be of type operation + */ + assertTrue(obj instanceof VirtualControlLoopNotification); + assertTrue(((VirtualControlLoopNotification)obj).notification.equals(ControlLoopNotificationType.OPERATION)); + + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + e.printStackTrace(); + logger.debug("An interrupt Exception was thrown"); + fail("An interrupt Exception was thrown"); + } + + /* + * Obtain the request sent from the Policy Engine + */ + obj = engine.subscribe("UEB", "APPC-CL"); + assertNotNull(obj); + + /* + * The request should be of type Request + * and the subrequestid should be 1 + */ + assertTrue(obj instanceof Request); + assertTrue(((Request)obj).getCommonHeader().SubRequestID.equals("1")); + + logger.debug("\n============ APPC received the request!!! ===========\n"); + + /* + * Give some time for processing + */ + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + e.printStackTrace(); + logger.debug("An interrupt Exception was thrown"); + fail("An interrupt Exception was thrown"); + } + + /* + * Simulate a success response from APPC and insert + * the response into the working memory + */ + Response appcResponse = new Response((Request)obj); + appcResponse.getStatus().Code = ResponseCode.SUCCESS.getValue(); + appcResponse.getStatus().Description = "AppC success"; + kieSession.insert(appcResponse); + + /* + * Give time for processing + */ + try { + Thread.sleep(4000); + } catch (InterruptedException e) { + e.printStackTrace(); + logger.debug("An interrupt Exception was thrown"); + fail("An interrupt Exception was thrown"); + } + + /* + * Make sure the next notification is delivered + */ + obj = engine.subscribe("UEB", "POLICY-CL-MGT"); + assertNotNull(obj); + logger.debug("Rule: {} Message {}", ((VirtualControlLoopNotification)obj).policyName, ((VirtualControlLoopNotification)obj).message); + + /* + * The ControlLoopNotification should be + * an OPERATION_SUCCESS + */ + assertTrue(obj instanceof VirtualControlLoopNotification); + assertTrue(((VirtualControlLoopNotification)obj).notification.equals(ControlLoopNotificationType.OPERATION_SUCCESS)); + + /* + * Now simulate the abatement sent from DCAE + */ + try { + sendAbatement(pair.a, requestID, triggerSourceName); + } catch (InterruptedException e1) { + e1.printStackTrace(); + logger.debug("Abatement could not be sent"); + fail("Abatement could not be sent"); + } + + /* + * Give time to finish processing + */ + try { + Thread.sleep(20000); + } catch (InterruptedException e) { + e.printStackTrace(); + logger.debug("An interrupt Exception was thrown"); + fail("An interrupt Exception was thrown"); + } + + /* + * This should be the final notification from the Policy Engine + */ + obj = engine.subscribe("UEB", "POLICY-CL-MGT"); + assertNotNull(obj); + logger.debug("Rule: {} Message {}", ((VirtualControlLoopNotification)obj).policyName, ((VirtualControlLoopNotification)obj).message); + + /* + * The ControlLoopNotification should be of type FINAL_SUCCESS + */ + assertTrue(obj instanceof VirtualControlLoopNotification); + assertTrue(((VirtualControlLoopNotification)obj).notification.equals(ControlLoopNotificationType.FINAL_SUCCESS)); + + /* + * One final check to make sure the lock is released + */ + assertFalse(PolicyGuard.isLocked(TargetType.VM, triggerSourceName, requestID)); + } + else { + fail("Operation Denied by Guard"); + } + + /* + * This will stop the thread that is firing the rules + */ + kieSession.halt(); + + /* + * The only fact in memory should be Params + */ + assertEquals(1, kieSession.getFactCount()); + + /* + * Print what's left in memory + */ + dumpFacts(kieSession); + + /* + * Gracefully shut down the kie session + */ + kieSession.dispose(); + } + + /** + * This method will start a kie session and instantiate + * the Policy Engine. + * + * @param droolsTemplate + * the DRL rules file + * @param yamlFile + * the yaml file containing the policies + * @param policyScope + * scope for policy + * @param policyName + * name of the policy + * @param policyVersion + * version of the policy + * @return the kieSession to be used to insert facts + * @throws IOException + */ + private KieSession startSession(String droolsTemplate, + String yamlFile, + String policyScope, + String policyName, + String policyVersion) throws IOException { + + /* + * Load policies from yaml + */ + pair = Util.loadYaml(yamlFile); + assertNotNull(pair); + assertNotNull(pair.a); + assertNotNull(pair.a.getControlLoop()); + assertNotNull(pair.a.getControlLoop().getControlLoopName()); + assertTrue(pair.a.getControlLoop().getControlLoopName().length() > 0); + + /* + * Construct a kie session + */ + final KieSession kieSession = Util.buildContainer(droolsTemplate, + pair.a.getControlLoop().getControlLoopName(), + policyScope, + policyName, + policyVersion, + URLEncoder.encode(pair.b, "UTF-8")); + + /* + * Retrieve the Policy Engine + */ + engine = (PolicyEngineJUnitImpl) kieSession.getGlobal("Engine"); + + logger.debug("============"); + logger.debug(URLEncoder.encode(pair.b, "UTF-8")); + logger.debug("============"); + + return kieSession; + } + + /** + * This method is used to simulate event messages from DCAE + * that start the control loop (onset message). + * + * @param policy the controlLoopName comes from the policy + * @param requestID the requestId for this event + * @param triggerSourceName + * @throws InterruptedException + */ + protected void sendOnset(ControlLoopPolicy policy, UUID requestID, String triggerSourceName) throws InterruptedException { + VirtualControlLoopEvent event = new VirtualControlLoopEvent(); + event.closedLoopControlName = policy.getControlLoop().getControlLoopName(); + event.requestID = requestID; + event.target = "vserver.vserver-name"; + event.closedLoopAlarmStart = Instant.now(); + event.AAI = new HashMap<>(); + event.AAI.put("cloud-region.identity-url", "foo"); + event.AAI.put("vserver.selflink", "bar"); + event.AAI.put("vserver.is-closed-loop-disabled", "false"); + event.AAI.put("vserver.vserver-name", "testGenericVnfName"); + event.closedLoopEventStatus = ControlLoopEventStatus.ONSET; + kieSession.insert(event); + Thread.sleep(2000); + } + + /** + * This method is used to simulate event messages from DCAE + * that end the control loop (abatement message). + * + * @param policy the controlLoopName comes from the policy + * @param requestID the requestId for this event + * @param triggerSourceName + * @throws InterruptedException + */ + protected void sendAbatement(ControlLoopPolicy policy, UUID requestID, String triggerSourceName) throws InterruptedException { + VirtualControlLoopEvent event = new VirtualControlLoopEvent(); + event.closedLoopControlName = policy.getControlLoop().getControlLoopName(); + event.requestID = requestID; + event.target = "vserver.vserver-name"; + event.closedLoopAlarmStart = Instant.now().minusSeconds(5); + event.closedLoopAlarmEnd = Instant.now(); + event.AAI = new HashMap<>(); + event.AAI.put("cloud-region.identity-url", "foo"); + event.AAI.put("vserver.selflink", "bar"); + event.AAI.put("vserver.is-closed-loop-disabled", "false"); + event.AAI.put("generic-vnf.vnf-name", "testGenericVnfName"); + event.closedLoopEventStatus = ControlLoopEventStatus.ABATED; + kieSession.insert(event); + } + + /** + * This method will dump all the facts in the working memory. + * + * @param kieSession the session containing the facts + */ + public void dumpFacts(KieSession kieSession) { + logger.debug("Fact Count: {}", kieSession.getFactCount()); + for (FactHandle handle : kieSession.getFactHandles()) { + logger.debug("FACT: {}", handle); + } + } +} diff --git a/controlloop/templates/template.demo/src/test/resources/yaml/policy_ControlLoop_vCPE.yaml b/controlloop/templates/template.demo/src/test/resources/yaml/policy_ControlLoop_vCPE.yaml new file mode 100644 index 000000000..de2ece4ed --- /dev/null +++ b/controlloop/templates/template.demo/src/test/resources/yaml/policy_ControlLoop_vCPE.yaml @@ -0,0 +1,23 @@ +controlLoop: + version: 2.0.0 + controlLoopName: ControlLoop-vCPE-48f0c2c3-a172-4192-9ae3-052274181b6e + trigger_policy: unique-policy-id-1-restart + timeout: 3600 + abatement: true + +policies: + - id: unique-policy-id-1-restart + name: Restart the VM + description: + actor: APPC + recipe: Restart + target: + type: VM + retry: 3 + timeout: 1200 + 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 diff --git a/controlloop/templates/template.demo/src/test/resources/yaml/policy_ControlLoop_vFW.yaml b/controlloop/templates/template.demo/src/test/resources/yaml/policy_ControlLoop_vFW.yaml new file mode 100644 index 000000000..e78b1ca33 --- /dev/null +++ b/controlloop/templates/template.demo/src/test/resources/yaml/policy_ControlLoop_vFW.yaml @@ -0,0 +1,28 @@ +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: 1200 + abatement: true + +policies: + - id: unique-policy-id-1-modifyConfig + name: modify packet gen config + description: + actor: APPC + recipe: ModifyConfig + target: + resourceID: Eace933104d443b496b8.nodes.heat.vpg + type: VM + retry: 0 + timeout: 300 + 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 diff --git a/controlloop/templates/template.demo/src/test/resources/yaml/policy_guard_appc_modifyconfig.yaml b/controlloop/templates/template.demo/src/test/resources/yaml/policy_guard_appc_modifyconfig.yaml new file mode 100644 index 000000000..a94d4f231 --- /dev/null +++ b/controlloop/templates/template.demo/src/test/resources/yaml/policy_guard_appc_modifyconfig.yaml @@ -0,0 +1,26 @@ +guard: + version: 2.0.0 + +guards: + - id: unique_guard_6 + name: APPC 6 ModifyConfig + description: | + We only allow 2 ModifyConfig over 10 minute window during the day time hours (avoid midnight to 5am) + match_parameters: + controlLoopName: ControlLoop-Service123-cbed919f-2212-4ef7-8051-fe6308da1bda + actor: APPC + recipe: ModifyConfig + targets: + - s1 + - s2 + - foobartriggersource36 + - s3 + - testGenericVnfName + limit_constraints: + - freq_limit_per_target: 1 + time_window: + value: 10 + units: minute + active_time_range: + start: 00:00:00-05:00 + end: 23:59:59-05:00
\ No newline at end of file |