From ecd1bafa033312db81872294a5bf099177952821 Mon Sep 17 00:00:00 2001 From: Mark Huang Date: Fri, 28 Apr 2006 19:27:43 +0000 Subject: [PATCH] - utility functions common to swapmon and bwmon --- pl_mom.py | 220 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 220 insertions(+) create mode 100644 pl_mom.py diff --git a/pl_mom.py b/pl_mom.py new file mode 100644 index 0000000..532dfd5 --- /dev/null +++ b/pl_mom.py @@ -0,0 +1,220 @@ +#!/usr/bin/python +# +# Utility functions +# +# Mark Huang +# Copyright (C) 2006 The Trustees of Princeton University +# +# $Id$ +# + +import os +import sys +import syslog +import socket +import xmlrpclib + +# /etc/planetlab/plc_config.py is a Python fragment maintained by +# PlanetLabConf that contains PLC configuration variables. +try: + sys.path.append("/etc/planetlab") + from plc_config import * +except: + print "Warning: Configuration file /etc/planetlab/plc_config.py not found" + PLC_NAME = "PlanetLab" + PLC_SLICE_PREFIX = "pl" + PLC_MAIL_SUPPORT_ADDRESS = "support@planet-lab.org" + PLC_MAIL_SLICE_ADDRESS = "SLICE@slices.planet-lab.org" + +def format_bytes(bytes, si = True): + """ + Formats bytes into a string + """ + if si: + kilo = 1000. + else: + # Officially, a kibibyte + kilo = 1024. + + if bytes >= (kilo * kilo * kilo): + return "%.1f GB" % (bytes / (kilo * kilo * kilo)) + elif bytes >= 1000000: + return "%.1f MB" % (bytes / (kilo * kilo)) + elif bytes >= 1000: + return "%.1f KB" % (bytes / kilo) + else: + return "%.0f bytes" % bytes + +def format_period(seconds): + """ + Formats a period in seconds into a string + """ + + if seconds == (24 * 60 * 60): + return "day" + elif seconds == (60 * 60): + return "hour" + elif seconds > (24 * 60 * 60): + return "%.1f days" % (seconds / 24. / 60. / 60.) + elif seconds > (60 * 60): + return "%.1f hours" % (seconds / 60. / 60.) + elif seconds > (60): + return "%.1f minutes" % (seconds / 60.) + else: + return "%.0f seconds" % seconds + +def writepid(prog): + """ + Check PID file. Exit if already running. Update PID file. + """ + + try: + pidfile = file("/var/run/%s.pid" % prog, "r") + pid = pidfile.readline().strip() + pidfile.close() + if os.path.isdir("/proc/" + pid): + print "Error: Another copy of %s is still running (%s)" % (prog, pid) + sys.exit(1) + except IOError: + pass + + pidfile = file("/var/run/%s.pid" % prog, "w") + pidfile.write(str(os.getpid())) + pidfile.close() + +def removepid(prog): + os.unlink("/var/run/%s.pid" % prog) + +def slicemail(slice, subject, body): + sendmail = os.popen("/usr/sbin/sendmail -t -f%s" % PLC_MAIL_SUPPORT_ADDRESS, "w") + + # PLC has a separate list for pl_mom messages + if PLC_MAIL_SUPPORT_ADDRESS == "support@planet-lab.org": + to = ["pl-mom@planet-lab.org"] + else: + to = [PLC_MAIL_SUPPORT_ADDRESS] + + if slice is not None and slice != "root": + to.append(PLC_MAIL_SLICE_ADDRESS.replace("SLICE", slice)) + + header = {'from': "%s Support <%s>" % (PLC_NAME, PLC_MAIL_SUPPORT_ADDRESS), + 'to': ", ".join(to), + 'version': sys.version.split(" ")[0], + 'subject': subject} + + # Write headers + sendmail.write( +""" +Content-type: text/plain +From: %(from)s +Reply-To: %(from)s +To: %(to)s +X-Mailer: Python/%(version)s +Subject: %(subject)s + +""".lstrip() % header) + + # Write body + sendmail.write(body) + + # Done + sendmail.close() + +class Logger: + """ + Simple file-like class for redirecting stdout and stderr to /var/log/messages + """ + + def write(self, text): + text = text.strip() + if text: + syslog.syslog(text) + +def daemonize(): + """ + Daemonize self. Detach from terminal, close all open files, and fork twice. + """ + + pid = os.fork() + if pid == 0: + # Detach from terminal + os.setsid() + # Orphan myself + pid = os.fork() + if pid == 0: + os.chdir("/") + else: + os._exit(0) + else: + os._exit(0) + + # Close all open file descriptors + import resource + maxfd = resource.getrlimit(resource.RLIMIT_NOFILE)[1] + if (maxfd == resource.RLIM_INFINITY): + maxfd = 1024 + for fd in range(0, maxfd): + try: + os.close(fd) + except OSError: + pass + + # Redirect stdin to /dev/null + os.open("/dev/null", os.O_RDWR) + +class NM: + """ + Simple interface to local Node Manager API + """ + + def __init__(self, url = "http://localhost:812/", timeout = 10): + """ + Open a new connection to the local Node Manager + """ + + socket.setdefaulttimeout(timeout) + try: + self.nm = xmlrpclib.ServerProxy(url) + except Exception, err: + print "Warning: Exception received while opening connection to Node Manager:", err + self.nm = None + + def close(self): + """ + Close connection to the local Node Manager + """ + + if self.nm is not None: + self.nm.close() + + def query(self, slice, attributes): + """ + Get values of various slice attributes from the local Node Manager + + slice - slice name + attributes - [attribute_name, (attribute_name, return_value_if_not_set), ...] + """ + + values = [None for attribute in attributes] + + if self.nm is not None: + try: + # Read rspec (the NM hash code for the slice) + rcap = open("/var/run/pl_nm/%s.vm_rcap" % slice, "r") + rspec = rcap.readline().strip() + rcap.close() + + for i, attribute in enumerate(attributes): + # NM interface allows you to pass in a tuple + # (attribute, default) instead of just an + # attribute name. default is returned if the + # attribute is not set. + if type(attribute) != tuple: + attribute = (attribute, 0) + (rc, (value,)) = self.nm.nm_inspect(rspec, [attribute]) + if rc == 0 and value != attribute[1]: + values[i] = value + except Exception, err: + print "Warning: Exception received while querying Node Manager:", err + + return values -- 2.43.0