Index: fedd/federation/experiment_control.py
===================================================================
--- fedd/federation/experiment_control.py	(revision e79498485b3ec2b8978dd39177a10fa7c472341a)
+++ fedd/federation/experiment_control.py	(revision 895a133b744bf8c1305194783b86b61ec6d114f0)
@@ -1097,84 +1097,28 @@
 
 
-    def create_experiment(self, req, fid):
-        """
-        The external interface to experiment creation called from the
-        dispatcher.
-
-        Creates a working directory, splits the incoming description using the
-        splitter script and parses out the avrious subsections using the
-        lcasses above.  Once each sub-experiment is created, use pooled threads
-        to instantiate them and start it all up.
-        """
-
-	def add_kit(e, kit):
-	    """
-	    Add a Software object created from the list of (install, location)
-	    tuples passed as kit  to the software attribute of an object e.  We
-	    do this enough to break out the code, but it's kind of a hack to
-	    avoid changing the old tuple rep.
-	    """
-
-	    s = [ topdl.Software(install=i, location=l) for i, l in kit]
-
-	    if isinstance(e.software, list): e.software.extend(s)
-	    else: e.software = s 
-
-
-        if not self.auth.check_attribute(fid, 'create'):
-            raise service_error(service_error.access, "Create access denied")
-
-        try:
-            tmpdir = tempfile.mkdtemp(prefix="split-")
-        except IOError:
-            raise service_error(service_error.internal, "Cannot create tmp dir")
-
-        gw_pubkey_base = "fed.%s.pub" % self.ssh_type
-        gw_secretkey_base = "fed.%s" % self.ssh_type
-        gw_pubkey = tmpdir + "/keys/" + gw_pubkey_base
-        gw_secretkey = tmpdir + "/keys/" + gw_secretkey_base
-        tclfile = tmpdir + "/experiment.tcl"
-        tbparams = { }
-        try:
-            access_user = self.accessdb[fid]
-        except KeyError:
-            raise service_error(service_error.internal,
-                    "Access map and authorizer out of sync in " + \
-                            "create_experiment for fedid %s"  % fid)
-
-        pid = "dummy"
-        gid = "dummy"
-        try:
-            os.mkdir(tmpdir+"/keys")
-        except OSError:
-            raise service_error(service_error.internal,
-                    "Can't make temporary dir")
-
-        req = req.get('CreateRequestBody', None)
-        if not req:
-            raise service_error(service_error.req,
-                    "Bad request format (no CreateRequestBody)")
-        # The tcl parser needs to read a file so put the content into that file
-        descr=req.get('experimentdescription', None)
-        if descr:
-            file_content=descr.get('ns2description', None)
-            if file_content:
-                try:
-                    f = open(tclfile, 'w')
-                    f.write(file_content)
-                    f.close()
-                except IOError:
-                    raise service_error(service_error.internal,
-                            "Cannot write temp experiment description")
-            else:
-                raise service_error(service_error.req, 
-                        "Only ns2descriptions supported")
-        else:
-            raise service_error(service_error.req, "No experiment description")
-
-        # Generate an ID for the experiment (slice) and a certificate that the
-        # allocator can use to prove they own it.  We'll ship it back through
-        # the encrypted connection.
-        (expid, expcert) = generate_fedid("test", dir=tmpdir, log=self.log)
+    def add_kit(self, e, kit):
+	"""
+	Add a Software object created from the list of (install, location)
+	tuples passed as kit  to the software attribute of an object e.  We
+	do this enough to break out the code, but it's kind of a hack to
+	avoid changing the old tuple rep.
+	"""
+
+	s = [ topdl.Software(install=i, location=l) for i, l in kit]
+
+	if isinstance(e.software, list): e.software.extend(s)
+	else: e.software = s 
+
+
+    def create_experiment_state(self, fid, req, expid, expcert):
+	"""
+	Create the initial entry in the experiment's state.  The expid and
+	expcert are the experiment's fedid and certifacte that represents that
+	ID, which are installed in the experiment state.  If the request
+	includes a suggested local name that is used if possible.  If the local
+	name is already taken by an experiment owned by this user that has
+	failed, it is overwriutten.  Otherwise new letters are added until a
+	valid localname is found.  The generated local name is returned.
+	"""
 
         if req.has_key('experimentID') and \
@@ -1233,4 +1177,360 @@
             self.state_lock.release()
 
