Merge "Simple instance allocations from resource tracker"

This commit is contained in:
Jenkins 2016-09-02 00:07:48 +00:00 committed by Gerrit Code Review
commit 8f35bb321d
3 changed files with 128 additions and 0 deletions

View File

@ -861,6 +861,8 @@ class ResourceTracker(object):
self.pci_tracker.update_pci_for_instance(context,
instance,
sign=sign)
self.scheduler_client.reportclient.update_instance_allocation(
self.compute_node, instance, sign)
# new instance, update compute node resource usage:
self._update_usage(self._get_usage_dict(instance), sign=sign)

View File

@ -20,6 +20,7 @@ from keystoneauth1 import loading as keystone
from keystoneauth1 import session
from oslo_log import log as logging
from nova.compute import utils as compute_utils
import nova.conf
from nova.i18n import _LE, _LI, _LW
from nova import objects
@ -94,6 +95,11 @@ class SchedulerReportClient(object):
url, json=data,
endpoint_filter=self.ks_filter, raise_exc=False)
def delete(self, url):
return self._client.delete(
url,
endpoint_filter=self.ks_filter, raise_exc=False)
@safe_connect
def _get_resource_provider(self, uuid):
"""Queries the placement API for a resource provider record with the
@ -293,3 +299,64 @@ class SchedulerReportClient(object):
compute_node.hypervisor_hostname)
if compute_node.uuid in self._resource_providers:
self._update_inventory(compute_node)
def _allocations(self, instance):
# NOTE(danms): Boot-from-volume instances consume no local disk
is_bfv = compute_utils.is_volume_backed_instance(instance._context,
instance)
disk = ((0 if is_bfv else instance.flavor.root_gb) +
instance.flavor.swap +
instance.flavor.ephemeral_gb)
return {
'MEMORY_MB': instance.flavor.memory_mb,
'VCPU': instance.flavor.vcpus,
'DISK_GB': disk,
}
@safe_connect
def _allocate_for_instance(self, compute_node, instance):
url = '/allocations/%s' % instance.uuid
allocations = {
'allocations': [
{
'resource_provider': {
'uuid': compute_node.uuid,
},
'resources': self._allocations(instance),
},
],
}
LOG.debug('Sending allocation for instance %s: %s' % (
instance.uuid, allocations))
r = self.put(url, allocations)
if not r:
LOG.warning(
_LW('Unable to submit allocation for instance '
'%(uuid)s (%(code)i %(text)s)'),
{'uuid': instance.uuid,
'code': r.status_code,
'text': r.text})
else:
LOG.info(_LI('Submitted allocation for instance %s'),
instance.uuid)
@safe_connect
def _delete_allocation_for_instance(self, instance):
url = '/allocations/%s' % instance.uuid
r = self.delete(url)
if r:
LOG.info(_LI('Deleted allocation for instance %s'),
instance.uuid)
else:
LOG.warning(
_LW('Unable to delete allocation for instance '
'%(uuid)s: (%(code)i %(text)s)'),
{'uuid': instance.uuid,
'code': r.status_code,
'text': r.text})
def update_instance_allocation(self, compute_node, instance, sign):
if sign > 0:
self._allocate_for_instance(compute_node, instance)
else:
self._delete_allocation_for_instance(instance)

View File

@ -535,3 +535,62 @@ class SchedulerReportClientTestCase(test.NoDBTestCase):
self.client.update_resource_stats(cn)
mock_save.assert_called_once_with()
mock_ensure.assert_called_once_with(uuids.compute_node, 'host1')
@mock.patch('nova.compute.utils.is_volume_backed_instance')
def test_allocations(self, mock_vbi):
mock_vbi.return_value = False
inst = objects.Instance(
uuid=uuids.inst,
flavor=objects.Flavor(root_gb=10,
swap=1,
ephemeral_gb=100,
memory_mb=1024,
vcpus=2))
expected = {
'MEMORY_MB': 1024,
'VCPU': 2,
'DISK_GB': 111,
}
self.assertEqual(expected, self.client._allocations(inst))
@mock.patch('nova.compute.utils.is_volume_backed_instance')
def test_allocations_boot_from_volume(self, mock_vbi):
mock_vbi.return_value = True
inst = objects.Instance(
uuid=uuids.inst,
flavor=objects.Flavor(root_gb=10,
swap=1,
ephemeral_gb=100,
memory_mb=1024,
vcpus=2))
expected = {
'MEMORY_MB': 1024,
'VCPU': 2,
'DISK_GB': 101,
}
self.assertEqual(expected, self.client._allocations(inst))
@mock.patch('nova.scheduler.client.report.SchedulerReportClient.'
'put')
def test_update_instance_allocation_new(self, mock_put):
cn = objects.ComputeNode(uuid=uuids.cn)
inst = objects.Instance(uuid=uuids.inst)
with mock.patch.object(self.client, '_allocations') as mock_a:
expected = {
'allocations': [
{'resource_provider': {'uuid': cn.uuid},
'resources': mock_a.return_value}]
}
self.client.update_instance_allocation(cn, inst, 1)
mock_put.assert_called_once_with(
'/allocations/%s' % inst.uuid,
expected)
@mock.patch('nova.scheduler.client.report.SchedulerReportClient.'
'delete')
def test_update_instance_allocation_delete(self, mock_delete):
cn = objects.ComputeNode(uuid=uuids.cn)
inst = objects.Instance(uuid=uuids.inst)
self.client.update_instance_allocation(cn, inst, -1)
mock_delete.assert_called_once_with(
'/allocations/%s' % inst.uuid)