Enable instance_plugin to handle on_start and on_end events
The Blazar manager service calls on_start/on_end methods of the instance_plugin class at the beginning or end of reservations. This patch implements the two methods in instance_plugin. The on_start method adds a flavor access right to the reserving user and adds allocated hosts to the reserved aggregate. The on_end method removes the access right to avoid creating new instances with the reserved flavor first, then it deletes all instances created by the flavor and removes hosts from the reserved aggregate. Partially implements: blueprint new-instance-reservation Change-Id: I885139224d8116599b2b02cab6ac1831352f8cb1
This commit is contained in:
parent
c2b65be7c4
commit
c79cd10f06
@ -257,7 +257,43 @@ class VirtualInstancePlugin(base.BasePlugin, nova.NovaClientWrapper):
|
||||
"support updates of reservation.")
|
||||
|
||||
def on_start(self, resource_id):
|
||||
pass
|
||||
ctx = context.current()
|
||||
instance_reservation = db_api.instance_reservation_get(resource_id)
|
||||
reservation_id = instance_reservation['reservation_id']
|
||||
|
||||
try:
|
||||
self.nova.flavor_access.add_tenant_access(reservation_id,
|
||||
ctx.project_id)
|
||||
except nova_exceptions.ClientException:
|
||||
LOG.info('Failed to associate flavor %s to project %s' %
|
||||
(reservation_id, ctx.project_id))
|
||||
raise mgr_exceptions.EventError()
|
||||
|
||||
pool = nova.ReservationPool()
|
||||
for allocation in db_api.host_allocation_get_all_by_values(
|
||||
reservation_id=reservation_id):
|
||||
host = db_api.host_get(allocation['compute_host_id'])
|
||||
pool.add_computehost(instance_reservation['aggregate_id'],
|
||||
host['service_name'], stay_in=True)
|
||||
|
||||
def on_end(self, resource_id):
|
||||
instance_reservation = db_api.instance_reservation_get(resource_id)
|
||||
ctx = context.current()
|
||||
|
||||
try:
|
||||
self.nova.flavor_access.remove_tenant_access(
|
||||
instance_reservation['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'])
|
||||
for allocation in allocations:
|
||||
db_api.host_allocation_destroy(allocation['id'])
|
||||
|
||||
for server in self.nova.servers.list(search_opts={
|
||||
'flavor': instance_reservation['reservation_id'],
|
||||
'all_tenants': 1}, detailed=False):
|
||||
server.delete()
|
||||
|
||||
self.cleanup_resources(instance_reservation)
|
||||
|
@ -444,3 +444,75 @@ class TestVirtualInstancePlugin(tests.TestCase):
|
||||
metadata={'reservation': 'reservation-id1',
|
||||
'filter_tenant_id': 'fake-project',
|
||||
'affinity_id': 'server_group_id1'})
|
||||
|
||||
def test_on_start(self):
|
||||
def fake_host_get(host_id):
|
||||
return {'service_name': 'host' + host_id[-1]}
|
||||
|
||||
self.set_context(context.BlazarContext(project_id='fake-project'))
|
||||
plugin = instance_plugin.VirtualInstancePlugin()
|
||||
|
||||
mock_inst_get = self.patch(db_api, 'instance_reservation_get')
|
||||
mock_inst_get.return_value = {'reservation_id': 'reservation-id1',
|
||||
'aggregate_id': 'aggregate-id1'}
|
||||
|
||||
mock_nova = mock.MagicMock()
|
||||
type(plugin).nova = mock_nova
|
||||
|
||||
fake_pool = mock.MagicMock()
|
||||
mock_pool = self.patch(nova, 'ReservationPool')
|
||||
mock_pool.return_value = fake_pool
|
||||
|
||||
mock_alloc_get = self.patch(db_api,
|
||||
'host_allocation_get_all_by_values')
|
||||
mock_alloc_get.return_value = [
|
||||
{'compute_host_id': 'host-id1'}, {'compute_host_id': 'host-id2'},
|
||||
{'compute_host_id': 'host-id3'}]
|
||||
|
||||
mock_host_get = self.patch(db_api, 'host_get')
|
||||
mock_host_get.side_effect = fake_host_get
|
||||
|
||||
plugin.on_start('resource-id1')
|
||||
|
||||
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)
|
||||
|
||||
def test_on_end(self):
|
||||
self.set_context(context.BlazarContext(project_id='fake-project-id'))
|
||||
|
||||
plugin = instance_plugin.VirtualInstancePlugin()
|
||||
|
||||
fake_instance_reservation = {'reservation_id': 'reservation-id1'}
|
||||
mock_inst_get = self.patch(db_api, 'instance_reservation_get')
|
||||
mock_inst_get.return_value = fake_instance_reservation
|
||||
|
||||
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'}]
|
||||
|
||||
self.patch(db_api, 'host_allocation_destroy')
|
||||
|
||||
fake_servers = [mock.MagicMock(method='delete') for i in range(5)]
|
||||
mock_nova = mock.MagicMock()
|
||||
type(plugin).nova = mock_nova
|
||||
mock_nova.servers.list.return_value = fake_servers
|
||||
|
||||
mock_cleanup_resources = self.patch(plugin, 'cleanup_resources')
|
||||
|
||||
plugin.on_end('resource-id1')
|
||||
|
||||
mock_nova.flavor_access.remove_tenant_access.assert_called_once_with(
|
||||
'reservation-id1', 'fake-project-id')
|
||||
|
||||
mock_nova.servers.list.assert_called_once_with(
|
||||
search_opts={'flavor': 'reservation-id1', 'all_tenants': 1},
|
||||
detailed=False)
|
||||
for fake in fake_servers:
|
||||
fake.delete.assert_called_once()
|
||||
mock_cleanup_resources.assert_called_once_with(
|
||||
fake_instance_reservation)
|
||||
|
@ -323,7 +323,7 @@ class ReservationPool(NovaClientWrapper):
|
||||
except manager_exceptions.AggregateNotFound:
|
||||
return []
|
||||
|
||||
def add_computehost(self, pool, host):
|
||||
def add_computehost(self, pool, host, stay_in=False):
|
||||
"""Add a compute host to an aggregate.
|
||||
|
||||
The `host` must exist otherwise raise an error
|
||||
@ -344,7 +344,7 @@ class ReservationPool(NovaClientWrapper):
|
||||
except manager_exceptions.AggregateNotFound:
|
||||
raise manager_exceptions.NoFreePool()
|
||||
|
||||
if freepool_agg.id != agg.id:
|
||||
if freepool_agg.id != agg.id and not stay_in:
|
||||
if host not in freepool_agg.hosts:
|
||||
raise manager_exceptions.HostNotInFreePool(
|
||||
host=host, freepool_name=freepool_agg.name)
|
||||
|
Loading…
Reference in New Issue
Block a user