From: Philip Joseph Date: Thu, 8 Dec 2016 09:14:58 +0000 (-0500) Subject: New feature: Support static IP in VNF connection points X-Git-Url: https://osm.etsi.org/gitweb/?a=commitdiff_plain;h=55e01f61d558380f6cc8b34a2d7834819371defd;p=osm%2FSO.git New feature: Support static IP in VNF connection points Signed-off-by: Philip Joseph --- diff --git a/examples/ping_pong_ns/rift/mano/examples/ping_pong_nsd.py b/examples/ping_pong_ns/rift/mano/examples/ping_pong_nsd.py index d84a912e..db066f83 100755 --- a/examples/ping_pong_ns/rift/mano/examples/ping_pong_nsd.py +++ b/examples/ping_pong_ns/rift/mano/examples/ping_pong_nsd.py @@ -127,7 +127,7 @@ class VirtualNetworkFunction(ManoDescriptor): def compose(self, image_name, cloud_init="", cloud_init_file="", endpoint=None, mon_params=[], mon_port=8888, mgmt_port=8888, num_vlr_count=1, num_ivlr_count=1, - num_vms=1, image_md5sum=None, mano_ut=False): + num_vms=1, image_md5sum=None, mano_ut=False, use_static_ip=False): self.descriptor = RwVnfdYang.YangData_Vnfd_VnfdCatalog() self.id = str(uuid.uuid1()) vnfd = self.descriptor.vnfd.add() @@ -156,6 +156,11 @@ class VirtualNetworkFunction(ManoDescriptor): cp = vnfd.connection_point.add() cp.type_yang = 'VPORT' cp.name = '%s/cp%d' % (self.name, i) + if use_static_ip: + if 'pong_' in self.name: + cp.static_ip_address = '31.31.31.31' + else: + cp.static_ip_address = '31.31.31.32' if endpoint is not None: endp = VnfdYang.YangData_Vnfd_VnfdCatalog_Vnfd_HttpEndpoint( @@ -892,6 +897,7 @@ def generate_ping_pong_descriptors(fmt="json", ex_pong_userdata=None, use_placement_group=True, use_ns_init_conf=True, + use_static_ip=False, ): # List of connection point groups # Each connection point group refers to a virtual link @@ -936,6 +942,7 @@ def generate_ping_pong_descriptors(fmt="json", num_vms=num_vnf_vms, image_md5sum=ping_md5sum, mano_ut=mano_ut, + use_static_ip=use_static_ip, ) pong = VirtualNetworkFunction("pong_vnfd%s" % (suffix)) @@ -976,6 +983,7 @@ def generate_ping_pong_descriptors(fmt="json", num_vms=num_vnf_vms, image_md5sum=pong_md5sum, mano_ut=mano_ut, + use_static_ip=use_static_ip, ) # Initialize the member VNF index diff --git a/models/plugins/yang/nsd.yang b/models/plugins/yang/nsd.yang index 31750cae..84b63251 100644 --- a/models/plugins/yang/nsd.yang +++ b/models/plugins/yang/nsd.yang @@ -292,9 +292,9 @@ module nsd } } - leaf vnfd-id-ref { - description - "A reference to a vnfd. This is a + leaf vnfd-id-ref { + description + "A reference to a vnfd. This is a leafref to path: ../../nsd:constituent-vnfd + [nsd:id = current()/../nsd:id-ref] @@ -304,12 +304,12 @@ module nsd to leafref, whose target is in a different module. Once that is resovled this will switched to use leafref"; - type string; - } + type string; + } - leaf vnfd-connection-point-ref { - description - "A reference to a connection point name + leaf vnfd-connection-point-ref { + description + "A reference to a connection point name in a vnfd. This is a leafref to path: /vnfd:vnfd-catalog/vnfd:vnfd + [vnfd:id = current()/../nsd:vnfd-id-ref] @@ -319,7 +319,7 @@ module nsd to leafref, whose target is in a different module. Once that is resovled this will switched to use leafref"; - type string; + type string; } } diff --git a/models/plugins/yang/vnfd.yang b/models/plugins/yang/vnfd.yang index 5dc19ce6..46c5edd3 100644 --- a/models/plugins/yang/vnfd.yang +++ b/models/plugins/yang/vnfd.yang @@ -67,6 +67,11 @@ module vnfd description "Type of the connection point."; type manotypes:connection-point-type; } + + leaf static-ip-address { + description "Static IP address for the connection point"; + type inet:ip-address; + } } grouping virtual-interface { @@ -271,6 +276,7 @@ module vnfd } } } + uses manotypes:provider-network; } diff --git a/rwcal/plugins/vala/rwcal_openstack/rift/rwcal/openstack/openstack_drv.py b/rwcal/plugins/vala/rwcal_openstack/rift/rwcal/openstack/openstack_drv.py index 943cdd54..5f44e5e0 100644 --- a/rwcal/plugins/vala/rwcal_openstack/rift/rwcal/openstack/openstack_drv.py +++ b/rwcal/plugins/vala/rwcal_openstack/rift/rwcal/openstack/openstack_drv.py @@ -1393,19 +1393,28 @@ class NeutronDriver(object): name (string) : Name of the port network_id(string) : UUID of the network_id identifying the network to which port belongs subnet_id(string) : UUID of the subnet_id from which IP-address will be assigned to port + ip_address(string) : Static IP address to assign to the port vnic_type(string) : Possible values are "normal", "direct", "macvtap" } Returns: port_id (string) : UUID of the port + + NOTE: Either subnet_id or ip_address need to be specified. """ params = { "port": { "admin_state_up" : kwargs['admin_state_up'], "name" : kwargs['name'], "network_id" : kwargs['network_id'], - "fixed_ips" : [ {"subnet_id": kwargs['subnet_id']}], "binding:vnic_type" : kwargs['port_type']}} + if 'ip_address' in kwargs: + params["port"]["fixed_ips"] = [{"ip_address": kwargs['ip_address']}] + else: + params["port"]["fixed_ips"] = [{"subnet_id": kwargs['subnet_id']}] + + logger.debug("Port create params: {}".format(params)) + ntconn = self._get_neutron_connection() try: port = ntconn.create_port(params) @@ -1861,7 +1870,7 @@ class OpenstackDriver(object): return pool_list[0] else: return None - + def neutron_port_list(self, **kwargs): return self.neutron_drv.port_list(**kwargs) @@ -1869,11 +1878,18 @@ class OpenstackDriver(object): return self.neutron_drv.port_get(port_id) def neutron_port_create(self, **kwargs): - subnets = [subnet for subnet in self.neutron_drv.subnet_list() if subnet['network_id'] == kwargs['network_id']] - assert len(subnets) == 1 - kwargs['subnet_id'] = subnets[0]['id'] + + if 'ip_address' not in kwargs: + subnets = [subnet for subnet in self.neutron_drv.subnet_list() + if subnet['network_id'] == kwargs['network_id']] + assert len(subnets) == 1 + kwargs['subnet_id'] = subnets[0]['id'] + if not 'admin_state_up' in kwargs: kwargs['admin_state_up'] = True + + logger.debug("Port create params: {}". + format(kwargs)) port_id = self.neutron_drv.port_create(**kwargs) if 'vm_id' in kwargs: diff --git a/rwcal/plugins/vala/rwcal_openstack/rwcal_openstack.py b/rwcal/plugins/vala/rwcal_openstack/rwcal_openstack.py index 05dc4989..3bdf8828 100644 --- a/rwcal/plugins/vala/rwcal_openstack/rwcal_openstack.py +++ b/rwcal/plugins/vala/rwcal_openstack/rwcal_openstack.py @@ -1460,6 +1460,7 @@ class RwcalOpenstackPlugin(GObject.Object, RwCal.Cloud): account - a cloud account c_point - connection_points """ + kwargs = {} kwargs['name'] = c_point.name kwargs['network_id'] = c_point.virtual_link_id @@ -1472,11 +1473,16 @@ class RwcalOpenstackPlugin(GObject.Object, RwCal.Cloud): else: raise NotImplementedError("Port Type: %s not supported" %(c_point.type_yang)) + if c_point.static_ip_address: + kwargs["ip_address"] = c_point.static_ip_address + with self._use_driver(account) as drv: if c_point.has_field('security_group'): group = drv.neutron_security_group_by_name(c_point.security_group) if group is not None: kwargs['security_groups'] = [group['id']] + self.log.debug("Create connection point port : {}". + format(kwargs)) return drv.neutron_port_create(**kwargs) def _allocate_floating_ip(self, drv, pool_name): diff --git a/rwcal/plugins/yang/rwcal.yang b/rwcal/plugins/yang/rwcal.yang index 76bd38b3..37a9f18e 100644 --- a/rwcal/plugins/yang/rwcal.yang +++ b/rwcal/plugins/yang/rwcal.yang @@ -43,6 +43,10 @@ module rwcal prefix "manotypes"; } + import ietf-inet-types { + prefix "inet"; + } + revision 2014-12-30 { description "Initial revision."; @@ -972,6 +976,11 @@ module rwcal type string; } + leaf static-ip-address { + description "Static IP address for the connection point"; + type inet:ip-address; + } + uses connection-point-type; } @@ -1049,6 +1058,11 @@ module rwcal default false; } + leaf static-ip-address { + description "Static IP address for the connection point"; + type inet:ip-address; + } + uses connection-point-type; } diff --git a/rwlaunchpad/plugins/rwnsm/rift/tasklets/rwnsmtasklet/rwnsmtasklet.py b/rwlaunchpad/plugins/rwnsm/rift/tasklets/rwnsmtasklet/rwnsmtasklet.py index 718d2b19..fff855e1 100755 --- a/rwlaunchpad/plugins/rwnsm/rift/tasklets/rwnsmtasklet/rwnsmtasklet.py +++ b/rwlaunchpad/plugins/rwnsm/rift/tasklets/rwnsmtasklet/rwnsmtasklet.py @@ -961,7 +961,8 @@ class VirtualNetworkFunctionRecord(object): 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.vnfd = VnfrYang.YangData_Vnfr_VnfrCatalog_Vnfr_Vnfd.from_dict(self.vnfd.as_dict(), + ignore_missing_keys=True) vnfr.member_vnf_index_ref = self.member_vnf_index vnfr.vnf_configuration.from_dict(self._vnfd.vnf_configuration.as_dict()) @@ -1083,6 +1084,13 @@ class VirtualNetworkFunctionRecord(object): continue cpr.vlr_ref = vlr_ref.id + + try: + if conn_p.static_ip_address: + cpr.static_ip_address = conn_p.static_ip_address + except AttributeError as e: + pass + 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.id) @@ -3266,7 +3274,11 @@ class NsrDtsHandler(object): def begin_instantiation(nsr): # Begin instantiation self._log.info("Beginning NS instantiation: %s", nsr.id) - yield from self._nsm.instantiate_ns(nsr.id, xact) + try: + yield from self._nsm.instantiate_ns(nsr.id, xact) + except Exception as e: + self._log.exception(e) + raise e self._log.debug("Got nsr apply (xact: %s) (action: %s)(scr: %s)", xact, action, scratch) diff --git a/rwlaunchpad/plugins/rwvnfm/rift/tasklets/rwvnfmtasklet/rwvnfmtasklet.py b/rwlaunchpad/plugins/rwvnfm/rift/tasklets/rwvnfmtasklet/rwvnfmtasklet.py index 8a4474e0..e39a8ae8 100755 --- a/rwlaunchpad/plugins/rwvnfm/rift/tasklets/rwvnfmtasklet/rwvnfmtasklet.py +++ b/rwlaunchpad/plugins/rwvnfm/rift/tasklets/rwvnfmtasklet/rwvnfmtasklet.py @@ -422,7 +422,7 @@ class VirtualDeploymentUnitRecord(object): 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.name)}) ii_list.append({"name": intf.name, "vdur_internal_connection_point_ref": cp.id, @@ -434,10 +434,10 @@ class VirtualDeploymentUnitRecord(object): 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_id(cp.name)) vdur_dict["external_interface"] = ei_list @@ -573,10 +573,16 @@ class VirtualDeploymentUnitRecord(object): cp_list = [] for intf, cp, vlr in self._ext_intf: - cp_info = {"name": cp, + cp_info = {"name": cp.name, "virtual_link_id": vlr.network_id, "type_yang": intf.virtual_interface.type_yang} + try: + if cp.static_ip_address: + cp_info["static_ip_address"] = cp.static_ip_address + except AttributeError as e: + pass + if (intf.virtual_interface.has_field('vpci') and intf.virtual_interface.vpci is not None): cp_info["vpci"] = intf.virtual_interface.vpci @@ -584,19 +590,28 @@ class VirtualDeploymentUnitRecord(object): 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 + self._log.debug("External CP info {}".format(cp_info)) cp_list.append(cp_info) - for intf, cp, vlr in self._int_intf: + for intf, cp_id, vlr in self._int_intf: + cp = self.find_internal_cp_by_cp_id(cp_id) + + cp_dict = {"name": cp_id, + "virtual_link_id": vlr.network_id, + "type_yang": intf.virtual_interface.type_yang} + if (intf.virtual_interface.has_field('vpci') and intf.virtual_interface.vpci is not None): - cp_list.append({"name": cp, - "virtual_link_id": vlr.network_id, - "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}) + cp_dict["vpci"] = intf.virtual_interface.vpci + + try: + if cp.static_ip_address: + cp_dict["static_ip_address"] = cp.static_ip_address + except AttributeError as e: + pass + + self._log.debug("Internal CP info {}".format(cp_info)) + cp_list.append(cp_dict) vm_create_msg_dict["connection_points"] = cp_list vm_create_msg_dict.update(vdu_copy_dict) @@ -680,28 +695,15 @@ class VirtualDeploymentUnitRecord(object): cp_name) return cp - def find_internal_vlr_by_cp_name(cp_name): - """ Find the VLR corresponding to the connection point name""" - cp = None - - self._log.debug("find_internal_vlr_by_cp_name(%s) called", - cp_name) - - for int_cp in self._vdud.internal_connection_point: - self._log.debug("Checking for int cp %s in internal connection points", - int_cp.id) - if int_cp.id == cp_name: - cp = int_cp - break + def find_internal_vlr_by_cp_id(cp_id): + self._log.debug("find_internal_vlr_by_cp_id(%s) called", + cp_id) - if cp is None: - self._log.debug("Failed to find cp %s in internal connection points", - cp_name) - msg = "Failed to find cp %s in internal connection points" % cp_name - raise VduRecordError(msg) + # Validate the cp + cp = self.find_internal_cp_by_cp_id(cp_id) # return the VLR associated with the connection point - return vnfr.find_vlr_by_cp(cp_name) + return vnfr.find_vlr_by_cp(cp_id) block = xact.block_create() @@ -722,7 +724,7 @@ class VirtualDeploymentUnitRecord(object): 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) @@ -734,7 +736,7 @@ class VirtualDeploymentUnitRecord(object): intf.name, cp_id) try: - vlr = find_internal_vlr_by_cp_name(cp_id) + vlr = find_internal_vlr_by_cp_id(cp_id) except Exception as e: self._log.debug("Failed to find cp %s in internal VLR list", cp_id) msg = "Failed to find cp %s in internal VLR list, e = %s" % (cp_id, e) @@ -1738,7 +1740,7 @@ class VirtualNetworkFunctionRecord(object): 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", "static_ip_address"] 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)