Test Failed
Push — develop ( 504450...f0e8ef )
by Nicolas
03:16
created

GlancesGrabHDDTemp.fetch()   B

Complexity

Conditions 6

Size

Total Lines 24
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
eloc 20
nop 1
dl 0
loc 24
rs 8.4666
c 0
b 0
f 0
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
"""HDD temperature plugin."""
21
22
import os
0 ignored issues
show
introduced by Alessio Sergi
import missing from __future__ import absolute_import
Loading history...
23
import socket
0 ignored issues
show
introduced by Alessio Sergi
import missing from __future__ import absolute_import
Loading history...
24
25
from glances.compat import nativestr, range
0 ignored issues
show
Bug Best Practice introduced by Alessio Sergi
This seems to re-define the built-in range.

It is generally discouraged to redefine built-ins as this makes code very hard to read.

Loading history...
introduced by Alessio Sergi
import missing from __future__ import absolute_import
Loading history...
26
from glances.logger import logger
0 ignored issues
show
introduced by Alessio Sergi
import missing from __future__ import absolute_import
Loading history...
27
from glances.plugins.glances_plugin import GlancesPlugin
0 ignored issues
show
introduced by Alessio Sergi
import missing from __future__ import absolute_import
Loading history...
28
29
30
class Plugin(GlancesPlugin):
31
    """Glances HDD temperature sensors plugin.
32
33
    stats is a list
34
    """
35
36
    def __init__(self, args=None, config=None):
37
        """Init the plugin."""
38
        super(Plugin, self).__init__(args=args,
39
                                     config=config,
40
                                     stats_init_value=[])
41
42
        # Init the sensor class
43
        hddtemp_host = self.get_conf_value("host",
44
                                           default=["127.0.0.1"])[0]
45
        hddtemp_port = int(self.get_conf_value("port",
46
                                               default="7634"))
47
        self.hddtemp = GlancesGrabHDDTemp(args=args,
48
                                          host=hddtemp_host,
49
                                          port=hddtemp_port)
50
51
        # We do not want to display the stat in a dedicated area
52
        # The HDD temp is displayed within the sensors plugin
53
        self.display_curse = False
54
55
    @GlancesPlugin._check_decorator
56
    @GlancesPlugin._log_result_decorator
57
    def update(self):
58
        """Update HDD stats using the input method."""
59
        # Init new stats
60
        stats = self.get_init_value()
61
62
        if self.input_method == 'local':
63
            # Update stats using the standard system lib
64
            stats = self.hddtemp.get()
65
66
        else:
67
            # Update stats using SNMP
68
            # Not available for the moment
69
            pass
70
71
        # Update the stats
72
        self.stats = stats
73
74
        return self.stats
75
76
77
class GlancesGrabHDDTemp(object):
78
    """Get hddtemp stats using a socket connection."""
79
80
    def __init__(self, host='127.0.0.1', port=7634, args=None):
81
        """Init hddtemp stats."""
82
        self.args = args
83
        self.host = host
84
        self.port = port
85
        self.cache = ""
86
        self.reset()
87
88
    def reset(self):
89
        """Reset/init the stats."""
90
        self.hddtemp_list = []
91
92
    def __update__(self):
93
        """Update the stats."""
94
        # Reset the list
95
        self.reset()
96
97
        # Fetch the data
98
        # data = ("|/dev/sda|WDC WD2500JS-75MHB0|44|C|"
99
        #         "|/dev/sdb|WDC WD2500JS-75MHB0|35|C|"
100
        #         "|/dev/sdc|WDC WD3200AAKS-75B3A0|45|C|"
101
        #         "|/dev/sdd|WDC WD3200AAKS-75B3A0|45|C|"
102
        #         "|/dev/sde|WDC WD3200AAKS-75B3A0|43|C|"
103
        #         "|/dev/sdf|???|ERR|*|"
104
        #         "|/dev/sdg|HGST HTS541010A9E680|SLP|*|"
105
        #         "|/dev/sdh|HGST HTS541010A9E680|UNK|*|")
106
        data = self.fetch()
107
108
        # Exit if no data
109
        if data == "":
110
            return
111
112
        # Safety check to avoid malformed data
113
        # Considering the size of "|/dev/sda||0||" as the minimum
114
        if len(data) < 14:
115
            data = self.cache if len(self.cache) > 0 else self.fetch()
0 ignored issues
show
introduced by Alessio Sergi
Do not use len(SEQUENCE) as condition value
Loading history...
116
        self.cache = data
117
118
        try:
119
            fields = data.split(b'|')
120
        except TypeError:
121
            fields = ""
122
        devices = (len(fields) - 1) // 5
123
        for item in range(devices):
124
            offset = item * 5
125
            hddtemp_current = {}
126
            device = os.path.basename(nativestr(fields[offset + 1]))
127
            temperature = fields[offset + 3]
128
            unit = nativestr(fields[offset + 4])
129
            hddtemp_current['label'] = device
130
            try:
131
                hddtemp_current['value'] = float(temperature)
132
            except ValueError:
133
                # Temperature could be 'ERR', 'SLP' or 'UNK' (see issue #824)
134
                # Improper bytes/unicode in glances_hddtemp.py (see issue #887)
135
                hddtemp_current['value'] = nativestr(temperature)
136
            hddtemp_current['unit'] = unit
137
            self.hddtemp_list.append(hddtemp_current)
138
139
    def fetch(self):
140
        """Fetch the data from hddtemp daemon."""
141
        # Taking care of sudden deaths/stops of hddtemp daemon
142
        try:
143
            sck = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
144
            sck.connect((self.host, self.port))
145
            data = b''
146
            while True:
147
                received = sck.recv(4096)
148
                if not received:
149
                    break
150
                data += received
151
        except Exception as e:
0 ignored issues
show
Best Practice introduced by Nicolas Hennion
Catching very general exceptions such as Exception is usually not recommended.

Generally, you would want to handle very specific errors in the exception handler. This ensure that you do not hide other types of errors which should be fixed.

So, unless you specifically plan to handle any error, consider adding a more specific exception.

Loading history...
Coding Style Naming introduced by Nicolas Hennion
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...
152
            logger.debug("Cannot connect to an HDDtemp server ({}:{} => {})".format(self.host, self.port, e))
0 ignored issues
show
Coding Style introduced by Alessio Sergi
This line is too long as per the coding-style (109/80).

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

Loading history...
introduced by Alessio Sergi
Use formatting in logging functions and pass the parameters as arguments
Loading history...
153
            logger.debug("Disable the HDDtemp module. Use the --disable-hddtemp to hide the previous message.")
0 ignored issues
show
Coding Style introduced by Nicolas Hennion
This line is too long as per the coding-style (111/80).

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

Loading history...
154
            if self.args is not None:
155
                self.args.disable_hddtemp = True
156
            data = ""
157
        finally:
158
            sck.close()
159
            if data != "":
160
                logger.debug("Received data from the HDDtemp server: {}".format(data))
0 ignored issues
show
Coding Style introduced by MendelGusmao
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...
introduced by MendelGusmao
Use formatting in logging functions and pass the parameters as arguments
Loading history...
161
162
        return data
163
164
    def get(self):
165
        """Get HDDs list."""
166
        self.__update__()
167
        return self.hddtemp_list
168