From 418c436cc9972866b91ca3acf9817815273eb925 Mon Sep 17 00:00:00 2001 From: Mitchell Jameson Date: Sun, 7 May 2017 17:15:02 -0700 Subject: [PATCH] Use vnic_type to determine whether a port is baremetal In ocata, the tenant network port for baremetal instances is owned by compute: instead of baremetal:. The vnic_type for those ports is still 'baremetal', so use the vnic_type to identify baremetal ports. Change-Id: I677148a7964ea4b3673cc918999073b2cd5caafd --- networking_arista/common/db_lib.py | 15 +- networking_arista/ml2/arista_ml2.py | 241 ++++++++---------- .../unit/ml2/test_arista_mechanism_driver.py | 15 +- 3 files changed, 132 insertions(+), 139 deletions(-) diff --git a/networking_arista/common/db_lib.py b/networking_arista/common/db_lib.py index cc68bab..f3da9fb 100644 --- a/networking_arista/common/db_lib.py +++ b/networking_arista/common/db_lib.py @@ -416,7 +416,7 @@ def get_tenants(): return res -def _make_bm_port_dict(record): +def _make_port_dict(record): """Make a dict from the BM profile DB record.""" return {'port_id': record.port_id, 'host_id': record.host, @@ -431,10 +431,21 @@ def get_all_baremetal_ports(): querry = session.query(ml2_models.PortBinding) bm_ports = querry.filter_by(vnic_type='baremetal').all() - return {bm_port.port_id: _make_bm_port_dict(bm_port) + return {bm_port.port_id: _make_port_dict(bm_port) for bm_port in bm_ports} +def get_all_portbindings(): + """Returns a list of all ports bindings.""" + session = db.get_session() + with session.begin(): + query = session.query(ml2_models.PortBinding) + ports = query.all() + + return {port.port_id: _make_port_dict(port) + for port in ports} + + def get_port_binding_level(filters): """Returns entries from PortBindingLevel based on the specified filters.""" session = db.get_reader_session() diff --git a/networking_arista/ml2/arista_ml2.py b/networking_arista/ml2/arista_ml2.py index 12efefe..f6c5f49 100644 --- a/networking_arista/ml2/arista_ml2.py +++ b/networking_arista/ml2/arista_ml2.py @@ -413,7 +413,7 @@ class AristaRPCWrapperBase(object): @abc.abstractmethod def create_instance_bulk(self, tenant_id, neutron_ports, vms, - bm_port_profiles, sync=False): + port_profiles, sync=False): """Sends a bulk request to create ports. :param tenant_id: globaly unique neutron tenant identifier @@ -873,7 +873,7 @@ class AristaRPCWrapperJSON(AristaRPCWrapperBase): return self._send_api_request(path, 'POST', data) def create_instance_bulk(self, tenant_id, neutron_ports, vms, - bm_port_profiles, sync=False): + port_profiles, sync=False): self._create_tenant_if_needed(tenant_id) vmInst = {} @@ -885,25 +885,6 @@ class AristaRPCWrapperJSON(AristaRPCWrapperBase): portBindings = {} for vm in vms.values(): - for v_port in vm['ports']: - port_id = v_port['portId'] - if (port_id in neutron_ports and - neutron_ports[port_id]['device_owner'].startswith( - 'baremetal')): - vm['baremetal_instance'] = True - - # Filter out all virtual ports, if instance type is baremetal - index = 0 - for index, v_port in enumerate(vm['ports']): - port_id = v_port['portId'] - if port_id in neutron_ports: - device_owner = neutron_ports[port_id]['device_owner'] - if(device_owner.startswith('compute') and - vm['baremetal_instance']): - del vm['ports'][index] - - # Now we are left with the ports that we are interested that - # require provisioning for v_port in vm['ports']: port_id = v_port['portId'] if not v_port['hosts']: @@ -919,18 +900,21 @@ class AristaRPCWrapperJSON(AristaRPCWrapperBase): instance = self._create_instance_data(inst_id, inst_host) device_owner = neutron_port['device_owner'] + vnic_type = port_profiles[port_id]['vnic_type'] if device_owner == n_const.DEVICE_OWNER_DHCP: instance_type = InstanceType.DHCP if inst_id not in dhcpInst: dhcpInst[inst_id] = instance - elif device_owner.startswith('compute'): - instance_type = InstanceType.VM - if inst_id not in vmInst: - vmInst[inst_id] = instance - elif device_owner.startswith('baremetal'): - instance_type = InstanceType.BAREMETAL - if inst_id not in baremetalInst: - baremetalInst[inst_id] = instance + elif (device_owner.startswith('compute') or + device_owner.startswith('baremetal')): + if vnic_type == 'baremetal': + instance_type = InstanceType.BAREMETAL + if inst_id not in baremetalInst: + baremetalInst[inst_id] = instance + else: + instance_type = InstanceType.VM + if inst_id not in vmInst: + vmInst[inst_id] = instance elif device_owner == n_const.DEVICE_OWNER_DVR_INTERFACE: instance_type = InstanceType.ROUTER if inst_id not in routerInst: @@ -957,7 +941,7 @@ class AristaRPCWrapperJSON(AristaRPCWrapperBase): port_id, inst_host, network_id, networkSegments[network_id]) elif instance_type in InstanceType.BAREMETAL_INSTANCE_TYPES: - switch_profile = json.loads(bm_port_profiles[ + switch_profile = json.loads(port_profiles[ port_id]['profile']) portBinding = self._get_switch_bindings( port_id, inst_host, network_id, @@ -1025,10 +1009,12 @@ class AristaRPCWrapperJSON(AristaRPCWrapperBase): device_type = '' if device_owner == n_const.DEVICE_OWNER_DHCP: device_type = InstanceType.DHCP - elif device_owner.startswith('compute'): - device_type = InstanceType.VM - elif device_owner.startswith('baremetal'): - device_type = InstanceType.BAREMETAL + elif (device_owner.startswith('compute') + or device_owner.startswith('baremetal')): + if vnic_type == 'baremetal': + device_type = InstanceType.BAREMETAL + else: + device_type = InstanceType.VM elif device_owner == n_const.DEVICE_OWNER_DVR_INTERFACE: device_type = InstanceType.ROUTER else: @@ -1066,10 +1052,12 @@ class AristaRPCWrapperJSON(AristaRPCWrapperBase): device_type = '' if device_owner == n_const.DEVICE_OWNER_DHCP: device_type = InstanceType.DHCP - elif device_owner.startswith('compute'): - device_type = InstanceType.VM - elif device_owner.startswith('baremetal'): - device_type = InstanceType.BAREMETAL + elif (device_owner.startswith('compute') or + device_owner.startswith('baremetal')): + if vnic_type == 'baremetal': + device_type = InstanceType.BAREMETAL + else: + device_type = InstanceType.VM elif device_owner == n_const.DEVICE_OWNER_DVR_INTERFACE: device_type = InstanceType.ROUTER else: @@ -1361,25 +1349,27 @@ class AristaRPCWrapperEapi(AristaRPCWrapperBase): tenant_id, segments, port_name) - elif device_owner.startswith('compute'): - self.plug_host_into_network(device_id, - host_id, - port_id, - net_id, - tenant_id, - segments, - port_name) - elif device_owner.startswith('baremetal'): - self.plug_baremetal_into_network(device_id, - host_id, - port_id, - net_id, - tenant_id, - segments, - port_name, - sg, orig_sg, - vnic_type, - switch_bindings) + elif (device_owner.startswith('compute') or + device_owner.startswith('baremetal')): + if vnic_type == 'baremetal': + self.plug_baremetal_into_network(device_id, + host_id, + port_id, + net_id, + tenant_id, + segments, + port_name, + sg, orig_sg, + vnic_type, + switch_bindings) + else: + self.plug_host_into_network(device_id, + host_id, + port_id, + net_id, + tenant_id, + segments, + port_name) elif device_owner == n_const.DEVICE_OWNER_DVR_INTERFACE: self.plug_distributed_router_port_into_network(device_id, host_id, @@ -1397,21 +1387,23 @@ class AristaRPCWrapperEapi(AristaRPCWrapperBase): port_id, network_id, tenant_id) - elif device_owner.startswith('compute'): - self.unplug_host_from_network(device_id, - hostname, - port_id, - network_id, - tenant_id) - elif device_owner.startswith('baremetal'): - self.unplug_baremetal_from_network(device_id, - hostname, - port_id, - network_id, - tenant_id, - sg, - vnic_type, - switch_bindings) + elif (device_owner.startswith('compute') or + device_owner.startswith('baremetal')): + if vnic_type == 'baremetal': + self.unplug_baremetal_from_network(device_id, + hostname, + port_id, + network_id, + tenant_id, + sg, + vnic_type, + switch_bindings) + else: + self.unplug_host_from_network(device_id, + hostname, + port_id, + network_id, + tenant_id) elif device_owner == n_const.DEVICE_OWNER_DVR_INTERFACE: self.unplug_distributed_router_port_from_network(device_id, port_id, @@ -1656,7 +1648,7 @@ class AristaRPCWrapperEapi(AristaRPCWrapperBase): self._run_openstack_cmds(cmds, sync=sync) def create_instance_bulk(self, tenant_id, neutron_ports, vms, - bm_port_profiles, sync=False): + port_profiles, sync=False): cmds = ['tenant %s' % tenant_id] # Create a reference to function to avoid name lookups in the loop append_cmd = cmds.append @@ -1664,27 +1656,6 @@ class AristaRPCWrapperEapi(AristaRPCWrapperBase): for vm in vms.values(): counter += 1 - # Mark an instance as baremetal if any of the ports is baremetal - for v_port in vm['ports']: - port_id = v_port['portId'] - if (port_id in neutron_ports and - neutron_ports[port_id]['device_owner'].startswith( - 'baremetal')): - vm['baremetal_instance'] = True - - # Filter out all virtual ports, if instance type is baremetal - index = 0 - for v_port in vm['ports']: - port_id = v_port['portId'] - if port_id in neutron_ports: - device_owner = neutron_ports[port_id]['device_owner'] - if(device_owner.startswith('compute') and - vm['baremetal_instance']): - del vm['ports'][index] - index += 1 - - # Now we are left with the ports that we are interested that - # require provisioning for v_port in vm['ports']: port_id = v_port['portId'] if not v_port['hosts']: @@ -1700,6 +1671,7 @@ class AristaRPCWrapperEapi(AristaRPCWrapperBase): port_name = 'name "%s"' % neutron_port['name'] device_owner = neutron_port['device_owner'] + vnic_type = port_profiles[port_id]['vnic_type'] network_id = neutron_port['network_id'] segments = [] if self.hpb_supported(): @@ -1712,44 +1684,47 @@ class AristaRPCWrapperEapi(AristaRPCWrapperBase): cmds.extend( 'segment level %d id %s' % (level, segment['id']) for level, segment in enumerate(segments)) - elif device_owner.startswith('baremetal'): - append_cmd('instance id %s hostid %s type baremetal' % - (vm['vmId'], v_port['hosts'][0])) - profile = bm_port_profiles[neutron_port['id']] - profile = json.loads(profile['profile']) - for binding in profile['local_link_information']: - if not binding or not isinstance(binding, dict): - # skip all empty entries - continue - # Ensure that profile contains switch and port ID info - if binding['switch_id'] and binding['port_id']: - if port_name: - cmds.append('port id %s name "%s" ' - 'network-id %s type native ' - 'switch-id %s switchport %s' % - (port_id, port_name, network_id, - binding['switch_id'], - binding['port_id'])) - else: - cmds.append('port id %s network-id %s ' - 'type native ' - 'switch-id %s switchport %s' % - (port_id, network_id, - binding['switch_id'], - binding['port_id'])) - cmds.extend('segment level %d id %s' % ( - level, segment['id']) - for level, segment in enumerate(segments)) + elif (device_owner.startswith('compute') or + device_owner.startswith('baremetal')): + if vnic_type == 'baremetal': + append_cmd('instance id %s hostid %s type baremetal' % + (vm['vmId'], v_port['hosts'][0])) + profile = port_profiles[neutron_port['id']] + profile = json.loads(profile['profile']) + for binding in profile['local_link_information']: + if not binding or not isinstance(binding, dict): + # skip all empty entries + continue + # Ensure that profile contains local link info + if binding['switch_id'] and binding['port_id']: + if port_name: + cmds.append('port id %s name "%s" ' + 'network-id %s type native ' + 'switch-id %s switchport %s' % + (port_id, port_name, + network_id, + binding['switch_id'], + binding['port_id'])) + else: + cmds.append('port id %s network-id %s ' + 'type native ' + 'switch-id %s switchport %s' % + (port_id, network_id, + binding['switch_id'], + binding['port_id'])) + cmds.extend('segment level %d id %s' % ( + level, segment['id']) + for level, segment in enumerate(segments)) - elif device_owner.startswith('compute'): - append_cmd('vm id %s hostid %s' % (vm['vmId'], - v_port['hosts'][0])) - append_cmd('port id %s %s network-id %s' % - (neutron_port['id'], port_name, - neutron_port['network_id'])) - cmds.extend('segment level %d id %s' % (level, - segment['id']) - for level, segment in enumerate(segments)) + else: + append_cmd('vm id %s hostid %s' % (vm['vmId'], + v_port['hosts'][0])) + append_cmd('port id %s %s network-id %s' % + (neutron_port['id'], port_name, + neutron_port['network_id'])) + cmds.extend('segment level %d id %s' % (level, + segment['id']) + for level, segment in enumerate(segments)) elif device_owner == n_const.DEVICE_OWNER_DVR_INTERFACE: if not self.bm_and_dvr_supported(): LOG.info(ERR_DVR_NOT_SUPPORTED) @@ -2125,7 +2100,7 @@ class SyncService(object): ) # Get Baremetal port switch_bindings, if any - bm_port_profiles = db_lib.get_all_baremetal_ports() + port_profiles = db_lib.get_all_portbindings() # To support shared networks, split the sync loop in two parts: # In first loop, delete unwanted VM and networks and update networks # In second loop, update VMs. This is done to ensure that networks for @@ -2230,7 +2205,7 @@ class SyncService(object): self._rpc.create_instance_bulk(tenant, ports_of_interest, db_vms, - bm_port_profiles, + port_profiles, sync=True) except arista_exc.AristaRpcError: LOG.warning(EOS_UNREACHABLE_MSG) diff --git a/networking_arista/tests/unit/ml2/test_arista_mechanism_driver.py b/networking_arista/tests/unit/ml2/test_arista_mechanism_driver.py index 07d5b46..27fd2d7 100644 --- a/networking_arista/tests/unit/ml2/test_arista_mechanism_driver.py +++ b/networking_arista/tests/unit/ml2/test_arista_mechanism_driver.py @@ -490,8 +490,10 @@ class TestAristaJSONRPCWrapper(testlib_api.SqlTestCase): profiles = {} for port in port_list: + profiles[port['portId']] = {'vnic_type': 'normal'} if port['device_owner'] == 'baremetal': profiles[port['portId']] = { + 'vnic_type': 'baremetal', 'profile': '{"local_link_information":' '[{"switch_id": "switch01", "port_id": "Ethernet1"}]}'} self.drv.create_instance_bulk(tenant_id, create_ports, devices, @@ -741,7 +743,7 @@ class TestAristaJSONRPCWrapper(testlib_api.SqlTestCase): switch_bindings = [{'switch_id': 'switch01', 'port_id': 'Ethernet1', 'switch_info': 'switch01'}] self.drv.plug_port_into_network('bm1', 'h1', 'p1', 'n1', 't1', 'port1', - 'baremetal', sg, None, None, + 'baremetal', sg, None, 'baremetal', segments, switch_bindings=switch_bindings) calls = [ @@ -767,7 +769,8 @@ class TestAristaJSONRPCWrapper(testlib_api.SqlTestCase): mock_get_instance_ports.return_value = [] switch_bindings = [{'switch_id': 'switch01', 'port_id': 'Ethernet1'}] self.drv.unplug_port_from_network('bm1', 'baremetal', 'h1', 'p1', 'n1', - 't1', None, None, switch_bindings) + 't1', None, 'baremetal', + switch_bindings) port = self.drv._create_port_data('p1', None, None, 'bm1', None, 'baremetal', None) calls = [ @@ -1174,12 +1177,14 @@ class PositiveRPCWrapperValidConfigTestCase(testlib_api.SqlTestCase): net_count += 1 create_ports = {} + port_profiles = {} for port in port_list: create_ports.update(port_dict_representation(port)) + port_profiles[port['portId']] = {'vnic_type': 'normal'} self.drv.cli_commands[arista_ml2.CMD_INSTANCE] = 'instance' self.drv.create_instance_bulk(tenant_id, create_ports, devices, - bm_port_profiles=None) + port_profiles=port_profiles) cmd1 = ['show openstack agent uuid'] cmd2 = ['enable', 'configure', @@ -1470,12 +1475,14 @@ class PositiveRPCWrapperValidConfigTestCase(testlib_api.SqlTestCase): net_count += 1 create_ports = {} + port_profiles = {} for port in port_list: create_ports.update(port_dict_representation(port)) + port_profiles[port['portId']] = {'vnic_type': 'normal'} self.drv.cli_commands[arista_ml2.CMD_INSTANCE] = 'instance' self.drv.create_instance_bulk(tenant_id, create_ports, devices, - bm_port_profiles=None, sync=True) + port_profiles=port_profiles, sync=True) cmd1 = ['show openstack agent uuid'] cmd2 = ['enable', 'configure',