virt: convert hardware module to use nova.objects.ImageMeta
Convert the APIs in the nova.virt.hardware module to expect to receive an instance of nova.objects.ImageMeta instead of a dict. Update the virt drivers to convert the dict into an ImageMeta module, as a stepping stone, until they to are converted to use ImageMeta throughout. Change-Id: Iac034d864cd0265759aaa7c8049fafa276763cc0
This commit is contained in:
parent
8a73c0430d
commit
36d37a670e
|
@ -851,8 +851,9 @@ class API(base.Base):
|
|||
block_device.properties_root_device_name(
|
||||
boot_meta.get('properties', {})))
|
||||
|
||||
image_meta = objects.ImageMeta.from_dict(boot_meta)
|
||||
numa_topology = hardware.numa_get_constraints(
|
||||
instance_type, boot_meta)
|
||||
instance_type, image_meta)
|
||||
|
||||
system_metadata = {}
|
||||
|
||||
|
|
|
@ -285,8 +285,9 @@ class MoveClaim(Claim):
|
|||
|
||||
@property
|
||||
def numa_topology(self):
|
||||
image_meta = objects.ImageMeta.from_dict(self.image_meta)
|
||||
return hardware.numa_get_constraints(
|
||||
self.instance_type, self.image_meta)
|
||||
self.instance_type, image_meta)
|
||||
|
||||
def _test_pci(self):
|
||||
pci_requests = objects.InstancePCIRequests.\
|
||||
|
|
|
@ -243,8 +243,11 @@ class ResourceTracker(object):
|
|||
instance_type = self._get_instance_type(ctxt, instance, prefix)
|
||||
|
||||
if image_meta is None:
|
||||
image_meta = utils.get_image_from_system_metadata(
|
||||
instance['system_metadata'])
|
||||
image_meta = objects.ImageMeta.from_instance(instance)
|
||||
# TODO(jaypipes): Remove when image_meta is always passed
|
||||
# as an objects.ImageMeta
|
||||
elif not isinstance(image_meta, objects.ImageMeta):
|
||||
image_meta = objects.ImageMeta.from_dict(image_meta)
|
||||
|
||||
if (instance_type is not None and
|
||||
instance_type.id == itype['id']):
|
||||
|
@ -661,8 +664,11 @@ class ResourceTracker(object):
|
|||
migration.old_instance_type_id)
|
||||
|
||||
if image_meta is None:
|
||||
image_meta = utils.get_image_from_system_metadata(
|
||||
instance['system_metadata'])
|
||||
image_meta = objects.ImageMeta.from_instance(instance)
|
||||
# TODO(jaypipes): Remove when image_meta is always passed
|
||||
# as an objects.ImageMeta
|
||||
elif not isinstance(image_meta, objects.ImageMeta):
|
||||
image_meta = objects.ImageMeta.from_dict(image_meta)
|
||||
|
||||
if itype:
|
||||
host_topology = self.compute_node.get('numa_topology')
|
||||
|
|
|
@ -219,7 +219,7 @@ class BaseTestCase(test.TestCase):
|
|||
|
||||
def fake_show(meh, context, id, **kwargs):
|
||||
if id:
|
||||
return {'id': id, 'min_disk': None, 'min_ram': None,
|
||||
return {'id': id,
|
||||
'name': 'fake_name',
|
||||
'status': 'active',
|
||||
'properties': {'kernel_id': 'fake_kernel_id',
|
||||
|
@ -7506,15 +7506,6 @@ class ComputeAPITestCase(BaseTestCase):
|
|||
@mock.patch('nova.virt.hardware.numa_get_constraints')
|
||||
def test_create_with_numa_topology(self, numa_constraints_mock):
|
||||
inst_type = flavors.get_default_flavor()
|
||||
# This is what the stubbed out method will return
|
||||
fake_image_props = {'status': 'active',
|
||||
'name': 'fake_name',
|
||||
'min_ram': None,
|
||||
'id': 1,
|
||||
'min_disk': None,
|
||||
'properties': {'kernel_id': 'fake_kernel_id',
|
||||
'something_else': 'meow',
|
||||
'ramdisk_id': 'fake_ramdisk_id'}}
|
||||
|
||||
numa_topology = objects.InstanceNUMATopology(
|
||||
cells=[objects.InstanceNUMACell(
|
||||
|
@ -7527,7 +7518,7 @@ class ComputeAPITestCase(BaseTestCase):
|
|||
self.fake_image['id'])
|
||||
|
||||
numa_constraints_mock.assert_called_once_with(
|
||||
inst_type, fake_image_props)
|
||||
inst_type, test.MatchType(objects.ImageMeta))
|
||||
self.assertEqual(
|
||||
numa_topology.cells[0].obj_to_primitive(),
|
||||
instances[0].numa_topology.cells[0].obj_to_primitive())
|
||||
|
|
|
@ -79,8 +79,8 @@ class _FakeImageService(object):
|
|||
'deleted': False,
|
||||
'status': 'active',
|
||||
'is_public': True,
|
||||
'container_format': None,
|
||||
'disk_format': None,
|
||||
'container_format': 'bare',
|
||||
'disk_format': 'raw',
|
||||
'size': '83594576',
|
||||
'properties': {'kernel_id': CONF.null_kernel,
|
||||
'ramdisk_id': CONF.null_kernel}}
|
||||
|
|
|
@ -2541,21 +2541,6 @@ class LibvirtConnTestCase(test.NoDBTestCase):
|
|||
self.assertEqual("tcp", cfg.devices[3].type)
|
||||
self.assertEqual("tcp", cfg.devices[4].type)
|
||||
|
||||
def test_get_guest_config_serial_console_invalid_img_meta(self):
|
||||
self.flags(enabled=True, group='serial_console')
|
||||
|
||||
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), True)
|
||||
instance_ref = objects.Instance(**self.test_instance)
|
||||
image_meta = {}
|
||||
|
||||
disk_info = blockinfo.get_disk_info(CONF.libvirt.virt_type,
|
||||
instance_ref,
|
||||
image_meta)
|
||||
image_meta = {"properties": {"hw_serial_port_count": "fail"}}
|
||||
self.assertRaises(
|
||||
exception.ImageSerialPortNumberInvalid,
|
||||
drvr._get_guest_config, instance_ref, [], image_meta, disk_info)
|
||||
|
||||
@mock.patch('nova.console.serial.acquire_port')
|
||||
def test_get_guest_config_serial_console_through_port_rng_exhausted(
|
||||
self, acquire_port):
|
||||
|
@ -2823,24 +2808,6 @@ class LibvirtConnTestCase(test.NoDBTestCase):
|
|||
self.assertEqual(cfg.devices[6].type, "vnc")
|
||||
self.assertEqual(cfg.devices[7].type, "spice")
|
||||
|
||||
def test_invalid_watchdog_action(self):
|
||||
self.flags(virt_type='kvm', group='libvirt')
|
||||
|
||||
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), True)
|
||||
instance_ref = objects.Instance(**self.test_instance)
|
||||
image_meta = {}
|
||||
|
||||
disk_info = blockinfo.get_disk_info(CONF.libvirt.virt_type,
|
||||
instance_ref,
|
||||
image_meta)
|
||||
image_meta = {"properties": {"hw_watchdog_action": "something"}}
|
||||
self.assertRaises(exception.InvalidWatchdogAction,
|
||||
drvr._get_guest_config,
|
||||
instance_ref,
|
||||
[],
|
||||
image_meta,
|
||||
disk_info)
|
||||
|
||||
def test_get_guest_config_with_watchdog_action_image_meta(self):
|
||||
self.flags(virt_type='kvm', group='libvirt')
|
||||
|
||||
|
@ -2993,24 +2960,6 @@ class LibvirtConnTestCase(test.NoDBTestCase):
|
|||
|
||||
self.assertEqual("pause", cfg.devices[7].action)
|
||||
|
||||
def test_unsupported_video_driver_through_image_meta(self):
|
||||
self.flags(virt_type='kvm', group='libvirt')
|
||||
|
||||
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), True)
|
||||
instance_ref = objects.Instance(**self.test_instance)
|
||||
image_meta = {}
|
||||
|
||||
disk_info = blockinfo.get_disk_info(CONF.libvirt.virt_type,
|
||||
instance_ref,
|
||||
image_meta)
|
||||
image_meta = {"properties": {"hw_video_model": "something"}}
|
||||
self.assertRaises(exception.InvalidVideoMode,
|
||||
drvr._get_guest_config,
|
||||
instance_ref,
|
||||
[],
|
||||
image_meta,
|
||||
disk_info)
|
||||
|
||||
def test_get_guest_config_with_video_driver_image_meta(self):
|
||||
self.flags(virt_type='kvm', group='libvirt')
|
||||
|
||||
|
@ -3762,12 +3711,6 @@ class LibvirtConnTestCase(test.NoDBTestCase):
|
|||
image_meta, disk_info)
|
||||
self.assertNotEqual(cfg.os_cmdline, "")
|
||||
|
||||
image_meta = {"properties": {"os_command_line": None}}
|
||||
cfg = drvr._get_guest_config(instance_ref,
|
||||
_fake_network_info(self.stubs, 1),
|
||||
image_meta, disk_info)
|
||||
self.assertIsNotNone(cfg.os_cmdline)
|
||||
|
||||
def test_get_guest_config_armv7(self):
|
||||
def get_host_capabilities_stub(self):
|
||||
cpu = vconfig.LibvirtConfigGuestCPU()
|
||||
|
|
|
@ -356,11 +356,11 @@ class VCPUTopologyTest(test.NoDBTestCase):
|
|||
]
|
||||
|
||||
for topo_test in testdata:
|
||||
image_meta = objects.ImageMeta.from_dict(topo_test["image"])
|
||||
if type(topo_test["expect"]) == tuple:
|
||||
(preferred,
|
||||
maximum) = hw._get_cpu_topology_constraints(
|
||||
topo_test["flavor"],
|
||||
topo_test["image"])
|
||||
topo_test["flavor"], image_meta)
|
||||
|
||||
self.assertEqual(topo_test["expect"][0], preferred.sockets)
|
||||
self.assertEqual(topo_test["expect"][1], preferred.cores)
|
||||
|
@ -372,7 +372,7 @@ class VCPUTopologyTest(test.NoDBTestCase):
|
|||
self.assertRaises(topo_test["expect"],
|
||||
hw._get_cpu_topology_constraints,
|
||||
topo_test["flavor"],
|
||||
topo_test["image"])
|
||||
image_meta)
|
||||
|
||||
def test_possible_topologies(self):
|
||||
testdata = [
|
||||
|
@ -797,9 +797,10 @@ class VCPUTopologyTest(test.NoDBTestCase):
|
|||
]
|
||||
|
||||
for topo_test in testdata:
|
||||
image_meta = objects.ImageMeta.from_dict(topo_test["image"])
|
||||
topology = hw._get_desirable_cpu_topologies(
|
||||
topo_test["flavor"],
|
||||
topo_test["image"],
|
||||
image_meta,
|
||||
topo_test["allow_threads"],
|
||||
topo_test.get("numa_topology"))[0]
|
||||
|
||||
|
@ -878,6 +879,30 @@ class NUMATopologyTest(test.NoDBTestCase):
|
|||
id=2, cpuset=set([5, 7]), memory=512)
|
||||
]),
|
||||
},
|
||||
{
|
||||
"flavor": objects.Flavor(vcpus=8, memory_mb=2048, extra_specs={
|
||||
}),
|
||||
"image": {
|
||||
"properties": {
|
||||
"hw_numa_nodes": 3,
|
||||
"hw_numa_cpus.0": "0-3",
|
||||
"hw_numa_mem.0": "1024",
|
||||
"hw_numa_cpus.1": "4,6",
|
||||
"hw_numa_mem.1": "512",
|
||||
"hw_numa_cpus.2": "5,7",
|
||||
"hw_numa_mem.2": "512",
|
||||
},
|
||||
},
|
||||
"expect": objects.InstanceNUMATopology(cells=
|
||||
[
|
||||
objects.InstanceNUMACell(
|
||||
id=0, cpuset=set([0, 1, 2, 3]), memory=1024),
|
||||
objects.InstanceNUMACell(
|
||||
id=1, cpuset=set([4, 6]), memory=512),
|
||||
objects.InstanceNUMACell(
|
||||
id=2, cpuset=set([5, 7]), memory=512)
|
||||
]),
|
||||
},
|
||||
{
|
||||
# Request a CPU that is out of range
|
||||
# wrt vCPU count
|
||||
|
@ -1062,18 +1087,20 @@ class NUMATopologyTest(test.NoDBTestCase):
|
|||
]
|
||||
|
||||
for testitem in testdata:
|
||||
image_meta = objects.ImageMeta.from_dict(testitem["image"])
|
||||
if testitem["expect"] is None:
|
||||
topology = hw.numa_get_constraints(
|
||||
testitem["flavor"], testitem["image"])
|
||||
testitem["flavor"], image_meta)
|
||||
self.assertIsNone(topology)
|
||||
elif type(testitem["expect"]) == type:
|
||||
self.assertRaises(testitem["expect"],
|
||||
hw.numa_get_constraints,
|
||||
testitem["flavor"],
|
||||
testitem["image"])
|
||||
image_meta)
|
||||
else:
|
||||
topology = hw.numa_get_constraints(
|
||||
testitem["flavor"], testitem["image"])
|
||||
testitem["flavor"], image_meta)
|
||||
self.assertIsNotNone(topology)
|
||||
self.assertEqual(len(testitem["expect"].cells),
|
||||
len(topology.cells))
|
||||
for i in range(len(topology.cells)):
|
||||
|
@ -1480,26 +1507,21 @@ class NumberOfSerialPortsTest(test.NoDBTestCase):
|
|||
def test_flavor(self):
|
||||
flavor = objects.Flavor(vcpus=8, memory_mb=2048,
|
||||
extra_specs={"hw:serial_port_count": 3})
|
||||
num_ports = hw.get_number_of_serial_ports(flavor, None)
|
||||
image_meta = objects.ImageMeta.from_dict({})
|
||||
num_ports = hw.get_number_of_serial_ports(flavor, image_meta)
|
||||
self.assertEqual(3, num_ports)
|
||||
|
||||
def test_image_meta(self):
|
||||
flavor = objects.Flavor(vcpus=8, memory_mb=2048, extra_specs={})
|
||||
image_meta = {"properties": {"hw_serial_port_count": 2}}
|
||||
image_meta = objects.ImageMeta.from_dict(
|
||||
{"properties": {"hw_serial_port_count": 2}})
|
||||
num_ports = hw.get_number_of_serial_ports(flavor, image_meta)
|
||||
self.assertEqual(2, num_ports)
|
||||
|
||||
def test_flavor_invalid_value(self):
|
||||
flavor = objects.Flavor(vcpus=8, memory_mb=2048,
|
||||
extra_specs={"hw:serial_port_count": 'foo'})
|
||||
image_meta = {"properties": {}}
|
||||
self.assertRaises(exception.ImageSerialPortNumberInvalid,
|
||||
hw.get_number_of_serial_ports,
|
||||
flavor, image_meta)
|
||||
|
||||
def test_image_meta_invalid_value(self):
|
||||
flavor = objects.Flavor(vcpus=8, memory_mb=2048, extra_specs={})
|
||||
image_meta = {"properties": {"hw_serial_port_count": 'bar'}}
|
||||
image_meta = objects.ImageMeta.from_dict({})
|
||||
self.assertRaises(exception.ImageSerialPortNumberInvalid,
|
||||
hw.get_number_of_serial_ports,
|
||||
flavor, image_meta)
|
||||
|
@ -1507,14 +1529,16 @@ class NumberOfSerialPortsTest(test.NoDBTestCase):
|
|||
def test_image_meta_smaller_than_flavor(self):
|
||||
flavor = objects.Flavor(vcpus=8, memory_mb=2048,
|
||||
extra_specs={"hw:serial_port_count": 3})
|
||||
image_meta = {"properties": {"hw_serial_port_count": 2}}
|
||||
image_meta = objects.ImageMeta.from_dict(
|
||||
{"properties": {"hw_serial_port_count": 2}})
|
||||
num_ports = hw.get_number_of_serial_ports(flavor, image_meta)
|
||||
self.assertEqual(2, num_ports)
|
||||
|
||||
def test_flavor_smaller_than_image_meta(self):
|
||||
flavor = objects.Flavor(vcpus=8, memory_mb=2048,
|
||||
extra_specs={"hw:serial_port_count": 3})
|
||||
image_meta = {"properties": {"hw_serial_port_count": 4}}
|
||||
image_meta = objects.ImageMeta.from_dict(
|
||||
{"properties": {"hw_serial_port_count": 4}})
|
||||
self.assertRaises(exception.ImageSerialPortNumberExceedFlavorValue,
|
||||
hw.get_number_of_serial_ports,
|
||||
flavor, image_meta)
|
||||
|
@ -1707,7 +1731,7 @@ class VirtMemoryPagesTestCase(test.NoDBTestCase):
|
|||
def _test_get_requested_mempages_pagesize(self, spec=None, props=None):
|
||||
flavor = objects.Flavor(vcpus=16, memory_mb=2048,
|
||||
extra_specs=spec or {})
|
||||
image_meta = {"properties": props or {}}
|
||||
image_meta = objects.ImageMeta.from_dict({"properties": props or {}})
|
||||
return hw._numa_get_pagesize_constraints(flavor, image_meta)
|
||||
|
||||
def test_get_requested_mempages_pagesize_from_flavor_swipe(self):
|
||||
|
|
|
@ -153,7 +153,7 @@ def get_number_of_serial_ports(flavor, image_meta):
|
|||
"""Get the number of serial consoles from the flavor or image
|
||||
|
||||
:param flavor: Flavor object to read extra specs from
|
||||
:param image_meta: Image object to read image metadata from
|
||||
:param image_meta: nova.objects.ImageMeta object instance
|
||||
|
||||
If flavor extra specs is not set, then any image meta value is permitted.
|
||||
If flavour extra specs *is* set, then this provides the default serial
|
||||
|
@ -182,10 +182,8 @@ def get_number_of_serial_ports(flavor, image_meta):
|
|||
num_ports=num_ports, property=property)
|
||||
return num_ports
|
||||
|
||||
image_meta_prop = (image_meta or {}).get('properties', {})
|
||||
|
||||
flavor_num_ports = get_number(flavor.extra_specs, "hw:serial_port_count")
|
||||
image_num_ports = get_number(image_meta_prop, "hw_serial_port_count")
|
||||
image_num_ports = image_meta.properties.get("hw_serial_port_count", None)
|
||||
|
||||
if (flavor_num_ports and image_num_ports) is not None:
|
||||
if image_num_ports > flavor_num_ports:
|
||||
|
@ -254,7 +252,7 @@ def _get_cpu_topology_constraints(flavor, image_meta):
|
|||
"""Get the topology constraints declared in flavor or image
|
||||
|
||||
:param flavor: Flavor object to read extra specs from
|
||||
:param image_meta: Image object to read image metadata from
|
||||
:param image_meta: nova.objects.ImageMeta object instance
|
||||
|
||||
Gets the topology constraints from the configuration defined
|
||||
in the flavor extra specs or the image metadata. In the flavor
|
||||
|
@ -309,12 +307,10 @@ def _get_cpu_topology_constraints(flavor, image_meta):
|
|||
"threads": flvmaxthreads})
|
||||
|
||||
# Get any customized limits from the image
|
||||
maxsockets = int(image_meta.get("properties", {})
|
||||
.get("hw_cpu_max_sockets", flvmaxsockets))
|
||||
maxcores = int(image_meta.get("properties", {})
|
||||
.get("hw_cpu_max_cores", flvmaxcores))
|
||||
maxthreads = int(image_meta.get("properties", {})
|
||||
.get("hw_cpu_max_threads", flvmaxthreads))
|
||||
props = image_meta.properties
|
||||
maxsockets = props.get("hw_cpu_max_sockets", flvmaxsockets)
|
||||
maxcores = props.get("hw_cpu_max_cores", flvmaxcores)
|
||||
maxthreads = props.get("hw_cpu_max_threads", flvmaxthreads)
|
||||
|
||||
LOG.debug("Image limits %(sockets)d:%(cores)d:%(threads)d",
|
||||
{"sockets": maxsockets,
|
||||
|
@ -354,12 +350,9 @@ def _get_cpu_topology_constraints(flavor, image_meta):
|
|||
|
||||
# Finally see if the image has provided a preferred
|
||||
# topology to use
|
||||
sockets = int(image_meta.get("properties", {})
|
||||
.get("hw_cpu_sockets", -1))
|
||||
cores = int(image_meta.get("properties", {})
|
||||
.get("hw_cpu_cores", -1))
|
||||
threads = int(image_meta.get("properties", {})
|
||||
.get("hw_cpu_threads", -1))
|
||||
sockets = props.get("hw_cpu_sockets", -1)
|
||||
cores = props.get("hw_cpu_cores", -1)
|
||||
threads = props.get("hw_cpu_threads", -1)
|
||||
|
||||
LOG.debug("Image pref %(sockets)d:%(cores)d:%(threads)d",
|
||||
{"sockets": sockets,
|
||||
|
@ -550,7 +543,7 @@ def _get_desirable_cpu_topologies(flavor, image_meta, allow_threads=True,
|
|||
"""Get desired CPU topologies according to settings
|
||||
|
||||
:param flavor: Flavor object to query extra specs from
|
||||
:param image_meta: ImageMeta object to query properties from
|
||||
:param image_meta: nova.objects.ImageMeta object instance
|
||||
:param allow_threads: if the hypervisor supports CPU threads
|
||||
:param numa_topology: InstanceNUMATopology object that may contain
|
||||
additional topology constraints (such as threading
|
||||
|
@ -610,7 +603,7 @@ def get_best_cpu_topology(flavor, image_meta, allow_threads=True,
|
|||
"""Get best CPU topology according to settings
|
||||
|
||||
:param flavor: Flavor object to query extra specs from
|
||||
:param image_meta: ImageMeta object to query properties from
|
||||
:param image_meta: nova.objects.ImageMeta object instance
|
||||
:param allow_threads: if the hypervisor supports CPU threads
|
||||
:param numa_topology: InstanceNUMATopology object that may contain
|
||||
additional topology constraints (such as threading
|
||||
|
@ -805,32 +798,11 @@ def _numa_fit_instance_cell(host_cell, instance_cell, limit_cell=None):
|
|||
return instance_cell
|
||||
|
||||
|
||||
def _numa_get_flavor_or_image_prop(flavor, image_meta, propname):
|
||||
"""Return the value of propname from flavor or image
|
||||
|
||||
:param flavor: a Flavor object or dict of instance type information
|
||||
:param image_meta: a dict of image information
|
||||
|
||||
:returns: a value or None
|
||||
"""
|
||||
flavor_val = flavor.get('extra_specs', {}).get("hw:" + propname)
|
||||
image_val = (image_meta or {}).get("properties", {}).get("hw_" + propname)
|
||||
|
||||
if flavor_val is not None:
|
||||
if image_val is not None:
|
||||
raise exception.ImageNUMATopologyForbidden(
|
||||
name='hw_' + propname)
|
||||
|
||||
return flavor_val
|
||||
else:
|
||||
return image_val
|
||||
|
||||
|
||||
def _numa_get_pagesize_constraints(flavor, image_meta):
|
||||
"""Return the requested memory page size
|
||||
|
||||
:param flavor: a Flavor object to read extra specs from
|
||||
:param image_meta: an Image object to read meta data from
|
||||
:param image_meta: nova.objects.ImageMeta object instance
|
||||
|
||||
:raises: MemoryPagesSizeInvalid or MemoryPageSizeForbidden
|
||||
:returns: a page size requested or MEMPAGES_*
|
||||
|
@ -854,10 +826,8 @@ def _numa_get_pagesize_constraints(flavor, image_meta):
|
|||
|
||||
return request
|
||||
|
||||
image_meta_prop = (image_meta or {}).get("properties", {})
|
||||
|
||||
flavor_request = flavor.get('extra_specs', {}).get("hw:mem_page_size", "")
|
||||
image_request = image_meta_prop.get("hw_mem_page_size", "")
|
||||
image_request = image_meta.properties.get("hw_mem_page_size", "")
|
||||
|
||||
if not flavor_request and image_request:
|
||||
raise exception.MemoryPageSizeForbidden(
|
||||
|
@ -880,25 +850,72 @@ def _numa_get_pagesize_constraints(flavor, image_meta):
|
|||
return pagesize
|
||||
|
||||
|
||||
def _numa_get_constraints_manual(nodes, flavor, image_meta):
|
||||
def _numa_get_flavor_cpu_map_list(flavor):
|
||||
hw_numa_cpus = []
|
||||
hw_numa_cpus_set = False
|
||||
extra_specs = flavor.get("extra_specs", {})
|
||||
for cellid in range(objects.ImageMetaProps.NUMA_NODES_MAX):
|
||||
cpuprop = "hw:numa_cpus.%d" % cellid
|
||||
if cpuprop not in extra_specs:
|
||||
break
|
||||
hw_numa_cpus.append(
|
||||
parse_cpu_spec(extra_specs[cpuprop]))
|
||||
hw_numa_cpus_set = True
|
||||
|
||||
if hw_numa_cpus_set:
|
||||
return hw_numa_cpus
|
||||
|
||||
|
||||
def _numa_get_cpu_map_list(flavor, image_meta):
|
||||
flavor_cpu_list = _numa_get_flavor_cpu_map_list(flavor)
|
||||
image_cpu_list = image_meta.properties.get("hw_numa_cpus", None)
|
||||
|
||||
if flavor_cpu_list is None:
|
||||
return image_cpu_list
|
||||
else:
|
||||
if image_cpu_list is not None:
|
||||
raise exception.ImageNUMATopologyForbidden(
|
||||
name='hw_numa_cpus')
|
||||
return flavor_cpu_list
|
||||
|
||||
|
||||
def _numa_get_flavor_mem_map_list(flavor):
|
||||
hw_numa_mem = []
|
||||
hw_numa_mem_set = False
|
||||
extra_specs = flavor.get("extra_specs", {})
|
||||
for cellid in range(objects.ImageMetaProps.NUMA_NODES_MAX):
|
||||
memprop = "hw:numa_mem.%d" % cellid
|
||||
if memprop not in extra_specs:
|
||||
break
|
||||
hw_numa_mem.append(int(extra_specs[memprop]))
|
||||
hw_numa_mem_set = True
|
||||
|
||||
if hw_numa_mem_set:
|
||||
return hw_numa_mem
|
||||
|
||||
|
||||
def _numa_get_mem_map_list(flavor, image_meta):
|
||||
flavor_mem_list = _numa_get_flavor_mem_map_list(flavor)
|
||||
image_mem_list = image_meta.properties.get("hw_numa_mem", None)
|
||||
|
||||
if flavor_mem_list is None:
|
||||
return image_mem_list
|
||||
else:
|
||||
if image_mem_list is not None:
|
||||
raise exception.ImageNUMATopologyForbidden(
|
||||
name='hw_numa_mem')
|
||||
return flavor_mem_list
|
||||
|
||||
|
||||
def _numa_get_constraints_manual(nodes, flavor, cpu_list, mem_list):
|
||||
cells = []
|
||||
totalmem = 0
|
||||
|
||||
availcpus = set(range(flavor.vcpus))
|
||||
|
||||
for node in range(nodes):
|
||||
cpus = _numa_get_flavor_or_image_prop(
|
||||
flavor, image_meta, "numa_cpus.%d" % node)
|
||||
mem = _numa_get_flavor_or_image_prop(
|
||||
flavor, image_meta, "numa_mem.%d" % node)
|
||||
|
||||
# We're expecting both properties set, so
|
||||
# raise an error if either is missing
|
||||
if cpus is None or mem is None:
|
||||
raise exception.ImageNUMATopologyIncomplete()
|
||||
|
||||
mem = int(mem)
|
||||
cpuset = parse_cpu_spec(cpus)
|
||||
mem = mem_list[node]
|
||||
cpuset = cpu_list[node]
|
||||
|
||||
for cpu in cpuset:
|
||||
if cpu > (flavor.vcpus - 1):
|
||||
|
@ -927,23 +944,13 @@ def _numa_get_constraints_manual(nodes, flavor, image_meta):
|
|||
return objects.InstanceNUMATopology(cells=cells)
|
||||
|
||||
|
||||
def _numa_get_constraints_auto(nodes, flavor, image_meta):
|
||||
def _numa_get_constraints_auto(nodes, flavor):
|
||||
if ((flavor.vcpus % nodes) > 0 or
|
||||
(flavor.memory_mb % nodes) > 0):
|
||||
raise exception.ImageNUMATopologyAsymmetric()
|
||||
|
||||
cells = []
|
||||
for node in range(nodes):
|
||||
cpus = _numa_get_flavor_or_image_prop(
|
||||
flavor, image_meta, "numa_cpus.%d" % node)
|
||||
mem = _numa_get_flavor_or_image_prop(
|
||||
flavor, image_meta, "numa_mem.%d" % node)
|
||||
|
||||
# We're not expecting any properties set, so
|
||||
# raise an error if there are any
|
||||
if cpus is not None or mem is not None:
|
||||
raise exception.ImageNUMATopologyIncomplete()
|
||||
|
||||
ncpus = int(flavor.vcpus / nodes)
|
||||
mem = int(flavor.memory_mb / nodes)
|
||||
start = node * ncpus
|
||||
|
@ -957,7 +964,7 @@ def _numa_get_constraints_auto(nodes, flavor, image_meta):
|
|||
|
||||
def _add_cpu_pinning_constraint(flavor, image_meta, numa_topology):
|
||||
flavor_pinning = flavor.get('extra_specs', {}).get("hw:cpu_policy")
|
||||
image_pinning = image_meta.get('properties', {}).get("hw_cpu_policy")
|
||||
image_pinning = image_meta.properties.get("hw_cpu_policy")
|
||||
if flavor_pinning == "dedicated":
|
||||
requested = True
|
||||
elif flavor_pinning == "shared":
|
||||
|
@ -991,30 +998,52 @@ def numa_get_constraints(flavor, image_meta):
|
|||
"""Return topology related to input request
|
||||
|
||||
:param flavor: Flavor object to read extra specs from
|
||||
:param image_meta: Image object to read image metadata from
|
||||
:param image_meta: nova.objects.ImageMeta object instance
|
||||
|
||||
May raise exception.ImageNUMATopologyIncomplete() if the
|
||||
image properties are not correctly specified, or
|
||||
exception.ImageNUMATopologyForbidden if an attempt is
|
||||
made to override flavor settings with image properties.
|
||||
|
||||
:returns: InstanceNUMATopology or None
|
||||
"""
|
||||
nodes = _numa_get_flavor_or_image_prop(
|
||||
flavor, image_meta, "numa_nodes")
|
||||
|
||||
nodes = flavor.get('extra_specs', {}).get("hw:numa_nodes")
|
||||
props = image_meta.properties
|
||||
if nodes is not None:
|
||||
if props.obj_attr_is_set("hw_numa_nodes"):
|
||||
raise exception.ImageNUMATopologyForbidden(
|
||||
name='hw_numa_nodes')
|
||||
nodes = int(nodes)
|
||||
else:
|
||||
nodes = props.get("hw_numa_nodes")
|
||||
|
||||
pagesize = _numa_get_pagesize_constraints(
|
||||
flavor, image_meta)
|
||||
|
||||
numa_topology = None
|
||||
if nodes or pagesize:
|
||||
nodes = nodes and int(nodes) or 1
|
||||
# We'll pick what path to go down based on whether
|
||||
# anything is set for the first node. Both paths
|
||||
# have logic to cope with inconsistent property usage
|
||||
auto = _numa_get_flavor_or_image_prop(
|
||||
flavor, image_meta, "numa_cpus.0") is None
|
||||
nodes = nodes or 1
|
||||
|
||||
if auto:
|
||||
cpu_list = _numa_get_cpu_map_list(flavor, image_meta)
|
||||
mem_list = _numa_get_mem_map_list(flavor, image_meta)
|
||||
|
||||
# If one property list is specified both must be
|
||||
if ((cpu_list is None and mem_list is not None) or
|
||||
(cpu_list is not None and mem_list is None)):
|
||||
raise exception.ImageNUMATopologyIncomplete()
|
||||
|
||||
# If any node has data set, all nodes must have data set
|
||||
if ((cpu_list is not None and len(cpu_list) != nodes) or
|
||||
(mem_list is not None and len(mem_list) != nodes)):
|
||||
raise exception.ImageNUMATopologyIncomplete()
|
||||
|
||||
if cpu_list is None:
|
||||
numa_topology = _numa_get_constraints_auto(
|
||||
nodes, flavor, image_meta)
|
||||
nodes, flavor)
|
||||
else:
|
||||
numa_topology = _numa_get_constraints_manual(
|
||||
nodes, flavor, image_meta)
|
||||
nodes, flavor, cpu_list, mem_list)
|
||||
|
||||
# We currently support same pagesize for all cells.
|
||||
[setattr(c, 'pagesize', pagesize) for c in numa_topology.cells]
|
||||
|
|
|
@ -3090,15 +3090,19 @@ class LibvirtDriver(driver.ComputeDriver):
|
|||
|
||||
return cpu
|
||||
|
||||
def _get_guest_cpu_config(self, flavor, image,
|
||||
def _get_guest_cpu_config(self, flavor, image_meta,
|
||||
guest_cpu_numa_config, instance_numa_topology):
|
||||
cpu = self._get_guest_cpu_model_config()
|
||||
|
||||
if cpu is None:
|
||||
return None
|
||||
|
||||
# TODO(jaypipes): Remove when image_meta is always passed
|
||||
# as an objects.ImageMeta
|
||||
if not isinstance(image_meta, objects.ImageMeta):
|
||||
image_meta = objects.ImageMeta.from_dict(image_meta)
|
||||
topology = hardware.get_best_cpu_topology(
|
||||
flavor, image, numa_topology=instance_numa_topology)
|
||||
flavor, image_meta, numa_topology=instance_numa_topology)
|
||||
|
||||
cpu.sockets = topology.sockets
|
||||
cpu.cores = topology.cores
|
||||
|
@ -3689,6 +3693,10 @@ class LibvirtDriver(driver.ComputeDriver):
|
|||
guest_arch = libvirt_utils.get_arch(image_meta)
|
||||
|
||||
if CONF.serial_console.enabled:
|
||||
# TODO(jaypipes): Remove when image_meta is always passed
|
||||
# as an objects.ImageMeta
|
||||
if not isinstance(image_meta, objects.ImageMeta):
|
||||
image_meta = objects.ImageMeta.from_dict(image_meta)
|
||||
num_ports = hardware.get_number_of_serial_ports(
|
||||
flavor, image_meta)
|
||||
for port in six.moves.range(num_ports):
|
||||
|
|
Loading…
Reference in New Issue