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 | """Connections plugin.""" |
||
21 | from __future__ import unicode_literals |
||
22 | |||
23 | from glances.logger import logger |
||
24 | from glances.timer import getTimeSinceLastUpdate |
||
25 | from glances.plugins.glances_plugin import GlancesPlugin |
||
26 | from glances.compat import n, u, b, nativestr |
||
27 | |||
28 | import psutil |
||
29 | |||
30 | # Define the history items list |
||
31 | # items_history_list = [{'name': 'rx', |
||
32 | # 'description': 'Download rate per second', |
||
33 | # 'y_unit': 'bit/s'}, |
||
34 | # {'name': 'tx', |
||
35 | # 'description': 'Upload rate per second', |
||
36 | # 'y_unit': 'bit/s'}] |
||
37 | |||
38 | |||
39 | class Plugin(GlancesPlugin): |
||
40 | """Glances connections plugin. |
||
41 | |||
42 | stats is a dict |
||
43 | """ |
||
44 | |||
45 | status_list = [psutil.CONN_LISTEN, |
||
46 | psutil.CONN_ESTABLISHED] |
||
47 | initiated_states = [psutil.CONN_SYN_SENT, |
||
48 | psutil.CONN_SYN_RECV] |
||
49 | terminated_states = [psutil.CONN_FIN_WAIT1, |
||
50 | psutil.CONN_FIN_WAIT2, |
||
51 | psutil.CONN_TIME_WAIT, |
||
52 | psutil.CONN_CLOSE, |
||
53 | psutil.CONN_CLOSE_WAIT, |
||
54 | psutil.CONN_LAST_ACK] |
||
55 | conntrack = {'nf_conntrack_count': '/proc/sys/net/netfilter/nf_conntrack_count', |
||
56 | 'nf_conntrack_max': '/proc/sys/net/netfilter/nf_conntrack_max'} |
||
57 | |||
58 | def __init__(self, args=None, config=None): |
||
59 | """Init the plugin.""" |
||
60 | super(Plugin, self).__init__(args=args, |
||
61 | config=config, |
||
62 | # items_history_list=items_history_list, |
||
63 | stats_init_value={}) |
||
64 | |||
65 | # We want to display the stat in the curse interface |
||
66 | self.display_curse = True |
||
67 | |||
68 | # This plugin is composed if net_connections and nf_conntrack |
||
69 | # Enabled by default |
||
70 | self.net_connections_enabled = True |
||
71 | self.nf_conntrack_enabled = True |
||
72 | |||
73 | @GlancesPlugin._check_decorator |
||
74 | @GlancesPlugin._log_result_decorator |
||
75 | def update(self): |
||
76 | """Update connections stats using the input method. |
||
77 | |||
78 | Stats is a dict |
||
79 | """ |
||
80 | # Init new stats |
||
81 | stats = self.get_init_value() |
||
82 | |||
83 | if self.input_method == 'local': |
||
84 | # Update stats using the PSUtils lib |
||
85 | |||
86 | # Grab network interface stat using the psutil net_connections method |
||
87 | if self.net_connections_enabled: |
||
88 | try: |
||
89 | net_connections = psutil.net_connections(kind="tcp") |
||
90 | except Exception as e: |
||
91 | logger.debug('Can not get network connections stats ({})'.format(e)) |
||
92 | self.net_connections_enabled = False |
||
93 | self.stats = stats |
||
94 | return self.stats |
||
95 | |||
96 | for s in self.status_list: |
||
97 | stats[s] = len([c for c in net_connections if c.status == s]) |
||
0 ignored issues
–
show
|
|||
98 | initiated = 0 |
||
99 | for s in self.initiated_states: |
||
100 | stats[s] = len([c for c in net_connections if c.status == s]) |
||
0 ignored issues
–
show
|
|||
101 | initiated += stats[s] |
||
102 | stats['initiated'] = initiated |
||
103 | terminated = 0 |
||
104 | for s in self.initiated_states: |
||
105 | stats[s] = len([c for c in net_connections if c.status == s]) |
||
0 ignored issues
–
show
|
|||
106 | terminated += stats[s] |
||
107 | stats['terminated'] = terminated |
||
108 | |||
109 | if self.nf_conntrack_enabled: |
||
110 | # Grab connections track directly from the /proc file |
||
111 | for i in self.conntrack: |
||
112 | try: |
||
113 | with open(self.conntrack[i], 'r') as f: |
||
114 | stats[i] = float(f.readline().rstrip("\n")) |
||
115 | except IOError as e: |
||
0 ignored issues
–
show
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...
|
|||
116 | logger.debug('Can not get network connections track ({})'.format(e)) |
||
0 ignored issues
–
show
|
|||
117 | self.nf_conntrack_enabled = False |
||
118 | self.stats = stats |
||
119 | return self.stats |
||
120 | stats['nf_conntrack_percent'] = stats['nf_conntrack_count'] * 100 / stats['nf_conntrack_max'] |
||
121 | |||
122 | elif self.input_method == 'snmp': |
||
123 | # Update stats using SNMP |
||
124 | pass |
||
125 | |||
126 | # Update the stats |
||
127 | self.stats = stats |
||
128 | return self.stats |
||
129 | |||
130 | def update_views(self): |
||
131 | """Update stats views.""" |
||
132 | # Call the father's method |
||
133 | super(Plugin, self).update_views() |
||
134 | |||
135 | # Add specifics informations |
||
136 | try: |
||
137 | # Alert and log |
||
138 | if self.nf_conntrack_enabled: |
||
139 | self.views['nf_conntrack_percent']['decoration'] = self.get_alert(header='nf_conntrack_percent') |
||
140 | except KeyError: |
||
141 | # try/except mandatory for Windows compatibility (no conntrack stats) |
||
142 | pass |
||
143 | |||
144 | def msg_curse(self, args=None, max_width=None): |
||
145 | """Return the dict to display in the curse interface.""" |
||
146 | # Init the return message |
||
147 | ret = [] |
||
148 | |||
149 | logger.info(self.is_disable()) |
||
150 | |||
151 | # Only process if stats exist and display plugin enable... |
||
152 | if not self.stats or self.is_disable(): |
||
153 | return ret |
||
154 | |||
155 | # Header |
||
156 | if self.net_connections_enabled or self.nf_conntrack_enabled: |
||
157 | msg = '{}'.format('TCP CONNECTIONS') |
||
158 | ret.append(self.curse_add_line(msg, "TITLE")) |
||
159 | # Connections status |
||
160 | if self.net_connections_enabled: |
||
161 | for s in [psutil.CONN_LISTEN, 'initiated', psutil.CONN_ESTABLISHED, 'terminated']: |
||
162 | ret.append(self.curse_new_line()) |
||
163 | msg = '{:{width}}'.format(nativestr(s).capitalize(), width=len(s)) |
||
0 ignored issues
–
show
|
|||
164 | ret.append(self.curse_add_line(msg)) |
||
165 | msg = '{:>{width}}'.format(self.stats[s], width=max_width - len(s) + 2) |
||
166 | ret.append(self.curse_add_line(msg)) |
||
167 | # Connections track |
||
168 | if self.nf_conntrack_enabled: |
||
169 | s = 'Tracked' |
||
170 | ret.append(self.curse_new_line()) |
||
171 | msg = '{:{width}}'.format(nativestr(s).capitalize(), width=len(s)) |
||
172 | ret.append(self.curse_add_line(msg)) |
||
173 | msg = '{:>{width}}'.format('{:0.0f}/{:0.0f}'.format(self.stats['nf_conntrack_count'], |
||
174 | self.stats['nf_conntrack_max']), |
||
175 | width=max_width - len(s) + 2) |
||
176 | ret.append(self.curse_add_line(msg, |
||
177 | self.get_views(key='nf_conntrack_percent', |
||
178 | option='decoration'))) |
||
179 | |||
180 | return ret |
||
181 |
This check looks for lines that are too long. You can specify the maximum line length.