Test Failed
Push — develop ( d7cf39...faa4bd )
by Nicolas
04:34 queued 10s
created

glances/amps_list.py (7 issues)

Checks whether an import is not accompanied by ``from __future__ import absolute_import`` (default behaviour in Python 3)

Minor
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
"""Manage the AMPs list."""
21
22
import os
0 ignored issues
show
import missing from __future__ import absolute_import
Loading history...
23
import re
0 ignored issues
show
import missing from __future__ import absolute_import
Loading history...
24
import threading
0 ignored issues
show
import missing from __future__ import absolute_import
Loading history...
25
26
from glances.compat import listkeys, iteritems
0 ignored issues
show
import missing from __future__ import absolute_import
Loading history...
27
from glances.logger import logger
0 ignored issues
show
import missing from __future__ import absolute_import
Loading history...
28
from glances.globals import amps_path
0 ignored issues
show
import missing from __future__ import absolute_import
Loading history...
29
from glances.processes import glances_processes
0 ignored issues
show
import missing from __future__ import absolute_import
Loading history...
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).")
62
63
        header = "glances_"
64
        # For each AMP scrip, call the load_config method
65
        for s in self.config.sections():
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:
77
                    logger.warning("Missing Python Lib ({}), cannot load {} AMP".format(e, amp_conf_name))
78
                except Exception as e:
79
                    logger.warning("Cannot load {} AMP ({})".format(amp_conf_name, e))
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)
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()):
112
            if not v.enable():
113
                # Do not update if the enable tag is set
114
                continue
115
116
            amps_list = self._build_amps_list(v, processlist)
117
118
            if len(amps_list) > 0:
119
                # At least one process is matching the regex
120
                logger.debug("AMPS: {} processes {} detected ({})".format(len(amps_list),
121
                                                                          k,
122
                                                                          amps_list))
123
                # Call the AMP update method
124
                thread = threading.Thread(target=v.update_wrapper, args=[amps_list])
125
                thread.start()
126
            else:
127
                # Set the process number to 0
128
                v.set_count(0)
129
                if v.count_min() is not None and v.count_min() > 0:
130
                    # Only display the "No running process message" if countmin is defined
131
                    v.set_result("No running process")
132
133
        return self.__amps_dict
134
135
    def _build_amps_list(self, amp_value, processlist):
136
        """Return the AMPS process list according to the amp_value
137
138
        Search application monitored processes by a regular expression
139
        """
140
        ret = []
141
        try:
142
            # Search in both cmdline and name (for kernel thread, see #1261)
143
            for p in processlist:
144
                add_it = False
145
                if (re.search(amp_value.regex(), p['name']) is not None):
146
                    add_it = True
147
                else:
148
                    for c in p['cmdline']:
149
                        if (re.search(amp_value.regex(), c) is not None):
150
                            add_it = True
151
                            break
152
                if add_it:
153
                    ret.append({'pid': p['pid'],
154
                                'cpu_percent': p['cpu_percent'],
155
                                'memory_percent': p['memory_percent']})
156
157
        except (TypeError, KeyError) as e:
158
            logger.debug("Can not build AMPS list ({})".format(e))
159
160
        return ret
161
162
    def getList(self):
163
        """Return the AMPs list."""
164
        return listkeys(self.__amps_dict)
165
166
    def get(self):
167
        """Return the AMPs dict."""
168
        return self.__amps_dict
169
170
    def set(self, new_dict):
171
        """Set the AMPs dict."""
172
        self.__amps_dict = new_dict
173