diff --git a/cloudkitty/common/__init__.py b/cloudkitty/common/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/cloudkitty/common/db/__init__.py b/cloudkitty/common/db/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/cloudkitty/common/db/alembic/__init__.py b/cloudkitty/common/db/alembic/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/cloudkitty/common/db/alembic/alembic.ini b/cloudkitty/common/db/alembic/alembic.ini new file mode 100644 index 00000000..aaefd533 --- /dev/null +++ b/cloudkitty/common/db/alembic/alembic.ini @@ -0,0 +1,59 @@ +# A generic, single database configuration. + +[alembic] +# path to migration scripts +script_location = alembic + +# template used to generate migration files +# file_template = %%(rev)s_%%(slug)s + +# max length of characters to apply to the +# "slug" field +#truncate_slug_length = 40 + +# set to 'true' to run the environment during +# the 'revision' command, regardless of autogenerate +# revision_environment = false + +# set to 'true' to allow .pyc and .pyo files without +# a source .py file to be detected as revisions in the +# versions/ directory +# sourceless = false + +# sqlalchemy.url = driver://user:pass@localhost/dbname + + +# Logging configuration +[loggers] +keys = root,sqlalchemy,alembic + +[handlers] +keys = console + +[formatters] +keys = generic + +[logger_root] +level = WARN +handlers = console +qualname = + +[logger_sqlalchemy] +level = WARN +handlers = +qualname = sqlalchemy.engine + +[logger_alembic] +level = INFO +handlers = +qualname = alembic + +[handler_console] +class = StreamHandler +args = (sys.stderr,) +level = NOTSET +formatter = generic + +[formatter_generic] +format = %(levelname)-5.5s [%(name)s] %(message)s +datefmt = %H:%M:%S diff --git a/cloudkitty/common/db/alembic/env.py b/cloudkitty/common/db/alembic/env.py new file mode 100644 index 00000000..af5fdaac --- /dev/null +++ b/cloudkitty/common/db/alembic/env.py @@ -0,0 +1,43 @@ +# -*- coding: utf-8 -*- +# Copyright 2014 Objectif Libre +# +# 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. +# +# @author: Stéphane Albert +# +from logging import config as log_config + +from alembic import context + +from cloudkitty import db + +config = context.config +log_config.fileConfig(config.config_file_name) + + +def run_migrations_online(target_metadata, version_table): + """Run migrations in 'online' mode. + + In this scenario we need to create an Engine + and associate a connection with the context. + + :param target_metadata: Model's metadata used for autogenerate support. + :param version_table: Override the default version table for alembic. + """ + engine = db.get_engine() + with engine.connect() as connection: + context.configure(connection=connection, + target_metadata=target_metadata, + version_table=version_table) + with context.begin_transaction(): + context.run_migrations() diff --git a/cloudkitty/common/db/alembic/migration.py b/cloudkitty/common/db/alembic/migration.py new file mode 100644 index 00000000..566e1113 --- /dev/null +++ b/cloudkitty/common/db/alembic/migration.py @@ -0,0 +1,70 @@ +# -*- coding: utf-8 -*- +# Copyright 2014 Objectif Libre +# +# 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. +# +# @author: Stéphane Albert +# +import os + +import alembic +from alembic import config as alembic_config + +ALEMBIC_INI_PATH = os.path.join(os.path.dirname(__file__), 'alembic.ini') + + +def load_alembic_config(repo_path, ini_path=ALEMBIC_INI_PATH): + if not os.path.exists(repo_path): + raise Exception('Repo path (%s) not found.' % repo_path) + if not os.path.exists(ini_path): + raise Exception('Ini path (%s) not found.' % ini_path) + config = alembic_config.Config(ini_path) + config.set_main_option('script_location', repo_path) + return config + + +def upgrade(config, version): + return alembic.command.upgrade(config, version or 'head') + + +def downgrade(config, version): + if isinstance(version, int) or version is None or version.isdigit(): + version = 'base' + return alembic.command.downgrade(config, version) + + +def version(config): + return alembic.command.current(config) + + +def revision(config, message='', autogenerate=False): + """Creates template for migration. + + :param message: Text that will be used for migration title + :type message: string + :param autogenerate: If True - generates diff based on current database + state + :type autogenerate: bool + """ + return alembic.command.revision(config, message=message, + autogenerate=autogenerate) + + +def stamp(config, revision): + """Stamps database with provided revision. + + :param revision: Should match one from repository or head - to stamp + database with most recent revision + :type revision: string + """ + return alembic.command.stamp(config, revision=revision)