Index: fedd/federation/emulab_access.py
===================================================================
--- fedd/federation/emulab_access.py	(revision 35aa3ae74d9953faf6d76c4d7f5e24359a260a0e)
+++ fedd/federation/emulab_access.py	(revision e02cd14c76fe2382e62f5e57ea53b1c682bf200c)
@@ -100,4 +100,7 @@
         set_log_level(config, "access", self.log)
         self.state_lock = Lock()
+	# XXX: Configurable
+	self.exports = set(('SMB', 'seer', 'tmcd'))
+	self.imports = set(('SMB', 'seer', 'tmcd'))
 
         if auth: self.auth = auth
@@ -485,5 +488,30 @@
                 owners
 
-    def build_response(self, alloc_id, ap):
+    def export_services(self, sreq, project, user):
+	exp = [ ]
+	# XXX: Filthy shortcut here using http so urlparse will give the right
+	# answers.
+	for s in sreq:
+	    sname = s.get('name', '')
+	    svis = s.get('visibility', '')
+	    if svis == 'export':
+		if sname in self.exports:
+		    outs = s.copy()
+		    if sname == 'SMB':
+			outs = s.copy()
+			outs['server'] = "http://fs:139" 
+			outs['fedAttr'] = [
+				{ 'attribute': 'SMBSHARE', 'value': 'USERS' },
+				{ 'attribute': 'SMBUSER', 'value': user },
+				{ 'attribute': 'SMBPROJ', 'value': project },
+			    ]
+		    elif sname == 'seer':
+			outs['server'] = "http://control:16606"
+		    elif sname == 'tmcd':
+			outs['server'] = "http://boss:7777"
+		    exp.append(outs)
+	return exp
+
+    def build_response(self, alloc_id, ap, services):
         """
         Create the SOAP response.
@@ -508,4 +536,7 @@
                 [ { 'attribute': x, 'value' : y } \
                         for x,y in self.attrs.iteritems()])
+
+	if services:
+	    msg['service'] = services
         return msg
 
@@ -676,5 +707,4 @@
                         "Misformed allocation response?")
 
-
             self.allocation[aid]['owners'] = owners
             self.write_state()
@@ -689,5 +719,6 @@
 		raise service_error(service_error.internal, 
 			"Can't open %s/%s : %s" % (self.certdir, aid, e))
-            resp = self.build_response({ 'fedid': allocID } , ap)
+	    services = self.export_services(req.get('service',[]), pname, uname)
+            resp = self.build_response({ 'fedid': allocID } , ap, services)
             return resp
         else:
@@ -819,5 +850,57 @@
 
     def generate_portal_configs(self, topo, pubkey_base, secretkey_base, 
-	    tmpdir, master):
+	    tmpdir, master, lproj, leid, connInfo, services):
+
+	def conninfo_to_dict(key, info):
+	    """
+	    Make a cpoy of the connection information about key, and flatten it
+	    into a single dict by parsing out any feddAttrs.
+	    """
+
+	    rv = None
+	    for i in info:
+		if i.get('portal', "") == key:
+		    rv = i.copy()
+		    break
+	    else:
+		return rv
+
+	    if 'fedAttr' in rv:
+		for a in rv['fedAttr']:
+		    attr = a.get('attribute', "")
+		    val = a.get('value', "")
+		    if attr and attr not in rv:
+			rv[attr] = val
+		del rv['fedAttr']
+	    return rv
+
+	# XXX: un hardcode this
+	def client_null(f, s): pass
+
+	def client_smb(f, s):
+	    smbshare = None
+	    smbuser = None
+	    smbproj = None
+	    for a in s.get('fedAttr', []):
+		if a.get('attribute', '') == 'SMBSHARE':
+		    smbshare = a.get('value', None)
+		elif a.get('attribute', '') == 'SMBUSER':
+		    smbuser = a.get('value', None)
+		elif a.get('attribute', '') == 'SMBPROJ':
+		    smbproj = a.get('value', None)
+
+	    if all((smbshare, smbuser, smbproj)):
+		print >>f, "SMBshare: %s" % smbshare
+		print >>f, "ProjectUser: %s" % smbuser
+		print >>f, "ProjectName: %s" % smbproj
+
+	client_service_out = {
+		'SMB': client_smb,
+		'tmcd': client_null,
+		'seer': client_null,
+		'userconfig': client_null,
+	    }
+	# XXX: end un hardcode this
+
 
 	seer_out = False
@@ -826,30 +909,24 @@
 		if isinstance(e, topdl.Computer) and e.get_attribute('portal')]:
 	    myname = e.name[0]
-	    peer = e.get_attribute('peer')
-	    lexp = e.get_attribute('experiment')
-	    lproj, leid = lexp.split('/', 1)
-	    ldomain = e.get_attribute('domain')
-	    mexp = e.get_attribute('masterexperiment')
+	    type = e.get_attribute('portal_type')
+
+	    info = conninfo_to_dict(myname, connInfo)
+
+	    if not info:
+		raise service_error(service_error.req,
+			"No connectivity info for %s" % myname)
+
+	    peer = info.get('peer', "")
+	    ldomain = self.domain;
+
+	    mexp = info.get('masterexperiment',"")
 	    mproj, meid = mexp.split("/", 1)
-	    mdomain = e.get_attribute('masterdomain')
-	    muser = e.get_attribute('masteruser') or 'root'
-	    smbshare = e.get_attribute('smbshare') or 'USERS'
-	    scriptdir = e.get_attribute('scriptdir')
-	    active = e.get_attribute('active')
-	    type = e.get_attribute('portal_type')
-	    segid = fedid(hexstr=e.get_attribute('peer_segment'))
-	    for e in topo.elements:
-		if isinstance(e, topdl.Segment) and e.id.fedid == segid:
-		    seg = e
-		    break
-	    else:
-		raise service_error(service_error.req, 
-			"Can't find segment for portal %s" % myname)
-
-	    is_ip = re.match('\d+\.\d+\.\d+\.\d+', peer)
-
-	    rexp = seg.get_attribute('experiment')
-	    rproj, reid = rexp.split("/", 1)
-	    rdomain = seg.get_attribute('domain')
+	    mdomain = info.get('masterdomain',"")
+	    muser = info.get('masteruser','root')
+	    smbshare = info.get('smbshare', 'USERS')
+
+	    active = info.get('active', 'False')
+
+
 	    cfn = "%s/%s.gw.conf" % (tmpdir, myname.lower())
 	    tunnelconfig = self.attrs.has_key('TunnelCfg')
@@ -857,20 +934,17 @@
 		f = open(cfn, "w")
 		if active == 'True':
-		    print >>f, "active: %s" % active
 		    if type in ('control', 'both'):
-			print >>f, 'port: remote:139:fs:139'
-			print >>f, 'port: remote:7777:boss:7777'
-			print >>f, 'port: remote:16606:control:16606'
+			for s in [s for s in services \
+				if s.get('name', "") in self.imports]:
+			    p = urlparse(s.get('server', 'http://localhost'))
+			    print >>f, 'port: remote:%s:%s:%s' % \
+				    (p.port, p.hostname, p.port)
 
 		if tunnelconfig:
 		    print >>f, "tunnelip: %s" % tunnelconfig
-		print >>f, "seercontrol: control.%s.%s%s" % \
-			(meid.lower(), mproj.lower(), mdomain)
-		if is_ip:
-		    print >>f, "peer: %s" % peer
-		else:
-		    print >>f, "peer: %s.%s.%s%s" % \
-			    (peer.lower(), reid.lower(), 
-				    rproj.lower(), rdomain)
+		# XXX: send this an fedattr
+		#print >>f, "seercontrol: control.%s.%s%s" % \
+			#(meid.lower(), mproj.lower(), mdomain)
+		print >>f, "peer: %s" % peer.lower()
 		print >>f, "ssh_pubkey: /proj/%s/exp/%s/tmp/%s" % \
 			(lproj, leid, pubkey_base)
@@ -903,8 +977,9 @@
 			(myname.lower(), leid.lower(), lproj.lower(),
 				ldomain.lower())
-		    print >>f, "SMBshare: %s" % smbshare
-		    print >>f, "ProjectUser: %s" % muser
-		    print >>f, "ProjectName: %s" % mproj
-		    print >>f, "ExperimentID: %s/%s" % (mproj, meid)
+		    for s in services:
+			if s.get('name',"") in self.imports:
+			    client_service_out[s['name']](f, s)
+		    # Does seer need this?
+		    # print >>f, "ExperimentID: %s/%s" % (mproj, meid)
 		    f.close()
 		except IOError, e:
@@ -1051,4 +1126,6 @@
 	    raise service_error(server_error.req, "Badly formed request")
 
+	connInfo = req.get('connection', [])
+	services = req.get('service', [])
 	auth_attr = req['allocID']['fedid']
 	aid = "%s" % auth_attr
@@ -1083,5 +1160,5 @@
 		os.mkdir(softdir)
 	    for s in sw:
-		print "%s %s %s" % ( s, certfile, softdir)
+		self.log.debug("Retrieving %s" % s)
 		get_url(s, certfile, softdir)
 
@@ -1131,5 +1208,6 @@
 
 	    self.generate_portal_configs(topo, pubkey_base, 
-		    secretkey_base, tmpdir, master)
+		    secretkey_base, tmpdir, master, proj, ename, connInfo, 
+		    services)
 	    self.generate_ns2(topo, expfile, 
 		    "/proj/%s/software/%s/" % (proj, ename), master)
@@ -1140,4 +1218,6 @@
 	except service_error, e:
 	    err = e
+	except e:
+	    err = service_error(service_error.internal, str(e))
 
         # Walk up tmpdir, deleting as we go
Index: fedd/federation/experiment_control.py
===================================================================
--- fedd/federation/experiment_control.py	(revision 35aa3ae74d9953faf6d76c4d7f5e24359a260a0e)
+++ fedd/federation/experiment_control.py	(revision e02cd14c76fe2382e62f5e57ea53b1c682bf200c)
@@ -726,5 +726,5 @@
 
     def get_access(self, tb, nodes, tbparam, master, export_project,
-            access_user):
+            access_user, services):
         """
         Get access to testbed through fedd and set the parameters for that tb
