GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Passed
Push — develop-v1.3.1 ( acb9c3...7a20bf )
by
unknown
06:25
created

st2reactor.container.SensorService.delete_value()   A

Complexity

Conditions 1

Size

Total Lines 2

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 2
rs 10
cc 1
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
import os
17
import sys
18
import json
19
import atexit
20
import argparse
21
22
import eventlet
23
from oslo_config import cfg
24
25
from st2common import log as logging
26
from st2common.logging.misc import set_log_level_for_all_loggers
27
from st2common.models.api.trace import TraceContext
28
from st2common.persistence.db_init import db_setup_with_retry
29
from st2common.transport.reactor import TriggerDispatcher
30
from st2common.util import loader
31
from st2common.util.config_parser import ContentPackConfigParser
32
from st2common.services.triggerwatcher import TriggerWatcher
33
from st2reactor.sensor.base import Sensor, PollingSensor
34
from st2reactor.sensor import config
35
from st2common.services.datastore import DatastoreService
36
37
__all__ = [
38
    'SensorWrapper'
39
]
40
41
eventlet.monkey_patch(
42
    os=True,
43
    select=True,
44
    socket=True,
45
    thread=False if '--use-debugger' in sys.argv else True,
46
    time=True)
47
48
49
class SensorService(object):
50
    """
51
    Instance of this class is passed to the sensor instance and exposes "public"
52
    methods which can be called by the sensor.
53
    """
54
55
    def __init__(self, sensor_wrapper):
56
        self._sensor_wrapper = sensor_wrapper
57
        self._logger = self._sensor_wrapper._logger
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like _logger was declared protected and should not be accessed from this context.

Prefixing a member variable _ is usually regarded as the equivalent of declaring it with protected visibility that exists in other languages. Consequentially, such a member should only be accessed from the same class or a child class:

class MyParent:
    def __init__(self):
        self._x = 1;
        self.y = 2;

class MyChild(MyParent):
    def some_method(self):
        return self._x    # Ok, since accessed from a child class

class AnotherClass:
    def some_method(self, instance_of_my_child):
        return instance_of_my_child._x   # Would be flagged as AnotherClass is not
                                         # a child class of MyParent
Loading history...
58
        self._dispatcher = TriggerDispatcher(self._logger)
59
        self._datastore_service = DatastoreService(logger=self._logger,
60
                                                   pack_name=self._sensor_wrapper._pack,
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like _pack was declared protected and should not be accessed from this context.

Prefixing a member variable _ is usually regarded as the equivalent of declaring it with protected visibility that exists in other languages. Consequentially, such a member should only be accessed from the same class or a child class:

class MyParent:
    def __init__(self):
        self._x = 1;
        self.y = 2;

class MyChild(MyParent):
    def some_method(self):
        return self._x    # Ok, since accessed from a child class

class AnotherClass:
    def some_method(self, instance_of_my_child):
        return instance_of_my_child._x   # Would be flagged as AnotherClass is not
                                         # a child class of MyParent
Loading history...
61
                                                   class_name=self._sensor_wrapper._class_name,
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like _class_name was declared protected and should not be accessed from this context.

Prefixing a member variable _ is usually regarded as the equivalent of declaring it with protected visibility that exists in other languages. Consequentially, such a member should only be accessed from the same class or a child class:

class MyParent:
    def __init__(self):
        self._x = 1;
        self.y = 2;

class MyChild(MyParent):
    def some_method(self):
        return self._x    # Ok, since accessed from a child class

class AnotherClass:
    def some_method(self, instance_of_my_child):
        return instance_of_my_child._x   # Would be flagged as AnotherClass is not
                                         # a child class of MyParent
Loading history...
62
                                                   api_username='sensor_service')
63
64
        self._client = None
65
66
    def get_logger(self, name):
67
        """
68
        Retrieve an instance of a logger to be used by the sensor class.
69
        """
70
        logger_name = '%s.%s' % (self._sensor_wrapper._logger.name, name)
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like _logger was declared protected and should not be accessed from this context.

Prefixing a member variable _ is usually regarded as the equivalent of declaring it with protected visibility that exists in other languages. Consequentially, such a member should only be accessed from the same class or a child class:

