From d3bece175bf3b90abdea021bbeb69719a9cb25f2 Mon Sep 17 00:00:00 2001 From: Paul Murray Date: Thu, 29 Oct 2015 04:47:38 +0000 Subject: [PATCH] Remove vcpu resource from extensible resource tracker This patch makes vcpu resource tracking explicit in the resource tracker and removes the corresponding VCPU resource plugin from the extensible resource tracker. This is a first step towards removing the extensible resource tracker in a future release. A follow-on patch will add deprecation notices for the extensible resource tracker. DocImpact: default value of compute_resources has changed to an empty list. blueprint resource-objects Change-Id: If4318ce1c942292ef041a0b5c800304544207cb4 --- nova/compute/claims.py | 30 +++++++- nova/compute/resource_tracker.py | 3 +- nova/compute/resources/vcpu.py | 84 ----------------------- nova/tests/unit/compute/test_resources.py | 72 ------------------- nova/tests/unit/compute/test_tracker.py | 42 ++---------- setup.cfg | 2 +- 6 files changed, 37 insertions(+), 196 deletions(-) delete mode 100644 nova/compute/resources/vcpu.py 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 =