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

glances/amps_list.py (21 issues)

1
# -*- coding: utf-8 -*-
2
#
3
# This file is part of Glances.
4
#
5
# Copyright (C) 2020 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
"""Manage the AMPs list."""
21
22
import os
23
import re
24
import threading
25
26
from glances.compat import listkeys, iteritems
27
from glances.logger import logger
28
from glances.globals import amps_path
29
from glances.processes import glances_processes
30
31
32
class AmpsList(object):
33
34
    """This class describes the optional application monitoring process list.
35
36
    The AMP list is a list of processes with a specific monitoring action.
37
38
    The list (Python list) is composed of items (Python dict).
39
    An item is defined (dict keys):
40
    *...
41
    """
42
43
    # The dict
44
    __amps_dict = {}
45
46
    def __init__(self, args, config):
47
        """Init the AMPs list."""
48
        self.args = args
49
        self.config = config
50
51
        # Load the AMP configurations / scripts
52
        self.load_configs()
53
54
    def load_configs(self):
55
        """Load the AMP configuration files."""
56
        if self.config is None:
57
            return False
58
59
        # Display a warning (deprecated) message if the monitor section exist
60
        if "monitor" in self.config.sections():
61
            logger.warning("A deprecated [monitor] section exists in the Glances configuration file. You should use the new Applications Monitoring Process module instead (http://glances.readthedocs.io/en/develop/aoa/amps.html).")
0 ignored issues
show
This line is too long as per the coding-style (230/80).

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

Loading history...
62
63
        header = "glances_"
64
        # For each AMP scrip, call the load_config method
65
        for s in self.config.sections():
