add get_by_metadata_key to AggregateList object

This change adds the get_by_metadata_key function to the AggregateList object
and the aggregate_get_by_metadata_key function to the DB API.

Previously, the only DB API function available for finding aggregates matching
a metadata key returned a dictionary of aggregated metadata. The
aggregate_get_by_metadata_key function returns all rows matching the specified
metadata key, and is called by the existing aggregate_host_get_by_metadata_key
DB API function.

The get_by_metadata_key function returns a list of Aggregate objects matching
the specified metadata key.

Related to blueprint compute-manager-objects-juno

Change-Id: If50c9f613dd192ab44577f26a81dd5b40e3a7af7
This commit is contained in:
melanie witt
2014-06-24 23:08:20 +00:00
parent b8e3902881
commit a167654eb3
5 changed files with 67 additions and 9 deletions

View File

@@ -1769,6 +1769,10 @@ def aggregate_host_get_by_metadata_key(context, key):
return IMPL.aggregate_host_get_by_metadata_key(context, key) return IMPL.aggregate_host_get_by_metadata_key(context, key)
def aggregate_get_by_metadata_key(context, key):
return IMPL.aggregate_get_by_metadata_key(context, key)
def aggregate_update(context, aggregate_id, values): def aggregate_update(context, aggregate_id, values):
"""Update the attributes of an aggregates. """Update the attributes of an aggregates.

View File

@@ -5094,13 +5094,7 @@ def aggregate_metadata_get_by_metadata_key(context, aggregate_id, key):
def aggregate_host_get_by_metadata_key(context, key): def aggregate_host_get_by_metadata_key(context, key):
query = model_query(context, models.Aggregate) rows = aggregate_get_by_metadata_key(context, key)
query = query.join("_metadata")
query = query.filter(models.AggregateMetadata.key == key)
query = query.options(contains_eager("_metadata"))
query = query.options(joinedload("_hosts"))
rows = query.all()
metadata = collections.defaultdict(set) metadata = collections.defaultdict(set)
for agg in rows: for agg in rows:
for agghost in agg._hosts: for agghost in agg._hosts:
@@ -5108,6 +5102,19 @@ def aggregate_host_get_by_metadata_key(context, key):
return dict(metadata) return dict(metadata)
def aggregate_get_by_metadata_key(context, key):
"""Return rows that match metadata key.
:param key Matches metadata key.
"""
query = model_query(context, models.Aggregate)
query = query.join("_metadata")
query = query.filter(models.AggregateMetadata.key == key)
query = query.options(contains_eager("_metadata"))
query = query.options(joinedload("_hosts"))
return query.all()
def aggregate_update(context, aggregate_id, values): def aggregate_update(context, aggregate_id, values):
session = get_session() session = get_session()

View File

@@ -151,7 +151,8 @@ class AggregateList(base.ObjectListBase, base.NovaObject):
# Version 1.0: Initial version # Version 1.0: Initial version
# Version 1.1: Added key argument to get_by_host() # Version 1.1: Added key argument to get_by_host()
# Aggregate <= version 1.1 # Aggregate <= version 1.1
VERSION = '1.1' # Version 1.2: Added get_by_metadata_key
VERSION = '1.2'
fields = { fields = {
'objects': fields.ListOfObjectsField('Aggregate'), 'objects': fields.ListOfObjectsField('Aggregate'),
@@ -160,8 +161,21 @@ class AggregateList(base.ObjectListBase, base.NovaObject):
'1.0': '1.1', '1.0': '1.1',
'1.1': '1.1', '1.1': '1.1',
# NOTE(danms): Aggregate was at 1.1 before we added this # NOTE(danms): Aggregate was at 1.1 before we added this
'1.2': '1.1',
} }
@classmethod
def _filter_db_aggregates(cls, db_aggregates, hosts):
if not isinstance(hosts, set):
hosts = set(hosts)
filtered_aggregates = []
for db_aggregate in db_aggregates:
for host in db_aggregate['hosts']:
if host in hosts:
filtered_aggregates.append(db_aggregate)
break
return filtered_aggregates
@base.remotable_classmethod @base.remotable_classmethod
def get_all(cls, context): def get_all(cls, context):
db_aggregates = db.aggregate_get_all(context) db_aggregates = db.aggregate_get_all(context)
@@ -173,3 +187,11 @@ class AggregateList(base.ObjectListBase, base.NovaObject):
db_aggregates = db.aggregate_get_by_host(context, host, key=key) db_aggregates = db.aggregate_get_by_host(context, host, key=key)
return base.obj_make_list(context, cls(context), objects.Aggregate, return base.obj_make_list(context, cls(context), objects.Aggregate,
db_aggregates) db_aggregates)
@base.remotable_classmethod
def get_by_metadata_key(cls, context, key, hosts=None):
db_aggregates = db.aggregate_get_by_metadata_key(context, key=key)
if hosts:
db_aggregates = cls._filter_db_aggregates(db_aggregates, hosts)
return base.obj_make_list(context, cls(context), objects.Aggregate,
db_aggregates)