@@ -769,4 +769,10 @@
                 # the type
                 req['exportProject'] = export_project
+		req['service'] = [
+			{ 'name': 'userconfig', 'visibility': 'export'},
+			{ 'name': 'SMB', 'visibility': 'export'},
+			{ 'name': 'seer', 'visibility': 'export'},
+			{ 'name': 'tmcd', 'visibility': 'export'},
+		    ]
 
             # node resources if any
@@ -820,4 +826,6 @@
 		"uri": uri,
 		}
+	if 'service' in r: 
+	    services.extend(r['service'])
 
 	# Add attributes to parameter space.  We don't allow attributes to
@@ -890,5 +898,6 @@
 	    self.response = None
 
-	def __call__(self, uri, aid, topo, master, attrs=None):
+	def __call__(self, uri, aid, topo, master, attrs=None, connInfo=None,
+		services=None):
 	    req = {
 		    'allocID': { 'fedid' : aid }, 
@@ -898,4 +907,15 @@
 		    'master': master,
 		}
+
+	    if connInfo:
+		req['connection'] = connInfo
+	    # Add services to request.  The master exports, everyone else
+	    # imports.
+	    if services:
+		svcs = [ x.copy() for x in services]
+		for s in svcs:
+		    if master: s['visibility'] = 'export'
+		    else: s['visibility'] = 'import'
+		req['service'] = svcs
 	    if attrs:
 		req['fedAttr'] = attrs
