#!/usr/bin/python import commands import os import sys import re import socket import struct import time #import ctypes # TODO: maybe when there's more time; for better readability. #class History(Structure): # _fields_ = [ ("version", c_int), # ("index", c_int), # ("history", c_float * HISTORY_LENGTH), ] # allocate fixed space on disk to save persistent state. # what to store in this file? # slice_history : x,x,x,x,x,... # root_history : y,y,y,y,y,y... HISTORY_LENGTH = 24*30 # 30 days, if checked once an hour HISTORY_fmt = ('ii', 'f'*HISTORY_LENGTH ) HISTORY_version = 1 def get_network_bytes(interface): for line in open('/proc/net/dev', 'r'): if interface in line: data = line.split('%s:' % interface)[1].split() rx_bytes, tx_bytes = (data[0], data[8]) return (float(rx_bytes), float(tx_bytes)) return None def get_uptime(): for line in open('/proc/uptime', 'r'): data = line.split()[0] return float(data) return None def read_safe_history(filename): """ This function guarantees that space is preserved. If one of the file operations fail, it will throw an exception. """ if os.path.exists(filename): # read existing data fd = os.open(filename, os.O_RDONLY) a = os.read(fd, os.path.getsize(filename)) try: (version, i) = struct.unpack_from(HISTORY_fmt[0], a, 0) assert version == HISTORY_version history = struct.unpack_from(HISTORY_fmt[1], a, struct.calcsize(HISTORY_fmt[0])) history = [ h for h in history ] except: # TODO: in the future a more clever version migration might be nice. os.remove(filename) # just nuke the old version # create for the first time, with empty data (i, history) = (0, [0]*HISTORY_LENGTH) write_safe_history(filename, (i, history), False) os.close(fd) else: # create for the first time, with empty data (i, history) = (0, [0]*HISTORY_LENGTH) write_safe_history(filename, (i, history), False) return (i, history) def write_safe_history(filename, (i, history), check_for_file=True): # length should match, and the file should already exist assert len(history) == HISTORY_LENGTH if check_for_file: assert os.path.exists(filename) # open without TRUNC nor APPEND, then seek to beginning to preserve space on disk fd = os.open(filename, os.O_WRONLY|os.O_CREAT) os.lseek(fd, 0, 0) ret = os.write(fd, struct.pack(HISTORY_fmt[0], HISTORY_version, i )) ret += os.write(fd, struct.pack(HISTORY_fmt[1], *history)) os.close(fd) return ret def add_to_history((i, history), data): try: assert data > 0.0 history[i] = data i += 1 i = i % HISTORY_LENGTH except: # do not record data if data <= 0 pass return (i, history) def record_data(filename, data): rh = read_safe_history(filename) return write_safe_history(filename, add_to_history(rh, data)) def get_avg_uptime(filename): (idx, history) = read_safe_history(filename) summary = history[idx:] + history[:idx] measured = filter(lambda x: x != 0, summary) if len(measured) == 0: return 0 return float(sum(measured))/float(len(measured)) def timed(method): def timeit(*args, **kw): ts = time.time() result = method(*args, **kw) te = time.time() #print '%r (%r, %r) %2.2f sec' % \ # (method.__name__, args, kw, te-ts) return (result, te-ts) return timeit @timed def check_dns(ip, protocol='udp'): try: #ip = ip[:-1] + "0" ro = DNS.Request(name="www.yahoo.com", qtype="A", server=ip) r = ro.req(protocol=protocol) r = "OK" except DNS.Base.DNSError, e: r = "Error: %s" % e return r def get_nameserver_ips(filename): ip_re = re.compile("\d+\.\d+\.\d+\.\d+") ret = {} if not os.path.exists(filename): return ret f = open(filename, 'r') if 'resolv' in filename: for l in f: for field in l.strip().split(): if ip_re.match(field) and field not in ret: ret[field] = 0 if 'ifcfg' in filename: for l in f: if 'DNS' not in l: continue for field in l.strip().split('='): field = field.replace('"', '') field = field.replace("'", '') if ip_re.match(field) and field not in ret: ret[field] = 0 return ret def main(): ut = get_uptime() if ut == None: # massive fail. cannot continue. sys.exit(1) record_data("uptime_history.dat", ut) print get_avg_uptime("uptime_history.dat"), print "" if __name__ == "__main__": main() # TODO: comon? #url = """http://comon.cs.princeton.edu/status/tabulator.cgi?table=table_nodeviewshort&select='dns1udp>80 && dns2udp>80&&name=="%s"'&format=formatcsv&dumpcols='dns1udp,dns1tcp,dns2udp,dns2tcp'""" % os.popen("hostname").read().strip()