From b0577ce19923aad530dde0363bd8cfe819f75970 Mon Sep 17 00:00:00 2001 From: Enbo Wang Date: Sat, 1 Feb 2020 21:35:09 +0800 Subject: Add new LCM actions DownloadNESw and ActivateNESw, etc 1. Add LCM actions DownloadNESw and ActivateNESw; 2. Add payload field in the output of Rollback action. Issue-ID: APPC-1811 Change-Id: I2e05522909a45d03927035fe35e9168751b5de0d Signed-off-by: Enbo Wang --- .../onap/appc/domainmodel/lcm/VNFOperation.java | 2 + .../onap/appc/requesthandler/conv/Converter.java | 19 +++ .../onap/appc/requesthandler/ConverterTest.java | 55 +++++-- .../appc/requesthandler/RequestHandlerTest.java | 6 +- .../appc/requesthandler/RequestValidatorTest.java | 6 +- .../org/onap/appc/provider/AppcProviderLcm.java | 20 +++ .../provider/lcm/service/AbstractBaseUtils.java | 4 +- .../appc/provider/lcm/service/ActivateNESw.java | 119 ++++++++++++++ .../appc/provider/lcm/service/DownloadNESw.java | 119 ++++++++++++++ .../onap/appc/provider/AppcProviderLcmTest.java | 16 ++ .../lcm/service/AbstractBaseUtilsTest.java | 4 + .../provider/lcm/service/ActivateNESwTest.java | 172 +++++++++++++++++++++ .../provider/lcm/service/DownloadNESwTest.java | 172 +++++++++++++++++++++ .../src/main/yang/appc-provider-lcm.yang | 61 ++++++++ docs/APPC LCM API Guide/APPC LCM API Guide.rst | 109 +++++++++++++ 15 files changed, 864 insertions(+), 20 deletions(-) create mode 100644 appc-provider/appc-provider-bundle/src/main/java/org/onap/appc/provider/lcm/service/ActivateNESw.java create mode 100644 appc-provider/appc-provider-bundle/src/main/java/org/onap/appc/provider/lcm/service/DownloadNESw.java create mode 100644 appc-provider/appc-provider-bundle/src/test/java/org/onap/appc/provider/lcm/service/ActivateNESwTest.java create mode 100644 appc-provider/appc-provider-bundle/src/test/java/org/onap/appc/provider/lcm/service/DownloadNESwTest.java diff --git a/appc-dispatcher/appc-dispatcher-common/domain-model-lib/src/main/java/org/onap/appc/domainmodel/lcm/VNFOperation.java b/appc-dispatcher/appc-dispatcher-common/domain-model-lib/src/main/java/org/onap/appc/domainmodel/lcm/VNFOperation.java index 95557aab7..1c436fa00 100644 --- a/appc-dispatcher/appc-dispatcher-common/domain-model-lib/src/main/java/org/onap/appc/domainmodel/lcm/VNFOperation.java +++ b/appc-dispatcher/appc-dispatcher-common/domain-model-lib/src/main/java/org/onap/appc/domainmodel/lcm/VNFOperation.java @@ -27,6 +27,7 @@ package org.onap.appc.domainmodel.lcm; public enum VNFOperation { ActionStatus, + ActivateNESw, AttachVolume, Audit, Backup, @@ -41,6 +42,7 @@ public enum VNFOperation { DetachVolume, DistributeTraffic, DistributeTrafficCheck, + DownloadNESw, Evacuate, GetConfig, HealthCheck, diff --git a/appc-dispatcher/appc-request-handler/appc-request-handler-core/src/main/java/org/onap/appc/requesthandler/conv/Converter.java b/appc-dispatcher/appc-request-handler/appc-request-handler-core/src/main/java/org/onap/appc/requesthandler/conv/Converter.java index de292284a..8e9c7f817 100644 --- a/appc-dispatcher/appc-request-handler/appc-request-handler-core/src/main/java/org/onap/appc/requesthandler/conv/Converter.java +++ b/appc-dispatcher/appc-request-handler/appc-request-handler-core/src/main/java/org/onap/appc/requesthandler/conv/Converter.java @@ -88,6 +88,7 @@ public class Converter { outObj = new RollbackOutputBuilder(); ((RollbackOutputBuilder)outObj).setCommonHeader(commonHeader); ((RollbackOutputBuilder)outObj).setStatus(status); + ((RollbackOutputBuilder)outObj).setPayload(payload); return outObj; case Snapshot: outObj = new SnapshotOutputBuilder(); @@ -383,6 +384,18 @@ public class Converter { ((ConfigScaleInOutputBuilder)outObj).setStatus(status); ((ConfigScaleInOutputBuilder)outObj).setPayload(payload); return outObj; + case DownloadNESw: + outObj = new DownloadNESwOutputBuilder(); + ((DownloadNESwOutputBuilder)outObj).setCommonHeader(commonHeader); + ((DownloadNESwOutputBuilder)outObj).setStatus(status); + ((DownloadNESwOutputBuilder)outObj).setPayload(payload); + return outObj; + case ActivateNESw: + outObj = new ActivateNESwOutputBuilder(); + ((ActivateNESwOutputBuilder)outObj).setCommonHeader(commonHeader); + ((ActivateNESwOutputBuilder)outObj).setStatus(status); + ((ActivateNESwOutputBuilder)outObj).setPayload(payload); + return outObj; default: throw new IllegalArgumentException(action+" action is not supported"); } @@ -576,6 +589,12 @@ public class Converter { "" : "-" + context.getCommonHeader().getSubRequestId()); } + public static String getRpcName(String action) { + String regex = "([a-zA-Z])(?=[A-Z])"; + String replacement = "$1-"; + return action.replaceAll(regex, replacement).toLowerCase(); + } + abstract class MixIn { @JsonIgnore abstract Class getImplementedInterface(); // to be removed during serialization diff --git a/appc-dispatcher/appc-request-handler/appc-request-handler-core/src/test/java/org/onap/appc/requesthandler/ConverterTest.java b/appc-dispatcher/appc-request-handler/appc-request-handler-core/src/test/java/org/onap/appc/requesthandler/ConverterTest.java index dbba6caa1..f82b46da7 100644 --- a/appc-dispatcher/appc-request-handler/appc-request-handler-core/src/test/java/org/onap/appc/requesthandler/ConverterTest.java +++ b/appc-dispatcher/appc-request-handler/appc-request-handler-core/src/test/java/org/onap/appc/requesthandler/ConverterTest.java @@ -39,7 +39,7 @@ import java.util.HashMap; public class ConverterTest { private String expectedJsonBodyStr ="{\"output\":{\"common-header\":{\"api-ver\":\"2.0.0\",\"flags\":{},\"originator-id\":\"oid\",\"request-id\":\"reqid\",\"timestamp\":\"1970-01-01T00:00:01.000Z\"},\"status\":{\"code\":400,\"message\":\"SUCCESS - request has been processed successfully\"}}}"; private String expectedDmaapOutgoingMessageJsonStringTest ="{\"body\":{\"output\":{\"common-header\":{\"api-ver\":\"2.0.0\",\"flags\":{},\"originator-id\":\"oid\",\"request-id\":\"reqid\",\"timestamp\":\"1970-01-01T00:00:01.000Z\"},\"status\":{\"code\":400,\"message\":\"SUCCESS - request has been processed successfully\"}}},\"cambria.partition\":\"MSO\",\"correlation-id\":\"reqid\",\"rpc-name\":\"test\",\"type\":\"response\"}"; - private String expectedDmaapOutgoingMessageJsonStringRollback ="{\"body\":{\"output\":{\"common-header\":{\"api-ver\":\"2.0.0\",\"flags\":{},\"originator-id\":\"oid\",\"request-id\":\"reqid\",\"timestamp\":\"1970-01-01T00:00:01.000Z\"},\"status\":{\"code\":400,\"message\":\"SUCCESS - request has been processed successfully\"}}},\"cambria.partition\":\"MSO\",\"correlation-id\":\"reqid\",\"rpc-name\":\"rollback\",\"type\":\"response\"}"; + private String expectedDmaapOutgoingMessageJsonStringRollback ="{\"body\":{\"output\":{\"common-header\":{\"api-ver\":\"2.0.0\",\"flags\":{},\"originator-id\":\"oid\",\"request-id\":\"reqid\",\"timestamp\":\"1970-01-01T00:00:01.000Z\"},\"payload\":\"{}\",\"status\":{\"code\":400,\"message\":\"SUCCESS - request has been processed successfully\"}}},\"cambria.partition\":\"MSO\",\"correlation-id\":\"reqid\",\"rpc-name\":\"rollback\",\"type\":\"response\"}"; private String expectedDmaapOutgoingMessageJsonStringSnapshot ="{\"body\":{\"output\":{\"common-header\":{\"api-ver\":\"2.0.0\",\"flags\":{},\"originator-id\":\"oid\",\"request-id\":\"reqid\",\"timestamp\":\"1970-01-01T00:00:01.000Z\"},\"status\":{\"code\":400,\"message\":\"SUCCESS - request has been processed successfully\"}}},\"cambria.partition\":\"MSO\",\"correlation-id\":\"reqid\",\"rpc-name\":\"snapshot\",\"type\":\"response\"}"; private String expectedDmaapOutgoingMessageJsonStringAudit ="{\"body\":{\"output\":{\"common-header\":{\"api-ver\":\"2.0.0\",\"flags\":{},\"originator-id\":\"oid\",\"request-id\":\"reqid\",\"timestamp\":\"1970-01-01T00:00:01.000Z\"},\"payload\":\"{}\",\"status\":{\"code\":400,\"message\":\"SUCCESS - request has been processed successfully\"}}},\"cambria.partition\":\"MSO\",\"correlation-id\":\"reqid\",\"rpc-name\":\"audit\",\"type\":\"response\"}"; private String expectedDmaapOutgoingMessageJsonStringHealthCheck ="{\"body\":{\"output\":{\"common-header\":{\"api-ver\":\"2.0.0\",\"flags\":{},\"originator-id\":\"oid\",\"request-id\":\"reqid\",\"timestamp\":\"1970-01-01T00:00:01.000Z\"},\"payload\":\"{}\",\"status\":{\"code\":400,\"message\":\"SUCCESS - request has been processed successfully\"}}},\"cambria.partition\":\"MSO\",\"correlation-id\":\"reqid\",\"rpc-name\":\"health-check\",\"type\":\"response\"}"; @@ -73,6 +73,8 @@ public class ConverterTest { private String expectedDmaapOutgoingMessageJsonStringStatusTraffic ="{\"body\":{\"output\":{\"common-header\":{\"api-ver\":\"2.0.0\",\"flags\":{},\"originator-id\":\"oid\",\"request-id\":\"reqid\",\"timestamp\":\"1970-01-01T00:00:01.000Z\"},\"payload\":\"{}\",\"status\":{\"code\":400,\"message\":\"SUCCESS - request has been processed successfully\"}}},\"cambria.partition\":\"MSO\",\"correlation-id\":\"reqid\",\"rpc-name\":\"status-traffic\",\"type\":\"response\"}"; private String expectedDmaapOutgoingMessageJsonStringStopTraffic ="{\"body\":{\"output\":{\"common-header\":{\"api-ver\":\"2.0.0\",\"flags\":{},\"originator-id\":\"oid\",\"request-id\":\"reqid\",\"timestamp\":\"1970-01-01T00:00:01.000Z\"},\"payload\":\"{}\",\"status\":{\"code\":400,\"message\":\"SUCCESS - request has been processed successfully\"}}},\"cambria.partition\":\"MSO\",\"correlation-id\":\"reqid\",\"rpc-name\":\"stop-traffic\",\"type\":\"response\"}"; private String expectedDmaapOutgoingMessageJsonStringProvisioning ="{\"body\":{\"output\":{\"common-header\":{\"api-ver\":\"2.0.0\",\"flags\":{},\"originator-id\":\"oid\",\"request-id\":\"reqid\",\"timestamp\":\"1970-01-01T00:00:01.000Z\"},\"payload\":\"{}\",\"status\":{\"code\":400,\"message\":\"SUCCESS - request has been processed successfully\"}}},\"cambria.partition\":\"MSO\",\"correlation-id\":\"reqid\",\"rpc-name\":\"provisioning\",\"type\":\"response\"}"; + private String expectedDmaapOutgoingMessageJsonStringDownloadNESw ="{\"body\":{\"output\":{\"common-header\":{\"api-ver\":\"2.0.0\",\"flags\":{},\"originator-id\":\"oid\",\"request-id\":\"reqid\",\"timestamp\":\"1970-01-01T00:00:01.000Z\"},\"payload\":\"{}\",\"status\":{\"code\":400,\"message\":\"SUCCESS - request has been processed successfully\"}}},\"cambria.partition\":\"MSO\",\"correlation-id\":\"reqid\",\"rpc-name\":\"download-n-e-sw\",\"type\":\"response\"}"; + private String expectedDmaapOutgoingMessageJsonStringActivateNESw ="{\"body\":{\"output\":{\"common-header\":{\"api-ver\":\"2.0.0\",\"flags\":{},\"originator-id\":\"oid\",\"request-id\":\"reqid\",\"timestamp\":\"1970-01-01T00:00:01.000Z\"},\"payload\":\"{}\",\"status\":{\"code\":400,\"message\":\"SUCCESS - request has been processed successfully\"}}},\"cambria.partition\":\"MSO\",\"correlation-id\":\"reqid\",\"rpc-name\":\"activate-n-e-sw\",\"type\":\"response\"}"; @Test public void convDateToZuluStringTest(){ @@ -112,16 +114,16 @@ public class ConverterTest { @Test public void convAsyncResponseToBuilderRollbackTest() throws JsonProcessingException { - ResponseContext asyncResponse = buildAsyncResponse(); + ResponseContext asyncResponse = buildAsyncResponsewithPayload(); VNFOperation action = VNFOperation.Rollback; String rpcName = action.name().toLowerCase(); String jsonStr = Converter.convAsyncResponseToJsonStringBody(action, rpcName, asyncResponse); - Assert.assertEquals(expectedJsonBodyStr, jsonStr); + Assert.assertEquals(expectedJsonBodyStrwithPayload, jsonStr); } @Test public void convAsyncResponseToDmaapOutgoingMessageJsonStringRollbackTest() throws JsonProcessingException { - ResponseContext asyncResponse = buildAsyncResponse(); + ResponseContext asyncResponse = buildAsyncResponsewithPayload(); VNFOperation action = VNFOperation.Rollback; String rpcName = action.name().toLowerCase(); String jsonStr = Converter.convAsyncResponseToDmaapOutgoingMessageJsonString(action, rpcName, asyncResponse); @@ -740,6 +742,44 @@ public class ConverterTest { Assert.assertEquals(expectedDmaapOutgoingMessageJsonStringStopTraffic, jsonStr); } + @Test + public void convAsyncResponseToBuilderDownloadNESwTest() throws JsonProcessingException { + ResponseContext asyncResponse = buildAsyncResponsewithPayload(); + VNFOperation action = VNFOperation.DownloadNESw; + String rpcName = convertActionNameToUrl(action.name()); + String jsonStr = Converter.convAsyncResponseToJsonStringBody(action, rpcName, asyncResponse); + Assert.assertEquals(expectedJsonBodyStrwithPayload, jsonStr); + } + + @Test + public void convAsyncResponseToDmaapOutgoingMessageJsonStringDownloadNESwTest() throws JsonProcessingException { + ResponseContext asyncResponse = buildAsyncResponsewithPayload(); + VNFOperation action = VNFOperation.DownloadNESw; + String rpcName = convertActionNameToUrl(action.name()); + String jsonStr = Converter.convAsyncResponseToDmaapOutgoingMessageJsonString(action, rpcName, asyncResponse); + System.out.println("jsonStr = " + jsonStr); + Assert.assertEquals(expectedDmaapOutgoingMessageJsonStringDownloadNESw, jsonStr); + } + + @Test + public void convAsyncResponseToBuilderActivateNESwTest() throws JsonProcessingException { + ResponseContext asyncResponse = buildAsyncResponsewithPayload(); + VNFOperation action = VNFOperation.ActivateNESw; + String rpcName = convertActionNameToUrl(action.name()); + String jsonStr = Converter.convAsyncResponseToJsonStringBody(action, rpcName, asyncResponse); + Assert.assertEquals(expectedJsonBodyStrwithPayload, jsonStr); + } + + @Test + public void convAsyncResponseToDmaapOutgoingMessageJsonStringActivateNESwTest() throws JsonProcessingException { + ResponseContext asyncResponse = buildAsyncResponsewithPayload(); + VNFOperation action = VNFOperation.ActivateNESw; + String rpcName = convertActionNameToUrl(action.name()); + String jsonStr = Converter.convAsyncResponseToDmaapOutgoingMessageJsonString(action, rpcName, asyncResponse); + System.out.println("jsonStr = " + jsonStr); + Assert.assertEquals(expectedDmaapOutgoingMessageJsonStringActivateNESw, jsonStr); + } + /*@Test public void convAsyncResponseToBuilderTest() throws JsonProcessingException { AsyncResponse asyncResponse = buildAsyncResponse(); @@ -794,11 +834,6 @@ public class ConverterTest { } private String convertActionNameToUrl(String action) { - String regex = "([a-z])([A-Z]+)"; - String replacement = "$1-$2"; - return action.replaceAll(regex, replacement) - .toLowerCase(); + return Converter.getRpcName(action); } - - } diff --git a/appc-dispatcher/appc-request-handler/appc-request-handler-core/src/test/java/org/onap/appc/requesthandler/RequestHandlerTest.java b/appc-dispatcher/appc-request-handler/appc-request-handler-core/src/test/java/org/onap/appc/requesthandler/RequestHandlerTest.java index 89bb13f7c..fe7dcbf9c 100644 --- a/appc-dispatcher/appc-request-handler/appc-request-handler-core/src/test/java/org/onap/appc/requesthandler/RequestHandlerTest.java +++ b/appc-dispatcher/appc-request-handler/appc-request-handler-core/src/test/java/org/onap/appc/requesthandler/RequestHandlerTest.java @@ -52,6 +52,7 @@ import org.onap.appc.lockmanager.api.LockException; import org.onap.appc.lockmanager.api.LockManager; import org.onap.appc.messageadapter.MessageAdapter; import org.onap.appc.messageadapter.impl.MessageAdapterImpl; +import org.onap.appc.requesthandler.conv.Converter; import org.onap.appc.requesthandler.exceptions.DGWorkflowNotFoundException; import org.onap.appc.requesthandler.exceptions.DuplicateRequestException; import org.onap.appc.requesthandler.exceptions.LCMOperationsDisabledException; @@ -588,10 +589,7 @@ public class RequestHandlerTest { } private String convertActionNameToUrl(String action) { - String regex = "([a-z])([A-Z]+)"; - String replacement = "$1-$2"; - return action.replaceAll(regex, replacement) - .toLowerCase(); + return Converter.getRpcName(action); } } diff --git a/appc-dispatcher/appc-request-handler/appc-request-handler-core/src/test/java/org/onap/appc/requesthandler/RequestValidatorTest.java b/appc-dispatcher/appc-request-handler/appc-request-handler-core/src/test/java/org/onap/appc/requesthandler/RequestValidatorTest.java index d3fab56bf..8f16a3768 100644 --- a/appc-dispatcher/appc-request-handler/appc-request-handler-core/src/test/java/org/onap/appc/requesthandler/RequestValidatorTest.java +++ b/appc-dispatcher/appc-request-handler/appc-request-handler-core/src/test/java/org/onap/appc/requesthandler/RequestValidatorTest.java @@ -51,6 +51,7 @@ import org.onap.appc.domainmodel.lcm.VNFContext; import org.onap.appc.domainmodel.lcm.VNFOperation; import org.onap.appc.exceptions.InvalidInputException; import org.onap.appc.lockmanager.api.LockManager; +import org.onap.appc.requesthandler.conv.Converter; import org.onap.appc.requesthandler.exceptions.DuplicateRequestException; import org.onap.appc.requesthandler.exceptions.LCMOperationsDisabledException; import org.onap.appc.requesthandler.exceptions.RequestValidationException; @@ -483,10 +484,7 @@ public class RequestValidatorTest { } private String convertActionNameToUrl(String action) { - String regex = "([a-z])([A-Z]+)"; - String replacement = "$1-$2"; - return action.replaceAll(regex, replacement) - .toLowerCase(); + return Converter.getRpcName(action); } private RuntimeContext putInputToRuntimeContext(RequestHandlerInput input) { diff --git a/appc-provider/appc-provider-bundle/src/main/java/org/onap/appc/provider/AppcProviderLcm.java b/appc-provider/appc-provider-bundle/src/main/java/org/onap/appc/provider/AppcProviderLcm.java index dc81f7e71..4aad66899 100644 --- a/appc-provider/appc-provider-bundle/src/main/java/org/onap/appc/provider/AppcProviderLcm.java +++ b/appc-provider/appc-provider-bundle/src/main/java/org/onap/appc/provider/AppcProviderLcm.java @@ -62,6 +62,8 @@ import org.onap.appc.provider.lcm.service.StartTraffic; import org.onap.appc.provider.lcm.service.StatusTraffic; import org.onap.appc.provider.lcm.service.StopTraffic; import org.onap.appc.provider.lcm.service.ConfigScaleInService; +import org.onap.appc.provider.lcm.service.DownloadNESw; +import org.onap.appc.provider.lcm.service.ActivateNESw; import org.onap.appc.provider.lcm.util.RequestInputBuilder; import org.onap.appc.provider.lcm.util.ValidationService; import org.onap.appc.requesthandler.objects.RequestHandlerInput; @@ -659,6 +661,24 @@ public class AppcProviderLcm extends AbstractBaseUtils implements AutoCloseable, return Futures.immediateFuture(result); } + @Override + public ListenableFuture> downloadNESw(DownloadNESwInput input) { + logger.debug(String.format("LCM DownloadNESw received input: %s", input.toString())); + DownloadNESwOutputBuilder outputBuilder = new DownloadNESw().process(input); + RpcResult result = + RpcResultBuilder.status(true).withResult(outputBuilder.build()).build(); + return Futures.immediateFuture(result); + } + + @Override + public ListenableFuture> activateNESw(ActivateNESwInput input) { + logger.debug(String.format("LCM ActivateNESw received input: %s", input.toString())); + ActivateNESwOutputBuilder outputBuilder = new ActivateNESw().process(input); + RpcResult result = + RpcResultBuilder.status(true).withResult(outputBuilder.build()).build(); + return Futures.immediateFuture(result); + } + @Override public ListenableFuture> terminate(TerminateInput input) { logger.debug("Input received : " + input.toString()); diff --git a/appc-provider/appc-provider-bundle/src/main/java/org/onap/appc/provider/lcm/service/AbstractBaseUtils.java b/appc-provider/appc-provider-bundle/src/main/java/org/onap/appc/provider/lcm/service/AbstractBaseUtils.java index b951bd966..eeeeb9341 100644 --- a/appc-provider/appc-provider-bundle/src/main/java/org/onap/appc/provider/lcm/service/AbstractBaseUtils.java +++ b/appc-provider/appc-provider-bundle/src/main/java/org/onap/appc/provider/lcm/service/AbstractBaseUtils.java @@ -149,8 +149,8 @@ public class AbstractBaseUtils { * @return RPC name of the Action */ protected String getRpcName(Action action) { - String regex = "([a-z])([A-Z]+)"; - String replacement = "$1-$2"; + String regex = "([a-zA-Z])(?=[A-Z])"; + String replacement = "$1-"; return action.name().replaceAll(regex, replacement).toLowerCase(); } } diff --git a/appc-provider/appc-provider-bundle/src/main/java/org/onap/appc/provider/lcm/service/ActivateNESw.java b/appc-provider/appc-provider-bundle/src/main/java/org/onap/appc/provider/lcm/service/ActivateNESw.java new file mode 100644 index 000000000..6125c1d27 --- /dev/null +++ b/appc-provider/appc-provider-bundle/src/main/java/org/onap/appc/provider/lcm/service/ActivateNESw.java @@ -0,0 +1,119 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP : APPC + * ================================================================================ + * Copyright (C) 2017-2019 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Copyright (C) 2017 Amdocs + * ================================================================================ + * Copyright (C) 2020 Huawei + * ================================================================================ + * 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. + * + * ECOMP is a trademark and service mark of AT&T Intellectual Property. + * ============LICENSE_END========================================================= + */ + +package org.onap.appc.provider.lcm.service; + +import org.opendaylight.yang.gen.v1.org.onap.appc.lcm.rev160108.Action; +import org.opendaylight.yang.gen.v1.org.onap.appc.lcm.rev160108.ActivateNESwInput; +import org.opendaylight.yang.gen.v1.org.onap.appc.lcm.rev160108.ActivateNESwOutputBuilder; +import org.opendaylight.yang.gen.v1.org.onap.appc.lcm.rev160108.Payload; +import org.opendaylight.yang.gen.v1.org.onap.appc.lcm.rev160108.action.identifiers.ActionIdentifiers; +import org.opendaylight.yang.gen.v1.org.onap.appc.lcm.rev160108.common.header.CommonHeader; +import org.onap.appc.requesthandler.objects.RequestHandlerInput; +import org.onap.appc.executor.objects.LCMCommandStatus; +import org.onap.appc.util.JsonUtil; + +import java.io.IOException; +import java.util.Map; + +/** + * Provide LCM command service for activating NE software + */ +public class ActivateNESw extends AbstractBaseService { + public ActivateNESw() { + super(Action.ActivateNESw); + logger.debug("ActivateNESw starts"); + } + + /** + * Process the ActivateNESw request. + * @param input of ActivateNESwInput from the REST API input + * @return ActivateNESwOutputBuilder which has the process results + */ + public ActivateNESwOutputBuilder process(ActivateNESwInput input) { + CommonHeader commonHeader = input.getCommonHeader(); + ActionIdentifiers actionIdentifiers = input.getActionIdentifiers(); + Payload payload = input.getPayload(); + + validate(commonHeader, input.getAction(), actionIdentifiers, payload); + if (status == null) { + proceedAction(commonHeader, actionIdentifiers, payload); + } + + ActivateNESwOutputBuilder outputBuilder = new ActivateNESwOutputBuilder(); + outputBuilder.setStatus(status); + outputBuilder.setCommonHeader(input.getCommonHeader()); + return outputBuilder; + } + + /** + * Validate the input. + * Set Status if any error occurs. + * + * @param input of ActivateNESwInput from the REST API input + */ + void validate(CommonHeader commonHeader, Action action, ActionIdentifiers actionIdentifiers, Payload payload) { + status = validateVnfId(commonHeader, action, actionIdentifiers); + if (status != null) { + return; + } + + // validate payload + String keyName = "payload"; + if (payload == null) { + status = buildStatusForParamName(LCMCommandStatus.MISSING_MANDATORY_PARAMETER, keyName); + return; + } + String payloadString = payload.getValue(); + status = validateMustHaveParamValue( + payloadString == null ? payloadString : payloadString.trim(), "payload"); + if (status != null) { + return; + } + + try { + Map payloadMap = JsonUtil.convertJsonStringToFlatMap(payloadString); + validateMustHaveParamValue(payloadMap.get(keyName), keyName); + } catch (IOException e) { + logger.error(String.format("ActivateNESw (%s) got IOException when converting payload", rpcName), e); + status = buildStatusForErrorMsg(LCMCommandStatus.UNEXPECTED_ERROR, e.getMessage()); + } + } + + /** + * Proceed to action for the ActivateNESw. + * + * @param input of ActivateNESwInput from the REST API input + */ + void proceedAction(CommonHeader commonHeader, ActionIdentifiers actionIdentifiers, Payload payload) { + RequestHandlerInput requestHandlerInput = getRequestHandlerInput(commonHeader, actionIdentifiers, payload, + this.getClass().getName()); + if (requestHandlerInput != null) { + executeAction(requestHandlerInput); + } + } +} + diff --git a/appc-provider/appc-provider-bundle/src/main/java/org/onap/appc/provider/lcm/service/DownloadNESw.java b/appc-provider/appc-provider-bundle/src/main/java/org/onap/appc/provider/lcm/service/DownloadNESw.java new file mode 100644 index 000000000..a21c51001 --- /dev/null +++ b/appc-provider/appc-provider-bundle/src/main/java/org/onap/appc/provider/lcm/service/DownloadNESw.java @@ -0,0 +1,119 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP : APPC + * ================================================================================ + * Copyright (C) 2017-2019 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Copyright (C) 2017 Amdocs + * ================================================================================ + * Copyright (C) 2020 Huawei + * ================================================================================ + * 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. + * + * ECOMP is a trademark and service mark of AT&T Intellectual Property. + * ============LICENSE_END========================================================= + */ + +package org.onap.appc.provider.lcm.service; + +import org.opendaylight.yang.gen.v1.org.onap.appc.lcm.rev160108.Action; +import org.opendaylight.yang.gen.v1.org.onap.appc.lcm.rev160108.DownloadNESwInput; +import org.opendaylight.yang.gen.v1.org.onap.appc.lcm.rev160108.DownloadNESwOutputBuilder; +import org.opendaylight.yang.gen.v1.org.onap.appc.lcm.rev160108.Payload; +import org.opendaylight.yang.gen.v1.org.onap.appc.lcm.rev160108.action.identifiers.ActionIdentifiers; +import org.opendaylight.yang.gen.v1.org.onap.appc.lcm.rev160108.common.header.CommonHeader; +import org.onap.appc.requesthandler.objects.RequestHandlerInput; +import org.onap.appc.executor.objects.LCMCommandStatus; +import org.onap.appc.util.JsonUtil; + +import java.io.IOException; +import java.util.Map; + +/** + * Provide LCM command service for downloading NE software + */ +public class DownloadNESw extends AbstractBaseService { + public DownloadNESw() { + super(Action.DownloadNESw); + logger.debug("DownloadNESw starts"); + } + + /** + * Process the DownloadNESw request. + * @param input of DownloadNESwInput from the REST API input + * @return DownloadNESwOutputBuilder which has the process results + */ + public DownloadNESwOutputBuilder process(DownloadNESwInput input) { + CommonHeader commonHeader = input.getCommonHeader(); + ActionIdentifiers actionIdentifiers = input.getActionIdentifiers(); + Payload payload = input.getPayload(); + + validate(commonHeader, input.getAction(), actionIdentifiers, payload); + if (status == null) { + proceedAction(commonHeader, actionIdentifiers, payload); + } + + DownloadNESwOutputBuilder outputBuilder = new DownloadNESwOutputBuilder(); + outputBuilder.setStatus(status); + outputBuilder.setCommonHeader(input.getCommonHeader()); + return outputBuilder; + } + + /** + * Validate the input. + * Set Status if any error occurs. + * + * @param input of DownloadNESwInput from the REST API input + */ + void validate(CommonHeader commonHeader, Action action, ActionIdentifiers actionIdentifiers, Payload payload) { + status = validateVnfId(commonHeader, action, actionIdentifiers); + if (status != null) { + return; + } + + // validate payload + String keyName = "payload"; + if (payload == null) { + status = buildStatusForParamName(LCMCommandStatus.MISSING_MANDATORY_PARAMETER, keyName); + return; + } + String payloadString = payload.getValue(); + status = validateMustHaveParamValue( + payloadString == null ? payloadString : payloadString.trim(), "payload"); + if (status != null) { + return; + } + + try { + Map payloadMap = JsonUtil.convertJsonStringToFlatMap(payloadString); + validateMustHaveParamValue(payloadMap.get(keyName), keyName); + } catch (IOException e) { + logger.error(String.format("DownloadNESw (%s) got IOException when converting payload", rpcName), e); + status = buildStatusForErrorMsg(LCMCommandStatus.UNEXPECTED_ERROR, e.getMessage()); + } + } + + /** + * Proceed to action for the DownloadNESw. + * + * @param input of DownloadNESwInput from the REST API input + */ + void proceedAction(CommonHeader commonHeader, ActionIdentifiers actionIdentifiers, Payload payload) { + RequestHandlerInput requestHandlerInput = getRequestHandlerInput(commonHeader, actionIdentifiers, payload, + this.getClass().getName()); + if (requestHandlerInput != null) { + executeAction(requestHandlerInput); + } + } +} + diff --git a/appc-provider/appc-provider-bundle/src/test/java/org/onap/appc/provider/AppcProviderLcmTest.java b/appc-provider/appc-provider-bundle/src/test/java/org/onap/appc/provider/AppcProviderLcmTest.java index 082f04982..abe7151db 100644 --- a/appc-provider/appc-provider-bundle/src/test/java/org/onap/appc/provider/AppcProviderLcmTest.java +++ b/appc-provider/appc-provider-bundle/src/test/java/org/onap/appc/provider/AppcProviderLcmTest.java @@ -83,6 +83,8 @@ import org.opendaylight.yang.gen.v1.org.onap.appc.lcm.rev160108.UpgradePostCheck import org.opendaylight.yang.gen.v1.org.onap.appc.lcm.rev160108.UpgradePreCheckInput; import org.opendaylight.yang.gen.v1.org.onap.appc.lcm.rev160108.UpgradeSoftwareInput; import org.opendaylight.yang.gen.v1.org.onap.appc.lcm.rev160108.ConfigScaleInInput; +import org.opendaylight.yang.gen.v1.org.onap.appc.lcm.rev160108.DownloadNESwInput; +import org.opendaylight.yang.gen.v1.org.onap.appc.lcm.rev160108.ActivateNESwInput; import org.opendaylight.yang.gen.v1.org.onap.appc.lcm.rev160108.ZULU; import org.opendaylight.yang.gen.v1.org.onap.appc.lcm.rev160108.action.identifiers.ActionIdentifiersBuilder; import org.opendaylight.yang.gen.v1.org.onap.appc.lcm.rev160108.common.header.CommonHeaderBuilder; @@ -360,6 +362,20 @@ public class AppcProviderLcmTest { assertTrue(underTest.upgradeBackout(upgradeBackoutInput).isDone()); } + @Test + public void downloadNESwTest() { + DownloadNESwInput downloadNESwInput = mock(DownloadNESwInput.class); + Mockito.doReturn(Action.DownloadNESw).when(downloadNESwInput).getAction(); + assertTrue(underTest.downloadNESw(downloadNESwInput).isDone()); + } + + @Test + public void activateNESwTest() { + ActivateNESwInput activateNESwInput = mock(ActivateNESwInput.class); + Mockito.doReturn(Action.ActivateNESw).when(activateNESwInput).getAction(); + assertTrue(underTest.activateNESw(activateNESwInput).isDone()); + } + @Test public void terminateTestParseException() { TerminateInput terminateInput = mock(TerminateInput.class); diff --git a/appc-provider/appc-provider-bundle/src/test/java/org/onap/appc/provider/lcm/service/AbstractBaseUtilsTest.java b/appc-provider/appc-provider-bundle/src/test/java/org/onap/appc/provider/lcm/service/AbstractBaseUtilsTest.java index 62a8ec4c7..263b85bef 100644 --- a/appc-provider/appc-provider-bundle/src/test/java/org/onap/appc/provider/lcm/service/AbstractBaseUtilsTest.java +++ b/appc-provider/appc-provider-bundle/src/test/java/org/onap/appc/provider/lcm/service/AbstractBaseUtilsTest.java @@ -199,5 +199,9 @@ public class AbstractBaseUtilsTest { "upgrade-backup", testAbstractBaseUtils.getRpcName(Action.UpgradeBackup)); Assert.assertEquals("Should return upgrade-backout", "upgrade-backout", testAbstractBaseUtils.getRpcName(Action.UpgradeBackout)); + Assert.assertEquals("Should return download-n-e-sw", + "download-n-e-sw", testAbstractBaseUtils.getRpcName(Action.DownloadNESw)); + Assert.assertEquals("Should return activate-n-e-sw", + "activate-n-e-sw", testAbstractBaseUtils.getRpcName(Action.ActivateNESw)); } } diff --git a/appc-provider/appc-provider-bundle/src/test/java/org/onap/appc/provider/lcm/service/ActivateNESwTest.java b/appc-provider/appc-provider-bundle/src/test/java/org/onap/appc/provider/lcm/service/ActivateNESwTest.java new file mode 100644 index 000000000..f32f889e5 --- /dev/null +++ b/appc-provider/appc-provider-bundle/src/test/java/org/onap/appc/provider/lcm/service/ActivateNESwTest.java @@ -0,0 +1,172 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP : APPC + * ================================================================================ + * Copyright (C) 2017-2019 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Copyright (C) 2017 Amdocs + * ================================================================================ + * Copyright (C) 2020 Huawei + * ================================================================================ + * 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. + * + * ECOMP is a trademark and service mark of AT&T Intellectual Property. + * ============LICENSE_END========================================================= + */ + +package org.onap.appc.provider.lcm.service; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.mockito.internal.util.reflection.Whitebox; +import org.mockito.runners.MockitoJUnitRunner; +import org.opendaylight.yang.gen.v1.org.onap.appc.lcm.rev160108.*; +import org.opendaylight.yang.gen.v1.org.onap.appc.lcm.rev160108.action.identifiers.ActionIdentifiers; +import org.opendaylight.yang.gen.v1.org.onap.appc.lcm.rev160108.common.header.CommonHeader; +import org.opendaylight.yang.gen.v1.org.onap.appc.lcm.rev160108.status.Status; +import org.onap.appc.domainmodel.lcm.ResponseContext; +import org.onap.appc.executor.objects.LCMCommandStatus; +import org.onap.appc.requesthandler.objects.RequestHandlerOutput; +import org.onap.appc.requesthandler.objects.RequestHandlerInput; + +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; + +@RunWith(MockitoJUnitRunner.class) +public class ActivateNESwTest { + private final Action myAction = Action.ActivateNESw; + private final String PAYLOAD_STRING = "{\"A\":\"A-value\",\"B\":{\"C\":\"B.C-value\",\"D\":\"B.D-value\"}}"; + private ActivateNESwInput mockInput = mock(ActivateNESwInput.class); + private CommonHeader mockCommonHeader = mock(CommonHeader.class); + private ActionIdentifiers mockAI = mock(ActionIdentifiers.class); + private Payload mockPayload = mock(Payload.class); + + private ActivateNESw activateNESwAction; + + @Before + public void setUp() throws Exception { + activateNESwAction = spy(new ActivateNESw()); + } + + @Test + public void testProcess() throws Exception { + // test error occurs in validation + ActivateNESwOutputBuilder outputBuilder = activateNESwAction.process(mockInput); + Mockito.verify(activateNESwAction, times(0)).proceedAction(any(), any(), any()); + Assert.assertTrue("Should not have commonHeader as we did not mock it", + outputBuilder.getCommonHeader() == null); + Assert.assertEquals("should return missing parameter status", + Integer.valueOf(LCMCommandStatus.MISSING_MANDATORY_PARAMETER.getResponseCode()), + outputBuilder.getStatus().getCode()); + + // make validation pass + Mockito.doReturn(mockCommonHeader).when(mockInput).getCommonHeader(); + Mockito.doReturn(mockPayload).when(mockInput).getPayload(); + Mockito.doReturn(PAYLOAD_STRING).when(mockPayload).getValue(); + + // to make validation pass + ZULU zuluTimeStamp = new ZULU("2017-06-29T21:44:00.35Z"); + Mockito.doReturn(zuluTimeStamp).when(mockCommonHeader).getTimestamp(); + Mockito.doReturn("api ver").when(mockCommonHeader).getApiVer(); + Mockito.doReturn("orignator Id").when(mockCommonHeader).getOriginatorId(); + Mockito.doReturn("request Id").when(mockCommonHeader).getRequestId(); + + Mockito.doReturn(myAction).when(mockInput).getAction(); + Mockito.doReturn(mockAI).when(mockInput).getActionIdentifiers(); + Mockito.doReturn("vnfId").when(mockAI).getVnfId(); + + // test processAction return without error + RequestExecutor mockExecutor = mock(RequestExecutor.class); + + RequestHandlerOutput mockOutput = mock(RequestHandlerOutput.class); + Mockito.doReturn(mockOutput).when(mockExecutor).executeRequest(any()); + + ResponseContext mockResponseContext = mock(ResponseContext.class); + Mockito.doReturn(mockResponseContext).when(mockOutput).getResponseContext(); + + org.onap.appc.domainmodel.lcm.Status mockStatus = mock(org.onap.appc.domainmodel.lcm.Status.class); + Integer successCode = Integer.valueOf(LCMCommandStatus.SUCCESS.getResponseCode()); + Mockito.doReturn(successCode).when(mockStatus).getCode(); + Mockito.doReturn(mockStatus).when(mockResponseContext).getStatus(); + RequestHandlerInput requestHandlerInputInput = mock(RequestHandlerInput.class); + AbstractBaseService abstractBaseService = mock(AbstractBaseService.class); + Mockito.when(abstractBaseService.executeAction(requestHandlerInputInput)).thenReturn(mockOutput); + try { + outputBuilder = activateNESwAction.process(mockInput); + } catch(Exception e) { + Assert.assertTrue(true); + } + Assert.assertTrue("Should have commonHeader", outputBuilder.getCommonHeader() == null); + Assert.assertEquals("should return success status", new Integer(302), outputBuilder.getStatus().getCode()); + } + + @Test + public void testValidate() throws Exception { + activateNESwAction.validate(mockCommonHeader, Action.ActivateNESw, mockAI, mockPayload); + Status status = (Status) Whitebox.getInternalState(activateNESwAction, "status"); + Assert.assertEquals("should return missing parameter", + Integer.valueOf(LCMCommandStatus.MISSING_MANDATORY_PARAMETER.getResponseCode()), status.getCode()); + Mockito.verify(activateNESwAction, times(0)).buildStatusForParamName(any(), any()); + Mockito.verify(activateNESwAction, times(0)).buildStatusForErrorMsg(any(), any()); + + ZULU mockTimeStamp = mock(ZULU.class); + Mockito.doReturn(mockTimeStamp).when(mockCommonHeader).getTimestamp(); + Mockito.doReturn("api ver").when(mockCommonHeader).getApiVer(); + Mockito.doReturn("orignator Id").when(mockCommonHeader).getOriginatorId(); + Mockito.doReturn("request Id").when(mockCommonHeader).getRequestId(); + + // test empty action + activateNESwAction.validate(mockCommonHeader, Action.ActivateNESw, mockAI, mockPayload); + status = (Status) Whitebox.getInternalState(activateNESwAction, "status"); + Assert.assertEquals("Should return missing parameter for action", + Integer.valueOf(LCMCommandStatus.MISSING_MANDATORY_PARAMETER.getResponseCode()), status.getCode()); + + // test empty ActionIdentifier + activateNESwAction.validate(mockCommonHeader, Action.ActivateNESw, mockAI, mockPayload); + status = (Status) Whitebox.getInternalState(activateNESwAction, "status"); + Assert.assertEquals("should return missing parameter", + Integer.valueOf(LCMCommandStatus.MISSING_MANDATORY_PARAMETER.getResponseCode()), status.getCode()); + + // test Invalid VNF_ID + Mockito.doReturn("").when(mockAI).getVnfId(); + activateNESwAction.validate(mockCommonHeader, Action.ActivateNESw, mockAI, mockPayload); + status = (Status) Whitebox.getInternalState(activateNESwAction, "status"); + Assert.assertEquals("should return invalid parameter", + Integer.valueOf(LCMCommandStatus.INVALID_INPUT_PARAMETER.getResponseCode()), status.getCode()); + + // test null payload + Mockito.doReturn("vnfId").when(mockAI).getVnfId(); + activateNESwAction.validate(mockCommonHeader, Action.ActivateNESw, mockAI, null); + Mockito.verify(activateNESwAction, times(1)).validateExcludedActIds(any(), any()); + status = (Status) Whitebox.getInternalState(activateNESwAction, "status"); + Assert.assertTrue("Should skip Payload", true); + + // test empty payload + Mockito.doReturn("").when(mockPayload).getValue(); + activateNESwAction.validate(mockCommonHeader, Action.ActivateNESw, mockAI, mockPayload); + status = (Status) Whitebox.getInternalState(activateNESwAction, "status"); + Assert.assertTrue("Should skip Payload", true); + + // test space payload + Mockito.doReturn(" ").when(mockPayload).getValue(); + activateNESwAction.validate(mockCommonHeader, Action.ActivateNESw, mockAI, mockPayload); + status = (Status) Whitebox.getInternalState(activateNESwAction, "status"); + Assert.assertTrue("Should skip Payload", true); + } +} + diff --git a/appc-provider/appc-provider-bundle/src/test/java/org/onap/appc/provider/lcm/service/DownloadNESwTest.java b/appc-provider/appc-provider-bundle/src/test/java/org/onap/appc/provider/lcm/service/DownloadNESwTest.java new file mode 100644 index 000000000..c787f714d --- /dev/null +++ b/appc-provider/appc-provider-bundle/src/test/java/org/onap/appc/provider/lcm/service/DownloadNESwTest.java @@ -0,0 +1,172 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP : APPC + * ================================================================================ + * Copyright (C) 2017-2019 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Copyright (C) 2017 Amdocs + * ================================================================================ + * Copyright (C) 2020 Huawei + * ================================================================================ + * 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. + * + * ECOMP is a trademark and service mark of AT&T Intellectual Property. + * ============LICENSE_END========================================================= + */ + +package org.onap.appc.provider.lcm.service; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.mockito.internal.util.reflection.Whitebox; +import org.mockito.runners.MockitoJUnitRunner; +import org.opendaylight.yang.gen.v1.org.onap.appc.lcm.rev160108.*; +import org.opendaylight.yang.gen.v1.org.onap.appc.lcm.rev160108.action.identifiers.ActionIdentifiers; +import org.opendaylight.yang.gen.v1.org.onap.appc.lcm.rev160108.common.header.CommonHeader; +import org.opendaylight.yang.gen.v1.org.onap.appc.lcm.rev160108.status.Status; +import org.onap.appc.domainmodel.lcm.ResponseContext; +import org.onap.appc.executor.objects.LCMCommandStatus; +import org.onap.appc.requesthandler.objects.RequestHandlerOutput; +import org.onap.appc.requesthandler.objects.RequestHandlerInput; + +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; + +@RunWith(MockitoJUnitRunner.class) +public class DownloadNESwTest { + private final Action myAction = Action.DownloadNESw; + private final String PAYLOAD_STRING = "{\"A\":\"A-value\",\"B\":{\"C\":\"B.C-value\",\"D\":\"B.D-value\"}}"; + private DownloadNESwInput mockInput = mock(DownloadNESwInput.class); + private CommonHeader mockCommonHeader = mock(CommonHeader.class); + private ActionIdentifiers mockAI = mock(ActionIdentifiers.class); + private Payload mockPayload = mock(Payload.class); + + private DownloadNESw downloadNESwAction; + + @Before + public void setUp() throws Exception { + downloadNESwAction = spy(new DownloadNESw()); + } + + @Test + public void testProcess() throws Exception { + // test error occurs in validation + DownloadNESwOutputBuilder outputBuilder = downloadNESwAction.process(mockInput); + Mockito.verify(downloadNESwAction, times(0)).proceedAction(any(), any(), any()); + Assert.assertTrue("Should not have commonHeader as we did not mock it", + outputBuilder.getCommonHeader() == null); + Assert.assertEquals("should return missing parameter status", + Integer.valueOf(LCMCommandStatus.MISSING_MANDATORY_PARAMETER.getResponseCode()), + outputBuilder.getStatus().getCode()); + + // make validation pass + Mockito.doReturn(mockCommonHeader).when(mockInput).getCommonHeader(); + Mockito.doReturn(mockPayload).when(mockInput).getPayload(); + Mockito.doReturn(PAYLOAD_STRING).when(mockPayload).getValue(); + + // to make validation pass + ZULU zuluTimeStamp = new ZULU("2017-06-29T21:44:00.35Z"); + Mockito.doReturn(zuluTimeStamp).when(mockCommonHeader).getTimestamp(); + Mockito.doReturn("api ver").when(mockCommonHeader).getApiVer(); + Mockito.doReturn("orignator Id").when(mockCommonHeader).getOriginatorId(); + Mockito.doReturn("request Id").when(mockCommonHeader).getRequestId(); + + Mockito.doReturn(myAction).when(mockInput).getAction(); + Mockito.doReturn(mockAI).when(mockInput).getActionIdentifiers(); + Mockito.doReturn("vnfId").when(mockAI).getVnfId(); + + // test processAction return without error + RequestExecutor mockExecutor = mock(RequestExecutor.class); + + RequestHandlerOutput mockOutput = mock(RequestHandlerOutput.class); + Mockito.doReturn(mockOutput).when(mockExecutor).executeRequest(any()); + + ResponseContext mockResponseContext = mock(ResponseContext.class); + Mockito.doReturn(mockResponseContext).when(mockOutput).getResponseContext(); + + org.onap.appc.domainmodel.lcm.Status mockStatus = mock(org.onap.appc.domainmodel.lcm.Status.class); + Integer successCode = Integer.valueOf(LCMCommandStatus.SUCCESS.getResponseCode()); + Mockito.doReturn(successCode).when(mockStatus).getCode(); + Mockito.doReturn(mockStatus).when(mockResponseContext).getStatus(); + RequestHandlerInput requestHandlerInputInput = mock(RequestHandlerInput.class); + AbstractBaseService abstractBaseService = mock(AbstractBaseService.class); + Mockito.when(abstractBaseService.executeAction(requestHandlerInputInput)).thenReturn(mockOutput); + try { + outputBuilder = downloadNESwAction.process(mockInput); + } catch(Exception e) { + Assert.assertTrue(true); + } + Assert.assertTrue("Should have commonHeader", outputBuilder.getCommonHeader() == null); + Assert.assertEquals("should return success status", new Integer(302), outputBuilder.getStatus().getCode()); + } + + @Test + public void testValidate() throws Exception { + downloadNESwAction.validate(mockCommonHeader, Action.DownloadNESw, mockAI, mockPayload); + Status status = (Status) Whitebox.getInternalState(downloadNESwAction, "status"); + Assert.assertEquals("should return missing parameter", + Integer.valueOf(LCMCommandStatus.MISSING_MANDATORY_PARAMETER.getResponseCode()), status.getCode()); + Mockito.verify(downloadNESwAction, times(0)).buildStatusForParamName(any(), any()); + Mockito.verify(downloadNESwAction, times(0)).buildStatusForErrorMsg(any(), any()); + + ZULU mockTimeStamp = mock(ZULU.class); + Mockito.doReturn(mockTimeStamp).when(mockCommonHeader).getTimestamp(); + Mockito.doReturn("api ver").when(mockCommonHeader).getApiVer(); + Mockito.doReturn("orignator Id").when(mockCommonHeader).getOriginatorId(); + Mockito.doReturn("request Id").when(mockCommonHeader).getRequestId(); + + // test empty action + downloadNESwAction.validate(mockCommonHeader, Action.DownloadNESw, mockAI, mockPayload); + status = (Status) Whitebox.getInternalState(downloadNESwAction, "status"); + Assert.assertEquals("Should return missing parameter for action", + Integer.valueOf(LCMCommandStatus.MISSING_MANDATORY_PARAMETER.getResponseCode()), status.getCode()); + + // test empty ActionIdentifier + downloadNESwAction.validate(mockCommonHeader, Action.DownloadNESw, mockAI, mockPayload); + status = (Status) Whitebox.getInternalState(downloadNESwAction, "status"); + Assert.assertEquals("should return missing parameter", + Integer.valueOf(LCMCommandStatus.MISSING_MANDATORY_PARAMETER.getResponseCode()), status.getCode()); + + // test Invalid VNF_ID + Mockito.doReturn("").when(mockAI).getVnfId(); + downloadNESwAction.validate(mockCommonHeader, Action.DownloadNESw, mockAI, mockPayload); + status = (Status) Whitebox.getInternalState(downloadNESwAction, "status"); + Assert.assertEquals("should return invalid parameter", + Integer.valueOf(LCMCommandStatus.INVALID_INPUT_PARAMETER.getResponseCode()), status.getCode()); + + // test null payload + Mockito.doReturn("vnfId").when(mockAI).getVnfId(); + downloadNESwAction.validate(mockCommonHeader, Action.DownloadNESw, mockAI, null); + Mockito.verify(downloadNESwAction, times(1)).validateExcludedActIds(any(), any()); + status = (Status) Whitebox.getInternalState(downloadNESwAction, "status"); + Assert.assertTrue("Should skip Payload", true); + + // test empty payload + Mockito.doReturn("").when(mockPayload).getValue(); + downloadNESwAction.validate(mockCommonHeader, Action.DownloadNESw, mockAI, mockPayload); + status = (Status) Whitebox.getInternalState(downloadNESwAction, "status"); + Assert.assertTrue("Should skip Payload", true); + + // test space payload + Mockito.doReturn(" ").when(mockPayload).getValue(); + downloadNESwAction.validate(mockCommonHeader, Action.DownloadNESw, mockAI, mockPayload); + status = (Status) Whitebox.getInternalState(downloadNESwAction, "status"); + Assert.assertTrue("Should skip Payload", true); + } +} + diff --git a/appc-provider/appc-provider-model/src/main/yang/appc-provider-lcm.yang b/appc-provider/appc-provider-model/src/main/yang/appc-provider-lcm.yang index 99de6c4d2..035fca223 100644 --- a/appc-provider/appc-provider-model/src/main/yang/appc-provider-lcm.yang +++ b/appc-provider/appc-provider-model/src/main/yang/appc-provider-lcm.yang @@ -139,6 +139,8 @@ module appc-provider-lcm { enum "StatusTraffic"; enum "StopTraffic"; enum "ConfigScaleIn"; + enum "DownloadNESw"; + enum "ActivateNESw"; } description "The action to be taken by APP-C, e.g. Restart, Rebuild, Migrate"; } @@ -704,6 +706,10 @@ module appc-provider-lcm { output { uses common-header; uses status; + leaf payload { + type payload; + mandatory false; + } } } @@ -1782,6 +1788,61 @@ module appc-provider-lcm { } } } + + /********************************************************************************** + * Define the downloadNESw operation + **********************************************************************************/ + rpc download-n-e-sw { + description "An operation to download NE software"; + input { + uses common-header; + leaf action { + type action; + mandatory true; + } + uses action-identifiers; + leaf payload { + type payload; + mandatory true; + } + } + output { + uses common-header; + uses status; + leaf payload { + type payload; + mandatory true; + } + } + } + + /********************************************************************************** + * Define the activateNESw operation + **********************************************************************************/ + rpc activate-n-e-sw { + description "An operation to activate NE software"; + input { + uses common-header; + leaf action { + type action; + mandatory true; + } + uses action-identifiers; + leaf payload { + type payload; + mandatory true; + } + } + output { + uses common-header; + uses status; + leaf payload { + type payload; + mandatory true; + } + } + } + /********************************************************************************** * Additional RPCs added here... **********************************************************************************/ diff --git a/docs/APPC LCM API Guide/APPC LCM API Guide.rst b/docs/APPC LCM API Guide/APPC LCM API Guide.rst index 22b28a540..8ea060030 100644 --- a/docs/APPC LCM API Guide/APPC LCM API Guide.rst +++ b/docs/APPC LCM API Guide/APPC LCM API Guide.rst @@ -554,6 +554,8 @@ Commands, or actions, may be currently supported on all VNF types or a limited s +=============================+===========+==================+================+==========+============================================================+ | ActionStatus | Yes | | | | Any | +-----------------------------+-----------+------------------+----------------+----------+------------------------------------------------------------+ +| ActivateNESw | Yes | | | | Chef and Ansible only (requires self-service onboarding) | ++-----------------------------+-----------+------------------+----------------+----------+------------------------------------------------------------+ | AttachVolume | | | | Yes | Any (uses OpenStack command) | +-----------------------------+-----------+------------------+----------------+----------+------------------------------------------------------------+ | Audit | Yes | | | | Any (requires self-service onboarding) | @@ -576,6 +578,8 @@ Commands, or actions, may be currently supported on all VNF types or a limited s +-----------------------------+-----------+------------------+----------------+----------+------------------------------------------------------------+ | DistributeTrafficCheck | Yes | | Yes | Yes | Chef and Ansible only (requires self-service onboarding) | +-----------------------------+-----------+------------------+----------------+----------+------------------------------------------------------------+ +| DownloadNESw | Yes | | | | Chef and Ansible only (requires self-service onboarding) | ++-----------------------------+-----------+------------------+----------------+----------+------------------------------------------------------------+ | Evacuate | | | | Yes | Any (uses OpenStack command) | +-----------------------------+-----------+------------------+----------------+----------+------------------------------------------------------------+ | GetConfig | Yes | | | | Ansible | @@ -741,6 +745,58 @@ If the ActionStatus request was rejected or could not be processed, it returns a request- id=c09ac7d1-de62-0016-2000-e63701125559 AND vnf-id=ctsf0007v", "code": 315`` +ActivateNESw +--------------- + +The ActivateNESw LCM action activates the target software version needed for a software upgrade. + +This command is executed using an Ansible playbook or Chef cookbook. + +Request Structure: + ++--------------------------+------------------------------------------------------------+ +| **Target URL** | /restconf/operations/appc-provider-lcm:activate-n-e-sw | ++--------------------------+------------------------------------------------------------+ +| **Action** | ActivateNESw | ++--------------------------+------------------------------------------------------------+ +| **Action-identifiers** | vnf-id | ++--------------------------+------------------------------------------------------------+ +| **Payload Parameters** | See below | ++--------------------------+------------------------------------------------------------+ +| **Revision History** | New in Frankfurt | ++--------------------------+------------------------------------------------------------+ + +Request Payload Parameters: + ++--------------------------+-------------------------------------+---------------------+-----------------------------------------------------------------------------------------------+ +| **Parameter** | **Description** | **Required?** | **Example** | ++==========================+=====================================+=====================+===============================================================================================+ +| swVersionToBeActivated | The software to be activated | Yes | "payload": | +| | | | "{\"swVersionToBeActivated\": \"v2\"}" | ++--------------------------+-------------------------------------+---------------------+-----------------------------------------------------------------------------------------------+ + +ActivateNESw Response +^^^^^^^^^^^^^^^^^^^^^^^^ + +**Success:** If the ActivateNESw runs successfully, it returns a success status code 400. The response payload contains the results of the activating. + +Response Payload Parameters: + ++-----------------+-----------------------------+---------------------+------------------------------------------------------------------------------------------------------------------------------+ +| **Parameter** | **Description** | **Required?** | **Example** | ++=================+=============================+=====================+==============================================================================================================================+ +| result | Returns the result | Yes | | +| | of the activate-n-e-sw. | | "payload": | +| | Indicates Success or | | "{\\"result\\": \\"Success\\"}” | +| | Failure. | | | ++-----------------+-----------------------------+---------------------+ | +| reason | If not Success, | | | +| | reason contains | | | +| | explanation. | | | ++-----------------+-----------------------------+---------------------+------------------------------------------------------------------------------------------------------------------------------+ + +**Failure:** If an ActivateNESw fails to run, it returns a failure code 401 and the failure reason from the Ansible or Chef server in the response payload block. + AttachVolume ------------ @@ -1425,6 +1481,59 @@ The response does not include any payload parameters. **Failure:** A failed check returns a failure code 401 and the failure message from the Ansible or Chef server in the response payload block. +DownloadNESw +--------------- + +The DownloadNESw LCM action downloads the target software needed for a software upgrade. + +This command is executed using an Ansible playbook or Chef cookbook. + +Request Structure: + ++--------------------------+------------------------------------------------------------+ +| **Target URL** | /restconf/operations/appc-provider-lcm:download-n-e-sw | ++--------------------------+------------------------------------------------------------+ +| **Action** | DownloadNESw | ++--------------------------+------------------------------------------------------------+ +| **Action-identifiers** | vnf-id | ++--------------------------+------------------------------------------------------------+ +| **Payload Parameters** | See below | ++--------------------------+------------------------------------------------------------+ +| **Revision History** | New in Frankfurt | ++--------------------------+------------------------------------------------------------+ + +Request Payload Parameters: + ++-----------------------+-------------------------------------+---------------------+-----------------------------------------------------------------------------------------------+ +| **Parameter** | **Description** | **Required?** | **Example** | ++=======================+=====================================+=====================+===============================================================================================+ +| swToBeDownloaded | The software to be downloaded | Yes | "payload": | +| | | | "{\"swToBeDownloaded\": \"\\\\'[{\\\\\\\"swLocation\\\\\\\": | +| | | | \\\\\\\"http://192.168.1.10:10080/ran_du_pkg1-v2.zip\\\\\\\"}]\\\\'\"}" | ++-----------------------+-------------------------------------+---------------------+-----------------------------------------------------------------------------------------------+ + +DownloadNESw Response +^^^^^^^^^^^^^^^^^^^^^^^^ + +**Success:** If the DownloadNESw runs successfully, it returns a success status code 400. The response payload contains the results of the downloading. + +Response Payload Parameters: + ++-----------------+-----------------------------+---------------------+------------------------------------------------------------------------------------------------------------------------------+ +| **Parameter** | **Description** | **Required?** | **Example** | ++=================+=============================+=====================+==============================================================================================================================+ +| result | Returns the result | Yes | | +| | of the download-n-e-sw. | | "payload": | +| | Indicates Success or | | "{\\"result\\": \\"Success\\"}” | +| | Failure. | | | ++-----------------+-----------------------------+---------------------+ | +| reason | If not Success, | | | +| | reason contains | | | +| | explanation. | | | ++-----------------+-----------------------------+---------------------+------------------------------------------------------------------------------------------------------------------------------+ + +**Failure:** If a DownloadNESw fails to run, it returns a failure code 401 and the failure reason from the Ansible or Chef server in the response payload block. + Evacuate -------- -- cgit 1.2.3-korg