+	return eid
+
+
+    def allocate_ips_to_topo(self, top):
+	"""
+	Add an ip4_address attribute to all the hosts in teh topology, based on
+	the shared substrates on which they sit.  An /etc/hosts file is also
+	created and returned as a list of hostfiles entries.
+	"""
+	subs = sorted(top.substrates, 
+		cmp=lambda x,y: cmp(len(x.interfaces), len(y.interfaces)),
+		reverse=True)
+	ips = ip_allocator(int(ip_addr("10.0.0.0")), 2 **24)
+	ifs = { }
+	hosts = [ ]
+
+	for idx, s in enumerate(subs):
+	    a = ips.allocate(len(s.interfaces)+2)
+	    if a :
+		base, num = a
+		if num < len(s.interfaces) +2 : 
+		    raise service_error(service_error.internal,
+			    "Allocator returned wrong number of IPs??")
+	    else:
+		raise service_error(service_error.req, 
+			"Cannot allocate IP addresses")
+
+	    base += 1
+	    for i in s.interfaces:
+		i.attribute.append(
+			topdl.Attribute('ip4_address', 
+			    "%s" % ip_addr(base)))
+		hname = i.element.name[0]
+		if ifs.has_key(hname):
+		    hosts.append("%s\t%s-%s %s-%d" % \
+			    (ip_addr(base), hname, s.name, hname,
+				ifs[hname]))
+		else:
+		    ifs[hname] = 0
+		    hosts.append("%s\t%s-%s %s-%d %s" % \
+			    (ip_addr(base), hname, s.name, hname,
+				ifs[hname], hname))
+
+		ifs[hname] += 1
+		base += 1
+	return hosts
+
+    def get_access_to_testbeds(self, testbeds, user, access_user, 
+	    export_project, master, allocated, tbparams):
+	"""
+	Request access to the various testbeds required for this instantiation
+	(passed in as testbeds).  User, access_user, expoert_project and master
+	are used to construct the correct requests.  Per-testbed parameters are
+	returned in tbparams.
+	"""
+	for tb in testbeds:
+	    self.get_access(tb, None, user, tbparams, master,
+		    export_project, access_user)
+	    allocated[tb] = 1
+
+    def split_topology(self, top, topo, testbeds, eid, master, tbparams):
+	"""
+	Create the sub-topologies that are needed for experimetn instantiation.
+	Along the way attach startup commands to the computers in the
+	subtopologies.
+	"""
+	for tb in testbeds:
+	    topo[tb] = top.clone()
+	    to_delete = [ ]
+	    for e in topo[tb].elements:
+		etb = e.get_attribute('testbed')
+		if etb and etb != tb:
+		    for i in e.interface:
+			for s in i.subs:
+			    try:
+				s.interfaces.remove(i)
+			    except ValueError:
+				raise service_error(service_error.internal,
+					"Can't remove interface??")
+		    to_delete.append(e)
+	    for e in to_delete:
+		topo[tb].elements.remove(e)
+	    topo[tb].make_indices()
+
+	    for e in [ e for e in topo[tb].elements \
+		    if isinstance(e,topdl.Computer)]:
+		if tb == master:
+		    cmd = 'sudo -H /usr/local/federation/bin/make_hosts /proj/%s/exp/%s/tmp/hosts >& /tmp/federate' % (tbparams[tb].get('project', 'project'), eid)
+		else:
+		    cmd = "sudo -H /bin/sh /usr/local/federation/bin/federate.sh >& /tmp/federate"
+		scmd = e.get_attribute('startup')
+		if scmd:
+		    cmd = "%s \\$USER '%s'" % (cmd, scmd)
+
+		e.set_attribute('startup', cmd)
+		if self.fedkit: self.add_kit(e, self.fedkit)
+
+    def add_portals(self, top, topo, eid, master, tbparams):
+	"""
+	For each substrate in the main topology, find those that
+	have nodes on more than one testbed.  Insert portal nodes
+	into the copies of those substrates on the sub topologies.
+	"""
+	for s in top.substrates:
+	    # tbs will contain an ip address on this subsrate that is in
+	    # each testbed.
+	    tbs = { }
+	    for i in s.interfaces:
+		e = i.element
+		tb = e.get_attribute('testbed')
+		if tb and not tbs.has_key(tb):
+		    for i in e.interface:
+			if s in i.subs:
+			    tbs[tb]= i.get_attribute('ip4_address')
+	    if len(tbs) < 2:
+		continue
+
+	    # More than one testbed is on this substrate.  Insert
+	    # some portals into the subtopologies.  st == source testbed,
+	    # dt == destination testbed.
+	    segment_substrate = { }
+	    for st in tbs.keys():
+		segment_substrate[st] = { }
+		for dt in [ t for t in tbs.keys() if t != st]:
+		    myname =  "%stunnel" % dt
+		    desthost  =  "%stunnel" % st
+		    sproject = tbparams[st].get('project', 'project')
+		    dproject = tbparams[dt].get('project', 'project')
+		    mproject = tbparams[master].get('project', 'project')
+		    sdomain = tbparams[st].get('domain', ".example.com")
+		    ddomain = tbparams[dt].get('domain', ".example.com")
+		    mdomain = tbparams[master].get('domain', '.example.com')
+		    muser = tbparams[master].get('user', 'root')
+		    smbshare = tbparams[master].get('smbshare', 'USERS')
+		    # XXX: active and type need to be unkludged
+		    active = ("%s" % (st == master))
+		    if not segment_substrate[st].has_key(dt):
+			# Put a substrate and a segment for the connected
+			# testbed in there.
+			tsubstrate = \
+				topdl.Substrate(name='%s-%s' % (st, dt),
+					attribute= [
+					    topdl.Attribute(
+						attribute='portal',
+						value='true')
+					    ]
+					)
+			segment_element = topdl.Segment(
+				id= tbparams[dt]['allocID'],
+				type='emulab',
+				uri = self.tbmap.get(dt, None),
+				interface=[ 
+				    topdl.Interface(
+					substrate=tsubstrate.name),
+				    ],
+				attribute = [
+				    topdl.Attribute(attribute=n, value=v)
+					for n, v in (\
+					    ('domain', ddomain),
+					    ('experiment', "%s/%s" % \
+						    (dproject, eid)),)
+				    ],
+				)
+			segment_substrate[st][dt] = tsubstrate
+			topo[st].substrates.append(tsubstrate)
+			topo[st].elements.append(segment_element)
+		    portal = topdl.Computer(
+			    name="%stunnel" % dt,
+			    attribute=[ 
+				topdl.Attribute(attribute=n,value=v)
+				    for n, v in (\
+					('portal', 'true'),
+					('domain', sdomain),
+					('masterdomain', mdomain),
+					('masterexperiment', "%s/%s" % \
+						(mproject, eid)),
+					('masteruser', muser),
+					('smbshare', smbshare),
+					('experiment', "%s/%s" % \
+						(sproject, eid)),
+					('peer', "%s" % desthost),
+					('peer_segment', "%s" % \
+						tbparams[dt]['allocID']['fedid']),
+					('scriptdir', 
+					    "/usr/local/federation/bin"),
+					('active', "%s" % active),
+					('portal_type', 'both'), 
+					('startup', 'sudo -H /usr/local/federation/bin/fed-tun.pl -f /proj/%s/exp/%s/tmp/%s.%s.%s%s.gw.conf >& /tmp/bridge.log' % (sproject, eid, myname.lower(), eid.lower(), sproject.lower(), sdomain.lower())))
+				],
+			    interface=[
+				topdl.Interface(
+				    substrate=s.name,
+				    attribute=[ 
+					topdl.Attribute(
+					    attribute='ip4_address', 
+					    value=tbs[dt]
+					)
+				    ]),
+				topdl.Interface(
+				    substrate=\
+					segment_substrate[st][dt].name,
+				    attribute=[
+					topdl.Attribute(attribute='portal',
+					    value='true')
+					]
+				    ),
+				],
+			    )
+		    if self.fedkit: self.add_kit(portal, self.fedkit)
+		    if self.gatewaykit: self.add_kit(portal, self.gatewaykit)
+
+		    topo[st].elements.append(portal)
+
+	# Connect the gateway nodes into the topologies and clear out
+	# substrates that are not in the topologies
+	for tb in tbparams.keys():
+	    topo[tb].incorporate_elements()
+	    topo[tb].substrates = \
+		    [s for s in topo[tb].substrates \
+			if len(s.interfaces) >0]
+
+    def wrangle_software(self, expid, top, topo, tbparams):
+	"""
+	Copy software out to the repository directory, allocate permissions and
+	rewrite the segment topologies to look for the software in local
+	places.
+	"""
+
+	# Copy the rpms and tarfiles to a distribution directory from
+	# which the federants can retrieve them
+	linkpath = "%s/software" %  expid
+	softdir ="%s/%s" % ( self.repodir, linkpath)
+	softmap = { }
+	# These are in a list of tuples format (each kit).  This comprehension
+	# unwraps them into a single list of tuples that initilaizes the set of
+	# tuples.
+	pkgs = set([ t for l in [self.fedkit, self.gatewaykit] \
+		for p, t in l ])
+	pkgs.update([x.location for e in top.elements \
+		for x in e.software])
+	try:
+	    os.makedirs(softdir)
+	except IOError, e:
+	    raise service_error(
+		    "Cannot create software directory: %s" % e)
+	# The actual copying.  Everything's converted into a url for copying.
+	for pkg in pkgs:
+	    loc = pkg
+
+	    scheme, host, path = urlparse(loc)[0:3]
+	    dest = os.path.basename(path)
+	    if not scheme:
+		if not loc.startswith('/'):
+		    loc = "/%s" % loc
+		loc = "file://%s" %loc
+	    try:
+		u = urlopen(loc)
+	    except Exception, e:
+		raise service_error(service_error.req, 
+			"Cannot open %s: %s" % (loc, e))
+	    try:
+		f = open("%s/%s" % (softdir, dest) , "w")
+		self.log.debug("Writing %s/%s" % (softdir,dest) )
+		data = u.read(4096)
+		while data:
+		    f.write(data)
+		    data = u.read(4096)
+		f.close()
+		u.close()
+	    except Exception, e:
+		raise service_error(service_error.internal,
+			"Could not copy %s: %s" % (loc, e))
+	    path = re.sub("/tmp", "", linkpath)
+	    # XXX
+	    softmap[pkg] = \
+		    "https://users.isi.deterlab.net:23232/%s/%s" %\
+		    ( path, dest)
+
+	    # Allow the individual segments to access the software.
+	    for tb in tbparams.keys():
+		self.auth.set_attribute(tbparams[tb]['allocID']['fedid'], 
+			"/%s/%s" % ( path, dest))
+
+	# Convert the software locations in the segments into the local
+	# copies on this host
+	for soft in [ s for tb in topo.values() \
+		for e in tb.elements \
+		    if getattr(e, 'software', False) \
+			for s in e.software ]:
+	    if softmap.has_key(soft.location):
+		soft.location = softmap[soft.location]
+
+
+    def create_experiment(self, req, fid):
+        """
+        The external interface to experiment creation called from the
+        dispatcher.
+
+        Creates a working directory, splits the incoming description using the
+        splitter script and parses out the avrious subsections using the
+        lcasses above.  Once each sub-experiment is created, use pooled threads
+        to instantiate them and start it all up.
+        """
+        if not self.auth.check_attribute(fid, 'create'):
+            raise service_error(service_error.access, "Create access denied")
+
+        try:
+            tmpdir = tempfile.mkdtemp(prefix="split-")
+            os.mkdir(tmpdir+"/keys")
+        except IOError:
+            raise service_error(service_error.internal, "Cannot create tmp dir")
+
+        gw_pubkey_base = "fed.%s.pub" % self.ssh_type
+        gw_secretkey_base = "fed.%s" % self.ssh_type
+        gw_pubkey = tmpdir + "/keys/" + gw_pubkey_base
+        gw_secretkey = tmpdir + "/keys/" + gw_secretkey_base
+        tclfile = tmpdir + "/experiment.tcl"
+        tbparams = { }
+        try:
+            access_user = self.accessdb[fid]
+        except KeyError:
+            raise service_error(service_error.internal,
+                    "Access map and authorizer out of sync in " + \
+                            "create_experiment for fedid %s"  % fid)
+
+        pid = "dummy"
+        gid = "dummy"
+
+        req = req.get('CreateRequestBody', None)
+        if not req:
+            raise service_error(service_error.req,
+                    "Bad request format (no CreateRequestBody)")
+        # The tcl parser needs to read a file so put the content into that file
+        descr=req.get('experimentdescription', None)
+        if descr:
+            file_content=descr.get('ns2description', None)
+            if file_content:
+                try:
+                    f = open(tclfile, 'w')
+                    f.write(file_content)
+                    f.close()
+                except IOError:
+                    raise service_error(service_error.internal,
+                            "Cannot write temp experiment description")
+            else:
+                raise service_error(service_error.req, 
+                        "Only ns2descriptions supported")
+        else:
+            raise service_error(service_error.req, "No experiment description")
+
+        # Generate an ID for the experiment (slice) and a certificate that the
+        # allocator can use to prove they own it.  We'll ship it back through
+        # the encrypted connection.
+        (expid, expcert) = generate_fedid("test", dir=tmpdir, log=self.log)
+
+	eid = self.create_experiment_state(fid, req, expid, expcert)
         try: 
             # This catches exceptions to clear the placeholder if necessary
