From 8c7fe145a76793c42786d9baaea63301c3dd5b6e Mon Sep 17 00:00:00 2001 From: Russell Bryant Date: Tue, 27 Nov 2012 17:24:19 -0500 Subject: Include 'hosts' and 'metadetails' in aggregate. When converting an Aggregate sqlalchemy model to primitive types using jsonutils.to_primitive(), the hosts and metadata were being left out. This is because they are implemented as properties on the model and must be explicitly listed as extra keys to be read. We also want to make sure that the _hosts and _metadata are eager loaded. This patch ensures this gets done by adding it to the _get_aggregate_query() helper, and making sure it is used everywhere that is appropriate. Also, on creation of the aggregate, just manually set _hosts and _metadata to empty lists, since we know they're empty at this point. These changes caused a side effect to the os-aggreages API extension. The result from creating an aggregate started including 'hosts' and 'metadata'. There's a hack in there to maintain the same API result. These don't add any value to this API call anyway, since we know they're blank at this point. Part of blueprint no-db-compute. Change-Id: I4048ea6f477f7a695701eb3ba57f97afca0c0e41 --- nova/compute/api.py | 9 ++++++++- nova/db/sqlalchemy/api.py | 26 ++++++++++++++++++++------ nova/db/sqlalchemy/models.py | 3 +++ 3 files changed, 31 insertions(+), 7 deletions(-) diff --git a/nova/compute/api.py b/nova/compute/api.py index c937b7cf5..79db499bd 100644 --- a/nova/compute/api.py +++ b/nova/compute/api.py @@ -2159,7 +2159,11 @@ class AggregateAPI(base.Base): values = {"name": aggregate_name, "availability_zone": availability_zone} aggregate = self.db.aggregate_create(context, values) - return dict(aggregate.iteritems()) + aggregate = self._get_aggregate_info(context, aggregate) + # To maintain the same API result as before. + del aggregate['hosts'] + del aggregate['metadata'] + return aggregate else: raise exception.InvalidAggregateAction(action='create_aggregate', aggregate_id="'N/A'", @@ -2236,6 +2240,9 @@ class AggregateAPI(base.Base): metadata = self.db.aggregate_metadata_get(context, aggregate.id) hosts = self.db.aggregate_host_get_all(context, aggregate.id) result = dict(aggregate.iteritems()) + # metadetails was not originally included here. We need to pull it + # back out to maintain API stability. + del result['metadetails'] result["metadata"] = metadata result["hosts"] = hosts return result diff --git a/nova/db/sqlalchemy/api.py b/nova/db/sqlalchemy/api.py index 96666079a..e423c3481 100644 --- a/nova/db/sqlalchemy/api.py +++ b/nova/db/sqlalchemy/api.py @@ -4161,10 +4161,20 @@ def s3_image_create(context, image_uuid): #################### -def _aggregate_get_query(context, model_class, id_field, id, +def _aggregate_get_query(context, model_class, id_field=None, id=None, session=None, read_deleted=None): - return model_query(context, model_class, session=session, - read_deleted=read_deleted).filter(id_field == id) + columns_to_join = {models.Aggregate: ['_hosts', '_metadata']} + + query = model_query(context, model_class, session=session, + read_deleted=read_deleted) + + for c in columns_to_join.get(model_class, []): + query = query.options(joinedload(c)) + + if id and id_field: + query = query.filter(id_field == id) + + return query @require_admin_context @@ -4180,6 +4190,10 @@ def aggregate_create(context, values, metadata=None): aggregate = models.Aggregate() aggregate.update(values) aggregate.save(session=session) + # We don't want these to be lazy loaded later. We know there is + # nothing here since we just created this aggregate. + aggregate._hosts = [] + aggregate._metadata = [] else: raise exception.AggregateNameExists(aggregate_name=values['name']) if metadata: @@ -4202,8 +4216,8 @@ def aggregate_get(context, aggregate_id): @require_admin_context def aggregate_get_by_host(context, host, key=None): - query = model_query(context, models.Aggregate).join( - "_hosts").filter(models.AggregateHost.host == host) + query = _aggregate_get_query(context, models.Aggregate, + models.AggregateHost.host, host) if key: query = query.join("_metadata").filter( @@ -4275,7 +4289,7 @@ def aggregate_delete(context, aggregate_id): @require_admin_context def aggregate_get_all(context): - return model_query(context, models.Aggregate).all() + return _aggregate_get_query(context, models.Aggregate).all() @require_admin_context diff --git a/nova/db/sqlalchemy/models.py b/nova/db/sqlalchemy/models.py index 48caaf18d..a09517b67 100644 --- a/nova/db/sqlalchemy/models.py +++ b/nova/db/sqlalchemy/models.py @@ -900,6 +900,9 @@ class Aggregate(BASE, NovaBase): 'Aggregate.deleted == False)', backref='aggregates') + def _extra_keys(self): + return ['hosts', 'metadetails'] + @property def hosts(self): return [h.host for h in self._hosts] -- cgit