From 1467304878daf06ef12349e8520ec00f962ff6ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Albert?= Date: Fri, 8 Aug 2014 15:56:14 +0200 Subject: [PATCH] Added cloudkitty-dbsync tool Change-Id: Ib20a0c20c93a4d67995d1a1ed848d20d841ec504 --- cloudkitty/cli/dbsync.py | 152 +++++++++++++++++++++++++++++++++++++++ setup.cfg | 1 + 2 files changed, 153 insertions(+) create mode 100644 cloudkitty/cli/dbsync.py diff --git a/cloudkitty/cli/dbsync.py b/cloudkitty/cli/dbsync.py new file mode 100644 index 00000000..c65ad6a7 --- /dev/null +++ b/cloudkitty/cli/dbsync.py @@ -0,0 +1,152 @@ +# -*- 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 sys + +from oslo.config import cfg +from stevedore import extension + +from cloudkitty import config # noqa +from cloudkitty.db import api as db_api +from cloudkitty.openstack.common import log as logging + +CONF = cfg.CONF + + +class ModuleNotFound(Exception): + def __init__(self, name): + self.name = name + super(ModuleNotFound, self).__init__( + 'Module %s not found' % name) + + +class MultipleModulesRevisions(Exception): + def __init__(self, revision): + self.revision = revision + super(MultipleModulesRevisions, self).__init__( + 'Can\'t apply revision %s to multiple modules' + % revision) + + +class DBCommand(object): + + def __init__(self): + self.billing_models = {} + self._load_billing_models() + + def _load_billing_models(self): + extensions = extension.ExtensionManager( + 'cloudkitty.billing.processors') + self.billing_models = {} + for ext in extensions: + if hasattr(ext.plugin, 'db_api'): + self.billing_models[ext.name] = ext.plugin.db_api + + def get_module_migration(self, name): + if name == 'cloudkitty': + mod_migration = db_api.get_instance().get_migration() + else: + try: + module = self.billing_models[name] + mod_migration = module.get_migrate() + except IndexError: + raise ModuleNotFound(name) + return mod_migration + + def get_migrations(self, name=None): + if not name: + migrations = [] + migrations.append(self.get_module_migration('cloudkitty')) + for model in self.billing_models.values(): + migrations.append(model.get_migrate()) + else: + return [self.get_module_migration(name)] + return migrations + + def check_revsion(self, revision): + revision = revision or 'head' + if revision not in ('base', 'head'): + raise MultipleModulesRevisions(revision) + + def upgrade(self): + if CONF.command.module: + self.check_revsion(CONF.command.revision) + migrations = self.get_migrations() + for migration in migrations: + migration.upgrade(CONF.command.revision) + + def downgrade(self): + if CONF.command.module: + self.check_revsion(CONF.command.revision) + migrations = self.get_migrations() + for migration in migrations: + migration.downgrade(CONF.command.revision) + + def revision(self): + migration = self.get_module_migration(CONF.command.module) + migration.revision(CONF.command.message, CONF.command.autogenerate) + + def stamp(self): + migration = self.get_module_migration(CONF.command.module) + migration.stamp(CONF.command.revision) + + def version(self): + migration = self.get_module_migration(CONF.command.module) + migration.version() + + +def add_command_parsers(subparsers): + command_object = DBCommand() + + parser = subparsers.add_parser('upgrade') + parser.set_defaults(func=command_object.upgrade) + parser.add_argument('--revision', nargs='?') + parser.add_argument('--module', nargs='?') + + parser = subparsers.add_parser('downgrade') + parser.set_defaults(func=command_object.downgrade) + parser.add_argument('--revision', nargs='?') + parser.add_argument('--module', nargs='?') + + parser = subparsers.add_parser('stamp') + parser.set_defaults(func=command_object.stamp) + parser.add_argument('--revision', nargs='?') + parser.add_argument('--module', required=True) + + parser = subparsers.add_parser('revision') + parser.set_defaults(func=command_object.revision) + parser.add_argument('-m', '--message') + parser.add_argument('--autogenerate', action='store_true') + parser.add_argument('--module', required=True) + + parser = subparsers.add_parser('version') + parser.set_defaults(func=command_object.version) + parser.add_argument('--module', required=True) + + +command_opt = cfg.SubCommandOpt('command', + title='Command', + help='Available commands', + handler=add_command_parsers) + +CONF.register_cli_opt(command_opt) + + +def main(): + cfg.CONF(sys.argv[1:], project='cloudkitty') + logging.setup('cloudkitty') + CONF.command.func() diff --git a/setup.cfg b/setup.cfg index e495611f..0e504b8d 100644 --- a/setup.cfg +++ b/setup.cfg @@ -21,6 +21,7 @@ packages = [entry_points] console_scripts = cloudkitty-api = cloudkitty.cli.api:main + cloudkitty-dbsync = cloudkitty.cli.dbsync:main cloudkitty-processor = cloudkitty.orchestrator:main cloudkitty.collector.backends =