@@ -950,5 +970,5 @@
     def allocate_resources(self, allocated, master, eid, expid, 
             tbparams, topo, tmpdir, alloc_log=None, log_collector=None, 
-	    attrs=None):
+	    attrs=None, connInfo={}, services=[]):
 	def get_vlan(r):
 	    if r.has_key('StartSegmentResponseBody'):
@@ -1001,5 +1021,6 @@
 	    t = self.pooled_thread(
 		    target=ss,
-		    args =(uri, aid, topo[tb], False, attrs),
+		    args =(uri, aid, topo[tb], False, attrs, connInfo[tb],
+			services),
 		    name=tb, pdata=thread_pool, trace_file=self.trace_file)
 	    threads.append(t)
@@ -1054,5 +1075,7 @@
 			    caller=self.call_StartSegment,
 			    log_collector=log_collector), 
-			args=(uri, aid, topo[tb], False, attrs), name=tb,
+			args=(uri, aid, topo[tb], False, attrs, connInfo[tb],
+			    services),
+			name=tb,
 			pdata=thread_pool, trace_file=self.trace_file)
 		threads.append(t)
@@ -1090,5 +1113,6 @@
 			caller=self.call_StartSegment,
 			log_collector=log_collector),
-		    args =(uri, aid, topo[master], True, attrs),
+		    args =(uri, aid, topo[master], True, attrs, 
+			connInfo[master], services),
 		    name=master, pdata=thread_pool, trace_file=self.trace_file)
 	    threads.append(t)
