Merge "Add aggregates tables to the API db."
This commit is contained in:
commit
bfc13b43e7
@ -0,0 +1,73 @@
|
|||||||
|
# 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.
|
||||||
|
"""API Database migrations for aggregates"""
|
||||||
|
|
||||||
|
from migrate import UniqueConstraint
|
||||||
|
from sqlalchemy import Column
|
||||||
|
from sqlalchemy import DateTime
|
||||||
|
from sqlalchemy import ForeignKey
|
||||||
|
from sqlalchemy import Index
|
||||||
|
from sqlalchemy import Integer
|
||||||
|
from sqlalchemy import MetaData
|
||||||
|
from sqlalchemy import String
|
||||||
|
from sqlalchemy import Table
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade(migrate_engine):
|
||||||
|
meta = MetaData()
|
||||||
|
meta.bind = migrate_engine
|
||||||
|
|
||||||
|
aggregates = Table('aggregates', meta,
|
||||||
|
Column('created_at', DateTime),
|
||||||
|
Column('updated_at', DateTime),
|
||||||
|
Column('id', Integer, primary_key=True, nullable=False),
|
||||||
|
Column('uuid', String(length=36)),
|
||||||
|
Column('name', String(length=255)),
|
||||||
|
Index('aggregate_uuid_idx', 'uuid'),
|
||||||
|
UniqueConstraint('name', name='uniq_aggregate0name'),
|
||||||
|
mysql_engine='InnoDB',
|
||||||
|
mysql_charset='utf8'
|
||||||
|
)
|
||||||
|
|
||||||
|
aggregates.create(checkfirst=True)
|
||||||
|
|
||||||
|
aggregate_hosts = Table('aggregate_hosts', meta,
|
||||||
|
Column('created_at', DateTime),
|
||||||
|
Column('updated_at', DateTime),
|
||||||
|
Column('id', Integer, primary_key=True, nullable=False),
|
||||||
|
Column('host', String(length=255)),
|
||||||
|
Column('aggregate_id', Integer, ForeignKey('aggregates.id'),
|
||||||
|
nullable=False),
|
||||||
|
UniqueConstraint('host', 'aggregate_id',
|
||||||
|
name='uniq_aggregate_hosts0host0aggregate_id'),
|
||||||
|
mysql_engine='InnoDB',
|
||||||
|
mysql_charset='utf8'
|
||||||
|
)
|
||||||
|
|
||||||
|
aggregate_hosts.create(checkfirst=True)
|
||||||
|
|
||||||
|
aggregate_metadata = Table('aggregate_metadata', meta,
|
||||||
|
Column('created_at', DateTime),
|
||||||
|
Column('updated_at', DateTime),
|
||||||
|
Column('id', Integer, primary_key=True, nullable=False),
|
||||||
|
Column('aggregate_id', Integer, ForeignKey('aggregates.id'),
|
||||||
|
nullable=False),
|
||||||
|
Column('key', String(length=255), nullable=False),
|
||||||
|
Column('value', String(length=255), nullable=False),
|
||||||
|
UniqueConstraint('aggregate_id', 'key',
|
||||||
|
name='uniq_aggregate_metadata0aggregate_id0key'),
|
||||||
|
Index('aggregate_metadata_key_idx', 'key'),
|
||||||
|
mysql_engine='InnoDB',
|
||||||
|
mysql_charset='utf8'
|
||||||
|
)
|
||||||
|
|
||||||
|
aggregate_metadata.create(checkfirst=True)
|
@ -35,6 +35,68 @@ class _NovaAPIBase(models.ModelBase, models.TimestampMixin):
|
|||||||
API_BASE = declarative_base(cls=_NovaAPIBase)
|
API_BASE = declarative_base(cls=_NovaAPIBase)
|
||||||
|
|
||||||
|
|
||||||
|
class AggregateHost(API_BASE):
|
||||||
|
"""Represents a host that is member of an aggregate."""
|
||||||
|
__tablename__ = 'aggregate_hosts'
|
||||||
|
__table_args__ = (schema.UniqueConstraint(
|
||||||
|
"host", "aggregate_id",
|
||||||
|
name="uniq_aggregate_hosts0host0aggregate_id"
|
||||||
|
),
|
||||||
|
)
|
||||||
|
id = Column(Integer, primary_key=True, autoincrement=True)
|
||||||
|
host = Column(String(255))
|
||||||
|
aggregate_id = Column(Integer, ForeignKey('aggregates.id'), nullable=False)
|
||||||
|
|
||||||
|
|
||||||
|
class AggregateMetadata(API_BASE):
|
||||||
|
"""Represents a metadata key/value pair for an aggregate."""
|
||||||
|
__tablename__ = 'aggregate_metadata'
|
||||||
|
__table_args__ = (
|
||||||
|
schema.UniqueConstraint("aggregate_id", "key",
|
||||||
|
name="uniq_aggregate_metadata0aggregate_id0key"
|
||||||
|
),
|
||||||
|
Index('aggregate_metadata_key_idx', 'key'),
|
||||||
|
)
|
||||||
|
id = Column(Integer, primary_key=True)
|
||||||
|
key = Column(String(255), nullable=False)
|
||||||
|
value = Column(String(255), nullable=False)
|
||||||
|
aggregate_id = Column(Integer, ForeignKey('aggregates.id'), nullable=False)
|
||||||
|
|
||||||
|
|
||||||
|
class Aggregate(API_BASE):
|
||||||
|
"""Represents a cluster of hosts that exists in this zone."""
|
||||||
|
__tablename__ = 'aggregates'
|
||||||
|
__table_args__ = (Index('aggregate_uuid_idx', 'uuid'),
|
||||||
|
schema.UniqueConstraint(
|
||||||
|
"name", name="uniq_aggregate0name")
|
||||||
|
)
|
||||||
|
id = Column(Integer, primary_key=True, autoincrement=True)
|
||||||
|
uuid = Column(String(36))
|
||||||
|
name = Column(String(255))
|
||||||
|
_hosts = orm.relationship(AggregateHost,
|
||||||
|
primaryjoin='Aggregate.id == AggregateHost.aggregate_id')
|
||||||
|
_metadata = orm.relationship(AggregateMetadata,
|
||||||
|
primaryjoin='Aggregate.id == AggregateMetadata.aggregate_id')
|
||||||
|
|
||||||
|
@property
|
||||||
|
def _extra_keys(self):
|
||||||
|
return ['hosts', 'metadetails', 'availability_zone']
|
||||||
|
|
||||||
|
@property
|
||||||
|
def hosts(self):
|
||||||
|
return [h.host for h in self._hosts]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def metadetails(self):
|
||||||
|
return {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 CellMapping(API_BASE):
|
class CellMapping(API_BASE):
|
||||||
"""Contains information on communicating with a cell"""
|
"""Contains information on communicating with a cell"""
|
||||||
__tablename__ = 'cell_mappings'
|
__tablename__ = 'cell_mappings'
|
||||||
|
57
nova/tests/functional/db/test_aggregate_model.py
Normal file
57
nova/tests/functional/db/test_aggregate_model.py
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
# 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 nova.db.sqlalchemy import api_models
|
||||||
|
from nova.db.sqlalchemy import models
|
||||||
|
from nova import test
|
||||||
|
|
||||||
|
|
||||||
|
class AggregateTablesCompareTestCase(test.NoDBTestCase):
|
||||||
|
def _get_column_list(self, model):
|
||||||
|
column_list = [m.key for m in model.__table__.columns]
|
||||||
|
return column_list
|
||||||
|
|
||||||
|
def _check_column_list(self,
|
||||||
|
columns_new,
|
||||||
|
columns_old,
|
||||||
|
added=None,
|
||||||
|
removed=None):
|
||||||
|
for c in added or []:
|
||||||
|
columns_new.remove(c)
|
||||||
|
for c in removed or []:
|
||||||
|
columns_old.remove(c)
|
||||||
|
intersect = set(columns_new).intersection(set(columns_old))
|
||||||
|
if intersect != set(columns_new) or intersect != set(columns_old):
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
def _compare_models(self, m_a, m_b,
|
||||||
|
added=None, removed=None):
|
||||||
|
added = added or []
|
||||||
|
removed = removed or ['deleted_at', 'deleted']
|
||||||
|
c_a = self._get_column_list(m_a)
|
||||||
|
c_b = self._get_column_list(m_b)
|
||||||
|
self.assertTrue(self._check_column_list(c_a, c_b,
|
||||||
|
added=added,
|
||||||
|
removed=removed))
|
||||||
|
|
||||||
|
def test_tables_aggregate_hosts(self):
|
||||||
|
self._compare_models(api_models.AggregateHost(),
|
||||||
|
models.AggregateHost())
|
||||||
|
|
||||||
|
def test_tables_aggregate_metadata(self):
|
||||||
|
self._compare_models(api_models.AggregateMetadata(),
|
||||||
|
models.AggregateMetadata())
|
||||||
|
|
||||||
|
def test_tables_aggregates(self):
|
||||||
|
self._compare_models(api_models.Aggregate(),
|
||||||
|
models.Aggregate())
|
Loading…
x
Reference in New Issue
Block a user