Merge "Remove vcpu resource from extensible resource tracker"

This commit is contained in:
Jenkins 2015-11-13 02:59:31 +00:00 committed by Gerrit Code Review
commit 7c5acd4f7b
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

@ -41,7 +41,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 =