diff --git a/nova/compute/claims.py b/nova/compute/claims.py index 4f9abe0371dc..3e4ffb035708 100644 --- a/nova/compute/claims.py +++ b/nova/compute/claims.py @@ -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) diff --git a/nova/compute/resource_tracker.py b/nova/compute/resource_tracker.py index ec3b8ef302fc..524fa5d89bda 100644 --- a/nova/compute/resource_tracker.py +++ b/nova/compute/resource_tracker.py @@ -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 - diff --git a/nova/compute/resources/vcpu.py b/nova/compute/resources/vcpu.py deleted file mode 100644 index 3f307b01d7d4..000000000000 --- a/nova/compute/resources/vcpu.py +++ /dev/null @@ -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) diff --git a/nova/tests/unit/compute/test_resources.py b/nova/tests/unit/compute/test_resources.py index 2dc7e9d5d940..4381e8314e37 100644 --- a/nova/tests/unit/compute/test_resources.py +++ b/nova/tests/unit/compute/test_resources.py @@ -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)) diff --git a/nova/tests/unit/compute/test_tracker.py b/nova/tests/unit/compute/test_tracker.py index 667daa66accc..54312be74ee1 100644 --- a/nova/tests/unit/compute/test_tracker.py +++ b/nova/tests/unit/compute/test_tracker.py @@ -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: diff --git a/setup.cfg b/setup.cfg index 8b9116d4f60b..d8bd4eaf5cc0 100644 --- a/setup.cfg +++ b/setup.cfg @@ -42,7 +42,7 @@ oslo.config.opts = nova.compute.monitors.cpu = virt_driver = nova.compute.monitors.cpu.virt_driver:Monitor nova.compute.resources = - vcpu = nova.compute.resources.vcpu:VCPU + nova.image.download.modules = file = nova.image.download.file console_scripts =