aboutsummaryrefslogtreecommitdiffstats
path: root/heat/vFW_CNF_CDS/automation
diff options
context:
space:
mode:
authorMichal Chabiera <michal.chabiera@orange.com>2020-12-07 18:18:27 +0100
committerMorgan Richomme <morgan.richomme@orange.com>2020-12-07 21:27:43 +0000
commit303fe3b4343838ae4c7b7a2511cb065f3abe7699 (patch)
treeb440bd4803ec5d8a19d3d4398573701456c5621b /heat/vFW_CNF_CDS/automation
parent28107b9b3116d05eead52f9b88bfa385f4762f0a (diff)
Automation scripts for vFW_CNF_CDS usecase
Automation scripts for vFW_CNF_CDS usecase Issue-ID: INT-1658 Signed-off-by: Michal Chabiera <michal.chabiera@orange.com> Change-Id: I32ba9afe0ca95c5db66c6789756508a76a13f948 (cherry picked from commit 6a7d598d08aa0e145a5aff71c4ed6deafb098e39)
Diffstat (limited to 'heat/vFW_CNF_CDS/automation')
-rwxr-xr-xheat/vFW_CNF_CDS/automation/Pipfile13
-rwxr-xr-xheat/vFW_CNF_CDS/automation/README.md18
-rwxr-xr-xheat/vFW_CNF_CDS/automation/__init__.py20
-rw-r--r--heat/vFW_CNF_CDS/automation/artifacts/cluster_kubeconfig0
-rw-r--r--heat/vFW_CNF_CDS/automation/artifacts/onap_kubeconfig0
-rwxr-xr-xheat/vFW_CNF_CDS/automation/config.py72
-rwxr-xr-xheat/vFW_CNF_CDS/automation/crds/crd1117
-rwxr-xr-xheat/vFW_CNF_CDS/automation/crds/crd234
-rwxr-xr-xheat/vFW_CNF_CDS/automation/create_k8s_region.py127
-rwxr-xr-xheat/vFW_CNF_CDS/automation/delete.py61
-rwxr-xr-xheat/vFW_CNF_CDS/automation/instantiate.py209
-rwxr-xr-xheat/vFW_CNF_CDS/automation/k8s_client.py59
-rwxr-xr-xheat/vFW_CNF_CDS/automation/onboard.py98
-rwxr-xr-xheat/vFW_CNF_CDS/automation/so_db_adapter.py92
-rwxr-xr-xheat/vFW_CNF_CDS/automation/update_connectivity_info.py49
15 files changed, 969 insertions, 0 deletions
diff --git a/heat/vFW_CNF_CDS/automation/Pipfile b/heat/vFW_CNF_CDS/automation/Pipfile
new file mode 100755
index 00000000..7c21af18
--- /dev/null
+++ b/heat/vFW_CNF_CDS/automation/Pipfile
@@ -0,0 +1,13 @@
+[[source]]
+name = "pypi"
+url = "https://pypi.org/simple"
+verify_ssl = true
+
+[dev-packages]
+
+[packages]
+onapsdk = "<=7.3.0"
+kubernetes = "<=12.0.1"
+
+[requires]
+python_version = "3.8"
diff --git a/heat/vFW_CNF_CDS/automation/README.md b/heat/vFW_CNF_CDS/automation/README.md
new file mode 100755
index 00000000..bbc9cdeb
--- /dev/null
+++ b/heat/vFW_CNF_CDS/automation/README.md
@@ -0,0 +1,18 @@
+# vFW_CNF_CDS use case automation
+
+1. Install required packages with pipenv `pipenv install`
+2. Run virtual environment `pipenv shell --fancy`
+3. Add kubeconfig files, one for ONAP cluster, and one for k8s cluster that will host vFW:
+ - `artifacts/cluster_kubeconfig`
+ - `artifacts/onap_kubeconfig`
+4. Prepare onboarding packages `cd ../templates/ && make && cd ../automation/`
+5. Modify `config.py`:
+ - NATIVE - enables native helm orchestration path in SO
+ - CLOUD_REGION
+ - GLOBAL_CUSTOMER_ID
+ - VENDOR
+ - SERVICENAME
+ - CUSTOMER_RESOURCE_DEFINITIONS - add list of CRDs to be installed on non KUD k8s cluster
+6. Run script `python create_k8s_region.py` in order to create **k8s cloud region**
+7. Onboard **vFW** `python onboard.py`
+8. Instantiate **vFW** `python instantiate.py`
diff --git a/heat/vFW_CNF_CDS/automation/__init__.py b/heat/vFW_CNF_CDS/automation/__init__.py
new file mode 100755
index 00000000..c9ad83e5
--- /dev/null
+++ b/heat/vFW_CNF_CDS/automation/__init__.py
@@ -0,0 +1,20 @@
+# ============LICENSE_START=======================================================
+# Copyright (C) 2020 Orange
+# ================================================================================
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# ============LICENSE_END=========================================================
+
+from .config import Config
+from .so_db_adapter import SoDBAdapter
+from .k8s_client import K8sClient
diff --git a/heat/vFW_CNF_CDS/automation/artifacts/cluster_kubeconfig b/heat/vFW_CNF_CDS/automation/artifacts/cluster_kubeconfig
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/heat/vFW_CNF_CDS/automation/artifacts/cluster_kubeconfig
diff --git a/heat/vFW_CNF_CDS/automation/artifacts/onap_kubeconfig b/heat/vFW_CNF_CDS/automation/artifacts/onap_kubeconfig
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/heat/vFW_CNF_CDS/automation/artifacts/onap_kubeconfig
diff --git a/heat/vFW_CNF_CDS/automation/config.py b/heat/vFW_CNF_CDS/automation/config.py
new file mode 100755
index 00000000..f5d39c16
--- /dev/null
+++ b/heat/vFW_CNF_CDS/automation/config.py
@@ -0,0 +1,72 @@
+# ============LICENSE_START=======================================================
+# Copyright (C) 2020 Orange
+# ================================================================================
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# ============LICENSE_END=========================================================
+
+class Config:
+ #### REGION DETAILS ####
+ NATIVE = False
+ COMPLEX_ID = "complex"
+ CLOUD_OWNER = "k8sCloudOwner"
+ CLOUD_REGION = "k8s-region-1"
+ AVAILABILITY_ZONE_NAME = "k8s-availability-zone"
+ HYPERVISOR_TYPE = "k8s"
+ TENANT_NAME = "k8s-tenant-1"
+ K8S_NAMESPACE = "vfirewall"
+ CUSTOMER_RESOURCE_DEFINITIONS = []
+# Uncomment, if you want to run on non KUD k8s cluster
+# CUSTOMER_RESOURCE_DEFINITIONS = ["crds/crd1",
+# "crds/crd2"]
+
+ CLUSTER_KUBECONFIG_PATH = "artifacts/cluster_kubeconfig"
+ ONAP_KUBECONFIG_PATH = "artifacts/onap_kubeconfig"
+
+ #### SERVICE DETAILS ####
+ GLOBAL_CUSTOMER_ID = "customer_cnf"
+ VSPFILE = "vsp/vfw_k8s_demo.zip"
+ if NATIVE:
+ VSPFILE = "vsp/native_vfw_k8s_demo.zip"
+ VENDOR = "vendor_cnf"
+ SERVICENAME = "vfw_k8s_demo_CNF"
+ VSPNAME = "VSP_" + SERVICENAME
+ VFNAME = "VF_" + SERVICENAME
+ SERVICE_INSTANCE_NAME = "INSTANCE_" + SERVICENAME
+ SDNC_ARTIFACT_NAME = "vnf"
+ VF_MODULE_PREFIX = ""
+ if NATIVE:
+ VF_MODULE_PREFIX = "helm_"
+
+ VF_MODULE_LIST = {VF_MODULE_PREFIX + "base_template":
+ {"name": VF_MODULE_PREFIX + "base_template",
+ "k8s-rb-profile-name": "vfw-cnf-cds-base-profile",
+ "k8s-rb-profile-namespace": K8S_NAMESPACE},
+ VF_MODULE_PREFIX + "vfw":
+ {"name": VF_MODULE_PREFIX + "vfw",
+ "k8s-rb-profile-name": "vfw-cnf-cds-base-profile",
+ "k8s-rb-profile-namespace": K8S_NAMESPACE},
+ VF_MODULE_PREFIX + "vpkg":
+ {"name": VF_MODULE_PREFIX + "vpkg",
+ "k8s-rb-profile-name": "vfw-cnf-cds-base-profile",
+ "k8s-rb-profile-namespace": K8S_NAMESPACE},
+ VF_MODULE_PREFIX + "vsn":
+ {"name": VF_MODULE_PREFIX + "vsn",
+ "k8s-rb-profile-name": "vfw-cnf-cds-base-profile",
+ "k8s-rb-profile-namespace": K8S_NAMESPACE}}
+
+ ######## DEFAULT VALUES ########
+ OWNING_ENTITY = "OE-Demonstration"
+ PROJECT = "Project-Demonstration"
+ PLATFORM = "test"
+ LINE_OF_BUSINESS = "LOB-Demonstration"
diff --git a/heat/vFW_CNF_CDS/automation/crds/crd1 b/heat/vFW_CNF_CDS/automation/crds/crd1
new file mode 100755
index 00000000..793261e0
--- /dev/null
+++ b/heat/vFW_CNF_CDS/automation/crds/crd1
@@ -0,0 +1,117 @@
+apiVersion: apiextensions.k8s.io/v1beta1
+kind: CustomResourceDefinition
+metadata:
+ name: networks.k8s.plugin.opnfv.org
+spec:
+ group: k8s.plugin.opnfv.org
+ names:
+ kind: Network
+ listKind: NetworkList
+ plural: networks
+ singular: network
+ scope: Namespaced
+ subresources:
+ status: {}
+ validation:
+ openAPIV3Schema:
+ properties:
+ apiVersion:
+ description: 'APIVersion defines the versioned schema of this representation
+ of an object. Servers should convert recognized schemas to the latest
+ internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#resources'
+ type: string
+ kind:
+ description: 'Kind is a string value representing the REST resource this
+ object represents. Servers may infer this from the endpoint the client
+ submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds'
+ type: string
+ metadata:
+ type: object
+ spec:
+ properties:
+ cniType:
+ description: 'INSERT ADDITIONAL SPEC FIELDS - desired state of cluster
+ Important: Run "operator-sdk generate k8s" to regenerate code after
+ modifying this file Add custom validation using kubebuilder tags:
+ https://book-v1.book.kubebuilder.io/beyond_basics/generating_crd.html'
+ type: string
+ dns:
+ properties:
+ domain:
+ type: string
+ nameservers:
+ items:
+ type: string
+ type: array
+ options:
+ items:
+ type: string
+ type: array
+ search:
+ items:
+ type: string
+ type: array
+ type: object
+ ipv4Subnets:
+ items:
+ properties:
+ excludeIps:
+ type: string
+ gateway:
+ type: string
+ name:
+ type: string
+ subnet:
+ type: string
+ required:
+ - name
+ - subnet
+ type: object
+ type: array
+ ipv6Subnets:
+ items:
+ properties:
+ excludeIps:
+ type: string
+ gateway:
+ type: string
+ name:
+ type: string
+ subnet:
+ type: string
+ required:
+ - name
+ - subnet
+ type: object
+ type: array
+ routes:
+ items:
+ properties:
+ dst:
+ type: string
+ gw:
+ type: string
+ required:
+ - dst
+ type: object
+ type: array
+ required:
+ - cniType
+ - ipv4Subnets
+ type: object
+ status:
+ properties:
+ state:
+ description: 'INSERT ADDITIONAL STATUS FIELD - define observed state
+ of cluster Important: Run "operator-sdk generate k8s" to regenerate
+ code after modifying this file Add custom validation using kubebuilder
+ tags: https://book-v1.book.kubebuilder.io/beyond_basics/generating_crd.html'
+ type: string
+ required:
+ - state
+ type: object
+ version: v1alpha1
+ versions:
+ - name: v1alpha1
+ served: true
+ storage: true
diff --git a/heat/vFW_CNF_CDS/automation/crds/crd2 b/heat/vFW_CNF_CDS/automation/crds/crd2
new file mode 100755
index 00000000..dcf52577
--- /dev/null
+++ b/heat/vFW_CNF_CDS/automation/crds/crd2
@@ -0,0 +1,34 @@
+apiVersion: apiextensions.k8s.io/v1beta1
+kind: CustomResourceDefinition
+metadata:
+ name: network-attachment-definitions.k8s.cni.cncf.io
+spec:
+ group: k8s.cni.cncf.io
+ scope: Namespaced
+ names:
+ plural: network-attachment-definitions
+ singular: network-attachment-definition
+ kind: NetworkAttachmentDefinition
+ shortNames:
+ - net-attach-def
+ validation:
+ openAPIV3Schema:
+ properties:
+ apiVersion:
+ type: string
+ kind:
+ type: string
+ metadata:
+ type: object
+ spec:
+ type: object
+ required:
+ - config
+ properties:
+ config:
+ type: string
+ version: v1
+ versions:
+ - name: v1
+ served: true
+ storage: true
diff --git a/heat/vFW_CNF_CDS/automation/create_k8s_region.py b/heat/vFW_CNF_CDS/automation/create_k8s_region.py
new file mode 100755
index 00000000..cfbec8cc
--- /dev/null
+++ b/heat/vFW_CNF_CDS/automation/create_k8s_region.py
@@ -0,0 +1,127 @@
+# ============LICENSE_START=======================================================
+# Copyright (C) 2020 Orange
+# ================================================================================
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# ============LICENSE_END=========================================================
+
+import logging
+import os
+from uuid import uuid4
+
+from config import Config
+from k8s_client import K8sClient
+from so_db_adapter import SoDBAdapter
+from onapsdk.aai.business import Customer
+from onapsdk.aai.cloud_infrastructure import Complex, CloudRegion
+from onapsdk.msb.k8s import ConnectivityInfo
+
+logger = logging.getLogger("")
+logger.setLevel(logging.DEBUG)
+fh = logging.StreamHandler()
+fh_formatter = logging.Formatter('%(asctime)s %(levelname)s %(lineno)d:%(filename)s(%(process)d) - %(message)s')
+fh.setFormatter(fh_formatter)
+logger.addHandler(fh)
+
+MYPATH = os.path.dirname(os.path.realpath(__file__))
+
+#### Create complex if not exists ####
+logger.info("******** Complex *******")
+try:
+ complex = list(Complex.get_all(physical_location_id=Config.COMPLEX_ID))[0]
+ logger.info("Complex exists")
+except IndexError:
+ logger.info("Complex does not exists")
+ complex = Complex.create(physical_location_id=Config.COMPLEX_ID,
+ name=Config.COMPLEX_ID,
+ physical_location_type="office",
+ street1="DummyStreet 1",
+ city="DummyCity",
+ postal_code="00-000",
+ country="DummyCountry",
+ region="DummyRegion")
+ logger.info("Complex created")
+
+#### Create cloud region if not exists ####
+logger.info("******** Cloud Region *******")
+try:
+ cloud_region = list(CloudRegion.get_all(cloud_owner=Config.CLOUD_OWNER, cloud_region_id=Config.CLOUD_REGION))[0]
+ logger.info("Cloud region exists")
+except IndexError:
+ logger.info("Cloud region does not exists")
+ cloud_region = CloudRegion.create(cloud_owner=Config.CLOUD_OWNER,
+ cloud_region_id=Config.CLOUD_REGION,
+ cloud_type="k8s",
+ owner_defined_type="t1",
+ cloud_region_version="1.0",
+ complex_name=complex.physical_location_id,
+ cloud_zone="CloudZone",
+ sriov_automation="false",
+ orchestration_disabled=False,
+ in_maint=False)
+ logger.info("Cloud region created")
+
+logger.info("******** Cloud regiongion <-> Complex *******")
+cloud_region.link_to_complex(complex)
+
+logger.info("******** Availability zone *******")
+cloud_region.add_availability_zone(availability_zone_name=Config.AVAILABILITY_ZONE_NAME,
+ availability_zone_hypervisor_type=Config.HYPERVISOR_TYPE)
+
+logger.info("******** Tenant *******")
+cloud_region.add_tenant(str(uuid4()), Config.TENANT_NAME)
+
+#### Update or create connectivity info ####
+logger.info("******** Connectivity Info *******")
+with open(os.path.join(MYPATH, Config.CLUSTER_KUBECONFIG_PATH), 'rb') as kubeconfig_file:
+ kubeconfig = kubeconfig_file.read()
+try:
+ connectivity_info = ConnectivityInfo.get_connectivity_info_by_region_id(cloud_region_id=Config.CLOUD_REGION)
+ logger.info("Connectivity Info exists ")
+ logger.info("Delete Connectivity Info ")
+ connectivity_info.delete()
+ connectivity_info = ConnectivityInfo.create(cloud_region_id=Config.CLOUD_REGION,
+ cloud_owner=Config.CLOUD_OWNER,
+ kubeconfig=kubeconfig)
+ logger.info("Connectivity Info created ")
+except:
+ logger.info("Connectivity Info does not exists ")
+ connectivity_info = ConnectivityInfo.create(cloud_region_id=Config.CLOUD_REGION,
+ cloud_owner=Config.CLOUD_OWNER,
+ kubeconfig=kubeconfig)
+ logger.info("Connectivity Info created ")
+
+#### Add Custom Resource Definitions ####
+k8s_client = K8sClient(kubeconfig_path=Config.CLUSTER_KUBECONFIG_PATH)
+for crd in Config.CUSTOMER_RESOURCE_DEFINITIONS:
+ k8s_client.create_custom_object(crd)
+
+#### Create customer if not exists ####
+logger.info("******** Customer *******")
+try:
+ customer = Customer.get_by_global_customer_id(Config.GLOBAL_CUSTOMER_ID)
+ logger.info("Customer exists")
+except:
+ logger.info("Customer exists")
+ customer = Customer.create(Config.GLOBAL_CUSTOMER_ID, Config.GLOBAL_CUSTOMER_ID, "INFRA")
+ logger.info("Customer created")
+
+#### Add region to SO db ####
+logger.info("******** SO Database *******")
+so_db_adapter = SoDBAdapter(cloud_region_id=Config.CLOUD_REGION,
+ complex_id=Config.COMPLEX_ID,
+ onap_kubeconfig_path=Config.ONAP_KUBECONFIG_PATH)
+is_region_in_so = so_db_adapter.check_region_in_db()
+
+if not is_region_in_so:
+ so_db_adapter.add_region_to_so_db()
diff --git a/heat/vFW_CNF_CDS/automation/delete.py b/heat/vFW_CNF_CDS/automation/delete.py
new file mode 100755
index 00000000..435d04ae
--- /dev/null
+++ b/heat/vFW_CNF_CDS/automation/delete.py
@@ -0,0 +1,61 @@
+# ============LICENSE_START=======================================================
+# Copyright (C) 2020 Orange
+# ================================================================================
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# ============LICENSE_END=========================================================
+
+import logging
+
+from onapsdk.aai.business import Customer
+
+from config import Config
+
+logger = logging.getLogger("")
+logger.setLevel(logging.DEBUG)
+fh = logging.StreamHandler()
+fh_formatter = logging.Formatter('%(asctime)s %(levelname)s %(lineno)d:%(filename)s(%(process)d) - %(message)s')
+fh.setFormatter(fh_formatter)
+logger.addHandler(fh)
+
+logger.info("******** Get Customer *******")
+customer = None
+try:
+ customer = Customer.get_by_global_customer_id(Config.GLOBAL_CUSTOMER_ID)
+except:
+ logger.error("Customer not found")
+ exit(1)
+
+logger.info("******** Check Service Subscription *******")
+service_subscription = None
+for service_sub in customer.service_subscriptions:
+ if service_sub.service_type == Config.SERVICENAME:
+ logger.info("Service %s subscribed", Config.SERVICENAME)
+ service_subscription = service_sub
+ break
+if not service_subscription:
+ logger.error("Service Subscription not found")
+ exit(1)
+
+logger.info("******** Get Service Instance details *******")
+service_instance = None
+for service in service_subscription.service_instances:
+ if service.instance_name == Config.SERVICE_INSTANCE_NAME:
+ service_instance = service
+ break
+if not service_instance:
+ logger.error("Service Instance not found")
+ exit(1)
+
+logger.info("******** Delete Service %s *******", service_instance.instance_name)
+service_deletion = service_instance.delete()
diff --git a/heat/vFW_CNF_CDS/automation/instantiate.py b/heat/vFW_CNF_CDS/automation/instantiate.py
new file mode 100755
index 00000000..0316f113
--- /dev/null
+++ b/heat/vFW_CNF_CDS/automation/instantiate.py
@@ -0,0 +1,209 @@
+# ============LICENSE_START=======================================================
+# Copyright (C) 2020 Orange
+# ================================================================================
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# ============LICENSE_END=========================================================
+
+import logging
+import zipfile
+from io import BytesIO
+from uuid import uuid4
+
+import oyaml as yaml
+
+from config import Config
+from onapsdk.aai.cloud_infrastructure import (
+ CloudRegion,
+)
+from onapsdk.aai.business import (
+ Customer,
+ OwningEntity as AaiOwningEntity
+)
+from onapsdk.msb.k8s import Definition
+
+from onapsdk.so.instantiation import (
+ ServiceInstantiation,
+ InstantiationParameter, VnfParameters, VfmoduleParameters)
+from onapsdk.sdc.service import Service
+from onapsdk.vid import LineOfBusiness, OwningEntity, Platform, Project
+
+logger = logging.getLogger("")
+logger.setLevel(logging.DEBUG)
+fh = logging.StreamHandler()
+fh_formatter = logging.Formatter('%(asctime)s %(levelname)s %(lineno)d:%(filename)s(%(process)d) - %(message)s')
+fh.setFormatter(fh_formatter)
+logger.addHandler(fh)
+
+logger.info("*******************************")
+logger.info("**** SERVICE INSTANTIATION ****")
+logger.info("*******************************")
+
+logger.info("******** Create Customer *******")
+customer = None
+for found_customer in list(Customer.get_all()):
+ logger.debug("Customer %s found", found_customer.subscriber_name)
+ if found_customer.subscriber_name == Config.GLOBAL_CUSTOMER_ID:
+ logger.info("Customer %s found", found_customer.subscriber_name)
+ customer = found_customer
+ break
+if not customer:
+ customer = Customer.create(Config.GLOBAL_CUSTOMER_ID, Config.GLOBAL_CUSTOMER_ID, "INFRA")
+
+logger.info("******** Find Service in SDC *******")
+service = None
+services = Service.get_all()
+for found_service in services:
+ logger.debug("Service %s is found, distribution %s", found_service.name, found_service.distribution_status)
+ if found_service.name == Config.SERVICENAME:
+ logger.info("Found Service %s in SDC", found_service.name)
+ service = found_service
+ break
+
+if not service:
+ logger.error("Service %s not found in SDC", Config.SERVICENAME)
+ exit(1)
+
+logger.info("******** Check Service Subscription *******")
+service_subscription = None
+for service_sub in customer.service_subscriptions:
+ logger.debug("Service subscription %s is found", service_sub.service_type)
+ if service_sub.service_type == Config.SERVICENAME:
+ logger.info("Service %s subscribed", Config.SERVICENAME)
+ service_subscription = service_sub
+ break
+
+if not service_subscription:
+ logger.info("******** Subscribe Service *******")
+ customer.subscribe_service(service)
+
+logger.info("******** Get Tenant *******")
+cloud_region = CloudRegion(cloud_owner=Config.CLOUD_OWNER, cloud_region_id=Config.CLOUD_REGION,
+ orchestration_disabled=True, in_maint=False)
+tenant = None
+for found_tenant in cloud_region.tenants:
+ logger.debug("Tenant %s found in %s_%s", found_tenant.name, cloud_region.cloud_owner, cloud_region.cloud_region_id)
+ if found_tenant.name == Config.TENANT_NAME:
+ logger.info("Found my Tenant %s", found_tenant.name)
+ tenant = found_tenant
+ break
+
+if not tenant:
+ logger.error("tenant %s not found", Config.TENANT_NAME)
+ exit(1)
+
+logger.info("******** Connect Service to Tenant *******")
+service_subscription = None
+for service_sub in customer.service_subscriptions:
+ logger.debug("Service subscription %s is found", service_sub.service_type)
+ if service_sub.service_type == Config.SERVICENAME:
+ logger.info("Service %s subscribed", Config.SERVICENAME)
+ service_subscription = service_sub
+ break
+
+if not service_subscription:
+ logger.error("Service subscription %s is not found", Config.SERVICENAME)
+ exit(1)
+
+service_subscription.link_to_cloud_region_and_tenant(cloud_region, tenant)
+
+logger.info("******** Add Business Objects (OE, P, Pl, LoB) in VID *******")
+vid_owning_entity = OwningEntity.create(Config.OWNING_ENTITY)
+vid_project = Project.create(Config.PROJECT)
+vid_platform = Platform.create(Config.PLATFORM)
+vid_line_of_business = LineOfBusiness.create(Config.LINE_OF_BUSINESS)
+
+logger.info("******** Add Owning Entity in AAI *******")
+owning_entity = None
+for oe in AaiOwningEntity.get_all():
+ if oe.name == vid_owning_entity.name:
+ owning_entity = oe
+ break
+if not owning_entity:
+ logger.info("******** Owning Entity not existing: create *******")
+ owning_entity = AaiOwningEntity.create(vid_owning_entity.name, str(uuid4()))
+
+logger.info("******** Delete old profiles ********")
+for vnf in service.vnfs:
+ for vf_module in vnf.vf_modules:
+ definition = Definition.get_definition_by_name_version(vf_module.metadata["vfModuleModelInvariantUUID"],
+ vf_module.metadata["vfModuleModelUUID"])
+ vf_module_label = vf_module.properties["vf_module_label"]
+ if vf_module_label == "base_template_dummy_ignore":
+ continue
+ profile_name = Config.VF_MODULE_LIST[vf_module_label]["k8s-rb-profile-name"]
+ try:
+ profile = definition.get_profile_by_name(profile_name)
+ if profile.namespace != Config.VF_MODULE_LIST[vf_module_label]["k8s-rb-profile-namespace"]:
+ profile.delete()
+ logger.info("Profile: " + profile_name + " for " + vf_module.name + " deleted")
+ else:
+ logger.info("No need to delete Profile " + profile_name +
+ " for " + vf_module.name + ". Namespace is fine")
+ except ValueError:
+ logger.info("Profile: " + profile_name + " for " + vf_module.name + " not found")
+
+# Read SDNC MODEL NAME and VERSION from CBA.zip
+logger.info("*******************************")
+logger.info("Retrieving SDNC MODEL NAME and VERSION")
+logger.info("*******************************")
+with zipfile.ZipFile(Config.VSPFILE, 'r') as package:
+ cba_io = BytesIO(package.read("CBA.zip"))
+ with zipfile.ZipFile(cba_io) as cba:
+ with cba.open('TOSCA-Metadata/TOSCA.meta') as meta_file:
+ tosca_meta = yaml.load(meta_file, Loader=yaml.FullLoader)
+ SDNC_MODEL_NAME = tosca_meta.get("Template-Name")
+ SDNC_MODEL_VERSION = tosca_meta.get("Template-Version")
+
+logger.info("******** Instantiate Service *******")
+service_instance = None
+service_instantiation = None
+for se in service_subscription.service_instances:
+ if se.instance_name == Config.SERVICE_INSTANCE_NAME:
+ service_instance = se
+ break
+if not service_instance:
+ logger.info("******** Service Instance not existing: Instantiate *******")
+ # Instantiate service
+ vfmodules_list = Config.VF_MODULE_LIST
+
+ vnf_param = [
+ InstantiationParameter(name="sdnc_model_name", value=SDNC_MODEL_NAME),
+ InstantiationParameter(name="sdnc_model_version", value=SDNC_MODEL_VERSION),
+ InstantiationParameter(name="sdnc_artifact_name", value=Config.SDNC_ARTIFACT_NAME)]
+
+ vfmodules_param = []
+ for vfmodule in vfmodules_list:
+ params = [
+ InstantiationParameter(name="k8s-rb-profile-name", value=vfmodules_list[vfmodule]["k8s-rb-profile-name"]),
+ InstantiationParameter(name="k8s-rb-profile-namespace", value=vfmodules_list[vfmodule]["k8s-rb-profile-namespace"]),
+ InstantiationParameter(name="sdnc_model_name", value=SDNC_MODEL_NAME),
+ InstantiationParameter(name="sdnc_model_version", value=SDNC_MODEL_VERSION),
+ InstantiationParameter(name="vf_module_label", value=vfmodules_list[vfmodule]["name"])]
+
+ vfmodules_param.append(VfmoduleParameters(vfmodules_list[vfmodule]["name"], params))
+
+ vnf_params = VnfParameters(name=Config.VFNAME, vnf_parameters=vnf_param, vfmodule_parameters=vfmodules_param)
+
+ service_instantiation = ServiceInstantiation.instantiate_macro(
+ sdc_service=service,
+ cloud_region=cloud_region,
+ tenant=tenant,
+ customer=customer,
+ owning_entity=owning_entity,
+ project=vid_project,
+ line_of_business=vid_line_of_business,
+ platform=vid_platform,
+ service_instance_name=Config.SERVICE_INSTANCE_NAME,
+ vnf_parameters=[vnf_params]
+ )
diff --git a/heat/vFW_CNF_CDS/automation/k8s_client.py b/heat/vFW_CNF_CDS/automation/k8s_client.py
new file mode 100755
index 00000000..7b0b634f
--- /dev/null
+++ b/heat/vFW_CNF_CDS/automation/k8s_client.py
@@ -0,0 +1,59 @@
+# ============LICENSE_START=======================================================
+# Copyright (C) 2020 Orange
+# ================================================================================
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# ============LICENSE_END=========================================================
+
+import os
+from pprint import pprint
+
+import oyaml as yaml
+from kubernetes import config, client
+from kubernetes.client import OpenApiException
+
+
+class K8sClient:
+ def __init__(self, kubeconfig_path):
+ self.mypath = os.path.dirname(os.path.realpath(__file__))
+ config.load_kube_config(config_file=os.path.join(self.mypath, kubeconfig_path))
+ self.api_instance = client.CustomObjectsApi()
+
+ def read_custom_object_file(self, file_path):
+ with open(file_path) as crd_file:
+ crd_body = yaml.load(crd_file, Loader=yaml.FullLoader)
+ return crd_body
+
+ def get_custom_object_details(self, crd_body):
+ group = crd_body["apiVersion"].split("/")[0]
+ version = crd_body["apiVersion"].split("/")[1]
+ plural = crd_body["kind"].lower() + "s"
+ #name = crd_body["metadata"]["name"]
+
+ return group, version, plural #, name
+
+ def create_custom_object(self, file_path):
+ crd_body = self.read_custom_object_file(file_path)
+ #group, version, plural, name = self.get_custom_object_details(crd_body)
+ group, version, plural = self.get_custom_object_details(crd_body)
+ api_response = None
+ try:
+ api_response = self.api_instance.create_cluster_custom_object(group=group,
+ version=version,
+ plural=plural,
+ body=crd_body,
+ pretty="true")
+ except OpenApiException as error:
+ print(str(error.status) + " " + error.reason)
+ pprint(error.body)
+ return api_response
diff --git a/heat/vFW_CNF_CDS/automation/onboard.py b/heat/vFW_CNF_CDS/automation/onboard.py
new file mode 100755
index 00000000..c97b3510
--- /dev/null
+++ b/heat/vFW_CNF_CDS/automation/onboard.py
@@ -0,0 +1,98 @@
+# ============LICENSE_START=======================================================
+# Copyright (C) 2020 Orange
+# ================================================================================
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# ============LICENSE_END=========================================================
+
+import logging
+
+import time
+import zipfile
+from io import BytesIO
+
+import oyaml as yaml
+
+from config import Config
+from onapsdk.sdc.properties import Property
+
+from onapsdk.sdc.vendor import Vendor
+from onapsdk.sdc.vsp import Vsp
+from onapsdk.sdc.vf import Vf
+from onapsdk.sdc.service import Service, ServiceInstantiationType
+
+import os
+
+logger = logging.getLogger("")
+logger.setLevel(logging.DEBUG)
+fh = logging.StreamHandler()
+fh_formatter = logging.Formatter('%(asctime)s %(levelname)s %(lineno)d:%(filename)s(%(process)d) - %(message)s')
+fh.setFormatter(fh_formatter)
+logger.addHandler(fh)
+
+# Read SDNC MODEL NAME and VERSION from CBA.zip
+logger.info("*******************************")
+logger.info("Retrieving SDNC MODEL NAME and VERSION")
+logger.info("*******************************")
+with zipfile.ZipFile(Config.VSPFILE, 'r') as package:
+ cba_io = BytesIO(package.read("CBA.zip"))
+ with zipfile.ZipFile(cba_io) as cba:
+ with cba.open('TOSCA-Metadata/TOSCA.meta') as meta_file:
+ tosca_meta = yaml.load(meta_file, Loader=yaml.FullLoader)
+ SDNC_MODEL_NAME = tosca_meta.get("Template-Name")
+ SDNC_MODEL_VERSION = tosca_meta.get("Template-Version")
+
+logger.info("*******************************")
+logger.info("******** SERVICE DESIGN *******")
+logger.info("*******************************")
+
+logger.info("******** Onboard Vendor *******")
+vendor = Vendor(name=Config.VENDOR)
+vendor.onboard()
+
+logger.info("******** Onboard VSP *******")
+mypath = os.path.dirname(os.path.realpath(__file__))
+myvspfile = os.path.join(mypath, Config.VSPFILE)
+vsp = Vsp(name=Config.VSPNAME, vendor=vendor, package=open(myvspfile, 'rb'))
+vsp.onboard()
+
+logger.info("******** Onboard VF *******")
+vf = Vf(name=Config.VFNAME, properties=[
+ Property(name="sdnc_model_name", property_type="string", value=SDNC_MODEL_NAME),
+ Property(name="sdnc_model_version", property_type="string", value=SDNC_MODEL_VERSION),
+ Property(name="sdnc_artifact_name", property_type="string", value=Config.SDNC_ARTIFACT_NAME)
+]
+ )
+vf.vsp = vsp
+vf.onboard()
+
+logger.info("******** Onboard Service *******")
+svc = Service(name=Config.SERVICENAME, resources=[vf], instantiation_type=ServiceInstantiationType.MACRO)
+svc.onboard()
+
+logger.info("******** Check Service Distribution *******")
+distribution_completed = False
+nb_try = 0
+nb_try_max = 10
+while distribution_completed is False and nb_try < nb_try_max:
+ distribution_completed = svc.distributed
+ if distribution_completed is True:
+ logger.info("Service Distribution for %s is successfully finished", svc.name)
+ break
+ logger.info("Service Distribution for %s ongoing, Wait for 60 s", svc.name)
+ time.sleep(60)
+ nb_try += 1
+
+if distribution_completed is False:
+ logger.error("Service Distribution for %s failed !!", svc.name)
+ exit(1)
diff --git a/heat/vFW_CNF_CDS/automation/so_db_adapter.py b/heat/vFW_CNF_CDS/automation/so_db_adapter.py
new file mode 100755
index 00000000..a829fbda
--- /dev/null
+++ b/heat/vFW_CNF_CDS/automation/so_db_adapter.py
@@ -0,0 +1,92 @@
+# ============LICENSE_START=======================================================
+# Copyright (C) 2020 Orange
+# ================================================================================
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# ============LICENSE_END=========================================================
+
+import base64
+import os
+
+from kubernetes import config, client
+from kubernetes.stream import stream
+
+
+class SoDBAdapter:
+
+ def __init__(self, cloud_region_id, complex_id, onap_kubeconfig_path):
+ self.CLOUD_REGION_ID = cloud_region_id
+ self.COMPLEX_ID = complex_id
+ self.ONAP_KUBECONFIG_PATH = onap_kubeconfig_path
+ self.MYPATH = os.path.dirname(os.path.realpath(__file__))
+
+ config.load_kube_config(config_file=os.path.join(self.MYPATH, self.ONAP_KUBECONFIG_PATH))
+ self.api_instance = client.CoreV1Api()
+ self.pod_name = self.get_mariadb_pod_name()
+ self.password = self.get_mariadb_root_username_password()
+
+ def get_mariadb_pod_name(self):
+ pods = self.api_instance.list_namespaced_pod(namespace="onap")
+ for pod in pods.items:
+ if pod.metadata.name.find("mariadb-galera-0") != -1:
+ return pod.metadata.name
+
+ def get_mariadb_root_username_password(self):
+ secrets = self.api_instance.list_namespaced_secret(namespace="onap")
+ for secret in secrets.items:
+ if secret.metadata.name.find("mariadb-galera-db-root-password") != -1:
+ base64_password = secret.data["password"]
+ base64_bytes = base64_password.encode('ascii')
+ password_bytes = base64.b64decode(base64_bytes)
+
+ return password_bytes.decode('ascii')
+
+ def run_exec_request(self, exec_command):
+ response = stream(self.api_instance.connect_get_namespaced_pod_exec,
+ name=self.pod_name,
+ # container="container-name",
+ namespace="onap",
+ command=exec_command,
+ stdin=False,
+ tty=False,
+ stderr=True,
+ stdout=True)
+ return response
+
+ def check_region_in_db(self):
+ exec_command = [
+ "/bin/sh",
+ "-c",
+ f"mysql -uroot -p{self.password} catalogdb -e 'SELECT * FROM cloud_sites;'"]
+ response = self.run_exec_request(exec_command)
+
+ is_region_found = False
+ for line in response.split("\n"):
+ if line.split("\t")[0] == self.CLOUD_REGION_ID:
+ print(line)
+ is_region_found = True
+ return is_region_found
+ return is_region_found
+
+ def add_region_to_so_db(self):
+ exec_command = [
+ "/bin/sh",
+ "-c",
+ f"mysql -uroot -p{self.password} catalogdb -e "
+ f"'insert into cloud_sites(ID, REGION_ID, IDENTITY_SERVICE_ID, CLOUD_VERSION, CLLI, ORCHESTRATOR ) "
+ f"values (\"{self.CLOUD_REGION_ID}\", \"{self.CLOUD_REGION_ID}\", \"DEFAULT_KEYSTONE\", \"2.5\", "
+ f"\"{self.COMPLEX_ID}\", \"multicloud\");'"]
+
+ response = self.run_exec_request(exec_command)
+
+ return response
diff --git a/heat/vFW_CNF_CDS/automation/update_connectivity_info.py b/heat/vFW_CNF_CDS/automation/update_connectivity_info.py
new file mode 100755
index 00000000..2a341f21
--- /dev/null
+++ b/heat/vFW_CNF_CDS/automation/update_connectivity_info.py
@@ -0,0 +1,49 @@
+# ============LICENSE_START=======================================================
+# Copyright (C) 2020 Orange
+# ================================================================================
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# ============LICENSE_END=========================================================
+
+import logging
+import os
+
+from config import Config
+from onapsdk.msb.k8s import ConnectivityInfo
+
+logger = logging.getLogger("")
+logger.setLevel(logging.DEBUG)
+fh = logging.StreamHandler()
+fh_formatter = logging.Formatter('%(asctime)s %(levelname)s %(lineno)d:%(filename)s(%(process)d) - %(message)s')
+fh.setFormatter(fh_formatter)
+logger.addHandler(fh)
+
+MYPATH = os.path.dirname(os.path.realpath(__file__))
+
+logger.info("******** Connectivity Info *******")
+with open(os.path.join(MYPATH, Config.CLUSTER_KUBECONFIG_PATH), 'rb') as kubeconfig_file:
+ kubeconfig = kubeconfig_file.read()
+try:
+ connectivity_info = ConnectivityInfo.get_connectivity_info_by_region_id(cloud_region_id=Config.CLOUD_REGION)
+ logger.info("Connectivity Info exists ")
+ logger.info("Delete Connectivity Info exists ")
+ connectivity_info.delete()
+ connectivity_info = ConnectivityInfo.create(cloud_region_id=Config.CLOUD_REGION,
+ cloud_owner=Config.CLOUD_OWNER,
+ kubeconfig=kubeconfig)
+except:
+ logger.info("Connectivity Info does not exists ")
+ connectivity_info = ConnectivityInfo.create(cloud_region_id=Config.CLOUD_REGION,
+ cloud_owner=Config.CLOUD_OWNER,
+ kubeconfig=kubeconfig)
+ logger.info("Connectivity Info created ")