@@ -1294,5 +1318,5 @@
 
     def get_access_to_testbeds(self, testbeds, access_user, 
-	    export_project, master, allocated, tbparams):
+	    export_project, master, allocated, tbparams, services):
 	"""
 	Request access to the various testbeds required for this instantiation
@@ -1303,16 +1327,15 @@
 	for tb in testbeds:
 	    self.get_access(tb, None, tbparams, master,
-		    export_project, access_user)
+		    export_project, access_user, services)
 	    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.
+	Create the sub-topologies that are needed for experiment instantiation.
 	"""
 	for tb in testbeds:
 	    topo[tb] = top.clone()
 	    to_delete = [ ]
+	    # XXX: copy in for loop to simplify
 	    for e in topo[tb].elements:
 		etb = e.get_attribute('testbed')
@@ -1332,30 +1355,23 @@
 	    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 new_portal_node(self, st, dt, tbparams, master, eid, myname, desthost,
 	    portal_type, iface_desc=()):
+	"""
+	Return a new internet portal node and a dict with the connectionInfo to
+	be attached.
+	"""
 	sproject = tbparams[st].get('project', 'project')
-	dproject = tbparams[dt].get('project', 'project')
+	sdomain = tbparams[st].get('domain', ".example.com")
+	mdomain = tbparams[master].get('domain', '.example.com')
 	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')
-	aid = tbparams[dt]['allocID']['fedid']
+
 	if st == master or dt == master:
 	    active = ("%s" % (st == master))
 	else:
-	    active = ("%s" %(st > dt))
+	    active = ("%s" % (st > dt))
 
 	ifaces = [ ]
@@ -1371,5 +1387,20 @@
 		    )
 	    ifaces.append(inf)
-	return topdl.Computer(
+	info = {
+		"type" : "ssh", 
+		"portal": myname,
+		'peer': "%s.%s.%s%s" %  (desthost.lower(), eid.lower(),
+			    sproject.lower(), sdomain.lower()),
+		'fedAttr': [ 
+			{ 'attribute': 'masterdomain', 'value': mdomain},
+			{ 'attribute': 'masterexperiment', 'value': 
+			    "%s/%s" % (mproject, eid)},
+			{ 'attribute': 'active', 'value': "%s" % active},
+			# Move to SMB service description
+			{ 'attribute': 'masteruser', 'value': muser},
+			{ 'attribute': 'smbshare', 'value': smbshare},
+		    ],
+		}
+	return (topdl.Computer(
 		name=myname,
 		attribute=[ 
@@ -1377,22 +1408,9 @@
 			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" % aid),
-			    ('scriptdir', 
-				"/usr/local/federation/bin"),
-			    ('active', "%s" % active),
 			    ('portal_type', portal_type), 
 			)
 		    ],
 		interface=ifaces,
-		)
+		), info)
 
     def new_portal_substrate(self, st, dt, eid, tbparams):
@@ -1496,5 +1514,5 @@
 
     def insert_internet_portals(self, sub, topo, tbs, tbparams, master, eid,
-	    segment_substrate, portals):
+	    segment_substrate, portals, connInfo):
 	# More than one testbed is on this substrate.  Insert
 	# some portals into the subtopologies.  st == source testbed,
@@ -1505,4 +1523,6 @@
 	    if not portals.has_key(st): 
 		portals[st] = { }
+	    if not connInfo.has_key(st):
+		connInfo[st] = [ ]
 	    for dt in [ t for t in tbs.keys() if t != st]:
 		sproject = tbparams[st].get('project', 'project')
