Use placement inventory for instance reservation
In instance plugin, this patch - changess the _create_resources() to create the ``CUSTOM_RESERVATION_{reservation UUID}`` class and add it into the private flavor extra specs. - changes the on_start(), update_resources(), and _reallocate() to add the ``CUSTOM_RESERVATION_{reservation UUID}`` inventory to the reservation provider. Note that the total parameter is fixed to 1. This should be fixed in a following patch where arbitrary affinity policy is enabled. - changes the on_end() to remove the custom resevation resource inventory from the reservation provider and delete the resource class itself. Change-Id: I41b9a9fba22830e391799fa2763e4e845959f37c Blueprint: placement-api
This commit is contained in:
parent
b7b600efc2
commit
e90cc65799
|
@ -27,7 +27,9 @@ from blazar.plugins import base
|
|||
from blazar.plugins import instances as plugin
|
||||
from blazar.plugins import oshosts
|
||||
from blazar import status
|
||||
from blazar.utils.openstack import exceptions as openstack_ex
|
||||
from blazar.utils.openstack import nova
|
||||
from blazar.utils.openstack import placement
|
||||
from blazar.utils import plugins as plugins_utils
|
||||
|
||||
CONF = cfg.CONF
|
||||
|
@ -54,6 +56,7 @@ class VirtualInstancePlugin(base.BasePlugin, nova.NovaClientWrapper):
|
|||
self.freepool_name = CONF.nova.aggregate_freepool_name
|
||||
self.monitor = oshosts.host_plugin.PhysicalHostMonitorPlugin()
|
||||
self.monitor.register_healing_handler(self.heal_reservations)
|
||||
self.placement_client = placement.BlazarPlacementClient()
|
||||
|
||||
def filter_hosts_by_reservation(self, hosts, start_date, end_date,
|
||||
excludes):
|
||||
|
@ -216,11 +219,17 @@ class VirtualInstancePlugin(base.BasePlugin, nova.NovaClientWrapper):
|
|||
'is_public': False
|
||||
}
|
||||
reserved_flavor = self.nova.nova.flavors.create(**flavor_details)
|
||||
|
||||
# Set extra specs to the flavor
|
||||
rsv_id_rc_format = reservation_id.upper().replace("-", "_")
|
||||
reservation_rc = "resources:CUSTOM_RESERVATION_" + rsv_id_rc_format
|
||||
extra_specs = {
|
||||
FLAVOR_EXTRA_SPEC: reservation_id,
|
||||
"affinity_id": group_id
|
||||
"affinity_id": group_id,
|
||||
reservation_rc: "1"
|
||||
}
|
||||
reserved_flavor.set_keys(extra_specs)
|
||||
|
||||
return reserved_flavor
|
||||
|
||||
def _create_resources(self, inst_reservation):
|
||||
|
@ -248,6 +257,8 @@ class VirtualInstancePlugin(base.BasePlugin, nova.NovaClientWrapper):
|
|||
}
|
||||
agg = pool.create(name=reservation_id, metadata=pool_metadata)
|
||||
|
||||
self.placement_client.create_reservation_class(reservation_id)
|
||||
|
||||
return reserved_flavor, reserved_group, agg
|
||||
|
||||
def cleanup_resources(self, instance_reservation):
|
||||
|
@ -289,6 +300,8 @@ class VirtualInstancePlugin(base.BasePlugin, nova.NovaClientWrapper):
|
|||
err_msg = ('Fail to add host %s to aggregate %s.'
|
||||
% (host, reservation['aggregate_id']))
|
||||
raise mgr_exceptions.NovaClientError(err_msg)
|
||||
self.placement_client.update_reservation_inventory(
|
||||
host['service_name'], reservation['id'], 1)
|
||||
else:
|
||||
try:
|
||||
self.nova.nova.flavors.delete(reservation['id'])
|
||||
|
@ -458,28 +471,38 @@ class VirtualInstancePlugin(base.BasePlugin, nova.NovaClientWrapper):
|
|||
host = db_api.host_get(allocation['compute_host_id'])
|
||||
pool.add_computehost(instance_reservation['aggregate_id'],
|
||||
host['service_name'], stay_in=True)
|
||||
self.placement_client.update_reservation_inventory(
|
||||
host['service_name'], reservation_id, 1)
|
||||
|
||||
def on_end(self, resource_id):
|
||||
instance_reservation = db_api.instance_reservation_get(resource_id)
|
||||
reservation_id = instance_reservation['reservation_id']
|
||||
ctx = context.current()
|
||||
|
||||
try:
|
||||
self.nova.flavor_access.remove_tenant_access(
|
||||
instance_reservation['reservation_id'], ctx.project_id)
|
||||
reservation_id, ctx.project_id)
|
||||
except nova_exceptions.NotFound:
|
||||
pass
|
||||
|
||||
allocations = db_api.host_allocation_get_all_by_values(
|
||||
reservation_id=instance_reservation['reservation_id'])
|
||||
reservation_id=reservation_id)
|
||||
for allocation in allocations:
|
||||
host = db_api.host_get(allocation['compute_host_id'])
|
||||
db_api.host_allocation_destroy(allocation['id'])
|
||||
try:
|
||||
self.placement_client.delete_reservation_inventory(
|
||||
host['service_name'], reservation_id)
|
||||
except openstack_ex.ResourceProviderNotFound:
|
||||
pass
|
||||
|
||||
for server in self.nova.servers.list(search_opts={
|
||||
'flavor': instance_reservation['reservation_id'],
|
||||
'flavor': reservation_id,
|
||||
'all_tenants': 1}, detailed=False):
|
||||
server.delete()
|
||||
|
||||
self.cleanup_resources(instance_reservation)
|
||||
self.placement_client.delete_reservation_class(reservation_id)
|
||||
|
||||
def heal_reservations(self, failed_resources, interval_begin,
|
||||
interval_end):
|
||||
|
@ -534,6 +557,11 @@ class VirtualInstancePlugin(base.BasePlugin, nova.NovaClientWrapper):
|
|||
host = db_api.host_get(allocation['compute_host_id'])
|
||||
pool.remove_computehost(reservation['aggregate_id'],
|
||||
host['service_name'])
|
||||
try:
|
||||
self.placement_client.delete_reservation_inventory(
|
||||
host['service_name'], reservation['id'])
|
||||
except openstack_ex.ResourceProviderNotFound:
|
||||
pass
|
||||
|
||||
# Allocate an alternative host.
|
||||
values = {}
|
||||
|
@ -561,6 +589,8 @@ class VirtualInstancePlugin(base.BasePlugin, nova.NovaClientWrapper):
|
|||
pool.add_computehost(reservation['aggregate_id'],
|
||||
new_host['service_name'],
|
||||
stay_in=True)
|
||||
self.placement_client.update_reservation_inventory(
|
||||
new_host['service_name'], reservation['id'], 1)
|
||||
LOG.warn('Resource changed for reservation %s (lease: %s).',
|
||||
reservation['id'], lease['name'])
|
||||
|
||||
|
|
|
@ -540,6 +540,9 @@ class TestVirtualInstancePlugin(tests.TestCase):
|
|||
type(plugin).nova = mock_nova
|
||||
mock_nova.nova.flavors.create.return_value = fake_flavor
|
||||
|
||||
mock_create_reservation_class = self.patch(
|
||||
plugin.placement_client, 'create_reservation_class')
|
||||
|
||||
fake_pool = mock.MagicMock(id='pool-id1')
|
||||
fake_agg = mock.MagicMock()
|
||||
fake_pool.create.return_value = fake_agg
|
||||
|
@ -560,12 +563,15 @@ class TestVirtualInstancePlugin(tests.TestCase):
|
|||
vcpus=2, ram=1024, disk=20, is_public=False)
|
||||
fake_flavor.set_keys.assert_called_once_with(
|
||||
{'aggregate_instance_extra_specs:reservation': 'reservation-id1',
|
||||
'affinity_id': 'server_group_id1'})
|
||||
'affinity_id': 'server_group_id1',
|
||||
'resources:CUSTOM_RESERVATION_RESERVATION_ID1': '1'})
|
||||
fake_pool.create.assert_called_once_with(
|
||||
name='reservation-id1',
|
||||
metadata={'reservation': 'reservation-id1',
|
||||
'filter_tenant_id': 'fake-project',
|
||||
'affinity_id': 'server_group_id1'})
|
||||
mock_create_reservation_class.assert_called_once_with(
|
||||
'reservation-id1')
|
||||
|
||||
def test_pickup_hosts_for_update(self):
|
||||
reservation = {'id': 'reservation-id1', 'status': 'pending'}
|
||||
|
@ -675,7 +681,8 @@ class TestVirtualInstancePlugin(tests.TestCase):
|
|||
vcpus=2, ram=1024, disk=10, is_public=False)
|
||||
fake_flavor.set_keys.assert_called_once_with(
|
||||
{'aggregate_instance_extra_specs:reservation': 'reservation-id1',
|
||||
'affinity_id': 'group-1'})
|
||||
'affinity_id': 'group-1',
|
||||
'resources:CUSTOM_RESERVATION_RESERVATION_ID1': '1'})
|
||||
|
||||
def test_update_resources_in_active(self):
|
||||
def fake_host_get(host_id):
|
||||
|
@ -692,6 +699,9 @@ class TestVirtualInstancePlugin(tests.TestCase):
|
|||
self.set_context(context.BlazarContext(project_id='fake-project'))
|
||||
plugin = instance_plugin.VirtualInstancePlugin()
|
||||
|
||||
mock_update_reservation_inventory = self.patch(
|
||||
plugin.placement_client, 'update_reservation_inventory')
|
||||
|
||||
fake_pool = mock.MagicMock()
|
||||
mock_pool = self.patch(nova, 'ReservationPool')
|
||||
mock_pool.return_value = fake_pool
|
||||
|
@ -709,9 +719,10 @@ class TestVirtualInstancePlugin(tests.TestCase):
|
|||
|
||||
mock_reservation_get.assert_called_once_with('reservation-id1')
|
||||
for i in range(3):
|
||||
fake_pool.add_computehost.assert_any_call('aggregate-1',
|
||||
'host' + str(i + 1),
|
||||
stay_in=True)
|
||||
fake_pool.add_computehost.assert_any_call(
|
||||
'aggregate-1', 'host' + str(i + 1), stay_in=True)
|
||||
mock_update_reservation_inventory.assert_any_call(
|
||||
'host' + str(i + 1), 'reservation-id1', 1)
|
||||
|
||||
def test_update_reservation(self):
|
||||
plugin = instance_plugin.VirtualInstancePlugin()
|
||||
|
@ -856,6 +867,9 @@ class TestVirtualInstancePlugin(tests.TestCase):
|
|||
mock_pool = self.patch(nova, 'ReservationPool')
|
||||
mock_pool.return_value = fake_pool
|
||||
|
||||
mock_update_reservation_inventory = self.patch(
|
||||
plugin.placement_client, 'update_reservation_inventory')
|
||||
|
||||
mock_alloc_get = self.patch(db_api,
|
||||
'host_allocation_get_all_by_values')
|
||||
mock_alloc_get.return_value = [
|
||||
|
@ -870,9 +884,10 @@ class TestVirtualInstancePlugin(tests.TestCase):
|
|||
mock_nova.flavor_access.add_tenant_access.assert_called_once_with(
|
||||
'reservation-id1', 'fake-project')
|
||||
for i in range(3):
|
||||
fake_pool.add_computehost.assert_any_call('aggregate-id1',
|
||||
'host' + str(i + 1),
|
||||
stay_in=True)
|
||||
fake_pool.add_computehost.assert_any_call(
|
||||
'aggregate-id1', 'host' + str(i + 1), stay_in=True)
|
||||
mock_update_reservation_inventory.assert_any_call(
|
||||
'host' + str(i + 1), 'reservation-id1', 1)
|
||||
|
||||
def test_on_end(self):
|
||||
self.set_context(context.BlazarContext(project_id='fake-project-id'))
|
||||
|
@ -885,8 +900,20 @@ class TestVirtualInstancePlugin(tests.TestCase):
|
|||
|
||||
mock_alloc_get = self.patch(db_api,
|
||||
'host_allocation_get_all_by_values')
|
||||
mock_alloc_get.return_value = [{'id': 'host-alloc-id1'},
|
||||
{'id': 'host-alloc-id2'}]
|
||||
mock_alloc_get.return_value = [{'id': 'host-alloc-id1',
|
||||
'compute_host_id': 'host-id1'},
|
||||
{'id': 'host-alloc-id2',
|
||||
'compute_host_id': 'host-id2'}]
|
||||
|
||||
mock_host_get = self.patch(db_api, 'host_get')
|
||||
mock_host_get.side_effect = [
|
||||
{'service_name': 'host1'}, {'service_name': 'host2'}
|
||||
]
|
||||
|
||||
mock_delete_reservation_inventory = self.patch(
|
||||
plugin.placement_client, 'delete_reservation_inventory')
|
||||
mock_delete_reservation_class = self.patch(
|
||||
plugin.placement_client, 'delete_reservation_class')
|
||||
|
||||
self.patch(db_api, 'host_allocation_destroy')
|
||||
|
||||
|
@ -907,8 +934,13 @@ class TestVirtualInstancePlugin(tests.TestCase):
|
|||
detailed=False)
|
||||
for fake in fake_servers:
|
||||
fake.delete.assert_called_once()
|
||||
for i in range(2):
|
||||
mock_delete_reservation_inventory.assert_any_call(
|
||||
'host' + str(i + 1), 'reservation-id1')
|
||||
mock_cleanup_resources.assert_called_once_with(
|
||||
fake_instance_reservation)
|
||||
mock_delete_reservation_class.assert_called_once_with(
|
||||
'reservation-id1')
|
||||
|
||||
def test_heal_reservations_before_start_and_resources_changed(self):
|
||||
plugin = instance_plugin.VirtualInstancePlugin()
|
||||
|
@ -1132,13 +1164,17 @@ class TestVirtualInstancePlugin(tests.TestCase):
|
|||
lease_get = self.patch(db_api, 'lease_get')
|
||||
lease_get.return_value = dummy_lease
|
||||
host_get = self.patch(db_api, 'host_get')
|
||||
host_get.return_value = failed_host
|
||||
host_get.side_effect = [failed_host, new_host]
|
||||
fake_pool = mock.MagicMock()
|
||||
mock_pool = self.patch(nova, 'ReservationPool')
|
||||
mock_pool.return_value = fake_pool
|
||||
pickup_hosts = self.patch(plugin, 'pickup_hosts')
|
||||
pickup_hosts.return_value = {'added': [new_host['id']], 'removed': []}
|
||||
alloc_update = self.patch(db_api, 'host_allocation_update')
|
||||
mock_delete_reservation_inventory = self.patch(
|
||||
plugin.placement_client, 'delete_reservation_inventory')
|
||||
mock_update_reservation_inventory = self.patch(
|
||||
plugin.placement_client, 'update_reservation_inventory')
|
||||
|
||||
with mock.patch.object(datetime, 'datetime',
|
||||
mock.Mock(wraps=datetime.datetime)) as patched:
|
||||
|
@ -1155,8 +1191,12 @@ class TestVirtualInstancePlugin(tests.TestCase):
|
|||
{'compute_host_id': new_host['id']})
|
||||
fake_pool.add_computehost.assert_called_once_with(
|
||||
dummy_reservation['aggregate_id'],
|
||||
failed_host['service_name'],
|
||||
new_host['service_name'],
|
||||
stay_in=True)
|
||||
mock_delete_reservation_inventory.assert_called_once_with(
|
||||
'compute-1', 'rsrv-1')
|
||||
mock_update_reservation_inventory.assert_called_once_with(
|
||||
'compute-2', 'rsrv-1', 1)
|
||||
self.assertEqual(True, result)
|
||||
|
||||
def test_reallocate_missing_resources(self):
|
||||
|
|
Loading…
Reference in New Issue