Test Failed
Push — master ( 4c6c3d...040528 )
by Nicolas
04:27
created

glances/amps/glances_amp.py (29 issues)

1
# -*- coding: utf-8 -*-
2
#
3
# This file is part of Glances.
4
#
5
# Copyright (C) 2019 Nicolargo <[email protected]>
6
#
7
# Glances is free software; you can redistribute it and/or modify
8
# it under the terms of the GNU Lesser General Public License as published by
9
# the Free Software Foundation, either version 3 of the License, or
10
# (at your option) any later version.
11
#
12
# Glances is distributed in the hope that it will be useful,
13
# but WITHOUT ANY WARRANTY; without even the implied warranty of
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
# GNU Lesser General Public License for more details.
16
#
17
# You should have received a copy of the GNU Lesser General Public License
18
# along with this program. If not, see <http://www.gnu.org/licenses/>.
19
20
"""
21
I am your father...
22
23
...for all Glances Application Monitoring Processes (AMP).
24
25
AMP (Application Monitoring Process)
26
A Glances AMP is a Python script called (every *refresh* seconds) if:
27
- the AMP is *enabled* in the Glances configuration file
28
- a process is running (match the *regex* define in the configuration file)
29
The script should define a Amp (GlancesAmp) class with, at least, an update method.
0 ignored issues
show
This line is too long as per the coding-style (83/80).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
30
The update method should call the set_result method to set the AMP return string.
0 ignored issues
show
This line is too long as per the coding-style (81/80).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
31
The return string is a string with one or more line (\n between lines).
32
If the *one_line* var is true then the AMP will be displayed in one line.
33
"""
34
35
from glances.compat import u, b, n, nativestr
0 ignored issues
show
import missing from __future__ import absolute_import
Loading history...
Unused nativestr imported from glances.compat
Loading history...
Unused b imported from glances.compat
Loading history...
Unused n imported from glances.compat
Loading history...
36
from glances.timer import Timer
0 ignored issues
show
import missing from __future__ import absolute_import
Loading history...
37
from glances.logger import logger
0 ignored issues
show
import missing from __future__ import absolute_import
Loading history...
38
39
40
class GlancesAmp(object):
41
    """Main class for Glances AMP."""
42
43
    NAME = '?'
44
    VERSION = '?'
45
    DESCRIPTION = '?'
46
    AUTHOR = '?'
47
    EMAIL = '?'
48
49
    def __init__(self, name=None, args=None):
50
        """Init AMP classe."""
51
        logger.debug("AMP - Init {} version {}".format(self.NAME, self.VERSION))
0 ignored issues
show
Use formatting in logging functions and pass the parameters as arguments
Loading history...
52
53
        # AMP name (= module name without glances_)
54
        if name is None:
55
            self.amp_name = self.__class__.__module__[len('glances_'):]
56
        else:
57
            self.amp_name = name
58
59
        # Init the args
60
        self.args = args
61
62
        # Init the configs
63
        self.configs = {}
64
65
        # A timer is needed to only update every refresh seconds
66
        # Init to 0 in order to update the AMP on startup
67
        self.timer = Timer(0)
68
69
    def load_config(self, config):
70
        """Load AMP parameters from the configuration file."""
71
72
        # Read AMP confifuration.
73
        # For ex, the AMP foo should have the following section:
74
        #
75
        # [foo]
76
        # enable=true
77
        # regex=\/usr\/bin\/nginx
78
        # refresh=60
79
        #
80
        # and optionnaly:
81
        #
82
        # one_line=false
83
        # option1=opt1
84
        # ...
85
        #
86
        amp_section = 'amp_' + self.amp_name
87
        if (hasattr(config, 'has_section') and
88
                config.has_section(amp_section)):
0 ignored issues
show
Wrong continued indentation (remove 4 spaces).
Loading history...
89
            logger.debug("AMP - {}: Load configuration".format(self.NAME))
0 ignored issues
show
Use formatting in logging functions and pass the parameters as arguments
Loading history...
90
            for param, _ in config.items(amp_section):
91
                try:
92
                    self.configs[param] = config.get_float_value(amp_section, param)
0 ignored issues
show
This line is too long as per the coding-style (84/80).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
93
                except ValueError:
94
                    self.configs[param] = config.get_value(amp_section, param).split(',')
0 ignored issues
show
This line is too long as per the coding-style (89/80).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
95
                    if len(self.configs[param]) == 1:
96
                        self.configs[param] = self.configs[param][0]
97
                logger.debug("AMP - {}: Load parameter: {} = {}".format(self.NAME, param, self.configs[param]))
