Completed
Push — master ( 8be562...193373 )
by Manas
05:42
created

st2common.cmd.purge_executions()   D

Complexity

Conditions 11

Size

Total Lines 54

Duplication

Lines 0
Ratio 0 %
Metric Value
cc 11
dl 0
loc 54
rs 4.5

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Complexity

Complex classes like st2common.cmd.purge_executions() often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
# Licensed to the StackStorm, Inc ('StackStorm') under one or more
2
# contributor license agreements.  See the NOTICE file distributed with
3
# this work for additional information regarding copyright ownership.
4
# The ASF licenses this file to You under the Apache License, Version 2.0
5
# (the "License"); you may not use this file except in compliance with
6
# the License.  You may obtain a copy of the License at
7
#
8
#     http://www.apache.org/licenses/LICENSE-2.0
9
#
10
# Unless required by applicable law or agreed to in writing, software
11
# distributed under the License is distributed on an "AS IS" BASIS,
12
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
# See the License for the specific language governing permissions and
14
# limitations under the License.
15
16
17
"""
18
A utility script that purges st2 executions older than certain
19
timestamp.
20
21
*** RISK RISK RISK. You will lose data. Run at your own risk. ***
22
"""
23
24
import copy
25
from datetime import datetime
26
import pytz
27
28
from mongoengine.errors import InvalidQueryError
29
from oslo_config import cfg
30
31
from st2common import config
32
from st2common import log as logging
33
from st2common.constants import action as action_constants
34
from st2common.script_setup import setup as common_setup
35
from st2common.script_setup import teardown as common_teardown
36
from st2common.persistence.liveaction import LiveAction
37
from st2common.persistence.execution import ActionExecution
38
from st2common.util import isotime
39
40
LOG = logging.getLogger(__name__)
41
42
DONE_STATES = [action_constants.LIVEACTION_STATUS_SUCCEEDED,
43
               action_constants.LIVEACTION_STATUS_FAILED,
44
               action_constants.LIVEACTION_STATUS_TIMED_OUT,
45
               action_constants.LIVEACTION_STATUS_CANCELED]
46
47
48
def _do_register_cli_opts(opts, ignore_errors=False):
49
    for opt in opts:
50
        try:
51
            cfg.CONF.register_cli_opt(opt)
52
        except:
53
            if not ignore_errors:
54
                raise
55
56
57
def _register_cli_opts():
58
    cli_opts = [
59
        cfg.StrOpt('timestamp', default=None,
60
                   help='Will delete execution and liveaction models older than ' +
61
                   'this UTC timestamp. ' +
62
                   'Example value: 2015-03-13T19:01:27.255542Z.'),
63
        cfg.StrOpt('action-ref', default='',
64
                   help='action-ref to delete executions for.'),
65
        cfg.BoolOpt('purge-incomplete', default=False,
66
                    help='Purge all models irrespective of their ``status``.' +
67
                    'By default, only executions in completed states such as "succeeeded" ' +
68
                    ', "failed", "canceled" and "timed_out" are deleted.'),
69
    ]
70
    _do_register_cli_opts(cli_opts)
71
72
73
def purge_executions(timestamp=None, action_ref=None, purge_incomplete=False):
74
    if not timestamp:
75
        LOG.error('Specify a valid timestamp to purge.')
76
        return 1
77
78
    LOG.info('Purging executions older than timestamp: %s' %
0 ignored issues
show
Coding Style Best Practice introduced by
Specify string format arguments as logging function parameters
Loading history...
79
             timestamp.strftime('%Y-%m-%dT%H:%M:%S.%fZ'))
80
81
    filters = {}
82
83
    if purge_incomplete:
84
        filters['start_timestamp__lt'] = isotime.parse(timestamp)
85
    else:
86
        filters['end_timestamp__lt'] = isotime.parse(timestamp)
87
        filters['start_timestamp__lt'] = isotime.parse(timestamp)
88
        filters['status'] = {"$in": DONE_STATES}
89
90
    exec_filters = copy.copy(filters)
91
    if action_ref:
92
        exec_filters['action__ref'] = action_ref
93
94
    liveaction_filters = copy.copy(filters)
95
    if action_ref:
96
        liveaction_filters['action'] = action_ref
97
98
    try:
99
        ActionExecution.delete_by_query(**exec_filters)
100
    except InvalidQueryError:
101
        LOG.exception('Bad query (%s) used to delete execution instances. ' +
102
                      'Please contact support.', exec_filters)
103
        return 2
104
    except:
105
        LOG.exception('Deletion of execution models failed for query with filters: %s.',
106
                      exec_filters)
107
108
    try:
109
        LiveAction.delete_by_query(**liveaction_filters)
110
    except InvalidQueryError:
111
        LOG.exception('Bad query (%s) used to delete liveaction instances. ' +
112
                      'Please contact support.', liveaction_filters)
113
        return 3
114
    except:
115
        LOG.exception('Deletion of liveaction models failed for query with filters: %s.',
116
                      liveaction_filters)
117
118
    zombie_execution_instances = len(ActionExecution.query(**exec_filters))
119
    zombie_liveaction_instances = len(LiveAction.query(**liveaction_filters))
120
121
    if (zombie_execution_instances > 0) or (zombie_liveaction_instances > 0):
122
        LOG.error('Zombie execution instances left: %d.', zombie_execution_instances)
123
        LOG.error('Zombie liveaction instances left: %s.', zombie_liveaction_instances)
124
    else:
125
        # Print stats
126
        LOG.info('#### All execution models less than timestamp %s were deleted.', timestamp)
127
128
129
def main():
130
    _register_cli_opts()
131
    common_setup(config=config, setup_db=True, register_mq_exchanges=False)
132
133
    # Get config values
134
    timestamp = cfg.CONF.timestamp
135
    action_ref = cfg.CONF.action_ref
136
    purge_incomplete = cfg.CONF.purge_incomplete
137
138
    if not timestamp:
139
        LOG.error('Please supply a timestamp for purging models. Aborting.')
140
        return 1
141
    else:
142
        timestamp = datetime.strptime(timestamp, '%Y-%m-%dT%H:%M:%S.%fZ')
143
        timestamp = timestamp.replace(tzinfo=pytz.UTC)
144
145
    # Purge models.
146
    try:
147
        return purge_executions(timestamp=timestamp, action_ref=action_ref,
148
                                purge_incomplete=purge_incomplete)
149
    finally:
150
        common_teardown()
151