--- /dev/null
+#!/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