Merge "Remove vcpu resource from extensible resource tracker"
This commit is contained in:
commit
7c5acd4f7b
@ -45,6 +45,10 @@ class NopClaim(object):
|
||||
def memory_mb(self):
|
||||
return 0
|
||||
|
||||
@property
|
||||
def vcpus(self):
|
||||
return 0
|
||||
|
||||
def __enter__(self):
|
||||
return self
|
||||
|
||||
@ -97,6 +101,10 @@ class Claim(NopClaim):
|
||||
def memory_mb(self):
|
||||
return self.instance.memory_mb + self.overhead['memory_mb']
|
||||
|
||||
@property
|
||||
def vcpus(self):
|
||||
return self.instance.vcpus
|
||||
|
||||
@property
|
||||
def numa_topology(self):
|
||||
if self._numa_topology_loaded:
|
||||
@ -129,15 +137,18 @@ class Claim(NopClaim):
|
||||
# unlimited:
|
||||
memory_mb_limit = limits.get('memory_mb')
|
||||
disk_gb_limit = limits.get('disk_gb')
|
||||
vcpus_limit = limits.get('vcpu')
|
||||
numa_topology_limit = limits.get('numa_topology')
|
||||
|
||||
msg = _("Attempting claim: memory %(memory_mb)d MB, disk %(disk_gb)d "
|
||||
"GB")
|
||||
params = {'memory_mb': self.memory_mb, 'disk_gb': self.disk_gb}
|
||||
msg = _("Attempting claim: memory %(memory_mb)d MB, "
|
||||
"disk %(disk_gb)d GB, vcpus %(vcpus)d CPU")
|
||||
params = {'memory_mb': self.memory_mb, 'disk_gb': self.disk_gb,
|
||||
'vcpus': self.vcpus}
|
||||
LOG.info(msg % params, instance=self.instance)
|
||||
|
||||
reasons = [self._test_memory(resources, memory_mb_limit),
|
||||
self._test_disk(resources, disk_gb_limit),
|
||||
self._test_vcpus(resources, vcpus_limit),
|
||||
self._test_numa_topology(resources, numa_topology_limit),
|
||||
self._test_pci()]
|
||||
reasons = reasons + self._test_ext_resources(limits)
|
||||
@ -166,6 +177,15 @@ class Claim(NopClaim):
|
||||
|
||||
return self._test(type_, unit, total, used, requested, limit)
|
||||
|
||||
def _test_vcpus(self, resources, limit):
|
||||
type_ = _("vcpu")
|
||||
unit = "VCPU"
|
||||
total = resources['vcpus']
|
||||
used = resources['vcpus_used']
|
||||
requested = self.vcpus
|
||||
|
||||
return self._test(type_, unit, total, used, requested, limit)
|
||||
|
||||
def _test_pci(self):
|
||||
pci_requests = objects.InstancePCIRequests.get_by_instance_uuid(
|
||||
self.context, self.instance.uuid)
|
||||
@ -265,6 +285,10 @@ class MoveClaim(Claim):
|
||||
def memory_mb(self):
|
||||
return self.instance_type.memory_mb + self.overhead['memory_mb']
|
||||
|
||||
@property
|
||||
def vcpus(self):
|
||||
return self.instance_type.vcpus
|
||||
|
||||
@property
|
||||
def numa_topology(self):
|
||||
image_meta = objects.ImageMeta.from_dict(self.image_meta)
|
||||
|
@ -50,7 +50,7 @@ resource_tracker_opts = [
|
||||
default='nova.compute.stats.Stats',
|
||||
help='Class that will manage stats for the local compute host'),
|
||||
cfg.ListOpt('compute_resources',
|
||||
default=['vcpu'],
|
||||
default=[],
|
||||
help='The names of the extra resources to track.'),
|
||||
]
|
||||
|
||||
@ -663,6 +663,7 @@ class ResourceTracker(object):
|
||||
self.compute_node.memory_mb_used += sign * mem_usage
|
||||
self.compute_node.local_gb_used += sign * usage.get('root_gb', 0)
|
||||
self.compute_node.local_gb_used += sign * usage.get('ephemeral_gb', 0)
|
||||
self.compute_node.vcpus_used += sign * usage.get('vcpus', 0)
|
||||
|
||||
# free ram and disk may be negative, depending on policy:
|
||||
self.compute_node.free_ram_mb = (self.compute_node.memory_mb -
|
||||
|
@ -1,84 +0,0 @@
|
||||
# Copyright (c) 2013 Hewlett-Packard Development Company, L.P.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from oslo_log import log as logging
|
||||
|
||||
from nova.compute.resources import base
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class VCPU(base.Resource):
|
||||
"""VCPU compute resource plugin.
|
||||
|
||||
This is effectively a simple counter based on the vcpu requirement of each
|
||||
instance.
|
||||
"""
|
||||
def __init__(self):
|
||||
# initialize to a 'zero' resource.
|
||||
# reset will be called to set real resource values
|
||||
self._total = 0
|
||||
self._used = 0
|
||||
|
||||
def reset(self, resources, driver):
|
||||
# total vcpu is reset to the value taken from resources.
|
||||
self._total = int(resources['vcpus'])
|
||||
self._used = 0
|
||||
|
||||
def _get_requested(self, usage):
|
||||
return int(usage.get('vcpus', 0))
|
||||
|
||||
def _get_limit(self, limits):
|
||||
if limits and 'vcpu' in limits:
|
||||
return int(limits.get('vcpu'))
|
||||
|
||||
def test(self, usage, limits):
|
||||
requested = self._get_requested(usage)
|
||||
limit = self._get_limit(limits)
|
||||
|
||||
LOG.debug('Total CPUs: %(total)d VCPUs, used: %(used).02f VCPUs' %
|
||||
{'total': self._total, 'used': self._used})
|
||||
|
||||
if limit is None:
|
||||
# treat resource as unlimited:
|
||||
LOG.debug('CPUs limit not specified, defaulting to unlimited')
|
||||
return
|
||||
|
||||
free = limit - self._used
|
||||
|
||||
# Oversubscribed resource policy info:
|
||||
LOG.debug('CPUs limit: %(limit).02f VCPUs, free: %(free).02f VCPUs' %
|
||||
{'limit': limit, 'free': free})
|
||||
|
||||
if requested > free:
|
||||
return ('Free CPUs %(free).02f VCPUs < '
|
||||
'requested %(requested)d VCPUs' %
|
||||
{'free': free, 'requested': requested})
|
||||
|
||||
def add_instance(self, usage):
|
||||
requested = int(usage.get('vcpus', 0))
|
||||
self._used += requested
|
||||
|
||||
def remove_instance(self, usage):
|
||||
requested = int(usage.get('vcpus', 0))
|
||||
self._used -= requested
|
||||
|
||||
def write(self, resources):
|
||||
resources['vcpus'] = self._total
|
||||
resources['vcpus_used'] = self._used
|
||||
|
||||
def report_free(self):
|
||||
free_vcpus = self._total - self._used
|
||||
LOG.debug('Free VCPUs: %s' % free_vcpus)
|
@ -22,11 +22,9 @@ from stevedore import named
|
||||
|
||||
from nova.compute import resources
|
||||
from nova.compute.resources import base
|
||||
from nova.compute.resources import vcpu
|
||||
from nova import context
|
||||
from nova.objects import flavor as flavor_obj
|
||||
from nova import test
|
||||
from nova.tests.unit import fake_instance
|
||||
|
||||
CONF = cfg.CONF
|
||||
|
||||
@ -271,73 +269,3 @@ class BaseTestCase(test.NoDBTestCase):
|
||||
self.assertEqual(expected_extra_resources, extra_resources)
|
||||
|
||||
empty_r_handler.report_free_resources()
|
||||
|
||||
def test_vcpu_resource_load(self):
|
||||
# load the vcpu example
|
||||
names = ['vcpu']
|
||||
real_r_handler = resources.ResourceHandler(names)
|
||||
ext_names = real_r_handler._mgr.names()
|
||||
self.assertEqual(names, ext_names)
|
||||
|
||||
# check the extension loaded is the one we expect
|
||||
# and an instance of the object has been created
|
||||
ext = real_r_handler._mgr['vcpu']
|
||||
self.assertIsInstance(ext.obj, vcpu.VCPU)
|
||||
|
||||
|
||||
class TestVCPU(test.NoDBTestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(TestVCPU, self).setUp()
|
||||
self._vcpu = vcpu.VCPU()
|
||||
self._vcpu._total = 10
|
||||
self._vcpu._used = 0
|
||||
self._flavor = fake_flavor_obj(vcpus=5)
|
||||
self._big_flavor = fake_flavor_obj(vcpus=20)
|
||||
self._instance = fake_instance.fake_instance_obj(None)
|
||||
|
||||
def test_reset(self):
|
||||
# set vcpu values to something different to test reset
|
||||
self._vcpu._total = 10
|
||||
self._vcpu._used = 5
|
||||
|
||||
driver_resources = {'vcpus': 20}
|
||||
self._vcpu.reset(driver_resources, None)
|
||||
self.assertEqual(20, self._vcpu._total)
|
||||
self.assertEqual(0, self._vcpu._used)
|
||||
|
||||
def test_add_and_remove_instance(self):
|
||||
self._vcpu.add_instance(self._flavor)
|
||||
self.assertEqual(10, self._vcpu._total)
|
||||
self.assertEqual(5, self._vcpu._used)
|
||||
|
||||
self._vcpu.remove_instance(self._flavor)
|
||||
self.assertEqual(10, self._vcpu._total)
|
||||
self.assertEqual(0, self._vcpu._used)
|
||||
|
||||
def test_test_pass_limited(self):
|
||||
result = self._vcpu.test(self._flavor, {'vcpu': 10})
|
||||
self.assertIsNone(result, 'vcpu test failed when it should pass')
|
||||
|
||||
def test_test_pass_unlimited(self):
|
||||
result = self._vcpu.test(self._big_flavor, {})
|
||||
self.assertIsNone(result, 'vcpu test failed when it should pass')
|
||||
|
||||
def test_test_fail(self):
|
||||
result = self._vcpu.test(self._flavor, {'vcpu': 2})
|
||||
expected = 'Free CPUs 2.00 VCPUs < requested 5 VCPUs'
|
||||
self.assertEqual(expected, result)
|
||||
|
||||
def test_write(self):
|
||||
resources = {'stats': {}}
|
||||
self._vcpu.write(resources)
|
||||
expected = {
|
||||
'vcpus': 10,
|
||||
'vcpus_used': 0,
|
||||
'stats': {
|
||||
'num_vcpus': 10,
|
||||
'num_vcpus_used': 0
|
||||
}
|
||||
}
|
||||
self.assertEqual(sorted(expected),
|
||||
sorted(resources))
|
||||
|
@ -564,18 +564,7 @@ class TestUpdateAvailableResources(BaseTestCase):
|
||||
'free_ram_mb': 384, # 512 - 128 used
|
||||
'memory_mb_used': 128,
|
||||
'pci_device_pools': objects.PciDevicePoolList(),
|
||||
# NOTE(jaypipes): Due to the design of the ERT, which now is used
|
||||
# track VCPUs, the actual used VCPUs isn't
|
||||
# "written" to the resources dictionary that is
|
||||
# passed to _update() like all the other
|
||||
# resources are. Instead, _update()
|
||||
# calls the ERT's write_resources() method, which
|
||||
# then queries each resource handler plugin for the
|
||||
# changes in its resource usage and the plugin
|
||||
# writes changes to the supplied "values" dict. For
|
||||
# this reason, all other resources except VCPUs
|
||||
# are accurate here. :(
|
||||
'vcpus_used': 0,
|
||||
'vcpus_used': 1,
|
||||
'hypervisor_type': 'fake',
|
||||
'local_gb_used': 1,
|
||||
'memory_mb': 512,
|
||||
@ -705,7 +694,7 @@ class TestUpdateAvailableResources(BaseTestCase):
|
||||
'free_ram_mb': 384, # 512 total - 128 for possible revert of orig
|
||||
'memory_mb_used': 128, # 128 possible revert amount
|
||||
'pci_device_pools': objects.PciDevicePoolList(),
|
||||
'vcpus_used': 0,
|
||||
'vcpus_used': 1,
|
||||
'hypervisor_type': 'fake',
|
||||
'local_gb_used': 1,
|
||||
'memory_mb': 512,
|
||||
@ -765,7 +754,7 @@ class TestUpdateAvailableResources(BaseTestCase):
|
||||
'free_ram_mb': 256, # 512 total - 256 for possible confirm of new
|
||||
'memory_mb_used': 256, # 256 possible confirmed amount
|
||||
'pci_device_pools': objects.PciDevicePoolList(),
|
||||
'vcpus_used': 0, # See NOTE(jaypipes) above about why this is 0
|
||||
'vcpus_used': 2,
|
||||
'hypervisor_type': 'fake',
|
||||
'local_gb_used': 5,
|
||||
'memory_mb': 512,
|
||||
@ -822,7 +811,7 @@ class TestUpdateAvailableResources(BaseTestCase):
|
||||
'free_ram_mb': 256, # 512 total - 256 for possible confirm of new
|
||||
'memory_mb_used': 256, # 256 possible confirmed amount
|
||||
'pci_device_pools': objects.PciDevicePoolList(),
|
||||
'vcpus_used': 0, # See NOTE(jaypipes) above about why this is 0
|
||||
'vcpus_used': 2,
|
||||
'hypervisor_type': 'fake',
|
||||
'local_gb_used': 5,
|
||||
'memory_mb': 512,
|
||||
@ -890,9 +879,7 @@ class TestUpdateAvailableResources(BaseTestCase):
|
||||
'free_ram_mb': 0,
|
||||
'memory_mb_used': 512, # 128 exist + 256 new flav + 128 old flav
|
||||
'pci_device_pools': objects.PciDevicePoolList(),
|
||||
# See NOTE(jaypipes) above for reason why this isn't accurate until
|
||||
# _update() is called.
|
||||
'vcpus_used': 0,
|
||||
'vcpus_used': 4,
|
||||
'hypervisor_type': 'fake',
|
||||
'local_gb_used': 7, # 1G existing, 5G new flav + 1 old flav
|
||||
'memory_mb': 512,
|
||||
@ -1100,18 +1087,7 @@ class TestUpdateComputeNode(BaseTestCase):
|
||||
cpu_allocation_ratio=16.0,
|
||||
ram_allocation_ratio=1.5,
|
||||
)
|
||||
expected_resources = copy.deepcopy(compute)
|
||||
expected_resources.stats = {}
|
||||
expected_resources.vcpus = 4
|
||||
expected_resources.vcpus_used = 2
|
||||
|
||||
self.rt.compute_node = compute
|
||||
self.rt.ext_resources_handler.reset_resources(self.rt.compute_node,
|
||||
self.rt.driver)
|
||||
# This emulates the behavior that occurs in the
|
||||
# RT.update_available_resource() method, which updates resource
|
||||
# information in the ERT differently than all other resources.
|
||||
self.rt.ext_resources_handler.update_from_instance(dict(vcpus=2))
|
||||
self.rt._update(mock.sentinel.ctx)
|
||||
|
||||
self.assertFalse(self.rt.disabled)
|
||||
@ -1190,9 +1166,7 @@ class TestInstanceClaim(BaseTestCase):
|
||||
'free_disk_gb': expected['local_gb'] - disk_used,
|
||||
"free_ram_mb": expected['memory_mb'] - self.instance.memory_mb,
|
||||
'running_vms': 1,
|
||||
# vcpus are claimed by the ERT in RT._update(), which is mocked
|
||||
# out below...
|
||||
'vcpus_used': 0,
|
||||
'vcpus_used': 1,
|
||||
'pci_device_pools': objects.PciDevicePoolList(),
|
||||
})
|
||||
with mock.patch.object(self.rt, '_update') as update_mock:
|
||||
@ -1217,9 +1191,7 @@ class TestInstanceClaim(BaseTestCase):
|
||||
'free_disk_gb': expected['local_gb'] - disk_used,
|
||||
"free_ram_mb": expected['memory_mb'] - self.instance.memory_mb,
|
||||
'running_vms': 1,
|
||||
# vcpus are claimed by the ERT in RT._update(), which is mocked
|
||||
# out below...
|
||||
'vcpus_used': 0,
|
||||
'vcpus_used': 1,
|
||||
'pci_device_pools': objects.PciDevicePoolList(),
|
||||
})
|
||||
with mock.patch.object(self.rt, '_update') as update_mock:
|
||||
|
Loading…
Reference in New Issue
Block a user