Index: fedd/federation/emulab_access.py
===================================================================
--- fedd/federation/emulab_access.py	(revision f37e9bf901a44a31dd31968c1aafbf084a3f5c81)
+++ fedd/federation/emulab_access.py	(revision 29d5f7c4d13631c64ec5dd7b7ca053cdada09c4d)
@@ -1016,11 +1016,20 @@
 	the response that may need to be replayed, and return the response.
 	"""
+	i = 0
 	# Copy the assigned names into the return topology
-	embedding = [ ]
-	for n in starter.node:
-	    embedding.append({ 
-		'toponame': n,
-		'physname': ["%s%s" %  (starter.node[n], self.domain)],
-		})
+	for e in topo.elements:
+	    if isinstance(e, topdl.Computer):
+		if not self.create_debug:
+		    if e.name in starter.node:
+			e.localname.append("%s%s" % \
+				(starter.node[e.name], self.domain))
+			e.status = 'active'
+		else:
+		    # Simple debugging assignment
+		    e.localname.append("node%d%s" % (i, self.domain))
+		    e.status = 'active'
+		    e.operation.extend(('testop1', 'testop2'))
+		    i += 1
+
 	# Grab the log (this is some anal locking, but better safe than
 	# sorry)
@@ -1036,5 +1045,4 @@
 		    'topdldescription': topo.clone().to_dict()
 		    },
-		'embedding': embedding,
 		'proof': proof.to_dict(),
 		}
Index: fedd/federation/experiment_control.py
===================================================================
--- fedd/federation/experiment_control.py	(revision f37e9bf901a44a31dd31968c1aafbf084a3f5c81)
+++ fedd/federation/experiment_control.py	(revision 29d5f7c4d13631c64ec5dd7b7ca053cdada09c4d)
@@ -36,4 +36,5 @@
 from authorizer import abac_authorizer
 from thread_pool import thread_pool, pooled_thread
+from experiment_info import experiment_info, allocation_info
 
 import topdl
@@ -286,16 +287,11 @@
 
     @staticmethod
-    def get_alloc_ids(state):
-	"""
-	Pull the fedids of the identifiers of each allocation from the
-	state.  Again, a dict dive that's best isolated.
-
-	Used by read_store and read state
-	"""
-
-	return [ f['allocID']['fedid'] 
-		for f in state.get('federant',[]) \
-		    if f.has_key('allocID') and \
-			f['allocID'].has_key('fedid')]
+    def get_alloc_ids(exp):
+	"""
+	Used by read_store and read state.  This used to be worse.
+	"""
+
+	return [ a.allocID for a in exp.get_all_allocations() ]
+
 
     # Call while holding self.state_lock
@@ -307,19 +303,4 @@
         """
 	
-	def get_experiment_id(state):
-	    """
-	    Pull the fedid experimentID out of the saved state.  This is kind
-	    of a gross walk through the dict.
-	    """
-
-	    if state.has_key('experimentID'):
-		for e in state['experimentID']:
-		    if e.has_key('fedid'):
-			return e['fedid']
-		else:
-		    return None
-	    else:
-		return None
-
         try:
             f = open(self.state_filename, "r")
@@ -337,10 +318,10 @@
             try:
 
-		eid = get_experiment_id(s)
+		eid = s.fedid
 		if eid : 
 		    if self.auth_type == 'legacy':
 			# XXX: legacy
 			# Give the owner rights to the experiment
-			self.auth.set_attribute(s['owner'], eid)
+			#self.auth.set_attribute(s['owner'], eid)
 			# And holders of the eid as well
 			self.auth.set_attribute(eid, eid)
@@ -809,9 +790,10 @@
         if self.local_access.has_key(uri):
             resp = self.local_access[uri].ReleaseAccess(\
-                    { 'ReleaseAccessRequestBody' : {'allocID': aid},}, 
+		    { 'ReleaseAccessRequestBody' : 
+			{'allocID': {'fedid': aid}},}, 
                     fedid(file=cert_file))
             resp = { 'ReleaseAccessResponseBody': resp } 
         else:
