From: Liang Chen Date: Fri, 26 Jul 2013 13:39:09 +0000 (+0800) Subject: Provide a way to clean up soft deleted data X-Git-Tag: 2014.1~253^2 X-Git-Url: https://review.fuel-infra.org/gitweb?a=commitdiff_plain;h=30b8a186a83522838b9bc1a30a4032770d2fb2e8;p=openstack-build%2Fheat-build.git Provide a way to clean up soft deleted data Add a purge_deleted command to heat-manage. The command takes an 'age' argument, and removes all database records that have been soft deleted for more than 'age' days. Default to 90. blueprint event-persistence Change-Id: I8a62108a907b4e709c91a93a1f7db6c702cec6b5 --- diff --git a/heat/cmd/manage.py b/heat/cmd/manage.py index 9834f506..d3852fb4 100644 --- a/heat/cmd/manage.py +++ b/heat/cmd/manage.py @@ -24,6 +24,7 @@ from oslo.config import cfg from heat.db import api as db_api from heat.db import migration +from heat.db import utils from heat.openstack.common import log from heat import version @@ -44,6 +45,13 @@ def do_db_sync(): migration.db_sync(CONF.command.version) +def purge_deleted(): + """ + Remove database records that have been previously soft deleted + """ + utils.purge_deleted(CONF.command.age) + + def add_command_parsers(subparsers): parser = subparsers.add_parser('db_version') parser.set_defaults(func=do_db_version) @@ -53,6 +61,9 @@ def add_command_parsers(subparsers): parser.add_argument('version', nargs='?') parser.add_argument('current_version', nargs='?') + parser = subparsers.add_parser('purge_deleted') + parser.set_defaults(func=purge_deleted) + parser.add_argument('age', nargs='?') command_opt = cfg.SubCommandOpt('command', title='Commands', diff --git a/heat/db/sqlalchemy/api.py b/heat/db/sqlalchemy/api.py index dd1b91c9..aa4f4049 100644 --- a/heat/db/sqlalchemy/api.py +++ b/heat/db/sqlalchemy/api.py @@ -14,11 +14,18 @@ # under the License. '''Implementation of SQLAlchemy backend.''' +from datetime import datetime +from datetime import timedelta + +import sqlalchemy from sqlalchemy.orm.session import Session +from heat.openstack.common.gettextutils import _ + from heat.common import crypt from heat.common import exception from heat.db.sqlalchemy import models +from heat.db.sqlalchemy.session import get_engine from heat.db.sqlalchemy.session import get_session @@ -388,3 +395,42 @@ def watch_data_delete(context, watch_name): for d in ds: session.delete(d) session.flush() + + +def purge_deleted(age): + if age is not None: + try: + age = int(age) + except ValueError: + raise exception.Error(_("age should be an integer")) + if age < 0: + raise exception.Error(_("age should be a positive integer")) + else: + age = 90 + + time_line = datetime.now() - timedelta(days=age) + engine = get_engine() + meta = sqlalchemy.MetaData() + meta.bind = engine + + stack = sqlalchemy.Table('stack', meta, autoload=True) + event = sqlalchemy.Table('event', meta, autoload=True) + raw_template = sqlalchemy.Table('raw_template', meta, autoload=True) + user_creds = sqlalchemy.Table('user_creds', meta, autoload=True) + + stmt = sqlalchemy.select([stack.c.id, + stack.c.raw_template_id, + stack.c.user_creds_id]).\ + where(stack.c.deleted_at < time_line) + deleted_stacks = engine.execute(stmt) + + for s in deleted_stacks: + event_del = event.delete().where(event.c.stack_id == s[0]) + engine.execute(event_del) + stack_del = stack.delete().where(stack.c.id == s[0]) + engine.execute(stack_del) + raw_template_del = raw_template.delete().\ + where(raw_template.c.id == s[1]) + engine.execute(raw_template_del) + user_creds_del = user_creds.delete().where(user_creds.c.id == s[2]) + engine.execute(user_creds_del) diff --git a/heat/db/utils.py b/heat/db/utils.py index d494b927..24504261 100644 --- a/heat/db/utils.py +++ b/heat/db/utils.py @@ -39,3 +39,11 @@ class LazyPluggable(object): def __getattr__(self, key): backend = self.__get_backend() return getattr(backend, key) + + +IMPL = LazyPluggable('db_backend', + sqlalchemy='heat.db.sqlalchemy.api') + + +def purge_deleted(age): + IMPL.purge_deleted(age)