Lucas Teske revidoval tento gist 11 years ago. Přejít na revizi
1 file changed, 255 insertions
tvs_tools.py(vytvořil soubor)
| @@ -0,0 +1,255 @@ | |||
| 1 | + | #!/usr/bin/python | |
| 2 | + | #encoding:UTF-8 | |
| 3 | + | ||
| 4 | + | import os, smtplib, shutil, syslog, subprocess, cgi, commands, re, MySQLdb | |
| 5 | + | from datetime import date, timedelta | |
| 6 | + | from email.mime.multipart import MIMEMultipart | |
| 7 | + | from email.mime.text import MIMEText | |
| 8 | + | from htmlentitydefs import codepoint2name | |
| 9 | + | ||
| 10 | + | ||
| 11 | + | def toNotationUnit(value, base=10): | |
| 12 | + | units = [ 'y','z','a','f','p','n','u','m',' ', 'k','M','G','T','P','E','Z','Y'] | |
| 13 | + | counter = 8 | |
| 14 | + | if base==10: | |
| 15 | + | val = value if value > 0 else -value | |
| 16 | + | if val < 1: | |
| 17 | + | while ( val < 1.00) and not (counter == 0): | |
| 18 | + | counter = counter - 1 | |
| 19 | + | val = val * 1000.0 | |
| 20 | + | else: | |
| 21 | + | while ( val >= 1000 ) and not (counter == 16): | |
| 22 | + | counter = counter + 1 | |
| 23 | + | val = val / 1000.0 | |
| 24 | + | return ( (val if value > 0 else -val) , units[counter]) | |
| 25 | + | elif base == 2: | |
| 26 | + | val = value if value > 0 else -value | |
| 27 | + | if val < 1: | |
| 28 | + | while ( val < 1.00) and not (counter == 0): | |
| 29 | + | counter = counter - 1 | |
| 30 | + | val = val * 1024.0 | |
| 31 | + | else: | |
| 32 | + | while ( val >= 1024 ) and not (counter == 16): | |
| 33 | + | counter = counter + 1 | |
| 34 | + | val = val / 1024.0 | |
| 35 | + | return ( (val if value > 0 else -val) , units[counter]) | |
| 36 | + | ||
| 37 | + | ||
| 38 | + | def htmlentities(text): | |
| 39 | + | text = (text).decode('utf-8') | |
| 40 | + | ||
| 41 | + | from htmlentitydefs import codepoint2name | |
| 42 | + | d = dict((unichr(code), u'&%s;' % name) for code,name in codepoint2name.iteritems() if code!=38) # exclude "&" | |
| 43 | + | if u"&" in text: | |
| 44 | + | text = text.replace(u"&", u"&") | |
| 45 | + | for key, value in d.iteritems(): | |
| 46 | + | if key in text: | |
| 47 | + | text = text.replace(key, value) | |
| 48 | + | return text | |
| 49 | + | ||
| 50 | + | def LOG(msg): | |
| 51 | + | syslog.syslog(syslog.LOG_INFO, 'TVS Backup System: %s' %msg) | |
| 52 | + | ||
| 53 | + | def WARN(msg): | |
| 54 | + | syslog.syslog(syslog.LOG_WARNING, 'TVS Backup System: %s' %msg) | |
| 55 | + | ||
| 56 | + | def ExecuteShell(cmd): | |
| 57 | + | return subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True).stdout.read() | |
| 58 | + | ||
| 59 | + | def GetDiskList(): | |
| 60 | + | disks = filter(None, ExecuteShell('ls /sys/block/ |grep "sd\|xvd\|drbd"').split('\n')) | |
| 61 | + | return [ ("/dev/%s" %d) for d in disks ] | |
| 62 | + | ||
| 63 | + | def GetSmartData(disk): | |
| 64 | + | try : | |
| 65 | + | smartok = commands.getstatusoutput('smartctl -a %s' %disk)[0] | |
| 66 | + | if smartok == 0: | |
| 67 | + | ModelFamily = ExecuteShell('smartctl -a %s | grep "Model Family" | cut -d: -f2' %disk).strip() | |
| 68 | + | DeviceModel = ExecuteShell('smartctl -a %s | grep "Device Model" | cut -d: -f2' %disk).strip() | |
| 69 | + | UserCapacity = ExecuteShell('smartctl -a %s | grep "User Capacity" | cut -d: -f2' %disk).strip() | |
| 70 | + | DiskHealth = ExecuteShell('smartctl -a %s | grep "SMART overall-health" | cut -d: -f2' %disk).strip() | |
| 71 | + | PowerOnHours = ExecuteShell('smartctl -a %s | grep "Power_On_Hours"' %disk).strip().split(' ') | |
| 72 | + | PowerOnHours = PowerOnHours[len(PowerOnHours)-1] | |
| 73 | + | PowerCycleCount = ExecuteShell('smartctl -a %s | grep "Power_Cycle_Count"' %disk).strip().split(' ') | |
| 74 | + | PowerCycleCount = PowerCycleCount[len(PowerCycleCount)-1] | |
| 75 | + | ReadErrorRate = ExecuteShell('smartctl -a %s | grep "Raw_Read_Error_Rate"' %disk).strip().split(' ') | |
| 76 | + | ReadErrorRate = ReadErrorRate[len(ReadErrorRate)-1] | |
| 77 | + | ReallocatedSector = ExecuteShell('smartctl -a %s | grep "Reallocated_Sector_Ct"' %disk).strip().split(' ') | |
| 78 | + | ReallocatedSector = ReallocatedSector[len(ReallocatedSector)-1] | |
| 79 | + | ||
| 80 | + | return { "Device": disk, "ModelFamily" : ModelFamily, "DeviceModel" : DeviceModel, "UserCapacity" : UserCapacity, "DiskHealth": DiskHealth, "PowerOnHours" : PowerOnHours, "PowerCycleCount" : PowerCycleCount, "ReadErrorRate" : ReadErrorRate, "ReallocatedSector" : ReallocatedSector } | |
| 81 | + | except Exception, e: | |
| 82 | + | WARN("Erro ao ler SMART (%s): %s" %(disk,e)) | |
| 83 | + | return None | |
| 84 | + | ||
| 85 | + | def Init3WareSmart(): | |
| 86 | + | try: | |
| 87 | + | smartok = commands.getstatusoutput('smartctl -d 3ware,0 /dev/twa0') | |
| 88 | + | except: | |
| 89 | + | pass | |
| 90 | + | ||
| 91 | + | ||
| 92 | + | def Get3WareSmartData(): | |
| 93 | + | Init3WareSmart() | |
| 94 | + | smlist = [] | |
| 95 | + | try : | |
| 96 | + | for disk in range(0,12): | |
| 97 | + | smartok = commands.getstatusoutput('smartctl -a -d 3ware,%s /dev/twa0' %disk)[0] | |
| 98 | + | if smartok == 0: | |
| 99 | + | ModelFamily = ExecuteShell('smartctl -a -d 3ware,%s /dev/twa0 | grep "Model Family" | cut -d: -f2' %disk).strip() | |
| 100 | + | DeviceModel = ExecuteShell('smartctl -a -d 3ware,%s /dev/twa0 | grep "Device Model" | cut -d: -f2' %disk).strip() | |
| 101 | + | UserCapacity = ExecuteShell('smartctl -a -d 3ware,%s /dev/twa0 | grep "User Capacity" | cut -d: -f2' %disk).strip() | |
| 102 | + | DiskHealth = ExecuteShell('smartctl -a -d 3ware,%s /dev/twa0 | grep "SMART overall-health" | cut -d: -f2' %disk).strip() | |
| 103 | + | PowerOnHours = ExecuteShell('smartctl -a -d 3ware,%s /dev/twa0 | grep "Power_On_Hours"' %disk).strip().split(' ') | |
| 104 | + | PowerOnHours = PowerOnHours[len(PowerOnHours)-1] | |
| 105 | + | PowerCycleCount = ExecuteShell('smartctl -a -d 3ware,%s /dev/twa0 | grep "Power_Cycle_Count"' %disk).strip().split(' ') | |
| 106 | + | PowerCycleCount = PowerCycleCount[len(PowerCycleCount)-1] | |
| 107 | + | ReadErrorRate = ExecuteShell('smartctl -a -d 3ware,%s /dev/twa0 | grep "Raw_Read_Error_Rate"' %disk).strip().split(' ') | |
| 108 | + | ReadErrorRate = ReadErrorRate[len(ReadErrorRate)-1] | |
| 109 | + | ReallocatedSector = ExecuteShell('smartctl -a -d 3ware,%s /dev/twa0 | grep "Reallocated_Sector_Ct"' %disk).strip().split(' ') | |
| 110 | + | ReallocatedSector = ReallocatedSector[len(ReallocatedSector)-1] | |
| 111 | + | ||
| 112 | + | smlist.append({ "Device": "3ware:%s" %disk, "ModelFamily" : ModelFamily, "DeviceModel" : DeviceModel, "UserCapacity" : UserCapacity, "DiskHealth": DiskHealth, "PowerOnHours" : PowerOnHours, "PowerCycleCount" : PowerCycleCount, "ReadErrorRate" : ReadErrorRate, "ReallocatedSector" : ReallocatedSector }) | |
| 113 | + | return smlist | |
| 114 | + | except Exception, e: | |
| 115 | + | WARN("Erro ao ler SMART: %s" %(e)) | |
| 116 | + | return None | |
| 117 | + | ||
| 118 | + | ||
| 119 | + | def GetDiskUsage(): | |
| 120 | + | disks = [] | |
| 121 | + | try: | |
| 122 | + | disk_data = filter(None, ExecuteShell('df -h |grep "/dev/sd\|/dev/xvd\|/dev/mapper/\|/dev/drbd"').split('\n')) | |
| 123 | + | for disk in disk_data: | |
| 124 | + | dsk = filter(None, disk.split(' ')) | |
| 125 | + | dk = { 'Device' : dsk[0], 'Size' : dsk[1], 'Used' : dsk[2], 'Free' : dsk[3], 'UsedPercent' : dsk[4], 'MountPoint' : dsk[5] } | |
| 126 | + | disks.append(dk) | |
| 127 | + | except Exception, e: | |
| 128 | + | WARN("Erro ao ler dados de disco : %s" %(e)) | |
| 129 | + | return disks | |
| 130 | + | ||
| 131 | + | def GetNetDevData(dev): | |
| 132 | + | devdata = { 'Device' : dev, "TX" : "(0.0 B)", "RX" : "(0.0 B)", "IP" : "Unknown", "Broadcast" : "Unknown", "NetMask" : "Unknown" } | |
| 133 | + | try: | |
| 134 | + | netstring = ExecuteShell('LANG="en_US.UTF-8" LANGUAGE="en" ifconfig %s' %dev) | |
| 135 | + | devdata["IP"] = '.'.join(re.findall("inet addr:([0-9]*).([0-9]*).([0-9]*).([0-9]*)", netstring)[0]) | |
| 136 | + | devdata["Broadcast"] = '.'.join(re.findall("Bcast:([0-9]*).([0-9]*).([0-9]*).([0-9]*)", netstring)[0]) | |
| 137 | + | devdata["NetMask"] = '.'.join(re.findall("Mask:([0-9]*).([0-9]*).([0-9]*).([0-9]*)", netstring)[0]) | |
| 138 | + | tx = toNotationUnit(int(re.findall("TX bytes:([0-9]*)", netstring)[0])) | |
| 139 | + | rx = toNotationUnit(int(re.findall("RX bytes:([0-9]*)", netstring)[0])) | |
| 140 | + | devdata["TX"] = '(%s %sB)' %(round(tx[0]*100)/100.0, tx[1]) | |
| 141 | + | devdata["RX"] = '(%s %sB)' %(round(rx[0]*100)/100.0, rx[1]) | |
| 142 | + | except Exception, e: | |
| 143 | + | WARN("Erro ao ler dados da rede (%s) : %s" %(dev, e)) | |
| 144 | + | return devdata | |
| 145 | + | ||
| 146 | + | def GetNetworkDevices(): | |
| 147 | + | devices = [] | |
| 148 | + | try: | |
| 149 | + | data = filter(None, ExecuteShell('cat /proc/net/dev').split('\n')) | |
| 150 | + | data.pop(0) | |
| 151 | + | data.pop(0) | |
| 152 | + | for i in data: | |
| 153 | + | devices.append(i.split(':', 1)[0].strip()) | |
| 154 | + | except Exception, e: | |
| 155 | + | WARN("Erro ao ler interfaces de rede : %s" %(e)) | |
| 156 | + | return devices | |
| 157 | + | ||
| 158 | + | def GetNetworkUsage(): | |
| 159 | + | devices = GetNetworkDevices() | |
| 160 | + | usages = [] | |
| 161 | + | for device in devices: | |
| 162 | + | usages.append( GetNetDevData(device) ) | |
| 163 | + | ||
| 164 | + | return usages | |
| 165 | + | ||
| 166 | + | def GetDevicesInfo(): | |
| 167 | + | devs = filter(None, ExecuteShell("lspci").split('\n')) | |
| 168 | + | devs = [ d[8:] for d in devs ] | |
| 169 | + | return devs | |
| 170 | + | ||
| 171 | + | def GetMemInfo(): | |
| 172 | + | ''' | |
| 173 | + | Retorna informações sobre a memória | |
| 174 | + | ''' | |
| 175 | + | total = toNotationUnit(int(commands.getstatusoutput('cat /proc/meminfo |grep MemTotal | cut -d: -f2')[1].strip()[:-3]) * 1000) | |
| 176 | + | free = toNotationUnit(int(commands.getstatusoutput('cat /proc/meminfo |grep MemFree | cut -d: -f2')[1].strip()[:-3]) * 1000) | |
| 177 | + | swaptotal = toNotationUnit(int(commands.getstatusoutput('cat /proc/meminfo |grep SwapTotal | cut -d: -f2')[1].strip()[:-3]) * 1000) | |
| 178 | + | swapfree = toNotationUnit(int(commands.getstatusoutput('cat /proc/meminfo |grep SwapFree | cut -d: -f2')[1].strip()[:-3]) * 1000) | |
| 179 | + | return { "total" : "%s %sB" % (round(total[0]*100)/100, total[1]) , "free" : "%s %sB" % (round(free[0]*100)/100, free[1]), "swaptotal" : "%s %sB" % (round(swaptotal[0]*100)/100, swaptotal[1]), "swapfree" : "%s %sB" % (round(swapfree[0]*100)/100, swapfree[1]) } | |
| 180 | + | ||
| 181 | + | def GetUpTime(): | |
| 182 | + | uptime = float(commands.getstatusoutput('cat /proc/uptime')[1].split(' ')[0]) | |
| 183 | + | return str( timedelta(seconds=round(uptime))) | |
| 184 | + | ||
| 185 | + | def GetCPUInfo(): | |
| 186 | + | ''' | |
| 187 | + | Retorna os dados do processador | |
| 188 | + | ''' | |
| 189 | + | cpu_family = commands.getstatusoutput('cat /proc/cpuinfo |grep "cpu family" |head -n1 |cut -d: -f2')[1].strip() | |
| 190 | + | cpu_model = commands.getstatusoutput('cat /proc/cpuinfo |grep "model" |head -n1 |cut -d: -f2')[1].strip() | |
| 191 | + | cpu_model_name = commands.getstatusoutput('cat /proc/cpuinfo |grep "model name" |head -n1 |cut -d: -f2')[1].strip() | |
| 192 | + | cpu_stepping = commands.getstatusoutput('cat /proc/cpuinfo |grep "stepping" |head -n1 |cut -d: -f2')[1].strip() | |
| 193 | + | cpu_cores = commands.getstatusoutput('cat /proc/cpuinfo |grep "cpu cores" |head -n1 |cut -d: -f2')[1].strip() | |
| 194 | + | cpu_bogomips = commands.getstatusoutput('cat /proc/cpuinfo |grep "bogomips" |head -n1 |cut -d: -f2')[1].strip() | |
| 195 | + | return { 'cpu_family' : cpu_family, 'cpu_model' : cpu_model, 'cpu_model_name' : cpu_model_name, 'cpu_stepping' : cpu_stepping, 'cpu_cores' : cpu_cores, 'cpu_bogomips' : cpu_bogomips } | |
| 196 | + | ||
| 197 | + | def GetDRBDInfo(): | |
| 198 | + | ''' | |
| 199 | + | Retorna informações sobre DRBD | |
| 200 | + | ''' | |
| 201 | + | drbdinfo = {"conn" : {}} | |
| 202 | + | try: | |
| 203 | + | f = open("/proc/drbd") | |
| 204 | + | data = f.read() | |
| 205 | + | f.close() | |
| 206 | + | drbdinfo["has"] = True | |
| 207 | + | drbdinfo["drbdfile"] = data | |
| 208 | + | data = filter(None, data.split("\n")) | |
| 209 | + | lastdigit = None | |
| 210 | + | for line in data: | |
| 211 | + | block = line.split(":",1) | |
| 212 | + | block[0] = block[0].strip() | |
| 213 | + | block[1] = block[1].strip() | |
| 214 | + | if 'srcversion' in block[0]: | |
| 215 | + | drbdinfo["srcversion"] = block[1] | |
| 216 | + | elif 'version' in block[0]: | |
| 217 | + | drbdinfo["version"] = block[1] | |
| 218 | + | elif block[0].isdigit(): | |
| 219 | + | lastdigit = int(block[0]) | |
| 220 | + | drbdinfo["conn"][lastdigit] = {} | |
| 221 | + | d2 = filter(None, block[1].split(" ")) | |
| 222 | + | for d in d2: | |
| 223 | + | o = d.split(":") | |
| 224 | + | if len(o) > 1: | |
| 225 | + | drbdinfo["conn"][lastdigit][o[0]] = o[1] | |
| 226 | + | else: | |
| 227 | + | if lastdigit == None: | |
| 228 | + | WARN("Problemas ao ler partes do DRBD! - Linha: \n %s \n\n /proc/drbd : \n %s" %(line, "\n".join(data))) | |
| 229 | + | else: | |
| 230 | + | drbdinfo["conn"][lastdigit][block[0]] = block[1] | |
| 231 | + | except: | |
| 232 | + | drbdinfo["has"] = False | |
| 233 | + | return drbdinfo | |
| 234 | + | ||
| 235 | + | def GetMySQLSlave(hostname,username,password): | |
| 236 | + | ''' | |
| 237 | + | Retorna informações da sincronia do MySQL | |
| 238 | + | ''' | |
| 239 | + | con = MySQLdb.connect(hostname,username,password) | |
| 240 | + | cursor = con.cursor() | |
| 241 | + | cursor.execute("SHOW SLAVE STATUS") | |
| 242 | + | data = cursor.fetchall()[0] | |
| 243 | + | desc = cursor.description | |
| 244 | + | ||
| 245 | + | con.close() | |
| 246 | + | ||
| 247 | + | output = {} | |
| 248 | + | c = 0 | |
| 249 | + | for dc in desc: | |
| 250 | + | output[dc[0]] = data[c] | |
| 251 | + | c = c + 1 | |
| 252 | + | ||
| 253 | + | return output | |
| 254 | + | ||
| 255 | + | ||
Novější
Starší