Test Failed
Push — develop ( 3e7080...29e3c5 )
by Nicolas
03:08
created

glances/plugins/glances_connections.py (1 issue)

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])
98
                initiated = 0
99
                for s in self.initiated_states:
100
                    stats[s] = len([c for c in net_connections if c.status == s])
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])
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:
116
                        logger.debug('Can not get network connections track ({})'.format(e))
0 ignored issues
show
Use formatting in logging functions and pass the parameters as arguments
Loading history...
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))
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