@@ -1252,6 +1552,8 @@
             if not export_project:
                 raise service_error(service_error.req, "No export project")
-            
+           
+	    # Translate to topdl
             if self.splitter_url:
+		# XXX: need remote topdl translator
                 self.log.debug("Calling remote splitter at %s" % \
                         self.splitter_url)
@@ -1279,52 +1581,23 @@
                 split_data = tclparser.stdout
 
+	    top = topdl.topology_from_xml(file=split_data, top="experiment")
+
+	    hosts = self.allocate_ips_to_topo(top)
+	     # Find the testbeds to look up
+            testbeds = set([ a.value for e in top.elements \
+		    for a in e.attribute \
+		    if a.attribute == 'testbed'] )
+
             allocated = { }         # Testbeds we can access
-	    # Allocate IP addresses: The allocator is a buddy system memory
-	    # allocator.  Allocate from the largest substrate to the
-	    # smallest to make the packing more likely to work - i.e.
-	    # avoiding internal fragmentation.
-	    top = topdl.topology_from_xml(file=split_data, top="experiment")
-	    subs = sorted(top.substrates, 
-		    cmp=lambda x,y: cmp(len(x.interfaces), 
-			len(y.interfaces)),
-		    reverse=True)
-	    ips = ip_allocator(int(ip_addr("10.0.0.0")), 2 **24)
-	    ifs = { }
-	    hosts = [ ]
+	    topo ={ }		    # Sub topologies
+	    self.get_access_to_testbeds(testbeds, user, access_user, 
+		    export_project, master, allocated, tbparams)
+	    self.split_topology(top, topo, testbeds, eid, master, tbparams)
+
+	    # Copy configuration files into the remote file store
 	    # The config urlpath
 	    configpath = "/%s/config" % expid
 	    # The config file system location
 	    configdir ="%s%s" % ( self.repodir, configpath)
