From f9ddddc3586193f4edd5f7bb2a05e91b7d15b494 Mon Sep 17 00:00:00 2001 From: Sahid Orentino Ferdjaoui Date: Fri, 4 May 2018 17:23:01 +0200 Subject: [PATCH] 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 --- doc/source/user/metadata-service.rst | 1 + nova/api/metadata/base.py | 26 +++++++------ nova/tests/unit/test_metadata.py | 39 ++++++++++++++++--- .../trusted-metatada-b999f1417f678c44.yaml | 6 +++ 4 files changed, 56 insertions(+), 16 deletions(-) create mode 100644 releasenotes/notes/trusted-metatada-b999f1417f678c44.yaml diff --git a/doc/source/user/metadata-service.rst b/doc/source/user/metadata-service.rst index 279b4012c776..25405cd2062a 100644 --- a/doc/source/user/metadata-service.rst +++ b/doc/source/user/metadata-service.rst @@ -25,6 +25,7 @@ GET request to ``http://169.254.169.254/openstack``: 2016-06-30 2016-10-06 2017-02-22 + 2018-08-27 latest To list supported versions for the EC2-compatible metadata API, make a GET diff --git a/nova/api/metadata/base.py b/nova/api/metadata/base.py index 2c61cdb25bc0..b4cd397c4e2e 100644 --- a/nova/api/metadata/base.py +++ b/nova/api/metadata/base.py @@ -72,6 +72,7 @@ LIBERTY = '2015-10-15' NEWTON_ONE = '2016-06-30' NEWTON_TWO = '2016-10-06' OCATA = '2017-02-22' +ROCKY = '2018-08-27' OPENSTACK_VERSIONS = [ FOLSOM, @@ -81,6 +82,7 @@ OPENSTACK_VERSIONS = [ NEWTON_ONE, NEWTON_TWO, OCATA, + ROCKY, ] VERSION = "version" @@ -391,6 +393,7 @@ class InstanceMetadata(object): """ device_metadata_list = [] 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: for device in self.instance.device_metadata.devices: device_metadata = {} @@ -421,19 +424,20 @@ class InstanceMetadata(object): address = device.bus.address if isinstance(device, metadata_obj.NetworkInterfaceMetadata): - vlan = None - if vif_vlans_supported and 'vlan' in device: - vlan = device.vlan - - # Skip devices without tags on versions that - # don't support vlans - if not (vlan or 'tags' in device): - continue - + vlan = device.vlan if 'vlan' in device else None + if vif_vlans_supported and vlan is not None: + device_metadata['vlan'] = vlan + if vif_vfs_trusted_supported: + vf_trusted = (device.vf_trusted if + 'vf_trusted' in device else False) + device_metadata['vf_trusted'] = vf_trusted device_metadata['type'] = 'nic' device_metadata['mac'] = device.mac - if vlan: - device_metadata['vlan'] = vlan + # NOTE(artom) If a device has neither tags, vlan or + # 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): device_metadata['type'] = 'disk' # serial and path are optional parameters diff --git a/nova/tests/unit/test_metadata.py b/nova/tests/unit/test_metadata.py index b94999aff573..641c7af89b70 100644 --- a/nova/tests/unit/test_metadata.py +++ b/nova/tests/unit/test_metadata.py @@ -168,6 +168,12 @@ def fake_metadata_objects(): mac='00:00:00:00:00:00', 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( bus=metadata_obj.PCIDeviceBus(address='0000:80:01.0'), mac='e3:a0:d0:12:c5:10', @@ -200,11 +206,12 @@ def fake_metadata_objects(): mdlist = metadata_obj.InstanceDeviceMetadata( instance_uuid='b65cee2f-8c69-4aeb-be2f-f79742548fc2', 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 -def fake_metadata_dicts(include_vlan=False): +def fake_metadata_dicts(include_vlan=False, include_vf_trusted=False): nic_meta = { 'type': 'nic', 'bus': 'pci', @@ -219,6 +226,13 @@ def fake_metadata_dicts(include_vlan=False): 'mac': 'e3:a0:d0:12:c5:10', '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 = { 'type': 'disk', 'bus': 'ide', @@ -236,9 +250,15 @@ def fake_metadata_dicts(include_vlan=False): usb_disk_meta['bus'] = 'usb' 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: - 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 @@ -478,6 +498,11 @@ class MetadataTestCase(test.TestCase): 'openstack/2017-02-22/vendor_data.json', 'openstack/2017-02-22/network_data.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/user_data', 'openstack/latest/vendor_data.json', @@ -567,6 +592,10 @@ class MetadataTestCase(test.TestCase): if md._check_os_version(base.NEWTON_ONE, os_version): expose_vlan = md._check_os_version(base.OCATA, os_version) 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 md._metadata_as_json(os_version, 'non useless path parameter') if instance.key_name: @@ -648,7 +677,7 @@ class OpenStackMetadataTestCase(test.TestCase): mdinst = fake_InstanceMetadata(self, inst) mdjson = mdinst.lookup("/openstack/latest/meta_data.json") 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): # request for /openstack// should show metadata.json diff --git a/releasenotes/notes/trusted-metatada-b999f1417f678c44.yaml b/releasenotes/notes/trusted-metatada-b999f1417f678c44.yaml new file mode 100644 index 000000000000..b6a44edd03cf --- /dev/null +++ b/releasenotes/notes/trusted-metatada-b999f1417f678c44.yaml @@ -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.