1# -*- coding: utf-8 -*- 2# 3# This file is part of Glances. 4# 5# Copyright (C) 2019 Nicolargo <nicolas@nicolargo.com> 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 22import os 23import socket 24 25from glances.compat import nativestr, range 26from glances.logger import logger 27from glances.plugins.glances_plugin import GlancesPlugin 28 29 30class 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 77class 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() 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: 152 logger.debug("Cannot connect to an HDDtemp server ({}:{} => {})".format(self.host, self.port, e)) 153 logger.debug("Disable the HDDtemp module. Use the --disable-hddtemp to hide the previous message.") 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)) 161 162 return data 163 164 def get(self): 165 """Get HDDs list.""" 166 self.__update__() 167 return self.hddtemp_list 168