metadata: add vf_trusted field to device metadata

The trusted vf attribute will be exposed to the instance through the
metadata API and on the config drive.

Note the logic when dealing with NetworkInterfaceMetadata devices was
refactored slightly in order to handle the existing cases where these
types of devices are skipped.

Implements blueprint sriov-trusted-vfs
Change-Id: Icbac4f11b2383b3d8295ec3362db0fc60b9c35a9
Signed-off-by: Sahid Orentino Ferdjaoui <sahid.ferdjaoui@redhat.com>
This commit is contained in:
Sahid Orentino Ferdjaoui 2018-05-04 17:23:01 +02:00 committed by Matt Riedemann
parent 397e883d67
commit f9ddddc358
4 changed files with 56 additions and 16 deletions

View File

@ -25,6 +25,7 @@ GET request to ``http://169.254.169.254/openstack``:
2016-06-30 2016-06-30
2016-10-06 2016-10-06
2017-02-22 2017-02-22
2018-08-27
latest latest
To list supported versions for the EC2-compatible metadata API, make a GET To list supported versions for the EC2-compatible metadata API, make a GET

View File

@ -72,6 +72,7 @@ LIBERTY = '2015-10-15'
NEWTON_ONE = '2016-06-30' NEWTON_ONE = '2016-06-30'
NEWTON_TWO = '2016-10-06' NEWTON_TWO = '2016-10-06'
OCATA = '2017-02-22' OCATA = '2017-02-22'
ROCKY = '2018-08-27'
OPENSTACK_VERSIONS = [ OPENSTACK_VERSIONS = [
FOLSOM, FOLSOM,
@ -81,6 +82,7 @@ OPENSTACK_VERSIONS = [
NEWTON_ONE, NEWTON_ONE,
NEWTON_TWO, NEWTON_TWO,
OCATA, OCATA,
ROCKY,
] ]
VERSION = "version" VERSION = "version"
@ -391,6 +393,7 @@ class InstanceMetadata(object):
""" """
device_metadata_list = [] device_metadata_list = []
vif_vlans_supported = self._check_os_version(OCATA, version) vif_vlans_supported = self._check_os_version(OCATA, version)
vif_vfs_trusted_supported = self._check_os_version(ROCKY, version)
if self.instance.device_metadata is not None: if self.instance.device_metadata is not None:
for device in self.instance.device_metadata.devices: for device in self.instance.device_metadata.devices:
device_metadata = {} device_metadata = {}
@ -421,19 +424,20 @@ class InstanceMetadata(object):
address = device.bus.address address = device.bus.address
if isinstance(device, metadata_obj.NetworkInterfaceMetadata): if isinstance(device, metadata_obj.NetworkInterfaceMetadata):
vlan = None vlan = device.vlan if 'vlan' in device else None
if vif_vlans_supported and 'vlan' in device: if vif_vlans_supported and vlan is not None:
vlan = device.vlan device_metadata['vlan'] = vlan
if vif_vfs_trusted_supported:
# Skip devices without tags on versions that vf_trusted = (device.vf_trusted if
# don't support vlans 'vf_trusted' in device else False)
if not (vlan or 'tags' in device): device_metadata['vf_trusted'] = vf_trusted
continue
device_metadata['type'] = 'nic' device_metadata['type'] = 'nic'
device_metadata['mac'] = device.mac device_metadata['mac'] = device.mac
if vlan: # NOTE(artom) If a device has neither tags, vlan or
device_metadata['vlan'] = vlan # vf_trusted, don't expose it
if not ('tags' in device or 'vlan' in device_metadata
or 'vf_trusted' in device_metadata):
continue
elif isinstance(device, metadata_obj.DiskMetadata): elif isinstance(device, metadata_obj.DiskMetadata):
device_metadata['type'] = 'disk' device_metadata['type'] = 'disk'
# serial and path are optional parameters # serial and path are optional parameters

View File

@ -168,6 +168,12 @@ def fake_metadata_objects():
mac='00:00:00:00:00:00', mac='00:00:00:00:00:00',
tags=['foo'] tags=['foo']
) )
nic_vf_trusted_obj = metadata_obj.NetworkInterfaceMetadata(
bus=metadata_obj.PCIDeviceBus(address='0000:00:02.0'),
mac='00:11:22:33:44:55',
vf_trusted=True,
tags=['trusted']
)
nic_vlans_obj = metadata_obj.NetworkInterfaceMetadata( nic_vlans_obj = metadata_obj.NetworkInterfaceMetadata(
bus=metadata_obj.PCIDeviceBus(address='0000:80:01.0'), bus=metadata_obj.PCIDeviceBus(address='0000:80:01.0'),
mac='e3:a0:d0:12:c5:10', mac='e3:a0:d0:12:c5:10',
@ -200,11 +206,12 @@ def fake_metadata_objects():
mdlist = metadata_obj.InstanceDeviceMetadata( mdlist = metadata_obj.InstanceDeviceMetadata(
instance_uuid='b65cee2f-8c69-4aeb-be2f-f79742548fc2', instance_uuid='b65cee2f-8c69-4aeb-be2f-f79742548fc2',
devices=[nic_obj, ide_disk_obj, scsi_disk_obj, usb_disk_obj, devices=[nic_obj, ide_disk_obj, scsi_disk_obj, usb_disk_obj,
fake_device_obj, device_with_fake_bus_obj, nic_vlans_obj]) fake_device_obj, device_with_fake_bus_obj, nic_vlans_obj,
nic_vf_trusted_obj])
return mdlist return mdlist
def fake_metadata_dicts(include_vlan=False): def fake_metadata_dicts(include_vlan=False, include_vf_trusted=False):
nic_meta = { nic_meta = {
'type': 'nic', 'type': 'nic',
'bus': 'pci', 'bus': 'pci',
@ -219,6 +226,13 @@ def fake_metadata_dicts(include_vlan=False):
'mac': 'e3:a0:d0:12:c5:10', 'mac': 'e3:a0:d0:12:c5:10',
'vlan': 1000, 'vlan': 1000,
} }
vf_trusted_nic_meta = {
'type': 'nic',
'bus': 'pci',
'address': '0000:00:02.0',
'mac': '00:11:22:33:44:55',
'tags': ['trusted'],
}
ide_disk_meta = { ide_disk_meta = {
'type': 'disk', 'type': 'disk',
'bus': 'ide', 'bus': 'ide',
@ -236,9 +250,15 @@ def fake_metadata_dicts(include_vlan=False):
usb_disk_meta['bus'] = 'usb' usb_disk_meta['bus'] = 'usb'
usb_disk_meta['address'] = '05c8:021e' usb_disk_meta['address'] = '05c8:021e'
dicts = [nic_meta, ide_disk_meta, scsi_disk_meta, usb_disk_meta] dicts = [nic_meta, ide_disk_meta, scsi_disk_meta, usb_disk_meta,
vf_trusted_nic_meta]
if include_vlan: if include_vlan:
dicts += [vlan_nic_meta] # NOTE(artom) Yeah, the order is important.
dicts.insert(len(dicts) - 1, vlan_nic_meta)
if include_vf_trusted:
nic_meta['vf_trusted'] = False
vlan_nic_meta['vf_trusted'] = False
vf_trusted_nic_meta['vf_trusted'] = True
return dicts return dicts
@ -478,6 +498,11 @@ class MetadataTestCase(test.TestCase):
'openstack/2017-02-22/vendor_data.json', 'openstack/2017-02-22/vendor_data.json',
'openstack/2017-02-22/network_data.json', 'openstack/2017-02-22/network_data.json',
'openstack/2017-02-22/vendor_data2.json', 'openstack/2017-02-22/vendor_data2.json',
'openstack/2018-08-27/meta_data.json',
'openstack/2018-08-27/user_data',
'openstack/2018-08-27/vendor_data.json',
'openstack/2018-08-27/network_data.json',
'openstack/2018-08-27/vendor_data2.json',
'openstack/latest/meta_data.json', 'openstack/latest/meta_data.json',
'openstack/latest/user_data', 'openstack/latest/user_data',
'openstack/latest/vendor_data.json', 'openstack/latest/vendor_data.json',
@ -567,6 +592,10 @@ class MetadataTestCase(test.TestCase):
if md._check_os_version(base.NEWTON_ONE, os_version): if md._check_os_version(base.NEWTON_ONE, os_version):
expose_vlan = md._check_os_version(base.OCATA, os_version) expose_vlan = md._check_os_version(base.OCATA, os_version)
expected_metadata['devices'] = fake_metadata_dicts(expose_vlan) expected_metadata['devices'] = fake_metadata_dicts(expose_vlan)
if md._check_os_version(base.OCATA, os_version):
expose_trusted = md._check_os_version(base.ROCKY, os_version)
expected_metadata['devices'] = fake_metadata_dicts(
True, expose_trusted)
mock_cells_keypair.return_value = keypair mock_cells_keypair.return_value = keypair
md._metadata_as_json(os_version, 'non useless path parameter') md._metadata_as_json(os_version, 'non useless path parameter')
if instance.key_name: if instance.key_name:
@ -648,7 +677,7 @@ class OpenStackMetadataTestCase(test.TestCase):
mdinst = fake_InstanceMetadata(self, inst) mdinst = fake_InstanceMetadata(self, inst)
mdjson = mdinst.lookup("/openstack/latest/meta_data.json") mdjson = mdinst.lookup("/openstack/latest/meta_data.json")
mddict = jsonutils.loads(mdjson) mddict = jsonutils.loads(mdjson)
self.assertEqual(fake_metadata_dicts(True), mddict['devices']) self.assertEqual(fake_metadata_dicts(True, True), mddict['devices'])
def test_top_level_listing(self): def test_top_level_listing(self):
# request for /openstack/<version>/ should show metadata.json # request for /openstack/<version>/ should show metadata.json

View File

@ -0,0 +1,6 @@
---
features:
- |
As of the ``2018-08-27`` metadata API version, a boolean ``vf_trusted`` key
appears for all network interface ``devices`` in ``meta_data.json``,
indicating whether the device is a trusted virtual function or not.