View File

@@ -12,6 +12,8 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
import mock
from nova import db from nova import db
from nova import exception from nova import exception
from nova.objects import aggregate from nova.objects import aggregate
@@ -163,6 +165,29 @@ class _TestAggregateObject(object):
self.assertEqual(1, len(aggs)) self.assertEqual(1, len(aggs))
self.compare_obj(aggs[0], fake_aggregate, subs=SUBS) self.compare_obj(aggs[0], fake_aggregate, subs=SUBS)
@mock.patch('nova.db.aggregate_get_by_metadata_key')
def test_get_by_metadata_key(self, get_by_metadata_key):
get_by_metadata_key.return_value = [fake_aggregate]
aggs = aggregate.AggregateList.get_by_metadata_key(
self.context, 'this')
self.assertEqual(1, len(aggs))
self.compare_obj(aggs[0], fake_aggregate, subs=SUBS)
@mock.patch('nova.db.aggregate_get_by_metadata_key')
def test_get_by_metadata_key_and_hosts_no_match(self, get_by_metadata_key):
get_by_metadata_key.return_value = [fake_aggregate]
aggs = aggregate.AggregateList.get_by_metadata_key(
self.context, 'this', hosts=['baz'])
self.assertEqual(0, len(aggs))
@mock.patch('nova.db.aggregate_get_by_metadata_key')
def test_get_by_metadata_key_and_hosts_match(self, get_by_metadata_key):
get_by_metadata_key.return_value = [fake_aggregate]
aggs = aggregate.AggregateList.get_by_metadata_key(
self.context, 'this', hosts=['foo', 'bar'])
self.assertEqual(1, len(aggs))
self.compare_obj(aggs[0], fake_aggregate, subs=SUBS)
class TestAggregateObject(test_objects._LocalTest, class TestAggregateObject(test_objects._LocalTest,
_TestAggregateObject): _TestAggregateObject):

View File

@@ -895,7 +895,7 @@ object_data = {
'Agent': '1.0-c4ff8a833aee8ae44ab8aed1a171273d', 'Agent': '1.0-c4ff8a833aee8ae44ab8aed1a171273d',
'AgentList': '1.0-f8b860e1f2ce80e676ba1a37ddf86e4f', 'AgentList': '1.0-f8b860e1f2ce80e676ba1a37ddf86e4f',
'Aggregate': '1.1-f5d477be06150529a9b2d27cc49030b5', 'Aggregate': '1.1-f5d477be06150529a9b2d27cc49030b5',
'AggregateList': '1.1-3e67b6a4840b19c797504cc6056b27ff', 'AggregateList': '1.2-504137b7ec3855b00d01f165dcebc23e',
'BlockDeviceMapping': '1.1-9968ffe513e7672484b0f528b034cd0f', 'BlockDeviceMapping': '1.1-9968ffe513e7672484b0f528b034cd0f',
'BlockDeviceMappingList': '1.2-d6d7df540ca149dda78b22b4b10bdef3', 'BlockDeviceMappingList': '1.2-d6d7df540ca149dda78b22b4b10bdef3',
'ComputeNode': '1.3-b3b8935a99ca48621dc9ba271d5ed668', 'ComputeNode': '1.3-b3b8935a99ca48621dc9ba271d5ed668',