Index: fedd/federation/benito_segment.py
===================================================================
--- fedd/federation/benito_segment.py	(revision 6a50b78172df7385895b43b3da46f5b4447e4d50)
+++ fedd/federation/benito_segment.py	(revision 6a50b78172df7385895b43b3da46f5b4447e4d50)
@@ -0,0 +1,195 @@
+#!/usr/local/bin/python
+
+import sys, os
+import re
+import os.path
+
+import tempfile
+import subprocess
+import logging 
+import time
+import signal
+
+import util
+
+from deter import topdl
+
+from ssh_emulab_segment import ssh_emulab_segment
+from xmlrpc_emulab_segment import xmlrpc_emulab_segment
+
+
+class start_segment(ssh_emulab_segment, xmlrpc_emulab_segment):
+    def __init__(self, log=None, keyfile=None, debug=False, boss=None,
+	    ops=None, cert=None):
+	ssh_emulab_segment.__init__(self, log=log, keyfile=keyfile, debug=debug)
+	xmlrpc_emulab_segment.__init__(self, boss=boss, ops=ops, cert=cert)
+	self.start_mixed = '/share/benito/start_mixed %s %s %s'
+	self.start_qemu =  '/share/benito/start_qemu %s %s %s'
+
+    def get_mapping(self, pid, eid):
+	"""
+	Benito's info reporting is not sufficient to support this yet
+	"""
+	pass
+
+    def set_up_experiment_filespace(self, user, host, pid, eid, tmpdir):
+	"""
+	Send all the software and configuration files into the experiment's
+	file space.  To reduce the number of ssh connections, we script many
+	changes and execute the script.
+	"""
+	# Configuration directories on the remote machine
+	proj_dir = "/proj/%s/exp/%s/tmp" % (pid, eid)
+	softdir = "/proj/%s/software/%s" % (pid, eid)
+	# Local software dir
+	lsoftdir = "%s/software" % tmpdir
+
+	# Open up a temporary file to contain a script for setting up the
+	# filespace for the new experiment.
+	self.log.info("[start_segment]: creating script file")
+	try:
+	    sf, scriptname = tempfile.mkstemp()
+	    scriptfile = os.fdopen(sf, 'w')
+	except EnvironmentError:
+	    return False
+
+	scriptbase = os.path.basename(scriptname)
+
+	# Script the filesystem changes
+	print >>scriptfile, "/bin/rm -rf %s" % proj_dir
+	# Clear and create the software directory
+	print >>scriptfile, "/bin/rm -rf %s/*" % softdir
+	print >>scriptfile, 'mkdir -p %s' % proj_dir
+	if os.path.isdir(lsoftdir):
+	    print >>scriptfile, 'mkdir -p %s' % softdir
+	print >>scriptfile, "rm -f %s" % scriptbase
+	scriptfile.close()
+
+	# Move the script to the remote machine
+	# XXX: could collide tempfile names on the remote host
+	if self.scp_file(scriptname, user, host, scriptbase):
+	    os.remove(scriptname)
+	else:
+	    return False
+
+	# Execute the script (and the script's last line deletes it)
+	if not self.ssh_cmd(user, host, "sh -x %s" % scriptbase):
+	    return False
+
+	for f in os.listdir(tmpdir):
+	    if not os.path.isdir("%s/%s" % (tmpdir, f)):
+		if not self.scp_file("%s/%s" % (tmpdir, f), user, host,
+			"%s/%s" % (proj_dir, f)):
+		    return False
+	if os.path.isdir(lsoftdir):
+	    for f in os.listdir(lsoftdir):
+		if not os.path.isdir("%s/%s" % (lsoftdir, f)):
+		    if not self.scp_file("%s/%s" % (lsoftdir, f), 
+			    user, host, "%s/%s" % (softdir, f)):
+			return False
+	return True
+
+
+    def __call__(self, parent, eid, pid, user, tclfile, tmpdir, timeout=0, 
+	    gid=None):
+	"""
+	Start a sub-experiment on a federant.
+
+	Get the current state, and terminate the experiment if it exists. The
+	group membership of the experiment is difficult to determine or change,
+	so start with a clean slate.  Create a new one and ship data
+	and configs and start the experiment.  There are small ordering
+	differences based on the initial state of the sub-experiment.
+	"""
+
+	# benito listens to the filename extension.  tclfile here is really
+	# topdl, but we'll move it to a different filename.
+	if tclfile.endswith('.tcl'):
+	    topdlfile = os.path.join(tmpdir, 'experiment.xml')
+	    os.rename(tclfile, topdlfile)
+	else:
+	    topdlfile = tclfile
+
+
+	state = self.get_state(pid, eid)
+
+	if state != 'none':
+	    self.terminate_exp(pid, eid)
+
+	top = topdl.topology_from_xml(filename=topdlfile, top='experiment')
+	embedded = False
+	for e in top.elements:
+	    if isinstance(e, topdl.Computer) and \
+		    e.get_attribute('partition') is not None:
+		embedded = True
+		break
+	# on the for
+	else:
+	    embedded = False
+
+	if embedded:
+	    cmd = self.start_mixed  %  (pid, eid, topdlfile)
+	else:
+	    cmd = self.start_qemu % (pid, eid, topdlfile, 20)
+
+	if not self.ssh_cmd(user, self.ops, cmd):
+	    self.log.error("Cannot create benito experiment")
+	    return False
+
+	if not self.swap_exp(pid, eid, 'in'):
+	    self.log.error("swap in failed")
+	    return False
+	# Everything has gone OK.
+	self.get_mapping(pid,eid)
+	return True
+
+class stop_segment(ssh_emulab_segment, xmlrpc_emulab_segment):
+    def __init__(self, log=None, keyfile=None, debug=False, boss=None, 
+	    ops=None, cert=None):
+	ssh_emulab_segment.__init__(self, log=log, keyfile=keyfile, debug=debug)
+	xmlrpc_emulab_segment.__init__(self, boss=boss, ops=ops, cert=cert)
+
+    def __call__(self, parent, user, pid, eid, gid=None, terminate=False):
+	"""
+	Stop a sub experiment by calling swapexp on the federant
+	"""
+
+	self.log.info("[stop_segment]: Stopping %s" % eid)
+	rv = False
+	try:
+	    # Clean out tar files: we've gone over quota in the past
+	    self.ssh_cmd(user, self.ops, 
+		    "rm -rf /proj/%s/software/%s" % (pid, eid))
+	    rv = self.swap_exp(pid, eid, 'out')
+	    if terminate:
+		rv = self.terminate_exp(pid, eid)
+	except self.cmd_timeout:
+	    rv = False
+	return rv
+
+class info_segment(ssh_emulab_segment, xmlrpc_emulab_segment):
+    def __init__(self, log=None, keyfile=None, debug=False, boss=None, 
+	    ops=None, cert=None):
+	ssh_emulab_segment.__init__(self, log=log, keyfile=keyfile, debug=debug)
+	xmlrpc_emulab_segment.__init__(self, boss=boss, ops=ops, cert=cert)
+
+    def get_mapping(self, pid, eid):
+	"""
+	Benito's info reporting is not sufficient to support this yet
+	"""
+	pass
+
+    def __call__(self, parent, user, pid, eid):
+	self.log.info("[info_segment]: Getting info from %s" % eid)
+	self.get_mapping(pid,eid)
+	return True
+
+class operation_segment(ssh_emulab_segment, xmlrpc_emulab_segment):
+    def __init__(self, log=None, keyfile=None, debug=False, boss=None, 
+	    ops=None, cert=None):
+	ssh_emulab_segment.__init__(self, log=log, keyfile=keyfile, debug=debug)
+	xmlrpc_emulab_segment.__init__(self, boss=boss, ops=ops, cert=cert)
+
+    def __call__(self, parent, op, targets, param, top):
+	self.status.append('operations not yet supported')
+	return True