0 ignored issues
show
Coding Style Naming introduced by
The name s does not conform to the variable naming conventions ((([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$).

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
66
            if s.startswith("amp_"):
67
                # An AMP section exists in the configuration file
68
                # If an AMP script exist in the glances/amps folder, use it
69
                amp_conf_name = s[4:]
70
                amp_script = os.path.join(amps_path, header + s[4:] + ".py")
71
                if not os.path.exists(amp_script):
72
                    # If not, use the default script
73
                    amp_script = os.path.join(amps_path, "glances_default.py")
74
                try:
75
                    amp = __import__(os.path.basename(amp_script)[:-3])
76
                except ImportError as e:
0 ignored issues
show
Coding Style Naming introduced by
The name e does not conform to the variable naming conventions ((([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$).

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
77
                    logger.warning("Missing Python Lib ({}), cannot load {} AMP".format(e, amp_conf_name))
0 ignored issues
show
This line is too long as per the coding-style (106/80).

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

Loading history...
78
                except Exception as e:
0 ignored issues
show
Coding Style Naming introduced by
The name e does not conform to the variable naming conventions ((([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$).

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
79
                    logger.warning("Cannot load {} AMP ({})".format(amp_conf_name, e))
0 ignored issues
show
This line is too long as per the coding-style (86/80).

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

Loading history...
80
                else:
81
                    # Add the AMP to the dictionary
82
                    # The key is the AMP name
83
                    # for example, the file glances_xxx.py
84
                    # generate self._amps_list["xxx"] = ...
85
                    self.__amps_dict[amp_conf_name] = amp.Amp(name=amp_conf_name, args=self.args)
0 ignored issues
show
This line is too long as per the coding-style (97/80).

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

Loading history...
86
                    # Load the AMP configuration
87
                    self.__amps_dict[amp_conf_name].load_config(self.config)
88
        # Log AMPs list
89
        logger.debug("AMPs list: {}".format(self.getList()))
90
91
        return True
92
93
    def __str__(self):
94
        return str(self.__amps_dict)
95
96
    def __repr__(self):
97
        return self.__amps_dict
98
99
    def __getitem__(self, item):
100
        return self.__amps_dict[item]
101
102
    def __len__(self):
103
        return len(self.__amps_dict)
104
105
    def update(self):
106
        """Update the command result attributed."""
107
        # Get the current processes list (once)
108
        processlist = glances_processes.getlist()
109
110
        # Iter upon the AMPs dict
111
        for k, v in iteritems(self.get()):
0 ignored issues
show
Coding Style Naming introduced by
The name v does not conform to the variable naming conventions ((([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$).

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
112
            if not v.enable():
113
                # Do not update if the enable tag is set
114
                continue
115
            
0 ignored issues
show
Trailing whitespace
Loading history...
116
            if v.regex() is None:
117
                # If there is no regex, execute anyway (see issue #1690)
118
                v.set_count(0)
119
                # Call the AMP update method
120
                thread = threading.Thread(target=v.update_wrapper, args=[[]])
121
                thread.start()
122
                continue
123
124
            amps_list = self._build_amps_list(v, processlist)
125
126
            if len(amps_list) > 0:
0 ignored issues
show
Do not use len(SEQUENCE) as condition value
Loading history...
127
                # At least one process is matching the regex
128
                logger.debug("AMPS: {} processes {} detected ({})".format(len(amps_list),
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...
129
                                                                          k,
130
                                                                          amps_list))
0 ignored issues
show
This line is too long as per the coding-style (85/80).

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

Loading history...
131
                # Call the AMP update method
132
                thread = threading.Thread(target=v.update_wrapper, args=[amps_list])
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...
133
                thread.start()
134
            else:
135
                # Set the process number to 0
136
                v.set_count(0)
137
                if v.count_min() is not None and v.count_min() > 0:
138
                    # Only display the "No running process message" if countmin is defined
0 ignored issues
show
This line is too long as per the coding-style (90/80).

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

Loading history...
139
                    v.set_result("No running process")
140
141
        return self.__amps_dict
142
143
    def _build_amps_list(self, amp_value, processlist):
0 ignored issues
show
This method could be written as a function/class method.

If a method does not access any attributes of the class, it could also be implemented as a function or static method. This can help improve readability. For example

class Foo:
    def some_method(self, x, y):
        return x + y;

could be written as

class Foo:
    @classmethod
    def some_method(cls, x, y):
        return x + y;
Loading history...
144
        """Return the AMPS process list according to the amp_value
145
146
        Search application monitored processes by a regular expression
147
        """
148
        ret = []
149
        try:
150
            # Search in both cmdline and name (for kernel thread, see #1261)
151
            for p in processlist:
0 ignored issues
show
Coding Style Naming introduced by
The name p does not conform to the variable naming conventions ((([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$).

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
152
                add_it = False
153
                if (re.search(amp_value.regex(), p['name']) is not None):
0 ignored issues
show
Unused Code Coding Style introduced by
Unnecessary parens after u'if' keyword
Loading history...
154
                    add_it = True
155
                else:
156
                    if p['cmdline'] is None:
157
                        # See issue #1689 (thanks to @darylkell)
158
                        continue
159
                    for c in p['cmdline']:
0 ignored issues
show
Coding Style Naming introduced by
The name c does not conform to the variable naming conventions ((([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$).

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
160
                        if (re.search(amp_value.regex(), c) is not None):
0 ignored issues
show
Unused Code Coding Style introduced by
Unnecessary parens after u'if' keyword
Loading history...
161
                            add_it = True
162
                            break
163
                if add_it:
164
                    ret.append({'pid': p['pid'],
165
                                'cpu_percent': p['cpu_percent'],
166
                                'memory_percent': p['memory_percent']})
167
168
        except (TypeError, KeyError) as e:
0 ignored issues
show
Coding Style Naming introduced by
The name e does not conform to the variable naming conventions ((([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$).

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
169
            logger.debug("Can not build AMPS list ({})".format(e))
170
171
        return ret
172
173
    def getList(self):
0 ignored issues
show
Coding Style Naming introduced by
The name getList does not conform to the method naming conventions ((([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$).

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
174
        """Return the AMPs list."""
175
        return listkeys(self.__amps_dict)
176
177
    def get(self):
178
        """Return the AMPs dict."""
179
        return self.__amps_dict
180
181
    def set(self, new_dict):
182
        """Set the AMPs dict."""
183
        self.__amps_dict = new_dict
184