Index: fedd/federation/emulab_access.py
===================================================================
--- fedd/federation/emulab_access.py	(revision ab847bc9dbf2f2164d533821757acdf8dcaa7b04)
+++ fedd/federation/emulab_access.py	(revision e76f38a443af4f35d34b5ab1b7952636b9576c20)
@@ -87,4 +87,7 @@
 	self.federation_software = config.get("access", "federation_software")
 	self.portal_software = config.get("access", "portal_software")
+	self.local_seer_software = config.get("access", "local_seer_software")
+	self.local_seer_image = config.get("access", "local_seer_image")
+	self.local_seer_start = config.get("access", "local_seer_start")
 	self.ssh_privkey_file = config.get("access","ssh_privkey_file")
 	self.ssh_pubkey_file = config.get("access","ssh_pubkey_file")
@@ -96,4 +99,5 @@
 	self.federation_software = software_list(self.federation_software)
 	self.portal_software = software_list(self.portal_software)
+	self.local_seer_software = software_list(self.local_seer_software)
 
 	self.access_type = self.access_type.lower()
@@ -126,6 +130,10 @@
 	# XXX: Configurable
 	self.exports = set(('SMB', 'seer', 'tmcd', 'userconfig', 
-	    'project_export'))
+	    'project_export', 'local_seer_control'))
 	self.imports = set(('SMB', 'seer', 'userconfig'))
+
+	if not self.local_seer_image or not self.local_seer_software or \
+		not self.local_seer_start:
+	    self.exports.discard('local_seer_control')
 
         if auth: self.auth = auth
@@ -160,5 +168,6 @@
             'ReleaseAccess': soap_handler("ReleaseAccess", self.ReleaseAccess),
             'StartSegment': soap_handler("StartSegment", self.StartSegment),
-            'TerminateSegment': soap_handler("TerminateSegment", self.TerminateSegment),
+            'TerminateSegment': soap_handler("TerminateSegment",
+		self.TerminateSegment),
             }
         self.xmlrpc_services =  {\
@@ -182,8 +191,23 @@
                 allocate_project_remote(config, auth)
 
+
         # If the project allocator exports services, put them in this object's
         # maps so that classes that instantiate this can call the services.
         self.soap_services.update(self.allocate_project.soap_services)
         self.xmlrpc_services.update(self.allocate_project.xmlrpc_services)
+
+    @staticmethod
+    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 
 
 
@@ -573,4 +597,12 @@
 		}
 