@@ -1531,5 +1551,5 @@
 		if portals[st].has_key(dt):
 		    # There's a portal set up to go to this destination.
-		    # See if there's room to multiples this connection on
+		    # See if there's room to multiplex this connection on
 		    # it.  If so, add an interface to the portal; if not,
 		    # set up to add a portal below.
@@ -1573,5 +1593,5 @@
 				(('ip4_address', tbs[dt]),))
 			)
-		    portal =  self.new_portal_node(st, dt, tbparams, 
+		    portal, info  =  self.new_portal_node(st, dt, tbparams, 
 			    master, eid, myname, desthost, portal_type,
 			    infs)
@@ -1583,6 +1603,7 @@
 		    topo[st].elements.append(portal)
 		    portals[st][dt].append(portal)
-
-    def add_control_portal(self, st, dt, master, eid, topo, tbparams):
+		    connInfo[st].append(info)
+
+    def add_control_portal(self, st, dt, master, eid, topo, tbparams, connInfo):
 	# Add to the master testbed
 	tsubstrate, segment_element = \
@@ -1591,5 +1612,5 @@
 	desthost = "%stunnel" % st
 
-	portal = self.new_portal_node(st, dt, tbparams, master,
+	portal, info = self.new_portal_node(st, dt, tbparams, master,
 		eid, myname, desthost, "control", 
 		((tsubstrate.name,(('portal','true'),)),))
@@ -1602,4 +1623,7 @@
 	topo[st].elements.append(segment_element)
 	topo[st].elements.append(portal)
+	if not connInfo.has_key(st):
+	    connInfo[st] = [ ]
+	connInfo[st].append(info)
 
     def new_dragon_portal(self, st, dt, master, eid, myip, dip, idx, 
@@ -1623,5 +1647,6 @@
 	return portal
 
-    def add_portals(self, top, topo, eid, master, tbparams, ip_allocator):
+    def add_portals(self, top, topo, eid, master, tbparams, ip_allocator, 
+	    connInfo):
 	"""
 	For each substrate in the main topology, find those that
@@ -1652,5 +1677,5 @@
 	    else:
 		self.insert_internet_portals(s, topo, tbs, tbparams, master,
-			eid, segment_substrate, portals)
+			eid, segment_substrate, portals, connInfo)
 
 	# Make sure that all the slaves have a control portal back to the
@@ -1738,7 +1763,7 @@
 		else:
 		    self.add_control_portal(master, tb, master, eid, topo, 
-			    tbparams)
+			    tbparams, connInfo)
 		    self.add_control_portal(tb, master, master, eid, topo, 
-			    tbparams)
+			    tbparams, connInfo)
 
 	# Connect the portal nodes into the topologies and clear out
@@ -2030,6 +2055,8 @@
             allocated = { }         # Testbeds we can access
 	    topo ={ }		    # Sub topologies
+	    connInfo = { }	    # Connection information
+	    services = [ ]
 	    self.get_access_to_testbeds(testbeds, access_user, 
-		    export_project, master, allocated, tbparams)
+		    export_project, master, allocated, tbparams, services)
 	    self.split_topology(top, topo, testbeds, eid, master, tbparams)
 
@@ -2066,5 +2093,6 @@
 		    self.auth.set_attribute(asignee, "%s/%s" % (configpath, f))
 
-	    self.add_portals(top, topo, eid, master, tbparams, ip_allocator)
+	    self.add_portals(top, topo, eid, master, tbparams, ip_allocator,
+		    connInfo)
 	    # Now get access to the dynamic testbeds
 	    for k, t in topo.items():
@@ -2074,5 +2102,5 @@
 		if tb: 
 		    self.get_access(tb, None, user, tbparams, master, 
-			    export_project, access_user)
+			    export_project, access_user, services)
 		    tbparams[k] = tbparams[tb]
 		    del tbparams[tb]
@@ -2168,5 +2196,6 @@
         t  = Thread(target=self.allocate_resources,
                 args=(allocated, master, eid, expid, tbparams, 
-                    topo, tmpdir, alloc_log, alloc_collector, attrs),
+                    topo, tmpdir, alloc_log, alloc_collector, attrs, connInfo,
+		    services),
                 name=eid)
         t.start()
