Index: fedd/federation/proxy_emulab_segment.py
===================================================================
--- fedd/federation/proxy_emulab_segment.py	(revision d3c8759502763e1a406b71e373ebea94021c6a05)
+++ fedd/federation/proxy_emulab_segment.py	(revision 5bf359d154de55a0b87fd796ccc5922453667777)
@@ -14,4 +14,11 @@
 
 class start_segment(proxy_segment):
+    """
+    This starts an experiment on an emulab accessed remotely via ssh.  Most of
+    the experiment constuction has been done by the emulab_access object.  This
+    just does the wrangling of the emulab commands and collected the node to
+    physical mapping.  The routine throws service errors.
+    """
+
     def __init__(self, log=None, keyfile=None, debug=False):
 	proxy_segment.__init__(self, log=log, keyfile=keyfile, debug=debug)
@@ -28,4 +35,7 @@
 
     def get_state(self, user, host, pid, eid):
+	"""
+	Return the state of the experiment as reported by emulab
+	"""
 	# command to test experiment state
 	expinfo_exec = "/usr/testbed/bin/expinfo"  
@@ -80,4 +90,8 @@
 
     def get_mapping(self, user, host, pid, eid):
+	"""
+	Get the physical to virtual mapping from the expinfo command and save
+	it in the self.map member.
+	"""
 	# command to test experiment state
 	expinfo_exec = "/usr/testbed/bin/expinfo"  
@@ -143,14 +157,43 @@
 
 
-    def __call__(self, parent, eid, pid, user, tclfile, tmpdir, timeout=0):
-	"""
-	Start a sub-experiment on a federant.
-
-	Get the current state, modify or create as appropriate, ship data
-	and configs and start the experiment.  There are small ordering
-	differences based on the initial state of the sub-experiment.
-	"""
-	# ops node in the federant
-	host = "%s%s" % (parent.ops, parent.domain)
+    def make_null_experiment(self, user, host, pid, eid, tmpdir):
+	"""
+	Create a null copy of the experiment so that we capture any logs there
+	if the modify fails.  Emulab software discards the logs from a failed
+	startexp
+	"""
+	try:
+	    f = open("%s/null.tcl" % tmpdir, "w")
+	    print >>f, self.null
+	    f.close()
+	except EnvironmentError, e:
+	    raise service_error(service_error.internal,
+		    "Cannot stage tarfile/rpm: %s" % e.strerror)
+
+	if not self.scp_file("%s/null.tcl" % tmpdir, user, host):
+	    return False
+	self.log.info("[start_segment]: Creating %s" % eid)
+	timedout = False
+	try:
+	    if not self.ssh_cmd(user, host,
+		    ("/usr/testbed/bin/startexp -i -f -w -p %s " + 
+		    "-e %s null.tcl") % (pid, eid), "startexp",
+		    timeout=60 * 10):
+		return False
+	except self.ssh_cmd_timeout:
+	    timedout = True
+
+	if timedout:
+	    state = self.get_state(user, host, pid, eid)
+	    if state != "swapped":
+		return False
+	return True
+
+    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)
@@ -159,39 +202,4 @@
 	lsoftdir = "%s/software" % tmpdir
 
-	state = self.get_state(user, host, pid, eid)
-
-	if not self.scp_file(tclfile, user, host):
-	    return False
-	
-	if state == 'none':
-	    # Create a null copy of the experiment so that we capture any
-	    # logs there if the modify fails.  Emulab software discards the
-	    # logs from a failed startexp
-	    try:
-		f = open("%s/null.tcl" % tmpdir, "w")
-		print >>f, self.null
-		f.close()
-	    except EnvironmentError, e:
-		raise service_error(service_error.internal,
-			"Cannot stage tarfile/rpm: %s" % e.strerror)
-
-	    if not self.scp_file("%s/null.tcl" % tmpdir, user, host):
-		return False
-	    self.log.info("[start_segment]: Creating %s" % eid)
-	    timedout = False
-	    try:
-		if not self.ssh_cmd(user, host,
-			("/usr/testbed/bin/startexp -i -f -w -p %s " + 
-			"-e %s null.tcl") % (pid, eid), "startexp",
-			timeout=60 * 10):
-		    return False
-	    except self.ssh_cmd_timeout:
-		timedout = True
-
-	    if timedout:
-		state = self.get_state(user, host, pid, eid)
-		if state != "swapped":
-		    return False
-	
 	# Open up a temporary file to contain a script for setting up the
 	# filespace for the new experiment.
@@ -237,6 +245,59 @@
 			    user, host, "%s/%s" % (softdir, f)):
 			return False
-	# Stage the new configuration (active experiments will stay swapped
-	# in now)
+	return True
+
+    def swap_in(self, user, host, pid, eid):
+	"""
+	Swap experiment in.  This includes code to cope with the experiment
+	swaping command timing out, but the experiment being swapped in
+	successfully.
+	"""
+	self.log.info("[start_segment]: Swapping %s in" % eid)
+	timedout = False
+	try:
+	    if not self.ssh_cmd(user, host,
+		    "/usr/testbed/bin/swapexp -w %s %s in" % (pid, eid),
+		    "swapexp", timeout=25*60):
+		return False
+	except self.ssh_cmd_timeout:
+	    timedout = True
+       
+	# If the command was terminated, but completed successfully,
+	# report success.
+	if timedout:
+	    self.log.debug("[start_segment]: swapin timed out " +\
+		    "checking state")
+	    state = self.get_state(user, host, pid, eid)
+	    self.log.debug("[start_segment]: state is %s" % state)
+	    return state == 'active'
+
+	return True
+
+
+    def __call__(self, parent, eid, pid, user, tclfile, tmpdir, timeout=0):
+	"""
+	Start a sub-experiment on a federant.
+
+	Get the current state, modify or create as appropriate, ship data
+	and configs and start the experiment.  There are small ordering
+	differences based on the initial state of the sub-experiment.
+	"""
+	# ops node in the federant
+	host = "%s%s" % (parent.ops, parent.domain)
+	state = self.get_state(user, host, pid, eid)
+
+	if not self.scp_file(tclfile, user, host):
+	    return False
+	
+	if state == 'none':
+	    # Put a dummy in place to capture logs, and establish an experiment
+	    # directory.
+	    if not self.make_null_experiment(user, host, pid, eid, tmpdir):
+		return False
+
+	if not self.set_up_experiment_filespace(user, host, pid, eid, tmpdir):
+	    return False
+
+	# With the filespace in place, we can modify and swap in.
 	self.log.info("[start_segment]: Modifying %s" % eid)
 	try:
@@ -253,22 +314,6 @@
 	# Active experiments are still swapped, this swaps the others in.
 	if state != 'active':
-	    self.log.info("[start_segment]: Swapping %s" % eid)
-	    timedout = False
-	    try:
-		if not self.ssh_cmd(user, host,
-			"/usr/testbed/bin/swapexp -w %s %s in" % (pid, eid),
-			"swapexp", timeout=25*60):
-		    return False
-	    except self.ssh_cmd_timeout:
-		timedout = True
-	   
-	    # If the command was terminated, but completed successfully,
-	    # report success.
-	    if timedout:
-		self.log.debug("[start_segment]: swapin timed out " +\
-			"checking state")
-		state = self.get_state(user, host, pid, eid)
-		self.log.debug("[start_segment]: state is %s" % state)
-		return state == 'active'
+	    if not self.swap_in(user, host, pid, eid):
+		return False
 	# Everything has gone OK.
 	self.get_mapping(user, host, pid,eid)