+    def export_local_seer(self, id, state, project, user):
+	return { 
+		'id': id,
+		'name': 'local_seer_control',
+		'visibility': 'export',
+		'server': 'http://control:16606',
+		}
+
     def export_tmcd(self, id, state, project, user):
 	return { 
@@ -623,4 +655,7 @@
 			exp.append(self.export_userconfig(id, state,
 			    project, user))
+		    elif sname == 'local_seer_control':
+			exp.append(self.export_local_seer(id, state, project,
+			    user))
 	return (exp, state)
 
@@ -1067,9 +1102,13 @@
 	seer_out = False
 	client_out = False
+	mproj = None
+	mexp = None
+	control_gw = None
+	testbed = ""
+	# Create configuration files for the portals
 	for e in [ e for e in topo.elements \
 		if isinstance(e, topdl.Computer) and e.get_attribute('portal')]:
 	    myname = e.name[0]
 	    type = e.get_attribute('portal_type')
-	    testbed = e.get_attribute('testbed')
 
 	    info = conninfo_to_dict(myname, connInfo)
@@ -1083,9 +1122,11 @@
 	    ssh_port = info.get('ssh_port', 22)
 
-	    mexp = info.get('masterexperiment',"")
-	    mproj, meid = mexp.split("/", 1)
-	    mdomain = info.get('masterdomain',"")
-	    muser = info.get('masteruser','root')
-	    smbshare = info.get('smbshare', 'USERS')
+	    # Collect this for the client.conf file
+	    if 'masterexperiment' in info:
+		mproj, meid = info['masterexperiment'].split("/", 1)
+
+	    if type in ('control', 'both'):
+		testbed = e.get_attribute('testbed')
+		control_gw = myname
 
 	    active = info.get('active', 'False')
@@ -1114,26 +1155,26 @@
 		raise service_error(service_error.internal,
 			"Can't write protal config %s: %s" % (cfn, e))
-	    
-	    if not client_out and type in ('control', 'both'):
-		try:
-		    f = open("%s/client.conf" % tmpdir, "w")
-		    print >>f, "ControlGateway: %s.%s.%s%s" % \
-			(myname.lower(), leid.lower(), lproj.lower(),
-				ldomain.lower())
-		    for s in services:
-			if s.get('name',"") in self.imports and \
-				s.get('visibility','') == 'import':
-			    client_service_out[s['name']](f, s)
-		    # Seer uses this.
-		    print >>f, "ExperimentID: %s/%s" % (mproj, meid)
-		    # Better way...
-		    if testbed == master:
-			print >>f, "SEERBase: True"
-		    f.close()
-		except IOError, e:
-		    raise service_error(service_error.internal,
-			    "Cannot write client.conf: %s" %s)
-		client_out = True
-
+
+	# Done with portals, write the client config file.
+	try:
+	    f = open("%s/client.conf" % tmpdir, "w")
+	    if control_gw:
+		print >>f, "ControlGateway: %s.%s.%s%s" % \
+		    (myname.lower(), leid.lower(), lproj.lower(),
+			    ldomain.lower())
+	    for s in services:
+		if s.get('name',"") in self.imports and \
+			s.get('visibility','') == 'import':
+		    client_service_out[s['name']](f, s)
+	    # Seer uses this.
+	    if mproj and meid:
+		print >>f, "ExperimentID: %s/%s" % (mproj, meid)
+	    # Better way...
+	    if testbed == master:
+		print >>f, "SEERBase: True"
+	    f.close()
+	except IOError, e:
+	    raise service_error(service_error.internal,
+		    "Cannot write client.conf: %s" %s)
 
     def generate_ns2(self, topo, expfn, softdir, master, connInfo):
@@ -1184,17 +1225,4 @@
 		return e.name[0] not in self.nodes
 
-	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 
-
 
 	t = topo.clone()
@@ -1243,8 +1271,8 @@
 		t.elements.remove(e)
 	    if isinstance(e, topdl.Computer):
-		add_kit(e, self.federation_software)
+		self.add_kit(e, self.federation_software)
 		if e.get_attribute('portal') and gate_cmd:
 		    # Add local portal support software
-		    add_kit(e, self.portal_software)
+		    self.add_kit(e, self.portal_software)
 		    # Portals never have a user-specified start command
 		    e.set_attribute('startup', gate_cmd)
@@ -1497,7 +1525,7 @@
 	    # data.
 	    for s in services:
-		if s.get("name", "") == 'userconfig' \
-			and s.get('visibility',"") == 'import':
-
+		s_name = s.get('name', '')
+		s_vis = s.get('visibility','')
+		if s_name  == 'userconfig' and s_vis == 'import':
 		    # Collect ther server and certificate info.
 		    u = s.get('server', None)
@@ -1535,6 +1563,22 @@
 				"No certificate for retreiving userconfig")
 		    break
-
-
+		if s_name  == 'local_seer_control'  and s_vis == 'export':
+		    # Copy local seer control node software to the tempdir
+		    for l, f in self.local_seer_software:
+			base = os.path.basename(f)
+			copy_file(f, "%s/%s" % (softdir, base))
+
+		    # Add a control node to the local topology
+		    c_node = topdl.Computer(
+			    name='control', 
+			    attribute=[
+				{ 'attribute': 'image', 
+				    'value': self.local_seer_image },
+				{ 'attribute': 'startup',
+				    'value': self.local_seer_start },
+				]
+			    )
+		    self.add_kit(c_node, self.local_seer_software)
+		    topo.elements.append(c_node)
 
 	    proj = None
