- utility functions common to swapmon and bwmon
authorMark Huang <mlhuang@cs.princeton.edu>
Fri, 28 Apr 2006 19:27:43 +0000 (19:27 +0000)
committerMark Huang <mlhuang@cs.princeton.edu>
Fri, 28 Apr 2006 19:27:43 +0000 (19:27 +0000)
pl_mom.py [new file with mode: 0644]

diff --git a/pl_mom.py b/pl_mom.py
new file mode 100644 (file)
index 0000000..532dfd5
--- /dev/null
+++ b/pl_mom.py
@@ -0,0 +1,220 @@
+#!/usr/bin/python
+#
+# Utility functions
+#
+# Mark Huang <mlhuang@cs.princeton.edu>
+# 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