summaryrefslogtreecommitdiffstats
path: root/nova
diff options
context:
space:
mode:
authorJenkins <jenkins@review.openstack.org>2013-01-09 04:09:00 +0000
committerGerrit Code Review <review@openstack.org>2013-01-09 04:09:00 +0000
commitdcd4327bd05a637bc49166920ccecf33e7ea4d5a (patch)
tree71be533ee37fa28a35d4d408444a34e6d8c9bd28 /nova
parentbeee8b112a92475d0e0cf575f5bcebefe3bc6188 (diff)
parent9f4534ab584faeee1e24d4c1bb38a2b194f24626 (diff)
downloadnova-dcd4327bd05a637bc49166920ccecf33e7ea4d5a.tar.gz
nova-dcd4327bd05a637bc49166920ccecf33e7ea4d5a.tar.xz
nova-dcd4327bd05a637bc49166920ccecf33e7ea4d5a.zip
Merge "Enable Aggregate based availability zones"
Diffstat (limited to 'nova')
-rw-r--r--nova/api/ec2/cloud.py17
-rw-r--r--nova/compute/api.py25
-rw-r--r--nova/db/api.py8
-rw-r--r--nova/db/sqlalchemy/api.py52
-rw-r--r--nova/db/sqlalchemy/migrate_repo/versions/146_aggregate_zones.py57
-rw-r--r--nova/db/sqlalchemy/models.py9
-rw-r--r--nova/scheduler/filters/availability_zone_filter.py17
-rw-r--r--nova/tests/api/ec2/test_cloud.py10
-rw-r--r--nova/tests/api/openstack/compute/contrib/test_aggregates.py16
-rw-r--r--nova/tests/compute/test_compute.py28
-rw-r--r--nova/tests/conductor/test_conductor.py2
-rw-r--r--nova/tests/integrated/api_samples/os-aggregates/aggregate-update-post-resp.json.tpl4
-rw-r--r--nova/tests/integrated/api_samples/os-aggregates/aggregate-update-post-resp.xml.tpl4
-rw-r--r--nova/tests/integrated/api_samples/os-aggregates/aggregates-add-host-post-resp.json.tpl4
-rw-r--r--nova/tests/integrated/api_samples/os-aggregates/aggregates-add-host-post-resp.xml.tpl4
-rw-r--r--nova/tests/integrated/api_samples/os-aggregates/aggregates-get-resp.json.tpl4
-rw-r--r--nova/tests/integrated/api_samples/os-aggregates/aggregates-get-resp.xml.tpl4
-rw-r--r--nova/tests/integrated/api_samples/os-aggregates/aggregates-list-get-resp.json.tpl4
-rw-r--r--nova/tests/integrated/api_samples/os-aggregates/aggregates-list-get-resp.xml.tpl4
-rw-r--r--nova/tests/integrated/api_samples/os-aggregates/aggregates-metadata-post-resp.json.tpl1
-rw-r--r--nova/tests/integrated/api_samples/os-aggregates/aggregates-metadata-post-resp.xml.tpl1
-rw-r--r--nova/tests/integrated/api_samples/os-aggregates/aggregates-remove-host-post-resp.json.tpl4
-rw-r--r--nova/tests/integrated/api_samples/os-aggregates/aggregates-remove-host-post-resp.xml.tpl4
-rw-r--r--nova/tests/scheduler/test_host_filters.py7
-rw-r--r--nova/tests/test_db_api.py123
-rw-r--r--nova/tests/test_migrations.py34
-rw-r--r--nova/tests/test_xenapi.py19
27 files changed, 304 insertions, 162 deletions
diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py
index a764a99bf..eb8139ad0 100644
--- a/nova/api/ec2/cloud.py
+++ b/nova/api/ec2/cloud.py
@@ -257,12 +257,18 @@ class CloudController(object):
if not zone in available_zones:
available_zones.append(zone)
+ # aggregate based availability_zones
+ metadata = db.aggregate_host_get_by_metadata_key(context,
+ key='availability_zone')
+ for zone_set in metadata.values():
+ for zone in zone_set:
+ if zone not in available_zones:
+ available_zones.append(zone)
not_available_zones = []
for zone in [service.availability_zone for service in disabled_services
if not service['availability_zone'] in available_zones]:
if not zone in not_available_zones:
not_available_zones.append(zone)
-
return (available_zones, not_available_zones)
def _describe_availability_zones(self, context, **kwargs):
@@ -294,6 +300,15 @@ class CloudController(object):
host_services.setdefault(service['host'], [])
host_services[service['host']].append(service)
+ # aggregate based available_zones
+ metadata = db.aggregate_host_get_by_metadata_key(context,
+ key='availability_zone')
+ # metdata: {machine: set( az1, az2 )}
+ for host, zones in metadata.items():
+ for zone in zones:
+ zone_hosts.setdefault(zone, [])
+ if host not in zone_hosts[zone]:
+ zone_hosts[zone].append(host)
result = []
for zone in available_zones:
diff --git a/nova/compute/api.py b/nova/compute/api.py
index f42891f89..b840dbc6b 100644
--- a/nova/compute/api.py
+++ b/nova/compute/api.py
@@ -2187,22 +2187,15 @@ class AggregateAPI(base.Base):
def create_aggregate(self, context, aggregate_name, availability_zone):
"""Creates the model for the aggregate."""
- zones = [s['availability_zone'] for s in
- self.db.service_get_all_by_topic(context,
- CONF.compute_topic)]
- if availability_zone in zones:
- values = {"name": aggregate_name,
- "availability_zone": availability_zone}
- aggregate = self.db.aggregate_create(context, values)
- 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'",
- reason='invalid zone')
+
+ values = {"name": aggregate_name}
+ aggregate = self.db.aggregate_create(context, values,
+ metadata={'availability_zone': availability_zone})
+ aggregate = self._get_aggregate_info(context, aggregate)
+ # To maintain the same API result as before.
+ del aggregate['hosts']
+ del aggregate['metadata']
+ return aggregate
def get_aggregate(self, context, aggregate_id):
"""Get an aggregate by id."""
diff --git a/nova/db/api.py b/nova/db/api.py
index 1322c29e9..8d93701c8 100644
--- a/nova/db/api.py
+++ b/nova/db/api.py
@@ -1543,6 +1543,14 @@ def aggregate_metadata_get_by_host(context, host, key=None):
return IMPL.aggregate_metadata_get_by_host(context, host, key)
+def aggregate_host_get_by_metadata_key(context, key):
+ """Get hosts with a specific metadata key metadata for all aggregates.
+
+ Returns a dictionary where each key is a hostname and each value is the
+ key value"""
+ return IMPL.aggregate_host_get_by_metadata_key(context, key)
+
+
def aggregate_update(context, aggregate_id, values):
"""Update the attributes of an aggregates. If values contains a metadata
key, it updates the aggregate metadata too."""
diff --git a/nova/db/sqlalchemy/api.py b/nova/db/sqlalchemy/api.py
index 57004be58..f89ebfaa3 100644
--- a/nova/db/sqlalchemy/api.py
+++ b/nova/db/sqlalchemy/api.py
@@ -4256,12 +4256,13 @@ def _aggregate_get_query(context, model_class, id_field=None, id=None,
@require_admin_context
def aggregate_create(context, values, metadata=None):
session = get_session()
- aggregate = _aggregate_get_query(context,
- models.Aggregate,
- models.Aggregate.name,
- values['name'],
- session=session,
- read_deleted='no').first()
+ query = _aggregate_get_query(context,
+ models.Aggregate,
+ models.Aggregate.name,
+ values['name'],
+ session=session,
+ read_deleted='no')
+ aggregate = query.options(joinedload('_metadata')).first()
if not aggregate:
aggregate = models.Aggregate()
aggregate.update(values)
@@ -4274,15 +4275,16 @@ def aggregate_create(context, values, metadata=None):
raise exception.AggregateNameExists(aggregate_name=values['name'])
if metadata:
aggregate_metadata_add(context, aggregate.id, metadata)
- return aggregate
+ return aggregate_get(context, aggregate.id)
@require_admin_context
def aggregate_get(context, aggregate_id):
- aggregate = _aggregate_get_query(context,
- models.Aggregate,
- models.Aggregate.id,
- aggregate_id).first()
+ query = _aggregate_get_query(context,
+ models.Aggregate,
+ models.Aggregate.id,
+ aggregate_id)
+ aggregate = query.options(joinedload('_metadata')).first()
if not aggregate:
raise exception.AggregateNotFound(aggregate_id=aggregate_id)
@@ -4314,18 +4316,38 @@ def aggregate_metadata_get_by_host(context, host, key=None):
for agg in rows:
for kv in agg._metadata:
metadata[kv['key']].add(kv['value'])
- return metadata
+ return dict(metadata)
+
+
+@require_admin_context
+def aggregate_host_get_by_metadata_key(context, key):
+ query = model_query(context, models.Aggregate).join(
+ "_metadata").filter(models.AggregateMetadata.key == key)
+ rows = query.all()
+ metadata = collections.defaultdict(set)
+ for agg in rows:
+ for agghost in agg._hosts:
+ metadata[agghost.host].add(agg._metadata[0]['value'])
+ return dict(metadata)
@require_admin_context
def aggregate_update(context, aggregate_id, values):
session = get_session()
- aggregate = _aggregate_get_query(context,
+ aggregate = (_aggregate_get_query(context,
models.Aggregate,
models.Aggregate.id,
aggregate_id,
- session=session).first()
+ session=session).
+ options(joinedload('_metadata')).first())
+
if aggregate:
+ if "availability_zone" in values:
+ az = values.pop('availability_zone')
+ if 'metadata' not in values:
+ values['metadata'] = {'availability_zone': az}
+ else:
+ values['metadata']['availability_zone'] = az
metadata = values.get('metadata')
if metadata is not None:
aggregate_metadata_add(context,
@@ -4336,7 +4358,7 @@ def aggregate_update(context, aggregate_id, values):
aggregate.update(values)
aggregate.save(session=session)
values['metadata'] = metadata
- return aggregate
+ return aggregate_get(context, aggregate.id)
else:
raise exception.AggregateNotFound(aggregate_id=aggregate_id)
diff --git a/nova/db/sqlalchemy/migrate_repo/versions/146_aggregate_zones.py b/nova/db/sqlalchemy/migrate_repo/versions/146_aggregate_zones.py
new file mode 100644
index 000000000..04f31ce5f
--- /dev/null
+++ b/nova/db/sqlalchemy/migrate_repo/versions/146_aggregate_zones.py
@@ -0,0 +1,57 @@
+# Copyright 2012 OpenStack LLC.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+from sqlalchemy import String, Column, MetaData, Table, delete, select
+
+from nova.openstack.common import log as logging
+
+LOG = logging.getLogger(__name__)
+
+
+def upgrade(migrate_engine):
+ meta = MetaData()
+ meta.bind = migrate_engine
+
+ aggregates = Table('aggregates', meta, autoload=True)
+ aggregate_metadata = Table('aggregate_metadata', meta, autoload=True)
+ # migrate data
+ record_list = list(aggregates.select().execute())
+ for rec in record_list:
+ row = aggregate_metadata.insert()
+ row.execute({'created_at': rec['created_at'],
+ 'updated_at': rec['updated_at'],
+ 'deleted_at': rec['deleted_at'],
+ 'deleted': rec['deleted'],
+ 'key': 'availability_zone',
+ 'value': rec['availability_zone'],
+ 'aggregate_id': rec['id'],
+ })
+ aggregates.drop_column('availability_zone')
+
+
+def downgrade(migrate_engine):
+ meta = MetaData()
+ meta.bind = migrate_engine
+
+ aggregates = Table('aggregates', meta, autoload=True)
+ aggregate_metadata = Table('aggregate_metadata', meta, autoload=True)
+ availability_zone = Column('availability_zone', String(255))
+ aggregates.create_column(availability_zone)
+ # migrate data
+ aggregates.update().values(availability_zone=select(
+ [aggregate_metadata.c.value]).where(aggregates.c.id ==
+ aggregate_metadata.c.aggregate_id).where(aggregate_metadata.c.key ==
+ 'availability_zone')).execute()
+ delete(aggregate_metadata, aggregate_metadata.c.key == 'availability_zone')
+ aggregates.c.availability_zone.alter(nullable=False)
diff --git a/nova/db/sqlalchemy/models.py b/nova/db/sqlalchemy/models.py
index cdd140b6e..8a161efdf 100644
--- a/nova/db/sqlalchemy/models.py
+++ b/nova/db/sqlalchemy/models.py
@@ -866,7 +866,6 @@ class Aggregate(BASE, NovaBase):
__tablename__ = 'aggregates'
id = Column(Integer, primary_key=True, autoincrement=True)
name = Column(String(255))
- availability_zone = Column(String(255), nullable=False)
_hosts = relationship(AggregateHost,
lazy="joined",
secondary="aggregate_hosts",
@@ -893,7 +892,7 @@ class Aggregate(BASE, NovaBase):
backref='aggregates')
def _extra_keys(self):
- return ['hosts', 'metadetails']
+ return ['hosts', 'metadetails', 'availability_zone']
@property
def hosts(self):
@@ -903,6 +902,12 @@ class Aggregate(BASE, NovaBase):
def metadetails(self):
return dict([(m.key, m.value) for m in self._metadata])
+ @property
+ def availability_zone(self):
+ if 'availability_zone' not in self.metadetails:
+ return None
+ return self.metadetails['availability_zone']
+
class AgentBuild(BASE, NovaBase):
"""Represents an agent build."""
diff --git a/nova/scheduler/filters/availability_zone_filter.py b/nova/scheduler/filters/availability_zone_filter.py
index 4e55d0b0c..24ea0dd35 100644
--- a/nova/scheduler/filters/availability_zone_filter.py
+++ b/nova/scheduler/filters/availability_zone_filter.py
@@ -14,11 +14,17 @@
# under the License.
+from nova import db
from nova.scheduler import filters
class AvailabilityZoneFilter(filters.BaseHostFilter):
- """Filters Hosts by availability zone."""
+ """Filters Hosts by availability zone.
+
+ Works with both service and aggregate metadata.
+ For aggregate metadata uses the key 'availability_zone'
+ Note: in theory a compute node can be part of multiple availability_zones
+ """
def host_passes(self, host_state, filter_properties):
spec = filter_properties.get('request_spec', {})
@@ -26,5 +32,12 @@ class AvailabilityZoneFilter(filters.BaseHostFilter):
availability_zone = props.get('availability_zone')
if availability_zone:
- return availability_zone == host_state.service['availability_zone']
+ if availability_zone == host_state.service['availability_zone']:
+ return True
+ context = filter_properties['context'].elevated()
+ metadata = db.aggregate_metadata_get_by_host(
+ context, host_state.host, key='availability_zone')
+ if 'availability_zone' in metadata:
+ return availability_zone in metadata['availability_zone']
+ return False
return True
diff --git a/nova/tests/api/ec2/test_cloud.py b/nova/tests/api/ec2/test_cloud.py
index d452c18cb..429746dac 100644
--- a/nova/tests/api/ec2/test_cloud.py
+++ b/nova/tests/api/ec2/test_cloud.py
@@ -710,8 +710,16 @@ class CloudTestCase(test.TestCase):
'topic': 'compute',
'report_count': 0,
'availability_zone': "zone2"})
+ # Aggregate based zones
+ agg = db.aggregate_create(self.context,
+ {'name': 'agg1'}, {'availability_zone': 'aggzones'})
+ db.aggregate_host_add(self.context, agg.id, 'host2_zones')
result = self.cloud.describe_availability_zones(self.context)
- self.assertEqual(len(result['availabilityZoneInfo']), 3)
+ self.assertEqual(len(result['availabilityZoneInfo']), 4)
+ admin_ctxt = context.get_admin_context(read_deleted="no")
+ result = self.cloud.describe_availability_zones(admin_ctxt,
+ zone_name='verbose')
+ self.assertEqual(len(result['availabilityZoneInfo']), 18)
db.service_destroy(self.context, service1['id'])
db.service_destroy(self.context, service2['id'])
diff --git a/nova/tests/api/openstack/compute/contrib/test_aggregates.py b/nova/tests/api/openstack/compute/contrib/test_aggregates.py
index 0f60b8128..c57d6a91b 100644
--- a/nova/tests/api/openstack/compute/contrib/test_aggregates.py
+++ b/nova/tests/api/openstack/compute/contrib/test_aggregates.py
@@ -123,7 +123,7 @@ class AggregateTestCase(test.TestCase):
def test_create_with_extra_invalid_arg(self):
self.assertRaises(exc.HTTPBadRequest, self.controller.create,
self.req, dict(name="test",
- availablity_zone="nova1",
+ availability_zone="nova1",
foo='bar'))
def test_show(self):
@@ -183,9 +183,7 @@ class AggregateTestCase(test.TestCase):
return AGGREGATE
self.stubs.Set(self.controller.api, "update_aggregate",
stub_update_aggregate)
-
result = self.controller.update(self.req, "1", body=body)
-
self.assertEqual(AGGREGATE, result["aggregate"])
def test_update_with_no_updates(self):
@@ -261,18 +259,6 @@ class AggregateTestCase(test.TestCase):
self.req, "bogus_aggregate",
body={"add_host": {"host": "host1"}})
- def test_add_host_with_host_in_wrong_availability_zone(self):
- def stub_add_host_to_aggregate(context, aggregate, host):
- raise exception.InvalidAggregateAction(action='create_aggregate',
- aggregate_id="'N/A'",
- reason='wrong zone')
- self.stubs.Set(self.controller.api, "add_host_to_aggregate",
- stub_add_host_to_aggregate)
-
- self.assertRaises(exc.HTTPConflict, self.controller.action,
- self.req, "bogus_aggregate",
- body={"add_host": {"host": "host1"}})
-
def test_add_host_with_missing_host(self):
self.assertRaises(exc.HTTPBadRequest, self.controller.action,
self.req, "1", body={"asdf": "asdf"})
diff --git a/nova/tests/compute/test_compute.py b/nova/tests/compute/test_compute.py
index b25ae191a..99504f580 100644
--- a/nova/tests/compute/test_compute.py
+++ b/nova/tests/compute/test_compute.py
@@ -5543,15 +5543,8 @@ class ComputeAPIAggrTestCase(BaseTestCase):
self.stubs.Set(rpc, 'call', fake_rpc_method)
self.stubs.Set(rpc, 'cast', fake_rpc_method)
- def test_create_invalid_availability_zone(self):
- """Ensure InvalidAggregateAction is raised with wrong avail_zone."""
- self.assertRaises(exception.InvalidAggregateAction,
- self.api.create_aggregate,
- self.context, 'fake_aggr', 'fake_avail_zone')
-
def test_update_aggregate_metadata(self):
"""Ensure metadata can be updated"""
- _create_service_entries(self.context, {'fake_zone': ['fake_host']})
aggr = self.api.create_aggregate(self.context, 'fake_aggregate',
'fake_zone')
metadata = {'foo_key1': 'foo_value1',
@@ -5562,11 +5555,11 @@ class ComputeAPIAggrTestCase(BaseTestCase):
expected = self.api.update_aggregate_metadata(self.context,
aggr['id'], metadata)
self.assertThat(expected['metadata'],
- matchers.DictMatches({'foo_key2': 'foo_value2'}))
+ matchers.DictMatches({'availability_zone': 'fake_zone',
+ 'foo_key2': 'foo_value2'}))
def test_delete_aggregate(self):
"""Ensure we can delete an aggregate."""
- _create_service_entries(self.context, {'fake_zone': ['fake_host']})
aggr = self.api.create_aggregate(self.context, 'fake_aggregate',
'fake_zone')
self.api.delete_aggregate(self.context, aggr['id'])
@@ -5607,19 +5600,8 @@ class ComputeAPIAggrTestCase(BaseTestCase):
aggr['id'], host)
self.assertEqual(len(aggr['hosts']), len(values[fake_zone]))
- def test_add_host_to_aggregate_zones_mismatch(self):
- """Ensure InvalidAggregateAction is raised when zones don't match."""
- _create_service_entries(self.context, {'fake_zoneX': ['fake_host1'],
- 'fake_zoneY': ['fake_host2']})
- aggr = self.api.create_aggregate(self.context,
- 'fake_aggregate', 'fake_zoneY')
- self.assertRaises(exception.InvalidAggregateAction,
- self.api.add_host_to_aggregate,
- self.context, aggr['id'], 'fake_host1')
-
def test_add_host_to_aggregate_raise_not_found(self):
"""Ensure ComputeHostNotFound is raised when adding invalid host."""
- _create_service_entries(self.context, {'fake_zone': ['fake_host']})
aggr = self.api.create_aggregate(self.context, 'fake_aggregate',
'fake_zone')
self.assertRaises(exception.ComputeHostNotFound,
@@ -5670,9 +5652,9 @@ class ComputeAggrTestCase(BaseTestCase):
def setUp(self):
super(ComputeAggrTestCase, self).setUp()
self.context = context.get_admin_context()
- values = {'name': 'test_aggr',
- 'availability_zone': 'test_zone'}
- self.aggr = db.aggregate_create(self.context, values)
+ values = {'name': 'test_aggr'}
+ az = {'availability_zone': 'test_zone'}
+ self.aggr = db.aggregate_create(self.context, values, metadata=az)
def test_add_aggregate_host(self):
def fake_driver_add_to_aggregate(context, aggregate, host, **_ignore):
diff --git a/nova/tests/conductor/test_conductor.py b/nova/tests/conductor/test_conductor.py
index dcbafec9e..fd87e420b 100644
--- a/nova/tests/conductor/test_conductor.py
+++ b/nova/tests/conductor/test_conductor.py
@@ -129,7 +129,7 @@ class _BaseTestCase(object):
def _setup_aggregate_with_host(self):
aggregate_ref = db.aggregate_create(self.context.elevated(),
- {'name': 'foo', 'availability_zone': 'foo'})
+ {'name': 'foo'}, metadata={'availability_zone': 'foo'})
self.conductor.aggregate_host_add(self.context, aggregate_ref, 'bar')
diff --git a/nova/tests/integrated/api_samples/os-aggregates/aggregate-update-post-resp.json.tpl b/nova/tests/integrated/api_samples/os-aggregates/aggregate-update-post-resp.json.tpl
index 89a48ee57..119f78ad2 100644
--- a/nova/tests/integrated/api_samples/os-aggregates/aggregate-update-post-resp.json.tpl
+++ b/nova/tests/integrated/api_samples/os-aggregates/aggregate-update-post-resp.json.tpl
@@ -6,7 +6,9 @@
"deleted_at": null,
"hosts": [],
"id": 1,
- "metadata": {},
+ "metadata": {
+ "availability_zone": "nova2"
+ },
"name": "newname",
"updated_at": "%(timestamp)s"
}
diff --git a/nova/tests/integrated/api_samples/os-aggregates/aggregate-update-post-resp.xml.tpl b/nova/tests/integrated/api_samples/os-aggregates/aggregate-update-post-resp.xml.tpl
index 3f72a0b43..071e1c43a 100644
--- a/nova/tests/integrated/api_samples/os-aggregates/aggregate-update-post-resp.xml.tpl
+++ b/nova/tests/integrated/api_samples/os-aggregates/aggregate-update-post-resp.xml.tpl
@@ -8,5 +8,7 @@
<hosts/>
<deleted_at>None</deleted_at>
<id>1</id>
- <metadata/>
+ <metadata>
+ <availability_zone>nova2</availability_zone>
+ </metadata>
</aggregate>
diff --git a/nova/tests/integrated/api_samples/os-aggregates/aggregates-add-host-post-resp.json.tpl b/nova/tests/integrated/api_samples/os-aggregates/aggregates-add-host-post-resp.json.tpl
index ee0ea6c3d..b311bb18e 100644
--- a/nova/tests/integrated/api_samples/os-aggregates/aggregates-add-host-post-resp.json.tpl
+++ b/nova/tests/integrated/api_samples/os-aggregates/aggregates-add-host-post-resp.json.tpl
@@ -8,7 +8,9 @@
"%(compute_host)s"
],
"id": 1,
- "metadata": {},
+ "metadata": {
+ "availability_zone": "nova"
+ },
"name": "name",
"updated_at": null
}
diff --git a/nova/tests/integrated/api_samples/os-aggregates/aggregates-add-host-post-resp.xml.tpl b/nova/tests/integrated/api_samples/os-aggregates/aggregates-add-host-post-resp.xml.tpl
index 82a0401ad..a45a01789 100644
--- a/nova/tests/integrated/api_samples/os-aggregates/aggregates-add-host-post-resp.xml.tpl
+++ b/nova/tests/integrated/api_samples/os-aggregates/aggregates-add-host-post-resp.xml.tpl
@@ -10,5 +10,7 @@
</hosts>
<deleted_at>None</deleted_at>
<id>1</id>
- <metadata/>
+ <metadata>
+ <availability_zone>nova</availability_zone>
+ </metadata>
</aggregate>
diff --git a/nova/tests/integrated/api_samples/os-aggregates/aggregates-get-resp.json.tpl b/nova/tests/integrated/api_samples/os-aggregates/aggregates-get-resp.json.tpl
index 8ce7d9c40..6b94465c4 100644
--- a/nova/tests/integrated/api_samples/os-aggregates/aggregates-get-resp.json.tpl
+++ b/nova/tests/integrated/api_samples/os-aggregates/aggregates-get-resp.json.tpl
@@ -6,7 +6,9 @@
"deleted_at": null,
"hosts": [],
"id": 1,
- "metadata": {},
+ "metadata": {
+ "availability_zone": "nova"
+ },
"name": "name",
"updated_at": null
}
diff --git a/nova/tests/integrated/api_samples/os-aggregates/aggregates-get-resp.xml.tpl b/nova/tests/integrated/api_samples/os-aggregates/aggregates-get-resp.xml.tpl
index 56f0dd3e8..d59d10a84 100644
--- a/nova/tests/integrated/api_samples/os-aggregates/aggregates-get-resp.xml.tpl
+++ b/nova/tests/integrated/api_samples/os-aggregates/aggregates-get-resp.xml.tpl
@@ -8,5 +8,7 @@
<hosts/>
<deleted_at>None</deleted_at>
<id>1</id>
- <metadata/>
+ <metadata>
+ <availability_zone>nova</availability_zone>
+ </metadata>
</aggregate>
diff --git a/nova/tests/integrated/api_samples/os-aggregates/aggregates-list-get-resp.json.tpl b/nova/tests/integrated/api_samples/os-aggregates/aggregates-list-get-resp.json.tpl
index f373f02f7..bed47e730 100644
--- a/nova/tests/integrated/api_samples/os-aggregates/aggregates-list-get-resp.json.tpl
+++ b/nova/tests/integrated/api_samples/os-aggregates/aggregates-list-get-resp.json.tpl
@@ -7,7 +7,9 @@
"deleted_at": null,
"hosts": [],
"id": 1,
- "metadata": {},
+ "metadata": {
+ "availability_zone": "nova"
+ },
"name": "name",
"updated_at": null
}
diff --git a/nova/tests/integrated/api_samples/os-aggregates/aggregates-list-get-resp.xml.tpl b/nova/tests/integrated/api_samples/os-aggregates/aggregates-list-get-resp.xml.tpl
index 417b1016f..0a6173a0b 100644
--- a/nova/tests/integrated/api_samples/os-aggregates/aggregates-list-get-resp.xml.tpl
+++ b/nova/tests/integrated/api_samples/os-aggregates/aggregates-list-get-resp.xml.tpl
@@ -9,6 +9,8 @@
<hosts/>
<deleted_at>None</deleted_at>
<id>1</id>
- <metadata/>
+ <metadata>
+ <availability_zone>nova</availability_zone>
+ </metadata>
</aggregate>
</aggregates>
diff --git a/nova/tests/integrated/api_samples/os-aggregates/aggregates-metadata-post-resp.json.tpl b/nova/tests/integrated/api_samples/os-aggregates/aggregates-metadata-post-resp.json.tpl
index 058a1ecf5..f34932617 100644
--- a/nova/tests/integrated/api_samples/os-aggregates/aggregates-metadata-post-resp.json.tpl
+++ b/nova/tests/integrated/api_samples/os-aggregates/aggregates-metadata-post-resp.json.tpl
@@ -7,6 +7,7 @@
"hosts": [],
"id": 1,
"metadata": {
+ "availability_zone": "nova",
"key": "value"
},
"name": "name",
diff --git a/nova/tests/integrated/api_samples/os-aggregates/aggregates-metadata-post-resp.xml.tpl b/nova/tests/integrated/api_samples/os-aggregates/aggregates-metadata-post-resp.xml.tpl
index 9bbd1f0bd..5b229cfc9 100644
--- a/nova/tests/integrated/api_samples/os-aggregates/aggregates-metadata-post-resp.xml.tpl
+++ b/nova/tests/integrated/api_samples/os-aggregates/aggregates-metadata-post-resp.xml.tpl
@@ -10,5 +10,6 @@
<id>1</id>
<metadata>
<key>value</key>
+ <availability_zone>nova</availability_zone>
</metadata>
</aggregate>
diff --git a/nova/tests/integrated/api_samples/os-aggregates/aggregates-remove-host-post-resp.json.tpl b/nova/tests/integrated/api_samples/os-aggregates/aggregates-remove-host-post-resp.json.tpl
index 8ce7d9c40..6b94465c4 100644
--- a/nova/tests/integrated/api_samples/os-aggregates/aggregates-remove-host-post-resp.json.tpl
+++ b/nova/tests/integrated/api_samples/os-aggregates/aggregates-remove-host-post-resp.json.tpl
@@ -6,7 +6,9 @@
"deleted_at": null,
"hosts": [],
"id": 1,
- "metadata": {},
+ "metadata": {
+ "availability_zone": "nova"
+ },
"name": "name",
"updated_at": null
}
diff --git a/nova/tests/integrated/api_samples/os-aggregates/aggregates-remove-host-post-resp.xml.tpl b/nova/tests/integrated/api_samples/os-aggregates/aggregates-remove-host-post-resp.xml.tpl
index 56f0dd3e8..d59d10a84 100644
--- a/nova/tests/integrated/api_samples/os-aggregates/aggregates-remove-host-post-resp.xml.tpl
+++ b/nova/tests/integrated/api_samples/os-aggregates/aggregates-remove-host-post-resp.xml.tpl
@@ -8,5 +8,7 @@
<hosts/>
<deleted_at>None</deleted_at>
<id>1</id>
- <metadata/>
+ <metadata>
+ <availability_zone>nova</availability_zone>
+ </metadata>
</aggregate>
diff --git a/nova/tests/scheduler/test_host_filters.py b/nova/tests/scheduler/test_host_filters.py
index 07a1bc2b8..b08da6baa 100644
--- a/nova/tests/scheduler/test_host_filters.py
+++ b/nova/tests/scheduler/test_host_filters.py
@@ -748,8 +748,11 @@ class HostFiltersTestCase(test.TestCase):
def _create_aggregate_with_host(self, name='fake_aggregate',
metadata=None,
hosts=['host1']):
- values = {'name': name,
- 'availability_zone': 'fake_avail_zone', }
+ values = {'name': name}
+ if metadata:
+ metadata['availability_zone'] = 'fake_avail_zone'
+ else:
+ metadata = {'availability_zone': 'fake_avail_zone'}
result = db.aggregate_create(self.context.elevated(), values, metadata)
for host in hosts:
db.aggregate_host_add(self.context.elevated(), result['id'], host)
diff --git a/nova/tests/test_db_api.py b/nova/tests/test_db_api.py
index 6ebfe6d3c..0aaa42a11 100644
--- a/nova/tests/test_db_api.py
+++ b/nova/tests/test_db_api.py
@@ -765,13 +765,13 @@ class DbApiTestCase(test.TestCase):
def _get_fake_aggr_values():
- return {'name': 'fake_aggregate',
- 'availability_zone': 'fake_avail_zone', }
+ return {'name': 'fake_aggregate'}
def _get_fake_aggr_metadata():
return {'fake_key1': 'fake_value1',
- 'fake_key2': 'fake_value2'}
+ 'fake_key2': 'fake_value2',
+ 'availability_zone': 'fake_avail_zone'}
def _get_fake_aggr_hosts():
@@ -802,28 +802,26 @@ class AggregateDBApiTestCase(test.TestCase):
self.project_id = 'fake'
self.context = context.RequestContext(self.user_id, self.project_id)
- def test_aggregate_create(self):
- """Ensure aggregate can be created with no metadata."""
+ def test_aggregate_create_no_metadata(self):
result = _create_aggregate(metadata=None)
self.assertEquals(result['name'], 'fake_aggregate')
def test_aggregate_create_avoid_name_conflict(self):
- """Test we can avoid conflict on deleted aggregates."""
r1 = _create_aggregate(metadata=None)
db.aggregate_delete(context.get_admin_context(), r1['id'])
- values = {'name': r1['name'], 'availability_zone': 'new_zone'}
- r2 = _create_aggregate(values=values)
+ values = {'name': r1['name']}
+ metadata = {'availability_zone': 'new_zone'}
+ r2 = _create_aggregate(values=values, metadata=metadata)
self.assertEqual(r2['name'], values['name'])
- self.assertEqual(r2['availability_zone'], values['availability_zone'])
+ self.assertEqual(r2['availability_zone'],
+ metadata['availability_zone'])
def test_aggregate_create_raise_exist_exc(self):
- """Ensure aggregate names are distinct."""
_create_aggregate(metadata=None)
self.assertRaises(exception.AggregateNameExists,
_create_aggregate, metadata=None)
def test_aggregate_get_raise_not_found(self):
- """Ensure AggregateNotFound is raised when getting an aggregate."""
ctxt = context.get_admin_context()
# this does not exist!
aggregate_id = 1
@@ -832,7 +830,6 @@ class AggregateDBApiTestCase(test.TestCase):
ctxt, aggregate_id)
def test_aggregate_metadata_get_raise_not_found(self):
- """Ensure AggregateNotFound is raised when getting metadata."""
ctxt = context.get_admin_context()
# this does not exist!
aggregate_id = 1
@@ -841,7 +838,6 @@ class AggregateDBApiTestCase(test.TestCase):
ctxt, aggregate_id)
def test_aggregate_create_with_metadata(self):
- """Ensure aggregate can be created with metadata."""
ctxt = context.get_admin_context()
result = _create_aggregate(context=ctxt)
expected_metadata = db.aggregate_metadata_get(ctxt, result['id'])
@@ -849,25 +845,25 @@ class AggregateDBApiTestCase(test.TestCase):
matchers.DictMatches(_get_fake_aggr_metadata()))
def test_aggregate_create_delete_create_with_metadata(self):
- """Ensure aggregate metadata is deleted bug 1052479."""
+ #test for bug 1052479
ctxt = context.get_admin_context()
result = _create_aggregate(context=ctxt)
expected_metadata = db.aggregate_metadata_get(ctxt, result['id'])
self.assertThat(expected_metadata,
matchers.DictMatches(_get_fake_aggr_metadata()))
db.aggregate_delete(ctxt, result['id'])
- result = _create_aggregate(metadata=None)
+ result = _create_aggregate(metadata={'availability_zone':
+ 'fake_avail_zone'})
expected_metadata = db.aggregate_metadata_get(ctxt, result['id'])
- self.assertEqual(expected_metadata, {})
+ self.assertEqual(expected_metadata, {'availability_zone':
+ 'fake_avail_zone'})
def test_aggregate_create_low_privi_context(self):
- """Ensure right context is applied when creating aggregate."""
self.assertRaises(exception.AdminRequired,
db.aggregate_create,
self.context, _get_fake_aggr_values())
def test_aggregate_get(self):
- """Ensure we can get aggregate with all its relations."""
ctxt = context.get_admin_context()
result = _create_aggregate_with_hosts(context=ctxt)
expected = db.aggregate_get(ctxt, result['id'])
@@ -875,20 +871,16 @@ class AggregateDBApiTestCase(test.TestCase):
self.assertEqual(_get_fake_aggr_metadata(), expected['metadetails'])
def test_aggregate_get_by_host(self):
- """Ensure we can get aggregates by host."""
ctxt = context.get_admin_context()
- values = {'name': 'fake_aggregate2',
- 'availability_zone': 'fake_avail_zone', }
+ values = {'name': 'fake_aggregate2'}
a1 = _create_aggregate_with_hosts(context=ctxt)
a2 = _create_aggregate_with_hosts(context=ctxt, values=values)
r1 = db.aggregate_get_by_host(ctxt, 'foo.openstack.org')
self.assertEqual([a1['id'], a2['id']], [x['id'] for x in r1])
def test_aggregate_get_by_host_with_key(self):
- """Ensure we can get aggregates by host."""
ctxt = context.get_admin_context()
- values = {'name': 'fake_aggregate2',
- 'availability_zone': 'fake_avail_zone', }
+ values = {'name': 'fake_aggregate2'}
a1 = _create_aggregate_with_hosts(context=ctxt,
metadata={'goodkey': 'good'})
a2 = _create_aggregate_with_hosts(context=ctxt, values=values)
@@ -896,13 +888,10 @@ class AggregateDBApiTestCase(test.TestCase):
r1 = db.aggregate_get_by_host(ctxt, 'foo.openstack.org', key='goodkey')
self.assertEqual([a1['id']], [x['id'] for x in r1])
- def test_aggregate_metdata_get_by_host(self):
- """Ensure we can get aggregates by host."""
+ def test_aggregate_metadata_get_by_host(self):
ctxt = context.get_admin_context()
- values = {'name': 'fake_aggregate2',
- 'availability_zone': 'fake_avail_zone', }
- values2 = {'name': 'fake_aggregate3',
- 'availability_zone': 'fake_avail_zone', }
+ values = {'name': 'fake_aggregate2'}
+ values2 = {'name': 'fake_aggregate3'}
a1 = _create_aggregate_with_hosts(context=ctxt)
a2 = _create_aggregate_with_hosts(context=ctxt, values=values)
a3 = _create_aggregate_with_hosts(context=ctxt, values=values2,
@@ -911,13 +900,10 @@ class AggregateDBApiTestCase(test.TestCase):
self.assertEqual(r1['fake_key1'], set(['fake_value1']))
self.assertFalse('badkey' in r1)
- def test_aggregate_metdata_get_by_host_with_key(self):
- """Ensure we can get aggregates by host."""
+ def test_aggregate_metadata_get_by_host_with_key(self):
ctxt = context.get_admin_context()
- values = {'name': 'fake_aggregate2',
- 'availability_zone': 'fake_avail_zone', }
- values2 = {'name': 'fake_aggregate3',
- 'availability_zone': 'fake_avail_zone', }
+ values = {'name': 'fake_aggregate2'}
+ values2 = {'name': 'fake_aggregate3'}
a1 = _create_aggregate_with_hosts(context=ctxt)
a2 = _create_aggregate_with_hosts(context=ctxt, values=values)
a3 = _create_aggregate_with_hosts(context=ctxt, values=values2,
@@ -932,14 +918,24 @@ class AggregateDBApiTestCase(test.TestCase):
key='good')
self.assertFalse('good' in r2)
+ def test_aggregate_host_get_by_metadata_key(self):
+ ctxt = context.get_admin_context()
+ values = {'name': 'fake_aggregate2'}
+ values2 = {'name': 'fake_aggregate3'}
+ a1 = _create_aggregate_with_hosts(context=ctxt)
+ a2 = _create_aggregate_with_hosts(context=ctxt, values=values)
+ a3 = _create_aggregate_with_hosts(context=ctxt, values=values2,
+ hosts=['foo.openstack.org'], metadata={'good': 'value'})
+ r1 = db.aggregate_host_get_by_metadata_key(ctxt, key='good')
+ self.assertEqual(r1, {'foo.openstack.org': set(['value'])})
+ self.assertFalse('fake_key1' in r1)
+
def test_aggregate_get_by_host_not_found(self):
- """Ensure AggregateHostNotFound is raised with unknown host."""
ctxt = context.get_admin_context()
_create_aggregate_with_hosts(context=ctxt)
self.assertEqual([], db.aggregate_get_by_host(ctxt, 'unknown_host'))
def test_aggregate_delete_raise_not_found(self):
- """Ensure AggregateNotFound is raised when deleting an aggregate."""
ctxt = context.get_admin_context()
# this does not exist!
aggregate_id = 1
@@ -948,7 +944,6 @@ class AggregateDBApiTestCase(test.TestCase):
ctxt, aggregate_id)
def test_aggregate_delete(self):
- """Ensure we can delete an aggregate."""
ctxt = context.get_admin_context()
result = _create_aggregate(context=ctxt, metadata=None)
db.aggregate_delete(ctxt, result['id'])
@@ -959,9 +954,10 @@ class AggregateDBApiTestCase(test.TestCase):
self.assertEqual(aggregate['deleted'], True)
def test_aggregate_update(self):
- """Ensure an aggregate can be updated."""
ctxt = context.get_admin_context()
- result = _create_aggregate(context=ctxt, metadata=None)
+ result = _create_aggregate(context=ctxt, metadata={'availability_zone':
+ 'fake_avail_zone'})
+ self.assertEqual(result.availability_zone, 'fake_avail_zone')
new_values = _get_fake_aggr_values()
new_values['availability_zone'] = 'different_avail_zone'
updated = db.aggregate_update(ctxt, 1, new_values)
@@ -969,18 +965,20 @@ class AggregateDBApiTestCase(test.TestCase):
updated['availability_zone'])
def test_aggregate_update_with_metadata(self):
- """Ensure an aggregate can be updated with metadata."""
ctxt = context.get_admin_context()
result = _create_aggregate(context=ctxt, metadata=None)
values = _get_fake_aggr_values()
values['metadata'] = _get_fake_aggr_metadata()
+ values['availability_zone'] = 'different_avail_zone'
db.aggregate_update(ctxt, 1, values)
expected = db.aggregate_metadata_get(ctxt, result['id'])
- self.assertThat(_get_fake_aggr_metadata(),
+ updated = db.aggregate_get(ctxt, result['id'])
+ self.assertThat(values['metadata'],
matchers.DictMatches(expected))
+ self.assertNotEqual(result.availability_zone,
+ updated.availability_zone)
def test_aggregate_update_with_existing_metadata(self):
- """Ensure an aggregate can be updated with existing metadata."""
ctxt = context.get_admin_context()
result = _create_aggregate(context=ctxt)
values = _get_fake_aggr_values()
@@ -991,7 +989,6 @@ class AggregateDBApiTestCase(test.TestCase):
self.assertThat(values['metadata'], matchers.DictMatches(expected))
def test_aggregate_update_raise_not_found(self):
- """Ensure AggregateNotFound is raised when updating an aggregate."""
ctxt = context.get_admin_context()
# this does not exist!
aggregate_id = 1
@@ -1000,26 +997,22 @@ class AggregateDBApiTestCase(test.TestCase):
db.aggregate_update, ctxt, aggregate_id, new_values)
def test_aggregate_get_all(self):
- """Ensure we can get all aggregates."""
ctxt = context.get_admin_context()
counter = 3
for c in xrange(counter):
_create_aggregate(context=ctxt,
- values={'name': 'fake_aggregate_%d' % c,
- 'availability_zone': 'fake_avail_zone'},
+ values={'name': 'fake_aggregate_%d' % c},
metadata=None)
results = db.aggregate_get_all(ctxt)
self.assertEqual(len(results), counter)
def test_aggregate_get_all_non_deleted(self):
- """Ensure we get only non-deleted aggregates."""
ctxt = context.get_admin_context()
add_counter = 5
remove_counter = 2
aggregates = []
for c in xrange(1, add_counter):
- values = {'name': 'fake_aggregate_%d' % c,
- 'availability_zone': 'fake_avail_zone'}
+ values = {'name': 'fake_aggregate_%d' % c}
aggregates.append(_create_aggregate(context=ctxt,
values=values, metadata=None))
for c in xrange(1, remove_counter):
@@ -1028,7 +1021,6 @@ class AggregateDBApiTestCase(test.TestCase):
self.assertEqual(len(results), add_counter - remove_counter)
def test_aggregate_metadata_add(self):
- """Ensure we can add metadata for the aggregate."""
ctxt = context.get_admin_context()
result = _create_aggregate(context=ctxt, metadata=None)
metadata = _get_fake_aggr_metadata()
@@ -1037,7 +1029,6 @@ class AggregateDBApiTestCase(test.TestCase):
self.assertThat(metadata, matchers.DictMatches(expected))
def test_aggregate_metadata_update(self):
- """Ensure we can update metadata for the aggregate."""
ctxt = context.get_admin_context()
result = _create_aggregate(context=ctxt)
metadata = _get_fake_aggr_metadata()
@@ -1050,7 +1041,6 @@ class AggregateDBApiTestCase(test.TestCase):
self.assertThat(metadata, matchers.DictMatches(expected))
def test_aggregate_metadata_delete(self):
- """Ensure we can delete metadata for the aggregate."""
ctxt = context.get_admin_context()
result = _create_aggregate(context=ctxt, metadata=None)
metadata = _get_fake_aggr_metadata()
@@ -1060,8 +1050,17 @@ class AggregateDBApiTestCase(test.TestCase):
del metadata[metadata.keys()[0]]
self.assertThat(metadata, matchers.DictMatches(expected))
+ def test_aggregate_remove_availability_zone(self):
+ ctxt = context.get_admin_context()
+ result = _create_aggregate(context=ctxt, metadata={'availability_zone':
+ 'fake_avail_zone'})
+ db.aggregate_metadata_delete(ctxt, result.id, 'availability_zone')
+ expected = db.aggregate_metadata_get(ctxt, result.id)
+ aggregate = db.aggregate_get(ctxt, result.id)
+ self.assertEquals(aggregate.availability_zone, None)
+ self.assertThat({}, matchers.DictMatches(expected))
+
def test_aggregate_metadata_delete_raise_not_found(self):
- """Ensure AggregateMetadataNotFound is raised when deleting."""
ctxt = context.get_admin_context()
result = _create_aggregate(context=ctxt)
self.assertRaises(exception.AggregateMetadataNotFound,
@@ -1069,14 +1068,12 @@ class AggregateDBApiTestCase(test.TestCase):
ctxt, result['id'], 'foo_key')
def test_aggregate_host_add(self):
- """Ensure we can add host to the aggregate."""
ctxt = context.get_admin_context()
result = _create_aggregate_with_hosts(context=ctxt, metadata=None)
expected = db.aggregate_host_get_all(ctxt, result['id'])
self.assertEqual(_get_fake_aggr_hosts(), expected)
- def test_aggregate_host_add_deleted(self):
- """Ensure we can add a host that was previously deleted."""
+ def test_aggregate_host_re_add(self):
ctxt = context.get_admin_context()
result = _create_aggregate_with_hosts(context=ctxt, metadata=None)
host = _get_fake_aggr_hosts()[0]
@@ -1086,19 +1083,16 @@ class AggregateDBApiTestCase(test.TestCase):
self.assertEqual(len(expected), 1)
def test_aggregate_host_add_duplicate_works(self):
- """Ensure we can add host to distinct aggregates."""
ctxt = context.get_admin_context()
r1 = _create_aggregate_with_hosts(context=ctxt, metadata=None)
r2 = _create_aggregate_with_hosts(ctxt,
- values={'name': 'fake_aggregate2',
- 'availability_zone': 'fake_avail_zone2', },
- metadata=None)
+ values={'name': 'fake_aggregate2'},
+ metadata={'availability_zone': 'fake_avail_zone2'})
h1 = db.aggregate_host_get_all(ctxt, r1['id'])
h2 = db.aggregate_host_get_all(ctxt, r2['id'])
self.assertEqual(h1, h2)
def test_aggregate_host_add_duplicate_raise_exist_exc(self):
- """Ensure we cannot add host to the same aggregate."""
ctxt = context.get_admin_context()
result = _create_aggregate_with_hosts(context=ctxt, metadata=None)
self.assertRaises(exception.AggregateHostExists,
@@ -1106,7 +1100,6 @@ class AggregateDBApiTestCase(test.TestCase):
ctxt, result['id'], _get_fake_aggr_hosts()[0])
def test_aggregate_host_add_raise_not_found(self):
- """Ensure AggregateFound when adding a host."""
ctxt = context.get_admin_context()
# this does not exist!
aggregate_id = 1
@@ -1116,7 +1109,6 @@ class AggregateDBApiTestCase(test.TestCase):
ctxt, aggregate_id, host)
def test_aggregate_host_delete(self):
- """Ensure we can add host to the aggregate."""
ctxt = context.get_admin_context()
result = _create_aggregate_with_hosts(context=ctxt, metadata=None)
db.aggregate_host_delete(ctxt, result['id'],
@@ -1125,7 +1117,6 @@ class AggregateDBApiTestCase(test.TestCase):
self.assertEqual(0, len(expected))
def test_aggregate_host_delete_raise_not_found(self):
- """Ensure AggregateHostNotFound is raised when deleting a host."""
ctxt = context.get_admin_context()
result = _create_aggregate(context=ctxt)
self.assertRaises(exception.AggregateHostNotFound,
diff --git a/nova/tests/test_migrations.py b/nova/tests/test_migrations.py
index 125b2fe36..bcd858d96 100644
--- a/nova/tests/test_migrations.py
+++ b/nova/tests/test_migrations.py
@@ -297,3 +297,37 @@ class TestMigrations(test.TestCase):
self.assertEqual(version,
migration_api.db_version(engine,
TestMigrations.REPOSITORY))
+
+ def test_migration_146(self):
+ name = 'name'
+ az = 'custom_az'
+
+ def _145_check():
+ agg = aggregates.select(aggregates.c.id == 1).execute().first()
+ self.assertEqual(name, agg.name)
+ self.assertEqual(az, agg.availability_zone)
+
+ for key, engine in self.engines.items():
+ migration_api.version_control(engine, TestMigrations.REPOSITORY,
+ migration.INIT_VERSION)
+ migration_api.upgrade(engine, TestMigrations.REPOSITORY, 145)
+ metadata = sqlalchemy.schema.MetaData()
+ metadata.bind = engine
+ aggregates = sqlalchemy.Table('aggregates', metadata,
+ autoload=True)
+
+ aggregates.insert().values(id=1, availability_zone=az,
+ aggregate_name=1, name=name).execute()
+
+ _145_check()
+
+ migration_api.upgrade(engine, TestMigrations.REPOSITORY, 146)
+
+ aggregate_metadata = sqlalchemy.Table('aggregate_metadata',
+ metadata, autoload=True)
+ metadata = aggregate_metadata.select(aggregate_metadata.c.
+ aggregate_id == 1).execute().first()
+ self.assertEqual(az, metadata['value'])
+
+ migration_api.downgrade(engine, TestMigrations.REPOSITORY, 145)
+ _145_check()
diff --git a/nova/tests/test_xenapi.py b/nova/tests/test_xenapi.py
index 5b347fc0f..758e5360c 100644
--- a/nova/tests/test_xenapi.py
+++ b/nova/tests/test_xenapi.py
@@ -2222,11 +2222,12 @@ class XenAPIAggregateTestCase(stubs.XenAPITestBase):
self.compute = importutils.import_object(CONF.compute_manager)
self.api = compute_api.AggregateAPI()
values = {'name': 'test_aggr',
- 'availability_zone': 'test_zone',
- 'metadata': {pool_states.POOL_FLAG: 'XenAPI'}}
+ 'metadata': {'availability_zone': 'test_zone',
+ pool_states.POOL_FLAG: 'XenAPI'}}
self.aggr = db.aggregate_create(self.context, values)
self.fake_metadata = {pool_states.POOL_FLAG: 'XenAPI',
'master_compute': 'host',
+ 'availability_zone': 'fake_zone',
pool_states.KEY: pool_states.ACTIVE,
'host': xenapi_fake.get_record('host',
host_ref)['uuid']}
@@ -2306,9 +2307,10 @@ class XenAPIAggregateTestCase(stubs.XenAPITestBase):
self.conn._session.call_xenapi("pool.create", {"name": "asdf"})
values = {"name": 'fake_aggregate',
- "availability_zone": 'fake_zone'}
+ 'metadata': {'availability_zone': 'fake_zone'}}
result = db.aggregate_create(self.context, values)
- metadata = {pool_states.POOL_FLAG: "XenAPI",
+ metadata = {'availability_zone': 'fake_zone',
+ pool_states.POOL_FLAG: "XenAPI",
pool_states.KEY: pool_states.CREATED}
db.aggregate_metadata_add(self.context, result['id'], metadata)
@@ -2358,7 +2360,8 @@ class XenAPIAggregateTestCase(stubs.XenAPITestBase):
self.conn._pool.remove_from_aggregate(self.context, aggregate, "host")
result = db.aggregate_get(self.context, aggregate['id'])
self.assertTrue(fake_clear_pool.called)
- self.assertThat({pool_states.POOL_FLAG: 'XenAPI',
+ self.assertThat({'availability_zone': 'fake_zone',
+ pool_states.POOL_FLAG: 'XenAPI',
pool_states.KEY: pool_states.ACTIVE},
matchers.DictMatches(result['metadetails']))
@@ -2375,9 +2378,9 @@ class XenAPIAggregateTestCase(stubs.XenAPITestBase):
aggr_zone='fake_zone',
aggr_state=pool_states.CREATED,
hosts=['host'], metadata=None):
- values = {"name": aggr_name,
- "availability_zone": aggr_zone}
- result = db.aggregate_create(self.context, values)
+ values = {"name": aggr_name}
+ result = db.aggregate_create(self.context, values,
+ metadata={'availability_zone': aggr_zone})
pool_flag = {pool_states.POOL_FLAG: "XenAPI",
pool_states.KEY: aggr_state}
db.aggregate_metadata_add(self.context, result['id'], pool_flag)