Add aggregate_host_add and _delete to conductor.
Offload the db writes for adding and removing a host to or from a host aggregate to the conductor service. Part of blueprint no-db-compute. Change-Id: I7c3da2d5c9fc6d7e72fb9371b7ea6a2b10c5218d
This commit is contained in:
@@ -3241,9 +3241,10 @@ class ComputeManager(manager.SchedulerDependentManager):
|
|||||||
slave_info=slave_info)
|
slave_info=slave_info)
|
||||||
except exception.AggregateError:
|
except exception.AggregateError:
|
||||||
with excutils.save_and_reraise_exception():
|
with excutils.save_and_reraise_exception():
|
||||||
self.driver.undo_aggregate_operation(context,
|
self.driver.undo_aggregate_operation(
|
||||||
self.db.aggregate_host_delete,
|
context,
|
||||||
aggregate['id'], host)
|
self.conductor_api.aggregate_host_delete,
|
||||||
|
aggregate, host)
|
||||||
|
|
||||||
@exception.wrap_exception(notifier=notifier, publisher_id=publisher_id())
|
@exception.wrap_exception(notifier=notifier, publisher_id=publisher_id())
|
||||||
def remove_aggregate_host(self, context, host, slave_info=None,
|
def remove_aggregate_host(self, context, host, slave_info=None,
|
||||||
@@ -3259,8 +3260,9 @@ class ComputeManager(manager.SchedulerDependentManager):
|
|||||||
exception.InvalidAggregateAction) as e:
|
exception.InvalidAggregateAction) as e:
|
||||||
with excutils.save_and_reraise_exception():
|
with excutils.save_and_reraise_exception():
|
||||||
self.driver.undo_aggregate_operation(
|
self.driver.undo_aggregate_operation(
|
||||||
context, self.db.aggregate_host_add,
|
context,
|
||||||
aggregate['id'], host,
|
self.conductor_api.aggregate_host_add,
|
||||||
|
aggregate, host,
|
||||||
isinstance(e, exception.AggregateError))
|
isinstance(e, exception.AggregateError))
|
||||||
|
|
||||||
@manager.periodic_task(
|
@manager.periodic_task(
|
||||||
|
|||||||
@@ -56,6 +56,12 @@ class LocalAPI(object):
|
|||||||
def migration_update(self, context, migration, status):
|
def migration_update(self, context, migration, status):
|
||||||
return self._manager.migration_update(context, migration, status)
|
return self._manager.migration_update(context, migration, status)
|
||||||
|
|
||||||
|
def aggregate_host_add(self, context, aggregate, host):
|
||||||
|
return self._manager.aggregate_host_add(context, aggregate, host)
|
||||||
|
|
||||||
|
def aggregate_host_delete(self, context, aggregate, host):
|
||||||
|
return self._manager.aggregate_host_delete(context, aggregate, host)
|
||||||
|
|
||||||
|
|
||||||
class API(object):
|
class API(object):
|
||||||
"""Conductor API that does updates via RPC to the ConductorManager"""
|
"""Conductor API that does updates via RPC to the ConductorManager"""
|
||||||
@@ -78,3 +84,11 @@ class API(object):
|
|||||||
def migration_update(self, context, migration, status):
|
def migration_update(self, context, migration, status):
|
||||||
return self.conductor_rpcapi.migration_update(context, migration,
|
return self.conductor_rpcapi.migration_update(context, migration,
|
||||||
status)
|
status)
|
||||||
|
|
||||||
|
def aggregate_host_add(self, context, aggregate, host):
|
||||||
|
return self.conductor_rpcapi.aggregate_host_add(context, aggregate,
|
||||||
|
host)
|
||||||
|
|
||||||
|
def aggregate_host_delete(self, context, aggregate, host):
|
||||||
|
return self.conductor_rpcapi.aggregate_host_delete(context, aggregate,
|
||||||
|
host)
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ datetime_fields = ['launched_at', 'terminated_at']
|
|||||||
class ConductorManager(manager.SchedulerDependentManager):
|
class ConductorManager(manager.SchedulerDependentManager):
|
||||||
"""Mission: TBD"""
|
"""Mission: TBD"""
|
||||||
|
|
||||||
RPC_API_VERSION = '1.2'
|
RPC_API_VERSION = '1.3'
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super(ConductorManager, self).__init__(service_name='conductor',
|
super(ConductorManager, self).__init__(service_name='conductor',
|
||||||
@@ -74,3 +74,13 @@ class ConductorManager(manager.SchedulerDependentManager):
|
|||||||
migration['id'],
|
migration['id'],
|
||||||
{'status': status})
|
{'status': status})
|
||||||
return jsonutils.to_primitive(migration_ref)
|
return jsonutils.to_primitive(migration_ref)
|
||||||
|
|
||||||
|
def aggregate_host_add(self, context, aggregate, host):
|
||||||
|
host_ref = self.db.aggregate_host_add(context.elevated(),
|
||||||
|
aggregate['id'], host)
|
||||||
|
|
||||||
|
return jsonutils.to_primitive(host_ref)
|
||||||
|
|
||||||
|
def aggregate_host_delete(self, context, aggregate, host):
|
||||||
|
self.db.aggregate_host_delete(context.elevated(),
|
||||||
|
aggregate['id'], host)
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ class ConductorAPI(nova.openstack.common.rpc.proxy.RpcProxy):
|
|||||||
1.0 - Initial version.
|
1.0 - Initial version.
|
||||||
1.1 - Added migration_update
|
1.1 - Added migration_update
|
||||||
1.2 - Added instance_get_by_uuid and instance_get_all_by_host
|
1.2 - Added instance_get_by_uuid and instance_get_all_by_host
|
||||||
|
1.3 - Added aggregate_host_add and aggregate_host_delete
|
||||||
"""
|
"""
|
||||||
|
|
||||||
BASE_RPC_API_VERSION = '1.0'
|
BASE_RPC_API_VERSION = '1.0'
|
||||||
@@ -59,3 +60,15 @@ class ConductorAPI(nova.openstack.common.rpc.proxy.RpcProxy):
|
|||||||
msg = self.make_msg('migration_update', migration=migration_p,
|
msg = self.make_msg('migration_update', migration=migration_p,
|
||||||
status=status)
|
status=status)
|
||||||
return self.call(context, msg, version='1.1')
|
return self.call(context, msg, version='1.1')
|
||||||
|
|
||||||
|
def aggregate_host_add(self, context, aggregate, host):
|
||||||
|
aggregate_p = jsonutils.to_primitive(aggregate)
|
||||||
|
msg = self.make_msg('aggregate_host_add', aggregate=aggregate_p,
|
||||||
|
host=host)
|
||||||
|
return self.call(context, msg, version='1.3')
|
||||||
|
|
||||||
|
def aggregate_host_delete(self, context, aggregate, host):
|
||||||
|
aggregate_p = jsonutils.to_primitive(aggregate)
|
||||||
|
msg = self.make_msg('aggregate_host_delete', aggregate=aggregate_p,
|
||||||
|
host=host)
|
||||||
|
return self.call(context, msg, version='1.3')
|
||||||
|
|||||||
@@ -113,6 +113,39 @@ class ConductorTestCase(BaseTestCase):
|
|||||||
self.assertEqual(orig_instance['name'],
|
self.assertEqual(orig_instance['name'],
|
||||||
all_instances[0]['name'])
|
all_instances[0]['name'])
|
||||||
|
|
||||||
|
def _setup_aggregate_with_host(self):
|
||||||
|
aggregate_ref = db.aggregate_create(self.context.elevated(),
|
||||||
|
{'name': 'foo', 'availability_zone': 'foo'})
|
||||||
|
|
||||||
|
self.conductor.aggregate_host_add(self.context, aggregate_ref, 'bar')
|
||||||
|
|
||||||
|
aggregate_ref = db.aggregate_get(self.context.elevated(),
|
||||||
|
aggregate_ref['id'])
|
||||||
|
|
||||||
|
return aggregate_ref
|
||||||
|
|
||||||
|
def test_aggregate_host_add(self):
|
||||||
|
aggregate_ref = self._setup_aggregate_with_host()
|
||||||
|
|
||||||
|
self.assertTrue(any([host == 'bar'
|
||||||
|
for host in aggregate_ref['hosts']]))
|
||||||
|
|
||||||
|
db.aggregate_delete(self.context.elevated(), aggregate_ref['id'])
|
||||||
|
|
||||||
|
def test_aggregate_host_delete(self):
|
||||||
|
aggregate_ref = self._setup_aggregate_with_host()
|
||||||
|
|
||||||
|
self.conductor.aggregate_host_delete(self.context, aggregate_ref,
|
||||||
|
'bar')
|
||||||
|
|
||||||
|
aggregate_ref = db.aggregate_get(self.context.elevated(),
|
||||||
|
aggregate_ref['id'])
|
||||||
|
|
||||||
|
self.assertFalse(any([host == 'bar'
|
||||||
|
for host in aggregate_ref['hosts']]))
|
||||||
|
|
||||||
|
db.aggregate_delete(self.context.elevated(), aggregate_ref['id'])
|
||||||
|
|
||||||
|
|
||||||
class ConductorRPCAPITestCase(ConductorTestCase):
|
class ConductorRPCAPITestCase(ConductorTestCase):
|
||||||
"""Conductor RPC API Tests"""
|
"""Conductor RPC API Tests"""
|
||||||
|
|||||||
@@ -2096,6 +2096,7 @@ class XenAPIAggregateTestCase(stubs.XenAPITestBase):
|
|||||||
host='host',
|
host='host',
|
||||||
compute_driver='xenapi.XenAPIDriver',
|
compute_driver='xenapi.XenAPIDriver',
|
||||||
node_availability_zone='avail_zone1')
|
node_availability_zone='avail_zone1')
|
||||||
|
self.flags(use_local=True, group='conductor')
|
||||||
host_ref = xenapi_fake.get_all('host')[0]
|
host_ref = xenapi_fake.get_all('host')[0]
|
||||||
stubs.stubout_session(self.stubs, stubs.FakeSessionForVMTests)
|
stubs.stubout_session(self.stubs, stubs.FakeSessionForVMTests)
|
||||||
self.context = context.get_admin_context()
|
self.context = context.get_admin_context()
|
||||||
|
|||||||
@@ -734,7 +734,7 @@ class ComputeDriver(object):
|
|||||||
"""Remove a compute host from an aggregate."""
|
"""Remove a compute host from an aggregate."""
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
def undo_aggregate_operation(self, context, op, aggregate_id,
|
def undo_aggregate_operation(self, context, op, aggregate,
|
||||||
host, set_error=True):
|
host, set_error=True):
|
||||||
"""Undo for Resource Pools"""
|
"""Undo for Resource Pools"""
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|||||||
@@ -3029,7 +3029,7 @@ class LibvirtDriver(driver.ComputeDriver):
|
|||||||
"""Remove a compute host from an aggregate."""
|
"""Remove a compute host from an aggregate."""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def undo_aggregate_operation(self, context, op, aggregate_id,
|
def undo_aggregate_operation(self, context, op, aggregate,
|
||||||
host, set_error=True):
|
host, set_error=True):
|
||||||
"""only used for Resource Pools"""
|
"""only used for Resource Pools"""
|
||||||
pass
|
pass
|
||||||
|
|||||||
@@ -593,11 +593,11 @@ class XenAPIDriver(driver.ComputeDriver):
|
|||||||
return self._pool.remove_from_aggregate(context,
|
return self._pool.remove_from_aggregate(context,
|
||||||
aggregate, host, **kwargs)
|
aggregate, host, **kwargs)
|
||||||
|
|
||||||
def undo_aggregate_operation(self, context, op, aggregate_id,
|
def undo_aggregate_operation(self, context, op, aggregate,
|
||||||
host, set_error=True):
|
host, set_error=True):
|
||||||
"""Undo aggregate operation when pool error raised"""
|
"""Undo aggregate operation when pool error raised"""
|
||||||
return self._pool.undo_aggregate_operation(context, op,
|
return self._pool.undo_aggregate_operation(context, op,
|
||||||
aggregate_id, host, set_error)
|
aggregate, host, set_error)
|
||||||
|
|
||||||
def legacy_nwinfo(self):
|
def legacy_nwinfo(self):
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -64,16 +64,17 @@ class ResourcePool(object):
|
|||||||
def _get_metadata(self, context, aggregate_id):
|
def _get_metadata(self, context, aggregate_id):
|
||||||
return self._virtapi.aggregate_metadata_get(context, aggregate_id)
|
return self._virtapi.aggregate_metadata_get(context, aggregate_id)
|
||||||
|
|
||||||
def undo_aggregate_operation(self, context, op, aggregate_id,
|
def undo_aggregate_operation(self, context, op, aggregate,
|
||||||
host, set_error):
|
host, set_error):
|
||||||
"""Undo aggregate operation when pool error raised"""
|
"""Undo aggregate operation when pool error raised"""
|
||||||
try:
|
try:
|
||||||
if set_error:
|
if set_error:
|
||||||
metadata = {pool_states.KEY: pool_states.ERROR}
|
metadata = {pool_states.KEY: pool_states.ERROR}
|
||||||
self._virtapi.aggregate_metadata_add(context, aggregate_id,
|
self._virtapi.aggregate_metadata_add(context, aggregate['id'],
|
||||||
metadata)
|
metadata)
|
||||||
op(context, aggregate_id, host)
|
op(context, aggregate, host)
|
||||||
except Exception:
|
except Exception:
|
||||||
|
aggregate_id = aggregate['id']
|
||||||
LOG.exception(_('Aggregate %(aggregate_id)s: unrecoverable state '
|
LOG.exception(_('Aggregate %(aggregate_id)s: unrecoverable state '
|
||||||
'during operation on %(host)s') % locals())
|
'during operation on %(host)s') % locals())
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user