Enable Aggregate based availability zones
Instead of implementing availability zones in the service table, availability zones are implemented using general aggregate metadata. This patch does not remove availability zones from the service table, a latter patch will do that. * In theory supports a single compute node in multiple availability zones * Drop availability_zone column from Aggregate table (is now a property) * map aggregate metadata 'availability_zone' so API does not change Implements blueprint aggregate-based-availability-zones Change-Id: I2a2ac5bfaa526d639dff5efa392c051347dbd9bb
This commit is contained in:
parent
72ebbda706
commit
645d46b03f
@ -1,13 +1,15 @@
|
||||
{
|
||||
"aggregate": {
|
||||
"availability_zone": "nova2",
|
||||
"created_at": "2012-10-01T18:50:27.781065",
|
||||
"created_at": "2012-12-04T12:04:27.075065",
|
||||
"deleted": false,
|
||||
"deleted_at": null,
|
||||
"hosts": [],
|
||||
"id": 1,
|
||||
"metadata": {},
|
||||
"metadata": {
|
||||
"availability_zone": "nova2"
|
||||
},
|
||||
"name": "newname",
|
||||
"updated_at": "2012-10-01T18:50:27.791392"
|
||||
"updated_at": "2012-12-04T12:04:27.242597"
|
||||
}
|
||||
}
|
@ -3,10 +3,12 @@
|
||||
<name>newname</name>
|
||||
<availability_zone>nova2</availability_zone>
|
||||
<deleted>False</deleted>
|
||||
<created_at>2012-10-01 18:50:35.506667</created_at>
|
||||
<updated_at>2012-10-01 18:50:35.517397</updated_at>
|
||||
<created_at>2012-12-04 12:04:30.245284</created_at>
|
||||
<updated_at>2012-12-04 12:04:30.357795</updated_at>
|
||||
<hosts/>
|
||||
<deleted_at>None</deleted_at>
|
||||
<id>1</id>
|
||||
<metadata/>
|
||||
<metadata>
|
||||
<availability_zone>nova2</availability_zone>
|
||||
</metadata>
|
||||
</aggregate>
|
@ -1,14 +1,16 @@
|
||||
{
|
||||
"aggregate": {
|
||||
"availability_zone": "nova",
|
||||
"created_at": "2012-10-01T18:50:27.511586",
|
||||
"created_at": "2012-12-04T12:04:24.399784",
|
||||
"deleted": false,
|
||||
"deleted_at": null,
|
||||
"hosts": [
|
||||
"581d29b9e3504d8a895caddb13839b15"
|
||||
"0438c6a4e8d841ad823b801d681f4680"
|
||||
],
|
||||
"id": 1,
|
||||
"metadata": {},
|
||||
"metadata": {
|
||||
"availability_zone": "nova"
|
||||
},
|
||||
"name": "name",
|
||||
"updated_at": null
|
||||
}
|
||||
|
@ -3,12 +3,14 @@
|
||||
<name>name</name>
|
||||
<availability_zone>nova</availability_zone>
|
||||
<deleted>False</deleted>
|
||||
<created_at>2012-10-01 18:50:35.236556</created_at>
|
||||
<created_at>2012-12-04 12:04:27.574038</created_at>
|
||||
<updated_at>None</updated_at>
|
||||
<hosts>
|
||||
<host>7c9e00dbca5e4fb88538b021c0f933a5</host>
|
||||
<host>392adba19dd449179804eaff16ff4a97</host>
|
||||
</hosts>
|
||||
<deleted_at>None</deleted_at>
|
||||
<id>1</id>
|
||||
<metadata/>
|
||||
<metadata>
|
||||
<availability_zone>nova</availability_zone>
|
||||
</metadata>
|
||||
</aggregate>
|
@ -1,13 +1,15 @@
|
||||
{
|
||||
"aggregate": {
|
||||
"availability_zone": "nova",
|
||||
"created_at": "2012-10-01T18:50:27.048605",
|
||||
"created_at": "2012-11-16T06:22:23.032493",
|
||||
"deleted": false,
|
||||
"deleted_at": null,
|
||||
"hosts": [],
|
||||
"id": 1,
|
||||
"metadata": {},
|
||||
"metadata": {
|
||||
"availability_zone": "nova"
|
||||
},
|
||||
"name": "name",
|
||||
"updated_at": null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,10 +3,12 @@
|
||||
<name>name</name>
|
||||
<availability_zone>nova</availability_zone>
|
||||
<deleted>False</deleted>
|
||||
<created_at>2012-10-01 18:50:34.764838</created_at>
|
||||
<created_at>2012-11-16 06:22:25.587739</created_at>
|
||||
<updated_at>None</updated_at>
|
||||
<hosts/>
|
||||
<deleted_at>None</deleted_at>
|
||||
<id>1</id>
|
||||
<metadata/>
|
||||
</aggregate>
|
||||
<metadata>
|
||||
<availability_zone>nova</availability_zone>
|
||||
</metadata>
|
||||
</aggregate>
|
||||
|
@ -2,12 +2,14 @@
|
||||
"aggregates": [
|
||||
{
|
||||
"availability_zone": "nova",
|
||||
"created_at": "2012-10-01T18:50:27.252869",
|
||||
"created_at": "2012-11-16T06:22:23.361359",
|
||||
"deleted": false,
|
||||
"deleted_at": null,
|
||||
"hosts": [],
|
||||
"id": 1,
|
||||
"metadata": {},
|
||||
"metadata": {
|
||||
"availability_zone": "nova"
|
||||
},
|
||||
"name": "name",
|
||||
"updated_at": null
|
||||
}
|
||||
|
@ -4,11 +4,13 @@
|
||||
<name>name</name>
|
||||
<availability_zone>nova</availability_zone>
|
||||
<deleted>False</deleted>
|
||||
<created_at>2012-10-01 18:50:34.970677</created_at>
|
||||
<created_at>2012-11-16 06:22:25.935099</created_at>
|
||||
<updated_at>None</updated_at>
|
||||
<hosts/>
|
||||
<deleted_at>None</deleted_at>
|
||||
<id>1</id>
|
||||
<metadata/>
|
||||
<metadata>
|
||||
<availability_zone>nova</availability_zone>
|
||||
</metadata>
|
||||
</aggregate>
|
||||
</aggregates>
|
||||
</aggregates>
|
||||
|
@ -1,12 +1,13 @@
|
||||
{
|
||||
"aggregate": {
|
||||
"availability_zone": "nova",
|
||||
"created_at": "2012-10-01T18:50:26.604176",
|
||||
"created_at": "2012-11-16T06:22:22.342791",
|
||||
"deleted": false,
|
||||
"deleted_at": null,
|
||||
"hosts": [],
|
||||
"id": 1,
|
||||
"metadata": {
|
||||
"availability_zone": "nova",
|
||||
"key": "value"
|
||||
},
|
||||
"name": "name",
|
||||
|
@ -3,12 +3,13 @@
|
||||
<name>name</name>
|
||||
<availability_zone>nova</availability_zone>
|
||||
<deleted>False</deleted>
|
||||
<created_at>2012-10-01 18:50:34.313003</created_at>
|
||||
<created_at>2012-11-16 06:22:24.864471</created_at>
|
||||
<updated_at>None</updated_at>
|
||||
<hosts/>
|
||||
<deleted_at>None</deleted_at>
|
||||
<id>1</id>
|
||||
<metadata>
|
||||
<key>value</key>
|
||||
<availability_zone>nova</availability_zone>
|
||||
</metadata>
|
||||
</aggregate>
|
@ -1,12 +1,14 @@
|
||||
{
|
||||
"aggregate": {
|
||||
"availability_zone": "nova",
|
||||
"created_at": "2012-10-01T18:50:27.511586",
|
||||
"created_at": "2012-12-04T12:04:26.557909",
|
||||
"deleted": false,
|
||||
"deleted_at": null,
|
||||
"hosts": [],
|
||||
"id": 1,
|
||||
"metadata": {},
|
||||
"metadata": {
|
||||
"availability_zone": "nova"
|
||||
},
|
||||
"name": "name",
|
||||
"updated_at": null
|
||||
}
|
||||
|
@ -3,10 +3,12 @@
|
||||
<name>name</name>
|
||||
<availability_zone>nova</availability_zone>
|
||||
<deleted>False</deleted>
|
||||
<created_at>2012-10-01 18:50:35.236556</created_at>
|
||||
<created_at>2012-12-04 12:04:29.722109</created_at>
|
||||
<updated_at>None</updated_at>
|
||||
<hosts/>
|
||||
<deleted_at>None</deleted_at>
|
||||
<id>1</id>
|
||||
<metadata/>
|
||||
<metadata>
|
||||
<availability_zone>nova</availability_zone>
|
||||
</metadata>
|
||||
</aggregate>
|
@ -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."""
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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)
|
@ -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"})
|
||||
|
@ -6,7 +6,9 @@
|
||||
"deleted_at": null,
|
||||
"hosts": [],
|
||||
"id": 1,
|
||||
"metadata": {},
|
||||
"metadata": {
|
||||
"availability_zone": "nova2"
|
||||
},
|
||||
"name": "newname",
|
||||
"updated_at": "%(timestamp)s"
|
||||
}
|
||||
|
@ -8,5 +8,7 @@
|
||||
<hosts/>
|
||||
<deleted_at>None</deleted_at>
|
||||
<id>1</id>
|
||||
<metadata/>
|
||||
<metadata>
|
||||
<availability_zone>nova2</availability_zone>
|
||||
</metadata>
|
||||
</aggregate>
|
||||
|
@ -8,7 +8,9 @@
|
||||
"%(compute_host)s"
|
||||
],
|
||||
"id": 1,
|
||||
"metadata": {},
|
||||
"metadata": {
|
||||
"availability_zone": "nova"
|
||||
},
|
||||
"name": "name",
|
||||
"updated_at": null
|
||||
}
|
||||
|
@ -10,5 +10,7 @@
|
||||
</hosts>
|
||||
<deleted_at>None</deleted_at>
|
||||
<id>1</id>
|
||||
<metadata/>
|
||||
<metadata>
|
||||
<availability_zone>nova</availability_zone>
|
||||
</metadata>
|
||||
</aggregate>
|
||||
|
@ -6,7 +6,9 @@
|
||||
"deleted_at": null,
|
||||
"hosts": [],
|
||||
"id": 1,
|
||||
"metadata": {},
|
||||
"metadata": {
|
||||
"availability_zone": "nova"
|
||||
},
|
||||
"name": "name",
|
||||
"updated_at": null
|
||||
}
|
||||
|
@ -8,5 +8,7 @@
|
||||
<hosts/>
|
||||
<deleted_at>None</deleted_at>
|
||||
<id>1</id>
|
||||
<metadata/>
|
||||
<metadata>
|
||||
<availability_zone>nova</availability_zone>
|
||||
</metadata>
|
||||
</aggregate>
|
||||
|
@ -7,7 +7,9 @@
|
||||
"deleted_at": null,
|
||||
"hosts": [],
|
||||
"id": 1,
|
||||
"metadata": {},
|
||||
"metadata": {
|
||||
"availability_zone": "nova"
|
||||
},
|
||||
"name": "name",
|
||||
"updated_at": null
|
||||
}
|
||||
|
@ -9,6 +9,8 @@
|
||||
<hosts/>
|
||||
<deleted_at>None</deleted_at>
|
||||
<id>1</id>
|
||||
<metadata/>
|
||||
<metadata>
|
||||
<availability_zone>nova</availability_zone>
|
||||
</metadata>
|
||||
</aggregate>
|
||||
</aggregates>
|
||||
|
@ -7,6 +7,7 @@
|
||||
"hosts": [],
|
||||
"id": 1,
|
||||
"metadata": {
|
||||
"availability_zone": "nova",
|
||||
"key": "value"
|
||||
},
|
||||
"name": "name",
|
||||
|
@ -10,5 +10,6 @@
|
||||
<id>1</id>
|
||||
<metadata>
|
||||
<key>value</key>
|
||||
<availability_zone>nova</availability_zone>
|
||||
</metadata>
|
||||
</aggregate>
|
||||
|
@ -6,7 +6,9 @@
|
||||
"deleted_at": null,
|
||||
"hosts": [],
|
||||
"id": 1,
|
||||
"metadata": {},
|
||||
"metadata": {
|
||||
"availability_zone": "nova"
|
||||
},
|
||||
"name": "name",
|
||||
"updated_at": null
|
||||
}
|
||||
|
@ -8,5 +8,7 @@
|
||||
<hosts/>
|
||||
<deleted_at>None</deleted_at>
|
||||
<id>1</id>
|
||||
<metadata/>
|
||||
<metadata>
|
||||
<availability_zone>nova</availability_zone>
|
||||
</metadata>
|
||||
</aggregate>
|
||||
|
Loading…
Reference in New Issue
Block a user