-#
+#
# Copyright 2016 RIFT.IO Inc
#
# Licensed under the Apache License, Version 2.0 (the "License");
import rift.tasklets
import rift.package.store
import rift.package.cloud_init
+import rift.package.script
+import rift.mano.dts as mano_dts
+from rift.mano.utils.project import (
+ ManoProject,
+ ProjectHandler,
+ )
+import rift.mano.utils.short_name as mano_short_name
class VMResourceError(Exception):
class VcsComponent(object):
""" VCS Component within the VNF descriptor """
- def __init__(self, dts, log, loop, cluster_name, vcs_handler, component, mangled_name):
+ def __init__(self, dts, log, loop, cluster_name,
+ vcs_handler, component, mangled_name):
self._dts = dts
self._log = log
self._loop = loop
@property
def path(self):
""" The path for this object """
- return("D,/rw-manifest:manifest" +
+ return ("D,/rw-manifest:manifest" +
"/rw-manifest:operational-inventory" +
"/rw-manifest:component" +
"[rw-manifest:component-name = '{}']").format(self.name)
dts,
log,
loop,
+ project,
vdud,
vnfr,
+ nsr_config,
mgmt_intf,
+ mgmt_network,
cloud_account_name,
vnfd_package_store,
vdur_id=None,
self._dts = dts
self._log = log
self._loop = loop
+ self._project = project
self._vdud = vdud
self._vnfr = vnfr
+ self._nsr_config = nsr_config
self._mgmt_intf = mgmt_intf
self._cloud_account_name = cloud_account_name
self._vnfd_package_store = vnfd_package_store
+ self._mgmt_network = mgmt_network
self._vdur_id = vdur_id or str(uuid.uuid4())
self._int_intf = []
self._rm_regh = None
self._vm_resp = None
self._vdud_cloud_init = None
- self._vdur_console_handler = VnfrConsoleOperdataDtsHandler(dts, log, loop, self._vnfr._vnfm, self._vnfr.vnfr_id, self._vdur_id,self.vdu_id)
+ self._vdur_console_handler = VnfrConsoleOperdataDtsHandler(
+ dts, log, loop, self._vnfr._vnfm, self._vnfr.vnfr_id, self._vdur_id,self.vdu_id)
@asyncio.coroutine
def vdu_opdata_register(self):
return conn_point.ip_address
return "0.0.0.0"
+ def cp_mac_addr(self, cp_name):
+ """ Find mac address by connection point name """
+ if self._vm_resp is not None:
+ for conn_point in self._vm_resp.connection_points:
+ if conn_point.name == cp_name:
+ return conn_point.mac_addr
+ return "00:00:00:00:00:00"
+
def cp_id(self, cp_name):
""" Find connection point id by connection point name """
if self._vm_resp is not None:
""" Return this VDUR's name """
return self._name
+ # Truncated name confirming to RFC 1123
+ @property
+ def unique_short_name(self):
+ """ Return this VDUR's unique short name """
+ # Impose these restrictions on Unique name
+ # Max 64
+ # - Max 10 of NSR name (remove all specialcharacters, only numbers and alphabets)
+ # - 6 chars of shortened name
+ # - Max 10 of VDU name (remove all specialcharacters, only numbers and alphabets)
+ #
+ def _restrict_tag(input_str):
+ # Exclude all characters except a-zA-Z0-9
+ outstr = re.sub('[^a-zA-Z0-9]', '', input_str)
+ # Take max of 10 chars
+ return outstr[-10:]
+
+ # Use NSR name for part1
+ part1 = _restrict_tag(self._nsr_config.name)
+ # Get unique short string (6 chars)
+ part2 = mano_short_name.StringShortner(self._name)
+ # Use VDU ID for part3
+ part3 = _restrict_tag(self._vdud.id)
+ shortstr = part1 + "-" + part2.short_string + "-" + part3
+ return shortstr
+
@property
def cloud_account_name(self):
""" Cloud account this VDU should be created in """
@property
def image_name(self):
""" name that should be used to lookup the image on the CMP """
+ if 'image' not in self._vdud:
+ return None
return os.path.basename(self._vdud.image)
@property
@property
def msg(self):
- """ VDU message """
+ """ Process VDU message from resmgr"""
vdu_fields = ["vm_flavor",
"guest_epa",
"vswitch_epa",
"hypervisor_epa",
"host_epa",
- "name"]
+ "volumes",
+ ]
vdu_copy_dict = {k: v for k, v in
self._vdud.as_dict().items() if k in vdu_fields}
vdur_dict = {"id": self._vdur_id,
"vdu_id_ref": self._vdud.id,
"operational_status": self.operational_status,
"operational_status_details": self._state_failed_reason,
+ "name": self.name,
+ "unique_short_name": self.unique_short_name
}
+
if self.vm_resp is not None:
vdur_dict.update({"vim_id": self.vm_resp.vdu_id,
- "flavor_id": self.vm_resp.flavor_id,
- "image_id": self.vm_resp.image_id,
+ "flavor_id": self.vm_resp.flavor_id
})
+ if self._vm_resp.has_field('image_id'):
+ vdur_dict.update({ "image_id": self.vm_resp.image_id })
if self.management_ip is not None:
vdur_dict["management_ip"] = self.management_ip
vdur_dict.update(vdu_copy_dict)
+ if self.vm_resp is not None:
+ if self._vm_resp.has_field('volumes'):
+ for opvolume in self._vm_resp.volumes:
+ vdurvol_data = [vduvol for vduvol in vdur_dict['volumes'] if vduvol['name'] == opvolume.name]
+ if len(vdurvol_data) == 1:
+ vdurvol_data[0]["volume_id"] = opvolume.volume_id
+ if opvolume.has_field('custom_meta_data'):
+ metadata_list = list()
+ for metadata_item in opvolume.custom_meta_data:
+ metadata_list.append(metadata_item.as_dict())
+ vdurvol_data[0]['custom_meta_data'] = metadata_list
+
+ if self._vm_resp.has_field('supplemental_boot_data'):
+ vdur_dict['supplemental_boot_data'] = dict()
+ if self._vm_resp.supplemental_boot_data.has_field('boot_data_drive'):
+ vdur_dict['supplemental_boot_data']['boot_data_drive'] = self._vm_resp.supplemental_boot_data.boot_data_drive
+ if self._vm_resp.supplemental_boot_data.has_field('custom_meta_data'):
+ metadata_list = list()
+ for metadata_item in self._vm_resp.supplemental_boot_data.custom_meta_data:
+ metadata_list.append(metadata_item.as_dict())
+ vdur_dict['supplemental_boot_data']['custom_meta_data'] = metadata_list
+ if self._vm_resp.supplemental_boot_data.has_field('config_file'):
+ file_list = list()
+ for file_item in self._vm_resp.supplemental_boot_data.config_file:
+ file_list.append(file_item.as_dict())
+ vdur_dict['supplemental_boot_data']['config_file'] = file_list
+
icp_list = []
ii_list = []
icp_list.append({"name": cp.name,
"id": cp.id,
"type_yang": "VPORT",
- "ip_address": self.cp_ip_addr(cp.id)})
+ "ip_address": self.cp_ip_addr(cp.id),
+ "mac_address": self.cp_mac_addr(cp.id)})
ii_list.append({"name": intf.name,
"vdur_internal_connection_point_ref": cp.id,
ei_list = []
for intf, cp, vlr in self._ext_intf:
- ei_list.append({"name": cp,
- "vnfd_connection_point_ref": cp,
+ ei_list.append({"name": cp.name,
+ "vnfd_connection_point_ref": cp.name,
"virtual_interface": {}})
- self._vnfr.update_cp(cp, self.cp_ip_addr(cp), self.cp_id(cp))
+ self._vnfr.update_cp(cp.name,
+ self.cp_ip_addr(cp.name),
+ self.cp_mac_addr(cp.name),
+ self.cp_id(cp.name))
vdur_dict["external_interface"] = ei_list
placement_groups = []
for group in self._placement_groups:
placement_groups.append(group.as_dict())
-
vdur_dict['placement_groups_info'] = placement_groups
- return RwVnfrYang.YangData_Vnfr_VnfrCatalog_Vnfr_Vdur.from_dict(vdur_dict)
+
+ return RwVnfrYang.YangData_RwProject_Project_VnfrCatalog_Vnfr_Vdur.from_dict(vdur_dict)
@property
def resmgr_path(self):
""" path for resource-mgr"""
- return ("D,/rw-resource-mgr:resource-mgmt" +
- "/vdu-event" +
- "/vdu-event-data[event-id='{}']".format(self._request_id))
+ xpath = self._project.add_project("D,/rw-resource-mgr:resource-mgmt" +
+ "/vdu-event" +
+ "/vdu-event-data[event-id='{}']".format(self._request_id))
+ return xpath
@property
def vm_flavor_msg(self):
try:
return cloud_init_extractor.read_script(stored_package, filename)
except rift.package.cloud_init.CloudInitExtractionError as e:
+ self.instantiation_failed(str(e))
raise VirtualDeploymentUnitRecordError(e)
else:
self._log.debug("VDU Instantiation: cloud-init script not provided")
if availability_zones:
if len(availability_zones) > 1:
- self._log.error("Can not launch VDU: %s in multiple availability zones. Requested Zones: %s", self.name, availability_zones)
- raise VNFMPlacementGroupError("Can not launch VDU: {} in multiple availability zones. Requsted Zones".format(self.name, availability_zones))
+ self._log.error("Can not launch VDU: %s in multiple availability zones. " +
+ "Requested Zones: %s", self.name, availability_zones)
+ raise VNFMPlacementGroupError("Can not launch VDU: {} in multiple availability" +
+ " zones. Requsted Zones".format(self.name, availability_zones))
else:
vm_create_msg_dict['availability_zone'] = availability_zones[0]
if server_groups:
if len(server_groups) > 1:
- self._log.error("Can not launch VDU: %s in multiple Server Group. Requested Groups: %s", self.name, server_groups)
- raise VNFMPlacementGroupError("Can not launch VDU: {} in multiple Server Groups. Requsted Groups".format(self.name, server_groups))
+ self._log.error("Can not launch VDU: %s in multiple Server Group. " +
+ "Requested Groups: %s", self.name, server_groups)
+ raise VNFMPlacementGroupError("Can not launch VDU: {} in multiple " +
+ "Server Groups. Requsted Groups".format(self.name, server_groups))
else:
vm_create_msg_dict['server_group'] = server_groups[0]
self._log.info("Ignoring placement group with cloud construct for cloud-type: %s", cloud_type)
return
+ def process_custom_bootdata(self, vm_create_msg_dict):
+ """Process the custom boot data"""
+ if 'config_file' not in vm_create_msg_dict['supplemental_boot_data']:
+ return
+
+ self._vnfd_package_store.refresh()
+ stored_package = self._vnfd_package_store.get_package(self._vnfr.vnfd_id)
+ cloud_init_extractor = rift.package.cloud_init.PackageCloudInitExtractor(self._log)
+ for file_item in vm_create_msg_dict['supplemental_boot_data']['config_file']:
+ if 'source' not in file_item or 'dest' not in file_item:
+ continue
+ source = file_item['source']
+ # Find source file in scripts dir of VNFD
+ self._log.debug("Checking for source config file at %s", source)
+ try:
+ source_file_str = cloud_init_extractor.read_script(stored_package, source)
+ except rift.package.cloud_init.CloudInitExtractionError as e:
+ raise VirtualDeploymentUnitRecordError(e)
+ # Update source file location with file contents
+ file_item['source'] = source_file_str
+
+ return
+
def resmgr_msg(self, config=None):
vdu_fields = ["vm_flavor",
"guest_epa",
"vswitch_epa",
"hypervisor_epa",
- "host_epa"]
+ "host_epa",
+ "volumes",
+ "supplemental_boot_data"]
self._log.debug("Creating params based on VDUD: %s", self._vdud)
vdu_copy_dict = {k: v for k, v in self._vdud.as_dict().items() if k in vdu_fields}
vm_create_msg_dict = {
- "name": self.name,
- "image_name": self.image_name,
+ "name": self.unique_short_name, # Truncated name confirming to RFC 1123
+ "node_id": self.name, # Rift assigned Id
}
+ if self.image_name is not None:
+ vm_create_msg_dict["image_name"] = self.image_name
+
if self.image_checksum is not None:
vm_create_msg_dict["image_checksum"] = self.image_checksum
if config is not None:
vm_create_msg_dict['vdu_init'] = {'userdata': config}
+ if self._mgmt_network:
+ vm_create_msg_dict['mgmt_network'] = self._mgmt_network
+
cp_list = []
for intf, cp, vlr in self._ext_intf:
- cp_info = {"name": cp,
- "virtual_link_id": vlr.network_id,
- "type_yang": intf.virtual_interface.type_yang}
+ cp_info = { "name": cp.name,
+ "virtual_link_id": vlr.network_id,
+ "type_yang": intf.virtual_interface.type_yang }
+
+ if cp.has_field('port_security_enabled'):
+ cp_info["port_security_enabled"] = cp.port_security_enabled
if (intf.virtual_interface.has_field('vpci') and
intf.virtual_interface.vpci is not None):
if (vlr.has_field('ip_profile_params')) and (vlr.ip_profile_params.has_field('security_group')):
cp_info['security_group'] = vlr.ip_profile_params.security_group
-
+
cp_list.append(cp_info)
for intf, cp, vlr in self._int_intf:
"type_yang": intf.virtual_interface.type_yang,
"vpci": intf.virtual_interface.vpci})
else:
- cp_list.append({"name": cp,
- "virtual_link_id": vlr.network_id,
- "type_yang": intf.virtual_interface.type_yang})
+ if cp.has_field('port_security_enabled'):
+ cp_list.append({"name": cp,
+ "virtual_link_id": vlr.network_id,
+ "type_yang": intf.virtual_interface.type_yang,
+ "port_security_enabled": cp.port_security_enabled})
+ else:
+ cp_list.append({"name": cp,
+ "virtual_link_id": vlr.network_id,
+ "type_yang": intf.virtual_interface.type_yang})
+
vm_create_msg_dict["connection_points"] = cp_list
vm_create_msg_dict.update(vdu_copy_dict)
self.process_placement_groups(vm_create_msg_dict)
+ if 'supplemental_boot_data' in vm_create_msg_dict:
+ self.process_custom_bootdata(vm_create_msg_dict)
msg = RwResourceMgrYang.VDUEventData()
msg.event_id = self._request_id
msg.cloud_account = self.cloud_account_name
msg.request_info.from_dict(vm_create_msg_dict)
+
return msg
@asyncio.coroutine
self._rm_regh = None
if self._vdur_console_handler is not None:
- self._log.error("Deregistering vnfr vdur registration handle")
+ self._log.debug("Deregistering vnfr vdur registration handle")
self._vdur_console_handler._regh.deregister()
self._vdur_console_handler._regh = None
vlr = vnfr.ext_vlr_by_id(cp.vlr_ref)
- etuple = (ext_intf, cp.name, vlr)
+ etuple = (ext_intf, cp, vlr)
self._ext_intf.append(etuple)
self._log.debug("Created external interface tuple : %s", etuple)
vm_resp = yield from self.create_resource(xact, vnfr, config)
self._vm_resp = vm_resp
-
self._state = VDURecordState.RESOURCE_ALLOC_PENDING
+
self._log.debug("Requested VM from resource manager response %s",
vm_resp)
if vm_resp.resource_state == "active":
class InternalVirtualLinkRecord(object):
""" Internal Virtual Link record """
- def __init__(self, dts, log, loop, ivld_msg, vnfr_name, cloud_account_name):
+ def __init__(self, dts, log, loop, project,
+ ivld_msg, vnfr_name, cloud_account_name, ip_profile=None):
self._dts = dts
self._log = log
self._loop = loop
+ self._project = project
self._ivld_msg = ivld_msg
self._vnfr_name = vnfr_name
self._cloud_account_name = cloud_account_name
+ self._ip_profile = ip_profile
self._vlr_req = self.create_vlr()
self._vlr = None
@property
def name(self):
""" Name of this VL """
- return self._vnfr_name + "." + self._ivld_msg.name
+ if self._ivld_msg.vim_network_name:
+ return self._ivld_msg.vim_network_name
+ else:
+ return self._vnfr_name + "." + self._ivld_msg.name
@property
def network_id(self):
def vlr_path(self):
""" VLR path for this VLR instance"""
- return "D,/vlr:vlr-catalog/vlr:vlr[vlr:id = '{}']".format(self.vlr_id)
+ return self._project.add_project("D,/vlr:vlr-catalog/vlr:vlr[vlr:id = '{}']".
+ format(self.vlr_id))
def create_vlr(self):
""" Create the VLR record which will be instantiated """
"description",
"version",
"type_yang",
+ "vim_network_name",
"provider_network"]
vld_copy_dict = {k: v for k, v in self._ivld_msg.as_dict().items() if k in vld_fields}
"name": self.name,
"cloud_account": self._cloud_account_name,
}
+
+ if self._ip_profile and self._ip_profile.has_field('ip_profile_params'):
+ vlr_dict['ip_profile_params' ] = self._ip_profile.ip_profile_params.as_dict()
+
vlr_dict.update(vld_copy_dict)
- vlr = RwVlrYang.YangData_Vlr_VlrCatalog_Vlr.from_dict(vlr_dict)
+ vlr = RwVlrYang.YangData_RwProject_Project_VlrCatalog_Vlr.from_dict(vlr_dict)
return vlr
@asyncio.coroutine
class VirtualNetworkFunctionRecord(object):
""" Virtual Network Function Record """
- def __init__(self, dts, log, loop, cluster_name, vnfm, vcs_handler, vnfr_msg):
+ def __init__(self, dts, log, loop, cluster_name, vnfm, vcs_handler, vnfr_msg, mgmt_network=None):
self._dts = dts
self._log = log
self._loop = loop
+ self._project = vnfm._project
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
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)
"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,/project-vnfd:vnfd-catalog/project-vnfd:vnfd[project-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):
def get_nsr_config(self):
### Need access to NS instance configuration for runtime resolution.
### This shall be replaced when deployment flavors are implemented
- xpath = "C,/nsr:ns-instance-config"
+ xpath = self._project.add_project("C,/nsr:ns-instance-config")
results = yield from self._dts.query_read(xpath, rwdts.XactFlag.MERGE)
for result in results:
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)
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()
+ mgmt_intf = VnfrYang.YangData_RwProject_Project_VnfrCatalog_Vnfr_MgmtInterface()
ip_address, port = self.mgmt_intf_info()
if ip_address is not None:
"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,
vnfr_dict.update(vnfd_copy_dict)
- vnfr_msg = RwVnfrYang.YangData_Vnfr_VnfrCatalog_Vnfr.from_dict(vnfr_dict)
+ vnfr_msg = RwVnfrYang.YangData_RwProject_Project_VnfrCatalog_Vnfr.from_dict(vnfr_dict)
+ vnfr_msg.vnfd = VnfrYang.YangData_RwProject_Project_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
# Add all the VLRs to VNFR
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:
- new_cp = VnfrYang.YangData_Vnfr_VnfrCatalog_Vnfr_ConnectionPoint.from_dict(cpr.as_dict())
+ new_cp = VnfrYang.YangData_RwProject_Project_VnfrCatalog_Vnfr_ConnectionPoint.from_dict(cpr.as_dict())
vnfr_msg.connection_point.append(new_cp)
if self._vnf_mon is not None:
for monp in self._vnf_mon.msg:
vnfr_msg.monitoring_param.append(
- VnfrYang.YangData_Vnfr_VnfrCatalog_Vnfr_MonitoringParam.from_dict(monp.as_dict()))
+ VnfrYang.YangData_RwProject_Project_VnfrCatalog_Vnfr_MonitoringParam.from_dict(monp.as_dict()))
if self._vnfr.vnf_configuration is not None:
vnfr_msg.vnf_configuration.from_dict(self._vnfr.vnf_configuration.as_dict())
vnfr_msg.vnf_configuration.config_access.mgmt_ip_address = ip_address
for group in self._vnfr_msg.placement_groups_info:
- group_info = VnfrYang.YangData_Vnfr_VnfrCatalog_Vnfr_PlacementGroupsInfo()
+ group_info = VnfrYang.YangData_RwProject_Project_VnfrCatalog_Vnfr_PlacementGroupsInfo()
group_info.from_dict(group.as_dict())
vnfr_msg.placement_groups_info.append(group_info)
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
@property
def xpath(self):
""" path for this VNFR """
- return("D,/vnfr:vnfr-catalog"
+ return self._project.add_project("D,/vnfr:vnfr-catalog"
"/vnfr:vnfr[vnfr:id='{}']".format(self.vnfr_id))
@asyncio.coroutine
self._log.debug("Published VNFR path = [%s], record = [%s]",
self.xpath, self.msg)
+ def resolve_vld_ip_profile(self, vnfd_msg, vld):
+ self._log.debug("Receieved ip profile ref is %s",vld.ip_profile_ref)
+ if not vld.has_field('ip_profile_ref'):
+ return None
+ profile = [profile for profile in vnfd_msg.ip_profiles if profile.name == vld.ip_profile_ref]
+ return profile[0] if profile else None
+
@asyncio.coroutine
def create_vls(self):
""" 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_ref
+ ivld_msg, ivld_msg.internal_connection_point
)
vlr = InternalVirtualLinkRecord(dts=self._dts,
log=self._log,
loop=self._loop,
ivld_msg=ivld_msg,
vnfr_name=self.name,
- cloud_account_name=self.cloud_account_name
+ cloud_account_name=self.cloud_account_name,
+ ip_profile=self.resolve_vld_ip_profile(self.vnfd, ivld_msg)
)
self._vlrs.append(vlr)
- for int_cp in ivld_msg.internal_connection_point_ref:
- if int_cp in self._vlr_by_cp:
+ for int_cp in ivld_msg.internal_connection_point:
+ if int_cp.id_ref in self._vlr_by_cp:
msg = ("Connection point %s already "
- " bound %s" % (int_cp, self._vlr_by_cp[int_cp]))
+ " bound %s" % (int_cp.id_ref, self._vlr_by_cp[int_cp.id_ref]))
raise InternalVirtualLinkRecordError(msg)
self._log.debug("Setting vlr %s to internal cp = %s",
- vlr, int_cp)
- self._vlr_by_cp[int_cp] = vlr
+ vlr, int_cp.id_ref)
+ self._vlr_by_cp[int_cp.id_ref] = vlr
@asyncio.coroutine
def instantiate_vls(self, xact, restart_mode=False):
for group_info in nsr_config.vnfd_placement_group_maps:
if group_info.placement_group_ref == input_group.name and \
group_info.vnfd_id_ref == self.vnfd_id:
- group = VnfrYang.YangData_Vnfr_VnfrCatalog_Vnfr_Vdur_PlacementGroupsInfo()
+ group = VnfrYang.YangData_RwProject_Project_VnfrCatalog_Vnfr_Vdur_PlacementGroupsInfo()
group_dict = {k:v for k,v in
group_info.as_dict().items()
if (k != 'placement_group_ref' and k !='vnfd_id_ref')}
return None
@asyncio.coroutine
- def get_vdu_placement_groups(self, vdu):
+ def get_vdu_placement_groups(self, vdu, nsr_config):
placement_groups = []
### Step-1: Get VNF level placement groups
for group in self._vnfr_msg.placement_groups_info:
- #group_info = VnfrYang.YangData_Vnfr_VnfrCatalog_Vnfr_Vdur_PlacementGroupsInfo()
+ #group_info = VnfrYang.YangData_RwProject_Project_VnfrCatalog_Vnfr_Vdur_PlacementGroupsInfo()
#group_info.from_dict(group.as_dict())
placement_groups.append(group)
- ### Step-2: Get NSR config. This is required for resolving placement_groups cloud constructs
- nsr_config = yield from self.get_nsr_config()
-
- ### Step-3: Get VDU level placement groups
- for group in self.vnfd.msg.placement_groups:
+ ### Step-2: Get VDU level 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,
nsr_config)
if group_info is None:
- self._log.info("Could not resolve cloud-construct for placement group: %s", group.name)
- ### raise VNFMPlacementGroupError("Could not resolve cloud-construct for placement group: {}".format(group.name))
+ self._log.info("Could not resolve cloud-construct for " +
+ "placement group: %s", group.name)
else:
- self._log.info("Successfully resolved cloud construct for placement group: %s for VDU: %s in VNF: %s (Member Index: %s)",
+ self._log.info("Successfully resolved cloud construct for " +
+ "placement group: %s for VDU: %s in VNF: %s (Member Index: %s)",
str(group_info),
vdu.name,
self.vnf_name,
return placement_groups
+ @asyncio.coroutine
+ def vdu_cloud_init_instantiation(self):
+ [vdu.vdud_cloud_init for vdu in self._vdus]
+
@asyncio.coroutine
def create_vdus(self, vnfr, restart_mode=False):
""" Create the VDUs associated with this VNF """
self._log.info("Creating VDU's for vnfd id: %s", self.vnfd_id)
- for vdu in self.vnfd.msg.vdu:
+
+ # Get NSR config - Needed for placement groups and to derive VDU short-name
+ nsr_config = yield from self.get_nsr_config()
+
+ for vdu in self._rw_vnfd.vdu:
self._log.debug("Creating vdu: %s", vdu)
vdur_id = get_vdur_id(vdu)
- placement_groups = yield from self.get_vdu_placement_groups(vdu)
- self._log.info("Launching VDU: %s from VNFD :%s (Member Index: %s) with Placement Groups: %s",
+
+ placement_groups = yield from self.get_vdu_placement_groups(vdu, nsr_config)
+ self._log.info("Launching VDU: %s from VNFD :%s (Member Index: %s) with Placement Groups: %s, Existing vdur_id %s",
vdu.name,
self.vnf_name,
self.member_vnf_index,
- [ group.name for group in placement_groups])
+ [ group.name for group in placement_groups],
+ vdur_id)
vdur = VirtualDeploymentUnitRecord(
dts=self._dts,
log=self._log,
loop=self._loop,
+ project = self._project,
vdud=vdu,
vnfr=vnfr,
+ nsr_config=nsr_config,
mgmt_intf=self.has_mgmt_interface(vdu),
+ mgmt_network=self._mgmt_network,
cloud_account_name=self.cloud_account_name,
vnfd_package_store=self._vnfd_package_store,
vdur_id=vdur_id,
vdu_id_pattern = re.compile(r"\{\{ vdu\[([^]]+)\]\S* \}\}")
for vdu in self._vdus:
- if vdu.vdud_cloud_init is not None:
- for vdu_id in vdu_id_pattern.findall(vdu.vdud_cloud_init):
+ if vdu._vdud_cloud_init is not None:
+ for vdu_id in vdu_id_pattern.findall(vdu._vdud_cloud_init):
if vdu_id != vdu.vdu_id:
# This means that vdu.vdu_id depends upon vdu_id,
# i.e. vdu_id must be instantiated before
# wait for the VDUR to enter a terminal state
while vdu._state not in terminal:
yield from asyncio.sleep(1, loop=self._loop)
-
# update the datastore
datastore.update(vdu)
datastore.add(vdu)
# Substitute any variables contained in the cloud config script
- config = str(vdu.vdud_cloud_init)
+ config = str(vdu.vdud_cloud_init) if vdu.vdud_cloud_init is not None else ""
parts = re.split("\{\{ ([^\}]+) \}\}", config)
if len(parts) > 1:
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
def vlr_xpath(self, vlr_id):
""" vlr xpath """
- return(
- "D,/vlr:vlr-catalog/"
+ return self._project.add_project("D,/vlr:vlr-catalog/"
"vlr:vlr[vlr:id = '{}']".format(vlr_id))
def ext_vlr_by_id(self, vlr_id):
""" 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,
# Update the VNFR with the changed status
yield from self.publish(None)
- def update_cp(self, cp_name, ip_address, cp_id):
+ def update_cp(self, cp_name, ip_address, mac_addr, cp_id):
"""Updated the connection point with ip address"""
for cp in self._cprs:
if cp.name == cp_name:
self._log.debug("Setting ip address and id for cp %s, cpr %s with ip %s id %s",
cp_name, cp, ip_address, cp_id)
cp.ip_address = ip_address
+ cp.mac_address = mac_addr
cp.connection_point_id = cp_id
return
@asyncio.coroutine
def instantiate(self, xact, restart_mode=False):
""" instantiate this VNF """
+ self._log.info("Instantiate VNF {}: {}".format(self._vnfr_id, self._state))
self.set_state(VirtualNetworkFunctionRecordState.VL_INIT_PHASE)
+ self._rw_vnfd = yield from self._vnfm.fetch_vnfd(self._vnfd_id)
@asyncio.coroutine
def fetch_vlrs():
def cpr_from_cp(cp):
""" Creates a record level connection point from the desciptor cp"""
- cp_fields = ["name", "image", "vm-flavor"]
+ cp_fields = ["name", "image", "vm-flavor", "port_security_enabled"]
cp_copy_dict = {k: v for k, v in cp.as_dict().items() if k in cp_fields}
cpr_dict = {}
cpr_dict.update(cp_copy_dict)
- return VnfrYang.YangData_Vnfr_VnfrCatalog_Vnfr_ConnectionPoint.from_dict(cpr_dict)
+ return VnfrYang.YangData_RwProject_Project_VnfrCatalog_Vnfr_ConnectionPoint.from_dict(cpr_dict)
self._log.debug("Fetching VLRs for VNFR id = %s, cps = %s",
self._vnfr_id, self._vnfr.connection_point)
vlr_path = self.vlr_xpath(cp.vlr_ref)
self._log.debug("Fetching VLR with path = %s", vlr_path)
- res_iter = yield from self._dts.query_read(self.vlr_xpath(cp.vlr_ref),
+ res_iter = yield from self._dts.query_read(vlr_path,
rwdts.XactFlag.MERGE)
for i in res_iter:
r = yield from i
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)
yield from self.publish_inventory(xact)
# Publish inventory
- self._log.debug("VNFR-ID %s: Creating VLs", self._vnfr_id)
+ self._log.debug("Create VLs {}: {}".format(self._vnfr_id, self._state))
yield from self.create_vls()
# publish the VNFR
- self._log.debug("VNFR-ID %s: Publish VNFR", self._vnfr_id)
+ self._log.debug("Publish VNFR {}: {}".format(self._vnfr_id, self._state))
yield from self.publish(xact)
+
# instantiate VLs
- self._log.debug("VNFR-ID %s: Instantiate VLs", self._vnfr_id)
+ self._log.debug("VNFR-ID %s: Instantiate VLs, restart mode %s", self._vnfr_id, restart_mode)
try:
yield from self.instantiate_vls(xact, restart_mode)
except Exception as e:
self.set_state(VirtualNetworkFunctionRecordState.VM_INIT_PHASE)
# instantiate VDUs
- self._log.debug("VNFR-ID %s: Create VDUs", self._vnfr_id)
+ self._log.debug("VNFR-ID %s: Create VDUs, restart mode %s", self._vnfr_id, restart_mode)
yield from self.create_vdus(self, restart_mode)
+ try:
+ yield from self.vdu_cloud_init_instantiation()
+ except Exception as e:
+ self.set_state(VirtualNetworkFunctionRecordState.FAILED)
+ self._state_failed_reason = str(e)
+ yield from self.publish(xact)
+
# publish the VNFR
- self._log.debug("VNFR-ID %s: Publish VNFR", self._vnfr_id)
+ self._log.debug("VNFR {}: Publish VNFR with state {}".
+ format(self._vnfr_id, self._state))
yield from self.publish(xact)
# instantiate VDUs
# ToDo: Check if this should be prevented during restart
- self._log.debug("VNFR-ID %s: Instantiate VDUs", self._vnfr_id)
+ self._log.debug("Instantiate VDUs {}: {}".format(self._vnfr_id, self._state))
_ = self._loop.create_task(self.instantiate_vdus(xact, self))
# publish the VNFR
self._log.debug("VNFR-ID %s: Instantiation Done", self._vnfr_id)
+ # create task updating uptime for this vnfr
+ self._log.debug("VNFR-ID %s: Starting task to update uptime", self._vnfr_id)
+ self._loop.create_task(self.vnfr_uptime_update(xact))
+
@asyncio.coroutine
def terminate(self, xact):
""" Terminate this virtual network function """
self._log.debug("Terminated VNF id %s", self.vnfr_id)
self.set_state(VirtualNetworkFunctionRecordState.TERMINATED)
+ @asyncio.coroutine
+ def vnfr_uptime_update(self, xact):
+ while True:
+ # Return when vnfr state is FAILED or TERMINATED etc
+ if self._state not in [VirtualNetworkFunctionRecordState.INIT,
+ VirtualNetworkFunctionRecordState.VL_INIT_PHASE,
+ VirtualNetworkFunctionRecordState.VM_INIT_PHASE,
+ VirtualNetworkFunctionRecordState.READY]:
+ return
+ yield from self.publish(xact)
+ yield from asyncio.sleep(2, loop=self._loop)
+
+
class VnfdDtsHandler(object):
""" DTS handler for VNFD config changes """
- XPATH = "C,/vnfd:vnfd-catalog/vnfd:vnfd"
+ XPATH = "C,/project-vnfd:vnfd-catalog/project-vnfd:vnfd"
def __init__(self, dts, log, loop, vnfm):
self._dts = dts
""" DTS registration handle """
return self._regh
+ def deregister(self):
+ '''De-register from DTS'''
+ self._log.debug("De-register VNFD DTS handler for project {}".
+ format(self._vnfm._project.name))
+ if self._regh:
+ self._regh.deregister()
+ self._regh = None
+
@asyncio.coroutine
def register(self):
""" Register for VNFD configuration"""
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):
""" on prepare callback """
- self._log.debug("Got on prepare for VNFD (path: %s) (action: %s)",
- ks_path.to_xpath(RwVnfmYang.get_schema()), msg)
+ self._log.debug("Got on prepare for VNFD (path: %s) (action: %s) (msg: %s)",
+ ks_path.to_xpath(RwVnfmYang.get_schema()),
+ xact_info.query_action, msg)
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)
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)
- self._log.debug(
- "Registering for VNFD config using xpath: %s",
- VnfdDtsHandler.XPATH,
- )
+ xpath = self._vnfm._project.add_project(VnfdDtsHandler.XPATH)
+ self._log.debug("Registering for VNFD config using xpath: {}".
+ format(xpath))
+
acg_hdl = rift.tasklets.AppConfGroup.Handler(on_apply=on_apply)
with self._dts.appconf_group_create(handler=acg_hdl) as acg:
self._regh = acg.register(
- xpath=VnfdDtsHandler.XPATH,
+ xpath=xpath,
flags=rwdts.Flag.SUBSCRIBER | rwdts.Flag.DELTA_READY,
on_prepare=on_prepare)
""" DTS registration handle """
return self._regh
+ def deregister(self):
+ '''De-register from DTS'''
+ self._log.debug("De-register VCS DTS handler for project {}".
+ format(self._vnfm._project))
+ if self._regh:
+ self._regh.deregister()
+ self._regh = None
+
@asyncio.coroutine
def register(self):
""" Registers VCS component dts publisher registration"""
VcsComponentDtsHandler.XPATH, xact, path, msg)
class VnfrConsoleOperdataDtsHandler(object):
- """ registers 'D,/vnfr:vnfr-console/vnfr:vnfr[id]/vdur[id]' and handles CRUD from DTS"""
+ """
+ Registers 'D,/rw-project:project/vnfr:vnfr-console/vnfr:vnfr[id]/vdur[id]'
+ and handles CRUD from DTS
+ """
+
@property
def vnfr_vdu_console_xpath(self):
""" path for resource-mgr"""
- return ("D,/rw-vnfr:vnfr-console/rw-vnfr:vnfr[rw-vnfr:id='{}']/rw-vnfr:vdur[vnfr:id='{}']".format(self._vnfr_id,self._vdur_id))
+ return self._project.add_project("D,/rw-vnfr:vnfr-console/rw-vnfr:vnfr[rw-vnfr:id='{}']" +
+ "/rw-vnfr:vdur[vnfr:id='{}']".format(self._vnfr_id,self._vdur_id))
def __init__(self, dts, log, loop, vnfm, vnfr_id, vdur_id, vdu_id):
self._dts = dts
self._vdur_id = vdur_id
self._vdu_id = vdu_id
+ self._project = vnfm._project
+
+ def deregister(self):
+ '''De-register from DTS'''
+ self._log.debug("De-register VNFR console DTS handler for project {}".
+ format(self._project))
+ if self._regh:
+ self._regh.deregister()
+ self._regh = None
+
@asyncio.coroutine
def register(self):
""" Register for VNFR VDU Operational Data read from dts """
)
if action == rwdts.QueryAction.READ:
- schema = RwVnfrYang.YangData_RwVnfr_VnfrConsole_Vnfr_Vdur.schema()
+ schema = RwVnfrYang.YangData_RwProject_Project_VnfrConsole_Vnfr_Vdur.schema()
path_entry = schema.keyspec_to_entry(ks_path)
- self._log.debug("VDU Opdata path is {}".format(path_entry))
+ self._log.debug("VDU Opdata path is {}".format(path_entry.key00.id))
try:
vnfr = self._vnfm.get_vnfr(self._vnfr_id)
except VnfRecordError as e:
if not vdur._state == VDURecordState.READY:
self._log.debug("VDUR state is not READY. current state is {}".format(vdur._state))
xact_info.respond_xpath(rsp_code=rwdts.XactRspCode.ACK)
- return
+ return
with self._dts.transaction() as new_xact:
resp = yield from vdur.read_resource(new_xact)
- vdur_console = RwVnfrYang.YangData_RwVnfr_VnfrConsole_Vnfr_Vdur()
+ vdur_console = RwVnfrYang.YangData_RwProject_Project_VnfrConsole_Vnfr_Vdur()
vdur_console.id = self._vdur_id
if resp.console_url:
vdur_console.console_url = resp.console_url
self._log.debug("Recevied console URL for vdu {} is {}".format(self._vdu_id,vdur_console))
except Exception:
self._log.exception("Caught exception while reading VDU %s", self._vdu_id)
- vdur_console = RwVnfrYang.YangData_RwVnfr_VnfrConsole_Vnfr_Vdur()
+ vdur_console = RwVnfrYang.YangData_RwProject_Project_VnfrConsole_Vnfr_Vdur()
vdur_console.id = self._vdur_id
vdur_console.console_url = 'none'
-
+
xact_info.respond_xpath(rsp_code=rwdts.XactRspCode.ACK,
xpath=self.vnfr_vdu_console_xpath,
msg=vdur_console)
#raise VnfRecordError("Not supported operation %s" % action)
self._log.error("Not supported operation %s" % action)
xact_info.respond_xpath(rsp_code=rwdts.XactRspCode.ACK)
- return
-
+ return
+
self._log.debug("Registering for VNFR VDU using xpath: %s",
self.vnfr_vdu_console_xpath)
class VnfrDtsHandler(object):
- """ registers 'D,/vnfr:vnfr-catalog/vnfr:vnfr' and handles CRUD from DTS"""
+ """ registers 'D,/rw-project:project/vnfr:vnfr-catalog/vnfr:vnfr' and handles CRUD from DTS"""
XPATH = "D,/vnfr:vnfr-catalog/vnfr:vnfr"
def __init__(self, dts, log, loop, vnfm):
self._vnfm = vnfm
self._regh = None
+ self._project = vnfm._project
@property
def regh(self):
""" Return VNF manager instance """
return self._vnfm
+ def deregister(self):
+ '''De-register from DTS'''
+ self._log.debug("De-register VNFR DTS handler for project {}".
+ format(self._project))
+ if self._regh:
+ self._regh.deregister()
+ self._regh = None
+
@asyncio.coroutine
def register(self):
""" Register for vnfr create/update/delete/read requests from dts """
)
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)
vnfr.set_state(VirtualNetworkFunctionRecordState.FAILED)
yield from vnfr.publish(None)
elif action == rwdts.QueryAction.DELETE:
- schema = RwVnfrYang.YangData_Vnfr_VnfrCatalog_Vnfr.schema()
+ schema = RwVnfrYang.YangData_RwProject_Project_VnfrCatalog_Vnfr.schema()
path_entry = schema.keyspec_to_entry(ks_path)
vnfr = self._vnfm.get_vnfr(path_entry.key00.id)
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)
self._log.error("Caught exception while deleting vnfr %s", path_entry.key00.id)
elif action == rwdts.QueryAction.UPDATE:
- schema = RwVnfrYang.YangData_Vnfr_VnfrCatalog_Vnfr.schema()
+ schema = RwVnfrYang.YangData_RwProject_Project_VnfrCatalog_Vnfr.schema()
path_entry = schema.keyspec_to_entry(ks_path)
vnfr = None
try:
xact_info.respond_xpath(rwdts.XactRspCode.ACK)
- self._log.debug("Registering for VNFR using xpath: %s",
- VnfrDtsHandler.XPATH,)
+ xpath = self._project.add_project(VnfrDtsHandler.XPATH)
+ self._log.debug("Registering for VNFR using xpath: {}".
+ format(xpath))
hdl = rift.tasklets.DTS.RegistrationHandler(on_commit=on_commit,
on_prepare=on_prepare,)
handlers = rift.tasklets.Group.Handler(on_event=on_event,)
with self._dts.group_create(handler=handlers) as group:
- self._regh = group.register(xpath=VnfrDtsHandler.XPATH,
+ self._regh = group.register(xpath=xpath,
handler=hdl,
flags=(rwdts.Flag.PUBLISHER |
rwdts.Flag.NO_PREP_READ |
rwdts.Flag.DATASTORE),)
@asyncio.coroutine
- def create(self, xact, path, msg):
+ def create(self, xact, xpath, msg):
"""
Create a VNFR record in DTS with path and message
"""
+ path = self._project.add_project(xpath)
self._log.debug("Creating VNFR xact = %s, %s:%s",
xact, path, msg)
xact, path, msg)
@asyncio.coroutine
- def update(self, xact, path, msg):
+ def update(self, xact, xpath, msg):
"""
Update a VNFR record in DTS with path and message
"""
+ path = self._project.add_project(xpath)
self._log.debug("Updating VNFR xact = %s, %s:%s",
xact, path, msg)
self.regh.update_element(path, msg)
xact, path, msg)
@asyncio.coroutine
- def delete(self, xact, path):
+ def delete(self, xact, xpath):
"""
Delete a VNFR record in DTS with path and message
"""
+ path = self._project.add_project(xpath)
self._log.debug("Deleting VNFR xact = %s, %s", xact, path)
self.regh.delete_element(path)
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"
""" Return the NS manager instance """
return self._vnfm
+ def deregister(self):
+ '''De-register from DTS'''
+ self._log.debug("De-register VNFD Ref DTS handler for project {}".
+ format(self._vnfm._project))
+ if self._regh:
+ self._regh.deregister()
+ self._regh = None
+
@asyncio.coroutine
def register(self):
""" Register for VNFD ref count read from dts """
)
if action == rwdts.QueryAction.READ:
- schema = RwVnfrYang.YangData_Vnfr_VnfrCatalog_VnfdRefCount.schema()
+ schema = RwVnfrYang.YangData_RwProject_Project_VnfrCatalog_VnfdRefCount.schema()
path_entry = schema.keyspec_to_entry(ks_path)
vnfd_list = yield from self._vnfm.get_vnfd_refcount(path_entry.key00.vnfd_id_ref)
for xpath, msg in vnfd_list:
hdl = rift.tasklets.DTS.RegistrationHandler(on_prepare=on_prepare,)
with self._dts.group_create() as group:
- self._regh = group.register(xpath=VnfdRefCountDtsHandler.XPATH,
+ self._regh = group.register(xpath=self._vnfm._project.add_project(
+ VnfdRefCountDtsHandler.XPATH),
handler=hdl,
flags=rwdts.Flag.PUBLISHER,
)
set_if_not_none('name', vdur._vdud.name)
set_if_not_none('mgmt.ip', vdur.vm_management_ip)
+ # The below can be used for hostname
+ set_if_not_none('vdur_name', vdur.unique_short_name)
def update(self, vdur):
"""Update the VDUR information in the datastore
set_or_delete('name', vdur._vdud.name)
set_or_delete('mgmt.ip', vdur.vm_management_ip)
+ # The below can be used for hostname
+ set_or_delete('vdur_name', vdur.unique_short_name)
def remove(self, vdur_id):
"""Remove all of the data associated with specified VDUR
class VnfManager(object):
""" The virtual network function manager class """
- def __init__(self, dts, log, loop, cluster_name):
+ def __init__(self, dts, log, loop, project, cluster_name):
self._dts = dts
self._log = log
self._loop = loop
+ self._project = project
self._cluster_name = cluster_name
self._vcs_handler = VcsComponentDtsHandler(dts, log, loop, self)
self._vnfr_handler = VnfrDtsHandler(dts, log, loop, self)
+ self._vnfr_ref_handler = VnfdRefCountDtsHandler(dts, log, loop, self)
+ self._nsr_handler = mano_dts.NsInstanceConfigSubscriber(
+ log, dts, loop, project, callback=self.handle_nsr)
self._dts_handlers = [VnfdDtsHandler(dts, log, loop, self),
self._vnfr_handler,
self._vcs_handler,
- VnfdRefCountDtsHandler(dts, log, loop, self)]
+ self._vnfr_ref_handler,
+ self._nsr_handler]
self._vnfrs = {}
- self._vnfds = {}
+ self._vnfds_to_vnfr = {}
+ self._nsrs = {}
@property
def vnfr_handler(self):
for hdl in self._dts_handlers:
yield from hdl.register()
+ def deregister(self):
+ self._log.debug("De-register VNFM project {}".format(self._project.name))
+ for hdl in self._dts_handlers:
+ hdl.deregister()
+
@asyncio.coroutine
def run(self):
""" Run this VNFM instance """
self._log.debug("Run VNFManager - registering static DTS handlers""")
yield from self.register()
+ def handle_nsr(self, nsr, action):
+ if action in [rwdts.QueryAction.CREATE]:
+ self._nsrs[nsr.id] = nsr
+ elif action == rwdts.QueryAction.DELETE:
+ if nsr.id in self._nsrs:
+ del self._nsrs[nsr.id]
+
+ def get_linked_mgmt_network(self, vnfr):
+ """For the given VNFR get the related mgmt network from the NSD, if
+ available.
+ """
+ vnfd_id = vnfr.vnfd.id
+ nsr_id = vnfr.nsr_id_ref
+
+ # for the given related VNFR, get the corresponding NSR-config
+ nsr_obj = None
+ try:
+ nsr_obj = self._nsrs[nsr_id]
+ except KeyError:
+ raise("Unable to find the NS with the ID: {}".format(nsr_id))
+
+ # for the related NSD check if a VLD exists such that it's a mgmt
+ # network
+ for vld in nsr_obj.nsd.vld:
+ if vld.mgmt_network:
+ return vld.name
+
+ return None
+
def get_vnfr(self, vnfr_id):
""" get VNFR by vnfr id """
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)
self._vnfrs[vnfr.id] = VirtualNetworkFunctionRecord(
- self._dts, self._log, self._loop, self._cluster_name, self, self.vcs_handler, vnfr
+ self._dts, self._log, self._loop, self._cluster_name, self, self.vcs_handler, vnfr,
+ mgmt_network=mgmt_network
)
+
+ #Update ref count
+ if vnfr.vnfd.id in self._vnfds_to_vnfr:
+ self._vnfds_to_vnfr[vnfr.vnfd.id] += 1
+ else:
+ self._vnfds_to_vnfr[vnfr.vnfd.id] = 1
+
return self._vnfrs[vnfr.id]
@asyncio.coroutine
if vnfr.vnfr_id in self._vnfrs:
self._log.debug("Deleting VNFR id %s", vnfr.vnfr_id)
yield from self._vnfr_handler.delete(xact, vnfr.xpath)
+
+ if vnfr.vnfd.id in self._vnfds_to_vnfr:
+ if self._vnfds_to_vnfr[vnfr.vnfd.id]:
+ self._vnfds_to_vnfr[vnfr.vnfd.id] -= 1
+
del self._vnfrs[vnfr.vnfr_id]
@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 = self._project.add_project(
+ VirtualNetworkFunctionRecord.vnfd_xpath(vnfd_id))
self._log.debug("Fetch vnfd with path %s", vnfd_path)
vnfd = None
- res_iter = yield from self._dts.query_read(vnfd_path, rwdts.XactFlag.MERGE)
+ res_iter = yield from self._dts.query_read(vnfd_path,
+ rwdts.XactFlag.MERGE)
for ent in res_iter:
res = yield from ent
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] > 0)
return False
@asyncio.coroutine
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)
-
- # Hack to remove duplicates from leaf-lists - to be fixed by RIFT-6511
- for ivld in vnfd.internal_vld:
- ivld.internal_connection_point_ref = list(set(ivld.internal_connection_point_ref))
-
- 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:
- 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():
- self._log.debug("Cannot delete VNFD id %s reference exists %s",
- vnfd_id,
- self._vnfds[vnfd_id].ref_count)
- raise VirtualNetworkFunctionDescriptorRefCountExists(
- "Cannot delete :%s, ref_count:%s",
- vnfd_id,
- self._vnfds[vnfd_id].ref_count)
+ if vnfd_id in self._vnfds_to_vnfr:
+ if self._vnfds_to_vnfr[vnfd_id]:
+ self._log.debug("Cannot delete VNFD id %s reference exists %s",
+ vnfd_id,
+ self._vnfds_to_vnfr[vnfd_id].vnfd_ref_count)
+ raise VirtualNetworkFunctionDescriptorRefCountExists(
+ "Cannot delete :%s, ref_count:%s",
+ vnfd_id,
+ self._vnfds_to_vnfr[vnfd_id].vnfd_ref_count)
+
+ del self._vnfds_to_vnfr[vnfd_id]
# Remove any files uploaded with VNFD and stored under $RIFT_ARTIFACTS/libs/<id>
try:
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]
def vnfd_refcount_xpath(self, vnfd_id):
""" xpath for ref count entry """
- return (VnfdRefCountDtsHandler.XPATH +
- "[rw-vnfr:vnfd-id-ref = '{}']").format(vnfd_id)
+ return self._project.add_project(VnfdRefCountDtsHandler.XPATH +
+ "[rw-vnfr:vnfd-id-ref = '{}']").format(vnfd_id)
@asyncio.coroutine
def get_vnfd_refcount(self, vnfd_id):
""" Get the vnfd_list from this VNFM"""
vnfd_list = []
if vnfd_id is None or vnfd_id == "":
- for vnfd in self._vnfds.values():
- 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
+ for vnfd in self._vnfds_to_vnfr.keys():
+ vnfd_msg = RwVnfrYang.YangData_RwProject_Project_VnfrCatalog_VnfdRefCount()
+ vnfd_msg.vnfd_id_ref = vnfd
+ vnfd_msg.instance_ref_count = self._vnfds_to_vnfr[vnfd]
+ vnfd_list.append((self.vnfd_refcount_xpath(vnfd), vnfd_msg))
+ elif vnfd_id in self._vnfds_to_vnfr:
+ vnfd_msg = RwVnfrYang.YangData_RwProject_Project_VnfrCatalog_VnfdRefCount()
+ vnfd_msg.vnfd_id_ref = vnfd_id
+ vnfd_msg.instance_ref_count = self._vnfds_to_vnfr[vnfd_id]
vnfd_list.append((self.vnfd_refcount_xpath(vnfd_id), vnfd_msg))
return vnfd_list
+class VnfmProject(ManoProject):
+
+ def __init__(self, name, tasklet, **kw):
+ super(VnfmProject, self).__init__(tasklet.log, name)
+ self.update(tasklet)
+
+ self._vnfm = None
+
+ @asyncio.coroutine
+ def register (self):
+ try:
+ vm_parent_name = self._tasklet.tasklet_info.get_parent_vm_parent_instance_name()
+ assert vm_parent_name is not None
+ self._vnfm = VnfManager(self._dts, self.log, self.loop, self, vm_parent_name)
+ yield from self._vnfm.run()
+ except Exception:
+ print("Caught Exception in VNFM init:", sys.exc_info()[0])
+ raise
+
+ def deregister(self):
+ self._log.debug("De-register project {} for VnfmProject".
+ format(self.name))
+ self._vnfm.deregister()
+
+
class VnfmTasklet(rift.tasklets.Tasklet):
""" VNF Manager tasklet class """
def __init__(self, *args, **kwargs):
self.rwlog.set_subcategory("vnfm")
self._dts = None
- self._vnfm = None
+ self._project_handler = None
+ self.projects = {}
+
+ @property
+ def dts(self):
+ return self._dts
def start(self):
try:
@asyncio.coroutine
def init(self):
""" Task init callback """
- try:
- vm_parent_name = self.tasklet_info.get_parent_vm_parent_instance_name()
- assert vm_parent_name is not None
- self._vnfm = VnfManager(self._dts, self.log, self.loop, vm_parent_name)
- yield from self._vnfm.run()
- except Exception:
- print("Caught Exception in VNFM init:", sys.exc_info()[0])
- raise
+ self.log.debug("creating project handler")
+ self.project_handler = ProjectHandler(self, VnfmProject)
+ self.project_handler.register()
@asyncio.coroutine
def run(self):