class MyParent:
    def __init__(self):
        self._x = 1;
        self.y = 2;

class MyChild(MyParent):
    def some_method(self):
        return self._x    # Ok, since accessed from a child class

class AnotherClass:
    def some_method(self, instance_of_my_child):
        return instance_of_my_child._x   # Would be flagged as AnotherClass is not
                                         # a child class of MyParent
Loading history...
71
        logger = logging.getLogger(logger_name)
72
        logger.propagate = True
73
74
        return logger
75
76
    def dispatch(self, trigger, payload=None, trace_tag=None):
77
        """
78
        Method which dispatches the trigger.
79
80
        :param trigger: Full name / reference of the trigger.
81
        :type trigger: ``str``
82
83
        :param payload: Trigger payload.
84
        :type payload: ``dict``
85
86
        :param trace_tag: Tracer to track the triggerinstance.
87
        :type trace_tags: ``str``
88
        """
89
        # empty strings
90
        trace_context = TraceContext(trace_tag=trace_tag) if trace_tag else None
91
        self.dispatch_with_context(trigger, payload=payload, trace_context=trace_context)
92
93
    def dispatch_with_context(self, trigger, payload=None, trace_context=None):
94
        """
95
        Method which dispatches the trigger.
96
97
        :param trigger: Full name / reference of the trigger.
98
        :type trigger: ``str``
99
100
        :param payload: Trigger payload.
101
        :type payload: ``dict``
102
103
        :param trace_context: Trace context to associate with Trigger.
104
        :type trace_context: ``st2common.api.models.api.trace.TraceContext``
105
        """
106
        self._dispatcher.dispatch(trigger, payload=payload, trace_context=trace_context)
107
108
    ##################################
109
    # Methods for datastore management
110
    ##################################
111
112
    def list_values(self, local=True, prefix=None):
113
        return self._datastore_service.list_values(local, prefix)
114
115
    def get_value(self, name, local=True):
116
        return self._datastore_service.get_value(name, local)
117
118
    def set_value(self, name, value, ttl=None, local=True):
119
        return self._datastore_service.set_value(name, value, ttl, local)
120
121
    def delete_value(self, name, local=True):
122
        return self._datastore_service.delete_value(name, local)
123
124
125
class SensorWrapper(object):
126
    def __init__(self, pack, file_path, class_name, trigger_types,
0 ignored issues
show
Comprehensibility Bug introduced by
trigger_types is re-defining a name which is already available in the outer-scope (previously defined on line 322).

It is generally a bad practice to shadow variables from the outer-scope. In most cases, this is done unintentionally and might lead to unexpected behavior:

param = 5

class Foo:
    def __init__(self, param):   # "param" would be flagged here
        self.param = param
Loading history...
127
                 poll_interval=None, parent_args=None):
0 ignored issues
show
Comprehensibility Bug introduced by
parent_args is re-defining a name which is already available in the outer-scope (previously defined on line 324).

It is generally a bad practice to shadow variables from the outer-scope. In most cases, this is done unintentionally and might lead to unexpected behavior:

param = 5

class Foo:
    def __init__(self, param):   # "param" would be flagged here
        self.param = param
Loading history...
128
        """
129
        :param pack: Name of the pack this sensor belongs to.
130
        :type pack: ``str``
131
132
        :param file_path: Path to the sensor module file.
133
        :type file_path: ``str``
134
135
        :param class_name: Sensor class name.
136
        :type class_name: ``str``
137
138
        :param trigger_types: A list of references to trigger types which
139
                                  belong to this sensor.
140
        :type trigger_types: ``list`` of ``str``
141
142
        :param poll_interval: Sensor poll interval (in seconds).
143
        :type poll_interval: ``int`` or ``None``
144
145
        :param parent_args: Command line arguments passed to the parent process.
146
        :type parse_args: ``list``
147
        """
148
        self._pack = pack
149
        self._file_path = file_path
150
        self._class_name = class_name
151
        self._trigger_types = trigger_types or []
152
        self._poll_interval = poll_interval
153
        self._parent_args = parent_args or []
