Completed
Pull Request — master (#2296)
by Manas
06:15
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
import sys
0 ignored issues
show
Unused Code introduced by
The import sys seems to be unused.
Loading history...
28
29
from mongoengine.errors import InvalidQueryError
30
from oslo_config import cfg
31
32
from st2common import config
33
from st2common import log as logging
34
from st2common.constants import action as action_constants
35
from st2common.script_setup import setup as common_setup
36
from st2common.script_setup import teardown as common_teardown
37
from st2common.persistence.liveaction import LiveAction
38
from st2common.persistence.execution import ActionExecution
39
from st2common.util import isotime
40
41
LOG = logging.getLogger(__name__)
42
43
DONE_STATES = [action_constants.LIVEACTION_STATUS_SUCCEEDED,
44
               action_constants.LIVEACTION_STATUS_FAILED,
45
               action_constants.LIVEACTION_STATUS_TIMED_OUT,
46
               action_constants.LIVEACTION_STATUS_CANCELED]
47
48
49
def _do_register_cli_opts(opts, ignore_errors=False):
50
    for opt in opts:
51
        try:
52
            cfg.CONF.register_cli_opt(opt)
53
        except:
54
            if not ignore_errors:
55
                raise
56
57
58
def _register_cli_opts():
59
    cli_opts = [
60
        cfg.StrOpt('timestamp', default=None,
61
                   help='Will delete execution and liveaction models older than ' +
62
                   'this UTC timestamp. ' +
63
                   'Example value: 2015-03-13T19:01:27.255542Z.'),
64
        cfg.StrOpt('action-ref', default='',
65
                   help='action-ref to delete executions for.'),
66
        cfg.BoolOpt('purge-incomplete', default=False,
67
                    help='Purge all models irrespective of their ``status``.' +
68
                    'By default, only executions in completed states such as "succeeeded" ' +
69
                    ', "failed", "canceled" and "timed_out" are deleted.'),
70
    ]
71
    _do_register_cli_opts(cli_opts)
72
73
74
def purge_executions(timestamp=None, action_ref=None, purge_incomplete=False):
75
    if not timestamp:
76
        LOG.error('Specify a valid timestamp to purge.')
77
        return 1
78
79
    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...
80
             timestamp.strftime('%Y-%m-%dT%H:%M:%S.%fZ'))
81
82
    filters = {}
83
84
    if purge_incomplete:
85
        filters['start_timestamp__lt'] = isotime.parse(timestamp)
86
    else:
87
        filters['end_timestamp__lt'] = isotime.parse(timestamp)
88
        filters['start_timestamp__lt'] = isotime.parse(timestamp)
89
        filters['status'] = {"$in": DONE_STATES}
90
91
    exec_filters = copy.copy(filters)
92
    if action_ref:
93
        exec_filters['action__ref'] = action_ref
94
95
    liveaction_filters = copy.copy(filters)
96
    if action_ref:
97
        liveaction_filters['action'] = action_ref
98
99
    try:
100
        ActionExecution.delete_by_query(**exec_filters)
101
    except InvalidQueryError:
102
        LOG.exception('Bad query (%s) used to delete execution instances. ' +
103
                      'Please contact support.', exec_filters)
104
        return 2
105
    except:
106
        LOG.exception('Deletion of execution models failed for query with filters: %s.',
107
                      exec_filters)
108
109
    try:
110
        LiveAction.delete_by_query(**liveaction_filters)
111
    except InvalidQueryError:
112
        LOG.exception('Bad query (%s) used to delete liveaction instances. ' +
113
                      'Please contact support.', liveaction_filters)
114
        return 3
115
    except:
116
        LOG.exception('Deletion of liveaction models failed for query with filters: %s.',
117
                      liveaction_filters)
118
119
    zombie_execution_instances = len(ActionExecution.query(**exec_filters))
120
    zombie_liveaction_instances = len(LiveAction.query(**liveaction_filters))
121
122
    if (zombie_execution_instances > 0) or (zombie_liveaction_instances > 0):
123
        LOG.error('Zombie execution instances left: %d.', zombie_execution_instances)
124
        LOG.error('Zombie liveaction instances left: %s.', zombie_liveaction_instances)
125
    else:
126
        # Print stats
127
        LOG.info('#### All execution models less than timestamp %s were deleted.', timestamp)
128
129
130
def main():
131
    _register_cli_opts()
132
    common_setup(config=config, setup_db=True, register_mq_exchanges=False)
133
134
    # Get config values
135
    timestamp = cfg.CONF.timestamp
136
    action_ref = cfg.CONF.action_ref
137
    purge_incomplete = cfg.CONF.purge_incomplete
138
139
    if not timestamp:
140
        LOG.error('Please supply a timestamp for purging models. Aborting.')
141
        return 1
142
    else:
143
        timestamp = datetime.strptime(timestamp, '%Y-%m-%dT%H:%M:%S.%fZ')
144
        timestamp = timestamp.replace(tzinfo=pytz.UTC)
145
146
    # Purge models.
147
    try:
148
        return purge_executions(timestamp=timestamp, action_ref=action_ref,
149
                                purge_incomplete=purge_incomplete)
150
    finally:
151
        common_teardown()
152