Add granularity option to purge_deleted
Allow users to choose how many days, hours, minutes, or seconds to preserve deleted data. Closes-bug: #1237195 Change-Id: I9227f5bf53c5b099a7a691a49c4ff2f5f0662098
This commit is contained in:
parent
a1ad08354b
commit
b61cd62db6
@ -48,7 +48,7 @@ def purge_deleted():
|
||||
"""
|
||||
Remove database records that have been previously soft deleted
|
||||
"""
|
||||
utils.purge_deleted(CONF.command.age)
|
||||
utils.purge_deleted(CONF.command.age, CONF.command.granularity)
|
||||
|
||||
|
||||
def add_command_parsers(subparsers):
|
||||
@ -62,8 +62,12 @@ def add_command_parsers(subparsers):
|
||||
|
||||
parser = subparsers.add_parser('purge_deleted')
|
||||
parser.set_defaults(func=purge_deleted)
|
||||
parser.add_argument('age', nargs='?',
|
||||
help=_('Number of days to preserve.'))
|
||||
parser.add_argument('age', nargs='?', default='90',
|
||||
help=_('How long to preserve deleted data.'))
|
||||
parser.add_argument(
|
||||
'-g', '--granularity', default='days',
|
||||
choices=['days', 'hours', 'minutes', 'seconds'],
|
||||
help=_('Granularity to use for age argument, defaults to days.'))
|
||||
|
||||
command_opt = cfg.SubCommandOpt('command',
|
||||
title='Commands',
|
||||
|
@ -470,18 +470,26 @@ def watch_data_get_all(context):
|
||||
return results
|
||||
|
||||
|
||||
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
|
||||
def purge_deleted(age, granularity='days'):
|
||||
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"))
|
||||
|
||||
time_line = datetime.now() - timedelta(days=age)
|
||||
if granularity not in ('days', 'hours', 'minutes', 'seconds'):
|
||||
raise exception.Error(
|
||||
_("granularity should be days, hours, minutes, or seconds"))
|
||||
|
||||
if granularity == 'days':
|
||||
age = age * 86400
|
||||
elif granularity == 'hours':
|
||||
age = age * 3600
|
||||
elif granularity == 'minutes':
|
||||
age = age * 60
|
||||
|
||||
time_line = datetime.now() - timedelta(seconds=age)
|
||||
engine = get_engine()
|
||||
meta = sqlalchemy.MetaData()
|
||||
meta.bind = engine
|
||||
|
@ -45,5 +45,5 @@ IMPL = LazyPluggable('db_backend',
|
||||
sqlalchemy='heat.db.sqlalchemy.api')
|
||||
|
||||
|
||||
def purge_deleted(age):
|
||||
IMPL.purge_deleted(age)
|
||||
def purge_deleted(age, granularity='days'):
|
||||
IMPL.purge_deleted(age, granularity)
|
||||
|
@ -10,9 +10,14 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import mox
|
||||
from datetime import datetime
|
||||
from datetime import timedelta
|
||||
|
||||
import fixtures
|
||||
from json import loads
|
||||
from json import dumps
|
||||
import mox
|
||||
|
||||
|
||||
from heat.db.sqlalchemy import api as db_api
|
||||
from heat.engine import environment
|
||||
@ -659,6 +664,45 @@ class DBAPIStackTest(HeatTestCase):
|
||||
|
||||
self.assertEqual(2, db_api.stack_count_all_by_tenant(self.ctx))
|
||||
|
||||
def test_purge_deleted(self):
|
||||
now = datetime.now()
|
||||
delta = timedelta(seconds=3600 * 7)
|
||||
deleted = [now - delta * i for i in range(1, 6)]
|
||||
templates = [create_raw_template(self.ctx) for i in range(5)]
|
||||
creds = [create_user_creds(self.ctx) for i in range(5)]
|
||||
stacks = [create_stack(self.ctx, templates[i], creds[i],
|
||||
deleted_at=deleted[i]) for i in range(5)]
|
||||
|
||||
class MyDatetime():
|
||||
def now(self):
|
||||
return now
|
||||
self.useFixture(fixtures.MonkeyPatch('heat.db.sqlalchemy.api.datetime',
|
||||
MyDatetime()))
|
||||
|
||||
db_api.purge_deleted(age=1, granularity='days')
|
||||
self._deleted_stack_existance(utils.dummy_context(), stacks,
|
||||
(0, 1, 2), (3, 4))
|
||||
|
||||
db_api.purge_deleted(age=22, granularity='hours')
|
||||
self._deleted_stack_existance(utils.dummy_context(), stacks,
|
||||
(0, 1, 2), (3, 4))
|
||||
|
||||
db_api.purge_deleted(age=1100, granularity='minutes')
|
||||
self._deleted_stack_existance(utils.dummy_context(), stacks,
|
||||
(0, 1), (2, 3, 4))
|
||||
|
||||
db_api.purge_deleted(age=3600, granularity='seconds')
|
||||
self._deleted_stack_existance(utils.dummy_context(), stacks,
|
||||
(), (0, 1, 2, 3, 4))
|
||||
|
||||
def _deleted_stack_existance(self, ctx, stacks, existing, deleted):
|
||||
for s in existing:
|
||||
self.assertIsNotNone(db_api.stack_get(ctx, stacks[s].id,
|
||||
show_deleted=True))
|
||||
for s in deleted:
|
||||
self.assertIsNone(db_api.stack_get(ctx, stacks[s].id,
|
||||
show_deleted=True))
|
||||
|
||||
|
||||
class DBAPIResourceTest(HeatTestCase):
|
||||
def setUp(self):
|
||||
|
Loading…
Reference in New Issue
Block a user