Make Aggregate.save work with the API db
Aggregate.save now updates aggregates if they are located in the api db. blueprint cells-aggregate-api-db Co-Authored-By: Dan Smith <dansmith@redhat.com> Change-Id: I6066857a421bfe489ae70f0e22f338c434195bf9
This commit is contained in:
parent
d62b60ec0f
commit
2110b69656
@ -159,6 +159,35 @@ def _metadata_delete_from_db(context, aggregate_id, key):
|
||||
aggregate_id=aggregate_id, metadata_key=key)
|
||||
|
||||
|
||||
@db_api.api_context_manager.writer
|
||||
def _aggregate_update_to_db(context, aggregate_id, values):
|
||||
aggregate = _aggregate_get_from_db(context, aggregate_id)
|
||||
|
||||
set_delete = True
|
||||
if "availability_zone" in values:
|
||||
az = values.pop('availability_zone')
|
||||
if 'metadata' not in values:
|
||||
values['metadata'] = {'availability_zone': az}
|
||||
set_delete = False
|
||||
else:
|
||||
values['metadata']['availability_zone'] = az
|
||||
metadata = values.get('metadata')
|
||||
if metadata is not None:
|
||||
_metadata_add_to_db(context, aggregate_id, values.pop('metadata'),
|
||||
set_delete=set_delete)
|
||||
|
||||
aggregate.update(values)
|
||||
try:
|
||||
aggregate.save(context.session)
|
||||
except db_exc.DBDuplicateEntry:
|
||||
if 'name' in values:
|
||||
raise exception.AggregateNameExists(
|
||||
aggregate_name=values['name'])
|
||||
else:
|
||||
raise
|
||||
return _aggregate_get_from_db(context, aggregate_id)
|
||||
|
||||
|
||||
@base.NovaObjectRegistry.register
|
||||
class Aggregate(base.NovaPersistentObject, base.NovaObject):
|
||||
# Version 1.0: Initial version
|
||||
@ -295,7 +324,13 @@ class Aggregate(base.NovaPersistentObject, base.NovaObject):
|
||||
"updateprop.start",
|
||||
payload)
|
||||
updates.pop('id', None)
|
||||
db_aggregate = db.aggregate_update(self._context, self.id, updates)
|
||||
db_aggregate = None
|
||||
try:
|
||||
db_aggregate = _aggregate_update_to_db(self._context,
|
||||
self.id, updates)
|
||||
except exception.AggregateNotFound:
|
||||
db_aggregate = db.aggregate_update(self._context, self.id, updates)
|
||||
|
||||
compute_utils.notify_about_aggregate_update(self._context,
|
||||
"updateprop.end",
|
||||
payload)
|
||||
|
@ -205,6 +205,74 @@ class AggregateObjectDbTestCase(test.NoDBTestCase):
|
||||
key='goodkey')
|
||||
self.assertEqual(2, len(rl1))
|
||||
|
||||
def test_aggregate_update(self):
|
||||
created = _create_aggregate(self.context,
|
||||
metadata={'availability_zone': 'fake_avail_zone'})
|
||||
result = aggregate_obj._aggregate_get_from_db(self.context,
|
||||
created['id'])
|
||||
self.assertEqual(result['availability_zone'], 'fake_avail_zone')
|
||||
new_values = deepcopy(_get_fake_aggregate(1, result=False))
|
||||
new_values['availability_zone'] = 'different_avail_zone'
|
||||
updated = aggregate_obj._aggregate_update_to_db(self.context,
|
||||
result['id'], new_values)
|
||||
self.assertEqual('different_avail_zone', updated['availability_zone'])
|
||||
|
||||
def test_aggregate_update_with_metadata(self):
|
||||
result = _create_aggregate(self.context, metadata=None)
|
||||
values = deepcopy(_get_fake_aggregate(1, result=False))
|
||||
values['metadata'] = deepcopy(_get_fake_metadata(1))
|
||||
values['availability_zone'] = 'different_avail_zone'
|
||||
expected_metadata = deepcopy(values['metadata'])
|
||||
expected_metadata['availability_zone'] = values['availability_zone']
|
||||
aggregate_obj._aggregate_update_to_db(self.context, result['id'],
|
||||
values)
|
||||
metadata = _aggregate_metadata_get_all(self.context, result['id'])
|
||||
updated = aggregate_obj._aggregate_get_from_db(self.context,
|
||||
result['id'])
|
||||
self.assertThat(metadata,
|
||||
matchers.DictMatches(expected_metadata))
|
||||
self.assertEqual('different_avail_zone', updated['availability_zone'])
|
||||
|
||||
def test_aggregate_update_with_existing_metadata(self):
|
||||
result = _create_aggregate(self.context)
|
||||
values = deepcopy(_get_fake_aggregate(1, result=False))
|
||||
values['metadata'] = deepcopy(_get_fake_metadata(1))
|
||||
values['metadata']['fake_key1'] = 'foo'
|
||||
expected_metadata = deepcopy(values['metadata'])
|
||||
aggregate_obj._aggregate_update_to_db(self.context, result['id'],
|
||||
values)
|
||||
metadata = _aggregate_metadata_get_all(self.context, result['id'])
|
||||
self.assertThat(metadata, matchers.DictMatches(expected_metadata))
|
||||
|
||||
def test_aggregate_update_zone_with_existing_metadata(self):
|
||||
result = _create_aggregate(self.context)
|
||||
new_zone = {'availability_zone': 'fake_avail_zone_2'}
|
||||
metadata = deepcopy(_get_fake_metadata(1))
|
||||
metadata.update(new_zone)
|
||||
aggregate_obj._aggregate_update_to_db(self.context, result['id'],
|
||||
new_zone)
|
||||
expected = _aggregate_metadata_get_all(self.context, result['id'])
|
||||
self.assertThat(metadata, matchers.DictMatches(expected))
|
||||
|
||||
def test_aggregate_update_raise_not_found(self):
|
||||
# this does not exist!
|
||||
aggregate_id = 2
|
||||
new_values = deepcopy(_get_fake_aggregate(1, result=False))
|
||||
self.assertRaises(exception.AggregateNotFound,
|
||||
aggregate_obj._aggregate_update_to_db,
|
||||
self.context, aggregate_id, new_values)
|
||||
|
||||
def test_aggregate_update_raise_name_exist(self):
|
||||
_create_aggregate(self.context, values={'name': 'test1'},
|
||||
metadata={'availability_zone': 'fake_avail_zone'})
|
||||
_create_aggregate(self.context, values={'name': 'test2'},
|
||||
metadata={'availability_zone': 'fake_avail_zone'})
|
||||
aggregate_id = 1
|
||||
new_values = {'name': 'test2'}
|
||||
self.assertRaises(exception.AggregateNameExists,
|
||||
aggregate_obj._aggregate_update_to_db,
|
||||
self.context, aggregate_id, new_values)
|
||||
|
||||
def test_aggregate_host_add_to_db(self):
|
||||
result = _create_aggregate(self.context, metadata=None)
|
||||
host = _get_fake_hosts(1)[0]
|
||||
|
@ -140,18 +140,39 @@ class _TestAggregateObject(object):
|
||||
{'name': 'foo', 'uuid': uuidsentinel.fake_agg},
|
||||
metadata={'one': 'two'})
|
||||
|
||||
@mock.patch.object(db, 'aggregate_update')
|
||||
def test_save(self, mock_aggregate_update):
|
||||
mock_aggregate_update.return_value = fake_aggregate
|
||||
|
||||
@mock.patch('nova.objects.aggregate._aggregate_update_to_db')
|
||||
@mock.patch('nova.db.aggregate_update')
|
||||
def test_save(self, update_mock, api_update_mock):
|
||||
api_update_mock.side_effect = exception.AggregateNotFound(
|
||||
aggregate_id='foo')
|
||||
update_mock.return_value = fake_aggregate
|
||||
agg = aggregate.Aggregate(context=self.context)
|
||||
agg.id = 123
|
||||
agg.name = 'baz'
|
||||
agg.name = 'fake-aggregate'
|
||||
agg.save()
|
||||
self.compare_obj(agg, fake_aggregate, subs=SUBS)
|
||||
update_mock.assert_called_once_with(self.context,
|
||||
123,
|
||||
{'name': 'fake-aggregate'})
|
||||
self.assertTrue(api_update_mock.called)
|
||||
|
||||
mock_aggregate_update.aasert_called_once_with(self.context,
|
||||
123, {'name': 'baz'})
|
||||
@mock.patch('nova.objects.Aggregate.in_api', return_value=True)
|
||||
@mock.patch('nova.objects.aggregate._aggregate_update_to_db')
|
||||
@mock.patch('nova.db.aggregate_update')
|
||||
def test_save_to_api(self, update_mock, api_update_mock, in_api_mock):
|
||||
api_update_mock.return_value = fake_aggregate
|
||||
agg = aggregate.Aggregate(context=self.context)
|
||||
agg.id = 123
|
||||
agg.name = 'fake-api-aggregate'
|
||||
agg.save()
|
||||
self.compare_obj(agg, fake_aggregate, subs=SUBS)
|
||||
api_update_mock.assert_called_once_with(self.context,
|
||||
123,
|
||||
{'name': 'fake-api-aggregate'})
|
||||
self.assertFalse(update_mock.called)
|
||||
|
||||
api_update_mock.assert_called_once_with(self.context,
|
||||
123, {'name': 'fake-api-aggregate'})
|
||||
|
||||
def test_save_and_create_no_hosts(self):
|
||||
agg = aggregate.Aggregate(context=self.context)
|
||||
|
Loading…
x
Reference in New Issue
Block a user