-
-	    for idx, s in enumerate(subs):
-		a = ips.allocate(len(s.interfaces)+2)
-		if a :
-		    base, num = a
-		    if num < len(s.interfaces) +2 : 
-			raise service_error(service_error.internal,
-				"Allocator returned wrong number of IPs??")
-		else:
-		    raise service_error(service_error.req, 
-			    "Cannot allocate IP addresses")
-
-		base += 1
-		for i in s.interfaces:
-		    i.attribute.append(
-			    topdl.Attribute('ip4_address', 
-				"%s" % ip_addr(base)))
-		    hname = i.element.name[0]
-		    if ifs.has_key(hname):
-			hosts.append("%s\t%s-%s %s-%d" % \
-				(ip_addr(base), hname, s.name, hname,
-				    ifs[hname]))
-		    else:
-			ifs[hname] = 0
-			hosts.append("%s\t%s-%s %s-%d %s" % \
-				(ip_addr(base), hname, s.name, hname,
-				    ifs[hname], hname))
-
-		    ifs[hname] += 1
-		    base += 1
-	    # save config files
 	    try:
 		os.makedirs(configdir)
@@ -1332,47 +1605,4 @@
 		raise service_error(
 			"Cannot create config directory: %s" % e)
-	    # Find the testbeds to look up
-	    testbeds = set([ a.value for e in top.elements \
-		    for a in e.attribute \
-			if a.attribute == 'testbed'] )
-
-
-	    # Make per testbed topologies.  Copy the main topo and remove
-	    # interfaces and nodes that don't live in the testbed.
-	    topo ={ }
-	    for tb in testbeds:
-		self.get_access(tb, None, user, tbparams, master,
-			export_project, access_user)
-		allocated[tb] = 1
-		topo[tb] = top.clone()
-		to_delete = [ ]
-		for e in topo[tb].elements:
-		    etb = e.get_attribute('testbed')
-		    if etb and etb != tb:
-			for i in e.interface:
-			    for s in i.subs:
-				try:
-				    s.interfaces.remove(i)
-				except ValueError:
-				    raise service_error(service_error.internal,
-					    "Can't remove interface??")
-			to_delete.append(e)
-		for e in to_delete:
-		    topo[tb].elements.remove(e)
-		topo[tb].make_indices()
-
-		for e in topo[tb].elements:
-		    if tb == master:
-			cmd = 'sudo -H /usr/local/federation/bin/make_hosts /proj/%s/exp/%s/tmp/hosts >& /tmp/federate' % (tbparams[tb].get('project', 'project'), eid)
-		    else:
-			cmd = "sudo -H /bin/sh /usr/local/federation/bin/federate.sh >& /tmp/federate"
-		    scmd = e.get_attribute('startup')
-		    if scmd:
-			cmd = "%s \\$USER '%s'" % (cmd, scmd)
-
-		    e.set_attribute('startup', cmd)
-		    if self.fedkit: add_kit(e, self.fedkit)
-
-	    # Copy configuration files into the remote file store
 	    try:
 		f = open("%s/hosts" % configdir, "w")
