Add fill_metadata() to InstanceList
This adds a non-remotable method to InstanceList which will batch- fill system_metadata for all the instances in the list that are missing it in as efficient of a manner as possible. This does not require an object bump because no remotable methods or fields are changed. Related to blueprint image-metadata-props-weigher Change-Id: Icc47de2b677b3d212a7f6faa61a85ea9bff9f412
This commit is contained in:
@@ -1521,6 +1521,18 @@ def _instances_fill_metadata(context, instances, manual_joins=None):
|
||||
return filled_instances
|
||||
|
||||
|
||||
@require_context
|
||||
@pick_context_manager_reader
|
||||
def instances_fill_metadata(context, instances, manual_joins=None):
|
||||
"""Selectively fill instances with manually-joined metadata.
|
||||
|
||||
See _instances_fill_metadata(). This is only for use as a standalone
|
||||
operation in its own transaction.
|
||||
"""
|
||||
return _instances_fill_metadata(context, instances,
|
||||
manual_joins=manual_joins)
|
||||
|
||||
|
||||
def _manual_join_columns(columns_to_join):
|
||||
"""Separate manually joined columns from columns_to_join
|
||||
|
||||
|
||||
@@ -1588,6 +1588,26 @@ class InstanceList(base.ObjectListBase, base.NovaObject):
|
||||
|
||||
return faults_by_uuid.keys()
|
||||
|
||||
def fill_metadata(self):
|
||||
# NOTE(danms): This only fills system_metadata currently, but could
|
||||
# be extended to support user metadata if needed in the future.
|
||||
# Make a uuid-indexed dict of non-object instance dicts that the DB
|
||||
# layer can use. They need only contain the uuid of the instances
|
||||
# we are looking up. Any of them that already have system_metadata
|
||||
# need not be included.
|
||||
db_inst_shells = {inst.uuid: {'uuid': inst.uuid} for inst in self
|
||||
if 'system_metadata' not in inst}
|
||||
if db_inst_shells:
|
||||
updates = db.instances_fill_metadata(
|
||||
self._context,
|
||||
db_inst_shells.values(),
|
||||
manual_joins=['system_metadata'])
|
||||
updated = {i['uuid']: i for i in updates}
|
||||
for inst in [i for i in self if i.uuid in updated]:
|
||||
# Patch up our instances with system_metadata from the fill
|
||||
# operation
|
||||
inst.system_metadata = utils.instance_sys_meta(updated)
|
||||
|
||||
@base.remotable_classmethod
|
||||
def get_uuids_by_host(cls, context, host):
|
||||
return db.instance_get_all_uuids_by_hosts(context, [host])[host]
|
||||
|
||||
@@ -2060,6 +2060,49 @@ class TestInstanceListObject(test_objects._LocalTest,
|
||||
{})
|
||||
self.assertEqual(2, len(insts))
|
||||
|
||||
def test_fill_metadata(self):
|
||||
values = {'user_id': self.context.user_id,
|
||||
'project_id': self.context.project_id,
|
||||
'host': 'foo'}
|
||||
|
||||
for i in range(5):
|
||||
db.instance_create(self.context,
|
||||
dict(values))
|
||||
|
||||
insts = objects.InstanceList.get_all(self.context)
|
||||
self.assertEqual(5, len(insts))
|
||||
|
||||
# One instance has system_metadata populated *and* saved in the DB
|
||||
insts[1].system_metadata = {'BTTF1': '1955'}
|
||||
insts[1].save()
|
||||
|
||||
# One instance has system_metadata populated but dirty
|
||||
insts[2].system_metadata = {'bttf3': '1885'}
|
||||
|
||||
# Three do not have system_metadata populated
|
||||
self.assertEqual(3, len([i for i in insts
|
||||
if 'system_metadata' not in i]))
|
||||
|
||||
insts.fill_metadata()
|
||||
|
||||
# Now all five have it populated
|
||||
self.assertEqual(0, len([i for i in insts
|
||||
if 'system_metadata' not in i]))
|
||||
|
||||
# Inst 2 should have not had its in-memory copy clobbered
|
||||
self.assertEqual({'bttf3': '1885'}, insts[2].system_metadata)
|
||||
|
||||
# Inst 1 should have system_metadata loaded, but empty
|
||||
self.assertIn('system_metadata', insts[0])
|
||||
self.assertEqual({}, insts[0].system_metadata)
|
||||
|
||||
def test_fill_metadata_nop(self):
|
||||
insts = objects.InstanceList([objects.Instance(uuid=uuids.inst,
|
||||
system_metadata={})])
|
||||
# This would fail if it tries to actually load anything
|
||||
# because context is None
|
||||
insts.fill_metadata()
|
||||
|
||||
|
||||
class TestRemoteInstanceListObject(test_objects._RemoteTest,
|
||||
_TestInstanceListObject):
|
||||
|
||||
Reference in New Issue
Block a user