154
        self._trigger_names = {}
155
156
        # 1. Parse the config with inherited parent args
157
        try:
158
            config.parse_args(args=self._parent_args)
159
        except Exception:
160
            pass
161
162
        # 2. Establish DB connection
163
        username = cfg.CONF.database.username if hasattr(cfg.CONF.database, 'username') else None
164
        password = cfg.CONF.database.password if hasattr(cfg.CONF.database, 'password') else None
165
        db_setup_with_retry(cfg.CONF.database.db_name, cfg.CONF.database.host,
166
                            cfg.CONF.database.port, username=username, password=password)
167
168
        # 3. Instantiate the watcher
169
        self._trigger_watcher = TriggerWatcher(create_handler=self._handle_create_trigger,
170
                                               update_handler=self._handle_update_trigger,
171
                                               delete_handler=self._handle_delete_trigger,
172
                                               trigger_types=self._trigger_types,
173
                                               queue_suffix='sensorwrapper_%s_%s' %
174
                                               (self._pack, self._class_name),
175
                                               exclusive=True)
176
177
        # 4. Set up logging
178
        self._logger = logging.getLogger('SensorWrapper.%s' %
179
                                         (self._class_name))
180
        logging.setup(cfg.CONF.sensorcontainer.logging)
181
182
        if '--debug' in parent_args:
183
            set_log_level_for_all_loggers()
184
185
        self._sensor_instance = self._get_sensor_instance()
186
187
    def run(self):
188
        atexit.register(self.stop)
189
190
        self._trigger_watcher.start()
191
        self._logger.info('Watcher started')
192
193
        self._logger.info('Running sensor initialization code')
194
        self._sensor_instance.setup()
195
196
        if self._poll_interval:
197
            message = ('Running sensor in active mode (poll interval=%ss)' %
198
                       (self._poll_interval))
199
        else:
200
            message = 'Running sensor in passive mode'
201
202
        self._logger.info(message)
203
204
        try:
205
            self._sensor_instance.run()
206
        except Exception as e:
207
            # Include traceback
208
            msg = ('Sensor "%s" run method raised an exception: %s.' %
209
                   (self._class_name, str(e)))
210
            self._logger.warn(msg, exc_info=True)
211
            raise Exception(msg)
212
213
    def stop(self):
214
        # Stop watcher
215
        self._logger.info('Stopping trigger watcher')
216
        self._trigger_watcher.stop()
217
218
        # Run sensor cleanup code
219
        self._logger.info('Invoking cleanup on sensor')
220
        self._sensor_instance.cleanup()
221
222
    ##############################################
223
    # Event handler methods for the trigger events
224
    ##############################################
225
226
    def _handle_create_trigger(self, trigger):
227
        self._logger.debug('Calling sensor "add_trigger" method (trigger.type=%s)' %
228
                           (trigger.type))
229
        self._trigger_names[str(trigger.id)] = trigger
230
231
        trigger = self._sanitize_trigger(trigger=trigger)
232
        self._sensor_instance.add_trigger(trigger=trigger)
233
234
    def _handle_update_trigger(self, trigger):
235
        self._logger.debug('Calling sensor "update_trigger" method (trigger.type=%s)' %
236
                           (trigger.type))
237
        self._trigger_names[str(trigger.id)] = trigger
238
239
        trigger = self._sanitize_trigger(trigger=trigger)
240
        self._sensor_instance.update_trigger(trigger=trigger)
241
242
    def _handle_delete_trigger(self, trigger):
243
        trigger_id = str(trigger.id)
244
        if trigger_id not in self._trigger_names:
245
            return
246
247
        self._logger.debug('Calling sensor "remove_trigger" method (trigger.type=%s)' %
248
                           (trigger.type))
249
        del self._trigger_names[trigger_id]
250
251
        trigger = self._sanitize_trigger(trigger=trigger)
252
        self._sensor_instance.remove_trigger(trigger=trigger)
253
254
    def _get_sensor_instance(self):
255
        """
256
        Retrieve instance of a sensor class.
257
        """
258
        _, filename = os.path.split(self._file_path)
259
        module_name, _ = os.path.splitext(filename)
