From 5a6a6de6f1a26a1897e4917a0df613e25a24eb70 Mon Sep 17 00:00:00 2001 From: "Benjamin, Max (mb388a)" Date: Mon, 30 Jul 2018 15:56:09 -0400 Subject: Containerization feature of SO Change-Id: I95381232eeefcd247a66a5cec370a8ce1c288e18 Issue-ID: SO-670 Signed-off-by: Benjamin, Max (mb388a) --- .../onap/so/adapters/network/BpelRestClient.java | 298 +++ .../so/adapters/network/ContrailPolicyRef.java | 75 + .../so/adapters/network/ContrailPolicyRefSeq.java | 66 + .../onap/so/adapters/network/ContrailSubnet.java | 214 ++ .../adapters/network/ContrailSubnetHostRoute.java | 67 + .../adapters/network/ContrailSubnetHostRoutes.java | 58 + .../onap/so/adapters/network/ContrailSubnetIp.java | 59 + .../so/adapters/network/ContrailSubnetPool.java | 68 + .../so/adapters/network/MsoNetworkAdapter.java | 222 ++ .../adapters/network/MsoNetworkAdapterAsync.java | 106 + .../network/MsoNetworkAdapterAsyncImpl.java | 698 ++++++ .../so/adapters/network/MsoNetworkAdapterImpl.java | 2125 ++++++++++++++++++ .../so/adapters/network/NetworkAdapterRest.java | 671 ++++++ .../async/client/CreateNetworkNotification.java | 437 ++++ .../client/CreateNetworkNotificationResponse.java | 51 + .../async/client/DeleteNetworkNotification.java | 181 ++ .../client/DeleteNetworkNotificationResponse.java | 51 + .../network/async/client/MsoExceptionCategory.java | 61 + .../adapters/network/async/client/MsoRequest.java | 106 + .../network/async/client/NetworkAdapterNotify.java | 191 ++ .../async/client/NetworkAdapterNotify_Service.java | 110 + .../network/async/client/NetworkRollback.java | 370 +++ .../network/async/client/NetworkStatus.java | 65 + .../network/async/client/ObjectFactory.java | 298 +++ .../async/client/QueryNetworkNotification.java | 497 +++++ .../client/QueryNetworkNotificationResponse.java | 51 + .../async/client/RollbackNetworkNotification.java | 154 ++ .../RollbackNetworkNotificationResponse.java | 51 + .../async/client/UpdateNetworkNotification.java | 383 ++++ .../client/UpdateNetworkNotificationResponse.java | 51 + .../network/async/client/package-info.java | 21 + .../network/exceptions/NetworkException.java | 80 + .../network/exceptions/NetworkExceptionBean.java | 73 + .../so/adapters/openstack/CXFConfiguration.java | 190 ++ .../openstack/MsoOpenstackAdaptersApplication.java | 73 + .../adapters/openstack/WebSecurityConfigImpl.java | 51 + .../onap/so/adapters/tenant/MsoTenantAdapter.java | 77 + .../so/adapters/tenant/MsoTenantAdapterImpl.java | 295 +++ .../onap/so/adapters/tenant/TenantAdapterRest.java | 345 +++ .../tenant/exceptions/TenantAlreadyExists.java | 45 + .../tenant/exceptions/TenantException.java | 75 + .../tenant/exceptions/TenantExceptionBean.java | 64 + .../so/adapters/valet/GenericValetResponse.java | 71 + .../org/onap/so/adapters/valet/ValetClient.java | 326 +++ .../onap/so/adapters/valet/beans/HeatRequest.java | 125 ++ .../adapters/valet/beans/ValetConfirmRequest.java | 65 + .../adapters/valet/beans/ValetConfirmResponse.java | 30 + .../adapters/valet/beans/ValetCreateRequest.java | 134 ++ .../adapters/valet/beans/ValetCreateResponse.java | 70 + .../adapters/valet/beans/ValetDeleteRequest.java | 84 + .../adapters/valet/beans/ValetDeleteResponse.java | 66 + .../adapters/valet/beans/ValetRollbackRequest.java | 81 + .../valet/beans/ValetRollbackResponse.java | 29 + .../onap/so/adapters/valet/beans/ValetStatus.java | 81 + .../adapters/valet/beans/ValetUpdateRequest.java | 134 ++ .../adapters/valet/beans/ValetUpdateResponse.java | 71 + .../mapper/VfModuleCustomizationToVduMapper.java | 127 ++ .../org/onap/so/adapters/vnf/BpelRestClient.java | 296 +++ .../main/java/org/onap/so/adapters/vnf/CSAR.java | 192 ++ .../org/onap/so/adapters/vnf/MsoVnfAdapter.java | 147 ++ .../onap/so/adapters/vnf/MsoVnfAdapterAsync.java | 105 + .../so/adapters/vnf/MsoVnfAdapterAsyncImpl.java | 666 ++++++ .../onap/so/adapters/vnf/MsoVnfAdapterImpl.java | 2347 ++++++++++++++++++++ .../so/adapters/vnf/MsoVnfCloudifyAdapterImpl.java | 1218 ++++++++++ .../so/adapters/vnf/MsoVnfPluginAdapterImpl.java | 1229 ++++++++++ .../java/org/onap/so/adapters/vnf/VfRollback.java | 137 ++ .../org/onap/so/adapters/vnf/VnfAdapterRest.java | 691 ++++++ .../onap/so/adapters/vnf/VnfAdapterRestUtils.java | 94 + .../org/onap/so/adapters/vnf/VnfAdapterRestV2.java | 704 ++++++ .../onap/so/adapters/vnf/VolumeAdapterRest.java | 646 ++++++ .../onap/so/adapters/vnf/VolumeAdapterRestV2.java | 648 ++++++ .../vnf/async/client/CreateVnfNotification.java | 410 ++++ .../vnf/async/client/DeleteVnfNotification.java | 154 ++ .../vnf/async/client/MsoExceptionCategory.java | 61 + .../so/adapters/vnf/async/client/MsoRequest.java | 106 + .../adapters/vnf/async/client/ObjectFactory.java | 208 ++ .../vnf/async/client/QueryVnfNotification.java | 437 ++++ .../vnf/async/client/RollbackVnfNotification.java | 154 ++ .../vnf/async/client/UpdateVnfNotification.java | 383 ++++ .../vnf/async/client/VnfAdapterNotify.java | 177 ++ .../vnf/async/client/VnfAdapterNotify_Service.java | 110 + .../so/adapters/vnf/async/client/VnfRollback.java | 198 ++ .../so/adapters/vnf/async/client/VnfStatus.java | 61 + .../so/adapters/vnf/async/client/package-info.java | 21 + .../adapters/vnf/exceptions/VnfAlreadyExists.java | 42 + .../so/adapters/vnf/exceptions/VnfException.java | 80 + .../adapters/vnf/exceptions/VnfExceptionBean.java | 74 + .../so/adapters/vnf/exceptions/VnfNotFound.java | 41 + .../java/org/onap/so/vdu/utils/VduBlueprint.java | 90 + .../main/java/org/onap/so/vdu/utils/VduInfo.java | 130 ++ .../main/java/org/onap/so/vdu/utils/VduPlugin.java | 248 +++ .../main/java/org/onap/so/vdu/utils/VduStatus.java | 37 + .../src/main/resources/NetworkAdapterNotify.wsdl | 295 +++ .../src/main/resources/VnfAdapterNotify.wsdl | 218 ++ .../src/main/resources/application-local.yaml | 134 ++ .../src/main/resources/application.yaml | 40 + .../src/main/resources/static/index.html | 35 + .../resources/static/swagger/favicon-16x16.png | Bin 0 -> 445 bytes .../resources/static/swagger/favicon-32x32.png | Bin 0 -> 1141 bytes .../src/main/resources/static/swagger/index.html | 110 + .../resources/static/swagger/oauth2-redirect.html | 60 + .../resources/static/swagger/swagger-ui-bundle.js | 99 + .../static/swagger/swagger-ui-standalone-preset.js | 13 + .../main/resources/static/swagger/swagger-ui.css | 2 + .../resources/static/swagger/swagger-ui.css.map | 1 + .../main/resources/static/swagger/swagger-ui.js | 8 + .../src/main/resources/static/swagger/welcome.html | 1 + .../main/resources/wsdl/NetworkAdapterNotify.wsdl | 295 +++ .../src/main/resources/wsdl/VnfAdapterNotify.wsdl | 218 ++ 109 files changed, 24589 insertions(+) create mode 100644 adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/BpelRestClient.java create mode 100644 adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/ContrailPolicyRef.java create mode 100644 adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/ContrailPolicyRefSeq.java create mode 100644 adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/ContrailSubnet.java create mode 100644 adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/ContrailSubnetHostRoute.java create mode 100644 adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/ContrailSubnetHostRoutes.java create mode 100644 adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/ContrailSubnetIp.java create mode 100644 adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/ContrailSubnetPool.java create mode 100644 adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/MsoNetworkAdapter.java create mode 100644 adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/MsoNetworkAdapterAsync.java create mode 100644 adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/MsoNetworkAdapterAsyncImpl.java create mode 100644 adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/MsoNetworkAdapterImpl.java create mode 100644 adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/NetworkAdapterRest.java create mode 100644 adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/CreateNetworkNotification.java create mode 100644 adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/CreateNetworkNotificationResponse.java create mode 100644 adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/DeleteNetworkNotification.java create mode 100644 adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/DeleteNetworkNotificationResponse.java create mode 100644 adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/MsoExceptionCategory.java create mode 100644 adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/MsoRequest.java create mode 100644 adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/NetworkAdapterNotify.java create mode 100644 adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/NetworkAdapterNotify_Service.java create mode 100644 adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/NetworkRollback.java create mode 100644 adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/NetworkStatus.java create mode 100644 adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/ObjectFactory.java create mode 100644 adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/QueryNetworkNotification.java create mode 100644 adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/QueryNetworkNotificationResponse.java create mode 100644 adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/RollbackNetworkNotification.java create mode 100644 adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/RollbackNetworkNotificationResponse.java create mode 100644 adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/UpdateNetworkNotification.java create mode 100644 adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/UpdateNetworkNotificationResponse.java create mode 100644 adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/package-info.java create mode 100644 adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/exceptions/NetworkException.java create mode 100644 adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/exceptions/NetworkExceptionBean.java create mode 100644 adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/openstack/CXFConfiguration.java create mode 100644 adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/openstack/MsoOpenstackAdaptersApplication.java create mode 100644 adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/openstack/WebSecurityConfigImpl.java create mode 100644 adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/tenant/MsoTenantAdapter.java create mode 100644 adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/tenant/MsoTenantAdapterImpl.java create mode 100644 adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/tenant/TenantAdapterRest.java create mode 100644 adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/tenant/exceptions/TenantAlreadyExists.java create mode 100644 adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/tenant/exceptions/TenantException.java create mode 100644 adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/tenant/exceptions/TenantExceptionBean.java create mode 100644 adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/valet/GenericValetResponse.java create mode 100644 adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/valet/ValetClient.java create mode 100644 adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/valet/beans/HeatRequest.java create mode 100644 adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/valet/beans/ValetConfirmRequest.java create mode 100644 adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/valet/beans/ValetConfirmResponse.java create mode 100644 adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/valet/beans/ValetCreateRequest.java create mode 100644 adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/valet/beans/ValetCreateResponse.java create mode 100644 adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/valet/beans/ValetDeleteRequest.java create mode 100644 adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/valet/beans/ValetDeleteResponse.java create mode 100644 adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/valet/beans/ValetRollbackRequest.java create mode 100644 adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/valet/beans/ValetRollbackResponse.java create mode 100644 adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/valet/beans/ValetStatus.java create mode 100644 adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/valet/beans/ValetUpdateRequest.java create mode 100644 adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/valet/beans/ValetUpdateResponse.java create mode 100644 adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vdu/mapper/VfModuleCustomizationToVduMapper.java create mode 100644 adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/BpelRestClient.java create mode 100644 adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/CSAR.java create mode 100644 adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/MsoVnfAdapter.java create mode 100644 adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/MsoVnfAdapterAsync.java create mode 100644 adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/MsoVnfAdapterAsyncImpl.java create mode 100644 adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/MsoVnfAdapterImpl.java create mode 100644 adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/MsoVnfCloudifyAdapterImpl.java create mode 100644 adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/MsoVnfPluginAdapterImpl.java create mode 100644 adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/VfRollback.java create mode 100644 adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/VnfAdapterRest.java create mode 100644 adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/VnfAdapterRestUtils.java create mode 100644 adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/VnfAdapterRestV2.java create mode 100644 adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/VolumeAdapterRest.java create mode 100644 adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/VolumeAdapterRestV2.java create mode 100644 adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/async/client/CreateVnfNotification.java create mode 100644 adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/async/client/DeleteVnfNotification.java create mode 100644 adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/async/client/MsoExceptionCategory.java create mode 100644 adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/async/client/MsoRequest.java create mode 100644 adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/async/client/ObjectFactory.java create mode 100644 adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/async/client/QueryVnfNotification.java create mode 100644 adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/async/client/RollbackVnfNotification.java create mode 100644 adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/async/client/UpdateVnfNotification.java create mode 100644 adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/async/client/VnfAdapterNotify.java create mode 100644 adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/async/client/VnfAdapterNotify_Service.java create mode 100644 adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/async/client/VnfRollback.java create mode 100644 adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/async/client/VnfStatus.java create mode 100644 adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/async/client/package-info.java create mode 100644 adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/exceptions/VnfAlreadyExists.java create mode 100644 adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/exceptions/VnfException.java create mode 100644 adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/exceptions/VnfExceptionBean.java create mode 100644 adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/exceptions/VnfNotFound.java create mode 100644 adapters/mso-openstack-adapters/src/main/java/org/onap/so/vdu/utils/VduBlueprint.java create mode 100644 adapters/mso-openstack-adapters/src/main/java/org/onap/so/vdu/utils/VduInfo.java create mode 100644 adapters/mso-openstack-adapters/src/main/java/org/onap/so/vdu/utils/VduPlugin.java create mode 100644 adapters/mso-openstack-adapters/src/main/java/org/onap/so/vdu/utils/VduStatus.java create mode 100644 adapters/mso-openstack-adapters/src/main/resources/NetworkAdapterNotify.wsdl create mode 100644 adapters/mso-openstack-adapters/src/main/resources/VnfAdapterNotify.wsdl create mode 100644 adapters/mso-openstack-adapters/src/main/resources/application-local.yaml create mode 100644 adapters/mso-openstack-adapters/src/main/resources/application.yaml create mode 100644 adapters/mso-openstack-adapters/src/main/resources/static/index.html create mode 100644 adapters/mso-openstack-adapters/src/main/resources/static/swagger/favicon-16x16.png create mode 100644 adapters/mso-openstack-adapters/src/main/resources/static/swagger/favicon-32x32.png create mode 100644 adapters/mso-openstack-adapters/src/main/resources/static/swagger/index.html create mode 100644 adapters/mso-openstack-adapters/src/main/resources/static/swagger/oauth2-redirect.html create mode 100644 adapters/mso-openstack-adapters/src/main/resources/static/swagger/swagger-ui-bundle.js create mode 100644 adapters/mso-openstack-adapters/src/main/resources/static/swagger/swagger-ui-standalone-preset.js create mode 100644 adapters/mso-openstack-adapters/src/main/resources/static/swagger/swagger-ui.css create mode 100644 adapters/mso-openstack-adapters/src/main/resources/static/swagger/swagger-ui.css.map create mode 100644 adapters/mso-openstack-adapters/src/main/resources/static/swagger/swagger-ui.js create mode 100644 adapters/mso-openstack-adapters/src/main/resources/static/swagger/welcome.html create mode 100644 adapters/mso-openstack-adapters/src/main/resources/wsdl/NetworkAdapterNotify.wsdl create mode 100644 adapters/mso-openstack-adapters/src/main/resources/wsdl/VnfAdapterNotify.wsdl (limited to 'adapters/mso-openstack-adapters/src/main') diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/BpelRestClient.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/BpelRestClient.java new file mode 100644 index 0000000000..cf11ab94c1 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/BpelRestClient.java @@ -0,0 +1,298 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * Copyright (C) 2017 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.so.adapters.network; + + +import java.security.GeneralSecurityException; +import java.util.Set; +import java.util.TreeSet; + +import javax.annotation.PostConstruct; +import javax.xml.bind.DatatypeConverter; + +import org.apache.http.HttpEntity; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.ContentType; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.util.EntityUtils; +import org.onap.so.logger.MessageEnum; +import org.onap.so.logger.MsoLogger; +import org.onap.so.utils.CryptoUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Scope; +import org.springframework.core.env.Environment; +import org.springframework.stereotype.Component; + +/** + * This is the class that is used to POST replies from the MSO adapters to the BPEL engine. + * It can be configured via property file, or modified using the member methods. + * The properties to use are: + * org.onap.so.adapters.vnf.bpelauth encrypted authorization string to send to BEPL engine + * org.onap.so.adapters.vnf.sockettimeout socket timeout value + * org.onap.so.adapters.vnf.connecttimeout connect timeout value + * org.onap.so.adapters.vnf.retrycount number of times to retry failed connections + * org.onap.so.adapters.vnf.retryinterval interval (in seconds) between retries + * org.onap.so.adapters.vnf.retrylist list of response codes that will trigger a retry (the special code + * 900 means "connection was not established") + */ +@Component("NetworkBpel") +@Scope("prototype") +public class BpelRestClient { + public static final String MSO_PROP_NETWORK_ADAPTER = "MSO_PROP_NETWORK_ADAPTER"; + private static final String PROPERTY_DOMAIN = "org.onap.so.adapters.network"; + private static final String BPEL_AUTH_PROPERTY = PROPERTY_DOMAIN+".bpelauth"; + private static final String SOCKET_TIMEOUT_PROPERTY = PROPERTY_DOMAIN+".sockettimeout"; + private static final String CONN_TIMEOUT_PROPERTY = PROPERTY_DOMAIN+".connecttimeout"; + private static final String RETRY_COUNT_PROPERTY = PROPERTY_DOMAIN+".retrycount"; + private static final String RETRY_INTERVAL_PROPERTY = PROPERTY_DOMAIN+".retryinterval"; + private static final String RETRY_LIST_PROPERTY = PROPERTY_DOMAIN+".retrylist"; + private static final String ENCRYPTION_KEY = "aa3871669d893c7fb8abbcda31b88b4f"; + private static final MsoLogger LOGGER = MsoLogger.getMsoLogger (MsoLogger.Catalog.RA, BpelRestClient.class); + + @Autowired + private Environment env; + /** Default socket timeout (in seconds) */ + public static final int DEFAULT_SOCKET_TIMEOUT = 5; + /** Default connect timeout (in seconds) */ + public static final int DEFAULT_CONNECT_TIMEOUT = 5; + /** By default, retry up to five times */ + public static final int DEFAULT_RETRY_COUNT = 5; + /** Default interval to wait between retries (in seconds), negative means use backoff algorithm */ + public static final int DEFAULT_RETRY_INTERVAL = -15; + /** Default list of response codes to trigger a retry */ + public static final String DEFAULT_RETRY_LIST = "408,429,500,502,503,504,900"; // 900 is "connection failed" + /** Default credentials */ + public static final String DEFAULT_CREDENTIALS = ""; + + // Properties of the BPEL client -- all are configurable + private int socketTimeout; + private int connectTimeout; + private int retryCount; + private int retryInterval; + private Set retryList; + private String credentials; + + // last response from BPEL engine + private int lastResponseCode; + private String lastResponse; + + /** + * Create a client to send results to the BPEL engine, using configuration from the + * MSO_PROP_NETWORK_ADAPTER properties. + */ + public BpelRestClient() { + socketTimeout = DEFAULT_SOCKET_TIMEOUT; + connectTimeout = DEFAULT_CONNECT_TIMEOUT; + retryCount = DEFAULT_RETRY_COUNT; + retryInterval = DEFAULT_RETRY_INTERVAL; + setRetryList(DEFAULT_RETRY_LIST); + credentials = DEFAULT_CREDENTIALS; + lastResponseCode = 0; + lastResponse = ""; + + } + + @PostConstruct + protected void init() { + + socketTimeout = env.getProperty(SOCKET_TIMEOUT_PROPERTY, Integer.class, DEFAULT_SOCKET_TIMEOUT); + connectTimeout = env.getProperty(CONN_TIMEOUT_PROPERTY, Integer.class, DEFAULT_CONNECT_TIMEOUT); + retryCount = env.getProperty(RETRY_COUNT_PROPERTY, Integer.class, DEFAULT_RETRY_COUNT); + retryInterval = env.getProperty(RETRY_INTERVAL_PROPERTY, Integer.class, DEFAULT_RETRY_INTERVAL); + setRetryList(env.getProperty(RETRY_LIST_PROPERTY, DEFAULT_RETRY_LIST)); + credentials = getEncryptedProperty(BPEL_AUTH_PROPERTY, DEFAULT_CREDENTIALS, ENCRYPTION_KEY); + } + + public int getSocketTimeout() { + return socketTimeout; + } + + public void setSocketTimeout(int socketTimeout) { + this.socketTimeout = socketTimeout; + } + + public int getConnectTimeout() { + return connectTimeout; + } + + public void setConnectTimeout(int connectTimeout) { + this.connectTimeout = connectTimeout; + } + + public int getRetryCount() { + return retryCount; + } + + public void setRetryCount(int retryCount) { + int retCnt = 0; + if (retryCount < 0) + retCnt = DEFAULT_RETRY_COUNT; + this.retryCount = retCnt; + } + + public int getRetryInterval() { + return retryInterval; + } + + public void setRetryInterval(int retryInterval) { + this.retryInterval = retryInterval; + } + + public String getCredentials() { + return credentials; + } + + public void setCredentials(String credentials) { + this.credentials = credentials; + } + + public String getRetryList() { + if (retryList.isEmpty()) + return ""; + String t = retryList.toString(); + return t.substring(1, t.length()-1); + } + + public void setRetryList(String retryList) { + Set s = new TreeSet<>(); + for (String t : retryList.split("[, ]")) { + try { + s.add(Integer.parseInt(t)); + } catch (NumberFormatException x) { + LOGGER.debug("Exception while parsing", x); + } + } + this.retryList = s; + } + + public int getLastResponseCode() { + return lastResponseCode; + } + + public String getLastResponse() { + return lastResponse; + } + + /** + * Post a response to the URL of the BPEL engine. As long as the response code is one of those in + * the retryList, the post will be retried up to "retrycount" times with an interval (in seconds) + * of "retryInterval". If retryInterval is negative, then each successive retry interval will be + * double the previous one. + * @param toBpelStr the content (XML or JSON) to post + * @param bpelUrl the URL to post to + * @param isxml true if the content is XML, otherwise assumed to be JSON + * @return true if the post succeeded, false if all retries failed + */ + public boolean bpelPost(final String toBpelStr, final String bpelUrl, final boolean isxml) { + debug("Sending response to BPEL: " + toBpelStr); + int totalretries = 0; + int retryint = retryInterval; + while (true) { + sendOne(toBpelStr, bpelUrl, isxml); + // Note: really should handle response code 415 by switching between content types if needed + if (!retryList.contains(lastResponseCode)) { + debug("Got response code: " + lastResponseCode + ": returning."); + return true; + } + if (totalretries >= retryCount) { + debug("Retried " + totalretries + " times, giving up."); + LOGGER.error(MessageEnum.RA_SEND_VNF_NOTIF_ERR, "Could not deliver response to BPEL after "+totalretries+" tries: "+toBpelStr, "Camunda", "", MsoLogger.ErrorCode.DataError, "Could not deliver response to BPEL"); + return false; + } + totalretries++; + int sleepinterval = retryint; + if (retryint < 0) { + // if retry interval is negative double the retry on each pass + sleepinterval = -retryint; + retryint *= 2; + } + debug("Sleeping for " + sleepinterval + " seconds."); + try { + Thread.sleep(sleepinterval * 1000L); + } catch (InterruptedException e) { + LOGGER.debug("Exception while Thread sleep", e); + Thread.currentThread().interrupt(); + } + } + } + private void debug(String m) { + LOGGER.debug(m); + } + private void sendOne(final String toBpelStr, final String bpelUrl, final boolean isxml) { + LOGGER.debug("Sending to BPEL server: "+bpelUrl); + LOGGER.debug("Content is: "+toBpelStr); + + //POST + HttpPost post = new HttpPost(bpelUrl); + if (credentials != null && !credentials.isEmpty()) + post.addHeader("Authorization", "Basic " + DatatypeConverter.printBase64Binary(credentials.getBytes())); + + //ContentType + ContentType ctype = isxml ? ContentType.APPLICATION_XML : ContentType.APPLICATION_JSON; + post.setEntity(new StringEntity(toBpelStr, ctype)); + + //Timeouts + RequestConfig requestConfig = RequestConfig + .custom() + .setSocketTimeout(socketTimeout * 1000) + .setConnectTimeout(connectTimeout * 1000) + .build(); + post.setConfig(requestConfig); + + //Client 4.3+ + //Execute & GetResponse + try (CloseableHttpClient client = HttpClients.createDefault()) { + CloseableHttpResponse response = client.execute(post); + if (response != null) { + lastResponseCode = response.getStatusLine().getStatusCode(); + HttpEntity entity = response.getEntity(); + lastResponse = (entity != null) ? EntityUtils.toString(entity) : ""; + } else { + lastResponseCode = 900; + lastResponse = ""; + } + } catch (Exception e) { + String error = "Error sending Bpel notification:" + toBpelStr; + LOGGER.error (MessageEnum.RA_SEND_VNF_NOTIF_ERR, error, "Camunda", "", MsoLogger.ErrorCode.AvailabilityError, "Exception sending Bpel notification", e); + lastResponseCode = 900; + lastResponse = ""; + } + LOGGER.debug("Response code from BPEL server: "+lastResponseCode); + LOGGER.debug("Response body is: "+lastResponse); + } + + private String getEncryptedProperty(String key, String defaultValue, String encryptionKey) { + if (env.getProperty(key) != null) { + try { + return CryptoUtils.decrypt(env.getProperty(key), encryptionKey); + } catch (GeneralSecurityException e) { + LOGGER.debug("Exception while decrypting property: " + env.getProperty(key), e); + } + } + return defaultValue; + } + +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/ContrailPolicyRef.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/ContrailPolicyRef.java new file mode 100644 index 0000000000..46fb651afe --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/ContrailPolicyRef.java @@ -0,0 +1,75 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.so.adapters.network; + + +import org.onap.so.logger.MessageEnum; +import org.onap.so.logger.MsoLogger; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; + +public class ContrailPolicyRef { + private static final MsoLogger logger = MsoLogger.getMsoLogger (MsoLogger.Catalog.RA, ContrailPolicyRef.class); + + @JsonProperty("network_policy_refs_data_sequence") + private ContrailPolicyRefSeq seq; + + public JsonNode toJsonNode() + { + JsonNode node = null; + try + { + ObjectMapper mapper = new ObjectMapper(); + node = mapper.convertValue(this, JsonNode.class); + } + catch (Exception e) + { + logger.error (MessageEnum.RA_MARSHING_ERROR, "Error creating JsonString for Contrail Policy Ref", "", "", MsoLogger.ErrorCode.SchemaError, "Exception creating JsonString for Contrail Policy Ref", e); + } + + return node; + } + + public String toJsonString() + { + String jsonString = null; + try + { + ObjectMapper mapper = new ObjectMapper(); + jsonString = mapper.writeValueAsString(this); + } + catch (Exception e) + { + logger.error (MessageEnum.RA_MARSHING_ERROR, "Error creating JsonString for Contrail Policy Ref", "", "", MsoLogger.ErrorCode.SchemaError, "Exception creating JsonString for Contrail Policy Ref", e); + } + + return jsonString; + } + + public void populate(String major, String minor) + { + seq = new ContrailPolicyRefSeq(major, minor); + return; + } + +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/ContrailPolicyRefSeq.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/ContrailPolicyRefSeq.java new file mode 100644 index 0000000000..17d4a743dc --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/ContrailPolicyRefSeq.java @@ -0,0 +1,66 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.so.adapters.network; + + +import com.fasterxml.jackson.annotation.JsonProperty; + +public class ContrailPolicyRefSeq { + + @JsonProperty("network_policy_refs_data_sequence_major") + private String major; + + @JsonProperty("network_policy_refs_data_sequence_minor") + private String minor; + + public ContrailPolicyRefSeq() { + /* To be done */ + } + + public ContrailPolicyRefSeq(String major, String minor) { + super(); + this.major = major; + this.minor = minor; + } + + public String getMajor() { + return major; + } + + public void setMajor(String major) { + this.major = major; + } + + public String getMinor() { + return minor; + } + + public void setMinor(String minor) { + this.minor = minor; + } + + @Override + public String toString() { + return "ContrailPolicyRefSeq [major=" + major + ", minor=" + minor + + "]"; + } + +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/ContrailSubnet.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/ContrailSubnet.java new file mode 100644 index 0000000000..019963b242 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/ContrailSubnet.java @@ -0,0 +1,214 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.so.adapters.network; + +import java.util.ArrayList; +import java.util.List; + +import org.onap.so.logger.MessageEnum; +import org.onap.so.logger.MsoLogger; +import org.onap.so.openstack.beans.HostRoute; +import org.onap.so.openstack.beans.Pool; +import org.onap.so.openstack.beans.Subnet; +import org.onap.so.openstack.utils.MsoCommonUtils; +import org.springframework.beans.factory.annotation.Autowired; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; + +public class ContrailSubnet { + private static final MsoLogger logger = MsoLogger.getMsoLogger (MsoLogger.Catalog.RA, ContrailSubnet.class); + @Autowired + private MsoCommonUtils msoCommonUtils; + + @JsonProperty("network_ipam_refs_data_ipam_subnets_subnet") + private ContrailSubnetIp subnet = new ContrailSubnetIp(); + + @JsonProperty("network_ipam_refs_data_ipam_subnets_default_gateway") + private String defaultGateway; + + @JsonProperty("network_ipam_refs_data_ipam_subnets_subnet_name") + private String subnetName; + + @JsonProperty("network_ipam_refs_data_ipam_subnets_enable_dhcp") + private Boolean enableDhcp; + + @JsonProperty("network_ipam_refs_data_ipam_subnets_addr_from_start") + private Boolean addrFromStart = true; + /** future - leave this commented + private String subnet_uuid; + private String dns_server_address; + private List dns_nameservers; + private String dhcp_option_list; + **/ + + @JsonProperty("network_ipam_refs_data_ipam_subnets_allocation_pools") + private List allocationPools = new ArrayList <> (); + + @JsonProperty("network_ipam_refs_data_ipam_subnets_host_routes") + private final ContrailSubnetHostRoutes host_routes = new ContrailSubnetHostRoutes(); + + public ContrailSubnet() { + super(); + } + + public String getDefaultGateway() { + return defaultGateway; + } + + public void setDefaultGateway(String defaultGateway) { + this.defaultGateway = defaultGateway; + } + + public ContrailSubnetIp getSubnet() { + return subnet; + } + + public void setSubnet(ContrailSubnetIp subnet) { + this.subnet = subnet; + } + + public Boolean isEnableDhcp() { + return enableDhcp; + } + + public void setEnableDhcp(Boolean enableDhcp) { + this.enableDhcp = enableDhcp; + } + + public String getSubnetName() { + return subnetName; + } + + public void setSubnetName(String subnetName) { + this.subnetName = subnetName; + } + + public List getAllocationPools() { + return allocationPools; + } + + public void setPools(List allocationPools) { + this.allocationPools = allocationPools; + } + + public Boolean isAddrFromStart() { + return addrFromStart; + } + + public void setAddrFromStart(Boolean addrFromStart) { + this.addrFromStart = addrFromStart; + } + + public JsonNode toJsonNode() + { + JsonNode node = null; + try + { + ObjectMapper mapper = new ObjectMapper(); + node = mapper.convertValue(this, JsonNode.class); + } + catch (Exception e) + { + String error = "Error creating JsonNode for Contrail Subnet:" + subnetName; + logger.error (MessageEnum.RA_MARSHING_ERROR, error, "", "", MsoLogger.ErrorCode.SchemaError, "Exception creating JsonNode for Contrail Subnet", e); + } + + return node; + } + + public String toJsonString() + { + String jsonString = null; + try + { + ObjectMapper mapper = new ObjectMapper(); + jsonString = mapper.writeValueAsString(this); + } + catch (Exception e) + { + String error = "Error creating JsonString for Contrail Subnet:" + subnetName; + logger.error (MessageEnum.RA_MARSHING_ERROR, error, "", "", MsoLogger.ErrorCode.SchemaError, "Exception creating JsonString for Contrail Subnet", e); + } + + return jsonString; + } + //poulate contrail subnet with input(from bopel) subnet + public void populateWith(Subnet inputSubnet) + { + if (inputSubnet != null) + { + if (!msoCommonUtils.isNullOrEmpty(inputSubnet.getSubnetName())) + subnetName = inputSubnet.getSubnetName(); + else + subnetName = inputSubnet.getSubnetId(); + enableDhcp = inputSubnet.getEnableDHCP(); + defaultGateway = inputSubnet.getGatewayIp(); + if (!msoCommonUtils.isNullOrEmpty(inputSubnet.getCidr()) ) + { + int idx = inputSubnet.getCidr().indexOf("/"); + if (idx != -1) + { + subnet.setIpPrefix(inputSubnet.getCidr().substring(0, idx)); + subnet.setIpPrefixLen(inputSubnet.getCidr().substring(idx+1)); + } + } + if (inputSubnet.getAllocationPools() != null) + { + for (Pool pool : inputSubnet.getAllocationPools()) + { + if ( !msoCommonUtils.isNullOrEmpty(pool.getStart()) && !msoCommonUtils.isNullOrEmpty(pool.getEnd()) ) + { + ContrailSubnetPool csp = new ContrailSubnetPool(); + csp.populateWith(pool); + allocationPools.add (csp); + } + } + } + if (inputSubnet.getHostRoutes() != null) + { + List hrList = host_routes.getHost_routes(); + for (HostRoute hr : inputSubnet.getHostRoutes()) + { + if ( !msoCommonUtils.isNullOrEmpty(hr.getPrefix()) || !msoCommonUtils.isNullOrEmpty(hr.getNextHop()) ) + { + ContrailSubnetHostRoute cshr = new ContrailSubnetHostRoute(); + cshr.populateWith(hr); + hrList.add (cshr); + } + } + } + } + } + + @Override + public String toString() { + StringBuilder buf = new StringBuilder (); + for (ContrailSubnetPool pool : allocationPools) + { + buf.append(pool.toString()); + } + return "ContrailSubnet [subnet=" + subnet.toString() + " default_gateway=" + defaultGateway + + " enable_dhcp=" + enableDhcp + " addr_from_start=" + addrFromStart + " subnet_name=" + subnetName + " allocation_pools=" + buf + " ]"; + } + +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/ContrailSubnetHostRoute.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/ContrailSubnetHostRoute.java new file mode 100644 index 0000000000..d938306c48 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/ContrailSubnetHostRoute.java @@ -0,0 +1,67 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.so.adapters.network; + + +import org.onap.so.openstack.beans.HostRoute; +import com.fasterxml.jackson.annotation.JsonProperty; +public class ContrailSubnetHostRoute { + + @JsonProperty("network_ipam_refs_data_ipam_subnets_host_routes_route_prefix") + private String prefix; + + @JsonProperty("network_ipam_refs_data_ipam_subnets_host_routes_route_next_hop") + private String nextHop; + + public ContrailSubnetHostRoute() { + } + + public String getPrefix() { + return prefix; + } + + public void setPrefix(String prefix) { + this.prefix = prefix; + } + + public String getNextHop() { + return nextHop; + } + + public void setNextHop(String nextHop) { + this.nextHop = nextHop; + } + + public void populateWith(HostRoute hostRoute) + { + if (hostRoute != null) + { + prefix = hostRoute.getPrefix(); + nextHop = hostRoute.getNextHop(); + } + } + + @Override + public String toString() { + return "ContrailSubnetHostRoute [prefix=" + prefix + ", nextHop=" + nextHop + "]"; + } + +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/ContrailSubnetHostRoutes.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/ContrailSubnetHostRoutes.java new file mode 100644 index 0000000000..9b07e20267 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/ContrailSubnetHostRoutes.java @@ -0,0 +1,58 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.so.adapters.network; + + +import org.onap.so.openstack.beans.HostRoute; + +import java.util.ArrayList; +import java.util.List; + +import com.fasterxml.jackson.annotation.JsonProperty; +public class ContrailSubnetHostRoutes { + + @JsonProperty("network_ipam_refs_data_ipam_subnets_host_routes_route") + private List host_routes = new ArrayList (); + + public ContrailSubnetHostRoutes() { + } + + public List getHost_routes() { + return host_routes; + } + + public void setHost_routes(List host_routes) { + this.host_routes = host_routes; + } + + @Override + public String toString() { + StringBuilder buf = new StringBuilder (); + if (host_routes != null) + { + for (ContrailSubnetHostRoute hr : host_routes) + { + buf.append(hr.toString()); + } + } + return "ContrailSubnetHostRoutes [" + buf.toString() + "]"; + } +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/ContrailSubnetIp.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/ContrailSubnetIp.java new file mode 100644 index 0000000000..91d089eb33 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/ContrailSubnetIp.java @@ -0,0 +1,59 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.so.adapters.network; + + +import com.fasterxml.jackson.annotation.JsonProperty; + +public class ContrailSubnetIp { + + @JsonProperty("network_ipam_refs_data_ipam_subnets_subnet_ip_prefix") + private String ipPrefix; + + @JsonProperty("network_ipam_refs_data_ipam_subnets_subnet_ip_prefix_len") + private String ipPrefixLen; + + public ContrailSubnetIp() { + /* Empty constructor */ + } + + public String getIpPrefix() { + return ipPrefix; + } + + public void setIpPrefix(String ipPrefix) { + this.ipPrefix = ipPrefix; + } + + public String getIpPrefixLen() { + return ipPrefixLen; + } + + public void setIpPrefixLen(String ipPrefixLen) { + this.ipPrefixLen = ipPrefixLen; + } + + @Override + public String toString() { + return "ContrailSubnetIp [ip_prefix=" + ipPrefix + ", ip_prefix_len=" + ipPrefixLen + "]"; + } + +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/ContrailSubnetPool.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/ContrailSubnetPool.java new file mode 100644 index 0000000000..710d0cc8fd --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/ContrailSubnetPool.java @@ -0,0 +1,68 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.so.adapters.network; + + +import org.onap.so.openstack.beans.Pool; +import com.fasterxml.jackson.annotation.JsonProperty; +public class ContrailSubnetPool { + + @JsonProperty("network_ipam_refs_data_ipam_subnets_allocation_pools_start") + private String start; + + @JsonProperty("network_ipam_refs_data_ipam_subnets_allocation_pools_end") + private String end; + + public ContrailSubnetPool() { + /* Empty constructor */ + } + + public String getStart() { + return start; + } + + public void setStart(String start) { + this.start = start; + } + + public String getEnd() { + return end; + } + + public void setEnd(String end) { + this.end = end; + } + + public void populateWith(Pool pool) + { + if (pool != null) + { + start = pool.getStart(); + end = pool.getEnd(); + } + } + + @Override + public String toString() { + return "ContrailSubnetPool [start=" + start + ", end=" + end + "]"; + } + +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/MsoNetworkAdapter.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/MsoNetworkAdapter.java new file mode 100644 index 0000000000..27829a6156 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/MsoNetworkAdapter.java @@ -0,0 +1,222 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.so.adapters.network; + + +import java.util.List; +import java.util.Map; + +import javax.jws.WebMethod; +import javax.jws.WebParam; +import javax.jws.WebParam.Mode; +import javax.jws.WebService; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.ws.Holder; + +import org.onap.so.adapters.network.exceptions.NetworkException; +import org.onap.so.entity.MsoRequest; +import org.onap.so.openstack.beans.NetworkRollback; +import org.onap.so.openstack.beans.NetworkStatus; +import org.onap.so.openstack.beans.RouteTarget; +import org.onap.so.openstack.beans.Subnet; + +@WebService (name="NetworkAdapter", targetNamespace="http://org.onap.so/network") +public interface MsoNetworkAdapter +{ + // TODO: Rename all of these to include Vlan in the service name? At least for the + // create and update calls, since they are specific to VLAN-based provider networks. + + /** + * This is the "Create Network" Web Service Endpoint definition. + */ + @WebMethod + public void createNetwork (@WebParam(name="cloudSiteId") @XmlElement(required=true) String cloudSiteId, + @WebParam(name="tenantId") @XmlElement(required=true) String tenantId, + @WebParam(name="networkType") @XmlElement(required=true) String networkType, + @WebParam(name="modelCustomizationUuid") String modelCustomizationUuid, + @WebParam(name="networkName") @XmlElement(required=true) String networkName, + @WebParam(name="physicalNetworkName") String physicalNetworkName, + @WebParam(name="vlans") List vlans, + @WebParam(name="failIfExists") Boolean failIfExists, + @WebParam(name="backout") Boolean backout, + @WebParam(name="subnets") List subnets, + @WebParam(name="request") MsoRequest msoRequest, + @WebParam(name="networkId", mode=Mode.OUT) Holder networkId, + @WebParam(name="neutronNetworkId", mode=Mode.OUT) Holder neutronNetworkId, + @WebParam(name="subnetIdMap", mode=Mode.OUT) Holder> subnetIdMap, + @WebParam(name="rollback", mode=Mode.OUT) Holder rollback ) + throws NetworkException; + + @WebMethod + public void createNetworkContrail (@WebParam(name="cloudSiteId") @XmlElement(required=true) String cloudSiteId, + @WebParam(name="tenantId") @XmlElement(required=true) String tenantId, + @WebParam(name="networkType") @XmlElement(required=true) String networkType, + @WebParam(name="modelCustomizationUuid") String modelCustomizationUuid, + @WebParam(name="networkName") @XmlElement(required=true) String networkName, + @WebParam(name="routeTargets") List routeTargets, + @WebParam(name="shared") String shared, + @WebParam(name="external") String external, + @WebParam(name="failIfExists") Boolean failIfExists, + @WebParam(name="backout") Boolean backout, + @WebParam(name="subnets") List subnets, + @WebParam(name="policyFqdns") List policyFqdns, + @WebParam(name="routeTableFqdns") List routeTableFqdns, + @WebParam(name="request") MsoRequest msoRequest, + @WebParam(name="networkId", mode=Mode.OUT) Holder networkId, + @WebParam(name="neutronNetworkId", mode=Mode.OUT) Holder neutronNetworkId, + @WebParam(name="networkFqdn", mode=Mode.OUT) Holder networkFqdn, + @WebParam(name="subnetIdMap", mode=Mode.OUT) Holder> subnetIdMap, + @WebParam(name="rollback", mode=Mode.OUT) Holder rollback ) + throws NetworkException; + + /** + * This is the "Update VLANs" Web Service Endpoint definition. + * This webservice replaces the set of VLANs on a network. + */ + @WebMethod + public void updateNetwork (@WebParam(name="cloudSiteId") @XmlElement(required=true) String cloudSiteId, + @WebParam(name="tenantId") @XmlElement(required=true) String tenantId, + @WebParam(name="networkType") @XmlElement(required=true) String networkType, + @WebParam(name="modelCustomizationUuid") String modelCustomizationUuid, + @WebParam(name="networkId") @XmlElement(required=true) String networkId, + @WebParam(name="networkName") @XmlElement(required=true) String networkName, + @WebParam(name="physicalNetworkName") @XmlElement(required=true) String physicalNetworkName, + @WebParam(name="vlans") @XmlElement(required=true) List vlans, + @WebParam(name="subnets") List subnets, + @WebParam(name="request") MsoRequest msoRequest, + @WebParam(name="subnetIdMap", mode=Mode.OUT) Holder> subnetIdMap, + @WebParam(name="rollback", mode=Mode.OUT) Holder rollback ) + throws NetworkException; + + @WebMethod + public void updateNetworkContrail (@WebParam(name="cloudSiteId") @XmlElement(required=true) String cloudSiteId, + @WebParam(name="tenantId") @XmlElement(required=true) String tenantId, + @WebParam(name="networkType") @XmlElement(required=true) String networkType, + @WebParam(name="modelCustomizationUuid") String modelCustomizationUuid, + @WebParam(name="networkId") @XmlElement(required=true) String networkId, + @WebParam(name="networkName") @XmlElement(required=true) String networkName, + @WebParam(name="routeTargets") List routeTargets, + @WebParam(name="shared") String shared, + @WebParam(name="external") String external, + @WebParam(name="subnets") List subnets, + @WebParam(name="policyFqdns") List policyFqdns, + @WebParam(name="routeTableFqdns") List routeTableFqdns, + @WebParam(name="request") MsoRequest msoRequest, + @WebParam(name="subnetIdMap", mode=Mode.OUT) Holder> subnetIdMap, + @WebParam(name="rollback", mode=Mode.OUT) Holder rollback ) + throws NetworkException; + + /** + * TODO: + * This is the "Add VLAN" Web Service Endpoint definition. + * This webservice adds a VLAN to a network. + * This service assumes that PO supports querying the current vlans in real time. + * Otherwise, the caller must have the complete list and should use updateVlans instead. + @WebMethod + public void addVlan (@WebParam(name="cloudSiteId") @XmlElement(required=true) String cloudSiteId, + @WebParam(name="tenantId") @XmlElement(required=true) String tenantId, + @WebParam(name="networkType") @XmlElement(required=true) String networkType, + @WebParam(name="networkId") @XmlElement(required=true) String networkId, + @WebParam(name="physicalNetworkName") @XmlElement(required=true) String physicalNetworkName, + @WebParam(name="vlan") @XmlElement(required=true) Integer vlan, + @WebParam(name="rollback", mode=Mode.OUT) Holder rollback ) + throws NetworkException; + */ + + /** + * TODO: + * This is the "Remove VLAN" Web Service Endpoint definition. + * This webservice removes a VLAN from a network. + * This service assumes that PO supports querying the current vlans in real time. + * Otherwise, the caller must have the complete list and should use updateVlans instead. + * + * This service returns an indicator (noMoreVLans) if the VLAN that was removed was + * the last one on the network. + * + * It is not clear that Rollback will work for delete. The network can be + * recreated from the NetworkRollback object, but the network ID (and stack ID + * for Heat-based orchestration) will be different. The caller will need to know + * to update these identifiers in the inventory DB (A&AI). + @WebMethod + public void removeVlan (@WebParam(name="cloudSiteId") @XmlElement(required=true) String cloudSiteId, + @WebParam(name="tenantId") @XmlElement(required=true) String tenantId, + @WebParam(name="networkType") @XmlElement(required=true) String networkType, + @WebParam(name="networkId") @XmlElement(required=true) String networkId, + @WebParam(name="physicalNetworkName") @XmlElement(required=true) String physicalNetworkName, + @WebParam(name="vlan") @XmlElement(required=true) Integer vlan, + @WebParam(name="noMoreVlans", mode=Mode.OUT) Holder noMoreVlans, + @WebParam(name="rollback", mode=Mode.OUT) Holder rollback ) + throws NetworkException; + */ + + /** + * This is the "Query Network" Web Service Endpoint definition. + * TODO: Should this just return the NetworkInfo complete structure? + */ + @WebMethod + public void queryNetwork (@WebParam(name="cloudSiteId") @XmlElement(required=true) String cloudSiteId, + @WebParam(name="tenantId") @XmlElement(required=true) String tenantId, + @WebParam(name="networkNameOrId") @XmlElement(required=true) String networkNameOrId, + @WebParam(name="request") MsoRequest msoRequest, + @WebParam(name="networkExists", mode=Mode.OUT) Holder networkExists, + @WebParam(name="networkId", mode=Mode.OUT) Holder networkId, + @WebParam(name="neutronNetworkId", mode=Mode.OUT) Holder neutronNetworkId, + @WebParam(name="status", mode=Mode.OUT) Holder status, + @WebParam(name="vlans", mode=Mode.OUT) Holder> vlans, + @WebParam(name="subnetIdMap", mode=Mode.OUT) Holder> subnetIdMap) + throws NetworkException; + + @WebMethod + public void queryNetworkContrail (@WebParam(name="cloudSiteId") @XmlElement(required=true) String cloudSiteId, + @WebParam(name="tenantId") @XmlElement(required=true) String tenantId, + @WebParam(name="networkNameOrId") @XmlElement(required=true) String networkNameOrId, + @WebParam(name="request") MsoRequest msoRequest, + @WebParam(name="networkExists", mode=Mode.OUT) Holder networkExists, + @WebParam(name="networkId", mode=Mode.OUT) Holder networkId, + @WebParam(name="neutronNetworkId", mode=Mode.OUT) Holder neutronNetworkId, + @WebParam(name="status", mode=Mode.OUT) Holder status, + @WebParam(name="routeTargets", mode=Mode.OUT) Holder> routeTargets, + @WebParam(name="subnetIdMap", mode=Mode.OUT) Holder> subnetIdMap) + throws NetworkException; + + /** + * This is the "Delete Network" Web Service endpoint definition. + */ + @WebMethod + public void deleteNetwork (@WebParam(name="cloudSiteId") @XmlElement(required=true) String cloudSiteId, + @WebParam(name="tenantId") @XmlElement(required=true) String tenantId, + @WebParam(name="networkType") @XmlElement(required=true) String networkType, + @WebParam(name="modelCustomizationUuid") String modelCustomizationUuid, + @WebParam(name="networkId") @XmlElement(required=true) String networkId, + @WebParam(name="request") MsoRequest msoRequest, + @WebParam(name="networkDeleted", mode=Mode.OUT) Holder networkDeleted) + throws NetworkException; + + /** + * This is the "Rollback Network" Web Service endpoint definition. + */ + @WebMethod + public void rollbackNetwork (@WebParam(name="rollback") @XmlElement(required=true) NetworkRollback rollback) + throws NetworkException; + + @WebMethod + public void healthCheck (); +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/MsoNetworkAdapterAsync.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/MsoNetworkAdapterAsync.java new file mode 100644 index 0000000000..99f590b773 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/MsoNetworkAdapterAsync.java @@ -0,0 +1,106 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.so.adapters.network; + + +import java.util.List; + +import javax.jws.Oneway; +import javax.jws.WebMethod; +import javax.jws.WebParam; +import javax.jws.WebService; +import javax.xml.bind.annotation.XmlElement; + +import org.onap.so.entity.MsoRequest; +import org.onap.so.openstack.beans.NetworkRollback; +import org.onap.so.openstack.beans.Subnet; +/** + * This webservice defines the Asynchronous versions of NETWORK adapter calls. + * The notification messages for final responses are documented elsewhere + * (by the client service WSDL). + * + */ +@WebService (name="NetworkAdapterAsync", targetNamespace="http://org.onap.so/networkA") +public interface MsoNetworkAdapterAsync +{ + /** + * This is the "Create NETWORK" Web Service Endpoint definition. + */ + @WebMethod + @Oneway + public void createNetworkA (@WebParam(name="cloudSiteId") @XmlElement(required=true) String cloudSiteId, + @WebParam(name="tenantId") @XmlElement(required=true) String tenantId, + @WebParam(name="networkType") @XmlElement(required=true) String networkType, + @WebParam(name="modelCustomizationUuid") String modelCustomizationUuid, + @WebParam(name="networkName") @XmlElement(required=true) String networkName, + @WebParam(name="physicalNetworkName") String physicalNetworkName, + @WebParam(name="vlans") List vlans, + @WebParam(name="failIfExists") Boolean failIfExists, + @WebParam(name="backout") Boolean backout, + @WebParam(name="subnets") List subnets, + @WebParam(name="messageId") @XmlElement(required=true) String messageId, + @WebParam(name="request") MsoRequest msoRequest, + @WebParam(name="notificationUrl") @XmlElement(required=true) String notificationUrl ); + + @WebMethod + @Oneway + public void updateNetworkA (@WebParam(name="cloudSiteId") @XmlElement(required=true) String cloudSiteId, + @WebParam(name="tenantId") @XmlElement(required=true) String tenantId, + @WebParam(name="networkType") @XmlElement(required=true) String networkType, + @WebParam(name="modelCustomizationUuid") String modelCustomizationUuid, + @WebParam(name="networkId") @XmlElement(required=true) String networkId, + @WebParam(name="networkName") @XmlElement(required=true) String networkName, + @WebParam(name="physicalNetworkName") @XmlElement(required=true) String physicalNetworkName, + @WebParam(name="vlans") @XmlElement(required=true) List vlans, + @WebParam(name="subnets") List subnets, + @WebParam(name="messageId") @XmlElement(required=true) String messageId, + @WebParam(name="request") MsoRequest msoRequest, + @WebParam(name="notificationUrl") @XmlElement(required=true) String notificationUrl ); + + @WebMethod + @Oneway + public void queryNetworkA (@WebParam(name="cloudSiteId") @XmlElement(required=true) String cloudSiteId, + @WebParam(name="tenantId") @XmlElement(required=true) String tenantId, + @WebParam(name="networkNameOrId") @XmlElement(required=true) String networkNameOrId, + @WebParam(name="messageId") @XmlElement(required=true) String messageId, + @WebParam(name="request") MsoRequest msoRequest, + @WebParam(name="notificationUrl") @XmlElement(required=true) String notificationUrl ); + + @WebMethod + @Oneway + public void deleteNetworkA (@WebParam(name="cloudSiteId") @XmlElement(required=true) String cloudSiteId, + @WebParam(name="tenantId") @XmlElement(required=true) String tenantId, + @WebParam(name="networkType") @XmlElement(required=true) String networkType, + @WebParam(name="modelCustomizationUuid") String modelCustomizationUuid, + @WebParam(name="networkId") @XmlElement(required=true) String networkId, + @WebParam(name="messageId") @XmlElement(required=true) String messageId, + @WebParam(name="request") MsoRequest msoRequest, + @WebParam(name="notificationUrl") @XmlElement(required=true) String notificationUrl ); + + @WebMethod + @Oneway + public void rollbackNetworkA (@WebParam(name="rollback") @XmlElement(required=true) NetworkRollback rollback, + @WebParam(name="messageId") @XmlElement(required=true) String messageId, + @WebParam(name="notificationUrl") @XmlElement(required=true) String notificationUrl ); + + @WebMethod + public void healthCheckA (); +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/MsoNetworkAdapterAsyncImpl.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/MsoNetworkAdapterAsyncImpl.java new file mode 100644 index 0000000000..b483d40b8a --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/MsoNetworkAdapterAsyncImpl.java @@ -0,0 +1,698 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * Copyright (C) 2017 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.so.adapters.network; + + +import java.net.MalformedURLException; +import java.net.URL; +import java.security.GeneralSecurityException; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.jws.WebService; +import javax.xml.bind.DatatypeConverter; +import javax.xml.namespace.QName; +import javax.xml.ws.BindingProvider; +import javax.xml.ws.Holder; +import javax.xml.ws.handler.MessageContext; + +import org.onap.so.adapters.network.async.client.CreateNetworkNotification; +import org.onap.so.adapters.network.async.client.MsoExceptionCategory; +import org.onap.so.adapters.network.async.client.NetworkAdapterNotify; +import org.onap.so.adapters.network.async.client.NetworkAdapterNotify_Service; +import org.onap.so.adapters.network.async.client.QueryNetworkNotification; +import org.onap.so.adapters.network.async.client.UpdateNetworkNotification; +import org.onap.so.adapters.network.exceptions.NetworkException; +import org.onap.so.entity.MsoRequest; +import org.onap.so.logger.MessageEnum; +import org.onap.so.logger.MsoAlarmLogger; +import org.onap.so.logger.MsoLogger; +import org.onap.so.openstack.beans.NetworkRollback; +import org.onap.so.openstack.beans.NetworkStatus; +import org.onap.so.openstack.beans.Subnet; +import org.onap.so.utils.CryptoUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.env.Environment; +import org.springframework.stereotype.Component; + +@Component +@WebService(serviceName = "NetworkAdapterAsync", endpointInterface = "org.onap.so.adapters.network.MsoNetworkAdapterAsync", targetNamespace = "http://org.onap.so/networkA") +public class MsoNetworkAdapterAsyncImpl implements MsoNetworkAdapterAsync { + + private static final MsoLogger LOGGER = MsoLogger.getMsoLogger (MsoLogger.Catalog.RA,MsoNetworkAdapterAsyncImpl.class); + private static final MsoAlarmLogger alarmLogger = new MsoAlarmLogger (); + private static final String BPEL_AUTH_PROP = "org.onap.so.adapters.network.bpelauth"; + private static final String ENCRYPTION_KEY = "aa3871669d893c7fb8abbcda31b88b4f"; + + @Autowired + private Environment environment; + + @Autowired + private MsoNetworkAdapter networkAdapter; + /** + * Health Check web method. Does nothing but return to show the adapter is deployed. + */ + @Override + public void healthCheckA () { + LOGGER.debug ("Health check call in Network Adapter"); + } + + /** + * This is the "Create Network" web service implementation. + * It will create a new Network of the requested type in the specified cloud + * and tenant. The tenant must exist at the time this service is called. + * + * If a network with the same name already exists, this can be considered a + * success or failure, depending on the value of the 'failIfExists' parameter. + * + * There will be a pre-defined set of network types defined in the MSO Catalog. + * All such networks will have a similar configuration, based on the allowable + * Openstack networking definitions. This includes basic networks, provider + * networks (with a single VLAN), and multi-provider networks (one or more VLANs) + * + * Initially, all provider networks must be "vlan" type, and multiple segments in + * a multi-provider network must be multiple VLANs on the same physical network. + * + * This service supports two modes of Network creation/update: + * - via Heat Templates + * - via Neutron API + * The network orchestration mode for each network type is declared in its + * catalog definition. All Heat-based templates must support some subset of + * the same input parameters: network_name, physical_network, vlan(s). + * + * The method returns the network ID and a NetworkRollback object. This latter + * object can be passed as-is to the rollbackNetwork operation to undo everything + * that was created. This is useful if a network is successfully created but + * the orchestration fails on a subsequent operation. + */ + @Override + public void createNetworkA (String cloudSiteId, + String tenantId, + String networkType, + String modelCustomizationUuid, + String networkName, + String physicalNetworkName, + List vlans, + Boolean failIfExists, + Boolean backout, + List subnets, + String messageId, + MsoRequest msoRequest, + String notificationUrl) { + String error; + + MsoLogger.setLogContext (msoRequest); + MsoLogger.setServiceName ("CreateNetworkA"); + LOGGER.debug ("Async Create Network: " + networkName + + " of type " + + networkType + + " in " + + cloudSiteId + + "/" + + tenantId); + + // Use the synchronous method to perform the actual Create + + + // Synchronous Web Service Outputs + Holder networkId = new Holder <> (); + Holder neutronNetworkId = new Holder <> (); + Holder networkRollback = new Holder <> (); + Holder > subnetIdMap = new Holder <> (); + + try { + networkAdapter.createNetwork (cloudSiteId, + tenantId, + networkType, + modelCustomizationUuid, + networkName, + physicalNetworkName, + vlans, + failIfExists, + backout, + subnets, + msoRequest, + networkId, + neutronNetworkId, + subnetIdMap, + networkRollback); + } catch (NetworkException e) { + LOGGER.debug ("Got a NetworkException on createNetwork: ", e); + MsoExceptionCategory exCat = null; + String eMsg = null; + try { + eMsg = e.getFaultInfo ().getMessage (); + exCat = MsoExceptionCategory.fromValue (e.getFaultInfo ().getCategory ().name ()); + } catch (Exception e1) { + LOGGER.error (MessageEnum.RA_FAULT_INFO_EXC, "", "", MsoLogger.ErrorCode.DataError, "Exception - fault info", e1); + } + // Build and send Asynchronous error response + try { + NetworkAdapterNotify notifyPort = getNotifyEP (notificationUrl); + notifyPort.createNetworkNotification (messageId, false, exCat, eMsg, null, null, null, null); + } catch (Exception e1) { + error = "Error sending createNetwork notification " + e1.getMessage (); + LOGGER.error (MessageEnum.RA_CREATE_NETWORK_NOTIF_EXC, "", "", MsoLogger.ErrorCode.DataError, "Exception sending createNetwork notification", e1); + alarmLogger.sendAlarm ("MsoInternalError", MsoAlarmLogger.CRITICAL, error); + } + return; + } + LOGGER.debug ("Async Create Network:Name " + networkName + " physicalNetworkName:" + physicalNetworkName); + // Build and send Asynchronous response + try { + NetworkAdapterNotify notifyPort = getNotifyEP (notificationUrl); + notifyPort.createNetworkNotification (messageId, + true, + null, + null, + networkId.value, + neutronNetworkId.value, + copyCreateSubnetIdMap (subnetIdMap), + copyNrb (networkRollback)); + } catch (Exception e) { + error = "Error sending createNetwork notification " + e.getMessage (); + LOGGER.error (MessageEnum.RA_CREATE_NETWORK_NOTIF_EXC, "", "", MsoLogger.ErrorCode.DataError, "Exception sending createNetwork notification", e); + alarmLogger.sendAlarm ("MsoInternalError", MsoAlarmLogger.CRITICAL, error); + } + return; + } + + /** + * This is the "Update Network" web service implementation. + * It will update an existing Network of the requested type in the specified cloud + * and tenant. The typical use will be to replace the VLANs with the supplied + * list (to add or remove a VLAN), but other properties may be updated as well. + * + * There will be a pre-defined set of network types defined in the MSO Catalog. + * All such networks will have a similar configuration, based on the allowable + * Openstack networking definitions. This includes basic networks, provider + * networks (with a single VLAN), and multi-provider networks (one or more VLANs). + * + * Initially, all provider networks must currently be "vlan" type, and multi-provider + * networks must be multiple VLANs on the same physical network. + * + * This service supports two modes of Network update: + * - via Heat Templates + * - via Neutron API + * The network orchestration mode for each network type is declared in its + * catalog definition. All Heat-based templates must support some subset of + * the same input parameters: network_name, physical_network, vlan, segments. + * + * The method returns a NetworkRollback object. This object can be passed + * as-is to the rollbackNetwork operation to undo everything that was updated. + * This is useful if a network is successfully updated but orchestration + * fails on a subsequent operation. + */ + @Override + public void updateNetworkA (String cloudSiteId, + String tenantId, + String networkType, + String modelCustomizationUuid, + String networkId, + String networkName, + String physicalNetworkName, + List vlans, + List subnets, + String messageId, + MsoRequest msoRequest, + String notificationUrl) { + String error; + + String serviceName = "UpdateNetworkA"; + MsoLogger.setServiceName (serviceName); + MsoLogger.setLogContext (msoRequest); + LOGGER.debug ("Async Update Network: " + networkId + + " of type " + + networkType + + "in " + + cloudSiteId + + "/" + + tenantId); + + // Use the synchronous method to perform the actual Create + + + // Synchronous Web Service Outputs + Holder networkRollback = new Holder <> (); + Holder > subnetIdMap = new Holder <> (); + + try { + networkAdapter.updateNetwork (cloudSiteId, + tenantId, + networkType, + modelCustomizationUuid, + networkId, + networkName, + physicalNetworkName, + vlans, + subnets, + msoRequest, + subnetIdMap, + networkRollback); + MsoLogger.setServiceName (serviceName); + } catch (NetworkException e) { + MsoLogger.setServiceName (serviceName); + LOGGER.debug ("Got a NetworkException on updateNetwork: ", e); + MsoExceptionCategory exCat = null; + String eMsg = null; + try { + eMsg = e.getFaultInfo ().getMessage (); + exCat = MsoExceptionCategory.fromValue (e.getFaultInfo ().getCategory ().name ()); + } catch (Exception e1) { + LOGGER.error (MessageEnum.RA_FAULT_INFO_EXC, "", "", MsoLogger.ErrorCode.DataError, "Exception - fault info", e1); + } + // Build and send Asynchronous error response + try { + NetworkAdapterNotify notifyPort = getNotifyEP (notificationUrl); + notifyPort.updateNetworkNotification (messageId, false, exCat, eMsg, null, copyNrb (networkRollback)); + } catch (Exception e1) { + error = "Error sending updateNetwork notification " + e1.getMessage (); + LOGGER.error (MessageEnum.RA_CREATE_NETWORK_NOTIF_EXC, "", "", MsoLogger.ErrorCode.DataError, "Exception sending updateNetwork notification", e1); + alarmLogger.sendAlarm ("MsoInternalError", MsoAlarmLogger.CRITICAL, error); + } + return; + } + LOGGER.debug ("Async Update Network:Name " + networkName + " NetworkId:" + networkId); + // Build and send Asynchronous response + try { + NetworkAdapterNotify notifyPort = getNotifyEP (notificationUrl); + notifyPort.updateNetworkNotification (messageId, + true, + null, + null, + copyUpdateSubnetIdMap (subnetIdMap), + copyNrb (networkRollback)); + } catch (Exception e) { + error = "Error sending updateNotification request" + e.getMessage (); + LOGGER.error (MessageEnum.RA_CREATE_NETWORK_NOTIF_EXC, "", "", MsoLogger.ErrorCode.DataError, "Exception sending updateNotification request", e); + alarmLogger.sendAlarm ("MsoInternalError", MsoAlarmLogger.CRITICAL, error); + } + return; + } + + /** + * This is the queryNetwork method. It returns the existence and status of + * the specified network, along with its Neutron UUID and list of VLANs. + * This method attempts to find the network using both Heat and Neutron. + * Heat stacks are first searched based on the provided network name/id. + * If none is found, the Neutron is directly queried. + */ + @Override + public void queryNetworkA (String cloudSiteId, + String tenantId, + String networkNameOrId, + String messageId, + MsoRequest msoRequest, + String notificationUrl) { + String error; + + MsoLogger.setLogContext (msoRequest); + String serviceName = "QueryNetworkA"; + MsoLogger.setServiceName (serviceName); + LOGGER.debug ("Async Query Network " + networkNameOrId + " in " + cloudSiteId + "/" + tenantId); + + // Use the synchronous method to perform the actual Create + + + // Synchronous Web Service Outputs + Holder networkExists = new Holder <> (); + Holder networkId = new Holder <> (); + Holder neutronNetworkId = new Holder <> (); + Holder status = new Holder <> (); + Holder > vlans = new Holder <> (); + Holder > subnetIdMap = new Holder <> (); + + try { + networkAdapter.queryNetwork (cloudSiteId, + tenantId, + networkNameOrId, + msoRequest, + networkExists, + networkId, + neutronNetworkId, + status, + vlans, + subnetIdMap); + MsoLogger.setServiceName (serviceName); + } catch (NetworkException e) { + MsoLogger.setServiceName (serviceName); + LOGGER.debug ("Got a NetworkException on createNetwork: ", e); + MsoExceptionCategory exCat = null; + String eMsg = null; + try { + eMsg = e.getFaultInfo ().getMessage (); + exCat = MsoExceptionCategory.fromValue (e.getFaultInfo ().getCategory ().name ()); + } catch (Exception e1) { + LOGGER.error (MessageEnum.RA_FAULT_INFO_EXC, "", "", MsoLogger.ErrorCode.DataError, "Exception - fault info", e1); + } + // Build and send Asynchronous error response + try { + NetworkAdapterNotify notifyPort = getNotifyEP (notificationUrl); + notifyPort.queryNetworkNotification (messageId, false, exCat, eMsg, null, null, null, null, null, null); + } catch (Exception e1) { + error = "Error sending createNetwork notification " + e1.getMessage (); + LOGGER.error (MessageEnum.RA_CREATE_NETWORK_NOTIF_EXC, "", "", MsoLogger.ErrorCode.DataError, "Exception sending createNetwork notification", e1); + alarmLogger.sendAlarm ("MsoInternalError", MsoAlarmLogger.CRITICAL, error); + } + return; + } + LOGGER.debug ("Async Query Network:NameOrId " + networkNameOrId + " tenantId:" + tenantId); + // Build and send Asynchronous response + try { + NetworkAdapterNotify notifyPort = getNotifyEP (notificationUrl); + org.onap.so.adapters.network.async.client.NetworkStatus networkS = org.onap.so.adapters.network.async.client.NetworkStatus.fromValue (status.value.name ()); + notifyPort.queryNetworkNotification (messageId, + true, + null, + null, + networkExists.value, + networkId.value, + neutronNetworkId.value, + networkS, + vlans.value, + copyQuerySubnetIdMap (subnetIdMap)); + } catch (Exception e) { + error = "Error sending createNetwork notification " + e.getMessage (); + LOGGER.error (MessageEnum.RA_CREATE_NETWORK_NOTIF_EXC, "", "", MsoLogger.ErrorCode.DataError, "Exception sending createNetwork notification", e); + alarmLogger.sendAlarm ("MsoInternalError", MsoAlarmLogger.CRITICAL, error); + } + return; + } + + /** + * This is the "Delete Network" web service implementation. + * It will delete a Network in the specified cloud and tenant. + * + * If the network is not found, it is treated as a success. + * + * This service supports two modes of Network creation/update/delete: + * - via Heat Templates + * - via Neutron API + * The network orchestration mode for each network type is declared in its + * catalog definition. + * + * For Heat-based orchestration, the networkId should be the stack ID. + * For Neutron-based orchestration, the networkId should be the Neutron network UUID. + * + * The method returns nothing on success. Rollback is not possible for delete + * commands, so any failure on delete will require manual fallout in the client. + */ + @Override + public void deleteNetworkA (String cloudSiteId, + String tenantId, + String networkType, + String modelCustomizationUuid, + String networkId, + String messageId, + MsoRequest msoRequest, + String notificationUrl) { + String error; + MsoLogger.setLogContext (msoRequest); + String serviceName = "DeleteNetworkA"; + MsoLogger.setServiceName (serviceName); + LOGGER.debug ("Async Delete Network " + networkId + " in " + cloudSiteId + "/" + tenantId); + + // Use the synchronous method to perform the actual Create + + + // Synchronous Web Service Outputs + Holder networkDeleted = new Holder <> (); + + try { + networkAdapter.deleteNetwork (cloudSiteId, tenantId, networkType, modelCustomizationUuid, networkId, msoRequest, networkDeleted); + MsoLogger.setServiceName (serviceName); + } catch (NetworkException e) { + MsoLogger.setServiceName (serviceName); + LOGGER.debug ("Got a NetworkException on createNetwork: ", e); + MsoExceptionCategory exCat = null; + String eMsg = null; + try { + eMsg = e.getFaultInfo ().getMessage (); + exCat = MsoExceptionCategory.fromValue (e.getFaultInfo ().getCategory ().name ()); + } catch (Exception e1) { + LOGGER.error (MessageEnum.RA_FAULT_INFO_EXC, "", "", MsoLogger.ErrorCode.DataError, "Exception - fault info", e1); + } + // Build and send Asynchronous error response + try { + NetworkAdapterNotify notifyPort = getNotifyEP (notificationUrl); + notifyPort.deleteNetworkNotification (messageId, false, exCat, eMsg, null); + } catch (Exception e1) { + error = "Error sending createNetwork notification " + e1.getMessage (); + LOGGER.error (MessageEnum.RA_CREATE_NETWORK_NOTIF_EXC, "", "", MsoLogger.ErrorCode.DataError, "Exception sending createNetwork notification", e1); + alarmLogger.sendAlarm ("MsoInternalError", MsoAlarmLogger.CRITICAL, error); + } + return; + } + LOGGER.debug ("Async Delete NetworkId: " + networkId + " tenantId:" + tenantId); + // Build and send Asynchronous response + try { + NetworkAdapterNotify notifyPort = getNotifyEP (notificationUrl); + notifyPort.deleteNetworkNotification (messageId, true, null, null, networkDeleted.value); + } catch (Exception e) { + error = "Error sending deleteNetwork notification " + e.getMessage (); + LOGGER.error (MessageEnum.RA_CREATE_NETWORK_NOTIF_EXC, "", "", MsoLogger.ErrorCode.DataError, "Exception sending deleteNetwork notification", e); + alarmLogger.sendAlarm ("MsoInternalError", MsoAlarmLogger.CRITICAL, error); + } + return; + } + + /** + * 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 rollbackNetwork + * operation to undo the creation. + * + * The rollback includes removing the VNF and deleting the tenant if the + * tenant did not exist prior to the VNF creation. + */ + @Override + public void rollbackNetworkA (NetworkRollback rollback, String messageId, String notificationUrl) { + String error; + String serviceName = "RollbackNetworkA"; + MsoLogger.setServiceName (serviceName); + // rollback may be null (e.g. if network already existed when Create was called) + if (rollback == null) { + LOGGER.warn (MessageEnum.RA_ROLLBACK_NULL, "", "", MsoLogger.ErrorCode.SchemaError, "Rollback is null"); + return; + } + + MsoLogger.setLogContext (rollback.getMsoRequest ()); + LOGGER.info (MessageEnum.RA_ASYNC_ROLLBACK, rollback.getNetworkStackId (), "", ""); + // Use the synchronous method to perform the actual Create + + + try { + networkAdapter.rollbackNetwork (rollback); + MsoLogger.setServiceName (serviceName); + } catch (NetworkException e) { + MsoLogger.setServiceName (serviceName); + LOGGER.debug ("Got a NetworkException on rollbackNetwork: ", e); + // Build and send Asynchronous error response + MsoExceptionCategory exCat = null; + String eMsg = null; + try { + eMsg = e.getFaultInfo ().getMessage (); + exCat = MsoExceptionCategory.fromValue (e.getFaultInfo ().getCategory ().name ()); + } catch (Exception e1) { + LOGGER.error (MessageEnum.RA_FAULT_INFO_EXC, "", "", MsoLogger.ErrorCode.DataError, "Exception in get fault info", e1); + } + // Build and send Asynchronous error response + try { + NetworkAdapterNotify notifyPort = getNotifyEP (notificationUrl); + notifyPort.rollbackNetworkNotification (rollback.getMsoRequest ().getRequestId (), false, exCat, eMsg); + } catch (Exception e1) { + error = "Error sending createNetwork notification " + e1.getMessage (); + LOGGER.error (MessageEnum.RA_CREATE_NETWORK_NOTIF_EXC, "", "", MsoLogger.ErrorCode.DataError, "Exception in sending createNetwork notification ", e1); + alarmLogger.sendAlarm ("MsoInternalError", MsoAlarmLogger.CRITICAL, error); + } + return; + } + LOGGER.debug ("Async Rollback NetworkId: " + rollback.getNetworkStackId () + " tenantId:" + rollback.getTenantId ()); + // Build and send Asynchronous response + try { + NetworkAdapterNotify notifyPort = getNotifyEP (notificationUrl); + notifyPort.rollbackNetworkNotification (rollback.getMsoRequest ().getRequestId (), true, null, null); + } catch (Exception e) { + error = "Error sending rollbackNetwork notification " + e.getMessage (); + LOGGER.error (MessageEnum.RA_CREATE_NETWORK_NOTIF_EXC, "", "", MsoLogger.ErrorCode.DataError, "Exception in sending rollbackNetwork notification", e); + alarmLogger.sendAlarm ("MsoInternalError", MsoAlarmLogger.CRITICAL, error); + } + return; + } + + private org.onap.so.adapters.network.async.client.NetworkRollback copyNrb (Holder hNrb) { + org.onap.so.adapters.network.async.client.NetworkRollback cnrb = new org.onap.so.adapters.network.async.client.NetworkRollback (); + + if (hNrb != null && hNrb.value != null) { + org.onap.so.adapters.network.async.client.MsoRequest cmr = new org.onap.so.adapters.network.async.client.MsoRequest (); + + cnrb.setCloudId (hNrb.value.getCloudId ()); + cmr.setRequestId (hNrb.value.getMsoRequest ().getRequestId ()); + cmr.setServiceInstanceId (hNrb.value.getMsoRequest ().getServiceInstanceId ()); + cnrb.setMsoRequest (cmr); + cnrb.setNetworkId (hNrb.value.getNetworkId ()); + cnrb.setNetworkStackId (hNrb.value.getNetworkStackId ()); + cnrb.setNeutronNetworkId (hNrb.value.getNeutronNetworkId ()); + cnrb.setTenantId (hNrb.value.getTenantId ()); + cnrb.setNetworkType (hNrb.value.getNetworkType ()); + cnrb.setNetworkCreated (hNrb.value.getNetworkCreated ()); + cnrb.setNetworkName (hNrb.value.getNetworkName ()); + cnrb.setPhysicalNetwork (hNrb.value.getPhysicalNetwork ()); + List vlansc = cnrb.getVlans (); + List vlansh = hNrb.value.getVlans (); + if (vlansh != null) { + vlansc.addAll (vlansh); + } + } + return cnrb; + } + + private NetworkAdapterNotify getNotifyEP (String notificationUrl) { + + URL warWsdlLoc = null; + try { + warWsdlLoc = Thread.currentThread ().getContextClassLoader ().getResource ("NetworkAdapterNotify.wsdl"); + } catch (Exception e) { + LOGGER.error (MessageEnum.RA_WSDL_NOT_FOUND, "NetworkAdpaterNotify.wsdl", "", "", MsoLogger.ErrorCode.DataError, "Exception - WSDL not found", e); + } + if (warWsdlLoc == null) { + LOGGER.error (MessageEnum.RA_WSDL_NOT_FOUND, "NetworkAdpaterNotify.wsdl", "", "", MsoLogger.ErrorCode.DataError, "WSDL not found"); + } else { + try { + LOGGER.debug ("NetworkAdpaterNotify.wsdl location:" + warWsdlLoc.toURI ().toString ()); + } catch (Exception e) { + LOGGER.error (MessageEnum.RA_WSDL_URL_CONVENTION_EXC, "NetworkAdpaterNotify.wsdl", "", "", MsoLogger.ErrorCode.SchemaError, "Exception - WSDL URL convention", e); + } + } + + NetworkAdapterNotify_Service notifySvc = new NetworkAdapterNotify_Service (warWsdlLoc, + new QName ("http://org.onap.so/networkNotify", + "networkAdapterNotify")); + + NetworkAdapterNotify notifyPort = notifySvc.getMsoNetworkAdapterAsyncImplPort (); + + BindingProvider bp = (BindingProvider) notifyPort; + + URL epUrl = null; + try { + epUrl = new URL (notificationUrl); + } catch (MalformedURLException e1) { + LOGGER.error (MessageEnum.RA_INIT_NOTIF_EXC, "", "", MsoLogger.ErrorCode.DataError, "Exception - init notification", e1); + } + + if(null != epUrl) { + LOGGER.debug ("Notification Endpoint URL: " + epUrl.toExternalForm ()); + bp.getRequestContext ().put (BindingProvider.ENDPOINT_ADDRESS_PROPERTY, epUrl.toExternalForm ()); + } + else { + LOGGER.debug ("Notification Endpoint URL is NULL: "); + } + + // authentication + try { + Map reqCtx = bp.getRequestContext (); + Map > headers = new HashMap <> (); + + String userCredentials = this.getEncryptedProperty (BPEL_AUTH_PROP, "", ENCRYPTION_KEY); + + String basicAuth = "Basic " + DatatypeConverter.printBase64Binary (userCredentials.getBytes ()); + reqCtx.put (MessageContext.HTTP_REQUEST_HEADERS, headers); + headers.put ("Authorization", Collections.singletonList (basicAuth)); + } catch (Exception e) { + String error1 = "Unable to set authorization in callback request" + e.getMessage (); + LOGGER.error (MessageEnum.RA_SET_CALLBACK_AUTH_EXC, "", "", MsoLogger.ErrorCode.DataError, "Exception - Unable to set authorization in callback request", e); + alarmLogger.sendAlarm ("MsoInternalError", MsoAlarmLogger.CRITICAL, error1); + } + + return notifyPort; + } + + public String getEncryptedProperty(String key, String defaultValue, String encryptionKey) { + try { + return CryptoUtils.decrypt(this.environment.getProperty(key), encryptionKey); + } catch (GeneralSecurityException e) { + LOGGER.debug("Exception while decrypting property: " + this.environment.getProperty(key), e); + } + return defaultValue; + + } + + private CreateNetworkNotification.SubnetIdMap copyCreateSubnetIdMap (Holder > hMap) { + + CreateNetworkNotification.SubnetIdMap subnetIdMap = new CreateNetworkNotification.SubnetIdMap (); + + if (hMap != null && hMap.value != null) { + Map sMap = new HashMap <> (); + sMap = hMap.value; + CreateNetworkNotification.SubnetIdMap.Entry entry = new CreateNetworkNotification.SubnetIdMap.Entry (); + + for (String key : sMap.keySet ()) { + entry.setKey (key); + entry.setValue (sMap.get (key)); + subnetIdMap.getEntry ().add (entry); + } + } + return subnetIdMap; + } + + private UpdateNetworkNotification.SubnetIdMap copyUpdateSubnetIdMap (Holder > hMap) { + + UpdateNetworkNotification.SubnetIdMap subnetIdMap = new UpdateNetworkNotification.SubnetIdMap (); + + if (hMap != null && hMap.value != null) { + Map sMap = new HashMap <> (); + sMap = hMap.value; + UpdateNetworkNotification.SubnetIdMap.Entry entry = new UpdateNetworkNotification.SubnetIdMap.Entry (); + + for (Map.Entry mapEntry : sMap.entrySet ()) { + String key = mapEntry.getKey(); + String value = mapEntry.getValue(); + entry.setKey (key); + entry.setValue (value); + subnetIdMap.getEntry ().add (entry); + } + } + return subnetIdMap; + } + + private QueryNetworkNotification.SubnetIdMap copyQuerySubnetIdMap (Holder > hMap) { + + QueryNetworkNotification.SubnetIdMap subnetIdMap = new QueryNetworkNotification.SubnetIdMap (); + + if (hMap != null && hMap.value != null) { + Map sMap = new HashMap <> (); + sMap = hMap.value; + QueryNetworkNotification.SubnetIdMap.Entry entry = new QueryNetworkNotification.SubnetIdMap.Entry (); + + for (Map.Entry mapEntry : sMap.entrySet ()) { + String key = mapEntry.getKey(); + String value = mapEntry.getValue(); + entry.setKey (key); + entry.setValue (value); + subnetIdMap.getEntry ().add (entry); + } + } + return subnetIdMap; + } +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/MsoNetworkAdapterImpl.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/MsoNetworkAdapterImpl.java new file mode 100644 index 0000000000..f5a05b7333 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/MsoNetworkAdapterImpl.java @@ -0,0 +1,2125 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * Copyright (C) 2017 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.so.adapters.network; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +import javax.jws.WebService; +import javax.xml.ws.Holder; + +import org.onap.so.adapters.network.beans.ContrailPolicyRef; +import org.onap.so.adapters.network.beans.ContrailPolicyRefSeq; +import org.onap.so.adapters.network.beans.ContrailSubnet; +import org.onap.so.adapters.network.exceptions.NetworkException; +import org.onap.so.adapters.network.mappers.ContrailSubnetMapper; +import org.onap.so.cloud.CloudConfig; +import org.onap.so.cloud.CloudSite; +import org.onap.so.db.catalog.beans.HeatTemplate; +import org.onap.so.db.catalog.beans.NetworkResource; +import org.onap.so.db.catalog.beans.NetworkResourceCustomization; +import org.onap.so.db.catalog.data.repository.NetworkResourceCustomizationRepository; +import org.onap.so.db.catalog.data.repository.NetworkResourceRepository; +import org.onap.so.db.catalog.utils.MavenLikeVersioning; +import org.onap.so.entity.MsoRequest; +import org.onap.so.logger.MessageEnum; +import org.onap.so.logger.MsoAlarmLogger; +import org.onap.so.logger.MsoLogger; +import org.onap.so.openstack.beans.HeatStatus; +import org.onap.so.openstack.beans.NetworkInfo; +import org.onap.so.openstack.beans.NetworkRollback; +import org.onap.so.openstack.beans.NetworkStatus; +import org.onap.so.openstack.beans.Pool; +import org.onap.so.openstack.beans.RouteTarget; +import org.onap.so.openstack.beans.StackInfo; +import org.onap.so.openstack.beans.Subnet; +import org.onap.so.openstack.exceptions.MsoAdapterException; +import org.onap.so.openstack.exceptions.MsoException; +import org.onap.so.openstack.exceptions.MsoExceptionCategory; +import org.onap.so.openstack.utils.MsoCommonUtils; +import org.onap.so.openstack.utils.MsoHeatUtils; +import org.onap.so.openstack.utils.MsoHeatUtilsWithUpdate; +import org.onap.so.openstack.utils.MsoNeutronUtils; +import org.onap.so.openstack.utils.MsoNeutronUtils.NetworkType; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.env.Environment; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; + +@Component +@Transactional +@WebService(serviceName = "NetworkAdapter", endpointInterface = "org.onap.so.adapters.network.MsoNetworkAdapter", targetNamespace = "http://org.onap.so/network") +public class MsoNetworkAdapterImpl implements MsoNetworkAdapter { + + private static final String AIC3_NW_PROPERTY= "org.onap.so.adapters.network.aic3nw"; + private static final String AIC3_NW="OS::ContrailV2::VirtualNetwork"; + private static final String VLANS = "vlans"; + private static final String PHYSICAL_NETWORK = "physical_network"; + private static final String UPDATE_NETWORK_CONTEXT = "UpdateNetwork"; + private static final String NETWORK_ID = "network_id"; + private static final String NETWORK_FQDN = "network_fqdn"; + private static final String CREATE_NETWORK_CONTEXT = "CreateNetwork"; + private static final String MSO_CONFIGURATION_ERROR = "MsoConfigurationError"; + private static final String NEUTRON_MODE = "NEUTRON"; + + private static final MsoLogger LOGGER = MsoLogger.getMsoLogger (MsoLogger.Catalog.RA,MsoNetworkAdapterImpl.class); + private static final MsoAlarmLogger alarmLogger = new MsoAlarmLogger (); + @Autowired + private CloudConfig cloudConfig; + @Autowired + private Environment environment; + @Autowired + private MsoNeutronUtils neutron; + @Autowired + private MsoHeatUtils heat; + @Autowired + private MsoHeatUtilsWithUpdate heatWithUpdate; + @Autowired + private MsoCommonUtils commonUtils; + + @Autowired + private NetworkResourceCustomizationRepository networkCustomRepo; + + @Autowired + private NetworkResourceRepository networkResourceRepo; + /** + * Health Check web method. Does nothing but return to show the adapter is deployed. + */ + @Override + public void healthCheck () { + LOGGER.debug ("Health check call in Network Adapter"); + } + + /** + * Do not use this constructor or the msoPropertiesFactory will be NULL. + * + * @see MsoNetworkAdapterImpl#MsoNetworkAdapterImpl(MsoPropertiesFactory) + */ + public MsoNetworkAdapterImpl() { + } + + @Override + public void createNetwork (String cloudSiteId, + String tenantId, + String networkType, + String modelCustomizationUuid, + String networkName, + String physicalNetworkName, + List vlans, + Boolean failIfExists, + Boolean backout, + List subnets, + MsoRequest msoRequest, + Holder networkId, + Holder neutronNetworkId, + Holder > subnetIdMap, + Holder rollback) throws NetworkException { + Holder networkFqdn = new Holder <> (); + createNetwork (cloudSiteId, + tenantId, + networkType, + modelCustomizationUuid, + networkName, + physicalNetworkName, + vlans, + null, + null, + null, + failIfExists, + backout, + subnets, + null, + null, + msoRequest, + networkId, + neutronNetworkId, + networkFqdn, + subnetIdMap, + rollback); + } + + @Override + public void createNetworkContrail (String cloudSiteId, + String tenantId, + String networkType, + String modelCustomizationUuid, + String networkName, + List routeTargets, + String shared, + String external, + Boolean failIfExists, + Boolean backout, + List subnets, + List policyFqdns, + List routeTableFqdns, + MsoRequest msoRequest, + Holder networkId, + Holder neutronNetworkId, + Holder networkFqdn, + Holder > subnetIdMap, + Holder rollback) throws NetworkException { + createNetwork (cloudSiteId, + tenantId, + networkType, + modelCustomizationUuid, + networkName, + null, + null, + routeTargets, + shared, + external, + failIfExists, + backout, + subnets, + policyFqdns, + routeTableFqdns, + msoRequest, + networkId, + neutronNetworkId, + networkFqdn, + subnetIdMap, + rollback); + } + + /** + * This is the "Create Network" web service implementation. + * It will create a new Network of the requested type in the specified cloud + * and tenant. The tenant must exist at the time this service is called. + * + * If a network with the same name already exists, this can be considered a + * success or failure, depending on the value of the 'failIfExists' parameter. + * + * There will be a pre-defined set of network types defined in the MSO Catalog. + * All such networks will have a similar configuration, based on the allowable + * Openstack networking definitions. This includes basic networks, provider + * networks (with a single VLAN), and multi-provider networks (one or more VLANs) + * + * Initially, all provider networks must be "vlan" type, and multiple segments in + * a multi-provider network must be multiple VLANs on the same physical network. + * + * This service supports two modes of Network creation/update: + * - via Heat Templates + * - via Neutron API + * The network orchestration mode for each network type is declared in its + * catalog definition. All Heat-based templates must support some subset of + * the same input parameters: network_name, physical_network, vlan(s). + * + * The method returns the network ID and a NetworkRollback object. This latter + * object can be passed as-is to the rollbackNetwork operation to undo everything + * that was created. This is useful if a network is successfully created but + * the orchestration fails on a subsequent operation. + */ + + private void createNetwork (String cloudSiteId, + String tenantId, + String networkType, + String modelCustomizationUuid, + String networkName, + String physicalNetworkName, + List vlans, + List routeTargets, + String shared, + String external, + Boolean failIfExists, + Boolean backout, + List subnets, + List policyFqdns, + List routeTableFqdns, + MsoRequest msoRequest, + Holder networkId, + Holder neutronNetworkId, + Holder networkFqdn, + Holder > subnetIdMap, + Holder rollback) throws NetworkException { + MsoLogger.setLogContext (msoRequest); + MsoLogger.setServiceName ("CreateNetwork"); + + LOGGER.debug ("*** CREATE Network: " + networkName + + " of type " + + networkType + + " in " + + cloudSiteId + + "/" + + tenantId); + + // Will capture execution time for metrics + long startTime = System.currentTimeMillis (); + + // Build a default rollback object (no actions performed) + NetworkRollback networkRollback = new NetworkRollback (); + networkRollback.setCloudId (cloudSiteId); + networkRollback.setTenantId (tenantId); + networkRollback.setMsoRequest (msoRequest); + networkRollback.setModelCustomizationUuid(modelCustomizationUuid); + + // tenant query is not required here. + // If the tenant doesn't exist, the Heat calls will fail anyway (when the HeatUtils try to obtain a token). + // So this is just catching that error in a bit more obvious way up front. + + Optional cloudSiteOpt = cloudConfig.getCloudSite(cloudSiteId); + if (!cloudSiteOpt.isPresent()) + { + String error = "Configuration Error. Stack " + networkName + " in " + + cloudSiteId + + "/" + + tenantId + + ": " + + " CloudSite does not exist in MSO Configuration"; + LOGGER.error (MessageEnum.RA_CONFIG_EXC, error, "", "", MsoLogger.ErrorCode.DataError, "Configuration Error"); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataError, error); + // Set the detailed error as the Exception 'message' + throw new NetworkException (error, MsoExceptionCategory.USERDATA); + } + + + NetworkResource networkResource = networkCheck (startTime, + networkType, + modelCustomizationUuid, + networkName, + physicalNetworkName, + vlans, + routeTargets, + cloudSiteId, + cloudSiteOpt.get()); + String mode = networkResource.getOrchestrationMode (); + NetworkType neutronNetworkType = NetworkType.valueOf (networkResource.getNeutronNetworkType ()); + + if (NEUTRON_MODE.equals (mode)) { + + // Use an MsoNeutronUtils for all neutron commands + + // See if the Network already exists (by name) + NetworkInfo netInfo = null; + long queryNetworkStarttime = System.currentTimeMillis (); + try { + netInfo = neutron.queryNetwork (networkName, tenantId, cloudSiteId); + LOGGER.recordMetricEvent (queryNetworkStarttime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Response successfully received from OpenStack", "OpenStack", "QueryNetwork", null); + } catch (MsoException me) { + LOGGER.recordMetricEvent (queryNetworkStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, "Exception while querying network from OpenStack", "OpenStack", "QueryNetwork", null); + LOGGER.error (MessageEnum.RA_QUERY_NETWORK_EXC, networkName, cloudSiteId, tenantId, "OpenStack", "", MsoLogger.ErrorCode.BusinessProcesssError, "Exception while querying network from OpenStack", me); + me.addContext (CREATE_NETWORK_CONTEXT); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, "Exception while querying network from OpenStack"); + throw new NetworkException (me); + } + + if (netInfo != null) { + // Exists. If that's OK, return success with the network ID. + // Otherwise, return an exception. + if (failIfExists != null && failIfExists) { + String error = "Create Nework: Network " + networkName + + " already exists in " + + cloudSiteId + + "/" + + tenantId + + " with ID " + netInfo.getId(); + LOGGER.error (MessageEnum.RA_NETWORK_ALREADY_EXIST, networkName, cloudSiteId, tenantId, "OpenStack", "", MsoLogger.ErrorCode.DataError, "Network already exists"); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error); + throw new NetworkException(error, MsoExceptionCategory.USERDATA); + } else { + // Populate the outputs from the existing network. + networkId.value = netInfo.getId (); + neutronNetworkId.value = netInfo.getId (); + rollback.value = networkRollback; // Default rollback - no updates performed + String msg = "Found Existing network, status=" + netInfo.getStatus () + " for Neutron mode"; + LOGGER.warn (MessageEnum.RA_NETWORK_ALREADY_EXIST, networkName, cloudSiteId, tenantId, "", MsoLogger.ErrorCode.DataError, "Found Existing network, status=" + netInfo.getStatus ()); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, msg); + } + return; + } + + long createNetworkStarttime = System.currentTimeMillis (); + try { + netInfo = neutron.createNetwork (cloudSiteId, + tenantId, + neutronNetworkType, + networkName, + physicalNetworkName, + vlans); + LOGGER.recordMetricEvent (createNetworkStarttime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Response successfully received from OpenStack", "OpenStack", "CreateNetwork", null); + } catch (MsoException me) { + me.addContext (CREATE_NETWORK_CONTEXT); + LOGGER.recordMetricEvent (createNetworkStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, "Exception while communicate with OpenStack", "OpenStack", "CreateNetwork", null); + String error = "Create Network: type " + neutronNetworkType + + " in " + + cloudSiteId + + "/" + + tenantId + + ": " + + me; + LOGGER.error (MessageEnum.RA_CREATE_NETWORK_EXC, networkName, cloudSiteId, tenantId, "OpenStack", "", MsoLogger.ErrorCode.DataError, "Exception while communicate with OpenStack", me); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error); + + throw new NetworkException (me); + } + + // Note: ignoring MsoNetworkAlreadyExists because we already checked. + + // If reach this point, network creation is successful. + // Since directly created via Neutron, networkId tracked by MSO is the same + // as the neutron network ID. + networkId.value = netInfo.getId (); + neutronNetworkId.value = netInfo.getId (); + + networkRollback.setNetworkCreated (true); + networkRollback.setNetworkId (netInfo.getId ()); + networkRollback.setNeutronNetworkId (netInfo.getId ()); + networkRollback.setNetworkType (networkType); + + LOGGER.debug ("Network " + networkName + " created, id = " + netInfo.getId ()); + } else if ("HEAT".equals (mode)) { + + HeatTemplate heatTemplate = networkResource.getHeatTemplate(); + if (heatTemplate == null) { + String error = "Network error - undefined Heat Template. Network Type = " + networkType; + LOGGER.error (MessageEnum.RA_PARAM_NOT_FOUND, "Heat Template", "Network Type", networkType, "Openstack", "", MsoLogger.ErrorCode.DataError, "Network error - undefined Heat Template. Network Type = " + networkType); + alarmLogger.sendAlarm (MSO_CONFIGURATION_ERROR, MsoAlarmLogger.CRITICAL, error); // Alarm on this + // error, + // configuration + // must be fixed + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error); + throw new NetworkException (error, MsoExceptionCategory.INTERNAL); + } + + LOGGER.debug ("Got HEAT Template from DB: " + heatTemplate.toString()); + + // "Fix" the template if it has CR/LF (getting this from Oracle) + String template = heatTemplate.getHeatTemplate (); + template = template.replaceAll ("\r\n", "\n"); + + boolean aic3template=false; + String aic3nw = AIC3_NW; + + aic3nw = environment.getProperty(AIC3_NW_PROPERTY, AIC3_NW); + + if (template.contains(aic3nw)) + aic3template = true; + + // First, look up to see if the Network already exists (by name). + // For HEAT orchestration of networks, the stack name will always match the network name + StackInfo heatStack = null; + long queryNetworkStarttime = System.currentTimeMillis (); + try { + heatStack = heat.queryStack (cloudSiteId, tenantId, networkName); + LOGGER.recordMetricEvent (queryNetworkStarttime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Response successfully received from OpenStack", "OpenStack", "QueryNetwork", null); + } catch (MsoException me) { + me.addContext (CREATE_NETWORK_CONTEXT); + LOGGER.recordMetricEvent (queryNetworkStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, "Exception while querying stack from OpenStack", "OpenStack", "QueryNetwork", null); + String error = "Create Network (heat): query network " + networkName + + " in " + + cloudSiteId + + "/" + + tenantId + + ": " + + me; + LOGGER.error (MessageEnum.RA_QUERY_NETWORK_EXC, networkName, cloudSiteId, tenantId, "OpenStack", "", MsoLogger.ErrorCode.DataError, "Exception while querying stack from OpenStack", me); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error); + throw new NetworkException (me); + } + + if (heatStack != null && (heatStack.getStatus () != HeatStatus.NOTFOUND)) { + // Stack exists. Return success or error depending on input directive + if (failIfExists != null && failIfExists) { + String error = "CreateNetwork: Stack " + networkName + + " already exists in " + + cloudSiteId + + "/" + + tenantId + + " as " + heatStack.getCanonicalName(); + LOGGER.error (MessageEnum.RA_NETWORK_ALREADY_EXIST, networkName, cloudSiteId, tenantId, "", "", MsoLogger.ErrorCode.DataError, "Network already exists"); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error); + throw new NetworkException(error, MsoExceptionCategory.USERDATA); + } else { + // Populate the outputs from the existing stack. + networkId.value = heatStack.getCanonicalName (); + neutronNetworkId.value = (String) heatStack.getOutputs ().get (NETWORK_ID); + rollback.value = networkRollback; // Default rollback - no updates performed + if (aic3template) + { + networkFqdn.value = (String) heatStack.getOutputs().get(NETWORK_FQDN); + } + Map outputs = heatStack.getOutputs (); + Map sMap = new HashMap <> (); + if (outputs != null) { + for (String key : outputs.keySet ()) { + if (key != null && key.startsWith ("subnet")) { + if (aic3template) //one subnet_id output + { + Map map = getSubnetUUId(key, outputs, subnets); + sMap.putAll(map); + } + else //multiples subnet_%aaid% outputs + { + String subnetUUId = (String) outputs.get(key); + sMap.put (key.substring("subnet_id_".length()), subnetUUId); + } + } + } + } + subnetIdMap.value = sMap; + LOGGER.warn (MessageEnum.RA_NETWORK_ALREADY_EXIST, networkName, cloudSiteId, tenantId, "", MsoLogger.ErrorCode.DataError, "Found Existing network stack, status=" + heatStack.getStatus ()); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Suc, "Found Existing network stack"); + } + return; + } + + // Ready to deploy the new Network + // Build the common set of HEAT template parameters + Map stackParams = populateNetworkParams (neutronNetworkType, + networkName, + physicalNetworkName, + vlans, + routeTargets, + shared, + external, + aic3template); + + // Validate (and update) the input parameters against the DB definition + // Shouldn't happen unless DB config is wrong, since all networks use same inputs + // and inputs were already validated. + try { + stackParams = heat.validateStackParams (stackParams, heatTemplate); + } catch (IllegalArgumentException e) { + String error = "Create Network: Configuration Error: " + e.getMessage (); + LOGGER.error (MessageEnum.RA_CONFIG_EXC, e.getMessage(), "Openstack", "", MsoLogger.ErrorCode.DataError, "Exception - Create Network, Configuration Error", e); + alarmLogger.sendAlarm (MSO_CONFIGURATION_ERROR, MsoAlarmLogger.CRITICAL, error); // Alarm on this + // error, + // configuration + // must be fixed + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataError, error); + // Input parameters were not valid + throw new NetworkException (error, MsoExceptionCategory.INTERNAL); + } + + if (subnets != null) { + try { + if (aic3template) + { + template = mergeSubnetsAIC3 (template, subnets, stackParams); + } + else + { + template = mergeSubnets (template, subnets); + } + } catch (MsoException me) { + me.addContext (CREATE_NETWORK_CONTEXT); + String error = "Create Network (heat): type " + neutronNetworkType + + " in " + + cloudSiteId + + "/" + + tenantId + + ": " + + me; + LOGGER.error (MessageEnum.RA_CREATE_NETWORK_EXC, neutronNetworkType.toString(), cloudSiteId, tenantId, "Openstack", "", MsoLogger.ErrorCode.DataError, "Exception Create Network, merging subnets", me); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.InternalError, error); + throw new NetworkException (me); + } + } + + if (policyFqdns != null && !policyFqdns.isEmpty() && aic3template) { + try { + mergePolicyRefs (policyFqdns, stackParams); + } catch (MsoException me) { + me.addContext (CREATE_NETWORK_CONTEXT); + String error = "Create Network (heat) mergePolicyRefs type " + neutronNetworkType + + " in " + + cloudSiteId + + "/" + + tenantId + + ": " + + me; + LOGGER.error (MessageEnum.RA_CREATE_NETWORK_EXC, neutronNetworkType.toString(), cloudSiteId, tenantId, "Openstack", "", MsoLogger.ErrorCode.DataError, "Exception Create Network, merging policyRefs", me); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.InternalError, error); + throw new NetworkException (me); + } + } + + if (routeTableFqdns != null && !routeTableFqdns.isEmpty() && aic3template) { + try { + mergeRouteTableRefs (routeTableFqdns, stackParams); + } catch (MsoException me) { + me.addContext (CREATE_NETWORK_CONTEXT); + String error = "Create Network (heat) mergeRouteTableRefs type " + neutronNetworkType + + " in " + + cloudSiteId + + "/" + + tenantId + + ": " + + me; + LOGGER.error (MessageEnum.RA_CREATE_NETWORK_EXC, neutronNetworkType.toString(), cloudSiteId, tenantId, "Openstack", "", MsoLogger.ErrorCode.DataError, "Exception Create Network, merging routeTableRefs", me); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.InternalError, error); + throw new NetworkException (me); + } + } + + // Deploy the network stack + // Ignore MsoStackAlreadyExists exception because we already checked. + try { + if (backout == null) + backout = true; + heatStack = heat.createStack (cloudSiteId, + tenantId, + networkName, + template, + stackParams, + true, + heatTemplate.getTimeoutMinutes (), + null, + null, + null, + backout.booleanValue()); + } catch (MsoException me) { + me.addContext (CREATE_NETWORK_CONTEXT); + String error = "Create Network (heat): type " + neutronNetworkType + + " in " + + cloudSiteId + + "/" + + tenantId + + ": " + + me; + LOGGER.error (MessageEnum.RA_CREATE_NETWORK_EXC, networkName, cloudSiteId, tenantId, "Openstack", "", MsoLogger.ErrorCode.DataError, "Exception creating network", me); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error); + throw new NetworkException (me); + } + + // Reach this point if createStack is successful. + + // For Heat-based orchestration, the MSO-tracked network ID is the heat stack, + // and the neutronNetworkId is the network UUID returned in stack outputs. + networkId.value = heatStack.getCanonicalName (); + neutronNetworkId.value = (String) heatStack.getOutputs ().get (NETWORK_ID); + if (aic3template) + { + networkFqdn.value = (String) heatStack.getOutputs().get(NETWORK_FQDN); + } + Map outputs = heatStack.getOutputs (); + Map sMap = new HashMap <> (); + if (outputs != null) { + for (String key : outputs.keySet ()) { + if (key != null && key.startsWith ("subnet")) { + if (aic3template) //one subnet output expected + { + Map map = getSubnetUUId(key, outputs, subnets); + sMap.putAll(map); + } + else //multiples subnet_%aaid% outputs allowed + { + String subnetUUId = (String) outputs.get(key); + sMap.put (key.substring("subnet_id_".length()), subnetUUId); + } + } + } + } + subnetIdMap.value = sMap; + + rollback.value = networkRollback; + // Populate remaining rollback info and response parameters. + networkRollback.setNetworkStackId (heatStack.getCanonicalName ()); + networkRollback.setNeutronNetworkId ((String) heatStack.getOutputs ().get (NETWORK_ID)); + networkRollback.setNetworkCreated (true); + networkRollback.setNetworkType (networkType); + + LOGGER.debug ("Network " + networkName + " successfully created via HEAT"); + } + + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Suc, "Successfully created network"); + return; + } + + @Override + public void updateNetwork (String cloudSiteId, + String tenantId, + String networkType, + String modelCustomizationUuid, + String networkId, + String networkName, + String physicalNetworkName, + List vlans, + List subnets, + MsoRequest msoRequest, + Holder > subnetIdMap, + Holder rollback) throws NetworkException { + updateNetwork (cloudSiteId, + tenantId, + networkType, + modelCustomizationUuid, + networkId, + networkName, + physicalNetworkName, + vlans, + null, + null, + null, + subnets, + null, + null, + msoRequest, + subnetIdMap, + rollback); + + } + + @Override + public void updateNetworkContrail (String cloudSiteId, + String tenantId, + String networkType, + String modelCustomizationUuid, + String networkId, + String networkName, + List routeTargets, + String shared, + String external, + List subnets, + List policyFqdns, + List routeTableFqdns, + MsoRequest msoRequest, + Holder > subnetIdMap, + Holder rollback) throws NetworkException { + updateNetwork (cloudSiteId, + tenantId, + networkType, + modelCustomizationUuid, + networkId, + networkName, + null, + null, + routeTargets, + shared, + external, + subnets, + policyFqdns, + routeTableFqdns, + msoRequest, + subnetIdMap, + rollback); + } + + /** + * This is the "Update Network" web service implementation. + * It will update an existing Network of the requested type in the specified cloud + * and tenant. The typical use will be to replace the VLANs with the supplied + * list (to add or remove a VLAN), but other properties may be updated as well. + * + * There will be a pre-defined set of network types defined in the MSO Catalog. + * All such networks will have a similar configuration, based on the allowable + * Openstack networking definitions. This includes basic networks, provider + * networks (with a single VLAN), and multi-provider networks (one or more VLANs). + * + * Initially, all provider networks must currently be "vlan" type, and multi-provider + * networks must be multiple VLANs on the same physical network. + * + * This service supports two modes of Network update: + * - via Heat Templates + * - via Neutron API + * The network orchestration mode for each network type is declared in its + * catalog definition. All Heat-based templates must support some subset of + * the same input parameters: network_name, physical_network, vlan, segments. + * + * The method returns a NetworkRollback object. This object can be passed + * as-is to the rollbackNetwork operation to undo everything that was updated. + * This is useful if a network is successfully updated but orchestration + * fails on a subsequent operation. + */ + private void updateNetwork (String cloudSiteId, + String tenantId, + String networkType, + String modelCustomizationUuid, + String networkId, + String networkName, + String physicalNetworkName, + List vlans, + List routeTargets, + String shared, + String external, + List subnets, + List policyFqdns, + List routeTableFqdns, + MsoRequest msoRequest, + Holder > subnetIdMap, + Holder rollback) throws NetworkException { + MsoLogger.setLogContext (msoRequest); + MsoLogger.setServiceName ("UpdateNetwork"); + LOGGER.debug ("***UPDATE Network adapter with Network: " + networkName + + " of type " + + networkType + + " in " + + cloudSiteId + + "/" + + tenantId); + + + // Will capture execution time for metrics + long startTime = System.currentTimeMillis (); + + // Build a default rollback object (no actions performed) + NetworkRollback networkRollback = new NetworkRollback (); + networkRollback.setCloudId (cloudSiteId); + networkRollback.setTenantId (tenantId); + networkRollback.setMsoRequest (msoRequest); + + Optional cloudSiteOpt = cloudConfig.getCloudSite (cloudSiteId); + if (!cloudSiteOpt.isPresent()) { + String error = "UpdateNetwork: Configuration Error. Stack " + networkName + " in " + + cloudSiteId + + "/" + + tenantId + + ": " + + " CloudSite does not exist in MSO Configuration"; + LOGGER.error (MessageEnum.RA_CONFIG_EXC, error, "Openstack", "", MsoLogger.ErrorCode.DataError, "CloudSite does not exist in MSO Configuration"); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataError, error); + // Set the detailed error as the Exception 'message' + throw new NetworkException (error, MsoExceptionCategory.USERDATA); + } + + + + + NetworkResource networkResource = networkCheck( + startTime, + networkType, + modelCustomizationUuid, + networkName, + physicalNetworkName, + vlans, + routeTargets, + cloudSiteId, + cloudSiteOpt.get()); + String mode = networkResource.getOrchestrationMode(); + NetworkType neutronNetworkType = NetworkType.valueOf(networkResource.getNeutronNetworkType()); + + // Use an MsoNeutronUtils for all Neutron commands + + if (NEUTRON_MODE.equals(mode)) { + + // Verify that the Network exists + // For Neutron-based orchestration, the networkId is the Neutron Network UUID. + NetworkInfo netInfo = null; + long queryNetworkStarttime = System.currentTimeMillis(); + try { + netInfo = neutron.queryNetwork(networkId, tenantId, cloudSiteId); + LOGGER.recordMetricEvent(queryNetworkStarttime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "QueryNetwork", null); + } catch (MsoException me) { + me.addContext(UPDATE_NETWORK_CONTEXT); + String error = "Update Network (neutron): query " + networkId + + " in " + + cloudSiteId + + "/" + + tenantId + + ": " + + me; + LOGGER.recordMetricEvent(queryNetworkStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryNetwork", null); + LOGGER.error(MessageEnum.RA_QUERY_NETWORK_EXC, networkId, cloudSiteId, tenantId, "OpenStack", "QueryNetwork", MsoLogger.ErrorCode.BusinessProcesssError, "Exception - queryNetwork", me); + LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error); + throw new NetworkException(me); + } + + if (netInfo == null) { + String error = "Update Nework: Network " + networkId + + " does not exist in " + + cloudSiteId + + "/" + + tenantId; + LOGGER.error(MessageEnum.RA_NETWORK_NOT_FOUND, networkId, cloudSiteId, tenantId, "OpenStack", "", MsoLogger.ErrorCode.BusinessProcesssError, "Network not found"); + LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.BadRequest, error); + // Does not exist. Throw an exception (can't update a non-existent network) + throw new NetworkException(error, MsoExceptionCategory.USERDATA); + } + long updateNetworkStarttime = System.currentTimeMillis(); + try { + netInfo = neutron.updateNetwork(cloudSiteId, + tenantId, + networkId, + neutronNetworkType, + physicalNetworkName, + vlans); + LOGGER.recordMetricEvent(updateNetworkStarttime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "UpdateNetwork", null); + } catch (MsoException me) { + me.addContext(UPDATE_NETWORK_CONTEXT); + String error = "Update Network (neutron): " + networkId + + " in " + + cloudSiteId + + "/" + + tenantId + + ": " + + me; + LOGGER.error(MessageEnum.RA_UPDATE_NETWORK_ERR, networkId, cloudSiteId, tenantId, "Openstack", "updateNetwork", MsoLogger.ErrorCode.DataError, "Exception - updateNetwork", me); + LOGGER.recordMetricEvent(updateNetworkStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "UpdateNetwork", null); + LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error); + throw new NetworkException(me); + } + + // Add the network ID and previously queried vlans to the rollback object + networkRollback.setNetworkId(netInfo.getId()); + networkRollback.setNeutronNetworkId(netInfo.getId()); + networkRollback.setNetworkType(networkType); + // Save previous parameters + networkRollback.setNetworkName(netInfo.getName()); + networkRollback.setPhysicalNetwork(netInfo.getProvider()); + networkRollback.setVlans(netInfo.getVlans()); + + LOGGER.debug("Network " + networkId + " updated, id = " + netInfo.getId()); + } else if ("HEAT".equals(mode)) { + + // First, look up to see that the Network already exists. + // For Heat-based orchestration, the networkId is the network Stack ID. + StackInfo heatStack = null; + long queryStackStarttime = System.currentTimeMillis(); + try { + heatStack = heat.queryStack(cloudSiteId, tenantId, networkName); + LOGGER.recordMetricEvent(queryStackStarttime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "QueryStack", null); + } catch (MsoException me) { + me.addContext(UPDATE_NETWORK_CONTEXT); + String error = "UpdateNetwork (heat): query " + networkName + + " in " + + cloudSiteId + + "/" + + tenantId + + ": " + + me; + LOGGER.recordMetricEvent(queryStackStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", null); + LOGGER.error(MessageEnum.RA_QUERY_NETWORK_EXC, networkId, cloudSiteId, tenantId, "OpenStack", "queryStack", MsoLogger.ErrorCode.DataError, "Exception - QueryStack", me); + LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error); + throw new NetworkException(me); + } + + if (heatStack == null || (heatStack.getStatus() == HeatStatus.NOTFOUND)) { + String error = "UpdateNetwork: Stack " + networkName + + " does not exist in " + + cloudSiteId + + "/" + + tenantId; + LOGGER.error(MessageEnum.RA_NETWORK_NOT_FOUND, networkId, cloudSiteId, tenantId, "OpenStack", "queryStack", MsoLogger.ErrorCode.DataError, "Network not found"); + LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.BadRequest, error); + // Network stack does not exist. Return an error + throw new NetworkException(error, MsoExceptionCategory.USERDATA); + } + + // Get the previous parameters for rollback + Map heatParams = heatStack.getParameters(); + + String previousNetworkName = (String) heatParams.get("network_name"); + String previousPhysicalNetwork = (String) heatParams.get(PHYSICAL_NETWORK); + + List previousVlans = new ArrayList<>(); + String vlansParam = (String) heatParams.get(VLANS); + if (vlansParam != null) { + for (String vlan : vlansParam.split(",")) { + try { + previousVlans.add(Integer.parseInt(vlan)); + } catch (NumberFormatException e) { + LOGGER.warn(MessageEnum.RA_VLAN_PARSE, networkId, vlansParam, "", MsoLogger.ErrorCode.DataError, "Exception - VLAN parse", e); + } + } + } + LOGGER.debug("Update Stack: Previous VLANS: " + previousVlans); + + // Ready to deploy the updated Network via Heat + + + HeatTemplate heatTemplate = networkResource.getHeatTemplate(); + if (heatTemplate == null) { + String error = "Network error - undefined Heat Template. Network Type=" + networkType; + LOGGER.error(MessageEnum.RA_PARAM_NOT_FOUND, "Heat Template", "Network Type", networkType, "OpenStack", "getHeatTemplate", MsoLogger.ErrorCode.DataError, "Network error - undefined Heat Template. Network Type=" + networkType); + alarmLogger.sendAlarm(MSO_CONFIGURATION_ERROR, MsoAlarmLogger.CRITICAL, error); + LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.BadRequest, error); + throw new NetworkException(error, MsoExceptionCategory.INTERNAL); + } + + LOGGER.debug("Got HEAT Template from DB: " + heatTemplate.toString()); + + // "Fix" the template if it has CR/LF (getting this from Oracle) + String template = heatTemplate.getHeatTemplate(); + template = template.replaceAll("\r\n", "\n"); + + boolean aic3template = false; + String aic3nw = AIC3_NW; + + aic3nw = environment.getProperty(AIC3_NW_PROPERTY, AIC3_NW); + + if (template.contains(aic3nw)) + aic3template = true; + + // Build the common set of HEAT template parameters + Map stackParams = populateNetworkParams(neutronNetworkType, + networkName, + physicalNetworkName, + vlans, + routeTargets, + shared, + external, + aic3template); + + // Validate (and update) the input parameters against the DB definition + // Shouldn't happen unless DB config is wrong, since all networks use same inputs + try { + stackParams = heat.validateStackParams(stackParams, heatTemplate); + } catch (IllegalArgumentException e) { + String error = "UpdateNetwork: Configuration Error: Network Type=" + networkType; + LOGGER.error(MessageEnum.RA_CONFIG_EXC, "Network Type=" + networkType, "OpenStack", "", MsoLogger.ErrorCode.DataError, "Exception - UpdateNetwork: Configuration Error"); + alarmLogger.sendAlarm(MSO_CONFIGURATION_ERROR, MsoAlarmLogger.CRITICAL, error); + LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.SchemaError, error); + throw new NetworkException(error, MsoExceptionCategory.INTERNAL, e); + } + + if (subnets != null) { + try { + if (aic3template) { + template = mergeSubnetsAIC3(template, subnets, stackParams); + } else { + template = mergeSubnets(template, subnets); + } + } catch (MsoException me) { + me.addContext(UPDATE_NETWORK_CONTEXT); + String error = "Update Network (heat): type " + neutronNetworkType + + " in " + + cloudSiteId + + "/" + + tenantId + + ": " + + me; + LOGGER.error(MessageEnum.RA_UPDATE_NETWORK_ERR, neutronNetworkType.toString(), cloudSiteId, tenantId, "OpenStack", "", MsoLogger.ErrorCode.DataError, "Exception - UpdateNetwork mergeSubnets ", me); + LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.InternalError, error); + throw new NetworkException(me); + } + } + + if (policyFqdns != null && aic3template) { + try { + mergePolicyRefs(policyFqdns, stackParams); + } catch (MsoException me) { + me.addContext(UPDATE_NETWORK_CONTEXT); + String error = "UpdateNetwork (heat) mergePolicyRefs type " + neutronNetworkType + + " in " + + cloudSiteId + + "/" + + tenantId + + ": " + + me; + LOGGER.error(MessageEnum.RA_UPDATE_NETWORK_ERR, neutronNetworkType.toString(), cloudSiteId, tenantId, "OpenStack", "", MsoLogger.ErrorCode.DataError, "Exception - UpdateNetwork mergePolicyRefs", me); + LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.InternalError, error); + throw new NetworkException(me); + } + } + + if (routeTableFqdns != null && !routeTableFqdns.isEmpty() && aic3template) { + try { + mergeRouteTableRefs(routeTableFqdns, stackParams); + } catch (MsoException me) { + me.addContext(UPDATE_NETWORK_CONTEXT); + String error = "UpdateNetwork (heat) mergeRouteTableRefs type " + neutronNetworkType + + " in " + + cloudSiteId + + "/" + + tenantId + + ": " + + me; + LOGGER.error(MessageEnum.RA_UPDATE_NETWORK_ERR, neutronNetworkType.toString(), cloudSiteId, tenantId, "Openstack", "", MsoLogger.ErrorCode.DataError, "Exception - UpdateNetwork mergeRouteTableRefs", me); + LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.InternalError, error); + throw new NetworkException(me); + } + } + + // Update the network stack + // Ignore MsoStackNotFound exception because we already checked. + long updateStackStarttime = System.currentTimeMillis(); + try { + heatStack = heatWithUpdate.updateStack(cloudSiteId, + tenantId, + networkId, + template, + stackParams, + true, + heatTemplate.getTimeoutMinutes()); + LOGGER.recordMetricEvent(updateStackStarttime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "UpdateStack", null); + } catch (MsoException me) { + me.addContext(UPDATE_NETWORK_CONTEXT); + String error = "Update Network: " + networkId + " in " + cloudSiteId + "/" + tenantId + ": " + me; + LOGGER.recordMetricEvent(updateStackStarttime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "UpdateStack", null); + LOGGER.error(MessageEnum.RA_UPDATE_NETWORK_ERR, networkId, cloudSiteId, tenantId, "OpenStack", "", MsoLogger.ErrorCode.DataError, "Exception - update network", me); + LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error); + throw new NetworkException(me); + } + + Map outputs = heatStack.getOutputs(); + Map sMap = new HashMap<>(); + if (outputs != null) { + for (String key : outputs.keySet()) { + if (key != null && key.startsWith("subnet")) { + if (aic3template) //one subnet output expected + { + Map map = getSubnetUUId(key, outputs, subnets); + sMap.putAll(map); + } else //multiples subnet_%aaid% outputs allowed + { + String subnetUUId = (String) outputs.get(key); + sMap.put(key.substring("subnet_id_".length()), subnetUUId); + } + } + } + } + subnetIdMap.value = sMap; + + // Reach this point if createStack is successful. + // Populate remaining rollback info and response parameters. + networkRollback.setNetworkStackId(heatStack.getCanonicalName()); + if(null != outputs) { + networkRollback.setNeutronNetworkId((String) outputs.get(NETWORK_ID)); + } + else { + LOGGER.debug("outputs is NULL"); + } + networkRollback.setNetworkType(networkType); + // Save previous parameters + networkRollback.setNetworkName(previousNetworkName); + networkRollback.setPhysicalNetwork(previousPhysicalNetwork); + networkRollback.setVlans(previousVlans); + + rollback.value = networkRollback; + + LOGGER.debug("Network " + networkId + " successfully updated via HEAT"); + } + + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully updated network"); + return; + } + + private NetworkResource networkCheck (long startTime, + String networkType, + String modelCustomizationUuid, + String networkName, + String physicalNetworkName, + List vlans, + List routeTargets, + String cloudSiteId, + CloudSite cloudSite) throws NetworkException { + // Retrieve the Network Resource definition + NetworkResource networkResource = null; + NetworkResourceCustomization networkCust = null; + if (commonUtils.isNullOrEmpty(modelCustomizationUuid)) { + if (!commonUtils.isNullOrEmpty(networkType)) { + networkResource = networkResourceRepo.findOneByModelName(networkType); + } + } else { + networkCust = networkCustomRepo.findOneByModelCustomizationUUID(modelCustomizationUuid); + } + if(networkCust != null){ + LOGGER.debug("Got Network Customization definition from Catalog: " + + networkCust.toString()); + + networkResource = networkCust.getNetworkResource(); + } + if (networkResource == null) { + String error = "Create/UpdateNetwork: Unable to get network resource with NetworkType:" + + networkType + + " or ModelCustomizationUUID:" + + modelCustomizationUuid; + LOGGER.error(MessageEnum.RA_UNKOWN_PARAM, + "NetworkType/ModelCustomizationUUID", networkType + "/" + + modelCustomizationUuid, "OpenStack", "", + MsoLogger.ErrorCode.DataError, + "Create/UpdateNetwork: Unknown NetworkType/ModelCustomizationUUID"); + + throw new NetworkException(error, MsoExceptionCategory.USERDATA); + } + LOGGER.debug("Got Network definition from Catalog: " + + networkResource.toString()); + + String mode = networkResource.getOrchestrationMode(); + NetworkType neutronNetworkType = NetworkType + .valueOf(networkResource.getNeutronNetworkType()); + + // All Networks are orchestrated via HEAT or Neutron + if (!("HEAT".equals(mode) || NEUTRON_MODE.equals(mode))) { + String error = "CreateNetwork: Configuration Error: Network Type = " + + networkType; + LOGGER.error(MessageEnum.RA_NETWORK_ORCHE_MODE_NOT_SUPPORT, + mode, "OpenStack", "", MsoLogger.ErrorCode.DataError, + "CreateNetwork: Configuration Error"); + // Alarm on this error, configuration must be fixed + alarmLogger.sendAlarm(MSO_CONFIGURATION_ERROR, + MsoAlarmLogger.CRITICAL, error); + + throw new NetworkException(error, MsoExceptionCategory.INTERNAL); + } + + MavenLikeVersioning aicV = new MavenLikeVersioning(); + aicV.setVersion(cloudSite.getAicVersion()); + if ((aicV.isMoreRecentThan(networkResource.getAicVersionMin()) || aicV + .isTheSameVersion(networkResource.getAicVersionMin())) // aic + // >= + // min + && (aicV.isTheSameVersion(networkResource + .getAicVersionMax()) || !(aicV + .isMoreRecentThan(networkResource + .getAicVersionMax())))) // aic <= max + { + LOGGER.debug("Network Type:" + networkType + " VersionMin:" + + networkResource.getAicVersionMin() + " VersionMax:" + + networkResource.getAicVersionMax() + + " supported on Cloud:" + cloudSiteId + + " with AIC_Version:" + cloudSite.getAicVersion()); + } else { + String error = "Network Type:" + networkType + " Version_Min:" + + networkResource.getAicVersionMin() + " Version_Max:" + + networkResource.getAicVersionMax() + + " not supported on Cloud:" + cloudSiteId + + " with AIC_Version:" + cloudSite.getAicVersion(); + LOGGER.error(MessageEnum.RA_CONFIG_EXC, error, "OpenStack", "", + MsoLogger.ErrorCode.DataError, + "Network Type not supported on Cloud"); + LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, + MsoLogger.ResponseCode.DataError, error); + throw new NetworkException(error, MsoExceptionCategory.USERDATA); + } + + // Validate the Network parameters. + String missing = validateNetworkParams(neutronNetworkType, + networkName, physicalNetworkName, vlans, routeTargets); + if (!missing.isEmpty()) { + String error = "Create Network: Missing parameters: " + missing; + LOGGER.error(MessageEnum.RA_MISSING_PARAM, missing, + "OpenStack", "", MsoLogger.ErrorCode.DataError, + "Create Network: Missing parameters"); + + throw new NetworkException(error, MsoExceptionCategory.USERDATA); + } + + return networkResource; + } + + @Override + public void queryNetwork (String cloudSiteId, + String tenantId, + String networkNameOrId, + MsoRequest msoRequest, + Holder networkExists, + Holder networkId, + Holder neutronNetworkId, + Holder status, + Holder > vlans, + Holder > subnetIdMap) throws NetworkException { + queryNetwork (cloudSiteId, + tenantId, + networkNameOrId, + msoRequest, + networkExists, + networkId, + neutronNetworkId, + status, + vlans, + null, + subnetIdMap); + } + + @Override + public void queryNetworkContrail (String cloudSiteId, + String tenantId, + String networkNameOrId, + MsoRequest msoRequest, + Holder networkExists, + Holder networkId, + Holder neutronNetworkId, + Holder status, + Holder > routeTargets, + Holder > subnetIdMap) throws NetworkException { + queryNetwork (cloudSiteId, + tenantId, + networkNameOrId, + msoRequest, + networkExists, + networkId, + neutronNetworkId, + status, + null, + routeTargets, + subnetIdMap); + } + + /** + * This is the queryNetwork method. It returns the existence and status of + * the specified network, along with its Neutron UUID and list of VLANs. + * This method attempts to find the network using both Heat and Neutron. + * Heat stacks are first searched based on the provided network name/id. + * If none is found, the Neutron is directly queried. + */ + private void queryNetwork (String cloudSiteId, + String tenantId, + String networkNameOrId, + MsoRequest msoRequest, + Holder networkExists, + Holder networkId, + Holder neutronNetworkId, + Holder status, + Holder > vlans, + Holder > routeTargets, + Holder > subnetIdMap) throws NetworkException { + MsoLogger.setLogContext (msoRequest); + MsoLogger.setServiceName ("QueryNetwork"); + LOGGER.debug ("*** QUERY Network with Network: " + networkNameOrId + + " in " + + cloudSiteId + + "/" + + tenantId); + + // Will capture execution time for metrics + long startTime = System.currentTimeMillis (); + + if (commonUtils.isNullOrEmpty (cloudSiteId) + || commonUtils.isNullOrEmpty(tenantId) + || commonUtils.isNullOrEmpty(networkNameOrId)) { + + String error = "Missing mandatory parameter cloudSiteId, tenantId or networkId"; + LOGGER.error (MessageEnum.RA_MISSING_PARAM, "cloudSiteId or tenantId or networkNameOrId", "OpenStack", "", MsoLogger.ErrorCode.DataError, "Missing mandatory parameter cloudSiteId, tenantId or networkId"); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.BadRequest, error); + throw new NetworkException (error, MsoExceptionCategory.USERDATA); + } + + Optional cloudSiteOpt = cloudConfig.getCloudSite(cloudSiteId); + if (!cloudSiteOpt.isPresent()) + { + String error = "Configuration Error. Stack " + networkNameOrId + " in " + + cloudSiteId + + "/" + + tenantId + + ": " + + " CloudSite does not exist in MSO Configuration"; + LOGGER.error (MessageEnum.RA_CONFIG_EXC, error, "OpenStack", "", MsoLogger.ErrorCode.DataError, "Configuration Error"); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataError, error); + // Set the detailed error as the Exception 'message' + throw new NetworkException (error, MsoExceptionCategory.USERDATA); + } + + // Use MsoNeutronUtils for all NEUTRON commands + + String mode; + String neutronId; + // Try Heat first, since networks may be named the same as the Heat stack + StackInfo heatStack = null; + long queryStackStarttime = System.currentTimeMillis (); + try { + heatStack = heat.queryStack (cloudSiteId, tenantId, networkNameOrId); + LOGGER.recordMetricEvent (queryStackStarttime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "QueryStack", null); + } catch (MsoException me) { + me.addContext ("QueryNetwork"); + String error = "Query Network (heat): " + networkNameOrId + + " in " + + cloudSiteId + + "/" + + tenantId + + ": " + + me; + LOGGER.recordMetricEvent (queryStackStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "BPMN", "QueryStack", null); + LOGGER.error (MessageEnum.RA_QUERY_NETWORK_EXC, networkNameOrId, cloudSiteId, tenantId, "OpenStack", "queryStack", MsoLogger.ErrorCode.DataError, "Exception - Query Network (heat)", me); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error); + throw new NetworkException (me); + } + + // Populate the outputs based on the returned Stack information + if (heatStack != null && heatStack.getStatus () != HeatStatus.NOTFOUND) { + // Found it. Get the neutronNetworkId for further query + Map outputs = heatStack.getOutputs (); + neutronId = (String) outputs.get (NETWORK_ID); + mode = "HEAT"; + + Map sMap = new HashMap <> (); + if (outputs != null) { + for (String key : outputs.keySet ()) { + if (key != null && key.startsWith ("subnet_id_")) //multiples subnet_%aaid% outputs + { + String subnetUUId = (String) outputs.get(key); + sMap.put (key.substring("subnet_id_".length()), subnetUUId); + } + else if (key != null && key.startsWith ("subnet")) //one subnet output expected + { + Map map = getSubnetUUId(key, outputs, null); + sMap.putAll(map); + } + + } + } + subnetIdMap.value = sMap; + } else { + // Input ID was not a Heat stack ID. Try it directly in Neutron + neutronId = networkNameOrId; + mode = NEUTRON_MODE; + } + + // Query directly against the Neutron Network for the details + // no RouteTargets available for ContrailV2 in neutron net-show + // networkId is heatStackId + long queryNetworkStarttime = System.currentTimeMillis (); + try { + NetworkInfo netInfo = neutron.queryNetwork (neutronId, tenantId, cloudSiteId); + LOGGER.recordMetricEvent (queryNetworkStarttime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "QueryNetwork", null); + if (netInfo != null) { + // Found. Populate the output elements + networkExists.value = Boolean.TRUE; + if ("HEAT".equals (mode)) { + networkId.value = heatStack.getCanonicalName (); + } else { + networkId.value = netInfo.getId (); + } + neutronNetworkId.value = netInfo.getId (); + status.value = netInfo.getStatus (); + if (vlans != null) + vlans.value = netInfo.getVlans (); + + LOGGER.debug ("Network " + networkNameOrId + + " found (" + + mode + + "), ID = " + + networkId.value + + ("HEAT".equals (mode) ? ",NeutronId = " + neutronNetworkId.value : "")); + } else { + // Not found. Populate the status fields, leave the rest null + networkExists.value = Boolean.FALSE; + status.value = NetworkStatus.NOTFOUND; + neutronNetworkId.value = null; + if (vlans != null) + vlans.value = new ArrayList<>(); + + LOGGER.debug ("Network " + networkNameOrId + " not found"); + } + } catch (MsoException me) { + me.addContext ("QueryNetwork"); + String error = "Query Network (neutron): " + networkNameOrId + + " in " + + cloudSiteId + + "/" + + tenantId + + ": " + + me; + LOGGER.recordMetricEvent (queryNetworkStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryNetwork", null); + LOGGER.error (MessageEnum.RA_QUERY_NETWORK_EXC, networkNameOrId, cloudSiteId, tenantId, "OpenStack", "", MsoLogger.ErrorCode.DataError, "Exception - Query Network (neutron)", me); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error); + throw new NetworkException (me); + } + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully queried network"); + return; + } + + /** + * This is the "Delete Network" web service implementation. + * It will delete a Network in the specified cloud and tenant. + * + * If the network is not found, it is treated as a success. + * + * This service supports two modes of Network creation/update/delete: + * - via Heat Templates + * - via Neutron API + * The network orchestration mode for each network type is declared in its + * catalog definition. + * + * For Heat-based orchestration, the networkId should be the stack ID. + * For Neutron-based orchestration, the networkId should be the Neutron network UUID. + * + * The method returns nothing on success. Rollback is not possible for delete + * commands, so any failure on delete will require manual fallout in the client. + */ + @Override + public void deleteNetwork (String cloudSiteId, + String tenantId, + String networkType, + String modelCustomizationUuid, + String networkId, + MsoRequest msoRequest, + Holder networkDeleted) throws NetworkException { + MsoLogger.setLogContext (msoRequest); + MsoLogger.setServiceName ("DeleteNetwork"); + LOGGER.debug ("*** DELETE Network adapter with Network: " + networkId + + " in " + + cloudSiteId + + "/" + + tenantId); + + // Will capture execution time for metrics + long startTime = System.currentTimeMillis (); + + + if (commonUtils.isNullOrEmpty (cloudSiteId) + || commonUtils.isNullOrEmpty(tenantId) + || commonUtils.isNullOrEmpty(networkId)) { + String error = "Missing mandatory parameter cloudSiteId, tenantId or networkId"; + LOGGER.error (MessageEnum.RA_MISSING_PARAM, "cloudSiteId or tenantId or networkId", "Openstack", "", MsoLogger.ErrorCode.DataError, "Missing mandatory parameter cloudSiteId, tenantId or networkId"); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.BadRequest, error); + throw new NetworkException (error, MsoExceptionCategory.USERDATA); + } + + // Retrieve the Network Resource definition + NetworkResource networkResource = null; + + if (commonUtils.isNullOrEmpty(modelCustomizationUuid)) { + if (!commonUtils.isNullOrEmpty(networkType)) { + networkResource = networkResourceRepo.findFirstByModelNameOrderByModelVersionDesc(networkType); + } + } else { + NetworkResourceCustomization nrc = networkCustomRepo.findOneByModelCustomizationUUID(modelCustomizationUuid); + if (nrc != null) { + networkResource = nrc.getNetworkResource(); + } + } + + String mode = ""; + if (networkResource != null) { + LOGGER.debug ("Got Network definition from Catalog: " + networkResource.toString ()); + + mode = networkResource.getOrchestrationMode (); + } + + if (NEUTRON_MODE.equals (mode)) { + + // Use MsoNeutronUtils for all NEUTRON commands + long deleteNetworkStarttime = System.currentTimeMillis (); + try { + // The deleteNetwork function in MsoNeutronUtils returns success if the network + // was not found. So don't bother to query first. + boolean deleted = neutron.deleteNetwork (networkId, tenantId, cloudSiteId); + LOGGER.recordMetricEvent (deleteNetworkStarttime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "DeleteNetwork", null); + networkDeleted.value = deleted; + } catch (MsoException me) { + me.addContext ("DeleteNetwork"); + String error = "Delete Network (neutron): " + networkId + + " in " + + cloudSiteId + + "/" + + tenantId + + ": " + + me; + LOGGER.recordMetricEvent (deleteNetworkStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "DeleteNetwork", null); + LOGGER.error (MessageEnum.RA_DELETE_NETWORK_EXC, networkId, cloudSiteId, tenantId, "Openstack", "", MsoLogger.ErrorCode.DataError, "Delete Network (neutron)", me); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error); + throw new NetworkException (me); + } + } else { // DEFAULT to ("HEAT".equals (mode)) + long deleteStackStarttime = System.currentTimeMillis (); + + try { + // The deleteStack function in MsoHeatUtils returns NOTFOUND if the stack was not found or if the stack was deleted. + // So query first to report back if stack WAS deleted or just NOTOFUND + StackInfo heatStack = null; + heatStack = heat.queryStack(cloudSiteId, tenantId, networkId); + if (heatStack != null && heatStack.getStatus() != HeatStatus.NOTFOUND) + { + heat.deleteStack (tenantId, cloudSiteId, networkId, true); + LOGGER.recordMetricEvent (deleteStackStarttime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "DeleteStack", null); + networkDeleted.value = true; + } + else + { + networkDeleted.value = false; + } + } catch (MsoException me) { + me.addContext ("DeleteNetwork"); + String error = "Delete Network (heat): " + networkId + + " in " + + cloudSiteId + + "/" + + tenantId + + ": " + + me; + LOGGER.recordMetricEvent (deleteStackStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "DeleteStack", null); + LOGGER.error (MessageEnum.RA_DELETE_NETWORK_EXC, networkId, cloudSiteId, tenantId, "Openstack", "", MsoLogger.ErrorCode.DataError, "Delete Network (heat)", me); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error); + throw new NetworkException (me); + } + } + + + // On success, nothing is returned. + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully deleted network"); + return; + } + + /** + * 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. + * + * The rollback includes removing the VNF and deleting the tenant if the + * tenant did not exist prior to the VNF creation. + */ + @Override + public void rollbackNetwork (NetworkRollback rollback) throws NetworkException { + MsoLogger.setServiceName ("RollbackNetwork"); + // Will capture execution time for metrics + long startTime = System.currentTimeMillis (); + + if (rollback == null) { + LOGGER.error (MessageEnum.RA_ROLLBACK_NULL, "Openstack", "", MsoLogger.ErrorCode.DataError, "rollback is null"); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.BadRequest, "No action to perform"); + return; + } + + MsoLogger.setLogContext (rollback.getMsoRequest()); + + // Get the elements of the VnfRollback object for easier access + String cloudSiteId = rollback.getCloudId (); + String tenantId = rollback.getTenantId (); + String networkId = rollback.getNetworkStackId (); + String networkType = rollback.getNetworkType (); + String modelCustomizationUuid = rollback.getModelCustomizationUuid(); + + LOGGER.debug ("*** ROLLBACK Network " + networkId + " in " + cloudSiteId + "/" + tenantId); + + + + // Retrieve the Network Resource definition + NetworkResource networkResource = null; + if (commonUtils.isNullOrEmpty(modelCustomizationUuid)) { + networkResource = networkCustomRepo.findOneByNetworkType(networkType).getNetworkResource(); + } else { + networkResource = networkCustomRepo.findOneByModelCustomizationUUID(modelCustomizationUuid).getNetworkResource(); + } + String mode = ""; + if (networkResource != null) { + + LOGGER.debug ("Got Network definition from Catalog: " + networkResource.toString ()); + + mode = networkResource.getOrchestrationMode (); + } + + if (rollback.getNetworkCreated ()) { + // Rolling back a newly created network, so delete it. + if (NEUTRON_MODE.equals (mode)) { + // Use MsoNeutronUtils for all NEUTRON commands + long deleteNetworkStarttime = System.currentTimeMillis (); + try { + // The deleteNetwork function in MsoNeutronUtils returns success if the network + // was not found. So don't bother to query first. + neutron.deleteNetwork (networkId, tenantId, cloudSiteId); + LOGGER.recordMetricEvent (deleteNetworkStarttime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "DeleteNetwork", null); + } catch (MsoException me) { + me.addContext ("RollbackNetwork"); + String error = "Rollback Network (neutron): " + networkId + + " in " + + cloudSiteId + + "/" + + tenantId + + ": " + + me; + LOGGER.recordMetricEvent (deleteNetworkStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "DeleteNetwork", null); + LOGGER.error (MessageEnum.RA_DELETE_NETWORK_EXC, networkId, cloudSiteId, tenantId, "OpenStack", "", MsoLogger.ErrorCode.BusinessProcesssError, "Exception - Rollback Network (neutron)", me); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error); + throw new NetworkException (me); + } + } else { // DEFAULT to if ("HEAT".equals (mode)) + long deleteStackStarttime = System.currentTimeMillis (); + try { + // The deleteStack function in MsoHeatUtils returns success if the stack + // was not found. So don't bother to query first. + heat.deleteStack (tenantId, cloudSiteId, networkId, true); + LOGGER.recordMetricEvent (deleteStackStarttime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "DeleteStack", null); + } catch (MsoException me) { + me.addContext ("RollbackNetwork"); + String error = "Rollback Network (heat): " + networkId + + " in " + + cloudSiteId + + "/" + + tenantId + + ": " + + me; + LOGGER.recordMetricEvent (deleteStackStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "DeleteStack", null); + LOGGER.error (MessageEnum.RA_DELETE_NETWORK_EXC, networkId, cloudSiteId, tenantId, "OpenStack", "", MsoLogger.ErrorCode.BusinessProcesssError, "Exception - Rollback Network (heat)", me); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error); + throw new NetworkException (me); + } + } + } + + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully rolled back network"); + return; + } + + private String validateNetworkParams (NetworkType neutronNetworkType, + String networkName, + String physicalNetwork, + List vlans, + List routeTargets) { + String sep = ""; + StringBuilder missing = new StringBuilder (); + if (commonUtils.isNullOrEmpty(networkName)) { + missing.append ("networkName"); + sep = ","; + } + + if (neutronNetworkType == NetworkType.PROVIDER || neutronNetworkType == NetworkType.MULTI_PROVIDER) { + if (commonUtils.isNullOrEmpty(physicalNetwork)) { + missing.append (sep).append ("physicalNetworkName"); + sep = ","; + } + if (vlans == null || vlans.isEmpty ()) { + missing.append (sep).append (VLANS); + } + } + + return missing.toString (); + } + + private Map populateNetworkParams (NetworkType neutronNetworkType, + String networkName, + String physicalNetwork, + List vlans, + List routeTargets, + String shared, + String external, + boolean aic3template) { + // Build the common set of HEAT template parameters + Map stackParams = new HashMap <> (); + stackParams.put ("network_name", networkName); + + if (neutronNetworkType == NetworkType.PROVIDER) { + // For Provider type + stackParams.put (PHYSICAL_NETWORK, physicalNetwork); + stackParams.put ("vlan", vlans.get (0).toString ()); + } else if (neutronNetworkType == NetworkType.MULTI_PROVIDER) { + // For Multi-provider, PO supports a custom resource extension of ProviderNet. + // It supports all ProviderNet properties except segmentation_id, and adds a + // comma-separated-list of VLANs as a "segments" property. + // Note that this does not match the Neutron definition of Multi-Provider network, + // which contains a list of 'segments', each having physical_network, network_type, + // and segmentation_id. + StringBuilder buf = new StringBuilder (); + String sep = ""; + for (Integer vlan : vlans) { + buf.append (sep).append (vlan.toString ()); + sep = ","; + } + String csl = buf.toString (); + + stackParams.put (PHYSICAL_NETWORK, physicalNetwork); + stackParams.put (VLANS, csl); + } + if (routeTargets != null) { + + String rtGlobal = ""; + String rtImport = ""; + String rtExport = ""; + String sep = ""; + for (RouteTarget rt : routeTargets) { + boolean rtIsNull = false; + if (rt != null) + { + String routeTarget = rt.getRouteTarget(); + String routeTargetRole = rt.getRouteTargetRole(); + LOGGER.debug("Checking for an actually null route target: " + rt.toString()); + if (routeTarget == null || routeTarget.equals("") || routeTarget.equalsIgnoreCase("null")) + rtIsNull = true; + if (routeTargetRole == null || routeTargetRole.equals("") || routeTargetRole.equalsIgnoreCase("null")) + rtIsNull = true; + } else { + rtIsNull = true; + } + if (!rtIsNull) { + LOGGER.debug("Input RT:" + rt.toString()); + String role = rt.getRouteTargetRole(); + String rtValue = rt.getRouteTarget(); + + if ("IMPORT".equalsIgnoreCase(role)) + { + sep = rtImport.isEmpty() ? "" : ","; + rtImport = aic3template ? rtImport + sep + "target:" + rtValue : rtImport + sep + rtValue ; + } + else if ("EXPORT".equalsIgnoreCase(role)) + { + sep = rtExport.isEmpty() ? "" : ","; + rtExport = aic3template ? rtExport + sep + "target:" + rtValue : rtExport + sep + rtValue ; + } + else // covers BOTH, empty etc + { + sep = rtGlobal.isEmpty() ? "" : ","; + rtGlobal = aic3template ? rtGlobal + sep + "target:" + rtValue : rtGlobal + sep + rtValue ; + } + + } + } + + if (!rtImport.isEmpty()) + { + stackParams.put ("route_targets_import", rtImport); + } + if (!rtExport.isEmpty()) + { + stackParams.put ("route_targets_export", rtExport); + } + if (!rtGlobal.isEmpty()) + { + stackParams.put ("route_targets", rtGlobal); + } + } + if (commonUtils.isNullOrEmpty(shared)) { + stackParams.put ("shared", "False"); + } else { + stackParams.put ("shared", shared); + } + if (commonUtils.isNullOrEmpty(external)) { + stackParams.put ("external", "False"); + } else { + stackParams.put ("external", external); + } + return stackParams; + } + + + + /** policyRef_list structure in stackParams + [ + { + "network_policy_refs_data_sequence": { + "network_policy_refs_data_sequence_major": "1", + "network_policy_refs_data_sequence_minor": "0" + } + }, + { + "network_policy_refs_data_sequence": { + "network_policy_refs_data_sequence_major": "2", + "network_policy_refs_data_sequence_minor": "0" + } + } + ] + **/ + private void mergePolicyRefs(List pFqdns, Map stackParams) throws MsoException { + //Resource Property + List prlist = new ArrayList <> (); + int index = 1; + for (String pf : pFqdns) { + if (!commonUtils.isNullOrEmpty(pf)) + { + ContrailPolicyRef pr = new ContrailPolicyRef(); + ContrailPolicyRefSeq refSeq = new ContrailPolicyRefSeq(String.valueOf(index), "0"); + pr.setSeq(refSeq); + index++; + LOGGER.debug("Contrail PolicyRefs Data:" + pr.toString()); + prlist.add(pr); + } + } + + JsonNode node = null; + try + { + ObjectMapper mapper = new ObjectMapper(); + node = mapper.convertValue(prlist, JsonNode.class); + String jsonString = mapper.writeValueAsString(prlist); + LOGGER.debug("Json PolicyRefs Data:" + jsonString); + } + catch (Exception e) + { + String error = "Error creating JsonNode for policyRefs Data"; + LOGGER.error (MessageEnum.RA_MARSHING_ERROR, error, "Openstack", "", MsoLogger.ErrorCode.BusinessProcesssError, "Exception creating JsonNode for policyRefs Data", e); + throw new MsoAdapterException (error); + } + //update parameters + if (pFqdns != null && node != null) + { + StringBuilder buf = new StringBuilder (); + String sep = ""; + for (String pf : pFqdns) { + if (!commonUtils.isNullOrEmpty(pf)) + { + buf.append (sep).append (pf); + sep = ","; + } + } + String csl = buf.toString (); + stackParams.put ("policy_refs", csl); + stackParams.put ("policy_refsdata", node); + } + + LOGGER.debug ("StackParams updated with policy refs"); + return; + } + + private void mergeRouteTableRefs(List rtFqdns, Map stackParams) throws MsoException { + + //update parameters + if (rtFqdns != null) + { + StringBuilder buf = new StringBuilder (); + String sep = ""; + for (String rtf : rtFqdns) { + if (!commonUtils.isNullOrEmpty(rtf)) + { + buf.append (sep).append (rtf); + sep = ","; + } + } + String csl = buf.toString (); + stackParams.put ("route_table_refs", csl); + } + + LOGGER.debug ("StackParams updated with route_table refs"); + return; + } + + + /*** Subnet Output structure from Juniper + { + "ipam_subnets": [ + { + "subnet": { + "ip_prefix": "10.100.1.0", + "ip_prefix_len": 28 + }, + "addr_from_start": null, + "enable_dhcp": false, + "default_gateway": "10.100.1.1", + "dns_nameservers": [], + "dhcp_option_list": null, + "subnet_uuid": "10391fbf-6b9c-4160-825d-2d018b7649cf", + "allocation_pools": [ + { + "start": "10.100.1.3", + "end": "10.100.1.5" + }, + { + "start": "10.100.1.6", + "end": "10.100.1.9" + } + ], + "host_routes": null, + "dns_server_address": "10.100.1.13", + "subnet_name": "subnet_MsoNW1_692c9032-e1a2-4d64-828c-7b9a4fcc05b0" + }, + { + "subnet": { + "ip_prefix": "10.100.2.16", + "ip_prefix_len": 28 + }, + "addr_from_start": null, + "enable_dhcp": true, + "default_gateway": "10.100.2.17", + "dns_nameservers": [], + "dhcp_option_list": null, + "subnet_uuid": "c7aac5ea-66fe-443a-85f9-9c38a608c0f6", + "allocation_pools": [ + { + "start": "10.100.2.18", + "end": "10.100.2.20" + } + ], + "host_routes": null, + "dns_server_address": "10.100.2.29", + "subnet_name": "subnet_MsoNW1_692c9032-e1a2-4d64-828c-7b9a4fcc05b1" + } + ], + "host_routes": null + } + ***/ + private String mergeSubnetsAIC3 (String heatTemplate, List subnets, Map stackParams) throws MsoException { + + //Resource Property + List cslist = new ArrayList <> (); + for (Subnet subnet : subnets) { + LOGGER.debug("Input Subnet:" + subnet.toString()); + ContrailSubnet cs = new ContrailSubnetMapper(subnet).map(); + LOGGER.debug("Contrail Subnet:" + cs.toString()); + cslist.add(cs); + } + + JsonNode node = null; + try + { + ObjectMapper mapper = new ObjectMapper(); + node = mapper.convertValue(cslist, JsonNode.class); + String jsonString = mapper.writeValueAsString(cslist); + LOGGER.debug("Json Subnet List:" + jsonString); + } + catch (Exception e) + { + String error = "Error creating JsonNode from input subnets"; + LOGGER.error (MessageEnum.RA_MARSHING_ERROR, error, "", "", MsoLogger.ErrorCode.DataError, "Exception creating JsonNode from input subnets", e); + throw new MsoAdapterException (error); + } + //update parameters + if (node != null) + { + stackParams.put ("subnet_list", node); + } + //Outputs - All subnets are in one ipam_subnets structure + String outputTempl = " subnet:\n" + " description: Openstack subnet identifier\n" + + " value: { get_attr: [network, network_ipam_refs, 0, attr]}\n"; + + // append outputs in heatTemplate + int outputsIdx = heatTemplate.indexOf ("outputs:"); + heatTemplate = insertStr (heatTemplate, outputTempl, outputsIdx + 8); + LOGGER.debug ("Template updated with all AIC3.0 subnets:" + heatTemplate); + return heatTemplate; + } + + + private String mergeSubnets (String heatTemplate, List subnets) throws MsoException { + + String resourceTempl = " subnet_%subnetId%:\n" + " type: OS::Neutron::Subnet\n" + + " properties:\n" + + " name: %name%\n" + + " network_id: { get_resource: network }\n" + + " cidr: %cidr%\n"; + + /* make these optional + + " ip_version: %ipversion%\n" + + " enable_dhcp: %enabledhcp%\n" + + " gateway_ip: %gatewayip%\n" + + " allocation_pools:\n" + + " - start: %poolstart%\n" + + " end: %poolend%\n"; + + */ + + String outputTempl = " subnet_id_%subnetId%:\n" + " description: Openstack subnet identifier\n" + + " value: {get_resource: subnet_%subnetId%}\n"; + + String curR; + String curO; + StringBuilder resourcesBuf = new StringBuilder (); + StringBuilder outputsBuf = new StringBuilder (); + for (Subnet subnet : subnets) { + + // build template for each subnet + curR = resourceTempl; + if (subnet.getSubnetId () != null) { + curR = curR.replace ("%subnetId%", subnet.getSubnetId ()); + } else { + String error = "Missing Required AAI SubnetId for subnet in HEAT Template"; + LOGGER.error (MessageEnum.RA_MISSING_PARAM, error, "Openstack", "", MsoLogger.ErrorCode.DataError, "Missing Required AAI ID for subnet in HEAT Template"); + throw new MsoAdapterException (error); + } + + if (subnet.getSubnetName () != null) { + curR = curR.replace ("%name%", subnet.getSubnetName ()); + } else { + curR = curR.replace ("%name%", subnet.getSubnetId ()); + } + + if (subnet.getCidr () != null) { + curR = curR.replace ("%cidr%", subnet.getCidr ()); + } else { + String error = "Missing Required cidr for subnet in HEAT Template"; + LOGGER.error (MessageEnum.RA_MISSING_PARAM, error, "Openstack", "", MsoLogger.ErrorCode.DataError, "Missing Required cidr for subnet in HEAT Template"); + throw new MsoAdapterException (error); + } + + if (subnet.getIpVersion () != null) { + curR = curR + " ip_version: " + subnet.getIpVersion () + "\n"; + } + if (subnet.getEnableDHCP () != null) { + curR = curR + " enable_dhcp: " + Boolean.toString (subnet.getEnableDHCP ()) + "\n"; + } + if (subnet.getGatewayIp () != null && !subnet.getGatewayIp ().isEmpty() ) { + curR = curR + " gateway_ip: " + subnet.getGatewayIp () + "\n"; + } + + if (subnet.getAllocationPools() != null) { + curR = curR + " allocation_pools:\n"; + for (Pool pool : subnet.getAllocationPools()) + { + if (!commonUtils.isNullOrEmpty(pool.getStart()) && !commonUtils.isNullOrEmpty(pool.getEnd())) + { + curR = curR + " - start: " + pool.getStart () + "\n"; + curR = curR + " end: " + pool.getEnd () + "\n"; + } + } + } + + resourcesBuf.append (curR); + + curO = outputTempl; + curO = curO.replace ("%subnetId%", subnet.getSubnetId ()); + + outputsBuf.append (curO); + + } + // append resources and outputs in heatTemplate + LOGGER.debug ("Tempate initial:" + heatTemplate); + int outputsIdx = heatTemplate.indexOf ("outputs:"); + heatTemplate = insertStr (heatTemplate, outputsBuf.toString (), outputsIdx + 8); + int resourcesIdx = heatTemplate.indexOf ("resources:"); + heatTemplate = insertStr (heatTemplate, resourcesBuf.toString (), resourcesIdx + 10); + + LOGGER.debug ("Template updated with all subnets:" + heatTemplate); + return heatTemplate; + } + + private Map getSubnetUUId(String key, Map outputs, List subnets) { + + Map sMap = new HashMap <> (); + + try{ + Object obj = outputs.get(key); + ObjectMapper mapper = new ObjectMapper(); + String jStr = mapper.writeValueAsString(obj); + LOGGER.debug ("Subnet_Ipam Output JSON String:" + obj.getClass() + " " + jStr); + + JsonNode rootNode = mapper.readTree(jStr); + for (JsonNode sNode : rootNode.path("ipam_subnets")) + { + LOGGER.debug("Output Subnet Node" + sNode.toString()); + String name = sNode.path("subnet_name").textValue(); + String uuid = sNode.path("subnet_uuid").textValue(); + String aaiId = name; // default + // try to find aaiId for name in input subnetList + if (subnets != null) + { + for (Subnet subnet : subnets) + { + if ( subnet != null && !commonUtils.isNullOrEmpty(subnet.getSubnetName())) + { + if (subnet.getSubnetName().equals(name)) + { + aaiId = subnet.getSubnetId(); + break; + } + } + } + } + sMap.put(aaiId, uuid); //bpmn needs aaid to uuid map + } + } + catch (Exception e) + { + LOGGER.error (MessageEnum.RA_MARSHING_ERROR, "error getting subnet-uuids", "Openstack", "", MsoLogger.ErrorCode.DataError, "Exception getting subnet-uuids", e); + } + + LOGGER.debug ("Return sMap" + sMap.toString()); + return sMap; + } + + private static String insertStr (String template, String snippet, int index) { + + String updatedTemplate; + + LOGGER.debug ("Index:" + index + " Snippet:" + snippet); + + String templateBeg = template.substring (0, index); + String templateEnd = template.substring (index); + + updatedTemplate = templateBeg + "\n" + snippet + templateEnd; + + LOGGER.debug ("Template updated with a subnet:" + updatedTemplate); + return updatedTemplate; + } + +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/NetworkAdapterRest.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/NetworkAdapterRest.java new file mode 100644 index 0000000000..465fb6d866 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/NetworkAdapterRest.java @@ -0,0 +1,671 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * Copyright (C) 2017 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.so.adapters.network; + + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.inject.Provider; +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.GenericEntity; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.xml.ws.Holder; + +import org.apache.http.HttpStatus; +import org.onap.so.adapters.network.exceptions.NetworkException; +import org.onap.so.adapters.nwrest.ContrailNetwork; +import org.onap.so.adapters.nwrest.CreateNetworkError; +import org.onap.so.adapters.nwrest.CreateNetworkRequest; +import org.onap.so.adapters.nwrest.CreateNetworkResponse; +import org.onap.so.adapters.nwrest.DeleteNetworkError; +import org.onap.so.adapters.nwrest.DeleteNetworkRequest; +import org.onap.so.adapters.nwrest.DeleteNetworkResponse; +import org.onap.so.adapters.nwrest.ProviderVlanNetwork; +import org.onap.so.adapters.nwrest.QueryNetworkError; +import org.onap.so.adapters.nwrest.QueryNetworkResponse; +import org.onap.so.adapters.nwrest.RollbackNetworkError; +import org.onap.so.adapters.nwrest.RollbackNetworkRequest; +import org.onap.so.adapters.nwrest.RollbackNetworkResponse; +import org.onap.so.adapters.nwrest.UpdateNetworkError; +import org.onap.so.adapters.nwrest.UpdateNetworkRequest; +import org.onap.so.adapters.nwrest.UpdateNetworkResponse; +import org.onap.so.entity.MsoRequest; +import org.onap.so.logger.MessageEnum; +import org.onap.so.logger.MsoLogger; +import org.onap.so.openstack.beans.NetworkRollback; +import org.onap.so.openstack.beans.NetworkStatus; +import org.onap.so.openstack.beans.RouteTarget; +import org.onap.so.openstack.exceptions.MsoExceptionCategory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import io.swagger.annotations.ApiResponse; +import io.swagger.annotations.ApiResponses; + +@Path("/v1/networks") +@Api(value = "/v1/networks", description = "root of network adapters restful web service") +@Component +@Transactional +public class NetworkAdapterRest { + private static final MsoLogger LOGGER = MsoLogger.getMsoLogger (MsoLogger.Catalog.RA,NetworkAdapterRest.class); + private static final String TESTING_KEYWORD = "___TESTING___"; + + + + @Autowired + private MsoNetworkAdapterImpl adapter; + @Autowired + @Qualifier("NetworkBpel") + private Provider bpelRestClientProvider; + + + @POST + @Path("") + @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @ApiOperation(value = "CreateNetwork", + response = Response.class, + notes = "Creates a new network, CreateNetworkRquest JSON is required") + @ApiResponses({ + @ApiResponse(code = 200, message = "network has been successfully created"), + @ApiResponse(code = 202, message = "create network request has been accepted (async only)"), + @ApiResponse(code = 500, message = "create network failed, examine entity object for details") }) + public Response createNetwork( + @ApiParam(value = "details of network being created", required = true) + CreateNetworkRequest req) { + LOGGER.debug("createNetwork enter: " + req.toJsonString()); + CreateNetworkTask task = new CreateNetworkTask(req); + if (req.isSynchronous()) { + // This is a synchronous request + task.run(); + return Response + .status(task.getStatusCode()) + .entity(task.getGenericEntityResponse()) + .build(); + } else { + // This is an asynchronous request + try { + Thread t1 = new Thread(task); + t1.start(); + } catch (Exception e) { + // problem handling create, send generic failure as sync resp to caller + LOGGER.error (MessageEnum.RA_CREATE_NETWORK_EXC, "", "", MsoLogger.ErrorCode.BusinessProcesssError, "Exception while create network", e); + return Response.serverError().build(); + } + // send sync response (ACK) to caller + LOGGER.debug ("createNetwork exit"); + return Response.status(HttpStatus.SC_ACCEPTED).build(); + } + } + + public class CreateNetworkTask implements Runnable { + private final CreateNetworkRequest req; + private CreateNetworkResponse response = null; + private CreateNetworkError eresp = null; + private boolean sendxml; + + public CreateNetworkTask(CreateNetworkRequest req) { + this.req = req; + this.sendxml = true; // can be set with a field or header later + } + public int getStatusCode() { + return (response != null) ? HttpStatus.SC_OK : HttpStatus.SC_BAD_REQUEST; + } + public Object getGenericEntityResponse() { + return (response != null) + ? new GenericEntity(response) {} + : new GenericEntity(eresp) {}; + } + private String getResponse() { + if (response != null) { + return sendxml ? response.toXmlString() : response.toJsonString(); + } else { + return sendxml ? eresp.toXmlString() : eresp.toJsonString(); + } + } + @Override + public void run() { + LOGGER.debug ("CreateNetworkTask start"); + try { + // Synchronous Web Service Outputs + Holder networkId = new Holder<>(); + Holder neutronNetworkId = new Holder<>(); + Holder networkFqdn = new Holder<>(); + Holder> subnetIdMap = new Holder<>(); + Holder rollback = new Holder<>(); + + String cloudsite = req.getCloudSiteId(); + if (cloudsite != null && cloudsite.equals(TESTING_KEYWORD)) { + String tenant = req.getTenantId(); + if (tenant != null && tenant.equals(TESTING_KEYWORD)) { + throw new NetworkException("testing."); + } + networkId.value = "479D3D8B-6360-47BC-AB75-21CC91981484"; + neutronNetworkId.value = "55e55884-28fa-11e6-8971-0017f20fe1b8"; + networkFqdn.value = "086f70b6-28fb-11e6-8260-0017f20fe1b8"; + subnetIdMap.value = testMap(); + rollback.value = new NetworkRollback(); + } else if (req.isContrailRequest()) { + ContrailNetwork ctn = req.getContrailNetwork(); + if (ctn == null) { + ctn = new ContrailNetwork(); + req.setContrailNetwork(ctn); + } + adapter.createNetworkContrail( + req.getCloudSiteId(), + req.getTenantId(), + req.getNetworkType(), + req.getModelCustomizationUuid(), + req.getNetworkName(), + req.getContrailNetwork().getRouteTargets(), + req.getContrailNetwork().getShared(), + req.getContrailNetwork().getExternal(), + req.getFailIfExists(), + req.getBackout(), + req.getSubnets(), + req.getContrailNetwork().getPolicyFqdns(), + req.getContrailNetwork().getRouteTableFqdns(), + req.getMsoRequest(), + networkId, + neutronNetworkId, + networkFqdn, + subnetIdMap, + rollback); + } else { + ProviderVlanNetwork pvn = req.getProviderVlanNetwork(); + if (pvn == null) { + pvn = new ProviderVlanNetwork(); + req.setProviderVlanNetwork(pvn); + } + adapter.createNetwork( + req.getCloudSiteId(), + req.getTenantId(), + req.getNetworkType(), + req.getModelCustomizationUuid(), + req.getNetworkName(), + req.getProviderVlanNetwork().getPhysicalNetworkName(), + req.getProviderVlanNetwork().getVlans(), + req.getFailIfExists(), + req.getBackout(), + req.getSubnets(), + req.getMsoRequest(), + networkId, + neutronNetworkId, + subnetIdMap, + rollback); + } + response = new CreateNetworkResponse( + req.getNetworkId(), + neutronNetworkId.value, + rollback.value.getNetworkStackId(), + networkFqdn.value, + rollback.value.getNetworkCreated(), + subnetIdMap.value, + rollback.value, + req.getMessageId()); + } catch (NetworkException e) { + LOGGER.debug ("Exception:", e); + eresp = new CreateNetworkError( + e.getMessage(), MsoExceptionCategory.INTERNAL, true, req.getMessageId()); + } + if (!req.isSynchronous()) { + // This is asynch, so POST response back to caller + BpelRestClient bpelClient = bpelRestClientProvider.get(); + bpelClient.bpelPost(getResponse(), req.getNotificationUrl(), sendxml); + } + LOGGER.debug ("CreateNetworkTask exit: code=" + getStatusCode() + ", resp="+ getResponse()); + } + } + + @DELETE + @Path("{aaiNetworkId}") + @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @ApiOperation(value = "DeleteNetwork", + response = Response.class, + notes = "Deletes an existing network, aaiNetworkId and DeleteNetworkRequest JSON are required") + @ApiResponses({ + @ApiResponse(code = 200, message = "network has been successfully deleted"), + @ApiResponse(code = 202, message = "request to delete network has been accepted (async only)"), + @ApiResponse(code = 500, message = "delete network failed, examine entity object for details") }) + public Response deleteNetwork( + @ApiParam(value = "aaiNetworkId to be deleted ", required = true) + @PathParam("aaiNetworkId") String aaiNetworkId, + @ApiParam(value = "details of network being deleted", required = true) + DeleteNetworkRequest req) + { + LOGGER.debug("deleteNetwork enter: " + req.toJsonString()); + if (aaiNetworkId == null || !aaiNetworkId.equals(req.getNetworkId())) { + return Response + .status(HttpStatus.SC_BAD_REQUEST) + .type(MediaType.TEXT_PLAIN) + .entity("A&AI NetworkId in URL ("+aaiNetworkId+") does not match content ("+req.getNetworkId()+")") + .build(); + } + DeleteNetworkTask task = new DeleteNetworkTask(req); + if (req.isSynchronous()) { + // This is a synchronous request + task.run(); + return Response + .status(task.getStatusCode()) + .entity(task.getGenericEntityResponse()) + .build(); + } else { + // This is an asynchronous request + try { + Thread t1 = new Thread(task); + t1.start(); + } catch (Exception e) { + // problem handling create, send generic failure as sync resp to caller + LOGGER.error (MessageEnum.RA_DELETE_NETWORK_EXC, "", "", MsoLogger.ErrorCode.BusinessProcesssError, "Exception while delete network", e); + return Response.serverError().build(); + } + // send sync response (ACK) to caller + LOGGER.debug ("deleteNetwork exit"); + return Response.status(HttpStatus.SC_ACCEPTED).build(); + } + } + + public class DeleteNetworkTask implements Runnable { + private final DeleteNetworkRequest req; + private DeleteNetworkResponse response = null; + private DeleteNetworkError eresp = null; + private boolean sendxml; + + public DeleteNetworkTask(DeleteNetworkRequest req) { + this.req = req; + this.sendxml = true; // can be set with a field or header later + } + public int getStatusCode() { + return (response != null) ? HttpStatus.SC_OK : HttpStatus.SC_BAD_REQUEST; + } + public Object getGenericEntityResponse() { + return (response != null) + ? new GenericEntity(response) {} + : new GenericEntity(eresp) {}; + } + private String getResponse() { + if (response != null) { + return sendxml ? response.toXmlString() : response.toJsonString(); + } else { + return sendxml ? eresp.toXmlString() : eresp.toJsonString(); + } + } + @Override + public void run() { + LOGGER.debug("DeleteNetworkTask start"); + try { + Holder networkDeleted = new Holder<>(); + if (req.getCloudSiteId().equals(TESTING_KEYWORD)) { + networkDeleted.value = true; + } else { + adapter.deleteNetwork( + req.getCloudSiteId(), + req.getTenantId(), + req.getNetworkType(), + req.getModelCustomizationUuid(), + req.getNetworkStackId(), + req.getMsoRequest(), + networkDeleted); + } + response = new DeleteNetworkResponse(req.getNetworkId(), networkDeleted.value, req.getMessageId()); + } catch (NetworkException e) { + LOGGER.debug ("Exception:", e); + eresp = new DeleteNetworkError(e.getMessage(), MsoExceptionCategory.INTERNAL, true, req.getMessageId()); + } + if (!req.isSynchronous()) { + // This is asynch, so POST response back to caller + BpelRestClient bpelClient = bpelRestClientProvider.get(); + bpelClient.bpelPost(getResponse(), req.getNotificationUrl(), sendxml); + } + LOGGER.debug("DeleteNetworkTask exit: code=" + getStatusCode() + ", resp="+ getResponse()); + } + } + + @GET + @Path("{aaiNetworkId}") + @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @ApiOperation(value = "QueryNetwork", + response = Response.class, + notes = "Queries an existing network") + @ApiResponses({ + @ApiResponse(code = 200, message = "Query network successful"), + @ApiResponse(code = 500, message = "Query network failed, examine entity object for details") }) + public Response queryNetwork( + @ApiParam(value = "cloudSiteId", required = false) + @QueryParam("cloudSiteId") String cloudSiteId, + @ApiParam(value = "tenantId", required = false) + @QueryParam("tenantId") String tenantId, + @ApiParam(value = "networkStackId", required = false) + @QueryParam("networkStackId") String networkStackId, + @ApiParam(value = "skipAAI", required = false) + @QueryParam("skipAAI") String skipAAI, + @ApiParam(value = "msoRequest.requestId", required = false) + @QueryParam("msoRequest.requestId") String requestId, + @ApiParam(value = "msoRequest.serviceInstanceId", required = false) + @QueryParam("msoRequest.serviceInstanceId") String serviceInstanceId, + @ApiParam(value = "aaiNetworkId", required = false) + @PathParam("aaiNetworkId") String aaiNetworkId) + { + //This request responds synchronously only + LOGGER.debug ("Query network enter:" + aaiNetworkId); + MsoRequest msoRequest = new MsoRequest(requestId, serviceInstanceId); + + try { + int respStatus = HttpStatus.SC_OK; + QueryNetworkResponse resp = new QueryNetworkResponse(networkStackId, null, networkStackId, null, null); + Holder networkExists = new Holder<>(); + Holder networkId = new Holder<>(); + Holder neutronNetworkId = new Holder<>(); + Holder status = new Holder<>(); + Holder> routeTargets = new Holder<>(); + Holder> subnetIdMap = new Holder<>(); + + adapter.queryNetworkContrail(cloudSiteId, tenantId, aaiNetworkId, msoRequest, + networkExists, networkId, neutronNetworkId, status, routeTargets, subnetIdMap); + + if (!networkExists.value) { + LOGGER.debug ("network not found"); + respStatus = HttpStatus.SC_NOT_FOUND; + } else { + LOGGER.debug ("network found" + networkId.value + ", status=" + status.value); + resp.setNetworkExists(networkExists.value); + resp.setNetworkId(networkId.value); + resp.setNeutronNetworkId(neutronNetworkId.value); + resp.setNetworkStatus(status.value); + resp.setRouteTargets(routeTargets.value); + resp.setSubnetIdMap(subnetIdMap.value); + } + LOGGER.debug ("Query network exit"); + return Response + .status(respStatus) + .entity(new GenericEntity(resp) {}) + .build(); + } catch (NetworkException e) { + LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, aaiNetworkId, "", "", MsoLogger.ErrorCode.BusinessProcesssError, "Exception when query VNF", e); + QueryNetworkError err = new QueryNetworkError(); + err.setMessage(e.getMessage()); + err.setCategory(MsoExceptionCategory.INTERNAL); + return Response + .status(HttpStatus.SC_INTERNAL_SERVER_ERROR) + .entity(new GenericEntity(err) {}) + .build(); + } + } + + @DELETE + @Path("{aaiNetworkId}/rollback") + @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @ApiOperation(value = "RollbackNetwork", + response = Response.class, + notes = "Rollback an existing network") + @ApiResponses({ + @ApiResponse(code = 200, message = "Rollback network successful"), + @ApiResponse(code = 202, message = "Rollback network request has been accepted (async only)"), + @ApiResponse(code = 500, message = "Rollback network failed, examine entity object for details") }) + public Response rollbackNetwork( + @ApiParam(value = "RollbackNetworkRequest in JSON format", required = true) + RollbackNetworkRequest req) + { + LOGGER.debug("rollbackNetwork enter: " + req.toJsonString()); + RollbackNetworkTask task = new RollbackNetworkTask(req); + if (req.isSynchronous()) { + // This is a synchronous request + task.run(); + return Response + .status(task.getStatusCode()) + .entity(task.getGenericEntityResponse()) + .build(); + } else { + // This is an asynchronous request + try { + Thread t1 = new Thread(task); + t1.start(); + } catch (Exception e) { + // problem handling create, send generic failure as sync resp to caller + LOGGER.error (MessageEnum.RA_ROLLBACK_NULL, "", "", MsoLogger.ErrorCode.BusinessProcesssError, "Exception in rollbackNetwork", e); + return Response.serverError().build(); + } + // send sync response (ACK) to caller + LOGGER.debug("rollbackNetwork exit"); + return Response.status(HttpStatus.SC_ACCEPTED).build(); + } + } + + public class RollbackNetworkTask implements Runnable { + private final RollbackNetworkRequest req; + private RollbackNetworkResponse response = null; + private RollbackNetworkError eresp = null; + private boolean sendxml; + + public RollbackNetworkTask(RollbackNetworkRequest req) { + this.req = req; + this.sendxml = true; // can be set with a field or header later + } + public int getStatusCode() { + return (response != null) ? HttpStatus.SC_OK : HttpStatus.SC_BAD_REQUEST; + } + public Object getGenericEntityResponse() { + return (response != null) + ? new GenericEntity(response) {} + : new GenericEntity(eresp) {}; + } + private String getResponse() { + if (response != null) { + return sendxml ? response.toXmlString() : response.toJsonString(); + } else { + return sendxml ? eresp.toXmlString() : eresp.toJsonString(); + } + } + @Override + public void run() { + LOGGER.debug("RollbackNetworkTask start"); + try { + NetworkRollback nwr = req.getNetworkRollback(); + adapter.rollbackNetwork(nwr); + response = new RollbackNetworkResponse(true, req.getMessageId()); + } catch (NetworkException e) { + LOGGER.debug ("Exception:", e); + eresp = new RollbackNetworkError(e.getMessage(), MsoExceptionCategory.INTERNAL, true, req.getMessageId()); + } + if (!req.isSynchronous()) { + // This is asynch, so POST response back to caller + BpelRestClient bpelClient = bpelRestClientProvider.get(); + bpelClient.bpelPost(getResponse(), req.getNotificationUrl(), sendxml); + } + LOGGER.debug("RollbackNetworkTask exit: code=" + getStatusCode() + ", resp="+ getResponse()); + } + } + + @PUT + @Path("{aaiNetworkId}") + @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @ApiOperation(value = "UpdateNetwork", + response = Response.class, + notes = "Update an existing network") + @ApiResponses({ + @ApiResponse(code = 200, message = "Update network successful"), + @ApiResponse(code = 202, message = "Update network request has been accepted (async only)"), + @ApiResponse(code = 500, message = "Update network failed, examine entity object for details") }) + public Response updateNetwork( + @ApiParam(value = "aaiNetworkId", required = true) + @PathParam("aaiNetworkId") String aaiNetworkId, + @ApiParam(value = "UpdateNetworkRequest in JSON format", required = true) + UpdateNetworkRequest req) + { + LOGGER.debug("updateNetwork enter: " + req.toJsonString()); + if (aaiNetworkId == null || !aaiNetworkId.equals(req.getNetworkId())) { + return Response + .status(HttpStatus.SC_BAD_REQUEST) + .type(MediaType.TEXT_PLAIN) + .entity("A&AI NetworkId in URL ("+aaiNetworkId+") does not match content ("+req.getNetworkId()+")") + .build(); + } + UpdateNetworkTask task = new UpdateNetworkTask(req); + if (req.isSynchronous()) { + // This is a synchronous request + task.run(); + return Response + .status(task.getStatusCode()) + .entity(task.getGenericEntityResponse()) + .build(); + } else { + // This is an asynchronous request + try { + Thread t1 = new Thread(task); + t1.start(); + } catch (Exception e) { + // problem handling create, send generic failure as sync resp to caller + LOGGER.error (MessageEnum.RA_UPDATE_NETWORK_ERR, "", "", MsoLogger.ErrorCode.BusinessProcesssError, "Exception in updateNetwork", e); + return Response.serverError().build(); + } + // send sync response (ACK) to caller + LOGGER.debug ("updateNetwork exit"); + return Response.status(HttpStatus.SC_ACCEPTED).build(); + } + } + + public class UpdateNetworkTask implements Runnable { + private final UpdateNetworkRequest req; + private UpdateNetworkResponse response = null; + private UpdateNetworkError eresp = null; + private boolean sendxml; + + public UpdateNetworkTask(UpdateNetworkRequest req) { + this.req = req; + this.sendxml = true; // can be set with a field or header later + } + public int getStatusCode() { + return (response != null) ? HttpStatus.SC_OK : HttpStatus.SC_BAD_REQUEST; + } + public Object getGenericEntityResponse() { + return (response != null) + ? new GenericEntity(response) {} + : new GenericEntity(eresp) {}; + } + private String getResponse() { + if (response != null) { + return sendxml ? response.toXmlString() : response.toJsonString(); + } else { + return sendxml ? eresp.toXmlString() : eresp.toJsonString(); + } + } + @Override + public void run() { + LOGGER.debug("UpdateNetworkTask start"); + try { + Holder> subnetIdMap = new Holder<>(); + Holder rollback = new Holder<> (); + + if (req.getCloudSiteId().equals(TESTING_KEYWORD)) { + subnetIdMap.value = testMap(); + NetworkRollback rb = new NetworkRollback (); + rb.setCloudId(req.getCloudSiteId()); + rb.setTenantId(req.getTenantId()); + rb.setMsoRequest(req.getMsoRequest()); + rollback.value = rb; + } else if (req.isContrailRequest()) { + ContrailNetwork ctn = req.getContrailNetwork(); + if (ctn == null) { + ctn = new ContrailNetwork(); + req.setContrailNetwork(ctn); + } + adapter.updateNetworkContrail( + req.getCloudSiteId(), + req.getTenantId(), + req.getNetworkType(), + req.getModelCustomizationUuid(), + req.getNetworkStackId(), + req.getNetworkName(), + req.getContrailNetwork().getRouteTargets(), + req.getContrailNetwork().getShared(), + req.getContrailNetwork().getExternal(), + req.getSubnets(), + req.getContrailNetwork().getPolicyFqdns(), + req.getContrailNetwork().getRouteTableFqdns(), + req.getMsoRequest(), + subnetIdMap, + rollback); + } else { + ProviderVlanNetwork pvn = req.getProviderVlanNetwork(); + if (pvn == null) { + pvn = new ProviderVlanNetwork(); + req.setProviderVlanNetwork(pvn); + } + adapter.updateNetwork( + req.getCloudSiteId(), + req.getTenantId(), + req.getNetworkType(), + req.getModelCustomizationUuid(), + req.getNetworkStackId(), + req.getNetworkName(), + req.getProviderVlanNetwork().getPhysicalNetworkName(), + req.getProviderVlanNetwork().getVlans(), + req.getSubnets(), + req.getMsoRequest(), + subnetIdMap, + rollback); + } + response = new UpdateNetworkResponse( + req.getNetworkId(), + null, // NeutronNetworkId is not available from an update + subnetIdMap.value, + req.getMessageId()); + } catch (NetworkException e) { + LOGGER.debug ("Exception:", e); + eresp = new UpdateNetworkError(e.getMessage(), MsoExceptionCategory.INTERNAL, true, req.getMessageId()); + } + if (!req.isSynchronous()) { + // This is asynch, so POST response back to caller + BpelRestClient bpelClient = bpelRestClientProvider.get(); + bpelClient.bpelPost(getResponse(), req.getNotificationUrl(), sendxml); + } + LOGGER.debug("UpdateNetworkTask exit: code=" + getStatusCode() + ", resp="+ getResponse()); + } + } + + public static Map testMap() { + Map m = new HashMap<>(); + m.put("mickey", "7"); + m.put("clyde", "10"); + m.put("wayne", "99"); + return m; + } +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/CreateNetworkNotification.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/CreateNetworkNotification.java new file mode 100644 index 0000000000..8135088d7c --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/CreateNetworkNotification.java @@ -0,0 +1,437 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.so.adapters.network.async.client; + +import java.util.ArrayList; +import java.util.List; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlType; + + +/** + *

Java class for createNetworkNotification complex type. + * + *

The following schema fragment specifies the expected content contained within this class. + * + *

+ * <complexType name="createNetworkNotification">
+ *   <complexContent>
+ *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *       <sequence>
+ *         <element name="messageId" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ *         <element name="completed" type="{http://www.w3.org/2001/XMLSchema}boolean"/>
+ *         <element name="exception" type="{http://org.onap.so/networkNotify}msoExceptionCategory" minOccurs="0"/>
+ *         <element name="errorMessage" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
+ *         <element name="networkId" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
+ *         <element name="neutronNetworkId" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
+ *         <element name="subnetIdMap" minOccurs="0">
+ *           <complexType>
+ *             <complexContent>
+ *               <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *                 <sequence>
+ *                   <element name="entry" maxOccurs="unbounded" minOccurs="0">
+ *                     <complexType>
+ *                       <complexContent>
+ *                         <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *                           <sequence>
+ *                             <element name="key" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
+ *                             <element name="value" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
+ *                           </sequence>
+ *                         </restriction>
+ *                       </complexContent>
+ *                     </complexType>
+ *                   </element>
+ *                 </sequence>
+ *               </restriction>
+ *             </complexContent>
+ *           </complexType>
+ *         </element>
+ *         <element name="rollback" type="{http://org.onap.so/networkNotify}networkRollback" minOccurs="0"/>
+ *       </sequence>
+ *     </restriction>
+ *   </complexContent>
+ * </complexType>
+ * 
+ * + * + */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "createNetworkNotification", propOrder = { + "messageId", + "completed", + "exception", + "errorMessage", + "networkId", + "neutronNetworkId", + "subnetIdMap", + "rollback" +}) +public class CreateNetworkNotification { + + @XmlElement(required = true) + protected String messageId; + protected boolean completed; + protected MsoExceptionCategory exception; + protected String errorMessage; + protected String networkId; + protected String neutronNetworkId; + protected CreateNetworkNotification.SubnetIdMap subnetIdMap; + protected NetworkRollback rollback; + + /** + * Gets the value of the messageId property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getMessageId() { + return messageId; + } + + /** + * Sets the value of the messageId property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setMessageId(String value) { + this.messageId = value; + } + + /** + * Gets the value of the completed property. + * + */ + public boolean isCompleted() { + return completed; + } + + /** + * Sets the value of the completed property. + * + */ + public void setCompleted(boolean value) { + this.completed = value; + } + + /** + * Gets the value of the exception property. + * + * @return + * possible object is + * {@link MsoExceptionCategory } + * + */ + public MsoExceptionCategory getException() { + return exception; + } + + /** + * Sets the value of the exception property. + * + * @param value + * allowed object is + * {@link MsoExceptionCategory } + * + */ + public void setException(MsoExceptionCategory value) { + this.exception = value; + } + + /** + * Gets the value of the errorMessage property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getErrorMessage() { + return errorMessage; + } + + /** + * Sets the value of the errorMessage property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setErrorMessage(String value) { + this.errorMessage = value; + } + + /** + * Gets the value of the networkId property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getNetworkId() { + return networkId; + } + + /** + * Sets the value of the networkId property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setNetworkId(String value) { + this.networkId = value; + } + + /** + * Gets the value of the neutronNetworkId property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getNeutronNetworkId() { + return neutronNetworkId; + } + + /** + * Sets the value of the neutronNetworkId property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setNeutronNetworkId(String value) { + this.neutronNetworkId = value; + } + + /** + * Gets the value of the subnetIdMap property. + * + * @return + * possible object is + * {@link CreateNetworkNotification.SubnetIdMap } + * + */ + public CreateNetworkNotification.SubnetIdMap getSubnetIdMap() { + return subnetIdMap; + } + + /** + * Sets the value of the subnetIdMap property. + * + * @param value + * allowed object is + * {@link CreateNetworkNotification.SubnetIdMap } + * + */ + public void setSubnetIdMap(CreateNetworkNotification.SubnetIdMap value) { + this.subnetIdMap = value; + } + + /** + * Gets the value of the rollback property. + * + * @return + * possible object is + * {@link NetworkRollback } + * + */ + public NetworkRollback getRollback() { + return rollback; + } + + /** + * Sets the value of the rollback property. + * + * @param value + * allowed object is + * {@link NetworkRollback } + * + */ + public void setRollback(NetworkRollback value) { + this.rollback = value; + } + + + /** + *

Java class for anonymous complex type. + * + *

The following schema fragment specifies the expected content contained within this class. + * + *

+     * <complexType>
+     *   <complexContent>
+     *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+     *       <sequence>
+     *         <element name="entry" maxOccurs="unbounded" minOccurs="0">
+     *           <complexType>
+     *             <complexContent>
+     *               <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+     *                 <sequence>
+     *                   <element name="key" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
+     *                   <element name="value" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
+     *                 </sequence>
+     *               </restriction>
+     *             </complexContent>
+     *           </complexType>
+     *         </element>
+     *       </sequence>
+     *     </restriction>
+     *   </complexContent>
+     * </complexType>
+     * 
+ * + * + */ + @XmlAccessorType(XmlAccessType.FIELD) + @XmlType(name = "", propOrder = { + "entry" + }) + public static class SubnetIdMap { + + protected List entry; + + /** + * Gets the value of the entry property. + * + *

+ * This accessor method returns a reference to the live list, + * not a snapshot. Therefore any modification you make to the + * returned list will be present inside the JAXB object. + * This is why there is not a set method for the entry property. + * + *

+ * For example, to add a new item, do as follows: + *

+         *    getEntry().add(newItem);
+         * 
+ * + * + *

+ * Objects of the following type(s) are allowed in the list + * {@link CreateNetworkNotification.SubnetIdMap.Entry } + * + * + */ + public List getEntry() { + if (entry == null) { + entry = new ArrayList(); + } + return this.entry; + } + + + /** + *

Java class for anonymous complex type. + * + *

The following schema fragment specifies the expected content contained within this class. + * + *

+         * <complexType>
+         *   <complexContent>
+         *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+         *       <sequence>
+         *         <element name="key" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
+         *         <element name="value" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
+         *       </sequence>
+         *     </restriction>
+         *   </complexContent>
+         * </complexType>
+         * 
+ * + * + */ + @XmlAccessorType(XmlAccessType.FIELD) + @XmlType(name = "", propOrder = { + "key", + "value" + }) + public static class Entry { + + protected String key; + protected String value; + + /** + * Gets the value of the key property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getKey() { + return key; + } + + /** + * Sets the value of the key property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setKey(String value) { + this.key = value; + } + + /** + * Gets the value of the value property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getValue() { + return value; + } + + /** + * Sets the value of the value property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setValue(String value) { + this.value = value; + } + + } + + } + +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/CreateNetworkNotificationResponse.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/CreateNetworkNotificationResponse.java new file mode 100644 index 0000000000..a0e40c0e6a --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/CreateNetworkNotificationResponse.java @@ -0,0 +1,51 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.so.adapters.network.async.client; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlType; + + +/** + *

Java class for createNetworkNotificationResponse complex type. + * + *

The following schema fragment specifies the expected content contained within this class. + * + *

+ * <complexType name="createNetworkNotificationResponse">
+ *   <complexContent>
+ *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *       <sequence>
+ *       </sequence>
+ *     </restriction>
+ *   </complexContent>
+ * </complexType>
+ * 
+ * + * + */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "createNetworkNotificationResponse") +public class CreateNetworkNotificationResponse { + + +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/DeleteNetworkNotification.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/DeleteNetworkNotification.java new file mode 100644 index 0000000000..d4f992a9b4 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/DeleteNetworkNotification.java @@ -0,0 +1,181 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.so.adapters.network.async.client; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlType; + + +/** + *

Java class for deleteNetworkNotification complex type. + * + *

The following schema fragment specifies the expected content contained within this class. + * + *

+ * <complexType name="deleteNetworkNotification">
+ *   <complexContent>
+ *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *       <sequence>
+ *         <element name="messageId" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ *         <element name="completed" type="{http://www.w3.org/2001/XMLSchema}boolean"/>
+ *         <element name="exception" type="{http://org.onap.so/networkNotify}msoExceptionCategory" minOccurs="0"/>
+ *         <element name="errorMessage" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
+ *         <element name="networkDeleted" type="{http://www.w3.org/2001/XMLSchema}boolean" minOccurs="0"/>
+ *       </sequence>
+ *     </restriction>
+ *   </complexContent>
+ * </complexType>
+ * 
+ * + * + */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "deleteNetworkNotification", propOrder = { + "messageId", + "completed", + "exception", + "errorMessage", + "networkDeleted" +}) +public class DeleteNetworkNotification { + + @XmlElement(required = true) + protected String messageId; + protected boolean completed; + protected MsoExceptionCategory exception; + protected String errorMessage; + protected Boolean networkDeleted; + + /** + * Gets the value of the messageId property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getMessageId() { + return messageId; + } + + /** + * Sets the value of the messageId property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setMessageId(String value) { + this.messageId = value; + } + + /** + * Gets the value of the completed property. + * + */ + public boolean isCompleted() { + return completed; + } + + /** + * Sets the value of the completed property. + * + */ + public void setCompleted(boolean value) { + this.completed = value; + } + + /** + * Gets the value of the exception property. + * + * @return + * possible object is + * {@link MsoExceptionCategory } + * + */ + public MsoExceptionCategory getException() { + return exception; + } + + /** + * Sets the value of the exception property. + * + * @param value + * allowed object is + * {@link MsoExceptionCategory } + * + */ + public void setException(MsoExceptionCategory value) { + this.exception = value; + } + + /** + * Gets the value of the errorMessage property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getErrorMessage() { + return errorMessage; + } + + /** + * Sets the value of the errorMessage property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setErrorMessage(String value) { + this.errorMessage = value; + } + + /** + * Gets the value of the networkDeleted property. + * + * @return + * possible object is + * {@link Boolean } + * + */ + public Boolean isNetworkDeleted() { + return networkDeleted; + } + + /** + * Sets the value of the networkDeleted property. + * + * @param value + * allowed object is + * {@link Boolean } + * + */ + public void setNetworkDeleted(Boolean value) { + this.networkDeleted = value; + } + +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/DeleteNetworkNotificationResponse.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/DeleteNetworkNotificationResponse.java new file mode 100644 index 0000000000..76eb8115d5 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/DeleteNetworkNotificationResponse.java @@ -0,0 +1,51 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.so.adapters.network.async.client; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlType; + + +/** + *

Java class for deleteNetworkNotificationResponse complex type. + * + *

The following schema fragment specifies the expected content contained within this class. + * + *

+ * <complexType name="deleteNetworkNotificationResponse">
+ *   <complexContent>
+ *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *       <sequence>
+ *       </sequence>
+ *     </restriction>
+ *   </complexContent>
+ * </complexType>
+ * 
+ * + * + */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "deleteNetworkNotificationResponse") +public class DeleteNetworkNotificationResponse { + + +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/MsoExceptionCategory.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/MsoExceptionCategory.java new file mode 100644 index 0000000000..8c18a59e68 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/MsoExceptionCategory.java @@ -0,0 +1,61 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.so.adapters.network.async.client; + +import javax.xml.bind.annotation.XmlEnum; +import javax.xml.bind.annotation.XmlType; + + +/** + *

Java class for msoExceptionCategory. + * + *

The following schema fragment specifies the expected content contained within this class. + *

+ *

+ * <simpleType name="msoExceptionCategory">
+ *   <restriction base="{http://www.w3.org/2001/XMLSchema}string">
+ *     <enumeration value="OPENSTACK"/>
+ *     <enumeration value="IO"/>
+ *     <enumeration value="INTERNAL"/>
+ *     <enumeration value="USERDATA"/>
+ *   </restriction>
+ * </simpleType>
+ * 
+ * + */ +@XmlType(name = "msoExceptionCategory") +@XmlEnum +public enum MsoExceptionCategory { + + OPENSTACK, + IO, + INTERNAL, + USERDATA; + + public String value() { + return name(); + } + + public static MsoExceptionCategory fromValue(String v) { + return valueOf(v); + } + +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/MsoRequest.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/MsoRequest.java new file mode 100644 index 0000000000..aa6f34f2e0 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/MsoRequest.java @@ -0,0 +1,106 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.so.adapters.network.async.client; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlType; + + +/** + *

Java class for msoRequest complex type. + * + *

The following schema fragment specifies the expected content contained within this class. + * + *

+ * <complexType name="msoRequest">
+ *   <complexContent>
+ *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *       <sequence>
+ *         <element name="requestId" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
+ *         <element name="serviceInstanceId" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
+ *       </sequence>
+ *     </restriction>
+ *   </complexContent>
+ * </complexType>
+ * 
+ * + * + */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "msoRequest", propOrder = { + "requestId", + "serviceInstanceId" +}) +public class MsoRequest { + + protected String requestId; + protected String serviceInstanceId; + + /** + * Gets the value of the requestId property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getRequestId() { + return requestId; + } + + /** + * Sets the value of the requestId property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setRequestId(String value) { + this.requestId = value; + } + + /** + * Gets the value of the serviceInstanceId property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getServiceInstanceId() { + return serviceInstanceId; + } + + /** + * Sets the value of the serviceInstanceId property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setServiceInstanceId(String value) { + this.serviceInstanceId = value; + } + +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/NetworkAdapterNotify.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/NetworkAdapterNotify.java new file mode 100644 index 0000000000..0433aab0cc --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/NetworkAdapterNotify.java @@ -0,0 +1,191 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.so.adapters.network.async.client; + +import java.util.List; + +import javax.jws.WebMethod; +import javax.jws.WebParam; +import javax.jws.WebService; +import javax.xml.bind.annotation.XmlSeeAlso; +import javax.xml.ws.Action; +import javax.xml.ws.RequestWrapper; +import javax.xml.ws.ResponseWrapper; + + +/** + * This class was generated by the JAX-WS RI. + * JAX-WS RI 2.2.9-b14002 + * Generated source version: 2.2 + * + */ +@WebService(name = "networkAdapterNotify", targetNamespace = "http://org.onap.so/networkNotify") +@XmlSeeAlso({ + ObjectFactory.class +}) +public interface NetworkAdapterNotify { + + + /** + * + * @param exception + * @param errorMessage + * @param messageId + * @param completed + */ + @WebMethod + @RequestWrapper(localName = "rollbackNetworkNotification", targetNamespace = "http://org.onap.so/networkNotify", className = "org.onap.so.adapters.network.async.client.RollbackNetworkNotification") + @ResponseWrapper(localName = "rollbackNetworkNotificationResponse", targetNamespace = "http://org.onap.so/networkNotify", className = "org.onap.so.adapters.network.async.client.RollbackNetworkNotificationResponse") + @Action(input = "http://org.onap.so/notify/adapterNotify/rollbackNetworkNotificationRequest", output = "http://org.onap.so/notify/adapterNotify/rollbackNetworkNotificationResponse") + public void rollbackNetworkNotification( + @WebParam(name = "messageId", targetNamespace = "") + String messageId, + @WebParam(name = "completed", targetNamespace = "") + boolean completed, + @WebParam(name = "exception", targetNamespace = "") + MsoExceptionCategory exception, + @WebParam(name = "errorMessage", targetNamespace = "") + String errorMessage); + + /** + * + * @param exception + * @param vlans + * @param networkExists + * @param errorMessage + * @param messageId + * @param networkId + * @param completed + * @param neutronNetworkId + * @param status + * @param subnetIdMap + */ + @WebMethod + @RequestWrapper(localName = "queryNetworkNotification", targetNamespace = "http://org.onap.so/networkNotify", className = "org.onap.so.adapters.network.async.client.QueryNetworkNotification") + @ResponseWrapper(localName = "queryNetworkNotificationResponse", targetNamespace = "http://org.onap.so/networkNotify", className = "org.onap.so.adapters.network.async.client.QueryNetworkNotificationResponse") + @Action(input = "http://org.onap.so/notify/adapterNotify/queryNetworkNotificationRequest", output = "http://org.onap.so/notify/adapterNotify/queryNetworkNotificationResponse") + public void queryNetworkNotification( + @WebParam(name = "messageId", targetNamespace = "") + String messageId, + @WebParam(name = "completed", targetNamespace = "") + boolean completed, + @WebParam(name = "exception", targetNamespace = "") + MsoExceptionCategory exception, + @WebParam(name = "errorMessage", targetNamespace = "") + String errorMessage, + @WebParam(name = "networkExists", targetNamespace = "") + Boolean networkExists, + @WebParam(name = "networkId", targetNamespace = "") + String networkId, + @WebParam(name = "neutronNetworkId", targetNamespace = "") + String neutronNetworkId, + @WebParam(name = "status", targetNamespace = "") + NetworkStatus status, + @WebParam(name = "vlans", targetNamespace = "") + List vlans, + @WebParam(name = "subnetIdMap", targetNamespace = "") + org.onap.so.adapters.network.async.client.QueryNetworkNotification.SubnetIdMap subnetIdMap); + + /** + * + * @param exception + * @param rollback + * @param errorMessage + * @param messageId + * @param networkId + * @param completed + * @param neutronNetworkId + * @param subnetIdMap + */ + @WebMethod + @RequestWrapper(localName = "createNetworkNotification", targetNamespace = "http://org.onap.so/networkNotify", className = "org.onap.so.adapters.network.async.client.CreateNetworkNotification") + @ResponseWrapper(localName = "createNetworkNotificationResponse", targetNamespace = "http://org.onap.so/networkNotify", className = "org.onap.so.adapters.network.async.client.CreateNetworkNotificationResponse") + @Action(input = "http://org.onap.so/notify/adapterNotify/createNetworkNotificationRequest", output = "http://org.onap.so/notify/adapterNotify/createNetworkNotificationResponse") + public void createNetworkNotification( + @WebParam(name = "messageId", targetNamespace = "") + String messageId, + @WebParam(name = "completed", targetNamespace = "") + boolean completed, + @WebParam(name = "exception", targetNamespace = "") + MsoExceptionCategory exception, + @WebParam(name = "errorMessage", targetNamespace = "") + String errorMessage, + @WebParam(name = "networkId", targetNamespace = "") + String networkId, + @WebParam(name = "neutronNetworkId", targetNamespace = "") + String neutronNetworkId, + @WebParam(name = "subnetIdMap", targetNamespace = "") + org.onap.so.adapters.network.async.client.CreateNetworkNotification.SubnetIdMap subnetIdMap, + @WebParam(name = "rollback", targetNamespace = "") + NetworkRollback rollback); + + /** + * + * @param exception + * @param networkDeleted + * @param errorMessage + * @param messageId + * @param completed + */ + @WebMethod + @RequestWrapper(localName = "deleteNetworkNotification", targetNamespace = "http://org.onap.so/networkNotify", className = "org.onap.so.adapters.network.async.client.DeleteNetworkNotification") + @ResponseWrapper(localName = "deleteNetworkNotificationResponse", targetNamespace = "http://org.onap.so/networkNotify", className = "org.onap.so.adapters.network.async.client.DeleteNetworkNotificationResponse") + @Action(input = "http://org.onap.so/notify/adapterNotify/deleteNetworkNotificationRequest", output = "http://org.onap.so/notify/adapterNotify/deleteNetworkNotificationResponse") + public void deleteNetworkNotification( + @WebParam(name = "messageId", targetNamespace = "") + String messageId, + @WebParam(name = "completed", targetNamespace = "") + boolean completed, + @WebParam(name = "exception", targetNamespace = "") + MsoExceptionCategory exception, + @WebParam(name = "errorMessage", targetNamespace = "") + String errorMessage, + @WebParam(name = "networkDeleted", targetNamespace = "") + Boolean networkDeleted); + + /** + * + * @param exception + * @param rollback + * @param errorMessage + * @param messageId + * @param completed + * @param subnetIdMap + */ + @WebMethod + @RequestWrapper(localName = "updateNetworkNotification", targetNamespace = "http://org.onap.so/networkNotify", className = "org.onap.so.adapters.network.async.client.UpdateNetworkNotification") + @ResponseWrapper(localName = "updateNetworkNotificationResponse", targetNamespace = "http://org.onap.so/networkNotify", className = "org.onap.so.adapters.network.async.client.UpdateNetworkNotificationResponse") + @Action(input = "http://org.onap.so/notify/adapterNotify/updateNetworkNotificationRequest", output = "http://org.onap.so/notify/adapterNotify/updateNetworkNotificationResponse") + public void updateNetworkNotification( + @WebParam(name = "messageId", targetNamespace = "") + String messageId, + @WebParam(name = "completed", targetNamespace = "") + boolean completed, + @WebParam(name = "exception", targetNamespace = "") + MsoExceptionCategory exception, + @WebParam(name = "errorMessage", targetNamespace = "") + String errorMessage, + @WebParam(name = "subnetIdMap", targetNamespace = "") + org.onap.so.adapters.network.async.client.UpdateNetworkNotification.SubnetIdMap subnetIdMap, + @WebParam(name = "rollback", targetNamespace = "") + NetworkRollback rollback); + +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/NetworkAdapterNotify_Service.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/NetworkAdapterNotify_Service.java new file mode 100644 index 0000000000..fb69db702a --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/NetworkAdapterNotify_Service.java @@ -0,0 +1,110 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.so.adapters.network.async.client; + +import java.net.URL; + +import javax.xml.namespace.QName; +import javax.xml.ws.Service; +import javax.xml.ws.WebEndpoint; +import javax.xml.ws.WebServiceClient; +import javax.xml.ws.WebServiceException; +import javax.xml.ws.WebServiceFeature; + + +/** + * This class was generated by the JAX-WS RI. + * JAX-WS RI 2.2.9-b14002 + * Generated source version: 2.2 + * + */ +@WebServiceClient(name = "networkAdapterNotify", targetNamespace = "http://org.onap.so/networkNotify", wsdlLocation = "/NetworkAdapterNotify.wsdl") +public class NetworkAdapterNotify_Service + extends Service +{ + + private final static URL NETWORKADAPTERNOTIFY_WSDL_LOCATION; + private final static WebServiceException NETWORKADAPTERNOTIFY_EXCEPTION; + private final static QName NETWORKADAPTERNOTIFY_QNAME = new QName("http://org.onap.so/networkNotify", "networkAdapterNotify"); + + static { + NETWORKADAPTERNOTIFY_WSDL_LOCATION = org.onap.so.adapters.network.async.client.NetworkAdapterNotify_Service.class.getResource("/NetworkAdapterNotify.wsdl"); + WebServiceException e = null; + if (NETWORKADAPTERNOTIFY_WSDL_LOCATION == null) { + e = new WebServiceException("Cannot find '/NetworkAdapterNotify.wsdl' wsdl. Place the resource correctly in the classpath."); + } + NETWORKADAPTERNOTIFY_EXCEPTION = e; + } + + public NetworkAdapterNotify_Service() { + super(__getWsdlLocation(), NETWORKADAPTERNOTIFY_QNAME); + } + + public NetworkAdapterNotify_Service(WebServiceFeature... features) { + super(__getWsdlLocation(), NETWORKADAPTERNOTIFY_QNAME, features); + } + + public NetworkAdapterNotify_Service(URL wsdlLocation) { + super(wsdlLocation, NETWORKADAPTERNOTIFY_QNAME); + } + + public NetworkAdapterNotify_Service(URL wsdlLocation, WebServiceFeature... features) { + super(wsdlLocation, NETWORKADAPTERNOTIFY_QNAME, features); + } + + public NetworkAdapterNotify_Service(URL wsdlLocation, QName serviceName) { + super(wsdlLocation, serviceName); + } + + public NetworkAdapterNotify_Service(URL wsdlLocation, QName serviceName, WebServiceFeature... features) { + super(wsdlLocation, serviceName, features); + } + + /** + * + * @return + * returns NetworkAdapterNotify + */ + @WebEndpoint(name = "MsoNetworkAdapterAsyncImplPort") + public NetworkAdapterNotify getMsoNetworkAdapterAsyncImplPort() { + return super.getPort(new QName("http://org.onap.so/networkNotify", "MsoNetworkAdapterAsyncImplPort"), NetworkAdapterNotify.class); + } + + /** + * + * @param features + * A list of {@link javax.xml.ws.WebServiceFeature} to configure on the proxy. Supported features not in the features parameter will have their default values. + * @return + * returns NetworkAdapterNotify + */ + @WebEndpoint(name = "MsoNetworkAdapterAsyncImplPort") + public NetworkAdapterNotify getMsoNetworkAdapterAsyncImplPort(WebServiceFeature... features) { + return super.getPort(new QName("http://org.onap.so/networkNotify", "MsoNetworkAdapterAsyncImplPort"), NetworkAdapterNotify.class, features); + } + + private static URL __getWsdlLocation() { + if (NETWORKADAPTERNOTIFY_EXCEPTION!= null) { + throw NETWORKADAPTERNOTIFY_EXCEPTION; + } + return NETWORKADAPTERNOTIFY_WSDL_LOCATION; + } + +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/NetworkRollback.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/NetworkRollback.java new file mode 100644 index 0000000000..4fde850a53 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/NetworkRollback.java @@ -0,0 +1,370 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.so.adapters.network.async.client; + +import java.util.ArrayList; +import java.util.List; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlType; + + +/** + *

Java class for networkRollback complex type. + * + *

The following schema fragment specifies the expected content contained within this class. + * + *

+ * <complexType name="networkRollback">
+ *   <complexContent>
+ *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *       <sequence>
+ *         <element name="cloudId" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
+ *         <element name="msoRequest" type="{http://org.onap.so/networkNotify}msoRequest" minOccurs="0"/>
+ *         <element name="networkCreated" type="{http://www.w3.org/2001/XMLSchema}boolean"/>
+ *         <element name="networkId" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
+ *         <element name="networkStackId" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
+ *         <element name="networkName" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
+ *         <element name="networkType" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
+ *         <element name="networkUpdated" type="{http://www.w3.org/2001/XMLSchema}boolean"/>
+ *         <element name="neutronNetworkId" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
+ *         <element name="physicalNetwork" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
+ *         <element name="tenantId" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
+ *         <element name="vlans" type="{http://www.w3.org/2001/XMLSchema}int" maxOccurs="unbounded" minOccurs="0"/>
+ *       </sequence>
+ *     </restriction>
+ *   </complexContent>
+ * </complexType>
+ * 
+ * + * + */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "networkRollback", propOrder = { + "cloudId", + "msoRequest", + "networkCreated", + "networkId", + "networkStackId", + "networkName", + "networkType", + "networkUpdated", + "neutronNetworkId", + "physicalNetwork", + "tenantId", + "vlans" +}) +public class NetworkRollback { + + protected String cloudId; + protected MsoRequest msoRequest; + protected boolean networkCreated; + protected String networkId; + protected String networkStackId; + protected String networkName; + protected String networkType; + protected boolean networkUpdated; + protected String neutronNetworkId; + protected String physicalNetwork; + protected String tenantId; + @XmlElement(nillable = true) + protected List vlans; + + /** + * Gets the value of the cloudId property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getCloudId() { + return cloudId; + } + + /** + * Sets the value of the cloudId property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setCloudId(String value) { + this.cloudId = value; + } + + /** + * Gets the value of the msoRequest property. + * + * @return + * possible object is + * {@link MsoRequest } + * + */ + public MsoRequest getMsoRequest() { + return msoRequest; + } + + /** + * Sets the value of the msoRequest property. + * + * @param value + * allowed object is + * {@link MsoRequest } + * + */ + public void setMsoRequest(MsoRequest value) { + this.msoRequest = value; + } + + /** + * Gets the value of the networkCreated property. + * + */ + public boolean isNetworkCreated() { + return networkCreated; + } + + /** + * Sets the value of the networkCreated property. + * + */ + public void setNetworkCreated(boolean value) { + this.networkCreated = value; + } + + /** + * Gets the value of the networkId property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getNetworkId() { + return networkId; + } + + /** + * Sets the value of the networkId property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setNetworkId(String value) { + this.networkId = value; + } + + /** + * Gets the value of the networkStackId property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getNetworkStackId() { + return networkStackId; + } + + /** + * Sets the value of the networkStackId property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setNetworkStackId(String value) { + this.networkStackId = value; + } + + /** + * Gets the value of the networkName property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getNetworkName() { + return networkName; + } + + /** + * Sets the value of the networkName property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setNetworkName(String value) { + this.networkName = value; + } + + /** + * Gets the value of the networkType property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getNetworkType() { + return networkType; + } + + /** + * Sets the value of the networkType property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setNetworkType(String value) { + this.networkType = value; + } + + /** + * Gets the value of the networkUpdated property. + * + */ + public boolean isNetworkUpdated() { + return networkUpdated; + } + + /** + * Sets the value of the networkUpdated property. + * + */ + public void setNetworkUpdated(boolean value) { + this.networkUpdated = value; + } + + /** + * Gets the value of the neutronNetworkId property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getNeutronNetworkId() { + return neutronNetworkId; + } + + /** + * Sets the value of the neutronNetworkId property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setNeutronNetworkId(String value) { + this.neutronNetworkId = value; + } + + /** + * Gets the value of the physicalNetwork property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getPhysicalNetwork() { + return physicalNetwork; + } + + /** + * Sets the value of the physicalNetwork property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setPhysicalNetwork(String value) { + this.physicalNetwork = value; + } + + /** + * Gets the value of the tenantId property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getTenantId() { + return tenantId; + } + + /** + * Sets the value of the tenantId property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setTenantId(String value) { + this.tenantId = value; + } + + /** + * Gets the value of the vlans property. + * + *

+ * This accessor method returns a reference to the live list, + * not a snapshot. Therefore any modification you make to the + * returned list will be present inside the JAXB object. + * This is why there is not a set method for the vlans property. + * + *

+ * For example, to add a new item, do as follows: + *

+     *    getVlans().add(newItem);
+     * 
+ * + * + *

+ * Objects of the following type(s) are allowed in the list + * {@link Integer } + * + * + */ + public List getVlans() { + if (vlans == null) { + vlans = new ArrayList(); + } + return this.vlans; + } + +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/NetworkStatus.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/NetworkStatus.java new file mode 100644 index 0000000000..982f214bd8 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/NetworkStatus.java @@ -0,0 +1,65 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.so.adapters.network.async.client; + +import javax.xml.bind.annotation.XmlEnum; +import javax.xml.bind.annotation.XmlType; + + +/** + *

Java class for networkStatus. + * + *

The following schema fragment specifies the expected content contained within this class. + *

+ *

+ * <simpleType name="networkStatus">
+ *   <restriction base="{http://www.w3.org/2001/XMLSchema}string">
+ *     <enumeration value="NOTFOUND"/>
+ *     <enumeration value="ACTIVE"/>
+ *     <enumeration value="DOWN"/>
+ *     <enumeration value="BUILD"/>
+ *     <enumeration value="ERROR"/>
+ *     <enumeration value="UNKNOWN"/>
+ *   </restriction>
+ * </simpleType>
+ * 
+ * + */ +@XmlType(name = "networkStatus") +@XmlEnum +public enum NetworkStatus { + + NOTFOUND, + ACTIVE, + DOWN, + BUILD, + ERROR, + UNKNOWN; + + public String value() { + return name(); + } + + public static NetworkStatus fromValue(String v) { + return valueOf(v); + } + +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/ObjectFactory.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/ObjectFactory.java new file mode 100644 index 0000000000..91243769aa --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/ObjectFactory.java @@ -0,0 +1,298 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.so.adapters.network.async.client; + +import javax.xml.bind.JAXBElement; +import javax.xml.bind.annotation.XmlElementDecl; +import javax.xml.bind.annotation.XmlRegistry; +import javax.xml.namespace.QName; + + +/** + * This object contains factory methods for each + * Java content interface and Java element interface + * generated in the org.onap.so.adapters.network.async.client package. + *

An ObjectFactory allows you to programatically + * construct new instances of the Java representation + * for XML content. The Java representation of XML + * content can consist of schema derived interfaces + * and classes representing the binding of schema + * type definitions, element declarations and model + * groups. Factory methods for each of these are + * provided in this class. + * + */ +@XmlRegistry +public class ObjectFactory { + + private final static QName _RollbackNetworkNotification_QNAME = new QName("http://org.onap.so/networkNotify", "rollbackNetworkNotification"); + private final static QName _UpdateNetworkNotification_QNAME = new QName("http://org.onap.so/networkNotify", "updateNetworkNotification"); + private final static QName _QueryNetworkNotificationResponse_QNAME = new QName("http://org.onap.so/networkNotify", "queryNetworkNotificationResponse"); + private final static QName _UpdateNetworkNotificationResponse_QNAME = new QName("http://org.onap.so/networkNotify", "updateNetworkNotificationResponse"); + private final static QName _CreateNetworkNotificationResponse_QNAME = new QName("http://org.onap.so/networkNotify", "createNetworkNotificationResponse"); + private final static QName _DeleteNetworkNotification_QNAME = new QName("http://org.onap.so/networkNotify", "deleteNetworkNotification"); + private final static QName _DeleteNetworkNotificationResponse_QNAME = new QName("http://org.onap.so/networkNotify", "deleteNetworkNotificationResponse"); + private final static QName _CreateNetworkNotification_QNAME = new QName("http://org.onap.so/networkNotify", "createNetworkNotification"); + private final static QName _QueryNetworkNotification_QNAME = new QName("http://org.onap.so/networkNotify", "queryNetworkNotification"); + private final static QName _RollbackNetworkNotificationResponse_QNAME = new QName("http://org.onap.so/networkNotify", "rollbackNetworkNotificationResponse"); + + /** + * Create a new ObjectFactory that can be used to create new instances of schema derived classes for package: org.onap.so.adapters.network.async.client + * + */ + public ObjectFactory() { + } + + /** + * Create an instance of {@link QueryNetworkNotification } + * + */ + public QueryNetworkNotification createQueryNetworkNotification() { + return new QueryNetworkNotification(); + } + + /** + * Create an instance of {@link QueryNetworkNotification.SubnetIdMap } + * + */ + public QueryNetworkNotification.SubnetIdMap createQueryNetworkNotificationSubnetIdMap() { + return new QueryNetworkNotification.SubnetIdMap(); + } + + /** + * Create an instance of {@link CreateNetworkNotification } + * + */ + public CreateNetworkNotification createCreateNetworkNotification() { + return new CreateNetworkNotification(); + } + + /** + * Create an instance of {@link CreateNetworkNotification.SubnetIdMap } + * + */ + public CreateNetworkNotification.SubnetIdMap createCreateNetworkNotificationSubnetIdMap() { + return new CreateNetworkNotification.SubnetIdMap(); + } + + /** + * Create an instance of {@link UpdateNetworkNotification } + * + */ + public UpdateNetworkNotification createUpdateNetworkNotification() { + return new UpdateNetworkNotification(); + } + + /** + * Create an instance of {@link UpdateNetworkNotification.SubnetIdMap } + * + */ + public UpdateNetworkNotification.SubnetIdMap createUpdateNetworkNotificationSubnetIdMap() { + return new UpdateNetworkNotification.SubnetIdMap(); + } + + /** + * Create an instance of {@link UpdateNetworkNotificationResponse } + * + */ + public UpdateNetworkNotificationResponse createUpdateNetworkNotificationResponse() { + return new UpdateNetworkNotificationResponse(); + } + + /** + * Create an instance of {@link CreateNetworkNotificationResponse } + * + */ + public CreateNetworkNotificationResponse createCreateNetworkNotificationResponse() { + return new CreateNetworkNotificationResponse(); + } + + /** + * Create an instance of {@link RollbackNetworkNotification } + * + */ + public RollbackNetworkNotification createRollbackNetworkNotification() { + return new RollbackNetworkNotification(); + } + + /** + * Create an instance of {@link QueryNetworkNotificationResponse } + * + */ + public QueryNetworkNotificationResponse createQueryNetworkNotificationResponse() { + return new QueryNetworkNotificationResponse(); + } + + /** + * Create an instance of {@link RollbackNetworkNotificationResponse } + * + */ + public RollbackNetworkNotificationResponse createRollbackNetworkNotificationResponse() { + return new RollbackNetworkNotificationResponse(); + } + + /** + * Create an instance of {@link DeleteNetworkNotification } + * + */ + public DeleteNetworkNotification createDeleteNetworkNotification() { + return new DeleteNetworkNotification(); + } + + /** + * Create an instance of {@link DeleteNetworkNotificationResponse } + * + */ + public DeleteNetworkNotificationResponse createDeleteNetworkNotificationResponse() { + return new DeleteNetworkNotificationResponse(); + } + + /** + * Create an instance of {@link NetworkRollback } + * + */ + public NetworkRollback createNetworkRollback() { + return new NetworkRollback(); + } + + /** + * Create an instance of {@link MsoRequest } + * + */ + public MsoRequest createMsoRequest() { + return new MsoRequest(); + } + + /** + * Create an instance of {@link QueryNetworkNotification.SubnetIdMap.Entry } + * + */ + public QueryNetworkNotification.SubnetIdMap.Entry createQueryNetworkNotificationSubnetIdMapEntry() { + return new QueryNetworkNotification.SubnetIdMap.Entry(); + } + + /** + * Create an instance of {@link CreateNetworkNotification.SubnetIdMap.Entry } + * + */ + public CreateNetworkNotification.SubnetIdMap.Entry createCreateNetworkNotificationSubnetIdMapEntry() { + return new CreateNetworkNotification.SubnetIdMap.Entry(); + } + + /** + * Create an instance of {@link UpdateNetworkNotification.SubnetIdMap.Entry } + * + */ + public UpdateNetworkNotification.SubnetIdMap.Entry createUpdateNetworkNotificationSubnetIdMapEntry() { + return new UpdateNetworkNotification.SubnetIdMap.Entry(); + } + + /** + * Create an instance of {@link JAXBElement }{@code <}{@link RollbackNetworkNotification }{@code >}} + * + */ + @XmlElementDecl(namespace = "http://org.onap.so/networkNotify", name = "rollbackNetworkNotification") + public JAXBElement createRollbackNetworkNotification(RollbackNetworkNotification value) { + return new JAXBElement(_RollbackNetworkNotification_QNAME, RollbackNetworkNotification.class, null, value); + } + + /** + * Create an instance of {@link JAXBElement }{@code <}{@link UpdateNetworkNotification }{@code >}} + * + */ + @XmlElementDecl(namespace = "http://org.onap.so/networkNotify", name = "updateNetworkNotification") + public JAXBElement createUpdateNetworkNotification(UpdateNetworkNotification value) { + return new JAXBElement(_UpdateNetworkNotification_QNAME, UpdateNetworkNotification.class, null, value); + } + + /** + * Create an instance of {@link JAXBElement }{@code <}{@link QueryNetworkNotificationResponse }{@code >}} + * + */ + @XmlElementDecl(namespace = "http://org.onap.so/networkNotify", name = "queryNetworkNotificationResponse") + public JAXBElement createQueryNetworkNotificationResponse(QueryNetworkNotificationResponse value) { + return new JAXBElement(_QueryNetworkNotificationResponse_QNAME, QueryNetworkNotificationResponse.class, null, value); + } + + /** + * Create an instance of {@link JAXBElement }{@code <}{@link UpdateNetworkNotificationResponse }{@code >}} + * + */ + @XmlElementDecl(namespace = "http://org.onap.so/networkNotify", name = "updateNetworkNotificationResponse") + public JAXBElement createUpdateNetworkNotificationResponse(UpdateNetworkNotificationResponse value) { + return new JAXBElement(_UpdateNetworkNotificationResponse_QNAME, UpdateNetworkNotificationResponse.class, null, value); + } + + /** + * Create an instance of {@link JAXBElement }{@code <}{@link CreateNetworkNotificationResponse }{@code >}} + * + */ + @XmlElementDecl(namespace = "http://org.onap.so/networkNotify", name = "createNetworkNotificationResponse") + public JAXBElement createCreateNetworkNotificationResponse(CreateNetworkNotificationResponse value) { + return new JAXBElement(_CreateNetworkNotificationResponse_QNAME, CreateNetworkNotificationResponse.class, null, value); + } + + /** + * Create an instance of {@link JAXBElement }{@code <}{@link DeleteNetworkNotification }{@code >}} + * + */ + @XmlElementDecl(namespace = "http://org.onap.so/networkNotify", name = "deleteNetworkNotification") + public JAXBElement createDeleteNetworkNotification(DeleteNetworkNotification value) { + return new JAXBElement(_DeleteNetworkNotification_QNAME, DeleteNetworkNotification.class, null, value); + } + + /** + * Create an instance of {@link JAXBElement }{@code <}{@link DeleteNetworkNotificationResponse }{@code >}} + * + */ + @XmlElementDecl(namespace = "http://org.onap.so/networkNotify", name = "deleteNetworkNotificationResponse") + public JAXBElement createDeleteNetworkNotificationResponse(DeleteNetworkNotificationResponse value) { + return new JAXBElement(_DeleteNetworkNotificationResponse_QNAME, DeleteNetworkNotificationResponse.class, null, value); + } + + /** + * Create an instance of {@link JAXBElement }{@code <}{@link CreateNetworkNotification }{@code >}} + * + */ + @XmlElementDecl(namespace = "http://org.onap.so/networkNotify", name = "createNetworkNotification") + public JAXBElement createCreateNetworkNotification(CreateNetworkNotification value) { + return new JAXBElement(_CreateNetworkNotification_QNAME, CreateNetworkNotification.class, null, value); + } + + /** + * Create an instance of {@link JAXBElement }{@code <}{@link QueryNetworkNotification }{@code >}} + * + */ + @XmlElementDecl(namespace = "http://org.onap.so/networkNotify", name = "queryNetworkNotification") + public JAXBElement createQueryNetworkNotification(QueryNetworkNotification value) { + return new JAXBElement(_QueryNetworkNotification_QNAME, QueryNetworkNotification.class, null, value); + } + + /** + * Create an instance of {@link JAXBElement }{@code <}{@link RollbackNetworkNotificationResponse }{@code >}} + * + */ + @XmlElementDecl(namespace = "http://org.onap.so/networkNotify", name = "rollbackNetworkNotificationResponse") + public JAXBElement createRollbackNetworkNotificationResponse(RollbackNetworkNotificationResponse value) { + return new JAXBElement(_RollbackNetworkNotificationResponse_QNAME, RollbackNetworkNotificationResponse.class, null, value); + } + +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/QueryNetworkNotification.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/QueryNetworkNotification.java new file mode 100644 index 0000000000..55a8e3d0d1 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/QueryNetworkNotification.java @@ -0,0 +1,497 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.so.adapters.network.async.client; + +import java.util.ArrayList; +import java.util.List; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlType; + + +/** + *

Java class for queryNetworkNotification complex type. + * + *

The following schema fragment specifies the expected content contained within this class. + * + *

+ * <complexType name="queryNetworkNotification">
+ *   <complexContent>
+ *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *       <sequence>
+ *         <element name="messageId" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ *         <element name="completed" type="{http://www.w3.org/2001/XMLSchema}boolean"/>
+ *         <element name="exception" type="{http://org.onap.so/networkNotify}msoExceptionCategory" minOccurs="0"/>
+ *         <element name="errorMessage" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
+ *         <element name="networkExists" type="{http://www.w3.org/2001/XMLSchema}boolean" minOccurs="0"/>
+ *         <element name="networkId" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
+ *         <element name="neutronNetworkId" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
+ *         <element name="status" type="{http://org.onap.so/networkNotify}networkStatus" minOccurs="0"/>
+ *         <element name="vlans" type="{http://www.w3.org/2001/XMLSchema}int" maxOccurs="unbounded" minOccurs="0"/>
+ *         <element name="subnetIdMap" minOccurs="0">
+ *           <complexType>
+ *             <complexContent>
+ *               <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *                 <sequence>
+ *                   <element name="entry" maxOccurs="unbounded" minOccurs="0">
+ *                     <complexType>
+ *                       <complexContent>
+ *                         <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *                           <sequence>
+ *                             <element name="key" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
+ *                             <element name="value" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
+ *                           </sequence>
+ *                         </restriction>
+ *                       </complexContent>
+ *                     </complexType>
+ *                   </element>
+ *                 </sequence>
+ *               </restriction>
+ *             </complexContent>
+ *           </complexType>
+ *         </element>
+ *       </sequence>
+ *     </restriction>
+ *   </complexContent>
+ * </complexType>
+ * 
+ * + * + */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "queryNetworkNotification", propOrder = { + "messageId", + "completed", + "exception", + "errorMessage", + "networkExists", + "networkId", + "neutronNetworkId", + "status", + "vlans", + "subnetIdMap" +}) +public class QueryNetworkNotification { + + @XmlElement(required = true) + protected String messageId; + protected boolean completed; + protected MsoExceptionCategory exception; + protected String errorMessage; + protected Boolean networkExists; + protected String networkId; + protected String neutronNetworkId; + protected NetworkStatus status; + @XmlElement(type = Integer.class) + protected List vlans; + protected QueryNetworkNotification.SubnetIdMap subnetIdMap; + + /** + * Gets the value of the messageId property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getMessageId() { + return messageId; + } + + /** + * Sets the value of the messageId property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setMessageId(String value) { + this.messageId = value; + } + + /** + * Gets the value of the completed property. + * + */ + public boolean isCompleted() { + return completed; + } + + /** + * Sets the value of the completed property. + * + */ + public void setCompleted(boolean value) { + this.completed = value; + } + + /** + * Gets the value of the exception property. + * + * @return + * possible object is + * {@link MsoExceptionCategory } + * + */ + public MsoExceptionCategory getException() { + return exception; + } + + /** + * Sets the value of the exception property. + * + * @param value + * allowed object is + * {@link MsoExceptionCategory } + * + */ + public void setException(MsoExceptionCategory value) { + this.exception = value; + } + + /** + * Gets the value of the errorMessage property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getErrorMessage() { + return errorMessage; + } + + /** + * Sets the value of the errorMessage property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setErrorMessage(String value) { + this.errorMessage = value; + } + + /** + * Gets the value of the networkExists property. + * + * @return + * possible object is + * {@link Boolean } + * + */ + public Boolean isNetworkExists() { + return networkExists; + } + + /** + * Sets the value of the networkExists property. + * + * @param value + * allowed object is + * {@link Boolean } + * + */ + public void setNetworkExists(Boolean value) { + this.networkExists = value; + } + + /** + * Gets the value of the networkId property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getNetworkId() { + return networkId; + } + + /** + * Sets the value of the networkId property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setNetworkId(String value) { + this.networkId = value; + } + + /** + * Gets the value of the neutronNetworkId property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getNeutronNetworkId() { + return neutronNetworkId; + } + + /** + * Sets the value of the neutronNetworkId property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setNeutronNetworkId(String value) { + this.neutronNetworkId = value; + } + + /** + * Gets the value of the status property. + * + * @return + * possible object is + * {@link NetworkStatus } + * + */ + public NetworkStatus getStatus() { + return status; + } + + /** + * Sets the value of the status property. + * + * @param value + * allowed object is + * {@link NetworkStatus } + * + */ + public void setStatus(NetworkStatus value) { + this.status = value; + } + + /** + * Gets the value of the vlans property. + * + *

+ * This accessor method returns a reference to the live list, + * not a snapshot. Therefore any modification you make to the + * returned list will be present inside the JAXB object. + * This is why there is not a set method for the vlans property. + * + *

+ * For example, to add a new item, do as follows: + *

+     *    getVlans().add(newItem);
+     * 
+ * + * + *

+ * Objects of the following type(s) are allowed in the list + * {@link Integer } + * + * + */ + public List getVlans() { + if (vlans == null) { + vlans = new ArrayList(); + } + return this.vlans; + } + + /** + * Gets the value of the subnetIdMap property. + * + * @return + * possible object is + * {@link QueryNetworkNotification.SubnetIdMap } + * + */ + public QueryNetworkNotification.SubnetIdMap getSubnetIdMap() { + return subnetIdMap; + } + + /** + * Sets the value of the subnetIdMap property. + * + * @param value + * allowed object is + * {@link QueryNetworkNotification.SubnetIdMap } + * + */ + public void setSubnetIdMap(QueryNetworkNotification.SubnetIdMap value) { + this.subnetIdMap = value; + } + + + /** + *

Java class for anonymous complex type. + * + *

The following schema fragment specifies the expected content contained within this class. + * + *

+     * <complexType>
+     *   <complexContent>
+     *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+     *       <sequence>
+     *         <element name="entry" maxOccurs="unbounded" minOccurs="0">
+     *           <complexType>
+     *             <complexContent>
+     *               <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+     *                 <sequence>
+     *                   <element name="key" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
+     *                   <element name="value" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
+     *                 </sequence>
+     *               </restriction>
+     *             </complexContent>
+     *           </complexType>
+     *         </element>
+     *       </sequence>
+     *     </restriction>
+     *   </complexContent>
+     * </complexType>
+     * 
+ * + * + */ + @XmlAccessorType(XmlAccessType.FIELD) + @XmlType(name = "", propOrder = { + "entry" + }) + public static class SubnetIdMap { + + protected List entry; + + /** + * Gets the value of the entry property. + * + *

+ * This accessor method returns a reference to the live list, + * not a snapshot. Therefore any modification you make to the + * returned list will be present inside the JAXB object. + * This is why there is not a set method for the entry property. + * + *

+ * For example, to add a new item, do as follows: + *

+         *    getEntry().add(newItem);
+         * 
+ * + * + *

+ * Objects of the following type(s) are allowed in the list + * {@link QueryNetworkNotification.SubnetIdMap.Entry } + * + * + */ + public List getEntry() { + if (entry == null) { + entry = new ArrayList(); + } + return this.entry; + } + + + /** + *

Java class for anonymous complex type. + * + *

The following schema fragment specifies the expected content contained within this class. + * + *

+         * <complexType>
+         *   <complexContent>
+         *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+         *       <sequence>
+         *         <element name="key" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
+         *         <element name="value" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
+         *       </sequence>
+         *     </restriction>
+         *   </complexContent>
+         * </complexType>
+         * 
+ * + * + */ + @XmlAccessorType(XmlAccessType.FIELD) + @XmlType(name = "", propOrder = { + "key", + "value" + }) + public static class Entry { + + protected String key; + protected String value; + + /** + * Gets the value of the key property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getKey() { + return key; + } + + /** + * Sets the value of the key property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setKey(String value) { + this.key = value; + } + + /** + * Gets the value of the value property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getValue() { + return value; + } + + /** + * Sets the value of the value property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setValue(String value) { + this.value = value; + } + + } + + } + +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/QueryNetworkNotificationResponse.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/QueryNetworkNotificationResponse.java new file mode 100644 index 0000000000..0320df27fc --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/QueryNetworkNotificationResponse.java @@ -0,0 +1,51 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.so.adapters.network.async.client; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlType; + + +/** + *

Java class for queryNetworkNotificationResponse complex type. + * + *

The following schema fragment specifies the expected content contained within this class. + * + *

+ * <complexType name="queryNetworkNotificationResponse">
+ *   <complexContent>
+ *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *       <sequence>
+ *       </sequence>
+ *     </restriction>
+ *   </complexContent>
+ * </complexType>
+ * 
+ * + * + */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "queryNetworkNotificationResponse") +public class QueryNetworkNotificationResponse { + + +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/RollbackNetworkNotification.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/RollbackNetworkNotification.java new file mode 100644 index 0000000000..08f37fc85d --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/RollbackNetworkNotification.java @@ -0,0 +1,154 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.so.adapters.network.async.client; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlType; + + +/** + *

Java class for rollbackNetworkNotification complex type. + * + *

The following schema fragment specifies the expected content contained within this class. + * + *

+ * <complexType name="rollbackNetworkNotification">
+ *   <complexContent>
+ *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *       <sequence>
+ *         <element name="messageId" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ *         <element name="completed" type="{http://www.w3.org/2001/XMLSchema}boolean"/>
+ *         <element name="exception" type="{http://org.onap.so/networkNotify}msoExceptionCategory" minOccurs="0"/>
+ *         <element name="errorMessage" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
+ *       </sequence>
+ *     </restriction>
+ *   </complexContent>
+ * </complexType>
+ * 
+ * + * + */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "rollbackNetworkNotification", propOrder = { + "messageId", + "completed", + "exception", + "errorMessage" +}) +public class RollbackNetworkNotification { + + @XmlElement(required = true) + protected String messageId; + protected boolean completed; + protected MsoExceptionCategory exception; + protected String errorMessage; + + /** + * Gets the value of the messageId property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getMessageId() { + return messageId; + } + + /** + * Sets the value of the messageId property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setMessageId(String value) { + this.messageId = value; + } + + /** + * Gets the value of the completed property. + * + */ + public boolean isCompleted() { + return completed; + } + + /** + * Sets the value of the completed property. + * + */ + public void setCompleted(boolean value) { + this.completed = value; + } + + /** + * Gets the value of the exception property. + * + * @return + * possible object is + * {@link MsoExceptionCategory } + * + */ + public MsoExceptionCategory getException() { + return exception; + } + + /** + * Sets the value of the exception property. + * + * @param value + * allowed object is + * {@link MsoExceptionCategory } + * + */ + public void setException(MsoExceptionCategory value) { + this.exception = value; + } + + /** + * Gets the value of the errorMessage property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getErrorMessage() { + return errorMessage; + } + + /** + * Sets the value of the errorMessage property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setErrorMessage(String value) { + this.errorMessage = value; + } + +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/RollbackNetworkNotificationResponse.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/RollbackNetworkNotificationResponse.java new file mode 100644 index 0000000000..44db3a1583 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/RollbackNetworkNotificationResponse.java @@ -0,0 +1,51 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.so.adapters.network.async.client; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlType; + + +/** + *

Java class for rollbackNetworkNotificationResponse complex type. + * + *

The following schema fragment specifies the expected content contained within this class. + * + *

+ * <complexType name="rollbackNetworkNotificationResponse">
+ *   <complexContent>
+ *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *       <sequence>
+ *       </sequence>
+ *     </restriction>
+ *   </complexContent>
+ * </complexType>
+ * 
+ * + * + */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "rollbackNetworkNotificationResponse") +public class RollbackNetworkNotificationResponse { + + +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/UpdateNetworkNotification.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/UpdateNetworkNotification.java new file mode 100644 index 0000000000..f61d0a8dea --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/UpdateNetworkNotification.java @@ -0,0 +1,383 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.so.adapters.network.async.client; + +import java.util.ArrayList; +import java.util.List; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlType; + + +/** + *

Java class for updateNetworkNotification complex type. + * + *

The following schema fragment specifies the expected content contained within this class. + * + *

+ * <complexType name="updateNetworkNotification">
+ *   <complexContent>
+ *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *       <sequence>
+ *         <element name="messageId" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ *         <element name="completed" type="{http://www.w3.org/2001/XMLSchema}boolean"/>
+ *         <element name="exception" type="{http://org.onap.so/networkNotify}msoExceptionCategory" minOccurs="0"/>
+ *         <element name="errorMessage" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
+ *         <element name="subnetIdMap" minOccurs="0">
+ *           <complexType>
+ *             <complexContent>
+ *               <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *                 <sequence>
+ *                   <element name="entry" maxOccurs="unbounded" minOccurs="0">
+ *                     <complexType>
+ *                       <complexContent>
+ *                         <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *                           <sequence>
+ *                             <element name="key" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
+ *                             <element name="value" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
+ *                           </sequence>
+ *                         </restriction>
+ *                       </complexContent>
+ *                     </complexType>
+ *                   </element>
+ *                 </sequence>
+ *               </restriction>
+ *             </complexContent>
+ *           </complexType>
+ *         </element>
+ *         <element name="rollback" type="{http://org.onap.so/networkNotify}networkRollback" minOccurs="0"/>
+ *       </sequence>
+ *     </restriction>
+ *   </complexContent>
+ * </complexType>
+ * 
+ * + * + */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "updateNetworkNotification", propOrder = { + "messageId", + "completed", + "exception", + "errorMessage", + "subnetIdMap", + "rollback" +}) +public class UpdateNetworkNotification { + + @XmlElement(required = true) + protected String messageId; + protected boolean completed; + protected MsoExceptionCategory exception; + protected String errorMessage; + protected UpdateNetworkNotification.SubnetIdMap subnetIdMap; + protected NetworkRollback rollback; + + /** + * Gets the value of the messageId property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getMessageId() { + return messageId; + } + + /** + * Sets the value of the messageId property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setMessageId(String value) { + this.messageId = value; + } + + /** + * Gets the value of the completed property. + * + */ + public boolean isCompleted() { + return completed; + } + + /** + * Sets the value of the completed property. + * + */ + public void setCompleted(boolean value) { + this.completed = value; + } + + /** + * Gets the value of the exception property. + * + * @return + * possible object is + * {@link MsoExceptionCategory } + * + */ + public MsoExceptionCategory getException() { + return exception; + } + + /** + * Sets the value of the exception property. + * + * @param value + * allowed object is + * {@link MsoExceptionCategory } + * + */ + public void setException(MsoExceptionCategory value) { + this.exception = value; + } + + /** + * Gets the value of the errorMessage property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getErrorMessage() { + return errorMessage; + } + + /** + * Sets the value of the errorMessage property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setErrorMessage(String value) { + this.errorMessage = value; + } + + /** + * Gets the value of the subnetIdMap property. + * + * @return + * possible object is + * {@link UpdateNetworkNotification.SubnetIdMap } + * + */ + public UpdateNetworkNotification.SubnetIdMap getSubnetIdMap() { + return subnetIdMap; + } + + /** + * Sets the value of the subnetIdMap property. + * + * @param value + * allowed object is + * {@link UpdateNetworkNotification.SubnetIdMap } + * + */ + public void setSubnetIdMap(UpdateNetworkNotification.SubnetIdMap value) { + this.subnetIdMap = value; + } + + /** + * Gets the value of the rollback property. + * + * @return + * possible object is + * {@link NetworkRollback } + * + */ + public NetworkRollback getRollback() { + return rollback; + } + + /** + * Sets the value of the rollback property. + * + * @param value + * allowed object is + * {@link NetworkRollback } + * + */ + public void setRollback(NetworkRollback value) { + this.rollback = value; + } + + + /** + *

Java class for anonymous complex type. + * + *

The following schema fragment specifies the expected content contained within this class. + * + *

+     * <complexType>
+     *   <complexContent>
+     *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+     *       <sequence>
+     *         <element name="entry" maxOccurs="unbounded" minOccurs="0">
+     *           <complexType>
+     *             <complexContent>
+     *               <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+     *                 <sequence>
+     *                   <element name="key" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
+     *                   <element name="value" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
+     *                 </sequence>
+     *               </restriction>
+     *             </complexContent>
+     *           </complexType>
+     *         </element>
+     *       </sequence>
+     *     </restriction>
+     *   </complexContent>
+     * </complexType>
+     * 
+ * + * + */ + @XmlAccessorType(XmlAccessType.FIELD) + @XmlType(name = "", propOrder = { + "entry" + }) + public static class SubnetIdMap { + + protected List entry; + + /** + * Gets the value of the entry property. + * + *

+ * This accessor method returns a reference to the live list, + * not a snapshot. Therefore any modification you make to the + * returned list will be present inside the JAXB object. + * This is why there is not a set method for the entry property. + * + *

+ * For example, to add a new item, do as follows: + *

+         *    getEntry().add(newItem);
+         * 
+ * + * + *

+ * Objects of the following type(s) are allowed in the list + * {@link UpdateNetworkNotification.SubnetIdMap.Entry } + * + * + */ + public List getEntry() { + if (entry == null) { + entry = new ArrayList(); + } + return this.entry; + } + + + /** + *

Java class for anonymous complex type. + * + *

The following schema fragment specifies the expected content contained within this class. + * + *

+         * <complexType>
+         *   <complexContent>
+         *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+         *       <sequence>
+         *         <element name="key" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
+         *         <element name="value" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
+         *       </sequence>
+         *     </restriction>
+         *   </complexContent>
+         * </complexType>
+         * 
+ * + * + */ + @XmlAccessorType(XmlAccessType.FIELD) + @XmlType(name = "", propOrder = { + "key", + "value" + }) + public static class Entry { + + protected String key; + protected String value; + + /** + * Gets the value of the key property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getKey() { + return key; + } + + /** + * Sets the value of the key property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setKey(String value) { + this.key = value; + } + + /** + * Gets the value of the value property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getValue() { + return value; + } + + /** + * Sets the value of the value property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setValue(String value) { + this.value = value; + } + + } + + } + +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/UpdateNetworkNotificationResponse.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/UpdateNetworkNotificationResponse.java new file mode 100644 index 0000000000..e0016d9b8e --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/UpdateNetworkNotificationResponse.java @@ -0,0 +1,51 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.so.adapters.network.async.client; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlType; + + +/** + *

Java class for updateNetworkNotificationResponse complex type. + * + *

The following schema fragment specifies the expected content contained within this class. + * + *

+ * <complexType name="updateNetworkNotificationResponse">
+ *   <complexContent>
+ *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *       <sequence>
+ *       </sequence>
+ *     </restriction>
+ *   </complexContent>
+ * </complexType>
+ * 
+ * + * + */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "updateNetworkNotificationResponse") +public class UpdateNetworkNotificationResponse { + + +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/package-info.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/package-info.java new file mode 100644 index 0000000000..fdd8711170 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/package-info.java @@ -0,0 +1,21 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * 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========================================================= + */ +@javax.xml.bind.annotation.XmlSchema(namespace = "http://org.onap.so/networkNotify") +package org.onap.so.adapters.network.async.client; diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/exceptions/NetworkException.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/exceptions/NetworkException.java new file mode 100644 index 0000000000..cb4cd8b927 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/exceptions/NetworkException.java @@ -0,0 +1,80 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.so.adapters.network.exceptions; + + + +import javax.xml.ws.WebFault; + +import org.onap.so.openstack.exceptions.MsoException; +import org.onap.so.openstack.exceptions.MsoExceptionCategory; + +/** + * This class simply extends Exception (without addition additional functionality) + * to provide an identifier for Network related exceptions on create, delete, query. + * + * + */ +@WebFault (name="NetworkException", faultBean="org.onap.so.adapters.network.exceptions.NetworkExceptionBean", targetNamespace="http://org.onap.so/network") +public class NetworkException extends Exception { + + private static final long serialVersionUID = 1L; + + private NetworkExceptionBean faultInfo; + + public NetworkException (String msg) { + super(msg); + faultInfo = new NetworkExceptionBean (msg); + } + + public NetworkException (Throwable e) { + super(e); + faultInfo = new NetworkExceptionBean (e.getMessage()); + } + + public NetworkException (String msg, Throwable e) { + super (msg, e); + faultInfo = new NetworkExceptionBean (msg); + } + + public NetworkException (String msg, MsoExceptionCategory category) { + super(msg); + faultInfo = new NetworkExceptionBean (msg, category); + } + + public NetworkException (String msg, MsoExceptionCategory category, Throwable e) { + super (msg, e); + faultInfo = new NetworkExceptionBean (msg, category); + } + + public NetworkException (MsoException e) { + super (e); + faultInfo = new NetworkExceptionBean (e.getContextMessage(), e.getCategory()); + } + + public NetworkExceptionBean getFaultInfo() { + return faultInfo; + } + + public void setFaultInfo(NetworkExceptionBean faultInfo) { + this.faultInfo = faultInfo; + } +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/exceptions/NetworkExceptionBean.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/exceptions/NetworkExceptionBean.java new file mode 100644 index 0000000000..5256891ffa --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/exceptions/NetworkExceptionBean.java @@ -0,0 +1,73 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.so.adapters.network.exceptions; + + +import java.io.Serializable; + +import org.onap.so.openstack.exceptions.MsoExceptionCategory; + +/** + * Jax-WS Fault Bean for Network Exceptions + */ +public class NetworkExceptionBean implements Serializable { + + private static final long serialVersionUID = 1655343530371342871L; + + private String message; + private MsoExceptionCategory category; + private Boolean rolledBack; + + public NetworkExceptionBean () {} + + public NetworkExceptionBean (String message) { + this.message = message; + } + + public NetworkExceptionBean (String message, MsoExceptionCategory category) { + this.message = message; + this.category = category; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + public MsoExceptionCategory getCategory () { + return category; + } + + public void setCategory (MsoExceptionCategory category) { + this.category = category; + } + + public Boolean isRolledBack() { + return rolledBack; + } + + public void setRolledBack(Boolean rolledBack) { + this.rolledBack = rolledBack; + } +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/openstack/CXFConfiguration.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/openstack/CXFConfiguration.java new file mode 100644 index 0000000000..d29818614d --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/openstack/CXFConfiguration.java @@ -0,0 +1,190 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.so.adapters.openstack; + +import java.util.Arrays; + +import javax.xml.ws.Endpoint; + +import org.apache.cxf.Bus; +import org.apache.cxf.bus.spring.SpringBus; +import org.apache.cxf.endpoint.Server; +import org.apache.cxf.feature.LoggingFeature; +import org.apache.cxf.jaxrs.JAXRSServerFactoryBean; +import org.apache.cxf.jaxrs.swagger.Swagger2Feature; +import org.apache.cxf.jaxws.EndpointImpl; +import org.apache.cxf.transport.servlet.CXFServlet; +import org.onap.so.adapters.network.MsoNetworkAdapterAsyncImpl; +import org.onap.so.adapters.network.MsoNetworkAdapterImpl; +import org.onap.so.adapters.network.NetworkAdapterRest; +import org.onap.so.adapters.tenant.MsoTenantAdapterImpl; +import org.onap.so.adapters.tenant.TenantAdapterRest; +import org.onap.so.adapters.vnf.MsoVnfAdapterAsyncImpl; +import org.onap.so.adapters.vnf.MsoVnfAdapterImpl; +import org.onap.so.adapters.vnf.MsoVnfCloudifyAdapterImpl; +import org.onap.so.adapters.vnf.VnfAdapterRest; +import org.onap.so.adapters.vnf.VnfAdapterRestV2; +import org.onap.so.adapters.vnf.VolumeAdapterRest; +import org.onap.so.adapters.vnf.VolumeAdapterRestV2; +import org.onap.so.client.policy.JettisonStyleMapperProvider; +import org.onap.so.logger.MsoLogger; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.web.servlet.ServletRegistrationBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider; + + +@Configuration +public class CXFConfiguration { + private static final MsoLogger msoLogger = MsoLogger.getMsoLogger(MsoLogger.Catalog.RA, CXFConfiguration.class); + + @Autowired + private NetworkAdapterRest networkAdapterRest; + @Autowired + private TenantAdapterRest tenantAdapterRest; + @Autowired + private VnfAdapterRest vnfAdapterRest; + @Autowired + private VnfAdapterRestV2 vnfAdapterRestV2; + @Autowired + private VolumeAdapterRest volumeAdapterRest; + @Autowired + private VolumeAdapterRestV2 volumeAdapterRestV2; + @Autowired + private MsoNetworkAdapterImpl networkAdapterImpl; + @Autowired + private MsoNetworkAdapterAsyncImpl networkAdapterAsyncImpl; + @Autowired + private MsoTenantAdapterImpl tenantAdapterImpl; + @Autowired + private MsoVnfAdapterImpl vnfAdapterImpl; + @Autowired + private MsoVnfAdapterAsyncImpl vnfAdapterAsyncImpl; + @Autowired + private MsoVnfCloudifyAdapterImpl vnfCloudifyAdapterImpl; + @Autowired + private JettisonStyleMapperProvider jettisonStyleObjectMapper; + + + @Bean(name=Bus.DEFAULT_BUS_ID) + public SpringBus springBus() { + return new SpringBus(); + } + + @Bean + public ServletRegistrationBean SoapDispatcherServlet() { + ServletRegistrationBean servletRegistrationBean = + new ServletRegistrationBean(new CXFServlet(), "/services/*"); + servletRegistrationBean.setName("services"); + return servletRegistrationBean; + } + + /* + * network adapter endpoint + */ + @Bean + public Endpoint networkAdapterEndpoint() { + EndpointImpl endpoint = new EndpointImpl(springBus(), networkAdapterImpl); + endpoint.publish("/NetworkAdapter"); + endpoint.setWsdlLocation("NetworkAdapter.wsdl"); + return endpoint; + } + + @Bean + public Endpoint networkAdapterAsyncEndpoint() { + EndpointImpl endpoint = new EndpointImpl(springBus(), networkAdapterAsyncImpl); + endpoint.publish("/NetworkAdapterAsync"); + endpoint.setWsdlLocation("NetworkAdapterAsync.wsdl"); + return endpoint; + } + + /* + * tenant adapter endpoint + */ + @Bean + public Endpoint tenantAdapterEndpoint() { + EndpointImpl endpoint = new EndpointImpl(springBus(), tenantAdapterImpl); + endpoint.publish("/TenantAdapter"); + endpoint.setWsdlLocation("TenantAdapter.wsdl"); + return endpoint; + } + + /* + * vnfAdapterEndpoint + * VnfAsyncAdapterEndpoint + * VnfCloudAdapterEndpoint + */ + @Bean + public Endpoint vnfAdapterEndpoint() { + EndpointImpl endpoint = new EndpointImpl(springBus(), vnfAdapterImpl); + endpoint.publish("/VnfAdapter"); + endpoint.setWsdlLocation("VnfAdapter.wsdl"); + return endpoint; + } + + @Bean + public Endpoint VnfAsyncAdapterEndpoint() { + EndpointImpl endpoint = new EndpointImpl(springBus(), vnfAdapterAsyncImpl); + endpoint.publish("/VnfAsyncAdapter"); + endpoint.setWsdlLocation("VnfAsyncAdapter.wsdl"); + return endpoint; + } + + @Bean + public Endpoint VnfCloudAdapterEndpoint() { + EndpointImpl endpoint = new EndpointImpl(springBus(), vnfCloudifyAdapterImpl); + endpoint.publish("/VnfCloudifyAdapterImpl"); + endpoint.setWsdlLocation("VnfCloudifyAdapterImpl.wsdl"); + return endpoint; + } + + @Bean + public Server rsServer() { + JAXRSServerFactoryBean endpoint = new JAXRSServerFactoryBean(); + endpoint.setBus(springBus()); + endpoint.setServiceBeans(Arrays.asList(networkAdapterRest, + tenantAdapterRest, + vnfAdapterRest, + vnfAdapterRestV2, + volumeAdapterRest, + volumeAdapterRestV2)); + endpoint.setAddress("/rest"); + endpoint.setFeatures(Arrays.asList(createSwaggerFeature(), new LoggingFeature())); + endpoint.setProvider(new JacksonJsonProvider(jettisonStyleObjectMapper.getMapper())); + return endpoint.create(); + } + + + @Bean + public Swagger2Feature createSwaggerFeature() { + Swagger2Feature swagger2Feature= new Swagger2Feature(); + swagger2Feature.setPrettyPrint(true); + swagger2Feature.setTitle("SO Orchestration Application"); + swagger2Feature.setContact("The ONAP SO team"); + swagger2Feature.setDescription("This project is the SO Orchestration Engine"); + swagger2Feature.setVersion("1.0.0"); + swagger2Feature.setResourcePackage("org.onap.so.adapters.network,org.onap.so.adapters.tenant,org.onap.so.adapters.vnf"); + swagger2Feature.setScan(true); + return swagger2Feature; + } +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/openstack/MsoOpenstackAdaptersApplication.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/openstack/MsoOpenstackAdaptersApplication.java new file mode 100644 index 0000000000..d67a4b684c --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/openstack/MsoOpenstackAdaptersApplication.java @@ -0,0 +1,73 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.so.adapters.openstack; + +import java.util.concurrent.Executor; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.domain.EntityScan; +import org.springframework.context.annotation.Bean; +import org.springframework.data.jpa.repository.config.EnableJpaRepositories; +import org.springframework.scheduling.annotation.EnableAsync; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; + +@SpringBootApplication(scanBasePackages = { "org.onap.so" }) +@EnableAsync +@EnableJpaRepositories({ "org.onap.so.db.catalog.data.repository", + "org.onap.so.db.request.data.repository" }) +@EntityScan({ "org.onap.so.db.catalog.beans", "org.onap.so.db.request.beans" }) +public class MsoOpenstackAdaptersApplication { + + @Value("${mso.async.core-pool-size}") + private int corePoolSize; + + @Value("${mso.async.max-pool-size}") + private int maxPoolSize; + + @Value("${mso.async.queue-capacity}") + private int queueCapacity; + + private static final String LOGS_DIR = "logs_dir"; + + private static void setLogsDir() { + if (System.getProperty(LOGS_DIR) == null) { + System.getProperties().setProperty(LOGS_DIR, "./logs/openstack/"); + } + } + + public static void main(String[] args) { + SpringApplication.run(MsoOpenstackAdaptersApplication.class, args); + setLogsDir(); + } + + @Bean + public Executor asyncExecutor() { + ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); + executor.setCorePoolSize(corePoolSize); + executor.setMaxPoolSize(maxPoolSize); + executor.setQueueCapacity(queueCapacity); + executor.setThreadNamePrefix("OpenstackAdapters-"); + executor.initialize(); + return executor; + } +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/openstack/WebSecurityConfigImpl.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/openstack/WebSecurityConfigImpl.java new file mode 100644 index 0000000000..6bbdebea52 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/openstack/WebSecurityConfigImpl.java @@ -0,0 +1,51 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 - 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.onap.so.adapters.openstack; + +import org.onap.so.security.MSOSpringFirewall; +import org.onap.so.security.WebSecurityConfig; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.builders.WebSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.web.firewall.StrictHttpFirewall; +import org.springframework.util.StringUtils; + +@EnableWebSecurity +public class WebSecurityConfigImpl extends WebSecurityConfig { + + @Override + protected void configure(HttpSecurity http) throws Exception { + http.csrf().disable() + .authorizeRequests() + .antMatchers("/manage/health","/manage/info").permitAll() + .antMatchers("/**").hasAnyRole(StringUtils.collectionToDelimitedString(getRoles(),",").toString()) + .and() + .httpBasic(); + } + + @Override + public void configure(WebSecurity web) throws Exception { + super.configure(web); + StrictHttpFirewall firewall = new MSOSpringFirewall(); + web.httpFirewall(firewall); + } + +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/tenant/MsoTenantAdapter.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/tenant/MsoTenantAdapter.java new file mode 100644 index 0000000000..ef66d6876c --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/tenant/MsoTenantAdapter.java @@ -0,0 +1,77 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.so.adapters.tenant; + + +import java.util.Map; + +import javax.jws.WebMethod; +import javax.jws.WebParam; +import javax.jws.WebParam.Mode; +import javax.jws.WebService; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.ws.Holder; + +import org.onap.so.adapters.tenant.exceptions.TenantAlreadyExists; +import org.onap.so.adapters.tenant.exceptions.TenantException; +import org.onap.so.adapters.tenantrest.TenantRollback; +import org.onap.so.entity.MsoRequest; + +@WebService (name="TenantAdapter", targetNamespace="http://org.onap.so/tenant") +public interface MsoTenantAdapter +{ + /** + * This is the "Create Tenant" Web Service Endpoint definition. + */ + @WebMethod + public void createTenant (@WebParam(name="cloudSiteId") @XmlElement(required=true) String cloudSiteId, + @WebParam(name="tenantName") @XmlElement(required=true) String tenantName, + @WebParam(name="metadata") Map metadata, + @WebParam(name="failIfExists") Boolean failIfExists, + @WebParam(name="backout") Boolean backout, + @WebParam(name="request") MsoRequest msoRequest, + @WebParam(name="tenantId", mode=Mode.OUT) Holder tenantId, + @WebParam(name="rollback", mode=Mode.OUT) Holder rollback ) + throws TenantException, TenantAlreadyExists; + + @WebMethod + public void queryTenant (@WebParam(name="cloudSiteId") @XmlElement(required=true) String cloudSiteId, + @WebParam(name="tenantNameOrId") @XmlElement(required=true) String tenantNameOrId, + @WebParam(name="request") MsoRequest msoRequest, + @WebParam(name="tenantId", mode=Mode.OUT) Holder tenantId, + @WebParam(name="tenantName", mode=Mode.OUT) Holder tenantName, + @WebParam(name="metadata", mode=Mode.OUT) Holder> metadata ) + throws TenantException; + + @WebMethod + public void deleteTenant (@WebParam(name="cloudSiteId") @XmlElement(required=true) String cloudSiteId, + @WebParam(name="tenantId") @XmlElement(required=true) String tenantId, + @WebParam(name="request") MsoRequest msoRequest, + @WebParam(name="tenantDeleted", mode=Mode.OUT) Holder tenantDeleted) + throws TenantException; + + @WebMethod + public void rollbackTenant (@WebParam(name="rollback") @XmlElement(required=true) TenantRollback rollback) + throws TenantException; + + @WebMethod + public void healthCheck (); +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/tenant/MsoTenantAdapterImpl.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/tenant/MsoTenantAdapterImpl.java new file mode 100644 index 0000000000..f58382f53c --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/tenant/MsoTenantAdapterImpl.java @@ -0,0 +1,295 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.so.adapters.tenant; + + +import java.util.Map; + +import javax.annotation.Resource; +import javax.jws.WebService; +import javax.xml.ws.Holder; +import javax.xml.ws.WebServiceContext; + +import org.onap.so.adapters.tenant.exceptions.TenantAlreadyExists; +import org.onap.so.adapters.tenant.exceptions.TenantException; +import org.onap.so.adapters.tenantrest.TenantRollback; +import org.onap.so.entity.MsoRequest; +import org.onap.so.logger.MessageEnum; +import org.onap.so.logger.MsoLogger; +import org.onap.so.openstack.beans.MsoTenant; +import org.onap.so.openstack.exceptions.MsoCloudSiteNotFound; +import org.onap.so.openstack.exceptions.MsoException; +import org.onap.so.openstack.utils.MsoTenantUtils; +import org.onap.so.openstack.utils.MsoTenantUtilsFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@WebService(serviceName = "TenantAdapter", endpointInterface = "org.onap.so.adapters.tenant.MsoTenantAdapter", targetNamespace = "http://org.onap.so/tenant") +@Component +public class MsoTenantAdapterImpl implements MsoTenantAdapter { + public static final String CREATE_TENANT = "CreateTenant"; + public static final String OPENSTACK = "OpenStack"; + public static final String QUERY_TENANT = "QueryTenant"; + public static final String DELETE_TENANT = "DeleteTenant"; + public static final String ROLLBACK_TENANT = "RollbackTenant"; + + @Resource + private WebServiceContext wsContext; + + @Autowired + private MsoTenantUtilsFactory tFactory; + private static MsoLogger logger = MsoLogger.getMsoLogger (MsoLogger.Catalog.RA,MsoTenantAdapterImpl.class); + /** + * Health Check web method. Does nothing but return to show the adapter is deployed. + */ + @Override + public void healthCheck () { + logger.debug ("Health check call in Tenant Adapter"); + } + + /** + * This is the "Create Tenant" web service implementation. It will create + * a new Tenant in the specified cloud. If the tenant already exists, this + * can be considered a success or failure, depending on the value of the + * 'failIfExists' parameter. + * + * The method returns the tenantId (the Openstack ID), and a TenantRollback + * object. This last object can be passed as-is to the rollbackTenant method + * to undo what (if anything) was created. This is useful if a Tenant is + * successfully created but the orchestrator fails on a subsequent operation. + */ + @Override + public void createTenant (String cloudSiteId, + String tenantName, + Map metadata, + Boolean failIfExists, + Boolean backout, + MsoRequest msoRequest, + Holder tenantId, + Holder rollback) throws TenantException, TenantAlreadyExists { + MsoLogger.setLogContext (msoRequest); + MsoLogger.setServiceName (CREATE_TENANT); + + logger.debug ("Call to MSO createTenant adapter. Creating Tenant: " + tenantName + + "in " + + cloudSiteId); + + // Will capture total time for metrics + long startTime = System.currentTimeMillis (); + + // Start building up rollback object + TenantRollback tenantRollback = new TenantRollback (); + tenantRollback.setCloudId (cloudSiteId); + tenantRollback.setMsoRequest (msoRequest); + + MsoTenantUtils tUtils; + try { + tUtils = tFactory.getTenantUtils (cloudSiteId); + } catch (MsoCloudSiteNotFound me) { + logger.error (MessageEnum.RA_CREATE_TENANT_ERR, me.getMessage(), OPENSTACK, "createTenant", MsoLogger.ErrorCode.DataError, "no implementation found for " + cloudSiteId, me); + throw new TenantException (me); + } + + MsoTenant newTenant = null; + String newTenantId; + long queryTenantStartTime = System.currentTimeMillis (); + try { + newTenant = tUtils.queryTenantByName (tenantName, cloudSiteId); + logger.recordMetricEvent (queryTenantStartTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", OPENSTACK, QUERY_TENANT, null); + } catch (MsoException me) { + logger.recordMetricEvent (queryTenantStartTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, "Exception while communicate with Open Stack", OPENSTACK, QUERY_TENANT, null); + String error = "Create Tenant " + tenantName + ": " + me; + logger.error (MessageEnum.RA_CREATE_TENANT_ERR, me.getMessage(), OPENSTACK, "createTenant", MsoLogger.ErrorCode.DataError, "Exception while communicate with Open Stack", me); + logger.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error); + throw new TenantException (me); + } + if (newTenant == null) { + if (backout == null) + backout = true; + long createTenantStartTime = System.currentTimeMillis (); + try { + newTenantId = tUtils.createTenant (tenantName, cloudSiteId, metadata, backout.booleanValue ()); + logger.recordMetricEvent (createTenantStartTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", OPENSTACK, CREATE_TENANT, null); + } catch (MsoException me) { + logger.recordMetricEvent (createTenantStartTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, "Exception while communicate with Open Stack", OPENSTACK, CREATE_TENANT, null); + String error = "Create Tenant " + tenantName + ": " + me; + logger.error (MessageEnum.RA_CREATE_TENANT_ERR, me.getMessage(), OPENSTACK, "createTenant", MsoLogger.ErrorCode.DataError, "Exception while communicate with Open Stack", me); + logger.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error); + throw new TenantException (me); + } + tenantRollback.setTenantId (newTenantId); + tenantRollback.setTenantCreated (true); + logger.debug ("Tenant " + tenantName + " successfully created with ID " + newTenantId); + } else { + if (failIfExists != null && failIfExists) { + String error = CREATE_TENANT + ": Tenant " + tenantName + " already exists in " + cloudSiteId; + logger.error (MessageEnum.RA_TENANT_ALREADY_EXIST, tenantName, cloudSiteId, OPENSTACK, "", MsoLogger.ErrorCode.DataError, CREATE_TENANT + ", Tenant already exists"); + logger.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataError, error); + throw new TenantAlreadyExists (tenantName, cloudSiteId, newTenant.getTenantId ()); + } + + newTenantId = newTenant.getTenantId (); + tenantRollback.setTenantCreated (false); + logger.debug ("Tenant " + tenantName + " already exists with ID " + newTenantId); + } + + + tenantId.value = newTenantId; + rollback.value = tenantRollback; + logger.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully create tenant"); + return; + } + + @Override + public void queryTenant (String cloudSiteId, + String tenantNameOrId, + MsoRequest msoRequest, + Holder tenantId, + Holder tenantName, + Holder > metadata) throws TenantException { + MsoLogger.setLogContext (msoRequest); + MsoLogger.setServiceName (QUERY_TENANT); + logger.debug ("Querying Tenant " + tenantNameOrId + " in " + cloudSiteId); + + // Will capture execution time for metrics + long startTime = System.currentTimeMillis (); + + MsoTenantUtils tUtils; + try { + tUtils = tFactory.getTenantUtils (cloudSiteId); + } catch (MsoCloudSiteNotFound me) { + logger.error (MessageEnum.RA_CREATE_TENANT_ERR, me.getMessage(), OPENSTACK, "createTenant", MsoLogger.ErrorCode.DataError, "no implementation found for " + cloudSiteId, me); + throw new TenantException (me); + } + + MsoTenant qTenant = null; + long subStartTime = System.currentTimeMillis (); + try { + qTenant = tUtils.queryTenant (tenantNameOrId, cloudSiteId); + logger.recordMetricEvent (subStartTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", OPENSTACK, QUERY_TENANT, null); + if (qTenant == null) { + // Not found by ID, Try by name. + qTenant = tUtils.queryTenantByName (tenantNameOrId, cloudSiteId); + } + + if (qTenant == null) { + logger.debug ("QueryTenant: Tenant " + tenantNameOrId + " not found"); + tenantId.value = null; + tenantName.value = null; + metadata.value = null; + } else { + logger.debug ("QueryTenant: Tenant " + tenantNameOrId + " found with ID " + qTenant.getTenantId ()); + tenantId.value = qTenant.getTenantId (); + tenantName.value = qTenant.getTenantName (); + metadata.value = qTenant.getMetadata (); + } + } catch (MsoException me) { + String error = "Query Tenant " + tenantNameOrId + ": " + me; + logger.recordMetricEvent (subStartTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, OPENSTACK, QUERY_TENANT, null); + logger.error (MessageEnum.RA_GENERAL_EXCEPTION, me.getMessage(), OPENSTACK, "", MsoLogger.ErrorCode.DataError, "Exception in queryTenant", me); + logger.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error); + throw new TenantException (me); + } + logger.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully query tenant"); + return; + } + + @Override + public void deleteTenant (String cloudSiteId, + String tenantId, + MsoRequest msoRequest, + Holder tenantDeleted) throws TenantException { + MsoLogger.setLogContext (msoRequest); + MsoLogger.setServiceName (DELETE_TENANT); + + logger.debug ("Deleting Tenant " + tenantId + " in " + cloudSiteId); + + // Will capture execution time for metrics + long startTime = System.currentTimeMillis (); + + // Delete the Tenant. + long subStartTime = System.currentTimeMillis (); + try { + + MsoTenantUtils tUtils = tFactory.getTenantUtils (cloudSiteId); + boolean deleted = tUtils.deleteTenant (tenantId, cloudSiteId); + tenantDeleted.value = deleted; + logger.recordMetricEvent (subStartTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully communicate with Open Stack", OPENSTACK, DELETE_TENANT, null); + } catch (MsoException me) { + String error = "Delete Tenant " + tenantId + ": " + me; + logger.recordMetricEvent (subStartTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, OPENSTACK, DELETE_TENANT, null); + logger.error (MessageEnum.RA_DELETE_TEMAMT_ERR, me.getMessage(), OPENSTACK, "", MsoLogger.ErrorCode.DataError, "Exception - DeleteTenant", me); + logger.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error); + throw new TenantException (me); + } + + // On success, nothing is returned. + logger.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully delete tenant"); + return; + } + + /** + * 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. + * + * The rollback includes removing the VNF and deleting the tenant if the + * tenant did not exist prior to the VNF creation. + */ + @Override + public void rollbackTenant (TenantRollback rollback) throws TenantException { + long startTime = System.currentTimeMillis (); + MsoLogger.setServiceName (ROLLBACK_TENANT); + // rollback may be null (e.g. if stack already existed when Create was called) + if (rollback == null) { + logger.warn (MessageEnum.RA_ROLLBACK_NULL, OPENSTACK, "rollbackTenant", MsoLogger.ErrorCode.DataError, "rollbackTenant, rollback is null"); + return; + } + + // Get the elements of the VnfRollback object for easier access + String cloudSiteId = rollback.getCloudId (); + String tenantId = rollback.getTenantId (); + + MsoLogger.setLogContext (rollback.getMsoRequest ()); + logger.debug ("Rolling Back Tenant " + rollback.getTenantId () + " in " + cloudSiteId); + + long subStartTime = System.currentTimeMillis (); + if (rollback.getTenantCreated ()) { + try { + + MsoTenantUtils tUtils = tFactory.getTenantUtils (cloudSiteId); + tUtils.deleteTenant (tenantId, cloudSiteId); + logger.recordMetricEvent (subStartTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully communicate with Open Stack", OPENSTACK, ROLLBACK_TENANT, null); + } catch (MsoException me) { + me.addContext (ROLLBACK_TENANT); + // Failed to delete the tenant. + String error = "Rollback Tenant " + tenantId + ": " + me; + logger.recordMetricEvent (subStartTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, OPENSTACK, ROLLBACK_TENANT, null); + logger.error (MessageEnum.RA_ROLLBACK_TENANT_ERR, me.getMessage(), OPENSTACK, "rollbackTenant", MsoLogger.ErrorCode.DataError, "Exception - rollbackTenant", me); + logger.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error); + throw new TenantException (me); + } + } + logger.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully roll back tenant"); + return; + } +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/tenant/TenantAdapterRest.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/tenant/TenantAdapterRest.java new file mode 100644 index 0000000000..2bba3f559e --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/tenant/TenantAdapterRest.java @@ -0,0 +1,345 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * Copyright (C) 2017 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.so.adapters.tenant; + + +import java.util.Map; + +import javax.servlet.http.HttpServletResponse; +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.xml.ws.Holder; + +import org.onap.so.adapters.tenant.exceptions.TenantAlreadyExists; +import org.onap.so.adapters.tenant.exceptions.TenantException; +import org.onap.so.adapters.tenantrest.CreateTenantError; +import org.onap.so.adapters.tenantrest.CreateTenantRequest; +import org.onap.so.adapters.tenantrest.CreateTenantResponse; +import org.onap.so.adapters.tenantrest.DeleteTenantError; +import org.onap.so.adapters.tenantrest.DeleteTenantRequest; +import org.onap.so.adapters.tenantrest.DeleteTenantResponse; +import org.onap.so.adapters.tenantrest.QueryTenantError; +import org.onap.so.adapters.tenantrest.QueryTenantResponse; +import org.onap.so.adapters.tenantrest.RollbackTenantError; +import org.onap.so.adapters.tenantrest.RollbackTenantRequest; +import org.onap.so.adapters.tenantrest.RollbackTenantResponse; +import org.onap.so.adapters.tenantrest.TenantRollback; +import org.onap.so.logger.MsoLogger; +import org.onap.so.openstack.beans.MsoTenant; +import org.onap.so.openstack.exceptions.MsoExceptionCategory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import io.swagger.annotations.ApiResponse; +import io.swagger.annotations.ApiResponses; + +/** + * This class services calls to the REST interface for Tenants (http://host:port/vnfs/rest/v1/tenants) + * Both XML and JSON can be produced/consumed. Set Accept: and Content-Type: headers appropriately. XML is the default. + */ +@Path("/v1/tenants") +@Api(value = "/v1/tenants", description = "root of tenant adapters restful web service") +@Component +public class TenantAdapterRest { + private static MsoLogger LOGGER = MsoLogger.getMsoLogger (MsoLogger.Catalog.RA, TenantAdapterRest.class); + + //RAA? No logging in wrappers + @Autowired + private MsoTenantAdapterImpl tenantImpl; + + + + /* + URL: + EP: http://host:8080/tenants/rest + Resource: v1/tenants + REQ - metadata? + { + "cloudSiteId": "DAN", + "tenantName": "RAA_1", + "failIfExists": true, + "msoRequest": { + "requestId": "ra1", + "serviceInstanceId": "sa1" + }} + RESP- + { + "cloudSiteId": "DAN", + "tenantId": "128e10b9996d43a7874f19bbc4eb6749", + "tenantCreated": true, + "tenantRollback": { + "tenantId": "128e10b9996d43a7874f19bbc4eb6749", + "cloudId": "DAN", // RAA? cloudId instead of cloudSiteId + "tenantCreated": true, + "msoRequest": { + "requestId": "ra1", + "serviceInstanceId": "sa1" + } + } + } + */ + @POST + @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @ApiOperation(value = "CreateTenant", + response = Response.class, + notes = "Creates a new tenant, CreateTenantRequest data is required") + @ApiResponses({ + @ApiResponse(code = 200, message = "tenant has been successfully created"), + @ApiResponse(code = 500, message = "create tenant failed") }) + public Response createTenant( + @ApiParam(value = "details of tenant being created", required = true) + CreateTenantRequest req) { + LOGGER.debug("createTenant enter: " + req.toJsonString()); + + String newTenantId = null; + TenantRollback tenantRollback = new TenantRollback (); + + try { + Holder htenant = new Holder<>(); + Holder hrollback = new Holder<>(); + MsoTenantAdapter impl = tenantImpl; + impl.createTenant( + req.getCloudSiteId(), + req.getTenantName(), + req.getMetadata(), + req.getFailIfExists(), + req.getBackout(), + req.getMsoRequest(), + htenant, + hrollback); + newTenantId = htenant.value; + tenantRollback = hrollback.value; +// TenantAdapterCore TAImpl = new TenantAdapterCore(); +// newTenantId = TAImpl.createTenant (req.getCloudSiteId(), +// req.getTenantName(), +// req.getFailIfExists(), +// req.getBackout(), +// req.getMetadata(), +// req.getMsoRequest(), +// tenantRollback); + } + catch (TenantAlreadyExists tae) { + LOGGER.debug("Exception :",tae); + CreateTenantError exc = new CreateTenantError(tae.getMessage(), tae.getFaultInfo().getCategory(), Boolean.TRUE); + return Response.status(HttpServletResponse.SC_NOT_IMPLEMENTED).entity(exc).build(); + } + catch (TenantException te) { + LOGGER.debug("Exception :",te); + CreateTenantError exc = new CreateTenantError(te.getFaultInfo().getMessage(), te.getFaultInfo().getCategory(), Boolean.TRUE); + return Response.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).entity(exc).build(); + } + catch (Exception e) { + LOGGER.debug("Exception :",e); + CreateTenantError exc = new CreateTenantError(e.getMessage(), MsoExceptionCategory.INTERNAL, Boolean.TRUE); + return Response.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).entity(exc).build(); + } + + CreateTenantResponse resp = new CreateTenantResponse (req.getCloudSiteId(), newTenantId, tenantRollback.getTenantCreated(), tenantRollback); + return Response.status(HttpServletResponse.SC_OK).entity(resp).build(); + } + + /* + URL: + http://host:8080/tenants/rest + Resource: v1/tenant/tennatId + REQ: + {"cloudSiteId": "DAN", + "tenantId": "ca84cd3d3df44272845da554656b3ace", + "msoRequest": { + "requestId": "ra1", + "serviceInstanceId": "sa1" + } + } + RESP: + {"tenantDeleted": true} + */ + @DELETE + @Path("{tenantId}") + @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @ApiOperation(value = "DeleteTenant", + response = Response.class, + notes = "Delete an existing tenant") + @ApiResponses({ + @ApiResponse(code = 200, message = "tenant has been successfully deleted"), + @ApiResponse(code = 500, message = "delete tenant failed") }) + public Response deleteTenant( + @ApiParam(value = "tenantId of tenant being deleted", required = true) + @PathParam("tenantId") String tenantId, + @ApiParam(value = "DeleteTenantRequest object containing additional information of tenant being deleted", required = false) + DeleteTenantRequest req) + { + boolean tenantDeleted = false; + + try { + Holder deleted = new Holder<>(); + MsoTenantAdapter impl = tenantImpl; + impl.deleteTenant( + req.getCloudSiteId(), + req.getTenantId(), + req.getMsoRequest(), + deleted); + tenantDeleted = deleted.value; + } + catch (TenantException te) { + LOGGER.debug("Exception :",te); + DeleteTenantError exc = new DeleteTenantError(te.getFaultInfo().getMessage(), te.getFaultInfo().getCategory(), Boolean.TRUE); + return Response.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).entity(exc).build(); + } + catch (Exception e) { + LOGGER.debug("Exception :",e); + DeleteTenantError exc = new DeleteTenantError(e.getMessage(), MsoExceptionCategory.INTERNAL, Boolean.TRUE); + return Response.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).entity(exc).build(); + } + DeleteTenantResponse resp = new DeleteTenantResponse(); + resp.setTenantDeleted(tenantDeleted); + return Response.status(HttpServletResponse.SC_OK).entity(resp).build(); + } + + /* + URL + EP://http://host:8080/tenants/rest + Resource: /v1/tenants + Params:?tenantNameOrId=RAA_1&cloudSiteId=DAN + RESP + { + "tenantId": "214b428a1f554c02935e66330f6a5409", + "tenantName": "RAA_1", + "metadata": {} + } + */ + @GET + @Path("{tenantId}") + @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @ApiOperation(value = "QueryTenant", + response = Response.class, + notes = "Query an existing tenant") + @ApiResponses({ + @ApiResponse(code = 200, message = "tenant has been successfully queried"), + @ApiResponse(code = 500, message = "query tenant failed") }) + public Response queryTenant( + @ApiParam(value = "tenantId", required = true) + @PathParam("tenantId") String tenantId, +// @QueryParam("tenantNameOrId") String tenantNameOrId, //RAA? diff from doc + @ApiParam(value = "cloudSiteId", required = true) + @QueryParam("cloudSiteId") String cloudSiteId, + @ApiParam(value = "msoRequest.requestId", required = true) + @QueryParam("msoRequest.requestId") String requestId, + @ApiParam(value = "msoRequest.serviceInstanceId", required = true) + @QueryParam("msoRequest.serviceInstanceId") String serviceInstanceId) + { + MsoTenant tenant = null; + try { + Holder htenant = new Holder<>(); + Holder tenantName = new Holder<>(); + Holder> metadata = new Holder<>(); + MsoTenantAdapter impl = tenantImpl; + impl.queryTenant( + cloudSiteId, + tenantId, + null, + htenant, + tenantName, + metadata + ); + tenant = new MsoTenant(htenant.value, tenantName.value, metadata.value); +// TenantAdapterCore TAImpl = new TenantAdapterCore(); +// MsoRequest msoReq = new MsoRequest(); +// tenant = TAImpl.queryTenant (cloudSiteId, tenantId, msoReq); + } + catch (TenantException te) { + LOGGER.debug("Exception :",te); + QueryTenantError exc = new QueryTenantError(te.getFaultInfo().getMessage(), te.getFaultInfo().getCategory()); + return Response.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).entity(exc).build(); + } + catch (Exception e) { + LOGGER.debug("Exception :",e); + QueryTenantError exc = new QueryTenantError(e.getMessage(), MsoExceptionCategory.INTERNAL); + return Response.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).entity(exc).build(); + } + QueryTenantResponse resp = new QueryTenantResponse(tenant.getTenantId(), tenant.getTenantName(), tenant.getMetadata()); + return Response.status(HttpServletResponse.SC_OK).entity(resp).build(); + } + + /* + URL + EP: //http://host:8080/tenants/rest + Resource: /v1/tenants/rollback + REQ + {"cloudSiteId": "DAN", + "tenantId": "f58abb05041d4ff384d4d22d1ccd2a6c", + "msoRequest": { + "requestId": "ra1", + "serviceInstanceId": "sa1" + } + } + RESP: + {"tenantDeleted": true} + */ + @DELETE + @Path("") + @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @ApiOperation(value = "RollbackTenant", + response = Response.class, + notes = "Rollback an existing tenant") + @ApiResponses({ + @ApiResponse(code = 200, message = "tenant has been successfully rolledback"), + @ApiResponse(code = 500, message = "rollback tenant failed") }) + public Response rollbackTenant( + @ApiParam(value = "rollback, command action", required = true) + @QueryParam("rollback") String action, // WTF? + @ApiParam(value = "RollbackTenantRequest", required = true) + RollbackTenantRequest req) + { + try { + MsoTenantAdapter impl = tenantImpl; + impl.rollbackTenant(req.getTenantRollback()); + } + catch (TenantException te) { + LOGGER.debug("Exception :",te); + RollbackTenantError exc = new RollbackTenantError(te.getFaultInfo().getMessage(), te.getFaultInfo().getCategory(), Boolean.TRUE); + return Response.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).entity(exc).build(); + } + catch (Exception e) { + LOGGER.debug("Exception :",e); + RollbackTenantError exc = new RollbackTenantError(e.getMessage(), MsoExceptionCategory.INTERNAL, Boolean.TRUE); + return Response.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).entity(exc).build(); + } + + RollbackTenantResponse resp = new RollbackTenantResponse (); + resp.setTenantRolledback(req != null); + return Response.status(HttpServletResponse.SC_OK).entity(resp).build(); + } +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/tenant/exceptions/TenantAlreadyExists.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/tenant/exceptions/TenantAlreadyExists.java new file mode 100644 index 0000000000..5b8e7c7294 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/tenant/exceptions/TenantAlreadyExists.java @@ -0,0 +1,45 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.so.adapters.tenant.exceptions; + + + +import javax.xml.ws.WebFault; + +import org.onap.so.openstack.exceptions.MsoExceptionCategory; + + +/** + * This class reports an exception when trying to create a VNF when another + * VNF of the same name already exists in the target cloud/tenant. Note that + * the createVnf method suppresses this exception by default. + * + * + */ +@WebFault (name="TenantAlreadyExists", faultBean="org.onap.so.adapters.tenant.exceptions.TenantExceptionBean", targetNamespace="http://org.onap.so/tenant") +public class TenantAlreadyExists extends TenantException { + + private static final long serialVersionUID = 1L; + + public TenantAlreadyExists (String name, String cloudId, String tenantId) { + super("Tenant " + name + " already exists in " + cloudId + " with ID " + tenantId, MsoExceptionCategory.USERDATA); + } +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/tenant/exceptions/TenantException.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/tenant/exceptions/TenantException.java new file mode 100644 index 0000000000..b8074ef7fc --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/tenant/exceptions/TenantException.java @@ -0,0 +1,75 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.so.adapters.tenant.exceptions; + + + +import javax.xml.ws.WebFault; + +import org.onap.so.openstack.exceptions.MsoException; +import org.onap.so.openstack.exceptions.MsoExceptionCategory; + +/** + * This class simply extends Exception (without addition additional functionality) + * to provide an identifier for Tenant related exceptions on create, delete, query. + * + * + */ +@WebFault (name="TenantException", faultBean="org.onap.so.adapters.tenant.exceptions.TenantExceptionBean", targetNamespace="http://org.onap.so/tenant") +public class TenantException extends Exception { + + private static final long serialVersionUID = 1L; + + private TenantExceptionBean faultInfo; + + public TenantException (String msg) { + super(msg); + faultInfo = new TenantExceptionBean (msg); + } + + public TenantException (String msg, Throwable e) { + super (msg, e); + faultInfo = new TenantExceptionBean (msg); + } + + public TenantException (String msg, MsoExceptionCategory category) { + super(msg); + faultInfo = new TenantExceptionBean (msg, category); + } + + public TenantException (String msg, MsoExceptionCategory category, Throwable e) { + super (msg, e); + faultInfo = new TenantExceptionBean (msg, category); + } + + public TenantException (MsoException e) { + super (e); + faultInfo = new TenantExceptionBean (e.getContextMessage(), e.getCategory()); + } + + public TenantExceptionBean getFaultInfo() { + return faultInfo; + } + + public void setFaultInfo(TenantExceptionBean faultInfo) { + this.faultInfo = faultInfo; + } +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/tenant/exceptions/TenantExceptionBean.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/tenant/exceptions/TenantExceptionBean.java new file mode 100644 index 0000000000..1dada60e93 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/tenant/exceptions/TenantExceptionBean.java @@ -0,0 +1,64 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.so.adapters.tenant.exceptions; + + +import java.io.Serializable; + +import org.onap.so.openstack.exceptions.MsoExceptionCategory; + +/** + * Jax-WS Fault Bean for Network Exceptions + */ +public class TenantExceptionBean implements Serializable { + + private static final long serialVersionUID = -9062290006520066109L; + + private String message; + private MsoExceptionCategory category; + + public TenantExceptionBean () {} + + public TenantExceptionBean (String message) { + this.message = message; + } + + public TenantExceptionBean (String message, MsoExceptionCategory category) { + this.message = message; + this.category = category; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + public MsoExceptionCategory getCategory () { + return category; + } + + public void setCategory (MsoExceptionCategory category) { + this.category = category; + } +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/valet/GenericValetResponse.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/valet/GenericValetResponse.java new file mode 100644 index 0000000000..344895f8f3 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/valet/GenericValetResponse.java @@ -0,0 +1,71 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.so.adapters.valet; + +import org.apache.commons.lang3.builder.ToStringBuilder; + +/* + * The purpose of this class is to encapsulate the possible responses from Valet in to one generic class + * that the vnf adapter can more easily utilize. This will ensure we get an object back. Any status + * code other than 200 will be treated as a failure. We may still get a 200 back - but the + * ValetStatus.status is "failed" - which will also be treated as a failure. The T class is + * expected to be one of the Valet*Response pojos. + */ +public class GenericValetResponse { + private int statusCode; + private String errorMessage; + private T returnObject; + + @Override + public String toString() { + return new ToStringBuilder(this).append("statusCode", statusCode).append("errorMessage", errorMessage) + .append("returnObject", returnObject).toString(); + } + public GenericValetResponse(int statusCode, String errorMessage, T obj) { + super(); + this.statusCode = statusCode; + this.errorMessage = errorMessage; + this.returnObject = obj; + } + public GenericValetResponse() { + this(-1, "not set", null); + } + public void setErrorMessage(String errorMessage) { + this.errorMessage = errorMessage; + } + public String getErrorMessage() { + return this.errorMessage; + } + public void setStatusCode(int statusCode) { + this.statusCode = statusCode; + } + public int getStatusCode() { + return this.statusCode; + } + public void setReturnObject(T obj) { + this.returnObject = obj; + } + public T getReturnObject() { + return this.returnObject; + } + +} + diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/valet/ValetClient.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/valet/ValetClient.java new file mode 100644 index 0000000000..f4bda4aaa0 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/valet/ValetClient.java @@ -0,0 +1,326 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * Copyright (C) 2017 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.so.adapters.valet; + +import org.onap.so.adapters.valet.beans.HeatRequest; +import org.onap.so.adapters.valet.beans.ValetConfirmRequest; +import org.onap.so.adapters.valet.beans.ValetConfirmResponse; +import org.onap.so.adapters.valet.beans.ValetCreateRequest; +import org.onap.so.adapters.valet.beans.ValetCreateResponse; +import org.onap.so.adapters.valet.beans.ValetDeleteRequest; +import org.onap.so.adapters.valet.beans.ValetDeleteResponse; +import org.onap.so.adapters.valet.beans.ValetRollbackRequest; +import org.onap.so.adapters.valet.beans.ValetRollbackResponse; +import org.onap.so.adapters.valet.beans.ValetUpdateRequest; +import org.onap.so.adapters.valet.beans.ValetUpdateResponse; + +import java.net.URI; + +import javax.annotation.PostConstruct; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.UriBuilder; + +import org.onap.so.adapters.valet.GenericValetResponse; + +import org.onap.so.logger.MsoLogger; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.env.Environment; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.ResponseEntity; +import org.springframework.web.client.RestTemplate; +import org.springframework.stereotype.Component; + +import com.fasterxml.jackson.databind.ObjectMapper; + +@Component +public class ValetClient { + private static MsoLogger LOGGER = MsoLogger.getMsoLogger(MsoLogger.Catalog.RA, ValetClient.class); + + @Autowired + private Environment environment; + + private static final String VALET_BASE_URL = "org.onap.so.adapters.valet.base_url"; + private static final String VALET_BASE_PATH = "org.onap.so.adapters.valet.base_path"; + private static final String VALET_AUTH = "org.onap.so.adapters.valet.basic_auth"; + private static final String REQ_ID_HEADER_NAME = "X-RequestID"; + protected static final String NO_STATUS_RETURNED = "no status returned from Valet"; + + private static final String DEFAULT_BASE_URL = "http://localhost:8080/"; + private static final String DEFAULT_BASE_PATH = "api/valet/placement/v1"; + private static final String DEFAULT_AUTH_STRING = ""; + + @Autowired + private ObjectMapper mapper; + + protected String baseUrl; + protected String basePath; + protected String authString; + + /* + * Setup the properties needed from properties file. Each will fall to a default + */ + @PostConstruct + private void setupParams() { + try { + this.baseUrl = this.environment.getProperty(ValetClient.VALET_BASE_URL, ValetClient.DEFAULT_BASE_URL); + this.basePath = this.environment.getProperty(ValetClient.VALET_BASE_PATH, ValetClient.DEFAULT_BASE_PATH); + this.authString = this.environment.getProperty(ValetClient.VALET_AUTH, ValetClient.DEFAULT_AUTH_STRING); + } catch (Exception e) { + LOGGER.debug("Error retrieving valet properties. " + e.getMessage()); + } + } + + /* + * This method will be invoked to send a Create request to Valet. + */ + public GenericValetResponse callValetCreateRequest(String requestId, String regionId, String tenantId, String serviceInstanceId, + String vnfId, String vnfName, String vfModuleId, String vfModuleName, String keystoneUrl, HeatRequest heatRequest) throws Exception { + ResponseEntity response = null; + GenericValetResponse gvr = null; + + try { + UriBuilder builder = UriBuilder.fromPath(baseUrl).path(basePath).queryParam("requestId", requestId); + URI uri = builder.build(); + + ValetCreateRequest vcr = this.createValetCreateRequest(regionId, tenantId, serviceInstanceId, vnfId, vnfName, vfModuleId, vfModuleName, keystoneUrl, heatRequest); + RestTemplate restTemplate = new RestTemplate(); + String body = mapper.writeValueAsString(vcr); + HttpHeaders headers = generateHeaders(requestId); + HttpEntity entity = new HttpEntity<>(body, headers); + LOGGER.debug("valet create req: " + uri.toString() + ", headers=" + headers.toString() + ", body=" + body.toString()); + + response = restTemplate.exchange(uri, HttpMethod.POST, entity, ValetCreateResponse.class); + gvr = this.getGVRFromResponse(response); + } catch (Exception e) { + LOGGER.error("An exception occurred in callValetCreateRequest", e); + throw e; + } + return gvr; + } + + /* + * This method will be invoked to send an Update request to Valet. + */ + public GenericValetResponse callValetUpdateRequest(String requestId, String regionId, String tenantId, String serviceInstanceId, + String vnfId, String vnfName, String vfModuleId, String vfModuleName, String keystoneUrl, HeatRequest heatRequest) throws Exception { + ResponseEntity response = null; + GenericValetResponse gvr = null; + + try { + UriBuilder builder = UriBuilder.fromPath(baseUrl).path(basePath).queryParam("requestId", requestId); + URI uri = builder.build(); + + ValetUpdateRequest vur = this.createValetUpdateRequest(regionId, tenantId, serviceInstanceId, vnfId, vnfName, vfModuleId, vfModuleName, keystoneUrl, heatRequest); + RestTemplate restTemplate = new RestTemplate(); + String body = mapper.writeValueAsString(vur); + HttpHeaders headers = generateHeaders(requestId); + HttpEntity entity = new HttpEntity<>(body, headers); + LOGGER.debug("valet update req: " + uri.toString() + ", headers=" + headers.toString() + ", body=" + body.toString()); + + response = restTemplate.exchange(uri, HttpMethod.PUT, entity, ValetUpdateResponse.class); + gvr = this.getGVRFromResponse(response); + } catch (Exception e) { + LOGGER.error("An exception occurred in callValetUpdateRequest", e); + throw e; + } + return gvr; + } + + /* + * This method will be invoked to send a Delete request to Valet. + */ + public GenericValetResponse callValetDeleteRequest(String requestId, String regionId, String tenantId, String vfModuleId, String vfModuleName) throws Exception { + ResponseEntity response = null; + GenericValetResponse gvr = null; + + try { + UriBuilder builder = UriBuilder.fromPath(baseUrl).path(basePath).queryParam("requestId", requestId); + URI uri = builder.build(); + + ValetDeleteRequest vdr = this.createValetDeleteRequest(regionId, tenantId, vfModuleId, vfModuleName); + RestTemplate restTemplate = new RestTemplate(); + String body = mapper.writeValueAsString(vdr); + HttpHeaders headers = generateHeaders(requestId); + HttpEntity entity = new HttpEntity<>(body, headers); + LOGGER.debug("valet delete req: " + uri.toString() + ", headers=" + headers.toString() + ", body=" + body.toString()); + + response = restTemplate.exchange(uri, HttpMethod.DELETE, entity, ValetDeleteResponse.class); + gvr = this.getGVRFromResponse(response); + } catch (Exception e) { + LOGGER.error("An exception occurred in callValetDeleteRequest", e); + throw e; + } + return gvr; + } + + /* + * This method is called to invoke a Confirm request to Valet. + */ + public GenericValetResponse callValetConfirmRequest(String requestId, String stackId) throws Exception { + ResponseEntity response = null; + GenericValetResponse gvr = null; + + try { + UriBuilder builder = UriBuilder.fromPath(this.baseUrl).path(this.basePath).path("{requestId}/confirm/"); + URI uri = builder.build(requestId); + + ValetConfirmRequest vcr = this.createValetConfirmRequest(stackId); + RestTemplate restTemplate = new RestTemplate(); + String body = mapper.writeValueAsString(vcr); + HttpHeaders headers = generateHeaders(requestId); + HttpEntity entity = new HttpEntity<>(body, headers); + LOGGER.debug("valet confirm req: " + uri.toString() + ", headers=" + headers.toString() + ", body=" + body); + + response = restTemplate.exchange(uri, HttpMethod.PUT, entity, ValetConfirmResponse.class); + gvr = this.getGVRFromResponse(response); + } catch (Exception e) { + LOGGER.error("An exception occurred in callValetConfirmRequest", e); + throw e; + } + return gvr; + } + + /* + * This method is called to invoke a Rollback request to Valet. + */ + public GenericValetResponse callValetRollbackRequest(String requestId, String stackId, Boolean suppressRollback, String errorMessage) throws Exception { + ResponseEntity response = null; + GenericValetResponse gvr = null; + + try { + UriBuilder builder = UriBuilder.fromPath(this.baseUrl).path(this.basePath).path("{requestId}/rollback/"); + URI uri = builder.build(requestId); + + ValetRollbackRequest vrr = this.createValetRollbackRequest(stackId, suppressRollback, errorMessage); + RestTemplate restTemplate = new RestTemplate(); + String body = mapper.writeValueAsString(vrr); + HttpHeaders headers = generateHeaders(requestId); + HttpEntity entity = new HttpEntity<>(body, headers); + LOGGER.debug("valet rollback req: " + uri.toString() + ", headers=" + headers.toString() + ", body=" + body.toString()); + + response = restTemplate.exchange(uri, HttpMethod.PUT, entity, ValetRollbackResponse.class); + gvr = this.getGVRFromResponse(response); + } catch (Exception e) { + LOGGER.error("An exception occurred in callValetRollbackRequest", e); + throw e; + } + return gvr; + } + + /* + * This method is to construct the ValetCreateRequest pojo + */ + private ValetCreateRequest createValetCreateRequest(String regionId, String tenantId, String serviceInstanceId, + String vnfId, String vnfName, String vfModuleId, String vfModuleName, String keystoneUrl, HeatRequest heatRequest) { + ValetCreateRequest vcr = new ValetCreateRequest(); + vcr.setHeatRequest(heatRequest); + vcr.setKeystoneUrl(keystoneUrl); + vcr.setRegionId(regionId); + vcr.setServiceInstanceId(serviceInstanceId); + vcr.setTenantId(tenantId); + vcr.setVfModuleId(vfModuleId); + vcr.setVfModuleName(vfModuleName); + vcr.setVnfId(vnfId); + vcr.setVnfName(vnfName); + + return vcr; + } + + /* + * This method is to construct the ValetUpdateRequest pojo + */ + private ValetUpdateRequest createValetUpdateRequest(String regionId, String tenantId, String serviceInstanceId, + String vnfId, String vnfName, String vfModuleId, String vfModuleName, String keystoneUrl, HeatRequest heatRequest) { + ValetUpdateRequest vur = new ValetUpdateRequest(); + vur.setHeatRequest(heatRequest); + vur.setKeystoneUrl(keystoneUrl); + vur.setRegionId(regionId == null ? "" : regionId); + vur.setServiceInstanceId(serviceInstanceId == null ? "" : serviceInstanceId); + vur.setTenantId(tenantId == null ? "" : tenantId); + vur.setVfModuleId(vfModuleId == null ? "" : vfModuleId); + vur.setVfModuleName(vfModuleName == null ? "" : vfModuleName); + vur.setVnfId(vnfId == null ? "" : vnfId); + vur.setVnfName(vnfName == null ? "" : vnfName); + + return vur; + } + + /* + * This method is to construct the ValetDeleteRequest pojo + */ + private ValetDeleteRequest createValetDeleteRequest(String regionId, String tenantId, String vfModuleId, String vfModuleName) { + ValetDeleteRequest vdr = new ValetDeleteRequest(); + vdr.setRegionId(regionId == null ? "" : regionId); + vdr.setTenantId(tenantId == null ? "" : tenantId); + vdr.setVfModuleId(vfModuleId == null ? "" : vfModuleId); + vdr.setVfModuleName(vfModuleName == null ? "" : vfModuleName); + + return vdr; + } + + /* + * This method is to construct the ValetDeleteRequest pojo + */ + private ValetConfirmRequest createValetConfirmRequest(String stackId) { + ValetConfirmRequest vcr = new ValetConfirmRequest(); + vcr.setStackId(stackId); + + return vcr; + } + + /* + * This method is to construct the ValetRollbackRequest pojo + */ + private ValetRollbackRequest createValetRollbackRequest(String stackId, Boolean suppressRollback, String errorMessage) { + ValetRollbackRequest vrr = new ValetRollbackRequest(); + vrr.setStackId(stackId); + vrr.setSuppressRollback(suppressRollback); + vrr.setErrorMessage(errorMessage); + + return vrr; + } + + private HttpHeaders generateHeaders(String requestId) { + HttpHeaders headers = new HttpHeaders(); + headers.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON); + if (!(this.authString == null || this.authString.isEmpty())) { + headers.add("Authorization", "Basic " + this.authString); + } + headers.add(ValetClient.REQ_ID_HEADER_NAME, requestId); + + return headers; + } + + private GenericValetResponse getGVRFromResponse(ResponseEntity response) { + GenericValetResponse gvr = null; + if (response != null) { + T responseObj = response.getBody(); + gvr = new GenericValetResponse<>(response.getStatusCodeValue(), ValetClient.NO_STATUS_RETURNED, responseObj); + + } else { + gvr = new GenericValetResponse<>(-1, ValetClient.NO_STATUS_RETURNED, null); + } + return gvr; + } +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/valet/beans/HeatRequest.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/valet/beans/HeatRequest.java new file mode 100644 index 0000000000..dfd257b06b --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/valet/beans/HeatRequest.java @@ -0,0 +1,125 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.so.adapters.valet.beans; + +import java.io.Serializable; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.woorea.openstack.heat.model.CreateStackParam; + +/* + * This class represents the heat request as sent to OpenStack as defined in the + * Valet Placement Operations API + */ +public class HeatRequest implements Serializable { + private static final long serialVersionUID = 768026109321305392L; + @JsonProperty("stack_name") + private String stackName; + @JsonProperty("disable_rollback") + private Boolean disableRollback; + @JsonProperty("timeout_mins") + private Integer timeoutMins; + @JsonProperty("template") + private String template; + @JsonProperty("environment") + private String environment; + @JsonProperty("files") + private Map files = new HashMap(); + @JsonProperty("parameters") + private Map parameters = new HashMap(); + + public HeatRequest(String stackName, boolean disableRollback, int timeoutMins, String template, String environment, Map files, Map parameters) { + super(); + this.stackName = stackName; + this.disableRollback = disableRollback; + this.timeoutMins = timeoutMins; + this.template = template; + this.environment = environment; + this.files = files; + this.parameters = parameters; + } + + public String getStackName() { + return this.stackName; + } + public void setStackName(String stackName) { + this.stackName = stackName; + } + public Boolean getDisableRollback() { + return this.disableRollback; + } + public void setDisableRollback(Boolean disableRollback) { + this.disableRollback = disableRollback; + } + public Integer getTimeoutMins() { + return this.timeoutMins; + } + public void setTimeoutMins(Integer timeoutMins) { + this.timeoutMins = timeoutMins; + } + public String getTemplate() { + return this.template; + } + public void setTemplate(String template) { + this.template = template; + } + public String getEnvironment() { + return this.environment; + } + public void setEnvironment(String environment) { + this.environment = environment; + } + public Map getFiles() { + return this.files; + } + public void setFiles(Map files) { + this.files = files; + } + public Map getParameters() { + return this.parameters; + } + public void setParameters(Map parameters) { + this.parameters = parameters; + } + @Override + public int hashCode() { + return Objects.hash(stackName, disableRollback, timeoutMins, template, environment, files, parameters); + } + @Override + public boolean equals(Object o) { + if (o == this) + return true; + if (!(o instanceof HeatRequest)) { + return false; + } + HeatRequest hr = (HeatRequest) o; + return Objects.equals(stackName, hr.stackName) + && Objects.equals(disableRollback, hr.disableRollback) + && Objects.equals(timeoutMins, hr.timeoutMins) + && Objects.equals(template, hr.template) + && Objects.equals(environment, hr.environment) + && Objects.equals(files, hr.files) + && Objects.equals(parameters, hr.parameters); + } +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/valet/beans/ValetConfirmRequest.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/valet/beans/ValetConfirmRequest.java new file mode 100644 index 0000000000..36083e8be6 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/valet/beans/ValetConfirmRequest.java @@ -0,0 +1,65 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.so.adapters.valet.beans; + +import java.io.Serializable; +import java.util.Objects; + +import com.fasterxml.jackson.annotation.JsonProperty; +/* + * This class represents the body of a Confirm operation on a Valet Placement API call + */ +public class ValetConfirmRequest implements Serializable { + private static final long serialVersionUID = 768026109321305392L; + + @JsonProperty("stack_id") + private String stackId; + + public ValetConfirmRequest() { + super(); + } + public ValetConfirmRequest(String stackId) { + super(); + this.stackId = stackId; + } + + public String getStackId() { + return this.stackId; + } + public void setStackId(String stackId) { + this.stackId = stackId; + } + + @Override + public int hashCode() { + return Objects.hash(stackId); + } + @Override + public boolean equals(Object o) { + if (o == this) + return true; + if (!(o instanceof ValetConfirmRequest)) { + return false; + } + ValetConfirmRequest vcr = (ValetConfirmRequest) o; + return Objects.equals(stackId, vcr.stackId); + } +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/valet/beans/ValetConfirmResponse.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/valet/beans/ValetConfirmResponse.java new file mode 100644 index 0000000000..c009da9608 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/valet/beans/ValetConfirmResponse.java @@ -0,0 +1,30 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.so.adapters.valet.beans; + +import java.io.Serializable; + +/* This class has no body - placeholder if needed - for the response to a Confirm operation */ + +public class ValetConfirmResponse implements Serializable { + private static final long serialVersionUID = 768026109321305392L; + +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/valet/beans/ValetCreateRequest.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/valet/beans/ValetCreateRequest.java new file mode 100644 index 0000000000..d692416ea1 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/valet/beans/ValetCreateRequest.java @@ -0,0 +1,134 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.so.adapters.valet.beans; + +import java.io.Serializable; +import java.util.Objects; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/* + * This class represents the body of a Create request operation on a Valet Placement API call + */ +public class ValetCreateRequest implements Serializable { + private static final long serialVersionUID = 768026109321305392L; + + @JsonProperty("region_id") + private String regionId; + @JsonProperty("tenant_id") + private String tenantId; + @JsonProperty("service_instance_id") + private String serviceInstanceId; + @JsonProperty("vnf_id") + private String vnfId; + @JsonProperty("vnf_name") + private String vnfName; + @JsonProperty("vf_module_id") + private String vfModuleId; + @JsonProperty("vf_module_name") + private String vfModuleName; + @JsonProperty("keystone_url") + private String keystoneUrl; + @JsonProperty("heat_request") + private HeatRequest heatRequest; + + public ValetCreateRequest() { + super(); + } + + public String getRegionId() { + return this.regionId; + } + public void setRegionId(String regionId) { + this.regionId = regionId; + } + public String getTenantId() { + return this.tenantId; + } + public void setTenantId(String tenantId) { + this.tenantId = tenantId; + } + public String getServiceInstanceId() { + return this.serviceInstanceId; + } + public void setServiceInstanceId(String serviceInstanceId) { + this.serviceInstanceId = serviceInstanceId; + } + public String getVnfId() { + return this.vnfId; + } + public void setVnfId(String vnfId) { + this.vnfId = vnfId; + } + public String getVnfName() { + return this.vnfName; + } + public void setVnfName(String vnfName) { + this.vnfName = vnfName; + } + public String getVfModuleId() { + return this.vfModuleId; + } + public void setVfModuleId(String vfModuleId) { + this.vfModuleId = vfModuleId; + } + public String getVfModuleName() { + return this.vfModuleName; + } + public void setVfModuleName(String vfModuleName) { + this.vfModuleName = vfModuleName; + } + public String getKeystoneUrl() { + return this.keystoneUrl; + } + public void setKeystoneUrl(String keystoneUrl) { + this.keystoneUrl = keystoneUrl; + } + public HeatRequest getHeatRequest() { + return this.heatRequest; + } + public void setHeatRequest(HeatRequest heatRequest) { + this.heatRequest = heatRequest; + } + + @Override + public int hashCode() { + return Objects.hash(regionId, tenantId, serviceInstanceId, vnfId, vnfName, vfModuleId, vfModuleName, keystoneUrl, heatRequest); + } + @Override + public boolean equals(Object o) { + if (o == this) + return true; + if (!(o instanceof ValetCreateRequest)) { + return false; + } + ValetCreateRequest vcr = (ValetCreateRequest) o; + return Objects.equals(regionId, vcr.regionId) + && Objects.equals(tenantId, vcr.tenantId) + && Objects.equals(serviceInstanceId, vcr.serviceInstanceId) + && Objects.equals(vnfId, vcr.vnfId) + && Objects.equals(vnfName, vcr.vnfName) + && Objects.equals(vfModuleId, vcr.vfModuleId) + && Objects.equals(vfModuleName, vcr.vfModuleName) + && Objects.equals(keystoneUrl, vcr.keystoneUrl) + && Objects.equals(heatRequest, vcr.heatRequest); + } +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/valet/beans/ValetCreateResponse.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/valet/beans/ValetCreateResponse.java new file mode 100644 index 0000000000..e0c750e79f --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/valet/beans/ValetCreateResponse.java @@ -0,0 +1,70 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.so.adapters.valet.beans; + +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.Map; +import java.util.Objects; +import java.io.Serializable; +/* + * This class represents the body of a Create response on a Valet Placement API call + */ +public class ValetCreateResponse implements Serializable { + private static final long serialVersionUID = 768026109321305392L; + + @JsonProperty("status") + private ValetStatus status; + @JsonProperty("parameters") + private Map parameters; + + public ValetCreateResponse() { + super(); + } + + public ValetStatus getStatus() { + return this.status; + } + public void setStatus(ValetStatus status) { + this.status = status; + } + public Map getParameters() { + return this.parameters; + } + public void setParameters(Map parameters) { + this.parameters = parameters; + } + + @Override + public int hashCode() { + return Objects.hash(status, parameters); + } + @Override + public boolean equals(Object o) { + if (o == this) + return true; + if (!(o instanceof ValetCreateResponse)) { + return false; + } + ValetCreateResponse vcr = (ValetCreateResponse) o; + return Objects.equals(status, vcr.status) + && Objects.equals(parameters, vcr.parameters); + } +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/valet/beans/ValetDeleteRequest.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/valet/beans/ValetDeleteRequest.java new file mode 100644 index 0000000000..7bd5855d0e --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/valet/beans/ValetDeleteRequest.java @@ -0,0 +1,84 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.so.adapters.valet.beans; + +import java.io.Serializable; +import java.util.Objects; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/* + * This class represents the body of a Delete request on a Valet Placement API call + */ +public class ValetDeleteRequest implements Serializable { + private static final long serialVersionUID = 768026109321305392L; + + @JsonProperty("region_id") + private String regionId; + @JsonProperty("tenant_id") + private String tenantId; + @JsonProperty("vf_module_id") + private String vfModuleId; + @JsonProperty("vf_module_name") + private String vfModuleName; + + public String getRegionId() { + return this.regionId; + } + public void setRegionId(String regionId) { + this.regionId = regionId; + } + public String getTenantId() { + return this.tenantId; + } + public void setTenantId(String tenantId) { + this.tenantId = tenantId; + } + public String getVfModuleId() { + return this.vfModuleId; + } + public void setVfModuleId(String vfModuleId) { + this.vfModuleId = vfModuleId; + } + public String getVfModuleName() { + return this.vfModuleName; + } + public void setVfModuleName(String vfModuleName) { + this.vfModuleName = vfModuleName; + } + @Override + public int hashCode() { + return Objects.hash(regionId, tenantId, vfModuleId, vfModuleName); + } + @Override + public boolean equals(Object o) { + if (o == this) + return true; + if (!(o instanceof ValetDeleteRequest)) { + return false; + } + ValetDeleteRequest vdr = (ValetDeleteRequest) o; + return Objects.equals(regionId, vdr.regionId) + && Objects.equals(tenantId, vdr.tenantId) + && Objects.equals(vfModuleId, vdr.vfModuleId) + && Objects.equals(vfModuleName, vdr.vfModuleName); + } +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/valet/beans/ValetDeleteResponse.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/valet/beans/ValetDeleteResponse.java new file mode 100644 index 0000000000..fa58752d61 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/valet/beans/ValetDeleteResponse.java @@ -0,0 +1,66 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.so.adapters.valet.beans; + +import java.io.Serializable; +import java.util.Objects; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/* + * This class represents the body of a Delete response on a Valet Placement API call + */ +public class ValetDeleteResponse implements Serializable { + private static final long serialVersionUID = 768026109321305392L; + @JsonProperty("status") + private ValetStatus status; + + public ValetDeleteResponse() { + super(); + } + public ValetDeleteResponse(ValetStatus status) { + super(); + this.status = status; + } + + public ValetStatus getStatus() { + return this.status; + } + public void setStatus(ValetStatus status) { + this.status = status; + } + + @Override + public int hashCode() { + return Objects.hash(status); + } + @Override + public boolean equals(Object o) { + if (o == this) + return true; + if (!(o instanceof ValetDeleteResponse)) { + return false; + } + ValetDeleteResponse vdr = (ValetDeleteResponse) o; + return Objects.equals(status, vdr.status); + } + +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/valet/beans/ValetRollbackRequest.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/valet/beans/ValetRollbackRequest.java new file mode 100644 index 0000000000..ae0af67f80 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/valet/beans/ValetRollbackRequest.java @@ -0,0 +1,81 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.so.adapters.valet.beans; + +import java.io.Serializable; +import java.util.Objects; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/* + * This class represents the body of a Rollback request on a Valet Placement API call + */ +public class ValetRollbackRequest implements Serializable { + private static final long serialVersionUID = 768026109321305392L; + + @JsonProperty("stack_id") + private String stackId; + @JsonProperty("suppress_rollback") + private Boolean suppressRollback = false; + @JsonProperty("error_message") + private String errorMessage; + + public ValetRollbackRequest() { + super(); + } + + public String getStackId() { + return this.stackId; + } + public void setStackId(String stackId) { + this.stackId = stackId; + } + public Boolean getSuppressRollback() { + return this.suppressRollback; + } + public void setSuppressRollback(Boolean suppressRollback) { + this.suppressRollback = suppressRollback; + } + public String getErrorMessage() { + return this.errorMessage; + } + public void setErrorMessage(String errorMessage) { + this.errorMessage = errorMessage; + } + + @Override + public int hashCode() { + return Objects.hash(stackId, suppressRollback, errorMessage); + } + @Override + public boolean equals(Object o) { + if (o == this) + return true; + if (!(o instanceof ValetRollbackRequest)) { + return false; + } + ValetRollbackRequest vrr = (ValetRollbackRequest) o; + return Objects.equals(stackId, vrr.stackId) + && Objects.equals(suppressRollback, vrr.suppressRollback) + && Objects.equals(errorMessage, vrr.errorMessage); + } + +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/valet/beans/ValetRollbackResponse.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/valet/beans/ValetRollbackResponse.java new file mode 100644 index 0000000000..429aa95af0 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/valet/beans/ValetRollbackResponse.java @@ -0,0 +1,29 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.so.adapters.valet.beans; + +import java.io.Serializable; +/* This class has no body - placeholder - body of a Rollback response on a Valet Placement Operation */ + +public class ValetRollbackResponse implements Serializable { + private static final long serialVersionUID = 768026109321305392L; + +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/valet/beans/ValetStatus.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/valet/beans/ValetStatus.java new file mode 100644 index 0000000000..067a6727c1 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/valet/beans/ValetStatus.java @@ -0,0 +1,81 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 - 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.onap.so.adapters.valet.beans; + +import java.io.Serializable; +import java.util.Objects; + +import com.fasterxml.jackson.annotation.JsonProperty; +import org.apache.commons.lang3.builder.ToStringBuilder; + +/* + * This class represents the status object as defined in the Valet Placement Operations API - part of Response objects + */ +public class ValetStatus implements Serializable { + private static final long serialVersionUID = 1L; + @JsonProperty("status") + private String status; + @JsonProperty("message") + private String message; + + @Override + public String toString() { + return new ToStringBuilder(this).append("status", status).append("message", message).toString(); + } + + public ValetStatus() { + super(); + } + + public ValetStatus(String statusCode, String statusMessage) { + super(); + this.status = statusCode; + this.message = statusMessage; + } + + public String getStatus() { + return this.status; + } + public void setStatus(String statusCode) { + this.status = statusCode; + } + public String getMessage() { + return this.message; + } + public void setMessage(String statusMessage) { + this.message = statusMessage; + } + + @Override + public int hashCode() { + return Objects.hash(status, message); + } + @Override + public boolean equals(Object o) { + if (o == this) + return true; + if (!(o instanceof ValetStatus)) { + return false; + } + ValetStatus vs = (ValetStatus) o; + return Objects.equals(status, vs.status) && Objects.equals(message, vs.message); + } +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/valet/beans/ValetUpdateRequest.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/valet/beans/ValetUpdateRequest.java new file mode 100644 index 0000000000..360c07b225 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/valet/beans/ValetUpdateRequest.java @@ -0,0 +1,134 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.so.adapters.valet.beans; + +import java.io.Serializable; +import java.util.Objects; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/* + * This class represents the body of an Update request on a Valet Placement API call + */ +public class ValetUpdateRequest implements Serializable { + private static final long serialVersionUID = 768026109321305392L; + + @JsonProperty("region_id") + private String regionId; + @JsonProperty("tenant_id") + private String tenantId; + @JsonProperty("service_instance_id") + private String serviceInstanceId; + @JsonProperty("vnf_id") + private String vnfId; + @JsonProperty("vnf_name") + private String vnfName; + @JsonProperty("vf_module_id") + private String vfModuleId; + @JsonProperty("vf_module_name") + private String vfModuleName; + @JsonProperty("keystone_url") + private String keystoneUrl; + @JsonProperty("heat_request") + private HeatRequest heatRequest; + + public ValetUpdateRequest() { + super(); + } + + public String getRegionId() { + return this.regionId; + } + public void setRegionId(String regionId) { + this.regionId = regionId; + } + public String getTenantId() { + return this.tenantId; + } + public void setTenantId(String tenantId) { + this.tenantId = tenantId; + } + public String getServiceInstanceId() { + return this.serviceInstanceId; + } + public void setServiceInstanceId(String serviceInstanceId) { + this.serviceInstanceId = serviceInstanceId; + } + public String getVnfId() { + return this.vnfId; + } + public void setVnfId(String vnfId) { + this.vnfId = vnfId; + } + public String getVnfName() { + return this.vnfName; + } + public void setVnfName(String vnfName) { + this.vnfName = vnfName; + } + public String getVfModuleId() { + return this.vfModuleId; + } + public void setVfModuleId(String vfModuleId) { + this.vfModuleId = vfModuleId; + } + public String getVfModuleName() { + return this.vfModuleName; + } + public void setVfModuleName(String vfModuleName) { + this.vfModuleName = vfModuleName; + } + public String getKeystoneUrl() { + return this.keystoneUrl; + } + public void setKeystoneUrl(String keystoneUrl) { + this.keystoneUrl = keystoneUrl; + } + public HeatRequest getHeatRequest() { + return this.heatRequest; + } + public void setHeatRequest(HeatRequest heatRequest) { + this.heatRequest = heatRequest; + } + @Override + public int hashCode() { + return Objects.hash(regionId, tenantId, serviceInstanceId, vnfId, vnfName, vfModuleId, vfModuleName, keystoneUrl, heatRequest); + + } + @Override + public boolean equals(Object o) { + if (o == this) + return true; + if (!(o instanceof ValetUpdateRequest)) { + return false; + } + ValetUpdateRequest vur = (ValetUpdateRequest) o; + return Objects.equals(regionId, vur.regionId) + && Objects.equals(tenantId, vur.tenantId) + && Objects.equals(serviceInstanceId, vur.serviceInstanceId) + && Objects.equals(vnfId, vur.vnfId) + && Objects.equals(vnfName, vur.vnfName) + && Objects.equals(vfModuleId, vur.vfModuleId) + && Objects.equals(vfModuleName, vur.vfModuleName) + && Objects.equals(keystoneUrl, vur.keystoneUrl) + && Objects.equals(heatRequest, vur.heatRequest); + } +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/valet/beans/ValetUpdateResponse.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/valet/beans/ValetUpdateResponse.java new file mode 100644 index 0000000000..36f11d30c0 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/valet/beans/ValetUpdateResponse.java @@ -0,0 +1,71 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.so.adapters.valet.beans; + +import java.io.Serializable; +import java.util.Map; +import java.util.Objects; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/* + * This class represents the body of an Update response on a Valet Placement API call + */ +public class ValetUpdateResponse implements Serializable { + private static final long serialVersionUID = 768026109321305392L; + @JsonProperty("status") + private ValetStatus status; + @JsonProperty("parameters") + private Map parameters; + + public ValetUpdateResponse() { + super(); + } + + public ValetStatus getStatus() { + return this.status; + } + public void setStatus(ValetStatus status) { + this.status = status; + } + public Map getParameters() { + return this.parameters; + } + public void setParameters(Map parameters) { + this.parameters = parameters; + } + + @Override + public int hashCode() { + return Objects.hash(status, parameters); + } + @Override + public boolean equals(Object o) { + if (o == this) + return true; + if (!(o instanceof ValetUpdateResponse)) { + return false; + } + ValetUpdateResponse vur = (ValetUpdateResponse) o; + return Objects.equals(status, vur.status) + && Objects.equals(parameters, vur.parameters); + } +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vdu/mapper/VfModuleCustomizationToVduMapper.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vdu/mapper/VfModuleCustomizationToVduMapper.java new file mode 100644 index 0000000000..f6442b6252 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vdu/mapper/VfModuleCustomizationToVduMapper.java @@ -0,0 +1,127 @@ +/*- + * ============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.onap.so.adapters.vdu.mapper; + +import java.util.List; + +import org.onap.so.adapters.vdu.VduModelInfo; +import org.onap.so.adapters.vdu.VduArtifact; +import org.onap.so.adapters.vdu.VduArtifact.ArtifactType; +import org.onap.so.db.catalog.beans.HeatEnvironment; +import org.onap.so.db.catalog.beans.HeatFiles; +import org.onap.so.db.catalog.beans.HeatTemplate; +import org.onap.so.db.catalog.beans.VfModuleCustomization; +import org.springframework.stereotype.Component; + +@Component +public class VfModuleCustomizationToVduMapper { + + public VduModelInfo mapVfModuleCustomizationToVdu(VfModuleCustomization vfModuleCustom) + { + VduModelInfo vduModel = new VduModelInfo(); + vduModel.setModelCustomizationUUID(vfModuleCustom.getModelCustomizationUUID()); + + // Map the cloud templates, attached files, and environment file + mapCloudTemplates(vfModuleCustom.getVfModule().getModuleHeatTemplate(), vduModel); + mapCloudFiles(vfModuleCustom,vduModel); + mapEnvironment(vfModuleCustom.getHeatEnvironment(), vduModel); + + return vduModel; + } + + public VduModelInfo mapVfModuleCustVolumeToVdu(VfModuleCustomization vfModuleCustom) + { + VduModelInfo vduModel = new VduModelInfo(); + vduModel.setModelCustomizationUUID(vfModuleCustom.getModelCustomizationUUID()); + + // Map the cloud templates, attached files, and environment file + mapCloudTemplates(vfModuleCustom.getVfModule().getVolumeHeatTemplate(), vduModel); + mapCloudFiles(vfModuleCustom,vduModel); + mapEnvironment(vfModuleCustom.getVolumeHeatEnv(), vduModel); + + return vduModel; + } + + private void mapCloudTemplates(HeatTemplate heatTemplate, VduModelInfo vduModel) { + // TODO: These catalog objects will be refactored to be non-Heat-specific + + 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 + List childTemplates = heatTemplate.getChildTemplates(); + if (childTemplates != null) { + for(HeatTemplate childTemplate : childTemplates){ + vduArtifacts.add(mapHeatTemplateToVduArtifact(childTemplate, ArtifactType.NESTED_TEMPLATE)); + } + } + } + + 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) { + // TODO: These catalog objects will be refactored to be non-Heat-specific + + List vduArtifacts = vduModel.getArtifacts(); + + // Attached Files + List heatFiles = vfModuleCustom.getVfModule().getHeatFiles(); + if (heatFiles != null) { + for(HeatFiles file : heatFiles){ + vduArtifacts.add(mapCloudFileToVduArtifact(file, ArtifactType.TEXT_FILE)); + } + } + } + + 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; + } + +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/BpelRestClient.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/BpelRestClient.java new file mode 100644 index 0000000000..6383f57693 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/BpelRestClient.java @@ -0,0 +1,296 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.so.adapters.vnf; + + +import java.security.GeneralSecurityException; +import java.util.Set; +import java.util.TreeSet; + +import javax.annotation.PostConstruct; +import javax.xml.bind.DatatypeConverter; + +import org.apache.http.HttpEntity; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.ContentType; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.util.EntityUtils; +import org.onap.so.logger.MessageEnum; +import org.onap.so.logger.MsoLogger; +import org.onap.so.utils.CryptoUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Scope; +import org.springframework.core.env.Environment; +import org.springframework.stereotype.Component; + +/** + * This is the class that is used to POST replies from the MSO adapters to the BPEL engine. + * It can be configured via property file, or modified using the member methods. + * The properties to use are: + * org.onap.so.adapters.vnf.bpelauth encrypted authorization string to send to BEPL engine + * org.onap.so.adapters.vnf.sockettimeout socket timeout value + * org.onap.so.adapters.vnf.connecttimeout connect timeout value + * org.onap.so.adapters.vnf.retrycount number of times to retry failed connections + * org.onap.so.adapters.vnf.retryinterval interval (in seconds) between retries + * org.onap.so.adapters.vnf.retrylist list of response codes that will trigger a retry (the special code + * 900 means "connection was not established") + */ +@Component("VnfBpel") +@Scope("prototype") +public class BpelRestClient { + public static final String MSO_PROP_VNF_ADAPTER = "MSO_PROP_VNF_ADAPTER"; + private static final String PROPERTY_DOMAIN = "org.onap.so.adapters.vnf"; + private static final String BPEL_AUTH_PROPERTY = PROPERTY_DOMAIN+".bpelauth"; + private static final String SOCKET_TIMEOUT_PROPERTY = PROPERTY_DOMAIN+".sockettimeout"; + private static final String CONN_TIMEOUT_PROPERTY = PROPERTY_DOMAIN+".connecttimeout"; + private static final String RETRY_COUNT_PROPERTY = PROPERTY_DOMAIN+".retrycount"; + private static final String RETRY_INTERVAL_PROPERTY = PROPERTY_DOMAIN+".retryinterval"; + private static final String RETRY_LIST_PROPERTY = PROPERTY_DOMAIN+".retrylist"; + private static final String ENCRYPTION_KEY = "aa3871669d893c7fb8abbcda31b88b4f"; + private static final MsoLogger LOGGER = MsoLogger.getMsoLogger (MsoLogger.Catalog.RA, BpelRestClient.class); + + /** Default socket timeout (in seconds) */ + public static final int DEFAULT_SOCKET_TIMEOUT = 5; + /** Default connect timeout (in seconds) */ + public static final int DEFAULT_CONNECT_TIMEOUT = 5; + /** By default, retry up to five times */ + public static final int DEFAULT_RETRY_COUNT = 5; + /** Default interval to wait between retries (in seconds), negative means use backoff algorithm */ + public static final int DEFAULT_RETRY_INTERVAL = -15; + /** Default list of response codes to trigger a retry */ + public static final String DEFAULT_RETRY_LIST = "408,429,500,502,503,504,900"; // 900 is "connection failed" + /** Default credentials */ + public static final String DEFAULT_CREDENTIALS = ""; + + @Autowired + private Environment env; + // Properties of the BPEL client -- all are configurable + private int socketTimeout; + private int connectTimeout; + private int retryCount; + private int retryInterval; + private Set retryList; + private String credentials; + + // last response from BPEL engine + private int lastResponseCode; + private String lastResponse; + + /** + * Create a client to send results to the BPEL engine, using configuration from the + * MSO_PROP_VNF_ADAPTER properties. + */ + public BpelRestClient() { + socketTimeout = DEFAULT_SOCKET_TIMEOUT; + connectTimeout = DEFAULT_CONNECT_TIMEOUT; + retryCount = DEFAULT_RETRY_COUNT; + retryInterval = DEFAULT_RETRY_INTERVAL; + setRetryList(DEFAULT_RETRY_LIST); + credentials = DEFAULT_CREDENTIALS; + lastResponseCode = 0; + lastResponse = ""; + + } + + @PostConstruct + protected void init() { + + socketTimeout = env.getProperty(SOCKET_TIMEOUT_PROPERTY, Integer.class, DEFAULT_SOCKET_TIMEOUT); + connectTimeout = env.getProperty(CONN_TIMEOUT_PROPERTY, Integer.class, DEFAULT_CONNECT_TIMEOUT); + retryCount = env.getProperty(RETRY_COUNT_PROPERTY, Integer.class, DEFAULT_RETRY_COUNT); + retryInterval = env.getProperty(RETRY_INTERVAL_PROPERTY, Integer.class, DEFAULT_RETRY_INTERVAL); + setRetryList(env.getProperty(RETRY_LIST_PROPERTY, DEFAULT_RETRY_LIST)); + credentials = getEncryptedProperty(BPEL_AUTH_PROPERTY, DEFAULT_CREDENTIALS, ENCRYPTION_KEY); + } + + public int getSocketTimeout() { + return socketTimeout; + } + + public void setSocketTimeout(int socketTimeout) { + this.socketTimeout = socketTimeout; + } + + public int getConnectTimeout() { + return connectTimeout; + } + + public void setConnectTimeout(int connectTimeout) { + this.connectTimeout = connectTimeout; + } + + public int getRetryCount() { + return retryCount; + } + + public void setRetryCount(int retryCount) { + int newRetryCount = retryCount; + if (newRetryCount < 0) + newRetryCount = DEFAULT_RETRY_COUNT; + this.retryCount = newRetryCount; + } + + public int getRetryInterval() { + return retryInterval; + } + + public void setRetryInterval(int retryInterval) { + this.retryInterval = retryInterval; + } + + public String getCredentials() { + return credentials; + } + + public void setCredentials(String credentials) { + this.credentials = credentials; + } + + public String getRetryList() { + if (retryList.isEmpty()) + return ""; + String t = retryList.toString(); + return t.substring(1, t.length()-1); + } + + public void setRetryList(String retryList) { + Set s = new TreeSet<>(); + for (String t : retryList.split("[, ]")) { + try { + s.add(Integer.parseInt(t)); + } catch (NumberFormatException x) { + // ignore + } + } + this.retryList = s; + } + + public int getLastResponseCode() { + return lastResponseCode; + } + + public String getLastResponse() { + return lastResponse; + } + + /** + * Post a response to the URL of the BPEL engine. As long as the response code is one of those in + * the retryList, the post will be retried up to "retrycount" times with an interval (in seconds) + * of "retryInterval". If retryInterval is negative, then each successive retry interval will be + * double the previous one. + * @param toBpelStr the content (XML or JSON) to post + * @param bpelUrl the URL to post to + * @param isxml true if the content is XML, otherwise assumed to be JSON + * @return true if the post succeeded, false if all retries failed + */ + public boolean bpelPost(final String toBpelStr, final String bpelUrl, final boolean isxml) { + debug("Sending response to BPEL: " + toBpelStr); + int totalretries = 0; + int retryint = retryInterval; + while (true) { + sendOne(toBpelStr, bpelUrl, isxml); + // Note: really should handle response code 415 by switching between content types if needed + if (!retryList.contains(lastResponseCode)) { + debug("Got response code: " + lastResponseCode + ": returning."); + return true; + } + if (totalretries >= retryCount) { + debug("Retried " + totalretries + " times, giving up."); + LOGGER.error(MessageEnum.RA_SEND_VNF_NOTIF_ERR, "Could not deliver response to BPEL after "+totalretries+" tries: "+toBpelStr, "Camunda", "", MsoLogger.ErrorCode.BusinessProcesssError, "Could not deliver response to BPEL"); + return false; + } + totalretries++; + int sleepinterval = retryint; + if (retryint < 0) { + // if retry interval is negative double the retry on each pass + sleepinterval = -retryint; + retryint *= 2; + } + debug("Sleeping for " + sleepinterval + " seconds."); + try { + Thread.sleep(sleepinterval * 1000L); + } catch (InterruptedException e) { + LOGGER.debug("Exception while Thread sleep", e); + Thread.currentThread().interrupt(); + } + } + } + private void debug(String m) { + LOGGER.debug(m); + } + private void sendOne(final String toBpelStr, final String bpelUrl, final boolean isxml) { + LOGGER.debug("Sending to BPEL server: "+bpelUrl); + LOGGER.debug("Content is: "+toBpelStr); + + //POST + HttpPost post = new HttpPost(bpelUrl); + if (credentials != null && !credentials.isEmpty()) + post.addHeader("Authorization", "Basic " + DatatypeConverter.printBase64Binary(credentials.getBytes())); + + //ContentType + ContentType ctype = isxml ? ContentType.APPLICATION_XML : ContentType.APPLICATION_JSON; + post.setEntity(new StringEntity(toBpelStr, ctype)); + + //Timeouts + RequestConfig requestConfig = RequestConfig + .custom() + .setSocketTimeout(socketTimeout * 1000) + .setConnectTimeout(connectTimeout * 1000) + .build(); + post.setConfig(requestConfig); + + try (CloseableHttpClient client = HttpClients.createDefault()) { + CloseableHttpResponse response = client.execute(post); + if (response != null) { + lastResponseCode = response.getStatusLine().getStatusCode(); + HttpEntity entity = response.getEntity(); + lastResponse = (entity != null) ? EntityUtils.toString(entity) : ""; + } else { + lastResponseCode = 900; + lastResponse = ""; + } + } catch (Exception e) { + String error = "Error sending Bpel notification:" + toBpelStr; + LOGGER.error (MessageEnum.RA_SEND_VNF_NOTIF_ERR, error, "Camunda", "", MsoLogger.ErrorCode.BusinessProcesssError, "Exception - Error sending Bpel notification", e); + lastResponseCode = 900; + lastResponse = ""; + } + + LOGGER.debug("Response code from BPEL server: "+lastResponseCode); + LOGGER.debug("Response body is: "+lastResponse); + } + + private String getEncryptedProperty(String key, String defaultValue, String encryptionKey) { + if (env.getProperty(key) != null) { + try { + return CryptoUtils.decrypt(env.getProperty(key), encryptionKey); + } catch (GeneralSecurityException e) { + LOGGER.debug("Exception while decrypting property: " + env.getProperty(key), e); + } + } + return defaultValue; + } + +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/CSAR.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/CSAR.java new file mode 100644 index 0000000000..bbfcef02e2 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/CSAR.java @@ -0,0 +1,192 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 - 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.onap.so.adapters.vnf; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintStream; +import java.util.ArrayList; +import java.util.List; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; + +import org.onap.so.adapters.vdu.VduArtifact; +import org.onap.so.adapters.vdu.VduArtifact.ArtifactType; +import org.onap.so.adapters.vdu.VduModelInfo; +import org.onap.so.adapters.vnf.exceptions.VnfException; + +import com.google.common.io.Files; + +/** + * The purpose of this class is to create a CSAR byte array from Vdu inputs for the purpose + * of forwarding to a TOSCA orchestrator. + * + * @author DeWayne + * + */ +public class CSAR { + private static final String MANIFEST_FILENAME = "MANIFEST.MF"; + private VduModelInfo vduModel; + + public CSAR(VduModelInfo model){ + this.vduModel = model; + } + + /** + * Creates a byte array representation of a CSAR corresponding to the VduBlueprint arg in the + * constructor. + * + * @return + * @throws VnfException + */ + public byte[] create() { + File dir = Files.createTempDir(); + + /** + * Create subdir + */ + File metadir = new File(dir.getAbsolutePath() + "/TOSCA-Metadata"); + if (!metadir.mkdir()) { + throw new RuntimeException("CSAR TOSCA-Metadata directory create failed"); + } + + /** + * Organize model info for consumption + */ + VduArtifact mainTemplate = null; + List extraFiles = new ArrayList<>(); + for(VduArtifact artifact: vduModel.getArtifacts()) { + if(artifact.getType() == ArtifactType.MAIN_TEMPLATE ) { + mainTemplate = artifact; + } else{ + extraFiles.add(artifact); + } + } + + if (mainTemplate == null) { // make a dummy to avoid null pointers + mainTemplate = new VduArtifact("", new byte[0], null); + } + + /** + * Write template files + */ + try (OutputStream ofs = new FileOutputStream(new File(dir, mainTemplate.getName())); + PrintStream mfstream = new PrintStream(new File(metadir.getAbsolutePath() + '/' + MANIFEST_FILENAME)); + ) { + ofs.write(mainTemplate.getContent()); + + /** + * Write other files + */ + if (!extraFiles.isEmpty()) { + for (VduArtifact artifact: extraFiles){ + try (OutputStream out = new FileOutputStream(new File(dir, artifact.getName()));) { + out.write(artifact.getContent()); + } + } + } + + + /** + * Create manifest + */ + mfstream.println("TOSCA-Meta-File-Version: 1.0"); + mfstream.println("CSAR-Version: 1.1"); + mfstream.println("Created-by: ONAP"); + mfstream.println("Entry-Definitions: " + mainTemplate.getName()); + + /** + * ZIP it up + */ + ByteArrayOutputStream zipbytes = new ByteArrayOutputStream(); + ZipOutputStream zos = new ZipOutputStream(zipbytes); + compressTree(zos, "", dir, dir); + zos.close(); + return zipbytes.toByteArray(); + + } catch (Exception e) { + throw new RuntimeException("Failed to create CSAR: " + e.getMessage()); + } finally { + /** + * Clean up tmpdir + */ + deleteDirectory(dir); + } + } + + /** + * Private methods + */ + + /** + * Compresses (ZIPs) a directory tree + * + * @param dir + * @throws IOException + */ + private void compressTree(ZipOutputStream zos, String path, File basedir, File dir) throws IOException { + if (!dir.isDirectory()) + return; + + for (File f : dir.listFiles()) { + if (f.isDirectory()) { + String newpath = path + f.getName() + '/'; + ZipEntry entry = new ZipEntry(newpath); + zos.putNextEntry(entry); + zos.closeEntry(); + compressTree(zos, newpath, basedir, f); + } else { + ZipEntry ze = new ZipEntry( + f.getAbsolutePath().substring(basedir.getAbsolutePath().length() + 1).replaceAll("\\\\", "/")); + zos.putNextEntry(ze); + // read the file and write to ZipOutputStream + try (FileInputStream fis = new FileInputStream(f);) { + byte[] buffer = new byte[1024]; + int len; + while ((len = fis.read(buffer)) > 0) { + zos.write(buffer, 0, len); + } + } + zos.closeEntry(); + } + } + } + + private boolean deleteDirectory(File directory) { + if (directory.exists()) { + File[] files = directory.listFiles(); + if (null != files) { + for (int i = 0; i < files.length; i++) { + if (files[i].isDirectory()) { + deleteDirectory(files[i]); + } else { + files[i].delete(); + } + } + } + } + return (directory.delete()); + } +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/MsoVnfAdapter.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/MsoVnfAdapter.java new file mode 100644 index 0000000000..5efcc2c90d --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/MsoVnfAdapter.java @@ -0,0 +1,147 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.so.adapters.vnf; + + +import java.util.Map; + +import javax.jws.WebMethod; +import javax.jws.WebParam; +import javax.jws.WebParam.Mode; +import javax.jws.WebService; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.ws.Holder; + +import org.onap.so.adapters.vnf.exceptions.VnfAlreadyExists; +import org.onap.so.adapters.vnf.exceptions.VnfException; +import org.onap.so.entity.MsoRequest; +import org.onap.so.openstack.beans.VnfRollback; +import org.onap.so.openstack.beans.VnfStatus; + +@WebService (name="VnfAdapter", targetNamespace="http://org.onap.so/vnf") +public interface MsoVnfAdapter +{ + /** + * This is the "Create VNF" Web Service Endpoint definition. + */ + @WebMethod + public void createVnf (@WebParam(name="cloudSiteId") @XmlElement(required=true) String cloudSiteId, + @WebParam(name="tenantId") @XmlElement(required=true) String tenantId, + @WebParam(name="vnfType") @XmlElement(required=true) String vnfType, + @WebParam(name="vnfVersion") @XmlElement(required=false) String vnfVersion, + @WebParam(name="vnfName") @XmlElement(required=true) String vnfName, + @WebParam(name="requestType") @XmlElement(required=false) String requestType, + @WebParam(name="volumeGroupHeatStackId") @XmlElement(required=false) String volumeGroupHeatStackId, + @WebParam(name="inputs") Map inputs, + @WebParam(name="failIfExists") Boolean failIfExists, + @WebParam(name="backout") Boolean backout, + @WebParam(name="enableBridge") Boolean enableBridge, + @WebParam(name="request") MsoRequest msoRequest, + @WebParam(name="vnfId", mode=Mode.OUT) Holder vnfId, + @WebParam(name="outputs", mode=Mode.OUT) Holder> outputs, + @WebParam(name="rollback", mode=Mode.OUT) Holder rollback ) + throws VnfException, VnfAlreadyExists; + + @WebMethod + public void updateVnf (@WebParam(name="cloudSiteId") @XmlElement(required=true) String cloudSiteId, + @WebParam(name="tenantId") @XmlElement(required=true) String tenantId, + @WebParam(name="vnfType") @XmlElement(required=true) String vnfType, + @WebParam(name="vnfVersion") @XmlElement(required=false) String vnfVersion, + @WebParam(name="vnfName") @XmlElement(required=true) String vnfName, + @WebParam(name="requestType") @XmlElement(required=false) String requestType, + @WebParam(name="volumeGroupHeatStackId") @XmlElement(required=false) String volumeGroupHeatStackId, + @WebParam(name="inputs") Map inputs, + @WebParam(name="request") MsoRequest msoRequest, + @WebParam(name="outputs", mode=Mode.OUT) Holder> outputs, + @WebParam(name="rollback", mode=Mode.OUT) Holder rollback ) + throws VnfException; + + @WebMethod + public void queryVnf (@WebParam(name="cloudSiteId") @XmlElement(required=true) String cloudSiteId, + @WebParam(name="tenantId") @XmlElement(required=true) String tenantId, + @WebParam(name="vnfName") @XmlElement(required=true) String vnfName, + @WebParam(name="request") MsoRequest msoRequest, + @WebParam(name="vnfExists", mode=Mode.OUT) Holder vnfExists, + @WebParam(name="vnfId", mode=Mode.OUT) Holder vnfId, + @WebParam(name="status", mode=Mode.OUT) Holder status, + @WebParam(name="outputs", mode=Mode.OUT) Holder> outputs ) + throws VnfException; + + @WebMethod + public void deleteVnf (@WebParam(name="cloudSiteId") @XmlElement(required=true) String cloudSiteId, + @WebParam(name="tenantId") @XmlElement(required=true) String tenantId, + @WebParam(name="vnfName") @XmlElement(required=true) String vnfName, + @WebParam(name="request") MsoRequest msoRequest) + throws VnfException; + + + @WebMethod + public void rollbackVnf (@WebParam(name="rollback") @XmlElement(required=true) VnfRollback rollback) + throws VnfException; + + @WebMethod + public void createVfModule (@WebParam(name="cloudSiteId") @XmlElement(required=true) String cloudSiteId, + @WebParam(name="tenantId") @XmlElement(required=true) String tenantId, + @WebParam(name="vnfType") @XmlElement(required=true) String vnfType, + @WebParam(name="vnfVersion") @XmlElement(required=false) String vnfVersion, + @WebParam(name="vnfName") @XmlElement(required=true) String vnfName, + @WebParam(name="requestType") @XmlElement(required=false) String requestType, + @WebParam(name="volumeGroupHeatStackId") @XmlElement(required=false) String volumeGroupHeatStackId, + @WebParam(name="baseVfHeatStackId") @XmlElement(required=false) String baseVfHeatStackId, + @WebParam(name = "modelCustomizationUuid") @XmlElement(required = false) String modelCustomizationUuid, + @WebParam(name="inputs") Map inputs, + @WebParam(name="failIfExists") Boolean failIfExists, + @WebParam(name="backout") Boolean backout, + @WebParam(name="enableBridge") Boolean enableBridge, + @WebParam(name="request") MsoRequest msoRequest, + @WebParam(name="vnfId", mode=Mode.OUT) Holder vnfId, + @WebParam(name="outputs", mode=Mode.OUT) Holder> outputs, + @WebParam(name="rollback", mode=Mode.OUT) Holder rollback ) + throws VnfException, VnfAlreadyExists; + + @WebMethod + public void deleteVfModule (@WebParam(name="cloudSiteId") @XmlElement(required=true) String cloudSiteId, + @WebParam(name="tenantId") @XmlElement(required=true) String tenantId, + @WebParam(name="vfName") @XmlElement(required=true) String vfName, + @WebParam(name="request") MsoRequest msoRequest, + @WebParam(name = "vfModuleOutputs", mode = Mode.OUT) Holder> vfModuleOutputs) + throws VnfException; + + @WebMethod + public void updateVfModule (@WebParam(name="cloudSiteId") @XmlElement(required=true) String cloudSiteId, + @WebParam(name="tenantId") @XmlElement(required=true) String tenantId, + @WebParam(name="vnfType") @XmlElement(required=true) String vnfType, + @WebParam(name="vnfVersion") @XmlElement(required=false) String vnfVersion, + @WebParam(name="vnfName") @XmlElement(required=true) String vnfName, + @WebParam(name="requestType") @XmlElement(required=false) String requestType, + @WebParam(name="volumeGroupHeatStackId") @XmlElement(required=false) String volumeGroupHeatStackId, + @WebParam(name="baseVfHeatStackId") @XmlElement(required=false) String baseVfHeatStackId, + @WebParam(name="vfModuleStackId") @XmlElement(required=false) String vfModuleStackId, + @WebParam(name = "modelCustomizationUuid") @XmlElement(required = false) String modelCustomizationUuid, + @WebParam(name="inputs") Map inputs, + @WebParam(name="request") MsoRequest msoRequest, + @WebParam(name="outputs", mode=Mode.OUT) Holder> outputs, + @WebParam(name="rollback", mode=Mode.OUT) Holder rollback ) + throws VnfException; + + @WebMethod + public void healthCheck (); +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/MsoVnfAdapterAsync.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/MsoVnfAdapterAsync.java new file mode 100644 index 0000000000..b67a412c3e --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/MsoVnfAdapterAsync.java @@ -0,0 +1,105 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.so.adapters.vnf; + + +import java.util.Map; + +import javax.jws.Oneway; +import javax.jws.WebMethod; +import javax.jws.WebParam; +import javax.jws.WebService; +import javax.xml.bind.annotation.XmlElement; + +import org.onap.so.entity.MsoRequest; +import org.onap.so.openstack.beans.VnfRollback; + +/** + * This webservice defines the Asynchronous versions of VNF adapter calls. + * The notification messages for final responses are documented elsewhere + * (by the client service WSDL). + * + */ +@WebService (name="VnfAdapterAsync", targetNamespace="http://org.onap.so/vnfA") +public interface MsoVnfAdapterAsync +{ + /** + * This is the "Create VNF" Web Service Endpoint definition. + */ + @WebMethod + @Oneway + public void createVnfA (@WebParam(name="cloudSiteId") @XmlElement(required=true) String cloudSiteId, + @WebParam(name="tenantId") @XmlElement(required=true) String tenantId, + @WebParam(name="vnfType") @XmlElement(required=true) String vnfType, + @WebParam(name="vnfVersion") @XmlElement(required=false) String vnfVersion, + @WebParam(name="vnfName") @XmlElement(required=true) String vnfName, + @WebParam(name="requestType") @XmlElement(required=false) String requestType, + @WebParam(name="volumeGroupHeatStackId") @XmlElement(required=false) String volumeGroupHeatStackId, + @WebParam(name="inputs") Map inputs, + @WebParam(name="failIfExists") Boolean failIfExists, + @WebParam(name="backout") Boolean backout, + @WebParam(name="enableBridge") Boolean enableBridge, + @WebParam(name="messageId") @XmlElement(required=true) String messageId, + @WebParam(name="request") MsoRequest msoRequest, + @WebParam(name="notificationUrl") @XmlElement(required=true) String notificationUrl ); + + @WebMethod + @Oneway + public void updateVnfA (@WebParam(name="cloudSiteId") @XmlElement(required=true) String cloudSiteId, + @WebParam(name="tenantId") @XmlElement(required=true) String tenantId, + @WebParam(name="vnfType") @XmlElement(required=true) String vnfType, + @WebParam(name="vnfVersion") @XmlElement(required=false) String vnfVersion, + @WebParam(name="vnfName") @XmlElement(required=true) String vnfName, + @WebParam(name="requestType") @XmlElement(required=false) String requestType, + @WebParam(name="volumeGroupHeatStackId") @XmlElement(required=false) String volumeGroupHeatStackId, + @WebParam(name="inputs") Map inputs, + @WebParam(name="messageId") @XmlElement(required=true) String messageId, + @WebParam(name="request") MsoRequest msoRequest, + @WebParam(name="notificationUrl") @XmlElement(required=true) String notificationUrl ); + + @WebMethod + @Oneway + public void queryVnfA (@WebParam(name="cloudSiteId") @XmlElement(required=true) String cloudSiteId, + @WebParam(name="tenantId") @XmlElement(required=true) String tenantId, + @WebParam(name="vnfName") @XmlElement(required=true) String vnfName, + @WebParam(name="messageId") @XmlElement(required=true) String messageId, + @WebParam(name="request") MsoRequest msoRequest, + @WebParam(name="notificationUrl") @XmlElement(required=true) String notificationUrl ); + + @WebMethod + @Oneway + public void deleteVnfA (@WebParam(name="cloudSiteId") @XmlElement(required=true) String cloudSiteId, + @WebParam(name="tenantId") @XmlElement(required=true) String tenantId, + @WebParam(name="vnfName") @XmlElement(required=true) String vnfName, + @WebParam(name="messageId") @XmlElement(required=true) String messageId, + @WebParam(name="request") MsoRequest msoRequest, + @WebParam(name="notificationUrl") @XmlElement(required=true) String notificationUrl ); + + @WebMethod + @Oneway + public void rollbackVnfA (@WebParam(name="rollback") @XmlElement(required=true) VnfRollback rollback, + @WebParam(name="messageId") @XmlElement(required=true) String messageId, + @WebParam(name="notificationUrl") @XmlElement(required=true) String notificationUrl ); + + + @WebMethod + public void healthCheckA (); +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/MsoVnfAdapterAsyncImpl.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/MsoVnfAdapterAsyncImpl.java new file mode 100644 index 0000000000..95135f579d --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/MsoVnfAdapterAsyncImpl.java @@ -0,0 +1,666 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * Copyright (C) 2017 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.so.adapters.vnf; + + +import java.net.MalformedURLException; +import java.net.URL; +import java.security.GeneralSecurityException; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.jws.WebService; +import javax.xml.bind.DatatypeConverter; +import javax.xml.namespace.QName; +import javax.xml.ws.BindingProvider; +import javax.xml.ws.Holder; +import javax.xml.ws.handler.MessageContext; + +import org.onap.so.adapters.vnf.async.client.CreateVnfNotification; +import org.onap.so.adapters.vnf.async.client.QueryVnfNotification; +import org.onap.so.adapters.vnf.async.client.UpdateVnfNotification; +import org.onap.so.adapters.vnf.async.client.VnfAdapterNotify; +import org.onap.so.adapters.vnf.async.client.VnfAdapterNotify_Service; +import org.onap.so.adapters.vnf.exceptions.VnfException; +import org.onap.so.entity.MsoRequest; +import org.onap.so.logger.MessageEnum; +import org.onap.so.logger.MsoAlarmLogger; +import org.onap.so.logger.MsoLogger; +import org.onap.so.openstack.beans.VnfRollback; +import org.onap.so.openstack.beans.VnfStatus; +import org.onap.so.utils.CryptoUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.env.Environment; +import org.springframework.stereotype.Component; + +@WebService(serviceName = "VnfAdapterAsync", endpointInterface = "org.onap.so.adapters.vnf.MsoVnfAdapterAsync", targetNamespace = "http://org.onap.so/vnfA") +@Component +public class MsoVnfAdapterAsyncImpl implements MsoVnfAdapterAsync { + + public static final String MSO_PROP_VNF_ADAPTER="MSO_PROP_VNF_ADAPTER"; + private static final MsoLogger LOGGER = MsoLogger.getMsoLogger (MsoLogger.Catalog.RA, MsoVnfAdapterAsyncImpl.class); + private static MsoAlarmLogger alarmLogger = new MsoAlarmLogger (); + private static final String BPEL_AUTH_PROP = "org.onap.so.adapters.vnf.bpelauth"; + private static final String ENCRYPTION_KEY = "aa3871669d893c7fb8abbcda31b88b4f"; + + @Autowired + private Environment environment; + + @Autowired + private MsoVnfAdapterImpl vnfImpl; + + /** + * Health Check web method. Does nothing but return to show the adapter is deployed. + */ + @Override + public void healthCheckA () { + LOGGER.debug ("Health check call in VNF Adapter"); + } + + /** + * This is the asynchronous "Create VNF" web service implementation. + * It will create a new VNF of the requested type in the specified cloud + * and tenant. The tenant must exist before this service is called. + * + * If a VNF with the same name already exists, this can be considered a + * success or failure, depending on the value of the 'failIfExists' parameter. + * + * All VNF types will be defined in the MSO catalog. The caller must request + * one of these pre-defined types or an error will be returned. Within the + * catalog, each VNF type references (among other things) a Heat template + * which is used to deploy the required VNF artifacts (VMs, networks, etc.) + * to the cloud. + * + * Depending on the Heat template, 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 VNF or an error will be thrown. + * + * The method sends an asynchronous response to the notification URL when + * processing completes. The createAsyncResponse contains the vnfId (the + * canonical name of the stack), a Map of VNF 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 VNF. + * This is useful if a VNF is successfully created but the orchestrator + * fails on a subsequent operation. + * + * Note: this method is implemented by calling the synchronous web method + * and translating the response to an asynchronous notification. + * + * @param cloudSiteId CLLI code of the cloud site in which to create the VNF + * @param tenantId Openstack tenant identifier + * @param vnfType VNF type key, should match a VNF definition in catalog DB + * @param vnfName Name to be assigned to the new VNF + * @param inputs Map of key=value inputs for VNF stack creation + * @param failIfExists Flag whether already existing VNF should be considered + * a success or failure + * @param msoRequest Request tracking information for logs + * @param notificationURL the target URL for asynchronous response + */ + @Override + public void createVnfA (String cloudSiteId, + String tenantId, + String vnfType, + String vnfVersion, + String vnfName, + String requestType, + String volumeGroupHeatStackId, + Map inputs, + Boolean failIfExists, + Boolean backout, + Boolean enableBridge, + String messageId, + MsoRequest msoRequest, + String notificationUrl) { + String error; + String serviceName = "CreateVnfA"; + MsoLogger.setLogContext (msoRequest); + MsoLogger.setServiceName (serviceName); + LOGGER.info (MessageEnum.RA_ASYNC_CREATE_VNF, vnfName, vnfType, cloudSiteId, tenantId, "createVnfA"); + // Use the synchronous method to perform the actual Create + MsoVnfAdapter vnfAdapter = vnfImpl; + // Synchronous Web Service Outputs + Holder vnfId = new Holder <> (); + Holder > outputs = new Holder <> (); + Holder vnfRollback = new Holder <> (); + + try { + vnfAdapter.createVnf (cloudSiteId, + tenantId, + vnfType, + vnfVersion, + vnfName, + requestType, + volumeGroupHeatStackId, + inputs, + failIfExists, + backout, + enableBridge, + msoRequest, + vnfId, + outputs, + vnfRollback); + MsoLogger.setServiceName (serviceName); + } catch (VnfException e) { + MsoLogger.setServiceName (serviceName); + LOGGER.error (MessageEnum.RA_CREATE_VNF_ERR, vnfName, cloudSiteId, tenantId, "", "createVnfA", MsoLogger.ErrorCode.BusinessProcesssError, "VnfException in createVnfA", e); + org.onap.so.adapters.vnf.async.client.MsoExceptionCategory exCat = null; + String eMsg = null; + try { + eMsg = e.getFaultInfo ().getMessage (); + exCat = org.onap.so.adapters.vnf.async.client.MsoExceptionCategory.fromValue (e.getFaultInfo () + .getCategory () + .name ()); + } catch (Exception e1) { + LOGGER.error (MessageEnum.RA_FAULT_INFO_EXC, "", "createVnfA", MsoLogger.ErrorCode.BusinessProcesssError, "Exception - Fault info", e1); + } + // Build and send Asynchronous error response + try { + VnfAdapterNotify notifyPort = getNotifyEP (notificationUrl); + notifyPort.createVnfNotification (messageId, false, exCat, eMsg, null, null, null); + } catch (Exception e1) { + error = "Error sending createVnf notification " + e1.getMessage (); + LOGGER.error (MessageEnum.RA_SEND_VNF_NOTIF_ERR, "", "createVnfA", MsoLogger.ErrorCode.BusinessProcesssError, "Exception sending createVnf notification", e1); + alarmLogger.sendAlarm ("MsoInternalError", MsoAlarmLogger.CRITICAL, error); + } + LOGGER.info (MessageEnum.RA_ASYNC_CREATE_VNF_COMPLETE, "", "createVnfA", ""); + return; + } + LOGGER.debug ("Async Create VNF: " + vnfName + " VnfId:" + vnfId.value); + // Build and send Asynchronous response + try { + VnfAdapterNotify notifyPort = getNotifyEP (notificationUrl); + notifyPort.createVnfNotification (messageId, + true, + null, + null, + vnfId.value, + copyCreateOutputs (outputs), + copyVrb (vnfRollback)); + } catch (Exception e) { + error = "Error sending createVnf notification " + e.getMessage (); + LOGGER.error (MessageEnum.RA_SEND_VNF_NOTIF_ERR, "", "createVnfA", MsoLogger.ErrorCode.BusinessProcesssError, "Exception sending createVnf notification", e); + alarmLogger.sendAlarm ("MsoInternalError", MsoAlarmLogger.CRITICAL, error); + } + LOGGER.info (MessageEnum.RA_ASYNC_CREATE_VNF_COMPLETE, "", "","createVnfA"); + return; + } + + @Override + public void updateVnfA (String cloudSiteId, + String tenantId, + String vnfType, + String vnfVersion, + String vnfName, + String requestType, + String volumeGroupHeatStackId, + Map inputs, + String messageId, + MsoRequest msoRequest, + String notificationUrl) { + String error; + String serviceName = "UpdateVnfA"; + MsoLogger.setServiceName (serviceName); + MsoLogger.setLogContext (msoRequest); + LOGGER.info (MessageEnum.RA_ASYNC_UPDATE_VNF, vnfName, vnfType, cloudSiteId, tenantId, "UpdateVnfA"); + + // Use the synchronous method to perform the actual Create + MsoVnfAdapter vnfAdapter = vnfImpl; + + // Synchronous Web Service Outputs + Holder vnfId = new Holder <> (); + Holder > outputs = new Holder <> (); + Holder vnfRollback = new Holder <> (); + + try { + vnfAdapter.updateVnf (cloudSiteId, tenantId, vnfType,vnfVersion, vnfName, requestType, volumeGroupHeatStackId, inputs, msoRequest, outputs, vnfRollback); + MsoLogger.setServiceName (serviceName); + } catch (VnfException e) { + MsoLogger.setServiceName (serviceName); + LOGGER.error (MessageEnum.RA_UPDATE_VNF_ERR, vnfName, cloudSiteId, tenantId, "", "UpdateVnfA", MsoLogger.ErrorCode.BusinessProcesssError, "Exception sending updateVnf notification", e); + org.onap.so.adapters.vnf.async.client.MsoExceptionCategory exCat = null; + String eMsg = null; + try { + eMsg = e.getFaultInfo ().getMessage (); + exCat = org.onap.so.adapters.vnf.async.client.MsoExceptionCategory.fromValue (e.getFaultInfo () + .getCategory () + .name ()); + } catch (Exception e1) { + LOGGER.error (MessageEnum.RA_FAULT_INFO_EXC, "", "UpdateVnfA", MsoLogger.ErrorCode.BusinessProcesssError, "Exception - fault info", e1); + } + // Build and send Asynchronous error response + try { + VnfAdapterNotify notifyPort = getNotifyEP (notificationUrl); + notifyPort.updateVnfNotification (messageId, false, exCat, eMsg, null, null); + } catch (Exception e1) { + error = "Error sending updateVnf notification " + e1.getMessage (); + LOGGER.error (MessageEnum.RA_SEND_VNF_NOTIF_ERR, "", "UpdateVnfA", MsoLogger.ErrorCode.BusinessProcesssError, "Exception sending updateVnf notification", e1); + alarmLogger.sendAlarm ("MsoInternalError", MsoAlarmLogger.CRITICAL, error); + } + LOGGER.info (MessageEnum.RA_ASYNC_UPDATE_VNF_COMPLETE,"","","UpdateVnfA"); + return; + } + LOGGER.debug ("Async Update VNF: " + vnfName + " VnfId:" + vnfId.value); + // Build and send Asynchronous response + try { + VnfAdapterNotify notifyPort = getNotifyEP (notificationUrl); + notifyPort.updateVnfNotification (messageId, + true, + null, + null, + copyUpdateOutputs (outputs), + copyVrb (vnfRollback)); + } catch (Exception e) { + error = "Error sending updateVnf notification " + e.getMessage (); + LOGGER.error (MessageEnum.RA_SEND_VNF_NOTIF_ERR, "", "UpdateVnfA", MsoLogger.ErrorCode.BusinessProcesssError, "Exception sending updateVnf notification", e); + alarmLogger.sendAlarm ("MsoInternalError", MsoAlarmLogger.CRITICAL, error); + } + LOGGER.info (MessageEnum.RA_ASYNC_UPDATE_VNF_COMPLETE, "", "","UpdateVnfA"); + return; + } + + /** + * This is the "Query VNF" web service implementation. + * It will look up a VNF by name or ID in the specified cloud and tenant. + * + * The method returns an indicator that the VNF exists, its Openstack internal + * ID, its status, and the set of outputs (from when the stack was created). + * + * @param cloudSiteId CLLI code of the cloud site in which to query + * @param tenantId Openstack tenant identifier + * @param vnfName VNF Name or Openstack ID + * @param msoRequest Request tracking information for logs + * @param notificationURL the target URL for asynchronous response + */ + @Override + public void queryVnfA (String cloudSiteId, + String tenantId, + String vnfName, + String messageId, + MsoRequest msoRequest, + String notificationUrl) { + String error; + String serviceName = "QueryVnfA"; + MsoLogger.setServiceName (serviceName); + MsoLogger.setLogContext (msoRequest); + LOGGER.info (MessageEnum.RA_ASYNC_QUERY_VNF, vnfName, cloudSiteId, tenantId); + + // Use the synchronous method to perform the actual query + MsoVnfAdapter vnfAdapter = vnfImpl; + + // Synchronous Web Service Outputs + Holder vnfExists = new Holder <> (); + Holder vnfId = new Holder <> (); + Holder status = new Holder <> (); + Holder > outputs = new Holder <> (); + + try { + vnfAdapter.queryVnf (cloudSiteId, tenantId, vnfName, msoRequest, vnfExists, vnfId, status, outputs); + MsoLogger.setServiceName (serviceName); + } catch (VnfException e) { + MsoLogger.setServiceName (serviceName); + LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vnfName, cloudSiteId, tenantId, "", "queryVnfA", MsoLogger.ErrorCode.BusinessProcesssError, "Exception sending queryVnfA notification", e); + org.onap.so.adapters.vnf.async.client.MsoExceptionCategory exCat = null; + String eMsg = null; + try { + eMsg = e.getFaultInfo ().getMessage (); + exCat = org.onap.so.adapters.vnf.async.client.MsoExceptionCategory.fromValue (e.getFaultInfo () + .getCategory () + .name ()); + } catch (Exception e1) { + LOGGER.error (MessageEnum.RA_FAULT_INFO_EXC, "", "queryVnfA", MsoLogger.ErrorCode.BusinessProcesssError, "Exception - fault info", e1); + } + // Build and send Asynchronous error response + try { + VnfAdapterNotify notifyPort = getNotifyEP (notificationUrl); + notifyPort.queryVnfNotification (messageId, false, exCat, eMsg, null, null, null, null); + } catch (Exception e1) { + error = "Error sending queryVnf notification " + e1.getMessage (); + LOGGER.error (MessageEnum.RA_SEND_VNF_NOTIF_ERR, "", "queryVnfA", MsoLogger.ErrorCode.BusinessProcesssError, "Exception sending queryVnf notification", e1); + alarmLogger.sendAlarm ("MsoInternalError", MsoAlarmLogger.CRITICAL, error); + } + LOGGER.info (MessageEnum.RA_ASYNC_QUERY_VNF_COMPLETE, "","", "queryVnfA"); + return; + } + + if (!vnfExists.value) { + LOGGER.debug ("Async Query, VNF not found"); + } else { + LOGGER.debug ("Async Query, VNF=" + vnfId.value + ", status=" + status.value); + } + // Build and send Asynchronous response + try { + VnfAdapterNotify notifyPort = getNotifyEP (notificationUrl); + org.onap.so.adapters.vnf.async.client.VnfStatus vnfS = org.onap.so.adapters.vnf.async.client.VnfStatus.fromValue (status.value.name ()); + notifyPort.queryVnfNotification (messageId, + true, + null, + null, + vnfExists.value, + vnfId.value, + vnfS, + copyQueryOutputs (outputs)); + } catch (Exception e) { + error = "Error sending queryVnf notification " + e.getMessage (); + LOGGER.error (MessageEnum.RA_SEND_VNF_NOTIF_ERR, "", "queryVnfA", MsoLogger.ErrorCode.BusinessProcesssError, "Exception sending queryVnf notification", e); + alarmLogger.sendAlarm ("MsoInternalError", MsoAlarmLogger.CRITICAL, error); + } + + LOGGER.info (MessageEnum.RA_ASYNC_QUERY_VNF_COMPLETE, "","", "queryVnfA"); + return; + } + + /** + * This is the Asynchronous "Delete VNF" web service implementation. + * It will delete a VNF by name or ID in the specified cloud and tenant. + * + * The method has no outputs. + * + * @param cloudSiteId CLLI code of the cloud site in which to delete + * @param tenantId Openstack tenant identifier + * @param vnfName VNF Name or Openstack ID + * @param msoRequest Request tracking information for logs + * @param notificationURL the target URL for asynchronous response + */ + @Override + public void deleteVnfA (String cloudSiteId, + String tenantId, + String vnfName, + String messageId, + MsoRequest msoRequest, + String notificationUrl) { + String error; + String serviceName = "DeleteVnfA"; + MsoLogger.setServiceName (serviceName); + MsoLogger.setLogContext (msoRequest); + LOGGER.info (MessageEnum.RA_ASYNC_DELETE_VNF, vnfName, cloudSiteId, tenantId); + + // Use the synchronous method to perform the actual delete + MsoVnfAdapter vnfAdapter = vnfImpl; + + try { + vnfAdapter.deleteVnf (cloudSiteId, tenantId, vnfName, msoRequest); + MsoLogger.setServiceName (serviceName); + } catch (VnfException e) { + MsoLogger.setServiceName (serviceName); + LOGGER.error (MessageEnum.RA_DELETE_VNF_ERR, vnfName, cloudSiteId, tenantId, "", "deleteVnfA", MsoLogger.ErrorCode.BusinessProcesssError, "Exception sending deleteVnfA notification", e); + org.onap.so.adapters.vnf.async.client.MsoExceptionCategory exCat = null; + String eMsg = null; + try { + eMsg = e.getFaultInfo ().getMessage (); + exCat = org.onap.so.adapters.vnf.async.client.MsoExceptionCategory.fromValue (e.getFaultInfo () + .getCategory () + .name ()); + } catch (Exception e1) { + LOGGER.error (MessageEnum.RA_FAULT_INFO_EXC, "", "deleteVnfA", MsoLogger.ErrorCode.BusinessProcesssError, "Exception - fault info", e1); + } + // Build and send Asynchronous error response + try { + VnfAdapterNotify notifyPort = getNotifyEP (notificationUrl); + notifyPort.deleteVnfNotification (messageId, false, exCat, eMsg); + } catch (Exception e1) { + error = "Error sending deleteVnf notification " + e1.getMessage (); + LOGGER.error (MessageEnum.RA_SEND_VNF_NOTIF_ERR, "", "deleteVnfA", MsoLogger.ErrorCode.BusinessProcesssError, "Exception sending deleteVnfA notification", e1); + alarmLogger.sendAlarm ("MsoInternalError", MsoAlarmLogger.CRITICAL, error); + } + LOGGER.info (MessageEnum.RA_ASYNC_DELETE_VNF_COMPLETE, "","", "deleteVnfA"); + return; + } + + LOGGER.debug ("Async Delete VNF: " + vnfName); + // Build and send Asynchronous response + try { + VnfAdapterNotify notifyPort = getNotifyEP (notificationUrl); + notifyPort.deleteVnfNotification (messageId, true, null, null); + + } catch (Exception e) { + error = "Error sending deleteVnf notification " + e.getMessage (); + LOGGER.error (MessageEnum.RA_SEND_VNF_NOTIF_ERR, "", "deleteVnfA", MsoLogger.ErrorCode.BusinessProcesssError, "Exception sending deleteVnfA notification", e); + alarmLogger.sendAlarm ("MsoInternalError", MsoAlarmLogger.CRITICAL, error); + } + + LOGGER.info (MessageEnum.RA_ASYNC_DELETE_VNF_COMPLETE, "", "","deleteVnfA"); + return; + } + + /** + * 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. + */ + @Override + public void rollbackVnfA (VnfRollback rollback, String messageId, String notificationUrl) { + String serviceName = "RollbackVnfA"; + MsoLogger.setServiceName (serviceName); + String error; + // rollback may be null (e.g. if stack already existed when Create was called) + if (rollback == null) { + error = "Empty Rollback: No action to perform"; + LOGGER.info (MessageEnum.RA_ROLLBACK_NULL, "","", "rollbackVnfA"); + alarmLogger.sendAlarm ("MsoInternalError", MsoAlarmLogger.CRITICAL, error); + return; + } + + MsoLogger.setLogContext (rollback.getMsoRequest ()); + LOGGER.info (MessageEnum.RA_ASYNC_ROLLBACK_VNF, "", "","rollbackVnfA"); + + // Use the synchronous method to perform the actual rollback + MsoVnfAdapter vnfAdapter = vnfImpl; + + try { + vnfAdapter.rollbackVnf (rollback); + MsoLogger.setServiceName (serviceName); + } catch (VnfException e) { + MsoLogger.setServiceName (serviceName); + LOGGER.error (MessageEnum.RA_ROLLBACK_VNF_ERR, "", "rollbackVnfA", MsoLogger.ErrorCode.BusinessProcesssError, "Exception sending rollbackVnfA notification", e); + org.onap.so.adapters.vnf.async.client.MsoExceptionCategory exCat = null; + String eMsg = null; + try { + eMsg = e.getFaultInfo ().getMessage (); + exCat = org.onap.so.adapters.vnf.async.client.MsoExceptionCategory.fromValue (e.getFaultInfo () + .getCategory () + .name ()); + } catch (Exception e1) { + LOGGER.error (MessageEnum.RA_FAULT_INFO_EXC, "", "rollbackVnfA", MsoLogger.ErrorCode.BusinessProcesssError, "Exception - fault info", e1); + } + // Build and send Asynchronous error response + try { + VnfAdapterNotify notifyPort = getNotifyEP (notificationUrl); + notifyPort.rollbackVnfNotification (messageId, false, exCat, eMsg); + } catch (Exception e1) { + error = "Error sending rollbackVnf notification " + e1.getMessage (); + LOGGER.error (MessageEnum.RA_SEND_VNF_NOTIF_ERR, "", "rollbackVnfA", MsoLogger.ErrorCode.BusinessProcesssError, "Exception sending rollbackVnfA notification", e1); + alarmLogger.sendAlarm ("MsoInternalError", MsoAlarmLogger.CRITICAL, error); + } + LOGGER.info (MessageEnum.RA_ASYNC_ROLLBACK_VNF_COMPLETE, "","", "rollbackVnfA"); + return; + } + + LOGGER.debug ("Async Rollback VNF:" + rollback.getVnfId ()); + // Build and send Asynchronous response + try { + VnfAdapterNotify notifyPort = getNotifyEP (notificationUrl); + notifyPort.rollbackVnfNotification (messageId, true, null, null); + } catch (Exception e) { + error = "Error sending rollbackVnf notification " + e.getMessage (); + LOGGER.error (MessageEnum.RA_SEND_VNF_NOTIF_ERR, "", "rollbackVnfA", MsoLogger.ErrorCode.BusinessProcesssError, "Exception sending rollbackVnfA notification", e); + alarmLogger.sendAlarm ("MsoInternalError", MsoAlarmLogger.CRITICAL, error); + } + + LOGGER.info (MessageEnum.RA_ASYNC_ROLLBACK_VNF_COMPLETE, "", "","rollbackVnfA"); + return; + } + + private org.onap.so.adapters.vnf.async.client.VnfRollback copyVrb (Holder hVrb) { + org.onap.so.adapters.vnf.async.client.VnfRollback cvrb = new org.onap.so.adapters.vnf.async.client.VnfRollback (); + + if (hVrb != null && hVrb.value != null) { + org.onap.so.adapters.vnf.async.client.MsoRequest cmr = new org.onap.so.adapters.vnf.async.client.MsoRequest (); + + cvrb.setCloudSiteId (hVrb.value.getCloudSiteId ()); + if (hVrb.value.getMsoRequest() != null) { + cmr.setRequestId (hVrb.value.getMsoRequest ().getRequestId ()); + cmr.setServiceInstanceId (hVrb.value.getMsoRequest ().getServiceInstanceId ()); + } else { + cmr.setRequestId (null); + cmr.setServiceInstanceId (null); + } + cvrb.setMsoRequest (cmr); + cvrb.setVnfId (hVrb.value.getVnfId ()); + cvrb.setTenantId (hVrb.value.getTenantId ()); + cvrb.setTenantCreated (hVrb.value.getTenantCreated ()); + cvrb.setVnfCreated (hVrb.value.getVnfCreated ()); + } + return cvrb; + } + + private CreateVnfNotification.Outputs copyCreateOutputs (Holder > hMap) { + + CreateVnfNotification.Outputs outputs = new CreateVnfNotification.Outputs (); + + if (hMap != null && hMap.value != null) { + Map sMap = new HashMap <> (); + sMap = hMap.value; + CreateVnfNotification.Outputs.Entry entry = new CreateVnfNotification.Outputs.Entry (); + + for (String key : sMap.keySet ()) { + entry.setKey (key); + entry.setValue (sMap.get (key)); + outputs.getEntry ().add (entry); + } + } + return outputs; + } + + private UpdateVnfNotification.Outputs copyUpdateOutputs (Holder > hMap) { + + UpdateVnfNotification.Outputs outputs = new UpdateVnfNotification.Outputs (); + + if (hMap != null && hMap.value != null) { + Map sMap = new HashMap <> (); + sMap = hMap.value; + UpdateVnfNotification.Outputs.Entry entry = new UpdateVnfNotification.Outputs.Entry (); + + for (Map.Entry mapEntry : sMap.entrySet ()) { + String key = mapEntry.getKey(); + String value = mapEntry.getValue(); + entry.setKey (key); + entry.setValue (value); + outputs.getEntry ().add (entry); + } + } + return outputs; + } + + private QueryVnfNotification.Outputs copyQueryOutputs (Holder > hMap) { + + QueryVnfNotification.Outputs outputs = new QueryVnfNotification.Outputs (); + + if (hMap != null && hMap.value != null) { + Map sMap = new HashMap <> (); + sMap = hMap.value; + + QueryVnfNotification.Outputs.Entry entry = new QueryVnfNotification.Outputs.Entry (); + + for (Map.Entry mapEntry : sMap.entrySet ()) { + String key = mapEntry.getKey(); + String value = mapEntry.getValue(); + entry.setKey (key); + entry.setValue (value); + outputs.getEntry ().add (entry); + } + } + return outputs; + } + + private VnfAdapterNotify getNotifyEP (String notificationUrl) { + + URL warWsdlLoc = null; + try { + warWsdlLoc = Thread.currentThread ().getContextClassLoader ().getResource ("VnfAdapterNotify.wsdl"); + } catch (Exception e) { + LOGGER.error (MessageEnum.RA_WSDL_NOT_FOUND, "VnfAdapterNotify.wsdl", "", "getNotifyEP", MsoLogger.ErrorCode.BusinessProcesssError, "Exception - WSDL not found", e); + } + if (warWsdlLoc == null) { + LOGGER.error (MessageEnum.RA_WSDL_NOT_FOUND, "VnfAdapterNotify.wsdl", "", "getNotifyEP", MsoLogger.ErrorCode.BusinessProcesssError, "WSDL not found"); + } else { + try { + LOGGER.debug ("VnfAdpaterNotify.wsdl location:" + warWsdlLoc.toURI ().toString ()); + } catch (Exception e) { + LOGGER.error (MessageEnum.RA_WSDL_URL_CONVENTION_EXC, "VnfAdapterNotify.wsdl", "", "getNotifyEP", MsoLogger.ErrorCode.BusinessProcesssError, "Exception - WSDL URL convention", e); + } + } + + VnfAdapterNotify_Service notifySvc = new VnfAdapterNotify_Service (warWsdlLoc, + new QName ("http://org.onap.so/vnfNotify", + "vnfAdapterNotify")); + + VnfAdapterNotify notifyPort = notifySvc.getMsoVnfAdapterAsyncImplPort (); + + BindingProvider bp = (BindingProvider) notifyPort; + + URL epUrl = null; + try { + epUrl = new URL (notificationUrl); + } catch (MalformedURLException e1) { + LOGGER.error (MessageEnum.RA_INIT_NOTIF_EXC, "", "getNotifyEP", MsoLogger.ErrorCode.BusinessProcesssError, "MalformedURLException", e1); + } + + if(null != epUrl) { + LOGGER.debug ("Notification Endpoint URL: " + epUrl.toExternalForm ()); + bp.getRequestContext ().put (BindingProvider.ENDPOINT_ADDRESS_PROPERTY, epUrl.toExternalForm ()); + } + else { + LOGGER.debug ("epUrl is NULL:"); + } + + // authentication + try { + Map reqCtx = bp.getRequestContext (); + Map > headers = new HashMap <> (); + + String userCredentials = this.getEncryptedProperty(BPEL_AUTH_PROP, "", ENCRYPTION_KEY); + + String basicAuth = "Basic " + DatatypeConverter.printBase64Binary (userCredentials.getBytes ()); + reqCtx.put (MessageContext.HTTP_REQUEST_HEADERS, headers); + headers.put ("Authorization", Collections.singletonList (basicAuth)); + } catch (Exception e) { + LOGGER.error (MessageEnum.RA_SET_CALLBACK_AUTH_EXC, "", "getNotifyEP", MsoLogger.ErrorCode.BusinessProcesssError, "Exception - Unable to set authorization in callback request", e); + alarmLogger.sendAlarm ("MsoInternalError", MsoAlarmLogger.CRITICAL, "Unable to set authorization in callback request"); + } + + return notifyPort; + } + + public String getEncryptedProperty(String key, String defaultValue, String encryptionKey) { + try { + return CryptoUtils.decrypt(this.environment.getProperty(key), encryptionKey); + } catch (GeneralSecurityException e) { + LOGGER.debug("Exception while decrypting property: " + this.environment.getProperty(key), e); + } + return defaultValue; + + } + +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/MsoVnfAdapterImpl.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/MsoVnfAdapterImpl.java new file mode 100644 index 0000000000..994a83c422 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/MsoVnfAdapterImpl.java @@ -0,0 +1,2347 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * Copyright (C) 2017 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.so.adapters.vnf; + + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.TimeUnit; + +import javax.jws.WebService; +import javax.xml.ws.Holder; + +import org.onap.so.adapters.vnf.exceptions.VnfAlreadyExists; +import org.onap.so.adapters.vnf.exceptions.VnfException; +import org.onap.so.adapters.vnf.exceptions.VnfNotFound; +import org.onap.so.cloud.CloudConfig; +import org.onap.so.cloud.CloudSite; +import org.onap.so.db.catalog.beans.HeatEnvironment; +import org.onap.so.db.catalog.beans.HeatFiles; +import org.onap.so.db.catalog.beans.HeatTemplate; +import org.onap.so.db.catalog.beans.HeatTemplateParam; +import org.onap.so.db.catalog.beans.VfModule; +import org.onap.so.db.catalog.beans.VfModuleCustomization; +import org.onap.so.db.catalog.beans.VnfResource; +import org.onap.so.db.catalog.data.repository.VFModuleCustomizationRepository; +import org.onap.so.db.catalog.data.repository.VnfResourceRepository; +import org.onap.so.db.catalog.utils.MavenLikeVersioning; +import org.onap.so.entity.MsoRequest; +import org.onap.so.logger.MessageEnum; +import org.onap.so.logger.MsoAlarmLogger; +import org.onap.so.logger.MsoLogger; +import org.onap.so.openstack.beans.HeatStatus; +import org.onap.so.openstack.beans.StackInfo; +import org.onap.so.openstack.beans.VnfRollback; +import org.onap.so.openstack.beans.VnfStatus; +import org.onap.so.openstack.exceptions.MsoException; +import org.onap.so.openstack.exceptions.MsoExceptionCategory; +import org.onap.so.openstack.exceptions.MsoHeatNotFoundException; +import org.onap.so.openstack.utils.MsoHeatEnvironmentEntry; +import org.onap.so.openstack.utils.MsoHeatUtils; +import org.onap.so.openstack.utils.MsoHeatUtilsWithUpdate; +import org.onap.so.adapters.valet.ValetClient; +import org.onap.so.adapters.valet.beans.HeatRequest; +import org.onap.so.adapters.valet.beans.ValetConfirmResponse; +import org.onap.so.adapters.valet.beans.ValetCreateResponse; +import org.onap.so.adapters.valet.beans.ValetDeleteResponse; +import org.onap.so.adapters.valet.beans.ValetRollbackResponse; +import org.onap.so.adapters.valet.beans.ValetStatus; +import org.onap.so.adapters.valet.beans.ValetUpdateResponse; +import org.onap.so.adapters.valet.GenericValetResponse; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.env.Environment; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +import com.fasterxml.jackson.core.JsonParseException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; + +@WebService(serviceName = "VnfAdapter", endpointInterface = "org.onap.so.adapters.vnf.MsoVnfAdapter", targetNamespace = "http://org.onap.so/vnf") +@Component +@Transactional +public class MsoVnfAdapterImpl implements MsoVnfAdapter { + + @Autowired + private CloudConfig cloudConfig; + + @Autowired + private Environment environment; + + private static final String MSO_CONFIGURATION_ERROR = "MsoConfigurationError"; + private static final String VNF_ADAPTER_SERVICE_NAME = "MSO-BPMN:MSO-VnfAdapter."; + private static final MsoLogger LOGGER = MsoLogger.getMsoLogger (MsoLogger.Catalog.RA,MsoVnfAdapterImpl.class); + private static final MsoAlarmLogger alarmLogger = new MsoAlarmLogger (); + private static final String CHECK_REQD_PARAMS = "org.onap.so.adapters.vnf.checkRequiredParameters"; + private static final String ADD_GET_FILES_ON_VOLUME_REQ = "org.onap.so.adapters.vnf.addGetFilesOnVolumeReq"; + private static final ObjectMapper JSON_MAPPER = new ObjectMapper(); + private static final String VALET_ENABLED = "org.onap.so.adapters.vnf.valet_enabled"; + private static final String FAIL_REQUESTS_ON_VALET_FAILURE = "org.onap.so.adapters.vnf.fail_requests_on_valet_failure"; + + @Autowired + private VFModuleCustomizationRepository vfModuleCustomRepo; + + + @Autowired + private VnfResourceRepository vnfResourceRepo; + + @Autowired + private MsoHeatUtilsWithUpdate heatU; + @Autowired + private MsoHeatUtils heat; + @Autowired + private ValetClient vci; + /** + * 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 Adapter"); + } + + /** + * DO NOT use that constructor to instantiate this class, the msoPropertiesfactory will be NULL. + * @see MsoVnfAdapterImpl#MsoVnfAdapterImpl(MsoPropertiesFactory, CloudConfigFactory) + */ + public MsoVnfAdapterImpl() {} + + /** + * This is the "Create VNF" web service implementation. + * It will create a new VNF of the requested type in the specified cloud + * and tenant. The tenant must exist before this service is called. + * + * If a VNF with the same name already exists, this can be considered a + * success or failure, depending on the value of the 'failIfExists' parameter. + * + * All VNF types will be defined in the MSO catalog. The caller must request + * one of these pre-defined types or an error will be returned. Within the + * catalog, each VNF type references (among other things) a Heat template + * which is used to deploy the required VNF artifacts (VMs, networks, etc.) + * to the cloud. + * + * Depending on the Heat template, 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 VNF or an error will be thrown. + * + * The method returns the vnfId (the canonical name), a Map of VNF 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 VNF. This is useful if a VNF is successfully created but the + * orchestrator fails on a subsequent operation. + * + * @param cloudSiteId CLLI code of the cloud site in which to create the VNF + * @param tenantId Openstack tenant identifier + * @param vnfType VNF type key, should match a VNF definition in catalog DB + * @param vnfVersion VNF version key, should match a VNF definition in catalog DB + * @param vnfName Name to be assigned to the new VNF + * @param inputs Map of key=value inputs for VNF stack creation + * @param failIfExists Flag whether already existing VNF should be considered + * a success or failure + * @param msoRequest Request tracking information for logs + * @param vnfId Holder for output VNF Openstack ID + * @param outputs Holder for Map of VNF outputs from heat (assigned IPs, etc) + * @param rollback Holder for returning VnfRollback object + */ + @Override + public void createVnf (String cloudSiteId, + String tenantId, + String vnfType, + String vnfVersion, + String vnfName, + String requestType, + String volumeGroupHeatStackId, + Map inputs, + Boolean failIfExists, + Boolean backout, + Boolean enableBridge, + MsoRequest msoRequest, + Holder vnfId, + Holder > outputs, + Holder rollback) throws VnfException { + // Create a hook here to catch shortcut createVf requests: + if (requestType != null && requestType.startsWith("VFMOD")) { + LOGGER.debug("Calling createVfModule from createVnf -- requestType=" + requestType); + String newRequestType = requestType.substring(5); + String vfVolGroupHeatStackId = ""; + String vfBaseHeatStackId = ""; + try { + if (volumeGroupHeatStackId != null) { + vfVolGroupHeatStackId = volumeGroupHeatStackId.substring(0, volumeGroupHeatStackId.lastIndexOf('|')); + vfBaseHeatStackId = volumeGroupHeatStackId.substring(volumeGroupHeatStackId.lastIndexOf('|')+1); + } + } catch (Exception e) { + // might be ok - both are just blank + LOGGER.debug("ERROR trying to parse the volumeGroupHeatStackId " + volumeGroupHeatStackId,e); + } + this.createVfModule(cloudSiteId, + tenantId, + vnfType, + vnfVersion, + vnfName, + newRequestType, + vfVolGroupHeatStackId, + vfBaseHeatStackId, + null, + inputs, + failIfExists, + backout, + enableBridge, + msoRequest, + vnfId, + outputs, + rollback); + return; + } + // createVf will know if the requestType starts with "X" that it's the "old" way + StringBuilder newRequestTypeSb = new StringBuilder("X"); + String vfVolGroupHeatStackId = ""; + String vfBaseHeatStackId = ""; + if (requestType != null) { + newRequestTypeSb.append(requestType); + } + this.createVfModule(cloudSiteId, + tenantId, + vnfType, + vnfVersion, + vnfName, + newRequestTypeSb.toString(), + vfVolGroupHeatStackId, + vfBaseHeatStackId, + null, + inputs, + failIfExists, + backout, + enableBridge, + msoRequest, + vnfId, + outputs, + rollback); + return; + // End createVf shortcut + } + + @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 { + // As of 1707 - this method should no longer be called + MsoLogger.setLogContext (msoRequest.getRequestId (), msoRequest.getServiceInstanceId ()); + MsoLogger.setServiceName ("UpdateVnf"); + LOGGER.debug("UpdateVnf called?? This should not be called any longer - update vfModule"); + } + + /** + * This is the "Query VNF" web service implementation. + * It will look up a VNF by name or ID in the specified cloud and tenant. + * + * The method returns an indicator that the VNF exists, its Openstack internal + * ID, its status, and the set of outputs (from when the stack was created). + * + * @param cloudSiteId CLLI code of the cloud site in which to query + * @param tenantId Openstack tenant identifier + * @param vnfName VNF Name or Openstack ID + * @param msoRequest Request tracking information for logs + * @param vnfExists Flag reporting the result of the query + * @param vnfId Holder for output VNF Openstack ID + * @param outputs Holder for Map of VNF outputs from heat (assigned IPs, etc) + */ + @Override + public void queryVnf (String cloudSiteId, + String tenantId, + String vnfName, + MsoRequest msoRequest, + Holder vnfExists, + Holder vnfId, + Holder status, + Holder > outputs) throws VnfException { + MsoLogger.setLogContext (msoRequest); + MsoLogger.setServiceName ("QueryVnf"); + LOGGER.debug ("Querying VNF " + vnfName + " in " + cloudSiteId + "/" + tenantId); + + // Will capture execution time for metrics + long startTime = System.currentTimeMillis (); + + StackInfo heatStack = null; + long subStartTime = System.currentTimeMillis (); + try { + heatStack = heat.queryStack (cloudSiteId, tenantId, vnfName); + LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "QueryStack", vnfName); + } catch (MsoException me) { + me.addContext ("QueryVNF"); + // Failed to query the Stack due to an openstack exception. + // Convert to a generic VnfException + String error = "Query VNF: " + vnfName + " in " + cloudSiteId + "/" + tenantId + ": " + me; + LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", vnfName); + LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vnfName, cloudSiteId, tenantId, "OpenStack", "QueryVNF", MsoLogger.ErrorCode.DataError, "Exception - queryStack", me); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error); + throw new VnfException (me); + } + + // Populate the outputs based on the returned Stack information + // + if (heatStack == null || heatStack.getStatus () == HeatStatus.NOTFOUND) { + // Not Found + vnfExists.value = Boolean.FALSE; + status.value = VnfStatus.NOTFOUND; + vnfId.value = null; + outputs.value = new HashMap<>(); // Return as an empty map + + LOGGER.debug ("VNF " + vnfName + " not found"); + } else { + vnfExists.value = Boolean.TRUE; + status.value = stackStatusToVnfStatus (heatStack.getStatus ()); + vnfId.value = heatStack.getCanonicalName (); + outputs.value = copyStringOutputs (heatStack.getOutputs ()); + + LOGGER.debug ("VNF " + vnfName + " found, ID = " + vnfId.value); + } + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully query VNF"); + return; + } + + /** + * This is the "Delete VNF" web service implementation. + * It will delete a VNF by name or ID in the specified cloud and tenant. + * + * The method has no outputs. + * + * @param cloudSiteId CLLI code of the cloud site in which to delete + * @param tenantId Openstack tenant identifier + * @param vnfName VNF Name or Openstack ID + * @param msoRequest Request tracking information for logs + */ + @Override + public void deleteVnf (String cloudSiteId, + String tenantId, + String vnfName, + MsoRequest msoRequest) throws VnfException { + MsoLogger.setLogContext (msoRequest); + MsoLogger.setServiceName ("DeleteVnf"); + LOGGER.debug ("Deleting VNF " + vnfName + " in " + cloudSiteId + "/" + tenantId); + // Will capture execution time for metrics + long startTime = System.currentTimeMillis (); + + // Use the MsoHeatUtils to delete the stack. Set the polling flag to true. + // The possible outcomes of deleteStack are a StackInfo object with status + // of NOTFOUND (on success) or FAILED (on error). Also, MsoOpenstackException + // could be thrown. + long subStartTime = System.currentTimeMillis (); + try { + heat.deleteStack (tenantId, cloudSiteId, vnfName, true); + LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "DeleteStack", vnfName); + } catch (MsoException me) { + me.addContext ("DeleteVNF"); + // Failed to query the Stack due to an openstack exception. + // Convert to a generic VnfException + String error = "Delete VNF: " + vnfName + " in " + cloudSiteId + "/" + tenantId + ": " + me; + LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "DeleteStack", vnfName); + LOGGER.error (MessageEnum.RA_DELETE_VNF_ERR, vnfName, cloudSiteId, tenantId, "OpenStack", "DeleteVNF", MsoLogger.ErrorCode.DataError, "Exception - DeleteVNF", me); + 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 VNF"); + return; + } + + /** + * 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. + */ + @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.toString(), "OpenStack", "rollbackVnf"); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.BadRequest, "Rollback request content is null"); + return; + } + + // Get the elements of the VnfRollback object for easier access + String cloudSiteId = rollback.getCloudSiteId (); + String tenantId = rollback.getTenantId (); + String vnfId = rollback.getVnfId (); + + MsoLogger.setLogContext (rollback.getMsoRequest()); + + LOGGER.debug ("Rolling Back VNF " + vnfId + " in " + cloudSiteId + "/" + tenantId); + + // Use the MsoHeatUtils to delete the stack. Set the polling flag to true. + // The possible outcomes of deleteStack are a StackInfo object with status + // of NOTFOUND (on success) or FAILED (on error). Also, MsoOpenstackException + // could be thrown. + long subStartTime = System.currentTimeMillis (); + try { + heat.deleteStack (tenantId, cloudSiteId, vnfId, true); + LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "DeleteStack", null); + } catch (MsoException me) { + // Failed to rollback the Stack due to an openstack exception. + // Convert to a generic VnfException + me.addContext ("RollbackVNF"); + String error = "Rollback VNF: " + vnfId + " in " + cloudSiteId + "/" + tenantId + ": " + me; + LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "DeleteStack", null); + LOGGER.error (MessageEnum.RA_DELETE_VNF_ERR, vnfId, cloudSiteId, tenantId, "OpenStack", "DeleteStack", MsoLogger.ErrorCode.DataError, "Exception - DeleteStack", me); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error); + throw new VnfException (me); + } + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully roll back VNF"); + return; + } + + private VnfStatus stackStatusToVnfStatus (HeatStatus stackStatus) { + switch (stackStatus) { + case CREATED: + return VnfStatus.ACTIVE; + case UPDATED: + return VnfStatus.ACTIVE; + case FAILED: + return VnfStatus.FAILED; + default: + return VnfStatus.UNKNOWN; + } + } + + private Map copyStringOutputs(Map stackOutputs) { + Map stringOutputs = new HashMap <> (); + for (Map.Entry entry : stackOutputs.entrySet ()) { + String key = entry.getKey(); + Object value = entry.getValue(); + try { + stringOutputs.put(key, value.toString()); + } catch (Exception e) { + StringBuilder msg = new StringBuilder("Unable to add " + key + " to outputs"); + if (value instanceof Integer) { // nothing to add to the message + } else if (value instanceof JsonNode) { + msg.append(" - exception converting JsonNode"); + } else if (value instanceof java.util.LinkedHashMap) { + msg.append(" exception converting LinkedHashMap"); + } else { + msg.append(" - unable to call .toString() " + e.getMessage()); + } + LOGGER.debug(msg.toString(), e); + } + } + return stringOutputs; + } + + private Map copyStringInputs (Map stringInputs) { + return new HashMap <> (stringInputs); + } + + protected boolean callHeatbridge(String heatStackId) { + String executionDir = "/usr/local/lib/python2.7/dist-packages/heatbridge"; + String openstackIdentityUrl = "", username = "", password = "", tenant = "", region = "", owner = ""; + long waitTimeMs = 10000L; + try { + String[] cmdarray = {"/usr/bin/python", "HeatBridgeMain.py", openstackIdentityUrl, username, password, tenant, region, owner, heatStackId}; + String[] envp = null; + File dir = new File(executionDir); + LOGGER.debug("Calling HeatBridgeMain.py in " + dir + " with arguments " + Arrays.toString(cmdarray)); + Runtime r = Runtime.getRuntime(); + Process p = r.exec(cmdarray, envp, dir); + boolean wait = p.waitFor(waitTimeMs, TimeUnit.MILLISECONDS); + + LOGGER.debug(" HeatBridgeMain.py returned " + wait + " with code " + p.exitValue()); + return wait && p.exitValue()==0; + } catch (IOException e) { + LOGGER.debug(" HeatBridgeMain.py failed with IO Exception! " + e); + return false; + } catch (InterruptedException e) { + LOGGER.debug(" HeatBridgeMain.py failed when interrupted! " + e); + return false; + } catch (RuntimeException e) { + LOGGER.debug(" HeatBridgeMain.py failed for unknown reasons!" + e); + return false; + } + } + + 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 (Map.Entry entry : inputs.entrySet()) { + String outputString; + String str = entry.getKey(); + Object value = entry.getValue(); + try { + outputString = value.toString(); + } catch (Exception e) { + LOGGER.debug("Exception :",e); + outputString = "Unable to call toString() on the value for " + str; + } + sb.append("\t\nitem ").append(i++).append(": '").append(str).append("'='").append(outputString) + .append("'"); + } + } + 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 (Map.Entry entry: inputs.entrySet()) { + sb.append("\titem ").append(i++).append(": ").append(entry.getKey()).append("=").append(entry.getValue()); + } + } + LOGGER.debug(sb.toString()); + return; + } + + private String convertNode(final JsonNode node) { + try { + final Object obj = JSON_MAPPER.treeToValue(node, Object.class); + return JSON_MAPPER.writeValueAsString(obj); + } catch (JsonParseException jpe) { + LOGGER.debug("Error converting json to string " + jpe.getMessage(),jpe); + } catch (Exception e) { + LOGGER.debug("Error converting json to string " + e.getMessage(),e); + } + 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,e); + //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,e); + } + } 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,e); + } + } 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() + ")",e); + } + } + } + } + + return stringMap; + } + + @Override + public void createVfModule(String cloudSiteId, + String tenantId, + String vnfType, + String vnfVersion, + String vnfName, + String requestType, + String volumeGroupHeatStackId, + String baseVfHeatStackId, + String modelCustomizationUuid, + Map inputs, + Boolean failIfExists, + Boolean backout, + Boolean enableBridge, + MsoRequest msoRequest, + Holder vnfId, + Holder > outputs, + Holder rollback) throws VnfException { + String vfModuleName = vnfName; + String vfModuleType = vnfType; + String vfVersion = vnfVersion; + String mcu = modelCustomizationUuid; + boolean useMCUuid = false; + if (mcu != null && !mcu.isEmpty()) { + if ("null".equalsIgnoreCase(mcu)) { + LOGGER.debug("modelCustomizationUuid: passed in as the string 'null' - will ignore: " + modelCustomizationUuid); + useMCUuid = false; + mcu = ""; + } else { + LOGGER.debug("Found modelCustomizationUuid! Will use that: " + mcu); + useMCUuid = true; + } + } + MsoLogger.setLogContext (msoRequest); + MsoLogger.setServiceName ("CreateVfModule"); + String requestTypeString = ""; + if (requestType != null && !"".equals(requestType)) { + requestTypeString = requestType; + } + String nestedStackId = null; + if (volumeGroupHeatStackId != null && !"".equals(volumeGroupHeatStackId) && !"null".equalsIgnoreCase(volumeGroupHeatStackId)) { + nestedStackId = volumeGroupHeatStackId; + } + String nestedBaseStackId = null; + if (baseVfHeatStackId != null && !"".equals(baseVfHeatStackId) && !"null".equalsIgnoreCase(baseVfHeatStackId)) { + nestedBaseStackId = baseVfHeatStackId; + } + + if (inputs == null) { + // Create an empty set of inputs + inputs = new HashMap<>(); + LOGGER.debug("inputs == null - setting to empty"); + } else { + this.sendMapToDebug(inputs); + } + //This method will also handle doing things the "old" way - i.e., just orchestrate a VNF + boolean oldWay = false; + if (requestTypeString.startsWith("X")) { + oldWay = true; + LOGGER.debug("orchestrating a VNF - *NOT* a module!"); + requestTypeString = requestTypeString.substring(1); + } + + // 1607 - let's parse out the request type we're being sent + boolean isBaseRequest = false; + boolean isVolumeRequest = false; + if (requestTypeString.startsWith("VOLUME")) { + isVolumeRequest = true; + } + + LOGGER.debug("requestTypeString = " + requestTypeString + ", nestedStackId = " + nestedStackId + ", nestedBaseStackId = " + nestedBaseStackId); + // Will capture execution time for metrics + long startTime = System.currentTimeMillis (); + + // Build a default rollback object (no actions performed) + VnfRollback vfRollback = new VnfRollback(); + vfRollback.setCloudSiteId(cloudSiteId); + vfRollback.setTenantId(tenantId); + vfRollback.setMsoRequest(msoRequest); + vfRollback.setRequestType(requestTypeString); + vfRollback.setVolumeGroupHeatStackId(volumeGroupHeatStackId); + vfRollback.setBaseGroupHeatStackId(baseVfHeatStackId); + vfRollback.setIsBase(isBaseRequest); + vfRollback.setModelCustomizationUuid(mcu); + + // Put data into A&AI through Heatstack + if(enableBridge != null && enableBridge) { + callHeatbridge(baseVfHeatStackId); + } + + StackInfo heatStack = null; + long subStartTime1 = System.currentTimeMillis (); + try { + heatStack = heat.queryStack (cloudSiteId, tenantId, vfModuleName); + LOGGER.recordMetricEvent (subStartTime1, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "QueryStack", vfModuleName); + } catch (MsoException me) { + String error = "Create VF Module: Query " + vfModuleName + " in " + cloudSiteId + "/" + tenantId + ": " + me ; + LOGGER.recordMetricEvent (subStartTime1, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", vfModuleName); + LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vfModuleName, cloudSiteId, tenantId, "OpenStack", "queryStack", MsoLogger.ErrorCode.DataError, "Exception - queryStack", me); + // Failed to query the Stack due to an openstack exception. + // Convert to a generic VnfException + me.addContext ("CreateVFModule"); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error); + throw new VnfException (me); + } + // New with 1607 - more precise handling/messaging if the stack already exists + if (heatStack != null && heatStack.getStatus() != HeatStatus.NOTFOUND) { + // INIT, CREATED, NOTFOUND, FAILED, BUILDING, DELETING, UNKNOWN, UPDATING, UPDATED + HeatStatus status = heatStack.getStatus(); + if (status == HeatStatus.INIT || status == HeatStatus.BUILDING || status == HeatStatus.DELETING || status == HeatStatus.UPDATING) { + // fail - it's in progress - return meaningful error + String error = "Create VF: Stack " + 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, "OpenStack", "queryStack", MsoLogger.ErrorCode.DataError, "Stack " + vfModuleName + " already exists"); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error); + throw new VnfAlreadyExists (vfModuleName, cloudSiteId, tenantId, heatStack.getCanonicalName ()); + } + if (status == HeatStatus.FAILED) { + // fail - it exists and is in a FAILED state + String error = "Create VF: Stack " + vfModuleName + " already exists and is in FAILED state in " + cloudSiteId + "/" + tenantId + "; requires manual intervention."; + LOGGER.error (MessageEnum.RA_VNF_ALREADY_EXIST, vfModuleName, cloudSiteId, tenantId, "OpenStack", "queryStack", MsoLogger.ErrorCode.DataError, "Stack " + vfModuleName + " already exists and is in FAILED state"); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error); + throw new VnfAlreadyExists (vfModuleName, cloudSiteId, tenantId, heatStack.getCanonicalName ()); + } + if (status == HeatStatus.UNKNOWN || status == HeatStatus.UPDATED) { + // fail - it exists and is in a FAILED state + String error = "Create VF: Stack " + vfModuleName + " already exists and has status " + status.toString() + " in " + cloudSiteId + "/" + tenantId + "; requires manual intervention."; + LOGGER.error (MessageEnum.RA_VNF_ALREADY_EXIST, vfModuleName, cloudSiteId, tenantId, "OpenStack", "queryStack", MsoLogger.ErrorCode.DataError, "Stack " + vfModuleName + " already exists and is in UPDATED or UNKNOWN state"); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error); + throw new VnfAlreadyExists (vfModuleName, cloudSiteId, tenantId, heatStack.getCanonicalName ()); + } + if (status == HeatStatus.CREATED) { + // fail - it exists + if (failIfExists != null && failIfExists) { + String error = "Create VF: Stack " + vfModuleName + " already exists in " + cloudSiteId + "/" + tenantId; + LOGGER.error (MessageEnum.RA_VNF_ALREADY_EXIST, vfModuleName, cloudSiteId, tenantId, "OpenStack", "queryStack", MsoLogger.ErrorCode.DataError, "Stack " + vfModuleName + " already exists"); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error); + throw new VnfAlreadyExists (vfModuleName, cloudSiteId, tenantId, heatStack.getCanonicalName ()); + } else { + LOGGER.debug ("Found Existing stack, status=" + heatStack.getStatus ()); + // Populate the outputs from the existing stack. + vnfId.value = heatStack.getCanonicalName (); + outputs.value = copyStringOutputs (heatStack.getOutputs ()); + rollback.value = vfRollback; // Default rollback - no updates performed + } + } + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully create VF Module"); + return; + + } + + // handle a nestedStackId if sent- this one would be for the volume - so applies to both Vf and Vnf + StackInfo nestedHeatStack = null; + long subStartTime2 = System.currentTimeMillis (); + Map nestedVolumeOutputs = null; + if (nestedStackId != null) { + try { + LOGGER.debug("Querying for nestedStackId = " + nestedStackId); + nestedHeatStack = heat.queryStack(cloudSiteId, tenantId, nestedStackId); + LOGGER.recordMetricEvent (subStartTime2, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "QueryStack", vfModuleName); + } catch (MsoException me) { + // Failed to query the Stack due to an openstack exception. + // Convert to a generic VnfException + me.addContext ("CreateVFModule"); + String error = "Create VFModule: Attached heatStack ID Query " + nestedStackId + " in " + cloudSiteId + "/" + tenantId + ": " + me ; + LOGGER.recordMetricEvent (subStartTime2, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", vfModuleName); + LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vfModuleName, cloudSiteId, tenantId, "OpenStack", "queryStack", MsoLogger.ErrorCode.BusinessProcesssError, "MsoException trying to query nested stack", me); + LOGGER.debug("ERROR trying to query nested stack= " + error); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error); + throw new VnfException (me); + } + if (nestedHeatStack == null || nestedHeatStack.getStatus() == HeatStatus.NOTFOUND) { + String error = "Create VFModule: Attached heatStack ID DOES NOT EXIST " + nestedStackId + " in " + cloudSiteId + "/" + tenantId + " USER ERROR" ; + LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vfModuleName, cloudSiteId, tenantId, error, "OpenStack", "queryStack", MsoLogger.ErrorCode.BusinessProcesssError, "Create VFModule: Attached heatStack ID 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 heat stack - copying values to inputs *later*"); + //this.sendMapToDebug(inputs); + nestedVolumeOutputs = nestedHeatStack.getOutputs(); + this.sendMapToDebug(nestedVolumeOutputs, "volumeStackOutputs"); + //TODO + //heat.copyStringOutputsToInputs(inputs, nestedHeatStack.getOutputs(), false); + //this.sendMapToDebug(inputs); + } + } + + // handle a nestedBaseStackId if sent- this is the stack ID of the base. Should be null for VNF requests + StackInfo nestedBaseHeatStack = null; + long subStartTime3 = System.currentTimeMillis (); + Map baseStackOutputs = null; + if (nestedBaseStackId != null) { + try { + LOGGER.debug("Querying for nestedBaseStackId = " + nestedBaseStackId); + nestedBaseHeatStack = heat.queryStack(cloudSiteId, tenantId, nestedBaseStackId); + LOGGER.recordMetricEvent (subStartTime3, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "QueryStack", vfModuleName); + } catch (MsoException me) { + // Failed to query the Stack due to an openstack exception. + // Convert to a generic VnfException + me.addContext ("CreateVFModule"); + String error = "Create VFModule: Attached baseHeatStack ID Query " + nestedBaseStackId + " in " + cloudSiteId + "/" + tenantId + ": " + me ; + LOGGER.recordMetricEvent (subStartTime3, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", vfModuleName); + LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vfModuleName, cloudSiteId, tenantId, "OpenStack", "QueryStack", MsoLogger.ErrorCode.BusinessProcesssError, "MsoException trying to query nested base stack", me); + LOGGER.debug("ERROR trying to query nested base stack= " + error); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error); + throw new VnfException (me); + } + if (nestedBaseHeatStack == null || nestedBaseHeatStack.getStatus() == HeatStatus.NOTFOUND) { + String error = "Create VFModule: Attached base heatStack ID DOES NOT EXIST " + nestedBaseStackId + " in " + cloudSiteId + "/" + tenantId + " USER ERROR" ; + LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vfModuleName, cloudSiteId, tenantId, error, "OpenStack", "QueryStack", MsoLogger.ErrorCode.BusinessProcesssError, "Create VFModule: Attached base heatStack ID 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 base heat stack - these values will be copied to inputs *later*"); + //this.sendMapToDebug(inputs); + baseStackOutputs = nestedBaseHeatStack.getOutputs(); + this.sendMapToDebug(baseStackOutputs, "baseStackOutputs"); + //TODO + //heat.copyStringOutputsToInputs(inputs, nestedBaseHeatStack.getOutputs(), false); + //this.sendMapToDebug(inputs); + } + } + + // Ready to deploy the new VNF + + + + try { + // Retrieve the VF + VfModule vf = null; + VnfResource vnfResource = null; + VfModuleCustomization vfmc = null; + LOGGER.debug("version: " + vfVersion); + if (useMCUuid) { + // 1707 - db refactoring + vfmc = vfModuleCustomRepo.findByModelCustomizationUUID(mcu); + if(vfmc != null) + vf=vfmc.getVfModule(); + else + vf=null; + + // 1702 - this will be the new way going forward. We find the vf by mcu - otherwise, code is the same. + if (vf == null) { + LOGGER.debug("Unable to find vfModuleCust with modelCustomizationUuid=" + mcu); + String error = "Create vfModule error: Unable to find vfModuleCust with modelCustomizationUuid=" + mcu; + LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM, + "VF Module ModelCustomizationUuid", modelCustomizationUuid, "OpenStack", "", MsoLogger.ErrorCode.DataError, "Create VF Module: Unable to find vfModule with modelCustomizationUuid=" + mcu); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error); + throw new VnfException(error, MsoExceptionCategory.USERDATA); + } else { + LOGGER.debug("Found vfModuleCust entry " + vfmc.toString()); + } + if (vf.getIsBase()) { + isBaseRequest = true; + LOGGER.debug("This is a BASE VF request!"); + } else { + LOGGER.debug("This is *not* a BASE VF request!"); + if (!isVolumeRequest && nestedBaseStackId == null) { + LOGGER.debug("DANGER WILL ROBINSON! This is unexpected - no nestedBaseStackId with this non-base request"); + } + } + } + + else { // This is to support gamma only - get info from vnf_resource table + if (vfVersion != null && !vfVersion.isEmpty()) { + vnfResource = vnfResourceRepo.findByModelNameAndModelVersion(vnfType, vnfVersion); + } else { + vnfResource = vnfResourceRepo.findByModelName(vnfType); + } + if (vnfResource == null) { + String error = "Create VNF: Unknown VNF Type: " + vnfType; + LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM, "VNF Type", + vnfType, "OpenStack", "", MsoLogger.ErrorCode.DataError, "Create VNF: Unknown VNF Type"); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error); + throw new VnfException(error, MsoExceptionCategory.USERDATA); + } + LOGGER.debug("Got VNF module definition from Catalog: " + + vnfResource.toString()); + } + // By here - we have either a vf or vnfResource + + //1607 - Add version check + // First - see if it's in the VnfResource record + // if we have a vf Module - then we have to query to get the VnfResource record. + if (!oldWay && vf.getVnfResources() != null) { + vnfResource = vf.getVnfResources(); + if (vnfResource == null) { + LOGGER.debug("Unable to find vnfResource will not error for now..."); + } + } + String minVersionVnf = null; + String maxVersionVnf = null; + if (vnfResource != null) { + try { + minVersionVnf = vnfResource.getAicVersionMin(); + maxVersionVnf = vnfResource.getAicVersionMax(); + } catch (Exception e) { + LOGGER.debug("Unable to pull min/max version for this VNF Resource entry",e); + minVersionVnf = null; + maxVersionVnf = null; + } + if (minVersionVnf != null && "".equals(minVersionVnf)) { + minVersionVnf = null; + } + if (maxVersionVnf != null && "".equals(maxVersionVnf)) { + maxVersionVnf = null; + } + } + if (minVersionVnf != null && maxVersionVnf != null) { + MavenLikeVersioning aicV = new MavenLikeVersioning(); + + // double check + if (this.cloudConfig != null) { + Optional cloudSiteOpt = this.cloudConfig.getCloudSite(cloudSiteId); + if (cloudSiteOpt.isPresent()) { + aicV.setVersion(cloudSiteOpt.get().getAicVersion()); + // Add code to handle unexpected values in here + boolean moreThanMin = true; + boolean equalToMin = true; + boolean moreThanMax = true; + boolean equalToMax = true; + boolean doNotTest = false; + try { + moreThanMin = aicV.isMoreRecentThan(minVersionVnf); + equalToMin = aicV.isTheSameVersion(minVersionVnf); + moreThanMax = aicV.isMoreRecentThan(maxVersionVnf); + equalToMax = aicV.isTheSameVersion(maxVersionVnf); + } catch (Exception e) { + LOGGER.debug("An exception occured while trying to test AIC Version " + e.getMessage() + " - will default to not check",e); + doNotTest = true; + } + if (!doNotTest) { + if ((moreThanMin || equalToMin) // aic >= min + && (equalToMax || !(moreThanMax))) { //aic <= max + LOGGER.debug("VNF Resource " + vnfResource.getModelName() + ", ModelUuid=" + vnfResource.getModelUUID() + " VersionMin=" + minVersionVnf + " VersionMax:" + maxVersionVnf + " supported on Cloud: " + cloudSiteId + " with AIC_Version:" + cloudSiteOpt.get().getAicVersion()); + } else { + // ERROR + String error = "VNF Resource type: " + vnfResource.getModelName() + ", ModelUuid=" + vnfResource.getModelUUID() + " VersionMin=" + minVersionVnf + " VersionMax:" + maxVersionVnf + " NOT supported on Cloud: " + cloudSiteId + " with AIC_Version:" + cloudSiteOpt.get().getAicVersion(); + LOGGER.error(MessageEnum.RA_CONFIG_EXC, error, "OpenStack", "", MsoLogger.ErrorCode.BusinessProcesssError, "Exception - setVersion"); + LOGGER.debug(error); + throw new VnfException(error, MsoExceptionCategory.USERDATA); + } + } else { + LOGGER.debug("bypassing testing AIC version..."); + } + } // let this error out downstream to avoid introducing uncertainty at this stage + } else { + LOGGER.debug("cloudConfig is NULL - cannot check cloud site version"); + } + } else { + LOGGER.debug("AIC Version not set in VNF_Resource - this is expected thru 1607 - do not error here - not checked."); + } + // End Version check 1607 + + // with VF_MODULE - we have both the non-vol and vol template/envs in that object + // with VNF_RESOURCE - we use the old methods. + //Integer heatTemplateId = null; + //Integer heatEnvtId = null; + + + + // By the time we get here - heatTemplateId and heatEnvtId should be populated (or null) + HeatTemplate heatTemplate = null; + HeatEnvironment heatEnvironment = null; + if (oldWay) { + //This will handle old Gamma BrocadeVCE VNF + heatTemplate = vnfResource.getHeatTemplates(); + } + else { + if (vf != null) { + if (isVolumeRequest) { + heatTemplate = vf.getVolumeHeatTemplate(); + heatEnvironment = vfmc.getVolumeHeatEnv(); + } else { + heatTemplate = vf.getModuleHeatTemplate(); + heatEnvironment = vfmc.getHeatEnvironment(); + } + } + } + + if (heatTemplate == null) { + String error = "UpdateVF: No Heat Template ID defined in catalog database for " + vfModuleType + ", reqType=" + requestTypeString; + LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM, "Heat Template ID", vfModuleType, "OpenStack", "", MsoLogger.ErrorCode.DataError, error); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error); + alarmLogger.sendAlarm(MSO_CONFIGURATION_ERROR, + MsoAlarmLogger.CRITICAL, error); + throw new VnfException(error, MsoExceptionCategory.INTERNAL); + } else { + LOGGER.debug ("Got HEAT Template from DB: " + heatTemplate.getHeatTemplate()); + } + + if (oldWay) { + //This will handle old Gamma BrocadeVCE VNF + LOGGER.debug ("No environment parameter found for this Type " + vfModuleType); + } else { + if (heatEnvironment == null) { + String error = "Update VNF: undefined Heat Environment. VF=" + vfModuleType; + LOGGER.error (MessageEnum.RA_VNF_UNKNOWN_PARAM, "Heat Environment ID", "OpenStack", "", MsoLogger.ErrorCode.DataError, error); + 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); + } else { + LOGGER.debug ("Got Heat Environment from DB: " + heatEnvironment.getEnvironment()); + } + } + // Replace flavors in environment with those returned by OOF + if (!oldWay) { + Map returnMap = updateFlavorsFromOof(heatEnvironment.getEnvironment(), inputs); + String heatEnvironmentString = returnMap.get("heatEnvironmentString").toString(); + LOGGER.debug("After OOF Update Heat Env String is: " + heatEnvironmentString); + if (returnMap.get("inputs") instanceof Map) { + inputs = (Map) returnMap.get("inputs"); + LOGGER.debug("After OOF Update inputs are: " + inputs.toString()); + } else { + LOGGER.debug("inputs is not an instance of a Map: " + returnMap.get("inputs")); + throw new VnfException("Updating inputs using OOF info failed.", MsoExceptionCategory.INTERNAL); + } + } + + LOGGER.debug ("In MsoVnfAdapterImpl, about to call db.getNestedTemplates avec templateId=" + + heatTemplate.getArtifactUuid ()); + + + List nestedTemplates = heatTemplate.getChildTemplates(); + Map nestedTemplatesChecked = new HashMap <> (); + if (nestedTemplates != null && !nestedTemplates.isEmpty()) { + // for debugging print them out + LOGGER.debug ("Contents of nestedTemplates - to be added to files: on stack:"); + for (HeatTemplate entry : nestedTemplates) { + nestedTemplatesChecked.put (entry.getTemplateName(), entry.getTemplateBody()); + LOGGER.debug (entry.getTemplateName() + " -> " + entry.getTemplateBody()); + } + } else { + LOGGER.debug ("No nested templates found - nothing to do here"); + nestedTemplatesChecked = null; + } + + // 1510 - Also add the files: for any get_files associated with this vnf_resource_id + // *if* there are any + List heatFiles = null; + + Map heatFilesObjects = new HashMap<>(); + + // Add ability to turn on adding get_files with volume requests (by property). + boolean addGetFilesOnVolumeReq = false; + try { + String propertyString = this.environment.getProperty(MsoVnfAdapterImpl.ADD_GET_FILES_ON_VOLUME_REQ); + if ("true".equalsIgnoreCase(propertyString) || "y".equalsIgnoreCase(propertyString)) { + addGetFilesOnVolumeReq = true; + LOGGER.debug("AddGetFilesOnVolumeReq - setting to true! " + propertyString); + } + } catch (Exception e) { + LOGGER.debug("An error occured trying to get property " + MsoVnfAdapterImpl.ADD_GET_FILES_ON_VOLUME_REQ + " - default to false", e); + } + + if (!isVolumeRequest || addGetFilesOnVolumeReq) { + if (oldWay) { + LOGGER.debug("In MsoVnfAdapterImpl createVfModule, this should not happen - old way is gamma only - no heat files!"); + } else { + // 1607 - now use VF_MODULE_TO_HEAT_FILES table + LOGGER.debug("In MsoVnfAdapterImpl createVfModule, about to call db.getHeatFilesForVfModule avec vfModuleId=" + + vf.getModelUUID()); + heatFiles = vf.getHeatFiles(); + } + if (heatFiles != null && !heatFiles.isEmpty()) { + // add these to stack - to be done in createStack + // here, we will map them to Map from + // Map + // this will match the nested templates format + LOGGER.debug("Contents of heatFiles - to be added to files: on stack"); + + for(HeatFiles heatfile : heatFiles){ + LOGGER.debug(heatfile.getFileName() + " -> " + + heatfile.getFileBody()); + heatFilesObjects.put(heatfile.getFileName(), heatfile.getFileBody()); + } + } else { + LOGGER.debug("No heat files found -nothing to do here"); + heatFilesObjects = null; + } + } + + // Check that required parameters have been supplied + String missingParams = null; + List paramList = new ArrayList <> (); + + // New for 1510 - consult the PARAM_ALIAS field to see if we've been + // supplied an alias. Only check if we don't find it initially. + // Also new in 1510 - don't flag missing parameters if there's an environment - because they might be there. + // And also new - add parameter to turn off checking all together if we find we're blocking orders we + // shouldn't + boolean checkRequiredParameters = true; + try { + String propertyString = this.environment.getProperty (MsoVnfAdapterImpl.CHECK_REQD_PARAMS); + if ("false".equalsIgnoreCase (propertyString) || "n".equalsIgnoreCase (propertyString)) { + checkRequiredParameters = false; + LOGGER.debug ("CheckRequiredParameters is FALSE. Will still check but then skip blocking..." + + MsoVnfAdapterImpl.CHECK_REQD_PARAMS); + } + } catch (Exception e) { + // No problem - default is true + LOGGER.debug ("An exception occured trying to get property " + MsoVnfAdapterImpl.CHECK_REQD_PARAMS, e); + } + // 1604 - Add enhanced environment & parameter checking + // Part 1: parse envt entries to see if reqd parameter is there (before used a simple grep + // Part 2: only submit to openstack the parameters in the envt that are in the heat template + // Note this also removes any comments + MsoHeatEnvironmentEntry mhee = null; + if (heatEnvironment != null && heatEnvironment.getEnvironment() != null && heatEnvironment.getEnvironment().contains ("parameters:")) { + //LOGGER.debug ("Have an Environment argument with a parameters: section - will bypass checking for valid params - but will still check for aliases"); + LOGGER.debug("Enhanced environment checking enabled - 1604"); + StringBuilder sb = new StringBuilder(heatEnvironment.getEnvironment()); + //LOGGER.debug("About to create MHEE with " + sb); + mhee = new MsoHeatEnvironmentEntry(sb); + StringBuilder sb2 = new StringBuilder("\nHeat Template Parameters:\n"); + for (HeatTemplateParam parm : heatTemplate.getParameters()) { + sb2.append("\t" + parm.getParamName() + ", required=" + parm.isRequired()); + } + if (!mhee.isValid()) { + sb2.append("Environment says it's not valid! " + mhee.getErrorString()); + } else { + sb2.append("\nEnvironment:"); + sb2.append(mhee.toFullString()); + } + LOGGER.debug(sb2.toString()); + } else { + LOGGER.debug("NO ENVIRONMENT for this entry"); + } + // New with 1707 - all variables converted to their native object types + Map goldenInputs = null; + + LOGGER.debug("Now handle the inputs....first convert"); + ArrayList parameterNames = new ArrayList<>(); + HashMap aliasToParam = new HashMap<>(); + StringBuilder sb = new StringBuilder("\nTemplate Parameters:\n"); + int cntr = 0; + try { + for (HeatTemplateParam htp : heatTemplate.getParameters()) { + sb.append("param[" + cntr++ + "]=" + htp.getParamName()); + parameterNames.add(htp.getParamName()); + if (htp.getParamAlias() != null && !"".equals(htp.getParamAlias())) { + aliasToParam.put(htp.getParamAlias(), htp.getParamName()); + sb.append(" ** (alias=" + htp.getParamAlias() + ")"); + } + sb.append("\n"); + } + LOGGER.debug(sb.toString()); + } catch (Exception e) { + LOGGER.debug("??An exception occurred trying to go through Parameter Names " + e.getMessage(),e); + } + // Step 1 - convert what we got as inputs (Map) to a + // Map - where the object matches the param type identified in the template + // This will also not copy over params that aren't identified in the template + goldenInputs = heat.convertInputMap(inputs, heatTemplate); + // Step 2 - now simply add the outputs as we received them - no need to convert to string + LOGGER.debug("Now add in the base stack outputs if applicable"); + heat.copyBaseOutputsToInputs(goldenInputs, baseStackOutputs, parameterNames, aliasToParam); + // Step 3 - add the volume inputs if any + LOGGER.debug("Now add in the volume stack outputs if applicable"); + heat.copyBaseOutputsToInputs(goldenInputs, nestedVolumeOutputs, parameterNames, aliasToParam); + this.sendMapToDebug(goldenInputs, "Final inputs sent to openstack"); + + for (HeatTemplateParam parm : heatTemplate.getParameters ()) { + LOGGER.debug ("Parameter:'" + parm.getParamName () + + "', isRequired=" + + parm.isRequired () + + ", alias=" + + parm.getParamAlias ()); + + if (parm.isRequired () && (goldenInputs == null || !goldenInputs.containsKey (parm.getParamName ()))) { + // The check for an alias was moved to the method in MsoHeatUtils - when we converted the Map to Map + LOGGER.debug("**Parameter " + parm.getParamName() + " is required and not in the inputs...check environment"); + 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 (); + } + } + } + paramList.add (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, "OpenStack", "", 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 - but checkRequiredParameters is false - will not block"); + } + } else { + LOGGER.debug ("No missing parameters found - ok to proceed"); + } + // We can now remove the recreating of the ENV with only legit params - that check is done for us, + // and it causes problems with json that has arrays + String newEnvironmentString = null; + if (mhee != null) { + newEnvironmentString = mhee.getRawEntry().toString(); + } + + // "Fix" the template if it has CR/LF (getting this from Oracle) + String template = heatTemplate.getHeatTemplate (); + template = template.replaceAll ("\r\n", "\n"); + + // Valet - 1806 + boolean isValetEnabled = this.checkBooleanProperty(MsoVnfAdapterImpl.VALET_ENABLED, false); + boolean failRequestOnValetFailure = this.checkBooleanProperty(MsoVnfAdapterImpl.FAIL_REQUESTS_ON_VALET_FAILURE, false); + LOGGER.debug("isValetEnabled=" + isValetEnabled + ", failRequestsOnValetFailure=" + failRequestOnValetFailure); + if (oldWay || isVolumeRequest) { + isValetEnabled = false; + LOGGER.debug("do not send to valet for volume requests or brocade"); + } + boolean sendResponseToValet = false; + if (isValetEnabled) { + Holder> valetModifiedParamsHolder = new Holder<>(); + sendResponseToValet = this.valetCreateRequest(cloudSiteId, tenantId, heatFilesObjects, + nestedTemplatesChecked, vfModuleName, backout, heatTemplate, newEnvironmentString, goldenInputs, + msoRequest, inputs, failRequestOnValetFailure, valetModifiedParamsHolder); + if (sendResponseToValet) { + goldenInputs = valetModifiedParamsHolder.value; + } + } + + // Have the tenant. Now deploy the stack itself + // Ignore MsoTenantNotFound and MsoStackAlreadyExists exceptions + // because we already checked for those. + long createStackStarttime = System.currentTimeMillis (); + try { + // heatStack = heat.createStack(cloudSiteId, tenantId, vnfName, template, inputs, true, + // heatTemplate.getTimeoutMinutes()); + if (backout == null) { + backout = true; + } + if (heat != null) { + LOGGER.debug("heat is not null!!"); + + heatStack = heat.createStack (cloudSiteId, + tenantId, + vfModuleName, + template, + goldenInputs, + true, + heatTemplate.getTimeoutMinutes(), + newEnvironmentString, + nestedTemplatesChecked, + heatFilesObjects, + backout.booleanValue()); + } + else { + LOGGER.debug("heat is null!"); + throw new MsoHeatNotFoundException(); + } + LOGGER.recordMetricEvent (createStackStarttime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "CreateStack", vfModuleName); + } catch (MsoException me) { + me.addContext ("CreateVFModule"); + String error = "Create VF Module " + vfModuleType + " in " + cloudSiteId + "/" + tenantId + ": " + me; + LOGGER.recordMetricEvent (createStackStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "CreateStack", vfModuleName); + LOGGER.error (MessageEnum.RA_CREATE_VNF_ERR, vfModuleType, cloudSiteId, tenantId, "OpenStack", "", MsoLogger.ErrorCode.DataError, "MsoException - createStack", me); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error); + if (isValetEnabled && sendResponseToValet) { + LOGGER.debug("valet is enabled, the orchestration failed - now sending rollback to valet"); + try { + GenericValetResponse gvr = this.vci.callValetRollbackRequest(msoRequest.getRequestId(), null, backout, me.getMessage()); + // Nothing to really do here whether it succeeded or not other than log it. + LOGGER.debug("Return code from Rollback response is " + gvr.getStatusCode()); + } catch (Exception e) { + LOGGER.error("Exception encountered while sending Rollback to Valet ", e); + } + } + throw new VnfException (me); + } catch (NullPointerException npe) { + String error = "Create VFModule " + vfModuleType + " in " + cloudSiteId + "/" + tenantId + ": " + npe; + LOGGER.recordMetricEvent (createStackStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "CreateStack", vfModuleName); + LOGGER.error (MessageEnum.RA_CREATE_VNF_ERR, vfModuleType, cloudSiteId, tenantId, "OpenStack", "", MsoLogger.ErrorCode.DataError, "NullPointerException - createStack", npe); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error); + LOGGER.debug("NULL POINTER EXCEPTION at heat.createStack"); + //npe.addContext ("CreateVNF"); + throw new VnfException ("NullPointerException during heat.createStack"); + } catch (Exception e) { + LOGGER.recordMetricEvent (createStackStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, "Exception while creating stack with OpenStack", "OpenStack", "CreateStack", vfModuleName); + LOGGER.debug("unhandled exception at heat.createStack",e); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, "Exception while creating stack with OpenStack"); + throw new VnfException("Exception during heat.createStack! " + e.getMessage()); + } + // Reach this point if createStack is successful. + // Populate remaining rollback info and response parameters. + vfRollback.setVnfId (heatStack.getCanonicalName ()); + vfRollback.setVnfCreated (true); + + vnfId.value = heatStack.getCanonicalName (); + outputs.value = copyStringOutputs (heatStack.getOutputs ()); + rollback.value = vfRollback; + if (isValetEnabled && sendResponseToValet) { + LOGGER.debug("valet is enabled, the orchestration succeeded - now send confirm to valet with stack id"); + try { + GenericValetResponse gvr = this.vci.callValetConfirmRequest(msoRequest.getRequestId(), heatStack.getCanonicalName()); + // Nothing to really do here whether it succeeded or not other than log it. + LOGGER.debug("Return code from Confirm response is " + gvr.getStatusCode()); + } catch (Exception e) { + LOGGER.error("Exception encountered while sending Confirm to Valet ", e); + } + } + LOGGER.debug ("VF Module " + vfModuleName + " successfully created"); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully create VF Module"); + return; + } catch (Exception e) { + LOGGER.debug("unhandled exception in create VF",e); + throw new VnfException("Exception during create VF " + e.getMessage()); + } + } + + @Override + public void deleteVfModule (String cloudSiteId, + String tenantId, + String vnfName, + MsoRequest msoRequest, + Holder > outputs) throws VnfException { + MsoLogger.setLogContext (msoRequest); + MsoLogger.setServiceName ("DeleteVf"); + LOGGER.debug ("Deleting VF " + vnfName + " in " + cloudSiteId + "/" + tenantId); + // Will capture execution time for metrics + long startTime = System.currentTimeMillis (); + + // 1702 capture the output parameters on a delete + // so we'll need to query first + Map stackOutputs = null; + try { + stackOutputs = heat.queryStackForOutputs(cloudSiteId, tenantId, vnfName); + } catch (MsoException me) { + // Failed to query the Stack due to an openstack exception. + // Convert to a generic VnfException + me.addContext ("DeleteVFModule"); + String error = "Delete VFModule: Query to get outputs: " + vnfName + " in " + cloudSiteId + "/" + tenantId + ": " + me; + LOGGER.recordMetricEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", null); + LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vnfName, cloudSiteId, tenantId, "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, "Exception - QueryStack", me); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error); + throw new VnfException (me); + } + // call method which handles the conversion from Map to Map for our expected Object types + outputs.value = this.convertMapStringObjectToStringString(stackOutputs); + + boolean isValetEnabled = this.checkBooleanProperty(MsoVnfAdapterImpl.VALET_ENABLED, false); + boolean failRequestOnValetFailure = this.checkBooleanProperty(MsoVnfAdapterImpl.FAIL_REQUESTS_ON_VALET_FAILURE, false); + LOGGER.debug("isValetEnabled=" + isValetEnabled + ", failRequestsOnValetFailure=" + failRequestOnValetFailure); + boolean valetDeleteRequestSucceeded = false; + if (isValetEnabled) { + valetDeleteRequestSucceeded = this.valetDeleteRequest(cloudSiteId, tenantId, vnfName, msoRequest, failRequestOnValetFailure); + } + + // Use the MsoHeatUtils to delete the stack. Set the polling flag to true. + // The possible outcomes of deleteStack are a StackInfo object with status + // of NOTFOUND (on success) or FAILED (on error). Also, MsoOpenstackException + // could be thrown. + long subStartTime = System.currentTimeMillis (); + try { + heat.deleteStack (tenantId, cloudSiteId, vnfName, true); + LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "DeleteStack", vnfName); + } catch (MsoException me) { + me.addContext ("DeleteVNF"); + // Failed to query the Stack due to an openstack exception. + // Convert to a generic VnfException + String error = "Delete VF: " + vnfName + " in " + cloudSiteId + "/" + tenantId + ": " + me; + LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "DeleteStack", vnfName); + LOGGER.error (MessageEnum.RA_DELETE_VNF_ERR, vnfName, cloudSiteId, tenantId, "OpenStack", "DeleteStack", MsoLogger.ErrorCode.DataError, "Exception - deleteStack", me); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error); + if (isValetEnabled && valetDeleteRequestSucceeded) { + LOGGER.debug("valet is enabled, the orchestration failed - now sending rollback to valet"); + try { + GenericValetResponse gvr = this.vci.callValetRollbackRequest(msoRequest.getRequestId(), vnfName, false, me.getMessage()); + // Nothing to really do here whether it succeeded or not other than log it. + LOGGER.debug("Return code from Rollback response is " + gvr.getStatusCode()); + } catch (Exception e) { + LOGGER.error("Exception encountered while sending Rollback to Valet ", e); + } + } + throw new VnfException (me); + } + if (isValetEnabled && valetDeleteRequestSucceeded) { + // only if the original request succeeded do we send a confirm + LOGGER.debug("valet is enabled, the delete succeeded - now send confirm to valet"); + try { + GenericValetResponse gvr = this.vci.callValetConfirmRequest(msoRequest.getRequestId(), vnfName); + // Nothing to really do here whether it succeeded or not other than log it. + LOGGER.debug("Return code from Confirm response is " + gvr.getStatusCode()); + } catch (Exception e) { + LOGGER.error("Exception encountered while sending Confirm to Valet ", e); + } + } + + // On success, nothing is returned. + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully delete VF"); + return; + } + + @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 { + String vfModuleName = vnfName; + String vfModuleType = vnfType; + String methodName = "updateVfModule"; + MsoLogger.setLogContext (msoRequest.getRequestId (), msoRequest.getServiceInstanceId ()); + String serviceName = VNF_ADAPTER_SERVICE_NAME + methodName; + MsoLogger.setServiceName (serviceName); + + StringBuilder sbInit = new StringBuilder(); + sbInit.append("updateVfModule: \n"); + sbInit.append("cloudSiteId=" + cloudSiteId + "\n"); + sbInit.append("tenantId=" + tenantId + "\n"); + sbInit.append("vnfType=" + vnfType + "\n"); + sbInit.append("vnfVersion=" + vnfVersion + "\n"); + sbInit.append("vnfName=" + vnfName + "\n"); + sbInit.append("requestType=" + requestType + "\n"); + sbInit.append("volumeGroupHeatStackId=" + volumeGroupHeatStackId + "\n"); + sbInit.append("baseVfHeatStackId=" + baseVfHeatStackId + "\n"); + sbInit.append("vfModuleStackId=" + vfModuleStackId + "\n"); + sbInit.append("modelCustomizationUuid=" + modelCustomizationUuid + "\n"); + LOGGER.debug(sbInit.toString()); + + String mcu = modelCustomizationUuid; + boolean useMCUuid = false; + if (mcu != null && !mcu.isEmpty()) { + if (mcu.equalsIgnoreCase("null")) { + LOGGER.debug("modelCustomizationUuid: passed in as the string 'null' - will ignore: " + modelCustomizationUuid); + useMCUuid = false; + mcu = ""; + } else { + LOGGER.debug("Found modelCustomizationUuid! Will use that: " + mcu); + useMCUuid = true; + } + } + + String requestTypeString = ""; + if (requestType != null && !"".equals(requestType)) { + requestTypeString = requestType; + } + + String nestedStackId = null; + if (volumeGroupHeatStackId != null && !"".equals(volumeGroupHeatStackId) && !"null".equalsIgnoreCase(volumeGroupHeatStackId)) { + nestedStackId = volumeGroupHeatStackId; + } + String nestedBaseStackId = null; + if (baseVfHeatStackId != null && !"".equals(baseVfHeatStackId) && !"null".equalsIgnoreCase(baseVfHeatStackId)) { + nestedBaseStackId = baseVfHeatStackId; + } + + if (inputs == null) { + // Create an empty set of inputs + inputs = new HashMap<>(); + LOGGER.debug("inputs == null - setting to empty"); + } else { + this.sendMapToDebug(inputs); + } + boolean isBaseRequest = false; + boolean isVolumeRequest = false; + if (requestTypeString.startsWith("VOLUME")) { + isVolumeRequest = true; + } + if ((vfModuleName == null || "".equals(vfModuleName.trim())) && vfModuleStackId != null) { + vfModuleName = this.getVfModuleNameFromModuleStackId(vfModuleStackId); + } + + LOGGER.debug ("Updating VFModule: " + vfModuleName + " of type " + vfModuleType + "in " + cloudSiteId + "/" + tenantId); + LOGGER.debug("requestTypeString = " + requestTypeString + ", nestedVolumeStackId = " + nestedStackId + ", nestedBaseStackId = " + nestedBaseStackId); + + // Will capture execution time for metrics + long startTime = System.currentTimeMillis (); + + // Build a default rollback object (no actions performed) + VnfRollback vfRollback = new VnfRollback (); + vfRollback.setCloudSiteId (cloudSiteId); + vfRollback.setTenantId (tenantId); + vfRollback.setMsoRequest (msoRequest); + vfRollback.setRequestType(requestTypeString); + vfRollback.setVolumeGroupHeatStackId(volumeGroupHeatStackId); + vfRollback.setBaseGroupHeatStackId(baseVfHeatStackId); + vfRollback.setIsBase(isBaseRequest); + vfRollback.setVfModuleStackId(vfModuleStackId); + vfRollback.setModelCustomizationUuid(mcu); + + StackInfo heatStack = null; + long queryStackStarttime = System.currentTimeMillis (); + LOGGER.debug("UpdateVfModule - querying for " + vfModuleName); + try { + heatStack = heat.queryStack (cloudSiteId, tenantId, vfModuleName); + LOGGER.recordMetricEvent (queryStackStarttime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully receive response from Open Stack", "OpenStack", "QueryStack", null); + } catch (MsoException me) { + // Failed to query the Stack due to an openstack exception. + // Convert to a generic VnfException + me.addContext ("UpdateVFModule"); + String error = "Update VFModule: Query " + vfModuleName + " in " + cloudSiteId + "/" + tenantId + ": " + me; + LOGGER.recordMetricEvent (queryStackStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", null); + LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vfModuleName, cloudSiteId, tenantId, "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, "Exception - QueryStack", me); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error); + throw new VnfException (me); + } + + //TODO - do we need to check for the other status possibilities? + if (heatStack == null || heatStack.getStatus () == HeatStatus.NOTFOUND) { + // Not Found + String error = "Update VF: Stack " + vfModuleName + " does not exist in " + cloudSiteId + "/" + tenantId; + LOGGER.error (MessageEnum.RA_VNF_NOT_EXIST, vfModuleName, cloudSiteId, tenantId, "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, error); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error); + throw new VnfNotFound (cloudSiteId, tenantId, vfModuleName); + } else { + LOGGER.debug ("Found Existing stack, status=" + heatStack.getStatus ()); + // Populate the outputs from the existing stack. + outputs.value = copyStringOutputs (heatStack.getOutputs ()); + rollback.value = vfRollback; // Default rollback - no updates performed + } + + // 1604 Cinder Volume support - handle a nestedStackId if sent (volumeGroupHeatStackId): + StackInfo nestedHeatStack = null; + long queryStackStarttime2 = System.currentTimeMillis (); + Map nestedVolumeOutputs = null; + if (nestedStackId != null) { + try { + LOGGER.debug("Querying for nestedStackId = " + nestedStackId); + nestedHeatStack = heat.queryStack(cloudSiteId, tenantId, nestedStackId); + LOGGER.recordMetricEvent (queryStackStarttime2, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully receive response from Open Stack", "OpenStack", "QueryStack", null); + } catch (MsoException me) { + // Failed to query the Stack due to an openstack exception. + // Convert to a generic VnfException + me.addContext ("UpdateVFModule"); + String error = "Update VF: Attached heatStack ID Query " + nestedStackId + " in " + cloudSiteId + "/" + tenantId + ": " + me ; + LOGGER.recordMetricEvent (queryStackStarttime2, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", null); + LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vnfName, cloudSiteId, tenantId, "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, "Exception - " + error, me); + LOGGER.debug("ERROR trying to query nested stack= " + error); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error); + throw new VnfException (me); + } + if (nestedHeatStack == null || nestedHeatStack.getStatus() == HeatStatus.NOTFOUND) { + MsoLogger.setServiceName (serviceName); + String error = "Update VFModule: Attached volume heatStack ID DOES NOT EXIST " + nestedStackId + " in " + cloudSiteId + "/" + tenantId + " USER ERROR" ; + LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vnfName, cloudSiteId, tenantId, error, "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, error); + LOGGER.debug(error); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error); + throw new VnfException (error, MsoExceptionCategory.USERDATA); + } else { + LOGGER.debug("Found nested heat stack - copying values to inputs *later*"); + nestedVolumeOutputs = nestedHeatStack.getOutputs(); + //this.sendMapToDebug(inputs); + this.sendMapToDebug(nestedVolumeOutputs, "volumeStackOutputs"); + //TODO + heat.copyStringOutputsToInputs(inputs, nestedHeatStack.getOutputs(), false); + //this.sendMapToDebug(inputs); + } + } + // handle a nestedBaseStackId if sent - this is the stack ID of the base. + StackInfo nestedBaseHeatStack = null; + Map baseStackOutputs = null; + if (nestedBaseStackId != null) { + long queryStackStarttime3 = System.currentTimeMillis (); + try { + LOGGER.debug("Querying for nestedBaseStackId = " + nestedBaseStackId); + nestedBaseHeatStack = heat.queryStack(cloudSiteId, tenantId, nestedBaseStackId); + LOGGER.recordMetricEvent (queryStackStarttime3, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully receive response from Open Stack", "OpenStack", "QueryStack", null); + } catch (MsoException me) { + // Failed to query the Stack due to an openstack exception. + // Convert to a generic VnfException + me.addContext ("UpdateVfModule"); + String error = "Update VFModule: Attached baseHeatStack ID Query " + nestedBaseStackId + " in " + cloudSiteId + "/" + tenantId + ": " + me ; + LOGGER.recordMetricEvent (queryStackStarttime3, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", null); + LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vfModuleName, cloudSiteId, tenantId, "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, "Exception - " + error, me); + LOGGER.debug("ERROR trying to query nested base stack= " + error); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error); + throw new VnfException (me); + } + if (nestedBaseHeatStack == null || nestedBaseHeatStack.getStatus() == HeatStatus.NOTFOUND) { + MsoLogger.setServiceName (serviceName); + String error = "Update VFModule: Attached base heatStack ID DOES NOT EXIST " + nestedBaseStackId + " in " + cloudSiteId + "/" + tenantId + " USER ERROR" ; + LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vfModuleName, cloudSiteId, tenantId, error, "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, error); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error); + LOGGER.debug(error); + throw new VnfException (error, MsoExceptionCategory.USERDATA); + } else { + LOGGER.debug("Found nested base heat stack - copying values to inputs *later*"); + baseStackOutputs = nestedBaseHeatStack.getOutputs(); + //this.sendMapToDebug(inputs); + this.sendMapToDebug(baseStackOutputs, "baseStackOutputs"); + //TODO + heat.copyStringOutputsToInputs(inputs, nestedBaseHeatStack.getOutputs(), false); + //this.sendMapToDebug(inputs); + } + } + + // Ready to deploy the new VNF + + + + // Retrieve the VF definition + VnfResource vnfResource = null; + VfModule vf = null; + VfModuleCustomization vfmc = null; + if (useMCUuid){ + vfmc = vfModuleCustomRepo.findByModelCustomizationUUID(modelCustomizationUuid); + vf = vfmc != null ? vfmc.getVfModule() : null; + if (vf == null) { + LOGGER.debug("Unable to find a vfModule matching modelCustomizationUuid=" + mcu); + } + } else { + LOGGER.debug("1707 and later - MUST PROVIDE Model Customization UUID!"); + } + if (vf == null) { + String error = "Update VfModule: unable to find vfModule with modelCustomizationUuid=" + mcu; + LOGGER.error (MessageEnum.RA_VNF_UNKNOWN_PARAM, "VF Module Type", vfModuleType, "OpenStack", "", MsoLogger.ErrorCode.DataError, error); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataError, error); + throw new VnfException (error, MsoExceptionCategory.USERDATA); + } + LOGGER.debug ("Got VF module definition from Catalog: " + vf.toString ()); + if (vf.getIsBase()) { + isBaseRequest = true; + LOGGER.debug("This a BASE update request"); + } else { + LOGGER.debug("This is *not* a BASE VF update request"); + if (!isVolumeRequest && nestedBaseStackId == null) { + LOGGER.debug("DANGER WILL ROBINSON! This is unexpected - no nestedBaseStackId with this non-base request"); + } + } + + //1607 - Add version check + // First - see if it's in the VnfResource record + // if we have a vf Module - then we have to query to get the VnfResource record. + if (vf.getModelUUID() != null) { + String vnfResourceModelUuid = vf.getModelUUID(); + + vnfResource = vf.getVnfResources(); + if (vnfResource == null) { + LOGGER.debug("Unable to find vnfResource at " + vnfResourceModelUuid + " will not error for now..."); + } + } + + String minVersionVnf = null; + String maxVersionVnf = null; + if (vnfResource != null) { + try { + minVersionVnf = vnfResource.getAicVersionMin(); + maxVersionVnf = vnfResource.getAicVersionMax(); + } catch (Exception e) { + LOGGER.debug("Unable to pull min/max version for this VNF Resource entry",e); + minVersionVnf = null; + maxVersionVnf = null; + } + if (minVersionVnf != null && "".equals(minVersionVnf)) { + minVersionVnf = null; + } + if (maxVersionVnf != null && "".equals(maxVersionVnf)) { + maxVersionVnf = null; + } + } + if (minVersionVnf != null && maxVersionVnf != null) { + MavenLikeVersioning aicV = new MavenLikeVersioning(); + + // double check + if (this.cloudConfig != null) { + Optional cloudSiteOpt = this.cloudConfig.getCloudSite(cloudSiteId); + if (cloudSiteOpt.isPresent()) { + aicV.setVersion(cloudSiteOpt.get().getAicVersion()); + boolean moreThanMin = true; + boolean equalToMin = true; + boolean moreThanMax = true; + boolean equalToMax = true; + boolean doNotTest = false; + try { + moreThanMin = aicV.isMoreRecentThan(minVersionVnf); + equalToMin = aicV.isTheSameVersion(minVersionVnf); + moreThanMax = aicV.isMoreRecentThan(maxVersionVnf); + equalToMax = aicV.isTheSameVersion(maxVersionVnf); + } catch (Exception e) { + LOGGER.debug("An exception occured while trying to test AIC Version " + e.getMessage() + + " - will default to not check", e); + doNotTest = true; + } + if (!doNotTest) { + if ((moreThanMin || equalToMin) // aic >= min + && ((equalToMax) || !(moreThanMax))) { // aic <= max + LOGGER.debug("VNF Resource " + vnfResource.getModelName() + " VersionMin=" + minVersionVnf + + " VersionMax:" + maxVersionVnf + " supported on Cloud: " + cloudSiteId + + " with AIC_Version:" + aicV); + } else { + // ERROR + String error = "VNF Resource type: " + vnfResource.getModelName() + " VersionMin=" + + minVersionVnf + " VersionMax:" + maxVersionVnf + " NOT supported on Cloud: " + + cloudSiteId + " with AIC_Version:" + aicV; + LOGGER.error(MessageEnum.RA_CONFIG_EXC, error, "OpenStack", "", + MsoLogger.ErrorCode.BusinessProcesssError, "Exception - setVersion"); + LOGGER.debug(error); + throw new VnfException(error, MsoExceptionCategory.USERDATA); + } + } else { + LOGGER.debug("bypassing testing AIC version..."); + } + } // let this error out downstream to avoid introducing uncertainty at this stage + } else { + LOGGER.debug("cloudConfig is NULL - cannot check cloud site version"); + } + + } else { + LOGGER.debug("AIC Version not set in VNF_Resource - do not error for now - not checked."); + } + // End Version check 1607 + + HeatTemplate heatTemplate = null; + HeatEnvironment heatEnvironment = null; + if (isVolumeRequest) { + heatTemplate = vf.getVolumeHeatTemplate(); + heatEnvironment = vfmc.getVolumeHeatEnv(); + } else { + heatTemplate = vf.getModuleHeatTemplate(); + heatEnvironment = vfmc.getHeatEnvironment(); + } + + if (heatTemplate == null) { + String error = "UpdateVF: No Heat Template ID defined in catalog database for " + vfModuleType + ", reqType=" + requestTypeString; + LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM, "Heat Template ID", vfModuleType, "OpenStack", "", MsoLogger.ErrorCode.DataError, error); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error); + alarmLogger.sendAlarm(MSO_CONFIGURATION_ERROR, + MsoAlarmLogger.CRITICAL, error); + throw new VnfException(error, MsoExceptionCategory.INTERNAL); + } else { + LOGGER.debug ("Got HEAT Template from DB: " + heatTemplate.getHeatTemplate()); + } + + if (heatEnvironment == null) { + String error = "Update VNF: undefined Heat Environment. VF=" + vfModuleType; + LOGGER.error (MessageEnum.RA_VNF_UNKNOWN_PARAM, "Heat Environment ID", "OpenStack", "", MsoLogger.ErrorCode.DataError, error); + 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); + } else { + LOGGER.debug ("Got Heat Environment from DB: " + heatEnvironment.getEnvironment()); + } + + LOGGER.debug ("In MsoVnfAdapterImpl, about to call db.getNestedTemplates avec templateId=" + + heatTemplate.getArtifactUuid ()); + + + List nestedTemplates = heatTemplate.getChildTemplates(); + Map nestedTemplatesChecked = new HashMap <> (); + if (nestedTemplates != null && !nestedTemplates.isEmpty()) { + // for debugging print them out + LOGGER.debug ("Contents of nestedTemplates - to be added to files: on stack:"); + for (HeatTemplate entry : nestedTemplates) { + + nestedTemplatesChecked.put (entry.getTemplateName(), entry.getTemplateBody()); + LOGGER.debug (entry.getTemplateName() + " -> " + entry.getTemplateBody()); + } + } else { + LOGGER.debug ("No nested templates found - nothing to do here"); + nestedTemplatesChecked = null; + } + + // Also add the files: for any get_files associated with this VfModule + // *if* there are any + LOGGER.debug ("In MsoVnfAdapterImpl.updateVfModule, about to call db.getHeatFiles avec vfModuleId=" + + vf.getModelUUID()); + + List heatFiles = null; + Map heatFilesObjects = new HashMap <> (); + + // Add ability to turn on adding get_files with volume requests (by property). + boolean addGetFilesOnVolumeReq = false; + try { + String propertyString = this.environment.getProperty(MsoVnfAdapterImpl.ADD_GET_FILES_ON_VOLUME_REQ); + if ("true".equalsIgnoreCase(propertyString) || "y".equalsIgnoreCase(propertyString)) { + addGetFilesOnVolumeReq = true; + LOGGER.debug("AddGetFilesOnVolumeReq - setting to true! " + propertyString); + } + } catch (Exception e) { + LOGGER.debug("An error occured trying to get property " + MsoVnfAdapterImpl.ADD_GET_FILES_ON_VOLUME_REQ + " - default to false", e); + } + if (!isVolumeRequest || addGetFilesOnVolumeReq) { + LOGGER.debug("In MsoVnfAdapterImpl updateVfModule, about to call db.getHeatFilesForVfModule avec vfModuleId=" + + vf.getModelUUID()); + + heatFiles = vf.getHeatFiles(); + if (heatFiles != null && !heatFiles.isEmpty()) { + // add these to stack - to be done in createStack + // here, we will map them to Map from Map + // this will match the nested templates format + LOGGER.debug ("Contents of heatFiles - to be added to files: on stack:"); + for(HeatFiles heatfile : heatFiles){ + LOGGER.debug(heatfile.getFileName() + " -> " + + heatfile.getFileBody()); + heatFilesObjects.put(heatfile.getFileName(), heatfile.getFileBody()); + } + } else { + LOGGER.debug ("No heat files found -nothing to do here"); + heatFilesObjects = null; + } + } + + // Check that required parameters have been supplied + String missingParams = null; + List paramList = new ArrayList <> (); + + // New for 1510 - consult the PARAM_ALIAS field to see if we've been + // supplied an alias. Only check if we don't find it initially. + // Also new in 1510 - don't flag missing parameters if there's an environment - because they might be there. + // And also new - add parameter to turn off checking all together if we find we're blocking orders we + // shouldn't + boolean checkRequiredParameters = true; + try { + String propertyString = this.environment.getProperty (MsoVnfAdapterImpl.CHECK_REQD_PARAMS); + if ("false".equalsIgnoreCase (propertyString) || "n".equalsIgnoreCase (propertyString)) { + checkRequiredParameters = false; + LOGGER.debug ("CheckRequiredParameters is FALSE. Will still check but then skip blocking..." + + MsoVnfAdapterImpl.CHECK_REQD_PARAMS); + } + } catch (Exception e) { + // No problem - default is true + LOGGER.debug ("An exception occured trying to get property " + MsoVnfAdapterImpl.CHECK_REQD_PARAMS, e); + } + // 1604 - Add enhanced environment & parameter checking + // Part 1: parse envt entries to see if reqd parameter is there (before used a simple grep + // Part 2: only submit to openstack the parameters in the envt that are in the heat template + // Note this also removes any comments + MsoHeatEnvironmentEntry mhee = null; + if (heatEnvironment != null && heatEnvironment.getEnvironment().toLowerCase ().contains ("parameters:")) { + LOGGER.debug("Enhanced environment checking enabled - 1604"); + StringBuilder sb = new StringBuilder(heatEnvironment.getEnvironment()); + mhee = new MsoHeatEnvironmentEntry(sb); + StringBuilder sb2 = new StringBuilder("\nHeat Template Parameters:\n"); + for (HeatTemplateParam parm : heatTemplate.getParameters()) { + sb2.append("\t" + parm.getParamName() + ", required=" + parm.isRequired()); + } + if (!mhee.isValid()) { + sb2.append("Environment says it's not valid! " + mhee.getErrorString()); + } else { + sb2.append("\nEnvironment:"); + sb2.append(mhee.toFullString()); + } + LOGGER.debug(sb2.toString()); + } else { + LOGGER.debug("NO ENVIRONMENT for this entry"); + } + // New for 1607 - support params of json type + HashMap jsonParams = new HashMap<>(); + boolean hasJson = false; + + for (HeatTemplateParam parm : heatTemplate.getParameters ()) { + LOGGER.debug ("Parameter:'" + parm.getParamName () + + "', isRequired=" + + parm.isRequired () + + ", alias=" + + parm.getParamAlias ()); + // handle json + String parameterType = parm.getParamType(); + if (parameterType == null || "".equals(parameterType.trim())) { + parameterType = "String"; + } + JsonNode jsonNode = null; + if ("json".equalsIgnoreCase(parameterType) && inputs != null) { + if (inputs.containsKey(parm.getParamName()) ) { + hasJson = true; + String jsonString = null; + try { + jsonString = inputs.get(parm.getParamName()); + jsonNode = new ObjectMapper().readTree(jsonString); + } catch (JsonParseException jpe) { + //TODO - what to do here? + //for now - send the error to debug, but just leave it as a String + String errorMessage = jpe.getMessage(); + LOGGER.debug("Json Error Converting " + parm.getParamName() + " - " + errorMessage,jpe); + hasJson = false; + jsonNode = null; + } catch (Exception e) { + // or here? + LOGGER.debug("Json Error Converting " + parm.getParamName() + " " + e.getMessage(),e); + hasJson = false; + jsonNode = null; + } + if (jsonNode != null) { + jsonParams.put(parm.getParamName(), jsonNode); + } + } else if (inputs.containsKey(parm.getParamAlias())) { + hasJson = true; + String jsonString = null; + try { + jsonString = inputs.get(parm.getParamAlias()); + jsonNode = new ObjectMapper().readTree(jsonString); + } catch (JsonParseException jpe) { + //TODO - what to do here? + //for now - send the error to debug, but just leave it as a String + String errorMessage = jpe.getMessage(); + LOGGER.debug("Json Error Converting " + parm.getParamName() + " - " + errorMessage,jpe); + hasJson = false; + jsonNode = null; + } catch (Exception e) { + // or here? + LOGGER.debug("Json Error Converting " + parm.getParamName() + " " + e.getMessage(),e); + hasJson = false; + jsonNode = null; + } + if (jsonNode != null) { + // Notice here - we add it to the jsonParams hashMap with the actual name - + // then manipulate the inputs so when we check for aliases below - it will not + // get flagged. + jsonParams.put(parm.getParamName(), jsonNode); + inputs.remove(parm.getParamAlias()); + inputs.put(parm.getParamName(), jsonString); + } + } //TODO add a check for the parameter in the env file + } + + if (parm.isRequired () && (inputs == null || !inputs.containsKey (parm.getParamName ()))) { + if (inputs.containsKey (parm.getParamAlias ())) { + // They've submitted using an alias name. Remove that from inputs, and add back using real name. + String realParamName = parm.getParamName (); + String alias = parm.getParamAlias (); + String value = inputs.get (alias); + LOGGER.debug ("*Found an Alias: paramName=" + realParamName + + ",alias=" + + alias + + ",value=" + + value); + inputs.remove (alias); + inputs.put (realParamName, value); + LOGGER.debug (alias + " entry removed from inputs, added back using " + realParamName); + } + // enhanced - check if it's in the Environment (note: that method + else 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 (); + } + } + } + paramList.add (parm.getParamName ()); + } + + + if (missingParams != null) { + // Problem - missing one or more required parameters + if (checkRequiredParameters) { + String error = "Update VNF: Missing Required inputs: " + missingParams; + LOGGER.error (MessageEnum.RA_MISSING_PARAM, missingParams, "OpenStack", "", MsoLogger.ErrorCode.DataError, error); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.BadRequest, error); + throw new VnfException (error, MsoExceptionCategory.USERDATA); + } else { + LOGGER.debug ("found missing parameters - but checkRequiredParameters is false - will not block"); + } + } else { + LOGGER.debug ("No missing parameters found - ok to proceed"); + } + + // Just submit the envt entry as received from the database + String newEnvironmentString = null; + if (mhee != null) { + newEnvironmentString = mhee.getRawEntry().toString(); + } + // Remove any extraneous parameters (don't throw an error) + if (inputs != null) { + List extraParams = new ArrayList <> (); + extraParams.addAll (inputs.keySet ()); + // This is not a valid parameter for this template + extraParams.removeAll (paramList); + if (!extraParams.isEmpty ()) { + LOGGER.warn (MessageEnum.RA_VNF_EXTRA_PARAM, vnfType, extraParams.toString(), "OpenStack", "", MsoLogger.ErrorCode.DataError, "Extra params"); + inputs.keySet ().removeAll (extraParams); + } + } + Map goldenInputs = copyStringInputs(inputs); + // 1607 - when we get here - we have clean inputs. Create inputsTwo in case we have json + Map inputsTwo = null; + if (hasJson && jsonParams.size() > 0) { + inputsTwo = new HashMap<>(); + for (Map.Entry entry : inputs.entrySet()) { + String keyParamName = entry.getKey(); + String value = entry.getValue(); + if (jsonParams.containsKey(keyParamName)) { + inputsTwo.put(keyParamName, jsonParams.get(keyParamName)); + } else { + inputsTwo.put(keyParamName, value); + } + } + goldenInputs = inputsTwo; + } + + // "Fix" the template if it has CR/LF (getting this from Oracle) + String template = heatTemplate.getHeatTemplate (); + template = template.replaceAll ("\r\n", "\n"); + + boolean isValetEnabled = this.checkBooleanProperty(MsoVnfAdapterImpl.VALET_ENABLED, false); + boolean failRequestOnValetFailure = this.checkBooleanProperty(MsoVnfAdapterImpl.FAIL_REQUESTS_ON_VALET_FAILURE, false); + LOGGER.debug("isValetEnabled=" + isValetEnabled + ", failRequestsOnValetFailure=" + failRequestOnValetFailure); + if (isVolumeRequest) { + isValetEnabled = false; + LOGGER.debug("never send a volume request to valet"); + } + boolean sendResponseToValet = false; + if (isValetEnabled) { + Holder> valetModifiedParamsHolder = new Holder<>(); + String parsedVfModuleName = this.getVfModuleNameFromModuleStackId(vfModuleStackId); + // Make sure it is set to something. + if (parsedVfModuleName == null || parsedVfModuleName.isEmpty()) { + parsedVfModuleName = "unknown"; + } + sendResponseToValet = this.valetUpdateRequest(cloudSiteId, tenantId, heatFilesObjects, + nestedTemplatesChecked, parsedVfModuleName, false, heatTemplate, newEnvironmentString, (HashMap) goldenInputs, + msoRequest, inputs, failRequestOnValetFailure, valetModifiedParamsHolder); + if (sendResponseToValet) { + goldenInputs = valetModifiedParamsHolder.value; + } + } + + // Have the tenant. Now deploy the stack itself + // Ignore MsoTenantNotFound and MsoStackAlreadyExists exceptions + // because we already checked for those. + long updateStackStarttime = System.currentTimeMillis (); + try { + heatStack = heatU.updateStack( + cloudSiteId, + tenantId, + vfModuleName, + template, + goldenInputs, + true, + heatTemplate.getTimeoutMinutes(), + newEnvironmentString, + //heatEnvironmentString, + nestedTemplatesChecked, + heatFilesObjects + ); + LOGGER.recordMetricEvent (updateStackStarttime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully receive response from Open Stack", "OpenStack", "UpdateStack", null); + } catch (MsoException me) { + me.addContext ("UpdateVFModule"); + String error = "Update VFModule " + vfModuleType + " in " + cloudSiteId + "/" + tenantId + ": " + me; + LOGGER.recordMetricEvent (updateStackStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "UpdateStack", null); + LOGGER.error (MessageEnum.RA_UPDATE_VNF_ERR, vfModuleType, cloudSiteId, tenantId, "OpenStack", "", MsoLogger.ErrorCode.DataError, "Exception - " + error, me); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error); + if (isValetEnabled && sendResponseToValet) { + LOGGER.debug("valet is enabled, the orchestration failed - now sending rollback to valet"); + try { + GenericValetResponse gvr = this.vci.callValetRollbackRequest(msoRequest.getRequestId(), null, false, me.getMessage()); + // Nothing to really do here whether it succeeded or not other than log it. + LOGGER.debug("Return code from Rollback response is " + gvr.getStatusCode()); + } catch (Exception e) { + LOGGER.error("Exception encountered while sending Rollback to Valet ", e); + } + } + throw new VnfException (me); + } + + + // Reach this point if updateStack is successful. + // Populate remaining rollback info and response parameters. + vfRollback.setVnfId (heatStack.getCanonicalName ()); + vfRollback.setVnfCreated (true); + + if (isValetEnabled && sendResponseToValet) { + LOGGER.debug("valet is enabled, the update succeeded - now send confirm to valet with stack id"); + try { + GenericValetResponse gvr = this.vci.callValetConfirmRequest(msoRequest.getRequestId(), heatStack.getCanonicalName()); + // Nothing to really do here whether it succeeded or not other than log it. + LOGGER.debug("Return code from Confirm response is " + gvr.getStatusCode()); + } catch (Exception e) { + LOGGER.error("Exception encountered while sending Confirm to Valet ", e); + } + } + + outputs.value = copyStringOutputs (heatStack.getOutputs ()); + rollback.value = vfRollback; + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully update VF Module"); + return; + } + + private String getVfModuleNameFromModuleStackId(String vfModuleStackId) { + // expected format of vfModuleStackId is "MSOTEST51-vSAMP3_base_module-0/1fc1f86c-7b35-447f-99a6-c23ec176ae24" + // before the "/" is the vfModuleName and after the "/" is the heat stack id in Openstack + if (vfModuleStackId == null) + return null; + int index = vfModuleStackId.lastIndexOf('/'); + if (index <= 0) + return null; + String vfModuleName = null; + try { + vfModuleName = vfModuleStackId.substring(0, index); + } catch (Exception e) { + LOGGER.debug("Exception", e); + vfModuleName = null; + } + return vfModuleName; + } + + private Map updateFlavorsFromOof(String heatEnvironmentString, Map inputs) { + Map returnMap = new HashMap<>(); + for (Map.Entry input : inputs.entrySet()){ + if (heatEnvironmentString.contains("label_" + input.getKey())){ + heatEnvironmentString = heatEnvironmentString.replace("label_" + input.getKey(), + input.getValue()); + inputs.remove("label_" + input.getKey()); + } + } + returnMap.put("heatEnvironmentString", heatEnvironmentString); + returnMap.put("inputs", inputs); + return returnMap; + } + /* + * Helper method to check a boolean property value - on error return provided default + */ + private boolean checkBooleanProperty(String propertyName, boolean defaultValue) { + boolean property = defaultValue; + try { + String propertyString = this.environment.getProperty(propertyName); + if ("true".equalsIgnoreCase(propertyString) || "y".equalsIgnoreCase(propertyString)) { + property = true; + } else if ("false".equalsIgnoreCase(propertyString) || "n".equalsIgnoreCase(propertyString)) { + property = false; + } + } catch (Exception e) { + LOGGER.debug ("An exception occured trying to get property " + propertyName + " - defaulting to " + defaultValue, e); + property = defaultValue; + } + return property; + } + + /* + * Helper method to combine getFiles and nestedTemplates in to a single Map + */ + private Map combineGetFilesAndNestedTemplates(Map getFiles, Map nestedTemplates) { + boolean haveGetFiles = true; + boolean haveNestedTemplates = true; + Map files = new HashMap(); + if (getFiles == null || getFiles.isEmpty()) { + haveGetFiles = false; + } + if (nestedTemplates == null || nestedTemplates.isEmpty()) { + haveNestedTemplates = false; + } + if (haveGetFiles && haveNestedTemplates) { + for (String keyString : getFiles.keySet ()) { + files.put (keyString, getFiles.get (keyString)); + } + for (String keyString : nestedTemplates.keySet ()) { + files.put (keyString, nestedTemplates.get (keyString)); + } + } else { + // Handle if we only have one or neither: + if (haveGetFiles) { + files = getFiles; + } + if (haveNestedTemplates) { + files = nestedTemplates; + } + } + return files; + } + + /* + * Valet Create request + */ + private boolean valetCreateRequest(String cloudSiteId, String tenantId, Map heatFilesObjects, Map nestedTemplatesChecked, + String vfModuleName, boolean backout, HeatTemplate heatTemplate, String newEnvironmentString, Map goldenInputs, + MsoRequest msoRequest, Map inputs, boolean failRequestOnValetFailure, Holder> valetModifiedParamsHolder) throws VnfException { + boolean valetSucceeded = false; + String valetErrorMessage = "more detail not available"; + try { + String keystoneUrl = heat.getCloudSiteKeystoneUrl(cloudSiteId); + Map files = this.combineGetFilesAndNestedTemplates(heatFilesObjects, + nestedTemplatesChecked); + HeatRequest heatRequest = new HeatRequest(vfModuleName, backout, heatTemplate.getTimeoutMinutes(), + heatTemplate.getTemplateBody(), newEnvironmentString, files, goldenInputs); + GenericValetResponse createReq = this.vci.callValetCreateRequest(msoRequest.getRequestId(), + cloudSiteId, tenantId, msoRequest.getServiceInstanceId(), inputs.get("vnf_id"), + inputs.get("vnf_name"), inputs.get("vf_module_id"), inputs.get("vf_module_name"), keystoneUrl, + heatRequest); + ValetCreateResponse vcr = createReq.getReturnObject(); + if (vcr != null && createReq.getStatusCode() == 200) { + ValetStatus status = vcr.getStatus(); + if (status != null) { + String statusCode = status.getStatus(); // "ok" or "failed" + if ("ok".equalsIgnoreCase(statusCode)) { + Map newInputs = vcr.getParameters(); + if (newInputs != null) { + Map oldGold = goldenInputs; + LOGGER.debug("parameters before being modified by valet:" + oldGold.toString()); + goldenInputs = new HashMap(); + for (String key : newInputs.keySet()) { + goldenInputs.put(key, newInputs.get(key)); + } + valetModifiedParamsHolder.value = goldenInputs; + LOGGER.debug("parameters after being modified by valet:" + goldenInputs.toString()); + valetSucceeded = true; + } + } else { + valetErrorMessage = status.getMessage(); + } + } + } else { + LOGGER.debug("Got a bad response back from valet"); + valetErrorMessage = "Bad response back from Valet"; + valetSucceeded = false; + } + } catch (Exception e) { + LOGGER.error("An exception occurred trying to call valet ...", e); + valetSucceeded = false; + valetErrorMessage = e.getMessage(); + } + if (failRequestOnValetFailure && !valetSucceeded) { + // The valet request failed - and property says to fail the request + //TODO Create a new exception class for valet? + throw new VnfException("A failure occurred with Valet: " + valetErrorMessage); + } + return valetSucceeded; + } + + /* + * Valet update request + */ + + private boolean valetUpdateRequest(String cloudSiteId, String tenantId, + Map heatFilesObjects, Map nestedTemplatesChecked, String vfModuleName, + boolean backout, HeatTemplate heatTemplate, String newEnvironmentString, + Map goldenInputs, MsoRequest msoRequest, Map inputs, + boolean failRequestOnValetFailure, Holder> valetModifiedParamsHolder) throws VnfException { + + boolean valetSucceeded = false; + String valetErrorMessage = "more detail not available"; + try { + String keystoneUrl = heat.getCloudSiteKeystoneUrl(cloudSiteId); + Map files = this.combineGetFilesAndNestedTemplates(heatFilesObjects, + nestedTemplatesChecked); + HeatRequest heatRequest = new HeatRequest(vfModuleName, false, heatTemplate.getTimeoutMinutes(), + heatTemplate.getTemplateBody(), newEnvironmentString, files, goldenInputs); + // vnf name is not sent to MSO on update requests - so we will set it to the vf module name for now + GenericValetResponse updateReq = this.vci.callValetUpdateRequest(msoRequest.getRequestId(), + cloudSiteId, tenantId, msoRequest.getServiceInstanceId(), inputs.get("vnf_id"), + vfModuleName, inputs.get("vf_module_id"), vfModuleName, keystoneUrl, + heatRequest); + ValetUpdateResponse vur = updateReq.getReturnObject(); + if (vur != null && updateReq.getStatusCode() == 200) { + ValetStatus status = vur.getStatus(); + if (status != null) { + String statusCode = status.getStatus(); // "ok" or "failed" + if ("ok".equalsIgnoreCase(statusCode)) { + Map newInputs = vur.getParameters(); + if (newInputs != null) { + Map oldGold = goldenInputs; + LOGGER.debug("parameters before being modified by valet:" + oldGold.toString()); + goldenInputs = new HashMap(); + for (String key : newInputs.keySet()) { + goldenInputs.put(key, newInputs.get(key)); + } + valetModifiedParamsHolder.value = goldenInputs; + LOGGER.debug("parameters after being modified by valet:" + goldenInputs.toString()); + valetSucceeded = true; + } + } else { + valetErrorMessage = status.getMessage(); + } + } + } else { + LOGGER.debug("Got a bad response back from valet"); + valetErrorMessage = "Got a bad response back from valet"; + valetSucceeded = false; + } + } catch (Exception e) { + LOGGER.error("An exception occurred trying to call valet - will continue processing for now...", e); + valetErrorMessage = e.getMessage(); + valetSucceeded = false; + } + if (failRequestOnValetFailure && !valetSucceeded) { + // The valet request failed - and property says to fail the request + // TODO Create a new exception class for valet? + throw new VnfException("A failure occurred with Valet: " + valetErrorMessage); + } + return valetSucceeded; + } + + /* + * Valet delete request + */ + private boolean valetDeleteRequest(String cloudSiteId, String tenantId, String vnfName, + MsoRequest msoRequest, boolean failRequestOnValetFailure) { + boolean valetDeleteRequestSucceeded = false; + String valetErrorMessage = "more detail not available"; + try { + String vfModuleId = vnfName; + String vfModuleName = vnfName; + try { + vfModuleName = vnfName.substring(0, vnfName.indexOf('/')); + vfModuleId = vnfName.substring(vnfName.indexOf('/') + 1); + } catch (Exception e) { + // do nothing - send what we got for vnfName for both to valet + } + GenericValetResponse deleteReq = this.vci.callValetDeleteRequest(msoRequest.getRequestId(), + cloudSiteId, tenantId, vfModuleId, vfModuleName); + ValetDeleteResponse vdr = deleteReq.getReturnObject(); + if (vdr != null && deleteReq.getStatusCode() == 200) { + ValetStatus status = vdr.getStatus(); + if (status != null) { + String statusCode = status.getStatus(); // "ok" or "failed" + if ("ok".equalsIgnoreCase(statusCode)) { + LOGGER.debug("delete request to valet returned success"); + valetDeleteRequestSucceeded = true; + } else { + LOGGER.debug("delete request to valet returned failure"); + valetDeleteRequestSucceeded = false; + valetErrorMessage = status.getMessage(); + } + } + } else { + LOGGER.debug("Got a bad response back from valet - delete request failed"); + valetDeleteRequestSucceeded = false; + valetErrorMessage = "Got a bad response back from valet - delete request failed"; + } + } catch (Exception e) { + LOGGER.error("An exception occurred trying to call valet - valetDeleteRequest failed", e); + valetDeleteRequestSucceeded = false; + valetErrorMessage = e.getMessage(); + } + if (valetDeleteRequestSucceeded == false && failRequestOnValetFailure == true) { + LOGGER.error("ValetDeleteRequestFailed - del req still will be sent to openstack", new VnfException("ValetDeleteRequestFailedError")); + } + return valetDeleteRequestSucceeded; + } +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/MsoVnfCloudifyAdapterImpl.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/MsoVnfCloudifyAdapterImpl.java new file mode 100644 index 0000000000..0266e87523 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/MsoVnfCloudifyAdapterImpl.java @@ -0,0 +1,1218 @@ +/*- + * ============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.onap.so.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.onap.so.adapters.vnf.exceptions.VnfAlreadyExists; +import org.onap.so.adapters.vnf.exceptions.VnfException; +import org.onap.so.cloud.CloudConfig; +import org.onap.so.cloud.CloudSite; +import org.onap.so.cloudify.beans.DeploymentInfo; +import org.onap.so.cloudify.beans.DeploymentStatus; +import org.onap.so.cloudify.exceptions.MsoCloudifyManagerNotFound; +import org.onap.so.cloudify.utils.MsoCloudifyUtils; +import org.onap.so.db.catalog.beans.HeatEnvironment; +import org.onap.so.db.catalog.beans.HeatFiles; +import org.onap.so.db.catalog.beans.HeatTemplate; +import org.onap.so.db.catalog.beans.HeatTemplateParam; +import org.onap.so.db.catalog.beans.VfModule; +import org.onap.so.db.catalog.beans.VfModuleCustomization; +import org.onap.so.db.catalog.beans.VnfResource; +import org.onap.so.db.catalog.data.repository.VFModuleCustomizationRepository; +import org.onap.so.db.catalog.utils.MavenLikeVersioning; +import org.onap.so.entity.MsoRequest; +import org.onap.so.logger.MessageEnum; +import org.onap.so.logger.MsoAlarmLogger; +import org.onap.so.logger.MsoLogger; +import org.onap.so.openstack.beans.MsoTenant; +import org.onap.so.openstack.beans.VnfRollback; +import org.onap.so.openstack.beans.VnfStatus; +import org.onap.so.openstack.exceptions.MsoCloudSiteNotFound; +import org.onap.so.openstack.exceptions.MsoException; +import org.onap.so.openstack.exceptions.MsoExceptionCategory; +import org.onap.so.openstack.utils.MsoHeatEnvironmentEntry; +import org.onap.so.openstack.utils.MsoHeatEnvironmentParameter; +import org.onap.so.openstack.utils.MsoKeystoneUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.env.Environment; +import org.springframework.stereotype.Component; + +import com.fasterxml.jackson.core.JsonParseException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.springframework.transaction.annotation.Transactional; + +@Component +@Transactional +@WebService(serviceName = "VnfAdapter", endpointInterface = "org.onap.so.adapters.vnf.MsoVnfAdapter", targetNamespace = "http://org.onap.so/vnf") +public class MsoVnfCloudifyAdapterImpl implements MsoVnfAdapter { + + private static final String MSO_CONFIGURATION_ERROR = "MsoConfigurationError"; + private static final String VNF_ADAPTER_SERVICE_NAME = "MSO-BPMN:MSO-VnfAdapter."; + private static final String LOG_REPLY_NAME = "MSO-VnfAdapter:MSO-BPMN."; + private static MsoLogger LOGGER = MsoLogger.getMsoLogger (MsoLogger.Catalog.RA, MsoVnfCloudifyAdapterImpl.class); + private static MsoAlarmLogger alarmLogger = new MsoAlarmLogger (); + private static final String CHECK_REQD_PARAMS = "org.onap.so.adapters.vnf.checkRequiredParameters"; + private static final String ADD_GET_FILES_ON_VOLUME_REQ = "org.onap.so.adapters.vnf.addGetFilesOnVolumeReq"; + private static final ObjectMapper JSON_MAPPER = new ObjectMapper(); + + @Autowired + protected CloudConfig cloudConfig; + + @Autowired + private VFModuleCustomizationRepository vfModuleCustomRepo; + + @Autowired + private Environment environment; + + @Autowired + protected MsoKeystoneUtils keystoneUtils; + + @Autowired + protected MsoCloudifyUtils cloudifyUtils; + /** + * 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 Cloudify Adapter"); + } + + /** + * DO NOT use that constructor to instantiate this class, the msoPropertiesfactory will be NULL. + * @see MsoVnfCloudifyAdapterImpl#MsoVnfAdapterImpl(MsoPropertiesFactory, CloudConfigFactory) + */ + public MsoVnfCloudifyAdapterImpl() { + + } + + /** + * 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, + Boolean enableBridge, + 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. + * + * For Cloudify, this will look up a deployment by its deployment ID, which is really the same + * as deployment name, since it assigned by the client when a deployment is created. + * Also, the input cloudSiteId is used only to identify which Cloudify instance to query, + * and the tenantId is ignored (since that really only applies for Openstack/Heat). + * + * 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 - ignored for Cloudify + * @param vnfName VNF Name (should match a deployment ID) + * @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 VNF outputs from Cloudify deployment (assigned IPs, etc) + */ + @Override + public void queryVnf (String cloudSiteId, + String tenantId, + String vnfName, + MsoRequest msoRequest, + Holder vnfExists, + Holder vnfId, + Holder status, + Holder > outputs) + throws VnfException + { + MsoLogger.setLogContext (msoRequest); + MsoLogger.setServiceName ("QueryVnfCloudify"); + LOGGER.debug ("Querying VNF " + vnfName + " in " + cloudSiteId + "/" + tenantId); + + // Will capture execution time for metrics + long startTime = System.currentTimeMillis (); + long subStartTime = System.currentTimeMillis (); + + DeploymentInfo deployment = null; + + try { + deployment = cloudifyUtils.queryDeployment(cloudSiteId, tenantId, vnfName); + LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Cloudify", "Cloudify", "QueryDeployment", vnfName); + } + catch (MsoCloudifyManagerNotFound e) { + // This site does not have a Cloudify Manager. + // This isn't an error, just means we won't find the VNF here. + deployment = null; + } + catch (MsoException me) { + // Failed to query the Deployment due to a cloudify exception. + // Convert to a generic VnfException + me.addContext ("QueryVNF"); + String error = "Query VNF (Cloudify): " + vnfName + " in " + cloudSiteId + "/" + tenantId + ": " + me; + LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "Cloudify", "QueryDeployment", vnfName); + LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vnfName, cloudSiteId, tenantId, "Cloudify", "QueryVNF", MsoLogger.ErrorCode.DataError, "Exception - queryDeployment", me); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error); + throw new VnfException (me); + } + + if (deployment != null && deployment.getStatus() != DeploymentStatus.NOTFOUND) { + vnfExists.value = Boolean.TRUE; + status.value = deploymentStatusToVnfStatus(deployment); + vnfId.value = deployment.getId(); + outputs.value = copyStringOutputs (deployment.getOutputs ()); + + LOGGER.debug ("VNF " + vnfName + " found in Cloudify, 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 " + vnfName + " 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", MsoLogger.getServiceName()); + 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 (); + String vfModuleId = rollback.getVfModuleStackId (); + + MsoLogger.setLogContext (rollback.getMsoRequest()); + + LOGGER.debug ("Rolling Back VF Module " + vfModuleId + " in " + cloudSiteId + "/" + tenantId); + + DeploymentInfo deployment = null; + + // Use the MsoCloudifyUtils to delete the deployment. Set the polling flag to true. + // The possible outcomes of deleteStack are a StackInfo object with status + // of NOTFOUND (on success) or FAILED (on error). Also, MsoOpenstackException + // could be thrown. + long subStartTime = System.currentTimeMillis (); + try { + // KLUDGE - Cloudify requires Tenant Name for Openstack. We have the ID. + // Go directly to Keystone until APIs could be updated to supply the name. + MsoTenant msoTenant = keystoneUtils.queryTenant(tenantId, cloudSiteId); + String tenantName = (msoTenant != null? msoTenant.getTenantName() : tenantId); + + // TODO: Get a reasonable timeout. Use a global property, or store the creation timeout in rollback object and use that. + deployment = cloudifyUtils.uninstallAndDeleteDeployment(cloudSiteId, tenantName, vfModuleId, 5); + LOGGER.debug("Rolled back deployment: " + deployment.getId()); + LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Cloudify", "Cloudify", "DeleteDeployment", null); + } catch (MsoException me) { + // Failed to rollback the VNF due to a cloudify exception. + // Convert to a generic VnfException + me.addContext ("RollbackVNF"); + String error = "Rollback VF Module: " + vfModuleId + " in " + cloudSiteId + "/" + tenantId + ": " + me; + LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "Cloudify", "DeleteDeployment", null); + LOGGER.error (MessageEnum.RA_DELETE_VNF_ERR, vfModuleId, cloudSiteId, tenantId, "Cloudify", "DeleteDeployment", MsoLogger.ErrorCode.DataError, "Exception - DeleteDeployment", me); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error); + throw new VnfException (me); + } + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully roll back VF Module"); + return; + } + + + private VnfStatus deploymentStatusToVnfStatus (DeploymentInfo deployment) { + // Determine the status based on last action & status + // DeploymentInfo object should be enhanced to report a better status internally. + DeploymentStatus status = deployment.getStatus(); + String lastAction = deployment.getLastAction(); + + if (status == null || lastAction == null) { + return VnfStatus.UNKNOWN; + } + else if (status == DeploymentStatus.NOTFOUND) { + return VnfStatus.NOTFOUND; + } + else if (status == DeploymentStatus.INSTALLED) { + return VnfStatus.ACTIVE; + } + else if (status == DeploymentStatus.CREATED) { + // Should have an INACTIVE status for this case. Shouldn't really happen, but + // Install was never run, or Uninstall was done but deployment didn't get deleted. + return VnfStatus.UNKNOWN; + } + else if (status == DeploymentStatus.FAILED) { + return VnfStatus.FAILED; + } + + return VnfStatus.UNKNOWN; + } + + 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 cloud template + * which is used to deploy the required artifacts (VMs, networks, etc.) + * to the cloud. In this adapter implementation, that artifact is expected + * to be a Cloudify blueprint. + * + * Depending on the blueprint, 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 VNF Cloudify Deployment ID + * @param outputs Holder for Map of VNF outputs from Deployment (assigned IPs, etc) + * @param rollback Holder for returning VnfRollback object + */ + @Override + 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, + Boolean enableBridge, + 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", "Cloudify", "", 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 + + VfModule vf = null; + VnfResource vnfResource = null; + VfModuleCustomization vfmc = null; + + try { + vfmc = vfModuleCustomRepo.findByModelCustomizationUUID(modelCustomizationUuid); + + if (vfmc == 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 " + vfmc.toString()); + } + + // Get the vfModule and vnfResource records + vf = vfmc.getVfModule(); + vnfResource = vfmc.getVfModule().getVnfResources(); + } + catch (Exception e) { + + 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 cloudSiteOp = cloudConfig.getCloudSite (cloudSiteId); + if (!cloudSiteOp.isPresent()) { + throw new VnfException (new MsoCloudSiteNotFound (cloudSiteId)); + } + CloudSite cloudSite = cloudSiteOp.get(); + MavenLikeVersioning aicV = new MavenLikeVersioning(); + aicV.setVersion(cloudSite.getAicVersion()); + + 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: " + cloudSiteId + " with AIC_Version:" + cloudSite.getAicVersion(); + 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 + + + DeploymentInfo cloudifyDeployment = null; + + // First, look up to see if the VF already exists. + + long subStartTime1 = System.currentTimeMillis (); + try { + cloudifyDeployment = cloudifyUtils.queryDeployment (cloudSiteId, tenantId, vfModuleName); + LOGGER.recordMetricEvent (subStartTime1, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Cloudify", "Cloudify", "QueryDeployment", vfModuleName); + } + catch (MsoException me) { + // Failed to query the Deployment due to a cloudify exception. + String error = "Create VF Module: Query " + vfModuleName + " in " + cloudSiteId + "/" + tenantId + ": " + me ; + LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vfModuleName, cloudSiteId, tenantId, "Cloudify", "queryDeployment", MsoLogger.ErrorCode.DataError, "Exception - queryDeployment", me); + LOGGER.recordMetricEvent (subStartTime1, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "Cloudify", "QueryDeployment", 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 (cloudifyDeployment != null && !(cloudifyDeployment.getStatus () == DeploymentStatus.NOTFOUND)) { + // CREATED, INSTALLED, INSTALLING, FAILED, UNINSTALLING, UNKNOWN + DeploymentStatus status = cloudifyDeployment.getStatus(); + LOGGER.debug ("Found Existing Deployment, status=" + status); + + if (status == DeploymentStatus.INSTALLED) { + // fail - it exists + if (failIfExists != null && failIfExists) { + String error = "Create VF: Deployment " + vfModuleName + " already exists in " + cloudSiteId + "/" + tenantId; + LOGGER.error (MessageEnum.RA_VNF_ALREADY_EXIST, vfModuleName, cloudSiteId, tenantId, "Cloudify", "queryDeployment", MsoLogger.ErrorCode.DataError, "Deployment " + vfModuleName + " already exists"); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error); + throw new VnfAlreadyExists (vfModuleName, cloudSiteId, tenantId, cloudifyDeployment.getId()); + } else { + // Found existing deployment and client has not requested "failIfExists". + // Populate the outputs from the existing deployment. + + vnfId.value = cloudifyDeployment.getId(); + outputs.value = copyStringOutputs (cloudifyDeployment.getOutputs ()); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully create VF Module (found existing)"); + return; + } + } + // Check through various detailed error cases + if (status == DeploymentStatus.INSTALLING || status == DeploymentStatus.UNINSTALLING) { + // 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, "Cloudify", "queryDeployment", MsoLogger.ErrorCode.DataError, "Deployment " + vfModuleName + " already exists"); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error); + throw new VnfAlreadyExists (vfModuleName, cloudSiteId, tenantId, cloudifyDeployment.getId()); + } + else if (status == DeploymentStatus.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, "Cloudify", "queryDeployment", MsoLogger.ErrorCode.DataError, "Deployment " + vfModuleName + " already exists and is in FAILED state"); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error); + throw new VnfAlreadyExists (vfModuleName, cloudSiteId, tenantId, cloudifyDeployment.getId()); + } + else if (status == DeploymentStatus.UNKNOWN || status == DeploymentStatus.CREATED) { + // 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, "Cloudify", "queryDeployment", MsoLogger.ErrorCode.DataError, "Deployment " + 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, cloudifyDeployment.getId()); + } + 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, "Cloudify", "queryDeployment", MsoLogger.ErrorCode.DataError, "Deployment " + 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, cloudifyDeployment.getId()); + } + } + + + // 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 (); + DeploymentInfo volumeDeployment = null; + try { + volumeDeployment = cloudifyUtils.queryDeployment (cloudSiteId, tenantId, volumeGroupId); + LOGGER.recordMetricEvent (subStartTime2, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Success response from Cloudify", "Cloudify", "QueryDeployment", volumeGroupId); + } + catch (MsoException me) { + // Failed to query the Volume GroupDeployment due to a cloudify exception. + String error = "Create VF Module: Query Volume Group " + volumeGroupId + " in " + cloudSiteId + "/" + tenantId + ": " + me ; + LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, volumeGroupId, cloudSiteId, tenantId, "Cloudify", "queryDeployment(volume)", MsoLogger.ErrorCode.DataError, "Exception - queryDeployment(volume)", me); + LOGGER.recordMetricEvent (subStartTime2, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "Cloudify", "QueryDeployment(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 (volumeDeployment == null || volumeDeployment.getStatus() == DeploymentStatus.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, "Cloudify", "queryDeployment(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 = volumeDeployment.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 (vf.getIsBase()) { + 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 (); + DeploymentInfo baseDeployment = null; + try { + baseDeployment = cloudifyUtils.queryDeployment (cloudSiteId, tenantId, baseVfModuleId); + LOGGER.recordMetricEvent (subStartTime2, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Success response from Cloudify", "Cloudify", "QueryDeployment(Base)", baseVfModuleId); + } + catch (MsoException me) { + // Failed to query the Volume GroupDeployment due to a cloudify exception. + String error = "Create VF Module: Query Base " + baseVfModuleId + " in " + cloudSiteId + "/" + tenantId + ": " + me ; + LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, baseVfModuleId, cloudSiteId, tenantId, "Cloudify", "queryDeployment(Base)", MsoLogger.ErrorCode.DataError, "Exception - queryDeployment(Base)", me); + LOGGER.recordMetricEvent (subStartTime2, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "Cloudify", "QueryDeployment(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 (baseDeployment == null || baseDeployment.getStatus() == DeploymentStatus.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, "Cloudify", "queryDeployment(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 = baseDeployment.getOutputs(); + this.sendMapToDebug(baseModuleOutputs, "baseModuleOutputs"); + } + } + } + + + // Ready to deploy the new VNF + + // NOTE: For this section, heatTemplate is used for both HEAT templates and Cloudify blueprints. + // In final implementation (post-POC), the template object would either be generic or there would + // be a separate DB Table/Object for Blueprints. + + + // NOTE: The template is fixed for the VF Module. The environment is part of the customization. + HeatTemplate heatTemplate = null; + HeatEnvironment heatEnvironment = null; + if (isVolumeRequest) { + heatTemplate = vf.getVolumeHeatTemplate(); + heatEnvironment = vfmc.getVolumeHeatEnv(); + } else { + heatTemplate = vf.getModuleHeatTemplate(); + heatEnvironment = vfmc.getHeatEnvironment(); + } + + if (heatTemplate == null) { + String error = "UpdateVF: No Heat Template ID defined in catalog database for " + vfModuleType + ", reqType=" + requestType; + LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM, "Heat Template ID", vfModuleType, "OpenStack", "", MsoLogger.ErrorCode.DataError, error); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error); + alarmLogger.sendAlarm(MSO_CONFIGURATION_ERROR, + MsoAlarmLogger.CRITICAL, error); + throw new VnfException(error, MsoExceptionCategory.INTERNAL); + } else { + LOGGER.debug ("Got HEAT Template from DB: " + heatTemplate.getHeatTemplate()); + } + + if (heatEnvironment == null) { + String error = "Update VNF: undefined Heat Environment. VF=" + vfModuleType; + LOGGER.error (MessageEnum.RA_VNF_UNKNOWN_PARAM, "Heat Environment ID", "OpenStack", "", MsoLogger.ErrorCode.DataError, error); + 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); + } else { + LOGGER.debug ("Got Heat Environment from DB: " + heatEnvironment.getEnvironment()); + } + + + try { + // All variables converted to their native object types + HashMap goldenInputs = new HashMap(); + List extraInputs = new ArrayList(); + + // NOTE: SKIP THIS FOR CLOUDIFY for now. Just use what was passed in. + // This whole section needs to be rewritten. + 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 = cloudifyUtils.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)); + } + } + } + + // Last, add in values from the "environment" file. + // These are added to the inputs, since Cloudify doesn't pass an environment file like Heat. + + // TODO: This may take a different form for Cloudify, but for now process it + // with Heat environment file syntax + StringBuilder sb = new StringBuilder(heatEnvironment.getEnvironment()); + MsoHeatEnvironmentEntry mhee = new MsoHeatEnvironmentEntry (sb); + + if (mhee.getParameters() != null) { + for (MsoHeatEnvironmentParameter envParam : mhee.getParameters()) { + // If this is a template input, copy to golden inputs + String envKey = envParam.getName(); + if (params.containsKey(envKey) && !goldenInputs.containsKey(envKey)) { + Object value = cloudifyUtils.convertInputValue(envParam.getValue(), params.get(envKey)); + if (value != null) { + goldenInputs.put(envKey, value); + } + else { + LOGGER.debug("Failed to convert environment parameter " + envKey + "='" + envParam.getValue() + "' to " + params.get(envKey).getParamType()); + } + } + } + } + + this.sendMapToDebug(goldenInputs, "Final inputs sent to Cloudify"); + + + // Check that required parameters have been supplied from any of the sources + String missingParams = null; + boolean checkRequiredParameters = true; + try { + String propertyString = this.environment.getProperty(MsoVnfCloudifyAdapterImpl.CHECK_REQD_PARAMS); + if ("false".equalsIgnoreCase (propertyString) || "n".equalsIgnoreCase (propertyString)) { + checkRequiredParameters = false; + LOGGER.debug ("CheckRequiredParameters is FALSE. Will still check but then skip blocking..." + + MsoVnfCloudifyAdapterImpl.CHECK_REQD_PARAMS); + } + } catch (Exception e) { + // No problem - default is true + LOGGER.debug ("An exception occured trying to get property " + MsoVnfCloudifyAdapterImpl.CHECK_REQD_PARAMS, e); + } + + + for (HeatTemplateParam parm : heatTemplate.getParameters ()) { + if (parm.isRequired () && (!goldenInputs.containsKey (parm.getParamName ()))) { + 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, "Cloudify", "", 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 + + // Ready to deploy the VF Module. + // *First step - make sure the blueprint is loaded into Cloudify. + String blueprintName = heatTemplate.getTemplateName(); + String blueprint = heatTemplate.getTemplateBody(); + String blueprintId = blueprintName; + + // Use the main blueprint name as the blueprint ID (strip yaml extensions). + if (blueprintId.endsWith(".yaml")) + blueprintId = blueprintId.substring(0,blueprintId.lastIndexOf(".yaml")); + + try { + if (! cloudifyUtils.isBlueprintLoaded (cloudSiteId, blueprintId)) { + LOGGER.debug ("Blueprint " + blueprintId + " is not loaded. Will upload it now."); + + Map blueprintFiles = new HashMap(); + + blueprintFiles.put(blueprintName, blueprint.getBytes()); + + // TODO: Implement nested blueprint logic based on Cloudify structures. + // For now, just use the Heat structures. + // The query returns a map of String->Object, where the map keys provide one layer of + // indirection from the Heat template names. For this case, assume the map key matches + // the nested blueprint name. + List nestedBlueprints = heatTemplate.getChildTemplates(); + if (nestedBlueprints != null) { + for (HeatTemplate nestedBlueprint: nestedBlueprints) { + blueprintFiles.put(nestedBlueprint.getTemplateName(), nestedBlueprint.getTemplateBody().getBytes()); + } + } + + // TODO: Implement file artifact logic based on Cloudify structures. + // For now, just use the Heat structures. + List heatFiles = vf.getHeatFiles(); + if (heatFiles != null) { + for (HeatFiles heatFile: heatFiles) { + blueprintFiles.put(heatFile.getFileName(), heatFile.getFileBody().getBytes()); + } + } + + // Upload the blueprint package + cloudifyUtils.uploadBlueprint(cloudSiteId, blueprintId, blueprintName, blueprintFiles, false); + + } + } + + catch (MsoException me) { + me.addContext ("CreateVFModule"); + String error = "Create VF Module: Upload blueprint failed. Blueprint=" + blueprintName + ": " + me; + LOGGER.error (MessageEnum.RA_CREATE_VNF_ERR, vfModuleType, cloudSiteId, tenantId, "Cloudify", "", MsoLogger.ErrorCode.DataError, "MsoException - uploadBlueprint", me); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error); + throw new VnfException (me); + + } + + // Ignore MsoTenantNotFound and MsoStackAlreadyExists exceptions + // because we already checked for those. + long createDeploymentStarttime = System.currentTimeMillis (); + try { + // KLUDGE - Cloudify requires Tenant Name for Openstack. We have the ID. + // Go directly to Keystone until APIs could be updated to supply the name. + MsoTenant msoTenant = keystoneUtils.queryTenant(tenantId, cloudSiteId); + String tenantName = (msoTenant != null? msoTenant.getTenantName() : tenantId); + + if (backout == null) { + backout = true; + } + + cloudifyDeployment = cloudifyUtils.createAndInstallDeployment (cloudSiteId, + tenantName, + vfModuleName, + blueprintId, + goldenInputs, + true, + heatTemplate.getTimeoutMinutes (), + backout.booleanValue()); + + LOGGER.recordMetricEvent (createDeploymentStarttime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Cloudify", "Cloudify", "CreateDeployment", vfModuleName); + } catch (MsoException me) { + me.addContext ("CreateVFModule"); + String error = "Create VF Module " + vfModuleType + " in " + cloudSiteId + "/" + tenantId + ": " + me; + LOGGER.recordMetricEvent (createDeploymentStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "Cloudify", "CreateDeployment", vfModuleName); + LOGGER.error (MessageEnum.RA_CREATE_VNF_ERR, vfModuleType, cloudSiteId, tenantId, "Cloudify", "", MsoLogger.ErrorCode.DataError, "MsoException - createDeployment", me); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error); + throw new VnfException (me); + } catch (NullPointerException npe) { + String error = "Create VFModule " + vfModuleType + " in " + cloudSiteId + "/" + tenantId + ": " + npe; + LOGGER.recordMetricEvent (createDeploymentStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "Cloudify", "CreateDeployment", vfModuleName); + LOGGER.error (MessageEnum.RA_CREATE_VNF_ERR, vfModuleType, cloudSiteId, tenantId, "Cloudify", "", MsoLogger.ErrorCode.DataError, "NullPointerException - createDeployment", npe); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error); + LOGGER.debug("NULL POINTER EXCEPTION at cloudify.createAndInstallDeployment"); + //npe.addContext ("CreateVNF"); + throw new VnfException ("NullPointerException during cloudify.createAndInstallDeployment"); + } catch (Exception e) { + LOGGER.recordMetricEvent (createDeploymentStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, "Exception while creating deployment with Cloudify", "Cloudify", "CreateDeployment", vfModuleName); + LOGGER.debug("unhandled exception at cloudify.createAndInstallDeployment"); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, "Exception while creating deployment with Cloudify"); + throw new VnfException("Exception during cloudify.createAndInstallDeployment! " + e.getMessage()); + } + } catch (Exception e) { + LOGGER.debug("unhandled exception in create VF"); + throw new VnfException("Exception during create VF " + e.getMessage()); + + } + + // Reach this point if create is successful. + // Populate remaining rollback info and response parameters. + vfRollback.setVnfCreated (true); + vfRollback.setVnfId (cloudifyDeployment.getId()); + vnfId.value = cloudifyDeployment.getId(); + outputs.value = copyStringOutputs (cloudifyDeployment.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 vnfName, + MsoRequest msoRequest, + Holder > outputs) throws VnfException { + MsoLogger.setLogContext (msoRequest); + MsoLogger.setServiceName ("DeleteVf"); + LOGGER.debug ("Deleting VF " + vnfName + " in " + cloudSiteId + "/" + tenantId); + // Will capture execution time for metrics + long startTime = System.currentTimeMillis (); + + // 1702 capture the output parameters on a delete + // so we'll need to query first + DeploymentInfo deployment = null; + try { + deployment = cloudifyUtils.queryDeployment(cloudSiteId, tenantId, vnfName); + } catch (MsoException me) { + // Failed to query the deployment. Convert to a generic VnfException + me.addContext ("DeleteVFModule"); + String error = "Delete VFModule: Query to get outputs: " + vnfName + " in " + cloudSiteId + "/" + tenantId + ": " + me; + LOGGER.recordMetricEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "Cloudify", "QueryDeployment", null); + LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vnfName, cloudSiteId, tenantId, "Cloudify", "QueryDeployment", MsoLogger.ErrorCode.DataError, "Exception - QueryDeployment", me); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error); + throw new VnfException (me); + } + // call method which handles the conversion from Map to Map for our expected Object types + outputs.value = convertMapStringObjectToStringString(deployment.getOutputs()); + + // Use the MsoHeatUtils to delete the stack. Set the polling flag to true. + // The possible outcomes of deleteStack are a StackInfo object with status + // of NOTFOUND (on success) or FAILED (on error). Also, MsoOpenstackException + // could be thrown. + long subStartTime = System.currentTimeMillis (); + try { + cloudifyUtils.uninstallAndDeleteDeployment(cloudSiteId, tenantId, vnfName, 5); + LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from DeleteDeployment", "Cloudify", "DeleteDeployment", vnfName); + } catch (MsoException me) { + me.addContext ("DeleteVfModule"); + // Convert to a generic VnfException + String error = "Delete VF: " + vnfName + " in " + cloudSiteId + "/" + tenantId + ": " + me; + LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "DeleteDeployment", "DeleteDeployment", vnfName); + LOGGER.error (MessageEnum.RA_DELETE_VNF_ERR, vnfName, cloudSiteId, tenantId, "DeleteDeployment", "DeleteDeployment", MsoLogger.ErrorCode.DataError, "Exception - DeleteDeployment: " + 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; + } + + // TODO: Should Update be supported for Cloudify? What would this look like? + @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 Cloudify-orchestrated VF Modules. + LOGGER.debug ("Update VF Module command attempted but not supported"); + throw new VnfException ("UpdateVfModule: Unsupported command", MsoExceptionCategory.USERDATA); + } + +} \ No newline at end of file diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/MsoVnfPluginAdapterImpl.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/MsoVnfPluginAdapterImpl.java new file mode 100644 index 0000000000..0a7b30f9ca --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/MsoVnfPluginAdapterImpl.java @@ -0,0 +1,1229 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * 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.onap.so.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.onap.so.adapters.vdu.CloudInfo; +import org.onap.so.adapters.vdu.VduException; +import org.onap.so.adapters.vdu.VduInstance; +import org.onap.so.adapters.vdu.VduModelInfo; +import org.onap.so.adapters.vdu.VduPlugin; +import org.onap.so.adapters.vdu.VduStateType; +import org.onap.so.adapters.vdu.VduStatus; +import org.onap.so.adapters.vdu.mapper.VfModuleCustomizationToVduMapper; +import org.onap.so.adapters.vnf.exceptions.VnfAlreadyExists; +import org.onap.so.adapters.vnf.exceptions.VnfException; +import org.onap.so.cloud.CloudConfig; +import org.onap.so.cloud.CloudSite; +import org.onap.so.cloudify.utils.MsoCloudifyUtils; +import org.onap.so.db.catalog.beans.HeatEnvironment; +import org.onap.so.db.catalog.beans.HeatTemplate; +import org.onap.so.db.catalog.beans.HeatTemplateParam; +import org.onap.so.db.catalog.beans.VfModule; +import org.onap.so.db.catalog.beans.VfModuleCustomization; +import org.onap.so.db.catalog.beans.VnfResource; +import org.onap.so.db.catalog.data.repository.VFModuleCustomizationRepository; +import org.onap.so.db.catalog.utils.MavenLikeVersioning; +import org.onap.so.entity.MsoRequest; +import org.onap.so.logger.MessageEnum; +import org.onap.so.logger.MsoAlarmLogger; +import org.onap.so.logger.MsoLogger; +import org.onap.so.openstack.beans.VnfRollback; +import org.onap.so.openstack.beans.VnfStatus; +import org.onap.so.openstack.exceptions.MsoCloudSiteNotFound; +import org.onap.so.openstack.exceptions.MsoException; +import org.onap.so.openstack.exceptions.MsoExceptionCategory; +import org.onap.so.openstack.utils.MsoHeatEnvironmentEntry; +import org.onap.so.openstack.utils.MsoHeatUtils; +import org.onap.so.openstack.utils.MsoKeystoneUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.env.Environment; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +import com.fasterxml.jackson.core.JsonParseException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; + +@WebService(serviceName = "VnfAdapter", endpointInterface = "org.onap.so.adapters.vnf.MsoVnfAdapter", targetNamespace = "http://org.onap.so/vnf") +@Component +@Transactional +public class MsoVnfPluginAdapterImpl implements MsoVnfAdapter { + + private static final String MSO_CONFIGURATION_ERROR = "MsoConfigurationError"; + private static MsoLogger LOGGER = MsoLogger.getMsoLogger (MsoLogger.Catalog.RA, MsoVnfPluginAdapterImpl.class); + private static MsoAlarmLogger alarmLogger = new MsoAlarmLogger (); + private static final String CHECK_REQD_PARAMS = "org.onap.so.adapters.vnf.checkRequiredParameters"; + private static final ObjectMapper JSON_MAPPER = new ObjectMapper(); + + @Autowired + protected CloudConfig cloudConfig; + + @Autowired + private VFModuleCustomizationRepository vfModuleCustomRepo; + + @Autowired + private Environment environment; + + @Autowired + protected MsoKeystoneUtils keystoneUtils; + + @Autowired + protected MsoCloudifyUtils cloudifyUtils; + + @Autowired + protected MsoHeatUtils heatUtils; + + @Autowired + protected VfModuleCustomizationToVduMapper vduMapper; + + /** + * 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 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, + Boolean enableBridge, + 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. + // Convert to a generic VnfException + 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", MsoLogger.getServiceName()); + 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!" , e); + 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!", e); + 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", e); + } + } 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", e); + } + } 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", e); + } + } 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(), e); + } + } + } + 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, e); + //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, e); + } + } 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, e); + } + } 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() + ")", e); + } + } + } + } + + 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 + */ + @Override + 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, + Boolean enableBridge, + 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 + + VfModule vfModule = null; + VnfResource vnfResource = null; + VfModuleCustomization vfModuleCust = null; + + try { + vfModuleCust = vfModuleCustomRepo.findByModelCustomizationUUID(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 = vfModuleCust.getVfModule().getVnfResources(); + } + catch (Exception e) { + + 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 cloudSiteOp = cloudConfig.getCloudSite (cloudSiteId); + if (!cloudSiteOp.isPresent()) { + throw new VnfException (new MsoCloudSiteNotFound (cloudSiteId)); + } + CloudSite cloudSite = cloudSiteOp.get(); + MavenLikeVersioning aicV = new MavenLikeVersioning(); + aicV.setVersion(cloudSite.getAicVersion()); + + 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: " + cloudSiteId + " with AIC_Version:" + cloudSite.getAicVersion(); + 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.getIsBase()) { + 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. + + HeatTemplate heatTemplate = null; + HeatEnvironment heatEnvironment = null; + if (isVolumeRequest) { + heatTemplate = vfModule.getVolumeHeatTemplate(); + heatEnvironment = vfModuleCust.getVolumeHeatEnv(); + } else { + heatTemplate = vfModule.getModuleHeatTemplate(); + heatEnvironment = vfModuleCust.getHeatEnvironment(); + } + + if (heatTemplate == null) { + String error = "UpdateVF: No Heat Template ID defined in catalog database for " + vfModuleType + ", reqType=" + requestType; + LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM, "Heat Template ID", vfModuleType, "VNF", "", MsoLogger.ErrorCode.DataError, error); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error); + alarmLogger.sendAlarm(MSO_CONFIGURATION_ERROR, + MsoAlarmLogger.CRITICAL, error); + throw new VnfException(error, MsoExceptionCategory.INTERNAL); + } else { + LOGGER.debug ("Got HEAT Template from DB: " + heatTemplate.getHeatTemplate()); + } + + if (heatEnvironment == null) { + String error = "Update VNF: undefined Heat Environment. VF=" + vfModuleType; + LOGGER.error (MessageEnum.RA_VNF_UNKNOWN_PARAM, "Heat Environment ID", "OpenStack", "", MsoLogger.ErrorCode.DataError, error); + 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); + } else { + LOGGER.debug ("Got Heat Environment from DB: " + heatEnvironment.getEnvironment()); + } + + + // 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.environment.getProperty(MsoVnfPluginAdapterImpl.CHECK_REQD_PARAMS); + 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); + throw new VnfException("Exception during instantiateVdu: " + e.getMessage()); + } + + + // 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 cloudSiteOp = cloudConfig.getCloudSite(cloudSiteId); + if (cloudSiteOp.isPresent()) { + CloudSite cloudSite = cloudSiteOp.get(); + String orchestrator = cloudSite.getOrchestrator(); + + if (orchestrator.equalsIgnoreCase("CLOUDIFY")) { + return cloudifyUtils; + } + else if (orchestrator.equalsIgnoreCase("HEAT")) { + return heatUtils; + } + } + + // Default - return HEAT plugin, though will fail later + return heatUtils; + } +} \ No newline at end of file diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/VfRollback.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/VfRollback.java new file mode 100644 index 0000000000..5dca8696ef --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/VfRollback.java @@ -0,0 +1,137 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.so.adapters.vnf; + + + +import org.onap.so.entity.MsoRequest; + +public class VfRollback { + private String vnfId; + private String tenantId; + private String cloudSiteId; + private boolean tenantCreated = false; + private boolean vnfCreated = false; + private MsoRequest msoRequest; + private String volumeGroupName; + private String volumeGroupId; + private String requestType; + private String volumeGroupHeatStackId; + private String baseGroupHeatStackId; + private boolean isBase = false; + private String vfModuleStackId; + + + public String getVnfId() { + return vnfId; + } + public void setVnfId(String vnfId) { + this.vnfId = vnfId; + } + public String getTenantId() { + return tenantId; + } + + public void setTenantId(String tenantId) { + this.tenantId = tenantId; + } + public String getCloudSiteId() { + return cloudSiteId; + } + public void setCloudSiteId(String cloudId) { + this.cloudSiteId = cloudId; + } + public boolean getTenantCreated() { + return tenantCreated; + } + public void setTenantCreated(boolean tenantCreated) { + this.tenantCreated = tenantCreated; + } + public boolean getVnfCreated() { + return vnfCreated; + } + public void setVnfCreated(boolean vnfCreated) { + this.vnfCreated = vnfCreated; + } + public MsoRequest getMsoRequest() { + return msoRequest; + } + public void setMsoRequest (MsoRequest msoRequest) { + this.msoRequest = msoRequest; + } + public String getVolumeGroupName() { + return this.volumeGroupName; + } + public void setVolumeGroupName(String volumeGroupName) { + this.volumeGroupName = volumeGroupName; + } + public String getVolumeGroupId() { + return this.volumeGroupId; + } + public void setVolumeGroupId(String volumeGroupId) { + this.volumeGroupId = volumeGroupId; + } + public String getRequestType() { + return this.requestType; + } + public void setRequestType(String requestType) { + this.requestType = requestType; + } + /* + private String volumeGroupHeatStackId; + private String baseGroupHeatStackId; + private boolean isBase = false; + */ + public String getVolumeGroupHeatStackId() { + return this.volumeGroupHeatStackId; + } + public void setVolumeGroupHeatStackId(String volumeGroupHeatStackId) { + this.volumeGroupHeatStackId = volumeGroupHeatStackId; + } + + public String getBaseGroupHeatStackId() { + return this.baseGroupHeatStackId; + } + public void setBaseGroupHeatStackId(String baseGroupHeatStackId) { + this.baseGroupHeatStackId = baseGroupHeatStackId; + } + + public boolean isBase() { + return this.isBase; + } + public void setIsBase(boolean isBase) { + this.isBase = isBase; + } + public String getVfModuleStackId() { + return this.vfModuleStackId; + } + public void setVfModuleStackId(String vfModuleStackId) { + this.vfModuleStackId = vfModuleStackId; + } + + @Override + public String toString() { + return "VfRollback: cloud=" + cloudSiteId + ", tenant=" + tenantId + + ", vnf=" + vnfId + ", tenantCreated=" + tenantCreated + + ", vnfCreated=" + vnfCreated + ", requestType = " + requestType + + ", volumeGroupHeatStackId = " + this.volumeGroupHeatStackId; + } +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/VnfAdapterRest.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/VnfAdapterRest.java new file mode 100644 index 0000000000..3e27361ed1 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/VnfAdapterRest.java @@ -0,0 +1,691 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * Copyright (C) 2017 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.so.adapters.vnf; + + +import java.util.Map; + +import javax.inject.Provider; +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.GenericEntity; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.xml.ws.Holder; + +import org.apache.http.HttpStatus; +import org.onap.so.adapters.vnf.exceptions.VnfException; +import org.onap.so.adapters.vnfrest.CreateVfModuleRequest; +import org.onap.so.adapters.vnfrest.CreateVfModuleResponse; +import org.onap.so.adapters.vnfrest.DeleteVfModuleRequest; +import org.onap.so.adapters.vnfrest.DeleteVfModuleResponse; +import org.onap.so.adapters.vnfrest.QueryVfModuleResponse; +import org.onap.so.adapters.vnfrest.RollbackVfModuleRequest; +import org.onap.so.adapters.vnfrest.RollbackVfModuleResponse; +import org.onap.so.adapters.vnfrest.UpdateVfModuleRequest; +import org.onap.so.adapters.vnfrest.UpdateVfModuleResponse; +import org.onap.so.adapters.vnfrest.VfModuleExceptionResponse; +import org.onap.so.adapters.vnfrest.VfModuleRollback; +import org.onap.so.entity.MsoRequest; +import org.onap.so.logger.MessageEnum; +import org.onap.so.logger.MsoLogger; +import org.onap.so.openstack.beans.VnfRollback; +import org.onap.so.openstack.beans.VnfStatus; +import org.onap.so.openstack.exceptions.MsoExceptionCategory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import io.swagger.annotations.ApiResponse; +import io.swagger.annotations.ApiResponses; + +/** + * This class services calls to the REST interface for VF Modules (http://host:port/vnfs/rest/v1/vnfs) + * Both XML and JSON can be produced/consumed. Set Accept: and Content-Type: headers appropriately. XML is the default. + * For testing, call with cloudSiteId = ___TESTING___ + * To test exceptions, also set tenantId = ___TESTING___ + */ +@Path("/v1/vnfs") +@Api(value = "/v1/vnfs", description = "root of vnf adapters restful web service") +@Transactional +@Component +public class VnfAdapterRest { + private static MsoLogger LOGGER = MsoLogger.getMsoLogger (MsoLogger.Catalog.RA, VnfAdapterRest.class); + private static final String TESTING_KEYWORD = "___TESTING___"; + + @Autowired + private MsoVnfAdapterImpl vnfAdapter; + //TODO Logging, SkipAAI, CREATED flags, Integrate with BPEL, Auth, + + @Autowired + @Qualifier("VnfBpel") + private Provider bpelRestClientProvider; + + + /* + * URL:http://localhost:8080/vnfs/rest/v1/vnfs//vf-modules/ + * REQUEST: + * {"deleteVfModuleRequest": + {"cloudSiteId": "DAN", + "tenantId": "214b428a1f554c02935e66330f6a5409", + "vnfId": "somevnfid", + "vfModuleId": "somemodid", + "vfModuleStackId": "4e567676-e266-4594-a3a6-131c8a2baf73", + "messageId": "ra.1", + "notificationUrl": "http://localhost:8089/vnfmock", + "skipAAI": true, + "msoRequest": { + "requestId": "ra1", + "serviceInstanceId": "sa1" + }} + } + */ + @DELETE + @Path("{aaiVnfId}/vf-modules/{aaiVfModuleId}") + @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @ApiOperation(value = "DeleteVfModule", + response = Response.class, + notes = "Delete an existing vnfModule, DeleteVfModuleRequest JSON is required") + @ApiResponses({ + @ApiResponse(code = 200, message = "vnfModule has been successfully deleted"), + @ApiResponse(code = 202, message = "delete vnfModule request has been accepted (async only)"), + @ApiResponse(code = 500, message = "delete vnfModule failed, examine entity object for details") }) + public Response deleteVfModule ( + @ApiParam(value = "aaiVnfId", required = true) + @PathParam("aaiVnfId") String aaiVnfId, + @ApiParam(value = "aaiVfModuleId", required = true) + @PathParam("aaiVfModuleId") String aaiVfModuleId, + @ApiParam(value = "DeleteVfModuleRequest", required = true) + final DeleteVfModuleRequest req) + { + LOGGER.debug("Delete VfModule enter: " + req.toJsonString()); + if (aaiVnfId == null || !aaiVnfId.equals(req.getVnfId())) { + LOGGER.debug("Req rejected - aaiVnfId not provided or doesn't match URL"); + return Response + .status(HttpStatus.SC_BAD_REQUEST) + .type(MediaType.TEXT_PLAIN) + .entity("vnfid in URL does not match content") + .build(); + } + if (aaiVfModuleId == null || !aaiVfModuleId.equals(req.getVfModuleId())) { + LOGGER.debug("Req rejected - aaiVfModuleId not provided or doesn't match URL"); + return Response + .status(HttpStatus.SC_BAD_REQUEST) + .type(MediaType.TEXT_PLAIN) + .entity("vfModuleId in URL does not match content") + .build(); + } + DeleteVfModuleTask task = new DeleteVfModuleTask(req); + if (req.isSynchronous()) { + // This is a synchronous request + task.run(); + return Response + .status(task.getStatusCode()) + .entity(task.getGenericEntityResponse()) + .build(); + } else { + // This is an asynchronous request + try { + Thread t1 = new Thread(task); + t1.start(); + } catch (Exception e) { + // problem handling delete, send generic failure as sync resp to caller + LOGGER.error (MessageEnum.RA_DELETE_VNF_ERR, "", "deleteVfModule", MsoLogger.ErrorCode.BusinessProcesssError, "Exception in deleteVfModule", e); + return Response.serverError().build(); + } + // send sync response (ACK) to caller + LOGGER.debug ("deleteVNFVolumes exit"); + return Response.status(HttpStatus.SC_ACCEPTED).build(); + } + } + + public class DeleteVfModuleTask implements Runnable { + private final DeleteVfModuleRequest req; + private DeleteVfModuleResponse response = null; + private VfModuleExceptionResponse eresp = null; + private boolean sendxml; + + public DeleteVfModuleTask(DeleteVfModuleRequest req) { + this.req = req; + this.sendxml = true; // can be set with a field or header later + } + public int getStatusCode() { + return (response != null) ? HttpStatus.SC_OK : HttpStatus.SC_BAD_REQUEST; + } + public Object getGenericEntityResponse() { + return (response != null) + ? new GenericEntity(response) {} + : new GenericEntity(eresp) {}; + } + private String getResponse() { + if (response != null) { + return sendxml ? response.toXmlString() : response.toJsonString(); + } else { + return sendxml ? eresp.toXmlString() : eresp.toJsonString(); + } + } + + @Override + public void run() { + try { + String cloudsite = req.getCloudSiteId(); + Holder> outputs = new Holder <> (); + if (cloudsite != null && !cloudsite.equals(TESTING_KEYWORD)) { + //vnfAdapter.deleteVnf (req.getCloudSiteId(), req.getTenantId(), req.getVfModuleStackId(), req.getMsoRequest()); + vnfAdapter.deleteVfModule (req.getCloudSiteId(), req.getTenantId(), req.getVfModuleStackId(), req.getMsoRequest(), outputs); + } + response = new DeleteVfModuleResponse(req.getVnfId(), req.getVfModuleId(), Boolean.TRUE, req.getMessageId(), outputs.value); + } catch (VnfException e) { + LOGGER.error (MessageEnum.RA_DELETE_VNF_ERR, "", "", MsoLogger.ErrorCode.BusinessProcesssError, "VnfException - Delete VNF Module", e); + eresp = new VfModuleExceptionResponse(e.getMessage(), MsoExceptionCategory.INTERNAL, Boolean.TRUE, req.getMessageId()); + } + if (!req.isSynchronous()) { + BpelRestClient bpelClient = bpelRestClientProvider.get(); + bpelClient.bpelPost(getResponse(), req.getNotificationUrl(), sendxml); + } + LOGGER.debug ("Delete vfModule exit: code=" + getStatusCode() + ", resp="+ getResponse()); + } + } + + /* + * URL:http://localhost:8080/vnfs/rest/v1/vnfs//vf-modules/?cloudSiteId=DAN&tenantId=vfModule?&skipAAI=TRUE&msoRequest.requestId=ra1&msoRequest.serviceInstanceId=si1&vfModuleName=T2N2S1 + * RESP: + * {"queryVfModuleResponse": { + "vfModuleId": "AvfmodId", + "vfModuleOutputs": {"entry": { + "key": "server_private_ip_1", + "value": "10.100.1.25" + }}, + "vfModuleStackId": "RaaVnf1/abfa8a6d-feb1-40af-aea3-109403b1cf6b", + "vnfId": "AvnfID", + "vnfStatus": "ACTIVE" + }} + */ + @GET + @Path("{aaiVnfId}/vf-modules/{aaiVfModuleId}") + @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @ApiOperation(value = "QueryVfModule", + response = Response.class, + notes = "Query an existing vnfModule") + @ApiResponses({ + @ApiResponse(code = 200, message = "vnfModule has been successfully queried"), + @ApiResponse(code = 500, message = "query vnfModule failed, examine entity object for details") }) + public Response queryVfModule( + @ApiParam(value = "aaiVnfId", required = true) + @PathParam("aaiVnfId") String aaiVnfId, + @ApiParam(value = "aaiVfModuleId", required = true) + @PathParam("aaiVfModuleId") String aaiVfModuleId, + @ApiParam(value = "cloudSiteId", required = true) + @QueryParam("cloudSiteId") String cloudSiteId, + @ApiParam(value = "tenantId", required = true) + @QueryParam("tenantId") String tenantId, + @ApiParam(value = "vfModuleName", required = true) + @QueryParam("vfModuleName") String vfModuleName, //RAA? Id in doc + @ApiParam(value = "skipAAI", required = true) + @QueryParam("skipAAI") Boolean skipAAI, + @ApiParam(value = "msoRequest.requestId", required = true) + @QueryParam("msoRequest.requestId") String requestId, + @ApiParam(value = "msoRequest.serviceInstanceId", required = true) + @QueryParam("msoRequest.serviceInstanceId") String serviceInstanceId) + { + //This request responds synchronously only + LOGGER.debug ("Query vfModule enter:" + vfModuleName); + MsoRequest msoRequest = new MsoRequest(requestId, serviceInstanceId); + + try { + int respStatus = HttpStatus.SC_OK; + QueryVfModuleResponse qryResp = new QueryVfModuleResponse(aaiVnfId, aaiVfModuleId, null, null, null); + Holder vnfExists = new Holder<>(); + Holder vfModuleId = new Holder<>(); + Holder status = new Holder<>(); + Holder> outputs = new Holder <> (); + vnfAdapter.queryVnf (cloudSiteId, tenantId, vfModuleName, msoRequest, vnfExists, vfModuleId, status, outputs); + if (!vnfExists.value) { + LOGGER.debug ("vfModule not found"); + respStatus = HttpStatus.SC_NOT_FOUND; + } else { + LOGGER.debug ("vfModule found" + vfModuleId.value + ", status=" + status.value); + qryResp.setVfModuleId(vfModuleId.value); + qryResp.setVnfStatus(status.value); + qryResp.setVfModuleOutputs(outputs.value); + } + LOGGER.debug ("Query vfModule exit"); + return Response + .status(respStatus) + .entity(new GenericEntity(qryResp) {}) + .build(); + } catch (VnfException e) { + LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vfModuleName, "", "queryVfModule", MsoLogger.ErrorCode.BusinessProcesssError, "VnfException - queryVfModule", e); + VfModuleExceptionResponse excResp = new VfModuleExceptionResponse(e.getMessage(), MsoExceptionCategory.INTERNAL, Boolean.FALSE, null); + return Response + .status(HttpStatus.SC_INTERNAL_SERVER_ERROR) + .entity(new GenericEntity(excResp) {}) + .build(); + } + } + + /*URL: http://localhost:8080/vnfs/rest/v1/vnfs//vf-modules + *REQUEST: + * {"createVfModuleRequest": + {"cloudSiteId": "DAN", + "tenantId": "214b428a1f554c02935e66330f6a5409", + "vnfId": "somevnfid", + "vfModuleId": "somemodid", + "vfModuleName": "RaaVnf1", + "vnfType": "ApacheVnf", + "vfModuleParams": {"entry": [ + {"key": "network_id", + "value": "59ed7b41-2983-413f-ba93-e7d437433916"}, + {"key": "subnet_id", + "value": "086c9298-5c57-49b7-bb2b-6fd5730c5d92"}, + {"key": "server_name_0", + "value": "RaaVnf1"} + ]}, + "failIfExists": true, + "messageId": "ra.1", + "notificationUrl": "http://localhost:8089/vnfmock", + "skipAAI": true, + "msoRequest": { + "requestId": "ra1", + "serviceInstanceId": "sa1" + }} + } + */ + @POST + @Path("{aaiVnfId}/vf-modules") + @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @ApiOperation(value = "CreateVfModule", + response = Response.class, + notes = "Create a vnfModule") + @ApiResponses({ + @ApiResponse(code = 200, message = "vnfModule has been successfully created"), + @ApiResponse(code = 202, message = "create vnfModule request has been successfully accepted (async only)"), + @ApiResponse(code = 500, message = "create vnfModule failed, examine entity object for details") }) + public Response createVfModule( + @ApiParam(value = "aaiVnfId", required = true) + @PathParam("aaiVnfId") String aaiVnfId, + @ApiParam(value = "CreateVfModuleRequest", required = true) + final CreateVfModuleRequest req) + { + LOGGER.debug("Create VfModule enter inside VnfAdapterRest: " + req.toJsonString()); + if (aaiVnfId == null || !aaiVnfId.equals(req.getVnfId())) { + LOGGER.debug("Req rejected - aaiVnfId not provided or doesn't match URL"); + return Response + .status(HttpStatus.SC_BAD_REQUEST) + .type(MediaType.TEXT_PLAIN) + .entity("vnfid in URL does not match content") + .build(); + } + CreateVfModuleTask task = new CreateVfModuleTask(req); + if (req.isSynchronous()) { + // This is a synchronous request + task.run(); + return Response + .status(task.getStatusCode()) + .entity(task.getGenericEntityResponse()) + .build(); + } else { + // This is an asynchronous request + try { + Thread t1 = new Thread(task); + t1.start(); + } catch (Exception e) { + // problem handling create, send generic failure as sync resp to caller + LOGGER.error (MessageEnum.RA_CREATE_VNF_ERR, "", "createVfModule", MsoLogger.ErrorCode.BusinessProcesssError, "Exception - createVfModule", e); + return Response.serverError().build(); + } + // send sync response (ACK) to caller + LOGGER.debug ("createVfModule exit"); + return Response.status(HttpStatus.SC_ACCEPTED).build(); + } + } + + public class CreateVfModuleTask implements Runnable { + private final CreateVfModuleRequest req; + private CreateVfModuleResponse response = null; + private VfModuleExceptionResponse eresp = null; + private boolean sendxml; + + public CreateVfModuleTask(CreateVfModuleRequest req) { + this.req = req; + this.sendxml = true; // can be set with a field or header later + } + public int getStatusCode() { + return (response != null) ? HttpStatus.SC_OK : HttpStatus.SC_BAD_REQUEST; + } + public Object getGenericEntityResponse() { + return (response != null) + ? new GenericEntity(response) {} + : new GenericEntity(eresp) {}; + } + private String getResponse() { + if (response != null) { + return sendxml ? response.toXmlString() : response.toJsonString(); + } else { + return sendxml ? eresp.toXmlString() : eresp.toJsonString(); + } + } + + @Override + public void run() { + LOGGER.debug ("CreateVfModuleTask start"); + try { + // Synchronous Web Service Outputs + Holder vfModuleStackId = new Holder <> (); + Holder > outputs = new Holder <> (); + Holder vnfRollback = new Holder <> (); + String completeVnfVfModuleType = req.getVnfType() + "::" + req.getVfModuleType(); + LOGGER.debug("completeVnfVfModuleType=" + completeVnfVfModuleType); + String cloudsite = req.getCloudSiteId(); + if (cloudsite != null && cloudsite.equals(TESTING_KEYWORD)) { + String tenant = req.getTenantId(); + if (tenant != null && tenant.equals(TESTING_KEYWORD)) { + throw new VnfException("testing."); + } + vnfRollback.value = new VnfRollback(req.getVnfId(), tenant, cloudsite, + true, false, new MsoRequest("reqid", "svcid"), + req.getVolumeGroupId(), req.getVolumeGroupId(), req.getRequestType(), req.getModelCustomizationUuid()); + vfModuleStackId.value = "479D3D8B-6360-47BC-AB75-21CC91981484"; + outputs.value = VolumeAdapterRest.testMap(); + } else { +// vnfAdapter.createVnf (createReq.getCloudSiteId(), +// createReq.getTenantId(), +// createReq.getVnfType(), +// createReq.getVnfVersion(), +// createReq.getVfModuleName(), +// createReq.getRequestType(), +// createReq.getVolumeGroupStackId(), +// createReq.getVfModuleParams(), +// createReq.getFailIfExists(), +// createReq.getBackout(), +// createReq.getMsoRequest(), +// vfModuleStackId, +// outputs, +// vnfRollback); + vnfAdapter.createVfModule(req.getCloudSiteId(), + req.getTenantId(), + //req.getVnfType(), + completeVnfVfModuleType, + req.getVnfVersion(), + req.getVfModuleName(), + req.getRequestType(), + req.getVolumeGroupStackId(), + req.getBaseVfModuleStackId(), + req.getModelCustomizationUuid(), + req.getVfModuleParams(), + req.getFailIfExists(), + req.getBackout(), + req.getEnableBridge(), + req.getMsoRequest(), + vfModuleStackId, + outputs, + vnfRollback); + } + VfModuleRollback modRollback = new VfModuleRollback(vnfRollback.value, req.getVfModuleId(), vfModuleStackId.value, req.getMessageId()); + response = new CreateVfModuleResponse(req.getVnfId(), req.getVfModuleId(), + vfModuleStackId.value, Boolean.TRUE, outputs.value, modRollback, req.getMessageId()); + } catch (VnfException e) { + LOGGER.debug("Exception :",e); + eresp = new VfModuleExceptionResponse(e.getMessage(), MsoExceptionCategory.INTERNAL, Boolean.TRUE, req.getMessageId()); + } + if (!req.isSynchronous()) { + BpelRestClient bpelClient = bpelRestClientProvider.get(); + bpelClient.bpelPost(getResponse(), req.getNotificationUrl(), sendxml); + } + LOGGER.debug ("CreateVfModuleTask exit: code=" + getStatusCode() + ", resp="+ getResponse()); + } + } + + @PUT + @Path("{aaiVnfId}/vf-modules/{aaiVfModuleId}") + @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @ApiOperation(value = "UpdateVfModule", + response = Response.class, + notes = "Update an existing vnfModule") + @ApiResponses({ + @ApiResponse(code = 200, message = "vnfModule has been successfully updated"), + @ApiResponse(code = 202, message = "update vnfModule request has been successfully accepted (async only)"), + @ApiResponse(code = 500, message = "update vnfModule failed, examine entity object for details") }) + public Response updateVfModule( + @ApiParam(value = "aaiVnfId", required = true) + @PathParam("aaiVnfId") String aaiVnfId, + @ApiParam(value = "aaiVfModuleId", required = true) + @PathParam("aaiVfModuleId") String aaiVfModuleId, + @ApiParam(value = "UpdateVfModuleRequest", required = true) + final UpdateVfModuleRequest req) + { + LOGGER.debug("Update VfModule enter: " + req.toJsonString()); + UpdateVfModulesTask task = new UpdateVfModulesTask(req); + if (req.isSynchronous()) { + // This is a synchronous request + task.run(); + return Response + .status(task.getStatusCode()) + .entity(task.getGenericEntityResponse()) + .build(); + } else { + // This is an asynchronous request + try { + Thread t1 = new Thread(task); + t1.start(); + } catch (Exception e) { + // problem handling create, send generic failure as sync resp to caller + LOGGER.error (MessageEnum.RA_UPDATE_VNF_ERR, "", "updateVfModule", MsoLogger.ErrorCode.BusinessProcesssError, "Exception - updateVfModule", e); + return Response.serverError().build(); + } + // send sync response (ACK) to caller + LOGGER.debug ("updateVfModules exit"); + return Response.status(HttpStatus.SC_ACCEPTED).build(); + } + } + + public class UpdateVfModulesTask implements Runnable { + private final UpdateVfModuleRequest req; + private UpdateVfModuleResponse response = null; + private VfModuleExceptionResponse eresp = null; + private boolean sendxml; + + public UpdateVfModulesTask(UpdateVfModuleRequest req) { + this.req = req; + this.sendxml = true; // can be set with a field or header later + } + public int getStatusCode() { + return (response != null) ? HttpStatus.SC_OK : HttpStatus.SC_BAD_REQUEST; + } + public Object getGenericEntityResponse() { + return (response != null) + ? new GenericEntity(response) {} + : new GenericEntity(eresp) {}; + } + private String getResponse() { + if (response != null) { + return sendxml ? response.toXmlString() : response.toJsonString(); + } else { + return sendxml ? eresp.toXmlString() : eresp.toJsonString(); + } + } + @Override + public void run() { + try { + //MsoVnfAdapter vnfAdapter = new MsoVnfAdapterImpl (msoPropertiesFactory, cloudConfigFactory); + + // Synchronous Web Service Outputs + Holder vfModuleStackId = new Holder <> (); + Holder > outputs = new Holder <> (); + Holder vnfRollback = new Holder <> (); + String completeVnfVfModuleType = req.getVnfType() + "::" + req.getVfModuleType(); + LOGGER.debug("in updateVf - completeVnfVfModuleType=" + completeVnfVfModuleType); + + vnfAdapter.updateVfModule (req.getCloudSiteId(), + req.getTenantId(), + //req.getVnfType(), + completeVnfVfModuleType, + req.getVnfVersion(), + req.getVfModuleName(), + req.getRequestType(), + req.getVolumeGroupStackId(), + req.getBaseVfModuleStackId(), + req.getVfModuleStackId(), + req.getModelCustomizationUuid(), + req.getVfModuleParams(), + req.getMsoRequest(), + outputs, + vnfRollback); + + response = new UpdateVfModuleResponse(req.getVnfId(), req.getVfModuleId(), + vfModuleStackId.value, outputs.value, req.getMessageId()); + } catch (VnfException e) { + LOGGER.debug("Exception :",e); + eresp = new VfModuleExceptionResponse(e.getMessage(), MsoExceptionCategory.INTERNAL, Boolean.TRUE, req.getMessageId()); + } + if (!req.isSynchronous()) { + // This is asynch, so POST response back to caller + BpelRestClient bpelClient = bpelRestClientProvider.get(); + bpelClient.bpelPost (getResponse(), req.getNotificationUrl(), sendxml); + } + LOGGER.debug ("Update VfModule exit: code=" + getStatusCode() + ", resp="+ getResponse()); + } + } + /* + * URL:http://localhost:8080/vnfs/rest/v1/vnfs//vf-modules//rollback + * REQUEST: + * {"deleteVfModuleRequest": + {"cloudSiteId": "DAN", + "tenantId": "214b428a1f554c02935e66330f6a5409", + "vnfId": "somevnfid", + "vfModuleId": "somemodid", + "vfModuleStackId": "4e567676-e266-4594-a3a6-131c8a2baf73", + "messageId": "ra.1", + "notificationUrl": "http://localhost:8089/vnfmock", + "skipAAI": true, + "msoRequest": { + "requestId": "ra1", + "serviceInstanceId": "sa1" + }} + } + */ + @DELETE + @Path("{aaiVnfId}/vf-modules/{aaiVfModuleId}/rollback") + @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @ApiOperation(value = "RollbackVfModule", + response = Response.class, + notes = "Rollback an existing vnfModule") + @ApiResponses({ + @ApiResponse(code = 200, message = "vnfModule has been successfully rolled back"), + @ApiResponse(code = 202, message = "rollback vnfModule request has been successfully accepted (async only)"), + @ApiResponse(code = 500, message = "rollback vnfModule failed, examine entity object for details") }) + public Response rollbackVfModule ( + @ApiParam(value = "aaiVnfId", required = true) + @PathParam("aaiVnfId") String aaiVnfId, + @ApiParam(value = "aaiVfModuleId", required = true) + @PathParam("aaiVfModuleId") String aaiVfModuleId, + @ApiParam(value = "RollbackVfModuleRequest", required = true) + //@QueryParam("rollback") String rollback, + final RollbackVfModuleRequest req) + { + LOGGER.debug("Rollback VfModule enter: " + req.toJsonString()); + RollbackVfModulesTask task = new RollbackVfModulesTask(req); + if (req.isSynchronous()) { + // This is a synchronous request + task.run(); + return Response + .status(task.getStatusCode()) + .entity(task.getGenericEntityResponse()) + .build(); + } else { + // This is an asynchronous request + try { + Thread t1 = new Thread(task); + t1.start(); + } catch (Exception e) { + // problem handling create, send generic failure as sync resp to caller + LOGGER.error (MessageEnum.RA_ROLLBACK_VNF_ERR, "", "rollbackVfModule", MsoLogger.ErrorCode.BusinessProcesssError, "Exception - rollbackVfModule", e); + return Response.serverError().build(); + } + // send sync response (ACK) to caller + LOGGER.debug ("rollbackVfModule exit"); + return Response.status(HttpStatus.SC_ACCEPTED).build(); + } + } + + public class RollbackVfModulesTask implements Runnable { + private final RollbackVfModuleRequest req; + private RollbackVfModuleResponse response = null; + private VfModuleExceptionResponse eresp = null; + private boolean sendxml; + + public RollbackVfModulesTask(RollbackVfModuleRequest req) { + this.req = req; + this.sendxml = true; // can be set with a field or header later + } + public int getStatusCode() { + return (response != null) ? HttpStatus.SC_OK : HttpStatus.SC_BAD_REQUEST; + } + public Object getGenericEntityResponse() { + return (response != null) + ? new GenericEntity(response) {} + : new GenericEntity(eresp) {}; + } + private String getResponse() { + if (response != null) { + return sendxml ? response.toXmlString() : response.toJsonString(); + } else { + return sendxml ? eresp.toXmlString() : eresp.toJsonString(); + } + } + @Override + public void run() { + try { + VfModuleRollback vmr = req.getVfModuleRollback(); + VnfRollback vrb = new VnfRollback( + vmr.getVfModuleStackId(), vmr.getTenantId(), vmr.getCloudSiteId(), true, true, + vmr.getMsoRequest(), null, null, null, null); + vnfAdapter.rollbackVnf (vrb); + response = new RollbackVfModuleResponse(Boolean.TRUE, req.getMessageId()); + } catch (VnfException e) { + LOGGER.error (MessageEnum.RA_ROLLBACK_VNF_ERR, "", "", MsoLogger.ErrorCode.BusinessProcesssError, "Exception - rollbackVfModule", e); + eresp = new VfModuleExceptionResponse(e.getMessage(), MsoExceptionCategory.INTERNAL, false, req.getMessageId()); + } + if (!req.isSynchronous()) { + // This is asynch, so POST response back to caller + BpelRestClient bpelClient = bpelRestClientProvider.get(); + bpelClient.bpelPost (getResponse(), req.getNotificationUrl(), sendxml); + } + LOGGER.debug ("RollbackVfModulesTask exit: code=" + getStatusCode() + ", resp="+ getResponse()); + } + } +} \ No newline at end of file diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/VnfAdapterRestUtils.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/VnfAdapterRestUtils.java new file mode 100644 index 0000000000..876aae8a37 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/VnfAdapterRestUtils.java @@ -0,0 +1,94 @@ +/*- + * ============LICENSE_START======================================================= + * OPENECOMP - SO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.so.adapters.vnf; + +import java.util.Optional; + +import org.onap.so.cloud.CloudConfig; +import org.onap.so.cloud.CloudSite; +import org.onap.so.logger.MsoLogger; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +public class VnfAdapterRestUtils +{ + private static MsoLogger LOGGER = MsoLogger.getMsoLogger (MsoLogger.Catalog.RA, VnfAdapterRestUtils.class); + + @Autowired + private CloudConfig cloudConfig; + + @Autowired + private MsoVnfCloudifyAdapterImpl cloudifyImpl; + + @Autowired + private MsoVnfAdapterImpl vnfImpl; + + /* + * Choose which implementation of VNF Adapter to use, based on the orchestration mode. + * Currently, the two supported orchestrators are HEAT and CLOUDIFY. + */ + public MsoVnfAdapter getVnfAdapterImpl (String mode, String cloudSiteId) + { + // First, determine the orchestration mode to use. + // If was explicitly provided as a parameter, use that. Else if specified for the + // cloudsite, use that. Otherwise, the default is the (original) HEAT-based impl. + + LOGGER.debug ("Entered GetVnfAdapterImpl: mode=" + mode + ", cloudSite=" + cloudSiteId); + + if (mode == null) { + // Didn't get an explicit mode type requested. + // Use the CloudSite to determine which Impl to use, based on whether the target cloutSite + // has a CloudifyManager assigned to it + Optional cloudSite = cloudConfig.getCloudSite(cloudSiteId); + if (cloudSite.isPresent()) { + LOGGER.debug("Got CloudSite: " + cloudSite.toString()); + if (cloudConfig.getCloudifyManager(cloudSite.get().getCloudifyId()) != null) { + mode = "CLOUDIFY"; + } else { + mode = "HEAT"; + } + } + } + + LOGGER.debug ("GetVnfAdapterImpl: mode=" + mode); + + MsoVnfAdapter vnfAdapter = null; + + // TODO: Make this more dynamic (e.g. Service Loader) + if ("CLOUDIFY".equalsIgnoreCase(mode)) { + LOGGER.debug ("GetVnfAdapterImpl: Return Cloudify Adapter"); + vnfAdapter = cloudifyImpl; + } + else if ("HEAT".equalsIgnoreCase(mode)) { + LOGGER.debug ("GetVnfAdapterImpl: Return Heat Adapter"); + vnfAdapter = vnfImpl; + } + else { + // Don't expect this, but default is the HEAT adapter + LOGGER.debug ("GetVnfAdapterImpl: Return Default (Heat) Adapter"); + vnfAdapter = vnfImpl; + } + + return vnfAdapter; + } + +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/VnfAdapterRestV2.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/VnfAdapterRestV2.java new file mode 100644 index 0000000000..143f169c84 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/VnfAdapterRestV2.java @@ -0,0 +1,704 @@ +/*- + * ============LICENSE_START======================================================= + * OPENECOMP - SO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.so.adapters.vnf; + + +import java.util.Map; + +import javax.inject.Provider; +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.GenericEntity; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.xml.ws.Holder; + +import org.apache.http.HttpStatus; +import org.onap.so.adapters.vnf.exceptions.VnfException; +import org.onap.so.adapters.vnfrest.CreateVfModuleRequest; +import org.onap.so.adapters.vnfrest.CreateVfModuleResponse; +import org.onap.so.adapters.vnfrest.DeleteVfModuleRequest; +import org.onap.so.adapters.vnfrest.DeleteVfModuleResponse; +import org.onap.so.adapters.vnfrest.QueryVfModuleResponse; +import org.onap.so.adapters.vnfrest.RollbackVfModuleRequest; +import org.onap.so.adapters.vnfrest.RollbackVfModuleResponse; +import org.onap.so.adapters.vnfrest.UpdateVfModuleRequest; +import org.onap.so.adapters.vnfrest.UpdateVfModuleResponse; +import org.onap.so.adapters.vnfrest.VfModuleExceptionResponse; +import org.onap.so.adapters.vnfrest.VfModuleRollback; +import org.onap.so.entity.MsoRequest; +import org.onap.so.logger.MessageEnum; +import org.onap.so.logger.MsoLogger; +import org.onap.so.openstack.beans.VnfRollback; +import org.onap.so.openstack.beans.VnfStatus; +import org.onap.so.openstack.exceptions.MsoExceptionCategory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Component; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import io.swagger.annotations.ApiResponse; +import io.swagger.annotations.ApiResponses; + +/** + * This class services calls to the REST interface for VF Modules (http://host:port/vnfs/rest/v2/vnfs) + * Both XML and JSON can be produced/consumed. Set Accept: and Content-Type: headers appropriately. XML is the default. + * For testing, call with cloudSiteId = ___TESTING___ + * To test exceptions, also set tenantId = ___TESTING___ + * + * V2 incorporates run-time selection of sub-orchestrator implementation (Heat or Cloudify) + * based on the target cloud. + */ +@Path("/v2/vnfs") +@Api(value = "/v2/vnfs", description = "root of vnf adapters restful web service v2") +@Component +public class VnfAdapterRestV2 { + private static MsoLogger LOGGER = MsoLogger.getMsoLogger (MsoLogger.Catalog.RA, VnfAdapterRestV2.class); + private static final String TESTING_KEYWORD = "___TESTING___"; + + @Autowired + private VnfAdapterRestUtils vnfAdapterRestUtils; + + @Autowired + @Qualifier("VnfBpel") + private Provider bpelRestClientProvider; + + /* + * URL:http://localhost:8080/vnfs/rest/v2/vnfs//vf-modules/ + * REQUEST: + * {"deleteVfModuleRequest": + {"cloudSiteId": "DAN", + "tenantId": "214b428a1f554c02935e66330f6a5409", + "vnfId": "somevnfid", + "vfModuleId": "somemodid", + "vfModuleStackId": "4e567676-e266-4594-a3a6-131c8a2baf73", + "messageId": "ra.1", + "notificationUrl": "http://localhost:8089/vnfmock", + "skipAAI": true, + "msoRequest": { + "requestId": "ra1", + "serviceInstanceId": "sa1" + }} + } + */ + @DELETE + @Path("{aaiVnfId}/vf-modules/{aaiVfModuleId}") + @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @ApiOperation(value = "DeleteVfModule", + response = Response.class, + notes = "Delete an existing vnfModule, DeleteVfModuleRequest JSON is required") + @ApiResponses({ + @ApiResponse(code = 200, message = "vnfModule has been successfully deleted"), + @ApiResponse(code = 202, message = "delete vnfModule request has been accepted (async only)"), + @ApiResponse(code = 500, message = "delete vnfModule failed, examine entity object for details") }) + public Response deleteVfModule ( + @ApiParam(value = "aaiVnfId", required = true) + @PathParam("aaiVnfId") String aaiVnfId, + @ApiParam(value = "aaiVfModuleId", required = true) + @PathParam("aaiVfModuleId") String aaiVfModuleId, + @ApiParam(value = "mode", required = true) + @QueryParam("mode") String mode, + @ApiParam(value = "DeleteVfModuleRequest", required = true) + final DeleteVfModuleRequest req) + { + LOGGER.debug("Delete VfModule enter: " + req.toJsonString()); + if (aaiVnfId == null || !aaiVnfId.equals(req.getVnfId())) { + LOGGER.debug("Req rejected - aaiVnfId not provided or doesn't match URL"); + return Response + .status(HttpStatus.SC_BAD_REQUEST) + .type(MediaType.TEXT_PLAIN) + .entity("vnfid in URL does not match content") + .build(); + } + if (aaiVfModuleId == null || !aaiVfModuleId.equals(req.getVfModuleId())) { + LOGGER.debug("Req rejected - aaiVfModuleId not provided or doesn't match URL"); + return Response + .status(HttpStatus.SC_BAD_REQUEST) + .type(MediaType.TEXT_PLAIN) + .entity("vfModuleId in URL does not match content") + .build(); + } + + DeleteVfModuleTask task = new DeleteVfModuleTask(req, mode); + if (req.isSynchronous()) { + // This is a synchronous request + task.run(); + return Response + .status(task.getStatusCode()) + .entity(task.getGenericEntityResponse()) + .build(); + } else { + // This is an asynchronous request + try { + Thread t1 = new Thread(task); + t1.start(); + } catch (Exception e) { + // problem handling delete, send generic failure as sync resp to caller + LOGGER.error (MessageEnum.RA_DELETE_VNF_ERR, "", "deleteVfModule", MsoLogger.ErrorCode.BusinessProcesssError, "Exception in deleteVfModule", e); + return Response.serverError().build(); + } + // send sync response (ACK) to caller + LOGGER.debug ("deleteVNFVolumes exit"); + return Response.status(HttpStatus.SC_ACCEPTED).build(); + } + } + + public class DeleteVfModuleTask implements Runnable { + private final DeleteVfModuleRequest req; + private DeleteVfModuleResponse response = null; + private VfModuleExceptionResponse eresp = null; + private boolean sendxml; + private String mode; + + public DeleteVfModuleTask(DeleteVfModuleRequest req, String mode) { + this.req = req; + this.sendxml = true; // can be set with a field or header later + this.mode = mode; + } + public int getStatusCode() { + return (response != null) ? HttpStatus.SC_OK : HttpStatus.SC_BAD_REQUEST; + } + public Object getGenericEntityResponse() { + return (response != null) + ? new GenericEntity(response) {} + : new GenericEntity(eresp) {}; + } + private String getResponse() { + if (response != null) { + return sendxml ? response.toXmlString() : response.toJsonString(); + } else { + return sendxml ? eresp.toXmlString() : eresp.toJsonString(); + } + } + + @Override + public void run() { + try { + String cloudsite = req.getCloudSiteId(); + Holder> outputs = new Holder > (); + if (cloudsite != null && !cloudsite.equals(TESTING_KEYWORD)) { + //vnfAdapter.deleteVnf (req.getCloudSiteId(), req.getTenantId(), req.getVfModuleStackId(), req.getMsoRequest()); + // Support different Adapter Implementations + MsoVnfAdapter adapter = vnfAdapterRestUtils.getVnfAdapterImpl(mode, cloudsite); + adapter.deleteVfModule (req.getCloudSiteId(), req.getTenantId(), req.getVfModuleStackId(), req.getMsoRequest(), outputs); + } + response = new DeleteVfModuleResponse(req.getVnfId(), req.getVfModuleId(), Boolean.TRUE, req.getMessageId(), outputs.value); + } catch (VnfException e) { + LOGGER.error (MessageEnum.RA_DELETE_VNF_ERR, "", "", MsoLogger.ErrorCode.BusinessProcesssError, "VnfException - Delete VNF Module", e); + eresp = new VfModuleExceptionResponse(e.getMessage(), MsoExceptionCategory.INTERNAL, Boolean.TRUE, req.getMessageId()); + } + if (!req.isSynchronous()) { + BpelRestClient bpelClient = bpelRestClientProvider.get(); + bpelClient.bpelPost(getResponse(), req.getNotificationUrl(), sendxml); + } + LOGGER.debug ("Delete vfModule exit: code=" + getStatusCode() + ", resp="+ getResponse()); + } + } + + /* + * URL:http://localhost:8080/vnfs/rest/v2/vnfs//vf-modules/?cloudSiteId=DAN&tenantId=vfModule?&skipAAI=TRUE&msoRequest.requestId=ra1&msoRequest.serviceInstanceId=si1&vfModuleName=T2N2S1 + * RESP: + * {"queryVfModuleResponse": { + "vfModuleId": "AvfmodId", + "vfModuleOutputs": {"entry": { + "key": "server_private_ip_1", + "value": "10.100.1.25" + }}, + "vfModuleStackId": "RaaVnf1/abfa8a6d-feb1-40af-aea3-109403b1cf6b", + "vnfId": "AvnfID", + "vnfStatus": "ACTIVE" + }} + */ + @GET + @Path("{aaiVnfId}/vf-modules/{aaiVfModuleId}") + @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @ApiOperation(value = "QueryVfModule", + response = Response.class, + notes = "Query an existing vnfModule") + @ApiResponses({ + @ApiResponse(code = 200, message = "vnfModule has been successfully queried"), + @ApiResponse(code = 500, message = "query vnfModule failed, examine entity object for details") }) + public Response queryVfModule( + @ApiParam(value = "aaiVnfId", required = true) + @PathParam("aaiVnfId") String aaiVnfId, + @ApiParam(value = "aaiVfModuleId", required = true) + @PathParam("aaiVfModuleId") String aaiVfModuleId, + @ApiParam(value = "cloudSiteId", required = true) + @QueryParam("cloudSiteId") String cloudSiteId, + @ApiParam(value = "tenantId", required = true) + @QueryParam("tenantId") String tenantId, + @ApiParam(value = "vfModuleName", required = true) + @QueryParam("vfModuleName") String vfModuleName, //RAA? Id in doc + @ApiParam(value = "skipAAI", required = true) + @QueryParam("skipAAI") Boolean skipAAI, + @ApiParam(value = "msoRequest.requestId", required = true) + @QueryParam("msoRequest.requestId") String requestId, + @ApiParam(value = "msoRequest.serviceInstanceId", required = true) + @QueryParam("msoRequest.serviceInstanceId") String serviceInstanceId, + @ApiParam(value = "mode", required = true) + @QueryParam("mode") String mode) + { + //This request responds synchronously only + LOGGER.debug ("Query vfModule enter:" + vfModuleName); + MsoRequest msoRequest = new MsoRequest(requestId, serviceInstanceId); + + try { + int respStatus = HttpStatus.SC_OK; + QueryVfModuleResponse qryResp = new QueryVfModuleResponse(aaiVnfId, aaiVfModuleId, null, null, null); + Holder vnfExists = new Holder(); + Holder vfModuleId = new Holder(); + Holder status = new Holder(); + Holder> outputs = new Holder > (); + + // Support different Adapter Implementations + MsoVnfAdapter adapter = vnfAdapterRestUtils.getVnfAdapterImpl(mode, cloudSiteId); + adapter.queryVnf (cloudSiteId, tenantId, vfModuleName, msoRequest, vnfExists, vfModuleId, status, outputs); + + if (!vnfExists.value) { + LOGGER.debug ("vfModule not found"); + respStatus = HttpStatus.SC_NOT_FOUND; + } else { + LOGGER.debug ("vfModule found" + vfModuleId.value + ", status=" + status.value); + qryResp.setVfModuleId(vfModuleId.value); + qryResp.setVnfStatus(status.value); + qryResp.setVfModuleOutputs(outputs.value); + } + LOGGER.debug ("Query vfModule exit"); + return Response + .status(respStatus) + .entity(new GenericEntity(qryResp) {}) + .build(); + } catch (VnfException e) { + LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vfModuleName, "", "queryVfModule", MsoLogger.ErrorCode.BusinessProcesssError, "VnfException - queryVfModule", e); + VfModuleExceptionResponse excResp = new VfModuleExceptionResponse(e.getMessage(), MsoExceptionCategory.INTERNAL, Boolean.FALSE, null); + return Response + .status(HttpStatus.SC_INTERNAL_SERVER_ERROR) + .entity(new GenericEntity(excResp) {}) + .build(); + } + } + + /*URL: http://localhost:8080/vnfs/rest/v2/vnfs//vf-modules + *REQUEST: + * {"createVfModuleRequest": + {"cloudSiteId": "DAN", + "tenantId": "214b428a1f554c02935e66330f6a5409", + "vnfId": "somevnfid", + "vfModuleId": "somemodid", + "vfModuleName": "RaaVnf1", + "vnfType": "ApacheVnf", + "vfModuleParams": {"entry": [ + {"key": "network_id", + "value": "59ed7b41-2983-413f-ba93-e7d437433916"}, + {"key": "subnet_id", + "value": "086c9298-5c57-49b7-bb2b-6fd5730c5d92"}, + {"key": "server_name_0", + "value": "RaaVnf1"} + ]}, + "failIfExists": true, + "messageId": "ra.1", + "notificationUrl": "http://localhost:8089/vnfmock", + "skipAAI": true, + "msoRequest": { + "requestId": "ra1", + "serviceInstanceId": "sa1" + }} + } + */ + @POST + @Path("{aaiVnfId}/vf-modules") + @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @ApiOperation(value = "CreateVfModule", + response = Response.class, + notes = "Create a vnfModule") + @ApiResponses({ + @ApiResponse(code = 200, message = "vnfModule has been successfully created"), + @ApiResponse(code = 202, message = "create vnfModule request has been successfully accepted (async only)"), + @ApiResponse(code = 500, message = "create vnfModule failed, examine entity object for details") }) + public Response createVfModule( + @ApiParam(value = "aaiVnfId", required = true) + @PathParam("aaiVnfId") String aaiVnfId, + @ApiParam(value = "mode", required = true) + @QueryParam("mode") String mode, + @ApiParam(value = "CreateVfModuleRequest", required = true) + final CreateVfModuleRequest req) + { + LOGGER.debug("Create VfModule enter inside VnfAdapterRest: " + req.toJsonString()); + if (aaiVnfId == null || !aaiVnfId.equals(req.getVnfId())) { + LOGGER.debug("Req rejected - aaiVnfId not provided or doesn't match URL"); + return Response + .status(HttpStatus.SC_BAD_REQUEST) + .type(MediaType.TEXT_PLAIN) + .entity("vnfid in URL does not match content") + .build(); + } + + CreateVfModuleTask task = new CreateVfModuleTask(req, mode); + if (req.isSynchronous()) { + // This is a synchronous request + task.run(); + return Response + .status(task.getStatusCode()) + .entity(task.getGenericEntityResponse()) + .build(); + } else { + // This is an asynchronous request + try { + Thread t1 = new Thread(task); + t1.start(); + } catch (Exception e) { + // problem handling create, send generic failure as sync resp to caller + LOGGER.error (MessageEnum.RA_CREATE_VNF_ERR, "", "createVfModule", MsoLogger.ErrorCode.BusinessProcesssError, "Exception - createVfModule", e); + return Response.serverError().build(); + } + // send sync response (ACK) to caller + LOGGER.debug ("createVfModule exit"); + return Response.status(HttpStatus.SC_ACCEPTED).build(); + } + } + + public class CreateVfModuleTask implements Runnable { + private final CreateVfModuleRequest req; + private CreateVfModuleResponse response = null; + private VfModuleExceptionResponse eresp = null; + private boolean sendxml; + private String mode; + + public CreateVfModuleTask(CreateVfModuleRequest req, String mode) { + this.req = req; + this.sendxml = true; // can be set with a field or header later + this.mode = mode; + } + public int getStatusCode() { + return (response != null) ? HttpStatus.SC_OK : HttpStatus.SC_BAD_REQUEST; + } + public Object getGenericEntityResponse() { + return (response != null) + ? new GenericEntity(response) {} + : new GenericEntity(eresp) {}; + } + private String getResponse() { + if (response != null) { + return sendxml ? response.toXmlString() : response.toJsonString(); + } else { + return sendxml ? eresp.toXmlString() : eresp.toJsonString(); + } + } + + @Override + public void run() { + LOGGER.debug ("CreateVfModuleTask start"); + try { + // Synchronous Web Service Outputs + Holder vfModuleStackId = new Holder (); + Holder > outputs = new Holder > (); + Holder vnfRollback = new Holder (); + String completeVnfVfModuleType = req.getVnfType() + "::" + req.getVfModuleType(); + LOGGER.debug("completeVnfVfModuleType=" + completeVnfVfModuleType); + + String cloudsiteId = req.getCloudSiteId(); + if (cloudsiteId != null && cloudsiteId.equals(TESTING_KEYWORD)) { + String tenant = req.getTenantId(); + if (tenant != null && tenant.equals(TESTING_KEYWORD)) { + throw new VnfException("testing."); + } + vnfRollback.value = new VnfRollback(req.getVnfId(), tenant, cloudsiteId, + true, false, new MsoRequest("reqid", "svcid"), + req.getVolumeGroupId(), req.getVolumeGroupId(), req.getRequestType(), req.getModelCustomizationUuid()); + vfModuleStackId.value = "479D3D8B-6360-47BC-AB75-21CC91981484"; + outputs.value = VolumeAdapterRest.testMap(); + } else { + // Support different Adapter Implementations + MsoVnfAdapter adapter = vnfAdapterRestUtils.getVnfAdapterImpl(mode, cloudsiteId); + adapter.createVfModule(req.getCloudSiteId(), + req.getTenantId(), + completeVnfVfModuleType, + req.getVnfVersion(), + req.getVfModuleName(), + req.getRequestType(), + req.getVolumeGroupStackId(), + req.getBaseVfModuleStackId(), + req.getModelCustomizationUuid(), + req.getVfModuleParams(), + req.getFailIfExists(), + req.getBackout(), + req.getEnableBridge(), + req.getMsoRequest(), + vfModuleStackId, + outputs, + vnfRollback); + } + VfModuleRollback modRollback = new VfModuleRollback(vnfRollback.value, req.getVfModuleId(), vfModuleStackId.value, req.getMessageId()); + response = new CreateVfModuleResponse(req.getVnfId(), req.getVfModuleId(), + vfModuleStackId.value, Boolean.TRUE, outputs.value, modRollback, req.getMessageId()); + } catch (VnfException e) { + eresp = new VfModuleExceptionResponse(e.getMessage(), MsoExceptionCategory.INTERNAL, Boolean.TRUE, req.getMessageId()); + } + if (!req.isSynchronous()) { + BpelRestClient bpelClient = bpelRestClientProvider.get(); + bpelClient.bpelPost(getResponse(), req.getNotificationUrl(), sendxml); + } + LOGGER.debug ("CreateVfModuleTask exit: code=" + getStatusCode() + ", resp="+ getResponse()); + } + } + + @PUT + @Path("{aaiVnfId}/vf-modules/{aaiVfModuleId}") + @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @ApiOperation(value = "UpdateVfModule", + response = Response.class, + notes = "Update an existing vnfModule") + @ApiResponses({ + @ApiResponse(code = 200, message = "vnfModule has been successfully updated"), + @ApiResponse(code = 202, message = "update vnfModule request has been successfully accepted (async only)"), + @ApiResponse(code = 500, message = "update vnfModule failed, examine entity object for details") }) + public Response updateVfModule( + @ApiParam(value = "aaiVnfId", required = true) + @PathParam("aaiVnfId") String aaiVnfId, + @ApiParam(value = "aaiVfModuleId", required = true) + @PathParam("aaiVfModuleId") String aaiVfModuleId, + @ApiParam(value = "mode", required = true) + @QueryParam("mode") String mode, + @ApiParam(value = "UpdateVfModuleRequest", required = true) + final UpdateVfModuleRequest req) + { + LOGGER.debug("Update VfModule enter: " + req.toJsonString()); + UpdateVfModulesTask task = new UpdateVfModulesTask(req, mode); + if (req.isSynchronous()) { + // This is a synchronous request + task.run(); + return Response + .status(task.getStatusCode()) + .entity(task.getGenericEntityResponse()) + .build(); + } else { + // This is an asynchronous request + try { + Thread t1 = new Thread(task); + t1.start(); + } catch (Exception e) { + // problem handling create, send generic failure as sync resp to caller + LOGGER.error (MessageEnum.RA_UPDATE_VNF_ERR, "", "updateVfModule", MsoLogger.ErrorCode.BusinessProcesssError, "Exception - updateVfModule", e); + return Response.serverError().build(); + } + // send sync response (ACK) to caller + LOGGER.debug ("updateVfModules exit"); + return Response.status(HttpStatus.SC_ACCEPTED).build(); + } + } + + public class UpdateVfModulesTask implements Runnable { + private final UpdateVfModuleRequest req; + private UpdateVfModuleResponse response = null; + private VfModuleExceptionResponse eresp = null; + private boolean sendxml; + private String mode; + + public UpdateVfModulesTask(UpdateVfModuleRequest req, String mode) { + this.req = req; + this.sendxml = true; // can be set with a field or header later + this.mode = mode; + } + public int getStatusCode() { + return (response != null) ? HttpStatus.SC_OK : HttpStatus.SC_BAD_REQUEST; + } + public Object getGenericEntityResponse() { + return (response != null) + ? new GenericEntity(response) {} + : new GenericEntity(eresp) {}; + } + private String getResponse() { + if (response != null) { + return sendxml ? response.toXmlString() : response.toJsonString(); + } else { + return sendxml ? eresp.toXmlString() : eresp.toJsonString(); + } + } + @Override + public void run() { + try { + //MsoVnfAdapter vnfAdapter = new MsoVnfAdapterImpl (msoPropertiesFactory, cloudConfigFactory); + + // Synchronous Web Service Outputs + Holder vfModuleStackId = new Holder (); + Holder > outputs = new Holder > (); + Holder vnfRollback = new Holder (); + String completeVnfVfModuleType = req.getVnfType() + "::" + req.getVfModuleType(); + LOGGER.debug("in updateVf - completeVnfVfModuleType=" + completeVnfVfModuleType); + + String cloudsiteId = req.getCloudSiteId(); + + // Support different Adapter Implementations + MsoVnfAdapter adapter = vnfAdapterRestUtils.getVnfAdapterImpl(mode, cloudsiteId); + adapter.updateVfModule (req.getCloudSiteId(), + req.getTenantId(), + completeVnfVfModuleType, + req.getVnfVersion(), + req.getVfModuleName(), + req.getRequestType(), + req.getVolumeGroupStackId(), + req.getBaseVfModuleId(), + req.getVfModuleStackId(), + req.getModelCustomizationUuid(), + req.getVfModuleParams(), + req.getMsoRequest(), + outputs, + vnfRollback); + + response = new UpdateVfModuleResponse(req.getVnfId(), req.getVfModuleId(), + vfModuleStackId.value, outputs.value, req.getMessageId()); + } catch (VnfException e) { + eresp = new VfModuleExceptionResponse(e.getMessage(), MsoExceptionCategory.INTERNAL, Boolean.TRUE, req.getMessageId()); + } + if (!req.isSynchronous()) { + // This is asynch, so POST response back to caller + BpelRestClient bpelClient = bpelRestClientProvider.get(); + bpelClient.bpelPost (getResponse(), req.getNotificationUrl(), sendxml); + } + LOGGER.debug ("Update VfModule exit: code=" + getStatusCode() + ", resp="+ getResponse()); + } + } + /* + * URL:http://localhost:8080/vnfs/rest/v2/vnfs//vf-modules//rollback + * REQUEST: + * {"deleteVfModuleRequest": + {"cloudSiteId": "DAN", + "tenantId": "214b428a1f554c02935e66330f6a5409", + "vnfId": "somevnfid", + "vfModuleId": "somemodid", + "vfModuleStackId": "4e567676-e266-4594-a3a6-131c8a2baf73", + "messageId": "ra.1", + "notificationUrl": "http://localhost:8089/vnfmock", + "skipAAI": true, + "msoRequest": { + "requestId": "ra1", + "serviceInstanceId": "sa1" + }} + } + */ + @DELETE + @Path("{aaiVnfId}/vf-modules/{aaiVfModuleId}/rollback") + @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @ApiOperation(value = "RollbackVfModule", + response = Response.class, + notes = "Rollback an existing vnfModule") + @ApiResponses({ + @ApiResponse(code = 200, message = "vnfModule has been successfully rolled back"), + @ApiResponse(code = 202, message = "rollback vnfModule request has been successfully accepted (async only)"), + @ApiResponse(code = 500, message = "rollback vnfModule failed, examine entity object for details") }) + public Response rollbackVfModule ( + @ApiParam(value = "aaiVnfId", required = true) + @PathParam("aaiVnfId") String aaiVnfId, + @ApiParam(value = "aaiVfModuleId", required = true) + @PathParam("aaiVfModuleId") String aaiVfModuleId, + @ApiParam(value = "RollbackVfModuleRequest", required = true) + //@QueryParam("rollback") String rollback, + final RollbackVfModuleRequest req) + { + LOGGER.debug("Rollback VfModule enter: " + req.toJsonString()); + RollbackVfModulesTask task = new RollbackVfModulesTask(req); + if (req.isSynchronous()) { + // This is a synchronous request + task.run(); + return Response + .status(task.getStatusCode()) + .entity(task.getGenericEntityResponse()) + .build(); + } else { + // This is an asynchronous request + try { + Thread t1 = new Thread(task); + t1.start(); + } catch (Exception e) { + // problem handling create, send generic failure as sync resp to caller + LOGGER.error (MessageEnum.RA_ROLLBACK_VNF_ERR, "", "rollbackVfModule", MsoLogger.ErrorCode.BusinessProcesssError, "Exception - rollbackVfModule", e); + return Response.serverError().build(); + } + // send sync response (ACK) to caller + LOGGER.debug ("rollbackVfModule exit"); + return Response.status(HttpStatus.SC_ACCEPTED).build(); + } + } + + public class RollbackVfModulesTask implements Runnable { + private final RollbackVfModuleRequest req; + private RollbackVfModuleResponse response = null; + private VfModuleExceptionResponse eresp = null; + private boolean sendxml; + + public RollbackVfModulesTask(RollbackVfModuleRequest req) { + this.req = req; + this.sendxml = true; // can be set with a field or header later + } + public int getStatusCode() { + return (response != null) ? HttpStatus.SC_OK : HttpStatus.SC_BAD_REQUEST; + } + public Object getGenericEntityResponse() { + return (response != null) + ? new GenericEntity(response) {} + : new GenericEntity(eresp) {}; + } + private String getResponse() { + if (response != null) { + return sendxml ? response.toXmlString() : response.toJsonString(); + } else { + return sendxml ? eresp.toXmlString() : eresp.toJsonString(); + } + } + @Override + public void run() { + try { + VfModuleRollback vmr = req.getVfModuleRollback(); + VnfRollback vrb = new VnfRollback( + vmr.getVfModuleStackId(), vmr.getTenantId(), vmr.getCloudSiteId(), true, vmr.isVfModuleCreated(), + vmr.getMsoRequest(), null, null, null, null); + + // Support multiple adapter implementations + MsoVnfAdapter adapter = vnfAdapterRestUtils.getVnfAdapterImpl (vmr.getMode(), vmr.getCloudSiteId()); + adapter.rollbackVnf (vrb); + + response = new RollbackVfModuleResponse(Boolean.TRUE, req.getMessageId()); + } catch (VnfException e) { + LOGGER.error (MessageEnum.RA_ROLLBACK_VNF_ERR, "", "", MsoLogger.ErrorCode.BusinessProcesssError, "Exception - rollbackVfModule", e); + eresp = new VfModuleExceptionResponse(e.getMessage(), MsoExceptionCategory.INTERNAL, false, req.getMessageId()); + } + if (!req.isSynchronous()) { + // This is asynch, so POST response back to caller + BpelRestClient bpelClient = bpelRestClientProvider.get(); + bpelClient.bpelPost (getResponse(), req.getNotificationUrl(), sendxml); + } + LOGGER.debug ("RollbackVfModulesTask exit: code=" + getStatusCode() + ", resp="+ getResponse()); + } + } +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/VolumeAdapterRest.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/VolumeAdapterRest.java new file mode 100644 index 0000000000..b4b5894491 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/VolumeAdapterRest.java @@ -0,0 +1,646 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * Copyright (C) 2017 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.so.adapters.vnf; + + +import java.util.HashMap; +import java.util.Map; + +import javax.inject.Provider; +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.GenericEntity; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.xml.ws.Holder; + +import org.apache.http.HttpStatus; +import org.onap.so.adapters.vnf.exceptions.VnfException; +import org.onap.so.adapters.vnfrest.CreateVolumeGroupRequest; +import org.onap.so.adapters.vnfrest.CreateVolumeGroupResponse; +import org.onap.so.adapters.vnfrest.DeleteVolumeGroupRequest; +import org.onap.so.adapters.vnfrest.DeleteVolumeGroupResponse; +import org.onap.so.adapters.vnfrest.QueryVolumeGroupResponse; +import org.onap.so.adapters.vnfrest.RollbackVolumeGroupRequest; +import org.onap.so.adapters.vnfrest.RollbackVolumeGroupResponse; +import org.onap.so.adapters.vnfrest.UpdateVolumeGroupRequest; +import org.onap.so.adapters.vnfrest.UpdateVolumeGroupResponse; +import org.onap.so.adapters.vnfrest.VolumeGroupExceptionResponse; +import org.onap.so.adapters.vnfrest.VolumeGroupRollback; +import org.onap.so.entity.MsoRequest; +import org.onap.so.logger.MessageEnum; +import org.onap.so.logger.MsoLogger; +import org.onap.so.openstack.beans.VnfRollback; +import org.onap.so.openstack.beans.VnfStatus; +import org.onap.so.openstack.exceptions.MsoExceptionCategory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Component; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import io.swagger.annotations.ApiResponse; +import io.swagger.annotations.ApiResponses; + +/** + * This class services calls to the REST interface for VNF Volumes (http://host:port/vnfs/rest/v1/volume-groups) + * Both XML and JSON can be produced/consumed. Set Accept: and Content-Type: headers appropriately. XML is the default. + * For testing, call with cloudSiteId = ___TESTING___ + * To test exceptions, also set tenantId = ___TESTING___ + */ +@Path("/v1/volume-groups") +@Api(value = "/v1/volume-groups", description = "root of volume-groups adapters restful web service") +@Component +public class VolumeAdapterRest { + private static final MsoLogger LOGGER = MsoLogger.getMsoLogger(MsoLogger.Catalog.RA, VolumeAdapterRest.class); + private static final String TESTING_KEYWORD = "___TESTING___"; + + @Autowired + private MsoVnfAdapterImpl vnfAdapter; + + @Autowired + @Qualifier("VnfBpel") + private Provider bpelRestClientProvider; + + @POST + @Path("") + @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @ApiOperation(value = "CreateVNFVolumes", + response = Response.class, + notes = "Create a new vnfVolume") + @ApiResponses({ + @ApiResponse(code = 200, message = "vnfVolume has been successfully created"), + @ApiResponse(code = 202, message = "create vnfVolume request has been successfully accepted (async only)"), + @ApiResponse(code = 500, message = "create vnfVolume failed, examine entity object for details") }) + public Response createVNFVolumes( + @ApiParam(value = "CreateVolumeGroupRequest", required = true) + final CreateVolumeGroupRequest req + ) { + LOGGER.debug("createVNFVolumes enter: " + req.toJsonString()); + CreateVNFVolumesTask task = new CreateVNFVolumesTask(req); + if (req.isSynchronous()) { + // This is a synchronous request + task.run(); + return Response + .status(task.getStatusCode()) + .entity(task.getGenericEntityResponse()) + .build(); + } else { + // This is an asynchronous request + try { + Thread t1 = new Thread(task); + t1.start(); + } catch (Exception e) { + // problem handling create, send generic failure as sync resp to caller + LOGGER.error (MessageEnum.RA_CREATE_VNF_ERR, "", "createVNFVolumes", MsoLogger.ErrorCode.BusinessProcesssError, "Exception - createVNFVolumes", e); + return Response.serverError().build(); + } + // send sync response (ACK) to caller + LOGGER.debug ("createVNFVolumes exit"); + return Response.status(HttpStatus.SC_ACCEPTED).build(); + } + } + + public class CreateVNFVolumesTask implements Runnable { + private final CreateVolumeGroupRequest req; + private CreateVolumeGroupResponse response = null; + private VolumeGroupExceptionResponse eresp = null; + private boolean sendxml; + + public CreateVNFVolumesTask(CreateVolumeGroupRequest req) { + this.req = req; + this.sendxml = true; // can be set with a field or header later + } + public int getStatusCode() { + return (response != null) ? HttpStatus.SC_OK : HttpStatus.SC_BAD_REQUEST; + } + public Object getGenericEntityResponse() { + return (response != null) + ? new GenericEntity(response) {} + : new GenericEntity(eresp) {}; + } + private String getResponse() { + if (response != null) { + return sendxml ? response.toXmlString() : response.toJsonString(); + } else { + return sendxml ? eresp.toXmlString() : eresp.toJsonString(); + } + } + @Override + public void run() { + LOGGER.debug ("CreateVFModule VolumesTask start"); + try { + // Synchronous Web Service Outputs + Holder stackId = new Holder<>(); + Holder> outputs = new Holder<>(); + Holder vnfRollback = new Holder<>(); + String completeVnfVfModuleType = req.getVnfType() + "::" + req.getVfModuleType(); + LOGGER.debug("in createVfModuleVolumes - completeVnfVfModuleType=" + completeVnfVfModuleType); + + String cloudsite = req.getCloudSiteId(); + if (cloudsite != null && cloudsite.equals(TESTING_KEYWORD)) { + String tenant = req.getTenantId(); + if (tenant != null && tenant.equals(TESTING_KEYWORD)) { + throw new VnfException("testing."); + } + stackId.value = "479D3D8B-6360-47BC-AB75-21CC91981484"; + outputs.value = testMap(); + } else { +// vnfAdapter.createVnf( +// req.getCloudSiteId(), +// req.getTenantId(), +// req.getVnfType(), +// req.getVnfVersion(), +// req.getVolumeGroupName(), +// "VOLUME", // request type is VOLUME +// null, // not sure about this +// req.getVolumeGroupParams(), +// req.getFailIfExists(), +// req.getSuppressBackout(), +// req.getMsoRequest(), +// stackId, +// outputs, +// vnfRollback); + vnfAdapter.createVfModule( + req.getCloudSiteId(), //cloudSiteId, + req.getTenantId(), //tenantId, + //req.getVnfType(), //vnfType, + completeVnfVfModuleType, + req.getVnfVersion(), //vnfVersion, + req.getVolumeGroupName(), //vnfName, + "VOLUME", //requestType, + null, //volumeGroupHeatStackId, + null, //baseVfHeatStackId, + req.getModelCustomizationUuid(), + req.getVolumeGroupParams(), //inputs, + req.getFailIfExists(), //failIfExists, + req.getSuppressBackout(), //backout, + req.getEnableBridge(), + req.getMsoRequest(), // msoRequest, + stackId, + outputs, + vnfRollback); + } + VolumeGroupRollback rb = new VolumeGroupRollback( + req.getVolumeGroupId(), + stackId.value, + true, // TODO boolean volumeGroupCreated, when would it be false? + req.getTenantId(), + req.getCloudSiteId(), + req.getMsoRequest(), + req.getMessageId()); + response = new CreateVolumeGroupResponse( + req.getVolumeGroupId(), + stackId.value, + true, // TODO boolean volumeGroupCreated, when would it be false? + outputs.value, + rb, + req.getMessageId()); + } catch (VnfException e) { + LOGGER.debug("Exception :",e); + eresp = new VolumeGroupExceptionResponse( + e.getMessage(), MsoExceptionCategory.INTERNAL, true, req.getMessageId()); + } + if (!req.isSynchronous()) { + // This is asynch, so POST response back to caller + BpelRestClient bpelClient = bpelRestClientProvider.get(); + bpelClient.bpelPost(getResponse(), req.getNotificationUrl(), sendxml); + } + LOGGER.debug ("CreateVFModule VolumesTask exit: code=" + getStatusCode() + ", resp="+ getResponse()); + } + } + + @DELETE + @Path("{aaiVolumeGroupId}") + @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @ApiOperation(value = "DeleteVNFVolumes", + response = Response.class, + notes = "Delete an existing vnfVolume") + @ApiResponses({ + @ApiResponse(code = 200, message = "vnfVolume has been successfully deleted"), + @ApiResponse(code = 202, message = "delete vnfVolume request has been successfully accepted (async only)"), + @ApiResponse(code = 500, message = "delete vnfVolume failed, examine entity object for details") }) + public Response deleteVNFVolumes( + @ApiParam(value = "aaiVolumeGroupId", required = true) + @PathParam("aaiVolumeGroupId") String aaiVolumeGroupId, + @ApiParam(value = "DeleteVolumeGroupRequest", required = true) + final DeleteVolumeGroupRequest req + ) + { + LOGGER.debug("deleteVNFVolumes enter: " + req.toJsonString()); + if (aaiVolumeGroupId == null || !aaiVolumeGroupId.equals(req.getVolumeGroupId())) { + return Response + .status(HttpStatus.SC_BAD_REQUEST) + .type(MediaType.TEXT_PLAIN) + .entity("VolumeGroupId in URL does not match content") + .build(); + } + DeleteVNFVolumesTask task = new DeleteVNFVolumesTask(req); + if (req.isSynchronous()) { + // This is a synchronous request + task.run(); + return Response + .status(task.getStatusCode()) + .entity(task.getGenericEntityResponse()) + .build(); + } else { + // This is an asynchronous request + try { + Thread t1 = new Thread(task); + t1.start(); + } catch (Exception e) { + // problem handling create, send generic failure as sync resp to caller + LOGGER.error (MessageEnum.RA_DELETE_VNF_ERR, "", "deleteVNFVolumes", MsoLogger.ErrorCode.BusinessProcesssError, "Exception - deleteVNFVolumes", e); + return Response.serverError().build(); + } + // send sync response (ACK) to caller + LOGGER.debug ("deleteVNFVolumes exit"); + return Response.status(HttpStatus.SC_ACCEPTED).build(); + } + } + + public class DeleteVNFVolumesTask implements Runnable { + private final DeleteVolumeGroupRequest req; + private DeleteVolumeGroupResponse response = null; + private VolumeGroupExceptionResponse eresp = null; + private boolean sendxml; + + public DeleteVNFVolumesTask(DeleteVolumeGroupRequest req) { + this.req = req; + this.sendxml = true; // can be set with a field or header later + } + public int getStatusCode() { + return (response != null) ? HttpStatus.SC_OK : HttpStatus.SC_BAD_REQUEST; + } + public Object getGenericEntityResponse() { + return (response != null) + ? new GenericEntity(response) {} + : new GenericEntity(eresp) {}; + } + private String getResponse() { + if (response != null) { + return sendxml ? response.toXmlString() : response.toJsonString(); + } else { + return sendxml ? eresp.toXmlString() : eresp.toJsonString(); + } + } + @Override + public void run() { + LOGGER.debug("DeleteVNFVolumesTask start"); + try { + if (!req.getCloudSiteId().equals(TESTING_KEYWORD)) { + vnfAdapter.deleteVnf(req.getCloudSiteId(), req.getTenantId(), req.getVolumeGroupStackId(), req.getMsoRequest()); + } + response = new DeleteVolumeGroupResponse(true, req.getMessageId()); + } catch (VnfException e) { + LOGGER.debug("Exception :",e); + eresp = new VolumeGroupExceptionResponse(e.getMessage(), MsoExceptionCategory.INTERNAL, true, req.getMessageId()); + } + if (!req.isSynchronous()) { + // This is asynch, so POST response back to caller + BpelRestClient bpelClient = bpelRestClientProvider.get(); + bpelClient.bpelPost(getResponse(), req.getNotificationUrl(), sendxml); + } + LOGGER.debug("DeleteVNFVolumesTask exit: code=" + getStatusCode() + ", resp="+ getResponse()); + } + } + + @DELETE + @Path("{aaiVolumeGroupId}/rollback") + @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @ApiOperation(value = "RollbackVNFVolumes", + response = Response.class, + notes = "Delete an existing vnfVolume") + @ApiResponses({ + @ApiResponse(code = 200, message = "vnfVolume has been successfully rolled back"), + @ApiResponse(code = 202, message = "rollback vnfVolume request has been successfully accepted (async only)"), + @ApiResponse(code = 500, message = "rollback vnfVolume failed, examine entity object for details") }) + public Response rollbackVNFVolumes( + @ApiParam(value = "aaiVolumeGroupId", required = true) + @PathParam("aaiVolumeGroupId") String aaiVolumeGroupId, + @ApiParam(value = "RollbackVolumeGroupRequest", required = true) + final RollbackVolumeGroupRequest req + ) + { + LOGGER.debug("rollbackVNFVolumes enter: " + req.toJsonString()); + if (aaiVolumeGroupId == null || req.getVolumeGroupRollback() == null || !aaiVolumeGroupId.equals(req.getVolumeGroupRollback().getVolumeGroupId())) { + return Response + .status(HttpStatus.SC_BAD_REQUEST) + .type(MediaType.TEXT_PLAIN) + .entity("VolumeGroupId in URL does not match content") + .build(); + } + RollbackVNFVolumesTask task = new RollbackVNFVolumesTask(req); + if (req.isSynchronous()) { + // This is a synchronous request + task.run(); + return Response + .status(task.getStatusCode()) + .entity(task.getGenericEntityResponse()) + .build(); + } else { + // This is an asynchronous request + try { + Thread t1 = new Thread(task); + t1.start(); + } catch (Exception e) { + // problem handling create, send generic failure as sync resp to caller + LOGGER.error (MessageEnum.RA_ROLLBACK_VNF_ERR, "", "rollbackVNFVolumes", MsoLogger.ErrorCode.BusinessProcesssError, "Exception - rollbackVNFVolumes", e); + return Response.serverError().build(); + } + // send sync response (ACK) to caller + LOGGER.debug("rollbackVNFVolumes exit"); + return Response.status(HttpStatus.SC_ACCEPTED).build(); + } + } + + public class RollbackVNFVolumesTask implements Runnable { + private final RollbackVolumeGroupRequest req; + private RollbackVolumeGroupResponse response = null; + private VolumeGroupExceptionResponse eresp = null; + private boolean sendxml; + + public RollbackVNFVolumesTask(RollbackVolumeGroupRequest req) { + this.req = req; + this.sendxml = true; // can be set with a field or header later + } + public int getStatusCode() { + return (response != null) ? HttpStatus.SC_OK : HttpStatus.SC_BAD_REQUEST; + } + public Object getGenericEntityResponse() { + return (response != null) + ? new GenericEntity(response) {} + : new GenericEntity(eresp) {}; + } + private String getResponse() { + if (response != null) { + return sendxml ? response.toXmlString() : response.toJsonString(); + } else { + return sendxml ? eresp.toXmlString() : eresp.toJsonString(); + } + } + @Override + public void run() { + LOGGER.debug("DeleteVNFVolumesTask start"); + try { + VolumeGroupRollback vgr = req.getVolumeGroupRollback(); + VnfRollback vrb = new VnfRollback( + vgr.getVolumeGroupStackId(), vgr.getTenantId(), vgr.getCloudSiteId(), true, true, + vgr.getMsoRequest(), null, null, null, null); + vnfAdapter.rollbackVnf(vrb); + response = new RollbackVolumeGroupResponse(true, req.getMessageId()); + } catch (VnfException e) { + LOGGER.debug("Exception :",e); + eresp = new VolumeGroupExceptionResponse(e.getMessage(), MsoExceptionCategory.INTERNAL, true, req.getMessageId()); + } + if (!req.isSynchronous()) { + // This is asynch, so POST response back to caller + BpelRestClient bpelClient = bpelRestClientProvider.get(); + bpelClient.bpelPost(getResponse(), req.getNotificationUrl(), sendxml); + } + LOGGER.debug("DeleteVNFVolumesTask exit: code=" + getStatusCode() + ", resp="+ getResponse()); + } + + } + + @PUT + @Path("{aaiVolumeGroupId}") + @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @ApiOperation(value = "UpdateVNFVolumes", + response = Response.class, + notes = "Update an existing vnfVolume") + @ApiResponses({ + @ApiResponse(code = 200, message = "vnfVolume has been successfully updated"), + @ApiResponse(code = 202, message = "update vnfVolume request has been successfully accepted (async only)"), + @ApiResponse(code = 500, message = "update vnfVolume failed, examine entity object for details") }) + public Response updateVNFVolumes( + @ApiParam(value = "aaiVolumeGroupId", required = true) + @PathParam("aaiVolumeGroupId") String aaiVolumeGroupId, + @ApiParam(value = "UpdateVolumeGroupRequest", required = true) + final UpdateVolumeGroupRequest req + ) + { + LOGGER.debug("updateVNFVolumes enter: " + req.toJsonString()); + if (aaiVolumeGroupId == null || !aaiVolumeGroupId.equals(req.getVolumeGroupId())) { + return Response + .status(HttpStatus.SC_BAD_REQUEST) + .type(MediaType.TEXT_PLAIN) + .entity("VolumeGroupId in URL does not match content") + .build(); + } + UpdateVNFVolumesTask task = new UpdateVNFVolumesTask(req); + if (req.isSynchronous()) { + // This is a synchronous request + task.run(); + return Response + .status(task.getStatusCode()) + .entity(task.getGenericEntityResponse()) + .build(); + } else { + // This is an asynchronous request + try { + Thread t1 = new Thread(task); + t1.start(); + } catch (Exception e) { + // problem handling create, send generic failure as sync resp to caller + LOGGER.error (MessageEnum.RA_UPDATE_VNF_ERR, "", "updateVNFVolumes", MsoLogger.ErrorCode.BusinessProcesssError, "Exception - updateVNFVolumes", e); + return Response.serverError().build(); + } + // send sync response (ACK) to caller + LOGGER.debug ("updateVNFVolumes exit"); + return Response.status(HttpStatus.SC_ACCEPTED).build(); + } + } + + public class UpdateVNFVolumesTask implements Runnable { + private final UpdateVolumeGroupRequest req; + private UpdateVolumeGroupResponse response = null; + private VolumeGroupExceptionResponse eresp = null; + private boolean sendxml; + + public UpdateVNFVolumesTask(UpdateVolumeGroupRequest req) { + this.req = req; + this.sendxml = true; // can be set with a field or header later + } + public int getStatusCode() { + return (response != null) ? HttpStatus.SC_OK : HttpStatus.SC_BAD_REQUEST; + } + public Object getGenericEntityResponse() { + return (response != null) + ? new GenericEntity(response) {} + : new GenericEntity(eresp) {}; + } + private String getResponse() { + if (response != null) { + return sendxml ? response.toXmlString() : response.toJsonString(); + } else { + return sendxml ? eresp.toXmlString() : eresp.toJsonString(); + } + } + @Override + public void run() { + LOGGER.debug("UpdateVNFVolumesTask start"); + try { + Holder> outputs = new Holder<> (); + Holder vnfRollback = new Holder<> (); + String completeVnfVfModuleType = req.getVnfType() + "::" + req.getVfModuleType(); + LOGGER.debug("in updateVfModuleVolume - completeVnfVfModuleType=" + completeVnfVfModuleType); + + if (req.getCloudSiteId().equals(TESTING_KEYWORD)) { + outputs.value = testMap(); + } else { + //vnfAdapter.updateVnf( + // req.getCloudSiteId(), + // req.getTenantId(), + // req.getVnfType(), + // req.getVnfVersion(), + // req.getVfModuleType(), + // "VOLUME", // request type is VOLUME + // req.getVolumeGroupStackId(), + // req.getVolumeGroupParams(), + // req.getMsoRequest(), + // outputs, + // vnfRollback); + vnfAdapter.updateVfModule (req.getCloudSiteId(), + req.getTenantId(), + //req.getVnfType(), + completeVnfVfModuleType, + req.getVnfVersion(), + req.getVolumeGroupStackId(), + "VOLUME", + null, + null, + req.getVolumeGroupStackId(), + req.getModelCustomizationUuid(), + req.getVolumeGroupParams(), + req.getMsoRequest(), + outputs, + vnfRollback); + } + response = new UpdateVolumeGroupResponse( + req.getVolumeGroupId(), req.getVolumeGroupStackId(), + outputs.value, req.getMessageId()); + } catch (VnfException e) { + LOGGER.debug("Exception :",e); + eresp = new VolumeGroupExceptionResponse(e.getMessage(), MsoExceptionCategory.INTERNAL, true, req.getMessageId()); + } + if (!req.isSynchronous()) { + // This is asynch, so POST response back to caller + BpelRestClient bpelClient = bpelRestClientProvider.get(); + bpelClient.bpelPost(getResponse(), req.getNotificationUrl(), sendxml); + } + LOGGER.debug("UpdateVNFVolumesTask exit: code=" + getStatusCode() + ", resp="+ getResponse()); + } + } + + @GET + @Path("{aaiVolumeGroupId}") + @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @ApiOperation(value = "QueryVNFVolumes", + response = Response.class, + notes = "Query an existing vnfVolume") + @ApiResponses({ + @ApiResponse(code = 200, message = "vnfVolume has been successfully queried"), + @ApiResponse(code = 500, message = "query vnfVolume failed, examine entity object for details") }) + public Response queryVNFVolumes( + @ApiParam(value = "aaiVolumeGroupId", required = true) + @PathParam("aaiVolumeGroupId") String aaiVolumeGroupId, + @ApiParam(value = "cloudSiteId", required = true) + @QueryParam("cloudSiteId") String cloudSiteId, + @ApiParam(value = "tenantId", required = true) + @QueryParam("tenantId") String tenantId, + @ApiParam(value = "volumeGroupStackId", required = true) + @QueryParam("volumeGroupStackId") String volumeGroupStackId, + @ApiParam(value = "skipAAI", required = true) + @QueryParam("skipAAI") Boolean skipAAI, + @ApiParam(value = "msoRequest.requestId", required = true) + @QueryParam("msoRequest.requestId") String requestId, + @ApiParam(value = "msoRequest.serviceInstanceId", required = true) + @QueryParam("msoRequest.serviceInstanceId") String serviceInstanceId + ) + { + //This request responds synchronously only + LOGGER.debug ("queryVNFVolumes enter:" + aaiVolumeGroupId + " " + volumeGroupStackId); + MsoRequest msoRequest = new MsoRequest(requestId, serviceInstanceId); + + try { + int respStatus = HttpStatus.SC_OK; + QueryVolumeGroupResponse qryResp = new QueryVolumeGroupResponse(aaiVolumeGroupId, volumeGroupStackId, null, null); + Holder vnfExists = new Holder<>(); + Holder vfModuleId = new Holder<>(); + Holder status = new Holder<>(); + Holder> outputs = new Holder<>(); + if (cloudSiteId != null && cloudSiteId.equals(TESTING_KEYWORD)) { + if (tenantId != null && tenantId.equals(TESTING_KEYWORD)) { + throw new VnfException("testing."); + } + vnfExists.value = true; + vfModuleId.value = TESTING_KEYWORD; + status.value = VnfStatus.ACTIVE; + outputs.value = testMap(); + } else { + vnfAdapter.queryVnf(cloudSiteId, tenantId, volumeGroupStackId, msoRequest, vnfExists, vfModuleId, status, outputs); + } + if (!vnfExists.value) { + LOGGER.debug ("VNFVolumes not found"); + qryResp.setVolumeGroupStatus(status.value); + respStatus = HttpStatus.SC_NOT_FOUND; + } else { + LOGGER.debug ("VNFVolumes found " + vfModuleId.value + ", status=" + status.value); + qryResp.setVolumeGroupStatus(status.value); + qryResp.setVolumeGroupOutputs(outputs.value); + } + LOGGER.debug("Query queryVNFVolumes exit"); + return Response + .status(respStatus) + .entity(new GenericEntity(qryResp) {}) + .build(); + } catch (VnfException e) { + LOGGER.error(MessageEnum.RA_QUERY_VNF_ERR, aaiVolumeGroupId, "", "queryVNFVolumes", MsoLogger.ErrorCode.BusinessProcesssError, "VnfException - queryVNFVolumes", e); + VolumeGroupExceptionResponse excResp = new VolumeGroupExceptionResponse(e.getMessage(), MsoExceptionCategory.INTERNAL, Boolean.FALSE, null); + LOGGER.debug("Query queryVNFVolumes exit"); + return Response + .status(HttpStatus.SC_INTERNAL_SERVER_ERROR) + .entity(new GenericEntity(excResp) {}) + .build(); + } + } + public static Map testMap() { + Map m = new HashMap<>(); + m.put("mickey", "7"); + m.put("clyde", "10"); + m.put("wayne", "99"); + return m; + } +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/VolumeAdapterRestV2.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/VolumeAdapterRestV2.java new file mode 100644 index 0000000000..3f3a312e12 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/VolumeAdapterRestV2.java @@ -0,0 +1,648 @@ +/*- + * ============LICENSE_START======================================================= + * OPENECOMP - SO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.so.adapters.vnf; + + +import java.util.HashMap; +import java.util.Map; + +import javax.inject.Provider; +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.GenericEntity; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.xml.ws.Holder; + +import org.apache.http.HttpStatus; +import org.onap.so.adapters.vnf.exceptions.VnfException; +import org.onap.so.adapters.vnfrest.CreateVolumeGroupRequest; +import org.onap.so.adapters.vnfrest.CreateVolumeGroupResponse; +import org.onap.so.adapters.vnfrest.DeleteVolumeGroupRequest; +import org.onap.so.adapters.vnfrest.DeleteVolumeGroupResponse; +import org.onap.so.adapters.vnfrest.QueryVolumeGroupResponse; +import org.onap.so.adapters.vnfrest.RollbackVolumeGroupRequest; +import org.onap.so.adapters.vnfrest.RollbackVolumeGroupResponse; +import org.onap.so.adapters.vnfrest.UpdateVolumeGroupRequest; +import org.onap.so.adapters.vnfrest.UpdateVolumeGroupResponse; +import org.onap.so.adapters.vnfrest.VolumeGroupExceptionResponse; +import org.onap.so.adapters.vnfrest.VolumeGroupRollback; +import org.onap.so.entity.MsoRequest; +import org.onap.so.logger.MessageEnum; +import org.onap.so.logger.MsoLogger; +import org.onap.so.openstack.beans.VnfRollback; +import org.onap.so.openstack.beans.VnfStatus; +import org.onap.so.openstack.exceptions.MsoExceptionCategory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Component; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import io.swagger.annotations.ApiResponse; +import io.swagger.annotations.ApiResponses; + +/** + * This class services calls to the REST interface for VNF Volumes (http://host:port/vnfs/rest/v1/volume-groups) + * Both XML and JSON can be produced/consumed. Set Accept: and Content-Type: headers appropriately. XML is the default. + * For testing, call with cloudSiteId = ___TESTING___ + * To test exceptions, also set tenantId = ___TESTING___ + * + * V2 incorporates run-time selection of sub-orchestrator implementation (Heat or Cloudify) + * based on the target cloud. + */ +@Path("/v2/volume-groups") +@Api(value = "/v2/volume-groups", description = "root of volume-groups adapters restful web service v2") +@Component +public class VolumeAdapterRestV2 { + private static final MsoLogger LOGGER = MsoLogger.getMsoLogger(MsoLogger.Catalog.RA, VolumeAdapterRestV2.class); + private static final String TESTING_KEYWORD = "___TESTING___"; + + @Autowired + private VnfAdapterRestUtils vnfAdapterRestUtils; + + @Autowired + @Qualifier("VnfBpel") + private Provider bpelRestClientProvider; + + @POST + @Path("") + @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @ApiOperation(value = "CreateVNFVolumes", + response = Response.class, + notes = "Create a new vnfVolume") + @ApiResponses({ + @ApiResponse(code = 200, message = "vnfVolume has been successfully created"), + @ApiResponse(code = 202, message = "create vnfVolume request has been successfully accepted (async only)"), + @ApiResponse(code = 500, message = "create vnfVolume failed, examine entity object for details") }) + public Response createVNFVolumes( + @ApiParam(value = "mode", required = true) + @QueryParam("mode") String mode, + @ApiParam(value = "CreateVolumeGroupRequest", required = true) + final CreateVolumeGroupRequest req) + { + LOGGER.debug("createVNFVolumes enter: " + req.toJsonString()); + CreateVNFVolumesTask task = new CreateVNFVolumesTask(req, mode); + if (req.isSynchronous()) { + // This is a synchronous request + task.run(); + return Response + .status(task.getStatusCode()) + .entity(task.getGenericEntityResponse()) + .build(); + } else { + // This is an asynchronous request + try { + Thread t1 = new Thread(task); + t1.start(); + } catch (Exception e) { + // problem handling create, send generic failure as sync resp to caller + LOGGER.error (MessageEnum.RA_CREATE_VNF_ERR, "", "createVNFVolumes", MsoLogger.ErrorCode.BusinessProcesssError, "Exception - createVNFVolumes", e); + return Response.serverError().build(); + } + // send sync response (ACK) to caller + LOGGER.debug ("createVNFVolumes exit"); + return Response.status(HttpStatus.SC_ACCEPTED).build(); + } + } + + public class CreateVNFVolumesTask implements Runnable { + private final CreateVolumeGroupRequest req; + private CreateVolumeGroupResponse response = null; + private VolumeGroupExceptionResponse eresp = null; + private boolean sendxml; + private String mode; + + public CreateVNFVolumesTask(CreateVolumeGroupRequest req, String mode) { + this.req = req; + this.sendxml = true; // can be set with a field or header later + this.mode = mode; + } + public int getStatusCode() { + return (response != null) ? HttpStatus.SC_OK : HttpStatus.SC_BAD_REQUEST; + } + public Object getGenericEntityResponse() { + return (response != null) + ? new GenericEntity(response) {} + : new GenericEntity(eresp) {}; + } + private String getResponse() { + if (response != null) { + return sendxml ? response.toXmlString() : response.toJsonString(); + } else { + return sendxml ? eresp.toXmlString() : eresp.toJsonString(); + } + } + @Override + public void run() { + LOGGER.debug ("CreateVFModule VolumesTask start"); + try { + // Synchronous Web Service Outputs + Holder stackId = new Holder<>(); + Holder> outputs = new Holder<>(); + Holder vnfRollback = new Holder<>(); + String completeVnfVfModuleType = req.getVnfType() + "::" + req.getVfModuleType(); + LOGGER.debug("in createVfModuleVolumes - completeVnfVfModuleType=" + completeVnfVfModuleType); + + String cloudsiteId = req.getCloudSiteId(); + if (cloudsiteId != null && cloudsiteId.equals(TESTING_KEYWORD)) { + String tenant = req.getTenantId(); + if (tenant != null && tenant.equals(TESTING_KEYWORD)) { + throw new VnfException("testing."); + } + stackId.value = "479D3D8B-6360-47BC-AB75-21CC91981484"; + outputs.value = testMap(); + } else { + // Support different Adapter Implementations + MsoVnfAdapter vnfAdapter = vnfAdapterRestUtils.getVnfAdapterImpl(mode, cloudsiteId); + vnfAdapter.createVfModule( + req.getCloudSiteId(), //cloudSiteId, + req.getTenantId(), //tenantId, + completeVnfVfModuleType, //vnfType, + req.getVnfVersion(), //vnfVersion, + req.getVolumeGroupName(), //vnfName, + "VOLUME", //requestType, + null, //volumeGroupHeatStackId, + null, //baseVfHeatStackId, + req.getModelCustomizationUuid(), + req.getVolumeGroupParams(), //inputs, + req.getFailIfExists(), //failIfExists, + req.getSuppressBackout(), //backout, + req.getEnableBridge(), + req.getMsoRequest(), // msoRequest, + stackId, + outputs, + vnfRollback); + } + + VolumeGroupRollback rb = new VolumeGroupRollback( + req.getVolumeGroupId(), + stackId.value, + vnfRollback.value.getVnfCreated(), + req.getTenantId(), + req.getCloudSiteId(), + req.getMsoRequest(), + req.getMessageId()); + + response = new CreateVolumeGroupResponse( + req.getVolumeGroupId(), + stackId.value, + vnfRollback.value.getVnfCreated(), + outputs.value, + rb, + req.getMessageId()); + } catch (VnfException e) { + LOGGER.debug("Exception :",e); + eresp = new VolumeGroupExceptionResponse( + e.getMessage(), MsoExceptionCategory.INTERNAL, true, req.getMessageId()); + } + if (!req.isSynchronous()) { + // This is asynch, so POST response back to caller + BpelRestClient bpelClient = bpelRestClientProvider.get(); + bpelClient.bpelPost(getResponse(), req.getNotificationUrl(), sendxml); + } + LOGGER.debug ("CreateVFModule VolumesTask exit: code=" + getStatusCode() + ", resp="+ getResponse()); + } + } + + @DELETE + @Path("{aaiVolumeGroupId}") + @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @ApiOperation(value = "DeleteVNFVolumes", + response = Response.class, + notes = "Delete an existing vnfVolume") + @ApiResponses({ + @ApiResponse(code = 200, message = "vnfVolume has been successfully deleted"), + @ApiResponse(code = 202, message = "delete vnfVolume request has been successfully accepted (async only)"), + @ApiResponse(code = 500, message = "delete vnfVolume failed, examine entity object for details") }) + public Response deleteVNFVolumes( + @ApiParam(value = "aaiVolumeGroupId", required = true) + @PathParam("aaiVolumeGroupId") String aaiVolumeGroupId, + @ApiParam(value = "mode", required = true) + @QueryParam("mode") String mode, + @ApiParam(value = "DeleteVolumeGroupRequest", required = true) + final DeleteVolumeGroupRequest req + ) + { + LOGGER.debug("deleteVNFVolumes enter: " + req.toJsonString()); + if (aaiVolumeGroupId == null || !aaiVolumeGroupId.equals(req.getVolumeGroupId())) { + return Response + .status(HttpStatus.SC_BAD_REQUEST) + .type(MediaType.TEXT_PLAIN) + .entity("VolumeGroupId in URL does not match content") + .build(); + } + DeleteVNFVolumesTask task = new DeleteVNFVolumesTask(req, mode); + if (req.isSynchronous()) { + // This is a synchronous request + task.run(); + return Response + .status(task.getStatusCode()) + .entity(task.getGenericEntityResponse()) + .build(); + } else { + // This is an asynchronous request + try { + Thread t1 = new Thread(task); + t1.start(); + } catch (Exception e) { + // problem handling create, send generic failure as sync resp to caller + LOGGER.error (MessageEnum.RA_DELETE_VNF_ERR, "", "deleteVNFVolumes", MsoLogger.ErrorCode.BusinessProcesssError, "Exception - deleteVNFVolumes", e); + return Response.serverError().build(); + } + // send sync response (ACK) to caller + LOGGER.debug ("deleteVNFVolumes exit"); + return Response.status(HttpStatus.SC_ACCEPTED).build(); + } + } + + public class DeleteVNFVolumesTask implements Runnable { + private final DeleteVolumeGroupRequest req; + private DeleteVolumeGroupResponse response = null; + private VolumeGroupExceptionResponse eresp = null; + private boolean sendxml; + private String mode; + + public DeleteVNFVolumesTask(DeleteVolumeGroupRequest req, String mode) { + this.req = req; + this.sendxml = true; // can be set with a field or header later + this.mode = mode; + } + public int getStatusCode() { + return (response != null) ? HttpStatus.SC_OK : HttpStatus.SC_BAD_REQUEST; + } + public Object getGenericEntityResponse() { + return (response != null) + ? new GenericEntity(response) {} + : new GenericEntity(eresp) {}; + } + private String getResponse() { + if (response != null) { + return sendxml ? response.toXmlString() : response.toJsonString(); + } else { + return sendxml ? eresp.toXmlString() : eresp.toJsonString(); + } + } + @Override + public void run() { + LOGGER.debug("DeleteVNFVolumesTask start"); + String cloudSiteId = req.getCloudSiteId(); + try { + if (! cloudSiteId.equals(TESTING_KEYWORD)) { + // Support different Adapter Implementations + MsoVnfAdapter vnfAdapter = vnfAdapterRestUtils.getVnfAdapterImpl(mode, cloudSiteId); + vnfAdapter.deleteVnf(req.getCloudSiteId(), req.getTenantId(), req.getVolumeGroupStackId(), req.getMsoRequest()); + } + response = new DeleteVolumeGroupResponse(true, req.getMessageId()); + } catch (VnfException e) { + LOGGER.debug("Exception :",e); + eresp = new VolumeGroupExceptionResponse(e.getMessage(), MsoExceptionCategory.INTERNAL, true, req.getMessageId()); + } + if (!req.isSynchronous()) { + // This is asynch, so POST response back to caller + BpelRestClient bpelClient = bpelRestClientProvider.get(); + bpelClient.bpelPost(getResponse(), req.getNotificationUrl(), sendxml); + } + LOGGER.debug("DeleteVNFVolumesTask exit: code=" + getStatusCode() + ", resp="+ getResponse()); + } + } + + @DELETE + @Path("{aaiVolumeGroupId}/rollback") + @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @ApiOperation(value = "RollbackVNFVolumes", + response = Response.class, + notes = "Delete an existing vnfVolume") + @ApiResponses({ + @ApiResponse(code = 200, message = "vnfVolume has been successfully rolled back"), + @ApiResponse(code = 202, message = "rollback vnfVolume request has been successfully accepted (async only)"), + @ApiResponse(code = 500, message = "rollback vnfVolume failed, examine entity object for details") }) + public Response rollbackVNFVolumes( + @ApiParam(value = "aaiVolumeGroupId", required = true) + @PathParam("aaiVolumeGroupId") String aaiVolumeGroupId, + @ApiParam(value = "RollbackVolumeGroupRequest", required = true) + final RollbackVolumeGroupRequest req + ) + { + LOGGER.debug("rollbackVNFVolumes enter: " + req.toJsonString()); + if (aaiVolumeGroupId == null || req.getVolumeGroupRollback() == null || !aaiVolumeGroupId.equals(req.getVolumeGroupRollback().getVolumeGroupId())) { + return Response + .status(HttpStatus.SC_BAD_REQUEST) + .type(MediaType.TEXT_PLAIN) + .entity("VolumeGroupId in URL does not match content") + .build(); + } + RollbackVNFVolumesTask task = new RollbackVNFVolumesTask(req); + if (req.isSynchronous()) { + // This is a synchronous request + task.run(); + return Response + .status(task.getStatusCode()) + .entity(task.getGenericEntityResponse()) + .build(); + } else { + // This is an asynchronous request + try { + Thread t1 = new Thread(task); + t1.start(); + } catch (Exception e) { + // problem handling create, send generic failure as sync resp to caller + LOGGER.error (MessageEnum.RA_ROLLBACK_VNF_ERR, "", "rollbackVNFVolumes", MsoLogger.ErrorCode.BusinessProcesssError, "Exception - rollbackVNFVolumes", e); + return Response.serverError().build(); + } + // send sync response (ACK) to caller + LOGGER.debug("rollbackVNFVolumes exit"); + return Response.status(HttpStatus.SC_ACCEPTED).build(); + } + } + + public class RollbackVNFVolumesTask implements Runnable { + private final RollbackVolumeGroupRequest req; + private RollbackVolumeGroupResponse response = null; + private VolumeGroupExceptionResponse eresp = null; + private boolean sendxml; + + public RollbackVNFVolumesTask(RollbackVolumeGroupRequest req) { + this.req = req; + this.sendxml = true; // can be set with a field or header later + } + public int getStatusCode() { + return (response != null) ? HttpStatus.SC_OK : HttpStatus.SC_BAD_REQUEST; + } + public Object getGenericEntityResponse() { + return (response != null) + ? new GenericEntity(response) {} + : new GenericEntity(eresp) {}; + } + private String getResponse() { + if (response != null) { + return sendxml ? response.toXmlString() : response.toJsonString(); + } else { + return sendxml ? eresp.toXmlString() : eresp.toJsonString(); + } + } + @Override + public void run() { + LOGGER.debug("RollbackVNFVolumesTask start"); + try { + VolumeGroupRollback vgr = req.getVolumeGroupRollback(); + VnfRollback vrb = new VnfRollback( + vgr.getVolumeGroupStackId(), vgr.getTenantId(), vgr.getCloudSiteId(), true, true, + vgr.getMsoRequest(), null, null, null, null); + + // Support different Adapter Implementations + MsoVnfAdapter vnfAdapter = vnfAdapterRestUtils.getVnfAdapterImpl(vrb.getMode(), vrb.getCloudSiteId()); + vnfAdapter.rollbackVnf(vrb); + response = new RollbackVolumeGroupResponse(true, req.getMessageId()); + } catch (VnfException e) { + LOGGER.debug("Exception :",e); + eresp = new VolumeGroupExceptionResponse(e.getMessage(), MsoExceptionCategory.INTERNAL, true, req.getMessageId()); + } + if (!req.isSynchronous()) { + // This is asynch, so POST response back to caller + BpelRestClient bpelClient = bpelRestClientProvider.get(); + bpelClient.bpelPost(getResponse(), req.getNotificationUrl(), sendxml); + } + LOGGER.debug("RollbackVNFVolumesTask exit: code=" + getStatusCode() + ", resp="+ getResponse()); + } + + } + + @PUT + @Path("{aaiVolumeGroupId}") + @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @ApiOperation(value = "UpdateVNFVolumes", + response = Response.class, + notes = "Update an existing vnfVolume") + @ApiResponses({ + @ApiResponse(code = 200, message = "vnfVolume has been successfully updated"), + @ApiResponse(code = 202, message = "update vnfVolume request has been successfully accepted (async only)"), + @ApiResponse(code = 500, message = "update vnfVolume failed, examine entity object for details") }) + public Response updateVNFVolumes( + @ApiParam(value = "aaiVolumeGroupId", required = true) + @PathParam("aaiVolumeGroupId") String aaiVolumeGroupId, + @ApiParam(value = "mode", required = true) + @QueryParam("mode") String mode, + @ApiParam(value = "UpdateVolumeGroupRequest", required = true) + final UpdateVolumeGroupRequest req + ) + { + LOGGER.debug("updateVNFVolumes enter: " + req.toJsonString()); + if (aaiVolumeGroupId == null || !aaiVolumeGroupId.equals(req.getVolumeGroupId())) { + return Response + .status(HttpStatus.SC_BAD_REQUEST) + .type(MediaType.TEXT_PLAIN) + .entity("VolumeGroupId in URL does not match content") + .build(); + } + UpdateVNFVolumesTask task = new UpdateVNFVolumesTask(req, mode); + if (req.isSynchronous()) { + // This is a synchronous request + task.run(); + return Response + .status(task.getStatusCode()) + .entity(task.getGenericEntityResponse()) + .build(); + } else { + // This is an asynchronous request + try { + Thread t1 = new Thread(task); + t1.start(); + } catch (Exception e) { + // problem handling create, send generic failure as sync resp to caller + LOGGER.error (MessageEnum.RA_UPDATE_VNF_ERR, "", "updateVNFVolumes", MsoLogger.ErrorCode.BusinessProcesssError, "Exception - updateVNFVolumes", e); + return Response.serverError().build(); + } + // send sync response (ACK) to caller + LOGGER.debug ("updateVNFVolumes exit"); + return Response.status(HttpStatus.SC_ACCEPTED).build(); + } + } + + public class UpdateVNFVolumesTask implements Runnable { + private final UpdateVolumeGroupRequest req; + private UpdateVolumeGroupResponse response = null; + private VolumeGroupExceptionResponse eresp = null; + private boolean sendxml; + private String mode; + + public UpdateVNFVolumesTask(UpdateVolumeGroupRequest req, String mode) { + this.req = req; + this.sendxml = true; // can be set with a field or header later + this.mode = mode; + } + public int getStatusCode() { + return (response != null) ? HttpStatus.SC_OK : HttpStatus.SC_BAD_REQUEST; + } + public Object getGenericEntityResponse() { + return (response != null) + ? new GenericEntity(response) {} + : new GenericEntity(eresp) {}; + } + private String getResponse() { + if (response != null) { + return sendxml ? response.toXmlString() : response.toJsonString(); + } else { + return sendxml ? eresp.toXmlString() : eresp.toJsonString(); + } + } + @Override + public void run() { + LOGGER.debug("UpdateVNFVolumesTask start"); + try { + Holder> outputs = new Holder<> (); + Holder vnfRollback = new Holder<> (); + String completeVnfVfModuleType = req.getVnfType() + "::" + req.getVfModuleType(); + LOGGER.debug("in updateVfModuleVolume - completeVnfVfModuleType=" + completeVnfVfModuleType); + + if (req.getCloudSiteId().equals(TESTING_KEYWORD)) { + outputs.value = testMap(); + } else { + // Support different Adapter Implementations + MsoVnfAdapter vnfAdapter = vnfAdapterRestUtils.getVnfAdapterImpl(mode, req.getCloudSiteId()); + vnfAdapter.updateVfModule (req.getCloudSiteId(), + req.getTenantId(), + //req.getVnfType(), + completeVnfVfModuleType, + req.getVnfVersion(), + req.getVolumeGroupStackId(), + "VOLUME", + null, + null, + req.getVolumeGroupStackId(), + req.getModelCustomizationUuid(), + req.getVolumeGroupParams(), + req.getMsoRequest(), + outputs, + vnfRollback); + } + response = new UpdateVolumeGroupResponse( + req.getVolumeGroupId(), req.getVolumeGroupStackId(), + outputs.value, req.getMessageId()); + } catch (VnfException e) { + LOGGER.debug("Exception :",e); + eresp = new VolumeGroupExceptionResponse(e.getMessage(), MsoExceptionCategory.INTERNAL, true, req.getMessageId()); + } + if (!req.isSynchronous()) { + // This is asynch, so POST response back to caller + BpelRestClient bpelClient = bpelRestClientProvider.get(); + bpelClient.bpelPost(getResponse(), req.getNotificationUrl(), sendxml); + } + LOGGER.debug("UpdateVNFVolumesTask exit: code=" + getStatusCode() + ", resp="+ getResponse()); + } + } + + @GET + @Path("{aaiVolumeGroupId}") + @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @ApiOperation(value = "QueryVNFVolumes", + response = Response.class, + notes = "Query an existing vnfVolume") + @ApiResponses({ + @ApiResponse(code = 200, message = "vnfVolume has been successfully queried"), + @ApiResponse(code = 500, message = "query vnfVolume failed, examine entity object for details") }) + public Response queryVNFVolumes( + @ApiParam(value = "aaiVolumeGroupId", required = true) + @PathParam("aaiVolumeGroupId") String aaiVolumeGroupId, + @ApiParam(value = "cloudSiteId", required = true) + @QueryParam("cloudSiteId") String cloudSiteId, + @ApiParam(value = "tenantId", required = true) + @QueryParam("tenantId") String tenantId, + @ApiParam(value = "volumeGroupStackId", required = true) + @QueryParam("volumeGroupStackId") String volumeGroupStackId, + @ApiParam(value = "skipAAI", required = true) + @QueryParam("skipAAI") Boolean skipAAI, + @ApiParam(value = "msoRequest.requestId", required = true) + @QueryParam("msoRequest.requestId") String requestId, + @ApiParam(value = "msoRequest.serviceInstanceId", required = true) + @QueryParam("msoRequest.serviceInstanceId") String serviceInstanceId, + @ApiParam(value = "mode", required = true) + @QueryParam("mode") String mode + ) + { + //This request responds synchronously only + LOGGER.debug ("queryVNFVolumes enter:" + aaiVolumeGroupId + " " + volumeGroupStackId); + MsoRequest msoRequest = new MsoRequest(requestId, serviceInstanceId); + + try { + int respStatus = HttpStatus.SC_OK; + QueryVolumeGroupResponse qryResp = new QueryVolumeGroupResponse(aaiVolumeGroupId, volumeGroupStackId, null, null); + Holder vnfExists = new Holder<>(); + Holder vfModuleId = new Holder<>(); + Holder status = new Holder<>(); + Holder> outputs = new Holder<>(); + if (cloudSiteId != null && cloudSiteId.equals(TESTING_KEYWORD)) { + if (tenantId != null && tenantId.equals(TESTING_KEYWORD)) { + throw new VnfException("testing."); + } + vnfExists.value = true; + vfModuleId.value = TESTING_KEYWORD; + status.value = VnfStatus.ACTIVE; + outputs.value = testMap(); + } else { + // Support different Adapter Implementations + MsoVnfAdapter vnfAdapter = vnfAdapterRestUtils.getVnfAdapterImpl(mode, cloudSiteId); + vnfAdapter.queryVnf(cloudSiteId, tenantId, volumeGroupStackId, msoRequest, vnfExists, vfModuleId, status, outputs); + } + if (!vnfExists.value) { + LOGGER.debug ("VNFVolumes not found"); + qryResp.setVolumeGroupStatus(status.value); + respStatus = HttpStatus.SC_NOT_FOUND; + } else { + LOGGER.debug ("VNFVolumes found " + vfModuleId.value + ", status=" + status.value); + qryResp.setVolumeGroupStatus(status.value); + qryResp.setVolumeGroupOutputs(outputs.value); + } + LOGGER.debug("Query queryVNFVolumes exit"); + return Response + .status(respStatus) + .entity(new GenericEntity(qryResp) {}) + .build(); + } catch (VnfException e) { + LOGGER.error(MessageEnum.RA_QUERY_VNF_ERR, aaiVolumeGroupId, "", "queryVNFVolumes", MsoLogger.ErrorCode.BusinessProcesssError, "VnfException - queryVNFVolumes", e); + VolumeGroupExceptionResponse excResp = new VolumeGroupExceptionResponse(e.getMessage(), MsoExceptionCategory.INTERNAL, Boolean.FALSE, null); + LOGGER.debug("Query queryVNFVolumes exit"); + return Response + .status(HttpStatus.SC_INTERNAL_SERVER_ERROR) + .entity(new GenericEntity(excResp) {}) + .build(); + } + } + public static Map testMap() { + Map m = new HashMap<>(); + m.put("mickey", "7"); + m.put("clyde", "10"); + m.put("wayne", "99"); + return m; + } +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/async/client/CreateVnfNotification.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/async/client/CreateVnfNotification.java new file mode 100644 index 0000000000..39bd3ebf61 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/async/client/CreateVnfNotification.java @@ -0,0 +1,410 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.so.adapters.vnf.async.client; + +import java.util.ArrayList; +import java.util.List; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlType; + + +/** + *

Java class for createVnfNotification complex type. + * + *

The following schema fragment specifies the expected content contained within this class. + * + *

+ * <complexType name="createVnfNotification">
+ *   <complexContent>
+ *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *       <sequence>
+ *         <element name="messageId" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ *         <element name="completed" type="{http://www.w3.org/2001/XMLSchema}boolean"/>
+ *         <element name="exception" type="{http://org.onap.so/vnfNotify}msoExceptionCategory" minOccurs="0"/>
+ *         <element name="errorMessage" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
+ *         <element name="vnfId" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
+ *         <element name="outputs" minOccurs="0">
+ *           <complexType>
+ *             <complexContent>
+ *               <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *                 <sequence>
+ *                   <element name="entry" maxOccurs="unbounded" minOccurs="0">
+ *                     <complexType>
+ *                       <complexContent>
+ *                         <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *                           <sequence>
+ *                             <element name="key" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
+ *                             <element name="value" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
+ *                           </sequence>
+ *                         </restriction>
+ *                       </complexContent>
+ *                     </complexType>
+ *                   </element>
+ *                 </sequence>
+ *               </restriction>
+ *             </complexContent>
+ *           </complexType>
+ *         </element>
+ *         <element name="rollback" type="{http://org.onap.so/vnfNotify}vnfRollback" minOccurs="0"/>
+ *       </sequence>
+ *     </restriction>
+ *   </complexContent>
+ * </complexType>
+ * 
+ * + * + */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "createVnfNotification", propOrder = { + "messageId", + "completed", + "exception", + "errorMessage", + "vnfId", + "outputs", + "rollback" +}) +public class CreateVnfNotification { + + @XmlElement(required = true) + protected String messageId; + protected boolean completed; + protected MsoExceptionCategory exception; + protected String errorMessage; + protected String vnfId; + protected CreateVnfNotification.Outputs outputs; + protected VnfRollback rollback; + + /** + * Gets the value of the messageId property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getMessageId() { + return messageId; + } + + /** + * Sets the value of the messageId property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setMessageId(String value) { + this.messageId = value; + } + + /** + * Gets the value of the completed property. + * + */ + public boolean isCompleted() { + return completed; + } + + /** + * Sets the value of the completed property. + * + */ + public void setCompleted(boolean value) { + this.completed = value; + } + + /** + * Gets the value of the exception property. + * + * @return + * possible object is + * {@link MsoExceptionCategory } + * + */ + public MsoExceptionCategory getException() { + return exception; + } + + /** + * Sets the value of the exception property. + * + * @param value + * allowed object is + * {@link MsoExceptionCategory } + * + */ + public void setException(MsoExceptionCategory value) { + this.exception = value; + } + + /** + * Gets the value of the errorMessage property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getErrorMessage() { + return errorMessage; + } + + /** + * Sets the value of the errorMessage property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setErrorMessage(String value) { + this.errorMessage = value; + } + + /** + * Gets the value of the vnfId property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getVnfId() { + return vnfId; + } + + /** + * Sets the value of the vnfId property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setVnfId(String value) { + this.vnfId = value; + } + + /** + * Gets the value of the outputs property. + * + * @return + * possible object is + * {@link CreateVnfNotification.Outputs } + * + */ + public CreateVnfNotification.Outputs getOutputs() { + return outputs; + } + + /** + * Sets the value of the outputs property. + * + * @param value + * allowed object is + * {@link CreateVnfNotification.Outputs } + * + */ + public void setOutputs(CreateVnfNotification.Outputs value) { + this.outputs = value; + } + + /** + * Gets the value of the rollback property. + * + * @return + * possible object is + * {@link VnfRollback } + * + */ + public VnfRollback getRollback() { + return rollback; + } + + /** + * Sets the value of the rollback property. + * + * @param value + * allowed object is + * {@link VnfRollback } + * + */ + public void setRollback(VnfRollback value) { + this.rollback = value; + } + + + /** + *

Java class for anonymous complex type. + * + *

The following schema fragment specifies the expected content contained within this class. + * + *

+     * <complexType>
+     *   <complexContent>
+     *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+     *       <sequence>
+     *         <element name="entry" maxOccurs="unbounded" minOccurs="0">
+     *           <complexType>
+     *             <complexContent>
+     *               <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+     *                 <sequence>
+     *                   <element name="key" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
+     *                   <element name="value" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
+     *                 </sequence>
+     *               </restriction>
+     *             </complexContent>
+     *           </complexType>
+     *         </element>
+     *       </sequence>
+     *     </restriction>
+     *   </complexContent>
+     * </complexType>
+     * 
+ * + * + */ + @XmlAccessorType(XmlAccessType.FIELD) + @XmlType(name = "", propOrder = { + "entry" + }) + public static class Outputs { + + protected List entry; + + /** + * Gets the value of the entry property. + * + *

+ * This accessor method returns a reference to the live list, + * not a snapshot. Therefore any modification you make to the + * returned list will be present inside the JAXB object. + * This is why there is not a set method for the entry property. + * + *

+ * For example, to add a new item, do as follows: + *

+         *    getEntry().add(newItem);
+         * 
+ * + * + *

+ * Objects of the following type(s) are allowed in the list + * {@link CreateVnfNotification.Outputs.Entry } + * + * + */ + public List getEntry() { + if (entry == null) { + entry = new ArrayList(); + } + return this.entry; + } + + + /** + *

Java class for anonymous complex type. + * + *

The following schema fragment specifies the expected content contained within this class. + * + *

+         * <complexType>
+         *   <complexContent>
+         *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+         *       <sequence>
+         *         <element name="key" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
+         *         <element name="value" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
+         *       </sequence>
+         *     </restriction>
+         *   </complexContent>
+         * </complexType>
+         * 
+ * + * + */ + @XmlAccessorType(XmlAccessType.FIELD) + @XmlType(name = "", propOrder = { + "key", + "value" + }) + public static class Entry { + + protected String key; + protected String value; + + /** + * Gets the value of the key property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getKey() { + return key; + } + + /** + * Sets the value of the key property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setKey(String value) { + this.key = value; + } + + /** + * Gets the value of the value property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getValue() { + return value; + } + + /** + * Sets the value of the value property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setValue(String value) { + this.value = value; + } + + } + + } + +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/async/client/DeleteVnfNotification.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/async/client/DeleteVnfNotification.java new file mode 100644 index 0000000000..d8c533b041 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/async/client/DeleteVnfNotification.java @@ -0,0 +1,154 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.so.adapters.vnf.async.client; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlType; + + +/** + *

Java class for deleteVnfNotification complex type. + * + *

The following schema fragment specifies the expected content contained within this class. + * + *

+ * <complexType name="deleteVnfNotification">
+ *   <complexContent>
+ *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *       <sequence>
+ *         <element name="messageId" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ *         <element name="completed" type="{http://www.w3.org/2001/XMLSchema}boolean"/>
+ *         <element name="exception" type="{http://org.onap.so/vnfNotify}msoExceptionCategory" minOccurs="0"/>
+ *         <element name="errorMessage" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
+ *       </sequence>
+ *     </restriction>
+ *   </complexContent>
+ * </complexType>
+ * 
+ * + * + */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "deleteVnfNotification", propOrder = { + "messageId", + "completed", + "exception", + "errorMessage" +}) +public class DeleteVnfNotification { + + @XmlElement(required = true) + protected String messageId; + protected boolean completed; + protected MsoExceptionCategory exception; + protected String errorMessage; + + /** + * Gets the value of the messageId property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getMessageId() { + return messageId; + } + + /** + * Sets the value of the messageId property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setMessageId(String value) { + this.messageId = value; + } + + /** + * Gets the value of the completed property. + * + */ + public boolean isCompleted() { + return completed; + } + + /** + * Sets the value of the completed property. + * + */ + public void setCompleted(boolean value) { + this.completed = value; + } + + /** + * Gets the value of the exception property. + * + * @return + * possible object is + * {@link MsoExceptionCategory } + * + */ + public MsoExceptionCategory getException() { + return exception; + } + + /** + * Sets the value of the exception property. + * + * @param value + * allowed object is + * {@link MsoExceptionCategory } + * + */ + public void setException(MsoExceptionCategory value) { + this.exception = value; + } + + /** + * Gets the value of the errorMessage property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getErrorMessage() { + return errorMessage; + } + + /** + * Sets the value of the errorMessage property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setErrorMessage(String value) { + this.errorMessage = value; + } + +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/async/client/MsoExceptionCategory.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/async/client/MsoExceptionCategory.java new file mode 100644 index 0000000000..73642a7f44 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/async/client/MsoExceptionCategory.java @@ -0,0 +1,61 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.so.adapters.vnf.async.client; + +import javax.xml.bind.annotation.XmlEnum; +import javax.xml.bind.annotation.XmlType; + + +/** + *

Java class for msoExceptionCategory. + * + *

The following schema fragment specifies the expected content contained within this class. + *

+ *

+ * <simpleType name="msoExceptionCategory">
+ *   <restriction base="{http://www.w3.org/2001/XMLSchema}string">
+ *     <enumeration value="OPENSTACK"/>
+ *     <enumeration value="IO"/>
+ *     <enumeration value="INTERNAL"/>
+ *     <enumeration value="USERDATA"/>
+ *   </restriction>
+ * </simpleType>
+ * 
+ * + */ +@XmlType(name = "msoExceptionCategory") +@XmlEnum +public enum MsoExceptionCategory { + + OPENSTACK, + IO, + INTERNAL, + USERDATA; + + public String value() { + return name(); + } + + public static MsoExceptionCategory fromValue(String v) { + return valueOf(v); + } + +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/async/client/MsoRequest.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/async/client/MsoRequest.java new file mode 100644 index 0000000000..a4253b0cef --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/async/client/MsoRequest.java @@ -0,0 +1,106 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.so.adapters.vnf.async.client; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlType; + + +/** + *

Java class for msoRequest complex type. + * + *

The following schema fragment specifies the expected content contained within this class. + * + *

+ * <complexType name="msoRequest">
+ *   <complexContent>
+ *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *       <sequence>
+ *         <element name="requestId" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
+ *         <element name="serviceInstanceId" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
+ *       </sequence>
+ *     </restriction>
+ *   </complexContent>
+ * </complexType>
+ * 
+ * + * + */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "msoRequest", propOrder = { + "requestId", + "serviceInstanceId" +}) +public class MsoRequest { + + protected String requestId; + protected String serviceInstanceId; + + /** + * Gets the value of the requestId property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getRequestId() { + return requestId; + } + + /** + * Sets the value of the requestId property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setRequestId(String value) { + this.requestId = value; + } + + /** + * Gets the value of the serviceInstanceId property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getServiceInstanceId() { + return serviceInstanceId; + } + + /** + * Sets the value of the serviceInstanceId property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setServiceInstanceId(String value) { + this.serviceInstanceId = value; + } + +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/async/client/ObjectFactory.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/async/client/ObjectFactory.java new file mode 100644 index 0000000000..0ab0fde747 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/async/client/ObjectFactory.java @@ -0,0 +1,208 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.so.adapters.vnf.async.client; + +import javax.xml.bind.JAXBElement; +import javax.xml.bind.annotation.XmlElementDecl; +import javax.xml.bind.annotation.XmlRegistry; +import javax.xml.namespace.QName; + + +/** + * This object contains factory methods for each + * Java content interface and Java element interface + * generated in the org.onap.so.adapters.vnf.async.client package. + *

An ObjectFactory allows you to programatically + * construct new instances of the Java representation + * for XML content. The Java representation of XML + * content can consist of schema derived interfaces + * and classes representing the binding of schema + * type definitions, element declarations and model + * groups. Factory methods for each of these are + * provided in this class. + * + */ +@XmlRegistry +public class ObjectFactory { + + private final static QName _QueryVnfNotification_QNAME = new QName("http://org.onap.so/vnfNotify", "queryVnfNotification"); + private final static QName _RollbackVnfNotification_QNAME = new QName("http://org.onap.so/vnfNotify", "rollbackVnfNotification"); + private final static QName _CreateVnfNotification_QNAME = new QName("http://org.onap.so/vnfNotify", "createVnfNotification"); + private final static QName _DeleteVnfNotification_QNAME = new QName("http://org.onap.so/vnfNotify", "deleteVnfNotification"); + private final static QName _UpdateVnfNotification_QNAME = new QName("http://org.onap.so/vnfNotify", "updateVnfNotification"); + + /** + * Create a new ObjectFactory that can be used to create new instances of schema derived classes for package: org.onap.so.adapters.vnf.async.client + * + */ + public ObjectFactory() { + } + + /** + * Create an instance of {@link UpdateVnfNotification } + * + */ + public UpdateVnfNotification createUpdateVnfNotification() { + return new UpdateVnfNotification(); + } + + /** + * Create an instance of {@link UpdateVnfNotification.Outputs } + * + */ + public UpdateVnfNotification.Outputs createUpdateVnfNotificationOutputs() { + return new UpdateVnfNotification.Outputs(); + } + + /** + * Create an instance of {@link CreateVnfNotification } + * + */ + public CreateVnfNotification createCreateVnfNotification() { + return new CreateVnfNotification(); + } + + /** + * Create an instance of {@link CreateVnfNotification.Outputs } + * + */ + public CreateVnfNotification.Outputs createCreateVnfNotificationOutputs() { + return new CreateVnfNotification.Outputs(); + } + + /** + * Create an instance of {@link QueryVnfNotification } + * + */ + public QueryVnfNotification createQueryVnfNotification() { + return new QueryVnfNotification(); + } + + /** + * Create an instance of {@link QueryVnfNotification.Outputs } + * + */ + public QueryVnfNotification.Outputs createQueryVnfNotificationOutputs() { + return new QueryVnfNotification.Outputs(); + } + + /** + * Create an instance of {@link RollbackVnfNotification } + * + */ + public RollbackVnfNotification createRollbackVnfNotification() { + return new RollbackVnfNotification(); + } + + /** + * Create an instance of {@link DeleteVnfNotification } + * + */ + public DeleteVnfNotification createDeleteVnfNotification() { + return new DeleteVnfNotification(); + } + + /** + * Create an instance of {@link MsoRequest } + * + */ + public MsoRequest createMsoRequest() { + return new MsoRequest(); + } + + /** + * Create an instance of {@link VnfRollback } + * + */ + public VnfRollback createVnfRollback() { + return new VnfRollback(); + } + + /** + * Create an instance of {@link UpdateVnfNotification.Outputs.Entry } + * + */ + public UpdateVnfNotification.Outputs.Entry createUpdateVnfNotificationOutputsEntry() { + return new UpdateVnfNotification.Outputs.Entry(); + } + + /** + * Create an instance of {@link CreateVnfNotification.Outputs.Entry } + * + */ + public CreateVnfNotification.Outputs.Entry createCreateVnfNotificationOutputsEntry() { + return new CreateVnfNotification.Outputs.Entry(); + } + + /** + * Create an instance of {@link QueryVnfNotification.Outputs.Entry } + * + */ + public QueryVnfNotification.Outputs.Entry createQueryVnfNotificationOutputsEntry() { + return new QueryVnfNotification.Outputs.Entry(); + } + + /** + * Create an instance of {@link JAXBElement }{@code <}{@link QueryVnfNotification }{@code >}} + * + */ + @XmlElementDecl(namespace = "http://org.onap.so/vnfNotify", name = "queryVnfNotification") + public JAXBElement createQueryVnfNotification(QueryVnfNotification value) { + return new JAXBElement(_QueryVnfNotification_QNAME, QueryVnfNotification.class, null, value); + } + + /** + * Create an instance of {@link JAXBElement }{@code <}{@link RollbackVnfNotification }{@code >}} + * + */ + @XmlElementDecl(namespace = "http://org.onap.so/vnfNotify", name = "rollbackVnfNotification") + public JAXBElement createRollbackVnfNotification(RollbackVnfNotification value) { + return new JAXBElement(_RollbackVnfNotification_QNAME, RollbackVnfNotification.class, null, value); + } + + /** + * Create an instance of {@link JAXBElement }{@code <}{@link CreateVnfNotification }{@code >}} + * + */ + @XmlElementDecl(namespace = "http://org.onap.so/vnfNotify", name = "createVnfNotification") + public JAXBElement createCreateVnfNotification(CreateVnfNotification value) { + return new JAXBElement(_CreateVnfNotification_QNAME, CreateVnfNotification.class, null, value); + } + + /** + * Create an instance of {@link JAXBElement }{@code <}{@link DeleteVnfNotification }{@code >}} + * + */ + @XmlElementDecl(namespace = "http://org.onap.so/vnfNotify", name = "deleteVnfNotification") + public JAXBElement createDeleteVnfNotification(DeleteVnfNotification value) { + return new JAXBElement(_DeleteVnfNotification_QNAME, DeleteVnfNotification.class, null, value); + } + + /** + * Create an instance of {@link JAXBElement }{@code <}{@link UpdateVnfNotification }{@code >}} + * + */ + @XmlElementDecl(namespace = "http://org.onap.so/vnfNotify", name = "updateVnfNotification") + public JAXBElement createUpdateVnfNotification(UpdateVnfNotification value) { + return new JAXBElement(_UpdateVnfNotification_QNAME, UpdateVnfNotification.class, null, value); + } + +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/async/client/QueryVnfNotification.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/async/client/QueryVnfNotification.java new file mode 100644 index 0000000000..0fd701d4f6 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/async/client/QueryVnfNotification.java @@ -0,0 +1,437 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.so.adapters.vnf.async.client; + +import java.util.ArrayList; +import java.util.List; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlType; + + +/** + *

Java class for queryVnfNotification complex type. + * + *

The following schema fragment specifies the expected content contained within this class. + * + *

+ * <complexType name="queryVnfNotification">
+ *   <complexContent>
+ *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *       <sequence>
+ *         <element name="messageId" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ *         <element name="completed" type="{http://www.w3.org/2001/XMLSchema}boolean"/>
+ *         <element name="exception" type="{http://org.onap.so/vnfNotify}msoExceptionCategory" minOccurs="0"/>
+ *         <element name="errorMessage" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
+ *         <element name="vnfExists" type="{http://www.w3.org/2001/XMLSchema}boolean" minOccurs="0"/>
+ *         <element name="vnfId" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
+ *         <element name="status" type="{http://org.onap.so/vnfNotify}vnfStatus" minOccurs="0"/>
+ *         <element name="outputs" minOccurs="0">
+ *           <complexType>
+ *             <complexContent>
+ *               <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *                 <sequence>
+ *                   <element name="entry" maxOccurs="unbounded" minOccurs="0">
+ *                     <complexType>
+ *                       <complexContent>
+ *                         <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *                           <sequence>
+ *                             <element name="key" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
+ *                             <element name="value" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
+ *                           </sequence>
+ *                         </restriction>
+ *                       </complexContent>
+ *                     </complexType>
+ *                   </element>
+ *                 </sequence>
+ *               </restriction>
+ *             </complexContent>
+ *           </complexType>
+ *         </element>
+ *       </sequence>
+ *     </restriction>
+ *   </complexContent>
+ * </complexType>
+ * 
+ * + * + */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "queryVnfNotification", propOrder = { + "messageId", + "completed", + "exception", + "errorMessage", + "vnfExists", + "vnfId", + "status", + "outputs" +}) +public class QueryVnfNotification { + + @XmlElement(required = true) + protected String messageId; + protected boolean completed; + protected MsoExceptionCategory exception; + protected String errorMessage; + protected Boolean vnfExists; + protected String vnfId; + protected VnfStatus status; + protected QueryVnfNotification.Outputs outputs; + + /** + * Gets the value of the messageId property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getMessageId() { + return messageId; + } + + /** + * Sets the value of the messageId property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setMessageId(String value) { + this.messageId = value; + } + + /** + * Gets the value of the completed property. + * + */ + public boolean isCompleted() { + return completed; + } + + /** + * Sets the value of the completed property. + * + */ + public void setCompleted(boolean value) { + this.completed = value; + } + + /** + * Gets the value of the exception property. + * + * @return + * possible object is + * {@link MsoExceptionCategory } + * + */ + public MsoExceptionCategory getException() { + return exception; + } + + /** + * Sets the value of the exception property. + * + * @param value + * allowed object is + * {@link MsoExceptionCategory } + * + */ + public void setException(MsoExceptionCategory value) { + this.exception = value; + } + + /** + * Gets the value of the errorMessage property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getErrorMessage() { + return errorMessage; + } + + /** + * Sets the value of the errorMessage property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setErrorMessage(String value) { + this.errorMessage = value; + } + + /** + * Gets the value of the vnfExists property. + * + * @return + * possible object is + * {@link Boolean } + * + */ + public Boolean isVnfExists() { + return vnfExists; + } + + /** + * Sets the value of the vnfExists property. + * + * @param value + * allowed object is + * {@link Boolean } + * + */ + public void setVnfExists(Boolean value) { + this.vnfExists = value; + } + + /** + * Gets the value of the vnfId property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getVnfId() { + return vnfId; + } + + /** + * Sets the value of the vnfId property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setVnfId(String value) { + this.vnfId = value; + } + + /** + * Gets the value of the status property. + * + * @return + * possible object is + * {@link VnfStatus } + * + */ + public VnfStatus getStatus() { + return status; + } + + /** + * Sets the value of the status property. + * + * @param value + * allowed object is + * {@link VnfStatus } + * + */ + public void setStatus(VnfStatus value) { + this.status = value; + } + + /** + * Gets the value of the outputs property. + * + * @return + * possible object is + * {@link QueryVnfNotification.Outputs } + * + */ + public QueryVnfNotification.Outputs getOutputs() { + return outputs; + } + + /** + * Sets the value of the outputs property. + * + * @param value + * allowed object is + * {@link QueryVnfNotification.Outputs } + * + */ + public void setOutputs(QueryVnfNotification.Outputs value) { + this.outputs = value; + } + + + /** + *

Java class for anonymous complex type. + * + *

The following schema fragment specifies the expected content contained within this class. + * + *

+     * <complexType>
+     *   <complexContent>
+     *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+     *       <sequence>
+     *         <element name="entry" maxOccurs="unbounded" minOccurs="0">
+     *           <complexType>
+     *             <complexContent>
+     *               <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+     *                 <sequence>
+     *                   <element name="key" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
+     *                   <element name="value" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
+     *                 </sequence>
+     *               </restriction>
+     *             </complexContent>
+     *           </complexType>
+     *         </element>
+     *       </sequence>
+     *     </restriction>
+     *   </complexContent>
+     * </complexType>
+     * 
+ * + * + */ + @XmlAccessorType(XmlAccessType.FIELD) + @XmlType(name = "", propOrder = { + "entry" + }) + public static class Outputs { + + protected List entry; + + /** + * Gets the value of the entry property. + * + *

+ * This accessor method returns a reference to the live list, + * not a snapshot. Therefore any modification you make to the + * returned list will be present inside the JAXB object. + * This is why there is not a set method for the entry property. + * + *

+ * For example, to add a new item, do as follows: + *

+         *    getEntry().add(newItem);
+         * 
+ * + * + *

+ * Objects of the following type(s) are allowed in the list + * {@link QueryVnfNotification.Outputs.Entry } + * + * + */ + public List getEntry() { + if (entry == null) { + entry = new ArrayList(); + } + return this.entry; + } + + + /** + *

Java class for anonymous complex type. + * + *

The following schema fragment specifies the expected content contained within this class. + * + *

+         * <complexType>
+         *   <complexContent>
+         *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+         *       <sequence>
+         *         <element name="key" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
+         *         <element name="value" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
+         *       </sequence>
+         *     </restriction>
+         *   </complexContent>
+         * </complexType>
+         * 
+ * + * + */ + @XmlAccessorType(XmlAccessType.FIELD) + @XmlType(name = "", propOrder = { + "key", + "value" + }) + public static class Entry { + + protected String key; + protected String value; + + /** + * Gets the value of the key property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getKey() { + return key; + } + + /** + * Sets the value of the key property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setKey(String value) { + this.key = value; + } + + /** + * Gets the value of the value property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getValue() { + return value; + } + + /** + * Sets the value of the value property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setValue(String value) { + this.value = value; + } + + } + + } + +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/async/client/RollbackVnfNotification.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/async/client/RollbackVnfNotification.java new file mode 100644 index 0000000000..05947f5e62 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/async/client/RollbackVnfNotification.java @@ -0,0 +1,154 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.so.adapters.vnf.async.client; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlType; + + +/** + *

Java class for rollbackVnfNotification complex type. + * + *

The following schema fragment specifies the expected content contained within this class. + * + *

+ * <complexType name="rollbackVnfNotification">
+ *   <complexContent>
+ *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *       <sequence>
+ *         <element name="messageId" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ *         <element name="completed" type="{http://www.w3.org/2001/XMLSchema}boolean"/>
+ *         <element name="exception" type="{http://org.onap.so/vnfNotify}msoExceptionCategory" minOccurs="0"/>
+ *         <element name="errorMessage" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
+ *       </sequence>
+ *     </restriction>
+ *   </complexContent>
+ * </complexType>
+ * 
+ * + * + */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "rollbackVnfNotification", propOrder = { + "messageId", + "completed", + "exception", + "errorMessage" +}) +public class RollbackVnfNotification { + + @XmlElement(required = true) + protected String messageId; + protected boolean completed; + protected MsoExceptionCategory exception; + protected String errorMessage; + + /** + * Gets the value of the messageId property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getMessageId() { + return messageId; + } + + /** + * Sets the value of the messageId property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setMessageId(String value) { + this.messageId = value; + } + + /** + * Gets the value of the completed property. + * + */ + public boolean isCompleted() { + return completed; + } + + /** + * Sets the value of the completed property. + * + */ + public void setCompleted(boolean value) { + this.completed = value; + } + + /** + * Gets the value of the exception property. + * + * @return + * possible object is + * {@link MsoExceptionCategory } + * + */ + public MsoExceptionCategory getException() { + return exception; + } + + /** + * Sets the value of the exception property. + * + * @param value + * allowed object is + * {@link MsoExceptionCategory } + * + */ + public void setException(MsoExceptionCategory value) { + this.exception = value; + } + + /** + * Gets the value of the errorMessage property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getErrorMessage() { + return errorMessage; + } + + /** + * Sets the value of the errorMessage property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setErrorMessage(String value) { + this.errorMessage = value; + } + +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/async/client/UpdateVnfNotification.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/async/client/UpdateVnfNotification.java new file mode 100644 index 0000000000..13fa8cb0ef --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/async/client/UpdateVnfNotification.java @@ -0,0 +1,383 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.so.adapters.vnf.async.client; + +import java.util.ArrayList; +import java.util.List; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlType; + + +/** + *

Java class for updateVnfNotification complex type. + * + *

The following schema fragment specifies the expected content contained within this class. + * + *

+ * <complexType name="updateVnfNotification">
+ *   <complexContent>
+ *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *       <sequence>
+ *         <element name="messageId" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ *         <element name="completed" type="{http://www.w3.org/2001/XMLSchema}boolean"/>
+ *         <element name="exception" type="{http://org.onap.so/vnfNotify}msoExceptionCategory" minOccurs="0"/>
+ *         <element name="errorMessage" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
+ *         <element name="outputs" minOccurs="0">
+ *           <complexType>
+ *             <complexContent>
+ *               <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *                 <sequence>
+ *                   <element name="entry" maxOccurs="unbounded" minOccurs="0">
+ *                     <complexType>
+ *                       <complexContent>
+ *                         <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *                           <sequence>
+ *                             <element name="key" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
+ *                             <element name="value" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
+ *                           </sequence>
+ *                         </restriction>
+ *                       </complexContent>
+ *                     </complexType>
+ *                   </element>
+ *                 </sequence>
+ *               </restriction>
+ *             </complexContent>
+ *           </complexType>
+ *         </element>
+ *         <element name="rollback" type="{http://org.onap.so/vnfNotify}vnfRollback" minOccurs="0"/>
+ *       </sequence>
+ *     </restriction>
+ *   </complexContent>
+ * </complexType>
+ * 
+ * + * + */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "updateVnfNotification", propOrder = { + "messageId", + "completed", + "exception", + "errorMessage", + "outputs", + "rollback" +}) +public class UpdateVnfNotification { + + @XmlElement(required = true) + protected String messageId; + protected boolean completed; + protected MsoExceptionCategory exception; + protected String errorMessage; + protected UpdateVnfNotification.Outputs outputs; + protected VnfRollback rollback; + + /** + * Gets the value of the messageId property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getMessageId() { + return messageId; + } + + /** + * Sets the value of the messageId property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setMessageId(String value) { + this.messageId = value; + } + + /** + * Gets the value of the completed property. + * + */ + public boolean isCompleted() { + return completed; + } + + /** + * Sets the value of the completed property. + * + */ + public void setCompleted(boolean value) { + this.completed = value; + } + + /** + * Gets the value of the exception property. + * + * @return + * possible object is + * {@link MsoExceptionCategory } + * + */ + public MsoExceptionCategory getException() { + return exception; + } + + /** + * Sets the value of the exception property. + * + * @param value + * allowed object is + * {@link MsoExceptionCategory } + * + */ + public void setException(MsoExceptionCategory value) { + this.exception = value; + } + + /** + * Gets the value of the errorMessage property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getErrorMessage() { + return errorMessage; + } + + /** + * Sets the value of the errorMessage property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setErrorMessage(String value) { + this.errorMessage = value; + } + + /** + * Gets the value of the outputs property. + * + * @return + * possible object is + * {@link UpdateVnfNotification.Outputs } + * + */ + public UpdateVnfNotification.Outputs getOutputs() { + return outputs; + } + + /** + * Sets the value of the outputs property. + * + * @param value + * allowed object is + * {@link UpdateVnfNotification.Outputs } + * + */ + public void setOutputs(UpdateVnfNotification.Outputs value) { + this.outputs = value; + } + + /** + * Gets the value of the rollback property. + * + * @return + * possible object is + * {@link VnfRollback } + * + */ + public VnfRollback getRollback() { + return rollback; + } + + /** + * Sets the value of the rollback property. + * + * @param value + * allowed object is + * {@link VnfRollback } + * + */ + public void setRollback(VnfRollback value) { + this.rollback = value; + } + + + /** + *

Java class for anonymous complex type. + * + *

The following schema fragment specifies the expected content contained within this class. + * + *

+     * <complexType>
+     *   <complexContent>
+     *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+     *       <sequence>
+     *         <element name="entry" maxOccurs="unbounded" minOccurs="0">
+     *           <complexType>
+     *             <complexContent>
+     *               <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+     *                 <sequence>
+     *                   <element name="key" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
+     *                   <element name="value" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
+     *                 </sequence>
+     *               </restriction>
+     *             </complexContent>
+     *           </complexType>
+     *         </element>
+     *       </sequence>
+     *     </restriction>
+     *   </complexContent>
+     * </complexType>
+     * 
+ * + * + */ + @XmlAccessorType(XmlAccessType.FIELD) + @XmlType(name = "", propOrder = { + "entry" + }) + public static class Outputs { + + protected List entry; + + /** + * Gets the value of the entry property. + * + *

+ * This accessor method returns a reference to the live list, + * not a snapshot. Therefore any modification you make to the + * returned list will be present inside the JAXB object. + * This is why there is not a set method for the entry property. + * + *

+ * For example, to add a new item, do as follows: + *

+         *    getEntry().add(newItem);
+         * 
+ * + * + *

+ * Objects of the following type(s) are allowed in the list + * {@link UpdateVnfNotification.Outputs.Entry } + * + * + */ + public List getEntry() { + if (entry == null) { + entry = new ArrayList(); + } + return this.entry; + } + + + /** + *

Java class for anonymous complex type. + * + *

The following schema fragment specifies the expected content contained within this class. + * + *

+         * <complexType>
+         *   <complexContent>
+         *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+         *       <sequence>
+         *         <element name="key" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
+         *         <element name="value" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
+         *       </sequence>
+         *     </restriction>
+         *   </complexContent>
+         * </complexType>
+         * 
+ * + * + */ + @XmlAccessorType(XmlAccessType.FIELD) + @XmlType(name = "", propOrder = { + "key", + "value" + }) + public static class Entry { + + protected String key; + protected String value; + + /** + * Gets the value of the key property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getKey() { + return key; + } + + /** + * Sets the value of the key property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setKey(String value) { + this.key = value; + } + + /** + * Gets the value of the value property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getValue() { + return value; + } + + /** + * Sets the value of the value property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setValue(String value) { + this.value = value; + } + + } + + } + +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/async/client/VnfAdapterNotify.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/async/client/VnfAdapterNotify.java new file mode 100644 index 0000000000..24370b4d79 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/async/client/VnfAdapterNotify.java @@ -0,0 +1,177 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.so.adapters.vnf.async.client; + +import javax.jws.Oneway; +import javax.jws.WebMethod; +import javax.jws.WebParam; +import javax.jws.WebService; +import javax.xml.bind.annotation.XmlSeeAlso; +import javax.xml.ws.Action; +import javax.xml.ws.RequestWrapper; + + +/** + * This class was generated by the JAX-WS RI. + * JAX-WS RI 2.2.9-b14002 + * Generated source version: 2.2 + * + */ +@WebService(name = "vnfAdapterNotify", targetNamespace = "http://org.onap.so/vnfNotify") +@XmlSeeAlso({ + ObjectFactory.class +}) +public interface VnfAdapterNotify { + + + /** + * + * @param exception + * @param errorMessage + * @param messageId + * @param completed + */ + @WebMethod + @Oneway + @RequestWrapper(localName = "rollbackVnfNotification", targetNamespace = "http://org.onap.so/vnfNotify", className = "org.onap.so.adapters.vnf.async.client.RollbackVnfNotification") + @Action(input = "http://org.onap.so/notify/adapterNotify/rollbackVnfNotificationRequest") + public void rollbackVnfNotification( + @WebParam(name = "messageId", targetNamespace = "") + String messageId, + @WebParam(name = "completed", targetNamespace = "") + boolean completed, + @WebParam(name = "exception", targetNamespace = "") + MsoExceptionCategory exception, + @WebParam(name = "errorMessage", targetNamespace = "") + String errorMessage); + + /** + * + * @param exception + * @param outputs + * @param errorMessage + * @param vnfExists + * @param messageId + * @param completed + * @param vnfId + * @param status + */ + @WebMethod + @Oneway + @RequestWrapper(localName = "queryVnfNotification", targetNamespace = "http://org.onap.so/vnfNotify", className = "org.onap.so.adapters.vnf.async.client.QueryVnfNotification") + @Action(input = "http://org.onap.so/notify/adapterNotify/queryVnfNotificationRequest") + public void queryVnfNotification( + @WebParam(name = "messageId", targetNamespace = "") + String messageId, + @WebParam(name = "completed", targetNamespace = "") + boolean completed, + @WebParam(name = "exception", targetNamespace = "") + MsoExceptionCategory exception, + @WebParam(name = "errorMessage", targetNamespace = "") + String errorMessage, + @WebParam(name = "vnfExists", targetNamespace = "") + Boolean vnfExists, + @WebParam(name = "vnfId", targetNamespace = "") + String vnfId, + @WebParam(name = "status", targetNamespace = "") + VnfStatus status, + @WebParam(name = "outputs", targetNamespace = "") + org.onap.so.adapters.vnf.async.client.QueryVnfNotification.Outputs outputs); + + /** + * + * @param exception + * @param outputs + * @param rollback + * @param errorMessage + * @param messageId + * @param completed + * @param vnfId + */ + @WebMethod + @Oneway + @RequestWrapper(localName = "createVnfNotification", targetNamespace = "http://org.onap.so/vnfNotify", className = "org.onap.so.adapters.vnf.async.client.CreateVnfNotification") + @Action(input = "http://org.onap.so/notify/adapterNotify/createVnfNotificationRequest") + public void createVnfNotification( + @WebParam(name = "messageId", targetNamespace = "") + String messageId, + @WebParam(name = "completed", targetNamespace = "") + boolean completed, + @WebParam(name = "exception", targetNamespace = "") + MsoExceptionCategory exception, + @WebParam(name = "errorMessage", targetNamespace = "") + String errorMessage, + @WebParam(name = "vnfId", targetNamespace = "") + String vnfId, + @WebParam(name = "outputs", targetNamespace = "") + org.onap.so.adapters.vnf.async.client.CreateVnfNotification.Outputs outputs, + @WebParam(name = "rollback", targetNamespace = "") + VnfRollback rollback); + + /** + * + * @param exception + * @param outputs + * @param rollback + * @param errorMessage + * @param messageId + * @param completed + */ + @WebMethod + @Oneway + @RequestWrapper(localName = "updateVnfNotification", targetNamespace = "http://org.onap.so/vnfNotify", className = "org.onap.so.adapters.vnf.async.client.UpdateVnfNotification") + @Action(input = "http://org.onap.so/notify/adapterNotify/updateVnfNotificationRequest") + public void updateVnfNotification( + @WebParam(name = "messageId", targetNamespace = "") + String messageId, + @WebParam(name = "completed", targetNamespace = "") + boolean completed, + @WebParam(name = "exception", targetNamespace = "") + MsoExceptionCategory exception, + @WebParam(name = "errorMessage", targetNamespace = "") + String errorMessage, + @WebParam(name = "outputs", targetNamespace = "") + org.onap.so.adapters.vnf.async.client.UpdateVnfNotification.Outputs outputs, + @WebParam(name = "rollback", targetNamespace = "") + VnfRollback rollback); + + /** + * + * @param exception + * @param errorMessage + * @param messageId + * @param completed + */ + @WebMethod + @Oneway + @RequestWrapper(localName = "deleteVnfNotification", targetNamespace = "http://org.onap.so/vnfNotify", className = "org.onap.so.adapters.vnf.async.client.DeleteVnfNotification") + @Action(input = "http://org.onap.so/notify/adapterNotify/deleteVnfNotificationRequest") + public void deleteVnfNotification( + @WebParam(name = "messageId", targetNamespace = "") + String messageId, + @WebParam(name = "completed", targetNamespace = "") + boolean completed, + @WebParam(name = "exception", targetNamespace = "") + MsoExceptionCategory exception, + @WebParam(name = "errorMessage", targetNamespace = "") + String errorMessage); + +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/async/client/VnfAdapterNotify_Service.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/async/client/VnfAdapterNotify_Service.java new file mode 100644 index 0000000000..4b140b1b30 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/async/client/VnfAdapterNotify_Service.java @@ -0,0 +1,110 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.so.adapters.vnf.async.client; + +import java.net.URL; + +import javax.xml.namespace.QName; +import javax.xml.ws.Service; +import javax.xml.ws.WebEndpoint; +import javax.xml.ws.WebServiceClient; +import javax.xml.ws.WebServiceException; +import javax.xml.ws.WebServiceFeature; + + +/** + * This class was generated by the JAX-WS RI. + * JAX-WS RI 2.2.9-b14002 + * Generated source version: 2.2 + * + */ +@WebServiceClient(name = "vnfAdapterNotify", targetNamespace = "http://org.onap.so/vnfNotify", wsdlLocation = "/VnfAdapterNotify.wsdl") +public class VnfAdapterNotify_Service + extends Service +{ + + private final static URL VNFADAPTERNOTIFY_WSDL_LOCATION; + private final static WebServiceException VNFADAPTERNOTIFY_EXCEPTION; + private final static QName VNFADAPTERNOTIFY_QNAME = new QName("http://org.onap.so/vnfNotify", "vnfAdapterNotify"); + + static { + VNFADAPTERNOTIFY_WSDL_LOCATION = org.onap.so.adapters.vnf.async.client.VnfAdapterNotify_Service.class.getResource("/VnfAdapterNotify.wsdl"); + WebServiceException e = null; + if (VNFADAPTERNOTIFY_WSDL_LOCATION == null) { + e = new WebServiceException("Cannot find '/VnfAdapterNotify.wsdl' wsdl. Place the resource correctly in the classpath."); + } + VNFADAPTERNOTIFY_EXCEPTION = e; + } + + public VnfAdapterNotify_Service() { + super(__getWsdlLocation(), VNFADAPTERNOTIFY_QNAME); + } + + public VnfAdapterNotify_Service(WebServiceFeature... features) { + super(__getWsdlLocation(), VNFADAPTERNOTIFY_QNAME, features); + } + + public VnfAdapterNotify_Service(URL wsdlLocation) { + super(wsdlLocation, VNFADAPTERNOTIFY_QNAME); + } + + public VnfAdapterNotify_Service(URL wsdlLocation, WebServiceFeature... features) { + super(wsdlLocation, VNFADAPTERNOTIFY_QNAME, features); + } + + public VnfAdapterNotify_Service(URL wsdlLocation, QName serviceName) { + super(wsdlLocation, serviceName); + } + + public VnfAdapterNotify_Service(URL wsdlLocation, QName serviceName, WebServiceFeature... features) { + super(wsdlLocation, serviceName, features); + } + + /** + * + * @return + * returns VnfAdapterNotify + */ + @WebEndpoint(name = "MsoVnfAdapterAsyncImplPort") + public VnfAdapterNotify getMsoVnfAdapterAsyncImplPort() { + return super.getPort(new QName("http://org.onap.so/vnfNotify", "MsoVnfAdapterAsyncImplPort"), VnfAdapterNotify.class); + } + + /** + * + * @param features + * A list of {@link javax.xml.ws.WebServiceFeature} to configure on the proxy. Supported features not in the features parameter will have their default values. + * @return + * returns VnfAdapterNotify + */ + @WebEndpoint(name = "MsoVnfAdapterAsyncImplPort") + public VnfAdapterNotify getMsoVnfAdapterAsyncImplPort(WebServiceFeature... features) { + return super.getPort(new QName("http://org.onap.so/vnfNotify", "MsoVnfAdapterAsyncImplPort"), VnfAdapterNotify.class, features); + } + + private static URL __getWsdlLocation() { + if (VNFADAPTERNOTIFY_EXCEPTION!= null) { + throw VNFADAPTERNOTIFY_EXCEPTION; + } + return VNFADAPTERNOTIFY_WSDL_LOCATION; + } + +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/async/client/VnfRollback.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/async/client/VnfRollback.java new file mode 100644 index 0000000000..9ad20738d0 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/async/client/VnfRollback.java @@ -0,0 +1,198 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.so.adapters.vnf.async.client; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlType; + + +/** + *

Java class for vnfRollback complex type. + * + *

The following schema fragment specifies the expected content contained within this class. + * + *

+ * <complexType name="vnfRollback">
+ *   <complexContent>
+ *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *       <sequence>
+ *         <element name="cloudSiteId" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
+ *         <element name="msoRequest" type="{http://org.onap.so/vnfNotify}msoRequest" minOccurs="0"/>
+ *         <element name="tenantCreated" type="{http://www.w3.org/2001/XMLSchema}boolean"/>
+ *         <element name="tenantId" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
+ *         <element name="vnfCreated" type="{http://www.w3.org/2001/XMLSchema}boolean"/>
+ *         <element name="vnfId" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
+ *       </sequence>
+ *     </restriction>
+ *   </complexContent>
+ * </complexType>
+ * 
+ * + * + */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "vnfRollback", propOrder = { + "cloudSiteId", + "msoRequest", + "tenantCreated", + "tenantId", + "vnfCreated", + "vnfId" +}) +public class VnfRollback { + + protected String cloudSiteId; + protected MsoRequest msoRequest; + protected boolean tenantCreated; + protected String tenantId; + protected boolean vnfCreated; + protected String vnfId; + + /** + * Gets the value of the cloudSiteId property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getCloudSiteId() { + return cloudSiteId; + } + + /** + * Sets the value of the cloudSiteId property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setCloudSiteId(String value) { + this.cloudSiteId = value; + } + + /** + * Gets the value of the msoRequest property. + * + * @return + * possible object is + * {@link MsoRequest } + * + */ + public MsoRequest getMsoRequest() { + return msoRequest; + } + + /** + * Sets the value of the msoRequest property. + * + * @param value + * allowed object is + * {@link MsoRequest } + * + */ + public void setMsoRequest(MsoRequest value) { + this.msoRequest = value; + } + + /** + * Gets the value of the tenantCreated property. + * + */ + public boolean isTenantCreated() { + return tenantCreated; + } + + /** + * Sets the value of the tenantCreated property. + * + */ + public void setTenantCreated(boolean value) { + this.tenantCreated = value; + } + + /** + * Gets the value of the tenantId property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getTenantId() { + return tenantId; + } + + /** + * Sets the value of the tenantId property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setTenantId(String value) { + this.tenantId = value; + } + + /** + * Gets the value of the vnfCreated property. + * + */ + public boolean isVnfCreated() { + return vnfCreated; + } + + /** + * Sets the value of the vnfCreated property. + * + */ + public void setVnfCreated(boolean value) { + this.vnfCreated = value; + } + + /** + * Gets the value of the vnfId property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getVnfId() { + return vnfId; + } + + /** + * Sets the value of the vnfId property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setVnfId(String value) { + this.vnfId = value; + } + +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/async/client/VnfStatus.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/async/client/VnfStatus.java new file mode 100644 index 0000000000..1998ae0ce9 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/async/client/VnfStatus.java @@ -0,0 +1,61 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.so.adapters.vnf.async.client; + +import javax.xml.bind.annotation.XmlEnum; +import javax.xml.bind.annotation.XmlType; + + +/** + *

Java class for vnfStatus. + * + *

The following schema fragment specifies the expected content contained within this class. + *

+ *

+ * <simpleType name="vnfStatus">
+ *   <restriction base="{http://www.w3.org/2001/XMLSchema}string">
+ *     <enumeration value="ACTIVE"/>
+ *     <enumeration value="FAILED"/>
+ *     <enumeration value="NOTFOUND"/>
+ *     <enumeration value="UNKNOWN"/>
+ *   </restriction>
+ * </simpleType>
+ * 
+ * + */ +@XmlType(name = "vnfStatus") +@XmlEnum +public enum VnfStatus { + + ACTIVE, + FAILED, + NOTFOUND, + UNKNOWN; + + public String value() { + return name(); + } + + public static VnfStatus fromValue(String v) { + return valueOf(v); + } + +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/async/client/package-info.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/async/client/package-info.java new file mode 100644 index 0000000000..cc4a2a78ec --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/async/client/package-info.java @@ -0,0 +1,21 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * 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========================================================= + */ +@javax.xml.bind.annotation.XmlSchema(namespace = "http://org.onap.so/vnfNotify") +package org.onap.so.adapters.vnf.async.client; diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/exceptions/VnfAlreadyExists.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/exceptions/VnfAlreadyExists.java new file mode 100644 index 0000000000..2a7f33a682 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/exceptions/VnfAlreadyExists.java @@ -0,0 +1,42 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.so.adapters.vnf.exceptions; + + + +import javax.xml.ws.WebFault; + +/** + * This class reports an exception when trying to create a VNF when another + * VNF of the same name already exists in the target cloud/tenant. Note that + * the createVnf method suppresses this exception by default. + * + * + */ +@WebFault (name="VnfAlreadyExists", faultBean="org.onap.so.adapters.vnf.exceptions.VnfExceptionBean", targetNamespace="http://org.onap.so/vnf") +public class VnfAlreadyExists extends VnfException { + + private static final long serialVersionUID = 1L; + + public VnfAlreadyExists (String name, String cloudId, String tenantId, String vnfId) { + super("Resource " + name + " already exists in cloud/tenant " + cloudId + "/" + tenantId + " with ID " + vnfId); + } +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/exceptions/VnfException.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/exceptions/VnfException.java new file mode 100644 index 0000000000..39f48e64dd --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/exceptions/VnfException.java @@ -0,0 +1,80 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.so.adapters.vnf.exceptions; + + + +import javax.xml.ws.WebFault; + +import org.onap.so.openstack.exceptions.MsoException; +import org.onap.so.openstack.exceptions.MsoExceptionCategory; + +/** + * This class simply extends Exception (without addition additional functionality) + * to provide an identifier for VNF related exceptions on create, delete, query. + * + * + */ +@WebFault (name="VnfException", faultBean="org.onap.so.adapters.vnf.exceptions.VnfExceptionBean", targetNamespace="http://org.onap.so/vnf") +public class VnfException extends Exception { + + private static final long serialVersionUID = 1L; + + private VnfExceptionBean faultInfo; + + public VnfException (String msg) { + super(msg); + faultInfo = new VnfExceptionBean (msg); + } + + public VnfException (Throwable e) { + super(e); + faultInfo = new VnfExceptionBean (e.getMessage()); + } + + public VnfException (String msg, Throwable e) { + super (msg, e); + faultInfo = new VnfExceptionBean (msg); + } + + public VnfException (String msg, MsoExceptionCategory category) { + super(msg); + faultInfo = new VnfExceptionBean (msg, category); + } + + public VnfException (String msg, MsoExceptionCategory category, Throwable e) { + super (msg, e); + faultInfo = new VnfExceptionBean (msg, category); + } + + public VnfException (MsoException e) { + super (e); + faultInfo = new VnfExceptionBean (e.getContextMessage(), e.getCategory()); + } + + public VnfExceptionBean getFaultInfo() { + return faultInfo; + } + + public void setFaultInfo(VnfExceptionBean faultInfo) { + this.faultInfo = faultInfo; + } +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/exceptions/VnfExceptionBean.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/exceptions/VnfExceptionBean.java new file mode 100644 index 0000000000..011afa72ee --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/exceptions/VnfExceptionBean.java @@ -0,0 +1,74 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.so.adapters.vnf.exceptions; + + +import java.io.Serializable; + +import org.onap.so.openstack.exceptions.MsoExceptionCategory; + +/** + * Jax-WS Fault Bean for Vnf Exception + */ +public class VnfExceptionBean implements Serializable { + + private static final long serialVersionUID = -5699310749783790095L; + + private String message; + private MsoExceptionCategory category; + private Boolean rolledBack; + + public VnfExceptionBean () {} + + public VnfExceptionBean (String message) { + // Create a default category to prevent null pointer exceptions + this(message, MsoExceptionCategory.INTERNAL); + } + + public VnfExceptionBean (String message, MsoExceptionCategory category) { + this.message = message; + this.category = category; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + public MsoExceptionCategory getCategory () { + return category; + } + + public void setCategory (MsoExceptionCategory category) { + this.category = category; + } + + public Boolean isRolledBack() { + return rolledBack; + } + + public void setRolledBack(Boolean rolledBack) { + this.rolledBack = rolledBack; + } +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/exceptions/VnfNotFound.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/exceptions/VnfNotFound.java new file mode 100644 index 0000000000..f3fa39cc2d --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/exceptions/VnfNotFound.java @@ -0,0 +1,41 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.so.adapters.vnf.exceptions; + + +import javax.xml.ws.WebFault; + +/** + * This class reports an exception when trying to update a Network that does + * not exist in the target cloud/tenant. Note that deleteNetwork suppresses + * this exception (deletion of non-existent network is considered a success). + * + * + */ +@WebFault (name="VnfNotFound", faultBean="org.onap.so.adapters.vnf.exceptions.VnfExceptionBean", targetNamespace="http://org.onap.so/vnf") +public class VnfNotFound extends VnfException { + + private static final long serialVersionUID = 1L; + + public VnfNotFound (String cloudId, String tenantId, String vnfName) { + super("Resource " + vnfName + " not found in cloud/tenant " + cloudId + "/" + tenantId); + } +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/vdu/utils/VduBlueprint.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/vdu/utils/VduBlueprint.java new file mode 100644 index 0000000000..cef0371789 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/vdu/utils/VduBlueprint.java @@ -0,0 +1,90 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.so.vdu.utils; + +import java.util.Map; + +/* + * This Java bean class describes the template model of a VDU as distributed + * by SDC to SO. It is composed of one or more templates, one of which must be + * the main template, + * + * The structure of this class corresponds to the format in which the templates + * and associated artifacts are represented in the SO Catalog. + * + * The map keys will be the "path" that is used to reference these artifacts within + * the other templates. This may be relevant to how different VDU plugins package + * the files for delivery to the sub-orchestrator. + * + * In the future, it is possible that pre-packaged blueprints (e.g. complete TOSCA CSARs) + * could be stored in the catalog (and added to this structure). + * + * This bean is passed as an input to instantiateVdu and updateVdu. + */ + +public class VduBlueprint { + String vduModelId; + String mainTemplateName; + Map templateFiles; + Map attachedFiles; + + public String getVduModelId() { + return vduModelId; + } + + public void setVduModelId(String vduModelId) { + this.vduModelId = vduModelId; + } + + public String getMainTemplateName() { + return mainTemplateName; + } + + public void setMainTemplateName(String mainTemplateName) { + this.mainTemplateName = mainTemplateName; + } + + public Map getTemplateFiles() { + return templateFiles; + } + + public void setTemplateFiles(Map templateFiles) { + this.templateFiles = templateFiles; + } + + public Map getAttachedFiles() { + return attachedFiles; + } + + public void setAttachedFiles(Map attachedFiles) { + this.attachedFiles = attachedFiles; + } + + @Override + public String toString() { + return "VduInfo {" + + "id='" + vduModelId + '\'' + + "mainTemplateName='" + mainTemplateName + '\'' + + '}'; + } + +} + diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/vdu/utils/VduInfo.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/vdu/utils/VduInfo.java new file mode 100644 index 0000000000..227d513a0b --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/vdu/utils/VduInfo.java @@ -0,0 +1,130 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.so.vdu.utils; + +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 MsoVduUtils interface operations + * (instantiate, query, delete). + */ + +public class VduInfo { + // Set defaults for everything + private String vduInstanceId = ""; + private String vduInstanceName = ""; + private VduStatus status = VduStatus.NOTFOUND; + private Map outputs = new HashMap<>(); + private Map inputs = new HashMap<>(); + private String lastAction; + private String actionStatus; + private String errorMessage; + + public VduInfo () { + } + + // Add more constructors as appropriate + // + + public VduInfo (String id, Map outputs) { + this.vduInstanceId = id; + if (outputs != null) this.outputs = outputs; + } + + public VduInfo (String id) { + this.vduInstanceId = id; + } + + public VduInfo (String id, VduStatus status) { + this.vduInstanceId = id; + this.status = status; + } + + public String getVnfInstanceId() { + return vduInstanceId; + } + + public void setVnfInstanceId (String id) { + this.vduInstanceId = id; + } + + public String getVnfInstanceName() { + return vduInstanceName; + } + + public void setVnfInstanceName (String name) { + this.vduInstanceName = name; + } + + 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; + } + + public String getLastAction() { + return lastAction; + } + + public String getActionStatus() { + return actionStatus; + } + + public String getErrorMessage() { + return errorMessage; + } + + @Override + public String toString() { + return "VduInfo {" + + "id='" + vduInstanceId + '\'' + + "name='" + vduInstanceName + '\'' + + ", inputs='" + inputs + '\'' + + ", outputs='" + outputs + '\'' + + ", lastAction='" + lastAction + '\'' + + ", status='" + status + '\'' + + ", errorMessage='" + errorMessage + '\'' + + '}'; + } + +} + diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/vdu/utils/VduPlugin.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/vdu/utils/VduPlugin.java new file mode 100644 index 0000000000..871260a86d --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/vdu/utils/VduPlugin.java @@ -0,0 +1,248 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ +package org.onap.so.vdu.utils; + +/** + * 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; + +import org.onap.so.openstack.exceptions.MsoException; + +public interface VduPlugin { + + /** + * The instantiateVdu interface deploys a new VDU instance from a blueprint package. + * The templates and files in the blueprint may be pre-installed where supported + * (e.g. in Cloudify or Aria), or may be passed in directly (e.g. for Heat). These + * files are expressed as byte arrays, though only text files are expected from ASDC. + * + * 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 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 cloudSiteId The target cloud for the VDU. Maps to a CloudConfig entry. + * @param tenantId The cloud tenant in which to deploy the VDU. The meaning may differ by + * cloud provider, but every cloud supports some sort of tenant partitioning. + * @param vduInstanceName A unique name for the VDU instance to create + * @param vduBlueprint Object containing the collection of templates and files that comprise + * the blueprint for this VDU. + * @param inputs A map of key/value inputs. Values may be strings, numbers, or JSON objects. + * @param environmentFile A file containing default parameter name/value pairs. This is + * primarily for Heat, though ASDC may create a similar file for other orchestrators. + * @param timeoutMinutes Timeout after which the instantiation attempt will be cancelled + * @param suppressBackout Flag to preserve the deployment on install Failure. Should normally + * be False except in troubleshooting/debug cases + * + * @return A VduInfo object + * @throws MsoException Thrown if the sub-orchestrator API calls fail or if a timeout occurs. + * Various subclasses of MsoException may be thrown. + */ + public VduInfo instantiateVdu ( + String cloudSiteId, + String tenantId, + String vduInstanceName, + VduBlueprint vduBlueprint, + Map inputs, + String environmentFile, + int timeoutMinutes, + boolean suppressBackout) + throws MsoException; + + + /** + * Query a deployed VDU instance. This call will return a VduInfo 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 VduInfo object contains the input and output parameter maps, + * as well as other properties of the deployment (name, status, last action, etc.). + * + * @param cloudSiteId The target cloud to query for the VDU. + * @param tenantId The cloud tenant in which to query + * @param vduInstanceId The ID of the deployment to query + * + * @return A VduInfo object + * @throws MsoException Thrown if the VIM/sub-orchestrator API calls fail. + * Various subclasses of MsoException may be thrown. + */ + public VduInfo queryVdu ( + String cloudSiteId, + String tenantId, + String vduInstanceId) + throws MsoException; + + + /** + * Delete a VDU instance by ID. If the VIM sub-orchestrator supports pre-installation + * of blueprints, 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 implementation. The deletion should be fully + * completed before returning. + * + * The successful return is a VduInfo object which contains the state of the object just prior + * to deletion, with a status of DELETED. If the deployment was not found, the VduInfo 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 cloudSiteId The target cloud from which to delete the VDU. + * @param tenantId The cloud tenant in which to delete the VDU. + * @param vduInstanceId The unique id of the deployment to delete. + * @param timeoutMinutes Timeout after which the delete action will be cancelled + * @param keepBlueprintLoaded Flag to also delete the blueprint + * + * @return A VduInfo object, representing the state of the instance just prior to deletion. + * + * @throws MsoException Thrown if the API calls fail or if a timeout occurs. + * Various subclasses of MsoException may be thrown. + */ + public VduInfo deleteVdu ( + String cloudSiteId, + String tenantId, + String vduInstanceId, + int timeoutMinutes, + boolean keepBlueprintLoaded) + throws MsoException; + + + /** + * 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 + * VduInfo 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 cloudSiteId The target cloud for the VDU. Maps to a CloudConfig entry. + * @param tenantId The cloud tenant in which to deploy the VDU. The meaning may differ by + * cloud provider, but every cloud supports some sort of tenant partitioning. + * @param vduInstanceId The unique ID for the VDU instance to update. + * @param vduBlueprint Object containing the collection of templates and files that comprise + * the blueprint for this VDU. + * @param inputs A map of key/value inputs. Values may be strings, numbers, or JSON objects. + * @param environmentFile A file containing default parameter name/value pairs. This is + * primarily for Heat, though ASDC may create a similar file for other orchestrators. + * @param timeoutMinutes Timeout after which the instantiation attempt will be cancelled + * + * @return A VduInfo object + * @throws MsoException Thrown if the sub-orchestrator API calls fail or if a timeout occurs. + * Various subclasses of MsoException may be thrown. + */ + public VduInfo updateVdu ( + String cloudSiteId, + String tenantId, + String vduInstanceId, + VduBlueprint vduBlueprint, + Map inputs, + String environmentFile, + int timeoutMinutes) + throws MsoException; + + + /** + * Check if a blueprint package has been installed in the sub-orchestrator and available + * for use at a targeted cloud site. If the specific sub-orchestrator does not support + * pre-installation, then those implementations should always return False. + * + * @param cloudSiteId The cloud site where the blueprint is needed + * @param vduModelId Unique ID of the VDU model to query + * + * @throws MsoException Thrown if the API call fails. + */ + public boolean isBlueprintLoaded (String cloudSiteId, String vduModelId) + throws MsoException; + + + /** + * Install a blueprint package to the target sub-orchestrator for a cloud site. + * The blueprints currently must be structured as a single directory with all of the + * required files. One of those files is designated the "main file" for the blueprint. + * Files are provided as byte arrays, though expect only text files will be distributed + * from ASDC and stored by MSO. + * + * @param cloudSiteId The cloud site where the blueprint is needed + * @param vduBlueprint Object containing the collection of templates and files that comprise + * the blueprint for this VDU. + * @param failIfExists Flag to return an error if blueprint already exists + * + * @throws MsoException Thrown if the API call fails. + */ + public void uploadBlueprint (String cloudSiteId, + VduBlueprint vduBlueprint, + boolean failIfExists) + throws MsoException; + + /** + * Indicator that this VIM sub-orchestrator implementation supports independent upload + * of blueprint packages. Each implementation should return a constant value. + * + * @returns True if the sub-orchestrator supports blueprint pre-installation (upload). + */ + public boolean blueprintUploadSupported (); + +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/vdu/utils/VduStatus.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/vdu/utils/VduStatus.java new file mode 100644 index 0000000000..1412b02da0 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/vdu/utils/VduStatus.java @@ -0,0 +1,37 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.so.vdu.utils; + + +/* + * Enum status values to capture the state of a generic (cloud-agnostic) VDU. + */ +public enum VduStatus { + NOTFOUND, + INSTANTIATING, + INSTANTIATED, + DELETING, + DELETED, // Note - only returned in success response to deleteVdu call. + UPDATING, + FAILED, + UNKNOWN +} + diff --git a/adapters/mso-openstack-adapters/src/main/resources/NetworkAdapterNotify.wsdl b/adapters/mso-openstack-adapters/src/main/resources/NetworkAdapterNotify.wsdl new file mode 100644 index 0000000000..900389f205 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/resources/NetworkAdapterNotify.wsdl @@ -0,0 +1,295 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/adapters/mso-openstack-adapters/src/main/resources/VnfAdapterNotify.wsdl b/adapters/mso-openstack-adapters/src/main/resources/VnfAdapterNotify.wsdl new file mode 100644 index 0000000000..eb3f1033cd --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/resources/VnfAdapterNotify.wsdl @@ -0,0 +1,218 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/adapters/mso-openstack-adapters/src/main/resources/application-local.yaml b/adapters/mso-openstack-adapters/src/main/resources/application-local.yaml new file mode 100644 index 0000000000..fa6078689e --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/resources/application-local.yaml @@ -0,0 +1,134 @@ +# will be used as entry in DB to say SITE OFF/ON for healthcheck +# MSO Properties go here +org: + onap: + so: + adapters: + default_keystone_url_version: /v2.0 + default_keystone_reg_ex: "/[vV][0-9]" + vnf: + bpelauth: d95a1aa9bd4d39f3ec23cb5ed2358f5f75fa14bc8c978664355661c0858d2505 + checkRequiredParameters: true + addGetFilesOnVolumeReq: false + sockettimeout: 30 + connecttimeout: 30 + retrycount: 5 + retryinterval: -15 + retrylist: 408,429,500,502,503,504,900 + network: + bpelauth: d95a1aa9bd4d39f3ec23cb5ed2358f5f75fa14bc8c978664355661c0858d2505 + sockettimeout: 5 + connecttimeout: 5 + retrycount: 5 + retryinterval: -15 + retrylist: 408,429,500,502,503,504,900 + tenant: + default_x_aic_orm_client_string: ECOMP-MSO + default_keystone_url_version: /v2.0 + default_keystone_reg_ex: "/[vV][0-9]" + default_tenant_description: ECOMP Tenant + default_region_type: single + default_user_role: admin + default_success_status_string: Success + default_no_regions_status_string: no regions + default_orm_request_path: /v1/orm/customers/ + default_orm_url_replace_this: 8080 + default_orm_url_replace_with_this: 7080 + default_quota_value: 10 + set_default_quota: false +ecomp: + mso: + adapters: + po: + retryCodes: 504 + retryDelay: 5 + retryCount: 3 + pollTimeout: 7500 + pollInterval: 15 + +server-port: 8080 +ssl-enable: false +tomcat: + max-threads: 50 +mso: + logPath: logs + catalog: + db: + spring: + endpoint: "http://localhost:8080" + db: + auth: Basic YnBlbDptc28tZGItMTUwNyE= + site-name: localDevEnv + async: + core-pool-size: 50 + max-pool-size: 50 + queue-capacity: 500 +# H2 +spring: + datasource: + url: jdbc:h2:mem:test;DB_CLOSE_DELAY=-1; + username: sa + password: sa + driver-class-name: org.h2.Driver + intialize: true + h2: + console: + enabled: true + path: /h2 + + jpa: + show-sql: true + hibernate: + dialect: org.hibernate.dialect.MySQL5Dialect + ddl-auto: validate + naming-strategy: org.hibernate.cfg.ImprovedNamingStrategy + enable_lazy_load_no_trans: true + security: + usercredentials: + - + username: sdnc + password: '$2a$12$mukkC6IvLikKGBdwqGnev.H0ccvV6K13TFeLvyNhJoCuNkRjWhqi6' + role: SDNC-Client + - + username: sitecontrol + password: '$2a$12$VBUF.qBmeK1FNyO2MqTpD.P2M1tvlesZlhCkAjjHvF9hmYNVdMDmu' + role: SiteControl-Client + - + username: bpel + password: '$2a$12$/GW0/AVAUooTag.7GDc9a.jW7XH3nq/.QsJJJFZJ0N24iXB2W9ksO' + role: BPEL-Client + - + username: sniro + password: '$2a$12$lbOQWS1iDmdQPxW2Mb6OiuTzGaPUrkrvoKVn2zwpFWb6n5Y86Lf1y' + role: SNIRO-Client + - + username: apih + password: '$2a$12$e1BGJ7qknMN/b7bqsQvU2OT9iGunt9IlfQclKlCs6n240oHBfcO5y' + role: MSO-Client + - + username: mso_admin + password: '$2a$12$tidKuu.h88E2nuL95pTVY.ZOYMN/1dp29A9b1o.0GFDsVVSYlMkHa' + role: ACTUATOR + +#Actuator +management: + context-path: /manage + +cloud_config: + identity_services: + MTN13: + identity_url: "http://localhost:5000/v2.0" + mso_id: "m93945" + mso_pass: "93937EA01B94A10A49279D4572B48369" + admin_tenant: "admin" + member_role: "admin" + tenant_metadata: true + identity_server_type: "KEYSTONE" + identity_authentication_type: "USERNAME_PASSWORD" + cloud_sites: + mtn13: + region_id: "mtn13" + clli: "MDT13" + aic_version: "3.0" + identity_service_id: "MTN13" + diff --git a/adapters/mso-openstack-adapters/src/main/resources/application.yaml b/adapters/mso-openstack-adapters/src/main/resources/application.yaml new file mode 100644 index 0000000000..faca1a3056 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/resources/application.yaml @@ -0,0 +1,40 @@ +# will be used as entry in DB to say SITE OFF/ON for healthcheck +# MSO Properties go here + +server: + port: 8080 + tomcat: + max-threads: 50 + +mso: + logPath: ./logs/openstack + site-name: localDevEnv + async: + core-pool-size: 50 + max-pool-size: 50 + queue-capacity: 500 + +# CatalogDB +spring: + datasource: + url: jdbc:mariadb://${DB_HOST}:${DB_PORT}/catalogdb + username: ${DB_USERNAME} + password: ${DB_PASSWORD} + driver-class-name: org.mariadb.jdbc.Driver + dbcp2: + initial-size: 5 + max-total: 20 + validation-query: select 1 + test-on-borrow: true + jpa: + show-sql: true + hibernate: + dialect: org.hibernate.dialect.MySQL5Dialect + ddl-auto: validate + naming-strategy: org.hibernate.cfg.ImprovedNamingStrategy + enable-lazy-load-no-trans: true + + +#Actuator +management: + context-path: /manage diff --git a/adapters/mso-openstack-adapters/src/main/resources/static/index.html b/adapters/mso-openstack-adapters/src/main/resources/static/index.html new file mode 100644 index 0000000000..2940adee10 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/resources/static/index.html @@ -0,0 +1,35 @@ + + + + SO Openstack Adapters + + +
+ + + + + + + + + + + + + + +
+ Available Services +
+ Swagger UI +
+ View Current Properties +
+ View Health +
+ View Metrics +
+
+ + \ No newline at end of file diff --git a/adapters/mso-openstack-adapters/src/main/resources/static/swagger/favicon-16x16.png b/adapters/mso-openstack-adapters/src/main/resources/static/swagger/favicon-16x16.png new file mode 100644 index 0000000000..0f7e13b0d9 Binary files /dev/null and b/adapters/mso-openstack-adapters/src/main/resources/static/swagger/favicon-16x16.png differ diff --git a/adapters/mso-openstack-adapters/src/main/resources/static/swagger/favicon-32x32.png b/adapters/mso-openstack-adapters/src/main/resources/static/swagger/favicon-32x32.png new file mode 100644 index 0000000000..b0a3352ffd Binary files /dev/null and b/adapters/mso-openstack-adapters/src/main/resources/static/swagger/favicon-32x32.png differ diff --git a/adapters/mso-openstack-adapters/src/main/resources/static/swagger/index.html b/adapters/mso-openstack-adapters/src/main/resources/static/swagger/index.html new file mode 100644 index 0000000000..7be0528b46 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/resources/static/swagger/index.html @@ -0,0 +1,110 @@ + + + + + + Swagger UI + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + diff --git a/adapters/mso-openstack-adapters/src/main/resources/static/swagger/oauth2-redirect.html b/adapters/mso-openstack-adapters/src/main/resources/static/swagger/oauth2-redirect.html new file mode 100644 index 0000000000..eb00dc686a --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/resources/static/swagger/oauth2-redirect.html @@ -0,0 +1,60 @@ + + + + + + diff --git a/adapters/mso-openstack-adapters/src/main/resources/static/swagger/swagger-ui-bundle.js b/adapters/mso-openstack-adapters/src/main/resources/static/swagger/swagger-ui-bundle.js new file mode 100644 index 0000000000..e6e9789ed9 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/resources/static/swagger/swagger-ui-bundle.js @@ -0,0 +1,99 @@ +!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.SwaggerUIBundle=t():e.SwaggerUIBundle=t()}(this,function(){return function(e){function t(r){if(n[r])return n[r].exports;var i=n[r]={i:r,l:!1,exports:{}};return e[r].call(i.exports,i,i.exports,t),i.l=!0,i.exports}var n={};return t.m=e,t.c=n,t.i=function(e){return e},t.d=function(e,n,r){t.o(e,n)||Object.defineProperty(e,n,{configurable:!1,enumerable:!0,get:r})},t.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(n,"a",n),n},t.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},t.p="/dist",t(t.s=1212)}([function(e,t,n){"use strict";e.exports=n(93)},function(e,t,n){e.exports=n(995)()},function(e,t,n){"use strict";t.__esModule=!0,t.default=function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}},function(e,t,n){"use strict";t.__esModule=!0;var r=n(332),i=function(e){return e&&e.__esModule?e:{default:e}}(r);t.default=function(){function e(e,t){for(var n=0;n>>0;if(""+n!==t||4294967295===n)return NaN;t=n}return t<0?d(e)+t:t}function v(){return!0}function g(e,t,n){return(0===e||void 0!==n&&e<=-n)&&(void 0===t||void 0!==n&&t>=n)}function y(e,t){return b(e,t,0)}function _(e,t){return b(e,t,t)}function b(e,t,n){return void 0===e?n:e<0?Math.max(0,t+e):void 0===t?e:Math.min(t,e)}function x(e){this.next=e}function w(e,t,n,r){var i=0===e?t:1===e?n:[t,n];return r?r.value=i:r={value:i,done:!1},r}function k(){return{value:void 0,done:!0}}function E(e){return!!A(e)}function S(e){return e&&"function"==typeof e.next}function C(e){var t=A(e);return t&&t.call(e)}function A(e){var t=e&&(wn&&e[wn]||e[kn]);if("function"==typeof t)return t}function D(e){return e&&"number"==typeof e.length}function O(e){return null===e||void 0===e?B():o(e)?e.toSeq():z(e)}function M(e){return null===e||void 0===e?B().toKeyedSeq():o(e)?a(e)?e.toSeq():e.fromEntrySeq():L(e)}function T(e){return null===e||void 0===e?B():o(e)?a(e)?e.entrySeq():e.toIndexedSeq():q(e)}function P(e){return(null===e||void 0===e?B():o(e)?a(e)?e.entrySeq():e:q(e)).toSetSeq()}function I(e){this._array=e,this.size=e.length}function R(e){var t=Object.keys(e);this._object=e,this._keys=t,this.size=t.length}function F(e){this._iterable=e,this.size=e.length||e.size}function j(e){this._iterator=e,this._iteratorCache=[]}function N(e){return!(!e||!e[Sn])}function B(){return Cn||(Cn=new I([]))}function L(e){var t=Array.isArray(e)?new I(e).fromEntrySeq():S(e)?new j(e).fromEntrySeq():E(e)?new F(e).fromEntrySeq():"object"==typeof e?new R(e):void 0;if(!t)throw new TypeError("Expected Array or iterable object of [k, v] entries, or keyed object: "+e);return t}function q(e){var t=U(e);if(!t)throw new TypeError("Expected Array or iterable object of values: "+e);return t}function z(e){var t=U(e)||"object"==typeof e&&new R(e);if(!t)throw new TypeError("Expected Array or iterable object of values, or keyed object: "+e);return t}function U(e){return D(e)?new I(e):S(e)?new j(e):E(e)?new F(e):void 0}function W(e,t,n,r){var i=e._cache;if(i){for(var o=i.length-1,a=0;a<=o;a++){var s=i[n?o-a:a];if(!1===t(s[1],r?s[0]:a,e))return a+1}return a}return e.__iterateUncached(t,n)}function V(e,t,n,r){var i=e._cache;if(i){var o=i.length-1,a=0;return new x(function(){var e=i[n?o-a:a];return a++>o?k():w(t,r?e[0]:a-1,e[1])})}return e.__iteratorUncached(t,n)}function H(e,t){return t?G(t,e,"",{"":e}):J(e)}function G(e,t,n,r){return Array.isArray(t)?e.call(r,n,T(t).map(function(n,r){return G(e,n,r,t)})):K(t)?e.call(r,n,M(t).map(function(n,r){return G(e,n,r,t)})):t}function J(e){return Array.isArray(e)?T(e).map(J).toList():K(e)?M(e).map(J).toMap():e}function K(e){return e&&(e.constructor===Object||void 0===e.constructor)}function X(e,t){if(e===t||e!==e&&t!==t)return!0;if(!e||!t)return!1;if("function"==typeof e.valueOf&&"function"==typeof t.valueOf){if(e=e.valueOf(),t=t.valueOf(),e===t||e!==e&&t!==t)return!0;if(!e||!t)return!1}return!("function"!=typeof e.equals||"function"!=typeof t.equals||!e.equals(t))}function Y(e,t){if(e===t)return!0;if(!o(t)||void 0!==e.size&&void 0!==t.size&&e.size!==t.size||void 0!==e.__hash&&void 0!==t.__hash&&e.__hash!==t.__hash||a(e)!==a(t)||s(e)!==s(t)||l(e)!==l(t))return!1;if(0===e.size&&0===t.size)return!0;var n=!u(e);if(l(e)){var r=e.entries();return t.every(function(e,t){var i=r.next().value;return i&&X(i[1],e)&&(n||X(i[0],t))})&&r.next().done}var i=!1;if(void 0===e.size)if(void 0===t.size)"function"==typeof e.cacheResult&&e.cacheResult();else{i=!0;var c=e;e=t,t=c}var p=!0,f=t.__iterate(function(t,r){if(n?!e.has(t):i?!X(t,e.get(r,vn)):!X(e.get(r,vn),t))return p=!1,!1});return p&&e.size===f}function $(e,t){if(!(this instanceof $))return new $(e,t);if(this._value=e,this.size=void 0===t?1/0:Math.max(0,t),0===this.size){if(An)return An;An=this}}function Z(e,t){if(!e)throw new Error(t)}function Q(e,t,n){if(!(this instanceof Q))return new Q(e,t,n);if(Z(0!==n,"Cannot step a Range by 0"),e=e||0,void 0===t&&(t=1/0),n=void 0===n?1:Math.abs(n),t>>1&1073741824|3221225471&e}function oe(e){if(!1===e||null===e||void 0===e)return 0;if("function"==typeof e.valueOf&&(!1===(e=e.valueOf())||null===e||void 0===e))return 0;if(!0===e)return 1;var t=typeof e;if("number"===t){if(e!==e||e===1/0)return 0;var n=0|e;for(n!==e&&(n^=4294967295*e);e>4294967295;)e/=4294967295,n^=e;return ie(n)}if("string"===t)return e.length>jn?ae(e):se(e);if("function"==typeof e.hashCode)return e.hashCode();if("object"===t)return ue(e);if("function"==typeof e.toString)return se(e.toString());throw new Error("Value type "+t+" cannot be hashed.")}function ae(e){var t=Ln[e];return void 0===t&&(t=se(e),Bn===Nn&&(Bn=0,Ln={}),Bn++,Ln[e]=t),t}function se(e){for(var t=0,n=0;n0)switch(e.nodeType){case 1:return e.uniqueID;case 9:return e.documentElement&&e.documentElement.uniqueID}}function ce(e){Z(e!==1/0,"Cannot perform this action with an infinite size.")}function pe(e){return null===e||void 0===e?we():fe(e)&&!l(e)?e:we().withMutations(function(t){var r=n(e);ce(r.size),r.forEach(function(e,n){return t.set(n,e)})})}function fe(e){return!(!e||!e[qn])}function he(e,t){this.ownerID=e,this.entries=t}function de(e,t,n){this.ownerID=e,this.bitmap=t,this.nodes=n}function me(e,t,n){this.ownerID=e,this.count=t,this.nodes=n}function ve(e,t,n){this.ownerID=e,this.keyHash=t,this.entries=n}function ge(e,t,n){this.ownerID=e,this.keyHash=t,this.entry=n}function ye(e,t,n){this._type=t,this._reverse=n,this._stack=e._root&&be(e._root)}function _e(e,t){return w(e,t[0],t[1])}function be(e,t){return{node:e,index:0,__prev:t}}function xe(e,t,n,r){var i=Object.create(zn);return i.size=e,i._root=t,i.__ownerID=n,i.__hash=r,i.__altered=!1,i}function we(){return Un||(Un=xe(0))}function ke(e,t,n){var r,i;if(e._root){var o=c(gn),a=c(yn);if(r=Ee(e._root,e.__ownerID,0,void 0,t,n,o,a),!a.value)return e;i=e.size+(o.value?n===vn?-1:1:0)}else{if(n===vn)return e;i=1,r=new he(e.__ownerID,[[t,n]])}return e.__ownerID?(e.size=i,e._root=r,e.__hash=void 0,e.__altered=!0,e):r?xe(i,r):we()}function Ee(e,t,n,r,i,o,a,s){return e?e.update(t,n,r,i,o,a,s):o===vn?e:(p(s),p(a),new ge(t,r,[i,o]))}function Se(e){return e.constructor===ge||e.constructor===ve}function Ce(e,t,n,r,i){if(e.keyHash===r)return new ve(t,r,[e.entry,i]);var o,a=(0===n?e.keyHash:e.keyHash>>>n)&mn,s=(0===n?r:r>>>n)&mn;return new de(t,1<>>=1)a[s]=1&n?t[o++]:void 0;return a[r]=i,new me(e,o+1,a)}function Me(e,t,r){for(var i=[],a=0;a>1&1431655765,e=(858993459&e)+(e>>2&858993459),e=e+(e>>4)&252645135,e+=e>>8,127&(e+=e>>16)}function je(e,t,n,r){var i=r?e:h(e);return i[t]=n,i}function Ne(e,t,n,r){var i=e.length+1;if(r&&t+1===i)return e[t]=n,e;for(var o=new Array(i),a=0,s=0;s0&&io?0:o-n,l=a-n;return l>dn&&(l=dn),function(){if(i===l)return Xn;var e=t?--l:i++;return r&&r[e]}}function i(e,r,i){var s,u=e&&e.array,l=i>o?0:o-i>>r,c=1+(a-i>>r);return c>dn&&(c=dn),function(){for(;;){if(s){var e=s();if(e!==Xn)return e;s=null}if(l===c)return Xn;var o=t?--c:l++;s=n(u&&u[o],r-hn,i+(o<=e.size||t<0)return e.withMutations(function(e){t<0?Xe(e,t).set(0,n):Xe(e,0,t+1).set(t,n)});t+=e._origin;var r=e._tail,i=e._root,o=c(yn);return t>=$e(e._capacity)?r=Ge(r,e.__ownerID,0,t,n,o):i=Ge(i,e.__ownerID,e._level,t,n,o),o.value?e.__ownerID?(e._root=i,e._tail=r,e.__hash=void 0,e.__altered=!0,e):We(e._origin,e._capacity,e._level,i,r):e}function Ge(e,t,n,r,i,o){var a=r>>>n&mn,s=e&&a0){var l=e&&e.array[a],c=Ge(l,t,n-hn,r,i,o);return c===l?e:(u=Je(e,t),u.array[a]=c,u)}return s&&e.array[a]===i?e:(p(o),u=Je(e,t),void 0===i&&a===u.array.length-1?u.array.pop():u.array[a]=i,u)}function Je(e,t){return t&&e&&t===e.ownerID?e:new ze(e?e.array.slice():[],t)}function Ke(e,t){if(t>=$e(e._capacity))return e._tail;if(t<1<0;)n=n.array[t>>>r&mn],r-=hn;return n}}function Xe(e,t,n){void 0!==t&&(t|=0),void 0!==n&&(n|=0);var r=e.__ownerID||new f,i=e._origin,o=e._capacity,a=i+t,s=void 0===n?o:n<0?o+n:i+n;if(a===i&&s===o)return e;if(a>=s)return e.clear();for(var u=e._level,l=e._root,c=0;a+c<0;)l=new ze(l&&l.array.length?[void 0,l]:[],r),u+=hn,c+=1<=1<p?new ze([],r):d;if(d&&h>p&&ahn;g-=hn){var y=p>>>g&mn;v=v.array[y]=Je(v.array[y],r)}v.array[p>>>hn&mn]=d}if(s=h)a-=h,s-=h,u=hn,l=null,m=m&&m.removeBefore(r,0,a);else if(a>i||h>>u&mn;if(_!==h>>>u&mn)break;_&&(c+=(1<i&&(l=l.removeBefore(r,u,a-c)),l&&ha&&(a=l.size),o(u)||(l=l.map(function(e){return H(e)})),i.push(l)}return a>e.size&&(e=e.setSize(a)),Ie(e,t,i)}function $e(e){return e>>hn<=dn&&a.size>=2*o.size?(i=a.filter(function(e,t){return void 0!==e&&s!==t}),r=i.toKeyedSeq().map(function(e){return e[0]}).flip().toMap(),e.__ownerID&&(r.__ownerID=i.__ownerID=e.__ownerID)):(r=o.remove(t),i=s===a.size-1?a.pop():a.set(s,void 0))}else if(u){if(n===a.get(s)[1])return e;r=o,i=a.set(s,[t,n])}else r=o.set(t,a.size),i=a.set(a.size,[t,n]);return e.__ownerID?(e.size=r.size,e._map=r,e._list=i,e.__hash=void 0,e):et(r,i)}function rt(e,t){this._iter=e,this._useKeys=t,this.size=e.size}function it(e){this._iter=e,this.size=e.size}function ot(e){this._iter=e,this.size=e.size}function at(e){this._iter=e,this.size=e.size}function st(e){var t=Dt(e);return t._iter=e,t.size=e.size,t.flip=function(){return e},t.reverse=function(){var t=e.reverse.apply(this);return t.flip=function(){return e.reverse()},t},t.has=function(t){return e.includes(t)},t.includes=function(t){return e.has(t)},t.cacheResult=Ot,t.__iterateUncached=function(t,n){var r=this;return e.__iterate(function(e,n){return!1!==t(n,e,r)},n)},t.__iteratorUncached=function(t,n){if(t===xn){var r=e.__iterator(t,n);return new x(function(){var e=r.next();if(!e.done){var t=e.value[0];e.value[0]=e.value[1],e.value[1]=t}return e})}return e.__iterator(t===bn?_n:bn,n)},t}function ut(e,t,n){var r=Dt(e);return r.size=e.size,r.has=function(t){return e.has(t)},r.get=function(r,i){var o=e.get(r,vn);return o===vn?i:t.call(n,o,r,e)},r.__iterateUncached=function(r,i){var o=this;return e.__iterate(function(e,i,a){return!1!==r(t.call(n,e,i,a),i,o)},i)},r.__iteratorUncached=function(r,i){var o=e.__iterator(xn,i);return new x(function(){var i=o.next();if(i.done)return i;var a=i.value,s=a[0];return w(r,s,t.call(n,a[1],s,e),i)})},r}function lt(e,t){var n=Dt(e);return n._iter=e,n.size=e.size,n.reverse=function(){return e},e.flip&&(n.flip=function(){var t=st(e);return t.reverse=function(){return e.flip()},t}),n.get=function(n,r){return e.get(t?n:-1-n,r)},n.has=function(n){return e.has(t?n:-1-n)},n.includes=function(t){return e.includes(t)},n.cacheResult=Ot,n.__iterate=function(t,n){var r=this;return e.__iterate(function(e,n){return t(e,n,r)},!n)},n.__iterator=function(t,n){return e.__iterator(t,!n)},n}function ct(e,t,n,r){var i=Dt(e);return r&&(i.has=function(r){var i=e.get(r,vn);return i!==vn&&!!t.call(n,i,r,e)},i.get=function(r,i){var o=e.get(r,vn);return o!==vn&&t.call(n,o,r,e)?o:i}),i.__iterateUncached=function(i,o){var a=this,s=0;return e.__iterate(function(e,o,u){if(t.call(n,e,o,u))return s++,i(e,r?o:s-1,a)},o),s},i.__iteratorUncached=function(i,o){var a=e.__iterator(xn,o),s=0;return new x(function(){for(;;){var o=a.next();if(o.done)return o;var u=o.value,l=u[0],c=u[1];if(t.call(n,c,l,e))return w(i,r?l:s++,c,o)}})},i}function pt(e,t,n){var r=pe().asMutable();return e.__iterate(function(i,o){r.update(t.call(n,i,o,e),0,function(e){return e+1})}),r.asImmutable()}function ft(e,t,n){var r=a(e),i=(l(e)?Ze():pe()).asMutable();e.__iterate(function(o,a){i.update(t.call(n,o,a,e),function(e){return e=e||[],e.push(r?[a,o]:o),e})});var o=At(e);return i.map(function(t){return Et(e,o(t))})}function ht(e,t,n,r){var i=e.size;if(void 0!==t&&(t|=0),void 0!==n&&(n===1/0?n=i:n|=0),g(t,n,i))return e;var o=y(t,i),a=_(n,i);if(o!==o||a!==a)return ht(e.toSeq().cacheResult(),t,n,r);var s,u=a-o;u===u&&(s=u<0?0:u);var l=Dt(e);return l.size=0===s?s:e.size&&s||void 0,!r&&N(e)&&s>=0&&(l.get=function(t,n){return t=m(this,t),t>=0&&ts)return k();var e=i.next();return r||t===bn?e:t===_n?w(t,u-1,void 0,e):w(t,u-1,e.value[1],e)})},l}function dt(e,t,n){var r=Dt(e);return r.__iterateUncached=function(r,i){var o=this;if(i)return this.cacheResult().__iterate(r,i);var a=0;return e.__iterate(function(e,i,s){return t.call(n,e,i,s)&&++a&&r(e,i,o)}),a},r.__iteratorUncached=function(r,i){var o=this;if(i)return this.cacheResult().__iterator(r,i);var a=e.__iterator(xn,i),s=!0;return new x(function(){if(!s)return k();var e=a.next();if(e.done)return e;var i=e.value,u=i[0],l=i[1];return t.call(n,l,u,o)?r===xn?e:w(r,u,l,e):(s=!1,k())})},r}function mt(e,t,n,r){var i=Dt(e);return i.__iterateUncached=function(i,o){var a=this;if(o)return this.cacheResult().__iterate(i,o);var s=!0,u=0;return e.__iterate(function(e,o,l){if(!s||!(s=t.call(n,e,o,l)))return u++,i(e,r?o:u-1,a)}),u},i.__iteratorUncached=function(i,o){var a=this;if(o)return this.cacheResult().__iterator(i,o);var s=e.__iterator(xn,o),u=!0,l=0;return new x(function(){var e,o,c;do{if(e=s.next(),e.done)return r||i===bn?e:i===_n?w(i,l++,void 0,e):w(i,l++,e.value[1],e);var p=e.value;o=p[0],c=p[1],u&&(u=t.call(n,c,o,a))}while(u);return i===xn?e:w(i,o,c,e)})},i}function vt(e,t){var r=a(e),i=[e].concat(t).map(function(e){return o(e)?r&&(e=n(e)):e=r?L(e):q(Array.isArray(e)?e:[e]),e}).filter(function(e){return 0!==e.size});if(0===i.length)return e;if(1===i.length){var u=i[0];if(u===e||r&&a(u)||s(e)&&s(u))return u}var l=new I(i);return r?l=l.toKeyedSeq():s(e)||(l=l.toSetSeq()),l=l.flatten(!0),l.size=i.reduce(function(e,t){if(void 0!==e){var n=t.size;if(void 0!==n)return e+n}},0),l}function gt(e,t,n){var r=Dt(e);return r.__iterateUncached=function(r,i){function a(e,l){var c=this;e.__iterate(function(e,i){return(!t||l0}function kt(e,n,r){var i=Dt(e);return i.size=new I(r).map(function(e){return e.size}).min(),i.__iterate=function(e,t){for(var n,r=this.__iterator(bn,t),i=0;!(n=r.next()).done&&!1!==e(n.value,i++,this););return i},i.__iteratorUncached=function(e,i){var o=r.map(function(e){return e=t(e),C(i?e.reverse():e)}),a=0,s=!1;return new x(function(){var t;return s||(t=o.map(function(e){return e.next()}),s=t.some(function(e){return e.done})),s?k():w(e,a++,n.apply(null,t.map(function(e){return e.value})))})},i}function Et(e,t){return N(e)?t:e.constructor(t)}function St(e){if(e!==Object(e))throw new TypeError("Expected [K, V] tuple: "+e)}function Ct(e){return ce(e.size),d(e)}function At(e){return a(e)?n:s(e)?r:i}function Dt(e){return Object.create((a(e)?M:s(e)?T:P).prototype)}function Ot(){return this._iter.cacheResult?(this._iter.cacheResult(),this.size=this._iter.size,this):O.prototype.cacheResult.call(this)}function Mt(e,t){return e>t?1:et?-1:0}function on(e){if(e.size===1/0)return 0;var t=l(e),n=a(e),r=t?1:0;return an(e.__iterate(n?t?function(e,t){r=31*r+sn(oe(e),oe(t))|0}:function(e,t){r=r+sn(oe(e),oe(t))|0}:t?function(e){r=31*r+oe(e)|0}:function(e){r=r+oe(e)|0}),r)}function an(e,t){return t=Mn(t,3432918353),t=Mn(t<<15|t>>>-15,461845907),t=Mn(t<<13|t>>>-13,5),t=(t+3864292196|0)^e,t=Mn(t^t>>>16,2246822507),t=Mn(t^t>>>13,3266489909),t=ie(t^t>>>16)}function sn(e,t){return e^t+2654435769+(e<<6)+(e>>2)|0}var un=Array.prototype.slice;e(n,t),e(r,t),e(i,t),t.isIterable=o,t.isKeyed=a,t.isIndexed=s,t.isAssociative=u,t.isOrdered=l,t.Keyed=n,t.Indexed=r,t.Set=i;var ln="@@__IMMUTABLE_ITERABLE__@@",cn="@@__IMMUTABLE_KEYED__@@",pn="@@__IMMUTABLE_INDEXED__@@",fn="@@__IMMUTABLE_ORDERED__@@",hn=5,dn=1<r?k():w(e,i,n[t?r-i++:i++])})},e(R,M),R.prototype.get=function(e,t){return void 0===t||this.has(e)?this._object[e]:t},R.prototype.has=function(e){return this._object.hasOwnProperty(e)},R.prototype.__iterate=function(e,t){for(var n=this._object,r=this._keys,i=r.length-1,o=0;o<=i;o++){var a=r[t?i-o:o];if(!1===e(n[a],a,this))return o+1}return o},R.prototype.__iterator=function(e,t){var n=this._object,r=this._keys,i=r.length-1,o=0;return new x(function(){var a=r[t?i-o:o];return o++>i?k():w(e,a,n[a])})},R.prototype[fn]=!0,e(F,T),F.prototype.__iterateUncached=function(e,t){if(t)return this.cacheResult().__iterate(e,t);var n=this._iterable,r=C(n),i=0;if(S(r))for(var o;!(o=r.next()).done&&!1!==e(o.value,i++,this););return i},F.prototype.__iteratorUncached=function(e,t){if(t)return this.cacheResult().__iterator(e,t);var n=this._iterable,r=C(n);if(!S(r))return new x(k);var i=0;return new x(function(){var t=r.next();return t.done?t:w(e,i++,t.value)})},e(j,T),j.prototype.__iterateUncached=function(e,t){if(t)return this.cacheResult().__iterate(e,t);for(var n=this._iterator,r=this._iteratorCache,i=0;i=r.length){var t=n.next();if(t.done)return t;r[i]=t.value}return w(e,i,r[i++])})};var Cn;e($,T),$.prototype.toString=function(){return 0===this.size?"Repeat []":"Repeat [ "+this._value+" "+this.size+" times ]"},$.prototype.get=function(e,t){return this.has(e)?this._value:t},$.prototype.includes=function(e){return X(this._value,e)},$.prototype.slice=function(e,t){var n=this.size;return g(e,t,n)?this:new $(this._value,_(t,n)-y(e,n))},$.prototype.reverse=function(){return this},$.prototype.indexOf=function(e){return X(this._value,e)?0:-1},$.prototype.lastIndexOf=function(e){return X(this._value,e)?this.size:-1},$.prototype.__iterate=function(e,t){for(var n=0;n=0&&t=0&&nn?k():w(e,o++,a)})},Q.prototype.equals=function(e){return e instanceof Q?this._start===e._start&&this._end===e._end&&this._step===e._step:Y(this,e)};var Dn;e(ee,t),e(te,ee),e(ne,ee),e(re,ee),ee.Keyed=te,ee.Indexed=ne,ee.Set=re;var On,Mn="function"==typeof Math.imul&&-2===Math.imul(4294967295,2)?Math.imul:function(e,t){e|=0,t|=0;var n=65535&e,r=65535&t;return n*r+((e>>>16)*r+n*(t>>>16)<<16>>>0)|0},Tn=Object.isExtensible,Pn=function(){try{return Object.defineProperty({},"@",{}),!0}catch(e){return!1}}(),In="function"==typeof WeakMap;In&&(On=new WeakMap);var Rn=0,Fn="__immutablehash__";"function"==typeof Symbol&&(Fn=Symbol(Fn));var jn=16,Nn=255,Bn=0,Ln={};e(pe,te),pe.of=function(){var e=un.call(arguments,0);return we().withMutations(function(t){for(var n=0;n=e.length)throw new Error("Missing value for key: "+e[n]);t.set(e[n],e[n+1])}})},pe.prototype.toString=function(){return this.__toString("Map {","}")},pe.prototype.get=function(e,t){return this._root?this._root.get(0,void 0,e,t):t},pe.prototype.set=function(e,t){return ke(this,e,t)},pe.prototype.setIn=function(e,t){return this.updateIn(e,vn,function(){return t})},pe.prototype.remove=function(e){return ke(this,e,vn)},pe.prototype.deleteIn=function(e){return this.updateIn(e,function(){return vn})},pe.prototype.update=function(e,t,n){return 1===arguments.length?e(this):this.updateIn([e],t,n)},pe.prototype.updateIn=function(e,t,n){n||(n=t,t=void 0);var r=Re(this,Tt(e),t,n);return r===vn?void 0:r},pe.prototype.clear=function(){return 0===this.size?this:this.__ownerID?(this.size=0,this._root=null,this.__hash=void 0,this.__altered=!0,this):we()},pe.prototype.merge=function(){return Me(this,void 0,arguments)},pe.prototype.mergeWith=function(e){return Me(this,e,un.call(arguments,1))},pe.prototype.mergeIn=function(e){var t=un.call(arguments,1);return this.updateIn(e,we(),function(e){return"function"==typeof e.merge?e.merge.apply(e,t):t[t.length-1]})},pe.prototype.mergeDeep=function(){return Me(this,Te,arguments)},pe.prototype.mergeDeepWith=function(e){var t=un.call(arguments,1);return Me(this,Pe(e),t)},pe.prototype.mergeDeepIn=function(e){var t=un.call(arguments,1);return this.updateIn(e,we(),function(e){return"function"==typeof e.mergeDeep?e.mergeDeep.apply(e,t):t[t.length-1]})},pe.prototype.sort=function(e){return Ze(bt(this,e))},pe.prototype.sortBy=function(e,t){return Ze(bt(this,t,e))},pe.prototype.withMutations=function(e){var t=this.asMutable();return e(t),t.wasAltered()?t.__ensureOwner(this.__ownerID):this},pe.prototype.asMutable=function(){return this.__ownerID?this:this.__ensureOwner(new f)},pe.prototype.asImmutable=function(){return this.__ensureOwner()},pe.prototype.wasAltered=function(){return this.__altered},pe.prototype.__iterator=function(e,t){return new ye(this,e,t)},pe.prototype.__iterate=function(e,t){var n=this,r=0;return this._root&&this._root.iterate(function(t){return r++,e(t[1],t[0],n)},t),r},pe.prototype.__ensureOwner=function(e){return e===this.__ownerID?this:e?xe(this.size,this._root,e,this.__hash):(this.__ownerID=e,this.__altered=!1,this)},pe.isMap=fe;var qn="@@__IMMUTABLE_MAP__@@",zn=pe.prototype;zn[qn]=!0,zn.delete=zn.remove,zn.removeIn=zn.deleteIn,he.prototype.get=function(e,t,n,r){for(var i=this.entries,o=0,a=i.length;o=Wn)return Ae(e,u,r,i);var d=e&&e===this.ownerID,m=d?u:h(u);return f?s?l===c-1?m.pop():m[l]=m.pop():m[l]=[r,i]:m.push([r,i]),d?(this.entries=m,this):new he(e,m)}},de.prototype.get=function(e,t,n,r){void 0===t&&(t=oe(n));var i=1<<((0===e?t:t>>>e)&mn),o=this.bitmap;return 0==(o&i)?r:this.nodes[Fe(o&i-1)].get(e+hn,t,n,r)},de.prototype.update=function(e,t,n,r,i,o,a){void 0===n&&(n=oe(r));var s=(0===t?n:n>>>t)&mn,u=1<=Vn)return Oe(e,f,l,s,d);if(c&&!d&&2===f.length&&Se(f[1^p]))return f[1^p];if(c&&d&&1===f.length&&Se(d))return d;var m=e&&e===this.ownerID,v=c?d?l:l^u:l|u,g=c?d?je(f,p,d,m):Be(f,p,m):Ne(f,p,d,m);return m?(this.bitmap=v,this.nodes=g,this):new de(e,v,g)},me.prototype.get=function(e,t,n,r){void 0===t&&(t=oe(n));var i=(0===e?t:t>>>e)&mn,o=this.nodes[i];return o?o.get(e+hn,t,n,r):r},me.prototype.update=function(e,t,n,r,i,o,a){void 0===n&&(n=oe(r));var s=(0===t?n:n>>>t)&mn,u=i===vn,l=this.nodes,c=l[s];if(u&&!c)return this;var p=Ee(c,e,t+hn,n,r,i,o,a);if(p===c)return this;var f=this.count;if(c){if(!p&&--f=0&&e>>t&mn;if(r>=this.array.length)return new ze([],e);var i,o=0===r;if(t>0){var a=this.array[r];if((i=a&&a.removeBefore(e,t-hn,n))===a&&o)return this}if(o&&!i)return this;var s=Je(this,e);if(!o)for(var u=0;u>>t&mn;if(r>=this.array.length)return this;var i;if(t>0){var o=this.array[r];if((i=o&&o.removeAfter(e,t-hn,n))===o&&r===this.array.length-1)return this}var a=Je(this,e);return a.array.splice(r+1),i&&(a.array[r]=i),a};var Kn,Xn={};e(Ze,pe),Ze.of=function(){return this(arguments)},Ze.prototype.toString=function(){return this.__toString("OrderedMap {","}")},Ze.prototype.get=function(e,t){var n=this._map.get(e);return void 0!==n?this._list.get(n)[1]:t},Ze.prototype.clear=function(){return 0===this.size?this:this.__ownerID?(this.size=0,this._map.clear(),this._list.clear(),this):tt()},Ze.prototype.set=function(e,t){return nt(this,e,t)},Ze.prototype.remove=function(e){return nt(this,e,vn)},Ze.prototype.wasAltered=function(){return this._map.wasAltered()||this._list.wasAltered()},Ze.prototype.__iterate=function(e,t){var n=this;return this._list.__iterate(function(t){return t&&e(t[1],t[0],n)},t)},Ze.prototype.__iterator=function(e,t){return this._list.fromEntrySeq().__iterator(e,t)},Ze.prototype.__ensureOwner=function(e){if(e===this.__ownerID)return this;var t=this._map.__ensureOwner(e),n=this._list.__ensureOwner(e);return e?et(t,n,e,this.__hash):(this.__ownerID=e,this._map=t,this._list=n,this)},Ze.isOrderedMap=Qe,Ze.prototype[fn]=!0,Ze.prototype.delete=Ze.prototype.remove;var Yn;e(rt,M),rt.prototype.get=function(e,t){return this._iter.get(e,t)},rt.prototype.has=function(e){return this._iter.has(e)},rt.prototype.valueSeq=function(){return this._iter.valueSeq()},rt.prototype.reverse=function(){var e=this,t=lt(this,!0);return this._useKeys||(t.valueSeq=function(){return e._iter.toSeq().reverse()}),t},rt.prototype.map=function(e,t){var n=this,r=ut(this,e,t);return this._useKeys||(r.valueSeq=function(){return n._iter.toSeq().map(e,t)}),r},rt.prototype.__iterate=function(e,t){var n,r=this;return this._iter.__iterate(this._useKeys?function(t,n){return e(t,n,r)}:(n=t?Ct(this):0,function(i){return e(i,t?--n:n++,r)}),t)},rt.prototype.__iterator=function(e,t){if(this._useKeys)return this._iter.__iterator(e,t);var n=this._iter.__iterator(bn,t),r=t?Ct(this):0;return new x(function(){var i=n.next();return i.done?i:w(e,t?--r:r++,i.value,i)})},rt.prototype[fn]=!0,e(it,T),it.prototype.includes=function(e){return this._iter.includes(e)},it.prototype.__iterate=function(e,t){var n=this,r=0;return this._iter.__iterate(function(t){return e(t,r++,n)},t)},it.prototype.__iterator=function(e,t){var n=this._iter.__iterator(bn,t),r=0;return new x(function(){var t=n.next();return t.done?t:w(e,r++,t.value,t)})},e(ot,P),ot.prototype.has=function(e){return this._iter.includes(e)},ot.prototype.__iterate=function(e,t){var n=this;return this._iter.__iterate(function(t){return e(t,t,n)},t)},ot.prototype.__iterator=function(e,t){var n=this._iter.__iterator(bn,t);return new x(function(){var t=n.next();return t.done?t:w(e,t.value,t.value,t)})},e(at,M),at.prototype.entrySeq=function(){return this._iter.toSeq()},at.prototype.__iterate=function(e,t){var n=this;return this._iter.__iterate(function(t){if(t){St(t);var r=o(t);return e(r?t.get(1):t[1],r?t.get(0):t[0],n)}},t)},at.prototype.__iterator=function(e,t){var n=this._iter.__iterator(bn,t);return new x(function(){for(;;){var t=n.next();if(t.done)return t;var r=t.value;if(r){St(r);var i=o(r);return w(e,i?r.get(0):r[0],i?r.get(1):r[1],t)}}})},it.prototype.cacheResult=rt.prototype.cacheResult=ot.prototype.cacheResult=at.prototype.cacheResult=Ot,e(Pt,te),Pt.prototype.toString=function(){return this.__toString(Rt(this)+" {","}")},Pt.prototype.has=function(e){return this._defaultValues.hasOwnProperty(e)},Pt.prototype.get=function(e,t){if(!this.has(e))return t;var n=this._defaultValues[e];return this._map?this._map.get(e,n):n},Pt.prototype.clear=function(){if(this.__ownerID)return this._map&&this._map.clear(),this;var e=this.constructor;return e._empty||(e._empty=It(this,we()))},Pt.prototype.set=function(e,t){if(!this.has(e))throw new Error('Cannot set unknown key "'+e+'" on '+Rt(this));if(this._map&&!this._map.has(e)){if(t===this._defaultValues[e])return this}var n=this._map&&this._map.set(e,t);return this.__ownerID||n===this._map?this:It(this,n)},Pt.prototype.remove=function(e){if(!this.has(e))return this;var t=this._map&&this._map.remove(e);return this.__ownerID||t===this._map?this:It(this,t)},Pt.prototype.wasAltered=function(){return this._map.wasAltered()},Pt.prototype.__iterator=function(e,t){var r=this;return n(this._defaultValues).map(function(e,t){return r.get(t)}).__iterator(e,t)},Pt.prototype.__iterate=function(e,t){var r=this;return n(this._defaultValues).map(function(e,t){return r.get(t)}).__iterate(e,t)},Pt.prototype.__ensureOwner=function(e){if(e===this.__ownerID)return this;var t=this._map&&this._map.__ensureOwner(e);return e?It(this,t,e):(this.__ownerID=e,this._map=t,this)};var $n=Pt.prototype;$n.delete=$n.remove,$n.deleteIn=$n.removeIn=zn.removeIn,$n.merge=zn.merge,$n.mergeWith=zn.mergeWith,$n.mergeIn=zn.mergeIn,$n.mergeDeep=zn.mergeDeep,$n.mergeDeepWith=zn.mergeDeepWith,$n.mergeDeepIn=zn.mergeDeepIn,$n.setIn=zn.setIn,$n.update=zn.update,$n.updateIn=zn.updateIn,$n.withMutations=zn.withMutations,$n.asMutable=zn.asMutable,$n.asImmutable=zn.asImmutable,e(Nt,re),Nt.of=function(){return this(arguments)},Nt.fromKeys=function(e){return this(n(e).keySeq())},Nt.prototype.toString=function(){return this.__toString("Set {","}")},Nt.prototype.has=function(e){return this._map.has(e)},Nt.prototype.add=function(e){return Lt(this,this._map.set(e,!0))},Nt.prototype.remove=function(e){return Lt(this,this._map.remove(e))},Nt.prototype.clear=function(){return Lt(this,this._map.clear())},Nt.prototype.union=function(){var e=un.call(arguments,0);return e=e.filter(function(e){return 0!==e.size}),0===e.length?this:0!==this.size||this.__ownerID||1!==e.length?this.withMutations(function(t){for(var n=0;n=0;n--)t={value:arguments[n],next:t};return this.__ownerID?(this.size=e,this._head=t,this.__hash=void 0,this.__altered=!0,this):Kt(e,t)},Gt.prototype.pushAll=function(e){if(e=r(e),0===e.size)return this;ce(e.size);var t=this.size,n=this._head;return e.reverse().forEach(function(e){t++,n={value:e,next:n}}),this.__ownerID?(this.size=t,this._head=n,this.__hash=void 0,this.__altered=!0,this):Kt(t,n)},Gt.prototype.pop=function(){return this.slice(1)},Gt.prototype.unshift=function(){return this.push.apply(this,arguments)},Gt.prototype.unshiftAll=function(e){return this.pushAll(e)},Gt.prototype.shift=function(){return this.pop.apply(this,arguments)},Gt.prototype.clear=function(){return 0===this.size?this:this.__ownerID?(this.size=0,this._head=void 0,this.__hash=void 0,this.__altered=!0,this):Xt()},Gt.prototype.slice=function(e,t){if(g(e,t,this.size))return this;var n=y(e,this.size);if(_(t,this.size)!==this.size)return ne.prototype.slice.call(this,e,t);for(var r=this.size-n,i=this._head;n--;)i=i.next;return this.__ownerID?(this.size=r,this._head=i,this.__hash=void 0,this.__altered=!0,this):Kt(r,i)},Gt.prototype.__ensureOwner=function(e){return e===this.__ownerID?this:e?Kt(this.size,this._head,e,this.__hash):(this.__ownerID=e,this.__altered=!1,this)},Gt.prototype.__iterate=function(e,t){if(t)return this.reverse().__iterate(e);for(var n=0,r=this._head;r&&!1!==e(r.value,n++,this);)r=r.next;return n},Gt.prototype.__iterator=function(e,t){if(t)return this.reverse().__iterator(e);var n=0,r=this._head;return new x(function(){if(r){var t=r.value;return r=r.next,w(e,n++,t)}return k()})},Gt.isStack=Jt;var rr="@@__IMMUTABLE_STACK__@@",ir=Gt.prototype;ir[rr]=!0,ir.withMutations=zn.withMutations,ir.asMutable=zn.asMutable,ir.asImmutable=zn.asImmutable,ir.wasAltered=zn.wasAltered;var or;t.Iterator=x,Yt(t,{toArray:function(){ce(this.size);var e=new Array(this.size||0);return this.valueSeq().__iterate(function(t,n){e[n]=t}),e},toIndexedSeq:function(){return new it(this)},toJS:function(){return this.toSeq().map(function(e){return e&&"function"==typeof e.toJS?e.toJS():e}).__toJS()},toJSON:function(){return this.toSeq().map(function(e){return e&&"function"==typeof e.toJSON?e.toJSON():e}).__toJS()},toKeyedSeq:function(){return new rt(this,!0)},toMap:function(){return pe(this.toKeyedSeq())},toObject:function(){ce(this.size);var e={};return this.__iterate(function(t,n){e[n]=t}),e},toOrderedMap:function(){return Ze(this.toKeyedSeq())},toOrderedSet:function(){return Ut(a(this)?this.valueSeq():this)},toSet:function(){return Nt(a(this)?this.valueSeq():this)},toSetSeq:function(){return new ot(this)},toSeq:function(){return s(this)?this.toIndexedSeq():a(this)?this.toKeyedSeq():this.toSetSeq()},toStack:function(){return Gt(a(this)?this.valueSeq():this)},toList:function(){return Le(a(this)?this.valueSeq():this)},toString:function(){return"[Iterable]"},__toString:function(e,t){return 0===this.size?e+t:e+" "+this.toSeq().map(this.__toStringMapper).join(", ")+" "+t},concat:function(){return Et(this,vt(this,un.call(arguments,0)))},includes:function(e){return this.some(function(t){return X(t,e)})},entries:function(){return this.__iterator(xn)},every:function(e,t){ce(this.size);var n=!0;return this.__iterate(function(r,i,o){if(!e.call(t,r,i,o))return n=!1,!1}),n},filter:function(e,t){return Et(this,ct(this,e,t,!0))},find:function(e,t,n){var r=this.findEntry(e,t);return r?r[1]:n},forEach:function(e,t){return ce(this.size),this.__iterate(t?e.bind(t):e)},join:function(e){ce(this.size),e=void 0!==e?""+e:",";var t="",n=!0;return this.__iterate(function(r){n?n=!1:t+=e,t+=null!==r&&void 0!==r?r.toString():""}),t},keys:function(){return this.__iterator(_n)},map:function(e,t){return Et(this,ut(this,e,t))},reduce:function(e,t,n){ce(this.size);var r,i;return arguments.length<2?i=!0:r=t,this.__iterate(function(t,o,a){i?(i=!1,r=t):r=e.call(n,r,t,o,a)}),r},reduceRight:function(e,t,n){var r=this.toKeyedSeq().reverse();return r.reduce.apply(r,arguments)},reverse:function(){return Et(this,lt(this,!0))},slice:function(e,t){return Et(this,ht(this,e,t,!0))},some:function(e,t){return!this.every(Qt(e),t)},sort:function(e){return Et(this,bt(this,e))},values:function(){return this.__iterator(bn)},butLast:function(){return this.slice(0,-1)},isEmpty:function(){return void 0!==this.size?0===this.size:!this.some(function(){return!0})},count:function(e,t){return d(e?this.toSeq().filter(e,t):this)},countBy:function(e,t){return pt(this,e,t)},equals:function(e){return Y(this,e)},entrySeq:function(){var e=this;if(e._cache)return new I(e._cache);var t=e.toSeq().map(Zt).toIndexedSeq();return t.fromEntrySeq=function(){return e.toSeq()},t},filterNot:function(e,t){return this.filter(Qt(e),t)},findEntry:function(e,t,n){var r=n;return this.__iterate(function(n,i,o){if(e.call(t,n,i,o))return r=[i,n],!1}),r},findKey:function(e,t){var n=this.findEntry(e,t);return n&&n[0]},findLast:function(e,t,n){return this.toKeyedSeq().reverse().find(e,t,n)},findLastEntry:function(e,t,n){return this.toKeyedSeq().reverse().findEntry(e,t,n)},findLastKey:function(e,t){return this.toKeyedSeq().reverse().findKey(e,t)},first:function(){return this.find(v)},flatMap:function(e,t){return Et(this,yt(this,e,t))},flatten:function(e){return Et(this,gt(this,e,!0))},fromEntrySeq:function(){return new at(this)},get:function(e,t){return this.find(function(t,n){return X(n,e)},void 0,t)},getIn:function(e,t){for(var n,r=this,i=Tt(e);!(n=i.next()).done;){var o=n.value;if((r=r&&r.get?r.get(o,vn):vn)===vn)return t}return r},groupBy:function(e,t){return ft(this,e,t)},has:function(e){return this.get(e,vn)!==vn},hasIn:function(e){return this.getIn(e,vn)!==vn},isSubset:function(e){return e="function"==typeof e.includes?e:t(e),this.every(function(t){return e.includes(t)})},isSuperset:function(e){return e="function"==typeof e.isSubset?e:t(e),e.isSubset(this)},keyOf:function(e){return this.findKey(function(t){return X(t,e)})},keySeq:function(){return this.toSeq().map($t).toIndexedSeq()},last:function(){return this.toSeq().reverse().first()},lastKeyOf:function(e){return this.toKeyedSeq().reverse().keyOf(e)},max:function(e){return xt(this,e)},maxBy:function(e,t){return xt(this,t,e)},min:function(e){return xt(this,e?en(e):rn)},minBy:function(e,t){return xt(this,t?en(t):rn,e)},rest:function(){return this.slice(1)},skip:function(e){return this.slice(Math.max(0,e))},skipLast:function(e){return Et(this,this.toSeq().reverse().skip(e).reverse())},skipWhile:function(e,t){return Et(this,mt(this,e,t,!0))},skipUntil:function(e,t){return this.skipWhile(Qt(e),t)},sortBy:function(e,t){return Et(this,bt(this,t,e))},take:function(e){return this.slice(0,Math.max(0,e))},takeLast:function(e){return Et(this,this.toSeq().reverse().take(e).reverse())},takeWhile:function(e,t){return Et(this,dt(this,e,t))},takeUntil:function(e,t){return this.takeWhile(Qt(e),t)},valueSeq:function(){return this.toIndexedSeq()},hashCode:function(){return this.__hash||(this.__hash=on(this))}});var ar=t.prototype;ar[ln]=!0,ar[En]=ar.values,ar.__toJS=ar.toArray,ar.__toStringMapper=tn,ar.inspect=ar.toSource=function(){return this.toString()},ar.chain=ar.flatMap,ar.contains=ar.includes,Yt(n,{flip:function(){return Et(this,st(this))},mapEntries:function(e,t){var n=this,r=0;return Et(this,this.toSeq().map(function(i,o){return e.call(t,[o,i],r++,n)}).fromEntrySeq())},mapKeys:function(e,t){var n=this;return Et(this,this.toSeq().flip().map(function(r,i){return e.call(t,r,i,n)}).flip())}});var sr=n.prototype;return sr[cn]=!0,sr[En]=ar.entries,sr.__toJS=ar.toObject,sr.__toStringMapper=function(e,t){return JSON.stringify(t)+": "+tn(e)},Yt(r,{toKeyedSeq:function(){return new rt(this,!1)},filter:function(e,t){return Et(this,ct(this,e,t,!1))},findIndex:function(e,t){var n=this.findEntry(e,t);return n?n[0]:-1},indexOf:function(e){var t=this.keyOf(e);return void 0===t?-1:t},lastIndexOf:function(e){var t=this.lastKeyOf(e);return void 0===t?-1:t},reverse:function(){return Et(this,lt(this,!1))},slice:function(e,t){return Et(this,ht(this,e,t,!1))},splice:function(e,t){var n=arguments.length;if(t=Math.max(0|t,0),0===n||2===n&&!t)return this;e=y(e,e<0?this.count():this.size);var r=this.slice(0,e);return Et(this,1===n?r:r.concat(h(arguments,2),this.slice(e+t)))},findLastIndex:function(e,t){var n=this.findLastEntry(e,t);return n?n[0]:-1},first:function(){return this.get(0)},flatten:function(e){return Et(this,gt(this,e,!1))},get:function(e,t){return e=m(this,e),e<0||this.size===1/0||void 0!==this.size&&e>this.size?t:this.find(function(t,n){return n===e},void 0,t)},has:function(e){return(e=m(this,e))>=0&&(void 0!==this.size?this.size===1/0||e5e3)return e.textContent;return function(e){for(var n,r,i,o,a,s=e.textContent,u=0,l=s[0],c=1,p=e.innerHTML="",f=0;r=n,n=f<7&&"\\"==n?1:c;){if(c=l,l=s[++u],o=p.length>1,!c||f>8&&"\n"==c||[/\S/.test(c),1,1,!/[$\w]/.test(c),("/"==n||"\n"==n)&&o,'"'==n&&o,"'"==n&&o,s[u-4]+r+n=="--\x3e",r+n=="*/"][f])for(p&&(e.appendChild(a=t.createElement("span")).setAttribute("style",["color: #555; font-weight: bold;","","","color: #555;",""][f?f<3?2:f>6?4:f>3?3:+/^(a(bstract|lias|nd|rguments|rray|s(m|sert)?|uto)|b(ase|egin|ool(ean)?|reak|yte)|c(ase|atch|har|hecked|lass|lone|ompl|onst|ontinue)|de(bugger|cimal|clare|f(ault|er)?|init|l(egate|ete)?)|do|double|e(cho|ls?if|lse(if)?|nd|nsure|num|vent|x(cept|ec|p(licit|ort)|te(nds|nsion|rn)))|f(allthrough|alse|inal(ly)?|ixed|loat|or(each)?|riend|rom|unc(tion)?)|global|goto|guard|i(f|mp(lements|licit|ort)|n(it|clude(_once)?|line|out|stanceof|t(erface|ernal)?)?|s)|l(ambda|et|ock|ong)|m(icrolight|odule|utable)|NaN|n(amespace|ative|ext|ew|il|ot|ull)|o(bject|perator|r|ut|verride)|p(ackage|arams|rivate|rotected|rotocol|ublic)|r(aise|e(adonly|do|f|gister|peat|quire(_once)?|scue|strict|try|turn))|s(byte|ealed|elf|hort|igned|izeof|tatic|tring|truct|ubscript|uper|ynchronized|witch)|t(emplate|hen|his|hrows?|ransient|rue|ry|ype(alias|def|id|name|of))|u(n(checked|def(ined)?|ion|less|signed|til)|se|sing)|v(ar|irtual|oid|olatile)|w(char_t|hen|here|hile|ith)|xor|yield)$/.test(p):0]),a.appendChild(t.createTextNode(p))),i=f&&f<7?f:i,p="",f=11;![1,/[\/{}[(\-+*=<>:;|\\.,?!&@~]/.test(c),/[\])]/.test(c),/[$\w]/.test(c),"/"==c&&i<2&&"<"!=n,'"'==c,"'"==c,c+l+s[u+1]+s[u+2]=="\x3c!--",c+l=="/*",c+l=="//","#"==c][--f];);p+=c}}(e)}function b(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"key",n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:B.default.Map();if(!B.default.Map.isMap(e)||!e.size)return B.default.List();if(Array.isArray(t)||(t=[t]),t.length<1)return e.merge(n);var r=B.default.List(),i=t[0],o=!0,a=!1,s=void 0;try{for(var u,l=(0,M.default)(e.entries());!(o=(u=l.next()).done);o=!0){var c=u.value,p=(0,D.default)(c,2),f=p[0],h=p[1],d=b(h,t.slice(1),n.set(i,f));r=B.default.List.isList(d)?r.concat(d):r.push(d)}}catch(e){a=!0,s=e}finally{try{!o&&l.return&&l.return()}finally{if(a)throw s}}return r}function x(e){return(0,W.default)((0,z.default)(e))}function w(e){return x(e.replace(/\.[^.\/]*$/,""))}function k(e){return"string"!=typeof e||""===e?"":(0,L.sanitizeUrl)(e)}function E(e){if(!B.default.OrderedMap.isOrderedMap(e))return null;if(!e.size)return null;var t=e.find(function(e,t){return t.startsWith("2")&&(0,R.default)(e.get("content")||{}).length>0}),n=e.get("default")||B.default.OrderedMap(),r=(n.get("content")||B.default.OrderedMap()).keySeq().toJS(),i=r.length?n:null;return t||i}Object.defineProperty(t,"__esModule",{value:!0}),t.getExtensions=t.escapeDeepLinkPath=t.createDeepLinkPath=t.shallowEqualKeys=t.buildFormData=t.sorters=t.btoa=t.parseSearch=t.getSampleSchema=t.validateParam=t.validatePattern=t.validateMinLength=t.validateMaxLength=t.validateGuid=t.validateDateTime=t.validateString=t.validateBoolean=t.validateFile=t.validateInteger=t.validateNumber=t.validateMinimum=t.validateMaximum=t.propChecker=t.errorLog=t.memoize=t.isImmutable=void 0;var S=n(35),C=r(S),A=n(17),D=r(A),O=n(96),M=r(O),T=n(36),P=r(T),I=n(47),R=r(I),F=n(48),j=r(F);t.isJSONObject=i,t.objectify=o,t.arrayify=a,t.fromJSOrdered=s,t.bindToState=u,t.normalizeArray=l,t.isFn=c,t.isObject=p,t.isFunc=f,t.isArray=h,t.objMap=d,t.objReduce=m,t.systemThunkMiddleware=v,t.defaultStatusCode=g,t.getList=y,t.highlight=_,t.mapToList=b,t.pascalCase=x,t.pascalCaseFilename=w,t.sanitizeUrl=k,t.getAcceptControllingResponse=E;var N=n(8),B=r(N),L=n(505),q=n(939),z=r(q),U=n(428),W=r(U),V=n(425),H=r(V),G=n(224),J=r(G),K=n(954),X=r(K),Y=n(120),$=r(Y),Z=n(172),Q=n(53),ee=r(Q),te=n(696),ne=r(te),re="default",ie=t.isImmutable=function(e){return B.default.Iterable.isIterable(e)},oe=(t.memoize=H.default,t.errorLog=function(e){return function(){return function(t){return function(n){try{t(n)}catch(t){e().errActions.newThrownErr(t,n)}}}}},t.propChecker=function(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:[],r=arguments.length>3&&void 0!==arguments[3]?arguments[3]:[];return(0,R.default)(e).length!==(0,R.default)(t).length||((0,X.default)(e,function(e,n){if(r.includes(n))return!1;var i=t[n];return B.default.Iterable.isIterable(e)?!B.default.is(e,i):("object"!==(void 0===e?"undefined":(0,j.default)(e))||"object"!==(void 0===i?"undefined":(0,j.default)(i)))&&e!==i})||n.some(function(n){return!(0,$.default)(e[n],t[n])}))},t.validateMaximum=function(e,t){if(e>t)return"Value must be less than Maximum"}),ae=t.validateMinimum=function(e,t){if(et)return"Value must be less than MaxLength"},me=t.validateMinLength=function(e,t){if(e.length2&&void 0!==arguments[2]&&arguments[2],r=[],i=t&&"body"===e.get("in")?e.get("value_xml"):e.get("value"),o=e.get("required"),a=n?e.get("schema"):e;if(!a)return r;var s=a.get("maximum"),u=a.get("minimum"),l=a.get("type"),c=a.get("format"),p=a.get("maxLength"),f=a.get("minLength"),h=a.get("pattern");if(l&&(o||i)){var d="string"===l&&i,m="array"===l&&Array.isArray(i)&&i.length,v="array"===l&&B.default.List.isList(i)&&i.count(),g="file"===l&&i instanceof ee.default.File,y="boolean"===l&&(i||!1===i),_="number"===l&&(i||0===i),b="integer"===l&&(i||0===i);if(o&&!(d||m||v||g||y||_||b))return r.push("Required field is not provided"),r;if(h){var x=ve(i,h);x&&r.push(x)}if(p||0===p){var w=de(i,p);w&&r.push(w)}if(f){var k=me(i,f);k&&r.push(k)}if(s||0===s){var E=oe(i,s);E&&r.push(E)}if(u||0===u){var S=ae(i,u);S&&r.push(S)}if("string"===l){var C=void 0;if(!(C="date-time"===c?fe(i):"uuid"===c?he(i):pe(i)))return r;r.push(C)}else if("boolean"===l){var A=ce(i);if(!A)return r;r.push(A)}else if("number"===l){var D=se(i);if(!D)return r;r.push(D)}else if("integer"===l){var O=ue(i);if(!O)return r;r.push(O)}else if("array"===l){var M=void 0;if(!i.count())return r;M=a.getIn(["items","type"]),i.forEach(function(e,t){var n=void 0;"number"===M?n=se(e):"integer"===M?n=ue(e):"string"===M&&(n=pe(e)),n&&r.push({index:t,error:n})})}else if("file"===l){var T=le(i);if(!T)return r;r.push(T)}}return r},t.getSampleSchema=function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"",n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{};if(/xml/.test(t)){if(!e.xml||!e.xml.name){if(e.xml=e.xml||{},!e.$$ref)return e.type||e.items||e.properties||e.additionalProperties?'\n\x3c!-- XML example cannot be generated --\x3e':null;var r=e.$$ref.match(/\S*\/(\S+)$/);e.xml.name=r[1]}return(0,Z.memoizedCreateXMLExample)(e,n)}return(0,C.default)((0,Z.memoizedSampleFromSchema)(e,n),null,2)},t.parseSearch=function(){var e={},t=ee.default.location.search;if(!t)return{};if(""!=t){var n=t.substr(1).split("&");for(var r in n)r=n[r].split("="),e[decodeURIComponent(r[0])]=decodeURIComponent(r[1])}return e},t.btoa=function(t){var n=void 0;return n=t instanceof e?t:new e(t.toString(),"utf-8"),n.toString("base64")},t.sorters={operationsSorter:{alpha:function(e,t){return e.get("path").localeCompare(t.get("path"))},method:function(e,t){return e.get("method").localeCompare(t.get("method"))}},tagsSorter:{alpha:function(e,t){return e.localeCompare(t)}}},t.buildFormData=function(e){var t=[];for(var n in e){var r=e[n];void 0!==r&&""!==r&&t.push([n,"=",encodeURIComponent(r).replace(/%20/g,"+")].join(""))}return t.join("&")},t.shallowEqualKeys=function(e,t,n){return!!(0,J.default)(n,function(n){return(0,$.default)(e[n],t[n])})},t.createDeepLinkPath=function(e){return"string"==typeof e||e instanceof String?e.trim().replace(/\s/g,"_"):""});t.escapeDeepLinkPath=function(e){return(0,ne.default)(ge(e))},t.getExtensions=function(e){return e.filter(function(e,t){return/^x-/.test(t)})}}).call(t,n(41).Buffer)},function(e,t,n){"use strict";function r(e){if(null===e||void 0===e)throw new TypeError("Object.assign cannot be called with null or undefined");return Object(e)}/* +object-assign +(c) Sindre Sorhus +@license MIT +*/ +var i=Object.getOwnPropertySymbols,o=Object.prototype.hasOwnProperty,a=Object.prototype.propertyIsEnumerable;e.exports=function(){try{if(!Object.assign)return!1;var e=new String("abc");if(e[5]="de","5"===Object.getOwnPropertyNames(e)[0])return!1;for(var t={},n=0;n<10;n++)t["_"+String.fromCharCode(n)]=n;if("0123456789"!==Object.getOwnPropertyNames(t).map(function(e){return t[e]}).join(""))return!1;var r={};return"abcdefghijklmnopqrst".split("").forEach(function(e){r[e]=e}),"abcdefghijklmnopqrst"===Object.keys(Object.assign({},r)).join("")}catch(e){return!1}}()?Object.assign:function(e,t){for(var n,s,u=r(e),l=1;l6?s-6:0),l=6;l5?l-5:0),p=5;p5?a-5:0),u=5;u key("+c[p]+")"].concat(s));if(h instanceof Error)return h}}return i(t)}function u(e){return a(e,"List",b.List.isList)}function l(e,t,n,r){function o(){for(var i=arguments.length,o=Array(i),u=0;u5?s-5:0),l=5;l5?l-5:0),p=5;p>",w={listOf:u,mapOf:c,orderedMapOf:p,setOf:f,orderedSetOf:h,stackOf:d,iterableOf:m,recordOf:v,shape:y,contains:y,mapContains:_,list:o("List",b.List.isList),map:o("Map",b.Map.isMap),orderedMap:o("OrderedMap",b.OrderedMap.isOrderedMap),set:o("Set",b.Set.isSet),orderedSet:o("OrderedSet",b.OrderedSet.isOrderedSet),stack:o("Stack",b.Stack.isStack),seq:o("Seq",b.Seq.isSeq),record:o("Record",function(e){return e instanceof b.Record}),iterable:o("Iterable",b.Iterable.isIterable)};e.exports=w},function(e,t,n){var r=n(24),i=n(14),o=n(54),a=n(57),s=function(e,t,n){var u,l,c,p=e&s.F,f=e&s.G,h=e&s.S,d=e&s.P,m=e&s.B,v=e&s.W,g=f?i:i[t]||(i[t]={}),y=g.prototype,_=f?r:h?r[t]:(r[t]||{}).prototype;f&&(n=t);for(u in n)(l=!p&&_&&void 0!==_[u])&&u in g||(c=l?_[u]:n[u],g[u]=f&&"function"!=typeof _[u]?n[u]:m&&l?o(c,r):v&&_[u]==c?function(e){var t=function(t,n,r){if(this instanceof e){switch(arguments.length){case 0:return new e;case 1:return new e(t);case 2:return new e(t,n)}return new e(t,n,r)}return e.apply(this,arguments)};return t.prototype=e.prototype,t}(c):d&&"function"==typeof c?o(Function.call,c):c,d&&((g.virtual||(g.virtual={}))[u]=c,e&s.R&&y&&!y[u]&&a(y,u,c)))};s.F=1,s.G=2,s.S=4,s.P=8,s.B=16,s.W=32,s.U=64,s.R=128,e.exports=s},function(e,t){var n=e.exports="undefined"!=typeof window&&window.Math==Math?window:"undefined"!=typeof self&&self.Math==Math?self:Function("return this")();"number"==typeof __g&&(__g=n)},function(e,t,n){"use strict";var r=!("undefined"==typeof window||!window.document||!window.document.createElement),i={canUseDOM:r,canUseWorkers:"undefined"!=typeof Worker,canUseEventListeners:r&&!(!window.addEventListener&&!window.attachEvent),canUseViewport:r&&!!window.screen,isInWorker:!r};e.exports=i},function(e,t,n){"use strict";function r(e){return Object.prototype.toString.call(e)}function i(e){return"[object String]"===r(e)}function o(e,t){return!!e&&d.call(e,t)}function a(e){return[].slice.call(arguments,1).forEach(function(t){if(t){if("object"!=typeof t)throw new TypeError(t+"must be object");Object.keys(t).forEach(function(n){e[n]=t[n]})}}),e}function s(e){return e.indexOf("\\")<0?e:e.replace(m,"$1")}function u(e){return!(e>=55296&&e<=57343)&&(!(e>=64976&&e<=65007)&&(65535!=(65535&e)&&65534!=(65535&e)&&(!(e>=0&&e<=8)&&(11!==e&&(!(e>=14&&e<=31)&&(!(e>=127&&e<=159)&&!(e>1114111)))))))}function l(e){if(e>65535){e-=65536;var t=55296+(e>>10),n=56320+(1023&e);return String.fromCharCode(t,n)}return String.fromCharCode(e)}function c(e,t){var n=0;return o(y,t)?y[t]:35===t.charCodeAt(0)&&g.test(t)&&(n="x"===t[1].toLowerCase()?parseInt(t.slice(2),16):parseInt(t.slice(1),10),u(n))?l(n):e}function p(e){return e.indexOf("&")<0?e:e.replace(v,c)}function f(e){return x[e]}function h(e){return _.test(e)?e.replace(b,f):e}var d=Object.prototype.hasOwnProperty,m=/\\([\\!"#$%&'()*+,.\/:;<=>?@[\]^_`{|}~-])/g,v=/&([a-z#][a-z0-9]{1,31});/gi,g=/^#((?:x[a-f0-9]{1,8}|[0-9]{1,8}))/i,y=n(488),_=/[&<>"]/,b=/[&<>"]/g,x={"&":"&","<":"<",">":">",'"':"""};t.assign=a,t.isString=i,t.has=o,t.unescapeMd=s,t.isValidEntityCode=u,t.fromCodePoint=l,t.replaceEntities=p,t.escapeHtml=h},function(e,t,n){"use strict";t.__esModule=!0;var r=n(562),i=function(e){return e&&e.__esModule?e:{default:e}}(r);t.default=function(e){if(Array.isArray(e)){for(var t=0,n=Array(e.length);t"+i+""};e.exports=function(e,t){var n={};n[e]=t(s),r(r.P+r.F*i(function(){var t=""[e]('"');return t!==t.toLowerCase()||t.split('"').length>3}),"String",n)}},function(e,t){var n=e.exports="undefined"!=typeof window&&window.Math==Math?window:"undefined"!=typeof self&&self.Math==Math?self:Function("return this")();"number"==typeof __g&&(__g=n)},function(e,t,n){"use strict";function r(e){return function(){return e}}var i=function(){};i.thatReturns=r,i.thatReturnsFalse=r(!1),i.thatReturnsTrue=r(!0),i.thatReturnsNull=r(null),i.thatReturnsThis=function(){return this},i.thatReturnsArgument=function(e){return e},e.exports=i},function(e,t){function n(){throw new Error("setTimeout has not been defined")}function r(){throw new Error("clearTimeout has not been defined")}function i(e){if(c===setTimeout)return setTimeout(e,0);if((c===n||!c)&&setTimeout)return c=setTimeout,setTimeout(e,0);try{return c(e,0)}catch(t){try{return c.call(null,e,0)}catch(t){return c.call(this,e,0)}}}function o(e){if(p===clearTimeout)return clearTimeout(e);if((p===r||!p)&&clearTimeout)return p=clearTimeout,clearTimeout(e);try{return p(e)}catch(t){try{return p.call(null,e)}catch(t){return p.call(this,e)}}}function a(){m&&h&&(m=!1,h.length?d=h.concat(d):v=-1,d.length&&s())}function s(){if(!m){var e=i(a);m=!0;for(var t=d.length;t;){for(h=d,d=[];++v1)for(var n=1;n=r())throw new RangeError("Attempt to allocate Buffer larger than maximum size: 0x"+r().toString(16)+" bytes");return 0|e}function m(e){return+e!=e&&(e=0),o.alloc(+e)}function v(e,t){if(o.isBuffer(e))return e.length;if("undefined"!=typeof ArrayBuffer&&"function"==typeof ArrayBuffer.isView&&(ArrayBuffer.isView(e)||e instanceof ArrayBuffer))return e.byteLength;"string"!=typeof e&&(e=""+e);var n=e.length;if(0===n)return 0;for(var r=!1;;)switch(t){case"ascii":case"latin1":case"binary":return n;case"utf8":case"utf-8":case void 0:return V(e).length;case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return 2*n;case"hex":return n>>>1;case"base64":return J(e).length;default:if(r)return V(e).length;t=(""+t).toLowerCase(),r=!0}}function g(e,t,n){var r=!1;if((void 0===t||t<0)&&(t=0),t>this.length)return"";if((void 0===n||n>this.length)&&(n=this.length),n<=0)return"";if(n>>>=0,t>>>=0,n<=t)return"";for(e||(e="utf8");;)switch(e){case"hex":return P(this,t,n);case"utf8":case"utf-8":return D(this,t,n);case"ascii":return M(this,t,n);case"latin1":case"binary":return T(this,t,n);case"base64":return A(this,t,n);case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return I(this,t,n);default:if(r)throw new TypeError("Unknown encoding: "+e);e=(e+"").toLowerCase(),r=!0}}function y(e,t,n){var r=e[t];e[t]=e[n],e[n]=r}function _(e,t,n,r,i){if(0===e.length)return-1;if("string"==typeof n?(r=n,n=0):n>2147483647?n=2147483647:n<-2147483648&&(n=-2147483648),n=+n,isNaN(n)&&(n=i?0:e.length-1),n<0&&(n=e.length+n),n>=e.length){if(i)return-1;n=e.length-1}else if(n<0){if(!i)return-1;n=0}if("string"==typeof t&&(t=o.from(t,r)),o.isBuffer(t))return 0===t.length?-1:b(e,t,n,r,i);if("number"==typeof t)return t&=255,o.TYPED_ARRAY_SUPPORT&&"function"==typeof Uint8Array.prototype.indexOf?i?Uint8Array.prototype.indexOf.call(e,t,n):Uint8Array.prototype.lastIndexOf.call(e,t,n):b(e,[t],n,r,i);throw new TypeError("val must be string, number or Buffer")}function b(e,t,n,r,i){function o(e,t){return 1===a?e[t]:e.readUInt16BE(t*a)}var a=1,s=e.length,u=t.length;if(void 0!==r&&("ucs2"===(r=String(r).toLowerCase())||"ucs-2"===r||"utf16le"===r||"utf-16le"===r)){if(e.length<2||t.length<2)return-1;a=2,s/=2,u/=2,n/=2}var l;if(i){var c=-1;for(l=n;ls&&(n=s-u),l=n;l>=0;l--){for(var p=!0,f=0;fi&&(r=i):r=i;var o=t.length;if(o%2!=0)throw new TypeError("Invalid hex string");r>o/2&&(r=o/2);for(var a=0;a239?4:o>223?3:o>191?2:1;if(i+s<=n){var u,l,c,p;switch(s){case 1:o<128&&(a=o);break;case 2:u=e[i+1],128==(192&u)&&(p=(31&o)<<6|63&u)>127&&(a=p);break;case 3:u=e[i+1],l=e[i+2],128==(192&u)&&128==(192&l)&&(p=(15&o)<<12|(63&u)<<6|63&l)>2047&&(p<55296||p>57343)&&(a=p);break;case 4:u=e[i+1],l=e[i+2],c=e[i+3],128==(192&u)&&128==(192&l)&&128==(192&c)&&(p=(15&o)<<18|(63&u)<<12|(63&l)<<6|63&c)>65535&&p<1114112&&(a=p)}}null===a?(a=65533,s=1):a>65535&&(a-=65536,r.push(a>>>10&1023|55296),a=56320|1023&a),r.push(a),i+=s}return O(r)}function O(e){var t=e.length;if(t<=Q)return String.fromCharCode.apply(String,e);for(var n="",r=0;rr)&&(n=r);for(var i="",o=t;on)throw new RangeError("Trying to access beyond buffer length")}function F(e,t,n,r,i,a){if(!o.isBuffer(e))throw new TypeError('"buffer" argument must be a Buffer instance');if(t>i||te.length)throw new RangeError("Index out of range")}function j(e,t,n,r){t<0&&(t=65535+t+1);for(var i=0,o=Math.min(e.length-n,2);i>>8*(r?i:1-i)}function N(e,t,n,r){t<0&&(t=4294967295+t+1);for(var i=0,o=Math.min(e.length-n,4);i>>8*(r?i:3-i)&255}function B(e,t,n,r,i,o){if(n+r>e.length)throw new RangeError("Index out of range");if(n<0)throw new RangeError("Index out of range")}function L(e,t,n,r,i){return i||B(e,t,n,4,3.4028234663852886e38,-3.4028234663852886e38),$.write(e,t,n,r,23,4),n+4}function q(e,t,n,r,i){return i||B(e,t,n,8,1.7976931348623157e308,-1.7976931348623157e308),$.write(e,t,n,r,52,8),n+8}function z(e){if(e=U(e).replace(ee,""),e.length<2)return"";for(;e.length%4!=0;)e+="=";return e}function U(e){return e.trim?e.trim():e.replace(/^\s+|\s+$/g,"")}function W(e){return e<16?"0"+e.toString(16):e.toString(16)}function V(e,t){t=t||1/0;for(var n,r=e.length,i=null,o=[],a=0;a55295&&n<57344){if(!i){if(n>56319){(t-=3)>-1&&o.push(239,191,189);continue}if(a+1===r){(t-=3)>-1&&o.push(239,191,189);continue}i=n;continue}if(n<56320){(t-=3)>-1&&o.push(239,191,189),i=n;continue}n=65536+(i-55296<<10|n-56320)}else i&&(t-=3)>-1&&o.push(239,191,189);if(i=null,n<128){if((t-=1)<0)break;o.push(n)}else if(n<2048){if((t-=2)<0)break;o.push(n>>6|192,63&n|128)}else if(n<65536){if((t-=3)<0)break;o.push(n>>12|224,n>>6&63|128,63&n|128)}else{if(!(n<1114112))throw new Error("Invalid code point");if((t-=4)<0)break;o.push(n>>18|240,n>>12&63|128,n>>6&63|128,63&n|128)}}return o}function H(e){for(var t=[],n=0;n>8,i=n%256,o.push(i),o.push(r);return o}function J(e){return Y.toByteArray(z(e))}function K(e,t,n,r){for(var i=0;i=t.length||i>=e.length);++i)t[i+n]=e[i];return i}function X(e){return e!==e}/*! + * The buffer module from node.js, for the browser. + * + * @author Feross Aboukhadijeh + * @license MIT + */ +var Y=n(569),$=n(763),Z=n(387);t.Buffer=o,t.SlowBuffer=m,t.INSPECT_MAX_BYTES=50,o.TYPED_ARRAY_SUPPORT=void 0!==e.TYPED_ARRAY_SUPPORT?e.TYPED_ARRAY_SUPPORT:function(){try{var e=new Uint8Array(1);return e.__proto__={__proto__:Uint8Array.prototype,foo:function(){return 42}},42===e.foo()&&"function"==typeof e.subarray&&0===e.subarray(1,1).byteLength}catch(e){return!1}}(),t.kMaxLength=r(),o.poolSize=8192,o._augment=function(e){return e.__proto__=o.prototype,e},o.from=function(e,t,n){return a(null,e,t,n)},o.TYPED_ARRAY_SUPPORT&&(o.prototype.__proto__=Uint8Array.prototype,o.__proto__=Uint8Array,"undefined"!=typeof Symbol&&Symbol.species&&o[Symbol.species]===o&&Object.defineProperty(o,Symbol.species,{value:null,configurable:!0})),o.alloc=function(e,t,n){return u(null,e,t,n)},o.allocUnsafe=function(e){return l(null,e)},o.allocUnsafeSlow=function(e){return l(null,e)},o.isBuffer=function(e){return!(null==e||!e._isBuffer)},o.compare=function(e,t){if(!o.isBuffer(e)||!o.isBuffer(t))throw new TypeError("Arguments must be Buffers");if(e===t)return 0;for(var n=e.length,r=t.length,i=0,a=Math.min(n,r);i0&&(e=this.toString("hex",0,n).match(/.{2}/g).join(" "),this.length>n&&(e+=" ... ")),""},o.prototype.compare=function(e,t,n,r,i){if(!o.isBuffer(e))throw new TypeError("Argument must be a Buffer");if(void 0===t&&(t=0),void 0===n&&(n=e?e.length:0),void 0===r&&(r=0),void 0===i&&(i=this.length),t<0||n>e.length||r<0||i>this.length)throw new RangeError("out of range index");if(r>=i&&t>=n)return 0;if(r>=i)return-1;if(t>=n)return 1;if(t>>>=0,n>>>=0,r>>>=0,i>>>=0,this===e)return 0;for(var a=i-r,s=n-t,u=Math.min(a,s),l=this.slice(r,i),c=e.slice(t,n),p=0;pi)&&(n=i),e.length>0&&(n<0||t<0)||t>this.length)throw new RangeError("Attempt to write outside buffer bounds");r||(r="utf8");for(var o=!1;;)switch(r){case"hex":return x(this,e,t,n);case"utf8":case"utf-8":return w(this,e,t,n);case"ascii":return k(this,e,t,n);case"latin1":case"binary":return E(this,e,t,n);case"base64":return S(this,e,t,n);case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return C(this,e,t,n);default:if(o)throw new TypeError("Unknown encoding: "+r);r=(""+r).toLowerCase(),o=!0}},o.prototype.toJSON=function(){return{type:"Buffer",data:Array.prototype.slice.call(this._arr||this,0)}};var Q=4096;o.prototype.slice=function(e,t){var n=this.length;e=~~e,t=void 0===t?n:~~t,e<0?(e+=n)<0&&(e=0):e>n&&(e=n),t<0?(t+=n)<0&&(t=0):t>n&&(t=n),t0&&(i*=256);)r+=this[e+--t]*i;return r},o.prototype.readUInt8=function(e,t){return t||R(e,1,this.length),this[e]},o.prototype.readUInt16LE=function(e,t){return t||R(e,2,this.length),this[e]|this[e+1]<<8},o.prototype.readUInt16BE=function(e,t){return t||R(e,2,this.length),this[e]<<8|this[e+1]},o.prototype.readUInt32LE=function(e,t){return t||R(e,4,this.length),(this[e]|this[e+1]<<8|this[e+2]<<16)+16777216*this[e+3]},o.prototype.readUInt32BE=function(e,t){return t||R(e,4,this.length),16777216*this[e]+(this[e+1]<<16|this[e+2]<<8|this[e+3])},o.prototype.readIntLE=function(e,t,n){e|=0,t|=0,n||R(e,t,this.length);for(var r=this[e],i=1,o=0;++o=i&&(r-=Math.pow(2,8*t)),r},o.prototype.readIntBE=function(e,t,n){e|=0,t|=0,n||R(e,t,this.length);for(var r=t,i=1,o=this[e+--r];r>0&&(i*=256);)o+=this[e+--r]*i;return i*=128,o>=i&&(o-=Math.pow(2,8*t)),o},o.prototype.readInt8=function(e,t){return t||R(e,1,this.length),128&this[e]?-1*(255-this[e]+1):this[e]},o.prototype.readInt16LE=function(e,t){t||R(e,2,this.length);var n=this[e]|this[e+1]<<8;return 32768&n?4294901760|n:n},o.prototype.readInt16BE=function(e,t){t||R(e,2,this.length);var n=this[e+1]|this[e]<<8;return 32768&n?4294901760|n:n},o.prototype.readInt32LE=function(e,t){return t||R(e,4,this.length),this[e]|this[e+1]<<8|this[e+2]<<16|this[e+3]<<24},o.prototype.readInt32BE=function(e,t){return t||R(e,4,this.length),this[e]<<24|this[e+1]<<16|this[e+2]<<8|this[e+3]},o.prototype.readFloatLE=function(e,t){return t||R(e,4,this.length),$.read(this,e,!0,23,4)},o.prototype.readFloatBE=function(e,t){return t||R(e,4,this.length),$.read(this,e,!1,23,4)},o.prototype.readDoubleLE=function(e,t){return t||R(e,8,this.length),$.read(this,e,!0,52,8)},o.prototype.readDoubleBE=function(e,t){return t||R(e,8,this.length),$.read(this,e,!1,52,8)},o.prototype.writeUIntLE=function(e,t,n,r){if(e=+e,t|=0,n|=0,!r){F(this,e,t,n,Math.pow(2,8*n)-1,0)}var i=1,o=0;for(this[t]=255&e;++o=0&&(o*=256);)this[t+i]=e/o&255;return t+n},o.prototype.writeUInt8=function(e,t,n){return e=+e,t|=0,n||F(this,e,t,1,255,0),o.TYPED_ARRAY_SUPPORT||(e=Math.floor(e)),this[t]=255&e,t+1},o.prototype.writeUInt16LE=function(e,t,n){return e=+e,t|=0,n||F(this,e,t,2,65535,0),o.TYPED_ARRAY_SUPPORT?(this[t]=255&e,this[t+1]=e>>>8):j(this,e,t,!0),t+2},o.prototype.writeUInt16BE=function(e,t,n){return e=+e,t|=0,n||F(this,e,t,2,65535,0),o.TYPED_ARRAY_SUPPORT?(this[t]=e>>>8,this[t+1]=255&e):j(this,e,t,!1),t+2},o.prototype.writeUInt32LE=function(e,t,n){return e=+e,t|=0,n||F(this,e,t,4,4294967295,0),o.TYPED_ARRAY_SUPPORT?(this[t+3]=e>>>24,this[t+2]=e>>>16,this[t+1]=e>>>8,this[t]=255&e):N(this,e,t,!0),t+4},o.prototype.writeUInt32BE=function(e,t,n){return e=+e,t|=0,n||F(this,e,t,4,4294967295,0),o.TYPED_ARRAY_SUPPORT?(this[t]=e>>>24,this[t+1]=e>>>16,this[t+2]=e>>>8,this[t+3]=255&e):N(this,e,t,!1),t+4},o.prototype.writeIntLE=function(e,t,n,r){if(e=+e,t|=0,!r){var i=Math.pow(2,8*n-1);F(this,e,t,n,i-1,-i)}var o=0,a=1,s=0;for(this[t]=255&e;++o>0)-s&255;return t+n},o.prototype.writeIntBE=function(e,t,n,r){if(e=+e,t|=0,!r){var i=Math.pow(2,8*n-1);F(this,e,t,n,i-1,-i)}var o=n-1,a=1,s=0;for(this[t+o]=255&e;--o>=0&&(a*=256);)e<0&&0===s&&0!==this[t+o+1]&&(s=1),this[t+o]=(e/a>>0)-s&255;return t+n},o.prototype.writeInt8=function(e,t,n){return e=+e,t|=0,n||F(this,e,t,1,127,-128),o.TYPED_ARRAY_SUPPORT||(e=Math.floor(e)),e<0&&(e=255+e+1),this[t]=255&e,t+1},o.prototype.writeInt16LE=function(e,t,n){return e=+e,t|=0,n||F(this,e,t,2,32767,-32768),o.TYPED_ARRAY_SUPPORT?(this[t]=255&e,this[t+1]=e>>>8):j(this,e,t,!0),t+2},o.prototype.writeInt16BE=function(e,t,n){return e=+e,t|=0,n||F(this,e,t,2,32767,-32768),o.TYPED_ARRAY_SUPPORT?(this[t]=e>>>8,this[t+1]=255&e):j(this,e,t,!1),t+2},o.prototype.writeInt32LE=function(e,t,n){return e=+e,t|=0,n||F(this,e,t,4,2147483647,-2147483648),o.TYPED_ARRAY_SUPPORT?(this[t]=255&e,this[t+1]=e>>>8,this[t+2]=e>>>16,this[t+3]=e>>>24):N(this,e,t,!0),t+4},o.prototype.writeInt32BE=function(e,t,n){return e=+e,t|=0,n||F(this,e,t,4,2147483647,-2147483648),e<0&&(e=4294967295+e+1),o.TYPED_ARRAY_SUPPORT?(this[t]=e>>>24,this[t+1]=e>>>16,this[t+2]=e>>>8,this[t+3]=255&e):N(this,e,t,!1),t+4},o.prototype.writeFloatLE=function(e,t,n){return L(this,e,t,!0,n)},o.prototype.writeFloatBE=function(e,t,n){return L(this,e,t,!1,n)},o.prototype.writeDoubleLE=function(e,t,n){return q(this,e,t,!0,n)},o.prototype.writeDoubleBE=function(e,t,n){return q(this,e,t,!1,n)},o.prototype.copy=function(e,t,n,r){if(n||(n=0),r||0===r||(r=this.length),t>=e.length&&(t=e.length),t||(t=0),r>0&&r=this.length)throw new RangeError("sourceStart out of bounds");if(r<0)throw new RangeError("sourceEnd out of bounds");r>this.length&&(r=this.length),e.length-t=0;--i)e[i+t]=this[i+n];else if(a<1e3||!o.TYPED_ARRAY_SUPPORT)for(i=0;i>>=0,n=void 0===n?this.length:n>>>0,e||(e=0);var a;if("number"==typeof e)for(a=t;a0&&(a=this.buffer[u-1],e.call(r,a)<0);)if(u--,this.pointer-u>n/2-1){o=" ... ",u+=5;break}for(l="",i=this.pointer;in/2-1){l=" ... ",i-=5;break}return""+new Array(t).join(" ")+o+this.buffer.slice(u,i)+l+"\n"+new Array(t+this.pointer-u+o.length).join(" ")+"^"},t.prototype.toString=function(){var e,t;return e=this.get_snippet(),t=" on line "+(this.line+1)+", column "+(this.column+1),e?t:t+":\n"+e},t}(),this.YAMLError=function(e){function n(e){this.message=e,n.__super__.constructor.call(this),this.stack=this.toString()+"\n"+(new Error).stack.split("\n").slice(1).join("\n")}return t(n,e),n.prototype.toString=function(){return this.message},n}(Error),this.MarkedYAMLError=function(e){function n(e,t,r,i,o){this.context=e,this.context_mark=t,this.problem=r,this.problem_mark=i,this.note=o,n.__super__.constructor.call(this)}return t(n,e),n.prototype.toString=function(){var e;return e=[],null!=this.context&&e.push(this.context),null==this.context_mark||null!=this.problem&&null!=this.problem_mark&&this.context_mark.line===this.problem_mark.line&&this.context_mark.column===this.problem_mark.column||e.push(this.context_mark.toString()),null!=this.problem&&e.push(this.problem),null!=this.problem_mark&&e.push(this.problem_mark.toString()),null!=this.note&&e.push(this.note),e.join("\n")},n}(this.YAMLError)}).call(this)},function(e,t,n){e.exports={default:n(592),__esModule:!0}},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}t.__esModule=!0;var i=n(566),o=r(i),a=n(565),s=r(a),u="function"==typeof s.default&&"symbol"==typeof o.default?function(e){return typeof e}:function(e){return e&&"function"==typeof s.default&&e.constructor===s.default&&e!==s.default.prototype?"symbol":typeof e};t.default="function"==typeof s.default&&"symbol"===u(o.default)?function(e){return void 0===e?"undefined":u(e)}:function(e){return e&&"function"==typeof s.default&&e.constructor===s.default&&e!==s.default.prototype?"symbol":void 0===e?"undefined":u(e)}},function(e,t,n){e.exports=!n(55)(function(){return 7!=Object.defineProperty({},"a",{get:function(){return 7}}).a})},function(e,t,n){"use strict";function r(e,t,n){return n?[e,t]:e}Object.defineProperty(t,"__esModule",{value:!0}),t.default=r,e.exports=t.default},function(e,t,n){"use strict";function r(e,t,n,r){this.dispatchConfig=e,this._targetInst=t,this.nativeEvent=n;var i=this.constructor.Interface;for(var o in i)if(i.hasOwnProperty(o)){var s=i[o];s?this[o]=s(n):"target"===o?this.target=r:this[o]=n[o]}var u=null!=n.defaultPrevented?n.defaultPrevented:!1===n.returnValue;return this.isDefaultPrevented=u?a.thatReturnsTrue:a.thatReturnsFalse,this.isPropagationStopped=a.thatReturnsFalse,this}var i=n(12),o=n(71),a=n(32),s=(n(9),["dispatchConfig","_targetInst","nativeEvent","isDefaultPrevented","isPropagationStopped","_dispatchListeners","_dispatchInstances"]),u={type:null,target:null,currentTarget:a.thatReturnsNull,eventPhase:null,bubbles:null,cancelable:null,timeStamp:function(e){return e.timeStamp||Date.now()},defaultPrevented:null,isTrusted:null};i(r.prototype,{preventDefault:function(){this.defaultPrevented=!0;var e=this.nativeEvent;e&&(e.preventDefault?e.preventDefault():"unknown"!=typeof e.returnValue&&(e.returnValue=!1),this.isDefaultPrevented=a.thatReturnsTrue)},stopPropagation:function(){var e=this.nativeEvent;e&&(e.stopPropagation?e.stopPropagation():"unknown"!=typeof e.cancelBubble&&(e.cancelBubble=!0),this.isPropagationStopped=a.thatReturnsTrue)},persist:function(){this.isPersistent=a.thatReturnsTrue},isPersistent:a.thatReturnsFalse,destructor:function(){var e=this.constructor.Interface;for(var t in e)this[t]=null;for(var n=0;n1?t-1:0),i=1;i2?n-2:0),o=2;o=n?e:e.length+1===n?""+t+e:""+new Array(n-e.length+1).join(t)+e},this.to_hex=function(e){return"string"==typeof e&&(e=e.charCodeAt(0)),e.toString(16)}}).call(this)}).call(t,n(16))},function(e,t,n){var r=n(78);e.exports=function(e){if(!r(e))throw TypeError(e+" is not an object!");return e}},function(e,t){var n=e.exports={version:"2.5.3"};"number"==typeof __e&&(__e=n)},function(e,t,n){var r=n(138),i=n(360);e.exports=n(106)?function(e,t,n){return r.f(e,t,i(1,n))}:function(e,t,n){return e[t]=n,e}},function(e,t,n){"use strict";var r=n(724),i=Math.max;e.exports=function(e){return i(0,r(e))}},function(e,t,n){function r(e){return null==e?void 0===e?u:s:(e=Object(e),l&&l in e?o(e):a(e))}var i=n(83),o=n(895),a=n(924),s="[object Null]",u="[object Undefined]",l=i?i.toStringTag:void 0;e.exports=r},function(e,t,n){function r(e,t){var n=o(e,t);return i(n)?n:void 0}var i=n(853),o=n(896);e.exports=r},function(e,t){function n(e){return null!=e&&"object"==typeof e}e.exports=n},function(e,t,n){"use strict"},function(e,t,n){"use strict";var r=n(10),i=(n(7),function(e){var t=this;if(t.instancePool.length){var n=t.instancePool.pop();return t.call(n,e),n}return new t(e)}),o=function(e,t){var n=this;if(n.instancePool.length){var r=n.instancePool.pop();return n.call(r,e,t),r}return new n(e,t)},a=function(e,t,n){var r=this;if(r.instancePool.length){var i=r.instancePool.pop();return r.call(i,e,t,n),i}return new r(e,t,n)},s=function(e,t,n,r){var i=this;if(i.instancePool.length){var o=i.instancePool.pop();return i.call(o,e,t,n,r),o}return new i(e,t,n,r)},u=function(e){var t=this;e instanceof t||r("25"),e.destructor(),t.instancePool.length`\\x00-\\x20]+|'[^']*'|\"[^\"]*\"))?)*\\s*/?>",u="]",l=new RegExp("^(?:<[A-Za-z][A-Za-z0-9-]*(?:\\s+[a-zA-Z_:][a-zA-Z0-9:._-]*(?:\\s*=\\s*(?:[^\"'=<>`\\x00-\\x20]+|'[^']*'|\"[^\"]*\"))?)*\\s*/?>|]|\x3c!----\x3e|\x3c!--(?:-?[^>-])(?:-?[^-])*--\x3e|[<][?].*?[?][>]|]*>|)","i"),c=/[\\&]/,p="[!\"#$%&'()*+,./:;<=>?@[\\\\\\]^_`{|}~-]",f=new RegExp("\\\\"+p+"|"+a,"gi"),h=new RegExp('[&<>"]',"g"),d=new RegExp(a+'|[&<>"]',"gi"),m=function(e){return 92===e.charCodeAt(0)?e.charAt(1):o(e)},v=function(e){return c.test(e)?e.replace(f,m):e},g=function(e){try{return r(i(e))}catch(t){return e}},y=function(e){switch(e){case"&":return"&";case"<":return"<";case">":return">";case'"':return""";default:return e}},_=function(e,t){return h.test(e)?t?e.replace(d,y):e.replace(h,y):e};e.exports={unescapeString:v,normalizeURI:g,escapeXml:_,reHtmlTag:l,OPENTAG:s,CLOSETAG:u,ENTITY:a,ESCAPABLE:p}},function(e,t){e.exports={}},function(e,t,n){var r=n(182),i=n(179);e.exports=function(e){return r(i(e))}},function(e,t,n){var r=n(179);e.exports=function(e){return Object(r(e))}},function(e,t){e.exports=function(e){return"object"==typeof e?null!==e:"function"==typeof e}},function(e,t,n){var r=n(31),i=n(65),o=n(108),a=n(203)("src"),s=Function.toString,u=(""+s).split("toString");n(64).inspectSource=function(e){return s.call(e)},(e.exports=function(e,t,n,s){var l="function"==typeof n;l&&(o(n,"name")||i(n,"name",t)),e[t]!==n&&(l&&(o(n,a)||i(n,a,e[t]?""+e[t]:u.join(String(t)))),e===r?e[t]=n:s?e[t]?e[t]=n:i(e,t,n):(delete e[t],i(e,t,n)))})(Function.prototype,"toString",function(){return"function"==typeof this&&this[a]||s.call(this)})},function(e,t,n){"use strict";var r=n(372)();e.exports=function(e){return e!==r&&null!==e}},function(e,t,n){"use strict";function r(e){return void 0===e||null===e}function i(e){return"object"==typeof e&&null!==e}function o(e){return Array.isArray(e)?e:r(e)?[]:[e]}function a(e,t){var n,r,i,o;if(t)for(o=Object.keys(t),n=0,r=o.length;n`\\x00-\\x20]+|'[^']*'|\"[^\"]*\"))?)*\\s*/?>",u="]",l=new RegExp("^(?:<[A-Za-z][A-Za-z0-9-]*(?:\\s+[a-zA-Z_:][a-zA-Z0-9:._-]*(?:\\s*=\\s*(?:[^\"'=<>`\\x00-\\x20]+|'[^']*'|\"[^\"]*\"))?)*\\s*/?>|]|\x3c!----\x3e|\x3c!--(?:-?[^>-])(?:-?[^-])*--\x3e|[<][?].*?[?][>]|]*>|)","i"),c=/[\\&]/,p="[!\"#$%&'()*+,./:;<=>?@[\\\\\\]^_`{|}~-]",f=new RegExp("\\\\"+p+"|"+a,"gi"),h=new RegExp('[&<>"]',"g"),d=new RegExp(a+'|[&<>"]',"gi"),m=function(e){return 92===e.charCodeAt(0)?e.charAt(1):o(e)},v=function(e){return c.test(e)?e.replace(f,m):e},g=function(e){try{return r(i(e))}catch(t){return e}},y=function(e){switch(e){case"&":return"&";case"<":return"<";case">":return">";case'"':return""";default:return e}},_=function(e,t){return h.test(e)?t?e.replace(d,y):e.replace(h,y):e};e.exports={unescapeString:v,normalizeURI:g,escapeXml:_,reHtmlTag:l,OPENTAG:s,CLOSETAG:u,ENTITY:a,ESCAPABLE:p}},function(e,t,n){"use strict";var r=n(12),i=n(474),o=n(1098),a=n(1099),s=n(94),u=n(1100),l=n(1101),c=n(1102),p=n(1106),f=s.createElement,h=s.createFactory,d=s.cloneElement,m=r,v=function(e){return e},g={Children:{map:o.map,forEach:o.forEach,count:o.count,toArray:o.toArray,only:p},Component:i.Component,PureComponent:i.PureComponent,createElement:f,cloneElement:d,isValidElement:s.isValidElement,PropTypes:u,createClass:c,createFactory:h,createMixin:v,DOM:a,version:l,__spread:m};e.exports=g},function(e,t,n){"use strict";function r(e){return void 0!==e.ref}function i(e){return void 0!==e.key}var o=n(12),a=n(52),s=(n(9),n(478),Object.prototype.hasOwnProperty),u=n(476),l={key:!0,ref:!0,__self:!0,__source:!0},c=function(e,t,n,r,i,o,a){var s={$$typeof:u,type:e,key:t,ref:n,props:a,_owner:o};return s};c.createElement=function(e,t,n){var o,u={},p=null,f=null;if(null!=t){r(t)&&(f=t.ref),i(t)&&(p=""+t.key),void 0===t.__self?null:t.__self,void 0===t.__source?null:t.__source;for(o in t)s.call(t,o)&&!l.hasOwnProperty(o)&&(u[o]=t[o])}var h=arguments.length-2;if(1===h)u.children=n;else if(h>1){for(var d=Array(h),m=0;m1){for(var g=Array(v),y=0;y=0||Object.prototype.hasOwnProperty.call(e,r)&&(n[r]=e[r]);return n}},function(e,t){e.exports=function(e){if("function"!=typeof e)throw TypeError(e+" is not a function!");return e}},function(e,t){var n={}.toString;e.exports=function(e){return n.call(e).slice(8,-1)}},function(e,t,n){var r=n(345),i=n(181);e.exports=Object.keys||function(e){return r(e,i)}},function(e,t){e.exports=function(e,t){return{enumerable:!(1&e),configurable:!(2&e),writable:!(4&e),value:t}}},function(e,t,n){var r=n(42).f,i=n(56),o=n(21)("toStringTag");e.exports=function(e,t,n){e&&!i(e=n?e:e.prototype,o)&&r(e,o,{configurable:!0,value:t})}},function(e,t,n){"use strict";var r=n(616)(!0);n(339)(String,"String",function(e){this._t=String(e),this._i=0},function(){var e,t=this._t,n=this._i;return n>=t.length?{value:void 0,done:!0}:(e=r(t,n),this._i+=e.length,{value:e,done:!1})})},function(e,t,n){n(621);for(var r=n(24),i=n(57),o=n(75),a=n(21)("toStringTag"),s="CSSRuleList,CSSStyleDeclaration,CSSValueList,ClientRectList,DOMRectList,DOMStringList,DOMTokenList,DataTransferItemList,FileList,HTMLAllCollection,HTMLCollection,HTMLFormElement,HTMLSelectElement,MediaList,MimeTypeArray,NamedNodeMap,NodeList,PaintRequestList,Plugin,PluginArray,SVGLengthList,SVGNumberList,SVGPathSegList,SVGPointList,SVGStringList,SVGTransformList,SourceBufferList,StyleSheetList,TextTrackCueList,TextTrackList,TouchList".split(","),u=0;u0?i(r(e),9007199254740991):0}},function(e,t,n){(function(e){function n(e){return Array.isArray?Array.isArray(e):"[object Array]"===v(e)}function r(e){return"boolean"==typeof e}function i(e){return null===e}function o(e){return null==e}function a(e){return"number"==typeof e}function s(e){return"string"==typeof e}function u(e){return"symbol"==typeof e}function l(e){return void 0===e}function c(e){return"[object RegExp]"===v(e)}function p(e){return"object"==typeof e&&null!==e}function f(e){return"[object Date]"===v(e)}function h(e){return"[object Error]"===v(e)||e instanceof Error}function d(e){return"function"==typeof e}function m(e){return null===e||"boolean"==typeof e||"number"==typeof e||"string"==typeof e||"symbol"==typeof e||void 0===e}function v(e){return Object.prototype.toString.call(e)}t.isArray=n,t.isBoolean=r,t.isNull=i,t.isNullOrUndefined=o,t.isNumber=a,t.isString=s,t.isSymbol=u,t.isUndefined=l,t.isRegExp=c,t.isObject=p,t.isDate=f,t.isError=h,t.isFunction=d,t.isPrimitive=m,t.isBuffer=e.isBuffer}).call(t,n(41).Buffer)},function(e,t,n){"use strict";function r(e){return"string"==typeof e&&i.test(e)}Object.defineProperty(t,"__esModule",{value:!0}),t.default=r;var i=/-webkit-|-moz-|-ms-/;e.exports=t.default},function(e,t){e.exports={Text:"text",Directive:"directive",Comment:"comment",Script:"script",Style:"style",Tag:"tag",CDATA:"cdata",Doctype:"doctype",isTag:function(e){return"tag"===e.type||"script"===e.type||"style"===e.type}}},function(e,t,n){var r=n(710),i=n(709);t.decode=function(e,t){return(!t||t<=0?i.XML:i.HTML)(e)},t.decodeStrict=function(e,t){return(!t||t<=0?i.XML:i.HTMLStrict)(e)},t.encode=function(e,t){return(!t||t<=0?r.XML:r.HTML)(e)},t.encodeXML=r.XML,t.encodeHTML4=t.encodeHTML5=t.encodeHTML=r.HTML,t.decodeXML=t.decodeXMLStrict=i.XML,t.decodeHTML4=t.decodeHTML5=t.decodeHTML=i.HTML,t.decodeHTML4Strict=t.decodeHTML5Strict=t.decodeHTMLStrict=i.HTMLStrict,t.escape=r.escape},function(e,t,n){"use strict";var r=n(80);e.exports=function(e){if(!r(e))throw new TypeError("Cannot use null or undefined");return e}},function(e,t,n){function r(t,n){return delete e.exports[t],e.exports[t]=n,n}var i=n(380),o=n(699);e.exports={Parser:i,Tokenizer:n(381),ElementType:n(113),DomHandler:o,get FeedHandler(){return r("FeedHandler",n(759))},get Stream(){return r("Stream",n(761))},get WritableStream(){return r("WritableStream",n(382))},get ProxyHandler(){return r("ProxyHandler",n(760))},get DomUtils(){return r("DomUtils",n(701))},get CollectingHandler(){return r("CollectingHandler",n(758))},DefaultHandler:o,get RssHandler(){return r("RssHandler",this.FeedHandler)},parseDOM:function(e,t){var n=new o(t);return new i(n,t).end(e),n.dom},parseFeed:function(t,n){var r=new e.exports.FeedHandler(n);return new i(r,n).end(t),r.dom},createDomStream:function(e,t,n){var r=new o(e,t,n);return new i(r,t)},EVENTS:{attribute:2,cdatastart:0,cdataend:0,text:1,processinginstruction:2,comment:1,commentend:0,closetag:1,opentag:2,opentagname:1,error:1,end:0}}},function(e,t,n){"use strict";function r(e,t){Error.call(this),this.name="YAMLException",this.reason=e,this.mark=t,this.message=(this.reason||"(unknown reason)")+(this.mark?" "+this.mark.toString():""),Error.captureStackTrace?Error.captureStackTrace(this,this.constructor):this.stack=(new Error).stack||""}r.prototype=Object.create(Error.prototype),r.prototype.constructor=r,r.prototype.toString=function(e){var t=this.name+": ";return t+=this.reason||"(unknown reason)",!e&&this.mark&&(t+=" "+this.mark.toString()),t},e.exports=r},function(e,t,n){"use strict";var r=n(82);e.exports=new r({include:[n(388)],implicit:[n(813),n(806)],explicit:[n(798),n(808),n(809),n(811)]})},function(e,t,n){function r(e){return"function"==typeof e?e:null==e?a:"object"==typeof e?s(e)?o(e[0],e[1]):i(e):u(e)}var i=n(857),o=n(858),a=n(226),s=n(19),u=n(951);e.exports=r},function(e,t){function n(e,t){return e===t||e!==e&&t!==t}e.exports=n},function(e,t){function n(e,t,n){if(t in e)return e[t];if(3===arguments.length)return n;throw new Error('"'+t+'" is a required argument.')}function r(e){var t=e.match(y);return t?{scheme:t[1],auth:t[2],host:t[3],port:t[4],path:t[5]}:null}function i(e){var t="";return e.scheme&&(t+=e.scheme+":"),t+="//",e.auth&&(t+=e.auth+"@"),e.host&&(t+=e.host),e.port&&(t+=":"+e.port),e.path&&(t+=e.path),t}function o(e){var n=e,o=r(e);if(o){if(!o.path)return e;n=o.path}for(var a,s=t.isAbsolute(n),u=n.split(/\/+/),l=0,c=u.length-1;c>=0;c--)a=u[c],"."===a?u.splice(c,1):".."===a?l++:l>0&&(""===a?(u.splice(c+1,l),l=0):(u.splice(c,2),l--));return n=u.join("/"),""===n&&(n=s?"/":"."),o?(o.path=n,i(o)):n}function a(e,t){""===e&&(e="."),""===t&&(t=".");var n=r(t),a=r(e);if(a&&(e=a.path||"/"),n&&!n.scheme)return a&&(n.scheme=a.scheme),i(n);if(n||t.match(_))return t;if(a&&!a.host&&!a.path)return a.host=t,i(a);var s="/"===t.charAt(0)?t:o(e.replace(/\/+$/,"")+"/"+t);return a?(a.path=s,i(a)):s}function s(e,t){""===e&&(e="."),e=e.replace(/\/$/,"");for(var n=0;0!==t.indexOf(e+"/");){var r=e.lastIndexOf("/");if(r<0)return t;if(e=e.slice(0,r),e.match(/^([^\/]+:\/)?\/*$/))return t;++n}return Array(n+1).join("../")+t.substr(e.length+1)}function u(e){return e}function l(e){return p(e)?"$"+e:e}function c(e){return p(e)?e.slice(1):e}function p(e){if(!e)return!1;var t=e.length;if(t<9)return!1;if(95!==e.charCodeAt(t-1)||95!==e.charCodeAt(t-2)||111!==e.charCodeAt(t-3)||116!==e.charCodeAt(t-4)||111!==e.charCodeAt(t-5)||114!==e.charCodeAt(t-6)||112!==e.charCodeAt(t-7)||95!==e.charCodeAt(t-8)||95!==e.charCodeAt(t-9))return!1;for(var n=t-10;n>=0;n--)if(36!==e.charCodeAt(n))return!1;return!0}function f(e,t,n){var r=d(e.source,t.source);return 0!==r?r:0!==(r=e.originalLine-t.originalLine)?r:0!==(r=e.originalColumn-t.originalColumn)||n?r:0!==(r=e.generatedColumn-t.generatedColumn)?r:(r=e.generatedLine-t.generatedLine,0!==r?r:d(e.name,t.name))}function h(e,t,n){var r=e.generatedLine-t.generatedLine;return 0!==r?r:0!==(r=e.generatedColumn-t.generatedColumn)||n?r:0!==(r=d(e.source,t.source))?r:0!==(r=e.originalLine-t.originalLine)?r:(r=e.originalColumn-t.originalColumn,0!==r?r:d(e.name,t.name))}function d(e,t){return e===t?0:null===e?1:null===t?-1:e>t?1:-1}function m(e,t){var n=e.generatedLine-t.generatedLine;return 0!==n?n:0!==(n=e.generatedColumn-t.generatedColumn)?n:0!==(n=d(e.source,t.source))?n:0!==(n=e.originalLine-t.originalLine)?n:(n=e.originalColumn-t.originalColumn,0!==n?n:d(e.name,t.name))}function v(e){return JSON.parse(e.replace(/^\)]}'[^\n]*\n/,""))}function g(e,t,n){if(t=t||"",e&&("/"!==e[e.length-1]&&"/"!==t[0]&&(e+="/"),t=e+t),n){var s=r(n);if(!s)throw new Error("sourceMapURL could not be parsed");if(s.path){var u=s.path.lastIndexOf("/");u>=0&&(s.path=s.path.substring(0,u+1))}t=a(i(s),t)}return o(t)}t.getArg=n;var y=/^(?:([\w+\-.]+):)?\/\/(?:(\w+:\w+)@)?([\w.-]*)(?::(\d+))?(.*)$/,_=/^data:.+\,.+$/;t.urlParse=r,t.urlGenerate=i,t.normalize=o,t.join=a,t.isAbsolute=function(e){return"/"===e.charAt(0)||y.test(e)},t.relative=s;var b=function(){return!("__proto__"in Object.create(null))}();t.toSetString=b?u:l,t.fromSetString=b?u:c,t.compareByOriginalPositions=f,t.compareByGeneratedPositionsDeflated=h,t.compareByGeneratedPositionsInflated=m,t.parseSourceMapInput=v,t.computeSourceURL=g},function(e,t,n){"use strict";function r(e){return"button"===e||"input"===e||"select"===e||"textarea"===e}function i(e,t,n){switch(e){case"onClick":case"onClickCapture":case"onDoubleClick":case"onDoubleClickCapture":case"onMouseDown":case"onMouseDownCapture":case"onMouseMove":case"onMouseMoveCapture":case"onMouseUp":case"onMouseUpCapture":return!(!n.disabled||!r(t));default:return!1}}var o=n(10),a=n(243),s=n(244),u=n(248),l=n(462),c=n(463),p=(n(7),{}),f=null,h=function(e,t){e&&(s.executeDispatchesInOrder(e,t),e.isPersistent()||e.constructor.release(e))},d=function(e){return h(e,!0)},m=function(e){return h(e,!1)},v=function(e){return"."+e._rootNodeID},g={injection:{injectEventPluginOrder:a.injectEventPluginOrder,injectEventPluginsByName:a.injectEventPluginsByName},putListener:function(e,t,n){"function"!=typeof n&&o("94",t,typeof n);var r=v(e);(p[t]||(p[t]={}))[r]=n;var i=a.registrationNameModules[t];i&&i.didPutListener&&i.didPutListener(e,t,n)},getListener:function(e,t){var n=p[t];if(i(t,e._currentElement.type,e._currentElement.props))return null;var r=v(e);return n&&n[r]},deleteListener:function(e,t){var n=a.registrationNameModules[t];n&&n.willDeleteListener&&n.willDeleteListener(e,t);var r=p[t];if(r){delete r[v(e)]}},deleteAllListeners:function(e){var t=v(e);for(var n in p)if(p.hasOwnProperty(n)&&p[n][t]){var r=a.registrationNameModules[n];r&&r.willDeleteListener&&r.willDeleteListener(e,n),delete p[n][t]}},extractEvents:function(e,t,n,r){for(var i,o=a.plugins,s=0;s0&&void 0!==arguments[0]?arguments[0]:{};return{type:v,payload:e}}Object.defineProperty(t,"__esModule",{value:!0}),t.CLEAR=t.NEW_AUTH_ERR=t.NEW_SPEC_ERR_BATCH=t.NEW_SPEC_ERR=t.NEW_THROWN_ERR_BATCH=t.NEW_THROWN_ERR=void 0,t.newThrownErr=r,t.newThrownErrBatch=i,t.newSpecErr=o,t.newSpecErrBatch=a,t.newAuthErr=s,t.clear=u;var l=n(265),c=function(e){return e&&e.__esModule?e:{default:e}}(l),p=t.NEW_THROWN_ERR="err_new_thrown_err",f=t.NEW_THROWN_ERR_BATCH="err_new_thrown_err_batch",h=t.NEW_SPEC_ERR="err_new_spec_err",d=t.NEW_SPEC_ERR_BATCH="err_new_spec_err_batch",m=t.NEW_AUTH_ERR="err_new_auth_err",v=t.CLEAR="err_clear"},function(e,t,n){var r=n(54),i=n(338),o=n(336),a=n(38),s=n(133),u=n(194),l={},c={},t=e.exports=function(e,t,n,p,f){var h,d,m,v,g=f?function(){return e}:u(e),y=r(n,p,t?2:1),_=0;if("function"!=typeof g)throw TypeError(e+" is not iterable!");if(o(g)){for(h=s(e.length);h>_;_++)if((v=t?y(a(d=e[_])[0],d[1]):y(e[_]))===l||v===c)return v}else for(m=g.call(e);!(d=m.next()).done;)if((v=i(m,y,d.value,t))===l||v===c)return v};t.BREAK=l,t.RETURN=c},function(e,t){e.exports=!0},function(e,t,n){var r=n(134)("meta"),i=n(28),o=n(56),a=n(42).f,s=0,u=Object.isExtensible||function(){return!0},l=!n(55)(function(){return u(Object.preventExtensions({}))}),c=function(e){a(e,r,{value:{i:"O"+ ++s,w:{}}})},p=function(e,t){if(!i(e))return"symbol"==typeof e?e:("string"==typeof e?"S":"P")+e;if(!o(e,r)){if(!u(e))return"F";if(!t)return"E";c(e)}return e[r].i},f=function(e,t){if(!o(e,r)){if(!u(e))return!0;if(!t)return!1;c(e)}return e[r].w},h=function(e){return l&&d.NEED&&u(e)&&!o(e,r)&&c(e),e},d=e.exports={KEY:r,NEED:!1,fastKey:p,getWeak:f,onFreeze:h}},function(e,t){t.f={}.propertyIsEnumerable},function(e,t,n){var r=n(190),i=Math.min;e.exports=function(e){return e>0?i(r(e),9007199254740991):0}},function(e,t){var n=0,r=Math.random();e.exports=function(e){return"Symbol(".concat(void 0===e?"":e,")_",(++n+r).toString(36))}},function(e,t){e.exports=function(e){if("function"!=typeof e)throw TypeError(e+" is not a function!");return e}},function(e,t,n){var r=n(135);e.exports=function(e,t,n){if(r(e),void 0===t)return e;switch(n){case 1:return function(n){return e.call(t,n)};case 2:return function(n,r){return e.call(t,n,r)};case 3:return function(n,r,i){return e.call(t,n,r,i)}}return function(){return e.apply(t,arguments)}}},function(e,t,n){"use strict";var r=n(65),i=n(79),o=n(107),a=n(58),s=n(18);e.exports=function(e,t,n){var u=s(e),l=n(a,u,""[e]),c=l[0],p=l[1];o(function(){var t={};return t[u]=function(){return 7},7!=""[e](t)})&&(i(String.prototype,e,c),r(RegExp.prototype,u,2==t?function(e,t){return p.call(e,this,t)}:function(e){return p.call(e,this)}))}},function(e,t,n){var r=n(63),i=n(641),o=n(660),a=Object.defineProperty;t.f=n(106)?Object.defineProperty:function(e,t,n){if(r(e),t=o(t,!0),r(n),i)try{return a(e,t,n)}catch(e){}if("get"in n||"set"in n)throw TypeError("Accessors not supported!");return"value"in n&&(e[t]=n.value),e}},function(e,t){var n=Math.ceil,r=Math.floor;e.exports=function(e){return isNaN(e=+e)?0:(e>0?r:n)(e)}},function(e,t,n){var r=n(643),i=n(58);e.exports=function(e){return r(i(e))}},function(e,t,n){"use strict";var r,i=n(373),o=n(376),a=n(728),s=n(733);r=e.exports=function(e,t){var n,r,a,u,l;return arguments.length<2||"string"!=typeof e?(u=t,t=e,e=null):u=arguments[2],null==e?(n=a=!0,r=!1):(n=s.call(e,"c"),r=s.call(e,"e"),a=s.call(e,"w")),l={value:t,configurable:n,enumerable:r,writable:a},u?i(o(u),l):l},r.gs=function(e,t,n){var r,u,l,c;return"string"!=typeof e?(l=n,n=t,t=e,e=null):l=arguments[3],null==t?t=void 0:a(t)?null==n?n=void 0:a(n)||(l=n,n=void 0):(l=t,t=n=void 0),null==e?(r=!0,u=!1):(r=s.call(e,"c"),u=s.call(e,"e")),c={get:t,set:n,configurable:r,enumerable:u},l?i(o(l),c):c}},function(e,t,n){"use strict";e.exports=n(725)("forEach")},function(e,t){function n(){this._events=this._events||{},this._maxListeners=this._maxListeners||void 0}function r(e){return"function"==typeof e}function i(e){return"number"==typeof e}function o(e){return"object"==typeof e&&null!==e}function a(e){return void 0===e}e.exports=n,n.EventEmitter=n,n.prototype._events=void 0,n.prototype._maxListeners=void 0,n.defaultMaxListeners=10,n.prototype.setMaxListeners=function(e){if(!i(e)||e<0||isNaN(e))throw TypeError("n must be a positive number");return this._maxListeners=e,this},n.prototype.emit=function(e){var t,n,i,s,u,l;if(this._events||(this._events={}),"error"===e&&(!this._events.error||o(this._events.error)&&!this._events.error.length)){if((t=arguments[1])instanceof Error)throw t;var c=new Error('Uncaught, unspecified "error" event. ('+t+")");throw c.context=t,c}if(n=this._events[e],a(n))return!1;if(r(n))switch(arguments.length){case 1:n.call(this);break;case 2:n.call(this,arguments[1]);break;case 3:n.call(this,arguments[1],arguments[2]);break;default:s=Array.prototype.slice.call(arguments,1),n.apply(this,s)}else if(o(n))for(s=Array.prototype.slice.call(arguments,1),l=n.slice(),i=l.length,u=0;u0&&this._events[e].length>i&&(this._events[e].warned=!0,console.error("(node) warning: possible EventEmitter memory leak detected. %d listeners added. Use emitter.setMaxListeners() to increase limit.",this._events[e].length),"function"==typeof console.trace&&console.trace()),this},n.prototype.on=n.prototype.addListener,n.prototype.once=function(e,t){function n(){this.removeListener(e,n),i||(i=!0,t.apply(this,arguments))}if(!r(t))throw TypeError("listener must be a function");var i=!1;return n.listener=t,this.on(e,n),this},n.prototype.removeListener=function(e,t){var n,i,a,s;if(!r(t))throw TypeError("listener must be a function");if(!this._events||!this._events[e])return this;if(n=this._events[e],a=n.length,i=-1,n===t||r(n.listener)&&n.listener===t)delete this._events[e],this._events.removeListener&&this.emit("removeListener",e,t);else if(o(n)){for(s=a;s-- >0;)if(n[s]===t||n[s].listener&&n[s].listener===t){i=s;break}if(i<0)return this;1===n.length?(n.length=0,delete this._events[e]):n.splice(i,1),this._events.removeListener&&this.emit("removeListener",e,t)}return this},n.prototype.removeAllListeners=function(e){var t,n;if(!this._events)return this;if(!this._events.removeListener)return 0===arguments.length?this._events={}:this._events[e]&&delete this._events[e],this;if(0===arguments.length){for(t in this._events)"removeListener"!==t&&this.removeAllListeners(t);return this.removeAllListeners("removeListener"),this._events={},this}if(n=this._events[e],r(n))this.removeListener(e,n);else if(n)for(;n.length;)this.removeListener(e,n[n.length-1]);return delete this._events[e],this},n.prototype.listeners=function(e){return this._events&&this._events[e]?r(this._events[e])?[this._events[e]]:this._events[e].slice():[]},n.prototype.listenerCount=function(e){if(this._events){var t=this._events[e];if(r(t))return 1;if(t)return t.length}return 0},n.listenerCount=function(e,t){return e.listenerCount(t)}},function(e,t,n){"use strict";var r={};e.exports=r},function(e,t,n){"use strict";var r=n(82);e.exports=r.DEFAULT=new r({include:[n(118)],explicit:[n(804),n(803),n(802)]})},function(e,t,n){function r(e){var t=-1,n=null==e?0:e.length;for(this.clear();++t-1&&e%1==0&&e]/;e.exports=i},function(e,t,n){"use strict";var r,i=n(25),o=n(242),a=/^[ \r\n\t\f]/,s=/<(!--|link|noscript|meta|script|style)[ \r\n\t\f\/>]/,u=n(250),l=u(function(e,t){if(e.namespaceURI!==o.svg||"innerHTML"in e)e.innerHTML=t;else{r=r||document.createElement("div"),r.innerHTML=""+t+"";for(var n=r.firstChild;n.firstChild;)e.appendChild(n.firstChild)}});if(i.canUseDOM){var c=document.createElement("div");c.innerHTML=" ",""===c.innerHTML&&(l=function(e,t){if(e.parentNode&&e.parentNode.replaceChild(e,e),a.test(t)||"<"===t[0]&&s.test(t)){e.innerHTML=String.fromCharCode(65279)+t;var n=e.firstChild;1===n.data.length?e.removeChild(n):n.deleteData(0,1)}else e.innerHTML=t}),c=null}e.exports=l},function(e,t,n){"use strict";function r(e){var t={};for(var n in e)Object.prototype.hasOwnProperty.call(e,n)&&(t[n]="number"==typeof e[n]?e[n]:e[n].val);return t}t.__esModule=!0,t.default=r,e.exports=t.default},function(e,t,n){"use strict";e.exports=function(e,t){var n,r,i,o=-1,a=e.posMax,s=e.pos,u=e.isInLabel;if(e.isInLabel)return-1;if(e.labelUnmatchedScopes)return e.labelUnmatchedScopes--,-1;for(e.pos=t+1,e.isInLabel=!0,n=1;e.pos1&&void 0!==arguments[1])||arguments[1];return e=(0,s.normalizeArray)(e),{type:p,payload:{thing:e,shown:t}}}function a(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"";return e=(0,s.normalizeArray)(e),{type:c,payload:{thing:e,mode:t}}}Object.defineProperty(t,"__esModule",{value:!0}),t.SHOW=t.UPDATE_MODE=t.UPDATE_FILTER=t.UPDATE_LAYOUT=void 0,t.updateLayout=r,t.updateFilter=i,t.show=o,t.changeMode=a;var s=n(11),u=t.UPDATE_LAYOUT="layout_update_layout",l=t.UPDATE_FILTER="layout_update_filter",c=t.UPDATE_MODE="layout_update_mode",p=t.SHOW="layout_show"},function(e,t,n){"use strict";function r(e,t){return{type:u,payload:{selectedServerUrl:e,namespace:t}}}function i(e){var t=e.value,n=e.pathMethod;return{type:l,payload:{value:t,pathMethod:n}}}function o(e){var t=e.value,n=e.pathMethod;return{type:c,payload:{value:t,pathMethod:n}}}function a(e){var t=e.value,n=e.path,r=e.method;return{type:p,payload:{value:t,path:n,method:r}}}function s(e){var t=e.server,n=e.namespace,r=e.key,i=e.val;return{type:f,payload:{server:t,namespace:n,key:r,val:i}}}Object.defineProperty(t,"__esModule",{value:!0}),t.setSelectedServer=r,t.setRequestBodyValue=i,t.setRequestContentType=o,t.setResponseContentType=a,t.setServerVariableValue=s;var u=t.UPDATE_SELECTED_SERVER="oas3_set_servers",l=t.UPDATE_REQUEST_BODY_VALUE="oas3_set_request_body_value",c=t.UPDATE_REQUEST_CONTENT_TYPE="oas3_set_request_content_type",p=t.UPDATE_RESPONSE_CONTENT_TYPE="oas3_set_response_content_type",f=t.UPDATE_SERVER_VARIABLE_VALUE="oas3_set_server_variable_value"},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function i(e,t){var n=h(e,t);if(n)return(0,s.default)(n,{declaration:!0,indent:"\t"})}Object.defineProperty(t,"__esModule",{value:!0}),t.memoizedSampleFromSchema=t.memoizedCreateXMLExample=t.sampleXmlFromSchema=t.inferSchema=t.sampleFromSchema=void 0,t.createXMLExample=i;var o=n(11),a=n(1197),s=r(a),u=n(967),l=r(u),c={string:function(){return"string"},string_email:function(){return"user@example.com"},"string_date-time":function(){return(new Date).toISOString()},number:function(){return 0},number_float:function(){return 0},integer:function(){return 0},boolean:function(e){return"boolean"!=typeof e.default||e.default}},p=function(e){e=(0,o.objectify)(e);var t=e,n=t.type,r=t.format,i=c[n+"_"+r]||c[n];return(0,o.isFunc)(i)?i(e):"Unknown Type: "+e.type},f=t.sampleFromSchema=function e(t){var n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},r=(0,o.objectify)(t),i=r.type,a=r.example,s=r.properties,u=r.additionalProperties,l=r.items,c=n.includeReadOnly,f=n.includeWriteOnly;if(void 0!==a)return a;if(!i)if(s)i="object";else{if(!l)return;i="array"}if("object"===i){var h=(0,o.objectify)(s),d={};for(var m in h)h[m].readOnly&&!c||h[m].writeOnly&&!f||(d[m]=e(h[m],n));if(!0===u)d.additionalProp1={};else if(u)for(var v=(0,o.objectify)(u),g=e(v,n),y=1;y<4;y++)d["additionalProp"+y]=g;return d}return"array"===i?[e(l,n)]:t.enum?t.default?t.default:(0,o.normalizeArray)(t.enum)[0]:"file"!==i?p(t):void 0},h=(t.inferSchema=function(e){return e.schema&&(e=e.schema),e.properties&&(e.type="object"),e},t.sampleXmlFromSchema=function e(t){var n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},r=(0,o.objectify)(t),i=r.type,a=r.properties,s=r.additionalProperties,u=r.items,l=r.example,c=n.includeReadOnly,f=n.includeWriteOnly,h=r.default,d={},m={},v=t.xml,g=v.name,y=v.prefix,_=v.namespace,b=r.enum,x=void 0,w=void 0;if(!i)if(a||s)i="object";else{if(!u)return;i="array"}if(g=g||"notagname",x=(y?y+":":"")+g,_){m[y?"xmlns:"+y:"xmlns"]=_}if("array"===i&&u){if(u.xml=u.xml||v||{},u.xml.name=u.xml.name||v.name,v.wrapped)return d[x]=[],Array.isArray(l)?l.forEach(function(t){u.example=t,d[x].push(e(u,n))}):Array.isArray(h)?h.forEach(function(t){u.default=t,d[x].push(e(u,n))}):d[x]=[e(u,n)],m&&d[x].push({_attr:m}),d;var k=[];return Array.isArray(l)?(l.forEach(function(t){u.example=t,k.push(e(u,n))}),k):Array.isArray(h)?(h.forEach(function(t){u.default=t,k.push(e(u,n))}),k):e(u,n)}if("object"===i){var E=(0,o.objectify)(a);d[x]=[],l=l||{};for(var S in E)if((!E[S].readOnly||c)&&(!E[S].writeOnly||f))if(E[S].xml=E[S].xml||{},E[S].xml.attribute){var C=Array.isArray(E[S].enum)&&E[S].enum[0],A=E[S].example,D=E[S].default;m[E[S].xml.name||S]=void 0!==A&&A||void 0!==l[S]&&l[S]||void 0!==D&&D||C||p(E[S])}else{E[S].xml.name=E[S].xml.name||S,E[S].example=void 0!==E[S].example?E[S].example:l[S];var O=e(E[S]);Array.isArray(O)?d[x]=d[x].concat(O):d[x].push(O)}return!0===s?d[x].push({additionalProp:"Anything can be here"}):s&&d[x].push({additionalProp:p(s)}),m&&d[x].push({_attr:m}),d}return w=void 0!==l?l:void 0!==h?h:Array.isArray(b)?b[0]:p(t),d[x]=m?[{_attr:m},w]:w,d});t.memoizedCreateXMLExample=(0,l.default)(i),t.memoizedSampleFromSchema=(0,l.default)(f)},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function i(e){var t=X(e).replace(/\t/g," ");if("string"==typeof e)return{type:R,payload:t}}function o(e){return{type:J,payload:e}}function a(e){return{type:F,payload:e}}function s(e){return{type:j,payload:e}}function u(e,t,n,r,i){return{type:N,payload:{path:e,value:r,paramName:t,paramIn:n,isXml:i}}}function l(e){return{type:H,payload:{pathMethod:e}}}function c(e,t){return{type:G,payload:{path:e,value:t,key:"consumes_value"}}}function p(e,t){return{type:G,payload:{path:e,value:t,key:"produces_value"}}}function f(e,t){return{type:W,payload:{path:e,method:t}}}function h(e,t){return{type:V,payload:{path:e,method:t}}}function d(e,t,n){return{type:K,payload:{scheme:e,path:t,method:n}}}Object.defineProperty(t,"__esModule",{value:!0}),t.execute=t.executeRequest=t.logRequest=t.setMutatedRequest=t.setRequest=t.setResponse=t.validateParams=t.resolveSpec=t.parseToJson=t.SET_SCHEME=t.UPDATE_RESOLVED=t.UPDATE_OPERATION_VALUE=t.CLEAR_VALIDATE_PARAMS=t.CLEAR_REQUEST=t.CLEAR_RESPONSE=t.LOG_REQUEST=t.SET_MUTATED_REQUEST=t.SET_REQUEST=t.SET_RESPONSE=t.VALIDATE_PARAMS=t.UPDATE_PARAM=t.UPDATE_JSON=t.UPDATE_URL=t.UPDATE_SPEC=void 0;var m=n(20),v=r(m),g=n(97),y=r(g),_=n(36),b=r(_),x=n(47),w=r(x),k=n(48),E=r(k);t.updateSpec=i,t.updateResolved=o,t.updateUrl=a,t.updateJsonSpec=s,t.changeParam=u,t.clearValidateParams=l,t.changeConsumesValue=c,t.changeProducesValue=p,t.clearResponse=f,t.clearRequest=h,t.setScheme=d;var S=n(212),C=r(S),A=n(1185),D=r(A),O=n(265),M=r(O),T=n(422),P=r(T),I=n(11),R=t.UPDATE_SPEC="spec_update_spec",F=t.UPDATE_URL="spec_update_url",j=t.UPDATE_JSON="spec_update_json",N=t.UPDATE_PARAM="spec_update_param",B=t.VALIDATE_PARAMS="spec_validate_param",L=t.SET_RESPONSE="spec_set_response",q=t.SET_REQUEST="spec_set_request",z=t.SET_MUTATED_REQUEST="spec_set_mutated_request",U=t.LOG_REQUEST="spec_log_request",W=t.CLEAR_RESPONSE="spec_clear_response",V=t.CLEAR_REQUEST="spec_clear_request",H=t.CLEAR_VALIDATE_PARAMS="spec_clear_validate_param",G=t.UPDATE_OPERATION_VALUE="spec_update_operation_value",J=t.UPDATE_RESOLVED="spec_update_resolved",K=t.SET_SCHEME="set_scheme",X=function(e){return(0,P.default)(e)?e:""},Y=(t.parseToJson=function(e){return function(t){var n=t.specActions,r=t.specSelectors,i=t.errActions,o=r.specStr,a=null;try{e=e||o(),i.clear({source:"parser"}),a=C.default.safeLoad(e)}catch(e){return console.error(e),i.newSpecErr({source:"parser",level:"error",message:e.reason,line:e.mark&&e.mark.line?e.mark.line+1:void 0})}return a&&"object"===(void 0===a?"undefined":(0,E.default)(a))?n.updateJsonSpec(a):{}}},t.resolveSpec=function(e,t){return function(n){var r=n.specActions,i=n.specSelectors,o=n.errActions,a=n.fn,s=a.fetch,u=a.resolve,l=a.AST,c=n.getConfigs,p=c(),f=p.modelPropertyMacro,h=p.parameterMacro,d=p.requestInterceptor,m=p.responseInterceptor;void 0===e&&(e=i.specJson()),void 0===t&&(t=i.url());var v=l.getLineNumberForPath,g=i.specStr();return u({fetch:s,spec:e,baseDoc:t,modelPropertyMacro:f,parameterMacro:h,requestInterceptor:d,responseInterceptor:m}).then(function(e){var t=e.spec,n=e.errors;if(o.clear({type:"thrown"}),Array.isArray(n)&&n.length>0){var i=n.map(function(e){return console.error(e),e.line=e.fullPath?v(g,e.fullPath):null,e.path=e.fullPath?e.fullPath.join("."):null,e.level="error",e.type="thrown",e.source="resolver",Object.defineProperty(e,"message",{enumerable:!0,value:e.message}),e});o.newThrownErrBatch(i)}return r.updateResolved(t)})}},t.validateParams=function(e,t){return{type:B,payload:{pathMethod:e,isOAS3:t}}},t.setResponse=function(e,t,n){return{payload:{path:e,method:t,res:n},type:L}},t.setRequest=function(e,t,n){return{payload:{path:e,method:t,req:n},type:q}},t.setMutatedRequest=function(e,t,n){return{payload:{path:e,method:t,req:n},type:z}},t.logRequest=function(e){return{payload:e,type:U}},t.executeRequest=function(e){return function(t){var n=t.fn,r=t.specActions,i=t.specSelectors,o=t.getConfigs,a=t.oas3Selectors,s=e.pathName,u=e.method,l=e.operation,c=o(),p=c.requestInterceptor,f=c.responseInterceptor,h=l.toJS();if(e.contextUrl=(0,D.default)(i.url()).toString(),h&&h.operationId?e.operationId=h.operationId:h&&s&&u&&(e.operationId=n.opId(h,s,u)),i.isOAS3()){var d=s+":"+u;e.server=a.selectedServer(d)||a.selectedServer();var m=a.serverVariables({server:e.server,namespace:d}).toJS(),v=a.serverVariables({server:e.server}).toJS();e.serverVariables=(0,w.default)(m).length?m:v,e.requestContentType=a.requestContentType(s,u),e.responseContentType=a.responseContentType(s,u)||"*/*";var g=a.requestBodyValue(s,u);(0,I.isJSONObject)(g)?e.requestBody=JSON.parse(g):e.requestBody=g}var y=(0,b.default)({},e);y=n.buildRequest(y),r.setRequest(e.pathName,e.method,y);var _=function(t){var n=p.apply(this,[t]),i=(0,b.default)({},n);return r.setMutatedRequest(e.pathName,e.method,i),n};e.requestInterceptor=_,e.responseInterceptor=f;var x=Date.now();return n.execute(e).then(function(t){t.duration=Date.now()-x,r.setResponse(e.pathName,e.method,t)}).catch(function(t){return r.setResponse(e.pathName,e.method,{error:!0,err:(0,M.default)(t)})})}},function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},t=e.path,n=e.method,r=(0,y.default)(e,["path","method"]);return function(e){var i=e.fn.fetch,o=e.specSelectors,a=e.specActions,s=o.spec().toJS(),u=o.operationScheme(t,n),l=o.contentTypeValues([t,n]).toJS(),c=l.requestContentType,p=l.responseContentType,f=/xml/i.test(c),h=o.parameterValues([t,n],f).toJS();return a.executeRequest((0,v.default)({fetch:i,spec:s,pathName:t,method:n,parameters:h,requestContentType:c,scheme:u,responseContentType:p},r))}});t.execute=Y},function(e,t,n){e.exports={default:n(594),__esModule:!0}},function(e,t,n){"use strict";function r(e){switch(e._type){case"document":case"block_quote":case"list":case"item":case"paragraph":case"heading":case"emph":case"strong":case"link":case"image":case"custom_inline":case"custom_block":return!0;default:return!1}}var i=function(e,t){this.current=e,this.entering=!0===t},o=function(){var e=this.current,t=this.entering;if(null===e)return null;var n=r(e);return t&&n?e._firstChild?(this.current=e._firstChild,this.entering=!0):this.entering=!1:e===this.root?this.current=null:null===e._next?(this.current=e._parent,this.entering=!1):(this.current=e._next,this.entering=!0),{entering:t,node:e}},a=function(e){return{current:e,root:e,entering:!0,next:o,resumeAt:i}},s=function(e,t){this._type=e,this._parent=null,this._firstChild=null,this._lastChild=null,this._prev=null,this._next=null,this._sourcepos=t,this._lastLineBlank=!1,this._open=!0,this._string_content=null,this._literal=null,this._listData={},this._info=null,this._destination=null,this._title=null,this._isFenced=!1,this._fenceChar=null,this._fenceLength=0,this._fenceOffset=null,this._level=null,this._onEnter=null,this._onExit=null},u=s.prototype;Object.defineProperty(u,"isContainer",{get:function(){return r(this)}}),Object.defineProperty(u,"type",{get:function(){return this._type}}),Object.defineProperty(u,"firstChild",{get:function(){return this._firstChild}}),Object.defineProperty(u,"lastChild",{get:function(){return this._lastChild}}),Object.defineProperty(u,"next",{get:function(){return this._next}}),Object.defineProperty(u,"prev",{get:function(){return this._prev}}),Object.defineProperty(u,"parent",{get:function(){return this._parent}}),Object.defineProperty(u,"sourcepos",{get:function(){return this._sourcepos}}),Object.defineProperty(u,"literal",{get:function(){return this._literal},set:function(e){this._literal=e}}),Object.defineProperty(u,"destination",{get:function(){return this._destination},set:function(e){this._destination=e}}),Object.defineProperty(u,"title",{get:function(){return this._title},set:function(e){this._title=e}}),Object.defineProperty(u,"info",{get:function(){return this._info},set:function(e){this._info=e}}),Object.defineProperty(u,"level",{get:function(){return this._level},set:function(e){this._level=e}}),Object.defineProperty(u,"listType",{get:function(){return this._listData.type},set:function(e){this._listData.type=e}}),Object.defineProperty(u,"listTight",{get:function(){return this._listData.tight},set:function(e){this._listData.tight=e}}),Object.defineProperty(u,"listStart",{get:function(){return this._listData.start},set:function(e){this._listData.start=e}}),Object.defineProperty(u,"listDelimiter",{get:function(){return this._listData.delimiter},set:function(e){this._listData.delimiter=e}}),Object.defineProperty(u,"onEnter",{get:function(){return this._onEnter},set:function(e){this._onEnter=e}}),Object.defineProperty(u,"onExit",{get:function(){return this._onExit},set:function(e){this._onExit=e}}),s.prototype.appendChild=function(e){e.unlink(),e._parent=this,this._lastChild?(this._lastChild._next=e,e._prev=this._lastChild,this._lastChild=e):(this._firstChild=e,this._lastChild=e)},s.prototype.prependChild=function(e){e.unlink(),e._parent=this,this._firstChild?(this._firstChild._prev=e,e._next=this._firstChild,this._firstChild=e):(this._firstChild=e,this._lastChild=e)},s.prototype.unlink=function(){this._prev?this._prev._next=this._next:this._parent&&(this._parent._firstChild=this._next),this._next?this._next._prev=this._prev:this._parent&&(this._parent._lastChild=this._prev),this._parent=null,this._next=null,this._prev=null},s.prototype.insertAfter=function(e){e.unlink(),e._next=this._next,e._next&&(e._next._prev=e),e._prev=this,this._next=e,e._parent=this._parent,e._next||(e._parent._lastChild=e)},s.prototype.insertBefore=function(e){e.unlink(),e._prev=this._prev,e._prev&&(e._prev._next=e),e._next=this,this._prev=e,e._parent=this._parent,e._prev||(e._parent._firstChild=e)},s.prototype.walker=function(){return new a(this)},e.exports=s},function(e,t){e.exports=function(e,t,n,r){if(!(e instanceof t)||void 0!==r&&r in e)throw TypeError(n+": incorrect invocation!");return e}},function(e,t,n){var r=n(54),i=n(182),o=n(77),a=n(133),s=n(601);e.exports=function(e,t){var n=1==e,u=2==e,l=3==e,c=4==e,p=6==e,f=5==e||p,h=t||s;return function(t,s,d){for(var m,v,g=o(t),y=i(g),_=r(s,d,3),b=a(y.length),x=0,w=n?h(t,b):u?h(t,0):void 0;b>x;x++)if((f||x in y)&&(m=y[x],v=_(m,x,g),e))if(n)w[x]=v;else if(v)switch(e){case 3:return!0;case 5:return m;case 6:return x;case 2:w.push(m)}else if(c)return!1;return p?-1:l||c?c:w}}},function(e,t,n){var r=n(99),i=n(21)("toStringTag"),o="Arguments"==r(function(){return arguments}()),a=function(e,t){try{return e[t]}catch(e){}};e.exports=function(e){var t,n,s;return void 0===e?"Undefined":null===e?"Null":"string"==typeof(n=a(t=Object(e),i))?n:o?r(t):"Object"==(s=r(t))&&"function"==typeof t.callee?"Arguments":s}},function(e,t){e.exports=function(e){if(void 0==e)throw TypeError("Can't call method on "+e);return e}},function(e,t,n){var r=n(28),i=n(24).document,o=r(i)&&r(i.createElement);e.exports=function(e){return o?i.createElement(e):{}}},function(e,t){e.exports="constructor,hasOwnProperty,isPrototypeOf,propertyIsEnumerable,toLocaleString,toString,valueOf".split(",")},function(e,t,n){var r=n(99);e.exports=Object("z").propertyIsEnumerable(0)?Object:function(e){return"String"==r(e)?e.split(""):Object(e)}},function(e,t,n){"use strict";function r(e){var t,n;this.promise=new e(function(e,r){if(void 0!==t||void 0!==n)throw TypeError("Bad Promise constructor");t=e,n=r}),this.resolve=i(t),this.reject=i(n)}var i=n(98);e.exports.f=function(e){return new r(e)}},function(e,t,n){var r=n(38),i=n(610),o=n(181),a=n(188)("IE_PROTO"),s=function(){},u=function(){var e,t=n(180)("iframe"),r=o.length;for(t.style.display="none",n(334).appendChild(t),t.src="javascript:",e=t.contentWindow.document,e.open(),e.write("