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
This commit is contained in:
Paul Murray 2015-10-29 04:47:38 +00:00 committed by John Garbutt
parent 63347382d5
commit d3bece175b
6 changed files with 37 additions and 196 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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