From 2d3f1023ac94d9c19115c0b63ce85ae7a8598517 Mon Sep 17 00:00:00 2001 From: Ananda Baitharu Date: Thu, 24 Nov 2016 05:23:39 -0500 Subject: [PATCH] Bug 113 add VNFD copy to VNFR Change-Id: I9bdb4da4af554d7947d1c4147c9eaf7a8e121360 Signed-off-by: Ananda Baitharu --- models/plugins/yang/vnfd.yang | 23 +- models/plugins/yang/vnfr.yang | 12 +- .../vala/rwcal_openstack/rwcal_openstack.py | 18 +- .../rift/tasklets/rwconmantasklet/jujuconf.py | 2 +- .../rwautoscaler/test/utest_autoscaler_dts.py | 10 +- .../rift/tasklets/rwmonparam/nsr_core.py | 4 +- .../rift/tasklets/rwmonparam/rwmonparam.py | 2 +- .../rwmonparam/test/utest_mon_params_dts.py | 2 +- .../tasklets/rwnsmtasklet/rwnsmtasklet.py | 5 +- .../tasklets/rwvnfmtasklet/rwvnfmtasklet.py | 293 +++++------------- .../ra/pytest/ns/pingpong/test_records.py | 2 +- rwlaunchpad/ra/pytest/test_failover.py | 2 +- 12 files changed, 124 insertions(+), 251 deletions(-) diff --git a/models/plugins/yang/vnfd.yang b/models/plugins/yang/vnfd.yang index 81bb2aa7..5dc19ce6 100644 --- a/models/plugins/yang/vnfd.yang +++ b/models/plugins/yang/vnfd.yang @@ -115,14 +115,7 @@ module vnfd } } - container vnfd-catalog { - - description - "Virtual Network Function Descriptor (VNFD)."; - - list vnfd { - key "id"; - + grouping vnfd-descriptor { leaf id { description "Identifier for the VNFD."; type string; @@ -490,7 +483,7 @@ module vnfd key "name"; uses manotypes:placement-group-info; - + list member-vdus { description @@ -504,7 +497,17 @@ module vnfd } } } - } + } + + container vnfd-catalog { + description + "Virtual Network Function Descriptor (VNFD)."; + + list vnfd { + key "id"; + + uses vnfd-descriptor; + } } } diff --git a/models/plugins/yang/vnfr.yang b/models/plugins/yang/vnfr.yang index 8f739f47..14a2d814 100644 --- a/models/plugins/yang/vnfr.yang +++ b/models/plugins/yang/vnfr.yang @@ -207,11 +207,9 @@ module vnfr type uint32; } - leaf vnfd-ref { - description "Reference to VNFD"; - type leafref { - path "/vnfd:vnfd-catalog/vnfd:vnfd/vnfd:id"; - } + container vnfd { + description "VNF descriptor used to instantiate this VNF"; + uses vnfd:vnfd-descriptor; } // Use parameters provided here to configure this VNF @@ -296,9 +294,7 @@ module vnfr leaf vdu-id-ref { type leafref { - path "/vnfd:vnfd-catalog/vnfd:vnfd" - + "[vnfd:id = current()/../../vnfr:vnfd-ref]" - + "/vnfd:vdu/vnfd:id"; + path "../../vnfd/vdu/id"; } } diff --git a/rwcal/plugins/vala/rwcal_openstack/rwcal_openstack.py b/rwcal/plugins/vala/rwcal_openstack/rwcal_openstack.py index e5dcb67f..05dc4989 100644 --- a/rwcal/plugins/vala/rwcal_openstack/rwcal_openstack.py +++ b/rwcal/plugins/vala/rwcal_openstack/rwcal_openstack.py @@ -2010,7 +2010,10 @@ class RwcalOpenstackPlugin(GObject.Object, RwCal.Cloud): The vdu_id """ ### First create required number of ports aka connection points + # Add the mgmt_ntwk by default. + mgmt_network_id = None with self._use_driver(account) as drv: + mgmt_network_id = drv._mgmt_network_id ### If floating_ip is required and we don't have one, better fail before any further allocation if vdu_init.has_field('allocate_public_address') and vdu_init.allocate_public_address: if account.openstack.has_field('floating_ip_pool'): @@ -2024,7 +2027,12 @@ class RwcalOpenstackPlugin(GObject.Object, RwCal.Cloud): port_list = [] network_list = [] imageinfo_list = [] + is_explicit_mgmt_defined = False for c_point in vdu_init.connection_points: + # if the user has specified explicit mgmt_network connection point + # then remove the mgmt_network from the VM list + if c_point.virtual_link_id == mgmt_network_id: + is_explicit_mgmt_defined = True if c_point.virtual_link_id in network_list: assert False, "Only one port per network supported. Refer: http://specs.openstack.org/openstack/nova-specs/specs/juno/implemented/nfv-multiple-if-1-net.html" else: @@ -2086,7 +2094,8 @@ class RwcalOpenstackPlugin(GObject.Object, RwCal.Cloud): with self._use_driver(account) as drv: ### Now Create VM vm_network_list = [] - vm_network_list.append(drv._mgmt_network_id) + if not is_explicit_mgmt_defined: + vm_network_list.append(drv._mgmt_network_id) if vdu_init.has_field('volumes'): # Only combination supported: Image->Volume @@ -2261,9 +2270,7 @@ class RwcalOpenstackPlugin(GObject.Object, RwCal.Cloud): Object of type RwcalYang.VDUInfoParams """ with self._use_driver(account) as drv: - - ### Get list of ports excluding the one for management network - port_list = [p for p in drv.neutron_port_list(**{'device_id': vdu_id}) if p['network_id'] != drv.get_mgmt_network_id()] + port_list = drv.neutron_port_list(**{'device_id': vdu_id}) vm = drv.nova_server_get(vdu_id) @@ -2309,8 +2316,7 @@ class RwcalOpenstackPlugin(GObject.Object, RwCal.Cloud): with self._use_driver(account) as drv: vms = drv.nova_server_list() for vm in vms: - ### Get list of ports excluding one for management network - port_list = [p for p in drv.neutron_port_list(**{'device_id': vm['id']}) if p['network_id'] != drv.get_mgmt_network_id()] + port_list = drv.neutron_port_list(**{'device_id': vm['id']}) flavor_info = None diff --git a/rwcm/plugins/rwconman/rift/tasklets/rwconmantasklet/jujuconf.py b/rwcm/plugins/rwconman/rift/tasklets/rwconmantasklet/jujuconf.py index dce31c3e..7779479d 100644 --- a/rwcm/plugins/rwconman/rift/tasklets/rwconmantasklet/jujuconf.py +++ b/rwcm/plugins/rwconman/rift/tasklets/rwconmantasklet/jujuconf.py @@ -182,7 +182,7 @@ class JujuConfigPlugin(riftcm_config_plugin.RiftCMConfigPluginBase): try: path = os.path.join(self._rift_artif_dir, 'launchpad/libs', - agent_vnfr.vnfr_msg.vnfd_ref, + agent_vnfr.vnfr_msg.vnfd.id, 'charms/trusty', charm) self._log.debug("jujuCA: Charm dir is {}".format(path)) diff --git a/rwlaunchpad/plugins/rwautoscaler/test/utest_autoscaler_dts.py b/rwlaunchpad/plugins/rwautoscaler/test/utest_autoscaler_dts.py index 78342cee..c00ca11f 100644 --- a/rwlaunchpad/plugins/rwautoscaler/test/utest_autoscaler_dts.py +++ b/rwlaunchpad/plugins/rwautoscaler/test/utest_autoscaler_dts.py @@ -37,7 +37,8 @@ from gi.repository import ( RwLaunchpadYang as launchpadyang, RwVnfrYang, RwVnfdYang, - RwNsdYang + RwNsdYang, + VnfrYang ) @@ -97,10 +98,9 @@ class MockStore(): store.get_vnfd = mock.MagicMock(return_value=mock_vnfd) - mock_vnfr = RwVnfrYang.YangData_Vnfr_VnfrCatalog_Vnfr.from_dict({ - 'id': '1', - 'vnfd_ref': '1', - }) + mock_vnfr = RwVnfrYang.YangData_Vnfr_VnfrCatalog_Vnfr.from_dict({'id': '1'}) + mock_vnfr.vnfd = VnfrYang.YangData_Vnfr_VnfrCatalog_Vnfr_Vnfd.from_dict({'id': '1'}) + store.get_vnfr = mock.MagicMock(return_value=mock_vnfr) mock_nsr = RwNsrYang.YangData_Nsr_NsInstanceOpdata_Nsr.from_dict({ diff --git a/rwlaunchpad/plugins/rwmonparam/rift/tasklets/rwmonparam/nsr_core.py b/rwlaunchpad/plugins/rwmonparam/rift/tasklets/rwmonparam/nsr_core.py index 31b76477..78a3c8fc 100644 --- a/rwlaunchpad/plugins/rwmonparam/rift/tasklets/rwmonparam/nsr_core.py +++ b/rwlaunchpad/plugins/rwmonparam/rift/tasklets/rwmonparam/nsr_core.py @@ -89,7 +89,7 @@ class NsrMonitoringParam(): # This indicates that the NSD had no mon-param config. if not nsd.monitoring_param: for vnfr in constituent_vnfrs: - vnfd = store.get_vnfd(vnfr.vnfd_ref) + vnfd = store.get_vnfd(vnfr.vnfd.id) for monp in vnfd.monitoring_param: mon_params.append(NsrMonitoringParam( monp, @@ -193,7 +193,7 @@ class NsrMonitoringParam(): def _convert_nsd_msg(self, nsd_monp): """Create initial msg without values""" - vnfd_to_vnfr = {vnfr.vnfd_ref: vnfr_id + vnfd_to_vnfr = {vnfr.vnfd.id: vnfr_id for vnfr_id, vnfr in self._constituent_vnfr_map.items()} # First, convert the monp param ref from vnfd to vnfr terms. diff --git a/rwlaunchpad/plugins/rwmonparam/rift/tasklets/rwmonparam/rwmonparam.py b/rwlaunchpad/plugins/rwmonparam/rift/tasklets/rwmonparam/rwmonparam.py index d0f31e34..04e03061 100644 --- a/rwlaunchpad/plugins/rwmonparam/rift/tasklets/rwmonparam/rwmonparam.py +++ b/rwlaunchpad/plugins/rwmonparam/rift/tasklets/rwmonparam/rwmonparam.py @@ -147,7 +147,7 @@ class MonitoringParameterTasklet(rift.tasklets.Tasklet): vnf_mon = vnfr_core.VnfMonitorDtsHandler.from_vnf_data( self, vnfr, - self.store.get_vnfd(vnfr.vnfd_ref)) + self.store.get_vnfd(vnfr.vnfd.id)) self.vnfr_monitors[vnfr.id] = vnf_mon self.vnfrs[vnfr.id] = vnfr diff --git a/rwlaunchpad/plugins/rwmonparam/test/utest_mon_params_dts.py b/rwlaunchpad/plugins/rwmonparam/test/utest_mon_params_dts.py index 680cc820..31634056 100644 --- a/rwlaunchpad/plugins/rwmonparam/test/utest_mon_params_dts.py +++ b/rwlaunchpad/plugins/rwmonparam/test/utest_mon_params_dts.py @@ -153,9 +153,9 @@ class MonParamsDtsTestCase(rift.test.dts.AbstractDTSTest): mock_vnfr = RwVnfrYang.YangData_Vnfr_VnfrCatalog_Vnfr.from_dict({ 'id': '1', - 'vnfd_ref': '1', 'monitoring_param': ([monp.as_dict() for monp in monps] if not legacy else []) }) + mock_vnfr.vnfd = vnfryang.YangData_Vnfr_VnfrCatalog_Vnfr_Vnfd.from_dict({'id': '1'}) store.get_vnfr = mock.MagicMock(return_value=mock_vnfr) mock_nsr = RwNsrYang.YangData_Nsr_NsInstanceOpdata_Nsr.from_dict({ diff --git a/rwlaunchpad/plugins/rwnsm/rift/tasklets/rwnsmtasklet/rwnsmtasklet.py b/rwlaunchpad/plugins/rwnsm/rift/tasklets/rwnsmtasklet/rwnsmtasklet.py index 1b1dcfc5..718d2b19 100755 --- a/rwlaunchpad/plugins/rwnsm/rift/tasklets/rwnsmtasklet/rwnsmtasklet.py +++ b/rwlaunchpad/plugins/rwnsm/rift/tasklets/rwnsmtasklet/rwnsmtasklet.py @@ -952,7 +952,6 @@ class VirtualNetworkFunctionRecord(object): vnfr_dict = { "id": self.id, "nsr_id_ref": self._nsr_id, - "vnfd_ref": self.vnfd.id, "name": self.name, "cloud_account": self._cloud_account_name, "om_datacenter": self._om_datacenter_name, @@ -961,6 +960,8 @@ class VirtualNetworkFunctionRecord(object): vnfr_dict.update(vnfd_copy_dict) vnfr = RwVnfrYang.YangData_Vnfr_VnfrCatalog_Vnfr.from_dict(vnfr_dict) + + vnfr.vnfd = VnfrYang.YangData_Vnfr_VnfrCatalog_Vnfr_Vnfd.from_dict(self.vnfd.as_dict()) vnfr.member_vnf_index_ref = self.member_vnf_index vnfr.vnf_configuration.from_dict(self._vnfd.vnf_configuration.as_dict()) @@ -1084,7 +1085,7 @@ class VirtualNetworkFunctionRecord(object): cpr.vlr_ref = vlr_ref.id self.vnfr_msg.connection_point.append(cpr) self._log.debug("Connection point [%s] added, vnf id=%s vnfd id=%s", - cpr, self.vnfr_msg.id, self.vnfr_msg.vnfd_ref) + cpr, self.vnfr_msg.id, self.vnfr_msg.vnfd.id) if not self.restart_mode: yield from self._dts.query_create(self.xpath, diff --git a/rwlaunchpad/plugins/rwvnfm/rift/tasklets/rwvnfmtasklet/rwvnfmtasklet.py b/rwlaunchpad/plugins/rwvnfm/rift/tasklets/rwvnfmtasklet/rwvnfmtasklet.py index c78c9a90..8a4474e0 100755 --- a/rwlaunchpad/plugins/rwvnfm/rift/tasklets/rwvnfmtasklet/rwvnfmtasklet.py +++ b/rwlaunchpad/plugins/rwvnfm/rift/tasklets/rwvnfmtasklet/rwvnfmtasklet.py @@ -1076,13 +1076,13 @@ class VirtualNetworkFunctionRecord(object): self._cluster_name = cluster_name self._vnfr_msg = vnfr_msg self._vnfr_id = vnfr_msg.id - self._vnfd_id = vnfr_msg.vnfd_ref + self._vnfd_id = vnfr_msg.vnfd.id self._vnfm = vnfm self._vcs_handler = vcs_handler self._vnfr = vnfr_msg self._mgmt_network = mgmt_network - self._vnfd = None + self._vnfd = vnfr_msg.vnfd self._state = VirtualNetworkFunctionRecordState.INIT self._state_failed_reason = None self._ext_vlrs = {} # The list of external virtual links @@ -1095,6 +1095,8 @@ class VirtualNetworkFunctionRecord(object): self._vnf_mon = None self._config_status = vnfr_msg.config_status self._vnfd_package_store = rift.package.store.VnfdPackageFilesystemStore(self._log) + self._rw_vnfd = None + self._vnfd_ref_count = 0 def _get_vdur_from_vdu_id(self, vdu_id): self._log.debug("Finding vdur for vdu_id %s", vdu_id) @@ -1120,11 +1122,36 @@ class VirtualNetworkFunctionRecord(object): "FAILED": "failed", } return op_status_map[self._state.name] - @property - def vnfd_xpath(self): + @staticmethod + def vnfd_xpath(vnfd_id): """ VNFD xpath associated with this VNFR """ - return("C,/vnfd:vnfd-catalog/" - "vnfd:vnfd[vnfd:id = '{}']".format(self._vnfd_id)) + return "C,/vnfd:vnfd-catalog/vnfd:vnfd[vnfd:id = '{}']".format(vnfd_id) + + @property + def vnfd_ref_count(self): + """ Returns the VNFD reference count associated with this VNFR """ + return self._vnfd_ref_count + + def vnfd_in_use(self): + """ Returns whether vnfd is in use or not """ + return True if self._vnfd_ref_count > 0 else False + + def vnfd_ref(self): + """ Take a reference on this object """ + self._vnfd_ref_count += 1 + return self._vnfd_ref_count + + def vnfd_unref(self): + """ Release reference on this object """ + if self._vnfd_ref_count < 1: + msg = ("Unref on a VNFD object - vnfd id %s, vnfd_ref_count = %s" % + (self.vnfd.id, self._vnfd_ref_count)) + self._log.critical(msg) + raise VnfRecordError(msg) + self._log.debug("Releasing ref on VNFD %s - curr vnfd_ref_count:%s", + self.vnfd.id, self._vnfd_ref_count) + self._vnfd_ref_count -= 1 + return self._vnfd_ref_count @property def vnfd(self): @@ -1206,7 +1233,7 @@ class VirtualNetworkFunctionRecord(object): def mgmt_intf_info(self): """ Get Management interface info for this VNFR """ - mgmt_intf_desc = self.vnfd.msg.mgmt_interface + mgmt_intf_desc = self.vnfd.mgmt_interface ip_addr = None if mgmt_intf_desc.has_field("cp"): ip_addr = self.cp_ip_addr(mgmt_intf_desc.cp) @@ -1227,7 +1254,7 @@ class VirtualNetworkFunctionRecord(object): def msg(self): """ Message associated with this VNFR """ vnfd_fields = ["short_name", "vendor", "description", "version"] - vnfd_copy_dict = {k: v for k, v in self.vnfd.msg.as_dict().items() if k in vnfd_fields} + vnfd_copy_dict = {k: v for k, v in self.vnfd.as_dict().items() if k in vnfd_fields} mgmt_intf = VnfrYang.YangData_Vnfr_VnfrCatalog_Vnfr_MgmtInterface() ip_address, port = self.mgmt_intf_info() @@ -1241,7 +1268,6 @@ class VirtualNetworkFunctionRecord(object): "nsr_id_ref": self._vnfr_msg.nsr_id_ref, "name": self.name, "member_vnf_index_ref": self.member_vnf_index, - "vnfd_ref": self.vnfd_id, "operational_status": self.operational_status, "operational_status_details": self._state_failed_reason, "cloud_account": self.cloud_account_name, @@ -1251,6 +1277,9 @@ class VirtualNetworkFunctionRecord(object): vnfr_dict.update(vnfd_copy_dict) vnfr_msg = RwVnfrYang.YangData_Vnfr_VnfrCatalog_Vnfr.from_dict(vnfr_dict) + vnfr_msg.vnfd = VnfrYang.YangData_Vnfr_VnfrCatalog_Vnfr_Vnfd.from_dict(self.vnfd.as_dict()) + + vnfr_msg.create_time = self._create_time vnfr_msg.uptime = int(time.time()) - self._create_time vnfr_msg.mgmt_interface = mgmt_intf @@ -1265,7 +1294,7 @@ class VirtualNetworkFunctionRecord(object): vdur = vnfr_msg.vdur.add() vdur.from_dict(vdu.msg.as_dict()) - if self.vnfd.msg.mgmt_interface.has_field('dashboard_params'): + if self.vnfd.mgmt_interface.has_field('dashboard_params'): vnfr_msg.dashboard_url = self.dashboard_url for cpr in self._cprs: @@ -1295,18 +1324,18 @@ class VirtualNetworkFunctionRecord(object): ip, cfg_port = self.mgmt_intf_info() protocol = 'http' http_port = 80 - if self.vnfd.msg.mgmt_interface.dashboard_params.has_field('https'): - if self.vnfd.msg.mgmt_interface.dashboard_params.https is True: + if self.vnfd.mgmt_interface.dashboard_params.has_field('https'): + if self.vnfd.mgmt_interface.dashboard_params.https is True: protocol = 'https' http_port = 443 - if self.vnfd.msg.mgmt_interface.dashboard_params.has_field('port'): - http_port = self.vnfd.msg.mgmt_interface.dashboard_params.port + if self.vnfd.mgmt_interface.dashboard_params.has_field('port'): + http_port = self.vnfd.mgmt_interface.dashboard_params.port url = "{protocol}://{ip_address}:{port}/{path}".format( protocol=protocol, ip_address=ip, port=http_port, - path=self.vnfd.msg.mgmt_interface.dashboard_params.path.lstrip("/"), + path=self.vnfd.mgmt_interface.dashboard_params.path.lstrip("/"), ) return url @@ -1333,7 +1362,7 @@ class VirtualNetworkFunctionRecord(object): """ Publish The VLs associated with this VNF """ self._log.debug("Publishing Internal Virtual Links for vnfd id: %s", self.vnfd_id) - for ivld_msg in self.vnfd.msg.internal_vld: + for ivld_msg in self.vnfd.internal_vld: self._log.debug("Creating internal vld:" " %s, int_cp_ref = %s", ivld_msg, ivld_msg.internal_connection_point @@ -1404,7 +1433,7 @@ class VirtualNetworkFunctionRecord(object): nsr_config = yield from self.get_nsr_config() ### Step-3: Get VDU level placement groups - for group in self.vnfd.msg.placement_groups: + for group in self.vnfd.placement_groups: for member_vdu in group.member_vdus: if member_vdu.member_vdu_ref == vdu.id: group_info = self.resolve_placement_group_cloud_construct(group, @@ -1446,7 +1475,7 @@ class VirtualNetworkFunctionRecord(object): self._log.info("Creating VDU's for vnfd id: %s", self.vnfd_id) - for vdu in self.vnfd.msg.vdu: + for vdu in self._rw_vnfd.vdu: self._log.debug("Creating vdu: %s", vdu) vdur_id = get_vdur_id(vdu) @@ -1602,7 +1631,7 @@ class VirtualNetworkFunctionRecord(object): def has_mgmt_interface(self, vdu): # ## TODO: Support additional mgmt_interface type options - if self.vnfd.msg.mgmt_interface.vdu_id == vdu.id: + if self.vnfd.mgmt_interface.vdu_id == vdu.id: return True return False @@ -1621,7 +1650,7 @@ class VirtualNetworkFunctionRecord(object): """ Publish the inventory associated with this VNF """ self._log.debug("Publishing inventory for VNFR id: %s", self._vnfr_id) - for component in self.vnfd.msg.component: + for component in self._rw_vnfd.component: self._log.debug("Creating inventory component %s", component) mangled_name = VcsComponent.mangle_name(component.component_name, self.vnf_name, @@ -1699,6 +1728,7 @@ class VirtualNetworkFunctionRecord(object): def instantiate(self, xact, restart_mode=False): """ instantiate this VNF """ self.set_state(VirtualNetworkFunctionRecordState.VL_INIT_PHASE) + self._rw_vnfd = yield from self._vnfm.fetch_vnfd(self._vnfd_id) @asyncio.coroutine def fetch_vlrs(): @@ -1733,12 +1763,10 @@ class VirtualNetworkFunctionRecord(object): cpr.vlr_ref = cp.vlr_ref self._log.debug("Fetched VLR [%s] with path = [%s]", d, vlr_path) - # Fetch the VNFD associated with the VNFR - self._log.debug("VNFR-ID %s: Fetching vnfds", self._vnfr_id) - self._vnfd = yield from self._vnfm.get_vnfd_ref(self._vnfd_id) - self._log.debug("VNFR-ID %s: Fetched vnfd:%s", self._vnfr_id, self._vnfd) + # Increase the VNFD reference count + self.vnfd_ref() - assert self.vnfd is not None + assert self.vnfd # Fetch External VLRs self._log.debug("VNFR-ID %s: Fetching vlrs", self._vnfr_id) @@ -1867,13 +1895,6 @@ class VnfdDtsHandler(object): xact, action, scratch) is_recovery = xact.xact is None and action == rwdts.AppconfAction.INSTALL - # Create/Update a VNFD record - for cfg in self._regh.get_xact_elements(xact): - # Only interested in those VNFD cfgs whose ID was received in prepare callback - if cfg.id in scratch.get('vnfds', []) or is_recovery: - self._vnfm.update_vnfd(cfg) - - scratch.pop('vnfds', None) @asyncio.coroutine def on_prepare(dts, acg, xact, xact_info, ks_path, msg, scratch): @@ -1883,7 +1904,7 @@ class VnfdDtsHandler(object): fref = ProtobufC.FieldReference.alloc() fref.goto_whole_message(msg.to_pbcm()) - # Handle deletes in prepare_callback, but adds/updates in apply_callback + # Handle deletes in prepare_callback if fref.is_field_deleted(): # Delete an VNFD record self._log.debug("Deleting VNFD with id %s", msg.id) @@ -1893,17 +1914,6 @@ class VnfdDtsHandler(object): raise VirtualNetworkFunctionDescriptorRefCountExists(err) # Delete a VNFD record yield from self._vnfm.delete_vnfd(msg.id) - else: - # Handle actual adds/updates in apply_callback, - # just check if VNFD in use in prepare_callback - if self._vnfm.vnfd_in_use(msg.id): - self._log.debug("Cannot modify an VNFD in use - %s", msg) - err = "Cannot modify an VNFD in use - %s" % msg - raise VirtualNetworkFunctionDescriptorRefCountExists(err) - - # Add this VNFD to scratch to create/update in apply callback - vnfds = scratch.setdefault('vnfds', []) - vnfds.append(msg.id) xact_info.respond_xpath(rwdts.XactRspCode.ACK) @@ -2110,8 +2120,8 @@ class VnfrDtsHandler(object): ) if action == rwdts.QueryAction.CREATE: - if not msg.has_field("vnfd_ref"): - err = "Vnfd reference not provided" + if not msg.has_field("vnfd"): + err = "Vnfd not provided" self._log.error(err) raise VnfRecordError(err) @@ -2138,7 +2148,7 @@ class VnfrDtsHandler(object): try: yield from vnfr.terminate(xact_info.xact) # Unref the VNFD - vnfr.vnfd.unref() + vnfr.vnfd_unref() yield from self._vnfm.delete_vnfr(xact_info.xact, vnfr) except Exception as e: self._log.exception(e) @@ -2220,100 +2230,6 @@ class VnfrDtsHandler(object): self._log.debug("Deleted VNFR xact = %s, %s", xact, path) -class VirtualNetworkFunctionDescriptor(object): - """ - Virtual Network Function descriptor class - """ - - def __init__(self, dts, log, loop, vnfm, vnfd): - self._dts = dts - self._log = log - self._loop = loop - - self._vnfm = vnfm - self._vnfd = vnfd - self._ref_count = 0 - - @property - def ref_count(self): - """ Returns the reference count associated with - this Virtual Network Function Descriptor""" - return self._ref_count - - @property - def id(self): - """ Returns vnfd id """ - return self._vnfd.id - - @property - def name(self): - """ Returns vnfd name """ - return self._vnfd.name - - def in_use(self): - """ Returns whether vnfd is in use or not """ - return True if self._ref_count > 0 else False - - def ref(self): - """ Take a reference on this object """ - self._ref_count += 1 - return self._ref_count - - def unref(self): - """ Release reference on this object """ - if self.ref_count < 1: - msg = ("Unref on a VNFD object - vnfd id %s, ref_count = %s" % - (self.id, self._ref_count)) - self._log.critical(msg) - raise VnfRecordError(msg) - self._log.debug("Releasing ref on VNFD %s - curr ref_count:%s", - self.id, self.ref_count) - self._ref_count -= 1 - return self._ref_count - - @property - def msg(self): - """ Return the message associated with this NetworkServiceDescriptor""" - return self._vnfd - - @staticmethod - def path_for_id(vnfd_id): - """ Return path for the passed vnfd_id""" - return "C,/vnfd:vnfd-catalog/vnfd:vnfd[vnfd:id = '{}']".format(vnfd_id) - - def path(self): - """ Return the path associated with this NetworkServiceDescriptor""" - return VirtualNetworkFunctionDescriptor.path_for_id(self.id) - - def update(self, vnfd): - """ Update the Virtual Network Function Descriptor """ - if self.in_use(): - self._log.error("Cannot update descriptor %s in use refcnt=%d", - self.id, self.ref_count) - - # The following loop is added to debug RIFT-13284 - for vnf_rec in self._vnfm._vnfrs.values(): - if vnf_rec.vnfd_id == self.id: - self._log.error("descriptor %s in used by %s:%s", - self.id, vnf_rec.vnfr_id, vnf_rec.msg) - raise VirtualNetworkFunctionDescriptorRefCountExists("Cannot update descriptor in use %s" % self.id) - self._vnfd = vnfd - - def delete(self): - """ Delete the Virtual Network Function Descriptor """ - if self.in_use(): - self._log.error("Cannot delete descriptor %s in use refcnt=%d", - self.id) - - # The following loop is added to debug RIFT-13284 - for vnf_rec in self._vnfm._vnfrs.values(): - if vnf_rec.vnfd_id == self.id: - self._log.error("descriptor %s in used by %s:%s", - self.id, vnf_rec.vnfr_id, vnf_rec.msg) - raise VirtualNetworkFunctionDescriptorRefCountExists("Cannot delete descriptor in use %s" % self.id) - self._vnfm.delete_vnfd(self.id) - - class VnfdRefCountDtsHandler(object): """ The VNFD Ref Count DTS handler """ XPATH = "D,/vnfr:vnfr-catalog/rw-vnfr:vnfd-ref-count" @@ -2505,10 +2421,12 @@ class VnfManager(object): self._nsr_handler = mano_dts.NsInstanceConfigSubscriber(log, dts, loop, callback=self.handle_nsr) self._dts_handlers = [VnfdDtsHandler(dts, log, loop, self), + self._vnfr_handler, self._vcs_handler, + self._vnfr_ref_handler, self._nsr_handler] self._vnfrs = {} - self._vnfds = {} + self._vnfds_to_vnfr = {} self._nsrs = {} @property @@ -2544,7 +2462,7 @@ class VnfManager(object): """For the given VNFR get the related mgmt network from the NSD, if available. """ - vnfd_id = vnfr.vnfd_ref + vnfd_id = vnfr.vnfd.id nsr_id = vnfr.nsr_id_ref # for the given related VNFR, get the corresponding NSR-config @@ -2579,7 +2497,7 @@ class VnfManager(object): self._log.info("Create VirtualNetworkFunctionRecord %s from vnfd_id: %s", vnfr.id, - vnfr.vnfd_ref) + vnfr.vnfd.id) mgmt_network = self.get_linked_mgmt_network(vnfr) @@ -2587,6 +2505,7 @@ class VnfManager(object): self._dts, self._log, self._loop, self._cluster_name, self, self.vcs_handler, vnfr, mgmt_network=mgmt_network ) + self._vnfds_to_vnfr[vnfr.vnfd.id] = self._vnfrs[vnfr.id] return self._vnfrs[vnfr.id] @asyncio.coroutine @@ -2600,7 +2519,7 @@ class VnfManager(object): @asyncio.coroutine def fetch_vnfd(self, vnfd_id): """ Fetch VNFDs based with the vnfd id""" - vnfd_path = VirtualNetworkFunctionDescriptor.path_for_id(vnfd_id) + vnfd_path = VirtualNetworkFunctionRecord.vnfd_xpath(vnfd_id) self._log.debug("Fetch vnfd with path %s", vnfd_path) vnfd = None @@ -2619,39 +2538,11 @@ class VnfManager(object): return vnfd - @asyncio.coroutine - def get_vnfd_ref(self, vnfd_id): - """ Get Virtual Network Function descriptor for the passed vnfd_id""" - vnfd = yield from self.get_vnfd(vnfd_id) - vnfd.ref() - return vnfd - - @asyncio.coroutine - def get_vnfd(self, vnfd_id): - """ Get Virtual Network Function descriptor for the passed vnfd_id""" - vnfd = None - if vnfd_id not in self._vnfds: - self._log.error("Cannot find VNFD id:%s", vnfd_id) - vnfd = yield from self.fetch_vnfd(vnfd_id) - - if vnfd is None: - self._log.error("Cannot find VNFD id:%s", vnfd_id) - raise VirtualNetworkFunctionDescriptorError("Cannot find VNFD id:%s", vnfd_id) - - if vnfd.id != vnfd_id: - self._log.error("Bad Recovery state {} found for {}".format(vnfd.id, vnfd_id)) - raise VirtualNetworkFunctionDescriptorError("Bad Recovery state {} found for {}".format(vnfd.id, vnfd_id)) - - if vnfd.id not in self._vnfds: - self.create_vnfd(vnfd) - - return self._vnfds[vnfd_id] - def vnfd_in_use(self, vnfd_id): """ Is this VNFD in use """ self._log.debug("Is this VNFD in use - msg:%s", vnfd_id) - if vnfd_id in self._vnfds: - return self._vnfds[vnfd_id].in_use() + if vnfd_id in self._vnfds_to_vnfr: + return self._vnfds_to_vnfr[vnfd_id].in_use() return False @asyncio.coroutine @@ -2661,47 +2552,22 @@ class VnfManager(object): path, msg) yield from self.vnfr_handler.update(xact, path, msg) - def create_vnfd(self, vnfd): - """ Create a virtual network function descriptor """ - self._log.debug("Create virtual networkfunction descriptor - %s", vnfd) - if vnfd.id in self._vnfds: - self._log.error("Cannot create VNFD %s -VNFD id already exists", vnfd) - raise VirtualNetworkFunctionDescriptorError("VNFD already exists-%s", vnfd.id) - - self._vnfds[vnfd.id] = VirtualNetworkFunctionDescriptor(self._dts, - self._log, - self._loop, - self, - vnfd) - return self._vnfds[vnfd.id] - - def update_vnfd(self, vnfd): - """ update the Virtual Network Function descriptor """ - self._log.debug("Update virtual network function descriptor - %s", vnfd) - - if vnfd.id not in self._vnfds: - self._log.debug("No VNFD found - creating VNFD id = %s", vnfd.id) - self.create_vnfd(vnfd) - else: - self._log.debug("Updating VNFD id = %s, vnfd = %s", vnfd.id, vnfd) - self._vnfds[vnfd.id].update(vnfd) - @asyncio.coroutine def delete_vnfd(self, vnfd_id): """ Delete the Virtual Network Function descriptor with the passed id """ self._log.debug("Deleting the virtual network function descriptor - %s", vnfd_id) - if vnfd_id not in self._vnfds: + if vnfd_id not in self._vnfds_to_vnfr: self._log.debug("Delete VNFD failed - cannot find vnfd-id %s", vnfd_id) raise VirtualNetworkFunctionDescriptorNotFound("Cannot find %s", vnfd_id) - if self._vnfds[vnfd_id].in_use(): + if self._vnfds_to_vnfr[vnfd_id].in_use(): self._log.debug("Cannot delete VNFD id %s reference exists %s", vnfd_id, - self._vnfds[vnfd_id].ref_count) + self._vnfds_to_vnfr[vnfd_id].vnfd_ref_count) raise VirtualNetworkFunctionDescriptorRefCountExists( "Cannot delete :%s, ref_count:%s", vnfd_id, - self._vnfds[vnfd_id].ref_count) + self._vnfds_to_vnfr[vnfd_id].vnfd_ref_count) # Remove any files uploaded with VNFD and stored under $RIFT_ARTIFACTS/libs/ try: @@ -2711,10 +2577,10 @@ class VnfManager(object): shutil.rmtree(vnfd_dir, ignore_errors=True) except Exception as e: self._log.error("Exception in cleaning up VNFD {}: {}". - format(self._vnfds[vnfd_id].name, e)) + format(self._vnfds_to_vnfr[vnfd_id].vnfd.name, e)) self._log.exception(e) - del self._vnfds[vnfd_id] + del self._vnfds_to_vnfr[vnfd_id] def vnfd_refcount_xpath(self, vnfd_id): """ xpath for ref count entry """ @@ -2726,14 +2592,15 @@ class VnfManager(object): """ Get the vnfd_list from this VNFM""" vnfd_list = [] if vnfd_id is None or vnfd_id == "": - for vnfd in self._vnfds.values(): + for vnfr in self._vnfds_to_vnfr.values(): + vnfd_msg = RwVnfrYang.YangData_Vnfr_VnfrCatalog_VnfdRefCount() + vnfd_msg.vnfd_id_ref = vnfr.vnfd.id + vnfd_msg.instance_ref_count = vnfr.vnfd_ref_count + vnfd_list.append((self.vnfd_refcount_xpath(vnfr.vnfd.id), vnfd_msg)) + elif vnfd_id in self._vnfds_to_vnfr: vnfd_msg = RwVnfrYang.YangData_Vnfr_VnfrCatalog_VnfdRefCount() - vnfd_msg.vnfd_id_ref = vnfd.id - vnfd_msg.instance_ref_count = vnfd.ref_count - vnfd_list.append((self.vnfd_refcount_xpath(vnfd.id), vnfd_msg)) - elif vnfd_id in self._vnfds: - vnfd_msg.vnfd_id_ref = self._vnfds[vnfd_id].id - vnfd_msg.instance_ref_count = self._vnfds[vnfd_id].ref_count + vnfd_msg.vnfd_id_ref = self._vnfds_to_vnfr[vnfd_id].vnfd.id + vnfd_msg.instance_ref_count = self._vnfds_to_vnfr[vnfd_id].vnfd_ref_count vnfd_list.append((self.vnfd_refcount_xpath(vnfd_id), vnfd_msg)) return vnfd_list diff --git a/rwlaunchpad/ra/pytest/ns/pingpong/test_records.py b/rwlaunchpad/ra/pytest/ns/pingpong/test_records.py index 920bd709..9f1cd0a2 100644 --- a/rwlaunchpad/ra/pytest/ns/pingpong/test_records.py +++ b/rwlaunchpad/ra/pytest/ns/pingpong/test_records.py @@ -78,7 +78,7 @@ def yield_vnfd_vnfr_pairs(proxy, nsr=None): if vnfr.id not in const_vnfr_ids: continue - vnfd = get_vnfd(vnfr.vnfd_ref) + vnfd = get_vnfd(vnfr.vnfd.id) yield vnfd, vnfr diff --git a/rwlaunchpad/ra/pytest/test_failover.py b/rwlaunchpad/ra/pytest/test_failover.py index 40dd7d0c..60ba82a4 100755 --- a/rwlaunchpad/ra/pytest/test_failover.py +++ b/rwlaunchpad/ra/pytest/test_failover.py @@ -60,7 +60,7 @@ def yield_vnfd_vnfr_pairs(proxy, nsr=None): if vnfr.id not in const_vnfr_ids: continue - vnfd = get_vnfd(vnfr.vnfd_ref) + vnfd = get_vnfd(vnfr.vnfd.id) yield vnfd, vnfr def check_configuration_on_standby(standby_ip): -- 2.25.1