#!/usr/local/bin/python import sys, os import re import tempfile import subprocess import logging import time import signal import util class local_segment: """ Base class for starting a segments on a local testbed accessed directly through commands rather than ssh connections. Code repository for executing commands with timeouts and other utility functions. """ class cmd_timeout(RuntimeError): pass def __init__(self, log=None, keyfile=None, debug=False): """ Parameters are a logger to use for updates, an unused key file, and a flag indicating that commands should not actually be carried out. """ self.log = log or logging.getLogger(\ 'fedd.access.proxy_emulab_segment') self.certfile = keyfile self.debug = debug self.cmd_timeout = local_segment.cmd_timeout def copy_file(self, src, dest, size=1024): """ Exceedingly simple file copy. """ if not self.debug: util.copy_file(src, dest, size) else: self.log.debug("Copy %s to %s" % (src, dest)) def cmd_with_timeout(self, cmd, wname=None, timeout=None): """ Run a command. If debug is set, the action is only logged. Commands are run without stdin, to avoid stray SIGTTINs. If timeout is given and the command runs longer, a cmd_timeout exception is thrown. """ try: dnull = open("/dev/null", "w") except EnvironmentError: self.log.debug("[cmd_with_timeout]: failed to open /dev/null " + \ "for redirect") dnull = Null self.log.debug("[cmd_with_timeout]: %s" % cmd) if not self.debug: if dnull: sub = subprocess.Popen(cmd, shell=True, stdout=dnull, stderr=dnull, close_fds=True) else: sub = subprocess.Popen(cmd, shell=True, close_fds=True) if timeout: i = 0 rv = sub.poll() while i < timeout: if rv is not None: break else: time.sleep(1) rv = sub.poll() i += 1 else: self.log.debug("Process exceeded runtime: %s" % cmd) os.kill(sub.pid, signal.SIGKILL) raise self.cmd_timeout(); return rv == 0 else: return sub.wait() == 0 else: if timeout == 0: self.log.debug("debug timeout raised on %s " % cmd) raise self.cmd_timeout() else: return True