db: Enable auto-generation of migrations
Let's take advantage of the features that alembic provides [1]. We use this opportunity to clean up how we do our base model creation and remove the downgrade section from the migration script template, since we don't support downgrades. [1] https://alembic.sqlalchemy.org/en/latest/autogenerate.html Change-Id: I18846a5c7557db45bb63b97c7e8be5c4367e4547 Signed-off-by: Stephen Finucane <stephenfin@redhat.com>
This commit is contained in:
parent
905c9723e9
commit
1ba2c1c55d
@ -15,7 +15,7 @@ from migrate import UniqueConstraint
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy import dialects
|
||||
|
||||
from nova.db.api.models import MediumText
|
||||
from nova.db import types
|
||||
from nova.objects import keypair
|
||||
|
||||
|
||||
@ -145,7 +145,7 @@ def upgrade(migrate_engine):
|
||||
sa.Column('updated_at', sa.DateTime),
|
||||
sa.Column('id', sa.Integer, primary_key=True, nullable=False),
|
||||
sa.Column('instance_uuid', sa.String(36), nullable=False),
|
||||
sa.Column('spec', MediumText(), nullable=False),
|
||||
sa.Column('spec', types.MediumText(), nullable=False),
|
||||
UniqueConstraint(
|
||||
'instance_uuid', name='uniq_request_specs0instance_uuid'),
|
||||
sa.Index('request_spec_instance_uuid_idx', 'instance_uuid'),
|
||||
@ -176,8 +176,8 @@ def upgrade(migrate_engine):
|
||||
'locked_by',
|
||||
sa.Enum('owner', 'admin', name='build_requests0locked_by')),
|
||||
sa.Column('instance_uuid', sa.String(length=36)),
|
||||
sa.Column('instance', MediumText()),
|
||||
sa.Column('block_device_mappings', MediumText()),
|
||||
sa.Column('instance', types.MediumText()),
|
||||
sa.Column('block_device_mappings', types.MediumText()),
|
||||
sa.Column('tags', sa.Text()),
|
||||
UniqueConstraint(
|
||||
'instance_uuid', name='uniq_build_requests0instance_uuid'),
|
||||
|
@ -30,7 +30,3 @@ depends_on = ${repr(depends_on)}
|
||||
|
||||
def upgrade():
|
||||
${upgrades if upgrades else "pass"}
|
||||
|
||||
|
||||
def downgrade():
|
||||
${downgrades if downgrades else "pass"}
|
||||
|
@ -21,7 +21,7 @@ from alembic import op
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy import dialects
|
||||
|
||||
from nova.db.api.models import MediumText
|
||||
from nova.db import types
|
||||
from nova.objects import keypair
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
@ -164,7 +164,7 @@ def upgrade():
|
||||
sa.Column('updated_at', sa.DateTime),
|
||||
sa.Column('id', sa.Integer, primary_key=True, nullable=False),
|
||||
sa.Column('instance_uuid', sa.String(36), nullable=False),
|
||||
sa.Column('spec', MediumText(), nullable=False),
|
||||
sa.Column('spec', types.MediumText(), nullable=False),
|
||||
sa.UniqueConstraint(
|
||||
'instance_uuid', name='uniq_request_specs0instance_uuid'),
|
||||
sa.Index('request_spec_instance_uuid_idx', 'instance_uuid'),
|
||||
@ -196,8 +196,8 @@ def upgrade():
|
||||
'locked_by',
|
||||
sa.Enum('owner', 'admin', name='build_requests0locked_by')),
|
||||
sa.Column('instance_uuid', sa.String(length=36)),
|
||||
sa.Column('instance', MediumText()),
|
||||
sa.Column('block_device_mappings', MediumText()),
|
||||
sa.Column('instance', types.MediumText()),
|
||||
sa.Column('block_device_mappings', types.MediumText()),
|
||||
sa.Column('tags', sa.Text()),
|
||||
sa.UniqueConstraint(
|
||||
'instance_uuid', name='uniq_build_requests0instance_uuid'),
|
||||
|
@ -15,26 +15,23 @@ from oslo_db.sqlalchemy import models
|
||||
from oslo_log import log as logging
|
||||
import sqlalchemy as sa
|
||||
import sqlalchemy.dialects.mysql
|
||||
from sqlalchemy.ext.declarative import declarative_base
|
||||
from sqlalchemy.ext import declarative
|
||||
from sqlalchemy import orm
|
||||
from sqlalchemy import schema
|
||||
|
||||
from nova.db import types
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def MediumText():
|
||||
return sa.Text().with_variant(
|
||||
sqlalchemy.dialects.mysql.MEDIUMTEXT(), 'mysql')
|
||||
|
||||
|
||||
class _NovaAPIBase(models.ModelBase, models.TimestampMixin):
|
||||
pass
|
||||
|
||||
|
||||
API_BASE = declarative_base(cls=_NovaAPIBase)
|
||||
BASE = declarative.declarative_base(cls=_NovaAPIBase)
|
||||
|
||||
|
||||
class AggregateHost(API_BASE):
|
||||
class AggregateHost(BASE):
|
||||
"""Represents a host that is member of an aggregate."""
|
||||
__tablename__ = 'aggregate_hosts'
|
||||
__table_args__ = (schema.UniqueConstraint(
|
||||
@ -48,7 +45,7 @@ class AggregateHost(API_BASE):
|
||||
sa.Integer, sa.ForeignKey('aggregates.id'), nullable=False)
|
||||
|
||||
|
||||
class AggregateMetadata(API_BASE):
|
||||
class AggregateMetadata(BASE):
|
||||
"""Represents a metadata key/value pair for an aggregate."""
|
||||
__tablename__ = 'aggregate_metadata'
|
||||
__table_args__ = (
|
||||
@ -64,7 +61,7 @@ class AggregateMetadata(API_BASE):
|
||||
sa.Integer, sa.ForeignKey('aggregates.id'), nullable=False)
|
||||
|
||||
|
||||
class Aggregate(API_BASE):
|
||||
class Aggregate(BASE):
|
||||
"""Represents a cluster of hosts that exists in this zone."""
|
||||
__tablename__ = 'aggregates'
|
||||
__table_args__ = (
|
||||
@ -102,7 +99,7 @@ class Aggregate(API_BASE):
|
||||
return self.metadetails['availability_zone']
|
||||
|
||||
|
||||
class CellMapping(API_BASE):
|
||||
class CellMapping(BASE):
|
||||
"""Contains information on communicating with a cell"""
|
||||
__tablename__ = 'cell_mappings'
|
||||
__table_args__ = (
|
||||
@ -123,7 +120,7 @@ class CellMapping(API_BASE):
|
||||
primaryjoin='CellMapping.id == HostMapping.cell_id')
|
||||
|
||||
|
||||
class InstanceMapping(API_BASE):
|
||||
class InstanceMapping(BASE):
|
||||
"""Contains the mapping of an instance to which cell it is in"""
|
||||
__tablename__ = 'instance_mappings'
|
||||
__table_args__ = (
|
||||
@ -154,7 +151,7 @@ class InstanceMapping(API_BASE):
|
||||
primaryjoin='InstanceMapping.cell_id == CellMapping.id')
|
||||
|
||||
|
||||
class HostMapping(API_BASE):
|
||||
class HostMapping(BASE):
|
||||
"""Contains mapping of a compute host to which cell it is in"""
|
||||
__tablename__ = "host_mappings"
|
||||
__table_args__ = (
|
||||
@ -168,7 +165,7 @@ class HostMapping(API_BASE):
|
||||
host = sa.Column(sa.String(255), nullable=False)
|
||||
|
||||
|
||||
class RequestSpec(API_BASE):
|
||||
class RequestSpec(BASE):
|
||||
"""Represents the information passed to the scheduler."""
|
||||
|
||||
__tablename__ = 'request_specs'
|
||||
@ -180,10 +177,10 @@ class RequestSpec(API_BASE):
|
||||
|
||||
id = sa.Column(sa.Integer, primary_key=True)
|
||||
instance_uuid = sa.Column(sa.String(36), nullable=False)
|
||||
spec = sa.Column(MediumText(), nullable=False)
|
||||
spec = sa.Column(types.MediumText(), nullable=False)
|
||||
|
||||
|
||||
class Flavors(API_BASE):
|
||||
class Flavors(BASE):
|
||||
"""Represents possible flavors for instances"""
|
||||
__tablename__ = 'flavors'
|
||||
__table_args__ = (
|
||||
@ -205,7 +202,7 @@ class Flavors(API_BASE):
|
||||
description = sa.Column(sa.Text)
|
||||
|
||||
|
||||
class FlavorExtraSpecs(API_BASE):
|
||||
class FlavorExtraSpecs(BASE):
|
||||
"""Represents additional specs as key/value pairs for a flavor"""
|
||||
__tablename__ = 'flavor_extra_specs'
|
||||
__table_args__ = (
|
||||
@ -226,7 +223,7 @@ class FlavorExtraSpecs(API_BASE):
|
||||
primaryjoin='FlavorExtraSpecs.flavor_id == Flavors.id')
|
||||
|
||||
|
||||
class FlavorProjects(API_BASE):
|
||||
class FlavorProjects(BASE):
|
||||
"""Represents projects associated with flavors"""
|
||||
__tablename__ = 'flavor_projects'
|
||||
__table_args__ = (schema.UniqueConstraint('flavor_id', 'project_id',
|
||||
@ -242,7 +239,7 @@ class FlavorProjects(API_BASE):
|
||||
primaryjoin='FlavorProjects.flavor_id == Flavors.id')
|
||||
|
||||
|
||||
class BuildRequest(API_BASE):
|
||||
class BuildRequest(BASE):
|
||||
"""Represents the information passed to the scheduler."""
|
||||
|
||||
__tablename__ = 'build_requests'
|
||||
@ -257,8 +254,8 @@ class BuildRequest(API_BASE):
|
||||
# TODO(mriedem): instance_uuid should be nullable=False
|
||||
instance_uuid = sa.Column(sa.String(36))
|
||||
project_id = sa.Column(sa.String(255), nullable=False)
|
||||
instance = sa.Column(MediumText())
|
||||
block_device_mappings = sa.Column(MediumText())
|
||||
instance = sa.Column(types.MediumText())
|
||||
block_device_mappings = sa.Column(types.MediumText())
|
||||
tags = sa.Column(sa.Text())
|
||||
# TODO(alaski): Drop these from the db in Ocata
|
||||
# columns_to_drop = ['request_spec_id', 'user_id', 'display_name',
|
||||
@ -269,7 +266,7 @@ class BuildRequest(API_BASE):
|
||||
# 'ramdisk_id', 'root_device_name', 'user_data']
|
||||
|
||||
|
||||
class KeyPair(API_BASE):
|
||||
class KeyPair(BASE):
|
||||
"""Represents a public key pair for ssh / WinRM."""
|
||||
__tablename__ = 'key_pairs'
|
||||
__table_args__ = (
|
||||
@ -288,7 +285,7 @@ class KeyPair(API_BASE):
|
||||
|
||||
|
||||
# TODO(stephenfin): Remove this as it's now unused post-placement split
|
||||
class ResourceClass(API_BASE):
|
||||
class ResourceClass(BASE):
|
||||
"""Represents the type of resource for an inventory or allocation."""
|
||||
__tablename__ = 'resource_classes'
|
||||
__table_args__ = (
|
||||
@ -300,7 +297,7 @@ class ResourceClass(API_BASE):
|
||||
|
||||
|
||||
# TODO(stephenfin): Remove this as it's now unused post-placement split
|
||||
class ResourceProvider(API_BASE):
|
||||
class ResourceProvider(BASE):
|
||||
"""Represents a mapping to a providers of resources."""
|
||||
|
||||
__tablename__ = "resource_providers"
|
||||
@ -332,7 +329,7 @@ class ResourceProvider(API_BASE):
|
||||
|
||||
|
||||
# TODO(stephenfin): Remove this as it's now unused post-placement split
|
||||
class Inventory(API_BASE):
|
||||
class Inventory(BASE):
|
||||
"""Represents a quantity of available resource."""
|
||||
|
||||
__tablename__ = "inventories"
|
||||
@ -369,7 +366,7 @@ class Inventory(API_BASE):
|
||||
|
||||
|
||||
# TODO(stephenfin): Remove this as it's now unused post-placement split
|
||||
class Allocation(API_BASE):
|
||||
class Allocation(BASE):
|
||||
"""A use of inventory."""
|
||||
|
||||
__tablename__ = "allocations"
|
||||
@ -396,7 +393,7 @@ class Allocation(API_BASE):
|
||||
|
||||
|
||||
# TODO(stephenfin): Remove this as it's now unused post-placement split
|
||||
class ResourceProviderAggregate(API_BASE):
|
||||
class ResourceProviderAggregate(BASE):
|
||||
"""Associate a resource provider with an aggregate."""
|
||||
|
||||
__tablename__ = 'resource_provider_aggregates'
|
||||
@ -411,7 +408,7 @@ class ResourceProviderAggregate(API_BASE):
|
||||
|
||||
|
||||
# TODO(stephenfin): Remove this as it's now unused post-placement split
|
||||
class PlacementAggregate(API_BASE):
|
||||
class PlacementAggregate(BASE):
|
||||
"""A grouping of resource providers."""
|
||||
__tablename__ = 'placement_aggregates'
|
||||
__table_args__ = (
|
||||
@ -422,7 +419,7 @@ class PlacementAggregate(API_BASE):
|
||||
uuid = sa.Column(sa.String(36), index=True)
|
||||
|
||||
|
||||
class InstanceGroupMember(API_BASE):
|
||||
class InstanceGroupMember(BASE):
|
||||
"""Represents the members for an instance group."""
|
||||
__tablename__ = 'instance_group_member'
|
||||
__table_args__ = (
|
||||
@ -434,7 +431,7 @@ class InstanceGroupMember(API_BASE):
|
||||
sa.Integer, sa.ForeignKey('instance_groups.id'), nullable=False)
|
||||
|
||||
|
||||
class InstanceGroupPolicy(API_BASE):
|
||||
class InstanceGroupPolicy(BASE):
|
||||
"""Represents the policy type for an instance group."""
|
||||
__tablename__ = 'instance_group_policy'
|
||||
__table_args__ = (
|
||||
@ -448,7 +445,7 @@ class InstanceGroupPolicy(API_BASE):
|
||||
rules = sa.Column(sa.Text)
|
||||
|
||||
|
||||
class InstanceGroup(API_BASE):
|
||||
class InstanceGroup(BASE):
|
||||
"""Represents an instance group.
|
||||
|
||||
A group will maintain a collection of instances and the relationship
|
||||
@ -487,7 +484,7 @@ class InstanceGroup(API_BASE):
|
||||
return [m.instance_uuid for m in self._members]
|
||||
|
||||
|
||||
class Quota(API_BASE):
|
||||
class Quota(BASE):
|
||||
"""Represents a single quota override for a project.
|
||||
|
||||
If there is no row for a given project id and resource, then the
|
||||
@ -511,7 +508,7 @@ class Quota(API_BASE):
|
||||
hard_limit = sa.Column(sa.Integer)
|
||||
|
||||
|
||||
class ProjectUserQuota(API_BASE):
|
||||
class ProjectUserQuota(BASE):
|
||||
"""Represents a single quota override for a user with in a project."""
|
||||
|
||||
__tablename__ = 'project_user_quotas'
|
||||
@ -535,7 +532,7 @@ class ProjectUserQuota(API_BASE):
|
||||
hard_limit = sa.Column(sa.Integer)
|
||||
|
||||
|
||||
class QuotaClass(API_BASE):
|
||||
class QuotaClass(BASE):
|
||||
"""Represents a single quota override for a quota class.
|
||||
|
||||
If there is no row for a given quota class and resource, then the
|
||||
@ -555,7 +552,7 @@ class QuotaClass(API_BASE):
|
||||
hard_limit = sa.Column(sa.Integer)
|
||||
|
||||
|
||||
class QuotaUsage(API_BASE):
|
||||
class QuotaUsage(BASE):
|
||||
"""Represents the current usage for a given resource."""
|
||||
|
||||
__tablename__ = 'quota_usages'
|
||||
@ -578,7 +575,7 @@ class QuotaUsage(API_BASE):
|
||||
until_refresh = sa.Column(sa.Integer)
|
||||
|
||||
|
||||
class Reservation(API_BASE):
|
||||
class Reservation(BASE):
|
||||
"""Represents a resource reservation for quotas."""
|
||||
|
||||
__tablename__ = 'reservations'
|
||||
@ -604,7 +601,7 @@ class Reservation(API_BASE):
|
||||
primaryjoin='Reservation.usage_id == QuotaUsage.id')
|
||||
|
||||
|
||||
class Trait(API_BASE):
|
||||
class Trait(BASE):
|
||||
"""Represents a trait."""
|
||||
|
||||
__tablename__ = "traits"
|
||||
@ -618,7 +615,7 @@ class Trait(API_BASE):
|
||||
|
||||
|
||||
# TODO(stephenfin): Remove this as it's now unused post-placement split
|
||||
class ResourceProviderTrait(API_BASE):
|
||||
class ResourceProviderTrait(BASE):
|
||||
"""Represents the relationship between traits and resource provider"""
|
||||
|
||||
__tablename__ = "resource_provider_traits"
|
||||
@ -638,7 +635,7 @@ class ResourceProviderTrait(API_BASE):
|
||||
|
||||
|
||||
# TODO(stephenfin): Remove this as it's unused
|
||||
class Project(API_BASE):
|
||||
class Project(BASE):
|
||||
"""The project is the Keystone project."""
|
||||
|
||||
__tablename__ = 'projects'
|
||||
@ -655,7 +652,7 @@ class Project(API_BASE):
|
||||
|
||||
|
||||
# TODO(stephenfin): Remove this as it's unused
|
||||
class User(API_BASE):
|
||||
class User(BASE):
|
||||
"""The user is the Keystone user."""
|
||||
|
||||
__tablename__ = 'users'
|
||||
@ -669,7 +666,7 @@ class User(API_BASE):
|
||||
|
||||
|
||||
# TODO(stephenfin): Remove this as it's unused
|
||||
class Consumer(API_BASE):
|
||||
class Consumer(BASE):
|
||||
"""Represents a resource consumer."""
|
||||
|
||||
__tablename__ = 'consumers'
|
||||
|
@ -25,14 +25,6 @@ from nova.objects import keypair
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
# NOTE(dprince): This wrapper allows us to easily match the Folsom MySQL
|
||||
# Schema. In Folsom we created tables as latin1 and converted them to utf8
|
||||
# later. This conversion causes some of the Text columns on MySQL to get
|
||||
# created as mediumtext instead of just text.
|
||||
def MediumText():
|
||||
return sa.Text().with_variant(dialects.mysql.MEDIUMTEXT(), 'mysql')
|
||||
|
||||
|
||||
def Inet():
|
||||
return sa.String(length=43).with_variant(
|
||||
dialects.postgresql.INET(), 'postgresql',
|
||||
@ -290,7 +282,7 @@ def upgrade(migrate_engine):
|
||||
sa.Column('volume_id', sa.String(length=36), nullable=True),
|
||||
sa.Column('volume_size', sa.Integer),
|
||||
sa.Column('no_device', sa.Boolean),
|
||||
sa.Column('connection_info', MediumText()),
|
||||
sa.Column('connection_info', types.MediumText()),
|
||||
sa.Column(
|
||||
'instance_uuid', sa.String(length=36),
|
||||
sa.ForeignKey(
|
||||
@ -391,9 +383,9 @@ def upgrade(migrate_engine):
|
||||
sa.Column('vcpus_used', sa.Integer, nullable=False),
|
||||
sa.Column('memory_mb_used', sa.Integer, nullable=False),
|
||||
sa.Column('local_gb_used', sa.Integer, nullable=False),
|
||||
sa.Column('hypervisor_type', MediumText(), nullable=False),
|
||||
sa.Column('hypervisor_type', types.MediumText(), nullable=False),
|
||||
sa.Column('hypervisor_version', sa.Integer, nullable=False),
|
||||
sa.Column('cpu_info', MediumText(), nullable=False),
|
||||
sa.Column('cpu_info', types.MediumText(), nullable=False),
|
||||
sa.Column('disk_available_least', sa.Integer),
|
||||
sa.Column('free_ram_mb', sa.Integer),
|
||||
sa.Column('free_disk_gb', sa.Integer),
|
||||
@ -584,7 +576,7 @@ def upgrade(migrate_engine):
|
||||
'instances.uuid', name='fk_instance_faults_instance_uuid')),
|
||||
sa.Column('code', sa.Integer, nullable=False),
|
||||
sa.Column('message', sa.String(length=255)),
|
||||
sa.Column('details', MediumText()),
|
||||
sa.Column('details', types.MediumText()),
|
||||
sa.Column('host', sa.String(length=255)),
|
||||
sa.Column('deleted', sa.Integer),
|
||||
sa.Index('instance_faults_host_idx', 'host'),
|
||||
@ -612,7 +604,7 @@ def upgrade(migrate_engine):
|
||||
sa.Column('updated_at', sa.DateTime),
|
||||
sa.Column('deleted_at', sa.DateTime),
|
||||
sa.Column('id', sa.Integer, primary_key=True, nullable=False),
|
||||
sa.Column('network_info', MediumText()),
|
||||
sa.Column('network_info', types.MediumText()),
|
||||
sa.Column(
|
||||
'instance_uuid', sa.String(length=36),
|
||||
sa.ForeignKey(
|
||||
@ -797,14 +789,14 @@ def upgrade(migrate_engine):
|
||||
sa.Column('ramdisk_id', sa.String(length=255)),
|
||||
sa.Column('launch_index', sa.Integer),
|
||||
sa.Column('key_name', sa.String(length=255)),
|
||||
sa.Column('key_data', MediumText()),
|
||||
sa.Column('key_data', types.MediumText()),
|
||||
sa.Column('power_state', sa.Integer),
|
||||
sa.Column('vm_state', sa.String(length=255)),
|
||||
sa.Column('memory_mb', sa.Integer),
|
||||
sa.Column('vcpus', sa.Integer),
|
||||
sa.Column('hostname', sa.String(length=255)),
|
||||
sa.Column('host', sa.String(length=255)),
|
||||
sa.Column('user_data', MediumText()),
|
||||
sa.Column('user_data', types.MediumText()),
|
||||
sa.Column('reservation_id', sa.String(length=255)),
|
||||
sa.Column('launched_at', sa.DateTime),
|
||||
sa.Column('terminated_at', sa.DateTime),
|
||||
@ -813,7 +805,7 @@ def upgrade(migrate_engine):
|
||||
sa.Column('availability_zone', sa.String(length=255)),
|
||||
sa.Column('locked', sa.Boolean),
|
||||
sa.Column('os_type', sa.String(length=255)),
|
||||
sa.Column('launched_on', MediumText()),
|
||||
sa.Column('launched_on', types.MediumText()),
|
||||
sa.Column('instance_type_id', sa.Integer),
|
||||
sa.Column('vm_mode', sa.String(length=255)),
|
||||
sa.Column('uuid', sa.String(length=36), nullable=False),
|
||||
@ -973,7 +965,7 @@ def upgrade(migrate_engine):
|
||||
sa.Column('name', sa.String(length=255), nullable=False),
|
||||
sa.Column('user_id', sa.String(length=255)),
|
||||
sa.Column('fingerprint', sa.String(length=255)),
|
||||
sa.Column('public_key', MediumText()),
|
||||
sa.Column('public_key', types.MediumText()),
|
||||
sa.Column('deleted', sa.Integer),
|
||||
sa.Column(
|
||||
'type', sa.Enum('ssh', 'x509', name='keypair_types'),
|
||||
|
@ -16,6 +16,8 @@ from alembic import context
|
||||
from sqlalchemy import engine_from_config
|
||||
from sqlalchemy import pool
|
||||
|
||||
from nova.db.main import models
|
||||
|
||||
# this is the Alembic Config object, which provides
|
||||
# access to the values within the .ini file in use.
|
||||
config = context.config
|
||||
@ -29,7 +31,20 @@ if config.attributes.get('configure_logger', True):
|
||||
# for 'autogenerate' support
|
||||
# from myapp import mymodel
|
||||
# target_metadata = mymodel.Base.metadata
|
||||
target_metadata = None
|
||||
target_metadata = models.BASE.metadata
|
||||
|
||||
|
||||
def include_name(name, type_, parent_names):
|
||||
if type_ == 'table':
|
||||
return not name.startswith('shadow_')
|
||||
|
||||
if type_ == 'column':
|
||||
return (parent_names['table_name'], name) not in {
|
||||
('instances', 'internal_id'),
|
||||
('instance_extra', 'vpmems'),
|
||||
}
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def run_migrations_offline():
|
||||
@ -45,6 +60,7 @@ def run_migrations_offline():
|
||||
context.configure(
|
||||
url=url,
|
||||
target_metadata=target_metadata,
|
||||
include_name=include_name,
|
||||
literal_binds=True,
|
||||
dialect_opts={"paramstyle": "named"},
|
||||
)
|
||||
@ -80,7 +96,9 @@ def run_migrations_online():
|
||||
|
||||
with connectable.connect() as connection:
|
||||
context.configure(
|
||||
connection=connection, target_metadata=target_metadata
|
||||
connection=connection,
|
||||
target_metadata=target_metadata,
|
||||
include_name=include_name,
|
||||
)
|
||||
|
||||
with context.begin_transaction():
|
||||
|
@ -30,7 +30,3 @@ depends_on = ${repr(depends_on)}
|
||||
|
||||
def upgrade():
|
||||
${upgrades if upgrades else "pass"}
|
||||
|
||||
|
||||
def downgrade():
|
||||
${downgrades if downgrades else "pass"}
|
||||
|
@ -33,14 +33,6 @@ branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
# NOTE(dprince): This wrapper allows us to easily match the Folsom MySQL
|
||||
# Schema. In Folsom we created tables as latin1 and converted them to utf8
|
||||
# later. This conversion causes some of the Text columns on MySQL to get
|
||||
# created as mediumtext instead of just text.
|
||||
def MediumText():
|
||||
return sa.Text().with_variant(dialects.mysql.MEDIUMTEXT(), 'mysql')
|
||||
|
||||
|
||||
def Inet():
|
||||
return sa.String(length=43).with_variant(
|
||||
dialects.postgresql.INET(), 'postgresql',
|
||||
@ -204,14 +196,14 @@ def upgrade():
|
||||
sa.Column('ramdisk_id', sa.String(length=255)),
|
||||
sa.Column('launch_index', sa.Integer),
|
||||
sa.Column('key_name', sa.String(length=255)),
|
||||
sa.Column('key_data', MediumText()),
|
||||
sa.Column('key_data', types.MediumText()),
|
||||
sa.Column('power_state', sa.Integer),
|
||||
sa.Column('vm_state', sa.String(length=255)),
|
||||
sa.Column('memory_mb', sa.Integer),
|
||||
sa.Column('vcpus', sa.Integer),
|
||||
sa.Column('hostname', sa.String(length=255)),
|
||||
sa.Column('host', sa.String(length=255)),
|
||||
sa.Column('user_data', MediumText()),
|
||||
sa.Column('user_data', types.MediumText()),
|
||||
sa.Column('reservation_id', sa.String(length=255)),
|
||||
sa.Column('launched_at', sa.DateTime),
|
||||
sa.Column('terminated_at', sa.DateTime),
|
||||
@ -220,7 +212,7 @@ def upgrade():
|
||||
sa.Column('availability_zone', sa.String(length=255)),
|
||||
sa.Column('locked', sa.Boolean),
|
||||
sa.Column('os_type', sa.String(length=255)),
|
||||
sa.Column('launched_on', MediumText()),
|
||||
sa.Column('launched_on', types.MediumText()),
|
||||
sa.Column('instance_type_id', sa.Integer),
|
||||
sa.Column('vm_mode', sa.String(length=255)),
|
||||
sa.Column('uuid', sa.String(length=36), nullable=False),
|
||||
@ -381,7 +373,7 @@ def upgrade():
|
||||
sa.Column('volume_id', sa.String(length=36), nullable=True),
|
||||
sa.Column('volume_size', sa.Integer),
|
||||
sa.Column('no_device', sa.Boolean),
|
||||
sa.Column('connection_info', MediumText()),
|
||||
sa.Column('connection_info', types.MediumText()),
|
||||
sa.Column(
|
||||
'instance_uuid', sa.String(length=36),
|
||||
sa.ForeignKey(
|
||||
@ -486,9 +478,9 @@ def upgrade():
|
||||
sa.Column('vcpus_used', sa.Integer, nullable=False),
|
||||
sa.Column('memory_mb_used', sa.Integer, nullable=False),
|
||||
sa.Column('local_gb_used', sa.Integer, nullable=False),
|
||||
sa.Column('hypervisor_type', MediumText(), nullable=False),
|
||||
sa.Column('hypervisor_type', types.MediumText(), nullable=False),
|
||||
sa.Column('hypervisor_version', sa.Integer, nullable=False),
|
||||
sa.Column('cpu_info', MediumText(), nullable=False),
|
||||
sa.Column('cpu_info', types.MediumText(), nullable=False),
|
||||
sa.Column('disk_available_least', sa.Integer),
|
||||
sa.Column('free_ram_mb', sa.Integer),
|
||||
sa.Column('free_disk_gb', sa.Integer),
|
||||
@ -686,7 +678,7 @@ def upgrade():
|
||||
'instances.uuid', name='fk_instance_faults_instance_uuid')),
|
||||
sa.Column('code', sa.Integer, nullable=False),
|
||||
sa.Column('message', sa.String(length=255)),
|
||||
sa.Column('details', MediumText()),
|
||||
sa.Column('details', types.MediumText()),
|
||||
sa.Column('host', sa.String(length=255)),
|
||||
sa.Column('deleted', sa.Integer),
|
||||
sa.Index('instance_faults_host_idx', 'host'),
|
||||
@ -716,7 +708,7 @@ def upgrade():
|
||||
sa.Column('updated_at', sa.DateTime),
|
||||
sa.Column('deleted_at', sa.DateTime),
|
||||
sa.Column('id', sa.Integer, primary_key=True, nullable=False),
|
||||
sa.Column('network_info', MediumText()),
|
||||
sa.Column('network_info', types.MediumText()),
|
||||
sa.Column(
|
||||
'instance_uuid', sa.String(length=36),
|
||||
sa.ForeignKey(
|
||||
@ -1004,7 +996,7 @@ def upgrade():
|
||||
sa.Column('name', sa.String(length=255), nullable=False),
|
||||
sa.Column('user_id', sa.String(length=255)),
|
||||
sa.Column('fingerprint', sa.String(length=255)),
|
||||
sa.Column('public_key', MediumText()),
|
||||
sa.Column('public_key', types.MediumText()),
|
||||
sa.Column('deleted', sa.Integer),
|
||||
sa.Column(
|
||||
'type', sa.Enum('ssh', 'x509', name='keypair_types'),
|
||||
|
@ -31,17 +31,13 @@ from sqlalchemy import schema
|
||||
from nova.db import types
|
||||
|
||||
CONF = cfg.CONF
|
||||
|
||||
# we don't configure 'cls' since we have models that don't use the
|
||||
# TimestampMixin
|
||||
BASE = declarative.declarative_base()
|
||||
|
||||
|
||||
def MediumText():
|
||||
return sa.Text().with_variant(
|
||||
sqlalchemy.dialects.mysql.MEDIUMTEXT(), 'mysql')
|
||||
|
||||
|
||||
class NovaBase(models.TimestampMixin,
|
||||
models.ModelBase):
|
||||
metadata = None
|
||||
class NovaBase(models.TimestampMixin, models.ModelBase):
|
||||
|
||||
def __copy__(self):
|
||||
"""Implement a safe copy.copy().
|
||||
@ -133,7 +129,7 @@ class ComputeNode(BASE, NovaBase, models.SoftDeleteMixin):
|
||||
vcpus_used = sa.Column(sa.Integer, nullable=False)
|
||||
memory_mb_used = sa.Column(sa.Integer, nullable=False)
|
||||
local_gb_used = sa.Column(sa.Integer, nullable=False)
|
||||
hypervisor_type = sa.Column(MediumText(), nullable=False)
|
||||
hypervisor_type = sa.Column(types.MediumText(), nullable=False)
|
||||
hypervisor_version = sa.Column(sa.Integer, nullable=False)
|
||||
hypervisor_hostname = sa.Column(sa.String(255))
|
||||
|
||||
@ -155,7 +151,7 @@ class ComputeNode(BASE, NovaBase, models.SoftDeleteMixin):
|
||||
# Points are "json translatable" and it must have all dictionary keys
|
||||
# above, since it is copied from <cpu> tag of getCapabilities()
|
||||
# (See libvirt.virtConnection).
|
||||
cpu_info = sa.Column(MediumText(), nullable=False)
|
||||
cpu_info = sa.Column(types.MediumText(), nullable=False)
|
||||
disk_available_least = sa.Column(sa.Integer)
|
||||
host_ip = sa.Column(types.IPAddress())
|
||||
supported_instances = sa.Column(sa.Text)
|
||||
@ -265,7 +261,7 @@ class Instance(BASE, NovaBase, models.SoftDeleteMixin):
|
||||
|
||||
launch_index = sa.Column(sa.Integer)
|
||||
key_name = sa.Column(sa.String(255))
|
||||
key_data = sa.Column(MediumText())
|
||||
key_data = sa.Column(types.MediumText())
|
||||
|
||||
power_state = sa.Column(sa.Integer)
|
||||
vm_state = sa.Column(sa.String(255))
|
||||
@ -287,7 +283,7 @@ class Instance(BASE, NovaBase, models.SoftDeleteMixin):
|
||||
# *not* flavorid, this is the internal primary_key
|
||||
instance_type_id = sa.Column(sa.Integer)
|
||||
|
||||
user_data = sa.Column(MediumText())
|
||||
user_data = sa.Column(types.MediumText())
|
||||
|
||||
reservation_id = sa.Column(sa.String(255))
|
||||
|
||||
@ -305,7 +301,7 @@ class Instance(BASE, NovaBase, models.SoftDeleteMixin):
|
||||
|
||||
# To remember on which host an instance booted.
|
||||
# An instance may have moved to another host by live migration.
|
||||
launched_on = sa.Column(MediumText())
|
||||
launched_on = sa.Column(types.MediumText())
|
||||
|
||||
# locked is superseded by locked_by and locked is not really
|
||||
# necessary but still used in API code so it remains.
|
||||
@ -369,7 +365,7 @@ class InstanceInfoCache(BASE, NovaBase, models.SoftDeleteMixin):
|
||||
id = sa.Column(sa.Integer, primary_key=True, autoincrement=True)
|
||||
|
||||
# text column used for storing a json object of network data for api
|
||||
network_info = sa.Column(MediumText())
|
||||
network_info = sa.Column(types.MediumText())
|
||||
|
||||
instance_uuid = sa.Column(sa.String(36), sa.ForeignKey('instances.uuid'),
|
||||
nullable=False)
|
||||
@ -644,7 +640,7 @@ class BlockDeviceMapping(BASE, NovaBase, models.SoftDeleteMixin):
|
||||
# for no device to suppress devices.
|
||||
no_device = sa.Column(sa.Boolean)
|
||||
|
||||
connection_info = sa.Column(MediumText())
|
||||
connection_info = sa.Column(types.MediumText())
|
||||
|
||||
tag = sa.Column(sa.String(255))
|
||||
|
||||
@ -767,7 +763,7 @@ class KeyPair(BASE, NovaBase, models.SoftDeleteMixin):
|
||||
user_id = sa.Column(sa.String(255))
|
||||
|
||||
fingerprint = sa.Column(sa.String(255))
|
||||
public_key = sa.Column(MediumText())
|
||||
public_key = sa.Column(types.MediumText())
|
||||
type = sa.Column(sa.Enum('ssh', 'x509', name='keypair_types'),
|
||||
nullable=False, server_default='ssh')
|
||||
|
||||
@ -1323,7 +1319,7 @@ class InstanceFault(BASE, NovaBase, models.SoftDeleteMixin):
|
||||
sa.ForeignKey('instances.uuid'))
|
||||
code = sa.Column(sa.Integer(), nullable=False)
|
||||
message = sa.Column(sa.String(255))
|
||||
details = sa.Column(MediumText())
|
||||
details = sa.Column(types.MediumText())
|
||||
host = sa.Column(sa.String(255))
|
||||
|
||||
|
||||
|
@ -17,12 +17,23 @@
|
||||
|
||||
import netaddr
|
||||
from oslo_utils import netutils
|
||||
from sqlalchemy.dialects import postgresql
|
||||
import sqlalchemy as sa
|
||||
import sqlalchemy.dialects.mysql
|
||||
import sqlalchemy.dialects.postgresql
|
||||
from sqlalchemy import types
|
||||
|
||||
from nova import utils
|
||||
|
||||
|
||||
# NOTE(dprince): This wrapper allows us to easily match the Folsom MySQL
|
||||
# Schema. In Folsom we created tables as latin1 and converted them to utf8
|
||||
# later. This conversion causes some of the Text columns on MySQL to get
|
||||
# created as mediumtext instead of just text.
|
||||
def MediumText():
|
||||
return sa.Text().with_variant(
|
||||
sqlalchemy.dialects.mysql.MEDIUMTEXT(), 'mysql')
|
||||
|
||||
|
||||
class IPAddress(types.TypeDecorator):
|
||||
"""An SQLAlchemy type representing an IP-address."""
|
||||
|
||||
@ -30,9 +41,10 @@ class IPAddress(types.TypeDecorator):
|
||||
|
||||
def load_dialect_impl(self, dialect):
|
||||
if dialect.name == 'postgresql':
|
||||
return dialect.type_descriptor(postgresql.INET())
|
||||
else:
|
||||
return dialect.type_descriptor(types.String(39))
|
||||
return dialect.type_descriptor(
|
||||
sqlalchemy.dialects.postgresql.INET())
|
||||
|
||||
return dialect.type_descriptor(types.String(39))
|
||||
|
||||
def process_bind_param(self, value, dialect):
|
||||
"""Process/Formats the value before insert it into the db."""
|
||||
@ -40,7 +52,7 @@ class IPAddress(types.TypeDecorator):
|
||||
return value
|
||||
# NOTE(maurosr): The purpose here is to convert ipv6 to the shortened
|
||||
# form, not validate it.
|
||||
elif netutils.is_valid_ipv6(value):
|
||||
if netutils.is_valid_ipv6(value):
|
||||
return utils.get_shortened_ipv6(value)
|
||||
return value
|
||||
|
||||
@ -52,9 +64,10 @@ class CIDR(types.TypeDecorator):
|
||||
|
||||
def load_dialect_impl(self, dialect):
|
||||
if dialect.name == 'postgresql':
|
||||
return dialect.type_descriptor(postgresql.INET())
|
||||
else:
|
||||
return dialect.type_descriptor(types.String(43))
|
||||
return dialect.type_descriptor(
|
||||
sqlalchemy.dialects.postgresql.INET())
|
||||
|
||||
return dialect.type_descriptor(types.String(43))
|
||||
|
||||
def process_bind_param(self, value, dialect):
|
||||
"""Process/Formats the value before insert it into the db."""
|
||||
|
@ -60,7 +60,7 @@ class NovaModelsMigrationsSync(test_migrations.ModelsMigrationsSync):
|
||||
return self.engine
|
||||
|
||||
def get_metadata(self):
|
||||
return models.API_BASE.metadata
|
||||
return models.BASE.metadata
|
||||
|
||||
def include_object(self, object_, name, type_, reflected, compare_to):
|
||||
if type_ == 'table':
|
||||
|
@ -14,7 +14,7 @@
|
||||
# under the License.
|
||||
|
||||
from nova.db.api import models as api_models
|
||||
from nova.db.main import models
|
||||
from nova.db.main import models as main_models
|
||||
from nova import test
|
||||
|
||||
|
||||
@ -78,9 +78,10 @@ class TestSoftDeletesDeprecated(test.NoDBTestCase):
|
||||
# Soft deletes are deprecated. Whitelist the tables that currently
|
||||
# allow soft deletes. No new tables should be added to this whitelist.
|
||||
tables = []
|
||||
for base in [models.BASE, api_models.API_BASE]:
|
||||
for base in [main_models.BASE, api_models.BASE]:
|
||||
for table_name, table in base.metadata.tables.items():
|
||||
columns = [column.name for column in table.columns]
|
||||
if 'deleted' in columns or 'deleted_at' in columns:
|
||||
tables.append(table_name)
|
||||
|
||||
self.assertEqual(whitelist, sorted(tables))
|
||||
|
@ -62,8 +62,10 @@ class _TestFlavor(object):
|
||||
# but the object has tz-aware datetimes. If we're comparing
|
||||
# a model to an object (as opposed to a fake dict), just
|
||||
# ignore the datetimes in the comparison.
|
||||
if (isinstance(db, api_models.API_BASE) and
|
||||
isinstance(value, datetime.datetime)):
|
||||
if (
|
||||
isinstance(db, api_models.BASE) and
|
||||
isinstance(value, datetime.datetime)
|
||||
):
|
||||
continue
|
||||
test.assertEqual(db[field], obj[field])
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user