Index: fedd/federation/emulab_segment.py
===================================================================
--- fedd/federation/emulab_segment.py	(revision 181aeb4705ccf35512b1d84210f06a0ce879f835)
+++ fedd/federation/emulab_segment.py	(revision 181aeb4705ccf35512b1d84210f06a0ce879f835)
@@ -0,0 +1,210 @@
+#!/usr/local/bin/python
+
+import logging 
+import util
+
+from M2Crypto import SSL
+from M2Crypto.m2xmlrpclib import SSL_Transport
+from xmlrpclib import ServerProxy, dumps, loads, Fault, Error, Binary
+from M2Crypto.SSL import SSLError
+from M2Crypto.BIO import BIOError
+from socket import error as socket_error
+from socket import sslerror
+import httplib
+from federation.util import fedd_ssl_context
+from federation import service_error
+
+class emulab_segment:
+    def __init__(self, boss, cert):
+	self.ctxt = fedd_ssl_context(my_cert=cert)
+	self.ctxt.set_verify(SSL.verify_none, 10)
+	self.boss = boss
+	self.null = """
+set ns [new Simulator]
+source tb_compat.tcl
+
+set a [$ns node]
+
+$ns rtproto Session
+$ns run 
+"""
+	self.log =  getattr(self, 'log', None) 
+	self.debug = getattr(self, 'debug', False)
+
+    def emulab_call(self, method, params):
+	VERSION = 0.1
+	try:
+	    transport = SSL_Transport(self.ctxt)
+	    port = ServerProxy(self.boss, transport=transport)
+	    remote_method = getattr(port, method, None)
+	    if remote_method is not None:
+		resp = remote_method(VERSION, params)
+	    else:
+		raise service_error(service_error.internal, 
+			"Bad method: %s" % method)
+	except socket_error, e:
+	    raise service_error(service_error.connect, 
+		    "Cannot connect to %s: %s" % (url, e[1]))
+	    raise e
+	except BIOError, e:
+	    if self.log:
+		self.log.warn("BIO error contacting %s: %s" % (url, e))
+	    raise e
+	except sslerror, e:
+	    if self.log:
+		self.log.warn("SSL (socket) error contacting %s: %s" % 
+			(url, e))
+	    raise e
+	except SSLError, e:
+	    if self.log:
+		self.log.warn("SSL error contacting %s: %s" % (url, e))
+	    raise e
+	except httplib.HTTPException, e:
+	    if self.log:
+		self.log.warn("HTTP error contacting %s: %s" % (url, e))
+	    raise e
+	except Fault, f:
+	    raise service_error(f.faultCode, f.faultString)
+	except Error, e:
+	    raise service_error(service_error.protocol, 
+		    "Remote XMLRPC Fault: %s" % e)
+
+	code = resp.get('code', -1)
+	if code ==0:
+	    return (code, resp.get('value', None))
+	else:
+	    return (code, resp.get('output', None))
+
+    def get_state(self, pid, eid):
+	"""
+	Return the state of the experiment as reported by emulab
+	"""
+
+	if self.debug:
+	    state = 'swapped'
+	else:
+	    params =  { 'proj': pid, 'exp': eid }
+	    code, state = self.emulab_call('experiment.state', params)
+	    if code != 0:
+		state = 'none'
+
+	if self.log:
+	    self.log.debug("State is %s" % state)
+	return state
+
+    def make_null_experiment(self, pid, eid, tmpdir):
+	"""
+	Create a null copy of the experiment so that we capture any logs there
+	if the modify fails.  Emulab software discards the logs from a failed
+	startexp.
+	"""
+
+	if self.debug:
+	    if self.log:
+		self.log("[make_null_experiment]: (debug) Creating experiment")
+	    return True
+	else:
+	    params = {
+		    'proj': pid,
+		    'exp': eid, 
+		    'nsfilestr': self.null,
+		    'batch': False,
+		    'idleswap': 0,
+		    'noidleswap_reason': 'Federated experiment',
+		    'noswapin': True,
+		    'wait': True
+		    }
+	    if self.log:
+		self.log("[make_null_experiment]: Creating experiment")
+	    code, value = self.emulab_call('experiment.startexp', params)
+
+	    if self.log:
+		if code == 0: 
+		    self.log.info('[make_null_experiment]: Create succeeded')
+		else: 
+		    self.log.error('[make_null_experiment]: Create failed: %s' \
+			    % value)
+
+	    return code == 0
+
+    def swap_exp(self, pid, eid, direction='out', wait=True):
+	"""
+	Swap experiment in.
+	"""
+	if self.debug:
+	    if self.log:
+		self.log.info("[swap_exp]: (debug) Swapping %s %s" % \
+			(eid, direction))
+	    return True
+	else:
+	    if self.log:
+		self.log.info("[swap_exp]: Swapping %s %s" % (eid, direction))
+	    params = {
+		    'proj': pid,
+		    'exp': eid,
+		    'direction': direction,
+		    'wait': wait,
+		    }
+	    code, value = self.emulab_call('experiment.swapexp', params)
+
+	    if self.log:
+		if code == 0: self.log.info('[swap_exp]: Swap succeeded')
+		else: self.log.error('[swap_exp]: Swap failed: %s' % value)
+
+	return code == 0
+
+    def modify_exp(self, pid, eid, tcl, wait=True):
+	if self.debug:
+	    self.log.info("[modify_exp]: (debug) Modifying %s" % eid)
+	    return True
+	else:
+	    self.log.info("[modify_exp]: Modifying %s" % eid)
+	    params = {
+		    'proj': pid,
+		    'exp': eid,
+		    'nsfilestr': tcl,
+		    'wait': wait,
+		    'reboot': True,
+		    'restart_eventsys': True,
+		    }
+	    code, value = self.emulab_call('experiment.modify', params)
+	    if self.log:
+		if code == 0: 
+		    self.log.info('[modify_exp]: Modify succeeded')
+		else: 
+		    self.log.error('[modify_exp]: Modify failed: %s' \
+			    % value)
+	    return code == 0
+
+
+    def get_mapping(self, pid, eid):
+	"""
+	Get the physical to virtual mapping from the expinfo command and save
+	it in the self.map member.
+	"""
+
+	if self.debug:
+	    if self.log:
+		self.log.info("[get_mapping] (debug) Generating mapping")
+		return True
+	else:
+	    if self.log:
+		self.log.info("[get_mapping] Generating mapping")
+
+	    params = {
+		    'proj': pid,
+		    'exp': eid,
+		    'aspect': 'mapping'
+		    }
+	    code, nodes = self.emulab_call('experiment.info', params)
+	    if code ==0:
+		for k, v in nodes.items():
+		    if v.get('erole', False) and 'pnode' in v:
+			self.node[k] = v['pnode']
+		if self.log:
+		    self.log.info("Mapping complete")
+		return True
+	    else:
+		raise service_error(service_error.internal,
+			"Cannot get node mapping of segment:%s/%s" % (pid, eid))
+
