aboutsummaryrefslogtreecommitdiffstats
path: root/onap-client/onap_client
diff options
context:
space:
mode:
authorstark, steven <steven.stark@att.com>2020-03-11 14:30:58 -0700
committerstark, steven <steven.stark@att.com>2020-03-12 14:41:09 -0700
commitc02d3ed39e53d4ce56406a43089fc4a336c43f17 (patch)
tree8354fe71b2b4d379f36042b76c0e29775692f03e /onap-client/onap_client
parentd7d8722ce27e308defb6764d8d76f85ce7d63927 (diff)
[VVP] Adding onap-client intial commit.
This is supplementary tooling to interact with various ONAP applications. It will be used by the OVP VNF Testcase, it's not deployed with the ONAP platform. Issue-ID: VVP-381 Change-Id: I2ff3952ba8f4b9448acb5a24717ccc3b1f0a92fe Signed-off-by: stark, steven <steven.stark@att.com>
Diffstat (limited to 'onap-client/onap_client')
-rw-r--r--onap-client/onap_client/__init__.py36
-rw-r--r--onap-client/onap_client/aai/__init__.py40
-rw-r--r--onap-client/onap_client/aai/catalog/__init__.py36
-rw-r--r--onap-client/onap_client/aai/catalog/business_catalog.py274
-rw-r--r--onap-client/onap_client/aai/catalog/cloud_infrastructure_catalog.py132
-rw-r--r--onap-client/onap_client/aai/client.py77
-rw-r--r--onap-client/onap_client/aai/tests/__init__.py36
-rw-r--r--onap-client/onap_client/cli.py215
-rw-r--r--onap-client/onap_client/client/__init__.py36
-rw-r--r--onap-client/onap_client/client/catalog.py156
-rw-r--r--onap-client/onap_client/client/clients.py85
-rw-r--r--onap-client/onap_client/client/request.py203
-rw-r--r--onap-client/onap_client/client/response.py115
-rw-r--r--onap-client/onap_client/config.py99
-rw-r--r--onap-client/onap_client/engine.py216
-rw-r--r--onap-client/onap_client/exceptions.py144
-rw-r--r--onap-client/onap_client/lib.py124
-rw-r--r--onap-client/onap_client/resource.py189
-rw-r--r--onap-client/onap_client/sdc/__init__.py40
-rw-r--r--onap-client/onap_client/sdc/catalog/__init__.py37
-rw-r--r--onap-client/onap_client/sdc/catalog/license_model_catalog.py318
-rw-r--r--onap-client/onap_client/sdc/catalog/service_catalog.py426
-rw-r--r--onap-client/onap_client/sdc/catalog/vnf_catalog.py410
-rw-r--r--onap-client/onap_client/sdc/catalog/vsp_catalog.py286
-rw-r--r--onap-client/onap_client/sdc/client.py81
-rw-r--r--onap-client/onap_client/sdc/license_model.py218
-rw-r--r--onap-client/onap_client/sdc/service.py426
-rw-r--r--onap-client/onap_client/sdc/tests/__init__.py0
-rw-r--r--onap-client/onap_client/sdc/tests/test.zipbin0 -> 428 bytes
-rw-r--r--onap-client/onap_client/sdc/tests/test_license_model.py125
-rw-r--r--onap-client/onap_client/sdc/tests/test_sdc_client.py68
-rw-r--r--onap-client/onap_client/sdc/tests/test_vnf.py172
-rw-r--r--onap-client/onap_client/sdc/tests/test_vsp.py118
-rw-r--r--onap-client/onap_client/sdc/vnf.py507
-rw-r--r--onap-client/onap_client/sdc/vsp.py213
-rw-r--r--onap-client/onap_client/sdnc/__init__.py40
-rw-r--r--onap-client/onap_client/sdnc/catalog/__init__.py36
-rw-r--r--onap-client/onap_client/sdnc/catalog/config_catalog.py114
-rw-r--r--onap-client/onap_client/sdnc/catalog/operations_catalog.py97
-rw-r--r--onap-client/onap_client/sdnc/client.py53
-rw-r--r--onap-client/onap_client/sdnc/preload.py191
-rw-r--r--onap-client/onap_client/sdnc/tests/__init__.py36
-rw-r--r--onap-client/onap_client/so/__init__.py40
-rw-r--r--onap-client/onap_client/so/catalog/__init__.py36
-rw-r--r--onap-client/onap_client/so/catalog/service_instantiation.py316
-rw-r--r--onap-client/onap_client/so/client.py69
-rw-r--r--onap-client/onap_client/so/module_instance.py236
-rw-r--r--onap-client/onap_client/so/service_instance.py230
-rw-r--r--onap-client/onap_client/so/tests/__init__.py36
-rw-r--r--onap-client/onap_client/so/vnf_instance.py267
-rw-r--r--onap-client/onap_client/tests/__init__.py36
-rw-r--r--onap-client/onap_client/tests/test.zipbin0 -> 221 bytes
-rw-r--r--onap-client/onap_client/tests/test_catalog.py125
-rw-r--r--onap-client/onap_client/tests/test_payload.jinja1
-rw-r--r--onap-client/onap_client/tests/test_request.py187
-rw-r--r--onap-client/onap_client/tests/test_resource.py68
-rw-r--r--onap-client/onap_client/tests/testdata.py92
-rw-r--r--onap-client/onap_client/tests/utils.py79
-rw-r--r--onap-client/onap_client/util.py134
-rw-r--r--onap-client/onap_client/vid/__init__.py40
-rw-r--r--onap-client/onap_client/vid/catalog/__init__.py36
-rw-r--r--onap-client/onap_client/vid/catalog/maintenance_catalog.py154
-rw-r--r--onap-client/onap_client/vid/client.py69
-rw-r--r--onap-client/onap_client/vid/tests/__init__.py36
64 files changed, 8512 insertions, 0 deletions
diff --git a/onap-client/onap_client/__init__.py b/onap-client/onap_client/__init__.py
new file mode 100644
index 0000000..5519a84
--- /dev/null
+++ b/onap-client/onap_client/__init__.py
@@ -0,0 +1,36 @@
+# -*- coding: utf8 -*-
+# ============LICENSE_START=======================================================
+# org.onap.vvp/validation-scripts
+# ===================================================================
+# Copyright © 2020 AT&T Intellectual Property. All rights reserved.
+# ===================================================================
+#
+# Unless otherwise specified, all software contained herein is licensed
+# under the Apache License, Version 2.0 (the "License");
+# you may not use this software 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.
+#
+#
+#
+# Unless otherwise specified, all documentation contained herein is licensed
+# under the Creative Commons License, Attribution 4.0 Intl. (the "License");
+# you may not use this documentation except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://creativecommons.org/licenses/by/4.0/
+#
+# Unless required by applicable law or agreed to in writing, documentation
+# 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============================================
diff --git a/onap-client/onap_client/aai/__init__.py b/onap-client/onap_client/aai/__init__.py
new file mode 100644
index 0000000..a67037c
--- /dev/null
+++ b/onap-client/onap_client/aai/__init__.py
@@ -0,0 +1,40 @@
+# -*- coding: utf8 -*-
+# ============LICENSE_START=======================================================
+# org.onap.vvp/validation-scripts
+# ===================================================================
+# Copyright © 2020 AT&T Intellectual Property. All rights reserved.
+# ===================================================================
+#
+# Unless otherwise specified, all software contained herein is licensed
+# under the Apache License, Version 2.0 (the "License");
+# you may not use this software 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.
+#
+#
+#
+# Unless otherwise specified, all documentation contained herein is licensed
+# under the Creative Commons License, Attribution 4.0 Intl. (the "License");
+# you may not use this documentation except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://creativecommons.org/licenses/by/4.0/
+#
+# Unless required by applicable law or agreed to in writing, documentation
+# 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============================================
+
+from onap_client.config import APP_CONFIG
+
+AAI_PROPERTIES = APP_CONFIG.aai
diff --git a/onap-client/onap_client/aai/catalog/__init__.py b/onap-client/onap_client/aai/catalog/__init__.py
new file mode 100644
index 0000000..5519a84
--- /dev/null
+++ b/onap-client/onap_client/aai/catalog/__init__.py
@@ -0,0 +1,36 @@
+# -*- coding: utf8 -*-
+# ============LICENSE_START=======================================================
+# org.onap.vvp/validation-scripts
+# ===================================================================
+# Copyright © 2020 AT&T Intellectual Property. All rights reserved.
+# ===================================================================
+#
+# Unless otherwise specified, all software contained herein is licensed
+# under the Apache License, Version 2.0 (the "License");
+# you may not use this software 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.
+#
+#
+#
+# Unless otherwise specified, all documentation contained herein is licensed
+# under the Creative Commons License, Attribution 4.0 Intl. (the "License");
+# you may not use this documentation except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://creativecommons.org/licenses/by/4.0/
+#
+# Unless required by applicable law or agreed to in writing, documentation
+# 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============================================
diff --git a/onap-client/onap_client/aai/catalog/business_catalog.py b/onap-client/onap_client/aai/catalog/business_catalog.py
new file mode 100644
index 0000000..2b9af21
--- /dev/null
+++ b/onap-client/onap_client/aai/catalog/business_catalog.py
@@ -0,0 +1,274 @@
+# -*- coding: utf8 -*-
+# ============LICENSE_START=======================================================
+# org.onap.vvp/validation-scripts
+# ===================================================================
+# Copyright © 2020 AT&T Intellectual Property. All rights reserved.
+# ===================================================================
+#
+# Unless otherwise specified, all software contained herein is licensed
+# under the Apache License, Version 2.0 (the "License");
+# you may not use this software 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.
+#
+#
+#
+# Unless otherwise specified, all documentation contained herein is licensed
+# under the Creative Commons License, Attribution 4.0 Intl. (the "License");
+# you may not use this documentation except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://creativecommons.org/licenses/by/4.0/
+#
+# Unless required by applicable law or agreed to in writing, documentation
+# 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============================================
+
+import uuid
+from functools import partial
+
+from onap_client import aai
+from onap_client import config
+from onap_client.aai.client import AAIClient
+
+PAYLOADS_DIR = config.PAYLOADS_DIR
+aai_properties = aai.AAI_PROPERTIES
+application_id = config.APPLICATION_ID
+
+
+class BusinessClient(AAIClient):
+ @property
+ def catalog_resources(self):
+ return CATALOG_RESOURCES
+
+ @property
+ def namespace(self):
+ return "business"
+
+
+CATALOG_RESOURCES = {
+ "GET_OWNING_ENTITY": {
+ "verb": "GET",
+ "description": "Queries AAI for an owning entity",
+ "uri": partial(
+ "{endpoint}{service_path}/owning-entities?owning-entity-name={name}".format,
+ endpoint=aai_properties.AAI_BE_ENDPOINT,
+ service_path=aai_properties.AAI_BUSINESS_PATH,
+ ),
+ "uri-parameters": ["name"],
+ "success_code": 200,
+ "headers": {
+ "Accept": "application/json",
+ "Content-Type": "application/json",
+ "X-TransactionId": str(uuid.uuid4()),
+ "X-FromAppId": application_id,
+ },
+ "auth": (aai_properties.AAI_USERNAME, aai_properties.AAI_PASSWORD,),
+ },
+ "GET_OWNING_ENTITIES": {
+ "verb": "GET",
+ "description": "Queries AAI for all owning entities",
+ "uri": partial(
+ "{endpoint}{service_path}/owning-entities".format,
+ endpoint=aai_properties.AAI_BE_ENDPOINT,
+ service_path=aai_properties.AAI_BUSINESS_PATH,
+ ),
+ "success_code": 200,
+ "headers": {
+ "Accept": "application/json",
+ "Content-Type": "application/json",
+ "X-TransactionId": str(uuid.uuid4()),
+ "X-FromAppId": application_id,
+ },
+ "auth": (aai_properties.AAI_USERNAME, aai_properties.AAI_PASSWORD,),
+ },
+ "GET_CUSTOMER": {
+ "verb": "GET",
+ "description": "Queries AAI for a customer",
+ "uri": partial(
+ "{endpoint}{service_path}/customers?global-customer-id={name}".format,
+ endpoint=aai_properties.AAI_BE_ENDPOINT,
+ service_path=aai_properties.AAI_BUSINESS_PATH,
+ ),
+ "uri-parameters": ["name"],
+ "success_code": 200,
+ "headers": {
+ "Accept": "application/json",
+ "Content-Type": "application/json",
+ "X-TransactionId": str(uuid.uuid4()),
+ "X-FromAppId": application_id,
+ },
+ "auth": (aai_properties.AAI_USERNAME, aai_properties.AAI_PASSWORD,),
+ },
+ "GET_CUSTOMERS": {
+ "verb": "GET",
+ "description": "Queries AAI for all customers",
+ "uri": partial(
+ "{endpoint}{service_path}/customers".format,
+ endpoint=aai_properties.AAI_BE_ENDPOINT,
+ service_path=aai_properties.AAI_BUSINESS_PATH,
+ ),
+ "success_code": 200,
+ "headers": {
+ "Accept": "application/json",
+ "Content-Type": "application/json",
+ "X-TransactionId": str(uuid.uuid4()),
+ "X-FromAppId": application_id,
+ },
+ "auth": (aai_properties.AAI_USERNAME, aai_properties.AAI_PASSWORD,),
+ },
+ "GET_PLATFORM": {
+ "verb": "GET",
+ "description": "Queries AAI for a platform",
+ "uri": partial(
+ "{endpoint}{service_path}/platforms?platform-name={name}".format,
+ endpoint=aai_properties.AAI_BE_ENDPOINT,
+ service_path=aai_properties.AAI_BUSINESS_PATH,
+ ),
+ "uri-parameters": ["name"],
+ "success_code": 200,
+ "headers": {
+ "Accept": "application/json",
+ "Content-Type": "application/json",
+ "X-TransactionId": str(uuid.uuid4()),
+ "X-FromAppId": application_id,
+ },
+ "auth": (aai_properties.AAI_USERNAME, aai_properties.AAI_PASSWORD,),
+ },
+ "GET_PLATFORMS": {
+ "verb": "GET",
+ "description": "Queries AAI for all platforms",
+ "uri": partial(
+ "{endpoint}{service_path}/platforms".format,
+ endpoint=aai_properties.AAI_BE_ENDPOINT,
+ service_path=aai_properties.AAI_BUSINESS_PATH,
+ ),
+ "success_code": 200,
+ "headers": {
+ "Accept": "application/json",
+ "Content-Type": "application/json",
+ "X-TransactionId": str(uuid.uuid4()),
+ "X-FromAppId": application_id,
+ },
+ "auth": (aai_properties.AAI_USERNAME, aai_properties.AAI_PASSWORD,),
+ },
+ "GET_PROJECT": {
+ "verb": "GET",
+ "description": "Queries AAI for a project",
+ "uri": partial(
+ "{endpoint}{service_path}/projects/project/{name}".format,
+ endpoint=aai_properties.AAI_BE_ENDPOINT,
+ service_path=aai_properties.AAI_BUSINESS_PATH,
+ ),
+ "uri-parameters": ["name"],
+ "success_code": 200,
+ "headers": {
+ "Accept": "application/json",
+ "Content-Type": "application/json",
+ "X-TransactionId": str(uuid.uuid4()),
+ "X-FromAppId": application_id,
+ },
+ "auth": (aai_properties.AAI_USERNAME, aai_properties.AAI_PASSWORD,),
+ },
+ "GET_PROJECTS": {
+ "verb": "GET",
+ "description": "Queries AAI for all projects",
+ "uri": partial(
+ "{endpoint}{service_path}/projects".format,
+ endpoint=aai_properties.AAI_BE_ENDPOINT,
+ service_path=aai_properties.AAI_BUSINESS_PATH,
+ ),
+ "success_code": 200,
+ "headers": {
+ "Accept": "application/json",
+ "Content-Type": "application/json",
+ "X-TransactionId": str(uuid.uuid4()),
+ "X-FromAppId": application_id,
+ },
+ "auth": (aai_properties.AAI_USERNAME, aai_properties.AAI_PASSWORD,),
+ },
+ "GET_LINES_OF_BUSINESS": {
+ "verb": "GET",
+ "description": "Queries AAI for all lobs",
+ "uri": partial(
+ "{endpoint}{service_path}/lines-of-business".format,
+ endpoint=aai_properties.AAI_BE_ENDPOINT,
+ service_path=aai_properties.AAI_BUSINESS_PATH,
+ ),
+ "success_code": 200,
+ "headers": {
+ "Accept": "application/json",
+ "Content-Type": "application/json",
+ "X-TransactionId": str(uuid.uuid4()),
+ "X-FromAppId": application_id,
+ },
+ "auth": (aai_properties.AAI_USERNAME, aai_properties.AAI_PASSWORD,),
+ },
+ "CREATE_CUSTOMER": {
+ "verb": "PUT",
+ "description": "Creates a customer in AAI",
+ "uri": partial(
+ "{endpoint}{service_path}/customers/customer/{customer_name}".format,
+ endpoint=aai_properties.AAI_BE_ENDPOINT,
+ service_path=aai_properties.AAI_BUSINESS_PATH,
+ ),
+ "uri-parameters": ["customer_name"],
+ "payload-parameters": ["customer_name", "subscriber_name"],
+ "payload": "{}/aai_create_customer.jinja".format(PAYLOADS_DIR),
+ "success_code": 201,
+ "headers": {
+ "Accept": "application/json",
+ "Content-Type": "application/json",
+ "X-TransactionId": str(uuid.uuid4()),
+ "X-FromAppId": application_id,
+ },
+ "auth": (aai_properties.AAI_USERNAME, aai_properties.AAI_PASSWORD,),
+ },
+ "GET_CUSTOMER_SUBSCRIPTIONS": {
+ "verb": "GET",
+ "description": "Queries AAI the subscriptions for a customer",
+ "uri": partial(
+ "{endpoint}{service_path}/customers/customer/{customer_name}/service-subscriptions".format,
+ endpoint=aai_properties.AAI_BE_ENDPOINT,
+ service_path=aai_properties.AAI_BUSINESS_PATH,
+ ),
+ "uri-parameters": ["customer_name"],
+ "success_code": 200,
+ "headers": {
+ "Accept": "application/json",
+ "Content-Type": "application/json",
+ "X-TransactionId": str(uuid.uuid4()),
+ "X-FromAppId": application_id,
+ },
+ "auth": (aai_properties.AAI_USERNAME, aai_properties.AAI_PASSWORD,),
+ },
+ "GET_SERVICE_INSTANCES": {
+ "verb": "GET",
+ "description": "Queries AAI the service instances for a customer subscription",
+ "uri": partial(
+ "{endpoint}{service_path}/customers/customer/{customer_name}/service-subscriptions/service-subscription/{subscription_name}/service-instances".format,
+ endpoint=aai_properties.AAI_BE_ENDPOINT,
+ service_path=aai_properties.AAI_BUSINESS_PATH,
+ ),
+ "uri-parameters": ["customer_name", "subscription_name"],
+ "success_code": 200,
+ "headers": {
+ "Accept": "application/json",
+ "Content-Type": "application/json",
+ "X-TransactionId": str(uuid.uuid4()),
+ "X-FromAppId": application_id,
+ },
+ "auth": (aai_properties.AAI_USERNAME, aai_properties.AAI_PASSWORD,),
+ },
+}
diff --git a/onap-client/onap_client/aai/catalog/cloud_infrastructure_catalog.py b/onap-client/onap_client/aai/catalog/cloud_infrastructure_catalog.py
new file mode 100644
index 0000000..b2570a0
--- /dev/null
+++ b/onap-client/onap_client/aai/catalog/cloud_infrastructure_catalog.py
@@ -0,0 +1,132 @@
+# -*- coding: utf8 -*-
+# ============LICENSE_START=======================================================
+# org.onap.vvp/validation-scripts
+# ===================================================================
+# Copyright © 2020 AT&T Intellectual Property. All rights reserved.
+# ===================================================================
+#
+# Unless otherwise specified, all software contained herein is licensed
+# under the Apache License, Version 2.0 (the "License");
+# you may not use this software 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.
+#
+#
+#
+# Unless otherwise specified, all documentation contained herein is licensed
+# under the Creative Commons License, Attribution 4.0 Intl. (the "License");
+# you may not use this documentation except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://creativecommons.org/licenses/by/4.0/
+#
+# Unless required by applicable law or agreed to in writing, documentation
+# 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============================================
+
+import uuid
+from functools import partial
+
+from onap_client import aai
+from onap_client import config
+from onap_client.aai.client import AAIClient
+
+PAYLOADS_DIR = config.PAYLOADS_DIR
+aai_properties = aai.AAI_PROPERTIES
+application_id = config.APPLICATION_ID
+
+
+class CloudInfrastructureClient(AAIClient):
+ @property
+ def catalog_resources(self):
+ return CATALOG_RESOURCES
+
+ @property
+ def namespace(self):
+ return "cloud_infrastructure"
+
+
+CATALOG_RESOURCES = {
+ "GET_CLOUD_REGIONS": {
+ "verb": "GET",
+ "description": "Queries AAI for all cloud regions",
+ "uri": partial(
+ "{endpoint}{service_path}/cloud-regions".format,
+ endpoint=aai_properties.AAI_BE_ENDPOINT,
+ service_path=aai_properties.AAI_CLOUD_INFRASTRUCTURE_PATH,
+ ),
+ "success_code": 200,
+ "headers": {
+ "Accept": "application/json",
+ "Content-Type": "application/json",
+ "X-TransactionId": str(uuid.uuid4()),
+ "X-FromAppId": application_id,
+ },
+ "auth": (aai_properties.AAI_USERNAME, aai_properties.AAI_PASSWORD,),
+ },
+ "GET_CLOUD_REGION": {
+ "verb": "GET",
+ "description": "Queries AAI for a cloud region",
+ "uri": partial(
+ "{endpoint}{service_path}/cloud-regions/cloud-region/{cloud_owner}/{cloud_region}".format,
+ endpoint=aai_properties.AAI_BE_ENDPOINT,
+ service_path=aai_properties.AAI_CLOUD_INFRASTRUCTURE_PATH,
+ ),
+ "uri-parameters": ["cloud_region", "cloud_owner"],
+ "success_code": 200,
+ "headers": {
+ "Accept": "application/json",
+ "Content-Type": "application/json",
+ "X-TransactionId": str(uuid.uuid4()),
+ "X-FromAppId": application_id,
+ },
+ "auth": (aai_properties.AAI_USERNAME, aai_properties.AAI_PASSWORD,),
+ },
+ "GET_CLOUD_REGION_TENANTS": {
+ "verb": "GET",
+ "description": "Queries AAI for a cloud region's tenants",
+ "uri": partial(
+ "{endpoint}{service_path}/cloud-regions/cloud-region/{cloud_owner}/{cloud_region}/tenants".format,
+ endpoint=aai_properties.AAI_BE_ENDPOINT,
+ service_path=aai_properties.AAI_CLOUD_INFRASTRUCTURE_PATH,
+ ),
+ "uri-parameters": ["cloud_region", "cloud_owner"],
+ "success_code": 200,
+ "headers": {
+ "Accept": "application/json",
+ "Content-Type": "application/json",
+ "X-TransactionId": str(uuid.uuid4()),
+ "X-FromAppId": application_id,
+ },
+ "auth": (aai_properties.AAI_USERNAME, aai_properties.AAI_PASSWORD,),
+ },
+ "GET_ESR_LIST": {
+ "verb": "GET",
+ "description": "Queries AAI for a esr info",
+ "uri": partial(
+ "{endpoint}{service_path}/cloud-regions/cloud-region/{cloud_owner}/{cloud_region}/esr-system-info-list".format,
+ endpoint=aai_properties.AAI_BE_ENDPOINT,
+ service_path=aai_properties.AAI_CLOUD_INFRASTRUCTURE_PATH,
+ ),
+ "uri-parameters": ["cloud_region", "cloud_owner"],
+ "success_code": 200,
+ "headers": {
+ "Accept": "application/json",
+ "Content-Type": "application/json",
+ "X-TransactionId": str(uuid.uuid4()),
+ "X-FromAppId": application_id,
+ },
+ "auth": (aai_properties.AAI_USERNAME, aai_properties.AAI_PASSWORD,),
+ },
+}
diff --git a/onap-client/onap_client/aai/client.py b/onap-client/onap_client/aai/client.py
new file mode 100644
index 0000000..5a2ddb1
--- /dev/null
+++ b/onap-client/onap_client/aai/client.py
@@ -0,0 +1,77 @@
+# -*- coding: utf8 -*-
+# ============LICENSE_START=======================================================
+# org.onap.vvp/validation-scripts
+# ===================================================================
+# Copyright © 2020 AT&T Intellectual Property. All rights reserved.
+# ===================================================================
+#
+# Unless otherwise specified, all software contained herein is licensed
+# under the Apache License, Version 2.0 (the "License");
+# you may not use this software 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.
+#
+#
+#
+# Unless otherwise specified, all documentation contained herein is licensed
+# under the Creative Commons License, Attribution 4.0 Intl. (the "License");
+# you may not use this documentation except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://creativecommons.org/licenses/by/4.0/
+#
+# Unless required by applicable law or agreed to in writing, documentation
+# 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============================================
+
+import uuid
+
+from functools import partial
+from onap_client import aai
+from onap_client.client.clients import Client
+from onap_client import config
+
+aai_properties = aai.AAI_PROPERTIES
+application_id = config.APPLICATION_ID
+
+
+class AAIClient(Client):
+ @property
+ def namespace(self):
+ return "aai"
+
+ @property
+ def catalog_resources(self):
+ return CATALOG_RESOURCES
+
+
+CATALOG_RESOURCES = {
+ "HEALTH_CHECK": {
+ "verb": "GET",
+ "description": "Queries AAI health check endpoint",
+ "uri": partial(
+ "{endpoint}{service_path}".format,
+ endpoint=aai_properties.AAI_BE_ENDPOINT,
+ service_path=aai_properties.AAI_HEALTH_CHECK_PATH,
+ ),
+ "success_code": 200,
+ "headers": {
+ "Accept": "application/json",
+ "Content-Type": "application/json",
+ "X-TransactionId": str(uuid.uuid4()),
+ "X-FromAppId": application_id,
+ },
+ "auth": (aai_properties.AAI_USERNAME, aai_properties.AAI_PASSWORD,),
+ },
+}
diff --git a/onap-client/onap_client/aai/tests/__init__.py b/onap-client/onap_client/aai/tests/__init__.py
new file mode 100644
index 0000000..5519a84
--- /dev/null
+++ b/onap-client/onap_client/aai/tests/__init__.py
@@ -0,0 +1,36 @@
+# -*- coding: utf8 -*-
+# ============LICENSE_START=======================================================
+# org.onap.vvp/validation-scripts
+# ===================================================================
+# Copyright © 2020 AT&T Intellectual Property. All rights reserved.
+# ===================================================================
+#
+# Unless otherwise specified, all software contained herein is licensed
+# under the Apache License, Version 2.0 (the "License");
+# you may not use this software 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.
+#
+#
+#
+# Unless otherwise specified, all documentation contained herein is licensed
+# under the Creative Commons License, Attribution 4.0 Intl. (the "License");
+# you may not use this documentation except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://creativecommons.org/licenses/by/4.0/
+#
+# Unless required by applicable law or agreed to in writing, documentation
+# 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============================================
diff --git a/onap-client/onap_client/cli.py b/onap-client/onap_client/cli.py
new file mode 100644
index 0000000..24f8b9b
--- /dev/null
+++ b/onap-client/onap_client/cli.py
@@ -0,0 +1,215 @@
+# -*- coding: utf8 -*-
+# ============LICENSE_START=======================================================
+# org.onap.vvp/validation-scripts
+# ===================================================================
+# Copyright © 2020 AT&T Intellectual Property. All rights reserved.
+# ===================================================================
+#
+# Unless otherwise specified, all software contained herein is licensed
+# under the Apache License, Version 2.0 (the "License");
+# you may not use this software 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.
+#
+#
+#
+# Unless otherwise specified, all documentation contained herein is licensed
+# under the Creative Commons License, Attribution 4.0 Intl. (the "License");
+# you may not use this documentation except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://creativecommons.org/licenses/by/4.0/
+#
+# Unless required by applicable law or agreed to in writing, documentation
+# 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============================================
+
+import json
+
+from prettytable import PrettyTable
+from onap_client.client.clients import Client
+from onap_client.client.catalog import Catalog
+from onap_client.engine import spec_cli
+from onap_client.util import utility_cli
+
+
+def main(*args):
+ cli_arguments = list(args)
+ request_arguments = {}
+ search_key = None
+ keys = None
+
+ oc = Client()
+
+ if len(args) > 0 and args[0] == "spec-engine":
+ # use engine cli instead
+ spec_cli(cli_arguments[1:])
+ elif len(args) > 0 and args[0] == "utility":
+ # use engine cli instead
+ utility_cli(oc, cli_arguments[1:])
+ elif len(args) == 0 or args[0] == "--help":
+ print(help(oc, extra_clients=["spec-engine", "utility"]))
+ else:
+ while cli_arguments:
+ arg = cli_arguments.pop(0)
+ if arg == "--help":
+ print(help(oc))
+ return
+ elif arg == "--search":
+ search_key = cli_arguments.pop(0)
+ continue
+ elif arg == "--keys":
+ keys = True
+ continue
+
+ if is_argument(arg):
+ arg = convert_to_underscores(arg)
+ arg = sanitize_argument(arg)
+ try:
+ value = get_value(cli_arguments.pop(0))
+ if is_argument(value):
+ print(
+ "No Value passed for argument: {}. Try --help".format(arg)
+ )
+ return
+ except IndexError:
+ print("No Value passed for argument: {}. Try --help".format(arg))
+ return
+ request_arguments[arg] = value
+ else:
+ arg = convert_to_underscores(arg)
+ oc = getattr(oc, arg, None)
+ if not oc:
+ print("Invalid Argument: {}. Try --help".format(arg))
+ return
+
+ if isinstance(oc, Catalog.CallHandle):
+ data = oc(**request_arguments)
+
+ output_data = data.response_data
+
+ if isinstance(output_data, dict):
+ if keys:
+ print("\n".join(x for x in output_data.keys()))
+ elif search_key:
+ print(output_data.get(search_key))
+ else:
+ print(json.dumps(output_data, indent=4))
+ else:
+ print(output_data)
+ else:
+ print("Command Invalid: {}. Try --help".format(args))
+
+
+def is_argument(argument):
+ return argument.startswith("--")
+
+
+def sanitize_argument(argument):
+ return argument.replace("__", "")
+
+
+def convert_to_underscores(argument):
+ return argument.replace("-", "_")
+
+
+def parameterize(argument):
+ return "--{}".format(argument.replace("_", "-"))
+
+
+def get_value(value):
+ if value in ["True", "true"]:
+ return True
+ elif value in ["False", "false"]:
+ return False
+
+ return value
+
+
+def help(client, extra_clients=[]):
+ namespaces = []
+ actions = []
+
+ if isinstance(client, Catalog):
+
+ for attr, item in client.__dict__.items():
+ if isinstance(item, Catalog):
+ namespaces.append(attr)
+
+ for item_name, catalog_item in client.catalog_items.items():
+ actions.append(get_catalog_item_data(catalog_item))
+
+ elif isinstance(client, Catalog.CallHandle):
+ actions.append(get_catalog_item_data(client.resource))
+
+ data = {"clients": namespaces, "actions": actions}
+ data["clients"].extend(extra_clients)
+
+ return help_table(data)
+
+
+def help_table(data):
+ x = PrettyTable()
+
+ x.field_names = [
+ "name",
+ "description",
+ "required parameters",
+ "optional parameters",
+ ]
+ x.align["name"] = "l"
+ x.align["description"] = "l"
+ x.align["required parameters"] = "l"
+ x.align["optional parameters"] = "l"
+
+ for item in data.get("actions"):
+ name = item.get("name").lower().replace("_", "-")
+ description = item.get("description")
+ parameters = []
+ for param in item.get("parameters"):
+ if isinstance(param, str):
+ parameters.append(parameterize(param))
+ elif isinstance(param, list):
+ for param2 in param:
+ parameters.append(parameterize(param2))
+ x.add_row([name, description, "\n".join(parameters), "--keys, --search"])
+ x.add_row(["", "", "", ""])
+
+ for item in data.get("clients"):
+ name = item
+ description = "Various actions available for {}".format(name)
+ parameters = ["--help"]
+ x.add_row([name, description, "\n".join(parameters), ""])
+ x.add_row(["", "", "", ""])
+
+ return x
+
+
+def get_catalog_item_data(catalog_item):
+ item = {}
+ item["parameters"] = []
+ item["name"] = catalog_item.catalog_resource_name.lower()
+ item["parameters"].extend(x for x in catalog_item.file_parameters)
+ item["parameters"].extend(
+ x for x in catalog_item.payload_parameters if x not in item["parameters"]
+ )
+ item["parameters"].extend(
+ x for x in catalog_item.uri_parameters if x not in item["parameters"]
+ )
+ item["parameters"] += (
+ [catalog_item.payload_path] if catalog_item.payload_path else []
+ )
+ item["description"] = catalog_item.description
+
+ return item
diff --git a/onap-client/onap_client/client/__init__.py b/onap-client/onap_client/client/__init__.py
new file mode 100644
index 0000000..5519a84
--- /dev/null
+++ b/onap-client/onap_client/client/__init__.py
@@ -0,0 +1,36 @@
+# -*- coding: utf8 -*-
+# ============LICENSE_START=======================================================
+# org.onap.vvp/validation-scripts
+# ===================================================================
+# Copyright © 2020 AT&T Intellectual Property. All rights reserved.
+# ===================================================================
+#
+# Unless otherwise specified, all software contained herein is licensed
+# under the Apache License, Version 2.0 (the "License");
+# you may not use this software 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.
+#
+#
+#
+# Unless otherwise specified, all documentation contained herein is licensed
+# under the Creative Commons License, Attribution 4.0 Intl. (the "License");
+# you may not use this documentation except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://creativecommons.org/licenses/by/4.0/
+#
+# Unless required by applicable law or agreed to in writing, documentation
+# 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============================================
diff --git a/onap-client/onap_client/client/catalog.py b/onap-client/onap_client/client/catalog.py
new file mode 100644
index 0000000..419d00f
--- /dev/null
+++ b/onap-client/onap_client/client/catalog.py
@@ -0,0 +1,156 @@
+# -*- coding: utf8 -*-
+# ============LICENSE_START=======================================================
+# org.onap.vvp/validation-scripts
+# ===================================================================
+# Copyright © 2020 AT&T Intellectual Property. All rights reserved.
+# ===================================================================
+#
+# Unless otherwise specified, all software contained herein is licensed
+# under the Apache License, Version 2.0 (the "License");
+# you may not use this software 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.
+#
+#
+#
+# Unless otherwise specified, all documentation contained herein is licensed
+# under the Creative Commons License, Attribution 4.0 Intl. (the "License");
+# you may not use this documentation except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://creativecommons.org/licenses/by/4.0/
+#
+# Unless required by applicable law or agreed to in writing, documentation
+# 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============================================
+
+from abc import ABC, abstractmethod
+from onap_client.lib import make_request
+
+
+class Catalog(ABC):
+ """Abstract class for an ONAP client, automatically loads
+ child classes as attributes."""
+
+ class CallHandle:
+ """Attached as an attribute for each catalog entry in a catalog.
+ Used to make a request to ONAP."""
+
+ def __init__(self, catalog_resource):
+ self.resource = catalog_resource
+
+ def __call__(self, **kwargs):
+ return make_request(self.resource, **kwargs)
+
+ def __init__(self):
+ """Iterates through all child classes and attaches them as attributes, named
+ after the namespace property.
+
+ If the child Catalog class has items in the
+ catalog_resources property, they will be added as attributes to the child attribute
+ as a CallHandle object.
+ """
+ self.catalog_items = {}
+
+ for cls in self.__class__.__subclasses__():
+ subclass = cls()
+ namespace = subclass.namespace
+ catalog_resources = subclass.catalog_resources
+
+ for k, v in catalog_resources.items():
+ subclass.load(k, v)
+
+ setattr(self, namespace, subclass)
+
+ def load(self, item_name, resource_data):
+ """Consume a catalog resource entry as an APICatalogResource,
+ and set it as an attribute on this.class as a CallHandle object"""
+ resource = APICatalogResource(item_name, resource_data)
+
+ self.catalog_items[item_name] = resource
+ setattr(self, item_name.lower(), self.CallHandle(resource))
+
+ @property
+ @abstractmethod
+ def namespace(self):
+ raise NotImplementedError
+
+ @property
+ @abstractmethod
+ def catalog_resources(self):
+ raise NotImplementedError
+
+
+class APICatalogResource:
+ """Class representation of a single catalog entry"""
+
+ def __init__(self, catalog_resource_name, resource_data):
+ """
+ :catalog_resource_name: name of the catalog resource
+ :resource_data: dictionary containing catalog resource attributes
+ """
+ self.catalog_resource_name = catalog_resource_name
+ self.catalog_resource_data = resource_data
+
+ @property
+ def verb(self):
+ return self.catalog_resource_data.get("verb", None)
+
+ @property
+ def description(self):
+ return self.catalog_resource_data.get("description", None)
+
+ @property
+ def uri(self):
+ return self.catalog_resource_data.get("uri", None)
+
+ @property
+ def payload(self):
+ return self.catalog_resource_data.get("payload", None)
+
+ @property
+ def uri_parameters(self):
+ return self.catalog_resource_data.get("uri-parameters", [])
+
+ @property
+ def payload_parameters(self):
+ return self.catalog_resource_data.get("payload-parameters", [])
+
+ @property
+ def payload_path(self):
+ return self.catalog_resource_data.get("payload-path", [])
+
+ @property
+ def file_parameters(self):
+ return self.catalog_resource_data.get("files-parameters", [])
+
+ @property
+ def header_parameters(self):
+ return self.catalog_resource_data.get("header_parameters", [])
+
+ @property
+ def success_code(self):
+ return self.catalog_resource_data.get("success_code", None)
+
+ @property
+ def headers(self):
+ return self.catalog_resource_data.get("headers", None)
+
+ @property
+ def return_data(self):
+ return self.catalog_resource_data.get("return_data", {})
+
+ @property
+ def auth(self):
+ return self.catalog_resource_data.get("auth", None)
diff --git a/onap-client/onap_client/client/clients.py b/onap-client/onap_client/client/clients.py
new file mode 100644
index 0000000..0c4605f
--- /dev/null
+++ b/onap-client/onap_client/client/clients.py
@@ -0,0 +1,85 @@
+# -*- coding: utf8 -*-
+# ============LICENSE_START=======================================================
+# org.onap.vvp/validation-scripts
+# ===================================================================
+# Copyright © 2020 AT&T Intellectual Property. All rights reserved.
+# ===================================================================
+#
+# Unless otherwise specified, all software contained herein is licensed
+# under the Apache License, Version 2.0 (the "License");
+# you may not use this software 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.
+#
+#
+#
+# Unless otherwise specified, all documentation contained herein is licensed
+# under the Creative Commons License, Attribution 4.0 Intl. (the "License");
+# you may not use this documentation except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://creativecommons.org/licenses/by/4.0/
+#
+# Unless required by applicable law or agreed to in writing, documentation
+# 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============================================
+
+import importlib
+import onap_client
+import pkgutil
+import inspect
+
+from onap_client.client.catalog import Catalog
+
+
+class Client(Catalog):
+ """Base class for the ONAP client. Subclasses are dynamically
+ loaded and added as attributes. Instantiate and use this class
+ to interact with ONAP."""
+ def __init__(self):
+ self.modules = import_submodules(onap_client)
+ super().__init__()
+
+ @property
+ def namespace(self):
+ return "onap"
+
+ @property
+ def catalog_resources(self):
+ return {}
+
+ @property
+ def utility_functions(self):
+ utility_functions = {}
+ for module_name, module in self.modules.items():
+ all_functions = inspect.getmembers(module, inspect.isfunction)
+ for func in all_functions:
+ function = func[1]
+ if hasattr(function, "utility_function"):
+ utility_functions[func[0]] = func[1]
+ return utility_functions
+
+
+def import_submodules(package, recursive=True):
+ """Import all the modules in onap-client, except for those starting
+ with tests*. This is needed so that the Client object can register child classes"""
+ if isinstance(package, str):
+ package = importlib.import_module(package)
+ results = {}
+ for loader, name, is_pkg in pkgutil.walk_packages(package.__path__):
+ full_name = package.__name__ + "." + name
+ results[full_name] = importlib.import_module(full_name)
+ if recursive and is_pkg and full_name.find("tests") == -1:
+ results.update(import_submodules(full_name))
+ return results
diff --git a/onap-client/onap_client/client/request.py b/onap-client/onap_client/client/request.py
new file mode 100644
index 0000000..0e40591
--- /dev/null
+++ b/onap-client/onap_client/client/request.py
@@ -0,0 +1,203 @@
+# -*- coding: utf8 -*-
+# ============LICENSE_START=======================================================
+# org.onap.vvp/validation-scripts
+# ===================================================================
+# Copyright © 2020 AT&T Intellectual Property. All rights reserved.
+# ===================================================================
+#
+# Unless otherwise specified, all software contained herein is licensed
+# under the Apache License, Version 2.0 (the "License");
+# you may not use this software 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.
+#
+#
+#
+# Unless otherwise specified, all documentation contained herein is licensed
+# under the Creative Commons License, Attribution 4.0 Intl. (the "License");
+# you may not use this documentation except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://creativecommons.org/licenses/by/4.0/
+#
+# Unless required by applicable law or agreed to in writing, documentation
+# 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============================================
+
+import jinja2
+import requests
+import json
+import os
+import copy
+
+from onap_client.client.response import ResponseHandler
+from onap_client.config import LOG as logger
+from onap_client.exceptions import FilesRequestFailure
+from jinja2 import exceptions as jinja_exceptions
+
+
+class RequestHandler:
+ """Handles a APICatalogRequestObject to make a request
+ and returns a ResponseHandler object"""
+
+ def __init__(self, request_object):
+ """
+ :request_object: APICatalogRequestObject
+ """
+ self.request_object = request_object
+
+ def make_request(self):
+ r = Request(self.request_object)
+
+ logger.warning("Submitting request: {}".format(self.request_object.description))
+ # TODO
+ # Add verify to config file
+ return ResponseHandler(r.request(verify=False), self.request_object)
+
+
+class Request:
+ """Parses a APICatalogRequestObject to fill out the
+ kwargs to send to the requests library"""
+
+ def __init__(self, request_object):
+ """
+ :request_object: APICatalogRequestObject
+ """
+ self.request_object = request_object
+ self.kwargs = {}
+ self.response = None
+
+ self.build_request()
+
+ def build_request(self):
+ request_object = self.request_object
+
+ if request_object.verb:
+ self.kwargs["method"] = request_object.verb
+
+ if request_object.auth:
+ self.kwargs["auth"] = request_object.auth
+
+ if request_object.uri:
+ self.kwargs["url"] = request_object.uri
+
+ if request_object.headers:
+ self.kwargs["headers"] = request_object.headers
+
+ if request_object.payload:
+ self.kwargs["data"] = request_object.payload
+
+ if request_object.files:
+ self.kwargs["files"] = request_object.files
+
+ debug_request = copy.deepcopy(self.kwargs)
+ if "auth" in debug_request:
+ debug_request["auth"] = "***********"
+
+ try:
+ logger.info(json.dumps(debug_request, indent=4))
+ except TypeError:
+ logger.info(debug_request)
+
+ def request(self, verify=True):
+ return requests.request(**self.kwargs, verify=verify)
+
+
+class APICatalogRequestObject:
+ """Fills a APICatalogResource object with request-specific data"""
+
+ def __init__(self, api_catalog_resource, **kwargs):
+ """
+ :api_catalog_resource: APICatalogResource object
+ :kwargs: key/value to fill in APICatalogResource parameters
+ """
+ self.api_catalog_resource = api_catalog_resource
+ self.payload_parameters = kwargs.get("payload_parameters", {})
+ self.uri_parameters = kwargs.get("uri_parameters", {})
+ self.header_parameters = kwargs.get("header_parameters", {})
+ self.file_parameters = kwargs.get("file_parameters", {})
+ if api_catalog_resource.payload_path:
+ self.payload_path = kwargs.get("payload_path", {}).get(
+ api_catalog_resource.payload_path[0]
+ )
+
+ self.uri = ""
+ self.files = None
+ self.payload = None
+ self.verb = api_catalog_resource.verb
+ self.headers = api_catalog_resource.headers
+ self.success_code = api_catalog_resource.success_code
+ self.return_data = api_catalog_resource.return_data
+ self.auth = api_catalog_resource.auth
+ self.description = api_catalog_resource.description
+
+ if api_catalog_resource.payload or api_catalog_resource.payload_path:
+ self.resolve_payload()
+
+ if api_catalog_resource.file_parameters:
+ self.resolve_files()
+
+ if isinstance(self.headers, dict):
+ for k, v in self.header_parameters.items():
+ self.headers[k] = v
+
+ self.resolve_uri()
+
+ def resolve_files(self):
+ # TODO
+ # is there a better way to figure out waht params are needed?
+ # right now its hardcoded
+ file_type = self.file_parameters.get("file_type", "application/zip")
+ file_path = self.file_parameters.get("file_path")
+ if not file_path:
+ raise FilesRequestFailure("File path was not provided")
+
+ try:
+ with open(file_path, "rb") as f:
+ data = f.read()
+ except IOError:
+ logger.error("file {} was not found".format(file_path))
+ raise
+
+ file_name = os.path.basename(file_path)
+
+ self.files = {"upload": [file_name, data, file_type]}
+
+ def resolve_payload(self):
+ try:
+ if self.api_catalog_resource.payload_path:
+ with open(self.payload_path, "r") as f:
+ self.payload = f.read()
+ else:
+ with open(self.api_catalog_resource.payload, "r") as f:
+ self.payload = jinja2.Template(f.read()).render(
+ **self.payload_parameters
+ )
+ except jinja_exceptions.TemplateNotFound:
+ logger.error(
+ "{} file not found. Check payloads directory.".format(self.payload)
+ )
+ raise
+ except FileNotFoundError:
+ logger.error(
+ "{} file not found. Check payloads directory.".format(self.payload)
+ )
+ raise
+
+ def resolve_uri(self):
+ try:
+ self.uri = self.api_catalog_resource.uri(**self.uri_parameters)
+ except KeyError:
+ logger.error("invalid uri keys {}.".format(self.uri_parameters))
+ raise
diff --git a/onap-client/onap_client/client/response.py b/onap-client/onap_client/client/response.py
new file mode 100644
index 0000000..ef0aab5
--- /dev/null
+++ b/onap-client/onap_client/client/response.py
@@ -0,0 +1,115 @@
+# -*- coding: utf8 -*-
+# ============LICENSE_START=======================================================
+# org.onap.vvp/validation-scripts
+# ===================================================================
+# Copyright © 2020 AT&T Intellectual Property. All rights reserved.
+# ===================================================================
+#
+# Unless otherwise specified, all software contained herein is licensed
+# under the Apache License, Version 2.0 (the "License");
+# you may not use this software 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.
+#
+#
+#
+# Unless otherwise specified, all documentation contained herein is licensed
+# under the Creative Commons License, Attribution 4.0 Intl. (the "License");
+# you may not use this documentation except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://creativecommons.org/licenses/by/4.0/
+#
+# Unless required by applicable law or agreed to in writing, documentation
+# 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============================================
+
+import simplejson
+
+from onap_client.config import LOG as logger
+
+
+class ResponseHandler:
+ """Handles a response from the requests library,
+ and compares it to the APICatalogRequestObject that was used to make the request.
+ If the request object has return_data, then it will parse the response
+ object and add the return data as an attribute."""
+
+ def __init__(self, response, request_object):
+ """
+ :response: requests.response
+ :request_object: APICatalogRequestObject
+ """
+ self.response = response
+ self.request_object = request_object
+ self.response_data = {}
+ self.status_code = None
+ self.success = False
+
+ self.validate_response()
+
+ def validate_response(self):
+ response = self.response
+ if self.request_object.success_code != response.status_code:
+ response_data = response.text
+ logger.error(
+ "Request failed with code {} and data {}".format(
+ response.status_code, response_data
+ )
+ )
+ else:
+ logger.info("Request was successful")
+ self.success = True
+ try:
+ response_data = response.json()
+ for (
+ response_key,
+ response_items,
+ ) in self.request_object.return_data.items():
+ response_value = response_iterator(response_data, *response_items)
+ if not response_value:
+ logger.warning(
+ "Request was successful but value for {} was not present in response".format(
+ response_key
+ )
+ )
+ setattr(self, response_key, response_value)
+ except simplejson.errors.JSONDecodeError:
+ response_data = response.text
+
+ logger.debug("{}\n".format(response_data))
+
+ self.response_data = response_data
+ self.status_code = response.status_code
+
+
+def response_iterator(response_content, *keys):
+ """helper function to search a response for return_data keys"""
+ props = list(keys)
+
+ key = props.pop(0)
+ prop = response_content.get(key, None)
+
+ if isinstance(prop, str) or len(props) <= 0:
+ return prop
+ elif isinstance(prop, list):
+ if isinstance(key, int):
+ return response_iterator(prop[key], *props)
+ else:
+ for x in prop:
+ return response_iterator(x, *props)
+ elif isinstance(prop, dict):
+ return response_iterator(prop, *props)
+ else:
+ return None
diff --git a/onap-client/onap_client/config.py b/onap-client/onap_client/config.py
new file mode 100644
index 0000000..9e6bd35
--- /dev/null
+++ b/onap-client/onap_client/config.py
@@ -0,0 +1,99 @@
+# -*- coding: utf8 -*-
+# ============LICENSE_START=======================================================
+# org.onap.vvp/validation-scripts
+# ===================================================================
+# Copyright © 2020 AT&T Intellectual Property. All rights reserved.
+# ===================================================================
+#
+# Unless otherwise specified, all software contained herein is licensed
+# under the Apache License, Version 2.0 (the "License");
+# you may not use this software 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.
+#
+#
+#
+# Unless otherwise specified, all documentation contained herein is licensed
+# under the Creative Commons License, Attribution 4.0 Intl. (the "License");
+# you may not use this documentation except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://creativecommons.org/licenses/by/4.0/
+#
+# Unless required by applicable law or agreed to in writing, documentation
+# 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============================================
+
+import distutils.sysconfig
+import logging as logger
+import os
+import yaml
+
+PATH = "{}/onap_client".format(distutils.sysconfig.PREFIX)
+PAYLOADS_DIR = "{}/payloads".format(PATH)
+APPLICATION_ID = "robot-ete"
+CONFIG_ENV = os.environ.get("OC_CONFIG")
+CONFIG_FILE = CONFIG_ENV or "/etc/onap_client/config.yaml"
+
+
+class Config:
+ class ConfigClient:
+ def __init__(self, config_dict):
+ self.config = config_dict
+
+ def __getattr__(self, attr):
+ return self.config.get(attr, None)
+
+ def __init__(self, config_file):
+ self.config = {}
+ self.config_file = config_file
+
+ def __getattr__(self, attr):
+ item = self.config.get(attr, None)
+ if isinstance(item, str):
+ return item
+ elif isinstance(item, dict):
+ return self.ConfigClient(item)
+ else:
+ return None
+
+ def load(self, *keys):
+ if self.config_file and self.config_file != "NONE":
+ try:
+ with open(self.config_file, "r") as f:
+ config_data = yaml.safe_load(f)
+ except FileNotFoundError:
+ logger.warn(
+ "Config file {} not found, using default".format(self.config_file)
+ )
+ else:
+ with open("{}/config.example.yaml".format(PATH), "r") as f:
+ config_data = yaml.safe_load(f)
+
+ self.config = config_data
+ for key in keys:
+ self.config = self.config.get(key, {})
+
+
+def load_config(config_file, *config_args):
+ config = Config(config_file)
+ config.load(*config_args)
+
+ return config
+
+
+APP_CONFIG = load_config(CONFIG_FILE, "onap_client")
+LOG = logger
+log_level = getattr(LOG, APP_CONFIG.LOG_LEVEL.upper())
+LOG.basicConfig(format="%(asctime)s %(message)s", level=log_level)
diff --git a/onap-client/onap_client/engine.py b/onap-client/onap_client/engine.py
new file mode 100644
index 0000000..7543783
--- /dev/null
+++ b/onap-client/onap_client/engine.py
@@ -0,0 +1,216 @@
+# -*- coding: utf8 -*-
+# ============LICENSE_START=======================================================
+# org.onap.vvp/validation-scripts
+# ===================================================================
+# Copyright © 2020 AT&T Intellectual Property. All rights reserved.
+# ===================================================================
+#
+# Unless otherwise specified, all software contained herein is licensed
+# under the Apache License, Version 2.0 (the "License");
+# you may not use this software 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.
+#
+#
+#
+# Unless otherwise specified, all documentation contained herein is licensed
+# under the Creative Commons License, Attribution 4.0 Intl. (the "License");
+# you may not use this documentation except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://creativecommons.org/licenses/by/4.0/
+#
+# Unless required by applicable law or agreed to in writing, documentation
+# 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============================================
+
+import argparse
+import json
+
+from onap_client.resource import Resource
+from onap_client.config import LOG as logger
+from onap_client.client.clients import import_submodules
+from onap_client.exceptions import InvalidSpecException, ResourceTypeNotFoundException
+
+
+def dumper(obj):
+ try:
+ return obj.toJSON()
+ except: # noqa: E722
+ return str(obj)
+
+
+def list_spec_resources():
+ for subclass in Resource.__subclasses__():
+ print(subclass.resource_name)
+
+
+def show_resource_spec(resource_name):
+ for subclass in Resource.__subclasses__():
+ if resource_name == subclass.resource_name:
+ print(json.dumps(subclass.spec, default=dumper, indent=4))
+ return subclass.spec
+
+ print(
+ "Resource {} not found. This is the list of available resources:".format(
+ resource_name
+ )
+ )
+ list_spec_resources()
+
+
+def load_spec(input_spec, validate_only=False):
+ try:
+ with open(input_spec, "r") as f:
+ jdata = json.loads(f.read())
+ except json.decoder.JSONDecodeError:
+ print("{} is not valid json, exiting...".format(input_spec))
+ raise
+
+ engine = SpecEngine()
+ return engine.load_spec(jdata, validate_only=validate_only)
+
+
+def spec_cli(args):
+ parser = argparse.ArgumentParser(description="Spec Engine CLI")
+
+ parser.add_argument(
+ "--load-spec",
+ required=False,
+ help="Load a local spec file into the ONAP client spec engine.",
+ )
+
+ parser.add_argument(
+ "--validate-spec",
+ required=False,
+ help="Validates a local spec file for the spec engine.",
+ )
+
+ parser.add_argument(
+ "--show-resource-spec", required=False, help="Show spec for a given resource."
+ )
+
+ parser.add_argument(
+ "--list-spec-resources",
+ action="store_true",
+ required=False,
+ help="List available spec resources.",
+ )
+
+ arguments = parser.parse_args(args)
+
+ if arguments.list_spec_resources:
+ list_spec_resources()
+ elif arguments.show_resource_spec:
+ show_resource_spec(arguments.show_resource_spec)
+ elif arguments.validate_spec:
+ print(json.dumps(load_spec(arguments.validate_spec, validate_only=True), indent=4))
+ elif arguments.load_spec:
+ load_spec(arguments.load_spec)
+
+
+class SpecEngine:
+ def __init__(self):
+ self.initialize()
+ self.spec = {}
+
+ def initialize(self):
+ import_submodules("onap_client")
+
+ def load_spec(self, spec, distribute=True, validate_only=False):
+ # print("loading spec {}".format(spec))
+ self.spec = resolve_spec(spec)
+ self.validate(self.spec.get("spec", {}))
+
+ if not validate_only:
+ self._create(self.spec.get("spec", {}), distribute)
+
+ return self.spec
+
+ def validate(self, spec):
+ if not isinstance(spec, list):
+ raise InvalidSpecException(
+ "Input spec to spec engine must be a list, but is type {}".format(
+ type(spec)
+ )
+ )
+
+ for item_spec in spec:
+ if not isinstance(item_spec, dict):
+ raise InvalidSpecException(
+ "Items in input spec to engine must be dict, but is type {}".format(
+ type(item_spec)
+ )
+ )
+ resource_type = item_spec.get("type")
+ if not resource_type:
+ raise InvalidSpecException(
+ "Items in input spec must contain key/value item for 'type:'"
+ )
+ resource_spec = item_spec.get("resource_spec")
+ if not resource_spec:
+ raise InvalidSpecException(
+ "Items in input spec must contain key/value item for 'resource_spec:'"
+ )
+ subclass = get_resource_subclass(resource_type)
+ if not subclass:
+ raise ResourceTypeNotFoundException(
+ "Resource type {} was not found".format(resource_type)
+ )
+ subclass.validate(resource_spec)
+
+ def _create(self, spec, distribute):
+ full_engine_spec = []
+ for item_spec in spec:
+ resource_type = item_spec.get("type")
+ resource_spec = item_spec.get("resource_spec")
+ subclass = get_resource_subclass(resource_type)
+ if not subclass:
+ raise ResourceTypeNotFoundException(
+ "Resource type {} was not found".format(resource_type)
+ )
+ full_spec = subclass.validate(resource_spec)
+ logger.debug(json.dumps(full_spec, indent=4))
+ subclass.create_from_spec(full_spec, submit=distribute)
+ full_engine_spec.append({"type": resource_type, "resource_spec": full_spec})
+
+ logger.info(json.dumps(full_engine_spec, indent=4))
+
+
+def resolve_spec(spec_dict):
+ specs = spec_dict.get("spec")
+ parameters = spec_dict.get("parameters", {})
+
+ for param_name, param_val in parameters.items():
+ specs = replace(specs, "{{{{{}}}}}".format(param_name), param_val)
+
+ spec_dict["spec"] = specs
+ return spec_dict
+
+
+def replace(data, match, repl):
+ if isinstance(data, dict):
+ return {k: replace(v, match, repl) for k, v in data.items()}
+ elif isinstance(data, list):
+ return [replace(i, match, repl) for i in data]
+ else:
+ return repl if data == match else data
+
+
+def get_resource_subclass(subclass_name):
+ for subclass in Resource.__subclasses__():
+ if subclass.resource_name == subclass_name:
+ return subclass
+
+ return None
diff --git a/onap-client/onap_client/exceptions.py b/onap-client/onap_client/exceptions.py
new file mode 100644
index 0000000..76bb77e
--- /dev/null
+++ b/onap-client/onap_client/exceptions.py
@@ -0,0 +1,144 @@
+# -*- coding: utf8 -*-
+# ============LICENSE_START=======================================================
+# org.onap.vvp/validation-scripts
+# ===================================================================
+# Copyright © 2020 AT&T Intellectual Property. All rights reserved.
+# ===================================================================
+#
+# Unless otherwise specified, all software contained herein is licensed
+# under the Apache License, Version 2.0 (the "License");
+# you may not use this software 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.
+#
+#
+#
+# Unless otherwise specified, all documentation contained herein is licensed
+# under the Creative Commons License, Attribution 4.0 Intl. (the "License");
+# you may not use this documentation except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://creativecommons.org/licenses/by/4.0/
+#
+# Unless required by applicable law or agreed to in writing, documentation
+# 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============================================
+
+
+class MissingAttributeException(Exception):
+ pass
+
+
+class RequestFailure(Exception):
+ pass
+
+
+class FilesRequestFailure(Exception):
+ pass
+
+
+class CatalogItemNotFound(Exception):
+ pass
+
+
+class InputNotFoundException(Exception):
+ pass
+
+
+class PropertyNotFoundException(Exception):
+ pass
+
+
+class MissingInputException(Exception):
+ pass
+
+
+class ResourceNotFoundException(Exception):
+ pass
+
+
+class UnknownGroupException(Exception):
+ pass
+
+
+class UnknownPolicyException(Exception):
+ pass
+
+
+class InvalidSpecException(Exception):
+ pass
+
+
+class ResourceAlreadyExistsException(Exception):
+ pass
+
+
+class ResourceTypeNotFoundException(Exception):
+ pass
+
+
+class ResourceIDNotFoundException(Exception):
+ pass
+
+
+class SORequestStatusUnavailable(Exception):
+ pass
+
+
+class SORequestFailed(Exception):
+ pass
+
+
+class SORequestTimeout(Exception):
+ pass
+
+
+class ServiceInstanceNotFound(Exception):
+ pass
+
+
+class VNFComponentNotFound(Exception):
+ pass
+
+
+class VNFInstanceNotFound(Exception):
+ pass
+
+
+class ModuleInstanceNotFound(Exception):
+ pass
+
+
+class NoArtifactFoundInModel(Exception):
+ pass
+
+
+class ModuleModelNameNotFound(Exception):
+ pass
+
+
+class DistributionNotFound(Exception):
+ pass
+
+
+class DistributionFailure(Exception):
+ pass
+
+
+class DistributionTimeout(Exception):
+ pass
+
+
+class TenantNotFound(Exception):
+ pass
diff --git a/onap-client/onap_client/lib.py b/onap-client/onap_client/lib.py
new file mode 100644
index 0000000..78da11b
--- /dev/null
+++ b/onap-client/onap_client/lib.py
@@ -0,0 +1,124 @@
+# -*- coding: utf8 -*-
+# ============LICENSE_START=======================================================
+# org.onap.vvp/validation-scripts
+# ===================================================================
+# Copyright © 2020 AT&T Intellectual Property. All rights reserved.
+# ===================================================================
+#
+# Unless otherwise specified, all software contained herein is licensed
+# under the Apache License, Version 2.0 (the "License");
+# you may not use this software 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.
+#
+#
+#
+# Unless otherwise specified, all documentation contained herein is licensed
+# under the Creative Commons License, Attribution 4.0 Intl. (the "License");
+# you may not use this documentation except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://creativecommons.org/licenses/by/4.0/
+#
+# Unless required by applicable law or agreed to in writing, documentation
+# 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============================================
+
+import uuid
+from datetime import datetime, timedelta
+
+from onap_client import exceptions
+from onap_client.client.request import RequestHandler, APICatalogRequestObject
+
+
+def make_request(catalog_item, **kwargs):
+ """Makes a request using by merging an APICatalogResource and
+ kwargs to fill in the required parameters
+
+ :catalog_item: APICatalogResource
+ :kwargs: key/value to fill in data for APICatalogResource parameters
+
+ :return: ResponseHandler object with response data from request
+ """
+ request_input = validate_request(catalog_item, kwargs)
+
+ catalog_request = APICatalogRequestObject(catalog_item, **request_input,)
+
+ request_handler = RequestHandler(catalog_request)
+
+ response_handler = request_handler.make_request()
+
+ if not response_handler.success:
+ raise exceptions.RequestFailure(
+ "Failed making request for catalog item {}: {}".format(
+ catalog_item.catalog_resource_name,
+ response_handler.response_data
+ )
+ )
+
+ return response_handler
+
+
+def validate_request(catalog_item, kwargs):
+ request_input = {}
+
+ request_input["payload_parameters"] = validate_parameters(
+ catalog_item.payload_parameters, kwargs
+ )
+ request_input["uri_parameters"] = validate_parameters(
+ catalog_item.uri_parameters, kwargs
+ )
+ request_input["file_parameters"] = validate_parameters(
+ catalog_item.file_parameters, kwargs
+ )
+ request_input["header_parameters"] = validate_parameters(
+ catalog_item.header_parameters, kwargs
+ )
+ request_input["payload_path"] = validate_parameters(
+ catalog_item.payload_path, kwargs
+ )
+
+ return request_input
+
+
+def validate_parameters(catalog_item_parameters, kwargs):
+ values = {}
+
+ if not valid_input(catalog_item_parameters, kwargs.keys()):
+ raise exceptions.MissingAttributeException(
+ "Missing parameters for request {}".format(
+ set(catalog_item_parameters) - set(kwargs.keys())
+ )
+ )
+ else:
+ for param in catalog_item_parameters:
+ values[param] = kwargs.get(param)
+
+ return values
+
+
+def valid_input(required_attributes, input_attributes):
+ return set(required_attributes).issubset(input_attributes)
+
+
+def generate_dummy_string(start="", random_length=4):
+ rand_string = str(uuid.uuid4())[0:random_length]
+ return "{}{}".format(start, rand_string)
+
+
+def generate_dummy_date(days=0):
+ tmpdate = datetime.now() + timedelta(days=days)
+ return "{}/{}/{}".format(
+ "{:02d}".format(tmpdate.month), "{:02d}".format(tmpdate.day), tmpdate.year
+ )
diff --git a/onap-client/onap_client/resource.py b/onap-client/onap_client/resource.py
new file mode 100644
index 0000000..0af0fad
--- /dev/null
+++ b/onap-client/onap_client/resource.py
@@ -0,0 +1,189 @@
+# -*- coding: utf8 -*-
+# ============LICENSE_START=======================================================
+# org.onap.vvp/validation-scripts
+# ===================================================================
+# Copyright © 2020 AT&T Intellectual Property. All rights reserved.
+# ===================================================================
+#
+# Unless otherwise specified, all software contained herein is licensed
+# under the Apache License, Version 2.0 (the "License");
+# you may not use this software 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.
+#
+#
+#
+# Unless otherwise specified, all documentation contained herein is licensed
+# under the Creative Commons License, Attribution 4.0 Intl. (the "License");
+# you may not use this documentation except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://creativecommons.org/licenses/by/4.0/
+#
+# Unless required by applicable law or agreed to in writing, documentation
+# 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============================================
+
+import inspect
+
+from abc import ABC, abstractmethod
+from onap_client.exceptions import InvalidSpecException
+
+
+class Resource(ABC):
+ resource_name = "abstract"
+ spec = {}
+
+ def __init__(self, input):
+ self.attributes = {}
+
+ attributes = self._create(input)
+ self.resolve_attributes(attributes)
+
+ self._post_create()
+
+ def __getattr__(self, attr):
+ return self.attributes.get(attr, None)
+
+ @abstractmethod
+ def _create(self, input):
+ pass
+
+ @abstractmethod
+ def _post_create(self):
+ pass
+
+ @abstractmethod
+ def _submit(self):
+ pass
+
+ @classmethod
+ def validate(cls, input, spec=None):
+ """Validates that an input dictionary spec
+ is valid according to a provided class spec.
+
+ Recursively walksdown and checks if all required attributes are present, and
+ attribute types match spec types.
+
+ Returns complete spec with all attributes.
+ """
+ valid_spec = {}
+
+ if not isinstance(input, dict):
+ raise InvalidSpecException("input spec was not a dictionary")
+
+ if not spec:
+ spec = cls.spec
+
+ for k, v in input.items():
+ if not spec.get(k):
+ raise InvalidSpecException("Unknown property found: {}".format(k))
+
+ for k, v in spec.items():
+ property_name = k
+ property_type = v.get("type")
+ property_required = v.get("required")
+ property_default = v.get("default", default_empty_value(property_type))
+
+ input_property = validate_property(
+ input, property_name, property_required, property_default, property_type
+ )
+
+ if (
+ property_type == dict
+ and input_property != property_default
+ and v.get("nested")
+ ):
+ property_value = cls.validate(input_property, v.get("nested"))
+ elif property_type == list:
+ list_property_type = v.get("list_item")
+ list_spec = []
+ for item in input_property:
+ if type(item) != list_property_type:
+ raise InvalidSpecException(
+ "list item {} not match type {}".format(
+ item, list_property_type
+ )
+ )
+ if list_property_type == str:
+ list_spec.insert(0, item)
+ else:
+ list_spec.insert(0, cls.validate(item, v.get("nested", {})))
+
+ property_value = list_spec
+ else:
+ property_value = input_property
+
+ valid_spec[property_name] = property_value
+
+ return valid_spec
+
+ @classmethod
+ def create_from_spec(cls, spec, submit=True):
+ input_args = []
+
+ arguments = inspect.getfullargspec(cls).args
+ arguments.pop(0)
+
+ for argument in arguments:
+ input_args.append(spec.get(argument))
+
+ instance = cls(*input_args)
+
+ if submit:
+ instance._submit()
+
+ return instance
+
+ def resolve_attributes(self, attributes):
+ for key, val in attributes.items():
+ self.attributes[key] = val
+
+ def print(self):
+ for k, v in self.attributes.items():
+ val = str(v)
+ value = val[:50] + "..." if len(val) > 50 else val
+ print("{}: {}".format(k, value))
+
+
+def validate_property(
+ input_spec, property_name, property_required, property_default, property_type
+):
+ input_property = input_spec.get(property_name)
+ if not input_property:
+ if property_required:
+ raise InvalidSpecException(
+ "required property {} not found in input spec".format(property_name)
+ )
+ else:
+ input_property = property_default
+ elif type(input_property) != property_type:
+ raise InvalidSpecException(
+ "input property {} not match type {}".format(property_name, property_type)
+ )
+
+ return input_property
+
+
+def default_empty_value(property_type):
+ if property_type == str:
+ return None
+ elif property_type == list:
+ return []
+ elif property_type == dict:
+ return {}
+ elif property_type == bool:
+ return False
+ else:
+ return None
diff --git a/onap-client/onap_client/sdc/__init__.py b/onap-client/onap_client/sdc/__init__.py
new file mode 100644
index 0000000..d8028f6
--- /dev/null
+++ b/onap-client/onap_client/sdc/__init__.py
@@ -0,0 +1,40 @@
+# -*- coding: utf8 -*-
+# ============LICENSE_START=======================================================
+# org.onap.vvp/validation-scripts
+# ===================================================================
+# Copyright © 2020 AT&T Intellectual Property. All rights reserved.
+# ===================================================================
+#
+# Unless otherwise specified, all software contained herein is licensed
+# under the Apache License, Version 2.0 (the "License");
+# you may not use this software 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.
+#
+#
+#
+# Unless otherwise specified, all documentation contained herein is licensed
+# under the Creative Commons License, Attribution 4.0 Intl. (the "License");
+# you may not use this documentation except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://creativecommons.org/licenses/by/4.0/
+#
+# Unless required by applicable law or agreed to in writing, documentation
+# 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============================================
+
+from onap_client.config import APP_CONFIG
+
+SDC_PROPERTIES = APP_CONFIG.sdc
diff --git a/onap-client/onap_client/sdc/catalog/__init__.py b/onap-client/onap_client/sdc/catalog/__init__.py
new file mode 100644
index 0000000..d35e96a
--- /dev/null
+++ b/onap-client/onap_client/sdc/catalog/__init__.py
@@ -0,0 +1,37 @@
+# -*- coding: utf8 -*-
+# ============LICENSE_START=======================================================
+# org.onap.vvp/validation-scripts
+# ===================================================================
+# Copyright © 2020 AT&T Intellectual Property. All rights reserved.
+# ===================================================================
+#
+# Unless otherwise specified, all software contained herein is licensed
+# under the Apache License, Version 2.0 (the "License");
+# you may not use this software 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.
+#
+#
+#
+# Unless otherwise specified, all documentation contained herein is licensed
+# under the Creative Commons License, Attribution 4.0 Intl. (the "License");
+# you may not use this documentation except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://creativecommons.org/licenses/by/4.0/
+#
+# Unless required by applicable law or agreed to in writing, documentation
+# 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============================================
+
diff --git a/onap-client/onap_client/sdc/catalog/license_model_catalog.py b/onap-client/onap_client/sdc/catalog/license_model_catalog.py
new file mode 100644
index 0000000..278645d
--- /dev/null
+++ b/onap-client/onap_client/sdc/catalog/license_model_catalog.py
@@ -0,0 +1,318 @@
+# -*- coding: utf8 -*-
+# ============LICENSE_START=======================================================
+# org.onap.vvp/validation-scripts
+# ===================================================================
+# Copyright © 2020 AT&T Intellectual Property. All rights reserved.
+# ===================================================================
+#
+# Unless otherwise specified, all software contained herein is licensed
+# under the Apache License, Version 2.0 (the "License");
+# you may not use this software 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.
+#
+#
+#
+# Unless otherwise specified, all documentation contained herein is licensed
+# under the Creative Commons License, Attribution 4.0 Intl. (the "License");
+# you may not use this documentation except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://creativecommons.org/licenses/by/4.0/
+#
+# Unless required by applicable law or agreed to in writing, documentation
+# 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============================================
+
+import uuid
+from functools import partial
+
+from onap_client import sdc
+from onap_client import config
+from onap_client.sdc.client import SDCClient
+
+PAYLOADS_DIR = config.PAYLOADS_DIR
+sdc_properties = sdc.SDC_PROPERTIES
+application_id = config.APPLICATION_ID
+
+
+class LicenseModelClient(SDCClient):
+ @property
+ def catalog_resources(self):
+ return CATALOG_RESOURCES
+
+ @property
+ def namespace(self):
+ return "license_model"
+
+
+CATALOG_RESOURCES = {
+ "ADD_LICENSE_MODEL": {
+ "verb": "POST",
+ "description": "creates a license model in the SDC catalog",
+ "uri": partial(
+ "{endpoint}{service_path}".format,
+ endpoint=sdc_properties.SDC_BE_ONBOARD_ENDPOINT,
+ service_path=sdc_properties.SDC_VENDOR_LICENSE_MODEL_PATH,
+ ),
+ "payload": "{}/license_model.jinja".format(PAYLOADS_DIR),
+ "payload-parameters": ["vendor_name"],
+ "success_code": 200,
+ "headers": {
+ "Accept": "application/json",
+ "Content-Type": "application/json",
+ "USER_ID": sdc_properties.SDC_DESIGNER_USER_ID,
+ "X-TransactionId": str(uuid.uuid4()),
+ "X-FromAppId": application_id,
+ },
+ "return_data": {
+ "license_model_id": ("itemId",),
+ "license_model_version_id": ("version", "id"),
+ },
+ "auth": (
+ sdc_properties.GLOBAL_SDC_USERNAME,
+ sdc_properties.GLOBAL_SDC_PASSWORD,
+ ),
+ },
+ "ADD_KEY_GROUP": {
+ "verb": "POST",
+ "description": "Adds a key group to a license model",
+ "uri": partial(
+ "{endpoint}{service_path}/{license_model_id}/versions/{license_model_version_id}/license-key-groups".format,
+ endpoint=sdc_properties.SDC_BE_ONBOARD_ENDPOINT,
+ service_path=sdc_properties.SDC_VENDOR_LICENSE_MODEL_PATH,
+ ),
+ "uri-parameters": ["license_model_id", "license_model_version_id"],
+ "payload": "{}/key_group.jinja".format(PAYLOADS_DIR),
+ "payload-parameters": [
+ "license_start_date",
+ "license_end_date",
+ "key_group_name",
+ ],
+ "success_code": 200,
+ "headers": {
+ "Accept": "application/json",
+ "Content-Type": "application/json",
+ "USER_ID": sdc_properties.SDC_DESIGNER_USER_ID,
+ "X-TransactionId": str(uuid.uuid4()),
+ "X-FromAppId": application_id,
+ },
+ "return_data": {"key_group_id": ("value",)},
+ "auth": (
+ sdc_properties.GLOBAL_SDC_USERNAME,
+ sdc_properties.GLOBAL_SDC_PASSWORD,
+ ),
+ },
+ "ADD_ENTITLEMENT_POOL": {
+ "verb": "POST",
+ "description": "Adds an entitlement pool to a license model",
+ "uri": partial(
+ "{endpoint}{service_path}/{license_model_id}/versions/{license_model_version_id}/entitlement-pools".format,
+ endpoint=sdc_properties.SDC_BE_ONBOARD_ENDPOINT,
+ service_path=sdc_properties.SDC_VENDOR_LICENSE_MODEL_PATH,
+ ),
+ "uri-parameters": ["license_model_id", "license_model_version_id"],
+ "payload": "{}/entitlement_pool.jinja".format(PAYLOADS_DIR),
+ "payload-parameters": [
+ "license_start_date",
+ "license_end_date",
+ "entitlement_pool_name",
+ ],
+ "success_code": 200,
+ "headers": {
+ "Accept": "application/json",
+ "Content-Type": "application/json",
+ "USER_ID": sdc_properties.SDC_DESIGNER_USER_ID,
+ "X-TransactionId": str(uuid.uuid4()),
+ "X-FromAppId": application_id,
+ },
+ "return_data": {"entitlement_pool_id": ("value",)},
+ "auth": (
+ sdc_properties.GLOBAL_SDC_USERNAME,
+ sdc_properties.GLOBAL_SDC_PASSWORD,
+ ),
+ },
+ "ADD_FEATURE_GROUP": {
+ "verb": "POST",
+ "description": "Adds an feature group to a license model",
+ "uri": partial(
+ "{endpoint}{service_path}/{license_model_id}/versions/{license_model_version_id}/feature-groups".format,
+ endpoint=sdc_properties.SDC_BE_ONBOARD_ENDPOINT,
+ service_path=sdc_properties.SDC_VENDOR_LICENSE_MODEL_PATH,
+ ),
+ "uri-parameters": ["license_model_id", "license_model_version_id"],
+ "payload": "{}/feature_group.jinja".format(PAYLOADS_DIR),
+ "payload-parameters": [
+ "feature_group_name",
+ "key_group_id",
+ "entitlement_pool_id",
+ "manufacturer_reference_number",
+ ],
+ "success_code": 200,
+ "headers": {
+ "Accept": "application/json",
+ "Content-Type": "application/json",
+ "USER_ID": sdc_properties.SDC_DESIGNER_USER_ID,
+ "X-TransactionId": str(uuid.uuid4()),
+ "X-FromAppId": application_id,
+ },
+ "return_data": {"feature_group_id": ("value",)},
+ "auth": (
+ sdc_properties.GLOBAL_SDC_USERNAME,
+ sdc_properties.GLOBAL_SDC_PASSWORD,
+ ),
+ },
+ "ADD_LICENSE_AGREEMENT": {
+ "verb": "POST",
+ "description": "Adds an license agreement to a license model",
+ "uri": partial(
+ "{endpoint}{service_path}/{license_model_id}/versions/{license_model_version_id}/license-agreements".format,
+ endpoint=sdc_properties.SDC_BE_ONBOARD_ENDPOINT,
+ service_path=sdc_properties.SDC_VENDOR_LICENSE_MODEL_PATH,
+ ),
+ "uri-parameters": ["license_model_id", "license_model_version_id"],
+ "payload": "{}/license_agreement.jinja".format(PAYLOADS_DIR),
+ "payload-parameters": ["feature_group_id", "license_agreement_name"],
+ "success_code": 200,
+ "headers": {
+ "Accept": "application/json",
+ "Content-Type": "application/json",
+ "USER_ID": sdc_properties.SDC_DESIGNER_USER_ID,
+ "X-TransactionId": str(uuid.uuid4()),
+ "X-FromAppId": application_id,
+ },
+ "return_data": {"license_agreement_id": ("value",)},
+ "auth": (
+ sdc_properties.GLOBAL_SDC_USERNAME,
+ sdc_properties.GLOBAL_SDC_PASSWORD,
+ ),
+ },
+ "SUBMIT_LICENSE_MODEL": {
+ "verb": "PUT",
+ "description": "Submits a license model",
+ "uri": partial(
+ "{endpoint}{service_path}/{license_model_id}/versions/{license_model_version_id}/actions".format,
+ endpoint=sdc_properties.SDC_BE_ONBOARD_ENDPOINT,
+ service_path=sdc_properties.SDC_VENDOR_LICENSE_MODEL_PATH,
+ ),
+ "uri-parameters": ["license_model_id", "license_model_version_id"],
+ "payload": "{}/action.jinja".format(PAYLOADS_DIR),
+ "payload-parameters": ["action"],
+ "success_code": 200,
+ "headers": {
+ "Accept": "application/json",
+ "Content-Type": "application/json",
+ "USER_ID": sdc_properties.SDC_DESIGNER_USER_ID,
+ "X-TransactionId": str(uuid.uuid4()),
+ "X-FromAppId": application_id,
+ },
+ "auth": (
+ sdc_properties.GLOBAL_SDC_USERNAME,
+ sdc_properties.GLOBAL_SDC_PASSWORD,
+ ),
+ },
+ "GET_LICENSE_MODEL": {
+ "verb": "GET",
+ "description": "Returns a license model",
+ "uri": partial(
+ "{endpoint}{service_path}/{license_model_id}/versions/{license_model_version_id}".format,
+ endpoint=sdc_properties.SDC_BE_ONBOARD_ENDPOINT,
+ service_path=sdc_properties.SDC_VENDOR_LICENSE_MODEL_PATH,
+ ),
+ "uri-parameters": ["license_model_id", "license_model_version_id"],
+ "success_code": 200,
+ "headers": {
+ "Accept": "application/json",
+ "Content-Type": "application/json",
+ "USER_ID": sdc_properties.SDC_DESIGNER_USER_ID,
+ "X-TransactionId": str(uuid.uuid4()),
+ "X-FromAppId": application_id,
+ },
+ "return_data": {
+ "vendor_name": ("vendorName",),
+ "license_model_id": ("id",),
+ "description": ("description",),
+ },
+ "auth": (
+ sdc_properties.GLOBAL_SDC_USERNAME,
+ sdc_properties.GLOBAL_SDC_PASSWORD,
+ ),
+ },
+ "GET_LICENSE_MODEL_VERSION_ATTRIBUTE": {
+ "verb": "GET",
+ "description": "Returns an attribute for a license model (license-agreements, features-groups, etc...)",
+ "uri": partial(
+ "{endpoint}{service_path}/{license_model_id}/versions/{license_model_version_id}/{attribute}".format,
+ endpoint=sdc_properties.SDC_BE_ONBOARD_ENDPOINT,
+ service_path=sdc_properties.SDC_VENDOR_LICENSE_MODEL_PATH,
+ ),
+ "uri-parameters": ["license_model_id", "license_model_version_id", "attribute"],
+ "success_code": 200,
+ "headers": {
+ "Accept": "application/json",
+ "Content-Type": "application/json",
+ "USER_ID": sdc_properties.SDC_DESIGNER_USER_ID,
+ "X-TransactionId": str(uuid.uuid4()),
+ "X-FromAppId": application_id,
+ },
+ "auth": (
+ sdc_properties.GLOBAL_SDC_USERNAME,
+ sdc_properties.GLOBAL_SDC_PASSWORD,
+ ),
+ },
+ "GET_LICENSE_MODEL_VERSIONS": {
+ "verb": "GET",
+ "description": "Returns the version list for a license model",
+ "uri": partial(
+ "{endpoint}{service_path}/{license_model_id}/versions".format,
+ endpoint=sdc_properties.SDC_BE_ONBOARD_ENDPOINT,
+ service_path=sdc_properties.SDC_VENDOR_ITEMS_PATH,
+ ),
+ "uri-parameters": ["license_model_id"],
+ "success_code": 200,
+ "headers": {
+ "Accept": "application/json",
+ "Content-Type": "application/json",
+ "USER_ID": sdc_properties.SDC_DESIGNER_USER_ID,
+ "X-TransactionId": str(uuid.uuid4()),
+ "X-FromAppId": application_id,
+ },
+ "auth": (
+ sdc_properties.GLOBAL_SDC_USERNAME,
+ sdc_properties.GLOBAL_SDC_PASSWORD,
+ ),
+ },
+ "GET_LICENSE_MODELS": {
+ "verb": "GET",
+ "description": "Returns the full list of license models from SDC",
+ "uri": partial(
+ "{endpoint}{service_path}?&itemType=vlm".format,
+ endpoint=sdc_properties.SDC_BE_ONBOARD_ENDPOINT,
+ service_path=sdc_properties.SDC_VENDOR_ITEMS_PATH,
+ ),
+ "success_code": 200,
+ "headers": {
+ "Accept": "application/json",
+ "Content-Type": "application/json",
+ "USER_ID": sdc_properties.SDC_DESIGNER_USER_ID,
+ "X-TransactionId": str(uuid.uuid4()),
+ "X-FromAppId": application_id,
+ },
+ "return_data": {"results": ("results",)},
+ "auth": (
+ sdc_properties.GLOBAL_SDC_USERNAME,
+ sdc_properties.GLOBAL_SDC_PASSWORD,
+ ),
+ },
+}
diff --git a/onap-client/onap_client/sdc/catalog/service_catalog.py b/onap-client/onap_client/sdc/catalog/service_catalog.py
new file mode 100644
index 0000000..1d30725
--- /dev/null
+++ b/onap-client/onap_client/sdc/catalog/service_catalog.py
@@ -0,0 +1,426 @@
+# -*- coding: utf8 -*-
+# ============LICENSE_START=======================================================
+# org.onap.vvp/validation-scripts
+# ===================================================================
+# Copyright © 2020 AT&T Intellectual Property. All rights reserved.
+# ===================================================================
+#
+# Unless otherwise specified, all software contained herein is licensed
+# under the Apache License, Version 2.0 (the "License");
+# you may not use this software 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.
+#
+#
+#
+# Unless otherwise specified, all documentation contained herein is licensed
+# under the Creative Commons License, Attribution 4.0 Intl. (the "License");
+# you may not use this documentation except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://creativecommons.org/licenses/by/4.0/
+#
+# Unless required by applicable law or agreed to in writing, documentation
+# 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============================================
+
+import uuid
+from functools import partial
+
+from onap_client import sdc
+from onap_client import config
+from onap_client.sdc.client import SDCClient
+
+PAYLOADS_DIR = config.PAYLOADS_DIR
+sdc_properties = sdc.SDC_PROPERTIES
+application_id = config.APPLICATION_ID
+
+
+class ServiceCatalog(SDCClient):
+ @property
+ def catalog_resources(self):
+ return CATALOG_RESOURCES
+
+ @property
+ def namespace(self):
+ return "service"
+
+
+CATALOG_RESOURCES = {
+ "ADD_CATALOG_SERVICE": {
+ "verb": "POST",
+ "description": "Creates a Service in the SDC catalog",
+ "uri": partial(
+ "{endpoint}{service_path}".format,
+ endpoint=sdc_properties.SDC_BE_ENDPOINT,
+ service_path=sdc_properties.SDC_CATALOG_SERVICES_PATH,
+ ),
+ "payload": "{}/catalog_service.jinja".format(PAYLOADS_DIR),
+ "payload-parameters": [
+ "service_name",
+ "instantiation_type",
+ "contact_id",
+ "category_name",
+ "category_id",
+ "category_name_lower",
+ "category_name_icon",
+ "tag",
+ "project_code",
+ "environment_context",
+ "ecomp_generated_naming",
+ "description",
+ "service_type",
+ "service_role",
+ "naming_policy",
+ ],
+ "success_code": 201,
+ "headers": {
+ "Accept": "application/json",
+ "Content-Type": "application/json",
+ "USER_ID": sdc_properties.SDC_DESIGNER_USER_ID,
+ "X-TransactionId": str(uuid.uuid4()),
+ "X-FromAppId": application_id,
+ },
+ "return_data": {"catalog_service_id": ("uniqueId",)},
+ "auth": (
+ sdc_properties.GLOBAL_SDC_USERNAME,
+ sdc_properties.GLOBAL_SDC_PASSWORD,
+ ),
+ },
+ "ADD_RESOURCE_INSTANCE": {
+ "verb": "POST",
+ "description": "Attaches a Resource to a Service",
+ "uri": partial(
+ "{endpoint}{service_path}/{catalog_service_id}/resourceInstance".format,
+ endpoint=sdc_properties.SDC_BE_ENDPOINT,
+ service_path=sdc_properties.SDC_CATALOG_SERVICES_PATH,
+ ),
+ "uri-parameters": ["catalog_service_id"],
+ "payload": "{}/resource_instance.jinja".format(PAYLOADS_DIR),
+ "payload-parameters": [
+ "milli_timestamp",
+ "catalog_resource_id",
+ "catalog_resource_name",
+ "originType",
+ "posX",
+ "posY",
+ ],
+ "success_code": 201,
+ "headers": {
+ "Accept": "application/json",
+ "Content-Type": "application/json",
+ "USER_ID": sdc_properties.SDC_DESIGNER_USER_ID,
+ "X-TransactionId": str(uuid.uuid4()),
+ "X-FromAppId": application_id,
+ },
+ "return_data": {"catalog_resource_instance_id": ("uniqueId",)},
+ "auth": (
+ sdc_properties.GLOBAL_SDC_USERNAME,
+ sdc_properties.GLOBAL_SDC_PASSWORD,
+ ),
+ },
+ "CHECKIN_SERVICE": {
+ "verb": "POST",
+ "description": "Checks a service into the SDC Catalog",
+ "uri": partial(
+ "{endpoint}{service_path}/{catalog_service_id}/lifecycleState/checkin".format,
+ endpoint=sdc_properties.SDC_BE_ENDPOINT,
+ service_path=sdc_properties.SDC_CATALOG_SERVICES_PATH,
+ ),
+ "uri-parameters": ["catalog_service_id"],
+ "payload": "{}/user_remarks.jinja".format(PAYLOADS_DIR),
+ "payload-parameters": ["user_remarks"],
+ "success_code": 200,
+ "headers": {
+ "Accept": "application/json",
+ "Content-Type": "application/json",
+ "USER_ID": sdc_properties.SDC_DESIGNER_USER_ID,
+ "X-TransactionId": str(uuid.uuid4()),
+ "X-FromAppId": application_id,
+ },
+ "auth": (
+ sdc_properties.GLOBAL_SDC_USERNAME,
+ sdc_properties.GLOBAL_SDC_PASSWORD,
+ ),
+ },
+ "REQUEST_SERVICE_CERTIFICATION": {
+ "verb": "POST",
+ "description": "Requests certification of a service into the SDC Catalog",
+ "uri": partial(
+ "{endpoint}{service_path}/{catalog_service_id}/lifecycleState/certificationRequest".format,
+ endpoint=sdc_properties.SDC_BE_ENDPOINT,
+ service_path=sdc_properties.SDC_CATALOG_SERVICES_PATH,
+ ),
+ "uri-parameters": ["catalog_service_id"],
+ "payload": "{}/user_remarks.jinja".format(PAYLOADS_DIR),
+ "payload-parameters": ["user_remarks"],
+ "success_code": 200,
+ "headers": {
+ "Accept": "application/json",
+ "Content-Type": "application/json",
+ "USER_ID": sdc_properties.SDC_DESIGNER_USER_ID,
+ "X-TransactionId": str(uuid.uuid4()),
+ "X-FromAppId": application_id,
+ },
+ "auth": (
+ sdc_properties.GLOBAL_SDC_USERNAME,
+ sdc_properties.GLOBAL_SDC_PASSWORD,
+ ),
+ },
+ "START_SERVICE_CERTIFICATION": {
+ "verb": "POST",
+ "description": "Starts certification of a service into the SDC Catalog",
+ "uri": partial(
+ "{endpoint}{service_path}/{catalog_service_id}/lifecycleState/startCertification".format,
+ endpoint=sdc_properties.SDC_BE_ENDPOINT,
+ service_path=sdc_properties.SDC_CATALOG_SERVICES_PATH,
+ ),
+ "uri-parameters": ["catalog_service_id"],
+ "payload": "{}/user_remarks.jinja".format(PAYLOADS_DIR),
+ "payload-parameters": ["user_remarks"],
+ "success_code": 200,
+ "headers": {
+ "Accept": "application/json",
+ "Content-Type": "application/json",
+ "USER_ID": sdc_properties.SDC_TESTER_USER_ID,
+ "X-TransactionId": str(uuid.uuid4()),
+ "X-FromAppId": application_id,
+ },
+ "auth": (
+ sdc_properties.GLOBAL_SDC_USERNAME,
+ sdc_properties.GLOBAL_SDC_PASSWORD,
+ ),
+ },
+ "FINISH_SERVICE_CERTIFICATION": {
+ "verb": "POST",
+ "description": "Finishes certification of a service from the SDC Catalog",
+ "uri": partial(
+ "{endpoint}{service_path}/{catalog_service_id}/lifecycleState/certify".format,
+ endpoint=sdc_properties.SDC_BE_ENDPOINT,
+ service_path=sdc_properties.SDC_CATALOG_SERVICES_PATH,
+ ),
+ "uri-parameters": ["catalog_service_id"],
+ "payload": "{}/user_remarks.jinja".format(PAYLOADS_DIR),
+ "payload-parameters": ["user_remarks"],
+ "success_code": 200,
+ "headers": {
+ "Accept": "application/json",
+ "Content-Type": "application/json",
+ "USER_ID": sdc_properties.SDC_TESTER_USER_ID,
+ "X-TransactionId": str(uuid.uuid4()),
+ "X-FromAppId": application_id,
+ },
+ "return_data": {"catalog_service_id": ("uniqueId",)},
+ "auth": (
+ sdc_properties.GLOBAL_SDC_USERNAME,
+ sdc_properties.GLOBAL_SDC_PASSWORD,
+ ),
+ },
+ "APPROVE_SERVICE_CERTIFICATION": {
+ "verb": "POST",
+ "description": "Approves a service from the SDC Catalog",
+ "uri": partial(
+ "{endpoint}{service_path}/{catalog_service_id}/distribution-state/approve".format,
+ endpoint=sdc_properties.SDC_BE_ENDPOINT,
+ service_path=sdc_properties.SDC_CATALOG_SERVICES_PATH,
+ ),
+ "uri-parameters": ["catalog_service_id"],
+ "payload": "{}/user_remarks.jinja".format(PAYLOADS_DIR),
+ "payload-parameters": ["user_remarks"],
+ "success_code": 200,
+ "headers": {
+ "Accept": "application/json",
+ "Content-Type": "application/json",
+ "USER_ID": sdc_properties.SDC_GOVERNOR_USER_ID,
+ "X-TransactionId": str(uuid.uuid4()),
+ "X-FromAppId": application_id,
+ },
+ "auth": (
+ sdc_properties.GLOBAL_SDC_USERNAME,
+ sdc_properties.GLOBAL_SDC_PASSWORD,
+ ),
+ },
+ "DISTRIBUTE_SDC_SERVICE": {
+ "verb": "POST",
+ "description": "Distributes a service from the SDC Catalog",
+ "uri": partial(
+ "{endpoint}{service_path}/{catalog_service_id}/distribution/PROD/activate".format,
+ endpoint=sdc_properties.SDC_BE_ENDPOINT,
+ service_path=sdc_properties.SDC_CATALOG_SERVICES_PATH,
+ ),
+ "uri-parameters": ["catalog_service_id"],
+ "success_code": 200,
+ "headers": {
+ "Accept": "application/json",
+ "Content-Type": "application/json",
+ "USER_ID": sdc_properties.SDC_OPS_USER_ID,
+ "X-TransactionId": str(uuid.uuid4()),
+ "X-FromAppId": application_id,
+ },
+ "auth": (
+ sdc_properties.GLOBAL_SDC_USERNAME,
+ sdc_properties.GLOBAL_SDC_PASSWORD,
+ ),
+ },
+ "ADD_CATALOG_SERVICE_PROPERTY": {
+ "verb": "POST",
+ "description": "Add a property value for a VF in a Service",
+ "uri": partial(
+ "{endpoint}{service_path}/{catalog_service_id}/resourceInstance/{catalog_resource_instance_id}/properties".format,
+ endpoint=sdc_properties.SDC_BE_ENDPOINT,
+ service_path=sdc_properties.SDC_CATALOG_RESOURCES_PATH,
+ ),
+ "uri-parameters": ["catalog_service_id", "catalog_resource_instance_id"],
+ "payload": "{}/catalog_service_property.jinja".format(PAYLOADS_DIR),
+ "payload-parameters": [
+ "unique_id",
+ "parent_unique_id",
+ "owner_id",
+ "input_name",
+ "input_value",
+ "schema_type",
+ "property_type",
+ ],
+ "success_code": 200,
+ "headers": {
+ "Accept": "application/json",
+ "Content-Type": "application/json",
+ "USER_ID": sdc_properties.SDC_DESIGNER_USER_ID,
+ "X-TransactionId": str(uuid.uuid4()),
+ "X-FromAppId": application_id,
+ },
+ "auth": (
+ sdc_properties.GLOBAL_SDC_USERNAME,
+ sdc_properties.GLOBAL_SDC_PASSWORD,
+ ),
+ },
+ "ADD_CATALOG_SERVICE_INPUT": {
+ "verb": "POST",
+ "description": "Add an input value for a VF in a Service",
+ "uri": partial(
+ "{endpoint}{service_path}/{catalog_service_id}/resourceInstance/{catalog_resource_instance_id}/inputs".format,
+ endpoint=sdc_properties.SDC_BE_ENDPOINT,
+ service_path=sdc_properties.SDC_CATALOG_RESOURCES_PATH,
+ ),
+ "uri-parameters": ["catalog_service_id", "catalog_resource_instance_id"],
+ "payload": "{}/catalog_service_property.jinja".format(PAYLOADS_DIR),
+ "payload-parameters": [
+ "unique_id",
+ "parent_unique_id",
+ "owner_id",
+ "input_name",
+ "input_value",
+ ],
+ "success_code": 200,
+ "headers": {
+ "Accept": "application/json",
+ "Content-Type": "application/json",
+ "USER_ID": sdc_properties.SDC_DESIGNER_USER_ID,
+ "X-TransactionId": str(uuid.uuid4()),
+ "X-FromAppId": application_id,
+ },
+ "auth": (
+ sdc_properties.GLOBAL_SDC_USERNAME,
+ sdc_properties.GLOBAL_SDC_PASSWORD,
+ ),
+ },
+ "GET_SDC_SERVICE": {
+ "verb": "GET",
+ "description": "Gets a service from the SDC Catalog",
+ "uri": partial(
+ "{endpoint}{service_path}/{catalog_service_id}".format,
+ endpoint=sdc_properties.SDC_BE_ENDPOINT,
+ service_path=sdc_properties.SDC_CATALOG_SERVICES_PATH,
+ ),
+ "uri-parameters": ["catalog_service_id"],
+ "success_code": 200,
+ "headers": {
+ "Accept": "application/json",
+ "Content-Type": "application/json",
+ "USER_ID": sdc_properties.SDC_DESIGNER_USER_ID,
+ "X-TransactionId": str(uuid.uuid4()),
+ "X-FromAppId": application_id,
+ },
+ "auth": (
+ sdc_properties.GLOBAL_SDC_USERNAME,
+ sdc_properties.GLOBAL_SDC_PASSWORD,
+ ),
+ },
+ "GET_SERVICES": {
+ "verb": "GET",
+ "description": "Get all services in the SDC catalog",
+ "uri": partial(
+ "{endpoint}{service_path}".format,
+ endpoint=sdc_properties.SDC_BE_ENDPOINT,
+ service_path=sdc_properties.SDC_SCREEN_PATH,
+ ),
+ "success_code": 200,
+ "headers": {
+ "Accept": "application/json",
+ "Content-Type": "application/json",
+ "USER_ID": sdc_properties.SDC_DESIGNER_USER_ID,
+ "X-TransactionId": str(uuid.uuid4()),
+ "X-FromAppId": application_id,
+ },
+ "return_data": {"services": ("services",)},
+ "auth": (
+ sdc_properties.GLOBAL_SDC_USERNAME,
+ sdc_properties.GLOBAL_SDC_PASSWORD,
+ ),
+ },
+ "GET_SERVICE_DISTRIBUTION": {
+ "verb": "GET",
+ "description": "Gets the distribution for a service from the SDC Catalog",
+ "uri": partial(
+ "{endpoint}{service_path}/{distribution_service_id}/distribution".format,
+ endpoint=sdc_properties.SDC_BE_ENDPOINT,
+ service_path=sdc_properties.SDC_CATALOG_SERVICES_PATH,
+ ),
+ "uri-parameters": ["distribution_service_id"],
+ "success_code": 200,
+ "headers": {
+ "Accept": "application/json",
+ "Content-Type": "application/json",
+ "USER_ID": sdc_properties.SDC_DESIGNER_USER_ID,
+ "X-TransactionId": str(uuid.uuid4()),
+ "X-FromAppId": application_id,
+ },
+ "auth": (
+ sdc_properties.GLOBAL_SDC_USERNAME,
+ sdc_properties.GLOBAL_SDC_PASSWORD,
+ ),
+ },
+ "GET_SERVICE_DISTRIBUTION_DETAILS": {
+ "verb": "GET",
+ "description": "Gets the distribution details for a service from the SDC Catalog",
+ "uri": partial(
+ "{endpoint}{service_path}/distribution/{distribution_id}".format,
+ endpoint=sdc_properties.SDC_BE_ENDPOINT,
+ service_path=sdc_properties.SDC_CATALOG_SERVICES_PATH,
+ ),
+ "uri-parameters": ["distribution_id"],
+ "success_code": 200,
+ "headers": {
+ "Accept": "application/json",
+ "Content-Type": "application/json",
+ "USER_ID": sdc_properties.SDC_DESIGNER_USER_ID,
+ "X-TransactionId": str(uuid.uuid4()),
+ "X-FromAppId": application_id,
+ },
+ "auth": (
+ sdc_properties.GLOBAL_SDC_USERNAME,
+ sdc_properties.GLOBAL_SDC_PASSWORD,
+ ),
+ },
+}
diff --git a/onap-client/onap_client/sdc/catalog/vnf_catalog.py b/onap-client/onap_client/sdc/catalog/vnf_catalog.py
new file mode 100644
index 0000000..c4fd3da
--- /dev/null
+++ b/onap-client/onap_client/sdc/catalog/vnf_catalog.py
@@ -0,0 +1,410 @@
+# -*- coding: utf8 -*-
+# ============LICENSE_START=======================================================
+# org.onap.vvp/validation-scripts
+# ===================================================================
+# Copyright © 2020 AT&T Intellectual Property. All rights reserved.
+# ===================================================================
+#
+# Unless otherwise specified, all software contained herein is licensed
+# under the Apache License, Version 2.0 (the "License");
+# you may not use this software 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.
+#
+#
+#
+# Unless otherwise specified, all documentation contained herein is licensed
+# under the Creative Commons License, Attribution 4.0 Intl. (the "License");
+# you may not use this documentation except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://creativecommons.org/licenses/by/4.0/
+#
+# Unless required by applicable law or agreed to in writing, documentation
+# 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============================================
+
+import uuid
+from functools import partial
+
+from onap_client import sdc
+from onap_client import config
+from onap_client.sdc.client import SDCClient
+
+PAYLOADS_DIR = config.PAYLOADS_DIR
+sdc_properties = sdc.SDC_PROPERTIES
+application_id = config.APPLICATION_ID
+
+
+class VNFCatalog(SDCClient):
+ @property
+ def catalog_resources(self):
+ return CATALOG_RESOURCES
+
+ @property
+ def namespace(self):
+ return "vnf"
+
+
+CATALOG_RESOURCES = {
+ "ADD_CATALOG_RESOURCE": {
+ "verb": "POST",
+ "description": "Adds a VNF to the SDC catalog",
+ "uri": partial(
+ "{endpoint}{service_path}".format,
+ endpoint=sdc_properties.SDC_BE_ENDPOINT,
+ service_path=sdc_properties.SDC_CATALOG_RESOURCES_PATH,
+ ),
+ "payload": "{}/catalog_resource.jinja".format(PAYLOADS_DIR),
+ "payload-parameters": [
+ "software_product_id",
+ "vnf_name",
+ "vendor_name",
+ "resource_type",
+ ],
+ "success_code": 201,
+ "headers": {
+ "Accept": "application/json",
+ "Content-Type": "application/json",
+ "USER_ID": sdc_properties.SDC_DESIGNER_USER_ID,
+ "X-TransactionId": str(uuid.uuid4()),
+ "X-FromAppId": application_id,
+ },
+ "return_data": {"catalog_resource_id": ("uniqueId",)},
+ "auth": (
+ sdc_properties.GLOBAL_SDC_USERNAME,
+ sdc_properties.GLOBAL_SDC_PASSWORD,
+ ),
+ },
+ "CERTIFY_CATALOG_RESOURCE": {
+ "verb": "POST",
+ "description": "Certifies a VNF in the SDC catalog",
+ "uri": partial(
+ "{endpoint}{service_path}/{catalog_resource_id}/lifecycleState/certify".format,
+ endpoint=sdc_properties.SDC_BE_ENDPOINT,
+ service_path=sdc_properties.SDC_CATALOG_RESOURCES_PATH,
+ ),
+ "uri-parameters": ["catalog_resource_id"],
+ "payload": "{}/user_remarks.jinja".format(PAYLOADS_DIR),
+ "payload-parameters": ["user_remarks"],
+ "success_code": 200,
+ "headers": {
+ "Accept": "application/json",
+ "Content-Type": "application/json",
+ "USER_ID": sdc_properties.SDC_DESIGNER_USER_ID,
+ "X-TransactionId": str(uuid.uuid4()),
+ "X-FromAppId": application_id,
+ },
+ "return_data": {"catalog_resource_id": ("uniqueId",)},
+ "auth": (
+ sdc_properties.GLOBAL_SDC_USERNAME,
+ sdc_properties.GLOBAL_SDC_PASSWORD,
+ ),
+ },
+ "ADD_CATALOG_RESOURCE_INPUT": {
+ "verb": "POST",
+ "description": "Adds an input value for a VNF",
+ "uri": partial(
+ "{endpoint}{service_path}/{catalog_resource_id}/update/inputs".format,
+ endpoint=sdc_properties.SDC_BE_ENDPOINT,
+ service_path=sdc_properties.SDC_CATALOG_RESOURCES_PATH,
+ ),
+ "payload": "{}/catalog_vnf_input.jinja".format(PAYLOADS_DIR),
+ "payload-parameters": [
+ "input_default_value",
+ "input_name",
+ "input_parent_unique_id",
+ "input_unique_id",
+ "input_owner_id",
+ ],
+ "uri-parameters": ["catalog_resource_id"],
+ "success_code": 200,
+ "headers": {
+ "Accept": "application/json",
+ "Content-Type": "application/json",
+ "USER_ID": sdc_properties.SDC_DESIGNER_USER_ID,
+ "X-TransactionId": str(uuid.uuid4()),
+ "X-FromAppId": application_id,
+ },
+ "auth": (
+ sdc_properties.GLOBAL_SDC_USERNAME,
+ sdc_properties.GLOBAL_SDC_PASSWORD,
+ ),
+ },
+ "ADD_CATALOG_RESOURCE_PROPERTY": {
+ "verb": "POST",
+ "description": "Adds an property value for a VNF",
+ "uri": partial(
+ "{endpoint}{service_path}/{catalog_resource_id}/resourceInstance/{catalog_resource_instance_id}/inputs".format,
+ endpoint=sdc_properties.SDC_BE_ENDPOINT,
+ service_path=sdc_properties.SDC_CATALOG_RESOURCES_PATH,
+ ),
+ "payload": "{}/catalog_vnf_property.jinja".format(PAYLOADS_DIR),
+ "payload-parameters": [
+ "unique_id",
+ "parent_unique_id",
+ "owner_id",
+ "property_name",
+ "property_default_value",
+ "schema_type",
+ "property_type",
+ ],
+ "uri-parameters": ["catalog_resource_id", "catalog_resource_instance_id"],
+ "success_code": 200,
+ "headers": {
+ "Accept": "application/json",
+ "Content-Type": "application/json",
+ "USER_ID": sdc_properties.SDC_DESIGNER_USER_ID,
+ "X-TransactionId": str(uuid.uuid4()),
+ "X-FromAppId": application_id,
+ },
+ "auth": (
+ sdc_properties.GLOBAL_SDC_USERNAME,
+ sdc_properties.GLOBAL_SDC_PASSWORD,
+ ),
+ },
+ "ADD_CATALOG_RESOURCE_POLICY": {
+ "verb": "POST",
+ "description": "Adds an policy resource to a VNF",
+ "uri": partial(
+ "{endpoint}{service_path}/{catalog_resource_id}/policies/{catalog_policy_name}".format,
+ endpoint=sdc_properties.SDC_BE_ENDPOINT,
+ service_path=sdc_properties.SDC_CATALOG_RESOURCES_PATH,
+ ),
+ "uri-parameters": ["catalog_resource_id", "catalog_policy_name"],
+ "success_code": 201,
+ "headers": {
+ "Accept": "application/json",
+ "Content-Type": "application/json",
+ "USER_ID": sdc_properties.SDC_DESIGNER_USER_ID,
+ "X-TransactionId": str(uuid.uuid4()),
+ "X-FromAppId": application_id,
+ },
+ "return_data": {"catalog_resource_id": ("uniqueId",)},
+ "auth": (
+ sdc_properties.GLOBAL_SDC_USERNAME,
+ sdc_properties.GLOBAL_SDC_PASSWORD,
+ ),
+ },
+ "ADD_CATALOG_POLICY_PROPERTY": {
+ "verb": "PUT",
+ "description": "Adds a property to a policy for a VNF",
+ "uri": partial(
+ "{endpoint}{service_path}/{catalog_resource_id}/policies/{catalog_policy_id}/properties".format,
+ endpoint=sdc_properties.SDC_BE_ENDPOINT,
+ service_path=sdc_properties.SDC_CATALOG_RESOURCES_PATH,
+ ),
+ "uri-parameters": ["catalog_resource_id", "catalog_policy_id"],
+ "payload": "{}/catalog_vnf_policy_property.jinja".format(PAYLOADS_DIR),
+ "payload-parameters": [
+ "unique_id",
+ "property_name",
+ "property_default_value",
+ "description",
+ "property_type",
+ ],
+ "success_code": 200,
+ "headers": {
+ "Accept": "application/json",
+ "Content-Type": "application/json",
+ "USER_ID": sdc_properties.SDC_DESIGNER_USER_ID,
+ "X-TransactionId": str(uuid.uuid4()),
+ "X-FromAppId": application_id,
+ },
+ "auth": (
+ sdc_properties.GLOBAL_SDC_USERNAME,
+ sdc_properties.GLOBAL_SDC_PASSWORD,
+ ),
+ },
+ "ADD_CATALOG_RESOURCE_GROUP": {
+ "verb": "POST",
+ "description": "Adds an group resource to a VNF",
+ "uri": partial(
+ "{endpoint}{service_path}/{catalog_resource_id}/groups/{catalog_group_name}".format,
+ endpoint=sdc_properties.SDC_BE_ENDPOINT,
+ service_path=sdc_properties.SDC_CATALOG_RESOURCES_PATH,
+ ),
+ "uri-parameters": ["catalog_resource_id", "catalog_group_name"],
+ "success_code": 201,
+ "headers": {
+ "Accept": "application/json",
+ "Content-Type": "application/json",
+ "USER_ID": sdc_properties.SDC_DESIGNER_USER_ID,
+ "X-TransactionId": str(uuid.uuid4()),
+ "X-FromAppId": application_id,
+ },
+ "return_data": {"catalog_resource_id": ("uniqueId",)},
+ "auth": (
+ sdc_properties.GLOBAL_SDC_USERNAME,
+ sdc_properties.GLOBAL_SDC_PASSWORD,
+ ),
+ },
+ "ADD_CATALOG_GROUP_PROPERTY": {
+ "verb": "PUT",
+ "description": "Adds a property to a group for a VNF",
+ "uri": partial(
+ "{endpoint}{service_path}/{catalog_resource_id}/groups/{catalog_group_id}/properties".format,
+ endpoint=sdc_properties.SDC_BE_ENDPOINT,
+ service_path=sdc_properties.SDC_CATALOG_RESOURCES_PATH,
+ ),
+ "uri-parameters": ["catalog_resource_id", "catalog_group_id"],
+ "payload": "{}/catalog_vnf_group_property.jinja".format(PAYLOADS_DIR),
+ "payload-parameters": [
+ "unique_id",
+ "property_name",
+ "property_default_value",
+ "description",
+ "property_type",
+ "owner_id",
+ "parent_unique_id",
+ ],
+ "success_code": 200,
+ "headers": {
+ "Accept": "application/json",
+ "Content-Type": "application/json",
+ "USER_ID": sdc_properties.SDC_DESIGNER_USER_ID,
+ "X-TransactionId": str(uuid.uuid4()),
+ "X-FromAppId": application_id,
+ },
+ "auth": (
+ sdc_properties.GLOBAL_SDC_USERNAME,
+ sdc_properties.GLOBAL_SDC_PASSWORD,
+ ),
+ },
+ "ADD_GROUP_TO_INSTANCE": {
+ "verb": "POST",
+ "description": "Associate a group with a Catalog Instance",
+ "uri": partial(
+ "{endpoint}{service_path}/{catalog_resource_id}/groups/{catalog_group_id}/members".format,
+ endpoint=sdc_properties.SDC_BE_ENDPOINT,
+ service_path=sdc_properties.SDC_CATALOG_RESOURCES_PATH,
+ ),
+ "payload": "{}/catalog_vnf_group.jinja".format(PAYLOADS_DIR),
+ "payload-parameters": ["instance_id"],
+ "uri-parameters": ["catalog_resource_id", "catalog_group_id"],
+ "success_code": 200,
+ "headers": {
+ "Accept": "application/json",
+ "Content-Type": "application/json",
+ "USER_ID": sdc_properties.SDC_DESIGNER_USER_ID,
+ "X-TransactionId": str(uuid.uuid4()),
+ "X-FromAppId": application_id,
+ },
+ "auth": (
+ sdc_properties.GLOBAL_SDC_USERNAME,
+ sdc_properties.GLOBAL_SDC_PASSWORD,
+ ),
+ },
+ "ADD_POLICY_TO_INSTANCE": {
+ "verb": "POST",
+ "description": "Associate a policy with a Catalog Instance",
+ "uri": partial(
+ "{endpoint}{service_path}/{catalog_resource_id}/policies/{catalog_policy_id}/targets".format,
+ endpoint=sdc_properties.SDC_BE_ENDPOINT,
+ service_path=sdc_properties.SDC_CATALOG_RESOURCES_PATH,
+ ),
+ "payload": "{}/catalog_vnf_policy.jinja".format(PAYLOADS_DIR),
+ "payload-parameters": ["instance_ids"],
+ "uri-parameters": ["catalog_resource_id", "catalog_policy_id"],
+ "success_code": 200,
+ "headers": {
+ "Accept": "application/json",
+ "Content-Type": "application/json",
+ "USER_ID": sdc_properties.SDC_DESIGNER_USER_ID,
+ "X-TransactionId": str(uuid.uuid4()),
+ "X-FromAppId": application_id,
+ },
+ "auth": (
+ sdc_properties.GLOBAL_SDC_USERNAME,
+ sdc_properties.GLOBAL_SDC_PASSWORD,
+ ),
+ },
+ "ADD_RESOURCE_INSTANCE": {
+ "verb": "POST",
+ "description": "Attaches a Resource to a VNF",
+ "uri": partial(
+ "{endpoint}{service_path}/{catalog_resource_id}/resourceInstance".format,
+ endpoint=sdc_properties.SDC_BE_ENDPOINT,
+ service_path=sdc_properties.SDC_CATALOG_RESOURCES_PATH,
+ ),
+ "uri-parameters": ["catalog_resource_id"],
+ "payload": "{}/resource_instance_vnf.jinja".format(PAYLOADS_DIR),
+ "payload-parameters": [
+ "milli_timestamp",
+ "new_catalog_resource_id",
+ "new_catalog_resource_name",
+ "originType",
+ "posX",
+ "posY",
+ ],
+ "success_code": 201,
+ "return_data": {"catalog_resource_instance_id": ("uniqueId",)},
+ "headers": {
+ "Accept": "application/json",
+ "Content-Type": "application/json",
+ "USER_ID": sdc_properties.SDC_DESIGNER_USER_ID,
+ "X-TransactionId": str(uuid.uuid4()),
+ "X-FromAppId": application_id,
+ },
+ "auth": (
+ sdc_properties.GLOBAL_SDC_USERNAME,
+ sdc_properties.GLOBAL_SDC_PASSWORD,
+ ),
+ },
+ "GET_CATALOG_RESOURCE": {
+ "verb": "GET",
+ "description": "Gets a VNF in the SDC catalog",
+ "uri": partial(
+ "{endpoint}{service_path}/{catalog_resource_id}".format,
+ endpoint=sdc_properties.SDC_BE_ENDPOINT,
+ service_path=sdc_properties.SDC_CATALOG_RESOURCES_PATH,
+ ),
+ "uri-parameters": ["catalog_resource_id"],
+ "success_code": 200,
+ "headers": {
+ "Accept": "application/json",
+ "Content-Type": "application/json",
+ "USER_ID": sdc_properties.SDC_DESIGNER_USER_ID,
+ "X-TransactionId": str(uuid.uuid4()),
+ "X-FromAppId": application_id,
+ },
+ "return_data": {"catalog_resource_name": ("name",)},
+ "auth": (
+ sdc_properties.GLOBAL_SDC_USERNAME,
+ sdc_properties.GLOBAL_SDC_PASSWORD,
+ ),
+ },
+ "GET_RESOURCES": {
+ "verb": "GET",
+ "description": "Get all resources in the SDC catalog",
+ "uri": partial(
+ "{endpoint}{service_path}".format,
+ endpoint=sdc_properties.SDC_BE_ENDPOINT,
+ service_path=sdc_properties.SDC_SCREEN_PATH,
+ ),
+ "success_code": 200,
+ "headers": {
+ "Accept": "application/json",
+ "Content-Type": "application/json",
+ "USER_ID": sdc_properties.SDC_DESIGNER_USER_ID,
+ "X-TransactionId": str(uuid.uuid4()),
+ "X-FromAppId": application_id,
+ },
+ "return_data": {"resources": ("resources",)},
+ "auth": (
+ sdc_properties.GLOBAL_SDC_USERNAME,
+ sdc_properties.GLOBAL_SDC_PASSWORD,
+ ),
+ },
+}
diff --git a/onap-client/onap_client/sdc/catalog/vsp_catalog.py b/onap-client/onap_client/sdc/catalog/vsp_catalog.py
new file mode 100644
index 0000000..65781a6
--- /dev/null
+++ b/onap-client/onap_client/sdc/catalog/vsp_catalog.py
@@ -0,0 +1,286 @@
+# -*- coding: utf8 -*-
+# ============LICENSE_START=======================================================
+# org.onap.vvp/validation-scripts
+# ===================================================================
+# Copyright © 2020 AT&T Intellectual Property. All rights reserved.
+# ===================================================================
+#
+# Unless otherwise specified, all software contained herein is licensed
+# under the Apache License, Version 2.0 (the "License");
+# you may not use this software 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.
+#
+#
+#
+# Unless otherwise specified, all documentation contained herein is licensed
+# under the Creative Commons License, Attribution 4.0 Intl. (the "License");
+# you may not use this documentation except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://creativecommons.org/licenses/by/4.0/
+#
+# Unless required by applicable law or agreed to in writing, documentation
+# 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============================================
+
+import uuid
+from functools import partial
+
+from onap_client import sdc
+from onap_client import config
+from onap_client.sdc.client import SDCClient
+
+PAYLOADS_DIR = config.PAYLOADS_DIR
+sdc_properties = sdc.SDC_PROPERTIES
+application_id = config.APPLICATION_ID
+
+
+class VSPCatalog(SDCClient):
+ @property
+ def catalog_resources(self):
+ return CATALOG_RESOURCES
+
+ @property
+ def namespace(self):
+ return "vsp"
+
+
+CATALOG_RESOURCES = {
+ "ADD_SOFTWARE_PRODUCT": {
+ "verb": "POST",
+ "description": "Creates a VSP in the SDC catalog",
+ "uri": partial(
+ "{endpoint}{service_path}".format,
+ endpoint=sdc_properties.SDC_BE_ONBOARD_ENDPOINT,
+ service_path=sdc_properties.SDC_VENDOR_SOFTWARE_PRODUCT_PATH,
+ ),
+ "payload": "{}/software_product.jinja".format(PAYLOADS_DIR),
+ "payload-parameters": [
+ "software_product_name",
+ "feature_group_id",
+ "license_agreement_id",
+ "vendor_name",
+ "license_model_id",
+ "license_model_version_id",
+ "description",
+ "category",
+ "sub_category",
+ ],
+ "success_code": 200,
+ "headers": {
+ "Accept": "application/json",
+ "Content-Type": "application/json",
+ "USER_ID": sdc_properties.SDC_DESIGNER_USER_ID,
+ "X-TransactionId": str(uuid.uuid4()),
+ "X-FromAppId": application_id,
+ },
+ "return_data": {
+ "software_product_id": ("itemId",),
+ "software_product_version_id": ("version", "id"),
+ },
+ "auth": (
+ sdc_properties.GLOBAL_SDC_USERNAME,
+ sdc_properties.GLOBAL_SDC_PASSWORD,
+ ),
+ },
+ "UPLOAD_HEAT_PACKAGE": {
+ "verb": "POST",
+ "description": "Uploads a heat zip to a VSP",
+ "uri": partial(
+ "{endpoint}{service_path}/{software_product_id}/versions/{software_product_version_id}/orchestration-template-candidate".format,
+ endpoint=sdc_properties.SDC_BE_ONBOARD_ENDPOINT,
+ service_path=sdc_properties.SDC_VENDOR_SOFTWARE_PRODUCT_PATH,
+ ),
+ "uri-parameters": ["software_product_id", "software_product_version_id"],
+ "files-parameters": ["file_path", "file_type"],
+ "success_code": 200,
+ "headers": {
+ "Accept": "application/json",
+ "Content-Type": "multipart/form-data",
+ "USER_ID": sdc_properties.SDC_DESIGNER_USER_ID,
+ "X-TransactionId": str(uuid.uuid4()),
+ "X-FromAppId": application_id,
+ },
+ "auth": (
+ sdc_properties.GLOBAL_SDC_USERNAME,
+ sdc_properties.GLOBAL_SDC_PASSWORD,
+ ),
+ },
+ "VALIDATE_SOFTWARE_PRODUCT": {
+ "verb": "PUT",
+ "description": "Validates VSP with Heat Zip",
+ "uri": partial(
+ "{endpoint}{service_path}/{software_product_id}/versions/{software_product_version_id}/orchestration-template-candidate/process".format,
+ endpoint=sdc_properties.SDC_BE_ONBOARD_ENDPOINT,
+ service_path=sdc_properties.SDC_VENDOR_SOFTWARE_PRODUCT_PATH,
+ ),
+ "uri-parameters": ["software_product_id", "software_product_version_id"],
+ "success_code": 200,
+ "headers": {
+ "Accept": "application/json",
+ "Content-Type": "application/json",
+ "USER_ID": sdc_properties.SDC_DESIGNER_USER_ID,
+ "X-TransactionId": str(uuid.uuid4()),
+ "X-FromAppId": application_id,
+ },
+ "auth": (
+ sdc_properties.GLOBAL_SDC_USERNAME,
+ sdc_properties.GLOBAL_SDC_PASSWORD,
+ ),
+ },
+ "SUBMIT_SOFTWARE_PRODUCT": {
+ "verb": "PUT",
+ "description": "Submits Heat Zip to VSP",
+ "uri": partial(
+ "{endpoint}{service_path}/{software_product_id}/versions/{software_product_version_id}/actions".format,
+ endpoint=sdc_properties.SDC_BE_ONBOARD_ENDPOINT,
+ service_path=sdc_properties.SDC_VENDOR_SOFTWARE_PRODUCT_PATH,
+ ),
+ "uri-parameters": ["software_product_id", "software_product_version_id"],
+ "payload": "{}/action.jinja".format(PAYLOADS_DIR),
+ "payload-parameters": ["action"],
+ "success_code": 200,
+ "headers": {
+ "Accept": "application/json",
+ "Content-Type": "application/json",
+ "USER_ID": sdc_properties.SDC_DESIGNER_USER_ID,
+ "X-TransactionId": str(uuid.uuid4()),
+ "X-FromAppId": application_id,
+ },
+ "auth": (
+ sdc_properties.GLOBAL_SDC_USERNAME,
+ sdc_properties.GLOBAL_SDC_PASSWORD,
+ ),
+ },
+ "PACKAGE_SOFTWARE_PRODUCT": {
+ "verb": "PUT",
+ "description": "Packages VSP (description needs to be better??)",
+ "uri": partial(
+ "{endpoint}{service_path}/{software_product_id}/versions/{software_product_version_id}/actions".format,
+ endpoint=sdc_properties.SDC_BE_ONBOARD_ENDPOINT,
+ service_path=sdc_properties.SDC_VENDOR_SOFTWARE_PRODUCT_PATH,
+ ),
+ "uri-parameters": ["software_product_id", "software_product_version_id"],
+ "payload": "{}/action.jinja".format(PAYLOADS_DIR),
+ "payload-parameters": ["action"],
+ "success_code": 200,
+ "headers": {
+ "Accept": "application/json",
+ "Content-Type": "application/json",
+ "USER_ID": sdc_properties.SDC_DESIGNER_USER_ID,
+ "X-TransactionId": str(uuid.uuid4()),
+ "X-FromAppId": application_id,
+ },
+ "auth": (
+ sdc_properties.GLOBAL_SDC_USERNAME,
+ sdc_properties.GLOBAL_SDC_PASSWORD,
+ ),
+ },
+ "GET_SOFTWARE_PRODUCT": {
+ "verb": "GET",
+ "description": "Gets VSP from Catalog",
+ "uri": partial(
+ "{endpoint}{service_path}/{software_product_id}/versions/{software_product_version_id}".format,
+ endpoint=sdc_properties.SDC_BE_ONBOARD_ENDPOINT,
+ service_path=sdc_properties.SDC_VENDOR_SOFTWARE_PRODUCT_PATH,
+ ),
+ "uri-parameters": ["software_product_id", "software_product_version_id"],
+ "success_code": 200,
+ "headers": {
+ "Accept": "application/json",
+ "Content-Type": "application/json",
+ "USER_ID": sdc_properties.SDC_DESIGNER_USER_ID,
+ "X-TransactionId": str(uuid.uuid4()),
+ "X-FromAppId": application_id,
+ },
+ "return_data": {"name": ("name",)},
+ "auth": (
+ sdc_properties.GLOBAL_SDC_USERNAME,
+ sdc_properties.GLOBAL_SDC_PASSWORD,
+ ),
+ },
+ "GET_SOFTWARE_PRODUCT_VERSIONS": {
+ "verb": "GET",
+ "description": "Returns a list of vsp versions",
+ "uri": partial(
+ "{endpoint}{service_path}/{software_product_id}/versions".format,
+ endpoint=sdc_properties.SDC_BE_ONBOARD_ENDPOINT,
+ service_path=sdc_properties.SDC_VENDOR_ITEMS_PATH,
+ ),
+ "uri-parameters": ["software_product_id"],
+ "success_code": 200,
+ "headers": {
+ "Accept": "application/json",
+ "Content-Type": "application/json",
+ "USER_ID": sdc_properties.SDC_DESIGNER_USER_ID,
+ "X-TransactionId": str(uuid.uuid4()),
+ "X-FromAppId": application_id,
+ },
+ "return_data": {
+ "software_product_version_id": ("id",),
+ "description": ("description",),
+ },
+ "auth": (
+ sdc_properties.GLOBAL_SDC_USERNAME,
+ sdc_properties.GLOBAL_SDC_PASSWORD,
+ ),
+ },
+ "GET_SOFTWARE_PRODUCTS": {
+ "verb": "GET",
+ "description": "Returns a list of vsps",
+ "uri": partial(
+ "{endpoint}{service_path}?&itemType=vsp".format,
+ endpoint=sdc_properties.SDC_BE_ONBOARD_ENDPOINT,
+ service_path=sdc_properties.SDC_VENDOR_ITEMS_PATH,
+ ),
+ "success_code": 200,
+ "headers": {
+ "Accept": "application/json",
+ "Content-Type": "application/json",
+ "USER_ID": sdc_properties.SDC_DESIGNER_USER_ID,
+ "X-TransactionId": str(uuid.uuid4()),
+ "X-FromAppId": application_id,
+ },
+ "return_data": {"results": ("results",)},
+ "auth": (
+ sdc_properties.GLOBAL_SDC_USERNAME,
+ sdc_properties.GLOBAL_SDC_PASSWORD,
+ ),
+ },
+ "ADD_VSP_CONTRIBUTER": {
+ "verb": "PUT",
+ "description": "Adds a user to a VSP as a contributer",
+ "uri": partial(
+ "{endpoint}{service_path}/{software_product_id}/permissions/Contributor".format,
+ endpoint=sdc_properties.SDC_BE_ONBOARD_ENDPOINT,
+ service_path=sdc_properties.SDC_VENDOR_ITEMS_PATH,
+ ),
+ "uri-parameters": ["software_product_id"],
+ "payload": "{}/add_vsp_contributer.jinja".format(PAYLOADS_DIR),
+ "payload-parameters": ["user_id"],
+ "success_code": 200,
+ "headers": {
+ "Accept": "application/json",
+ "Content-Type": "application/json",
+ "USER_ID": sdc_properties.SDC_DESIGNER_USER_ID,
+ "X-TransactionId": str(uuid.uuid4()),
+ "X-FromAppId": application_id,
+ },
+ "auth": (
+ sdc_properties.GLOBAL_SDC_USERNAME,
+ sdc_properties.GLOBAL_SDC_PASSWORD,
+ ),
+ },
+}
diff --git a/onap-client/onap_client/sdc/client.py b/onap-client/onap_client/sdc/client.py
new file mode 100644
index 0000000..8863e07
--- /dev/null
+++ b/onap-client/onap_client/sdc/client.py
@@ -0,0 +1,81 @@
+# -*- coding: utf8 -*-
+# ============LICENSE_START=======================================================
+# org.onap.vvp/validation-scripts
+# ===================================================================
+# Copyright © 2020 AT&T Intellectual Property. All rights reserved.
+# ===================================================================
+#
+# Unless otherwise specified, all software contained herein is licensed
+# under the Apache License, Version 2.0 (the "License");
+# you may not use this software 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.
+#
+#
+#
+# Unless otherwise specified, all documentation contained herein is licensed
+# under the Creative Commons License, Attribution 4.0 Intl. (the "License");
+# you may not use this documentation except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://creativecommons.org/licenses/by/4.0/
+#
+# Unless required by applicable law or agreed to in writing, documentation
+# 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============================================
+
+import uuid
+
+from functools import partial
+from onap_client import sdc
+from onap_client.client.clients import Client
+from onap_client import config
+
+sdc_properties = sdc.SDC_PROPERTIES
+application_id = config.APPLICATION_ID
+
+
+class SDCClient(Client):
+ @property
+ def namespace(self):
+ return "sdc"
+
+ @property
+ def catalog_resources(self):
+ return CATALOG_RESOURCES
+
+
+CATALOG_RESOURCES = {
+ "HEALTH_CHECK": {
+ "verb": "GET",
+ "description": "Queries SDC health check endpoint",
+ "uri": partial(
+ "{endpoint}{service_path}".format,
+ endpoint=sdc_properties.SDC_HC_ENDPOINT,
+ service_path=sdc_properties.SDC_HEALTH_CHECK_PATH,
+ ),
+ "success_code": 200,
+ "headers": {
+ "Accept": "application/json",
+ "Content-Type": "application/json",
+ "USER_ID": sdc_properties.SDC_DESIGNER_USER_ID,
+ "X-TransactionId": str(uuid.uuid4()),
+ "X-FromAppId": application_id,
+ },
+ "auth": (
+ sdc_properties.SDC_DESIGNER_USER_ID,
+ sdc_properties.SDC_DESIGNER_PASSWORD,
+ ),
+ },
+}
diff --git a/onap-client/onap_client/sdc/license_model.py b/onap-client/onap_client/sdc/license_model.py
new file mode 100644
index 0000000..e5ae740
--- /dev/null
+++ b/onap-client/onap_client/sdc/license_model.py
@@ -0,0 +1,218 @@
+# -*- coding: utf8 -*-
+# ============LICENSE_START=======================================================
+# org.onap.vvp/validation-scripts
+# ===================================================================
+# Copyright © 2020 AT&T Intellectual Property. All rights reserved.
+# ===================================================================
+#
+# Unless otherwise specified, all software contained herein is licensed
+# under the Apache License, Version 2.0 (the "License");
+# you may not use this software 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.
+#
+#
+#
+# Unless otherwise specified, all documentation contained herein is licensed
+# under the Creative Commons License, Attribution 4.0 Intl. (the "License");
+# you may not use this documentation except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://creativecommons.org/licenses/by/4.0/
+#
+# Unless required by applicable law or agreed to in writing, documentation
+# 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============================================
+
+from onap_client.lib import generate_dummy_string, generate_dummy_date
+from onap_client.resource import Resource
+from onap_client.client.clients import Client as SDCClient
+
+license_model_client = SDCClient().sdc.license_model
+
+
+class LicenseModel(Resource):
+ resource_name = "LICENSE_MODEL"
+ spec = {
+ "vendor_name": {
+ "type": str,
+ "required": False,
+ "default": generate_dummy_string("test_vendor_"),
+ },
+ "mfr_ref_number": {
+ "type": str,
+ "required": False,
+ "default": generate_dummy_string("mfref"),
+ },
+ "entitlement_pool_name": {
+ "type": str,
+ "required": False,
+ "default": generate_dummy_string("test_kg_"),
+ },
+ "key_group_name": {
+ "type": str,
+ "required": False,
+ "default": generate_dummy_string("test_ep_"),
+ },
+ "feature_group_name": {
+ "type": str,
+ "required": False,
+ "default": generate_dummy_string("test_fg_"),
+ },
+ "license_agreement_name": {
+ "type": str,
+ "required": False,
+ "default": generate_dummy_string("test_la_"),
+ },
+ "license_start_date": {
+ "type": str,
+ "required": False,
+ "default": generate_dummy_date(days=1),
+ },
+ "license_end_date": {
+ "type": str,
+ "required": False,
+ "default": generate_dummy_date(days=365),
+ },
+ }
+
+ def __init__(
+ self,
+ vendor_name,
+ mfr_ref_number,
+ entitlement_pool_name,
+ key_group_name,
+ feature_group_name,
+ license_agreement_name,
+ license_start_date,
+ license_end_date,
+ ):
+
+ license_input = {}
+ license_input["vendor_name"] = vendor_name
+ license_input["manufacturer_reference_number"] = mfr_ref_number
+ license_input["entitlement_pool_name"] = entitlement_pool_name
+ license_input["key_group_name"] = key_group_name
+ license_input["feature_group_name"] = feature_group_name
+ license_input["license_agreement_name"] = license_agreement_name
+ license_input["license_start_date"] = license_start_date
+ license_input["license_end_date"] = license_end_date
+
+ super().__init__(license_input)
+
+ def _create(self, license_input):
+ """Creates a license model object in SDC"""
+ return create_license_model(license_input)
+
+ def _post_create(self):
+ pass
+
+ def _submit(self):
+ """Submits the license model in SDC"""
+
+ license_model_client.submit_license_model(**self.attributes, action="Submit")
+
+ license_model = license_model_client.get_license_model(**self.attributes)
+ self.attributes["tosca"] = license_model.response_data
+
+
+# TODO
+# Break this up into class funcs?
+def create_license_model(license_input):
+ """Creates a license model object in SDC
+
+ :license_input: dictionary with values to input for lm creation
+
+ :return: dictionary of updated values for created lm
+ """
+ kwargs = license_input
+ license_model = license_model_client.add_license_model(**kwargs)
+
+ kwargs["license_model_id"] = license_model.license_model_id
+ kwargs["license_model_version_id"] = license_model.license_model_version_id
+
+ key_group = license_model_client.add_key_group(**kwargs)
+ key_group_id = key_group.key_group_id
+
+ entitlement_pool = license_model_client.add_entitlement_pool(**kwargs)
+ entitlement_pool_id = entitlement_pool.entitlement_pool_id
+
+ kwargs["entitlement_pool_id"] = entitlement_pool_id
+ kwargs["key_group_id"] = key_group_id
+
+ feature_group = license_model_client.add_feature_group(**kwargs)
+ feature_group_id = feature_group.feature_group_id
+
+ kwargs["feature_group_id"] = feature_group_id
+
+ license_agreement = license_model_client.add_license_agreement(**kwargs)
+ kwargs["license_agreement_id"] = license_agreement.license_agreement_id
+
+ license_model = license_model_client.get_license_model(**kwargs)
+ kwargs["tosca"] = license_model.response_data
+
+ return kwargs
+
+
+def get_license_model_id(license_model_name):
+ """GETs license model UUID from SDC
+
+ :license_model_name: name of license model in SDC
+
+ :return: uuid of lm or None
+ """
+ response = license_model_client.get_license_models()
+ results = response.response_data.get("results")
+ for license_model in results:
+ if license_model.get("name") == license_model_name:
+ return license_model.get("id")
+ return None
+
+
+def get_license_model_version_id(license_model_id):
+ """GETs license model version UUID from SDC
+
+ :license_model_id: uuid of license model in SDC
+
+ :return: uuid of lm version id or None
+ """
+ license_model_version_id = None
+ creation_time = -1
+ response = license_model_client.get_license_model_versions(
+ license_model_id=license_model_id
+ )
+ results = response.response_data.get("results")
+ for version in results:
+ if version.get("creationTime", 0) > creation_time:
+ creation_time = version.get("creationTime")
+ license_model_version_id = version.get("id")
+
+ return license_model_version_id
+
+
+def get_license_model_attribute(license_model_id, license_model_version_id, attribute):
+ """GETs license model attribute from SDC
+
+ :license_model_id: uuid of license model in SDC
+ :license_model_version_id: uuid of license model version in SDC
+ :attribute: attribute to GET (license-agreements, feature-groups, entitlement-pools, license-key-groups)
+
+ :return: uuid of attribute of license-model
+ """
+ response = license_model_client.get_license_model_version_attribute(
+ license_model_id=license_model_id,
+ license_model_version_id=license_model_version_id,
+ attribute=attribute,
+ )
+ return response.response_data.get("results")[0]
diff --git a/onap-client/onap_client/sdc/service.py b/onap-client/onap_client/sdc/service.py
new file mode 100644
index 0000000..4e3dd03
--- /dev/null
+++ b/onap-client/onap_client/sdc/service.py
@@ -0,0 +1,426 @@
+# -*- coding: utf8 -*-
+# ============LICENSE_START=======================================================
+# org.onap.vvp/validation-scripts
+# ===================================================================
+# Copyright © 2020 AT&T Intellectual Property. All rights reserved.
+# ===================================================================
+#
+# Unless otherwise specified, all software contained herein is licensed
+# under the Apache License, Version 2.0 (the "License");
+# you may not use this software 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.
+#
+#
+#
+# Unless otherwise specified, all documentation contained herein is licensed
+# under the Creative Commons License, Attribution 4.0 Intl. (the "License");
+# you may not use this documentation except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://creativecommons.org/licenses/by/4.0/
+#
+# Unless required by applicable law or agreed to in writing, documentation
+# 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============================================
+
+from onap_client.lib import generate_dummy_string
+from onap_client.resource import Resource
+from onap_client import exceptions
+from onap_client.client.clients import Client as SDCClient
+from onap_client.sdc.vnf import get_vnf_id
+from onap_client import sdc
+from onap_client.sdc import SDC_PROPERTIES
+from onap_client.util import utility
+
+import time
+import json
+import random
+
+service_client = SDCClient().sdc.service
+sdc_properties = sdc.SDC_PROPERTIES
+
+
+def normalize_category_icon(category_name):
+ if category_name == "Network L1-3":
+ return "network_l_4"
+ elif category_name == "Mobility":
+ return "mobility"
+ elif category_name == "E2E Service":
+ return "network_l_1-3"
+ elif category_name == "Network L1-3":
+ return "network_l_1-3"
+ elif category_name == "Network Service":
+ return "network_l_1-3"
+ elif category_name == "Network 4+":
+ return "network_l_4"
+ elif category_name == "VoIP Call Control":
+ return "call_controll"
+ else:
+ return "network_l_1-3"
+
+
+class Service(Resource):
+ resource_name = "SERVICE"
+ spec = {
+ "instantiation_type": {
+ "type": str,
+ "required": False,
+ "default": "A-la-carte",
+ },
+ "service_name": {
+ "type": str,
+ "required": False,
+ "default": generate_dummy_string("test_service_"),
+ },
+ "contact_id": {"type": str, "required": False, "default": "cs0008"},
+ "category_name": {"type": str, "required": False, "default": "Network L1-3"},
+ "tag": {"type": str, "required": False, "default": "robot-ete"},
+ "project_code": {"type": str, "required": False, "default": "123456"},
+ "environment_context": {
+ "type": str,
+ "required": False,
+ "default": "General_Revenue-Bearing",
+ },
+ "ecomp_generated_naming": {"type": str, "required": False, "default": "true"},
+ "description": {
+ "type": str,
+ "required": False,
+ "default": "Brand New Service",
+ },
+ "service_type": {"type": str, "required": False, "default": ""},
+ "service_role": {"type": str, "required": False, "default": ""},
+ "naming_policy": {"type": str, "required": False, "default": ""},
+ "resources": {
+ "type": list,
+ "list_item": dict,
+ "required": False,
+ "default": [],
+ "nested": {
+ "resource_name": {"type": str, "required": True},
+ "resource_id": {"type": str, "required": False},
+ "catalog_resource_name": {"type": str, "required": False},
+ "origin_type": {"type": str, "required": False, "default": "VF"},
+ "properties": {"type": dict, "required": False, "default": {}},
+ },
+ },
+ "wait_for_distribution": {"type": bool, "required": False, "default": False},
+ }
+
+ def __init__(
+ self,
+ instantiation_type,
+ service_name,
+ contact_id,
+ category_name,
+ tag,
+ project_code,
+ environment_context,
+ ecomp_generated_naming,
+ description,
+ service_type,
+ service_role,
+ naming_policy,
+ resources=[],
+ wait_for_distribution=False,
+ ):
+ service_input = {}
+
+ category_name_lower = category_name.lower()
+ category_name_icon = normalize_category_icon(category_name)
+ category_id = "serviceNewCategory.{}".format(category_name_lower)
+
+ service_input["service_name"] = service_name
+ service_input["instantiation_type"] = instantiation_type
+ service_input["contact_id"] = contact_id
+ service_input["category_name"] = category_name
+ service_input["category_id"] = category_id
+ service_input["category_name_lower"] = category_name_lower
+ service_input["category_name_icon"] = category_name_icon
+ service_input["tag"] = tag
+ service_input["project_code"] = project_code
+ service_input["environment_context"] = environment_context
+ service_input["ecomp_generated_naming"] = ecomp_generated_naming
+ service_input["description"] = description
+ service_input["service_type"] = service_type
+ service_input["service_role"] = service_role
+ service_input["naming_policy"] = naming_policy
+ service_input["resources"] = resources
+ service_input["wait_for_distribution"] = wait_for_distribution
+
+ super().__init__(service_input)
+
+ def _create(self, service_input):
+ """Creates a service object in SDC"""
+ service = None
+
+ if get_service_id(service_input.get("service_name")) is None:
+ service = create_service(service_input)
+ else:
+ raise exceptions.ResourceAlreadyExistsException(
+ "Service resource {} already exists".format(
+ service_input.get("service_name")
+ )
+ )
+
+ return service
+
+ def _post_create(self):
+ resources = self.resources
+
+ for resource in resources:
+ resource_name = resource.get("resource_name")
+ catalog_resource_name = resource.get("catalog_resource_name")
+ resource_id = resource.get("resource_id")
+ resource_properties = resource.get("properties")
+ if not resource_id:
+ resource_id = get_vnf_id(catalog_resource_name)
+ if not resource_id:
+ raise exceptions.ResourceIDNotFoundException(
+ "resource ID was not passed, and resource lookup by name was not found {}".format(
+ resource_name
+ )
+ )
+ resource_origin = resource.get("origin_type")
+ self.add_resource(resource_id, resource_name, origin_type=resource_origin)
+ for k, v in resource_properties.items():
+ if isinstance(v, dict):
+ v = json.dumps(v).replace('"', '\\"')
+ self.add_property_value(resource_name, k, v)
+
+ def _submit(self):
+ """Submits the service in SDC and distributes the model"""
+ DISTRIBUTION_STEPS = sdc_properties.SERVICE_DISTRIBUTION or []
+
+ service_client.checkin_service(**self.attributes, user_remarks="checking in")
+
+ if (
+ not DISTRIBUTION_STEPS
+ or "request_service_certification" in DISTRIBUTION_STEPS
+ ):
+ service_client.request_service_certification(
+ **self.attributes, user_remarks="requesting certification"
+ )
+
+ if (
+ not DISTRIBUTION_STEPS
+ or "start_service_certification" in DISTRIBUTION_STEPS
+ ):
+ service_client.start_service_certification(
+ **self.attributes, user_remarks="certifying"
+ )
+
+ if (
+ not DISTRIBUTION_STEPS
+ or "finish_service_certification" in DISTRIBUTION_STEPS
+ ):
+ catalog_service = service_client.finish_service_certification(
+ **self.attributes, user_remarks="certified"
+ )
+ self.attributes["catalog_service_id"] = catalog_service.catalog_service_id
+
+ if (
+ not DISTRIBUTION_STEPS
+ or "approve_service_certification" in DISTRIBUTION_STEPS
+ ):
+ service_client.approve_service_certification(
+ **self.attributes, user_remarks="approved"
+ )
+
+ service_client.distribute_sdc_service(**self.attributes)
+
+ if self.wait_for_distribution:
+ poll_distribution(self.service_name)
+
+ self._refresh()
+
+ def add_resource(
+ self, catalog_resource_id, catalog_resource_name, origin_type="VF"
+ ):
+ """Attaches a resource to a Service in SDC
+
+ :catalog_resource_id: ID of a resource in the SDC catalog
+ :catalog_resource_name: name to give to the resource when attaching to service
+ :origin_type: specifies the origin of the attached resource
+
+ """
+ milli_timestamp = int(time.time() * 1000)
+
+ resource_instance = service_client.add_resource_instance(
+ **self.attributes,
+ posX=random.randrange(150, 550), # nosec
+ posY=random.randrange(150, 450), # nosec
+ milli_timestamp=milli_timestamp,
+ catalog_resource_id=catalog_resource_id,
+ catalog_resource_name=catalog_resource_name,
+ originType=origin_type,
+ )
+
+ response = {
+ "id": resource_instance.catalog_resource_instance_id,
+ "tosca": resource_instance.response_data,
+ }
+ self.attributes[catalog_resource_name] = response
+
+ self._refresh()
+
+ def add_property_value(self, resource_name, property_name, input_value):
+ """Updates an property value on a resource attached to a Service
+
+ :resource_name: Name of a resource attached to a service
+ :property_name: property name to update
+ :input_value: value to update property with
+
+ """
+ resource = self.attributes.get(resource_name)
+ if not resource:
+ raise exceptions.ResourceNotFoundException(
+ "Resource {} was not found on Service {}".format(
+ resource_name, self.service_name
+ )
+ )
+ resource_id = resource["id"]
+
+ instance_inputs = self.tosca.get("componentInstancesProperties", {}).get(
+ resource_id, []
+ )
+ for prop in instance_inputs:
+ if prop.get("name") == property_name:
+ unique_id = prop.get("uniqueId")
+ parent_unique_id = prop.get("parentUniqueId")
+ owner_id = prop.get("ownerId")
+ schemaType = prop.get("schemaType", "")
+ property_type = prop.get("type")
+ return service_client.add_catalog_service_property(
+ **self.attributes,
+ unique_id=unique_id,
+ parent_unique_id=parent_unique_id,
+ owner_id=owner_id,
+ catalog_resource_instance_id=resource_id,
+ input_name=property_name,
+ input_value=input_value,
+ schema_type=schemaType,
+ property_type=property_type,
+ )
+
+ raise exceptions.PropertyNotFoundException(
+ "Property {} was not found in VF Instance {}".format(
+ property_name, resource_id
+ )
+ )
+
+ def _refresh(self):
+ self.tosca = service_client.get_sdc_service(
+ catalog_service_id=self.catalog_service_id
+ ).response_data
+
+
+def create_service(service_input):
+ """Creates a service object in SDC
+
+ :service_input: dictionary with values to input for service creation
+
+ :return: dictionary of updated values for created service
+ """
+ kwargs = service_input
+
+ service = service_client.add_catalog_service(**kwargs)
+
+ kwargs["catalog_service_id"] = service.catalog_service_id
+ kwargs["tosca"] = service.response_data
+
+ return kwargs
+
+
+@utility
+def get_service(service_name):
+ """Queries SDC for the TOSCA model for a service"""
+ return service_client.get_sdc_service(
+ catalog_service_id=get_service_id(service_name)
+ ).response_data
+
+
+@utility
+def get_service_id(service_name):
+ """Queries SDC for the uniqueId of a service model"""
+ response = service_client.get_services()
+ results = response.response_data.get("services", [])
+ for service in results:
+ if service.get("name") == service_name:
+ return service["uniqueId"]
+ return None
+
+
+def get_service_uuid(service_name):
+ return get_service(service_name).get("uuid")
+
+
+def get_service_distribution(service_name):
+ distribution_id = get_distribution_id(service_name)
+
+ if distribution_id:
+ return service_client.get_service_distribution_details(
+ distribution_id=distribution_id
+ ).response_data
+
+ return None
+
+
+def get_distribution_id(service_name):
+ distribution = service_client.get_service_distribution(
+ distribution_service_id=get_service_uuid(service_name)
+ ).response_data
+ if distribution:
+ details = distribution.get("distributionStatusOfServiceList", [])
+ for entry in details:
+ return entry.get("distributionID")
+
+ return None
+
+
+@utility
+def poll_distribution(service_name):
+ """Polls a distributed service until distribution is complete"""
+ poll_interval = SDC_PROPERTIES.POLL_INTERVAL or 30
+ x = 0
+ while x < 30:
+ distribution = get_service_distribution(service_name)
+ if not distribution:
+ raise exceptions.DistributionNotFound(
+ "Could not determine distribution status for {}".format(service_name)
+ )
+ distribution_list = distribution.get("distributionStatusList")
+ for component in distribution_list:
+ status = component.get("status")
+ component_name = component.get("omfComponentID")
+ if status == "DISTRIBUTION_COMPLETE_ERROR":
+ raise exceptions.DistributionFailure(
+ "Distribution failure for service {}, component details {}".format(
+ service_name, component
+ )
+ )
+ elif status == "COMPONENT_DONE_ERROR" and component_name == "aai-ml":
+ raise exceptions.DistributionFailure(
+ "Distribution failure for service {}, component details {}".format(
+ service_name, component
+ )
+ )
+ elif status == "DISTRIBUTION_COMPLETE_OK":
+ return "Distribution Successful"
+ x += 1
+ time.sleep(poll_interval)
+
+ raise exceptions.DistributionTimeout(
+ "Distribution polling timed out waiting for {}".format(service_name)
+ )
diff --git a/onap-client/onap_client/sdc/tests/__init__.py b/onap-client/onap_client/sdc/tests/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/onap-client/onap_client/sdc/tests/__init__.py
diff --git a/onap-client/onap_client/sdc/tests/test.zip b/onap-client/onap_client/sdc/tests/test.zip
new file mode 100644
index 0000000..37b2ed1
--- /dev/null
+++ b/onap-client/onap_client/sdc/tests/test.zip
Binary files differ
diff --git a/onap-client/onap_client/sdc/tests/test_license_model.py b/onap-client/onap_client/sdc/tests/test_license_model.py
new file mode 100644
index 0000000..459c2e0
--- /dev/null
+++ b/onap-client/onap_client/sdc/tests/test_license_model.py
@@ -0,0 +1,125 @@
+# -*- coding: utf8 -*-
+# ============LICENSE_START=======================================================
+# org.onap.vvp/validation-scripts
+# ===================================================================
+# Copyright © 2020 AT&T Intellectual Property. All rights reserved.
+# ===================================================================
+#
+# Unless otherwise specified, all software contained herein is licensed
+# under the Apache License, Version 2.0 (the "License");
+# you may not use this software 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.
+#
+#
+#
+# Unless otherwise specified, all documentation contained herein is licensed
+# under the Creative Commons License, Attribution 4.0 Intl. (the "License");
+# you may not use this documentation except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://creativecommons.org/licenses/by/4.0/
+#
+# Unless required by applicable law or agreed to in writing, documentation
+# 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============================================
+
+import responses
+from onap_client.client.clients import Client
+from onap_client.sdc.license_model import LicenseModel
+from onap_client.tests.utils import mockup_client, mockup_catalog_item
+
+license_model_client = Client().sdc.license_model
+
+
+@responses.activate
+def test_license_model_create():
+ LICENSE_MODEL_ID = "license_model_id"
+ LICENSE_MODEL_VERSION_ID = "license_model_version_id"
+ FEATURE_GROUP_ID = "feature_group_id"
+ KEYGROUP_ID = "key_group_id"
+ ENTITLEMENT_POOL_ID = "entitlement_pool_id"
+ LICENSE_AGREEMENT_ID = "license_agreement_id"
+ VENDOR_NAME = "vendor_name"
+ ID = "id"
+ DESCRIPTION = "description"
+
+ mockup_catalog_item(
+ license_model_client.catalog_items["ADD_LICENSE_MODEL"],
+ override_return_data={
+ "itemId": LICENSE_MODEL_ID,
+ "version": {"id": LICENSE_MODEL_VERSION_ID},
+ },
+ )
+
+ mockup_catalog_item(
+ license_model_client.catalog_items["ADD_KEY_GROUP"],
+ override_return_data={"value": KEYGROUP_ID},
+ override_uri_params={
+ "license_model_id": LICENSE_MODEL_ID,
+ "license_model_version_id": LICENSE_MODEL_VERSION_ID,
+ },
+ )
+
+ mockup_catalog_item(
+ license_model_client.catalog_items["ADD_ENTITLEMENT_POOL"],
+ override_return_data={"value": ENTITLEMENT_POOL_ID},
+ override_uri_params={
+ "license_model_id": LICENSE_MODEL_ID,
+ "license_model_version_id": LICENSE_MODEL_VERSION_ID,
+ },
+ )
+
+ mockup_catalog_item(
+ license_model_client.catalog_items["ADD_FEATURE_GROUP"],
+ override_return_data={"value": FEATURE_GROUP_ID},
+ override_uri_params={
+ "license_model_id": LICENSE_MODEL_ID,
+ "license_model_version_id": LICENSE_MODEL_VERSION_ID,
+ },
+ )
+
+ mockup_catalog_item(
+ license_model_client.catalog_items["ADD_LICENSE_AGREEMENT"],
+ override_return_data={"value": LICENSE_AGREEMENT_ID},
+ override_uri_params={
+ "license_model_id": LICENSE_MODEL_ID,
+ "license_model_version_id": LICENSE_MODEL_VERSION_ID,
+ },
+ )
+
+ return_data = {"vendorName": VENDOR_NAME, "id": ID, "description": DESCRIPTION}
+ mockup_catalog_item(
+ license_model_client.catalog_items["GET_LICENSE_MODEL"],
+ override_return_data=return_data,
+ override_uri_params={
+ "license_model_id": LICENSE_MODEL_ID,
+ "license_model_version_id": LICENSE_MODEL_VERSION_ID,
+ },
+ )
+
+ mockup_client(license_model_client)
+
+ lm = LicenseModel(
+ VENDOR_NAME,
+ "abc123",
+ "entitlement_pool_name",
+ "key_group_name",
+ "feature_group_name",
+ "license_agreement_name",
+ "license_start_date",
+ "license_end_date",
+ )
+
+ assert lm.tosca == return_data
diff --git a/onap-client/onap_client/sdc/tests/test_sdc_client.py b/onap-client/onap_client/sdc/tests/test_sdc_client.py
new file mode 100644
index 0000000..c4188a9
--- /dev/null
+++ b/onap-client/onap_client/sdc/tests/test_sdc_client.py
@@ -0,0 +1,68 @@
+# -*- coding: utf8 -*-
+# ============LICENSE_START=======================================================
+# org.onap.vvp/validation-scripts
+# ===================================================================
+# Copyright © 2020 AT&T Intellectual Property. All rights reserved.
+# ===================================================================
+#
+# Unless otherwise specified, all software contained herein is licensed
+# under the Apache License, Version 2.0 (the "License");
+# you may not use this software 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.
+#
+#
+#
+# Unless otherwise specified, all documentation contained herein is licensed
+# under the Creative Commons License, Attribution 4.0 Intl. (the "License");
+# you may not use this documentation except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://creativecommons.org/licenses/by/4.0/
+#
+# Unless required by applicable law or agreed to in writing, documentation
+# 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============================================
+
+from onap_client.client.clients import Client
+
+
+def test_sdc_client():
+ c = Client()
+
+ assert hasattr(c, "sdc")
+
+
+def test_license_model_client():
+ c = Client().sdc
+
+ assert hasattr(c, "license_model")
+
+
+def test_vsp_client():
+ c = Client().sdc
+
+ assert hasattr(c, "vsp")
+
+
+def test_vnf_client():
+ c = Client().sdc
+
+ assert hasattr(c, "vnf")
+
+
+def test_service_client():
+ c = Client().sdc
+
+ assert hasattr(c, "service")
diff --git a/onap-client/onap_client/sdc/tests/test_vnf.py b/onap-client/onap_client/sdc/tests/test_vnf.py
new file mode 100644
index 0000000..025a2d8
--- /dev/null
+++ b/onap-client/onap_client/sdc/tests/test_vnf.py
@@ -0,0 +1,172 @@
+# -*- coding: utf8 -*-
+# ============LICENSE_START=======================================================
+# org.onap.vvp/validation-scripts
+# ===================================================================
+# Copyright © 2020 AT&T Intellectual Property. All rights reserved.
+# ===================================================================
+#
+# Unless otherwise specified, all software contained herein is licensed
+# under the Apache License, Version 2.0 (the "License");
+# you may not use this software 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.
+#
+#
+#
+# Unless otherwise specified, all documentation contained herein is licensed
+# under the Creative Commons License, Attribution 4.0 Intl. (the "License");
+# you may not use this documentation except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://creativecommons.org/licenses/by/4.0/
+#
+# Unless required by applicable law or agreed to in writing, documentation
+# 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============================================
+
+import responses
+from onap_client.tests.utils import mockup_client, mockup_catalog_item
+from onap_client.client.clients import Client
+from onap_client.sdc.vnf import VNF
+from onap_client.sdc.vnf import (
+ instance_ids_for_property,
+ network_role_property_for_instance,
+)
+
+vnf_client = Client().sdc.vnf
+vsp_client = Client().sdc.vsp
+
+
+@responses.activate
+def test_vnf_create():
+ SOFTWARE_PRODUCT_NAME = "software_product_name"
+ SOFTWARE_PRODUCT_ID = "software_product_id"
+ SOFTWARE_PRODUCT_VERSION_ID = "software_product_version_id"
+ VNF_NAME = "vnf_name"
+ RESOURCE_TYPE = "VF"
+ CATALOG_RESOURCE_ID = "catalog_resource_id"
+
+ return_data = {
+ "uniqueId": CATALOG_RESOURCE_ID,
+ "componentInstancesInputs": {
+ "instance_id1": [
+ {"name": "vm_type_tag", "value": "red"},
+ {"name": "nf_role", "value": "dfankafd"},
+ ]
+ },
+ "name": VNF_NAME,
+ }
+ mockup_catalog_item(
+ vsp_client.catalog_items["GET_SOFTWARE_PRODUCTS"],
+ override_return_data={
+ "results": [{"name": SOFTWARE_PRODUCT_NAME, "id": SOFTWARE_PRODUCT_ID}]
+ },
+ )
+ mockup_catalog_item(
+ vsp_client.catalog_items["GET_SOFTWARE_PRODUCT_VERSIONS"],
+ override_return_data={
+ "results": [
+ {"name": SOFTWARE_PRODUCT_NAME, "id": SOFTWARE_PRODUCT_VERSION_ID}
+ ]
+ },
+ override_uri_params={"software_product_id": SOFTWARE_PRODUCT_ID},
+ )
+ mockup_catalog_item(
+ vsp_client.catalog_items["GET_SOFTWARE_PRODUCT"],
+ override_return_data={"vendorName": "vendor_name"},
+ override_uri_params={
+ "software_product_id": SOFTWARE_PRODUCT_ID,
+ "software_product_version_id": SOFTWARE_PRODUCT_VERSION_ID,
+ },
+ )
+ mockup_catalog_item(
+ vnf_client.catalog_items["GET_RESOURCES"],
+ override_return_data={"resources": []},
+ )
+ mockup_catalog_item(
+ vnf_client.catalog_items["ADD_CATALOG_RESOURCE"],
+ override_return_data=return_data,
+ )
+ mockup_catalog_item(
+ vnf_client.catalog_items["GET_CATALOG_RESOURCE"],
+ override_return_data=return_data,
+ override_uri_params={"catalog_resource_id": CATALOG_RESOURCE_ID},
+ )
+ mockup_catalog_item(
+ vnf_client.catalog_items["CERTIFY_CATALOG_RESOURCE"],
+ override_return_data=return_data,
+ override_uri_params={"catalog_resource_id": CATALOG_RESOURCE_ID},
+ )
+ mockup_catalog_item(
+ vnf_client.catalog_items["ADD_CATALOG_RESOURCE_PROPERTY"],
+ override_uri_params={
+ "catalog_resource_id": CATALOG_RESOURCE_ID,
+ "catalog_resource_instance_id": "instance_id1",
+ },
+ )
+
+ mockup_client(vnf_client)
+
+ vnf = VNF(
+ SOFTWARE_PRODUCT_NAME,
+ VNF_NAME,
+ RESOURCE_TYPE,
+ vm_types=[{"vm_type": "red", "properties": {"nf_role": "blue"}}],
+ )
+
+ vnf._submit()
+
+ assert "catalog_resource_name" in vnf.tosca
+
+
+def test_instance_ids_for_property():
+ vnf_model = {
+ "componentInstancesInputs": {
+ "item1id": [
+ {"name": "vm_type", "value": "db"},
+ {"name": "otherprop", "value": "otherval"},
+ ],
+ "item2id": [
+ {"name": "vm_type", "value": "db"},
+ {"name": "otherprop", "value": "otherval"},
+ ],
+ }
+ }
+
+ ids = instance_ids_for_property(vnf_model, "vm_type", "db")
+
+ assert "item1id" in ids and "item2id" in ids
+
+
+def test_network_role_property_for_instance():
+ vnf_model = {
+ "componentInstancesInputs": {
+ "item1id": [
+ {"name": "vm_type", "value": "db"},
+ {"name": "item1id.port123.oam.network_role_tag", "value": "oam"},
+ {
+ "name": "item1id.port123.oam.network_role",
+ "value": "ACTUALNETWORKROLE",
+ },
+ ],
+ "item2id": [
+ {"name": "vm_type", "value": "db"},
+ {"name": "otherprop", "value": "otherval"},
+ ],
+ }
+ }
+
+ prop = network_role_property_for_instance("oam", vnf_model, "item1id")
+
+ assert prop == "item1id.port123.oam.network_role"
diff --git a/onap-client/onap_client/sdc/tests/test_vsp.py b/onap-client/onap_client/sdc/tests/test_vsp.py
new file mode 100644
index 0000000..4d71a81
--- /dev/null
+++ b/onap-client/onap_client/sdc/tests/test_vsp.py
@@ -0,0 +1,118 @@
+# -*- coding: utf8 -*-
+# ============LICENSE_START=======================================================
+# org.onap.vvp/validation-scripts
+# ===================================================================
+# Copyright © 2020 AT&T Intellectual Property. All rights reserved.
+# ===================================================================
+#
+# Unless otherwise specified, all software contained herein is licensed
+# under the Apache License, Version 2.0 (the "License");
+# you may not use this software 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.
+#
+#
+#
+# Unless otherwise specified, all documentation contained herein is licensed
+# under the Creative Commons License, Attribution 4.0 Intl. (the "License");
+# you may not use this documentation except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://creativecommons.org/licenses/by/4.0/
+#
+# Unless required by applicable law or agreed to in writing, documentation
+# 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============================================
+
+import responses
+from onap_client.client.clients import Client
+from onap_client import sdc
+from onap_client.tests.utils import mockup_client, mockup_catalog_item
+from os.path import dirname, abspath
+
+THIS_DIR = dirname(abspath(__file__))
+
+license_model_client = Client().sdc.license_model
+vsp_client = Client().sdc.vsp
+
+
+@responses.activate
+def test_vsp_create():
+ LICENSE_MODEL_ID = "license_model_id"
+ LICENSE_MODEL_VERSION_ID = "license_model_version_id"
+ FEATURE_GROUP_ID = "feature_group_id"
+ LICENSE_AGREEMENT_ID = "license_agreement_id"
+ LICENSE_MODEL_NAME = "test"
+ VSP_MODEL_ID = "software_product_id"
+ VSP_MODEL_VERSION_ID = "software_product_version_id"
+ VSP_NAME = "software_product_name"
+
+ mockup_catalog_item(
+ license_model_client.catalog_items["GET_LICENSE_MODELS"],
+ override_return_data={
+ "results": [{"name": LICENSE_MODEL_NAME, "id": LICENSE_MODEL_ID}]
+ },
+ )
+ mockup_catalog_item(
+ license_model_client.catalog_items["GET_LICENSE_MODEL_VERSIONS"],
+ override_return_data={
+ "results": [{"name": LICENSE_MODEL_NAME, "id": LICENSE_MODEL_VERSION_ID}]
+ },
+ )
+ mockup_catalog_item(
+ license_model_client.catalog_items["GET_LICENSE_MODEL_VERSION_ATTRIBUTE"],
+ override_return_data={
+ "results": [{"name": LICENSE_MODEL_NAME, "id": FEATURE_GROUP_ID}]
+ },
+ override_uri_params={"attribute": "feature-groups"},
+ )
+ mockup_catalog_item(
+ license_model_client.catalog_items["GET_LICENSE_MODEL_VERSION_ATTRIBUTE"],
+ override_return_data={
+ "results": [{"name": LICENSE_MODEL_NAME, "id": LICENSE_AGREEMENT_ID}]
+ },
+ override_uri_params={"attribute": "license-agreements"},
+ )
+ mockup_client(license_model_client)
+
+ mockup_catalog_item(
+ vsp_client.catalog_items["GET_SOFTWARE_PRODUCTS"],
+ override_return_data={"results": []},
+ )
+ mockup_catalog_item(
+ vsp_client.catalog_items["ADD_SOFTWARE_PRODUCT"],
+ override_return_data={
+ "itemId": VSP_MODEL_ID,
+ "version": {"id": VSP_MODEL_VERSION_ID},
+ },
+ )
+ mockup_catalog_item(
+ vsp_client.catalog_items["GET_SOFTWARE_PRODUCT"],
+ override_return_data={"name": VSP_NAME},
+ )
+ mockup_client(vsp_client)
+
+ vsp = sdc.vsp.VSP(
+ "vendor_name",
+ LICENSE_MODEL_NAME,
+ "{}/test.zip".format(THIS_DIR),
+ "application/zip",
+ VSP_NAME,
+ "description",
+ "category",
+ "sub_category",
+ contributers=["test123"],
+ )
+
+ assert vsp.tosca == {"name": VSP_NAME}
diff --git a/onap-client/onap_client/sdc/vnf.py b/onap-client/onap_client/sdc/vnf.py
new file mode 100644
index 0000000..da8f213
--- /dev/null
+++ b/onap-client/onap_client/sdc/vnf.py
@@ -0,0 +1,507 @@
+# -*- coding: utf8 -*-
+# ============LICENSE_START=======================================================
+# org.onap.vvp/validation-scripts
+# ===================================================================
+# Copyright © 2020 AT&T Intellectual Property. All rights reserved.
+# ===================================================================
+#
+# Unless otherwise specified, all software contained herein is licensed
+# under the Apache License, Version 2.0 (the "License");
+# you may not use this software 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.
+#
+#
+#
+# Unless otherwise specified, all documentation contained herein is licensed
+# under the Creative Commons License, Attribution 4.0 Intl. (the "License");
+# you may not use this documentation except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://creativecommons.org/licenses/by/4.0/
+#
+# Unless required by applicable law or agreed to in writing, documentation
+# 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============================================
+
+from onap_client.lib import generate_dummy_string
+from onap_client.resource import Resource
+from onap_client import exceptions, sdc
+from onap_client.client.clients import Client as SDCClient
+from onap_client.sdc import vsp
+from onap_client.util import utility
+
+import time
+
+vnf_client = SDCClient().sdc.vnf
+
+
+class VNF(Resource):
+ resource_name = "VNF"
+ spec = {
+ "software_product_name": {"type": str, "required": True},
+ "vnf_name": {
+ "type": str,
+ "required": False,
+ "default": generate_dummy_string("test_vnf_"),
+ },
+ "resource_type": {"type": str, "required": False, "default": "VF"},
+ "inputs": {"type": dict, "required": False, "default": {}},
+ "vm_types": {
+ "type": list,
+ "list_item": dict,
+ "required": False,
+ "default": [],
+ "nested": {
+ "vm_type": {"type": str, "required": True},
+ "properties": {"type": dict, "required": True, "default": {}},
+ },
+ },
+ "network_roles": {
+ "type": list,
+ "list_item": dict,
+ "required": False,
+ "default": [],
+ "nested": {
+ "network_role_tag": {"type": str, "required": True},
+ "network_role": {"type": str, "required": True},
+ "related_networks": {
+ "type": list,
+ "list_item": str,
+ "required": False,
+ "default": [],
+ },
+ },
+ },
+ "policies": {
+ "type": list,
+ "list_item": dict,
+ "required": False,
+ "default": [],
+ "nested": {
+ "policy_name": {"type": str, "required": True},
+ "properties": {"type": dict, "required": False, "default": {}},
+ },
+ },
+ }
+
+ def __init__(
+ self,
+ software_product_name,
+ vnf_name,
+ resource_type,
+ inputs={},
+ vm_types=[],
+ network_roles=[],
+ policies=[],
+ ):
+
+ vnf_input = {}
+
+ software_product_id = vsp.get_vsp_id(software_product_name)
+ software_product_version_id = vsp.get_vsp_version_id(software_product_id)
+ vsp_model = vsp.get_vsp_model(software_product_id, software_product_version_id)
+ vsp_vendor = vsp_model.get("vendorName")
+
+ vnf_input["software_product_id"] = software_product_id
+ vnf_input["vendor_name"] = vsp_vendor
+ vnf_input["vnf_name"] = vnf_name
+ vnf_input["resource_type"] = resource_type
+ vnf_input["inputs"] = inputs
+ vnf_input["vm_types"] = vm_types
+ vnf_input["network_roles"] = network_roles
+ vnf_input["policies"] = policies
+
+ super().__init__(vnf_input)
+
+ def _create(self, vnf_input):
+ """Creates a vnf object in SDC"""
+ vnf = None
+
+ if get_vnf_id(vnf_input.get("vnf_name")) is None:
+ vnf = create_vnf(vnf_input)
+ else:
+ raise exceptions.ResourceAlreadyExistsException(
+ "VNF resource {} already exists".format(vnf_input.get("vnf_name"))
+ )
+
+ return vnf
+
+ def _post_create(self):
+ inputs = self.inputs
+ vm_types = self.vm_types
+ network_roles = self.network_roles
+ policies = self.policies
+ model = self.tosca
+ vm_type_instances = []
+
+ for vm_type in vm_types:
+ vm_type_tag = vm_type.get("vm_type")
+ properties = vm_type.get("properties")
+ instance_ids = instance_ids_for_property(model, "vm_type_tag", vm_type_tag)
+ for instance_id in instance_ids:
+ for k, v in properties.items():
+ # updating vm_type properties
+ self.add_instance_property(instance_id, k, v)
+ vm_type_instances.append(instance_id)
+ for network_role in network_roles:
+ # checking if abstract node has matching network role,
+ # and updating if found
+ nrt = network_role.get("network_role_tag")
+ nr = network_role.get("network_role")
+ related_networks = network_role.get("related_networks")
+ instance_property = network_role_property_for_instance(
+ nrt, model, instance_id
+ )
+ if instance_property:
+ self.add_instance_property(instance_id, instance_property, nr)
+ if related_networks:
+ property_val = [
+ {"related_network_role": related_network_role}
+ for related_network_role in related_networks
+ ]
+ rnr_instance_property = instance_property.replace(
+ "_network_role", "_related_networks"
+ )
+ self.add_instance_property(
+ instance_id,
+ rnr_instance_property,
+ str(property_val).replace("'", '\\"'),
+ )
+
+ for policy in policies:
+ policy_name = policy.get("policy_name")
+ policy_model = self.add_policy_resource(policy_name)
+ self.associate_policy(policy_model.catalog_resource_id, vm_type_instances)
+ for k, v in policy.get("properties", {}).items():
+ self.add_policy_property(policy_model.catalog_resource_id, k, v)
+
+ for k, v in inputs.items():
+ self.add_input_value(k, v)
+
+ def _submit(self):
+ """Submits the vnf in SDC"""
+ certification = vnf_client.certify_catalog_resource(
+ **self.attributes, user_remarks="Ready!"
+ )
+ self.attributes["catalog_resource_id"] = certification.catalog_resource_id
+
+ vnf = vnf_client.get_catalog_resource(**self.attributes)
+
+ self.attributes["catalog_resource_name"] = vnf.catalog_resource_name
+ self.attributes["tosca"] = vnf.response_data
+
+ def add_resource(
+ self, catalog_resource_id, catalog_resource_name, origin_type="VF"
+ ):
+ """Attaches a resource to a VNF in SDC
+
+ :catalog_resource_id: ID of a resource in the SDC catalog
+ :catalog_resource_name: name to give to the resource when attaching to vnf
+ :origin_type: specifies the origin of the attached resource
+
+ """
+ milli_timestamp = int(time.time() * 1000)
+
+ resource_instance = vnf_client.add_resource_instance(
+ **self.attributes,
+ posX=306,
+ posY=248,
+ milli_timestamp=milli_timestamp,
+ new_catalog_resource_id=catalog_resource_id,
+ new_catalog_resource_name=catalog_resource_name,
+ originType=origin_type,
+ )
+
+ response = {
+ "id": resource_instance.catalog_resource_instance_id,
+ "tosca": resource_instance.response_data,
+ }
+ self.attributes[catalog_resource_name] = response
+
+ def add_input_value(self, input_name, input_default_value):
+ """Updates an input value on a VNF
+
+ :input_name: input name to update
+ :property_value: value to update input with
+
+ """
+ self._refresh()
+
+ inputs = self.tosca.get("inputs", [])
+ for item in inputs:
+ if item["name"] == input_name:
+ unique_id = item["uniqueId"]
+ parent_unique_id = item["parentUniqueId"]
+ owner_id = item["ownerId"]
+ return vnf_client.add_catalog_resource_input(
+ **self.attributes,
+ input_default_value=input_default_value,
+ input_name=input_name,
+ input_parent_unique_id=parent_unique_id,
+ input_unique_id=unique_id,
+ input_owner_id=owner_id,
+ )
+
+ raise exceptions.InputNotFoundException(
+ "Input {} was not found in VF".format(input_name)
+ )
+
+ # TODO
+ # instance, policy, and group properties can probably be merged
+ # rn there is a lot of dup
+
+ def add_instance_property(self, instance_id, property_name, property_value):
+ """Updates an instance property on a abstract instance attached to a VNF
+
+ :instance_id: ID of a instance attached to a VNF
+ :property_name: property name to update
+ :property_value: value to update property with
+
+ """
+ self._refresh()
+
+ instance_inputs = self.tosca.get("componentInstancesInputs", {}).get(
+ instance_id, {}
+ )
+
+ for prop in instance_inputs:
+ if prop.get("name") == property_name:
+ unique_id = prop.get("uniqueId")
+ parent_unique_id = prop.get("parentUniqueId")
+ owner_id = prop.get("ownerId")
+ schemaType = prop.get("schemaType", "")
+ property_type = prop.get("type")
+ return vnf_client.add_catalog_resource_property(
+ **self.attributes,
+ unique_id=unique_id,
+ parent_unique_id=parent_unique_id,
+ owner_id=owner_id,
+ catalog_resource_instance_id=instance_id,
+ property_name=property_name,
+ property_default_value=property_value,
+ schema_type=schemaType,
+ property_type=property_type,
+ )
+
+ raise exceptions.PropertyNotFoundException(
+ "Property {} was not found in Instance {}".format(
+ property_name, instance_id
+ )
+ )
+
+ def add_policy_property(self, policy_id, property_name, property_value):
+ """Updates a policy property on a polic attached to a VNF
+
+ :policy_id: ID of a policy attached to a VNF
+ :property_name: property name to update
+ :property_value: value to update property with
+
+ """
+ self._refresh()
+
+ policies = (
+ self.tosca.get("policies", {}).get(policy_id, {}).get("properties", {})
+ )
+
+ for prop in policies:
+ if prop.get("name") == property_name:
+ unique_id = prop.get("uniqueId")
+ property_type = prop.get("type")
+ description = prop.get("description")
+ return vnf_client.add_catalog_policy_property(
+ **self.attributes,
+ unique_id=unique_id,
+ catalog_policy_id=policy_id,
+ property_name=property_name,
+ property_default_value=property_value,
+ description=description,
+ property_type=property_type,
+ )
+
+ raise exceptions.PropertyNotFoundException(
+ "Property {} was not found in policy {}".format(property_name, policy_id)
+ )
+
+ def add_group_property(self, group_id, property_name, property_value):
+ """Updates a group property on a group attached to a VNF
+
+ :group_id: ID of a group attached to a VNF
+ :property_name: property name to update
+ :property_value: value to update property with
+
+ """
+ self._refresh()
+
+ groups = self.tosca.get("groups", [])
+
+ for group in groups:
+ if group.get("uniqueId") == group_id:
+ properties = group.get("properties", [])
+ for prop in properties:
+ unique_id = prop.get("uniqueId")
+ property_type = prop.get("type")
+ description = prop.get("description")
+ parent_unique_id = prop.get("parentUniqueId")
+ owner_id = prop.get("ownerId")
+ return vnf_client.add_catalog_group_property(
+ **self.attributes,
+ unique_id=unique_id,
+ catalog_group_id=group_id,
+ property_name=property_name,
+ property_default_value=property_value,
+ description=description,
+ property_type=property_type,
+ parent_unique_id=parent_unique_id,
+ owner_id=owner_id,
+ )
+
+ raise exceptions.PropertyNotFoundException(
+ "Property {} was not found in group {}".format(property_name, group_id)
+ )
+
+ def add_group_resource(self, group_name):
+ """Adds an SDC group resource to a VNF
+
+ :group_name: name of the group, matching onap-client.conf
+
+ """
+ sdc_properties = sdc.SDC_PROPERTIES
+ group = sdc_properties.GROUPS.get(group_name)
+ if not group:
+ raise exceptions.UnknownGroupException(
+ "Group {} was not found in configuration file".format(group_name)
+ )
+
+ return vnf_client.add_catalog_resource_group(
+ **self.attributes, catalog_group_name=group
+ )
+
+ def add_policy_resource(self, policy_name):
+ """Adds an SDC policy resource to a VNF
+
+ :group_name: name of the policy, matching onap-client.conf
+
+ """
+ sdc_properties = sdc.SDC_PROPERTIES
+ policy = sdc_properties.POLICIES.get(policy_name)
+ if not policy:
+ raise exceptions.UnknownPolicyException(
+ "Policy {} was not found in configuration file".format(policy_name)
+ )
+
+ return vnf_client.add_catalog_resource_policy(
+ **self.attributes, catalog_policy_name=policy
+ )
+
+ def associate_policy(self, policy_id, instance_ids):
+ """associates an SDC policy resource to an VNF instance resource
+
+ :policy_id: ID of policy resource from catalog
+ :instance_ids: list of instance ids to associate policy with
+
+ """
+
+ return vnf_client.add_policy_to_instance(
+ **self.attributes, catalog_policy_id=policy_id, instance_ids=instance_ids
+ )
+
+ def associate_group(self, group_id, instance_id):
+ """associates an SDC group resource to an VNF instance resource"""
+ return vnf_client.add_group_to_instance(
+ **self.attributes, catalog_group_id=group_id, instance_id=instance_id
+ )
+
+ def _refresh(self):
+ """GETs the VNF model from SDC and updates the VNF object"""
+ vnf = vnf_client.get_catalog_resource(**self.attributes)
+ self.attributes["tosca"] = vnf.response_data
+
+
+def create_vnf(vnf_input):
+ """Creates a vnf object in SDC
+
+ :vnf_input: dictionary with values to input for vnf creation
+
+ :return: dictionary of updated values for created vnf
+ """
+ kwargs = vnf_input
+ vnf = vnf_client.add_catalog_resource(**kwargs)
+
+ kwargs["catalog_resource_id"] = vnf.catalog_resource_id
+ kwargs["tosca"] = vnf.response_data
+
+ return kwargs
+
+
+def instance_ids_for_property(vnf_model, property_name, property_value):
+ """Parses a VNF model dictionary for a property + property value, to find the
+ abstract node tosca uuid
+
+ :vnf_model: dictionary for a VNF tosca model
+ :property_name: name of a property to look for in the vnf model
+ :property_value: value of a property to look for in the vnf model
+
+ :return: matching [instance_ids] or []
+ """
+ instance_ids = []
+ instances = vnf_model.get("componentInstancesInputs", {})
+ for instance_id, properties in instances.items():
+ for prop in properties:
+ if (
+ prop.get("name") == property_name
+ and prop.get("value", "") == property_value
+ ):
+ instance_ids.append(instance_id)
+ break
+
+ return instance_ids
+
+
+def network_role_property_for_instance(network_role_tag, vnf_model, instance_id):
+ """Parses a VNF model dictionary for a network_role_tag property, to find the
+ corresponding network role property
+
+ :network_role_tag: the network role tag to search for
+ :vnf_model: dictionary for a VNF tosca model
+ :instance_id: unique ID for an abstract node to look for the network_tag_property
+
+ :return: network_role property ID or None
+ """
+ instance_inputs = vnf_model.get("componentInstancesInputs", {}).get(instance_id, {})
+ for prop in instance_inputs:
+ if prop.get("name").endswith(
+ "network_role_tag"
+ ) and network_role_tag == prop.get("value"):
+ network_role_property = prop.get("name").replace("_tag", "")
+ return network_role_property
+
+ return None
+
+
+@utility
+def get_vnf(vnf_name):
+ """Queries SDC for the TOSCA model for a VNF"""
+ return vnf_client.get_catalog_resource(
+ catalog_resource_id=get_vnf_id(vnf_name)
+ ).response_data
+
+
+def get_vnf_id(vnf_name):
+ response = vnf_client.get_resources()
+ results = response.response_data.get("resources", [])
+ for vnf in results:
+ if vnf.get("name") == vnf_name:
+ return vnf["uniqueId"]
+ return None
diff --git a/onap-client/onap_client/sdc/vsp.py b/onap-client/onap_client/sdc/vsp.py
new file mode 100644
index 0000000..fc9258b
--- /dev/null
+++ b/onap-client/onap_client/sdc/vsp.py
@@ -0,0 +1,213 @@
+# -*- coding: utf8 -*-
+# ============LICENSE_START=======================================================
+# org.onap.vvp/validation-scripts
+# ===================================================================
+# Copyright © 2020 AT&T Intellectual Property. All rights reserved.
+# ===================================================================
+#
+# Unless otherwise specified, all software contained herein is licensed
+# under the Apache License, Version 2.0 (the "License");
+# you may not use this software 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.
+#
+#
+#
+# Unless otherwise specified, all documentation contained herein is licensed
+# under the Creative Commons License, Attribution 4.0 Intl. (the "License");
+# you may not use this documentation except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://creativecommons.org/licenses/by/4.0/
+#
+# Unless required by applicable law or agreed to in writing, documentation
+# 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============================================
+
+from onap_client.lib import generate_dummy_string
+from onap_client.resource import Resource
+from onap_client.client.clients import Client as SDCClient
+from onap_client import sdc
+from onap_client.util import utility
+from onap_client.exceptions import ResourceAlreadyExistsException
+
+vsp_client = SDCClient().sdc.vsp
+
+
+class VSP(Resource):
+ resource_name = "VSP"
+ spec = {
+ "vendor_name": {"type": str, "required": True},
+ "license_model_name": {"type": str, "required": True},
+ "file_path": {"type": str, "required": True},
+ "file_type": {"type": str, "required": False, "default": "application/zip"},
+ "software_product_name": {
+ "type": str,
+ "required": False,
+ "default": generate_dummy_string("test_vsp_"),
+ },
+ "description": {
+ "type": str,
+ "required": False,
+ "default": "new software product",
+ },
+ "category": {"type": str, "required": False, "default": "generic"},
+ "sub_category": {"type": str, "required": False, "default": "abstract"},
+ "contributers": {
+ "type": list,
+ "list_item": str,
+ "required": False,
+ "default": [],
+ },
+ }
+
+ def __init__(
+ self,
+ vendor_name,
+ license_model_name,
+ file_path,
+ file_type,
+ software_product_name,
+ description,
+ category,
+ sub_category,
+ contributers=[],
+ ):
+
+ vsp_input = {}
+
+ license_model_id = sdc.license_model.get_license_model_id(license_model_name)
+ license_model_version_id = sdc.license_model.get_license_model_version_id(
+ license_model_id
+ )
+ feature_group = sdc.license_model.get_license_model_attribute(
+ license_model_id, license_model_version_id, "feature-groups"
+ )
+ license_agreement = sdc.license_model.get_license_model_attribute(
+ license_model_id, license_model_version_id, "license-agreements"
+ )
+
+ vsp_input["software_product_name"] = software_product_name
+ vsp_input["feature_group_id"] = feature_group["id"]
+ vsp_input["license_agreement_id"] = license_agreement["id"]
+ vsp_input["vendor_name"] = vendor_name
+ vsp_input["license_model_id"] = license_model_id
+ vsp_input["license_model_version_id"] = license_model_version_id
+ vsp_input["file_path"] = file_path
+ vsp_input["file_type"] = file_type
+ vsp_input["description"] = description
+ vsp_input["category"] = category.lower()
+ vsp_input["sub_category"] = sub_category.lower()
+ vsp_input["contributers"] = contributers
+
+ super().__init__(vsp_input)
+
+ def _create(self, kwargs):
+ """Creates a vsp object in SDC"""
+ vsp = None
+
+ if get_vsp_id(kwargs.get("software_product_name")) is None:
+ vsp = create_vsp(kwargs)
+ else:
+ raise ResourceAlreadyExistsException(
+ "VSP resource {} already exists".format(
+ kwargs.get("software_product_name")
+ )
+ )
+
+ return vsp
+
+ def _post_create(self):
+ for contributer in self.contributers:
+ vsp_client.add_vsp_contributer(
+ user_id=contributer, software_product_id=self.software_product_id
+ )
+
+ def _submit(self):
+ """Submits the vsp in SDC"""
+ vsp_client.submit_software_product(**self.attributes, action="Submit")
+ vsp_client.package_software_product(**self.attributes, action="Create_Package")
+
+ vsp = vsp_client.get_software_product(**self.attributes)
+ self.attributes["tosca"] = vsp.response_data
+
+
+def create_vsp(vsp_input):
+ """Creates a VSP object in SDC
+
+ :vsp_input: dictionary with values to input for vsp creation
+
+ :return: dictionary of updated values for created vsp
+ """
+ kwargs = vsp_input
+ vsp = vsp_client.add_software_product(**kwargs)
+
+ kwargs["software_product_id"] = vsp.software_product_id
+ kwargs["software_product_version_id"] = vsp.software_product_version_id
+
+ vsp_client.upload_heat_package(**kwargs)
+ vsp_client.validate_software_product(**kwargs)
+
+ vsp = vsp_client.get_software_product(**kwargs)
+ kwargs["tosca"] = vsp.response_data
+
+ return kwargs
+
+
+def get_vsp_id(vsp_name):
+ """GETs vsp model ID from SDC
+
+ :vsp_name: name of vsp model in SDC
+
+ :return: id of vsp or None
+ """
+ response = vsp_client.get_software_products()
+ results = response.response_data.get("results", {})
+ for vsp in results:
+ if vsp.get("name") == vsp_name:
+ return vsp["id"]
+ return None
+
+
+def get_vsp_version_id(vsp_id):
+ """GETs vsp model version UUID from SDC
+
+ :vsp_id: uuid of vsp model in SDC
+
+ :return: uuid of vsp version id or None
+ """
+ vsp_version_id = None
+ creation_time = -1
+ response = vsp_client.get_software_product_versions(software_product_id=vsp_id)
+ results = response.response_data.get("results")
+ for version in results:
+ if version.get("creationTime", 0) > creation_time:
+ creation_time = version.get("creationTime")
+ vsp_version_id = version.get("id")
+
+ return vsp_version_id
+
+
+def get_vsp_model(vsp_id, vsp_version_id):
+ return vsp_client.get_software_product(
+ software_product_id=vsp_id, software_product_version_id=vsp_version_id,
+ ).response_data
+
+
+@utility
+def get_vsp(vsp_name):
+ """Queries SDC for the tosca model for a VSP"""
+ vsp_id = get_vsp_id(vsp_name)
+ vsp_version_id = get_vsp_version_id(vsp_id)
+ return get_vsp_model(vsp_id, vsp_version_id)
diff --git a/onap-client/onap_client/sdnc/__init__.py b/onap-client/onap_client/sdnc/__init__.py
new file mode 100644
index 0000000..eb3184f
--- /dev/null
+++ b/onap-client/onap_client/sdnc/__init__.py
@@ -0,0 +1,40 @@
+# -*- coding: utf8 -*-
+# ============LICENSE_START=======================================================
+# org.onap.vvp/validation-scripts
+# ===================================================================
+# Copyright © 2020 AT&T Intellectual Property. All rights reserved.
+# ===================================================================
+#
+# Unless otherwise specified, all software contained herein is licensed
+# under the Apache License, Version 2.0 (the "License");
+# you may not use this software 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.
+#
+#
+#
+# Unless otherwise specified, all documentation contained herein is licensed
+# under the Creative Commons License, Attribution 4.0 Intl. (the "License");
+# you may not use this documentation except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://creativecommons.org/licenses/by/4.0/
+#
+# Unless required by applicable law or agreed to in writing, documentation
+# 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============================================
+
+from onap_client.config import APP_CONFIG
+
+SDNC_PROPERTIES = APP_CONFIG.sdnc
diff --git a/onap-client/onap_client/sdnc/catalog/__init__.py b/onap-client/onap_client/sdnc/catalog/__init__.py
new file mode 100644
index 0000000..5519a84
--- /dev/null
+++ b/onap-client/onap_client/sdnc/catalog/__init__.py
@@ -0,0 +1,36 @@
+# -*- coding: utf8 -*-
+# ============LICENSE_START=======================================================
+# org.onap.vvp/validation-scripts
+# ===================================================================
+# Copyright © 2020 AT&T Intellectual Property. All rights reserved.
+# ===================================================================
+#
+# Unless otherwise specified, all software contained herein is licensed
+# under the Apache License, Version 2.0 (the "License");
+# you may not use this software 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.
+#
+#
+#
+# Unless otherwise specified, all documentation contained herein is licensed
+# under the Creative Commons License, Attribution 4.0 Intl. (the "License");
+# you may not use this documentation except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://creativecommons.org/licenses/by/4.0/
+#
+# Unless required by applicable law or agreed to in writing, documentation
+# 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============================================
diff --git a/onap-client/onap_client/sdnc/catalog/config_catalog.py b/onap-client/onap_client/sdnc/catalog/config_catalog.py
new file mode 100644
index 0000000..da3c1cf
--- /dev/null
+++ b/onap-client/onap_client/sdnc/catalog/config_catalog.py
@@ -0,0 +1,114 @@
+# -*- coding: utf8 -*-
+# ============LICENSE_START=======================================================
+# org.onap.vvp/validation-scripts
+# ===================================================================
+# Copyright © 2020 AT&T Intellectual Property. All rights reserved.
+# ===================================================================
+#
+# Unless otherwise specified, all software contained herein is licensed
+# under the Apache License, Version 2.0 (the "License");
+# you may not use this software 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.
+#
+#
+#
+# Unless otherwise specified, all documentation contained herein is licensed
+# under the Creative Commons License, Attribution 4.0 Intl. (the "License");
+# you may not use this documentation except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://creativecommons.org/licenses/by/4.0/
+#
+# Unless required by applicable law or agreed to in writing, documentation
+# 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============================================
+
+import uuid
+from functools import partial
+
+from onap_client import sdnc
+from onap_client import config
+from onap_client.sdnc.client import SDNCClient
+
+PAYLOADS_DIR = config.PAYLOADS_DIR
+sdnc_properties = sdnc.SDNC_PROPERTIES
+application_id = config.APPLICATION_ID
+
+
+class ConfigClient(SDNCClient):
+ @property
+ def catalog_resources(self):
+ return CATALOG_RESOURCES
+
+ @property
+ def namespace(self):
+ return "config"
+
+
+CATALOG_RESOURCES = {
+ "GET_SERVICE_INSTANCES": {
+ "verb": "GET",
+ "description": "Get a list of all service instances",
+ "uri": partial(
+ "{endpoint}{service_path}/GENERIC-RESOURCE-API:services".format,
+ endpoint=sdnc_properties.SDNC_ENDPOINT,
+ service_path=sdnc_properties.SDNC_CONFIG_PATH,
+ ),
+ "success_code": 200,
+ "headers": {
+ "Accept": "application/json",
+ "Content-Type": "application/json",
+ "X-TransactionId": str(uuid.uuid4()),
+ "X-FromAppId": application_id,
+ },
+ "auth": (sdnc_properties.SDNC_USERNAME, sdnc_properties.SDNC_PASSWORD,),
+ },
+ "GET_SERVICE_INSTANCE": {
+ "verb": "GET",
+ "description": "Get details for a service instance",
+ "uri": partial(
+ "{endpoint}{service_path}/GENERIC-RESOURCE-API:services/service/{service_instance_id}".format,
+ endpoint=sdnc_properties.SDNC_ENDPOINT,
+ service_path=sdnc_properties.SDNC_CONFIG_PATH,
+ ),
+ "uri-parameters": ["service_instance_id"],
+ "success_code": 200,
+ "headers": {
+ "Accept": "application/json",
+ "Content-Type": "application/json",
+ "X-TransactionId": str(uuid.uuid4()),
+ "X-FromAppId": application_id,
+ },
+ "auth": (sdnc_properties.SDNC_USERNAME, sdnc_properties.SDNC_PASSWORD,),
+ },
+ "GET_VNF_INSTANCE": {
+ "verb": "GET",
+ "description": "Get details for a vnf instance",
+ "uri": partial(
+ "{endpoint}{service_path}/GENERIC-RESOURCE-API:services/service/{service_instance_id}/service-data/vnfs/vnf/{vnf_instance_id}".format,
+ endpoint=sdnc_properties.SDNC_ENDPOINT,
+ service_path=sdnc_properties.SDNC_CONFIG_PATH,
+ ),
+ "uri-parameters": ["service_instance_id", "vnf_instance_id"],
+ "success_code": 200,
+ "headers": {
+ "Accept": "application/json",
+ "Content-Type": "application/json",
+ "X-TransactionId": str(uuid.uuid4()),
+ "X-FromAppId": application_id,
+ },
+ "auth": (sdnc_properties.SDNC_USERNAME, sdnc_properties.SDNC_PASSWORD,),
+ },
+}
diff --git a/onap-client/onap_client/sdnc/catalog/operations_catalog.py b/onap-client/onap_client/sdnc/catalog/operations_catalog.py
new file mode 100644
index 0000000..12db3a3
--- /dev/null
+++ b/onap-client/onap_client/sdnc/catalog/operations_catalog.py
@@ -0,0 +1,97 @@
+# -*- coding: utf8 -*-
+# ============LICENSE_START=======================================================
+# org.onap.vvp/validation-scripts
+# ===================================================================
+# Copyright © 2020 AT&T Intellectual Property. All rights reserved.
+# ===================================================================
+#
+# Unless otherwise specified, all software contained herein is licensed
+# under the Apache License, Version 2.0 (the "License");
+# you may not use this software 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.
+#
+#
+#
+# Unless otherwise specified, all documentation contained herein is licensed
+# under the Creative Commons License, Attribution 4.0 Intl. (the "License");
+# you may not use this documentation except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://creativecommons.org/licenses/by/4.0/
+#
+# Unless required by applicable law or agreed to in writing, documentation
+# 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============================================
+
+import uuid
+from functools import partial
+
+from onap_client import sdnc
+from onap_client import config
+from onap_client.sdnc.client import SDNCClient
+
+PAYLOADS_DIR = config.PAYLOADS_DIR
+sdnc_properties = sdnc.SDNC_PROPERTIES
+application_id = config.APPLICATION_ID
+
+
+class OperationsClient(SDNCClient):
+ @property
+ def catalog_resources(self):
+ return CATALOG_RESOURCES
+
+ @property
+ def namespace(self):
+ return "operations"
+
+
+CATALOG_RESOURCES = {
+ "GR_API_PRELOAD": {
+ "verb": "POST",
+ "description": "Upload a GR API preload to SDNC",
+ "uri": partial(
+ "{endpoint}{service_path}/GENERIC-RESOURCE-API:preload-vf-module-topology-operation".format,
+ endpoint=sdnc_properties.SDNC_ENDPOINT,
+ service_path=sdnc_properties.SDNC_OPERATIONS_PATH,
+ ),
+ "payload-path": ["preload_path"],
+ "success_code": 200,
+ "headers": {
+ "Accept": "application/json",
+ "Content-Type": "application/json",
+ "X-TransactionId": str(uuid.uuid4()),
+ "X-FromAppId": application_id,
+ },
+ "auth": (sdnc_properties.SDNC_USERNAME, sdnc_properties.SDNC_PASSWORD,),
+ },
+ "VNF_API_PRELOAD": {
+ "verb": "POST",
+ "description": "Upload a VNF API preload to SDNC",
+ "uri": partial(
+ "{endpoint}{service_path}/VNF-API:preload-vnf-topology-operation".format,
+ endpoint=sdnc_properties.SDNC_ENDPOINT,
+ service_path=sdnc_properties.SDNC_OPERATIONS_PATH,
+ ),
+ "payload-path": ["preload_path"],
+ "success_code": 200,
+ "headers": {
+ "Accept": "application/json",
+ "Content-Type": "application/json",
+ "X-TransactionId": str(uuid.uuid4()),
+ "X-FromAppId": application_id,
+ },
+ "auth": (sdnc_properties.SDNC_USERNAME, sdnc_properties.SDNC_PASSWORD,),
+ },
+}
diff --git a/onap-client/onap_client/sdnc/client.py b/onap-client/onap_client/sdnc/client.py
new file mode 100644
index 0000000..c0a3d1b
--- /dev/null
+++ b/onap-client/onap_client/sdnc/client.py
@@ -0,0 +1,53 @@
+# -*- coding: utf8 -*-
+# ============LICENSE_START=======================================================
+# org.onap.vvp/validation-scripts
+# ===================================================================
+# Copyright © 2020 AT&T Intellectual Property. All rights reserved.
+# ===================================================================
+#
+# Unless otherwise specified, all software contained herein is licensed
+# under the Apache License, Version 2.0 (the "License");
+# you may not use this software 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.
+#
+#
+#
+# Unless otherwise specified, all documentation contained herein is licensed
+# under the Creative Commons License, Attribution 4.0 Intl. (the "License");
+# you may not use this documentation except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://creativecommons.org/licenses/by/4.0/
+#
+# Unless required by applicable law or agreed to in writing, documentation
+# 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============================================
+
+from onap_client import sdnc
+from onap_client.client.clients import Client
+from onap_client import config
+
+sdnc_properties = sdnc.SDNC_PROPERTIES
+application_id = config.APPLICATION_ID
+
+
+class SDNCClient(Client):
+ @property
+ def namespace(self):
+ return "sdnc"
+
+ @property
+ def catalog_resources(self):
+ return {}
diff --git a/onap-client/onap_client/sdnc/preload.py b/onap-client/onap_client/sdnc/preload.py
new file mode 100644
index 0000000..65c5e0c
--- /dev/null
+++ b/onap-client/onap_client/sdnc/preload.py
@@ -0,0 +1,191 @@
+# -*- coding: utf8 -*-
+# ============LICENSE_START=======================================================
+# org.onap.vvp/validation-scripts
+# ===================================================================
+# Copyright © 2020 AT&T Intellectual Property. All rights reserved.
+# ===================================================================
+#
+# Unless otherwise specified, all software contained herein is licensed
+# under the Apache License, Version 2.0 (the "License");
+# you may not use this software 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.
+#
+#
+#
+# Unless otherwise specified, all documentation contained herein is licensed
+# under the Creative Commons License, Attribution 4.0 Intl. (the "License");
+# you may not use this documentation except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://creativecommons.org/licenses/by/4.0/
+#
+# Unless required by applicable law or agreed to in writing, documentation
+# 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============================================
+
+import json
+import tempfile
+
+from onap_client.resource import Resource
+from onap_client.client.clients import Client as SDNCClient
+from onap_client.exceptions import ServiceInstanceNotFound, VNFInstanceNotFound
+from onap_client import so
+from onap_client.config import LOG as logger
+
+oc = SDNCClient()
+sdnc_client = oc.sdnc
+
+
+class Preload(Resource):
+ resource_name = "PRELOAD"
+ spec = {
+ "api_type": {"type": str, "required": True},
+ "preload_path": {"type": str, "required": True},
+ "service_instance_name": {"type": str, "required": True},
+ "vnf_instance_name": {"type": str, "required": True},
+ "module_instance_name": {"type": str, "required": True},
+ "heat_template_name": {"type": str, "required": True},
+ }
+
+ def __init__(
+ self,
+ preload_path,
+ vnf_instance_name,
+ service_instance_name,
+ module_instance_name,
+ heat_template_name,
+ api_type,
+ ):
+ instance_input = {}
+
+ instance_input["preload_path"] = preload_path
+ instance_input["vnf_instance_name"] = vnf_instance_name
+ instance_input["service_instance_name"] = service_instance_name
+ instance_input["module_instance_name"] = module_instance_name
+ instance_input["heat_template_name"] = heat_template_name
+ instance_input["api_type"] = api_type
+
+ super().__init__(instance_input)
+
+ def _create(self, instance_input):
+ service_instance = so.vnf_instance.get_service_instance(
+ instance_input.get("service_instance_name")
+ )
+ if not service_instance:
+ raise ServiceInstanceNotFound(
+ "No service instance found for {}".format(
+ instance_input.get("service_instance_name")
+ )
+ )
+
+ vnf_instance = so.vnf_instance.get_vnf_instance(
+ service_instance, instance_input.get("vnf_instance_name")
+ )
+ if not vnf_instance:
+ raise VNFInstanceNotFound(
+ "No vnf instance found for {}".format(
+ instance_input.get("vnf_instance_name")
+ )
+ )
+
+ service_model_information = (
+ service_instance.get("service-data")
+ .get("service-information")
+ .get("onap-model-information")
+ )
+ service_model_name = service_model_information["model-name"]
+ vnf_model_information = (
+ vnf_instance.get("vnf-data")
+ .get("vnf-information")
+ .get("onap-model-information")
+ )
+ vnf_model_name = vnf_model_information["model-name"]
+
+ vnf_component = so.vnf_instance.get_vnf_model_component(
+ service_model_name, vnf_model_name
+ )
+ module_model = so.vnf_instance.get_module_model(
+ vnf_component, instance_input.get("heat_template_name")
+ )
+
+ preload_path = update_preload_with_instance(
+ instance_input.get("preload_path"),
+ instance_input.get("api_type"),
+ "{}/{} 0".format(service_model_name, vnf_model_name),
+ instance_input.get("vnf_instance_name"),
+ instance_input.get("module_instance_name"),
+ module_model.get("groupName"),
+ )
+
+ logger.info("Created preload {}".format(preload_path))
+
+ create_preload(preload_path, instance_input.get("api_type"))
+
+ return instance_input
+
+ def _post_create(self):
+ pass
+
+ def _submit(self):
+ pass
+
+
+def create_preload(preload_path, api_type):
+ if api_type == "GR_API":
+ sdnc_client.operations.gr_api_preload(preload_path=preload_path)
+ elif api_type == "VNF_API":
+ sdnc_client.operations.vnf_api_preload(preload_path=preload_path)
+
+
+def update_preload_with_instance(
+ preload_path,
+ api_type,
+ vnf_type,
+ vnf_instance_name,
+ module_instance_name,
+ module_model_name,
+):
+ with open(preload_path, "r") as f:
+ preload_data = json.loads(f.read())
+
+ if api_type == "GR_API":
+ data = {"vnf-name": vnf_instance_name, "vnf-type": vnf_type}
+ preload_data["input"]["preload-vf-module-topology-information"][
+ "vnf-topology-identifier-structure"
+ ] = data
+ data = {
+ "vf-module-type": module_model_name,
+ "vf-module-name": module_instance_name,
+ }
+ preload_data["input"]["preload-vf-module-topology-information"][
+ "vf-module-topology"
+ ]["vf-module-topology-identifier"] = data
+ elif api_type == "VNF_API":
+ data = {
+ "vnf-name": module_instance_name,
+ "vnf-type": module_model_name,
+ "generic-vnf-type": vnf_type,
+ "generic-vnf-name": vnf_instance_name,
+ }
+ preload_data["input"]["vnf-topology-information"][
+ "vnf-topology-identifier"
+ ] = data
+
+ filename = ""
+ with tempfile.NamedTemporaryFile(mode='w+t', delete=False) as f:
+ filename = f.name
+ json.dump(preload_data, f, indent=4)
+
+ return filename
diff --git a/onap-client/onap_client/sdnc/tests/__init__.py b/onap-client/onap_client/sdnc/tests/__init__.py
new file mode 100644
index 0000000..5519a84
--- /dev/null
+++ b/onap-client/onap_client/sdnc/tests/__init__.py
@@ -0,0 +1,36 @@
+# -*- coding: utf8 -*-
+# ============LICENSE_START=======================================================
+# org.onap.vvp/validation-scripts
+# ===================================================================
+# Copyright © 2020 AT&T Intellectual Property. All rights reserved.
+# ===================================================================
+#
+# Unless otherwise specified, all software contained herein is licensed
+# under the Apache License, Version 2.0 (the "License");
+# you may not use this software 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.
+#
+#
+#
+# Unless otherwise specified, all documentation contained herein is licensed
+# under the Creative Commons License, Attribution 4.0 Intl. (the "License");
+# you may not use this documentation except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://creativecommons.org/licenses/by/4.0/
+#
+# Unless required by applicable law or agreed to in writing, documentation
+# 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============================================
diff --git a/onap-client/onap_client/so/__init__.py b/onap-client/onap_client/so/__init__.py
new file mode 100644
index 0000000..44cf6d7
--- /dev/null
+++ b/onap-client/onap_client/so/__init__.py
@@ -0,0 +1,40 @@
+# -*- coding: utf8 -*-
+# ============LICENSE_START=======================================================
+# org.onap.vvp/validation-scripts
+# ===================================================================
+# Copyright © 2020 AT&T Intellectual Property. All rights reserved.
+# ===================================================================
+#
+# Unless otherwise specified, all software contained herein is licensed
+# under the Apache License, Version 2.0 (the "License");
+# you may not use this software 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.
+#
+#
+#
+# Unless otherwise specified, all documentation contained herein is licensed
+# under the Creative Commons License, Attribution 4.0 Intl. (the "License");
+# you may not use this documentation except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://creativecommons.org/licenses/by/4.0/
+#
+# Unless required by applicable law or agreed to in writing, documentation
+# 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============================================
+
+from onap_client.config import APP_CONFIG
+
+SO_PROPERTIES = APP_CONFIG.so
diff --git a/onap-client/onap_client/so/catalog/__init__.py b/onap-client/onap_client/so/catalog/__init__.py
new file mode 100644
index 0000000..5519a84
--- /dev/null
+++ b/onap-client/onap_client/so/catalog/__init__.py
@@ -0,0 +1,36 @@
+# -*- coding: utf8 -*-
+# ============LICENSE_START=======================================================
+# org.onap.vvp/validation-scripts
+# ===================================================================
+# Copyright © 2020 AT&T Intellectual Property. All rights reserved.
+# ===================================================================
+#
+# Unless otherwise specified, all software contained herein is licensed
+# under the Apache License, Version 2.0 (the "License");
+# you may not use this software 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.
+#
+#
+#
+# Unless otherwise specified, all documentation contained herein is licensed
+# under the Creative Commons License, Attribution 4.0 Intl. (the "License");
+# you may not use this documentation except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://creativecommons.org/licenses/by/4.0/
+#
+# Unless required by applicable law or agreed to in writing, documentation
+# 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============================================
diff --git a/onap-client/onap_client/so/catalog/service_instantiation.py b/onap-client/onap_client/so/catalog/service_instantiation.py
new file mode 100644
index 0000000..665402f
--- /dev/null
+++ b/onap-client/onap_client/so/catalog/service_instantiation.py
@@ -0,0 +1,316 @@
+# -*- coding: utf8 -*-
+# ============LICENSE_START=======================================================
+# org.onap.vvp/validation-scripts
+# ===================================================================
+# Copyright © 2020 AT&T Intellectual Property. All rights reserved.
+# ===================================================================
+#
+# Unless otherwise specified, all software contained herein is licensed
+# under the Apache License, Version 2.0 (the "License");
+# you may not use this software 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.
+#
+#
+#
+# Unless otherwise specified, all documentation contained herein is licensed
+# under the Creative Commons License, Attribution 4.0 Intl. (the "License");
+# you may not use this documentation except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://creativecommons.org/licenses/by/4.0/
+#
+# Unless required by applicable law or agreed to in writing, documentation
+# 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============================================
+
+import uuid
+from functools import partial
+
+from onap_client import so
+from onap_client import config
+from onap_client.so.client import SOClient
+
+PAYLOADS_DIR = config.PAYLOADS_DIR
+so_properties = so.SO_PROPERTIES
+application_id = config.APPLICATION_ID
+
+
+class ServiceInstantiationClient(SOClient):
+ @property
+ def catalog_resources(self):
+ return CATALOG_RESOURCES
+
+ @property
+ def namespace(self):
+ return "service_instantiation"
+
+
+CATALOG_RESOURCES = {
+ "CREATE_SERVICE_INSTANCE": {
+ "verb": "POST",
+ "description": "Creates a Service Instance from the service catalog",
+ "uri": partial(
+ "{endpoint}{service_path}".format,
+ endpoint=so_properties.SO_ENDPOINT,
+ service_path=so_properties.SO_SERVICE_INSTANCE_PATH,
+ ),
+ "payload": "{}/so_service_instance.jinja".format(PAYLOADS_DIR),
+ "payload-parameters": [
+ "service_instance_name",
+ "requestor_id",
+ "model_invariant_id",
+ "model_version_id",
+ "model_name",
+ "model_version",
+ "tenant_id",
+ "cloud_owner",
+ "cloud_region",
+ "api_type",
+ "service_type",
+ "customer_id",
+ "project_name",
+ "owning_entity_id",
+ ],
+ "header-parameters": ["X-TransactionId"],
+ "success_code": 202,
+ "headers": {
+ "Accept": "application/json",
+ "Content-Type": "application/json",
+ # "X-TransactionId": str(uuid.uuid4()),
+ "X-FromAppId": application_id,
+ },
+ "auth": (so_properties.SO_USERNAME, so_properties.SO_PASSWORD),
+ },
+ "DELETE_SERVICE_INSTANCE": {
+ "verb": "DELETE",
+ "description": "Deletes a VNF Instance.",
+ "uri": partial(
+ "{endpoint}{service_path}/{service_instance_id}".format,
+ endpoint=so_properties.SO_ENDPOINT,
+ service_path=so_properties.SO_SERVICE_INSTANCE_PATH,
+ ),
+ "uri-parameters": ["service_instance_id"],
+ "payload": "{}/so_delete_service.jinja".format(PAYLOADS_DIR),
+ "payload-parameters": [
+ "service_invariant_id",
+ "service_name",
+ "service_version",
+ "api_type",
+ ],
+ "header-parameters": ["X-TransactionId"],
+ "success_code": 202,
+ "headers": {
+ "Accept": "application/json",
+ "Content-Type": "application/json",
+ # "X-TransactionId": str(uuid.uuid4()),
+ "X-FromAppId": application_id,
+ },
+ "auth": (so_properties.SO_USERNAME, so_properties.SO_PASSWORD),
+ },
+ "CREATE_VNF_INSTANCE": {
+ "verb": "POST",
+ "description": "Creates a VNF Instance.",
+ "uri": partial(
+ "{endpoint}{service_path}/{service_instance_id}/vnfs".format,
+ endpoint=so_properties.SO_ENDPOINT,
+ service_path=so_properties.SO_SERVICE_INSTANCE_PATH,
+ ),
+ "uri-parameters": ["service_instance_id"],
+ "payload": "{}/so_vnf_instance.jinja".format(PAYLOADS_DIR),
+ "payload-parameters": [
+ "vnf_instance_name",
+ "requestor_id",
+ "model_invariant_id",
+ "model_version_id",
+ "model_name",
+ "model_version",
+ "model_customization_id",
+ "tenant_id",
+ "cloud_owner",
+ "cloud_region",
+ "api_type",
+ "platform",
+ "line_of_business",
+ "service_model_name",
+ "service_model_invariant_id",
+ "service_model_version",
+ "service_model_version_id",
+ "service_instance_id",
+ ],
+ "header-parameters": ["X-TransactionId"],
+ "success_code": 202,
+ "headers": {
+ "Accept": "application/json",
+ "Content-Type": "application/json",
+ # "X-TransactionId": str(uuid.uuid4()),
+ "X-FromAppId": application_id,
+ },
+ "auth": (so_properties.SO_USERNAME, so_properties.SO_PASSWORD),
+ },
+ "DELETE_VNF_INSTANCE": {
+ "verb": "DELETE",
+ "description": "Deletes a VNF Instance.",
+ "uri": partial(
+ "{endpoint}{service_path}/{service_instance_id}/vnfs/{vnf_instance_id}".format,
+ endpoint=so_properties.SO_ENDPOINT,
+ service_path=so_properties.SO_SERVICE_INSTANCE_PATH,
+ ),
+ "uri-parameters": ["service_instance_id", "vnf_instance_id"],
+ "payload": "{}/so_delete_vnf.jinja".format(PAYLOADS_DIR),
+ "payload-parameters": [
+ "vnf_invariant_id",
+ "vnf_name",
+ "vnf_version",
+ "cloud_region",
+ "cloud_owner",
+ "tenant_id",
+ "api_type",
+ ],
+ "header-parameters": ["X-TransactionId"],
+ "success_code": 202,
+ "headers": {
+ "Accept": "application/json",
+ "Content-Type": "application/json",
+ # "X-TransactionId": str(uuid.uuid4()),
+ "X-FromAppId": application_id,
+ },
+ "auth": (so_properties.SO_USERNAME, so_properties.SO_PASSWORD),
+ },
+ "CREATE_MODULE_INSTANCE": {
+ "verb": "POST",
+ "description": "Creates a VNF Module Instance.",
+ "uri": partial(
+ "{endpoint}{service_path}/{service_instance_id}/vnfs/{vnf_instance_id}/vfModules".format,
+ endpoint=so_properties.SO_ENDPOINT,
+ service_path=so_properties.SO_SERVICE_INSTANCE_PATH,
+ ),
+ "uri-parameters": ["service_instance_id", "vnf_instance_id"],
+ "payload": "{}/so_create_module.jinja".format(PAYLOADS_DIR),
+ "payload-parameters": [
+ "module_instance_name",
+ "model_invariant_id",
+ "model_version_id",
+ "model_name",
+ "model_version",
+ "model_customization_id",
+ "model_name",
+ "api_type",
+ "tenant_id",
+ "cloud_owner",
+ "cloud_region",
+ "service_instance_id",
+ "service_model_name",
+ "service_model_invariant_id",
+ "service_model_version",
+ "service_model_version_id",
+ "vnf_instance_id",
+ "vnf_model_name",
+ "vnf_model_invariant_id",
+ "vnf_model_version",
+ "vnf_model_version_id",
+ "vnf_model_customization_id",
+ ],
+ "header-parameters": ["X-TransactionId"],
+ "success_code": 202,
+ "headers": {
+ "Accept": "application/json",
+ "Content-Type": "application/json",
+ # "X-TransactionId": str(uuid.uuid4()),
+ "X-FromAppId": application_id,
+ },
+ "auth": (so_properties.SO_USERNAME, so_properties.SO_PASSWORD),
+ },
+ "DELETE_MODULE_INSTANCE": {
+ "verb": "DELETE",
+ "description": "Deletes a VNF Module Instance.",
+ "uri": partial(
+ "{endpoint}{service_path}/{service_instance_id}/vnfs/{vnf_instance_id}/vfModules/{vf_module_id}".format,
+ endpoint=so_properties.SO_ENDPOINT,
+ service_path=so_properties.SO_SERVICE_INSTANCE_PATH,
+ ),
+ "uri-parameters": ["service_instance_id", "vnf_instance_id", "vf_module_id"],
+ "payload": "{}/so_delete_module.jinja".format(PAYLOADS_DIR),
+ "payload-parameters": [
+ "module_invariant_id",
+ "module_name",
+ "module_version",
+ "cloud_region",
+ "cloud_owner",
+ "tenant_id",
+ "api_type",
+ ],
+ "header-parameters": ["X-TransactionId"],
+ "success_code": 202,
+ "headers": {
+ "Accept": "application/json",
+ "Content-Type": "application/json",
+ # "X-TransactionId": str(uuid.uuid4()),
+ "X-FromAppId": application_id,
+ },
+ "auth": (so_properties.SO_USERNAME, so_properties.SO_PASSWORD),
+ },
+ "GET_REQUEST_STATUS": {
+ "verb": "GET",
+ "description": "Queries the status for a given request ID",
+ "uri": partial(
+ "{endpoint}{service_path}/{request_id}".format,
+ endpoint=so_properties.SO_ENDPOINT,
+ service_path=so_properties.SO_ORCHESTRATION_PATH,
+ ),
+ "uri-parameters": ["request_id"],
+ "success_code": 200,
+ "headers": {
+ "Accept": "application/json",
+ "Content-Type": "application/json",
+ "X-TransactionId": str(uuid.uuid4()),
+ "X-FromAppId": application_id,
+ },
+ "auth": (so_properties.SO_USERNAME, so_properties.SO_PASSWORD),
+ },
+ "GET_SERVICE_MODEL": {
+ "verb": "GET",
+ "description": "Searches the SO catalog for a service model",
+ "uri": partial(
+ "{endpoint}/service/search/findOneByModelName?modelName={model_name}".format,
+ endpoint=so_properties.SO_ENDPOINT,
+ ),
+ "uri-parameters": ["model_name"],
+ "success_code": 200,
+ "headers": {
+ "Accept": "application/json",
+ "Content-Type": "application/json",
+ "X-TransactionId": str(uuid.uuid4()),
+ "X-FromAppId": application_id,
+ },
+ "auth": (so_properties.SO_USERNAME, so_properties.SO_PASSWORD),
+ },
+ "GET_SERVICE_MODEL_DETAILS": {
+ "verb": "GET",
+ "description": "Searches the SO catalog for a service model",
+ "uri": partial(
+ "{endpoint}/service/search/findOneByModelName?modelName={model_name}".format,
+ endpoint=so_properties.SO_ENDPOINT,
+ ),
+ "uri-parameters": ["model_name"],
+ "success_code": 200,
+ "headers": {
+ "Accept": "application/json",
+ "Content-Type": "application/json",
+ "X-TransactionId": str(uuid.uuid4()),
+ "X-FromAppId": application_id,
+ },
+ "auth": (so_properties.SO_USERNAME, so_properties.SO_PASSWORD),
+ },
+}
diff --git a/onap-client/onap_client/so/client.py b/onap-client/onap_client/so/client.py
new file mode 100644
index 0000000..c38cf0c
--- /dev/null
+++ b/onap-client/onap_client/so/client.py
@@ -0,0 +1,69 @@
+# -*- coding: utf8 -*-
+# ============LICENSE_START=======================================================
+# org.onap.vvp/validation-scripts
+# ===================================================================
+# Copyright © 2020 AT&T Intellectual Property. All rights reserved.
+# ===================================================================
+#
+# Unless otherwise specified, all software contained herein is licensed
+# under the Apache License, Version 2.0 (the "License");
+# you may not use this software 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.
+#
+#
+#
+# Unless otherwise specified, all documentation contained herein is licensed
+# under the Creative Commons License, Attribution 4.0 Intl. (the "License");
+# you may not use this documentation except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://creativecommons.org/licenses/by/4.0/
+#
+# Unless required by applicable law or agreed to in writing, documentation
+# 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============================================
+
+from functools import partial
+from onap_client import so
+from onap_client.client.clients import Client
+from onap_client import config
+
+so_properties = so.SO_PROPERTIES
+application_id = config.APPLICATION_ID
+
+
+class SOClient(Client):
+ @property
+ def namespace(self):
+ return "so"
+
+ @property
+ def catalog_resources(self):
+ return CATALOG_RESOURCES
+
+
+CATALOG_RESOURCES = {
+ "HEALTH_CHECK": {
+ "verb": "GET",
+ "description": "Queries so health check endpoint",
+ "uri": partial(
+ "{endpoint}{service_path}".format,
+ endpoint=so_properties.SO_ENDPOINT,
+ service_path=so_properties.SO_HEALTH_CHECK_PATH,
+ ),
+ "success_code": 200,
+ "auth": (so_properties.SO_USERNAME, so_properties.SO_PASSWORD),
+ },
+}
diff --git a/onap-client/onap_client/so/module_instance.py b/onap-client/onap_client/so/module_instance.py
new file mode 100644
index 0000000..19af17a
--- /dev/null
+++ b/onap-client/onap_client/so/module_instance.py
@@ -0,0 +1,236 @@
+# -*- coding: utf8 -*-
+# ============LICENSE_START=======================================================
+# org.onap.vvp/validation-scripts
+# ===================================================================
+# Copyright © 2020 AT&T Intellectual Property. All rights reserved.
+# ===================================================================
+#
+# Unless otherwise specified, all software contained herein is licensed
+# under the Apache License, Version 2.0 (the "License");
+# you may not use this software 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.
+#
+#
+#
+# Unless otherwise specified, all documentation contained herein is licensed
+# under the Creative Commons License, Attribution 4.0 Intl. (the "License");
+# you may not use this documentation except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://creativecommons.org/licenses/by/4.0/
+#
+# Unless required by applicable law or agreed to in writing, documentation
+# 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============================================
+
+import uuid
+from onap_client.resource import Resource
+from onap_client.client.clients import Client as SOClient
+from onap_client.exceptions import ServiceInstanceNotFound, VNFInstanceNotFound, ModuleInstanceNotFound
+from onap_client import so
+from onap_client import sdnc
+from onap_client.util import utility
+
+oc = SOClient()
+so_client = oc.so
+
+
+class VNFInstance(Resource):
+ resource_name = "MODULE_INSTANCE"
+ spec = {
+ "module_instance_name": {"type": str, "required": True},
+ "vnf_instance_name": {"type": str, "required": True},
+ "service_instance_name": {"type": str, "required": True},
+ "requestor_id": {"type": str, "required": False, "default": "cs0008"},
+ "heat_template_name": {"type": str, "required": True},
+ "preload_path": {"type": str, "required": True},
+ "tenant_name": {"type": str, "required": True},
+ "cloud_owner": {"type": str, "required": True},
+ "cloud_region": {"type": str, "required": True},
+ "api_type": {"type": str, "required": False, "default": "GR_API"},
+ }
+
+ def __init__(
+ self,
+ module_instance_name,
+ vnf_instance_name,
+ service_instance_name,
+ requestor_id,
+ heat_template_name,
+ preload_path,
+ tenant_name,
+ cloud_owner,
+ cloud_region,
+ api_type,
+ ):
+ instance_input = {}
+
+ tenant_id = so.service_instance.get_tenant_id(cloud_region, cloud_owner, tenant_name)
+
+ instance_input["module_instance_name"] = module_instance_name
+ instance_input["vnf_instance_name"] = vnf_instance_name
+ instance_input["service_instance_name"] = service_instance_name
+ instance_input["requestor_id"] = requestor_id
+ instance_input["heat_template_name"] = heat_template_name
+ instance_input["preload_path"] = preload_path
+ instance_input["tenant_id"] = tenant_id
+ instance_input["cloud_owner"] = cloud_owner
+ instance_input["cloud_region"] = cloud_region
+ instance_input["api_type"] = api_type
+
+ super().__init__(instance_input)
+
+ def _create(self, instance_input):
+ service_instance = so.vnf_instance.get_service_instance(
+ instance_input.get("service_instance_name")
+ )
+ if not service_instance:
+ raise ServiceInstanceNotFound(
+ "No service instance found for {}".format(
+ instance_input.get("service_instance_name")
+ )
+ )
+ service_instance_id = service_instance.get("service-instance-id")
+ model_information = (
+ service_instance.get("service-data")
+ .get("service-information")
+ .get("onap-model-information")
+ )
+ service_model_invariant_id = model_information["model-invariant-uuid"]
+ service_model_version_id = model_information["model-uuid"]
+ service_model_version = model_information["model-version"]
+ service_model_name = model_information["model-name"]
+
+ vnf_instance = so.vnf_instance.get_vnf_instance(
+ service_instance, instance_input.get("vnf_instance_name")
+ )
+ if not vnf_instance:
+ raise VNFInstanceNotFound(
+ "No vnf instance found for {}".format(
+ instance_input.get("vnf_instance_name")
+ )
+ )
+ vnf_model_information = vnf_instance.get("vnf-data").get("vnf-information")
+ vnf_instance_id = vnf_model_information.get("vnf-id")
+ vnf_model_name = vnf_model_information.get("onap-model-information").get(
+ "model-name"
+ )
+ vnf_model_invariant_id = vnf_model_information.get(
+ "onap-model-information"
+ ).get("model-invariant-uuid")
+ vnf_model_version_id = vnf_model_information.get("onap-model-information").get(
+ "model-uuid"
+ )
+ vnf_model_customization_id = vnf_model_information.get(
+ "onap-model-information"
+ ).get("model-customization-uuid")
+ vnf_model_version = vnf_model_information.get("onap-model-information").get(
+ "model-version"
+ )
+
+ vnf_model = so.vnf_instance.get_vnf_model_component(
+ service_model_name, vnf_model_name
+ )
+
+ module_model = so.vnf_instance.get_module_model(
+ vnf_model, instance_input.get("heat_template_name")
+ )
+ model_invariant_id = module_model.get("invariantUUID")
+ model_version_id = module_model.get("groupUUID")
+ model_customization_id = module_model.get("customizationUUID")
+ model_name = module_model.get("groupName")
+ model_version = module_model.get("version")
+
+ instance_input["model_invariant_id"] = model_invariant_id
+ instance_input["model_version_id"] = model_version_id
+ instance_input["model_name"] = model_name
+ instance_input["model_version"] = model_version
+ instance_input["model_customization_id"] = model_customization_id
+ instance_input["service_instance_id"] = service_instance_id
+ instance_input["service_model_name"] = service_model_name
+ instance_input["service_model_invariant_id"] = service_model_invariant_id
+ instance_input["service_model_version"] = service_model_version
+ instance_input["service_model_version_id"] = service_model_version_id
+ instance_input["vnf_instance_id"] = vnf_instance_id
+ instance_input["vnf_model_name"] = vnf_model_name
+ instance_input["vnf_model_invariant_id"] = vnf_model_invariant_id
+ instance_input["vnf_model_version_id"] = vnf_model_version_id
+ instance_input["vnf_model_version"] = vnf_model_version
+ instance_input["vnf_model_customization_id"] = vnf_model_customization_id
+
+ return create_module_instance(instance_input)
+
+ def _post_create(self):
+ pass
+
+ def _submit(self):
+ pass
+
+
+def create_module_instance(instance_input):
+ sdnc.preload.Preload(
+ instance_input.get("preload_path"),
+ instance_input.get("vnf_instance_name"),
+ instance_input.get("service_instance_name"),
+ instance_input.get("module_instance_name"),
+ instance_input.get("heat_template_name"),
+ instance_input.get("api_type")
+ )
+
+ headers = {"X-TransactionId": str(uuid.uuid4())}
+ module_instance = so_client.service_instantiation.create_module_instance(
+ **instance_input, **headers
+ )
+
+ request_id = module_instance.response_data.get("requestReferences", {}).get(
+ "requestId"
+ )
+
+ instance_input["request_info"] = so.service_instance.poll_request(request_id)
+
+ return instance_input
+
+
+@utility
+def delete_module_instance(service_instance_name, vnf_instance_name, module_instance_name, api_type="GR_API"):
+ """Delete a Module Instance from SO"""
+ si = so.service_instance.get_service_instance(service_instance_name)
+ si_id = si.get("service-instance-id")
+ for vnfi in si.get("service-data", {}).get("vnfs", {}).get("vnf", []):
+ vnfi_id = vnfi.get("vnf-id")
+ if vnfi.get("vnf-data", {}).get("vnf-request-input", {}).get("vnf-name") == vnf_instance_name:
+ for modulei in vnfi.get("vnf-data").get("vf-modules", {}).get("vf-module", []):
+ if modulei.get("vf-module-data", {}).get("vf-module-request-input", {}).get("vf-module-name") == module_instance_name:
+ module_id = modulei.get("vf-module-id")
+ module_invariant_id = modulei.get("vf-module-data").get("vf-module-topology").get("onap-model-information").get("model-invariant-uuid")
+ module_version = modulei.get("vf-module-data").get("vf-module-topology").get("onap-model-information").get("model-version")
+ module_name = modulei.get("vf-module-data").get("vf-module-topology").get("onap-model-information").get("model-name")
+ tenant_id = modulei.get("vf-module-data").get("vf-module-request-input").get("tenant")
+ cloud_owner = modulei.get("vf-module-data").get("vf-module-request-input").get("cloud-owner")
+ cloud_region = modulei.get("vf-module-data").get("vf-module-request-input").get("aic-cloud-region")
+ return so_client.service_instantiation.delete_module_instance(
+ module_invariant_id=module_invariant_id,
+ module_name=module_name,
+ module_version=module_version,
+ cloud_region=cloud_region,
+ cloud_owner=cloud_owner,
+ tenant_id=tenant_id,
+ vnf_instance_id=vnfi_id,
+ service_instance_id=si_id,
+ vf_module_id=module_id,
+ api_type=api_type
+ ).response_data
+
+ raise ModuleInstanceNotFound("Module Instance was not found: {} {} {}".format(service_instance_name, vnf_instance_name, module_instance_name))
diff --git a/onap-client/onap_client/so/service_instance.py b/onap-client/onap_client/so/service_instance.py
new file mode 100644
index 0000000..a5a2e8f
--- /dev/null
+++ b/onap-client/onap_client/so/service_instance.py
@@ -0,0 +1,230 @@
+# -*- coding: utf8 -*-
+# ============LICENSE_START=======================================================
+# org.onap.vvp/validation-scripts
+# ===================================================================
+# Copyright © 2020 AT&T Intellectual Property. All rights reserved.
+# ===================================================================
+#
+# Unless otherwise specified, all software contained herein is licensed
+# under the Apache License, Version 2.0 (the "License");
+# you may not use this software 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.
+#
+#
+#
+# Unless otherwise specified, all documentation contained herein is licensed
+# under the Creative Commons License, Attribution 4.0 Intl. (the "License");
+# you may not use this documentation except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://creativecommons.org/licenses/by/4.0/
+#
+# Unless required by applicable law or agreed to in writing, documentation
+# 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============================================
+
+import uuid
+
+from onap_client.lib import generate_dummy_string
+from onap_client.resource import Resource
+from onap_client.client.clients import Client as SOClient
+from onap_client.so import SO_PROPERTIES
+from onap_client.exceptions import (
+ SORequestStatusUnavailable,
+ SORequestFailed,
+ SORequestTimeout,
+ TenantNotFound,
+ ServiceInstanceNotFound,
+)
+from onap_client import sdc
+from onap_client.util import utility
+
+from time import sleep
+
+oc = SOClient()
+so_client = oc.so
+sdc_client = oc.sdc
+aai_client = oc.aai
+sdnc_client = oc.sdnc
+vid_client = oc.vid
+
+
+class ServiceInstance(Resource):
+ resource_name = "SERVICE_INSTANCE"
+ spec = {
+ "service_instance_name": {
+ "type": str,
+ "required": False,
+ "default": generate_dummy_string("SI_"),
+ },
+ "requestor_id": {"type": str, "required": False, "default": "cs0008"},
+ "model_name": {"type": str, "required": True},
+ "model_version": {"type": str, "required": False, "default": "1.0"},
+ "tenant_name": {"type": str, "required": True},
+ "cloud_owner": {"type": str, "required": True},
+ "cloud_region": {"type": str, "required": True},
+ "api_type": {"type": str, "required": False, "default": "GR_API"},
+ "service_type": {"type": str, "required": True},
+ "customer_name": {"type": str, "required": True},
+ "project_name": {"type": str, "required": True},
+ "owning_entity_name": {"type": str, "required": True},
+ }
+
+ def __init__(
+ self,
+ service_instance_name,
+ requestor_id,
+ model_name,
+ model_version,
+ tenant_name,
+ cloud_owner,
+ cloud_region,
+ api_type,
+ service_type,
+ customer_name,
+ project_name,
+ owning_entity_name,
+ ):
+ instance_input = {}
+
+ tenant_id = get_tenant_id(cloud_region, cloud_owner, tenant_name)
+
+ instance_input["service_instance_name"] = service_instance_name
+ instance_input["requestor_id"] = requestor_id
+ instance_input["model_name"] = model_name
+ instance_input["model_version"] = model_version
+ instance_input["tenant_id"] = tenant_id
+ instance_input["cloud_owner"] = cloud_owner
+ instance_input["cloud_region"] = cloud_region
+ instance_input["api_type"] = api_type
+ instance_input["service_type"] = service_type
+ instance_input["customer_id"] = customer_name
+ instance_input["project_name"] = project_name
+ instance_input["owning_entity_name"] = owning_entity_name
+
+ super().__init__(instance_input)
+
+ def _create(self, instance_input):
+ service_model = sdc_client.service.get_sdc_service(
+ catalog_service_id=sdc.service.get_service_id(
+ instance_input.get("model_name")
+ )
+ ).response_data
+
+ instance_input["model_invariant_id"] = service_model["invariantUUID"]
+ instance_input["model_version_id"] = service_model["uniqueId"]
+
+ category_parameters = vid_client.maintenance.get_category_parameters().response_data
+ for entity in category_parameters.get("categoryParameters", {}).get("owningEntity", []):
+ if entity.get("name") == instance_input.get("owning_entity_name"):
+ instance_input["owning_entity_id"] = entity.get("id")
+ break
+
+ return create_service_instance(instance_input)
+
+ def _post_create(self):
+ pass
+
+ def _submit(self):
+ pass
+
+
+@utility
+def get_service_instance(instance_name):
+ """Queries SDNC for a list of all service instances and returns
+ The service instance that matches <instance name>"""
+ service_instances = sdnc_client.config.get_service_instances().response_data
+ for si in service_instances.get("services", {}).get("service", []):
+ if si.get("service-data", {}).get("service-request-input", {}).get("service-instance-name") == instance_name:
+ return si
+
+ raise ServiceInstanceNotFound("Service Instance {} was not found".format(instance_name))
+
+
+def get_tenant_id(cloud_region, cloud_owner, tenant_name):
+ tenants = aai_client.cloud_infrastructure.get_cloud_region_tenants(
+ cloud_owner=cloud_owner,
+ cloud_region=cloud_region
+ ).response_data
+
+ for tenant in tenants.get("tenant"):
+ if tenant.get("tenant-name") == tenant_name:
+ return tenant.get("tenant-id")
+
+ raise TenantNotFound("Tenant {} was not found in AAI".format(tenant_name))
+
+
+def create_service_instance(instance_input):
+ headers = {"X-TransactionId": str(uuid.uuid4())}
+ service_instance = so_client.service_instantiation.create_service_instance(
+ **instance_input, **headers
+ )
+
+ request_id = service_instance.response_data.get("requestReferences", {}).get(
+ "requestId"
+ )
+
+ instance_input["request_info"] = poll_request(request_id)
+
+ return instance_input
+
+
+@utility
+def poll_request(request_id):
+ """Poll an SO request until completion"""
+ poll_interval = SO_PROPERTIES.POLL_INTERVAL or 30
+ request = None
+ x = 0
+ while x < 30:
+ request = so_client.service_instantiation.get_request_status(
+ request_id=request_id
+ ).response_data
+ status = request.get("request", {}).get("requestStatus", {}).get("requestState")
+ if not status:
+ raise SORequestStatusUnavailable(
+ "Could not determine request for {}".format(request_id)
+ )
+ if status == "FAILED":
+ failure_message = (
+ request.get("request", {}).get("requestStatus", {}).get("statusMessage")
+ )
+ raise SORequestFailed(
+ "Request {} failed with message {}".format(request_id, failure_message)
+ )
+ elif status == "COMPLETE":
+ return request
+
+ x += 1
+
+ sleep(poll_interval)
+
+ raise SORequestTimeout("Request {} timed out polling for status".format(request_id))
+
+
+@utility
+def delete_service_instance(service_instance_name, api_type="GR_API"):
+ """Delete a Service Instance from SO"""
+ si = get_service_instance(service_instance_name)
+ si_id = si.get("service-instance-id")
+ invariant_id = si.get("service-data").get("service-information").get("onap-model-information").get("model-invariant-uuid")
+ version = si.get("service-data").get("service-information").get("onap-model-information").get("model-version")
+
+ return so_client.service_instantiation.delete_service_instance(
+ service_invariant_id=invariant_id,
+ service_name=service_instance_name,
+ service_version=version,
+ service_instance_id=si_id,
+ api_type=api_type,
+ ).response_data
diff --git a/onap-client/onap_client/so/tests/__init__.py b/onap-client/onap_client/so/tests/__init__.py
new file mode 100644
index 0000000..5519a84
--- /dev/null
+++ b/onap-client/onap_client/so/tests/__init__.py
@@ -0,0 +1,36 @@
+# -*- coding: utf8 -*-
+# ============LICENSE_START=======================================================
+# org.onap.vvp/validation-scripts
+# ===================================================================
+# Copyright © 2020 AT&T Intellectual Property. All rights reserved.
+# ===================================================================
+#
+# Unless otherwise specified, all software contained herein is licensed
+# under the Apache License, Version 2.0 (the "License");
+# you may not use this software 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.
+#
+#
+#
+# Unless otherwise specified, all documentation contained herein is licensed
+# under the Creative Commons License, Attribution 4.0 Intl. (the "License");
+# you may not use this documentation except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://creativecommons.org/licenses/by/4.0/
+#
+# Unless required by applicable law or agreed to in writing, documentation
+# 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============================================
diff --git a/onap-client/onap_client/so/vnf_instance.py b/onap-client/onap_client/so/vnf_instance.py
new file mode 100644
index 0000000..4d289a0
--- /dev/null
+++ b/onap-client/onap_client/so/vnf_instance.py
@@ -0,0 +1,267 @@
+# -*- coding: utf8 -*-
+# ============LICENSE_START=======================================================
+# org.onap.vvp/validation-scripts
+# ===================================================================
+# Copyright © 2020 AT&T Intellectual Property. All rights reserved.
+# ===================================================================
+#
+# Unless otherwise specified, all software contained herein is licensed
+# under the Apache License, Version 2.0 (the "License");
+# you may not use this software 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.
+#
+#
+#
+# Unless otherwise specified, all documentation contained herein is licensed
+# under the Creative Commons License, Attribution 4.0 Intl. (the "License");
+# you may not use this documentation except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://creativecommons.org/licenses/by/4.0/
+#
+# Unless required by applicable law or agreed to in writing, documentation
+# 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============================================
+
+import uuid
+
+from onap_client.lib import generate_dummy_string
+from onap_client.resource import Resource
+from onap_client.client.clients import Client as SOClient
+from onap_client.exceptions import (
+ ServiceInstanceNotFound,
+ VNFComponentNotFound,
+ ModuleModelNameNotFound,
+ NoArtifactFoundInModel,
+ VNFInstanceNotFound,
+)
+from onap_client import sdc
+from onap_client import so
+from onap_client.util import utility
+
+
+oc = SOClient()
+so_client = oc.so
+sdc_client = oc.sdc
+sdnc_client = oc.sdnc
+
+
+class VNFInstance(Resource):
+ resource_name = "VNF_INSTANCE"
+ spec = {
+ "vnf_instance_name": {
+ "type": str,
+ "required": False,
+ "default": generate_dummy_string("VNF_"),
+ },
+ "service_instance_name": {"type": str, "required": True},
+ "requestor_id": {"type": str, "required": False, "default": "cs0008"},
+ "model_name": {"type": str, "required": True},
+ "tenant_name": {"type": str, "required": True},
+ "cloud_owner": {"type": str, "required": True},
+ "cloud_region": {"type": str, "required": True},
+ "api_type": {"type": str, "required": False, "default": "GR_API"},
+ "platform": {"type": str, "required": True},
+ "line_of_business": {"type": str, "required": True},
+ }
+
+ def __init__(
+ self,
+ vnf_instance_name,
+ service_instance_name,
+ requestor_id,
+ model_name,
+ tenant_name,
+ cloud_owner,
+ cloud_region,
+ api_type,
+ platform,
+ line_of_business,
+ ):
+ instance_input = {}
+
+ tenant_id = so.service_instance.get_tenant_id(cloud_region, cloud_owner, tenant_name)
+
+ instance_input["vnf_instance_name"] = vnf_instance_name
+ instance_input["service_instance_name"] = service_instance_name
+ instance_input["requestor_id"] = requestor_id
+ instance_input["model_name"] = model_name
+ instance_input["tenant_id"] = tenant_id
+ instance_input["cloud_owner"] = cloud_owner
+ instance_input["cloud_region"] = cloud_region
+ instance_input["api_type"] = api_type
+ instance_input["platform"] = platform
+ instance_input["line_of_business"] = line_of_business
+
+ super().__init__(instance_input)
+
+ def _create(self, instance_input):
+ service_instance = get_service_instance(
+ instance_input.get("service_instance_name")
+ )
+ if not service_instance:
+ raise ServiceInstanceNotFound(
+ "No service instance found for {}".format(
+ instance_input.get("service_instance_name")
+ )
+ )
+ service_instance_id = service_instance.get("service-instance-id")
+ model_information = (
+ service_instance.get("service-data")
+ .get("service-information")
+ .get("onap-model-information")
+ )
+ service_invariant_id = model_information["model-invariant-uuid"]
+ service_model_id = model_information["model-uuid"]
+ service_model_version = model_information["model-version"]
+ service_model_name = model_information["model-name"]
+
+ vnf_component = get_vnf_model_component(
+ service_model_name, instance_input.get("model_name")
+ )
+ if not vnf_component:
+ raise VNFComponentNotFound(
+ "No component found for {}".format(instance_input.get("model_name"))
+ )
+ vnf_model_customization_id = vnf_component["customizationUUID"]
+ vnf_model_version_id = vnf_component["actualComponentUid"]
+ vnf_model_version = vnf_component["componentVersion"]
+
+ vnf_model = sdc_client.vnf.get_catalog_resource(
+ catalog_resource_id=vnf_model_version_id,
+ ).response_data
+ vnf_model_invariant_id = vnf_model["invariantUUID"]
+
+ instance_input["model_invariant_id"] = vnf_model_invariant_id
+ instance_input["model_version_id"] = vnf_model_version_id
+ instance_input["model_customization_id"] = vnf_model_customization_id
+ instance_input["model_version"] = vnf_model_version
+ instance_input["service_model_name"] = service_model_name
+ instance_input["service_model_invariant_id"] = service_invariant_id
+ instance_input["service_model_version"] = service_model_version
+ instance_input["service_model_version_id"] = service_model_id
+ instance_input["service_instance_id"] = service_instance_id
+
+ return create_vnf_instance(instance_input)
+
+ def _post_create(self):
+ pass
+
+ def _submit(self):
+ pass
+
+
+def get_vnf_model_component(service_model_name, vnf_model_name):
+ service_model = sdc_client.service.get_sdc_service(
+ catalog_service_id=sdc.service.get_service_id(service_model_name)
+ ).response_data
+
+ for component in service_model.get("componentInstances", []):
+ if component["componentName"] == vnf_model_name:
+ return component
+ return None
+
+
+def get_service_instance(service_instance_name):
+ service_instances = sdnc_client.config.get_service_instances().response_data
+ for si in service_instances.get("services", {}).get("service", []):
+ si_name = (
+ si.get("service-data", {})
+ .get("service-request-input", {})
+ .get("service-instance-name")
+ )
+ if si_name == service_instance_name:
+ return si
+ return None
+
+
+def get_module_model(vnf_model, heat_template_name):
+ artifact_uuid = None
+ deployment_artifacts = vnf_model.get("deploymentArtifacts", {})
+ for artifact_name, artifact_data in deployment_artifacts.items():
+ if artifact_data.get("artifactName") == heat_template_name:
+ artifact_uuid = artifact_data.get("artifactUUID")
+
+ if not artifact_uuid:
+ raise NoArtifactFoundInModel(
+ "Heat Template {} was not found in service model".format(heat_template_name)
+ )
+
+ group_instances = vnf_model.get("groupInstances", [])
+ for instance in group_instances:
+ if artifact_uuid in instance.get("artifactsUuid", []):
+ # return instance.get("groupName")
+ return instance
+
+ raise ModuleModelNameNotFound(
+ "Module Model Name for {} was not found in service model".format(
+ heat_template_name
+ )
+ )
+
+
+def get_vnf_instance(service_instance, vnf_instance_name):
+ for vnf_instance in (
+ service_instance.get("service-data", {}).get("vnfs", {}).get("vnf", [])
+ ):
+ vi_name = (
+ vnf_instance.get("vnf-data", {}).get("vnf-information", {}).get("vnf-name")
+ )
+ if vi_name == vnf_instance_name:
+ return vnf_instance
+ return None
+
+
+def create_vnf_instance(instance_input):
+ headers = {"X-TransactionId": str(uuid.uuid4())}
+ vnf_instance = so_client.service_instantiation.create_vnf_instance(
+ **instance_input, **headers
+ )
+
+ request_id = vnf_instance.response_data.get("requestReferences", {}).get(
+ "requestId"
+ )
+
+ instance_input["request_info"] = so.service_instance.poll_request(request_id)
+
+ return instance_input
+
+
+@utility
+def delete_vnf_instance(service_instance_name, vnf_instance_name, api_type="GR_API"):
+ """Delete a VNF Instance from SO"""
+ si = so.service_instance.get_service_instance(service_instance_name)
+ si_id = si.get("service-instance-id")
+ for vnfi in si.get("service-data", {}).get("vnfs", {}).get("vnf", []):
+ vnfi_id = vnfi.get("vnf-id")
+ if vnfi.get("vnf-data", {}).get("vnf-request-input", {}).get("vnf-name") == vnf_instance_name:
+ invariant_id = vnfi.get("vnf-data").get("vnf-information").get("onap-model-information").get("model-invariant-uuid")
+ vnf_version = vnfi.get("vnf-data").get("vnf-information").get("onap-model-information").get("model-version")
+ tenant_id = vnfi.get("vnf-data").get("vnf-request-input").get("tenant")
+ cloud_owner = vnfi.get("vnf-data").get("vnf-request-input").get("cloud-owner")
+ cloud_region = vnfi.get("vnf-data").get("vnf-request-input").get("aic-cloud-region")
+ return so_client.service_instantiation.delete_vnf_instance(
+ vnf_invariant_id=invariant_id,
+ vnf_version=vnf_version,
+ vnf_name=vnf_instance_name,
+ cloud_region=cloud_region,
+ cloud_owner=cloud_owner,
+ tenant_id=tenant_id,
+ vnf_instance_id=vnfi_id,
+ service_instance_id=si_id,
+ api_type=api_type,
+ ).response_data
+
+ raise VNFInstanceNotFound("VNF Instance was not found: {} {}".format(service_instance_name, vnf_instance_name))
diff --git a/onap-client/onap_client/tests/__init__.py b/onap-client/onap_client/tests/__init__.py
new file mode 100644
index 0000000..5519a84
--- /dev/null
+++ b/onap-client/onap_client/tests/__init__.py
@@ -0,0 +1,36 @@
+# -*- coding: utf8 -*-
+# ============LICENSE_START=======================================================
+# org.onap.vvp/validation-scripts
+# ===================================================================
+# Copyright © 2020 AT&T Intellectual Property. All rights reserved.
+# ===================================================================
+#
+# Unless otherwise specified, all software contained herein is licensed
+# under the Apache License, Version 2.0 (the "License");
+# you may not use this software 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.
+#
+#
+#
+# Unless otherwise specified, all documentation contained herein is licensed
+# under the Creative Commons License, Attribution 4.0 Intl. (the "License");
+# you may not use this documentation except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://creativecommons.org/licenses/by/4.0/
+#
+# Unless required by applicable law or agreed to in writing, documentation
+# 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============================================
diff --git a/onap-client/onap_client/tests/test.zip b/onap-client/onap_client/tests/test.zip
new file mode 100644
index 0000000..2bd8d04
--- /dev/null
+++ b/onap-client/onap_client/tests/test.zip
Binary files differ
diff --git a/onap-client/onap_client/tests/test_catalog.py b/onap-client/onap_client/tests/test_catalog.py
new file mode 100644
index 0000000..944c115
--- /dev/null
+++ b/onap-client/onap_client/tests/test_catalog.py
@@ -0,0 +1,125 @@
+# -*- coding: utf8 -*-
+# ============LICENSE_START=======================================================
+# org.onap.vvp/validation-scripts
+# ===================================================================
+# Copyright © 2020 AT&T Intellectual Property. All rights reserved.
+# ===================================================================
+#
+# Unless otherwise specified, all software contained herein is licensed
+# under the Apache License, Version 2.0 (the "License");
+# you may not use this software 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.
+#
+#
+#
+# Unless otherwise specified, all documentation contained herein is licensed
+# under the Creative Commons License, Attribution 4.0 Intl. (the "License");
+# you may not use this documentation except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://creativecommons.org/licenses/by/4.0/
+#
+# Unless required by applicable law or agreed to in writing, documentation
+# 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============================================
+
+from onap_client.client.clients import Client
+from onap_client.tests.testdata import TestClient, CATALOG_RESOURCES, THIS_DIR # noqa: F401
+
+
+def test_catalog_items():
+ c = Client()
+
+ assert "MAKE_TEST_REQUEST" in c.test.catalog_items
+
+
+def test_client_namespace():
+ c = Client()
+
+ assert hasattr(c, "test")
+
+
+def test_client_catalog_resources():
+ c = Client()
+
+ assert c.test.catalog_resources == CATALOG_RESOURCES
+
+
+def test_catalog_item_verb():
+ c = Client()
+
+ resource = c.test.catalog_items.get("MAKE_TEST_REQUEST")
+
+ assert resource.verb == "POST"
+
+
+def test_catalog_item_description():
+ c = Client()
+
+ resource = c.test.catalog_items.get("MAKE_TEST_REQUEST")
+
+ assert resource.description == "Test Catalog Request"
+
+
+def test_catalog_item_payload():
+ c = Client()
+
+ resource = c.test.catalog_items.get("MAKE_TEST_REQUEST")
+
+ assert resource.payload == "{}/test_payload.jinja".format(THIS_DIR)
+
+
+def test_catalog_item_uri_parameter():
+ c = Client()
+
+ resource = c.test.catalog_items.get("MAKE_TEST_REQUEST")
+
+ assert "test_uri_parameter" in resource.uri_parameters
+
+
+def test_catalog_item_payload_parameter():
+ c = Client()
+
+ resource = c.test.catalog_items.get("MAKE_TEST_REQUEST")
+
+ assert "test_item_parameter" in resource.payload_parameters
+
+
+def test_catalog_item_headers():
+ c = Client()
+
+ resource = c.test.catalog_items.get("MAKE_TEST_REQUEST")
+
+ headers = {"Accept": "application/json", "Content-Type": "application/json"}
+
+ assert resource.headers == headers
+
+
+def test_catalog_item_auth():
+ c = Client()
+
+ resource = c.test.catalog_items.get("MAKE_TEST_REQUEST")
+
+ auth = ("abc", "123")
+
+ assert resource.auth == auth
+
+
+def test_catalog_item_return_data():
+ c = Client()
+
+ resource = c.test.catalog_items.get("MAKE_TEST_REQUEST")
+
+ assert "return_data_1" in resource.return_data
diff --git a/onap-client/onap_client/tests/test_payload.jinja b/onap-client/onap_client/tests/test_payload.jinja
new file mode 100644
index 0000000..0038703
--- /dev/null
+++ b/onap-client/onap_client/tests/test_payload.jinja
@@ -0,0 +1 @@
+{"test_item_parameter": "{{test_item_parameter}}"} \ No newline at end of file
diff --git a/onap-client/onap_client/tests/test_request.py b/onap-client/onap_client/tests/test_request.py
new file mode 100644
index 0000000..5c7e019
--- /dev/null
+++ b/onap-client/onap_client/tests/test_request.py
@@ -0,0 +1,187 @@
+# -*- coding: utf8 -*-
+# ============LICENSE_START=======================================================
+# org.onap.vvp/validation-scripts
+# ===================================================================
+# Copyright © 2020 AT&T Intellectual Property. All rights reserved.
+# ===================================================================
+#
+# Unless otherwise specified, all software contained herein is licensed
+# under the Apache License, Version 2.0 (the "License");
+# you may not use this software 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.
+#
+#
+#
+# Unless otherwise specified, all documentation contained herein is licensed
+# under the Creative Commons License, Attribution 4.0 Intl. (the "License");
+# you may not use this documentation except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://creativecommons.org/licenses/by/4.0/
+#
+# Unless required by applicable law or agreed to in writing, documentation
+# 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============================================
+
+import responses
+import json
+import os
+import sys
+
+from io import StringIO
+
+from onap_client.client.clients import Client
+from onap_client.client.request import APICatalogRequestObject
+
+from onap_client.tests.testdata import (
+ THIS_DIR,
+ RETURN_DATA,
+)
+from onap_client.tests.testdata import TestClient # noqa: F401
+from onap_client.cli import main
+
+DUMMY_PARAM = "dummy_param"
+
+
+def test_request_uri():
+ c = Client()
+
+ resource = c.test.catalog_items.get("MAKE_FILES_REQUEST")
+
+ request_object = create_request_object(resource)
+
+ assert request_object.uri == "http://this.is.a.test.com/{}".format(DUMMY_PARAM)
+
+
+def test_payload():
+ c = Client()
+
+ resource = c.test.catalog_items.get("MAKE_FILES_REQUEST")
+
+ request_object = create_request_object(resource)
+
+ assert json.loads(request_object.payload) == {"test_item_parameter": DUMMY_PARAM}
+
+
+def test_files():
+ c = Client()
+
+ resource = c.test.catalog_items.get("MAKE_FILES_REQUEST")
+
+ request_object = create_request_object(resource)
+
+ file_path = "{}/test.zip".format(THIS_DIR)
+ with open(file_path, "rb") as f:
+ data = f.read()
+ file_name = os.path.basename(file_path)
+ files = {"upload": [file_name, data, "application/zip"]}
+ assert request_object.files == files
+
+
+@responses.activate
+def test_make_request():
+ responses.add(
+ responses.POST,
+ "http://this.is.a.test.com/{}".format(DUMMY_PARAM),
+ json=RETURN_DATA,
+ )
+
+ c = Client()
+
+ params = {"test_item_parameter": DUMMY_PARAM, "test_uri_parameter": DUMMY_PARAM}
+
+ resp = c.test.make_test_request(**params)
+
+ assert resp.response_data == RETURN_DATA
+
+
+def test_cli():
+ cli_string = ["test", "--help"]
+ temp_out = StringIO()
+ sys.stdout = temp_out
+
+ main(*cli_string)
+
+ sys.stdout.seek(0)
+ output = sys.stdout.read()
+
+ sys.stdout = sys.__stdout__
+
+ assert output.find("make-test-request") != -1
+
+
+def test_cli_request_help():
+ cli_string = ["test", "make-test-request", "--help"]
+ temp_out = StringIO()
+ sys.stdout = temp_out
+
+ main(*cli_string)
+ sys.stdout.seek(0)
+ output = sys.stdout.read()
+
+ sys.stdout = sys.__stdout__
+
+ assert output.find("--test-item-parameter") != -1
+
+
+@responses.activate
+def test_cli_request():
+ temp_out = StringIO()
+ sys.stdout = temp_out
+
+ responses.add(
+ responses.POST,
+ "http://this.is.a.test.com/{}".format(DUMMY_PARAM),
+ json=RETURN_DATA,
+ )
+
+ cli_string = [
+ "test",
+ "make-test-request",
+ "--test-item-parameter",
+ DUMMY_PARAM,
+ "--test-uri-parameter",
+ DUMMY_PARAM,
+ ]
+
+ main(*cli_string)
+
+ sys.stdout.seek(0)
+ output = sys.stdout.read()
+
+ sys.stdout = sys.__stdout__
+
+ assert json.loads(output) == RETURN_DATA
+
+
+def create_request_object(catalog_item):
+ payload_input = {}
+ uri_input = {}
+ file_input = {}
+
+ for param in catalog_item.payload_parameters:
+ payload_input[param] = DUMMY_PARAM
+
+ for param in catalog_item.uri_parameters:
+ uri_input[param] = DUMMY_PARAM
+
+ file_input["file_path"] = "{}/test.zip".format(THIS_DIR)
+
+ return APICatalogRequestObject(
+ catalog_item,
+ payload_parameters=payload_input,
+ uri_parameters=uri_input,
+ file_parameters=file_input,
+ )
diff --git a/onap-client/onap_client/tests/test_resource.py b/onap-client/onap_client/tests/test_resource.py
new file mode 100644
index 0000000..5b4124a
--- /dev/null
+++ b/onap-client/onap_client/tests/test_resource.py
@@ -0,0 +1,68 @@
+# -*- coding: utf8 -*-
+# ============LICENSE_START=======================================================
+# org.onap.vvp/validation-scripts
+# ===================================================================
+# Copyright © 2020 AT&T Intellectual Property. All rights reserved.
+# ===================================================================
+#
+# Unless otherwise specified, all software contained herein is licensed
+# under the Apache License, Version 2.0 (the "License");
+# you may not use this software 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.
+#
+#
+#
+# Unless otherwise specified, all documentation contained herein is licensed
+# under the Creative Commons License, Attribution 4.0 Intl. (the "License");
+# you may not use this documentation except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://creativecommons.org/licenses/by/4.0/
+#
+# Unless required by applicable law or agreed to in writing, documentation
+# 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============================================
+
+from onap_client.resource import Resource
+from onap_client.lib import generate_dummy_string, generate_dummy_date
+
+
+class TestResource(Resource):
+ def __init__(self, test_param):
+ test_input = {}
+
+ test_input["param1"] = test_param
+ test_input["param2"] = generate_dummy_string()
+ test_input["param3"] = generate_dummy_date()
+
+ super().__init__(test_input)
+
+ def _create(self, create_input):
+ return create_input
+
+ def _post_create(self):
+ pass
+
+ def _submit(self):
+ pass
+
+
+def test_resource():
+ test_param = "abc"
+
+ r = TestResource(test_param)
+ r.print()
+
+ assert hasattr(r, "param1") and r.param1 == test_param
diff --git a/onap-client/onap_client/tests/testdata.py b/onap-client/onap_client/tests/testdata.py
new file mode 100644
index 0000000..ade4713
--- /dev/null
+++ b/onap-client/onap_client/tests/testdata.py
@@ -0,0 +1,92 @@
+# -*- coding: utf8 -*-
+# ============LICENSE_START=======================================================
+# org.onap.vvp/validation-scripts
+# ===================================================================
+# Copyright © 2020 AT&T Intellectual Property. All rights reserved.
+# ===================================================================
+#
+# Unless otherwise specified, all software contained herein is licensed
+# under the Apache License, Version 2.0 (the "License");
+# you may not use this software 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.
+#
+#
+#
+# Unless otherwise specified, all documentation contained herein is licensed
+# under the Creative Commons License, Attribution 4.0 Intl. (the "License");
+# you may not use this documentation except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://creativecommons.org/licenses/by/4.0/
+#
+# Unless required by applicable law or agreed to in writing, documentation
+# 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============================================
+
+from functools import partial
+from os.path import dirname, abspath
+
+from onap_client.client.clients import Client
+
+TEST_URI = "http://this.is.a.test.com"
+THIS_DIR = dirname(abspath(__file__))
+
+
+class TestClient(Client):
+ @property
+ def namespace(self):
+ return "test"
+
+ @property
+ def catalog_resources(self):
+ return CATALOG_RESOURCES
+
+
+CATALOG_RESOURCES = {
+ "MAKE_TEST_REQUEST": {
+ "verb": "POST",
+ "description": "Test Catalog Request",
+ "uri": partial("{endpoint}/{test_uri_parameter}".format, endpoint=TEST_URI),
+ "uri-parameters": ["test_uri_parameter"],
+ "payload": "{}/test_payload.jinja".format(THIS_DIR),
+ "payload-parameters": ["test_item_parameter"],
+ "success_code": 200,
+ "headers": {"Accept": "application/json", "Content-Type": "application/json"},
+ "return_data": {
+ "return_data_1": ("return_parameter_1",),
+ "return_data_2": ("return_parameter_2",),
+ },
+ "auth": ("abc", "123"),
+ },
+ "MAKE_FILES_REQUEST": {
+ "verb": "POST",
+ "description": "Test Catalog Request With Files",
+ "uri": partial("{endpoint}/{test_uri_parameter}".format, endpoint=TEST_URI),
+ "uri-parameters": ["test_uri_parameter"],
+ "files-parameters": ["file_path", "file_type"],
+ "payload": "{}/test_payload.jinja".format(THIS_DIR),
+ "payload-parameters": ["test_item_parameter"],
+ "success_code": 200,
+ "headers": {"Accept": "application/json", "Content-Type": "application/json"},
+ "return_data": {
+ "return_data_1": ("return_parameter_1",),
+ "return_data_2": ("return_parameter_2",),
+ },
+ "auth": ("abc", "123"),
+ },
+}
+
+
+RETURN_DATA = {"return_parameter_1": "abc", "return_parameter_2": "123"}
diff --git a/onap-client/onap_client/tests/utils.py b/onap-client/onap_client/tests/utils.py
new file mode 100644
index 0000000..ddcca9e
--- /dev/null
+++ b/onap-client/onap_client/tests/utils.py
@@ -0,0 +1,79 @@
+# -*- coding: utf8 -*-
+# ============LICENSE_START=======================================================
+# org.onap.vvp/validation-scripts
+# ===================================================================
+# Copyright © 2020 AT&T Intellectual Property. All rights reserved.
+# ===================================================================
+#
+# Unless otherwise specified, all software contained herein is licensed
+# under the Apache License, Version 2.0 (the "License");
+# you may not use this software 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.
+#
+#
+#
+# Unless otherwise specified, all documentation contained herein is licensed
+# under the Creative Commons License, Attribution 4.0 Intl. (the "License");
+# you may not use this documentation except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://creativecommons.org/licenses/by/4.0/
+#
+# Unless required by applicable law or agreed to in writing, documentation
+# 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============================================
+
+import responses
+import functools
+
+
+def mockup_client(client):
+ for k, v in client.catalog_items.items():
+ mockup_catalog_item(v)
+
+
+def mockup_return_item(item, item_list):
+ items = list(item_list)
+ if not items:
+ return {item: item}
+ new_item = items.pop(0)
+ return {item: mockup_return_item(new_item, items)}
+
+
+def mockup_catalog_item(
+ catalog_resource, override_return_data=None, override_uri_params={}
+):
+ uri = catalog_resource.uri
+ if isinstance(uri, functools.partial):
+ params = {}
+ for param in catalog_resource.uri_parameters:
+ params[param] = param
+ params.update(override_uri_params)
+ uri = uri(**params)
+
+ return_data = catalog_resource.return_data
+ return_items = {}
+ for k, v in return_data.items():
+ return_items.update(mockup_return_item(k, v))
+
+ if override_return_data:
+ return_items = override_return_data
+
+ responses.add(
+ getattr(responses, catalog_resource.verb),
+ uri,
+ json=return_items,
+ status=catalog_resource.success_code,
+ )
diff --git a/onap-client/onap_client/util.py b/onap-client/onap_client/util.py
new file mode 100644
index 0000000..d3148d0
--- /dev/null
+++ b/onap-client/onap_client/util.py
@@ -0,0 +1,134 @@
+# -*- coding: utf8 -*-
+# ============LICENSE_START=======================================================
+# org.onap.vvp/validation-scripts
+# ===================================================================
+# Copyright © 2020 AT&T Intellectual Property. All rights reserved.
+# ===================================================================
+#
+# Unless otherwise specified, all software contained herein is licensed
+# under the Apache License, Version 2.0 (the "License");
+# you may not use this software 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.
+#
+#
+#
+# Unless otherwise specified, all documentation contained herein is licensed
+# under the Creative Commons License, Attribution 4.0 Intl. (the "License");
+# you may not use this documentation except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://creativecommons.org/licenses/by/4.0/
+#
+# Unless required by applicable law or agreed to in writing, documentation
+# 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============================================
+
+import json
+from prettytable import PrettyTable
+
+
+def utility_cli(onap_client, cli_arguments):
+ functions = onap_client.utility_functions
+
+ if len(cli_arguments) == 0 or cli_arguments[0] == "--help":
+ help(functions)
+ else:
+ while cli_arguments:
+ argument = cli_arguments.pop(0)
+
+ if argument == "--help":
+ help(functions)
+ return
+
+ argument = convert_to_underscores(argument)
+ functions = functions.get(argument)
+ if not functions:
+ print("Invalid argument {}. Try --help.".format(argument))
+ return
+
+ if callable(functions):
+ if cli_arguments[0] == "--help":
+ help(functions)
+ return
+
+ if functions.__code__.co_argcount != len(cli_arguments):
+ print(
+ "Function requires {} arguments, but {} were passed. Try --help.".format(
+ functions.__code__.co_argcount, len(cli_arguments)
+ )
+ )
+ return
+
+ return_data = functions(*cli_arguments[0:])
+ if isinstance(return_data, str):
+ print(return_data)
+ elif isinstance(return_data, dict) or isinstance(return_data, list):
+ print(json.dumps(return_data, indent=4))
+
+ return
+
+
+def convert_to_underscores(argument):
+ return argument.replace("-", "_")
+
+
+def convert_to_dash(argument):
+ return argument.replace("_", "-")
+
+
+def help(functions):
+ actions = {}
+ actions["--help"] = ("", "")
+ if isinstance(functions, dict):
+ for k, v in functions.items():
+ actions[convert_to_dash(k)] = (
+ v.__doc__,
+ list(v.__code__.co_varnames[: v.__code__.co_argcount]),
+ )
+ elif callable(functions):
+ actions[convert_to_dash(functions.__name__)] = (
+ functions.__doc__,
+ list(functions.__code__.co_varnames[: functions.__code__.co_argcount]),
+ )
+
+ print(help_table(actions))
+
+
+def help_table(actions):
+ x = PrettyTable()
+
+ x.field_names = [
+ "name",
+ "description",
+ "parameters",
+ ]
+ x.align["name"] = "l"
+ x.align["description"] = "l"
+ x.align["parameters"] = "l"
+
+ for action, data in actions.items():
+ name = action
+ description = data[0]
+ parameters = []
+ parameters.extend("<{}>".format(x) for x in data[1])
+ x.add_row([name, description, "\n".join(parameters)])
+ x.add_row(["", "", ""])
+
+ return x
+
+
+def utility(func):
+ func.utility_function = True
+ return func
diff --git a/onap-client/onap_client/vid/__init__.py b/onap-client/onap_client/vid/__init__.py
new file mode 100644
index 0000000..1cb6244
--- /dev/null
+++ b/onap-client/onap_client/vid/__init__.py
@@ -0,0 +1,40 @@
+# -*- coding: utf8 -*-
+# ============LICENSE_START=======================================================
+# org.onap.vvp/validation-scripts
+# ===================================================================
+# Copyright © 2020 AT&T Intellectual Property. All rights reserved.
+# ===================================================================
+#
+# Unless otherwise specified, all software contained herein is licensed
+# under the Apache License, Version 2.0 (the "License");
+# you may not use this software 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.
+#
+#
+#
+# Unless otherwise specified, all documentation contained herein is licensed
+# under the Creative Commons License, Attribution 4.0 Intl. (the "License");
+# you may not use this documentation except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://creativecommons.org/licenses/by/4.0/
+#
+# Unless required by applicable law or agreed to in writing, documentation
+# 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============================================
+
+from onap_client.config import APP_CONFIG
+
+VID_PROPERTIES = APP_CONFIG.vid
diff --git a/onap-client/onap_client/vid/catalog/__init__.py b/onap-client/onap_client/vid/catalog/__init__.py
new file mode 100644
index 0000000..5519a84
--- /dev/null
+++ b/onap-client/onap_client/vid/catalog/__init__.py
@@ -0,0 +1,36 @@
+# -*- coding: utf8 -*-
+# ============LICENSE_START=======================================================
+# org.onap.vvp/validation-scripts
+# ===================================================================
+# Copyright © 2020 AT&T Intellectual Property. All rights reserved.
+# ===================================================================
+#
+# Unless otherwise specified, all software contained herein is licensed
+# under the Apache License, Version 2.0 (the "License");
+# you may not use this software 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.
+#
+#
+#
+# Unless otherwise specified, all documentation contained herein is licensed
+# under the Creative Commons License, Attribution 4.0 Intl. (the "License");
+# you may not use this documentation except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://creativecommons.org/licenses/by/4.0/
+#
+# Unless required by applicable law or agreed to in writing, documentation
+# 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============================================
diff --git a/onap-client/onap_client/vid/catalog/maintenance_catalog.py b/onap-client/onap_client/vid/catalog/maintenance_catalog.py
new file mode 100644
index 0000000..2f01a79
--- /dev/null
+++ b/onap-client/onap_client/vid/catalog/maintenance_catalog.py
@@ -0,0 +1,154 @@
+# -*- coding: utf8 -*-
+# ============LICENSE_START=======================================================
+# org.onap.vvp/validation-scripts
+# ===================================================================
+# Copyright © 2020 AT&T Intellectual Property. All rights reserved.
+# ===================================================================
+#
+# Unless otherwise specified, all software contained herein is licensed
+# under the Apache License, Version 2.0 (the "License");
+# you may not use this software 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.
+#
+#
+#
+# Unless otherwise specified, all documentation contained herein is licensed
+# under the Creative Commons License, Attribution 4.0 Intl. (the "License");
+# you may not use this documentation except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://creativecommons.org/licenses/by/4.0/
+#
+# Unless required by applicable law or agreed to in writing, documentation
+# 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============================================
+
+import uuid
+from functools import partial
+
+from onap_client import vid
+from onap_client import config
+from onap_client.vid.client import VIDClient
+
+PAYLOADS_DIR = config.PAYLOADS_DIR
+vid_properties = vid.VID_PROPERTIES
+application_id = config.APPLICATION_ID
+
+
+class MaintenanceClient(VIDClient):
+ @property
+ def catalog_resources(self):
+ return CATALOG_RESOURCES
+
+ @property
+ def namespace(self):
+ return "maintenance"
+
+
+CATALOG_RESOURCES = {
+ "CREATE_OWNING_ENTITY": {
+ "verb": "POST",
+ "description": "Creates an owning entity in VID",
+ "uri": partial(
+ "{endpoint}{service_path}/category_parameter/owningEntity".format,
+ endpoint=vid_properties.VID_ENDPOINT,
+ service_path=vid_properties.VID_MAINTENANCE_PATH,
+ ),
+ "payload-parameters": ["name"],
+ "payload": "{}/vid_maintenance.jinja".format(PAYLOADS_DIR),
+ "success_code": 200,
+ "headers": {
+ "Accept": "application/json",
+ "Content-Type": "application/json",
+ "X-TransactionId": str(uuid.uuid4()),
+ "X-FromAppId": application_id,
+ },
+ "auth": (vid_properties.VID_USERNAME, vid_properties.VID_PASSWORD,),
+ },
+ "CREATE_LINE_OF_BUSINESS": {
+ "verb": "POST",
+ "description": "Creates a line of business in VID",
+ "uri": partial(
+ "{endpoint}{service_path}/category_parameter/lineOfBusiness".format,
+ endpoint=vid_properties.VID_ENDPOINT,
+ service_path=vid_properties.VID_MAINTENANCE_PATH,
+ ),
+ "payload-parameters": ["name"],
+ "payload": "{}/vid_maintenance.jinja".format(PAYLOADS_DIR),
+ "success_code": 200,
+ "headers": {
+ "Accept": "application/json",
+ "Content-Type": "application/json",
+ "X-TransactionId": str(uuid.uuid4()),
+ "X-FromAppId": application_id,
+ },
+ "auth": (vid_properties.VID_USERNAME, vid_properties.VID_PASSWORD,),
+ },
+ "CREATE_PLATFORM": {
+ "verb": "POST",
+ "description": "Creates a platform in VID",
+ "uri": partial(
+ "{endpoint}{service_path}/category_parameter/platform".format,
+ endpoint=vid_properties.VID_ENDPOINT,
+ service_path=vid_properties.VID_MAINTENANCE_PATH,
+ ),
+ "payload-parameters": ["name"],
+ "payload": "{}/vid_maintenance.jinja".format(PAYLOADS_DIR),
+ "success_code": 200,
+ "headers": {
+ "Accept": "application/json",
+ "Content-Type": "application/json",
+ "X-TransactionId": str(uuid.uuid4()),
+ "X-FromAppId": application_id,
+ },
+ "auth": (vid_properties.VID_USERNAME, vid_properties.VID_PASSWORD,),
+ },
+ "CREATE_PROJECT": {
+ "verb": "POST",
+ "description": "Creates a project in VID",
+ "uri": partial(
+ "{endpoint}{service_path}/category_parameter/project".format,
+ endpoint=vid_properties.VID_ENDPOINT,
+ service_path=vid_properties.VID_MAINTENANCE_PATH,
+ ),
+ "payload-parameters": ["name"],
+ "payload": "{}/vid_maintenance.jinja".format(PAYLOADS_DIR),
+ "success_code": 200,
+ "headers": {
+ "Accept": "application/json",
+ "Content-Type": "application/json",
+ "X-TransactionId": str(uuid.uuid4()),
+ "X-FromAppId": application_id,
+ },
+ "auth": (vid_properties.VID_USERNAME, vid_properties.VID_PASSWORD,),
+ },
+ "GET_CATEGORY_PARAMETERS": {
+ "verb": "GET",
+ "description": "Returns the category parameters currently stored in VID",
+ "uri": partial(
+ "{endpoint}{service_path}/category_parameter?familyName=PARAMETER_STANDARDIZATION".format,
+ endpoint=vid_properties.VID_ENDPOINT,
+ service_path=vid_properties.VID_MAINTENANCE_PATH,
+ ),
+ "success_code": 200,
+ "headers": {
+ "Accept": "application/json",
+ "Content-Type": "application/json",
+ "X-TransactionId": str(uuid.uuid4()),
+ "X-FromAppId": application_id,
+ },
+ "auth": (vid_properties.VID_USERNAME, vid_properties.VID_PASSWORD,),
+ },
+}
diff --git a/onap-client/onap_client/vid/client.py b/onap-client/onap_client/vid/client.py
new file mode 100644
index 0000000..3b95618
--- /dev/null
+++ b/onap-client/onap_client/vid/client.py
@@ -0,0 +1,69 @@
+# -*- coding: utf8 -*-
+# ============LICENSE_START=======================================================
+# org.onap.vvp/validation-scripts
+# ===================================================================
+# Copyright © 2020 AT&T Intellectual Property. All rights reserved.
+# ===================================================================
+#
+# Unless otherwise specified, all software contained herein is licensed
+# under the Apache License, Version 2.0 (the "License");
+# you may not use this software 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.
+#
+#
+#
+# Unless otherwise specified, all documentation contained herein is licensed
+# under the Creative Commons License, Attribution 4.0 Intl. (the "License");
+# you may not use this documentation except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://creativecommons.org/licenses/by/4.0/
+#
+# Unless required by applicable law or agreed to in writing, documentation
+# 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============================================
+
+from functools import partial
+from onap_client import vid
+from onap_client.client.clients import Client
+from onap_client import config
+
+vid_properties = vid.VID_PROPERTIES
+application_id = config.APPLICATION_ID
+
+
+class VIDClient(Client):
+ @property
+ def namespace(self):
+ return "vid"
+
+ @property
+ def catalog_resources(self):
+ return CATALOG_RESOURCES
+
+
+CATALOG_RESOURCES = {
+ "HEALTH_CHECK": {
+ "verb": "GET",
+ "description": "Queries VID health check endpoint",
+ "uri": partial(
+ "{endpoint}{service_path}".format,
+ endpoint=vid_properties.VID_ENDPOINT,
+ service_path=vid_properties.VID_HEALTH_CHECK_PATH,
+ ),
+ "success_code": 200,
+ "auth": (vid_properties.VID_USERNAME, vid_properties.VID_PASSWORD,),
+ },
+}
diff --git a/onap-client/onap_client/vid/tests/__init__.py b/onap-client/onap_client/vid/tests/__init__.py
new file mode 100644
index 0000000..5519a84
--- /dev/null
+++ b/onap-client/onap_client/vid/tests/__init__.py
@@ -0,0 +1,36 @@
+# -*- coding: utf8 -*-
+# ============LICENSE_START=======================================================
+# org.onap.vvp/validation-scripts
+# ===================================================================
+# Copyright © 2020 AT&T Intellectual Property. All rights reserved.
+# ===================================================================
+#
+# Unless otherwise specified, all software contained herein is licensed
+# under the Apache License, Version 2.0 (the "License");
+# you may not use this software 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.
+#
+#
+#
+# Unless otherwise specified, all documentation contained herein is licensed
+# under the Creative Commons License, Attribution 4.0 Intl. (the "License");
+# you may not use this documentation except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://creativecommons.org/licenses/by/4.0/
+#
+# Unless required by applicable law or agreed to in writing, documentation
+# 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============================================