Consider instance flavor resource overrides in allocations
This makes the scheduler reporting client consider resource overrides stored in instance flavors when making allocations against placement. This should ensure that compute nodes and scheduler calculate the same allocations for resource overrides, and will mean that ironic computes will start allocating custom resource amounts after existing instances have their flavors healed. Related to blueprint custom-resource-classes-in-flavors Change-Id: Ib1b05e33e2a2f4ed1c3f8949df19d1c0f48ae07f
This commit is contained in:
parent
430ec6504b
commit
a22ae8baa2
|
@ -158,6 +158,25 @@ def _instance_to_allocations_dict(instance):
|
|||
VCPU: instance.flavor.vcpus,
|
||||
DISK_GB: disk,
|
||||
}
|
||||
|
||||
# Pull out any resource overrides, which are in the format
|
||||
# "resources:FOO" and generate a dict of FOO=value candidates
|
||||
# for overriding the resources in the allocation.
|
||||
overrides = {k.split(':', 1)[1]: v for k, v in
|
||||
instance.flavor.extra_specs.items()
|
||||
if k.startswith('resources:')}
|
||||
|
||||
# Any resource overrides which are properly namespaced as custom,
|
||||
# or are standard resource class values override the alloc_dict
|
||||
# already constructed from the base flavor values above. Since
|
||||
# extra_specs are string values and resource counts are always
|
||||
# integers, we convert them here too for any that we find.
|
||||
overrides = {k: int(v) for k, v in overrides.items()
|
||||
if (k.startswith(objects.ResourceClass.CUSTOM_NAMESPACE) or
|
||||
k in fields.ResourceClass.STANDARD)}
|
||||
|
||||
alloc_dict.update(overrides)
|
||||
|
||||
# Remove any zero allocations.
|
||||
return {key: val for key, val in alloc_dict.items() if val}
|
||||
|
||||
|
|
|
@ -82,7 +82,8 @@ class SchedulerReportClientTests(test.TestCase):
|
|||
swap=1,
|
||||
ephemeral_gb=100,
|
||||
memory_mb=1024,
|
||||
vcpus=2))
|
||||
vcpus=2,
|
||||
extra_specs={}))
|
||||
|
||||
@mock.patch('nova.compute.utils.is_volume_backed_instance',
|
||||
return_value=False)
|
||||
|
|
|
@ -49,7 +49,8 @@ class IronicResourceTrackerTest(test.TestCase):
|
|||
root_gb=1024,
|
||||
swap=0,
|
||||
ephemeral_gb=0,
|
||||
),
|
||||
extra_specs={},
|
||||
),
|
||||
'CUSTOM_BIG_IRON': objects.Flavor(
|
||||
name='CUSTOM_BIG_IRON',
|
||||
flavorid=43,
|
||||
|
@ -58,6 +59,7 @@ class IronicResourceTrackerTest(test.TestCase):
|
|||
root_gb=1024,
|
||||
swap=0,
|
||||
ephemeral_gb=0,
|
||||
extra_specs={},
|
||||
),
|
||||
}
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@ import nova.conf
|
|||
from nova import context
|
||||
from nova import exception
|
||||
from nova import objects
|
||||
from nova.objects import fields
|
||||
from nova.scheduler.client import report
|
||||
from nova import test
|
||||
from nova.tests import uuidsentinel as uuids
|
||||
|
@ -1599,7 +1600,8 @@ class TestAllocations(SchedulerReportClientTestCase):
|
|||
swap=1023,
|
||||
ephemeral_gb=100,
|
||||
memory_mb=1024,
|
||||
vcpus=2))
|
||||
vcpus=2,
|
||||
extra_specs={}))
|
||||
result = report._instance_to_allocations_dict(inst)
|
||||
expected = {
|
||||
'MEMORY_MB': 1024,
|
||||
|
@ -1608,6 +1610,39 @@ class TestAllocations(SchedulerReportClientTestCase):
|
|||
}
|
||||
self.assertEqual(expected, result)
|
||||
|
||||
@mock.patch('nova.compute.utils.is_volume_backed_instance')
|
||||
def test_instance_to_allocations_dict_overrides(self, mock_vbi):
|
||||
"""Test that resource overrides in an instance's flavor extra_specs
|
||||
are reported to placement.
|
||||
"""
|
||||
|
||||
mock_vbi.return_value = False
|
||||
specs = {
|
||||
'resources:CUSTOM_DAN': '123',
|
||||
'resources:%s' % fields.ResourceClass.VCPU: '4',
|
||||
'resources:NOTATHING': '456',
|
||||
'resources:NOTEVENANUMBER': 'catfood',
|
||||
'resources:': '7',
|
||||
'resources:ferret:weasel': 'smelly',
|
||||
'foo': 'bar',
|
||||
}
|
||||
inst = objects.Instance(
|
||||
uuid=uuids.inst,
|
||||
flavor=objects.Flavor(root_gb=10,
|
||||
swap=1023,
|
||||
ephemeral_gb=100,
|
||||
memory_mb=1024,
|
||||
vcpus=2,
|
||||
extra_specs=specs))
|
||||
result = report._instance_to_allocations_dict(inst)
|
||||
expected = {
|
||||
'MEMORY_MB': 1024,
|
||||
'VCPU': 4,
|
||||
'DISK_GB': 111,
|
||||
'CUSTOM_DAN': 123,
|
||||
}
|
||||
self.assertEqual(expected, result)
|
||||
|
||||
@mock.patch('nova.compute.utils.is_volume_backed_instance')
|
||||
def test_instance_to_allocations_dict_boot_from_volume(self, mock_vbi):
|
||||
mock_vbi.return_value = True
|
||||
|
@ -1617,7 +1652,8 @@ class TestAllocations(SchedulerReportClientTestCase):
|
|||
swap=1,
|
||||
ephemeral_gb=100,
|
||||
memory_mb=1024,
|
||||
vcpus=2))
|
||||
vcpus=2,
|
||||
extra_specs={}))
|
||||
result = report._instance_to_allocations_dict(inst)
|
||||
expected = {
|
||||
'MEMORY_MB': 1024,
|
||||
|
@ -1635,7 +1671,8 @@ class TestAllocations(SchedulerReportClientTestCase):
|
|||
swap=0,
|
||||
ephemeral_gb=0,
|
||||
memory_mb=1024,
|
||||
vcpus=2))
|
||||
vcpus=2,
|
||||
extra_specs={}))
|
||||
result = report._instance_to_allocations_dict(inst)
|
||||
expected = {
|
||||
'MEMORY_MB': 1024,
|
||||
|
|
Loading…
Reference in New Issue