@@ -1397,184 +1627,6 @@
 		    self.auth.set_attribute(asignee, "%s/%s" % (configpath, f))
 
-	    # Now, for each substrate in the main topology, find those that
-	    # have nodes on more than one testbed.  Insert portal nodes
-	    # into the copies of those substrates on the sub topologies.
-	    for s in top.substrates:
-		# tbs will contain an ip address on this subsrate that is in
-		# each testbed.
-		tbs = { }
-		for i in s.interfaces:
-		    e = i.element
-		    tb = e.get_attribute('testbed')
-		    if tb and not tbs.has_key(tb):
-			for i in e.interface:
-			    if s in i.subs:
-				tbs[tb]= i.get_attribute('ip4_address')
-		if len(tbs) < 2:
-		    continue
-
-		# More than one testbed is on this substrate.  Insert
-		# some portals into the subtopologies.  st == source testbed,
-		# dt == destination testbed.
-		segment_substrate = { }
-		for st in tbs.keys():
-		    segment_substrate[st] = { }
-		    for dt in [ t for t in tbs.keys() if t != st]:
-			myname =  "%stunnel" % dt
-			desthost  =  "%stunnel" % st
-			sproject = tbparams[st].get('project', 'project')
-			dproject = tbparams[dt].get('project', 'project')
-			mproject = tbparams[master].get('project', 'project')
-			sdomain = tbparams[st].get('domain', ".example.com")
-			ddomain = tbparams[dt].get('domain', ".example.com")
-			mdomain = tbparams[master].get('domain', '.example.com')
-			muser = tbparams[master].get('user', 'root')
-			smbshare = tbparams[master].get('smbshare', 'USERS')
-			# XXX: active and type need to be unkludged
-			active = ("%s" % (st == master))
-			if not segment_substrate[st].has_key(dt):
-			    # Put a substrate and a segment for the connected
-			    # testbed in there.
-			    tsubstrate = \
-				    topdl.Substrate(name='%s-%s' % (st, dt),
-					    attribute= [
-						topdl.Attribute(
-						    attribute='portal',
-						    value='true')
-						]
-					    )
-			    segment_element = topdl.Segment(
-				    id= tbparams[dt]['allocID'],
-				    type='emulab',
-				    uri = self.tbmap.get(dt, None),
-				    interface=[ 
-					topdl.Interface(
-					    substrate=tsubstrate.name),
-					],
-				    attribute = [
-					topdl.Attribute(attribute=n, value=v)
-					    for n, v in (\
-						('domain', ddomain),
-						('experiment', "%s/%s" % \
-							(dproject, eid)),)
-					],
-				    )
-			    segment_substrate[st][dt] = tsubstrate
-			    topo[st].substrates.append(tsubstrate)
-			    topo[st].elements.append(segment_element)
-			portal = topdl.Computer(
-				name="%stunnel" % dt,
-				attribute=[ 
-				    topdl.Attribute(attribute=n,value=v)
-					for n, v in (\
-					    ('portal', 'true'),
-					    ('domain', sdomain),
-					    ('masterdomain', mdomain),
-					    ('masterexperiment', "%s/%s" % \
-						    (mproject, eid)),
-					    ('masteruser', muser),
-					    ('smbshare', smbshare),
-					    ('experiment', "%s/%s" % \
-						    (sproject, eid)),
-					    ('peer', "%s" % desthost),
-					    ('peer_segment', "%s" % \
-						    tbparams[dt]['allocID']['fedid']),
-					    ('scriptdir', 
-						"/usr/local/federation/bin"),
-					    ('active', "%s" % active),
-					    ('portal_type', 'both'), 
-					    ('startup', 'sudo -H /usr/local/federation/bin/fed-tun.pl -f /proj/%s/exp/%s/tmp/%s.%s.%s%s.gw.conf >& /tmp/bridge.log' % (sproject, eid, myname.lower(), eid.lower(), sproject.lower(), sdomain.lower())))
-				    ],
-				interface=[
-				    topdl.Interface(
-					substrate=s.name,
-					attribute=[ 
-					    topdl.Attribute(
-						attribute='ip4_address', 
-						value=tbs[dt]
-					    )
-					]),
-				    topdl.Interface(
-					substrate=\
-					    segment_substrate[st][dt].name,
-					attribute=[
-					    topdl.Attribute(attribute='portal',
-						value='true')
-					    ]
-					),
-				    ],
-				)
-			if self.fedkit: add_kit(portal, self.fedkit)
-			if self.gatewaykit: add_kit(portal, self.gatewaykit)
-
-			topo[st].elements.append(portal)
-
-	    # Connect the gateway nodes into the topologies and clear out
-	    # substrates that are not in the topologies
-	    for tb in testbeds:
-		topo[tb].incorporate_elements()
-		topo[tb].substrates = \
-			[s for s in topo[tb].substrates \
-			    if len(s.interfaces) >0]
-
-	    # Copy the rpms and tarfiles to a distribution directory from
-	    # which the federants can retrieve them
-	    linkpath = "%s/software" %  expid
-	    softdir ="%s/%s" % ( self.repodir, linkpath)
-	    softmap = { }
-	    pkgs = set([ t for l in [self.fedkit, self.gatewaykit] \
-		    for p, t in l ])
-	    pkgs.update([x.location for e in top.elements \
-		    for x in e.software])
-	    try:
-		os.makedirs(softdir)
-	    except IOError, e:
-		raise service_error(
-			"Cannot create software directory: %s" % e)
-	    for pkg in pkgs:
-		loc = pkg
-
-		scheme, host, path = urlparse(loc)[0:3]
-		dest = os.path.basename(path)
-		if not scheme:
-		    if not loc.startswith('/'):
-			loc = "/%s" % loc
-		    loc = "file://%s" %loc
-		try:
-		    u = urlopen(loc)
-		except Exception, e:
-		    raise service_error(service_error.req, 
-			    "Cannot open %s: %s" % (loc, e))
-		try:
-		    f = open("%s/%s" % (softdir, dest) , "w")
-		    self.log.debug("Writing %s/%s" % (softdir,dest) )
-		    data = u.read(4096)
-		    while data:
-			f.write(data)
-			data = u.read(4096)
-		    f.close()
-		    u.close()
-		except Exception, e:
-		    raise service_error(service_error.internal,
-			    "Could not copy %s: %s" % (loc, e))
-		path = re.sub("/tmp", "", linkpath)
-		# XXX
-		softmap[pkg] = \
-			"https://users.isi.deterlab.net:23232/%s/%s" %\
-			( path, dest)
-
-		# Allow the individual testbeds to access the software.
-		for tb in tbparams.keys():
-		    self.auth.set_attribute(tbparams[tb]['allocID']['fedid'], 
-			    "/%s/%s" % ( path, dest))
-
-	    # Convert the software locations in the segments into the local
-	    # copies on this host
-	    for soft in [ s for tb in topo.values() \
-		    for e in tb.elements \
-			if getattr(e, 'software', False) \
-			    for s in e.software ]:
-		if softmap.has_key(soft.location):
-		    soft.location = softmap[soft.location]
+	    self.add_portals(top, topo, eid, master, tbparams)
+	    self.wrangle_software(expid, top, topo, tbparams)
 
 	    vtopo = topdl.topology_to_vtopo(top)