0 ignored issues
show
This line is too long as per the coding-style (111/80).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
Use formatting in logging functions and pass the parameters as arguments
Loading history...
98
        else:
99
            logger.debug("AMP - {}: Can not find section {} in the configuration file".format(self.NAME, self.amp_name))
0 ignored issues
show
This line is too long as per the coding-style (120/80).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
Use formatting in logging functions and pass the parameters as arguments
Loading history...
100
            return False
101
102
        if self.enable():
103
            # Refresh option is mandatory
104
            for k in ['refresh']:
105
                if k not in self.configs:
106
                    logger.warning("AMP - {}: Can not find configuration key {} in section {} (the AMP will be disabled)".format(self.NAME, k, self.amp_name))
0 ignored issues
show
This line is too long as per the coding-style (158/80).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
Use formatting in logging functions and pass the parameters as arguments
Loading history...
107
                    self.configs['enable'] = 'false'
108
        else:
109
            logger.debug("AMP - {} is disabled".format(self.NAME))
0 ignored issues
show
Use formatting in logging functions and pass the parameters as arguments
Loading history...
110
111
        # Init the count to 0
112
        self.configs['count'] = 0
113
114
        return self.enable()
115
116
    def get(self, key):
117
        """Generic method to get the item in the AMP configuration"""
118
        if key in self.configs:
0 ignored issues
show
Unnecessary "else" after "return"
Loading history...
119
            return self.configs[key]
120
        else:
121
            return None
122
123
    def enable(self):
124
        """Return True|False if the AMP is enabled in the configuration file (enable=true|false)."""
0 ignored issues
show
This line is too long as per the coding-style (100/80).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
125
        ret = self.get('enable')
126
        if ret is None:
0 ignored issues
show
Unnecessary "else" after "return"
Loading history...
127
            return False
128
        else:
129
            return ret.lower().startswith('true')
130
131
    def regex(self):
132
        """Return regular expression used to identified the current application."""
0 ignored issues
show
This line is too long as per the coding-style (83/80).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
133
        return self.get('regex')
134
135
    def refresh(self):
136
        """Return refresh time in seconds for the current application monitoring process."""
0 ignored issues
show
This line is too long as per the coding-style (92/80).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
137
        return self.get('refresh')
138
139
    def one_line(self):
140
        """Return True|False if the AMP shoukd be displayed in oneline (one_lineline=true|false)."""
0 ignored issues
show
This line is too long as per the coding-style (100/80).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
141
        ret = self.get('one_line')
142
        if ret is None:
0 ignored issues
show
Unnecessary "else" after "return"
Loading history...
143
            return False
144
        else:
145
            return ret.lower().startswith('true')
146
147
    def time_until_refresh(self):
148
        """Return time in seconds until refresh."""
149
        return self.timer.get()
150
151
    def should_update(self):
152
        """Return True is the AMP should be updated:
153
        - AMP is enable
154
        - only update every 'refresh' seconds
155
        """
156
        if self.timer.finished():
157
            self.timer.set(self.refresh())
158
            self.timer.reset()
159
            return self.enable()
160
        return False
161
162
    def set_count(self, count):
163
        """Set the number of processes matching the regex"""
164
        self.configs['count'] = count
165
166
    def count(self):
167
        """Get the number of processes matching the regex"""
168
        return self.get('count')
169
170
    def count_min(self):
171
        """Get the minimum number of processes"""
172
        return self.get('countmin')
173
174
    def count_max(self):
175
        """Get the maximum number of processes"""
176
        return self.get('countmax')
177
178
    def set_result(self, result, separator=''):
179
        """Store the result (string) into the result key of the AMP
180
        if one_line is true then replace \n by separator
181
        """
182
        if self.one_line():
183
            self.configs['result'] = u(result).replace('\n', separator)
184
        else:
185
            self.configs['result'] = u(result)
186
187
    def result(self):
188
        """ Return the result of the AMP (as a string)"""
189
        ret = self.get('result')
190
        if ret is not None:
191
            ret = u(ret)
192
        return ret
193
194
    def update_wrapper(self, process_list):
195
        """Wrapper for the children update"""
196
        # Set the number of running process
197
        self.set_count(len(process_list))
198
        # Call the children update method
199
        if self.should_update():
0 ignored issues
show
Unnecessary "else" after "return"
Loading history...
200
            return self.update(process_list)
0 ignored issues
show
The Instance of GlancesAmp does not seem to have a member named update.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
201
        else:
202
            return self.result()
203