def add_to_aggregate(self, context, aggregate, host, **kwargs): """Add a compute host to an aggregate.""" if not pool_states.is_hv_pool(context, aggregate.id): return invalid = { pool_states.CHANGING: 'setup in progress', pool_states.DISMISSED: 'aggregate deleted', pool_states.ERROR: 'aggregate in error' } if (db.aggregate_metadata_get(context, aggregate.id)[pool_states.KEY] in invalid.keys()): raise exception.InvalidAggregateAction( action='add host', aggregate_id=aggregate.id, reason=invalid[db.aggregate_metadata_get( context, aggregate.id)[pool_states.KEY]]) if (db.aggregate_metadata_get( context, aggregate.id)[pool_states.KEY] == pool_states.CREATED): db.aggregate_metadata_add(context, aggregate.id, {pool_states.KEY: pool_states.CHANGING}) if len(aggregate.hosts) == 1: # this is the first host of the pool -> make it master self._init_pool(aggregate.id, aggregate.name) # save metadata so that we can find the master again metadata = { 'master_compute': host, host: self._host_uuid, pool_states.KEY: pool_states.ACTIVE } db.aggregate_metadata_add(context, aggregate.id, metadata) else: # the pool is already up and running, we need to figure out # whether we can serve the request from this host or not. master_compute = db.aggregate_metadata_get( context, aggregate.id)['master_compute'] if master_compute == FLAGS.host and master_compute != host: # this is the master -> do a pool-join # To this aim, nova compute on the slave has to go down. # NOTE: it is assumed that ONLY nova compute is running now self._join_slave(aggregate.id, host, kwargs.get('compute_uuid'), kwargs.get('url'), kwargs.get('user'), kwargs.get('passwd')) metadata = { host: kwargs.get('xenhost_uuid'), } db.aggregate_metadata_add(context, aggregate.id, metadata) elif master_compute and master_compute != host: # send rpc cast to master, asking to add the following # host with specified credentials. forward_request(context, "add_aggregate_host", master_compute, aggregate.id, host, self._host_addr, self._host_uuid)
def test_aggregate_create_delete_create_with_metadata(self): """Ensure aggregate metadata is deleted bug 1052479.""" ctxt = context.get_admin_context() result = _create_aggregate(context=ctxt) expected_metadata = db.aggregate_metadata_get(ctxt, result['id']) self.assertDictMatch(expected_metadata, _get_fake_aggr_metadata()) db.aggregate_delete(ctxt, result['id']) result = _create_aggregate(metadata=None) expected_metadata = db.aggregate_metadata_get(ctxt, result['id']) self.assertEqual(expected_metadata, {})
def remove_from_aggregate(self, context, aggregate, host, **kwargs): """Remove a compute host from an aggregate.""" if not pool_states.is_hv_pool(context, aggregate.id): return invalid = { pool_states.CREATED: 'no hosts to remove', pool_states.CHANGING: 'setup in progress', pool_states.DISMISSED: 'aggregate deleted', } if (db.aggregate_metadata_get(context, aggregate.id)[pool_states.KEY] in invalid.keys()): raise exception.InvalidAggregateAction( action='remove host', aggregate_id=aggregate.id, reason=invalid[db.aggregate_metadata_get( context, aggregate.id)[pool_states.KEY]]) master_compute = db.aggregate_metadata_get( context, aggregate.id)['master_compute'] if master_compute == FLAGS.host and master_compute != host: # this is the master -> instruct it to eject a host from the pool host_uuid = db.aggregate_metadata_get(context, aggregate.id)[host] self._eject_slave(aggregate.id, kwargs.get('compute_uuid'), host_uuid) db.aggregate_metadata_delete(context, aggregate.id, host) elif master_compute == host: # Remove master from its own pool -> destroy pool only if the # master is on its own, otherwise raise fault. Destroying a # pool made only by master is fictional if len(aggregate.hosts) > 1: # NOTE: this could be avoided by doing a master # re-election, but this is simpler for now. raise exception.InvalidAggregateAction( aggregate_id=aggregate.id, action='remove_from_aggregate', reason=_('Unable to eject %(host)s ' 'from the pool; pool not empty') % locals()) self._clear_pool(aggregate.id) for key in ['master_compute', host]: db.aggregate_metadata_delete(context, aggregate.id, key) elif master_compute and master_compute != host: # A master exists -> forward pool-eject request to master forward_request(context, "remove_aggregate_host", master_compute, aggregate.id, host, self._host_addr, self._host_uuid) else: # this shouldn't have happened raise exception.AggregateError( aggregate_id=aggregate.id, action='remove_from_aggregate', reason=_('Unable to eject %(host)s ' 'from the pool; No master found') % locals())
def remove_from_aggregate(self, context, aggregate, host, **kwargs): """Remove a compute host from an aggregate.""" if not pool_states.is_hv_pool(context, aggregate.id): return invalid = {pool_states.CREATED: 'no hosts to remove', pool_states.CHANGING: 'setup in progress', pool_states.DISMISSED: 'aggregate deleted', } if (db.aggregate_metadata_get(context, aggregate.id)[pool_states.KEY] in invalid.keys()): raise exception.InvalidAggregateAction( action='remove host', aggregate_id=aggregate.id, reason=invalid[db.aggregate_metadata_get(context, aggregate.id)[pool_states.KEY]]) master_compute = db.aggregate_metadata_get(context, aggregate.id)['master_compute'] if master_compute == FLAGS.host and master_compute != host: # this is the master -> instruct it to eject a host from the pool host_uuid = db.aggregate_metadata_get(context, aggregate.id)[host] self._eject_slave(aggregate.id, kwargs.get('compute_uuid'), host_uuid) db.aggregate_metadata_delete(context, aggregate.id, host) elif master_compute == host: # Remove master from its own pool -> destroy pool only if the # master is on its own, otherwise raise fault. Destroying a # pool made only by master is fictional if len(aggregate.hosts) > 1: # NOTE: this could be avoided by doing a master # re-election, but this is simpler for now. raise exception.InvalidAggregateAction( aggregate_id=aggregate.id, action='remove_from_aggregate', reason=_('Unable to eject %(host)s ' 'from the pool; pool not empty') % locals()) self._clear_pool(aggregate.id) for key in ['master_compute', host]: db.aggregate_metadata_delete(context, aggregate.id, key) elif master_compute and master_compute != host: # A master exists -> forward pool-eject request to master forward_request(context, "remove_aggregate_host", master_compute, aggregate.id, host, self._host_addr, self._host_uuid) else: # this shouldn't have happened raise exception.AggregateError(aggregate_id=aggregate.id, action='remove_from_aggregate', reason=_('Unable to eject %(host)s ' 'from the pool; No master found') % locals())
def add_to_aggregate(self, context, aggregate, host, **kwargs): """Add a compute host to an aggregate.""" if not pool_states.is_hv_pool(context, aggregate.id): return invalid = {pool_states.CHANGING: 'setup in progress', pool_states.DISMISSED: 'aggregate deleted', pool_states.ERROR: 'aggregate in error'} if (db.aggregate_metadata_get(context, aggregate.id)[pool_states.KEY] in invalid.keys()): raise exception.InvalidAggregateAction( action='add host', aggregate_id=aggregate.id, reason=invalid[db.aggregate_metadata_get(context, aggregate.id) [pool_states.KEY]]) if (db.aggregate_metadata_get(context, aggregate.id)[pool_states.KEY] == pool_states.CREATED): db.aggregate_metadata_add(context, aggregate.id, {pool_states.KEY: pool_states.CHANGING}) if len(aggregate.hosts) == 1: # this is the first host of the pool -> make it master self._init_pool(aggregate.id, aggregate.name) # save metadata so that we can find the master again metadata = {'master_compute': host, host: self._host_uuid, pool_states.KEY: pool_states.ACTIVE} db.aggregate_metadata_add(context, aggregate.id, metadata) else: # the pool is already up and running, we need to figure out # whether we can serve the request from this host or not. master_compute = db.aggregate_metadata_get(context, aggregate.id)['master_compute'] if master_compute == FLAGS.host and master_compute != host: # this is the master -> do a pool-join # To this aim, nova compute on the slave has to go down. # NOTE: it is assumed that ONLY nova compute is running now self._join_slave(aggregate.id, host, kwargs.get('compute_uuid'), kwargs.get('url'), kwargs.get('user'), kwargs.get('passwd')) metadata = {host: kwargs.get('xenhost_uuid'), } db.aggregate_metadata_add(context, aggregate.id, metadata) elif master_compute and master_compute != host: # send rpc cast to master, asking to add the following # host with specified credentials. forward_request(context, "add_aggregate_host", master_compute, aggregate.id, host, self._host_addr, self._host_uuid)
def test_aggregate_create_with_metadata(self): """Ensure aggregate can be created with metadata.""" ctxt = context.get_admin_context() result = _create_aggregate(context=ctxt) expected_metadata = db.aggregate_metadata_get(ctxt, result['id']) self.assertThat(expected_metadata, matchers.DictMatches(_get_fake_aggr_metadata()))
def test_aggregate_metadata_add(self): """Ensure we can add metadata for the aggregate.""" ctxt = context.get_admin_context() result = _create_aggregate(context=ctxt, metadata=None) metadata = _get_fake_aggr_metadata() db.aggregate_metadata_add(ctxt, result.id, metadata) expected = db.aggregate_metadata_get(ctxt, result.id) self.assertDictMatch(metadata, expected)
def test_aggregate_update_with_metadata(self): """Ensure an aggregate can be updated with metadata.""" ctxt = context.get_admin_context() result = _create_aggregate(context=ctxt, metadata=None) values = _get_fake_aggr_values() values['metadata'] = _get_fake_aggr_metadata() db.aggregate_update(ctxt, 1, values) expected = db.aggregate_metadata_get(ctxt, result.id) self.assertDictMatch(_get_fake_aggr_metadata(), expected)
def test_aggregate_metadata_delete(self): """Ensure we can delete metadata for the aggregate.""" ctxt = context.get_admin_context() result = _create_aggregate(context=ctxt, metadata=None) metadata = _get_fake_aggr_metadata() db.aggregate_metadata_add(ctxt, result.id, metadata) db.aggregate_metadata_delete(ctxt, result.id, metadata.keys()[0]) expected = db.aggregate_metadata_get(ctxt, result.id) del metadata[metadata.keys()[0]] self.assertThat(metadata, matchers.DictMatches(expected))
def test_aggregate_update_with_existing_metadata(self): """Ensure an aggregate can be updated with existing metadata.""" ctxt = context.get_admin_context() result = _create_aggregate(context=ctxt) values = _get_fake_aggr_values() values['metadata'] = _get_fake_aggr_metadata() values['metadata']['fake_key1'] = 'foo' db.aggregate_update(ctxt, 1, values) expected = db.aggregate_metadata_get(ctxt, result.id) self.assertDictMatch(values['metadata'], expected)
def test_aggregate_metadata_update(self): """Ensure we can update metadata for the aggregate.""" ctxt = context.get_admin_context() result = _create_aggregate(context=ctxt) metadata = _get_fake_aggr_metadata() key = metadata.keys()[0] db.aggregate_metadata_delete(ctxt, result.id, key) new_metadata = {key: 'foo'} db.aggregate_metadata_add(ctxt, result.id, new_metadata) expected = db.aggregate_metadata_get(ctxt, result.id) metadata[key] = 'foo' self.assertDictMatch(metadata, expected)
def remove_from_aggregate(self, context, aggregate, host, **kwargs): """Remove a compute host from an aggregate.""" main_compute = aggregate.metadetails.get('main_compute') if main_compute == FLAGS.host and main_compute != host: # this is the main -> instruct it to eject a host from the pool host_uuid = db.aggregate_metadata_get(context, aggregate.id)[host] self._eject_subordinate(aggregate.id, kwargs.get('compute_uuid'), host_uuid) db.aggregate_metadata_delete(context, aggregate.id, host) elif main_compute == host: # Remove main from its own pool -> destroy pool only if the # main is on its own, otherwise raise fault. Destroying a # pool made only by main is fictional if len(aggregate.hosts) > 1: # NOTE: this could be avoided by doing a main # re-election, but this is simpler for now. raise exception.InvalidAggregateAction( aggregate_id=aggregate.id, action='remove_from_aggregate', reason=_('Unable to eject %(host)s ' 'from the pool; pool not empty') % locals()) self._clear_pool(aggregate.id) for key in ['main_compute', host]: db.aggregate_metadata_delete(context, aggregate.id, key) elif main_compute and main_compute != host: # A main exists -> forward pool-eject request to main forward_request(context, "remove_aggregate_host", main_compute, aggregate.id, host, self._host_addr, self._host_uuid) else: # this shouldn't have happened raise exception.AggregateError( aggregate_id=aggregate.id, action='remove_from_aggregate', reason=_('Unable to eject %(host)s ' 'from the pool; No main found') % locals())
def _is_hv_pool(self, context, aggregate_id): """Checks if aggregate is a hypervisor_pool""" metadata = db.aggregate_metadata_get(context, aggregate_id) return pool_states.POOL_FLAG in metadata.keys()
def aggregate_metadata_get(self, context, aggregate_id): return db.aggregate_metadata_get(context, aggregate_id)
def is_hv_pool(context, aggregate_id): """Checks if aggregate is a hypervisor_pool""" metadata = db.aggregate_metadata_get(context, aggregate_id) return POOL_FLAG in metadata.keys()
def test_aggregate_create_with_metadata(self): """Ensure aggregate can be created with metadata.""" ctxt = context.get_admin_context() result = _create_aggregate(context=ctxt) expected_metadata = db.aggregate_metadata_get(ctxt, result['id']) self.assertDictMatch(expected_metadata, _get_fake_aggr_metadata())