Index: fedd/federation/experiment_control.py
===================================================================
--- fedd/federation/experiment_control.py	(revision ab662b6e68237865fbfcf2777c49069db4b7c07e)
+++ fedd/federation/experiment_control.py	(revision 9a52a804872b18f4b016e8b67146d63eb1717aaf)
@@ -44,4 +44,5 @@
 from deter import ip_allocator
 from deter import ip_addr
+from deter import topology_to_route_file
 import list_log
 
@@ -137,4 +138,5 @@
 		or 'legacy'
 	self.auth_dir = config.get('experiment_control', 'auth_dir')
+	self.routing = config.get('experiment_control', 'routing')
 	# XXX: document this!
 	self.info_cache_limit = \
@@ -1204,6 +1206,4 @@
 
 	for p, a in attrs:
-	    # PNNL Debug
-	    self.log.debug("Append auth: %s %s" % (p, a))
 	    if p and a:
 		# Improperly configured overrides can add bad principals.
@@ -1623,6 +1623,4 @@
 	"""
 
-	# XXX: PNNL debug
-	self.log.debug("calling wrangle software")
 	# Copy the rpms and tarfiles to a distribution directory from
 	# which the federants can retrieve them
@@ -1637,9 +1635,5 @@
 	pkgs.update([x.location for e in top.elements for x in e.software])
 	try:
-	    # XXX: PNNL debug
-	    self.log.debug("wrangle software: makedirs")
 	    os.makedirs(softdir)
-	    # XXX: PNNL debug
-	    self.log.debug("wrangle software: makedirs success")
 	except EnvironmentError, e:
 	    raise service_error(
@@ -1961,7 +1955,8 @@
 	Create the ssh keys necessary for interconnecting the portal nodes and
 	the global hosts file for letting each segment know about the IP
-	addresses in play.  Save these into the repo.  Add attributes to the
-	autorizer allowing access controllers to download them and return a set
-	of attributes that inform the segments where to find this stuff.  May
+	addresses in play.  If we have computed static routes, copy them into
+	the repo. Save these into the repo.  Add attributes to the autorizer
+	allowing access controllers to download them and return a set of
+	attributes that inform the segments where to find this stuff.  May
 	raise service_errors in if there are problems.
 	"""
@@ -1971,4 +1966,5 @@
         gw_pubkey = os.path.join(keydir, gw_pubkey_base)
         gw_secretkey = os.path.join(keydir, gw_secretkey_base)
+	route = os.path.join(tmpdir, 'route.tgz')
 
 	try:
@@ -1985,4 +1981,5 @@
 	# The config file system location
 	configdir ="%s%s" % ( self.repodir, configpath)
+	route_conf = os.path.join(configdir, 'route.tgz')
 	try:
 	    os.makedirs(configdir)
@@ -1998,4 +1995,7 @@
 		    "Cannot write hosts file: %s" % e)
 	try:
+	    if os.path.exists(route):
+		copy_file(route, route_conf)
+
 	    copy_file(gw_pubkey, os.path.join(configdir, gw_pubkey_base))
 	    copy_file(gw_secretkey, os.path.join(configdir, gw_secretkey_base))
@@ -2014,5 +2014,5 @@
 	    (tbparams[tb].allocID, "%s/%s" % (configpath, f)) \
 		    for tb in tbparams.keys() \
-			for f in ("hosts", 'ca.pem', 'node.pem', 
+			for f in ("hosts", 'ca.pem', 'node.pem', 'route.tgz',
 			    gw_secretkey_base, gw_pubkey_base)]))
 
@@ -2044,4 +2044,13 @@
 		},
 	    ]
+	# Add info about static routes if we have some
+	if os.path.exists(route_conf):
+	    attrs.append(
+		{
+		    'attribute': 'route.tgz', 
+		    'value': '%s/%s/config/%s' % \
+			    (self.repo_url, expid, 'route.tgz')
+		}
+	    )
 	return attrs
 
@@ -2170,4 +2179,42 @@
                 raise service_error(service_error.req, "No such experiment")
 
+    @staticmethod
+    def needs_route_computation(req):
+	'''
+	Walk the request services looking for a static routing request
+	'''
+	for s in req.get('service', []):
+	    if s.get('name', '') == 'static_routing':
+		return True
+	return False
+
+    def compute_static_routes(self, tmpdir, top):
+	'''
+	Compute a set of static routes for the topology.  The result is a file
+	called route.tgz in tmpdir that contains a dinrectory, route, with a
+	file per node in the topology that lists the prefix and router for all
+	the routes in that node's routing table.  Exceptions from the route
+	calculation program and the tar creation call are not caught.
+	'''
+	if self.routing is None:
+	    raise service_error(service_error.server, 
+		    'Cannot provide staticroutes, no routing program specified')
+	rg = tempfile.NamedTemporaryFile()
+	outdir = os.path.join(tmpdir, 'route')
+	tarfile = os.path.join(tmpdir, 'route.tgz')
+	topology_to_route_file(top, file=rg)
+	os.mkdir(outdir)
+	try:
+	    for cmd in (
+		    [self.routing, '--input', rg.name,'--output', outdir],
+		    ['tar', '-C', tmpdir, '-czf', tarfile, 'route']):
+		subprocess.check_call(cmd)
+	except subprocess.CalledProcessError, e:
+	    raise service_error(service_error.internal, 
+		    'Cannot call %s: %s' % (' '.join(cmd), e.returncode))
+	rg.close()
+	shutil.rmtree(outdir)
+
+
     
     def save_federant_information(self, allocated, tbparams, eid, top):
@@ -2279,4 +2326,6 @@
 	    # Assign the IPs
 	    hosts, ip_allocator = self.allocate_ips_to_topo(top)
+	    if self.needs_route_computation(req):
+		self.compute_static_routes(tmpdir, top)
 	    # Find the testbeds to look up
 	    tb_hosts = { }
@@ -2284,5 +2333,11 @@
 	    for e in top.elements:
 		if isinstance(e, topdl.Computer):
-		    tb = e.get_attribute('testbed') or 'default'
+		    tb = e.get_attribute('testbed')
+		    # Put nodes not in a testbed into the 'default' testbed if
+		    # 'default' is in the fedd map, the instantiation will
+		    # work.
+		    if tb is None:
+			tb = 'default'
+			e.set_attribute('testbed', tb)
 		    if tb in tb_hosts: tb_hosts[tb].append(e.name)
 		    else: 
@@ -2306,6 +2361,4 @@
 
 	    attrs = self.generate_keys_and_hosts(tmpdir, expid, hosts, tbparams)
-	    # XXX: PNNL debug
-	    self.log.debug("Back from generate keys")
 
 	    part = experiment_partition(self.auth, self.store_url, tbmap,
@@ -2313,12 +2366,8 @@
 	    part.add_portals(top, topo, eid, pmasters, tbparams, ip_allocator,
 		    connInfo, expid)
-	    # XXX: PNNL debug
-	    self.log.debug("Back from add portals")
 
 	    auth_attrs = set()
 	    # Now get access to the dynamic testbeds (those added above)
 	    for tb in [ t for t in topo if t not in allocated]:
-		# XXX: PNNL debug
-		self.log.debug("dynamic testbeds %s" %tb)
 		self.get_access(tb, tbparams, fid, masters, tbmap, 
 			expid, expcert_file)
@@ -2331,6 +2380,4 @@
 				for sk in store_keys.split(" ")]))
 
-	    # XXX: PNNL debug
-	    self.log.debug("done with dynamic testbeds %s" % auth_attrs)
 	    if auth_attrs:
 		self.append_experiment_authorization(expid, auth_attrs)
