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:
		| @@ -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. | ||||||
|  |  | ||||||
|   | |||||||
| @@ -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() | ||||||
|  |  | ||||||
|   | |||||||
| @@ -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) | ||||||
|   | |||||||
| @@ -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): | ||||||
|   | |||||||
| @@ -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', | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 melanie witt
					melanie witt