Test Failed
Push — develop ( 66c9ff...e21229 )
by Nicolas
05:06
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
        # enable, regex and refresh are mandatories
103
        # if not configured then AMP is disabled
104
        if self.enable():
105
            for k in ['regex', 'refresh']:
106
                if k not in self.configs:
107
                    logger.warning("AMP - {}: Can not find configuration key {} in section {}".format(self.NAME, k, self.amp_name))
0 ignored issues
show
This line is too long as per the coding-style (131/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...
108
                    self.configs['enable'] = 'false'
109
        else:
110
            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...
111
112
        # Init the count to 0
113
        self.configs['count'] = 0
114
115
        return self.enable()
116
117
    def get(self, key):
118
        """Generic method to get the item in the AMP configuration"""
119
        if key in self.configs:
0 ignored issues
show
Unnecessary "else" after "return"
Loading history...
120
            return self.configs[key]
121
        else:
122
            return None
123
124
    def enable(self):
125
        """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...
126
        ret = self.get('enable')
127
        if ret is None:
0 ignored issues
show
Unnecessary "else" after "return"
Loading history...
128
            return False
129
        else:
130
            return ret.lower().startswith('true')
131
132
    def regex(self):
133
        """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...
134
        return self.get('regex')
135
136
    def refresh(self):
137
        """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...
138
        return self.get('refresh')
139
140
    def one_line(self):
141
        """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...
142
        ret = self.get('one_line')
143
        if ret is None:
0 ignored issues
show
Unnecessary "else" after "return"
Loading history...
144
            return False
145
        else:
146
            return ret.lower().startswith('true')
147
148
    def time_until_refresh(self):
149
        """Return time in seconds until refresh."""
150
        return self.timer.get()
151
152
    def should_update(self):
153
        """Return True is the AMP should be updated:
154
        - AMP is enable
155
        - only update every 'refresh' seconds
156
        """
157
        if self.timer.finished():
158
            self.timer.set(self.refresh())
159
            self.timer.reset()
160
            return self.enable()
161
        return False
162
163
    def set_count(self, count):
164
        """Set the number of processes matching the regex"""
165
        self.configs['count'] = count
166
167
    def count(self):
168
        """Get the number of processes matching the regex"""
169
        return self.get('count')
170
171
    def count_min(self):
172
        """Get the minimum number of processes"""
173
        return self.get('countmin')
174
175
    def count_max(self):
176
        """Get the maximum number of processes"""
177
        return self.get('countmax')
178
179
    def set_result(self, result, separator=''):
180
        """Store the result (string) into the result key of the AMP
181
        if one_line is true then replace \n by separator
182
        """
183
        if self.one_line():
184
            self.configs['result'] = u(result).replace('\n', separator)
185
        else:
186
            self.configs['result'] = u(result)
187
188
    def result(self):
189
        """ Return the result of the AMP (as a string)"""
190
        ret = self.get('result')
191
        if ret is not None:
192
            ret = u(ret)
193
        return ret
194
195
    def update_wrapper(self, process_list):
196
        """Wrapper for the children update"""
197
        # Set the number of running process
198
        self.set_count(len(process_list))
199
        # Call the children update method
200
        if self.should_update():
0 ignored issues
show
Unnecessary "else" after "return"
Loading history...
201
            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...
202
        else:
203
            return self.result()
204