From 0cdb973be30e05fe7c42bb303ddc2187691984f3 Mon Sep 17 00:00:00 2001 From: "Kalkere Ramesh, Sharan (sk720x)" Date: Fri, 23 Mar 2018 16:11:44 -0400 Subject: [PATCH] Initial commit of VDU plugin implementation This was documented in the API we committed to at M3. Change-Id: Id0c886d956dc46dba71157cfa35d88844028e7fd Issue-ID: SO-511 Signed-off-by: Kalkere Ramesh, Sharan (sk720x) --- adapters/mso-adapter-utils/pom.xml | 17 +- .../org/openecomp/mso/adapters/vdu/CloudInfo.java | 69 ++ .../openecomp/mso/adapters/vdu/PluginAction.java | 63 + .../openecomp/mso/adapters/vdu/VduArtifact.java | 64 + .../openecomp/mso/adapters/vdu/VduException.java | 60 + .../openecomp/mso/adapters/vdu/VduInstance.java | 80 ++ .../openecomp/mso/adapters/vdu/VduModelInfo.java | 50 + .../org/openecomp/mso/adapters/vdu/VduPlugin.java | 186 +++ .../openecomp/mso/adapters/vdu/VduStateType.java | 36 + .../org/openecomp/mso/adapters/vdu/VduStatus.java | 54 + .../mso/cloudify/utils/MsoCloudifyUtils.java | 285 ++++- .../mso/openstack/utils/MsoHeatUtils.java | 220 +++- .../org/openecomp/mso/adapters/vdu/BeansTest.java | 56 + .../mso/cloudify/utils/MsoCloudifyUtilsTest.java | 2 +- .../mso/cloudify/utils/MsoCloudifyUtilsTest2.java | 254 ++++ .../mso/openstack/utils/MsoHeatUtilsTest2.java | 169 +++ .../mapper/VfModuleCustomizationToVduMapper.java | 174 +++ .../mso/adapters/vnf/MsoVnfPluginAdapterImpl.java | 1239 ++++++++++++++++++++ .../mso/adapters/vnf/VnfAdapterRestUtils.java | 6 +- .../adapters/vnf/MsoVnfPluginAdapterImplTest.java | 151 +++ .../mso/cloudify/v3/model/AzureConfig.java | 75 ++ 21 files changed, 3292 insertions(+), 18 deletions(-) create mode 100644 adapters/mso-adapter-utils/src/main/java/org/openecomp/mso/adapters/vdu/CloudInfo.java create mode 100644 adapters/mso-adapter-utils/src/main/java/org/openecomp/mso/adapters/vdu/PluginAction.java create mode 100644 adapters/mso-adapter-utils/src/main/java/org/openecomp/mso/adapters/vdu/VduArtifact.java create mode 100644 adapters/mso-adapter-utils/src/main/java/org/openecomp/mso/adapters/vdu/VduException.java create mode 100644 adapters/mso-adapter-utils/src/main/java/org/openecomp/mso/adapters/vdu/VduInstance.java create mode 100644 adapters/mso-adapter-utils/src/main/java/org/openecomp/mso/adapters/vdu/VduModelInfo.java create mode 100644 adapters/mso-adapter-utils/src/main/java/org/openecomp/mso/adapters/vdu/VduPlugin.java create mode 100644 adapters/mso-adapter-utils/src/main/java/org/openecomp/mso/adapters/vdu/VduStateType.java create mode 100644 adapters/mso-adapter-utils/src/main/java/org/openecomp/mso/adapters/vdu/VduStatus.java create mode 100644 adapters/mso-adapter-utils/src/test/java/org/openecomp/mso/adapters/vdu/BeansTest.java create mode 100644 adapters/mso-adapter-utils/src/test/java/org/openecomp/mso/cloudify/utils/MsoCloudifyUtilsTest2.java create mode 100644 adapters/mso-adapter-utils/src/test/java/org/openecomp/mso/openstack/utils/MsoHeatUtilsTest2.java create mode 100644 adapters/mso-vnf-adapter/src/main/java/org/openecomp/mso/adapters/vdu/mapper/VfModuleCustomizationToVduMapper.java create mode 100644 adapters/mso-vnf-adapter/src/main/java/org/openecomp/mso/adapters/vnf/MsoVnfPluginAdapterImpl.java create mode 100644 adapters/mso-vnf-adapter/src/test/java/org/openecomp/mso/adapters/vnf/MsoVnfPluginAdapterImplTest.java create mode 100644 cloudify-client/src/main/java/org/openecomp/mso/cloudify/v3/model/AzureConfig.java diff --git a/adapters/mso-adapter-utils/pom.xml b/adapters/mso-adapter-utils/pom.xml index e264a20d9d..ee70fb6f7f 100644 --- a/adapters/mso-adapter-utils/pom.xml +++ b/adapters/mso-adapter-utils/pom.xml @@ -112,6 +112,21 @@ snakeyaml 1.15 - + + com.shazam + shazamcrest + 0.11 + test + + + com.google.guava + guava + + + org.apache.commons + commons-lang3 + + + diff --git a/adapters/mso-adapter-utils/src/main/java/org/openecomp/mso/adapters/vdu/CloudInfo.java b/adapters/mso-adapter-utils/src/main/java/org/openecomp/mso/adapters/vdu/CloudInfo.java new file mode 100644 index 0000000000..035524510e --- /dev/null +++ b/adapters/mso-adapter-utils/src/main/java/org/openecomp/mso/adapters/vdu/CloudInfo.java @@ -0,0 +1,69 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2018 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.mso.adapters.vdu; + +/** + * Cloud information structure for deploying/managing a VDU. Includes the cloud site + * as well as tenant information within the site. Currently this is defined as a + * cloud site ID. which would map to a CloudConfig entry. + * Perhaps the CloudConfig entry itself should be provided, instead of requiring each + * plug-in to query it. + * + * The meaning of 'tenant' may differ by cloud provider, but every cloud supports some + * sort of tenant partitioning. + * + */ +public class CloudInfo { + + private String cloudSiteId; + private String tenantId; + private String tenantName;//bpmn query and pass + + public CloudInfo() { + } + + public CloudInfo (String cloudSiteId, String tenantId, String tenantName) { + this.cloudSiteId = cloudSiteId; + this.tenantId = tenantId; + this.tenantName = tenantName; + } + + public String getCloudSiteId() { + return cloudSiteId; + } + public void setCloudSiteId(String cloudSiteId) { + this.cloudSiteId = cloudSiteId; + } + public String getTenantId() { + return tenantId; + } + public void setTenantId(String tenantId) { + this.tenantId = tenantId; + } + public String getTenantName() { + return tenantName; + } + public void setTenantName(String tenantName) { + this.tenantName = tenantName; + } + + +} \ No newline at end of file diff --git a/adapters/mso-adapter-utils/src/main/java/org/openecomp/mso/adapters/vdu/PluginAction.java b/adapters/mso-adapter-utils/src/main/java/org/openecomp/mso/adapters/vdu/PluginAction.java new file mode 100644 index 0000000000..1f3cf2f113 --- /dev/null +++ b/adapters/mso-adapter-utils/src/main/java/org/openecomp/mso/adapters/vdu/PluginAction.java @@ -0,0 +1,63 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2018 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.mso.adapters.vdu; + +/** + * Java beam representing a detailed action performed within a plugin during VDU + * orchestration. This allows the plugin to convey more detailed information about + * recent activities it has performed. It is primarily intended for logging and + * troubleshooting, so plugins are free to populate this as desired. + */ +public class PluginAction { + + private String action; + private String status; + private String rawMessage; + + public PluginAction () { + } + + public PluginAction (String action, String status, String rawMessage) { + this.action = action; + this.status = status; + this.rawMessage = rawMessage; + } + + public String getAction() { + return action; + } + public void setAction(String action) { + this.action = action; + } + public String getStatus() { + return status; + } + public void setStatus(String status) { + this.status = status; + } + public String getRawMessage() { + return rawMessage; + } + public void setRawMessage(String rawMessage) { + this.rawMessage = rawMessage; + } + +} \ No newline at end of file diff --git a/adapters/mso-adapter-utils/src/main/java/org/openecomp/mso/adapters/vdu/VduArtifact.java b/adapters/mso-adapter-utils/src/main/java/org/openecomp/mso/adapters/vdu/VduArtifact.java new file mode 100644 index 0000000000..394d13d8d2 --- /dev/null +++ b/adapters/mso-adapter-utils/src/main/java/org/openecomp/mso/adapters/vdu/VduArtifact.java @@ -0,0 +1,64 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2018 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.mso.adapters.vdu; + +public class VduArtifact { + + // Enumerate the types of artifacts permitted. This may need to be a variable string + // value if arbitrary (cloud-specific) artifacts may be attached to VDUs in ASDC. + public enum ArtifactType { + MAIN_TEMPLATE, NESTED_TEMPLATE, CONFIG_FILE, SCRIPT_FILE, TEXT_FILE, ENVIRONMENT + } + + private String name; + private byte[] content; + private ArtifactType type; + + // Default constructor + public VduArtifact() {} + + // Fully specified constructor + public VduArtifact (String name, byte[] content, ArtifactType type) { + this.name = name; + this.content = content; + this.type = type; + } + + public String getName() { + return name; + } + public void setName (String name) { + this.name = name; + } + public byte[] getContent() { + return content; + } + public void setContent(byte[] content) { + this.content = content; + } + public ArtifactType getType() { + return type; + } + public void setType(ArtifactType type) { + this.type = type; + } + +} \ No newline at end of file diff --git a/adapters/mso-adapter-utils/src/main/java/org/openecomp/mso/adapters/vdu/VduException.java b/adapters/mso-adapter-utils/src/main/java/org/openecomp/mso/adapters/vdu/VduException.java new file mode 100644 index 0000000000..3fd1d2ec8a --- /dev/null +++ b/adapters/mso-adapter-utils/src/main/java/org/openecomp/mso/adapters/vdu/VduException.java @@ -0,0 +1,60 @@ +/*- + * ============LICENSE_START======================================================= + * OPENECOMP - MSO + * ================================================================================ + * 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.openecomp.mso.adapters.vdu; + +import org.openecomp.mso.openstack.exceptions.MsoException; +import org.openecomp.mso.openstack.exceptions.MsoExceptionCategory; + +/** + * OpenStack exception. + */ +public class VduException extends MsoException +{ + + /** + * Serialization id. + */ + private static final long serialVersionUID = 3313636124141766495L; + + /** + * Constructor to create a new VduException instance + * @param detail error details + */ + public VduException (String detail) { + // Set the detailed error as the Exception 'message' + super(detail); + // TODO: Need a more generic category than OPENSTACK + super.category = MsoExceptionCategory.OPENSTACK; + } + + /** + * Constructor to create a new VduException instance + * @param detail error details + * @param e the cause + */ + public VduException (String detail, Exception e) { + // Set the detailed error as the Exception 'message' + super(detail, e); + // TODO: Need a more generic category than OPENSTACK + super.category = MsoExceptionCategory.OPENSTACK; + } + +} \ No newline at end of file diff --git a/adapters/mso-adapter-utils/src/main/java/org/openecomp/mso/adapters/vdu/VduInstance.java b/adapters/mso-adapter-utils/src/main/java/org/openecomp/mso/adapters/vdu/VduInstance.java new file mode 100644 index 0000000000..5a5a6ab3d2 --- /dev/null +++ b/adapters/mso-adapter-utils/src/main/java/org/openecomp/mso/adapters/vdu/VduInstance.java @@ -0,0 +1,80 @@ +/*- + * ============LICENSE_START======================================================= + * OPENECOMP - MSO + * ================================================================================ + * 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.openecomp.mso.adapters.vdu; + +import java.util.Map; +import java.util.HashMap; + +/* + * This Java bean class relays VDU status information in a cloud-agnostic format. + * + * This bean is returned by all implementors of the VduPlugin interface operations + * (instantiate, query, delete). + */ + +public class VduInstance { + // Set defaults for everything + protected String vduInstanceId; + protected String vduInstanceName; + protected VduStatus status; + protected Map outputs = new HashMap<>(); + protected Map inputs = new HashMap<>(); + + public String getVduInstanceId() { + return vduInstanceId; + } + + public void setVduInstanceId(String vduInstanceId) { + this.vduInstanceId = vduInstanceId; + } + + public String getVduInstanceName() { + return vduInstanceName; + } + + public void setVduInstanceName(String vduInstanceName) { + this.vduInstanceName = vduInstanceName; + } + + public VduStatus getStatus() { + return status; + } + + public void setStatus(VduStatus status) { + this.status = status; + } + + public Map getOutputs() { + return outputs; + } + + public void setOutputs(Map outputs) { + this.outputs = outputs; + } + + public Map getInputs() { + return inputs; + } + + public void setInputs(Map inputs) { + this.inputs = inputs; + } +} \ No newline at end of file diff --git a/adapters/mso-adapter-utils/src/main/java/org/openecomp/mso/adapters/vdu/VduModelInfo.java b/adapters/mso-adapter-utils/src/main/java/org/openecomp/mso/adapters/vdu/VduModelInfo.java new file mode 100644 index 0000000000..3cef29255f --- /dev/null +++ b/adapters/mso-adapter-utils/src/main/java/org/openecomp/mso/adapters/vdu/VduModelInfo.java @@ -0,0 +1,50 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2018 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.mso.adapters.vdu; + +import java.util.ArrayList; +import java.util.List; + +public class VduModelInfo { + private String modelCustomizationUUID; + private int timeoutMinutes; + private List artifacts = new ArrayList<>(); + + public String getModelCustomizationUUID() { + return modelCustomizationUUID; + } + public void setModelCustomizationUUID(String modelCustomizationUUID) { + this.modelCustomizationUUID = modelCustomizationUUID; + } + public int getTimeoutMinutes() { + return timeoutMinutes; + } + public void setTimeoutMinutes(int timeoutMinutes) { + this.timeoutMinutes = timeoutMinutes; + } + public List getArtifacts() { + return artifacts; + } + public void setArtifacts(List artifacts) { + this.artifacts = artifacts; + } + +} \ No newline at end of file diff --git a/adapters/mso-adapter-utils/src/main/java/org/openecomp/mso/adapters/vdu/VduPlugin.java b/adapters/mso-adapter-utils/src/main/java/org/openecomp/mso/adapters/vdu/VduPlugin.java new file mode 100644 index 0000000000..3484646387 --- /dev/null +++ b/adapters/mso-adapter-utils/src/main/java/org/openecomp/mso/adapters/vdu/VduPlugin.java @@ -0,0 +1,186 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2018 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.mso.adapters.vdu; + +/** + * This interface defines a common API for template-based cloud deployments. + * The methods here should be adaptable for Openstack (Heat), Cloudify (TOSCA), + * Aria (TOSCA), Multi-VIM (TBD), and others (e.g. Azure Resource Manager). + * + * The deployed instances are referred to here as Virtual Deployment Units (VDUs). + * The package of templates that define a give VDU is referred to as its blueprint. + * + * Template-based orchestrators all follow a similar template/blueprint model. + * - One main template that is the top level definition + * - Optional nested templates referenced/included by the main template + * - Optional files attached to the template package, typically containing + * configuration files, install scripts, orchestration scripts, etc. + * + * The main template also defines the required inputs for creating a new instance, + * and output values exposed by successfully deployed instances. Inputs and outputs + * may include simple or complex (JSON) data types. + * + * Each implementation of this interface is expected to understand the MSO CloudConfig + * to obtain the credentials for its sub-orchestrator and the targeted cloud. + * The sub-orchestrator may have different credentials from the cloud (e.g. an Aria + * instance in front of an Openstack cloud) or they may be the same (e.g. Heat) + */ +import java.util.Map; + +public interface VduPlugin { + + /** + * The instantiateVdu interface deploys a new VDU instance from a vdu model package. + * + * For some VIMs, this may be a single command (e.g. Heat -> create stack) or may + * require a series of API calls (e.g. Cloudify -> upload blueprint, create deployment, + * execute install workflow). These details are hidden within the plug-in implementation. + * The instantiation should be fully completed before returning. On failures, this + * method is expected to back out the attempt, leaving the cloud in its previous state. + * + * It is expected that parameters have been validated and contain at minimum the + * required parameters for the given template with no extra parameters. + * + * The VDU name supplied by the caller will be globally unique, and identify the artifact + * in A&AI. Inventory is managed by the higher levels invoking this function. + * + * @param cloudInfo The target cloud + tenant identifiers for the VDU. + * @param instanceName A unique name for the VDU instance to update. + * @param inputs A map of key/value inputs. Values may be strings, numbers, or JSON objects. + * Will completely replace any inputs provided on the original instantiation. + * @param vduModel Object containing the collection of templates and files that comprise + * the blueprint for this VDU. + * @param rollbackOnFailure Flag to preserve or roll back the update on Failure. Should normally + * be True except in troubleshooting/debug cases. Might not be supported in all plug-ins. + * + * @return A VduInstance object + * @throws VduException Thrown if the sub-orchestrator API calls fail or if a timeout occurs. + * Various subclasses of VduException may be thrown. + */ + public VduInstance instantiateVdu ( + CloudInfo cloudInfo, + String instanceName, + Map inputs, + VduModelInfo vduModel, + boolean rollbackOnFailure) + throws VduException; + + /** + * Query a deployed VDU instance. This call will return a VduInstance object, or null + * if the deployment does not exist. + * + * Some VIM orchestrators identify deployment instances by string UUIDs, and others + * by integers. In the latter case, the ID will be passed in as a numeric string. + * + * The returned VduInstance object contains the input and output parameter maps, + * as well as other properties of the deployment (name, status, last action, etc.). + * + * @param cloudInfo The target cloud + tenant identifiers for the VDU. + * @param vduInstanceId The ID of the deployment to query + * + * @return A VduInstance object + * @throws VduException Thrown if the sub-orchestrator API calls fail or if a timeout occurs. + * Various subclasses of VduException may be thrown. + */ + public VduInstance queryVdu ( + CloudInfo cloudInfo, + String vduInstanceId) + throws VduException; + + + /** + * Delete a VDU instance by ID. If the VIM sub-orchestrator supports pre-installation + * of blueprints/models, the blueprint itself may remain installed. This is recommended, + * since other VDU instances may be using it. + * + * Some VIM orchestrators identify deployment instances by string UUIDs, and others + * by integers. In the latter case, the ID will be passed in as a numeric string. + * + * For some VIMs, deletion may be a single command (e.g. Heat -> delete stack) or a + * series of API calls (e.g. Cloudify -> execute uninstall workflow, delete deployment). + * These details are hidden within the plug-in implementation. The deletion should be + * fully completed before returning. + * + * The successful return is a VduInstance object which contains the state of the VDU + * just prior to deletion, with a status of DELETED. If the deployment was not found, + * the VduInstance object should be empty (with a status of NOTFOUND). + * There is no rollback from a successful deletion. + * + * A deletion failure will result in an undefined deployment state - the components may + * or may not have been all or partially uninstalled, so the resulting deployment must + * be considered invalid. + * + * @param cloudInfo The target cloud + tenant identifiers for the VDU. + * @param instanceId The unique id of the deployment to delete. + * @param timeoutMinutes Timeout after which the delete action will be cancelled. + * Consider sending the entire model here, if it may be of use to the plug-in? + * + * @return A VduInstance object, representing its state just prior to deletion. + * + * @throws VduException Thrown if the API calls fail or if a timeout occurs. + * Various subclasses of VduException may be thrown. + */ + public VduInstance deleteVdu ( + CloudInfo cloudInfo, + String instanceId, + int timeoutMinutes) + throws VduException; + + + /** + * The updateVdu interface attempts to update a VDU in-place, using either new inputs or + * a new model definition (i.e. updated templates/blueprints). This depends on the + * capabilities of the targeted sub-orchestrator, as not all implementations are expected + * to support this ability. It is primary included initially only for Heat. + * + * It is expected that parameters have been validated and contain at minimum the required + * parameters for the given template with no extra parameters. The VDU instance name cannot + * be updated. + * + * The update should be fully completed before returning. The successful return is a + * VduInstance object containing the updated VDU state. + * + * An update failure will result in an undefined deployment state - the components may + * or may not have been all or partially modified, deleted, recreated, etc. So the resulting + * VDU must be considered invalid. + * + * @param cloudInfo The target cloud + tenant identifiers for the VDU. + * @param instanceId The unique ID for the VDU instance to update. + * @param inputs A map of key/value inputs. Values may be strings, numbers, or JSON objects. + * Will completely replace any inputs provided on the original instantiation. + * @param vduModel Object containing the collection of templates and files that comprise + * the blueprint for this VDU. + * @param rollbackOnFailure Flag to preserve or roll back the update on Failure. Should normally + * be True except in troubleshooting/debug cases. Might not be supported in all plug-ins. + * + * @return A VduInfo object + * @throws VduException Thrown if the sub-orchestrator API calls fail or if a timeout occurs. + * Various subclasses of VduException may be thrown. + */ + public VduInstance updateVdu ( + CloudInfo cloudInfo, + String instanceId, + Map inputs, + VduModelInfo vduModel, + boolean rollbackOnFailure) + throws VduException; + +} \ No newline at end of file diff --git a/adapters/mso-adapter-utils/src/main/java/org/openecomp/mso/adapters/vdu/VduStateType.java b/adapters/mso-adapter-utils/src/main/java/org/openecomp/mso/adapters/vdu/VduStateType.java new file mode 100644 index 0000000000..92f5cdab3f --- /dev/null +++ b/adapters/mso-adapter-utils/src/main/java/org/openecomp/mso/adapters/vdu/VduStateType.java @@ -0,0 +1,36 @@ +/*- + * ============LICENSE_START======================================================= + * OPENECOMP - MSO + * ================================================================================ + * 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.openecomp.mso.adapters.vdu; + + +/* + * Enum status values to capture the state of a generic (cloud-agnostic) VDU. + */ +public enum VduStateType { + NOTFOUND, + INSTANTIATING, + INSTANTIATED, + DELETING, + DELETED, // Note - only returned in success response to deleteVdu call. + UPDATING, + FAILED, + UNKNOWN +} diff --git a/adapters/mso-adapter-utils/src/main/java/org/openecomp/mso/adapters/vdu/VduStatus.java b/adapters/mso-adapter-utils/src/main/java/org/openecomp/mso/adapters/vdu/VduStatus.java new file mode 100644 index 0000000000..174bed90a2 --- /dev/null +++ b/adapters/mso-adapter-utils/src/main/java/org/openecomp/mso/adapters/vdu/VduStatus.java @@ -0,0 +1,54 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2018 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.mso.adapters.vdu; + +public class VduStatus { + + private VduStateType state; + private String errorMessage; + private PluginAction lastAction; + + public VduStateType getState() { + return state; + } + public void setState(VduStateType state) { + this.state = state; + } + public String getErrorMessage() { + return errorMessage; + } + public void setErrorMessage(String errorMessage) { + this.errorMessage = errorMessage; + } + public PluginAction getLastAction() { + return lastAction; + } + public void setLastAction(PluginAction lastAction) { + this.lastAction = lastAction; + } + public void setLastAction (String action, String status, String rawCloudMessage) { + lastAction = new PluginAction(); + lastAction.setAction (action); + lastAction.setStatus (status); + lastAction.setRawMessage(rawCloudMessage); + } + +} \ No newline at end of file diff --git a/adapters/mso-adapter-utils/src/main/java/org/openecomp/mso/cloudify/utils/MsoCloudifyUtils.java b/adapters/mso-adapter-utils/src/main/java/org/openecomp/mso/cloudify/utils/MsoCloudifyUtils.java index f72e46a9d8..bc3aa4f94f 100644 --- a/adapters/mso-adapter-utils/src/main/java/org/openecomp/mso/cloudify/utils/MsoCloudifyUtils.java +++ b/adapters/mso-adapter-utils/src/main/java/org/openecomp/mso/cloudify/utils/MsoCloudifyUtils.java @@ -26,11 +26,22 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Optional; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; +import org.openecomp.mso.adapters.vdu.CloudInfo; +import org.openecomp.mso.adapters.vdu.PluginAction; +import org.openecomp.mso.adapters.vdu.VduArtifact; +import org.openecomp.mso.adapters.vdu.VduArtifact.ArtifactType; +import org.openecomp.mso.adapters.vdu.VduException; +import org.openecomp.mso.adapters.vdu.VduInstance; +import org.openecomp.mso.adapters.vdu.VduModelInfo; +import org.openecomp.mso.adapters.vdu.VduPlugin; +import org.openecomp.mso.adapters.vdu.VduStateType; +import org.openecomp.mso.adapters.vdu.VduStatus; import org.openecomp.mso.cloud.CloudConfig; import org.openecomp.mso.cloud.CloudConfigFactory; import org.openecomp.mso.cloud.CloudSite; @@ -56,6 +67,7 @@ import org.openecomp.mso.cloudify.v3.client.ExecutionsResource.CancelExecution; import org.openecomp.mso.cloudify.v3.client.ExecutionsResource.GetExecution; import org.openecomp.mso.cloudify.v3.client.ExecutionsResource.ListExecutions; import org.openecomp.mso.cloudify.v3.client.ExecutionsResource.StartExecution; +import org.openecomp.mso.cloudify.v3.model.AzureConfig; import org.openecomp.mso.cloudify.v3.model.Blueprint; import org.openecomp.mso.cloudify.v3.model.CancelExecutionParams; import org.openecomp.mso.cloudify.v3.model.CloudifyError; @@ -85,7 +97,7 @@ import com.fasterxml.jackson.core.JsonParseException; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; -public class MsoCloudifyUtils extends MsoCommonUtils { +public class MsoCloudifyUtils extends MsoCommonUtils implements VduPlugin{ private MsoPropertiesFactory msoPropertiesFactory; private CloudConfigFactory cloudConfigFactory; @@ -111,6 +123,12 @@ public class MsoCloudifyUtils extends MsoCommonUtils { private static final ObjectMapper JSON_MAPPER = new ObjectMapper(); + /** + * This constructor MUST be used ONLY in the JUNIT tests, not for real code. + */ + public MsoCloudifyUtils() { + + } /** * This constructor MUST be used ONLY in the JUNIT tests, not for real code. * The MsoPropertiesFactory will be added by EJB injection. @@ -186,17 +204,24 @@ public class MsoCloudifyUtils extends MsoCommonUtils { Cloudify cloudify = getCloudifyClient (cloudSite.get()); - // Create the Cloudify OpenstackConfig with the credentials - OpenstackConfig openstackConfig = getOpenstackConfig (cloudSite.get(), tenantId); - LOGGER.debug ("Ready to Create Deployment (" + deploymentId + ") with input params: " + inputs); // Build up the inputs, including: // - from provided "environment" file // - passed in by caller - // - special input for Openstack Credentials - Map expandedInputs = new HashMap (inputs); - expandedInputs.put("openstack_config", openstackConfig); + // - special input for cloud-specific Credentials + Map expandedInputs = new HashMap<> (inputs); + + String platform = cloudSite.get().getPlatform(); + if (platform == null || platform.equals("") || platform.equalsIgnoreCase("OPENSTACK")) { + // Create the Cloudify OpenstackConfig with the credentials + OpenstackConfig openstackConfig = getOpenstackConfig (cloudSite.get(), tenantId); + expandedInputs.put("openstack_config", openstackConfig); + } else if (platform.equalsIgnoreCase("AZURE")) { + // Create Cloudify AzureConfig with the credentials + AzureConfig azureConfig = getAzureConfig (cloudSite.get(), tenantId); + expandedInputs.put("azure_config", azureConfig); + } // Build up the parameters to create a new deployment CreateDeploymentParams deploymentParams = new CreateDeploymentParams(); @@ -236,10 +261,11 @@ public class MsoCloudifyUtils extends MsoCommonUtils { /* * It can take some time for Cloudify to be ready to execute a workflow - * on the deployment. Sleep 10 seconds. + * on the deployment. Sleep 30 seconds based on observation of behavior + * in a Cloudify VM instance (delay due to "create_deployment_environment"). */ try { - Thread.sleep(10000); + Thread.sleep(30000); } catch (InterruptedException e) {} /* @@ -825,7 +851,7 @@ public class MsoCloudifyUtils extends MsoCommonUtils { /* * Common method to load a blueprint. May be called from */ - private boolean uploadBlueprint (Cloudify cloudify, String blueprintId, String mainFileName, Map blueprintFiles) + protected boolean uploadBlueprint (Cloudify cloudify, String blueprintId, String mainFileName, Map blueprintFiles) throws MsoException { // Check if it already exists. If so, return false. @@ -1204,11 +1230,234 @@ public class MsoCloudifyUtils extends MsoCommonUtils { return me; } + + + /******************************************************************************* + * + * Methods (and associated utilities) to implement the VduPlugin interface + * + *******************************************************************************/ + + /** + * VduPlugin interface for instantiate function. + * + * This one is a bit more complex, in that it will first upload the blueprint if needed, + * then create the Cloudify deployment and execute the install workflow. + * + * This implementation also merges any parameters defined in the ENV file with the other + * other input parameters for any undefined parameters). + * The basic MsoCloudifyUtils separates blueprint management from deploument actions, + * but the VduPlugin does not declare blueprint management operations. + */ + public VduInstance instantiateVdu ( + CloudInfo cloudInfo, + String instanceName, + Map inputs, + VduModelInfo vduModel, + boolean rollbackOnFailure) + throws VduException + { + String cloudSiteId = cloudInfo.getCloudSiteId(); + String tenantId = cloudInfo.getTenantId(); + + // Translate the VDU ModelInformation structure to that which is needed for + // creating and uploading a blueprint. Use the model customization UUID as + // the blueprint identifier. + + String blueprintId = vduModel.getModelCustomizationUUID(); + + try { + + if (! isBlueprintLoaded (cloudSiteId, blueprintId)) { + LOGGER.debug ("Blueprint " + blueprintId + " is not loaded. Will upload it now."); + + // Prepare the blueprint inputs. Need the set of blueprint templates and files, + // plus the main blueprint name. + Map blueprintFiles = new HashMap<>(); + String mainTemplate = ""; + + // Add all of the blueprint artifacts from the VDU model + List vduArtifacts = vduModel.getArtifacts(); + for (VduArtifact vduArtifact: vduArtifacts) + { + // Add all artifacts to the blueprint, with one exception. + // ENVIRONMENT files will be processed later as additional parameters. + + ArtifactType artifactType = vduArtifact.getType(); + if (artifactType != ArtifactType.ENVIRONMENT) { + blueprintFiles.put(vduArtifact.getName(), vduArtifact.getContent()); + + if (artifactType == ArtifactType.MAIN_TEMPLATE) { + mainTemplate = vduArtifact.getName(); + } + } + } + + // Upload the blueprint package + uploadBlueprint(cloudSiteId, blueprintId, mainTemplate, blueprintFiles, false); + } + } + catch (Exception e) { + throw new VduException ("CloudifyUtils (instantiateVDU): blueprint Exception", e); + } + + + // Next, create and install a new deployment based on the blueprint. + // For Cloudify, the deploymentId is specified by the client. Just use the instance name + // as the ID. + + try { + // Query the Cloudify Deployment object and populate a VduInstance + DeploymentInfo deployment = createAndInstallDeployment (cloudSiteId, + tenantId, + instanceName, + blueprintId, + inputs, + true, // (poll for completion) + vduModel.getTimeoutMinutes(), + rollbackOnFailure); + + VduInstance vduInstance = deploymentInfoToVduInstance(deployment); + + return vduInstance; + } + catch (Exception e) { + throw new VduException ("CloudifyUtils (instantiateVDU): Create-and-install-deployment Exception", e); + } + } + + + /** + * VduPlugin interface for query function. + */ + public VduInstance queryVdu (CloudInfo cloudInfo, String instanceId) + throws VduException + { + String cloudSiteId = cloudInfo.getCloudSiteId(); + String tenantId = cloudInfo.getTenantId(); + + try { + // Query the Cloudify Deployment object and populate a VduInstance + DeploymentInfo deployment = queryDeployment (cloudSiteId, tenantId, instanceId); + + VduInstance vduInstance = deploymentInfoToVduInstance(deployment); + + return vduInstance; + } + catch (Exception e) { + throw new VduException ("Query VDU Exception", e); + } + } + + + /** + * VduPlugin interface for delete function. + */ + public VduInstance deleteVdu (CloudInfo cloudInfo, String instanceId, int timeoutMinutes) + throws VduException + { + String cloudSiteId = cloudInfo.getCloudSiteId(); + String tenantId = cloudInfo.getTenantId(); + + try { + // Uninstall and delete the Cloudify Deployment + DeploymentInfo deployment = uninstallAndDeleteDeployment (cloudSiteId, tenantId, instanceId, timeoutMinutes); + + // Populate a VduInstance based on the deleted Cloudify Deployment object + VduInstance vduInstance = deploymentInfoToVduInstance(deployment); + + return vduInstance; + } + catch (Exception e) { + throw new VduException ("Delete VDU Exception", e); + } + } + + + /** + * VduPlugin interface for update function. + * + * Update is currently not supported in the MsoCloudifyUtils implementation. + * Just return a VduException. + * + */ + public VduInstance updateVdu ( + CloudInfo cloudInfo, + String instanceId, + Map inputs, + VduModelInfo vduModel, + boolean rollbackOnFailure) + throws VduException + { + throw new VduException ("CloudifyUtils: updateVDU interface not supported"); + } + + + /* + * Convert the local DeploymentInfo object (Cloudify-specific) to a generic VduInstance object + */ + protected VduInstance deploymentInfoToVduInstance (DeploymentInfo deployment) + { + VduInstance vduInstance = new VduInstance(); + + // only one ID in Cloudify, use for both VDU name and ID + vduInstance.setVduInstanceId(deployment.getId()); + vduInstance.setVduInstanceName(deployment.getId()); + + // Copy inputs and outputs + vduInstance.setInputs(deployment.getInputs()); + vduInstance.setOutputs(deployment.getOutputs()); + + // Translate the status elements + vduInstance.setStatus(deploymentStatusToVduStatus (deployment)); + + return vduInstance; + } + + protected VduStatus deploymentStatusToVduStatus (DeploymentInfo deployment) + { + VduStatus vduStatus = new VduStatus(); + + // Determine the status based on last action & status + // DeploymentInfo object should be enhanced to report a better status internally. + DeploymentStatus status = deployment.getStatus(); + + if (status == null) { + vduStatus.setState(VduStateType.UNKNOWN); + } + else if (status == DeploymentStatus.NOTFOUND) { + vduStatus.setState(VduStateType.NOTFOUND); + } + else if (status == DeploymentStatus.INSTALLED) { + vduStatus.setState(VduStateType.INSTANTIATED); + } + else if (status == DeploymentStatus.CREATED) { + // Deployment exists but is not installed. This shouldn't really happen, + // since create + install or uninstall + delete are always done together. + // But account for it anyway, assuming the operation is still in progress. + String lastAction = deployment.getLastAction(); + if (lastAction == null) + vduStatus.setState(VduStateType.INSTANTIATING); + else + vduStatus.setState(VduStateType.DELETING); + } + else if (status == DeploymentStatus.FAILED) { + vduStatus.setState(VduStateType.FAILED); + } else { + vduStatus.setState(VduStateType.UNKNOWN); + } + + vduStatus.setErrorMessage(deployment.getErrorMessage()); + vduStatus.setLastAction(new PluginAction(deployment.getLastAction(), deployment.getActionStatus(), deployment.getErrorMessage())); + + return vduStatus; + } + /* * Return an OpenstackConfig object as expected by Cloudify Openstack Plug-in. * Base the values on the CloudSite definition. */ - private OpenstackConfig getOpenstackConfig (CloudSite cloudSite, String tenantId) { + protected OpenstackConfig getOpenstackConfig (CloudSite cloudSite, String tenantId) { OpenstackConfig openstackConfig = new OpenstackConfig(); openstackConfig.setRegion (cloudSite.getRegionId()); openstackConfig.setAuthUrl (cloudSite.getIdentityService().getIdentityUrl()); @@ -1217,4 +1466,18 @@ public class MsoCloudifyUtils extends MsoCommonUtils { openstackConfig.setTenantName (tenantId); return openstackConfig; } + + /* + * Return an Azure object as expected by Cloudify Azure Plug-in. + * Base the values on the CloudSite definition. + */ + protected AzureConfig getAzureConfig (CloudSite cloudSite, String tenantId) { + AzureConfig azureConfig = new AzureConfig(); + // TODO: Use adminTenant for now, instead of adding another element + azureConfig.setSubscriptionId (cloudSite.getIdentityService().getAdminTenant()); + azureConfig.setTenantId (tenantId); + azureConfig.setClientId (cloudSite.getIdentityService().getMsoId()); + azureConfig.setClientSecret (cloudSite.getIdentityService().getMsoPass()); + return azureConfig; + } } diff --git a/adapters/mso-adapter-utils/src/main/java/org/openecomp/mso/openstack/utils/MsoHeatUtils.java b/adapters/mso-adapter-utils/src/main/java/org/openecomp/mso/openstack/utils/MsoHeatUtils.java index 7dd14d865c..3f5da19854 100644 --- a/adapters/mso-adapter-utils/src/main/java/org/openecomp/mso/openstack/utils/MsoHeatUtils.java +++ b/adapters/mso-adapter-utils/src/main/java/org/openecomp/mso/openstack/utils/MsoHeatUtils.java @@ -30,6 +30,16 @@ import java.util.List; import java.util.Map; import java.util.Set; +import org.openecomp.mso.adapters.vdu.CloudInfo; +import org.openecomp.mso.adapters.vdu.PluginAction; +import org.openecomp.mso.adapters.vdu.VduArtifact; +import org.openecomp.mso.adapters.vdu.VduArtifact.ArtifactType; +import org.openecomp.mso.adapters.vdu.VduException; +import org.openecomp.mso.adapters.vdu.VduInstance; +import org.openecomp.mso.adapters.vdu.VduModelInfo; +import org.openecomp.mso.adapters.vdu.VduPlugin; +import org.openecomp.mso.adapters.vdu.VduStateType; +import org.openecomp.mso.adapters.vdu.VduStatus; import org.openecomp.mso.cloud.CloudConfig; import org.openecomp.mso.cloud.CloudConfigFactory; import org.openecomp.mso.cloud.CloudIdentity; @@ -52,7 +62,6 @@ import org.openecomp.mso.properties.MsoJavaProperties; import org.openecomp.mso.properties.MsoPropertiesException; import org.openecomp.mso.properties.MsoPropertiesFactory; -import com.fasterxml.jackson.core.JsonParseException; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.woorea.openstack.base.client.OpenStackConnectException; @@ -68,7 +77,7 @@ import com.woorea.openstack.keystone.model.Access; import com.woorea.openstack.keystone.model.Authentication; import com.woorea.openstack.keystone.utils.KeystoneUtils; -public class MsoHeatUtils extends MsoCommonUtils { +public class MsoHeatUtils extends MsoCommonUtils implements VduPlugin{ private MsoPropertiesFactory msoPropertiesFactory; @@ -110,6 +119,13 @@ public class MsoHeatUtils extends MsoCommonUtils { private static final ObjectMapper JSON_MAPPER = new ObjectMapper(); + /** + * This constructor MUST be used ONLY in the JUNIT tests, not for real code. + */ + public MsoHeatUtils() { + + } + /** * This constructor MUST be used ONLY in the JUNIT tests, not for real code. * The MsoPropertiesFactory will be added by EJB injection. @@ -1643,4 +1659,204 @@ public class MsoHeatUtils extends MsoCommonUtils { return sb.toString(); } + /******************************************************************************* + * + * Methods (and associated utilities) to implement the VduPlugin interface + * + *******************************************************************************/ + + /** + * VduPlugin interface for instantiate function. + * + * Translate the VduPlugin parameters to the corresponding 'createStack' parameters, + * and then invoke the existing function. + */ + public VduInstance instantiateVdu ( + CloudInfo cloudInfo, + String instanceName, + Map inputs, + VduModelInfo vduModel, + boolean rollbackOnFailure) + throws VduException + { + String cloudSiteId = cloudInfo.getCloudSiteId(); + String tenantId = cloudInfo.getTenantId(); + + // Translate the VDU ModelInformation structure to that which is needed for + // creating the Heat stack. Loop through the artifacts, looking specifically + // for MAIN_TEMPLATE and ENVIRONMENT. Any other artifact will + // be attached as a FILE. + String heatTemplate = null; + Map nestedTemplates = new HashMap<>(); + Map files = new HashMap<>(); + String heatEnvironment = null; + + for (VduArtifact vduArtifact: vduModel.getArtifacts()) { + if (vduArtifact.getType() == ArtifactType.MAIN_TEMPLATE) { + heatTemplate = new String(vduArtifact.getContent()); + } + else if (vduArtifact.getType() == ArtifactType.NESTED_TEMPLATE) { + nestedTemplates.put(vduArtifact.getName(), new String(vduArtifact.getContent())); + } + else if (vduArtifact.getType() == ArtifactType.ENVIRONMENT) { + heatEnvironment = new String(vduArtifact.getContent()); + } + } + + try { + StackInfo stackInfo = createStack (cloudSiteId, + tenantId, + instanceName, + heatTemplate, + inputs, + true, // poll for completion + vduModel.getTimeoutMinutes(), + heatEnvironment, + nestedTemplates, + files, + rollbackOnFailure); + + // Populate a vduInstance from the StackInfo + VduInstance vduInstance = stackInfoToVduInstance(stackInfo); + + return vduInstance; + } + catch (Exception e) { + throw new VduException ("MsoHeatUtils (instantiateVDU): createStack Exception", e); + } + } + + + /** + * VduPlugin interface for query function. + */ + public VduInstance queryVdu (CloudInfo cloudInfo, String instanceId) + throws VduException + { + String cloudSiteId = cloudInfo.getCloudSiteId(); + String tenantId = cloudInfo.getTenantId(); + + try { + // Query the Cloudify Deployment object and populate a VduInstance + StackInfo stackInfo = queryStack (cloudSiteId, tenantId, instanceId); + + VduInstance vduInstance = stackInfoToVduInstance(stackInfo); + + return vduInstance; + } + catch (Exception e) { + throw new VduException ("MsoHeatUtile (queryVdu): queryStack Exception ", e); + } + } + + + /** + * VduPlugin interface for delete function. + */ + public VduInstance deleteVdu (CloudInfo cloudInfo, String instanceId, int timeoutMinutes) + throws VduException + { + String cloudSiteId = cloudInfo.getCloudSiteId(); + String tenantId = cloudInfo.getTenantId(); + + try { + // Delete the Heat stack + StackInfo stackInfo = deleteStack (tenantId, cloudSiteId, instanceId, true); + + // Populate a VduInstance based on the deleted Cloudify Deployment object + VduInstance vduInstance = stackInfoToVduInstance(stackInfo); + + // Override return state to DELETED (HeatUtils sets to NOTFOUND) + vduInstance.getStatus().setState(VduStateType.DELETED); + + return vduInstance; + } + catch (Exception e) { + throw new VduException ("Delete VDU Exception", e); + } + } + + + /** + * VduPlugin interface for update function. + * + * Update is currently not supported in the MsoHeatUtils implementation of VduPlugin. + * Just return a VduException. + * + */ + public VduInstance updateVdu ( + CloudInfo cloudInfo, + String instanceId, + Map inputs, + VduModelInfo vduModel, + boolean rollbackOnFailure) + throws VduException + { + throw new VduException ("MsoHeatUtils: updateVdu interface not supported"); + } + + + /* + * Convert the local DeploymentInfo object (Cloudify-specific) to a generic VduInstance object + */ + private VduInstance stackInfoToVduInstance (StackInfo stackInfo) + { + VduInstance vduInstance = new VduInstance(); + + // The full canonical name as the instance UUID + vduInstance.setVduInstanceId(stackInfo.getCanonicalName()); + vduInstance.setVduInstanceName(stackInfo.getName()); + + // Copy inputs and outputs + vduInstance.setInputs(stackInfo.getParameters()); + vduInstance.setOutputs(stackInfo.getOutputs()); + + // Translate the status elements + vduInstance.setStatus(stackStatusToVduStatus (stackInfo)); + + return vduInstance; + } + + private VduStatus stackStatusToVduStatus (StackInfo stackInfo) + { + VduStatus vduStatus = new VduStatus(); + + // Map the status fields to more generic VduStatus. + // There are lots of HeatStatus values, so this is a bit long... + HeatStatus heatStatus = stackInfo.getStatus(); + String statusMessage = stackInfo.getStatusMessage(); + + if (heatStatus == HeatStatus.INIT || heatStatus == HeatStatus.BUILDING) { + vduStatus.setState(VduStateType.INSTANTIATING); + vduStatus.setLastAction((new PluginAction ("create", "in_progress", statusMessage))); + } + else if (heatStatus == HeatStatus.NOTFOUND) { + vduStatus.setState(VduStateType.NOTFOUND); + } + else if (heatStatus == HeatStatus.CREATED) { + vduStatus.setState(VduStateType.INSTANTIATED); + vduStatus.setLastAction((new PluginAction ("create", "complete", statusMessage))); + } + else if (heatStatus == HeatStatus.UPDATED) { + vduStatus.setState(VduStateType.INSTANTIATED); + vduStatus.setLastAction((new PluginAction ("update", "complete", statusMessage))); + } + else if (heatStatus == HeatStatus.UPDATING) { + vduStatus.setState(VduStateType.UPDATING); + vduStatus.setLastAction((new PluginAction ("update", "in_progress", statusMessage))); + } + else if (heatStatus == HeatStatus.DELETING) { + vduStatus.setState(VduStateType.DELETING); + vduStatus.setLastAction((new PluginAction ("delete", "in_progress", statusMessage))); + } + else if (heatStatus == HeatStatus.FAILED) { + vduStatus.setState(VduStateType.FAILED); + vduStatus.setErrorMessage(stackInfo.getStatusMessage()); + } else { + vduStatus.setState(VduStateType.UNKNOWN); + } + + return vduStatus; + } + } diff --git a/adapters/mso-adapter-utils/src/test/java/org/openecomp/mso/adapters/vdu/BeansTest.java b/adapters/mso-adapter-utils/src/test/java/org/openecomp/mso/adapters/vdu/BeansTest.java new file mode 100644 index 0000000000..1452c1569c --- /dev/null +++ b/adapters/mso-adapter-utils/src/test/java/org/openecomp/mso/adapters/vdu/BeansTest.java @@ -0,0 +1,56 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2018 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.mso.adapters.vdu; + +import org.junit.Test; + +import com.openpojo.reflection.PojoClass; +import com.openpojo.reflection.PojoClassFilter; +import com.openpojo.reflection.filters.FilterPackageInfo; +import com.openpojo.validation.Validator; +import com.openpojo.validation.ValidatorBuilder; +import com.openpojo.validation.rule.impl.GetterMustExistRule; +import com.openpojo.validation.test.impl.GetterTester; +import com.openpojo.validation.test.impl.SetterTester; + +public class BeansTest { + + private PojoClassFilter filterTestClasses = new FilterTestClasses(); + + @Test + public void pojoStructure() { + test("org.openecomp.mso.adapters.vdu"); + } + + private void test(String pojoPackage) { + Validator validator = ValidatorBuilder.create() + .with(new GetterMustExistRule()) + .with(new SetterTester()) + .with(new GetterTester()) + .build(); + validator.validate(pojoPackage, new FilterPackageInfo(), filterTestClasses); + } + private static class FilterTestClasses implements PojoClassFilter { + public boolean include(PojoClass pojoClass) { + return !pojoClass.getSourcePath().contains("/test-classes/"); + } + } +} diff --git a/adapters/mso-adapter-utils/src/test/java/org/openecomp/mso/cloudify/utils/MsoCloudifyUtilsTest.java b/adapters/mso-adapter-utils/src/test/java/org/openecomp/mso/cloudify/utils/MsoCloudifyUtilsTest.java index 214d6f2500..821522fedc 100644 --- a/adapters/mso-adapter-utils/src/test/java/org/openecomp/mso/cloudify/utils/MsoCloudifyUtilsTest.java +++ b/adapters/mso-adapter-utils/src/test/java/org/openecomp/mso/cloudify/utils/MsoCloudifyUtilsTest.java @@ -140,4 +140,4 @@ public class MsoCloudifyUtilsTest { } -} \ No newline at end of file +} diff --git a/adapters/mso-adapter-utils/src/test/java/org/openecomp/mso/cloudify/utils/MsoCloudifyUtilsTest2.java b/adapters/mso-adapter-utils/src/test/java/org/openecomp/mso/cloudify/utils/MsoCloudifyUtilsTest2.java new file mode 100644 index 0000000000..05608b4d99 --- /dev/null +++ b/adapters/mso-adapter-utils/src/test/java/org/openecomp/mso/cloudify/utils/MsoCloudifyUtilsTest2.java @@ -0,0 +1,254 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2018 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.mso.cloudify.utils; + +import static com.shazam.shazamcrest.MatcherAssert.assertThat; +import static com.shazam.shazamcrest.matcher.Matchers.sameBeanAs; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.when; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +import org.junit.Test; +import org.mockito.Mockito; +import org.openecomp.mso.adapters.vdu.CloudInfo; +import org.openecomp.mso.adapters.vdu.PluginAction; +import org.openecomp.mso.adapters.vdu.VduArtifact; +import org.openecomp.mso.adapters.vdu.VduArtifact.ArtifactType; +import org.openecomp.mso.adapters.vdu.VduInstance; +import org.openecomp.mso.adapters.vdu.VduModelInfo; +import org.openecomp.mso.adapters.vdu.VduStateType; +import org.openecomp.mso.adapters.vdu.VduStatus; +import org.openecomp.mso.cloud.CloudConfig; +import org.openecomp.mso.cloud.CloudIdentity; +import org.openecomp.mso.cloud.CloudSite; +import org.openecomp.mso.cloudify.beans.DeploymentInfo; +import org.openecomp.mso.cloudify.beans.DeploymentStatus; +import org.openecomp.mso.cloudify.v3.client.Cloudify; +import org.openecomp.mso.cloudify.v3.model.AzureConfig; +import org.openecomp.mso.cloudify.v3.model.OpenstackConfig; +import org.openecomp.mso.openstack.exceptions.MsoException; + +public class MsoCloudifyUtilsTest2 { + + @Test + public void instantiateVduTest() throws MsoException { + VduInstance expected = new VduInstance(); + expected.setVduInstanceId("id"); + expected.setVduInstanceName("id"); + VduStatus status = new VduStatus(); + status.setState(VduStateType.INSTANTIATED); + status.setLastAction(new PluginAction(null, null, null)); + expected.setStatus(status); + + MsoCloudifyUtils cloudify = Mockito.spy(MsoCloudifyUtils.class); + CloudSite site = new CloudSite(); + Optional opSite = Optional.ofNullable(site); + CloudConfig config = Mockito.mock(CloudConfig.class); + cloudify.cloudConfig = config; + Cloudify cloudifyClient = new Cloudify("cloudSite"); + CloudInfo cloudInfo = new CloudInfo(); + cloudInfo.setCloudSiteId("cloudSiteId"); + cloudInfo.setTenantId("tenantId"); + VduModelInfo vduModel = new VduModelInfo(); + vduModel.setModelCustomizationUUID("blueprintId"); + vduModel.setTimeoutMinutes(1); + VduArtifact artifact = new VduArtifact(); + artifact.setName("name"); + artifact.setType(ArtifactType.MAIN_TEMPLATE); + byte[] content = new byte[1]; + artifact.setContent(content); + List artifacts = new ArrayList<>(); + artifacts.add(artifact); + vduModel.setArtifacts(artifacts); + DeploymentInfo deployment = new DeploymentInfo(); + deployment.setId("id"); + deployment.setStatus(DeploymentStatus.INSTALLED); + Map blueprintFiles = new HashMap<>(); + blueprintFiles.put(artifact.getName(), artifact.getContent()); + String instanceName = "instanceName"; + Map inputs = new HashMap<>(); + boolean rollbackOnFailure = true; + + when(config.getCloudSite(cloudInfo.getCloudSiteId())).thenReturn(opSite); + doReturn(false).when(cloudify).isBlueprintLoaded(cloudInfo.getCloudSiteId(), + vduModel.getModelCustomizationUUID()); + doReturn(cloudifyClient).when(cloudify).getCloudifyClient(site); + doReturn(true).when(cloudify).uploadBlueprint(cloudifyClient, vduModel.getModelCustomizationUUID(), + artifact.getName(), blueprintFiles); + doReturn(deployment).when(cloudify).createAndInstallDeployment(cloudInfo.getCloudSiteId(), + cloudInfo.getTenantId(), instanceName, vduModel.getModelCustomizationUUID(), inputs, true, + vduModel.getTimeoutMinutes(), rollbackOnFailure); + + VduInstance actual = cloudify.instantiateVdu(cloudInfo, instanceName, inputs, vduModel, rollbackOnFailure); + assertThat(actual, sameBeanAs(expected)); + } + + @Test + public void queryVduTest() throws MsoException { + VduInstance expected = new VduInstance(); + expected.setVduInstanceId("id"); + expected.setVduInstanceName("id"); + VduStatus status = new VduStatus(); + status.setState(VduStateType.INSTANTIATED); + status.setLastAction(new PluginAction(null, null, null)); + expected.setStatus(status); + + CloudInfo cloudInfo = new CloudInfo(); + cloudInfo.setCloudSiteId("cloudSiteId"); + cloudInfo.setTenantId("tenantId"); + DeploymentInfo deployment = new DeploymentInfo(); + deployment.setId("id"); + deployment.setStatus(DeploymentStatus.INSTALLED); + String instanceId = "instanceId"; + + MsoCloudifyUtils cloudify = Mockito.spy(MsoCloudifyUtils.class); + + doReturn(deployment).when(cloudify).queryDeployment(cloudInfo.getCloudSiteId(), cloudInfo.getTenantId(), + instanceId); + + VduInstance actual = cloudify.queryVdu(cloudInfo, instanceId); + + assertThat(actual, sameBeanAs(expected)); + } + + @Test + public void deleteVduTest() throws MsoException { + VduInstance expected = new VduInstance(); + expected.setVduInstanceId("id"); + expected.setVduInstanceName("id"); + VduStatus status = new VduStatus(); + status.setState(VduStateType.DELETING); + status.setLastAction(new PluginAction("deleting", null, null)); + expected.setStatus(status); + + CloudInfo cloudInfo = new CloudInfo(); + cloudInfo.setCloudSiteId("cloudSiteId"); + cloudInfo.setTenantId("tenantId"); + String instanceId = "instanceId"; + int timeoutMinutes = 1; + DeploymentInfo deployment = Mockito.mock(DeploymentInfo.class); + deployment.setId("id"); + deployment.setStatus(DeploymentStatus.CREATED); + when(deployment.getId()).thenReturn("id"); + when(deployment.getStatus()).thenReturn(DeploymentStatus.CREATED); + when(deployment.getLastAction()).thenReturn("deleting"); + MsoCloudifyUtils cloudify = Mockito.spy(MsoCloudifyUtils.class); + doReturn(deployment).when(cloudify).uninstallAndDeleteDeployment(cloudInfo.getCloudSiteId(), + cloudInfo.getTenantId(), instanceId, timeoutMinutes); + + VduInstance actual = cloudify.deleteVdu(cloudInfo, instanceId, timeoutMinutes); + + assertThat(actual, sameBeanAs(expected)); + } + + @Test + public void deploymentInfoToVduInstanceTest() { + VduInstance expected = new VduInstance(); + expected.setVduInstanceId("id"); + expected.setVduInstanceName("id"); + VduStatus status = new VduStatus(); + status.setState(VduStateType.DELETING); + status.setLastAction(new PluginAction("deleting", null, null)); + expected.setStatus(status); + + DeploymentInfo deployment = Mockito.mock(DeploymentInfo.class); + deployment.setId("id"); + deployment.setStatus(DeploymentStatus.CREATED); + when(deployment.getId()).thenReturn("id"); + when(deployment.getStatus()).thenReturn(DeploymentStatus.CREATED); + when(deployment.getLastAction()).thenReturn("deleting"); + + MsoCloudifyUtils cloudify = new MsoCloudifyUtils(); + + VduInstance actual = cloudify.deploymentInfoToVduInstance(deployment); + + assertThat(actual, sameBeanAs(expected)); + } + + @Test + public void deploymentStatusToVduStatusTest() { + VduStatus expected = new VduStatus(); + expected.setState(VduStateType.DELETING); + expected.setLastAction(new PluginAction("deleting", null, null)); + + DeploymentInfo deployment = Mockito.mock(DeploymentInfo.class); + deployment.setId("id"); + deployment.setStatus(DeploymentStatus.CREATED); + when(deployment.getId()).thenReturn("id"); + when(deployment.getStatus()).thenReturn(DeploymentStatus.CREATED); + when(deployment.getLastAction()).thenReturn("deleting"); + + MsoCloudifyUtils cloudify = new MsoCloudifyUtils(); + + VduStatus actual = cloudify.deploymentStatusToVduStatus(deployment); + + assertThat(actual, sameBeanAs(expected)); + } + + @Test + public void getOpenstackConfigTest() { + OpenstackConfig expected = new OpenstackConfig(); + expected.setRegion("regionId"); + expected.setAuthUrl("identityUrl"); + expected.setUsername("msoId"); + expected.setPassword("msoPass"); + expected.setTenantName("tenantId"); + + MsoCloudifyUtils cloudify = new MsoCloudifyUtils(); + CloudSite cloudSite = Mockito.mock(CloudSite.class); + CloudIdentity cloudIdentity = Mockito.mock(CloudIdentity.class); + when(cloudSite.getIdentityService()).thenReturn(cloudIdentity); + when(cloudSite.getRegionId()).thenReturn("regionId"); + when(cloudIdentity.getIdentityUrl()).thenReturn("identityUrl"); + when(cloudIdentity.getMsoId()).thenReturn("msoId"); + when(cloudIdentity.getMsoPass()).thenReturn("msoPass"); + String tenantId = "tenantId"; + OpenstackConfig actual = cloudify.getOpenstackConfig(cloudSite, tenantId); + + assertThat(actual, sameBeanAs(expected)); + } + + @Test + public void getAzureConfigTest() { + AzureConfig expected = new AzureConfig(); + expected.setSubscriptionId("subscriptionId"); + expected.setTenantId("tenantId"); + expected.setClientId("msoId"); + expected.setClientSecret("msoPass"); + + MsoCloudifyUtils cloudify = new MsoCloudifyUtils(); + CloudSite cloudSite = Mockito.mock(CloudSite.class); + CloudIdentity cloudIdentity = Mockito.mock(CloudIdentity.class); + when(cloudSite.getIdentityService()).thenReturn(cloudIdentity); + when(cloudIdentity.getAdminTenant()).thenReturn("subscriptionId"); + when(cloudIdentity.getMsoId()).thenReturn("msoId"); + when(cloudIdentity.getMsoPass()).thenReturn("msoPass"); + String tenantId = "tenantId"; + AzureConfig actual = cloudify.getAzureConfig(cloudSite, tenantId); + + assertThat(actual, sameBeanAs(expected)); + } +} diff --git a/adapters/mso-adapter-utils/src/test/java/org/openecomp/mso/openstack/utils/MsoHeatUtilsTest2.java b/adapters/mso-adapter-utils/src/test/java/org/openecomp/mso/openstack/utils/MsoHeatUtilsTest2.java new file mode 100644 index 0000000000..a0ab8e6b11 --- /dev/null +++ b/adapters/mso-adapter-utils/src/test/java/org/openecomp/mso/openstack/utils/MsoHeatUtilsTest2.java @@ -0,0 +1,169 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2018 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.mso.openstack.utils; + +import static com.shazam.shazamcrest.MatcherAssert.assertThat; +import static com.shazam.shazamcrest.matcher.Matchers.sameBeanAs; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.when; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +import org.junit.Test; +import org.mockito.Mockito; +import org.openecomp.mso.adapters.vdu.CloudInfo; +import org.openecomp.mso.adapters.vdu.PluginAction; +import org.openecomp.mso.adapters.vdu.VduArtifact; +import org.openecomp.mso.adapters.vdu.VduArtifact.ArtifactType; +import org.openecomp.mso.adapters.vdu.VduInstance; +import org.openecomp.mso.adapters.vdu.VduModelInfo; +import org.openecomp.mso.adapters.vdu.VduStateType; +import org.openecomp.mso.adapters.vdu.VduStatus; +import org.openecomp.mso.cloud.CloudConfig; +import org.openecomp.mso.cloud.CloudSite; +import org.openecomp.mso.cloudify.beans.DeploymentInfo; +import org.openecomp.mso.cloudify.beans.DeploymentStatus; +import org.openecomp.mso.cloudify.utils.MsoCloudifyUtils; +import org.openecomp.mso.openstack.beans.HeatStatus; +import org.openecomp.mso.openstack.beans.StackInfo; +import org.openecomp.mso.openstack.exceptions.MsoException; + +import com.fasterxml.jackson.core.JsonProcessingException; + +public class MsoHeatUtilsTest2 { + + @Test + public void instantiateVduTest() throws MsoException, JsonProcessingException { + VduInstance expected = new VduInstance(); + expected.setVduInstanceId("canonicalName"); + expected.setVduInstanceName("name"); + VduStatus status = new VduStatus(); + status.setState(VduStateType.INSTANTIATED); + status.setLastAction((new PluginAction("create", "complete", ""))); + expected.setStatus(status); + + MsoHeatUtils heatUtils = Mockito.spy(MsoHeatUtils.class); + CloudSite site = new CloudSite(); + Optional opSite = Optional.ofNullable(site); + CloudConfig config = Mockito.mock(CloudConfig.class); + heatUtils.cloudConfig = config; + CloudInfo cloudInfo = new CloudInfo(); + cloudInfo.setCloudSiteId("cloudSiteId"); + cloudInfo.setTenantId("tenantId"); + VduModelInfo vduModel = new VduModelInfo(); + vduModel.setModelCustomizationUUID("blueprintId"); + vduModel.setTimeoutMinutes(1); + VduArtifact artifact = new VduArtifact(); + artifact.setName("name"); + artifact.setType(ArtifactType.MAIN_TEMPLATE); + byte[] content = new byte[1]; + artifact.setContent(content); + List artifacts = new ArrayList<>(); + artifacts.add(artifact); + vduModel.setArtifacts(artifacts); + Map blueprintFiles = new HashMap<>(); + blueprintFiles.put(artifact.getName(), artifact.getContent()); + String instanceName = "instanceName"; + Map inputs = new HashMap<>(); + boolean rollbackOnFailure = true; + String heatTemplate = new String(artifact.getContent()); + when(config.getCloudSite(cloudInfo.getCloudSiteId())).thenReturn(opSite); + Map nestedTemplates = new HashMap(); + Map files = new HashMap(); + + StackInfo stackInfo = new StackInfo(); + stackInfo.setCanonicalName("canonicalName"); + stackInfo.setName("name"); + stackInfo.setStatus(HeatStatus.CREATED); + + doReturn(stackInfo).when(heatUtils).createStack(cloudInfo.getCloudSiteId(), cloudInfo.getTenantId(), + instanceName, heatTemplate, inputs, true, vduModel.getTimeoutMinutes(), null, nestedTemplates, files, + rollbackOnFailure); + + VduInstance actual = heatUtils.instantiateVdu(cloudInfo, instanceName, inputs, vduModel, rollbackOnFailure); + + assertThat(actual, sameBeanAs(expected)); + } + + @Test + public void queryVduTest() throws MsoException, JsonProcessingException { + VduInstance expected = new VduInstance(); + expected.setVduInstanceId("canonicalName"); + expected.setVduInstanceName("name"); + VduStatus status = new VduStatus(); + status.setState(VduStateType.INSTANTIATED); + status.setLastAction((new PluginAction("create", "complete", ""))); + expected.setStatus(status); + + CloudInfo cloudInfo = new CloudInfo(); + cloudInfo.setCloudSiteId("cloudSiteId"); + cloudInfo.setTenantId("tenantId"); + String instanceId = "instanceId"; + + StackInfo stackInfo = new StackInfo(); + stackInfo.setCanonicalName("canonicalName"); + stackInfo.setName("name"); + stackInfo.setStatus(HeatStatus.CREATED); + + MsoHeatUtils heatUtils = Mockito.spy(MsoHeatUtils.class); + + doReturn(stackInfo).when(heatUtils).queryStack(cloudInfo.getCloudSiteId(), cloudInfo.getTenantId(), instanceId); + + VduInstance actual = heatUtils.queryVdu(cloudInfo, instanceId); + + assertThat(actual, sameBeanAs(expected)); + } + + @Test + public void deleteVduTest() throws MsoException { + VduInstance expected = new VduInstance(); + expected.setVduInstanceId("canonicalName"); + expected.setVduInstanceName("name"); + VduStatus status = new VduStatus(); + status.setState(VduStateType.DELETED); + expected.setStatus(status); + + CloudInfo cloudInfo = new CloudInfo(); + cloudInfo.setCloudSiteId("cloudSiteId"); + cloudInfo.setTenantId("tenantId"); + String instanceId = "instanceId"; + + StackInfo stackInfo = new StackInfo(); + stackInfo.setCanonicalName("canonicalName"); + stackInfo.setName("name"); + stackInfo.setStatus(HeatStatus.NOTFOUND); + + int timeoutInMinutes = 1; + + MsoHeatUtils heatUtils = Mockito.spy(MsoHeatUtils.class); + + doReturn(stackInfo).when(heatUtils).deleteStack( cloudInfo.getTenantId(), cloudInfo.getCloudSiteId(), instanceId, true); + + VduInstance actual = heatUtils.deleteVdu(cloudInfo, instanceId, timeoutInMinutes); + + assertThat(actual, sameBeanAs(expected)); + } + +} diff --git a/adapters/mso-vnf-adapter/src/main/java/org/openecomp/mso/adapters/vdu/mapper/VfModuleCustomizationToVduMapper.java b/adapters/mso-vnf-adapter/src/main/java/org/openecomp/mso/adapters/vdu/mapper/VfModuleCustomizationToVduMapper.java new file mode 100644 index 0000000000..22d988f4e4 --- /dev/null +++ b/adapters/mso-vnf-adapter/src/main/java/org/openecomp/mso/adapters/vdu/mapper/VfModuleCustomizationToVduMapper.java @@ -0,0 +1,174 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2018 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.mso.adapters.vdu.mapper; + +import java.util.List; +import java.util.Map; + +import org.openecomp.mso.adapters.vdu.VduArtifact; +import org.openecomp.mso.adapters.vdu.VduArtifact.ArtifactType; +import org.openecomp.mso.adapters.vdu.VduModelInfo; +import org.openecomp.mso.db.catalog.CatalogDatabase; +import org.openecomp.mso.db.catalog.beans.HeatEnvironment; +import org.openecomp.mso.db.catalog.beans.HeatFiles; +import org.openecomp.mso.db.catalog.beans.HeatTemplate; +import org.openecomp.mso.db.catalog.beans.VfModuleCustomization; +import org.openecomp.mso.logger.MsoLogger; +import org.springframework.stereotype.Component; + +@Component +public class VfModuleCustomizationToVduMapper { + + private static MsoLogger LOGGER = MsoLogger.getMsoLogger(MsoLogger.Catalog.RA); + + public VduModelInfo mapVfModuleCustomizationToVdu(VfModuleCustomization vfModuleCustom) throws Exception { + CatalogDatabase db = CatalogDatabase.getInstance(); + VduModelInfo vduModel = new VduModelInfo(); + vduModel.setModelCustomizationUUID(vfModuleCustom.getModelCustomizationUuid()); + try { + // Map the cloud templates, attached files, and environment file + mapCloudTemplates( + db.getHeatTemplateByArtifactUuid(vfModuleCustom.getVfModule().getHeatTemplateArtifactUUId()), + vduModel); + mapCloudFiles(vfModuleCustom, vduModel); + mapEnvironment(db.getHeatEnvironmentByArtifactUuid(vfModuleCustom.getHeatEnvironmentArtifactUuid()), + vduModel); + } catch (Exception e) { + LOGGER.debug("unhandled exception in mapVfModuleCustomizationToVdu", e); + throw new Exception("Exception during mapVfModuleCustomizationToVdu " + e.getMessage()); + } finally { + // Make sure DB session is closed + db.close(); + } + + return vduModel; + } + + public VduModelInfo mapVfModuleCustVolumeToVdu(VfModuleCustomization vfModuleCustom) throws Exception { + CatalogDatabase db = CatalogDatabase.getInstance(); + VduModelInfo vduModel = new VduModelInfo(); + vduModel.setModelCustomizationUUID(vfModuleCustom.getModelCustomizationUuid()); + try { + // Map the cloud templates, attached files, and environment file + mapCloudTemplates( + db.getHeatTemplateByArtifactUuid(vfModuleCustom.getVfModule().getVolHeatTemplateArtifactUUId()), + vduModel); + mapCloudFiles(vfModuleCustom, vduModel); + mapEnvironment(db.getHeatEnvironmentByArtifactUuid(vfModuleCustom.getVolEnvironmentArtifactUuid()), + vduModel); + } catch (Exception e) { + LOGGER.debug("unhandled exception in mapVfModuleCustVolumeToVdu", e); + throw new Exception("Exception during mapVfModuleCustVolumeToVdu " + e.getMessage()); + } finally { + // Make sure DB session is closed + db.close(); + } + + return vduModel; + } + + private void mapCloudTemplates(HeatTemplate heatTemplate, VduModelInfo vduModel) throws Exception { + // TODO: These catalog objects will be refactored to be + // non-Heat-specific + CatalogDatabase db = CatalogDatabase.getInstance(); + try { + List vduArtifacts = vduModel.getArtifacts(); + + // Main template. Also set the VDU timeout based on the main + // template. + vduArtifacts.add(mapHeatTemplateToVduArtifact(heatTemplate, ArtifactType.MAIN_TEMPLATE)); + vduModel.setTimeoutMinutes(heatTemplate.getTimeoutMinutes()); + + // Nested templates + Map nestedTemplates = db.getNestedTemplates(heatTemplate.getArtifactUuid()); + if (nestedTemplates != null) { + for (String name : nestedTemplates.keySet()) { + String body = (String) nestedTemplates.get(name); + VduArtifact vduArtifact = new VduArtifact(name, body.getBytes(), ArtifactType.NESTED_TEMPLATE); + vduArtifacts.add(vduArtifact); + } + } + + } catch (Exception e) { + LOGGER.debug("unhandled exception in mapCloudTemplates", e); + throw new Exception("Exception during mapCloudTemplates " + e.getMessage()); + } finally { + // Make sure DB session is closed + db.close(); + } + } + + private VduArtifact mapHeatTemplateToVduArtifact(HeatTemplate heatTemplate, ArtifactType artifactType) { + VduArtifact vduArtifact = new VduArtifact(); + vduArtifact.setName(heatTemplate.getTemplateName()); + vduArtifact.setContent(heatTemplate.getHeatTemplate().getBytes()); + vduArtifact.setType(artifactType); + return vduArtifact; + } + + private void mapCloudFiles(VfModuleCustomization vfModuleCustom, VduModelInfo vduModel) throws Exception { + // TODO: These catalog objects will be refactored to be + // non-Heat-specific + CatalogDatabase db = CatalogDatabase.getInstance(); + + try{ + Map heatFiles = db.getHeatFilesForVfModule(vfModuleCustom.getVfModuleModelUuid()); + if (heatFiles != null) { + for (HeatFiles heatFile: heatFiles.values()) { + mapCloudFileToVduArtifact(heatFile, ArtifactType.TEXT_FILE); + } + } + } catch (Exception e) { + LOGGER.debug("unhandled exception in mapCloudFiles", e); + throw new Exception("Exception during mapCloudFiles " + e.getMessage()); + } finally { + // Make sure DB session is closed + db.close(); + } + + } + + private VduArtifact mapCloudFileToVduArtifact(HeatFiles heatFile, ArtifactType artifactType) { + VduArtifact vduArtifact = new VduArtifact(); + vduArtifact.setName(heatFile.getFileName()); + vduArtifact.setContent(heatFile.getFileBody().getBytes()); + vduArtifact.setType(artifactType); + return vduArtifact; + } + + private void mapEnvironment(HeatEnvironment heatEnvironment, VduModelInfo vduModel) { + // TODO: These catalog objects will be refactored to be + // non-Heat-specific + if (heatEnvironment != null) { + List vduArtifacts = vduModel.getArtifacts(); + vduArtifacts.add(mapEnvironmentFileToVduArtifact(heatEnvironment)); + } + } + + private VduArtifact mapEnvironmentFileToVduArtifact(HeatEnvironment heatEnv) { + VduArtifact vduArtifact = new VduArtifact(); + vduArtifact.setName(heatEnv.getName()); + vduArtifact.setContent(heatEnv.getEnvironment().getBytes()); + vduArtifact.setType(ArtifactType.ENVIRONMENT); + return vduArtifact; + } + +} \ No newline at end of file diff --git a/adapters/mso-vnf-adapter/src/main/java/org/openecomp/mso/adapters/vnf/MsoVnfPluginAdapterImpl.java b/adapters/mso-vnf-adapter/src/main/java/org/openecomp/mso/adapters/vnf/MsoVnfPluginAdapterImpl.java new file mode 100644 index 0000000000..0a0747a98d --- /dev/null +++ b/adapters/mso-vnf-adapter/src/main/java/org/openecomp/mso/adapters/vnf/MsoVnfPluginAdapterImpl.java @@ -0,0 +1,1239 @@ +/*- + * ============LICENSE_START======================================================= + * OPENECOMP - MSO + * ================================================================================ + * 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========================================================= + */ + +/** + * This VNF Adapter implementation is based on the VDU Plugin model. It assumes that each + * VF Module definition in the MSO catalog is expressed via a set of template and/or file + * artifacts that are appropriate for some specific sub-orchestrator that provides an + * implementation of the VduPlugin interface. This adapter handles all of the common + * VF Module logic, including: + * - catalog lookups for artifact retrieval + * - parameter filtering and validation + * - base and volume module queries + * - rollback logic + * - logging and error handling + * + * Then based on the orchestration mode of the VNF, it will invoke different VDU plug-ins + * to perform the low level instantiations, deletions, and queries. At this time, the + * set of available plug-ins is hard-coded, though in the future a dynamic selection + * is expected (e.g. via a service-provider interface). + */ +package org.openecomp.mso.adapters.vnf; + + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; + +import javax.jws.WebService; +import javax.xml.ws.Holder; + +import org.openecomp.mso.adapters.vdu.CloudInfo; +import org.openecomp.mso.adapters.vdu.VduException; +import org.openecomp.mso.adapters.vdu.VduInstance; +import org.openecomp.mso.adapters.vdu.VduModelInfo; +import org.openecomp.mso.adapters.vdu.VduPlugin; +import org.openecomp.mso.adapters.vdu.VduStateType; +import org.openecomp.mso.adapters.vdu.VduStatus; +import org.openecomp.mso.adapters.vdu.mapper.VfModuleCustomizationToVduMapper; +import org.openecomp.mso.adapters.vnf.exceptions.VnfAlreadyExists; +import org.openecomp.mso.adapters.vnf.exceptions.VnfException; +import org.openecomp.mso.cloud.CloudConfig; +import org.openecomp.mso.cloud.CloudConfigFactory; +import org.openecomp.mso.cloud.CloudSite; +import org.openecomp.mso.cloudify.utils.MsoCloudifyUtils; +import org.openecomp.mso.db.catalog.CatalogDatabase; +import org.openecomp.mso.db.catalog.beans.HeatEnvironment; +import org.openecomp.mso.db.catalog.beans.HeatTemplate; +import org.openecomp.mso.db.catalog.beans.HeatTemplateParam; +import org.openecomp.mso.db.catalog.beans.VfModule; +import org.openecomp.mso.db.catalog.beans.VfModuleCustomization; +import org.openecomp.mso.db.catalog.beans.VnfResource; +import org.openecomp.mso.db.catalog.utils.MavenLikeVersioning; +import org.openecomp.mso.entity.MsoRequest; +import org.openecomp.mso.logger.MessageEnum; +import org.openecomp.mso.logger.MsoAlarmLogger; +import org.openecomp.mso.logger.MsoLogger; +import org.openecomp.mso.openstack.beans.VnfRollback; +import org.openecomp.mso.openstack.beans.VnfStatus; +import org.openecomp.mso.openstack.exceptions.MsoCloudSiteNotFound; +import org.openecomp.mso.openstack.exceptions.MsoException; +import org.openecomp.mso.openstack.exceptions.MsoExceptionCategory; +import org.openecomp.mso.openstack.utils.MsoHeatEnvironmentEntry; +import org.openecomp.mso.openstack.utils.MsoHeatUtils; +import org.openecomp.mso.properties.MsoPropertiesFactory; + +import com.fasterxml.jackson.core.JsonParseException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; + +@WebService(serviceName = "VnfAdapter", endpointInterface = "org.openecomp.mso.adapters.vnf.MsoVnfAdapter", targetNamespace = "http://org.openecomp.mso/vnf") +public class MsoVnfPluginAdapterImpl implements MsoVnfAdapter { + + CloudConfigFactory cloudConfigFactory = new CloudConfigFactory(); + protected CloudConfig cloudConfig = cloudConfigFactory.getCloudConfig(); + protected MsoHeatUtils heatUtils; + protected VfModuleCustomizationToVduMapper vduMapper; + protected MsoCloudifyUtils cloudifyUtils; + + MsoPropertiesFactory msoPropertiesFactory=new MsoPropertiesFactory(); + + private static final String MSO_PROP_VNF_ADAPTER = "MSO_PROP_VNF_ADAPTER"; + private static final String MSO_CONFIGURATION_ERROR = "MsoConfigurationError"; + private static MsoLogger LOGGER = MsoLogger.getMsoLogger (MsoLogger.Catalog.RA); + private static MsoAlarmLogger alarmLogger = new MsoAlarmLogger (); + private static final String CHECK_REQD_PARAMS = "org.openecomp.mso.adapters.vnf.checkRequiredParameters"; + private static final ObjectMapper JSON_MAPPER = new ObjectMapper(); + + /** + * Health Check web method. Does nothing but return to show the adapter is deployed. + */ + @Override + public void healthCheck () { + LOGGER.debug ("Health check call in VNF Plugin Adapter"); + } + + /** + * DO NOT use that constructor to instantiate this class, the msoPropertiesfactory will be NULL. + * @see MsoVnfPluginAdapterImpl#MsoVnfAdapterImpl(MsoPropertiesFactory, CloudConfigFactory) + */ + public MsoVnfPluginAdapterImpl() { + + } + + /** + * This constructor MUST be used if this class is called with the new operator. + * @param msoPropFactory + */ + public MsoVnfPluginAdapterImpl(MsoPropertiesFactory msoPropFactory, CloudConfigFactory cloudConfigFact) { + this.msoPropertiesFactory = msoPropFactory; + this.cloudConfigFactory = cloudConfigFact; + heatUtils = new MsoHeatUtils(MSO_PROP_VNF_ADAPTER, msoPropertiesFactory, cloudConfigFactory); + vduMapper = new VfModuleCustomizationToVduMapper(); + cloudifyUtils = new MsoCloudifyUtils (MSO_PROP_VNF_ADAPTER, msoPropertiesFactory,cloudConfigFactory); + } + + /** + * This is the "Create VNF" web service implementation. + * This function is now unsupported and will return an error. + * + */ + @Override + public void createVnf (String cloudSiteId, + String tenantId, + String vnfType, + String vnfVersion, + String vnfName, + String requestType, + String volumeGroupHeatStackId, + Map inputs, + Boolean failIfExists, + Boolean backout, + MsoRequest msoRequest, + Holder vnfId, + Holder > outputs, + Holder rollback) + throws VnfException + { + // This operation is no longer supported at the VNF level. The adapter is only called to deploy modules. + LOGGER.debug ("CreateVNF command attempted but not supported"); + throw new VnfException ("CreateVNF: Unsupported command", MsoExceptionCategory.USERDATA); + } + + /** + * This is the "Update VNF" web service implementation. + * This function is now unsupported and will return an error. + * + */ + @Override + public void updateVnf (String cloudSiteId, + String tenantId, + String vnfType, + String vnfVersion, + String vnfName, + String requestType, + String volumeGroupHeatStackId, + Map inputs, + MsoRequest msoRequest, + Holder > outputs, + Holder rollback) + throws VnfException + { + // This operation is no longer supported at the VNF level. The adapter is only called to deploy modules. + LOGGER.debug ("UpdateVNF command attempted but not supported"); + throw new VnfException ("UpdateVNF: Unsupported command", MsoExceptionCategory.USERDATA); + } + + /** + * This is the "Query VNF" web service implementation. + * + * This really should be QueryVfModule, but nobody ever changed it. + * + * The method returns an indicator that the VNF exists, along with its status and outputs. + * The input "vnfName" will also be reflected back as its ID. + * + * @param cloudSiteId CLLI code of the cloud site in which to query + * @param tenantId Openstack tenant identifier + * @param vnfNameOrId VNF Name or ID to query + * @param msoRequest Request tracking information for logs + * @param vnfExists Flag reporting the result of the query + * @param vnfId Holder for output VNF ID + * @param outputs Holder for Map of outputs from the deployed VF Module (assigned IPs, etc) + */ + @Override + public void queryVnf (String cloudSiteId, + String tenantId, + String vnfNameOrId, + MsoRequest msoRequest, + Holder vnfExists, + Holder vnfId, + Holder status, + Holder > outputs) + throws VnfException + { + MsoLogger.setLogContext (msoRequest); + MsoLogger.setServiceName ("QueryVnf"); + LOGGER.debug ("Querying VNF " + vnfNameOrId + " in " + cloudSiteId + "/" + tenantId); + + // Will capture execution time for metrics + long startTime = System.currentTimeMillis (); + long subStartTime = System.currentTimeMillis (); + + VduInstance vduInstance = null; + CloudInfo cloudInfo = new CloudInfo(cloudSiteId, tenantId, null); + + VduPlugin vduPlugin = getVduPlugin(cloudSiteId); + + try { + vduInstance = vduPlugin.queryVdu(cloudInfo, vnfNameOrId); + LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received VDU Query response", "VDU", "QueryVDU", vnfNameOrId); + } + catch (VduException e) { + // Failed to query the VDU due to a plugin exception. + e.addContext ("QueryVNF"); + String error = "Query VNF (VDU): " + vnfNameOrId + " in " + cloudSiteId + "/" + tenantId + ": " + e; + LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "VDU", "QueryVNF", vnfNameOrId); + LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vnfNameOrId, cloudSiteId, tenantId, "VDU", "QueryVNF", MsoLogger.ErrorCode.DataError, "Exception - queryVDU", e); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error); + throw new VnfException (e); + } + + if (vduInstance != null && vduInstance.getStatus().getState() != VduStateType.NOTFOUND) { + vnfExists.value = Boolean.TRUE; + status.value = vduStatusToVnfStatus(vduInstance); + vnfId.value = vduInstance.getVduInstanceId(); + outputs.value = copyStringOutputs (vduInstance.getOutputs ()); + + LOGGER.debug ("VNF " + vnfNameOrId + " found, ID = " + vnfId.value); + } + else { + vnfExists.value = Boolean.FALSE; + status.value = VnfStatus.NOTFOUND; + vnfId.value = null; + outputs.value = new HashMap (); // Return as an empty map + + LOGGER.debug ("VNF " + vnfNameOrId + " not found"); + } + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully query VNF"); + return; + } + + + /** + * This is the "Delete VNF" web service implementation. + * This function is now unsupported and will return an error. + * + */ + @Override + public void deleteVnf (String cloudSiteId, + String tenantId, + String vnfName, + MsoRequest msoRequest) throws VnfException { + MsoLogger.setLogContext (msoRequest); + MsoLogger.setServiceName ("DeleteVnf"); + + // This operation is no longer supported at the VNF level. The adapter is only called to deploy modules. + LOGGER.debug ("DeleteVNF command attempted but not supported"); + throw new VnfException ("DeleteVNF: Unsupported command", MsoExceptionCategory.USERDATA); + } + + /** + * This web service endpoint will rollback a previous Create VNF operation. + * A rollback object is returned to the client in a successful creation + * response. The client can pass that object as-is back to the rollbackVnf + * operation to undo the creation. + * + * TODO: This should be rollbackVfModule and/or rollbackVolumeGroup, + * but APIs were apparently never updated. + */ + @Override + public void rollbackVnf (VnfRollback rollback) throws VnfException { + long startTime = System.currentTimeMillis (); + MsoLogger.setServiceName ("RollbackVnf"); + // rollback may be null (e.g. if stack already existed when Create was called) + if (rollback == null) { + LOGGER.info (MessageEnum.RA_ROLLBACK_NULL, "OpenStack", "rollbackVnf"); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.BadRequest, "Rollback request content is null"); + return; + } + + // Don't rollback if nothing was done originally + if (!rollback.getVnfCreated()) { + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Rollback VF Module - nothing to roll back"); + return; + } + + // Get the elements of the VnfRollback object for easier access + String cloudSiteId = rollback.getCloudSiteId (); + String tenantId = rollback.getTenantId (); + CloudInfo cloudInfo = new CloudInfo (cloudSiteId, tenantId, null); + + String vfModuleId = rollback.getVfModuleStackId (); + + MsoLogger.setLogContext (rollback.getMsoRequest()); + + LOGGER.debug ("Rolling Back VF Module " + vfModuleId + " in " + cloudSiteId + "/" + tenantId); + + VduInstance vduInstance = null; + + // Use the VduPlugin to delete the VF Module. + VduPlugin vduPlugin = getVduPlugin(cloudSiteId); + + long subStartTime = System.currentTimeMillis (); + try { + // TODO: Get a reasonable timeout. Use a global property, or store the creation timeout in rollback object and use that. + vduInstance = vduPlugin.deleteVdu(cloudInfo, vfModuleId, 5); + + LOGGER.debug("Rolled back VDU instantiation: " + vduInstance.getVduInstanceId()); + LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from VDU Plugin", "VDU", "DeleteVdu", null); + } + catch (VduException ve) { + // Failed to rollback the VF Module due to a plugin exception. + // Convert to a generic VnfException + ve.addContext ("RollbackVFModule"); + String error = "Rollback VF Module: " + vfModuleId + " in " + cloudSiteId + "/" + tenantId + ": " + ve; + LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "VDU", "DeleteVdu", null); + LOGGER.error (MessageEnum.RA_DELETE_VNF_ERR, vfModuleId, cloudSiteId, tenantId, "VDU", "DeleteVdu", MsoLogger.ErrorCode.DataError, "Exception - DeleteVdu", ve); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error); + throw new VnfException (ve); + } + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully roll back VF Module"); + return; + } + + + private VnfStatus vduStatusToVnfStatus (VduInstance vdu) { + // Determine the status based on last action & status + // DeploymentInfo object should be enhanced to report a better status internally. + VduStatus vduStatus = vdu.getStatus(); + VduStateType status = vduStatus.getState(); + + if (status == null) { + return VnfStatus.UNKNOWN; + } + else if (status == VduStateType.NOTFOUND) { + return VnfStatus.NOTFOUND; + } + else if (status == VduStateType.INSTANTIATED) { + return VnfStatus.ACTIVE; + } + else if (status == VduStateType.FAILED) { + return VnfStatus.FAILED; + } + + return VnfStatus.UNKNOWN; + } + + /* + * Normalize an input value to an Object, based on the target parameter type. + * If the type is not recognized, it will just be returned unchanged (as a string). + */ + private Object convertInputValue (String inputValue, HeatTemplateParam templateParam) + { + String type = templateParam.getParamType(); + LOGGER.debug("Parameter: " + templateParam.getParamName() + " is of type " + type); + + if (type.equalsIgnoreCase("number")) { + try { + return Integer.valueOf(inputValue); + } + catch (Exception e) { + LOGGER.debug("Unable to convert " + inputValue + " to an integer!"); + return null; + } + } else if (type.equalsIgnoreCase("json")) { + try { + JsonNode jsonNode = new ObjectMapper().readTree(inputValue); + return jsonNode; + } + catch (Exception e) { + LOGGER.debug("Unable to convert " + inputValue + " to a JsonNode!"); + return null; + } + } else if (type.equalsIgnoreCase("boolean")) { + return new Boolean(inputValue); + } + + // Nothing else matched. Return the original string + return inputValue; + } + + private Map copyStringOutputs (Map stackOutputs) { + Map stringOutputs = new HashMap <> (); + for (String key : stackOutputs.keySet ()) { + if (stackOutputs.get (key) instanceof String) { + stringOutputs.put (key, (String) stackOutputs.get (key)); + } else if (stackOutputs.get(key) instanceof Integer) { + try { + String str = "" + stackOutputs.get(key); + stringOutputs.put(key, str); + } catch (Exception e) { + LOGGER.debug("Unable to add " + key + " to outputs"); + } + } else if (stackOutputs.get(key) instanceof JsonNode) { + try { + String str = this.convertNode((JsonNode) stackOutputs.get(key)); + stringOutputs.put(key, str); + } catch (Exception e) { + LOGGER.debug("Unable to add " + key + " to outputs - exception converting JsonNode"); + } + } else if (stackOutputs.get(key) instanceof java.util.LinkedHashMap) { + try { + String str = JSON_MAPPER.writeValueAsString(stackOutputs.get(key)); + stringOutputs.put(key, str); + } catch (Exception e) { + LOGGER.debug("Unable to add " + key + " to outputs - exception converting LinkedHashMap"); + } + } else { + try { + String str = stackOutputs.get(key).toString(); + stringOutputs.put(key, str); + } catch (Exception e) { + LOGGER.debug("Unable to add " + key + " to outputs - unable to call .toString() " + e.getMessage()); + } + } + } + return stringOutputs; + } + + + private void sendMapToDebug(Map inputs, String optionalName) { + int i = 0; + StringBuilder sb = new StringBuilder(optionalName == null ? "\ninputs" : "\n" + optionalName); + if (inputs == null) { + sb.append("\tNULL"); + } + else if (inputs.size() < 1) { + sb.append("\tEMPTY"); + } else { + for (String str : inputs.keySet()) { + String outputString; + try { + outputString = inputs.get(str).toString(); + } catch (Exception e) { + outputString = "Unable to call toString() on the value for " + str; + } + sb.append("\t\nitem " + i++ + ": '" + str + "'='" + outputString + "'"); + } + } + LOGGER.debug(sb.toString()); + return; + } + + private void sendMapToDebug(Map inputs) { + int i = 0; + StringBuilder sb = new StringBuilder("inputs:"); + if (inputs == null) { + sb.append("\tNULL"); + } + else if (inputs.size() < 1) { + sb.append("\tEMPTY"); + } else { + for (String str : inputs.keySet()) { + sb.append("\titem " + i++ + ": " + str + "=" + inputs.get(str)); + } + } + LOGGER.debug(sb.toString()); + return; + } + + private String convertNode(final JsonNode node) { + try { + final Object obj = JSON_MAPPER.treeToValue(node, Object.class); + final String json = JSON_MAPPER.writeValueAsString(obj); + return json; + } catch (JsonParseException jpe) { + LOGGER.debug("Error converting json to string " + jpe.getMessage()); + } catch (Exception e) { + LOGGER.debug("Error converting json to string " + e.getMessage()); + } + return "[Error converting json to string]"; + } + + private Map convertMapStringObjectToStringString(Map objectMap) { + if (objectMap == null) { + return null; + } + Map stringMap = new HashMap<>(); + for (String key : objectMap.keySet()) { + if (!stringMap.containsKey(key)) { + Object obj = objectMap.get(key); + if (obj instanceof String) { + stringMap.put(key, (String) objectMap.get(key)); + } else if (obj instanceof JsonNode ){ + // This is a bit of mess - but I think it's the least impacting + // let's convert it BACK to a string - then it will get converted back later + try { + String str = this.convertNode((JsonNode) obj); + stringMap.put(key, str); + } catch (Exception e) { + LOGGER.debug("DANGER WILL ROBINSON: unable to convert value for JsonNode "+ key); + //okay in this instance - only string values (fqdn) are expected to be needed + } + } else if (obj instanceof java.util.LinkedHashMap) { + LOGGER.debug("LinkedHashMap - this is showing up as a LinkedHashMap instead of JsonNode"); + try { + String str = JSON_MAPPER.writeValueAsString(obj); + stringMap.put(key, str); + } catch (Exception e) { + LOGGER.debug("DANGER WILL ROBINSON: unable to convert value for LinkedHashMap "+ key); + } + } else if (obj instanceof Integer) { + try { + String str = "" + obj; + stringMap.put(key, str); + } catch (Exception e) { + LOGGER.debug("DANGER WILL ROBINSON: unable to convert value for Integer "+ key); + } + } else { + try { + String str = obj.toString(); + stringMap.put(key, str); + } catch (Exception e) { + LOGGER.debug("DANGER WILL ROBINSON: unable to convert value "+ key + " (" + e.getMessage() + ")"); + } + } + } + } + + return stringMap; + } + + /** + * This is the "Create VF Module" web service implementation. + * It will instantiate a new VF Module of the requested type in the specified cloud + * and tenant. The tenant must exist before this service is called. + * + * If a VF Module with the same name already exists, this can be considered a + * success or failure, depending on the value of the 'failIfExists' parameter. + * + * All VF Modules are defined in the MSO catalog. The caller must request one of + * the pre-defined module types or an error will be returned. Within the catalog, + * each VF Module references (among other things) a collection of artifacts that + * are used to deploy the required cloud resources (VMs, networks, etc.). + * + * Depending on the module templates, a variable set of input parameters will + * be defined, some of which are required. The caller is responsible to + * pass the necessary input data for the module or an error will be thrown. + * + * The method returns the vfModuleId, a Map of output attributes, and a VnfRollback + * object. This last object can be passed as-is to the rollbackVnf operation to + * undo everything that was created for the Module. This is useful if a VF module + * is successfully created but the orchestration fails on a subsequent step. + * + * @param cloudSiteId CLLI code of the cloud site in which to create the VNF + * @param tenantId Openstack tenant identifier + * @param vfModuleType VF Module type key, should match a VNF definition in catalog DB. + * Deprecated - should use modelCustomizationUuid + * @param vnfVersion VNF version key, should match a VNF definition in catalog DB + * Deprecated - VF Module versions also captured by modelCustomizationUuid + * @param vfModuleName Name to be assigned to the new VF Module + * @param requestType Indicates if this is a Volume Group or Module request + * @param volumeGroupId Identifier (i.e. deployment ID) for a Volume Group + * to attach to a VF Module + * @param baseVfModuleId Identifier (i.e. deployment ID) of the Base Module if + * this is an Add-on module + * @param modelCustomizationUuid Unique ID for the VF Module's model. Replaces + * the use of vfModuleType. + * @param inputs Map of key=value inputs for VNF stack creation + * @param failIfExists Flag whether already existing VNF should be considered + * @param backout Flag whether to suppress automatic backout (for testing) + * @param msoRequest Request tracking information for logs + * @param vnfId Holder for output VF Module instance ID in the cloud + * @param outputs Holder for Map of VNF outputs from Deployment (assigned IPs, etc) + * @param rollback Holder for returning VnfRollback object + */ + public void createVfModule(String cloudSiteId, + String tenantId, + String vfModuleType, + String vnfVersion, + String vfModuleName, + String requestType, + String volumeGroupId, + String baseVfModuleId, + String modelCustomizationUuid, + Map inputs, + Boolean failIfExists, + Boolean backout, + MsoRequest msoRequest, + Holder vnfId, + Holder > outputs, + Holder rollback) + throws VnfException + { + // Will capture execution time for metrics + long startTime = System.currentTimeMillis (); + + MsoLogger.setLogContext (msoRequest); + MsoLogger.setServiceName ("CreateVfModule"); + + // Require a model customization ID. Every VF Module definition must have one. + if (modelCustomizationUuid == null || modelCustomizationUuid.isEmpty()) { + LOGGER.debug("Missing required input: modelCustomizationUuid"); + String error = "Create vfModule error: Missing required input: modelCustomizationUuid"; + LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM, + "VF Module ModelCustomizationUuid", "null", "VDU", "", MsoLogger.ErrorCode.DataError, "Create VF Module: Missing required input: modelCustomizationUuid"); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error); + throw new VnfException(error, MsoExceptionCategory.USERDATA); + } + + // Clean up some inputs to make comparisons easier + if (requestType == null) + requestType = ""; + + if ("".equals(volumeGroupId) || "null".equals(volumeGroupId)) + volumeGroupId = null; + + if ("".equals(baseVfModuleId) || "null".equals(baseVfModuleId)) + baseVfModuleId = null; + + if (inputs == null) { + // Create an empty set of inputs + inputs = new HashMap(); + LOGGER.debug("inputs == null - setting to empty"); + } else { + this.sendMapToDebug(inputs); + } + + // Check if this is for a "Volume" module + boolean isVolumeRequest = false; + if (requestType.startsWith("VOLUME")) { + isVolumeRequest = true; + } + + LOGGER.debug("requestType = " + requestType + ", volumeGroupStackId = " + volumeGroupId + ", baseStackId = " + baseVfModuleId); + + // Build a default rollback object (no actions performed) + VnfRollback vfRollback = new VnfRollback(); + vfRollback.setCloudSiteId(cloudSiteId); + vfRollback.setTenantId(tenantId); + vfRollback.setMsoRequest(msoRequest); + vfRollback.setRequestType(requestType); + vfRollback.setIsBase(false); // Until we know better + vfRollback.setVolumeGroupHeatStackId(volumeGroupId); + vfRollback.setBaseGroupHeatStackId(baseVfModuleId); + vfRollback.setModelCustomizationUuid(modelCustomizationUuid); + vfRollback.setMode("CFY"); + + rollback.value = vfRollback; // Default rollback - no updates performed + + // Get the VNF/VF Module definition from the Catalog DB first. + // There are three relevant records: VfModule, VfModuleCustomization, VnfResource + + CatalogDatabase db = CatalogDatabase.getInstance(); + VfModule vfModule = null; + VnfResource vnfResource = null; + VfModuleCustomization vfModuleCust = null; + + try { + vfModuleCust = db.getVfModuleCustomizationByModelCustomizationId(modelCustomizationUuid); + + if (vfModuleCust == null) { + String error = "Create vfModule error: Unable to find vfModuleCust with modelCustomizationUuid=" + modelCustomizationUuid; + LOGGER.debug(error); + LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM, + "VF Module ModelCustomizationUuid", modelCustomizationUuid, "CatalogDb", "", MsoLogger.ErrorCode.DataError, error); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error); + throw new VnfException(error, MsoExceptionCategory.USERDATA); + } else { + LOGGER.debug("Found vfModuleCust entry " + vfModuleCust.toString()); + } + + // Get the vfModule and vnfResource records + vfModule = vfModuleCust.getVfModule(); + vnfResource = db.getVnfResourceByModelUuid(vfModule.getVnfResourceModelUUId()); + } + catch (Exception e) { + db.close (); + LOGGER.debug("unhandled exception in create VF - [Query]" + e.getMessage()); + throw new VnfException("Exception during create VF " + e.getMessage()); + } + + // Perform a version check against cloudSite + // Obtain the cloud site information where we will create the VF Module + Optional cloudSite = cloudConfig.getCloudSite (cloudSiteId); + if (!cloudSite.isPresent()) { + throw new VnfException (new MsoCloudSiteNotFound (cloudSiteId)); + } + MavenLikeVersioning aicV = new MavenLikeVersioning(); + aicV.setVersion(cloudSite.get().getAic_version()); + + String vnfMin = vnfResource.getAicVersionMin(); + String vnfMax = vnfResource.getAicVersionMax(); + + if ( (vnfMin != null && !(aicV.isMoreRecentThan(vnfMin) || aicV.isTheSameVersion(vnfMin))) || + (vnfMax != null && aicV.isMoreRecentThan(vnfMax))) + { + // ERROR + String error = "VNF Resource type: " + vnfResource.getModelName() + ", ModelUuid=" + vnfResource.getModelUuid() + " VersionMin=" + vnfMin + " VersionMax:" + vnfMax + " NOT supported on Cloud: " + cloudSite.get().getId() + " with AIC_Version:" + cloudSite.get().getAic_version(); + LOGGER.error(MessageEnum.RA_CONFIG_EXC, error, "OpenStack", "", MsoLogger.ErrorCode.BusinessProcesssError, "Exception - setVersion"); + LOGGER.debug(error); + throw new VnfException(error, MsoExceptionCategory.USERDATA); + } + // End Version check + + + VduInstance vduInstance = null; + CloudInfo cloudInfo = new CloudInfo (cloudSiteId, tenantId, null); + + // Use the VduPlugin. + VduPlugin vduPlugin = getVduPlugin(cloudSiteId); + + // First, look up to see if the VF already exists. + + long subStartTime1 = System.currentTimeMillis (); + try { + vduInstance = vduPlugin.queryVdu (cloudInfo, vfModuleName); + LOGGER.recordMetricEvent (subStartTime1, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from VduPlugin", "VDU", "QueryVDU", vfModuleName); + } + catch (VduException me) { + // Failed to query the VDU due to a plugin exception. + String error = "Create VF Module: Query " + vfModuleName + " in " + cloudSiteId + "/" + tenantId + ": " + me ; + LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vfModuleName, cloudSiteId, tenantId, "VDU", "queryVdu", MsoLogger.ErrorCode.DataError, "Exception - queryVdu", me); + LOGGER.recordMetricEvent (subStartTime1, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "VDU", "QueryVdu", vfModuleName); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error); + + // Convert to a generic VnfException + me.addContext ("CreateVFModule"); + throw new VnfException (me); + } + + // More precise handling/messaging if the Module already exists + if (vduInstance != null && !(vduInstance.getStatus().getState() == VduStateType.NOTFOUND)) { + VduStateType status = vduInstance.getStatus().getState(); + LOGGER.debug ("Found Existing VDU, status=" + status); + + if (status == VduStateType.INSTANTIATED) { + if (failIfExists != null && failIfExists) { + // fail - it exists + String error = "Create VF: Deployment " + vfModuleName + " already exists in " + cloudSiteId + "/" + tenantId; + LOGGER.error (MessageEnum.RA_VNF_ALREADY_EXIST, vfModuleName, cloudSiteId, tenantId, "VDU", "queryVdu", MsoLogger.ErrorCode.DataError, "VF Module " + vfModuleName + " already exists"); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error); + throw new VnfAlreadyExists (vfModuleName, cloudSiteId, tenantId, vduInstance.getVduInstanceId()); + } else { + // Found existing deployment and client has not requested "failIfExists". + // Populate the outputs from the existing deployment. + + vnfId.value = vduInstance.getVduInstanceId(); + outputs.value = copyStringOutputs (vduInstance.getOutputs ()); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully create VF Module (found existing)"); + return; + } + } + // Check through various detailed error cases + else if (status == VduStateType.INSTANTIATING || status == VduStateType.DELETING || status == VduStateType.UPDATING) { + // fail - it's in progress - return meaningful error + String error = "Create VF: Deployment " + vfModuleName + " already exists and has status " + status.toString() + " in " + cloudSiteId + "/" + tenantId + "; please wait for it to complete, or fix manually."; + LOGGER.error (MessageEnum.RA_VNF_ALREADY_EXIST, vfModuleName, cloudSiteId, tenantId, "VDU", "queryVdu", MsoLogger.ErrorCode.DataError, "VF Module " + vfModuleName + " already exists"); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error); + throw new VnfAlreadyExists (vfModuleName, cloudSiteId, tenantId, vduInstance.getVduInstanceId()); + } + else if (status == VduStateType.FAILED) { + // fail - it exists and is in a FAILED state + String error = "Create VF: Deployment " + vfModuleName + " already exists and is in FAILED state in " + cloudSiteId + "/" + tenantId + "; requires manual intervention."; + LOGGER.error (MessageEnum.RA_VNF_ALREADY_EXIST, vfModuleName, cloudSiteId, tenantId, "VDU", "queryVdu", MsoLogger.ErrorCode.DataError, "VF Module " + vfModuleName + " already exists and is in FAILED state"); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error); + throw new VnfAlreadyExists (vfModuleName, cloudSiteId, tenantId, vduInstance.getVduInstanceId()); + } + else if (status == VduStateType.UNKNOWN) { + // fail - it exists and is in a UNKNOWN state + String error = "Create VF: Deployment " + vfModuleName + " already exists and has status " + status.toString() + " in " + cloudSiteId + "/" + tenantId + "; requires manual intervention."; + LOGGER.error (MessageEnum.RA_VNF_ALREADY_EXIST, vfModuleName, cloudSiteId, tenantId, "VDU", "queryVdu", MsoLogger.ErrorCode.DataError, "VF Module " + vfModuleName + " already exists and is in " + status.toString() + " state"); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error); + throw new VnfAlreadyExists (vfModuleName, cloudSiteId, tenantId, vduInstance.getVduInstanceId()); + } + else { + // Unexpected, since all known status values have been tested for + String error = "Create VF: Deployment " + vfModuleName + " already exists with unexpected status " + status.toString() + " in " + cloudSiteId + "/" + tenantId + "; requires manual intervention."; + LOGGER.error (MessageEnum.RA_VNF_ALREADY_EXIST, vfModuleName, cloudSiteId, tenantId, "VDU", "queryVdu", MsoLogger.ErrorCode.DataError, "VF Module " + vfModuleName + " already exists and is in an unknown state"); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error); + throw new VnfAlreadyExists (vfModuleName, cloudSiteId, tenantId, vduInstance.getVduInstanceId()); + } + } + + + // Collect outputs from Base Modules and Volume Modules + Map baseModuleOutputs = null; + Map volumeGroupOutputs = null; + + // If a Volume Group was provided, query its outputs for inclusion in Module input parameters + if (volumeGroupId != null) { + long subStartTime2 = System.currentTimeMillis (); + VduInstance volumeVdu = null; + try { + volumeVdu = vduPlugin.queryVdu (cloudInfo, volumeGroupId); + LOGGER.recordMetricEvent (subStartTime2, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Success response from VduPlugin", "VDU", "QueryVdu", volumeGroupId); + } + catch (VduException me) { + // Failed to query the Volume Group VDU due to a plugin exception. + String error = "Create VF Module: Query Volume Group " + volumeGroupId + " in " + cloudSiteId + "/" + tenantId + ": " + me ; + LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, volumeGroupId, cloudSiteId, tenantId, "VDU", "queryVdu(volume)", MsoLogger.ErrorCode.DataError, "Exception - queryVdu(volume)", me); + LOGGER.recordMetricEvent (subStartTime2, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "VDU", "QueryVdu(volume)", volumeGroupId); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error); + + // Convert to a generic VnfException + me.addContext ("CreateVFModule(QueryVolume)"); + throw new VnfException (me); + } + + if (volumeVdu == null || volumeVdu.getStatus().getState() == VduStateType.NOTFOUND) { + String error = "Create VFModule: Attached Volume Group DOES NOT EXIST " + volumeGroupId + " in " + cloudSiteId + "/" + tenantId + " USER ERROR" ; + LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, volumeGroupId, cloudSiteId, tenantId, error, "VDU", "queryVdu(volume)", MsoLogger.ErrorCode.BusinessProcesssError, "Create VFModule: Attached Volume Group DOES NOT EXIST"); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error); + LOGGER.debug(error); + throw new VnfException (error, MsoExceptionCategory.USERDATA); + } else { + LOGGER.debug("Found nested volume group"); + volumeGroupOutputs = volumeVdu.getOutputs(); + this.sendMapToDebug(volumeGroupOutputs, "volumeGroupOutputs"); + } + } + + // If this is an Add-On Module, query the Base Module outputs + // Note: This will be performed whether or not the current request is for an + // Add-On Volume Group or Add-On VF Module + + if (vfModule.isBase()) { + LOGGER.debug("This is a BASE Module request"); + vfRollback.setIsBase(true); + } else { + LOGGER.debug("This is an Add-On Module request"); + + // Add-On Modules should always have a Base, but just treat as a warning if not provided. + // Add-on Volume requests may or may not specify a base. + if (!isVolumeRequest && baseVfModuleId == null) { + LOGGER.debug ("WARNING: Add-on Module request - no Base Module ID provided"); + } + + if (baseVfModuleId != null) { + long subStartTime2 = System.currentTimeMillis (); + VduInstance baseVdu = null; + try { + baseVdu = vduPlugin.queryVdu (cloudInfo, baseVfModuleId); + LOGGER.recordMetricEvent (subStartTime2, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Success response from VduPlugin", "VDU", "QueryVdu(Base)", baseVfModuleId); + } + catch (MsoException me) { + // Failed to query the Base VF Module due to a Vdu Plugin exception. + String error = "Create VF Module: Query Base " + baseVfModuleId + " in " + cloudSiteId + "/" + tenantId + ": " + me ; + LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, baseVfModuleId, cloudSiteId, tenantId, "VDU", "queryVdu(Base)", MsoLogger.ErrorCode.DataError, "Exception - queryVdu(Base)", me); + LOGGER.recordMetricEvent (subStartTime2, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "VDU", "QueryVdu(Base)", baseVfModuleId); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error); + + // Convert to a generic VnfException + me.addContext ("CreateVFModule(QueryBase)"); + throw new VnfException (me); + } + + if (baseVdu == null || baseVdu.getStatus().getState() == VduStateType.NOTFOUND) { + String error = "Create VFModule: Base Module DOES NOT EXIST " + baseVfModuleId + " in " + cloudSiteId + "/" + tenantId + " USER ERROR" ; + LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, baseVfModuleId, cloudSiteId, tenantId, error, "VDU", "queryVdu(Base)", MsoLogger.ErrorCode.BusinessProcesssError, "Create VFModule: Base Module DOES NOT EXIST"); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error); + LOGGER.debug(error); + throw new VnfException (error, MsoExceptionCategory.USERDATA); + } else { + LOGGER.debug("Found base module"); + baseModuleOutputs = baseVdu.getOutputs(); + this.sendMapToDebug(baseModuleOutputs, "baseModuleOutputs"); + } + } + } + + // NOTE: For this section, heatTemplate is used for all template artifacts. + // In final implementation (post-POC), the template object would either be generic or there would + // be a separate DB Table/Object for different sub-orchestrators. + + // NOTE: The template is fixed for the VF Module. The environment is part of the customization. + + // NOTE: The template is fixed for the VF Module. The environment is part of the customization. + String heatTemplateArtifactUuid = null; + String heatEnvironmentArtifactUuid = null; + + if (isVolumeRequest) { + heatTemplateArtifactUuid = vfModule.getVolHeatTemplateArtifactUUId(); + heatEnvironmentArtifactUuid = vfModuleCust.getVolEnvironmentArtifactUuid(); + } else { + heatTemplateArtifactUuid = vfModule.getHeatTemplateArtifactUUId(); + heatEnvironmentArtifactUuid = vfModuleCust.getHeatEnvironmentArtifactUuid(); + } + + if (heatTemplateArtifactUuid == null || heatTemplateArtifactUuid.equals("")) { + String error = "Create: No Heat Template ID defined in catalog database for " + vfModuleType + ", reqType=" + requestType; + LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM, "Heat Template ID", vfModuleType, "Cloudify", "", MsoLogger.ErrorCode.DataError, "Create: No Heat Template ID defined in catalog database"); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error); + alarmLogger.sendAlarm(MSO_CONFIGURATION_ERROR, MsoAlarmLogger.CRITICAL, error); + throw new VnfException(error, MsoExceptionCategory.INTERNAL); + } + + HeatTemplate heatTemplate = db.getHeatTemplateByArtifactUuidRegularQuery(heatTemplateArtifactUuid); + + if (heatTemplate == null) { + String error = "Create VF/VNF: no entry found for heat template ID = " + heatTemplateArtifactUuid; + LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM, + "Heat Template ID", + String.valueOf(heatTemplateArtifactUuid), "Cloudify", "", MsoLogger.ErrorCode.BusinessProcesssError, "Create VF/VNF: no entry found for heat template ID = " + heatTemplateArtifactUuid); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error); + alarmLogger.sendAlarm(MSO_CONFIGURATION_ERROR, MsoAlarmLogger.CRITICAL, error); + throw new VnfException(error, MsoExceptionCategory.INTERNAL); + } + LOGGER.debug("Got HEAT Template record from DB"); + + // Next get the Environment record. This is optional. + HeatEnvironment heatEnvironment = null; + if (heatEnvironmentArtifactUuid != null && !heatEnvironmentArtifactUuid.equals("")) + { + heatEnvironment = db.getHeatEnvironmentByArtifactUuid(heatEnvironmentArtifactUuid); + if (heatEnvironment == null) { + String error = "Create VFModule: undefined Heat Environment. VFModule=" + vfModuleType + + ", Environment ID=" + + heatEnvironmentArtifactUuid; + LOGGER.error (MessageEnum.RA_VNF_UNKNOWN_PARAM, "Heat Environment ID", String.valueOf(heatEnvironmentArtifactUuid), "Cloudify", "getEnvironment", MsoLogger.ErrorCode.BusinessProcesssError, "Create VFModule: undefined Heat Environment"); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error); + // Alarm on this error, configuration must be fixed + alarmLogger.sendAlarm (MSO_CONFIGURATION_ERROR, MsoAlarmLogger.CRITICAL, error); + + throw new VnfException (error, MsoExceptionCategory.INTERNAL); + } + LOGGER.debug ("Got Heat Environment from DB"); + } else { + LOGGER.debug ("no environment parameter found for this Type " + vfModuleType); + } + + + // Create the combined set of parameters from the incoming request, base-module outputs, + // volume-module outputs. Also, convert all variables to their native object types. + + HashMap goldenInputs = new HashMap<>(); + List extraInputs = new ArrayList<>(); + + Boolean skipInputChecks = false; + + if (skipInputChecks) { + goldenInputs = new HashMap(); + for (String key : inputs.keySet()) { + goldenInputs.put(key, inputs.get(key)); + } + } + else { + // Build maps for the parameters (including aliases) to simplify checks + HashMap params = new HashMap<>(); + + Set paramSet = heatTemplate.getParameters(); + LOGGER.debug("paramSet has " + paramSet.size() + " entries"); + + for (HeatTemplateParam htp : paramSet) { + params.put(htp.getParamName(), htp); + + // Include aliases. + String alias = htp.getParamAlias(); + if (alias != null && !alias.equals("") && !params.containsKey(alias)) { + params.put(alias, htp); + } + } + + // First, convert all inputs to their "template" type + for (String key : inputs.keySet()) { + if (params.containsKey(key)) { + Object value = convertInputValue(inputs.get(key), params.get(key)); + if (value != null) { + goldenInputs.put(key, value); + } + else { + LOGGER.debug("Failed to convert input " + key + "='" + inputs.get(key) + "' to " + params.get(key).getParamType()); + } + } else { + extraInputs.add(key); + } + } + + if (!extraInputs.isEmpty()) { + LOGGER.debug("Ignoring extra inputs: " + extraInputs); + } + + // Next add in Volume Group Outputs if there are any. Copy directly without conversions. + if (volumeGroupOutputs != null && !volumeGroupOutputs.isEmpty()) { + for (String key : volumeGroupOutputs.keySet()) { + if (params.containsKey(key) && !goldenInputs.containsKey(key)) { + goldenInputs.put(key, volumeGroupOutputs.get(key)); + } + } + } + + // Next add in Base Module Outputs if there are any. Copy directly without conversions. + if (baseModuleOutputs != null && !baseModuleOutputs.isEmpty()) { + for (String key : baseModuleOutputs.keySet()) { + if (params.containsKey(key) && !goldenInputs.containsKey(key)) { + goldenInputs.put(key, baseModuleOutputs.get(key)); + } + } + } + + // TODO: The model should support a mechanism to pre-assign default parameter values + // per "customization" (i.e. usage) of a given module. In HEAT, this is specified by + // an Environment file. There is not a general mechanism in the model to handle this. + // For the general case, any such parameter/values can be added dynamically to the + // inputs (only if not already specified). + + + // Check that required parameters have been supplied from any of the sources + String missingParams = null; + boolean checkRequiredParameters = true; + try { + String propertyString = this.msoPropertiesFactory.getMsoJavaProperties(MSO_PROP_VNF_ADAPTER) + .getProperty(MsoVnfPluginAdapterImpl.CHECK_REQD_PARAMS,null); + if ("false".equalsIgnoreCase (propertyString) || "n".equalsIgnoreCase (propertyString)) { + checkRequiredParameters = false; + LOGGER.debug ("CheckRequiredParameters is FALSE. Will still check but then skip blocking..." + + MsoVnfPluginAdapterImpl.CHECK_REQD_PARAMS); + } + } catch (Exception e) { + // No problem - default is true + LOGGER.debug ("An exception occured trying to get property " + MsoVnfPluginAdapterImpl.CHECK_REQD_PARAMS, e); + } + + // Do the actual parameter checking. + // Include looking at the ENV file as a valid definition of a parameter value. + // TODO: This handling of ENV applies only to Heat. A general mechanism to + // support pre-set parameter/values does not yet exist in the model. + // + StringBuilder sb = new StringBuilder(heatEnvironment.getEnvironment()); + MsoHeatEnvironmentEntry mhee = new MsoHeatEnvironmentEntry (sb); + for (HeatTemplateParam parm : heatTemplate.getParameters ()) { + if (parm.isRequired () && (!goldenInputs.containsKey (parm.getParamName ()))) { + if (mhee != null && mhee.containsParameter(parm.getParamName())) { + LOGGER.debug ("Required parameter " + parm.getParamName () + + " appears to be in environment - do not count as missing"); + } else { + LOGGER.debug ("adding to missing parameters list: " + parm.getParamName ()); + if (missingParams == null) { + missingParams = parm.getParamName (); + } else { + missingParams += "," + parm.getParamName (); + } + } + } + } + + if (missingParams != null) { + if (checkRequiredParameters) { + // Problem - missing one or more required parameters + String error = "Create VFModule: Missing Required inputs: " + missingParams; + LOGGER.error (MessageEnum.RA_MISSING_PARAM, missingParams, "VDU", "", MsoLogger.ErrorCode.DataError, "Create VFModule: Missing Required inputs"); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.BadRequest, error); + throw new VnfException (error, MsoExceptionCategory.USERDATA); + } else { + LOGGER.debug ("found missing parameters [" + missingParams + "] - but checkRequiredParameters is false - will not block"); + } + } else { + LOGGER.debug ("No missing parameters found - ok to proceed"); + } + + } // NOTE: END PARAMETER CHECKING + + // Here we go... ready to deploy the VF Module. + long instantiateVduStartTime = System.currentTimeMillis (); + if (backout == null) backout = true; + + try { + // Construct the VDU Model structure to pass to the targeted VduPlugin + VduModelInfo vduModel = null; + if (! isVolumeRequest) { + vduModel = vduMapper.mapVfModuleCustomizationToVdu(vfModuleCust); + } else { + vduModel = vduMapper.mapVfModuleCustVolumeToVdu(vfModuleCust); + } + + // Invoke the VduPlugin to instantiate the VF Module + vduInstance = vduPlugin.instantiateVdu(cloudInfo, vfModuleName, goldenInputs, vduModel, backout); + + LOGGER.recordMetricEvent (instantiateVduStartTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from VduPlugin", "VDU", "instantiateVdu", vfModuleName); + } + catch (VduException me) { + // Failed to instantiate the VDU. + me.addContext ("CreateVFModule"); + String error = "Create VF Module " + vfModuleType + " in " + cloudSiteId + "/" + tenantId + ": " + me; + LOGGER.recordMetricEvent (instantiateVduStartTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "VDU", "instantiateVdu", vfModuleName); + LOGGER.error (MessageEnum.RA_CREATE_VNF_ERR, vfModuleType, cloudSiteId, tenantId, "VDU", "", MsoLogger.ErrorCode.DataError, "MsoException - instantiateVdu", me); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error); + // Convert to a generic VnfException + throw new VnfException (me); + } + catch (NullPointerException npe) { + String error = "Create VFModule " + vfModuleType + " in " + cloudSiteId + "/" + tenantId + ": " + npe; + LOGGER.recordMetricEvent (instantiateVduStartTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.InternalError, error, "VDU", "instantiateVdu", vfModuleName); + LOGGER.error (MessageEnum.RA_CREATE_VNF_ERR, vfModuleType, cloudSiteId, tenantId, "VDU", "", MsoLogger.ErrorCode.DataError, "NullPointerException - instantiateVdu", npe); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.InternalError, error); + LOGGER.debug("NULL POINTER EXCEPTION at vduPlugin.instantiateVdu", npe); + throw new VnfException ("NullPointerException during instantiateVdu"); + } + catch (Exception e) { + String error = "Create VFModule " + vfModuleType + " in " + cloudSiteId + "/" + tenantId + ": " + e; + LOGGER.recordMetricEvent (instantiateVduStartTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.UnknownError, error, "VDU", "instantiateVdu", vfModuleName); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.UnknownError, error); + LOGGER.debug("Unhandled exception at vduPlugin.instantiateVdu", e); + } finally { + db.close(); + } + + // Reach this point if create is successful. + // Populate remaining rollback info and response parameters. + vfRollback.setVnfCreated (true); + vfRollback.setVnfId (vduInstance.getVduInstanceId()); + vnfId.value = vduInstance.getVduInstanceId(); + outputs.value = copyStringOutputs (vduInstance.getOutputs ()); + + rollback.value = vfRollback; + + LOGGER.debug ("VF Module " + vfModuleName + " successfully created"); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully create VF Module"); + return; + } + + public void deleteVfModule (String cloudSiteId, + String tenantId, + String vfModuleId, + MsoRequest msoRequest, + Holder > outputs) throws VnfException + { + MsoLogger.setLogContext (msoRequest); + MsoLogger.setServiceName ("DeleteVfModule"); + + LOGGER.debug ("Deleting VF Module " + vfModuleId + " in " + cloudSiteId + "/" + tenantId); + // Will capture execution time for metrics + long startTime = System.currentTimeMillis (); + + // Capture the output parameters on a delete, so need to query first + VduInstance vduInstance = null; + CloudInfo cloudInfo = new CloudInfo(cloudSiteId, tenantId, null); + + // Use the VduPlugin. + VduPlugin vduPlugin = getVduPlugin(cloudSiteId); + + try { + vduInstance = vduPlugin.queryVdu (cloudInfo, vfModuleId); + LOGGER.recordMetricEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received VDU Query response", "VDU", "QueryVDU", vfModuleId); + } + catch (VduException e) { + // Failed to query the VDU due to a plugin exception. + // Convert to a generic VnfException + e.addContext ("QueryVFModule"); + String error = "Query VfModule (VDU): " + vfModuleId + " in " + cloudSiteId + "/" + tenantId + ": " + e; + LOGGER.recordMetricEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "VDU", "QueryVNF", vfModuleId); + LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vfModuleId, cloudSiteId, tenantId, "VDU", "QueryVFModule", MsoLogger.ErrorCode.DataError, "Exception - queryVDU", e); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error); + throw new VnfException (e); + } + + // call method which handles the conversion from Map to Map for our expected Object types + outputs.value = convertMapStringObjectToStringString(vduInstance.getOutputs()); + + // Use the VduPlugin to delete the VDU. + // The possible outcomes of deleteVdu are + // - a vnfInstance object with status of DELETED (success) + // - a vnfInstance object with status of NOTFOUND (VDU did not exist, treat as success) + // - a vnfInstance object with status of FAILED (error) + // Also, VduException could be thrown. + long subStartTime = System.currentTimeMillis (); + try { + // TODO: Get an appropriate timeout value - require access to the model + vduPlugin.deleteVdu(cloudInfo, vfModuleId, 5); + LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from deleteVdu", "VDU", "DeleteVdu", vfModuleId); + } catch (VduException me) { + me.addContext ("DeleteVfModule"); + // Convert to a generic VnfException + String error = "Delete VF: " + vfModuleId + " in " + cloudSiteId + "/" + tenantId + ": " + me; + LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "DeleteVdu", "DeleteVdu", vfModuleId); + LOGGER.error (MessageEnum.RA_DELETE_VNF_ERR, vfModuleId, cloudSiteId, tenantId, "VDU", "DeleteVdu", MsoLogger.ErrorCode.DataError, "Exception - DeleteVdu: " + me.getMessage()); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error); + throw new VnfException (me); + } + + // On success, nothing is returned. + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully delete VF"); + return; + } + + // Update VF Module not yet implemented for generic VDU plug-in model. + @Override + public void updateVfModule (String cloudSiteId, + String tenantId, + String vnfType, + String vnfVersion, + String vnfName, + String requestType, + String volumeGroupHeatStackId, + String baseVfHeatStackId, + String vfModuleStackId, + String modelCustomizationUuid, + Map inputs, + MsoRequest msoRequest, + Holder > outputs, + Holder rollback) throws VnfException + { + // This operation is not currently supported for VduPlugin-orchestrated VF Modules. + LOGGER.debug ("Update VF Module command attempted but not supported"); + throw new VnfException ("UpdateVfModule: Unsupported command", MsoExceptionCategory.USERDATA); + } + + /* + * Dynamic selection of a VduPlugin version. For initial tests, base on the "orchestrator" + * defined for the target cloud. Should really be looking at the VNF Model (ochestration_mode) + * but we don't currently have access to that in Query and Delete cases. + */ + private VduPlugin getVduPlugin (String cloudSiteId) { + Optional cloudSite = cloudConfig.getCloudSite(cloudSiteId); + if (cloudSite.isPresent()) { + String orchestrator = cloudSite.get().getOrchestrator(); + + if (orchestrator.equalsIgnoreCase("CLOUDIFY")) { + return cloudifyUtils; + } + else if (orchestrator.equalsIgnoreCase("HEAT")) { + return heatUtils; + } + } + + // Default - return HEAT plugin, though will fail later + return heatUtils; + } + +} diff --git a/adapters/mso-vnf-adapter/src/main/java/org/openecomp/mso/adapters/vnf/VnfAdapterRestUtils.java b/adapters/mso-vnf-adapter/src/main/java/org/openecomp/mso/adapters/vnf/VnfAdapterRestUtils.java index f7302c0bf5..487e9c2b60 100644 --- a/adapters/mso-vnf-adapter/src/main/java/org/openecomp/mso/adapters/vnf/VnfAdapterRestUtils.java +++ b/adapters/mso-vnf-adapter/src/main/java/org/openecomp/mso/adapters/vnf/VnfAdapterRestUtils.java @@ -74,9 +74,9 @@ public class VnfAdapterRestUtils vnfAdapter = new MsoVnfAdapterImpl (msoPropertiesFactory, cloudConfigFactory); } else { - // Don't expect this, but default is the HEAT adapter - LOGGER.debug ("GetVnfAdapterImpl: Return Default (Heat) Adapter"); - vnfAdapter = new MsoVnfAdapterImpl (msoPropertiesFactory, cloudConfigFactory); + // Default is the PLUGIN adapter + LOGGER.debug ("GetVnfAdapterImpl: Return Default (Plugin) Adapter"); + vnfAdapter = new MsoVnfPluginAdapterImpl (msoPropertiesFactory, cloudConfigFactory); } return vnfAdapter; diff --git a/adapters/mso-vnf-adapter/src/test/java/org/openecomp/mso/adapters/vnf/MsoVnfPluginAdapterImplTest.java b/adapters/mso-vnf-adapter/src/test/java/org/openecomp/mso/adapters/vnf/MsoVnfPluginAdapterImplTest.java new file mode 100644 index 0000000000..37ca4f762a --- /dev/null +++ b/adapters/mso-vnf-adapter/src/test/java/org/openecomp/mso/adapters/vnf/MsoVnfPluginAdapterImplTest.java @@ -0,0 +1,151 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2018 AT&T Intellectual Property. All rights reserved. + * Copyright (C) 2018 Huawei 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.openecomp.mso.adapters.vnf; + +import java.util.HashMap; +import java.util.Map; + +import javax.xml.ws.Holder; + +import org.junit.Test; +import org.openecomp.mso.adapters.vnf.exceptions.VnfException; +import org.openecomp.mso.entity.MsoRequest; +import org.openecomp.mso.openstack.beans.VnfRollback; + +public class MsoVnfPluginAdapterImplTest { + + @Test(expected = NullPointerException.class) + public void queryVnfNullPointerExceptionTest() throws Exception { + MsoVnfPluginAdapterImpl instance = new MsoVnfPluginAdapterImpl(); + MsoRequest msoRequest = new MsoRequest(); + msoRequest.setRequestId("12345"); + msoRequest.setServiceInstanceId("12345"); + + instance.queryVnf("siteid", "1234", "vfname", + msoRequest, new Holder<>(), new Holder<>(), new Holder<>(), + new Holder<>()); + } + + @Test(expected = VnfException.class) + public void deleteVnfVnfExceptionTest() throws Exception { + MsoVnfPluginAdapterImpl instance = new MsoVnfPluginAdapterImpl(); + MsoRequest msoRequest = new MsoRequest(); + msoRequest.setRequestId("12345"); + msoRequest.setServiceInstanceId("12345"); + + instance.deleteVnf("12344", "234", "vnfname", msoRequest); + + } + + @Test + public void rollbackVnf() throws Exception { + MsoVnfPluginAdapterImpl instance = new MsoVnfPluginAdapterImpl(); + MsoRequest msoRequest = new MsoRequest(); + msoRequest.setRequestId("12345"); + msoRequest.setServiceInstanceId("12345"); + + VnfRollback vnfRollback = new VnfRollback(); + vnfRollback.setModelCustomizationUuid("1234"); + vnfRollback.setVfModuleStackId("2134"); + vnfRollback.setVnfId("123"); + vnfRollback.setModelCustomizationUuid("1234"); + + instance.rollbackVnf(vnfRollback); + } + + @Test(expected = VnfException.class) + public void createVfModuleVnfException() throws Exception { + MsoVnfPluginAdapterImpl instance = new MsoVnfPluginAdapterImpl(); + MsoRequest msoRequest = new MsoRequest(); + msoRequest.setRequestId("12345"); + msoRequest.setServiceInstanceId("12345"); + + instance.createVfModule("123", "123", "vf", "v1", "module-005", "create", "3245", "234", "123", new HashMap<>(), true, true, msoRequest, new Holder<>(), new Holder<>(), new Holder<>()); + } + + @Test(expected = VnfException.class) + public void updateVfModuleVnfException() throws Exception { + MsoVnfPluginAdapterImpl instance = new MsoVnfPluginAdapterImpl(); + MsoRequest msoRequest = new MsoRequest(); + msoRequest.setRequestId("12345"); + msoRequest.setServiceInstanceId("12345"); + + instance.updateVfModule("123", "1234", "fw", "v2", "vnf1", "create", "123", "12", "233", "234", new HashMap<>(), msoRequest, new Holder<>(), new Holder<>()); + } + + @Test + public void healthCheckVNFTest() { + MsoVnfPluginAdapterImpl instance = new MsoVnfPluginAdapterImpl(); + instance.healthCheck(); + } + + @Test + public void createVnfTest() { + MsoVnfPluginAdapterImpl instance = new MsoVnfPluginAdapterImpl(); + MsoRequest msoRequest = new MsoRequest(); + msoRequest.setRequestId("12345"); + msoRequest.setServiceInstanceId("12345"); + + Map map = new HashMap<>(); + map.put("key1", "value1"); + try { + instance.createVnf("mdt1", "88a6ca3ee0394ade9403f075db23167e", "vnf", "1", "vSAMP12", "VFMOD", + "volumeGroupHeatStackId|1", map, + Boolean.FALSE, Boolean.TRUE, msoRequest, new Holder<>(), new Holder<>(), + new Holder<>()); + } catch (Exception e) { + } + } + + @Test + public void updateVnfTest() { + MsoVnfPluginAdapterImpl instance = new MsoVnfPluginAdapterImpl(); + MsoRequest msoRequest = new MsoRequest(); + msoRequest.setRequestId("12345"); + msoRequest.setServiceInstanceId("12345"); + + Map map = new HashMap<>(); + + map.put("key1", "value1"); + try { + instance.updateVnf("mdt1", "88a6ca3ee0394ade9403f075db23167e", "vnf", "1", "vSAMP12", "VFMOD", + "volumeGroupHeatStackId|1", map, msoRequest, new Holder<>(), + new Holder<>()); + } catch (Exception e) { + + } + } + + @Test + public void deleteVnfTest() { + MsoVnfPluginAdapterImpl instance = new MsoVnfPluginAdapterImpl(); + MsoRequest msoRequest = new MsoRequest(); + msoRequest.setRequestId("12345"); + msoRequest.setServiceInstanceId("12345"); + try { + instance.deleteVnf("mdt1", "88a6ca3ee0394ade9403f075db23167e", "vSAMP12", msoRequest); + } catch (Exception e) { + + } + } + +} diff --git a/cloudify-client/src/main/java/org/openecomp/mso/cloudify/v3/model/AzureConfig.java b/cloudify-client/src/main/java/org/openecomp/mso/cloudify/v3/model/AzureConfig.java new file mode 100644 index 0000000000..ddfd1fd6a4 --- /dev/null +++ b/cloudify-client/src/main/java/org/openecomp/mso/cloudify/v3/model/AzureConfig.java @@ -0,0 +1,75 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2018 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.mso.cloudify.v3.model; + +import java.io.Serializable; + +import com.fasterxml.jackson.annotation.JsonProperty; + +public class AzureConfig implements Serializable { + + private static final long serialVersionUID = 1L; + + @JsonProperty("subscription_id") + String subscriptionId; + + @JsonProperty("tenant_id") + String tenantId; + + @JsonProperty("client_id") + String clientId; + + @JsonProperty("client_secret") + String clientSecret; + + public String getSubscriptionId() { + return subscriptionId; + } + + public void setSubscriptionId(String subscriptionId) { + this.subscriptionId = subscriptionId; + } + + public String getTenantId() { + return tenantId; + } + + public void setTenantId(String tenantId) { + this.tenantId = tenantId; + } + + public String getClientId() { + return clientId; + } + + public void setClientId(String clientId) { + this.clientId = clientId; + } + + public String getClientSecret() { + return clientSecret; + } + + public void setClientSecret(String clientSecret) { + this.clientSecret = clientSecret; + } + +} \ No newline at end of file -- 2.16.6