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:
Dan Smith 2017-07-18 13:10:47 -07:00
parent 430ec6504b
commit a22ae8baa2
4 changed files with 64 additions and 5 deletions

View File

@ -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}

View File

@ -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)

View File

@ -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={},
),
}

View File

@ -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,