Skip to content

Commit b502989

Browse files
Zuulopenstack-gerrit
authored andcommitted
Merge "Move 'hw:pmu', 'hw_pmu' parsing to nova.virt.hardware"
2 parents 3a14c1a + eacecc2 commit b502989

File tree

7 files changed

+104
-87
lines changed

7 files changed

+104
-87
lines changed

nova/api/openstack/compute/servers.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,6 @@
6868
exception.ImageNUMATopologyIncomplete,
6969
exception.ImageNUMATopologyMemoryOutOfRange,
7070
exception.ImageNUMATopologyRebuildConflict,
71-
exception.ImagePMUConflict,
7271
exception.ImageSerialPortNumberExceedFlavorValue,
7372
exception.ImageSerialPortNumberInvalid,
7473
exception.ImageVCPULimitsRangeExceeded,

nova/compute/api.py

Lines changed: 2 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -840,17 +840,10 @@ def _validate_flavor_image_numa_pci(
840840
"""
841841
image_meta = _get_image_meta_obj(image)
842842

843-
API._validate_flavor_image_mem_encryption(flavor, image_meta)
844-
845-
# validate PMU extra spec and image metadata
846-
flavor_pmu = flavor.extra_specs.get('hw:pmu')
847-
image_pmu = image_meta.properties.get('hw_pmu')
848-
if (flavor_pmu is not None and image_pmu is not None and
849-
image_pmu != strutils.bool_from_string(flavor_pmu)):
850-
raise exception.ImagePMUConflict()
851-
852843
# Only validate values of flavor/image so the return results of
853844
# following 'get' functions are not used.
845+
hardware.get_mem_encryption_constraint(flavor, image_meta)
846+
hardware.get_pmu_constraint(flavor, image_meta)
854847
hardware.get_number_of_serial_ports(flavor, image_meta)
855848
hardware.get_realtime_cpu_constraint(flavor, image_meta)
856849
hardware.get_cpu_topology_constraints(flavor, image_meta)
@@ -860,19 +853,6 @@ def _validate_flavor_image_numa_pci(
860853
if validate_pci:
861854
pci_request.get_pci_requests_from_flavor(flavor)
862855

863-
@staticmethod
864-
def _validate_flavor_image_mem_encryption(flavor, image):
865-
"""Validate that the flavor and image don't make contradictory
866-
requests regarding memory encryption.
867-
868-
:param flavor: Flavor object
869-
:param image: an ImageMeta object
870-
:raises: nova.exception.FlavorImageConflict
871-
"""
872-
# This library function will raise the exception for us if
873-
# necessary; if not, we can ignore the result returned.
874-
hardware.get_mem_encryption_constraint(flavor, image)
875-
876856
def _get_image_defined_bdms(self, flavor, image_meta, root_device_name):
877857
image_properties = image_meta.get('properties', {})
878858

nova/exception.py

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1869,11 +1869,6 @@ class ImageCPUThreadPolicyForbidden(Forbidden):
18691869
"override CPU thread pinning policy set against the flavor")
18701870

18711871

1872-
class ImagePMUConflict(Forbidden):
1873-
msg_fmt = _("Image property 'hw_pmu' is not permitted to "
1874-
"override the PMU policy set in the flavor")
1875-
1876-
18771872
class UnsupportedPolicyException(Invalid):
18781873
msg_fmt = _("ServerGroup policy is not supported: %(reason)s")
18791874

nova/tests/unit/compute/test_api.py

Lines changed: 0 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -7192,57 +7192,6 @@ def test__validate_numa_rebuild_alter_numa_toplogy(self):
71927192
self.compute_api._validate_numa_rebuild, instance,
71937193
image, flavor)
71947194

7195-
@mock.patch('nova.pci.request.get_pci_requests_from_flavor')
7196-
def test_pmu_image_and_flavor_conflict(self, mock_request):
7197-
"""Tests that calling _validate_flavor_image_nostatus()
7198-
with an image that conflicts with the flavor raises but no
7199-
exception is raised if there is no conflict.
7200-
"""
7201-
image = {'id': uuids.image_id, 'status': 'foo',
7202-
'properties': {'hw_pmu': False}}
7203-
flavor = objects.Flavor(
7204-
vcpus=1, memory_mb=512, root_gb=1, extra_specs={'hw:pmu': "true"})
7205-
self.assertRaises(
7206-
exception.ImagePMUConflict,
7207-
self.compute_api._validate_flavor_image_nostatus,
7208-
self.context, image, flavor, None)
7209-
7210-
@mock.patch('nova.pci.request.get_pci_requests_from_flavor')
7211-
def test_pmu_image_and_flavor_same_value(self, mock_request):
7212-
# assert that if both the image and flavor are set to the same value
7213-
# no exception is raised and the function returns nothing.
7214-
flavor = objects.Flavor(
7215-
vcpus=1, memory_mb=512, root_gb=1, extra_specs={'hw:pmu': "true"})
7216-
7217-
image = {'id': uuids.image_id, 'status': 'foo',
7218-
'properties': {'hw_pmu': True}}
7219-
self.assertIsNone(self.compute_api._validate_flavor_image_nostatus(
7220-
self.context, image, flavor, None))
7221-
7222-
@mock.patch('nova.pci.request.get_pci_requests_from_flavor')
7223-
def test_pmu_image_only(self, mock_request):
7224-
# assert that if only the image metadata is set then it is valid
7225-
flavor = objects.Flavor(
7226-
vcpus=1, memory_mb=512, root_gb=1, extra_specs={})
7227-
7228-
# ensure string to bool conversion works for image metadata
7229-
# property by using "yes".
7230-
image = {'id': uuids.image_id, 'status': 'foo',
7231-
'properties': {'hw_pmu': "yes"}}
7232-
self.assertIsNone(self.compute_api._validate_flavor_image_nostatus(
7233-
self.context, image, flavor, None))
7234-
7235-
@mock.patch('nova.pci.request.get_pci_requests_from_flavor')
7236-
def test_pmu_flavor_only(self, mock_request):
7237-
# assert that if only the flavor extra_spec is set then it is valid
7238-
# and test the string to bool conversion of "on" works.
7239-
flavor = objects.Flavor(
7240-
vcpus=1, memory_mb=512, root_gb=1, extra_specs={'hw:pmu': "on"})
7241-
7242-
image = {'id': uuids.image_id, 'status': 'foo', 'properties': {}}
7243-
self.assertIsNone(self.compute_api._validate_flavor_image_nostatus(
7244-
self.context, image, flavor, None))
7245-
72467195
@mock.patch('nova.pci.request.get_pci_requests_from_flavor')
72477196
def test_pci_validated(self, mock_request):
72487197
"""Tests that calling _validate_flavor_image_nostatus() with

nova/tests/unit/virt/test_hardware.py

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5452,6 +5452,56 @@ def test_get_pci_numa_policy_invalid(self):
54525452
image_meta.properties.hw_pci_numa_affinity_policy = "fake"
54535453

54545454

5455+
class PMUEnabledTest(test.NoDBTestCase):
5456+
5457+
def test_pmu_image_and_flavor_conflict(self):
5458+
"""Tests that calling _validate_flavor_image_nostatus()
5459+
with an image that conflicts with the flavor raises but no
5460+
exception is raised if there is no conflict.
5461+
"""
5462+
flavor = objects.Flavor(
5463+
name='foo', vcpus=1, memory_mb=512, root_gb=1,
5464+
extra_specs={'hw:pmu': "true"})
5465+
image_meta = objects.ImageMeta.from_dict({
5466+
'name': 'bar', 'properties': {'hw_pmu': False},
5467+
})
5468+
self.assertRaises(
5469+
exception.FlavorImageConflict,
5470+
hw.get_pmu_constraint,
5471+
flavor, image_meta)
5472+
5473+
def test_pmu_image_and_flavor_same_value(self):
5474+
# assert that if both the image and flavor are set to the same value
5475+
# no exception is raised and the function returns nothing.
5476+
flavor = objects.Flavor(
5477+
vcpus=1, memory_mb=512, root_gb=1, extra_specs={'hw:pmu': "true"})
5478+
image_meta = objects.ImageMeta.from_dict({
5479+
'properties': {'hw_pmu': True},
5480+
})
5481+
self.assertTrue(hw.get_pmu_constraint(flavor, image_meta))
5482+
5483+
def test_pmu_image_only(self):
5484+
# assert that if only the image metadata is set then it is valid
5485+
flavor = objects.Flavor(
5486+
vcpus=1, memory_mb=512, root_gb=1, extra_specs={})
5487+
5488+
# ensure string to bool conversion works for image metadata
5489+
# property by using "yes".
5490+
image_meta = objects.ImageMeta.from_dict({
5491+
'properties': {'hw_pmu': 'yes'},
5492+
})
5493+
self.assertTrue(hw.get_pmu_constraint(flavor, image_meta))
5494+
5495+
def test_pmu_flavor_only(self):
5496+
# assert that if only the flavor extra_spec is set then it is valid
5497+
# and test the string to bool conversion of "on" works.
5498+
flavor = objects.Flavor(
5499+
vcpus=1, memory_mb=512, root_gb=1, extra_specs={'hw:pmu': "on"})
5500+
5501+
image_meta = objects.ImageMeta.from_dict({'properties': {}})
5502+
self.assertTrue(hw.get_pmu_constraint(flavor, image_meta))
5503+
5504+
54555505
@ddt.ddt
54565506
class VIFMultiqueueEnabledTest(test.NoDBTestCase):
54575507

nova/virt/hardware.py

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1784,6 +1784,57 @@ def get_pci_numa_policy_constraint(
17841784
return policy
17851785

17861786

1787+
def get_pmu_constraint(
1788+
flavor: 'objects.Flavor',
1789+
image_meta: 'objects.ImageMeta',
1790+
) -> ty.Optional[bool]:
1791+
"""Validate and return the requested vPMU configuration.
1792+
1793+
This one's a little different since we don't return False in the default
1794+
case: the PMU should only be configured if explicit configuration is
1795+
provided, otherwise we leave it to the hypervisor.
1796+
1797+
:param flavor: ``nova.objects.Flavor`` instance
1798+
:param image_meta: ``nova.objects.ImageMeta`` instance
1799+
:raises: nova.exception.FlavorImageConflict if a value is specified in both
1800+
the flavor and the image, but the values do not match
1801+
:raises: nova.exception.Invalid if a value or combination of values is
1802+
invalid
1803+
:returns: True if the virtual Performance Monitoring Unit must be enabled,
1804+
False if it should be disabled, or None if unconfigured.
1805+
"""
1806+
flavor_value_str, image_value = _get_flavor_image_meta(
1807+
'pmu', flavor, image_meta)
1808+
1809+
flavor_value = None
1810+
if flavor_value_str is not None:
1811+
flavor_value = strutils.bool_from_string(flavor_value_str)
1812+
1813+
if (
1814+
image_value is not None and
1815+
flavor_value is not None and
1816+
image_value != flavor_value
1817+
):
1818+
msg = _(
1819+
"Flavor %(flavor_name)s has %(prefix)s:%(key)s extra spec "
1820+
"explicitly set to %(flavor_val)s, conflicting with image "
1821+
"%(image_name)s which has %(prefix)s_%(key)s explicitly set to "
1822+
"%(image_val)s."
1823+
)
1824+
raise exception.FlavorImageConflict(
1825+
msg % {
1826+
'prefix': 'hw',
1827+
'key': 'pmu',
1828+
'flavor_name': flavor.name,
1829+
'flavor_val': flavor_value,
1830+
'image_name': image_meta.name,
1831+
'image_val': image_value,
1832+
},
1833+
)
1834+
1835+
return flavor_value if flavor_value is not None else image_value
1836+
1837+
17871838
def get_vif_multiqueue_constraint(
17881839
flavor: 'objects.Flavor',
17891840
image_meta: 'objects.ImageMeta',

nova/virt/libvirt/driver.py

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5934,14 +5934,7 @@ def _set_features(self, guest, os_type, image_meta, flavor):
59345934
guest.features.append(
59355935
vconfig.LibvirtConfigGuestFeatureKvmHidden())
59365936

5937-
# NOTE(sean-k-mooney): we validate that the image and flavor
5938-
# cannot have conflicting values in the compute API
5939-
# so we just use the values directly. If it is not set in
5940-
# either the flavor or image pmu will be none and we should
5941-
# not generate the element to allow qemu to decide if a vPMU
5942-
# should be provided for backwards compatibility.
5943-
pmu = (flavor.extra_specs.get('hw:pmu') or
5944-
image_meta.properties.get('hw_pmu'))
5937+
pmu = hardware.get_pmu_constraint(flavor, image_meta)
59455938
if pmu is not None:
59465939
guest.features.append(
59475940
vconfig.LibvirtConfigGuestFeaturePMU(pmu))

0 commit comments

Comments
 (0)