glances_system.py 7.8 KB
Newer Older
N
Nicolas Hennion 已提交
1 2
# -*- coding: utf-8 -*-
#
3
# This file is part of Glances.
N
Nicolas Hennion 已提交
4
#
5
# Copyright (C) 2015 Nicolargo <nicolas@nicolargo.com>
N
Nicolas Hennion 已提交
6 7 8 9 10 11 12 13 14 15 16 17 18
#
# Glances is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Glances is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
A
PEP 257  
Alessio Sergi 已提交
19 20

"""System plugin."""
N
Nicolas Hennion 已提交
21

N
Nicolas Hennion 已提交
22 23 24
# Import system libs
import os
import platform
N
Nicolargo 已提交
25
import re
N
Nicolas Hennion 已提交
26

N
Nicolas Hennion 已提交
27
# Import Glances libs
28
from glances.plugins.glances_plugin import GlancesPlugin
N
Nicolas Hennion 已提交
29

30
# SNMP OID
N
Nicolargo 已提交
31
snmp_oid = {'default': {'hostname': '1.3.6.1.2.1.1.5.0',
N
Nicolargo 已提交
32
                        'system_name': '1.3.6.1.2.1.1.1.0'},
N
Nicolargo 已提交
33 34 35
            'netapp': {'hostname': '1.3.6.1.2.1.1.5.0',
                       'system_name': '1.3.6.1.2.1.1.1.0',
                       'platform': '1.3.6.1.4.1.789.1.1.5.0'}}
N
Nicolargo 已提交
36 37 38

# SNMP to human read
# Dict (key: OS short name) of dict (reg exp OID to human)
N
Nicolargo 已提交
39 40
# Windows:
# http://msdn.microsoft.com/en-us/library/windows/desktop/ms724832%28v=vs.85%29.aspx
N
Nicolargo 已提交
41 42 43 44 45 46 47
snmp_to_human = {'windows': {'Windows Version 6.3': 'Windows 8.1 or Server 2012R2',
                             'Windows Version 6.2': 'Windows 8 or Server 2012',
                             'Windows Version 6.1': 'Windows 7 or Server 2008R2',
                             'Windows Version 6.0': 'Windows Vista or Server 2008',
                             'Windows Version 5.2': 'Windows XP 64bits or 2003 server',
                             'Windows Version 5.1': 'Windows XP',
                             'Windows Version 5.0': 'Windows 2000'}}
A
Alessio Sergi 已提交
48

A
Alessio Sergi 已提交
49

N
Nicolas Hennion 已提交
50
class Plugin(GlancesPlugin):
A
PEP 257  
Alessio Sergi 已提交
51 52

    """Glances' host/system plugin.
N
Nicolas Hennion 已提交
53

N
Nicolas Hennion 已提交
54
    stats is a dict
N
Nicolas Hennion 已提交
55 56
    """

57
    def __init__(self, args=None):
A
PEP 257  
Alessio Sergi 已提交
58
        """Init the plugin."""
59
        GlancesPlugin.__init__(self, args=args)
60 61 62 63

        # We want to display the stat in the curse interface
        self.display_curse = True

64
        # Init the stats
A
Alessio Sergi 已提交
65
        self.reset()
66 67

    def reset(self):
A
PEP 257  
Alessio Sergi 已提交
68
        """Reset/init the stats."""
N
Nicolas Hennion 已提交
69
        self.stats = {}
70

A
Alessio Sergi 已提交
71
    def _linux_os_release(self):
A
PEP 257  
Alessio Sergi 已提交
72
        """Try to determine the name of a Linux distribution.
A
Alessio Sergi 已提交
73 74 75 76 77 78 79 80 81 82 83 84 85 86

        It checks for the /etc/os-release file. It takes the name from the
        'NAME' field and the version from 'VERSION_ID'.
        An empty string is returned if the above values cannot be determined.
        """
        pretty_name = ''
        ashtray = {}
        keys = ['NAME', 'VERSION_ID']
        try:
            with open(os.path.join('/etc', 'os-release')) as f:
                for line in f:
                    for key in keys:
                        if line.startswith(key):
                            ashtray[key] = line.strip().split('=')[1][1:-1]
87
        except (OSError, IOError):
A
Alessio Sergi 已提交
88 89 90 91 92 93 94 95 96 97
            return pretty_name

        if ashtray:
            if 'NAME' in ashtray:
                pretty_name = ashtray['NAME']
            if 'VERSION_ID' in ashtray:
                pretty_name += ' {0}'.format(ashtray['VERSION_ID'])

        return pretty_name

98
    def update(self):
A
PEP 257  
Alessio Sergi 已提交
99 100
        """Update the host/system info using the input method.

101 102 103 104 105
        Return the stats (dict)
        """
        # Reset stats
        self.reset()

106
        if self.input_method == 'local':
107 108 109 110 111
            # Update stats using the standard system lib
            self.stats['os_name'] = platform.system()
            self.stats['hostname'] = platform.node()
            self.stats['platform'] = platform.architecture()[0]
            if self.stats['os_name'] == "Linux":
