Index: fedd/federation/emulab_access.py
===================================================================
--- fedd/federation/emulab_access.py	(revision 0de1b945e52a249b775807158d8b90c4ed19a8bd)
+++ fedd/federation/emulab_access.py	(revision 1962a5bee1a92769c3963c69d6e843f18314469d)
@@ -131,6 +131,8 @@
 	# XXX: Configurable
 	self.exports = set(('SMB', 'seer', 'tmcd', 'userconfig', 
-	    'project_export', 'local_seer_control', 'seer_master'))
-	self.imports = set(('SMB', 'seer', 'userconfig', 'seer_master'))
+	    'project_export', 'local_seer_control', 'seer_master', 
+	    'hide_hosts'))
+	self.imports = set(('SMB', 'seer', 'userconfig', 'seer_master',
+	    'hide_hosts'))
 
 	if not self.local_seer_image or not self.local_seer_software:
@@ -583,5 +585,5 @@
 	return confid, confcert
 
-    def export_SMB(self, id, state, project, user):
+    def export_SMB(self, id, state, project, user, attrs):
 	return { 
 		'id': id,
@@ -596,5 +598,5 @@
 		}
 
-    def export_seer(self, id, state, project, user):
+    def export_seer(self, id, state, project, user, attrs):
 	return { 
 		'id': id,
@@ -604,5 +606,5 @@
 		}
 
-    def export_local_seer(self, id, state, project, user):
+    def export_local_seer(self, id, state, project, user, attrs):
 	return { 
 		'id': id,
@@ -612,5 +614,5 @@
 		}
 
-    def export_seer_master(self, id, state, project, user):
+    def export_seer_master(self, id, state, project, user, attrs):
 	return { 
 		'id': id,
@@ -620,5 +622,5 @@
 		}
 
-    def export_tmcd(self, id, state, project, user):
+    def export_tmcd(self, id, state, project, user, attrs):
 	return { 
 		'id': id,
@@ -628,5 +630,5 @@
 		}
 
-    def export_userconfig(self, id, state, project, user):
+    def export_userconfig(self, id, state, project, user, attrs):
 	if self.userconfdir and self.userconfcmd \
 		and self.userconfurl:
@@ -645,4 +647,13 @@
 	    return None
 
+    def export_hide_hosts(self, id, state, project, user, attrs):
+	return {
+		'id': id, 
+		'name': 'hide_hosts',
+		'visibility': 'export',
+		'fedAttr': [ x for x in attrs \
+			if x.get('attribute', "") == 'hosts'],
+		}
+
     def export_services(self, sreq, project, user):
 	exp = [ ]
@@ -653,27 +664,36 @@
 	    sname = s.get('name', '')
 	    svis = s.get('visibility', '')
+	    sattrs = s.get('fedAttr', [])
 	    if svis == 'export':
 		if sname in self.exports:
 		    id = s.get('id', 'no_id')
 		    if sname == 'SMB':
-			exp.append(self.export_SMB(id, state, project, user))
+			exp.append(self.export_SMB(id, state, project, user,
+			    sattrs))
 		    elif sname == 'seer':
-			exp.append(self.export_seer(id, state, project, user))
+			exp.append(self.export_seer(id, state, project, user,
+			    sattrs))
 		    elif sname == 'tmcd':
-			exp.append(self.export_tmcd(id, state, project, user))
+			exp.append(self.export_tmcd(id, state, project, user,
+			    sattrs))
 		    elif sname == 'userconfig':
 			exp.append(self.export_userconfig(id, state,
-			    project, user))
+			    project, user, sattrs))
 		    elif sname == 'project_export':
-			exp.append(self.export_SMB(id, state, project, user))
-			#exp.append(self.export_seer(id, state, project, user))
+			exp.append(self.export_SMB(id, state, project, user,
+			    sattrs))
+			#exp.append(self.export_seer(id, state, project, user,
+			#sattrs))
 			exp.append(self.export_userconfig(id, state,
-			    project, user))
+			    project, user, sattrs))
 		    elif sname == 'local_seer_control':
 			exp.append(self.export_local_seer(id, state, project,
-			    user))
+			    user, sattrs))
 		    elif sname == 'seer_master':
 			exp.append(self.export_seer_master(id, state, project,
-			    user))
+			    user, sattrs))
+		    elif sname == 'hide_hosts':
+			exp.append(self.export_hide_hosts(id, state, project,
+			    user, sattrs))
 	return (exp, state)
 
