Add action_purge to senlin-manage
This patch add the action_purge subcommand to senlin-manage. This subcommand is used to purge the specified action records in senlin's database. Change-Id: Idf4e04621c812c3a7aa53e9fd402b2ec3081fa89
This commit is contained in:
parent
0700a8bf29
commit
3770d11a5f
|
@ -69,6 +69,20 @@ You can use command purge three days ago data.
|
|||
senlin-manage event_purge -p e127900ee5d94ff5aff30173aa607765 -g days 3
|
||||
|
||||
|
||||
Senlin Action Manage
|
||||
--------------------
|
||||
|
||||
``senlin-manage action_purge -p [<project1;project2...>] -g {days,hours,minutes,seconds} age``
|
||||
|
||||
Purge the specified action records in senlin's database.
|
||||
|
||||
You can use this command to purge actions that are older than 3 days.
|
||||
|
||||
::
|
||||
|
||||
senlin-manage action_purge -p e127900ee5d94ff5aff30173aa607765 -g days 3
|
||||
|
||||
|
||||
FILES
|
||||
~~~~~
|
||||
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
---
|
||||
features:
|
||||
- A action_purge subcommand is added to senlin-manage tool for purging actions
|
||||
from the actions table.
|
|
@ -45,7 +45,7 @@ def do_db_sync():
|
|||
def do_event_purge():
|
||||
"""Purge the specified event records in senlin's database."""
|
||||
if CONF.command.age < 0:
|
||||
print(_("age must be a positive integer."))
|
||||
print(_("Age must be a positive integer."))
|
||||
return
|
||||
api.event_purge(api.get_engine(),
|
||||
CONF.command.project_id,
|
||||
|
@ -53,6 +53,30 @@ def do_event_purge():
|
|||
CONF.command.age)
|
||||
|
||||
|
||||
def do_action_purge():
|
||||
"""Purge the specified action records in senlin's database."""
|
||||
age = CONF.command.age
|
||||
|
||||
if age < 0:
|
||||
print(_("Age must be a positive integer."))
|
||||
return
|
||||
|
||||
if CONF.command.granularity == 'days':
|
||||
age = age * 86400
|
||||
elif CONF.command.granularity == 'hours':
|
||||
age = age * 3600
|
||||
elif CONF.command.granularity == 'minutes':
|
||||
age = age * 60
|
||||
|
||||
if age < CONF.default_action_timeout:
|
||||
print(_("Age must be greater than the default action timeout."))
|
||||
return
|
||||
api.action_purge(api.get_engine(),
|
||||
CONF.command.project_id,
|
||||
CONF.command.granularity,
|
||||
CONF.command.age)
|
||||
|
||||
|
||||
class ServiceManageCommand(object):
|
||||
def __init__(self):
|
||||
self.ctx = context.get_admin_context()
|
||||
|
@ -157,6 +181,35 @@ def add_command_parsers(subparsers):
|
|||
"events created two hours ago. Defaults to "
|
||||
"30."))
|
||||
|
||||
parser = subparsers.add_parser('action_purge')
|
||||
parser.set_defaults(func=do_action_purge)
|
||||
parser.add_argument('-p',
|
||||
'--project-id',
|
||||
nargs='?',
|
||||
metavar='<project1;project2...>',
|
||||
help=_("Purge action records with specified project. "
|
||||
"This can be specified multiple times, or once "
|
||||
"with parameters separated by semicolon."),
|
||||
action='append')
|
||||
parser.add_argument('-g',
|
||||
'--granularity',
|
||||
default='days',
|
||||
choices=['days', 'hours', 'minutes', 'seconds'],
|
||||
help=_("Purge action records which were created in "
|
||||
"the specified time period. The time is "
|
||||
"specified by age and granularity, whose value "
|
||||
"must be one of 'days', 'hours', 'minutes' or "
|
||||
"'seconds' (default)."))
|
||||
parser.add_argument('age',
|
||||
type=int,
|
||||
default=30,
|
||||
help=_("Purge action records which were created in "
|
||||
"the specified time period. The time is "
|
||||
"specified by age and granularity. For "
|
||||
"example, granularity=hours and age=2 means "
|
||||
"purging actions created two hours ago. "
|
||||
"Defaults to 30."))
|
||||
|
||||
|
||||
command_opt = cfg.SubCommandOpt('command',
|
||||
title='Commands',
|
||||
|
|
|
@ -529,3 +529,8 @@ def db_version(engine):
|
|||
def event_purge(engine, project, granularity, age):
|
||||
"""Purge the event records in database."""
|
||||
return IMPL.event_purge(project, granularity, age)
|
||||
|
||||
|
||||
def action_purge(engine, project, granularity, age):
|
||||
"""Purge the action records in database."""
|
||||
return IMPL.action_purge(project, granularity, age)
|
||||
|
|
|
@ -1430,6 +1430,29 @@ def action_delete_by_target(context, target, action=None,
|
|||
return q.delete(synchronize_session='fetch')
|
||||
|
||||
|
||||
@retry_on_deadlock
|
||||
def action_purge(project, granularity='days', age=30):
|
||||
with session_for_write() as session:
|
||||
query = session.query(models.Action).with_for_update()
|
||||
if project is not None:
|
||||
query = query.filter(models.Action.project.in_(project))
|
||||
if granularity is not None and age is not None:
|
||||
if granularity == 'days':
|
||||
age = age * 86400
|
||||
elif granularity == 'hours':
|
||||
age = age * 3600
|
||||
elif granularity == 'minutes':
|
||||
age = age * 60
|
||||
time_line = timeutils.utcnow() - datetime.timedelta(seconds=age)
|
||||
query = query.filter(models.Action.created_at < time_line)
|
||||
|
||||
# Get dependants to delete
|
||||
for d in query.all():
|
||||
q = session.query(models.ActionDependency).filter_by(depended=d.id)
|
||||
q.delete(synchronize_session='fetch')
|
||||
return query.delete(synchronize_session='fetch')
|
||||
|
||||
|
||||
# Receivers
|
||||
@retry_on_deadlock
|
||||
def receiver_create(context, values):
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import datetime
|
||||
import six
|
||||
import time
|
||||
|
||||
|
@ -724,3 +725,30 @@ class DBAPIActionTest(base.SenlinTestCase):
|
|||
after_abandon.status_reason)
|
||||
self.assertEqual(consts.ACTION_READY, after_abandon.status)
|
||||
self.assertEqual({'retries': 1}, after_abandon.data)
|
||||
|
||||
def test_action_purge(self):
|
||||
old_timestamp = tu.utcnow(True) - datetime.timedelta(days=6)
|
||||
spec = {
|
||||
"owner": "test_owner",
|
||||
"created_at": old_timestamp
|
||||
}
|
||||
_create_action(self.ctx, **spec)
|
||||
_create_action(self.ctx, **spec)
|
||||
_create_action(self.ctx, **spec)
|
||||
|
||||
new_timestamp = tu.utcnow(True)
|
||||
spec = {
|
||||
"owner": "test_owner",
|
||||
"created_at": new_timestamp
|
||||
}
|
||||
_create_action(self.ctx, **spec)
|
||||
_create_action(self.ctx, **spec)
|
||||
_create_action(self.ctx, **spec)
|
||||
|
||||
actions = db_api.action_get_all(self.ctx)
|
||||
self.assertEqual(6, len(actions))
|
||||
|
||||
db_api.action_purge(project=None, granularity='days', age=5)
|
||||
|
||||
actions = db_api.action_get_all(self.ctx)
|
||||
self.assertEqual(3, len(actions))
|
||||
|
|
Loading…
Reference in New Issue