-            resp = self.call_ReleaseAccess(uri, {'allocID': aid},
+	    resp = self.call_ReleaseAccess(uri, {'allocID': {'fedid': aid} },
                     cert_file, cert_pwd, self.trusted_certs)
 
@@ -855,7 +837,16 @@
 
 	def make_map(self, resp):
-	    for e in resp.get('embedding', []):
-		if 'toponame' in e and 'physname' in e:
-		    self.node[e['toponame']] = e['physname'][0]
+	    if 'segmentdescription' not in resp  or \
+		    'topdldescription' not in resp['segmentdescription']:
+		self.log.warn('No topology returned from startsegment')
+		return 
+
+	    top = topdl.Topology(
+		    **resp['segmentdescription']['topdldescription'])
+
+	    for e in top.elements:
+		if isinstance(e, topdl.Computer):
+		    self.node[e.name] = \
+			    (e.localname, e.status, e.service, e.operation)
 
 	def __call__(self, uri, aid, topo, masters, attrs=None, connInfo=None):
@@ -928,5 +919,5 @@
 	def __call__(self, uri, aid ):
 	    req = {
-		    'allocID': aid , 
+		    'allocID': {'fedid': aid }, 
 		}
 	    try:
@@ -1056,5 +1047,5 @@
                 # Remove the placeholder
                 self.state_lock.acquire()
-                self.state[eid]['experimentStatus'] = 'failed'
+		self.state[eid].status = 'failed'
                 if self.state_filename: self.write_state()
                 self.state_lock.release()
@@ -1071,17 +1062,22 @@
                 return
         else:
-	    # Walk through the successes and gather the virtual to physical
-	    # mapping.
-	    embedding = [ ]
+	    # Walk through the successes and gather the proofs
 	    proofs = { }
 	    for s in starters:
-		for k, v in s.node.items():
-		    embedding.append({
-			'toponame': k, 
-			'physname': [ v],
-			'testbed': s.testbed
-			})
 		if s.proof:
 		    proofs[s.testbed] = s.proof
+
+	    # Annotate the topology with embedding info
+	    for e in top.elements:
+		if isinstance(e, topdl.Computer):
+		    for s in starters:
+			ann = s.node.get(e.name, None)
+			if ann is not None:
+			    e.localname.extend(ann[0])
+			    e.status = ann[1]
+			    e.service.extend(ann[2])
+			    e.operation.extend(ann[3])
+			    break
+
             log.info("[start_segment]: Experiment %s active" % eid)
 
@@ -1095,14 +1091,11 @@
         # Insert the experiment into our state and update the disk copy.
         self.state_lock.acquire()
-        self.state[expid]['experimentStatus'] = 'active'
+        self.state[expid].status = 'active'
         self.state[eid] = self.state[expid]
-	self.state[eid]['experimentdescription']['topdldescription'] = \
-		top.to_dict()
-	self.state[eid]['embedding'] = embedding
+	self.state[eid].top = top
 	# Append startup proofs
-	for f in self.state[eid]['federant']:
-	    if 'name' in f and 'localname' in f['name']:
-		if f['name']['localname'] in proofs:
-		    f['proof'].append(proofs[f['name']['localname']])
+	for f in self.state[eid].get_all_allocations():
+	    if f.tb in proofs:
+		f.proof.append(proofs[f.tb])
 
         if self.state_filename: self.write_state()
@@ -1135,5 +1128,6 @@
 
 	if need_state_lock: self.state_lock.acquire()
-	self.state[expid]['auth'].update(attrs)
+	# XXX: really a no op?
+	#self.state[expid]['auth'].update(attrs)
 	if self.state_filename: self.write_state()
 	if need_state_lock: self.state_lock.release()
@@ -1146,8 +1140,9 @@
 
 	if need_state_lock: self.state_lock.acquire()
-	if expid in self.state and 'auth' in self.state[expid]:
-	    for p, a in self.state[expid]['auth']:
-		self.auth.unset_attribute(p, a)
-	    self.state[expid]['auth'] = set()
+	# XXX: should be a no-op
+	#if expid in self.state and 'auth' in self.state[expid]:
+	    #for p, a in self.state[expid]['auth']:
+		#self.auth.unset_attribute(p, a)
+	    #self.state[expid]['auth'] = set()
 	if self.state_filename: self.write_state()
 	if need_state_lock: self.state_lock.release()
@@ -1184,5 +1179,5 @@
 		if users_experiment:
 		    self.state_lock.acquire()
-		    status = self.state[eid].get('experimentStatus', None)
+		    status = self.state[eid].status
 		    if status and status == 'failed':
 			# remove the old access attributes
@@ -1200,13 +1195,6 @@
                 eid += random.choice(string.ascii_letters)
             # Initial state
-            self.state[eid] = {
-                    'experimentID' : \
-                            [ { 'localname' : eid }, {'fedid': expid } ],
-                    'experimentStatus': state,
-                    'experimentAccess': { 'X509' : expcert },
-                    'owner': fid,
-                    'log' : [],
-		    'auth': set(),
-                }
+	    self.state[eid] = experiment_info(fedid=expid, localname=eid, 
+		    identity=expcert)
             self.state[expid] = self.state[eid]
 	    if self.state_filename: self.write_state()
@@ -1222,13 +1210,6 @@
                     eid += random.choice(string.ascii_letters)
             # Initial state
-            self.state[eid] = {
-                    'experimentID' : \
-                            [ { 'localname' : eid }, {'fedid': expid } ],
-                    'experimentStatus': state,
-                    'experimentAccess': { 'X509' : expcert },
-                    'owner': fid,
-                    'log' : [],
-		    'auth': set(),
-                }
+	    self.state[eid] = experiment_info(fedid=expid, localname=eid, 
+		    identity=expcert)
             self.state[expid] = self.state[eid]
 	    if self.state_filename: self.write_state()
@@ -1668,16 +1649,10 @@
 	expid = eid = None
 	self.state_lock.acquire()
-	if self.state.has_key(key):
-	    self.state[key]['experimentStatus'] = "starting"
-	    for e in self.state[key].get('experimentID',[]):
-		if not expid and e.has_key('fedid'):
-		    expid = e['fedid']
-		elif not eid and e.has_key('localname'):
-		    eid = e['localname']
-	    if 'experimentAccess' in self.state[key] and \
-		    'X509' in self.state[key]['experimentAccess']:
-		expcert = self.state[key]['experimentAccess']['X509']
-	    else:
-		expcert = None
+	if key in self.state:
+	    exp = self.state[key]
+	    exp.status = "starting"
+	    expid = exp.fedid
+	    eid = exp.localname
+	    expcert = exp.identity
 	self.state_lock.release()
 
@@ -1916,4 +1891,5 @@
 
         self.state_lock.acquire()
+	# XXX: this needs to be recalculated
         if self.state.has_key(key):
             if self.state[key].has_key('vtopo'):
@@ -1961,4 +1937,5 @@
 
         self.state_lock.acquire()
+	# XXX: this needs to be recalculated
         if self.state.has_key(key):
             if self.state[key].has_key('vis'):
@@ -1990,24 +1967,23 @@
 	response message.
 	"""
+	self.state_lock.acquire()
+	# XXX:
+	#self.state[eid]['vtopo'] = vtopo
+	#self.state[eid]['vis'] = vis
+	exp = self.state[eid]
+	exp.topology = top
 	# save federant information
 	for k in allocated.keys():
-	    tbparams[k]['federant'] = {
-		    'name': [ { 'localname' : eid} ],
-		    'allocID' : tbparams[k]['allocID'],
-		    'uri': tbparams[k]['uri'],
-		    'proof': tbparams[k]['proof'],
-		}
-
-	self.state_lock.acquire()
-	self.state[eid]['vtopo'] = vtopo
-	self.state[eid]['vis'] = vis
-	self.state[eid]['experimentdescription'] = \
-		{ 'topdldescription': top.to_dict() }
-	self.state[eid]['federant'] = \
-		[ tbparams[tb]['federant'] for tb in tbparams.keys() \
-		    if tbparams[tb].has_key('federant') ]
+	    exp.add_allocation(
+		    allocation_info(
+			tb=k, 
+			allocID=tbparams[k]['allocID'].get('fedid', None),
+			uri=tbparams[k]['uri'],
+			proof=tbparams[k]['proof'])
+		    )
+
 	# Access proofs for the response message
 	proofs = [copy.deepcopy(p) for k in tbparams.keys()\
-		    for p in tbparams[k]['federant']['proof']]
+		    for p in tbparams[k]['proof']]
 	if self.state_filename: 
 	    self.write_state()
@@ -2154,5 +2130,5 @@
         # to the main log file.
         alloc_log = logging.getLogger('fedd.experiment_control.%s' % eid)
-	alloc_collector = self.list_log(self.state[eid]['log'])
+	alloc_collector = self.list_log(self.state[eid].log)
         h = logging.StreamHandler(alloc_collector)
         # XXX: there should be a global one of these rather than repeating the
@@ -2187,26 +2163,6 @@
         rv = None
         self.state_lock.acquire()
-        if self.state.has_key(key):
-            if isinstance(self.state[key], dict):
-                try:
-                    kl = [ f['fedid'] for f in \
-                            self.state[key]['experimentID']\
-                                if f.has_key('fedid') ]
-                except KeyError:
-                    self.state_lock.release()
-                    raise service_error(service_error.internal, 
-                            "No fedid for experiment %s when getting "+\
-                                    "fedid(!?)" % key)
-                if len(kl) == 1:
-                    rv = kl[0]
-                else:
-                    self.state_lock.release()
-                    raise service_error(service_error.internal, 
-                            "multiple fedids for experiment %s when " +\
-                                    "getting fedid(!?)" % key)
-            else:
-                self.state_lock.release()
-                raise service_error(service_error.internal, 
-                        "Unexpected state for %s" % key)
+        if key in self.state:
+	    rv = self.state[key].fedid
         self.state_lock.release()
         return rv
@@ -2242,32 +2198,5 @@
 	    return (None, None)
 
-    def clean_info_response(self, rv, proof):
-        """
-        Remove the information in the experiment's state object that is not in
-        the info response.
-        """
-        # Remove the owner info (should always be there, but...)
-        if rv.has_key('owner'): del rv['owner']
-	if 'auth' in rv: del rv['auth']
-
-        # Convert the log into the allocationLog parameter and remove the
-        # log entry (with defensive programming)
-        if rv.has_key('log'):
-            rv['allocationLog'] = "".join(rv['log'])
-            del rv['log']
-        else:
-            rv['allocationLog'] = ""
-
-        if rv['experimentStatus'] != 'active':
-            if rv.has_key('federant'): del rv['federant']
-        else:
-            # remove the allocationID and uri info from each federant
-            for f in rv.get('federant', []):
-                if f.has_key('allocID'): del f['allocID']
-		if f.has_key('uri'): del f['uri']
-	rv['proof'] = proof.to_dict()
-
-        return rv
-
+    
     def get_info(self, req, fid):
         """
@@ -2295,14 +2224,12 @@
         proof = self.check_experiment_access(fid, key)
 
-        # The state may be massaged by the service function that called
-        # get_info (e.g., encoded for XMLRPC transport) so send a copy of the
-        # state.
         self.state_lock.acquire()
         if self.state.has_key(key):
-            rv = copy.deepcopy(self.state[key])
+	    rv = self.state[key].get_info()
         self.state_lock.release()
 
         if rv:
-            return self.clean_info_response(rv, proof)
+	    rv['proof'] = proof.to_dict()
+	    return rv
         else:
             raise service_error(service_error.req, "No such experiment")
@@ -2326,6 +2253,6 @@
 
             if self.state.has_key(key):
-                e = copy.deepcopy(self.state[key])
-                e = self.clean_info_response(e, proof)
+                e = self.state[key].get_info()
+		e['proof'] = proof.to_dict()
                 rv['info'].append(e)
 		rv['proof'].append(proof.to_dict())
@@ -2340,5 +2267,5 @@
 	"""
 	self.state_lock.acquire()
-	status = fed_exp.get('experimentStatus', None)
+	status = fed_exp.status
 
 	if status:
@@ -2364,36 +2291,16 @@
 	term_params = { }
 	self.state_lock.acquire()
-	#  experimentID is a list of dicts that are self-describing
-	#  identifiers.  This finds all the fedids and localnames - the
-	#  keys of self.state - and puts them into ids, which is used to delete
-	#  the state after everything is swapped out.
-	for id in fed_exp.get('experimentID', []):
-	    if 'fedid' in id: 
-		ids.append(id['fedid'])
-		repo = "%s" % id['fedid']
-	    if 'localname' in id: ids.append(id['localname'])
-
-	# Get the experimentAccess - the principal for this experiment.  It
-	# is this principal to which credentials have been delegated, and
-	# as which the experiment controller must act.
-	if 'experimentAccess' in fed_exp and \
-		'X509' in fed_exp['experimentAccess']:
-	    expcert = fed_exp['experimentAccess']['X509']
-	else:
-	    expcert = None
+	ids = [ x for x in (fed_exp.localname, fed_exp.fedid) if x is not None ]
+	expcert = fed_exp.identity
+	repo = "%s" % fed_exp.fedid
 
 	# Collect the allocation/segment ids into a dict keyed by the fedid
-	# of the allocation (or a monotonically increasing integer) that
-	# contains a tuple of uri, aid (which is a dict...)
-	for i, fed in enumerate(fed_exp.get('federant', [])):
-	    try:
-		uri = fed['uri']
-		aid = fed['allocID']
-		k = fed['allocID'].get('fedid', i)
-	    except KeyError, e:
-		continue
-	    term_params[k] = (uri, aid)
+	# of the allocation that contains a tuple of uri, aid
+	for i, fed in enumerate(fed_exp.get_all_allocations()):
+	    uri = fed.uri
+	    aid = fed.allocID
+	    term_params[aid] = (uri, aid)
 	# Change the experiment state
-	fed_exp['experimentStatus'] = 'terminating'
+	fed_exp.status = 'terminating'
 	if self.state_filename: self.write_state()
 	self.state_lock.release()
Index: fedd/federation/experiment_info.py
===================================================================
--- fedd/federation/experiment_info.py	(revision 29d5f7c4d13631c64ec5dd7b7ca053cdada09c4d)
+++ fedd/federation/experiment_info.py	(revision 29d5f7c4d13631c64ec5dd7b7ca053cdada09c4d)
@@ -0,0 +1,64 @@
+#!/usr/local/bin/python
+
+import copy
+
+class allocation_info:
+    """
+    An allocation identified by allocationID.  It includes the local name
+    of the testbed on which it was allocated and the uri on which to
+    contact it.  In addition, the proofs of access are included.
+    """
+    def __init__(self, allocID, tb, uri, proof=None):
+	self.allocID = allocID
+	self.tb = tb
+	self.uri = uri
+	self.proof = proof
+
+class experiment_info:
+    """
+    Information about an experiment in the eperiment controller.  It includes
+    the fedid and localnames, the identity the experiment acts as, current
+    status, topology allocation logs and the allocations themselves.
+    """
+    def __init__(self, fedid, localname, identity=None):
+	self.fedid = fedid
+	self.localname = localname
+	self.identity = identity
+	self.top = None
+	self.status = 'empty'
+	self.log = []
+	self.alloc = { }
+
+    def add_allocation(self, a):
+	self.alloc[a.tb] = a
+
+    def get_allocation(self, tb):
+	return self.alloc.get(tb,None)
+
+    def get_all_allocations(self):
+	return self.alloc.values()
+
+    def get_info(self):
+	"""
+	Return the information as a dict suitable for a soap return value.
+	This is an infoResponseType in fedd_types.xsd.
+	"""
+	# The state may be massaged by the service function that called
+	# get_info (e.g., encoded for XMLRPC transport) so copy structured
+	# fields.
+	rv = {
+		'experimentID': [
+		    { 'fedid': copy.deepcopy(self.fedid) },
+		    {'localname': self.localname },
+		],
+		'experimentStatus': self.status,
+	    }
+	if self.log:
+	    rv['allocationLog'] = "".join(self.log)
+	if self.identity is not None:
+	    rv['experimentAccess'] = {'X509': copy.deepcopy(self.identity)}
+	if self.top is not None:
+	    rv['experimentdescription'] = \
+		{ 'topdldescription': self.top.to_dict() }
+	return rv
+
Index: fedd/federation/topdl.py
===================================================================
--- fedd/federation/topdl.py	(revision f37e9bf901a44a31dd31968c1aafbf084a3f5c81)
+++ fedd/federation/topdl.py	(revision 29d5f7c4d13631c64ec5dd7b7ca053cdada09c4d)
@@ -168,5 +168,5 @@
 		    for i in self.importer],'')
 	if self.param:
-	    rv += join('<param>%s</param>' % p.to_xml() \
+	    rv += join(['<param>%s</param>' % p.to_xml() \
 		    for p in self.param], '')
 	if self.description is not None:
@@ -206,6 +206,6 @@
 		localname = [ ln for ln in self.localname],
 		status = self.status,
-		service = [ s.clone() for s in self.service]
-		operation=[ op for op in operation])
+		service = [ s.clone() for s in self.service],
+		operation=[ op for op in self.operation])
 
     def to_dict(self):
@@ -238,5 +238,5 @@
 		    for a in self.attribute], "")
 	if self.localname:
-	    rv += join('<localname>%s</localname>' % ln \
+	    rv += join(['<localname>%s</localname>' % ln \
 		    for ln in self.localname], '')
 	if self.status is not None:
@@ -489,5 +489,5 @@
 		interface=[x.clone() for x in self.interface],
 		attribute=[x.clone() for x in self.attribute],
-		localname =[ ln for for ln in self.localname],
+		localname =[ ln for ln in self.localname],
 		status = self.status,
 		service = [s.clone() for s in self.service],
@@ -539,5 +539,5 @@
 		    for a in self.attribute], "")
 	if self.localname:
-	    rv += join('<localname>%s</localname>' % ln \
+	    rv += join(['<localname>%s</localname>' % ln \
 		    for ln in self.localname], '')
 	if self.status is not None:
@@ -607,5 +607,5 @@
 		    for a in self.attribute], "")
 	if self.localname:
-	    rv += join('<localname>%s</localname>' % ln \
+	    rv += join(['<localname>%s</localname>' % ln \
 		    for ln in self.localname], '')
 	if self.status is not None:
