--- /dev/null
+#!/usr/bin/env python3
+###
+# ============LICENSE_START===================================================
+# ORAN SMO PACKAGE - PYTHONSDK TESTS
+# ================================================================================
+# Copyright (C) 2021 Samsung Electronics
+# Copyright (C) 2022 AT&T Intellectual Property. All rights
+# reserved.
+# ============================================================================
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+# ============LICENSE_END=====================================================
+#
+###
+"""Create SDC Templates for Network Slicing option2 test."""
+import logging
+import logging.config
+from time import sleep
+import os
+from onapsdk.sdc.vfc import Vfc
+from onapsdk.sdc.vf import Vf
+import onapsdk.constants as const
+from onapsdk.configuration import settings
+from onapsdk.exceptions import ResourceNotFound
+from onapsdk.sdc.properties import Property, ParameterError
+from waiting import wait
+from oransdk.aai.service_design_and_creation import AaiModel
+from oransdk.sdc.sdc import SdcTemplate
+from oransdk.sdc.service import OranService
+
+# Set working dir as python script location
+abspath = os.path.abspath(__file__)
+dname = os.path.dirname(abspath)
+os.chdir(dname)
+
+logging.config.dictConfig(settings.LOG_CONFIG)
+logger = logging.getLogger("####################### Start SDC Preparation")
+service_dict = {}
+service_list = []
+
+class SdcPreparation():
+ """Can be used to prepare SDC for Network Slicing usecase option2."""
+
+ def __init__(self, suffix: str = None):
+ """
+ Initialize SDC preparation object.
+
+ Args:
+ suffix (str, optional): the suffix of the SDC template names
+
+ """
+ if suffix is None:
+ self.suffix = ""
+ else:
+ self.suffix = suffix
+
+ def prepare_sdc(self) -> dict:
+ """Create SDC templates."""
+ # Populate AAI needed value
+
+ sdc = SdcTemplate()
+ vendor = sdc.create_vendor('ONAP')
+ sdc.create_vsp('test1', vendor)
+
+ # 0.create custom categories
+ logger.info("####################### create custom categories")
+ sdc.create_service_category(['CST', 'ServiceProfile', 'AN SliceProfile', 'CN SliceProfile', 'TN SliceProfile',
+ 'NST', 'TN BH NSST', 'TN Network Requirement', 'AN NF NSST', 'CN NSST', 'Allotted Resource'])
+
+
+ vf_tn_bh_ar = self.create_tn_resources(sdc, vendor)
+ vf_embban_nf_ar = self.create_an_resources(sdc, vendor)
+ vf_embbcn_external_ar = self.create_cn_resources(sdc, vendor)
+ self.create_nst(sdc, vf_embbcn_external_ar, vf_embban_nf_ar, vf_tn_bh_ar)
+
+ vf_slice_ar = self.create_slice_ar(sdc, vendor)
+
+ srv_slice_profile_an_o2 = self.create_an_slice_profiles(sdc, vf_slice_ar)
+ srv_slice_profile_tn = self.create_tn_slice_profiles(sdc, vf_slice_ar)
+ srv_slice_profile_cn = self.create_cn_slice_profiles(sdc, vf_slice_ar)
+ srv_profile_o2 = self.create_service_profile(sdc, vf_slice_ar, srv_slice_profile_cn, srv_slice_profile_tn, srv_slice_profile_an_o2)
+ cst = self.create_cst(sdc, srv_profile_o2)
+ wait(lambda: self.verify_distribution(), sleep_seconds=60, timeout_seconds=3600, waiting_for="All services distributed successfully")
+ return [cst.identifier, cst.unique_uuid, srv_profile_o2.identifier]
+
+ def create_tn_resources(self, sdc, vendor) -> dict:
+ """Create TN related resources."""
+ # 1.Create TN_Network_Requirement Service
+ logger.info("####################### create TN_Network_Requirement Service")
+ props = [Property('ConnectionLink', 'string'),
+ Property('jitter', 'string', value='10'),
+ Property('latency', 'integer', value=10),
+ Property('maxBandwith', 'integer', value=1000)]
+
+ srv_tn_network = sdc.create_service(self.updated_name('TN_Network_Requirement'), 'TN Network Requirement', properties=props,
+ inputs=[Property('ConnectionLink', 'string')])
+ service_dict[srv_tn_network.identifier] = False
+ service_list.append(srv_tn_network)
+
+ # 2.Create TN_Network_Req_AR
+ logger.info("####################### create TN_Network_Req_AR")
+ vf = sdc.create_vf(self.updated_name('TN_Network_Req_AR'), 'Allotted Resource', 'Allotted Resource', vendor)
+ for c in vf.components:
+ if c.name == 'AllottedResource 0':
+ c.get_property('providing_service_invariant_uuid').value = srv_tn_network.unique_uuid
+ c.get_property('providing_service_uuid').value = srv_tn_network.identifier
+ c.get_property('providing_service_name').value = srv_tn_network.name
+ break
+ sdc.onboard_vf(vf)
+
+ # 3.Create Tn_ONAP_internal_BH Service
+ logger.info("####################### create Tn_ONAP_internal_BH Service")
+ props = [Property('pLMNIdList', 'string', value='39-00'),
+ Property('jitter', 'string', value='10'),
+ Property('latency', 'integer', value=10),
+ Property('maxBandwith', 'integer', value=1000)]
+
+ srv_tn_bh = sdc.create_service(self.updated_name('Tn_ONAP_internal_BH'), 'TN BH NSST', vnfs=[vf],
+ role='ONAP_internal', properties=props)
+ service_dict[srv_tn_bh.identifier] = False
+ service_list.append(srv_tn_bh)
+
+ # 6.Create Tn_BH_AR
+ logger.info("####################### Create Tn_BH_AR")
+ vf_tn_bh_ar = sdc.create_vf(self.updated_name('Tn_BH_AR'), 'Allotted Resource', 'Allotted Resource', vendor)
+ for c in vf_tn_bh_ar.components:
+ if c.name == 'AllottedResource 0':
+ c.get_property('providing_service_invariant_uuid').value = srv_tn_bh.unique_uuid
+ c.get_property('providing_service_uuid').value = srv_tn_bh.identifier
+ c.get_property('providing_service_name').value = srv_tn_bh.name
+ break
+ sdc.onboard_vf(vf_tn_bh_ar)
+ return vf_tn_bh_ar
+
+ def create_an_resources(self, sdc, vendor) -> dict:
+ """Create AN related resources."""
+ # 4.Create EmbbAn_NF Service Template
+ logger.info("####################### create EmbbAn_NF Service Template")
+ props = [Property('anNSSCap', 'org.openecomp.datatypes.NSSCapabilities')]
+ srv_embban_nf = sdc.create_service(self.updated_name('EmbbAn_NF'), 'AN NF NSST', role='huawei', service_type='embb', properties=props)
+ service_dict[srv_embban_nf.identifier] = False
+ service_list.append(srv_embban_nf)
+
+ # 7.Create EmbbAn_NF_AR
+ logger.info("####################### create EmbbAn_NF_AR")
+ vf_embban_nf_ar = sdc.create_vf(self.updated_name('EmbbAn_NF_AR'), 'Allotted Resource', 'Allotted Resource', vendor)
+ for c in vf_embban_nf_ar.components:
+ if c.name == 'AllottedResource 0':
+ c.get_property('providing_service_invariant_uuid').value = srv_embban_nf.unique_uuid
+ c.get_property('providing_service_uuid').value = srv_embban_nf.identifier
+ c.get_property('providing_service_name').value = srv_embban_nf.name
+ break
+ sdc.onboard_vf(vf_embban_nf_ar)
+ return vf_embban_nf_ar
+
+ def create_cn_resources(self, sdc, vendor) -> dict:
+ """Create CN related resources."""
+ # 5.Create EmbbCn_External Service Template
+ logger.info("####################### create EmbbCn_External Service Template")
+ srv_embbcn = OranService(name=self.updated_name('EmbbCn_External'),
+ category='CN NSST',
+ role='huawei',
+ service_type='embb',
+ properties=[Property('cnCap', 'org.openecomp.datatypes.NSSCapabilities',\
+ value="{\\\"latency\\\":20,\\\"maxNumberofUEs\\\":10000,\
+ \\\"resourceSharingLevel\\\":\\\"Shared\\\",\\\"sST\\\":\\\"eMBB\\\",\
+ \\\"activityFactor\\\":30,\\\"areaTrafficCapDL\\\":800,\
+ \\\"areaTrafficCapUL\\\":800,\\\"expDataRateDL\\\":1000,\
+ \\\"survivalTime\\\":10,\\\"uEMobilityLevel\\\":\\\"stationary\\\",\
+ \\\"expDataRateUL\\\":1000,\\\"pLMNIdList\\\":\\\"39-00\\\"}")])
+
+ srv_embbcn.create()
+
+ if srv_embbcn.status == const.DRAFT:
+ srv_embbcn.add_deployment_artifact(artifact_type="WORKFLOW", artifact_name="eMBB.zip", artifact="../resources/eMBB.zip",
+ artifact_label="abc")
+
+ if srv_embbcn.status != const.DISTRIBUTED:
+ done = False
+ retry = 0
+ to = 1
+ while not done:
+ try:
+ srv_embbcn.onboard()
+ except ResourceNotFound as e:
+ retry += 1
+ if retry > 5:
+ raise e
+ to = 2 * to + 1
+ sleep(to)
+ else:
+ done = True
+ service_dict[srv_embbcn.identifier] = False
+ service_list.append(srv_embbcn)
+
+ # 8.EmbbCn_External_AR
+ logger.info("####################### create EmbbCn_External_AR")
+ vf_embbcn_external_ar = sdc.create_vf(self.updated_name('EmbbCn_External_AR'), 'Allotted Resource', 'Allotted Resource', vendor)
+ for c in vf_embbcn_external_ar.components:
+ if c.name == 'AllottedResource 0':
+ c.get_property('providing_service_invariant_uuid').value = srv_embbcn.unique_uuid
+ c.get_property('providing_service_uuid').value = srv_embbcn.identifier
+ c.get_property('providing_service_name').value = srv_embbcn.name
+ break
+ sdc.onboard_vf(vf_embbcn_external_ar)
+ return vf_embbcn_external_ar
+
+ def create_nst(self, sdc, vf_embbcn_external_ar, vf_embban_nf_ar, vf_tn_bh_ar) -> None:
+ """Create NST."""
+ # 9.Create EmbbNst_O2 Service Template
+ logger.info("####################### create service EmbbNst_O2")
+ props = [Property('latency', 'integer', value=20),
+ Property('maxNumberofUEs', 'integer', value=1000),
+ Property('maxNumberofConns', 'integer', value=100000),
+ Property('resourceSharingLevel', 'string', value='Shared'),
+ Property('sST', 'string', value='eMBB'),
+ Property('activityFactor', 'integer', value=60),
+ Property('availability', 'float', value=0.6),
+ Property('dLThptPerSlice', 'integer', value=1000),
+ Property('uLThptPerSlice', 'integer', value=1000),
+ Property('jitter', 'integer', value=10),
+ Property('survivalTime', 'integer', value=10),
+ Property('uEMobilityLevel', 'string', value='stationary'),
+ Property('pLMNIdList', 'string', value='39-00'),
+ Property('reliability', 'string', value='99%')]
+ nst = sdc.create_service(self.updated_name('EmbbNst_O2'),
+ 'NST',
+ role='option2',
+ vnfs=[vf_embbcn_external_ar, vf_embban_nf_ar, vf_tn_bh_ar],
+ properties=props)
+ service_dict[nst.identifier] = False
+ service_list.append(nst)
+
+ def create_slice_ar(self, sdc, vendor) -> dict:
+ """Create Slice AR."""
+ # 10. create Slice_AR
+ logger.info("####################### create Slice_AR")
+
+ vfc = Vfc('AllottedResource')
+ vf_slice_ar = Vf(name=self.updated_name('Slice_AR'), category='Allotted Resource', subcategory='Allotted Resource', vendor=vendor)
+ vf_slice_ar.create()
+ if vf_slice_ar.status == const.DRAFT:
+ vf_slice_ar.add_resource(vfc)
+
+ for c in vf_slice_ar.components:
+ if c.name == 'AllottedResource 0':
+ cp = sdc.get_component_property(c, 'providing_service_invariant_uuid')
+ if cp:
+ logger.info('declare input for property [%s]', cp)
+ vf_slice_ar.declare_input(cp)
+ else:
+ raise ParameterError('no property providing_service_invariant_uuid found')
+
+ cp = sdc.get_component_property(c, 'providing_service_uuid')
+ if cp:
+ logger.info('declare input for property [%s]', cp)
+ vf_slice_ar.declare_input(cp)
+ else:
+ raise ParameterError('no property providing_service_uuid found')
+
+ break
+
+ sdc.onboard_vf(vf_slice_ar)
+ # AAI bug workaround: create Slice_ar in AAI DB before SO distribution, otherwise service will not be deployed to AAI succesfully
+ aai = AaiModel(invariant_id=vf_slice_ar.unique_uuid, model_type="resource", resource_version=vf_slice_ar.version)
+ aai.create(vf_slice_ar.name, vf_slice_ar.identifier, aai.invariant_id)
+ return vf_slice_ar
+
+ def create_an_slice_profiles(self, sdc, vf_slice_ar) -> dict:
+ """Create AN Slice profile."""
+ # 11.Create SliceProfile_AN_O2 Service Template
+ logger.info("####################### create SliceProfile_AN_O2 Service Template")
+ an_slice_profile = [Property('ipAddress', 'string'),
+ Property('logicInterfaceId', 'string'),
+ Property('nextHopInfo', 'string')]
+ complex_property = Property('anSP', 'org.openecomp.datatypes.SliceProfile')
+ srv_slice_profile_an_o2 = sdc.create_service_1(self.updated_name('SliceProfile_AN_O2'),
+ 'AN SliceProfile',
+ properties=an_slice_profile,
+ inputs=an_slice_profile,
+ complex_input=complex_property,
+ vnfs=[vf_slice_ar])
+ service_dict[srv_slice_profile_an_o2.identifier] = False
+ service_list.append(srv_slice_profile_an_o2)
+ return srv_slice_profile_an_o2
+
+ def create_tn_slice_profiles(self, sdc, vf_slice_ar) -> dict:
+ """Create TN Slice profile."""
+ # 12.Create SliceProfile_TN Service Template
+ logger.info('####################### create service SliceProfile_TN')
+ tn_slice_profile = [Property('jitter', 'string'),
+ Property('latency', 'integer'),
+ Property('pLMNIdList', 'string'),
+ Property('sNSSAI', 'string'),
+ Property('sST', 'integer'),
+ Property('maxBandwidth', 'integer')]
+
+ srv_slice_profile_tn = sdc.create_service_1(self.updated_name('SliceProfile_TN'),
+ 'TN SliceProfile',
+ vnfs=[vf_slice_ar],
+ inputs=tn_slice_profile,
+ properties=tn_slice_profile)
+ service_dict[srv_slice_profile_tn.identifier] = False
+ service_list.append(srv_slice_profile_tn)
+ return srv_slice_profile_tn
+
+ def create_cn_slice_profiles(self, sdc, vf_slice_ar) -> dict:
+ """Create CN Slice profile."""
+ # 13.Create SliceProfile_CN Service Template
+ logger.info('####################### create slice SliceProfile_CN')
+ cn_slice_profile = [Property('ipAddress', 'string'),
+ Property('logicInterfaceId', 'string'),
+ Property('nextHopInfo', 'string')]
+ srv_slice_profile_cn = sdc.create_service_1(self.updated_name('SliceProfile_CN'),
+ 'CN SliceProfile',
+ vnfs=[vf_slice_ar],
+ inputs=cn_slice_profile,
+ properties=cn_slice_profile)
+ service_dict[srv_slice_profile_cn.identifier] = False
+ service_list.append(srv_slice_profile_cn)
+ return srv_slice_profile_cn
+
+ def create_service_profile(self, sdc, vf_slice_ar, srv_slice_profile_cn, srv_slice_profile_tn, srv_slice_profile_an_o2) -> dict:
+ """Create Slice profile."""
+ # 14.Create ServiceProfile_O2 Service Template
+ logger.info('####################### create service ServiceProfile O2')
+ service_props = Property('spProp', 'org.openecomp.datatypes.ServiceProfile')
+ srv_profile_o2 = sdc.create_service_1(self.updated_name('ServiceProfile_O2'),
+ 'ServiceProfile',
+ properties=[service_props],
+ complex_input=service_props,
+ vnfs=[vf_slice_ar, srv_slice_profile_cn, srv_slice_profile_tn, srv_slice_profile_an_o2],
+ role='option2')
+ service_dict[srv_profile_o2.identifier] = False
+ service_list.append(srv_profile_o2)
+ return srv_profile_o2
+
+ def create_cst(self, sdc, srv_profile_o2) -> dict:
+ """Create CST."""
+ # 15.Create CST_O2 Service Template
+ logger.info('####################### create service CST O2')
+ cs_prop = Property('csProp', 'org.openecomp.datatypes.CSProperties')
+ cst = sdc.create_service_1(self.updated_name('CST_O2'),
+ 'CST',
+ role='option2',
+ service_type='embb',
+ vnfs=[srv_profile_o2],
+ properties=[cs_prop],
+ complex_input=cs_prop)
+ service_dict[cst.identifier] = False
+ service_list.append(cst)
+ return cst
+
+ def updated_name(self, name) -> str:
+ """Adding suffix for the name."""
+ return name + self.suffix
+
+ @classmethod
+ def verify_distribution(cls) -> bool:
+ """Verify the distribution of all the services."""
+ for service in service_list:
+ logger.info('####################### verify service:%s', service.name)
+ if service_dict[service.identifier]:
+ continue
+ so_ready = False
+ aai_ready = False
+ result = service.get_distribution_status()
+ for element in result['distributionStatusList']:
+ if (element['omfComponentID'] == "SO-COpenSource-Env11" and (element['status'] == "DEPLOY_OK" or element['status'] == const.DOWNLOAD_OK)):
+ so_ready = True
+ if (element['omfComponentID'] == "aai-ml" and element['status'] == "DEPLOY_OK"):
+ aai_ready = True
+ if so_ready and aai_ready:
+ service_dict[service.identifier] = True
+ logger.info('####################### service %s distributed successfully to SO and AAI', service.name)
+
+ res = True
+ for value in service_dict.values():
+ res = res and value
+ logger.info('####################### res is:%s, value is:%s', str(res), str(value))
+ return res