A
Alessio Sergi 已提交
112 113 114
                linux_distro = platform.linux_distribution()
                if linux_distro[0] == '':
                    self.stats['linux_distro'] = self._linux_os_release()
115 116 117 118 119 120 121 122 123 124
                else:
                    self.stats['linux_distro'] = ' '.join(linux_distro[:2])
                self.stats['os_version'] = platform.release()
            elif self.stats['os_name'] == "FreeBSD":
                self.stats['os_version'] = platform.release()
            elif self.stats['os_name'] == "Darwin":
                self.stats['os_version'] = platform.mac_ver()[0]
            elif self.stats['os_name'] == "Windows":
                os_version = platform.win32_ver()
                self.stats['os_version'] = ' '.join(os_version[::2])
N
Nicolargo 已提交
125 126
                # if the python version is 32 bit perhaps the windows operating
                # system is 64bit
N
nicolargo 已提交
127 128
                if self.stats['platform'] == '32bit' and 'PROCESSOR_ARCHITEW6432' in os.environ:
                    self.stats['platform'] = '64bit'
N
Nicolas Hennion 已提交
129
            else:
130
                self.stats['os_version'] = ""
131 132 133
            # Add human readable name
            if self.stats['os_name'] == "Linux":
                self.stats['hr_name'] = self.stats['linux_distro']
A
Alessio Sergi 已提交
134
            else:
N
Nicolargo 已提交
135 136
                self.stats['hr_name'] = '{0} {1}'.format(
                    self.stats['os_name'], self.stats['os_version'])
137
            self.stats['hr_name'] += ' {0}'.format(self.stats['platform'])
138

139
        elif self.input_method == 'snmp':
N
Nicolargo 已提交
140
            # Update stats using SNMP
N
Nicolargo 已提交
141
            try:
142
                self.stats = self.get_stats_snmp(
143
                    snmp_oid=snmp_oid[self.short_system_name])
N
Nicolargo 已提交
144
            except KeyError:
145
                self.stats = self.get_stats_snmp(snmp_oid=snmp_oid['default'])
N
Nicolargo 已提交
146 147 148
            # Default behavor: display all the information
            self.stats['os_name'] = self.stats['system_name']
            # Windows OS tips
149
            if self.short_system_name == 'windows':
A
Alessio Sergi 已提交
150 151 152 153 154
                try:
                    iteritems = snmp_to_human['windows'].iteritems()
                except AttributeError:
                    iteritems = snmp_to_human['windows'].items()
                for r, v in iteritems:
N
Nicolargo 已提交
155
                    if re.search(r, self.stats['system_name']):
156
                        self.stats['os_name'] = v
N
Nicolargo 已提交
157
                        break
158 159
            # Add human readable name
            self.stats['hr_name'] = self.stats['os_name']
160

161
        return self.stats
162

N
Nicolas Hennion 已提交
163
    def msg_curse(self, args=None):
A
PEP 257  
Alessio Sergi 已提交
164
        """Return the string to display in the curse interface."""
165 166 167 168
        # Init the return message
        ret = []

        # Build the string message
169
        if args.client:
170
            # Client mode
171
            if args.cs_status.lower() == "connected":
A
Alessio Sergi 已提交
172
                msg = 'Connected to '
N
Nicolas Hennion 已提交
173
                ret.append(self.curse_add_line(msg, 'OK'))
174
            elif args.cs_status.lower() == "snmp":
A
Alessio Sergi 已提交
175
                msg = 'SNMP from '
176
                ret.append(self.curse_add_line(msg, 'OK'))
177
            elif args.cs_status.lower() == "disconnected":
A
Alessio Sergi 已提交
178
                msg = 'Disconnected from '
N
Nicolas Hennion 已提交
179
                ret.append(self.curse_add_line(msg, 'CRITICAL'))
180 181

        # Hostname is mandatory
182
        msg = self.stats['hostname']
N
Nicolas Hennion 已提交
183 184
        ret.append(self.curse_add_line(msg, "TITLE"))
        # System info
A
Alessio Sergi 已提交
185
        if self.stats['os_name'] == "Linux" and self.stats['linux_distro']:
A
Alessio Sergi 已提交
186
            msg = ' ({0} {1} / {2} {3})'.format(self.stats['linux_distro'],
187 188 189
                                                self.stats['platform'],
                                                self.stats['os_name'],
                                                self.stats['os_version'])
190
        else:
191
            try:
A
Alessio Sergi 已提交
192
                msg = ' ({0} {1} {2})'.format(self.stats['os_name'],
193 194
                                              self.stats['os_version'],
                                              self.stats['platform'])
A
Alessio Sergi 已提交
195
            except Exception:
A
Alessio Sergi 已提交
196
                msg = ' ({0})'.format(self.stats['os_name'])
N
Nicolas Hennion 已提交
197
        ret.append(self.curse_add_line(msg, optional=True))
A
Alessio Sergi 已提交
198 199

        # Return the message with decoration
200
        return ret