From baa0b4ff87a044228438cc32c27d4424fa6bc0c4 Mon Sep 17 00:00:00 2001 From: melanie witt Date: Wed, 10 Aug 2022 23:22:47 +0000 Subject: [PATCH 1/8] Fix exception catch when volume mount fails When we call nova.privsep.fs.mount(), we are catching ProcessExecutionError() (an instance of a class) and that is not allowed in python3. This changes the except statement to catch ProcessExecutionError (class) instead. Closes-Bug: #1984736 Change-Id: I24a269f9809063f864a4f0443d6724dfa8703d9d (cherry picked from commit f996674c36fe1a109853d88113e27b44a7a5cf45) --- .../unit/virt/libvirt/volume/test_mount.py | 26 +++++++++++++++++++ nova/virt/libvirt/volume/mount.py | 2 +- 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/nova/tests/unit/virt/libvirt/volume/test_mount.py b/nova/tests/unit/virt/libvirt/volume/test_mount.py index 8ecb117f050..a27505052f2 100644 --- a/nova/tests/unit/virt/libvirt/volume/test_mount.py +++ b/nova/tests/unit/virt/libvirt/volume/test_mount.py @@ -580,6 +580,32 @@ def test_umount_log_failure(self, mock_log): mock_log.assert_called() + @mock.patch.object(mount.LOG, 'exception') + def test_mount_failure(self, mock_log_exc): + m = self._get_clean_hostmountstate() + err = processutils.ProcessExecutionError + self.mock_mount.side_effect = err + + # Mount vol_a + self.assertRaises(err, self._sentinel_mount, m, mock.sentinel.vol_a) + + # Verify the mountpoint got removed after the failure + self.assertEqual({}, m.mountpoints) + + # Now try a scenario where the mount failed because the volume was + # already mounted + self.mock_ismount.side_effect = [False, True] + + # Mount vol_a + self._sentinel_mount(m, mock.sentinel.vol_a) + + # Verify the mountpoint is present despite the error + self.assertEqual(1, len(m.mountpoints)) + self.assertIn(mock.sentinel.mountpoint, m.mountpoints) + + # Verify we logged an exception + mock_log_exc.assert_called() + class MountManagerTestCase(test.NoDBTestCase): class FakeHostMountState(object): diff --git a/nova/virt/libvirt/volume/mount.py b/nova/virt/libvirt/volume/mount.py index d85ac8aa481..01338497b6a 100644 --- a/nova/virt/libvirt/volume/mount.py +++ b/nova/virt/libvirt/volume/mount.py @@ -306,7 +306,7 @@ def mount(self, fstype, export, vol_name, mountpoint, instance, options): try: nova.privsep.fs.mount(fstype, export, mountpoint, options) - except processutils.ProcessExecutionError(): + except processutils.ProcessExecutionError: # Check to see if mountpoint is mounted despite the error # eg it was already mounted if os.path.ismount(mountpoint): From b487ac262201cd2be337814182e371262eb7f801 Mon Sep 17 00:00:00 2001 From: Sylvain Bauza Date: Thu, 18 Jul 2024 19:08:49 +0200 Subject: [PATCH 2/8] cpu: Only check governor type on online cores Kernels don't accept to access the governor strategy on an offline core, so we need to only validate strategies for online cores. Change-Id: I14c9b268d0b97221216bd1a9ab9e48b48d6dcc2c Closes-Bug: #2073528 (cherry picked from commit 757c333c0e55df4bcaf9d442fbe8dc8009e36989) (cherry picked from commit cf721336d401e1ded843899b59b88e4f5030ade0) (cherry picked from commit 52f6968d47967b82c877e4ba137f1fcfb0e4b21d) --- nova/tests/unit/virt/libvirt/cpu/test_api.py | 18 ++++++++++++++++++ nova/virt/libvirt/cpu/api.py | 12 +++++++----- 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/nova/tests/unit/virt/libvirt/cpu/test_api.py b/nova/tests/unit/virt/libvirt/cpu/test_api.py index 408496dbd34..4d3684817e9 100644 --- a/nova/tests/unit/virt/libvirt/cpu/test_api.py +++ b/nova/tests/unit/virt/libvirt/cpu/test_api.py @@ -244,3 +244,21 @@ def test_validate_all_dedicated_cpus_no_cpu(self): self.api.validate_all_dedicated_cpus() # no assert we want to make sure the validation won't raise if # no dedicated cpus are configured + + @mock.patch.object(core, 'get_governor') + @mock.patch.object(core, 'get_online') + def test_validate_all_dedicated_cpus_for_cpu_state_with_off_cores( + self, mock_get_online, mock_get_governor): + self.flags(cpu_power_management=True, group='libvirt') + self.flags(cpu_dedicated_set='1-3', group='compute') + self.flags(cpu_power_management_strategy='cpu_state', group='libvirt') + # CPU1 and CPU3 are online while CPU2 is offline + mock_get_online.side_effect = (True, False, True) + mock_get_governor.return_value = 'performance' + self.api.validate_all_dedicated_cpus() + + mock_get_online.assert_has_calls([mock.call(1), mock.call(2), + mock.call(3)]) + # we only have two calls as CPU2 was skipped + mock_get_governor.assert_has_calls([mock.call(1), + mock.call(3)]) diff --git a/nova/virt/libvirt/cpu/api.py b/nova/virt/libvirt/cpu/api.py index 1c4bd19bee2..104a3b4d277 100644 --- a/nova/virt/libvirt/cpu/api.py +++ b/nova/virt/libvirt/cpu/api.py @@ -172,8 +172,7 @@ def validate_all_dedicated_cpus(self) -> None: if not CONF.libvirt.cpu_power_management: return cpu_dedicated_set = hardware.get_cpu_dedicated_set() or set() - governors = set() - cpu_states = set() + pcpus = [] for pcpu in cpu_dedicated_set: if (pcpu == 0 and CONF.libvirt.cpu_power_management_strategy == 'cpu_state'): @@ -181,11 +180,13 @@ def validate_all_dedicated_cpus(self) -> None: 'but it is not eligible for state management ' 'and will be ignored') continue - pcpu = self.core(pcpu) # we need to collect the governors strategy and the CPU states - governors.add(pcpu.governor) - cpu_states.add(pcpu.online) + pcpus.append(self.core(pcpu)) if CONF.libvirt.cpu_power_management_strategy == 'cpu_state': + # NOTE(sbauza): offline cores can't have a governor, it returns a + # DeviceBusy exception. + governors = set([pcpu.governor for pcpu in pcpus + if pcpu.online]) # all the cores need to have the same governor strategy if len(governors) > 1: msg = _("All the cores need to have the same governor strategy" @@ -193,6 +194,7 @@ def validate_all_dedicated_cpus(self) -> None: "compute node if you prefer.") raise exception.InvalidConfiguration(msg) elif CONF.libvirt.cpu_power_management_strategy == 'governor': + cpu_states = set([pcpu.online for pcpu in pcpus]) # all the cores need to be online if False in cpu_states: msg = _("All the cores need to be online before modifying the " From 77dfa4f6f3c39048b5d3bb9eb2b14dd6998b406b Mon Sep 17 00:00:00 2001 From: Dan Smith Date: Wed, 24 Jul 2024 09:01:31 -0700 Subject: [PATCH 3/8] Remove AMI snapshot format special case Note that this includes seemingly-unrelated test changes because we were actually skipping the snapshot_running test for libvirt, which has been a bug for years. In that test case, when we went to look for image_meta.disk_format, that attribute was not set on the o.vo object, which raised a NotImplementedError. That error is also checked by the test to skip the test for drivers that do not support snapshot, which meant that for libvirt, we haven't been running that case beyond the point at which we create snapshot metadata and trip that exception. Thus, once removing that, there are other mocks not in place that are required for the test to actually run. So, this adds mocks for qemu_img_info() calls that actually try to read the file on disk, as well as the privsep chown() that attempts to run after. Change-Id: Ie731045629f0899840a4680d21793a16ade9b98e (cherry picked from commit d5a631ba7791b37e49213707e4ea650a56d2ed9e) (cherry picked from commit 8c5929ff5156d5409d41872f1b8ee0abb04f35a8) (cherry picked from commit d2d3b2c9e87fe2247a34a776310221c8b12be515) --- nova/tests/unit/virt/libvirt/test_driver.py | 11 +++++++---- nova/tests/unit/virt/test_virt_drivers.py | 5 +++++ nova/virt/libvirt/driver.py | 6 +----- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/nova/tests/unit/virt/libvirt/test_driver.py b/nova/tests/unit/virt/libvirt/test_driver.py index 86a6d25b093..9815cde0888 100644 --- a/nova/tests/unit/virt/libvirt/test_driver.py +++ b/nova/tests/unit/virt/libvirt/test_driver.py @@ -9385,7 +9385,7 @@ def test_set_quiesced_agent_connection_fails(self): def test_create_snapshot_metadata(self): base = objects.ImageMeta.from_dict( - {'disk_format': 'raw'}) + {'disk_format': 'qcow2'}) instance_data = {'kernel_id': 'kernel', 'project_id': 'prj_id', 'ramdisk_id': 'ram_id', @@ -9417,10 +9417,12 @@ def test_create_snapshot_metadata(self): {'disk_format': 'ami', 'container_format': 'test_container'}) expected['properties']['os_type'] = instance['os_type'] - expected['disk_format'] = base.disk_format + # The disk_format of the snapshot should be the *actual* format of the + # thing we upload, regardless of what type of image we booted from. + expected['disk_format'] = img_fmt expected['container_format'] = base.container_format ret = drvr._create_snapshot_metadata(base, instance, img_fmt, snp_name) - self.assertEqual(ret, expected) + self.assertEqual(expected, ret) def test_get_volume_driver(self): conn = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False) @@ -29000,7 +29002,8 @@ def test_ami(self): utils.get_system_metadata_from_image( {'disk_format': 'ami'}) - self._test_snapshot(disk_format='ami') + # If we're uploading a qcow2, we must set the disk_format as such + self._test_snapshot(disk_format='qcow2') @mock.patch('nova.virt.libvirt.utils.get_disk_type_from_path', new=mock.Mock(return_value=None)) diff --git a/nova/tests/unit/virt/test_virt_drivers.py b/nova/tests/unit/virt/test_virt_drivers.py index ed9f1e3822d..802ea4f027f 100644 --- a/nova/tests/unit/virt/test_virt_drivers.py +++ b/nova/tests/unit/virt/test_virt_drivers.py @@ -838,6 +838,11 @@ def setUp(self): # since we don't care about it. self.stub_out('os_vif.unplug', lambda a, kw: None) self.stub_out('nova.compute.utils.get_machine_ips', lambda: []) + self.stub_out('nova.virt.libvirt.utils.get_disk_size', + lambda *a, **k: 123456) + self.stub_out('nova.virt.libvirt.utils.get_disk_backing_file', + lambda *a, **k: None) + self.stub_out('nova.privsep.path.chown', lambda *a, **k: None) def test_init_host_image_type_rbd_force_raw_images_true(self): CONF.set_override('images_type', 'rbd', group='libvirt') diff --git a/nova/virt/libvirt/driver.py b/nova/virt/libvirt/driver.py index 68eece5e930..39add9f24e4 100644 --- a/nova/virt/libvirt/driver.py +++ b/nova/virt/libvirt/driver.py @@ -2967,11 +2967,7 @@ def _create_snapshot_metadata(self, image_meta, instance, if instance.os_type: metadata['properties']['os_type'] = instance.os_type - # NOTE(vish): glance forces ami disk format to be ami - if image_meta.disk_format == 'ami': - metadata['disk_format'] = 'ami' - else: - metadata['disk_format'] = img_fmt + metadata['disk_format'] = img_fmt if image_meta.obj_attr_is_set("container_format"): metadata['container_format'] = image_meta.container_format From 734aa4611fd7fb99b053f26206e891949732cae5 Mon Sep 17 00:00:00 2001 From: Julien Le Jeune Date: Mon, 15 Jul 2024 14:10:43 +0200 Subject: [PATCH 4/8] Fix test_vmdk_bad_descriptor_mem_limit and test_vmdk_bad_descriptor_mem_limit_stream_optimized These tests depend on qemu-img being installed and in the path, if it is not installed, skip them. Change-Id: I896f16c512f24bcdd898ab002af4e5e068f66b64 Closes-bug: #2073862 Signed-off-by: Julien Le Jeune (cherry picked from commit a3202f7bf9f1aecc7d0632011167d38a1698f0a0) (cherry picked from commit c782f0e6a0f666c9187820f0065cc81664de296c) (cherry picked from commit 828a5d078620501716638c080ec490d35113b32e) --- nova/tests/unit/image/test_format_inspector.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/nova/tests/unit/image/test_format_inspector.py b/nova/tests/unit/image/test_format_inspector.py index 8406dfca378..605b67c0ec0 100644 --- a/nova/tests/unit/image/test_format_inspector.py +++ b/nova/tests/unit/image/test_format_inspector.py @@ -179,10 +179,16 @@ def _create_allocated_vmdk(self, size_mb, subformat=None): shell=True) # Convert it to VMDK - subprocess.check_output( - 'qemu-img convert -f raw -O vmdk -o subformat=%s -S 0 %s %s' % ( - subformat, raw, fn), - shell=True) + # these tests depend on qemu-img + # being installed and in the path, + # if it is not installed, skip + try: + subprocess.check_output( + 'qemu-img convert -f raw -O vmdk -o subformat=%s -S 0 %s %s' + % (subformat, raw, fn), + shell=True) + except Exception: + self.skipTest("qemu-img not installed") return fn def _test_format_at_block_size(self, format_name, img, block_size): From fe3513f37a7dd9dc66c6dd469b2b77c02e0c0f65 Mon Sep 17 00:00:00 2001 From: liwenjian Date: Fri, 8 Sep 2023 17:14:38 +0800 Subject: [PATCH 5/8] Fixed an error when caching multiple images in aggregate Because in the process of judging whether the image id is Duplicate,there is only deduplication without sorting, so no duplicate image error is judged as duplicate and an error "Duplicate images in request" is reported. Now it is changed to sort after deduplication and then compare. Two unit test cases were added to verify the fix Related-Bug: #2034702 Change-Id: I300a3e29ba56584f4c99d534a6cf8ee7dc0ed4b7 (cherry picked from commit aa500fbb31d2f7129c048460e57a3dff229cabc8) (cherry picked from commit f9abe047f6d7fb30141d6cd76208771d512c5653) --- nova/api/openstack/compute/aggregates.py | 2 +- .../api/openstack/compute/test_aggregates.py | 25 +++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/nova/api/openstack/compute/aggregates.py b/nova/api/openstack/compute/aggregates.py index 4b4e31b3486..45bd904ec03 100644 --- a/nova/api/openstack/compute/aggregates.py +++ b/nova/api/openstack/compute/aggregates.py @@ -289,7 +289,7 @@ def images(self, req, id, body): for image_req in body.get('cache'): image_ids.append(image_req['id']) - if image_ids != list(set(image_ids)): + if sorted(image_ids) != sorted(list(set(image_ids))): raise exc.HTTPBadRequest( explanation=_('Duplicate images in request')) diff --git a/nova/tests/unit/api/openstack/compute/test_aggregates.py b/nova/tests/unit/api/openstack/compute/test_aggregates.py index 21d644f0bed..891388590d4 100644 --- a/nova/tests/unit/api/openstack/compute/test_aggregates.py +++ b/nova/tests/unit/api/openstack/compute/test_aggregates.py @@ -738,3 +738,28 @@ def test_images_with_invalid_id(self): version='2.81') self.assertRaises(exc.HTTPBadRequest, self.controller.images, req, 'foo', body=body) + + def test_images_with_duplicate_id(self): + body = {"cache": [{"id": "faae1bd3-c848-41d6-b4dd-97d5b8be8b7e"}, + {"id": "faae1bd3-c848-41d6-b4dd-97d5b8be8b7e"}]} + req = fakes.HTTPRequest.blank('/v2/os-aggregates', + use_admin_context=True, + version='2.81') + self.assertRaises(exc.HTTPBadRequest, self.controller.images, + req, '1', body=body) + + def test_images_with_disorder_id(self): + body = {"cache": [{"id": "faae1bd3-c848-41d6-b4dd-97d5b8be8b7e"}, + {"id": "290de658-cf55-4cce-b025-9a1a9f93676a"}, + {"id": "896f7f54-4e4e-4c21-a2b7-47cff4e99ab0"}, + {"id": "d982bb82-04a0-4e9b-b40e-470f20a7b5d1"}]} + req = fakes.HTTPRequest.blank('/v2/os-aggregates', + use_admin_context=True, + version='2.81') + context = req.environ['nova.context'] + with mock.patch.object(self.controller.api, + 'get_aggregate') as mock_get: + with mock.patch.object(self.controller.conductor_tasks, + 'cache_images'): + self.controller.images(req, '1', body=body) + mock_get.assert_called_once_with(context, '1') From 8b79f0f6a4315a89cb90ea86c7e05dfde3b1fc92 Mon Sep 17 00:00:00 2001 From: Elod Illes Date: Fri, 12 Jul 2024 22:53:06 +0200 Subject: [PATCH 6/8] [tools] Ignore bot generated patches This is a fix for the test whether a patch is bot generated or not, as that did not worked as intended. The problem is that the script is checking the email address of the parent patch (HEAD~), which probably should be right in case the patch would be a MERGE patch. But this is wrong in case the patch is not a MERGE patch. This fix uses the very same pattern as it is using for the commit message parsing: the $commit_hash variable, which is the parent's commit hash if the patch is a MERGE patch, and an empty string in the other case (causing to call 'git show' on HEAD). Change-Id: I0abc72180edf34a6dd0624a40fb8682397805eca (cherry picked from commit b8f3975d3641fad19971cc159bdb9decb6ea95f8) (cherry picked from commit 92b781f96e076f22ef098ca7894a3eeddb647731) (cherry picked from commit 7a914d6bfc5467e91175c55c8ea63e62e3518d86) --- tools/check-cherry-picks.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/check-cherry-picks.sh b/tools/check-cherry-picks.sh index 3042aa16593..439f42df3af 100755 --- a/tools/check-cherry-picks.sh +++ b/tools/check-cherry-picks.sh @@ -14,7 +14,7 @@ if [ $parent_number -eq 2 ]; then commit_hash=$(git show --format='%P' --quiet | awk '{print $NF}') fi -if git show --format='%aE' HEAD~ --quiet | grep -qi 'infra-root@openstack.org'; then +if git show --format='%aE' --quiet $commit_hash | grep -qi 'infra-root@openstack.org'; then echo 'Bot generated change; ignoring' exit 0 fi From f53824f95bea8769a2b28c62f23e57cb8dbafae5 Mon Sep 17 00:00:00 2001 From: Elod Illes Date: Fri, 12 Jul 2024 23:10:26 +0200 Subject: [PATCH 7/8] [tools] Backport validator: handle unmaintained When the script was created there were only stable/* branches, but now there are unmaintained/* branches as well, where the validator fails when looking for hashes only on stable/* branches even if the given hash is already on unmtaintained/* branch. This patch matches now both stable/* and unmaintained/* branches. Change-Id: I08fcc63ab0fbe5af1be70d5fde5af98bf006101c (cherry picked from commit e2697de8e41a566eb86aefa364906bda9bc59863) (cherry picked from commit 602e68364c54fb54140006f38d6995b9a5b354a9) (cherry picked from commit 56e73cc7bad51435a79584e9411f07add0d0536a) --- tools/check-cherry-picks.sh | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/tools/check-cherry-picks.sh b/tools/check-cherry-picks.sh index 439f42df3af..74887a9178b 100755 --- a/tools/check-cherry-picks.sh +++ b/tools/check-cherry-picks.sh @@ -1,7 +1,8 @@ #!/bin/sh # # A tool to check the cherry-pick hashes from the current git commit message -# to verify that they're all on either master or stable/ branches +# to verify that they're all on either master, stable/ or unmaintained/ +# branches # commit_hash="" @@ -23,9 +24,9 @@ hashes=$(git show --format='%b' --quiet $commit_hash | sed -nr 's/^.cherry picke checked=0 branches+="" for hash in $hashes; do - branch=$(git branch -a --contains "$hash" 2>/dev/null| grep -oE '(master|stable/[a-z0-9.]+)') + branch=$(git branch -a --contains "$hash" 2>/dev/null| grep -oE '(master|stable/[a-z0-9.]+|unmaintained/[a-z0-9.]+)') if [ $? -ne 0 ]; then - echo "Cherry pick hash $hash not on any master or stable branches" + echo "Cherry pick hash $hash not on any master, stable or unmaintained branches" exit 1 fi branches+=" $branch" @@ -33,7 +34,7 @@ for hash in $hashes; do done if [ $checked -eq 0 ]; then - if ! grep -q '^defaultbranch=stable/' .gitreview; then + if ! grep -qE '^defaultbranch=(stable|unmaintained)/' .gitreview; then echo "Checked $checked cherry-pick hashes: OK" exit 0 else From 5b417108a7b148cd3e96929de9ea7885e8008551 Mon Sep 17 00:00:00 2001 From: Amit Uniyal Date: Tue, 9 Jan 2024 15:40:27 +0000 Subject: [PATCH 8/8] Refactor vf profile for PCI device In general the card_serial_number will not be present on sriov VFs/PFs, it is only supported on very new cards. Also, all 3 need not to be always required for vf_profile. Related-Bug: #2008238 Change-Id: I00b126635612ace51b5e3138afcb064f001f1901 (cherry picked from commit a1a07e0d2d01e95b7d3c8db62d149a4278617c93) (cherry picked from commit 9146e9056613815fcaa09f0a2d2f3d23fb42b317) (cherry picked from commit 114eabb38e607aa1feabc56bdf6e20c8162aa6a8) --- nova/network/neutron.py | 13 ++-- .../libvirt/test_pci_sriov_servers.py | 6 ++ nova/tests/unit/network/test_neutron.py | 67 +++++++++++++++++++ 3 files changed, 80 insertions(+), 6 deletions(-) diff --git a/nova/network/neutron.py b/nova/network/neutron.py index f37f8a343a6..d9544c1bc48 100644 --- a/nova/network/neutron.py +++ b/nova/network/neutron.py @@ -1595,12 +1595,13 @@ def _get_vf_pci_device_profile(self, pci_dev): pf_mac = pci_dev.sriov_cap.get('pf_mac_address') vf_num = pci_dev.sriov_cap.get('vf_num') card_serial_number = pci_dev.card_serial_number - if all((pf_mac, vf_num, card_serial_number)): - vf_profile.update({ - 'card_serial_number': card_serial_number, - 'pf_mac_address': pf_mac, - 'vf_num': vf_num, - }) + + if card_serial_number is not None: + vf_profile['card_serial_number'] = card_serial_number + if pf_mac is not None: + vf_profile['pf_mac_address'] = pf_mac + if vf_num is not None: + vf_profile['vf_num'] = vf_num # Update port binding capabilities using PCI device's network # capabilities if they exist. diff --git a/nova/tests/functional/libvirt/test_pci_sriov_servers.py b/nova/tests/functional/libvirt/test_pci_sriov_servers.py index 135a457154b..903fd5ef16d 100644 --- a/nova/tests/functional/libvirt/test_pci_sriov_servers.py +++ b/nova/tests/functional/libvirt/test_pci_sriov_servers.py @@ -521,6 +521,8 @@ def fake_create(cls, xml, host): 'pci_vendor_info': '8086:1515', 'pci_slot': '0000:81:00.2', 'physical_network': 'physnet4', + 'pf_mac_address': '52:54:00:1e:59:c6', + 'vf_num': 1 }, port['binding:profile'], ) @@ -1017,6 +1019,8 @@ def test_live_migrate_server_with_neutron(self): # matching one) 'pci_slot': '0000:81:00.4', 'physical_network': 'physnet4', + 'pf_mac_address': '52:54:00:1e:59:c6', + 'vf_num': 1 }, port['binding:profile'], ) @@ -1062,6 +1066,8 @@ def test_live_migrate_server_with_neutron(self): 'pci_vendor_info': '8086:1515', 'pci_slot': '0000:81:00.2', 'physical_network': 'physnet4', + 'pf_mac_address': '52:54:00:1e:59:c6', + 'vf_num': 1, }, port['binding:profile'], ) diff --git a/nova/tests/unit/network/test_neutron.py b/nova/tests/unit/network/test_neutron.py index a9aa501a134..767f8336399 100644 --- a/nova/tests/unit/network/test_neutron.py +++ b/nova/tests/unit/network/test_neutron.py @@ -8627,6 +8627,73 @@ def test_unbind_ports_clean_arq(self, mock_neutron, mock_show, self.assertEqual(call_args['port']['binding:profile'], {'key': 'val'}) + def test__get_vf_pci_device_profile_without_serial_num(self): + mydev = objects.PciDevice( + address='foo', + compute_node_id='123', + extra_info={ + 'capabilities': jsonutils.dumps({ + 'sriov': { + 'pf_mac_address': '52:54:00:1e:59:c6', + 'vf_num': 1, + }, + 'network': ['gso', 'sg', 'tso', 'tx'], + }), + }, + ) + self.assertEqual(self.api._get_vf_pci_device_profile(mydev), + {'pf_mac_address': '52:54:00:1e:59:c6', + 'vf_num': 1, + 'capabilities': ['gso', 'sg', 'tso', 'tx']}) + + def test__get_vf_pci_device_profile_without_pf_mac_addr(self): + mydev = objects.PciDevice( + address='foo', + compute_node_id='123', + extra_info={ + 'capabilities': jsonutils.dumps({ + 'vpd': {'card_serial_number': 'MT2113X00000'}, + 'sriov': {'vf_num': 1}, + 'network': ['gso', 'sg', 'tso', 'tx'], + }), + }, + ) + self.assertEqual(self.api._get_vf_pci_device_profile(mydev), + {'card_serial_number': 'MT2113X00000', + 'vf_num': 1, + 'capabilities': ['gso', 'sg', 'tso', 'tx']}) + + def test__get_vf_pci_device_profile_without_vf_num(self): + mydev = objects.PciDevice( + address='foo', + compute_node_id='123', + extra_info={ + 'capabilities': jsonutils.dumps({ + 'vpd': {'card_serial_number': 'MT2113X00000'}, + 'sriov': {'pf_mac_address': '52:54:00:1e:59:c6'}, + 'network': ['gso', 'sg', 'tso', 'tx'], + }), + }, + ) + self.assertEqual(self.api._get_vf_pci_device_profile(mydev), + {'card_serial_number': 'MT2113X00000', + 'pf_mac_address': '52:54:00:1e:59:c6', + 'capabilities': ['gso', 'sg', 'tso', 'tx']}) + + def test__get_vf_pci_device_profile_with_dev_capabilities(self): + mydev = objects.PciDevice( + address='foo', + compute_node_id='123', + extra_info={ + 'capabilities': jsonutils.dumps({ + 'sriov': {}, + 'network': ['gso', 'sg', 'tso', 'tx'], + }), + }, + ) + self.assertEqual(self.api._get_vf_pci_device_profile(mydev), + {'capabilities': ['gso', 'sg', 'tso', 'tx']}) + class TestAllocateForInstance(test.NoDBTestCase): def setUp(self):