260
261
        sensor_class = loader.register_plugin_class(base_class=Sensor,
262
                                                    file_path=self._file_path,
263
                                                    class_name=self._class_name)
264
265
        if not sensor_class:
266
            raise ValueError('Sensor module is missing a class with name "%s"' %
267
                             (self._class_name))
268
269
        sensor_class_kwargs = {}
270
        sensor_class_kwargs['sensor_service'] = SensorService(sensor_wrapper=self)
271
272
        sensor_config = self._get_sensor_config()
273
        sensor_class_kwargs['config'] = sensor_config
274
275
        if self._poll_interval and issubclass(sensor_class, PollingSensor):
276
            sensor_class_kwargs['poll_interval'] = self._poll_interval
277
278
        try:
279
            sensor_instance = sensor_class(**sensor_class_kwargs)
280
        except Exception:
281
            self._logger.exception('Failed to instantiate "%s" sensor class' % (self._class_name))
282
            raise Exception('Failed to instantiate "%s" sensor class' % (self._class_name))
283
284
        return sensor_instance
285
286
    def _get_sensor_config(self):
287
        config_parser = ContentPackConfigParser(pack_name=self._pack)
288
        config = config_parser.get_sensor_config(sensor_file_path=self._file_path)
0 ignored issues
show
Comprehensibility Bug introduced by
config is re-defining a name which is already available in the outer-scope (previously defined on line 34).

It is generally a bad practice to shadow variables from the outer-scope. In most cases, this is done unintentionally and might lead to unexpected behavior:

param = 5

class Foo:
    def __init__(self, param):   # "param" would be flagged here
        self.param = param
Loading history...
289
290
        if config:
291
            self._logger.info('Using config "%s" for sensor "%s"' % (config.file_path,
292
                                                                     self._class_name))
293
            return config.config
294
        else:
295
            self._logger.info('No config found for sensor "%s"' % (self._class_name))
296
            return {}
297
298
    def _sanitize_trigger(self, trigger):
299
        sanitized = trigger._data
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like _data was declared protected and should not be accessed from this context.

Prefixing a member variable _ is usually regarded as the equivalent of declaring it with protected visibility that exists in other languages. Consequentially, such a member should only be accessed from the same class or a child class:

class MyParent:
    def __init__(self):
        self._x = 1;
        self.y = 2;

class MyChild(MyParent):
    def some_method(self):
        return self._x    # Ok, since accessed from a child class

class AnotherClass:
    def some_method(self, instance_of_my_child):
        return instance_of_my_child._x   # Would be flagged as AnotherClass is not
                                         # a child class of MyParent
Loading history...
300
        if 'id' in sanitized:
301
            # Friendly objectid rather than the MongoEngine representation.
302
            sanitized['id'] = str(sanitized['id'])
303
        return sanitized
304
305
306
if __name__ == '__main__':
307
    parser = argparse.ArgumentParser(description='Sensor runner wrapper')
308
    parser.add_argument('--pack', required=True,
309
                        help='Name of the pack this sensor belongs to')
310
    parser.add_argument('--file-path', required=True,
311
                        help='Path to the sensor module')
312
    parser.add_argument('--class-name', required=True,
313
                        help='Name of the sensor class')
314
    parser.add_argument('--trigger-type-refs', required=False,
315
                        help='Comma delimited string of trigger type references')
316
    parser.add_argument('--poll-interval', type=int, default=None, required=False,
317
                        help='Sensor poll interval')
318
    parser.add_argument('--parent-args', required=False,
319
                        help='Command line arguments passed to the parent process')
320
    args = parser.parse_args()
321
322
    trigger_types = args.trigger_type_refs
323
    trigger_types = trigger_types.split(',') if trigger_types else []
324
    parent_args = json.loads(args.parent_args) if args.parent_args else []
325
    assert isinstance(parent_args, list)
326
327
    obj = SensorWrapper(pack=args.pack,
328
                        file_path=args.file_path,
329
                        class_name=args.class_name,
330
                        trigger_types=trigger_types,
331
                        poll_interval=args.poll_interval,
332
                        parent_args=parent_args)
333
    obj.run()
334