@@ -1094,4 +1114,9 @@
 		print >>f, "ProjectName: %s" % smbproj
 
+	def client_hide_hosts(f, s):
+	    for a in s.get('fedAttr', [ ]):
+		if a.get('attribute', "") == 'hosts':
+		    print >>f, "Hide: %s" % a.get('value', "")
+
 	client_service_out = {
 		'SMB': client_smb,
@@ -1101,4 +1126,5 @@
 		'project_export': client_null,
 		'seer_master': client_seer_master,
+		'hide_hosts': client_hide_hosts,
 	    }
 
@@ -1130,4 +1156,5 @@
 		'seer': server_seer,
 		'seer_master': server_port,
+		'hide_hosts': server_null,
 	    }
 	# XXX: end un hardcode this
Index: fedd/federation/experiment_control.py
===================================================================
--- fedd/federation/experiment_control.py	(revision 0de1b945e52a249b775807158d8b90c4ed19a8bd)
+++ fedd/federation/experiment_control.py	(revision 1962a5bee1a92769c3963c69d6e843f18314469d)
@@ -46,10 +46,19 @@
 # Right now, no support for composition.
 class federated_service:
-    def __init__(self, name, exporter=None, importers=[], params={ }, reqs=[]):
+    def __init__(self, name, exporter=None, importers=None, params=None, 
+	    reqs=None, portal=None):
 	self.name=name
 	self.exporter=exporter
-	self.importers=importers
-	self.params = params
-	self.reqs = reqs
+	if importers is None: self.importers = []
+	else: self.importers=importers
+	if params is None: self.params = { }
+	else: self.params = params
+	if reqs is None: self.reqs = []
+	else: self.reqs = reqs
+
+	if portal is not None:
+	    self.portal = portal
+	else:
+	    self.portal = (name in federated_service.needs_portal)
 
     def __str__(self):
@@ -57,4 +66,6 @@
 		(self.name, self.exporter, self.importers, self.params,
 			[ (r['name'], r['visibility']) for r in self.reqs] )
+
+    needs_portal = ('SMB', 'seer', 'tmcd', 'project_export', 'seer_master')
 
 class experiment_control_local:
@@ -1689,7 +1700,16 @@
 			if a.attribute == 'testbed'])
 
+	    tb_hosts = { }
+	    for tb in testbeds:
+		tb_hosts[tb] = [ e.name for e in top.elements \
+			if isinstance(e, topdl.Computer) and \
+			    e.get_attribute('testbed') and \
+			    e.get_attribute('testbed') == tb]
+
 	    masters = { }	    # testbeds exporting services
+	    pmasters = { }	    # Testbeds exporting services that 
+				    # need portals
 	    for s in tb_services:
-		# If this is a project_export request with the importall field
+		# If this is a service request with the importall field
 		# set, fill it out.
 
@@ -1711,7 +1731,16 @@
 					a.get('value','')
 
-			masters[tb].append(federated_service(name=s['name'],
+			fser = federated_service(name=s['name'],
 				exporter=tb, importers=s.get('import',[]),
-				params=params, reqs=[]))
+				params=params)
+			if fser.name == 'hide_hosts' \
+				and 'hosts' not in fser.params:
+			    fser.params['hosts'] = \
+				    ",".join(tb_hosts.get(fser.exporter, []))
+			masters[tb].append(fser)
+
+			if fser.portal:
+			    if tb not in pmasters: pmasters[tb] = [ fser ]
+			    else: pmasters[tb].append(fser)
 		    else:
 			self.log.error('Testbed service does not have name " + \
@@ -1722,4 +1751,5 @@
 	    topo ={ }		    # Sub topologies
 	    connInfo = { }	    # Connection information
+
 	    self.get_access_to_testbeds(testbeds, access_user, allocated, 
 		    tbparams, masters)
@@ -1761,5 +1791,5 @@
 	    part = experiment_partition(self.auth, self.store_url, self.tbmap,
 		    self.muxmax, self.direct_transit)
-	    part.add_portals(top, topo, eid, masters, tbparams, ip_allocator,
+	    part.add_portals(top, topo, eid, pmasters, tbparams, ip_allocator,
 		    connInfo, expid)
 	    # Now get access to the dynamic testbeds (those added above)
