Index: fedd/fedd_client.py
===================================================================
--- fedd/fedd_client.py	(revision 45ebc4d93e220aff2f18e6f5e5dee6bf5fdc85db)
+++ fedd/fedd_client.py	(revision 03e0290ca3c8437abef1a5c25750bc49f5bea8c5)
@@ -20,5 +20,5 @@
 
 from fedd_util import fedid, fedd_ssl_context, pack_soap, unpack_soap, \
-	pack_id, unpack_id
+	pack_id, unpack_id, encapsulate_binaries, decapsulate_binaries
 
 from optparse import OptionParser, OptionValueError
@@ -76,74 +76,68 @@
 		version="0.1")
 
-	self.set_defaults(url="https://localhost:23235", anonymous=False,
-		serialize_only=False, transport="soap", use_fedid=False,
-		debug=0)
-
-	self.add_option("-a","--anonymous", action="store_true",
-		dest="anonymous", help="Do not include a user in the request")
 	self.add_option("-c","--cert", action="store", dest="cert",
 		type="string", help="my certificate file")
 	self.add_option("-d", "--debug", action="count", dest="debug", 
-		help="Set debug.  Repeat for more information")
-	self.add_option("-f","--useFedid", action="store_true",
-		dest="use_fedid",
+		default=0, help="Set debug.  Repeat for more information")
+	self.add_option("-s", "--serializeOnly", action="store_true", 
+		dest="serialize_only", default=False,
+		help="Print the SOAP request that would be sent and exit")
+	self.add_option("-T","--trusted", action="store", dest="trusted",
+		type="string", help="Trusted certificates (required)")
+	self.add_option("-u", "--url", action="store", dest="url",
+		type="string",default="https://localhost:23235",  
+		help="URL to connect to (default %default)")
+	self.add_option("-x","--transport", action="store", type="choice",
+		choices=("xmlrpc", "soap"), default="soap",
+		help="Transport for request (xmlrpc|soap) (Default: %default)")
+	self.add_option("--trace", action="store_const", dest="tracefile", 
+		const=sys.stderr, help="Print SOAP exchange to stderr")
+
+class fedd_create_opts(fedd_client_opts):
+    def __init__(self, access_keys, add_key_callback=None, 
+	    add_cert_callback=None):
+	fedd_client_opts.__init__(self)
+	self.add_option("-e", "--experiment_cert", dest="out_certfile",
+		type="string", help="output certificate file")
+	self.add_option("-F","--useFedid", action="store_true",
+		dest="use_fedid", default=False,
 		help="Use a fedid derived from my certificate as user identity")
-	self.add_option("-k", "--sshKey", action="callback", type="string", 
-		callback=add_ssh_key, callback_args=(access_keys,),
-		help="ssh key for access (can be supplied more than once")
-	self.add_option("-K", "--x509Key", action="callback", type="string", 
-		callback=add_x509_cert, callback_args=(access_keys,),
-		help="X509 certificate for access " + \
+	self.add_option("-f", "--file", dest="file", 
+		help="experiment description file")
+	if add_key_callback:
+	    self.add_option("-k", "--sshKey", action="callback", type="string", 
+		    callback=add_key_callback, callback_args=(access_keys,),
+		    help="ssh key for access (can be supplied more than once")
+	if add_cert_callback:
+	    self.add_option("-K", "--x509Key", action="callback",
+		    type="string", callback=add_cert_callback,
+		    callback_args=(access_keys,),
+		    help="X509 certificate for access " + \
 			"(can be supplied more than once")
+	self.add_option("-m", "--master", dest="master",
+		help="Master testbed in the federation")
+	self.add_option("-U", "--username", action="store", dest="user",
+		type="string", help="Use this username instead of the uid")
+
+class fedd_access_opts(fedd_create_opts):
+    def __init__(self, access_keys, node_descs, add_key_callback=None, 
+	    add_cert_callback=None, add_node_callback=None):
+	fedd_create_opts.__init__(self, access_keys, add_key_callback,
+		add_cert_callback)
+	self.add_option("-a","--anonymous", action="store_true",
+		dest="anonymous", default=False,
+		help="Do not include a user in the request")
 	self.add_option("-l","--label", action="store", dest="label",
 		type="string", help="Label for output")
-	self.add_option("-n", "--node", action="callback", type="string", 
-		callback=add_node_desc, callback_args=(node_descs,),
-		help="Node description: image:hardware[:count]")
+	if add_node_callback:
+	    self.add_option("-n", "--node", action="callback", type="string", 
+		    callback=add_node_callback, callback_args=(node_descs,),
+		    help="Node description: image:hardware[:count]")
 	self.add_option("-p", "--project", action="store", dest="project", 
 		type="string",
 		help="Use a project request with this project name")
-	self.add_option("-s", "--serializeOnly", action="store_true", 
-		dest="serialize_only",
-		help="Print the SOAP request that would be sent and exit")
 	self.add_option("-t", "--testbed", action="store", dest="testbed",
 		type="string",
 		help="Testbed identifier (URI) to contact (required)")
-	self.add_option("-T","--trusted", action="store", dest="trusted",
-		type="string", help="Trusted certificates (required)")
-	self.add_option("-u", "--url", action="store", dest="url",
-		type="string",
-		help="URL to connect to (default %default)")
-	self.add_option("-U", "--username", action="store", dest="user",
-		type="string", help="Use this username instead of the uid")
-	self.add_option("-x","--transport", action="store", type="choice",
-		choices=("xmlrpc", "soap"),
-		help="Transport for request (xmlrpc|soap) (Default: %default)")
-	self.add_option("--trace", action="store_const", dest="tracefile", 
-		const=sys.stderr, help="Print SOAP exchange to stderr")
-
-def print_response_as_testbed(resp, label, out=sys.stdout):
-    """Print the response as input to the splitter script"""
-
-    e = resp['emulab']
-    p = e['project']
-    fields = { 
-	    "Boss": e['boss'],
-	    "OpsNode": e['ops'],
-	    "Domain": e['domain'],
-	    "FileServer": e['fileServer'],
-	    "EventServer": e['eventServer'],
-	    "Project": unpack_id(p['name'])
-	    }
-    if (label != None): print >> out, "[%s]" % label
-
-    for l, v in fields.iteritems():
-	print >>out, "%s: %s" % (l, v)
-
-    for u in p['user']:
-	print >>out, "User: %s" % unpack_id(u['userID'])
-
-    for a in e['fedAttr']:
-	print >>out, "%s: %s" % (a['attribute'], a['value'])
 
 def exit_with_fault(dict, out=sys.stderr):
@@ -166,199 +160,463 @@
     sys.exit(dict.get('code', 20))
 
-def add_ssh_key(option, opt_str, value, parser, access_keys):
-    try:
-	access_keys.append(access_method(file=value,
-	    type=access_method.type_ssh))
-    except IOError, (errno, strerror):
-	raise OptionValueError("Cannot generate sshPubkey from %s: %s (%d)" %
-		(value,strerror,errno))
-
-def add_x509_cert(option, opt_str, value, parser, access_keys):
-    try:
-	access_keys.append(access_method(file=value,
-	    type=access_method.type_x509))
-    except IOError, (errno, strerror):
-	raise OptionValueError("Cannot read x509 cert from %s: %s (%d)" %
-		(value,strerror,errno))
-
-def add_node_desc(option, opt_str, value, parser, node_descs):
-    def none_if_zero(x):
-	if len(x) > 0: return x
-	else: return None
-
-    params = map(none_if_zero, value.split(":"));
-    
-    if len(params) < 4 and len(params) > 1:
-	node_descs.append(node_desc(*params))
-    else:
-	raise OptionValueError("Bad node description: %s" % value)
-
-def get_user_info(access_keys):
-    pw = pwd.getpwuid(os.getuid());
-    try_cert=None
-    user = None
-
-    if pw != None:
-	user = pw[0]
-	try_cert = "%s/.ssl/emulab.pem" % pw[5];
-	if not os.access(try_cert, os.R_OK):
-	    try_cert = None
-	if len(access_keys) == 0:
-	    for k in ["%s/.ssh/id_rsa.pub", "%s/.ssh/id_dsa.pub", 
-		    "%s/.ssh/identity.pub"]:
-		try_key = k % pw[5];
-		if os.access(try_key, os.R_OK):
-		    access_keys.append(access_method(file=try_key,
-			type=access_method.type_ssh))
-		    break
-    return (user, try_cert)
-
-access_keys = []
-node_descs = []
-proj = None
-
-# Process the options using the customized option parser defined above
-parser = fedd_client_opts()
-
-(opts, args) = parser.parse_args()
-
-if opts.testbed == None:
-    parser.error("--testbed is required")
-
-if opts.trusted != None:
-    if ( not os.access(opts.trusted, os.R_OK) ) :
-	sys.exit("Cannot read trusted certificates (%s)" % opts.trusted)
+class fedd_exp_data_opts(fedd_client_opts):
+    def __init__(self):
+	fedd_client_opts.__init__(self)
+	self.add_option("-e", "--experiment_cert", dest="exp_certfile",
+		type="string", help="output certificate file")
+
+# Base class that will do a the SOAP/XMLRPC exchange for a request.
+class fedd_rpc:
+    class RPCException:
+	def __init__(self, fb):
+	    self.desc = fb.get('desc', None)
+	    self.code = fb.get('code', None)
+	    self.errstr = fb.get('errstr', None)
+
+    def __init__(self, pre): 
+	"""
+	Specialize the class for the prc method
+	"""
+	self.RequestMessage = globals()["%sRequestMessage" % pre]
+	self.ResponseMessage = globals()["%sResponseMessage" % pre]
+	self.RequestBody="%sRequestBody" % pre
+	self.ResponseBody="%sResponseBody" % pre
+	self.method = pre
+	self.RPCException = fedd_rpc.RPCException
+
+
+    def add_ssh_key(self, option, opt_str, value, parser, access_keys):
+	try:
+	    access_keys.append(access_method(file=value,
+		type=access_method.type_ssh))
+	except IOError, (errno, strerror):
+	    raise OptionValueError("Cannot generate sshPubkey from %s: "\
+		    "%s (%d)" % (value,strerror,errno))
+
+    def add_x509_cert(self, option, opt_str, value, parser, access_keys):
+	try:
+	    access_keys.append(access_method(file=value,
+		type=access_method.type_x509))
+	except IOError, (errno, strerror):
+	    raise OptionValueError("Cannot read x509 cert from %s: %s (%d)" %
+		    (value,strerror,errno))
+    def add_node_desc(self, option, opt_str, value, parser, node_descs):
+	def none_if_zero(x):
+	    if len(x) > 0: return x
+	    else: return None
+
+	params = map(none_if_zero, value.split(":"));
+	
+	if len(params) < 4 and len(params) > 1:
+	    node_descs.append(node_desc(*params))
+	else:
+	    raise OptionValueError("Bad node description: %s" % value)
+
+    def get_user_info(self, access_keys):
+	pw = pwd.getpwuid(os.getuid());
+	try_cert=None
+	user = None
+
+	if pw != None:
+	    user = pw[0]
+	    try_cert = "%s/.ssl/emulab.pem" % pw[5];
+	    if not os.access(try_cert, os.R_OK):
+		try_cert = None
+	    if len(access_keys) == 0:
+		for k in ["%s/.ssh/id_rsa.pub", "%s/.ssh/id_dsa.pub", 
+			"%s/.ssh/identity.pub"]:
+		    try_key = k % pw[5];
+		    if os.access(try_key, os.R_OK):
+			access_keys.append(access_method(file=try_key,
+			    type=access_method.type_ssh))
+			break
+	return (user, try_cert)
+
+    def do_rpc(self, req_dict, url, transport, cert, trusted, tracefile=None,
+	    serialize_only=False):
+	"""
+	The work of sending and parsing the RPC as either XMLRPC or SOAP
+	"""
+
+	context = None
+	while context == None:
+	    try:
+		context = fedd_ssl_context(cert, trusted)
+	    except SSL.SSLError, e:
+		# Yes, doing this on message type is not ideal.  The string
+		# comes from OpenSSL, so check there is this stops working.
+		if str(e) == "bad decrypt": 
+		    print >>sys.stderr, "Bad Passphrase given."
+		else: raise
+
+	if transport == "soap":
+	    loc = feddServiceLocator();
+	    port = loc.getfeddPortType(url,
+		    transport=M2Crypto.httpslib.HTTPSConnection, 
+		    transdict={ 'ssl_context' : context },
+		    tracefile=tracefile)
+
+	    req = self.RequestMessage()
+
+	    set_req = getattr(req, "set_element_%s" % self.RequestBody, None)
+	    set_req(pack_soap(req, self.RequestBody, req_dict))
+
+	    if serialize_only:
+		sw = SoapWriter()
+		sw.serialize(req)
+		print str(sw)
+		sys.exit(0)
+
+	    try:
+		method_call = getattr(port, self.method, None)
+		resp = method_call(req)
+	    except ZSI.ParseException, e:
+		raise RuntimeError("Malformed response (XMLPRC?): %s" % e)
+	    except ZSI.FaultException, e:
+		resp = e.fault.detail[0]
+
+	    if resp:
+		resp_call = getattr(resp, "get_element_%s" %self.ResponseBody,
+			None)
+		if resp_call: 
+		    resp_body = resp_call()
+		    if ( resp_body != None): 
+			try:
+			    return unpack_soap(resp_body)
+			except RuntimeError, e:
+			    raise RuntimeError("Bad response. %s" % e.message)
+		elif 'get_element_FeddFaultBody' in dir(resp): 
+		    resp_body = resp.get_element_FeddFaultBody()
+		    if resp_body != None: 
+			try:
+			    fb = unpack_soap(resp_body)
+			except RuntimeError, e:
+			    raise RuntimeError("Bad response. %s" % e.message)
+			raise self.RPCException(fb)
+		else: 
+		    raise RuntimeError("No body in response!?")
+	    else: 
+		raise RuntimeError("No response?!?")
+	elif transport == "xmlrpc":
+	    if serialize_only:
+		ser = dumps((req_dict,))
+		print ser
+		sys.exit(0)
+
+	    xtransport = SSL_Transport(context)
+	    port = ServerProxy(url, transport=xtransport)
+
+	    try:
+		method_call = getattr(port, self.method, None)
+		resp = method_call(
+			encapsulate_binaries({ self.RequestBody: msg},\
+			    ('fedid',)))
+	    except Error, e:
+		resp = { 'FeddFaultBody': \
+			{ 'errstr' : e.faultCode, 'desc' : e.faultString } }
+	    if resp:
+		if resp.has_key(self.ResponseBody): 
+		    return resp[self.ResponseBody]
+		elif resp.has_key('FeddFaultBody'):
+		    raise self.RPCException(resp['FeddFaultBody'])
+		else: 
+		    raise RuntimeError("No body in response!?")
+	    else: 
+		raise RuntimeError("No response?!?")
+	else:
+	    raise RuntimeError("Unknown RPC transport: %s" % transport)
+
+# Querying experiment data follows the same control flow regardless of the
+# specific data retrieved.  This class encapsulates that control flow.
+class exp_data(fedd_rpc):
+    def __init__(self, op): 
+	"""
+	Specialize the class for the type of data requested (op)
+	"""
+
+	fedd_rpc.__init__(self, op)
+	if op =='Vtopo':
+	    self.key="vtopo"
+	    self.xml='experiment'
+	elif op == 'Vis':
+	    self.key="vis"
+	    self.xml='vis'
+	else:
+	    raise TypeError("Bad op: %s" % op)
+
+    def print_xml(self, d, out=sys.stdout):
+	"""
+	Print the retrieved data is a simple xml representation of the dict.
+	"""
+	str = "<%s>\n" % self.xml
+	for t in ('node', 'lan'):
+	    if d.has_key(t): 
+		for x in d[t]:
+		    str += "<%s>" % t
+		    for k in x.keys():
+			str += "<%s>%s</%s>" % (k, x[k],k)
+		    str += "</%s>\n" % t
+	str+= "</%s>" % self.xml
+	print >>out, str
+
+    def __call__(self):
+	"""
+	The control flow.  Compose the request and print the response.
+	"""
+	# Process the options using the customized option parser defined above
+	parser = fedd_exp_data_opts()
+
+	(opts, args) = parser.parse_args()
+
+	if opts.trusted != None:
+	    if ( not os.access(opts.trusted, os.R_OK) ) :
+		sys.exit("Cannot read trusted certificates (%s)" % opts.trusted)
+	else:
+	    parser.error("--trusted is required")
+
+	if opts.debug > 0: opts.tracefile=sys.stderr
+
+	if opts.cert != None: cert = opts.cert
+
+	if cert == None:
+	    sys.exit("No certificate given (--cert) or found")
+
+	if os.access(cert, os.R_OK):
+	    fid = fedid(file=cert)
+	else:
+	    sys.exit("Cannot read certificate (%s)" % cert)
+
+	if opts.exp_certfile:
+	    exp_fedid = fedid(file=opts.exp_certfile)
+	else:
+	    sys.exit("Experiment certfile required")
+
+	try:
+	    resp_dict = self.do_rpc({ 'experiment': { 'fedid': exp_fedid } }, 
+		    opts.url, opts.transport, cert, opts.trusted, 
+		    serialize_only=opts.serialize_only,
+		    tracefile=opts.tracefile)
+	except self.RPCException, e:
+	    exit_with_fault(\
+		    {'desc': e.desc, 'errstr': e.errstr, 'code': e.code})
+	except RuntimeError, e:
+	    sys.exit("Error processing RPC: %s" % e.message)
+
+	try:
+	    if resp_dict.has_key(self.key):
+		self.print_xml(resp_dict[self.key])
+	except RuntimeError, e:
+	    sys.exit("Bad response. %s" % e.message)
+
+class create(fedd_rpc):
+    def __init__(self): 
+	fedd_rpc.__init__(self, "Create")
+    def __call__(self):
+	access_keys = []
+	# Process the options using the customized option parser defined above
+	parser = fedd_create_opts(access_keys, self.add_ssh_key,
+		self.add_x509_cert)
+
+	(opts, args) = parser.parse_args()
+
+	if opts.trusted != None:
+	    if ( not os.access(opts.trusted, os.R_OK) ) :
+		sys.exit("Cannot read trusted certificates (%s)" % opts.trusted)
+	else:
+	    parser.error("--trusted is required")
+
+	if opts.debug > 0: opts.tracefile=sys.stderr
+
+	(user, cert) = self.get_user_info(access_keys)
+
+	if opts.user: user = opts.user
+
+	if opts.cert != None: cert = opts.cert
+
+	if cert == None:
+	    sys.exit("No certificate given (--cert) or found")
+
+	if os.access(cert, os.R_OK):
+	    fid = fedid(file=cert)
+	    if opts.use_fedid == True:
+		user = fid
+	else:
+	    sys.exit("Cannot read certificate (%s)" % cert)
+
+	if opts.file:
+	    exp_desc = ""
+	    try:
+		f = open(opts.file, 'r')
+		for line in f:
+		    exp_desc += line
+		f.close()
+	    except IOError:
+		sys.exit("Cannot read description file (%s)" %opts.file)
+	else:
+	    sys.exit("Must specify an experiment description (--file)")
+
+	if not opts.master:
+	    sys.exit("Must specify a master testbed (--master)")
+
+	out_certfile = opts.out_certfile
+
+	msg = {
+		'experimentdescription': exp_desc,
+		'master': opts.master,
+		'user' : [ {\
+			'userID': pack_id(user), \
+			'access': [ { a.type: a.buf } for a in access_keys]\
+			} ]
+		}
+
+	if opts.debug > 1: print >>sys.stderr, msg
+
+	try:
+	    resp_dict = self.do_rpc(msg, 
+		    opts.url, opts.transport, cert, opts.trusted, 
+		    serialize_only=opts.serialize_only,
+		    tracefile=opts.tracefile)
+	except self.RPCException, e:
+	    exit_with_fault(\
+		    {'desc': e.desc, 'errstr': e.errstr, 'code': e.code})
+	except RuntimeError, e:
+	    sys.exit("Error processing RPC: %s" % e.message)
+
+	if opts.debug > 1: print >>sys.stderr, resp_dict
+
+	ea = resp_dict.get('experimentAccess', None)
+	if out_certfile and ea and ea.has_key('X509'):
+	    try:
+		f = open(out_certfile, "w")
+		print >>f, ea['X509']
+		f.close()
+	    except IOError:
+		sys.exit('Could not write to %s' %  out_certfile)
+
+class access(fedd_rpc):
+    def __init__(self):
+	fedd_rpc.__init__(self, "RequestAccess")
+
+    def print_response_as_testbed(self, resp, label, out=sys.stdout):
+	"""Print the response as input to the splitter script"""
+
+	e = resp['emulab']
+	p = e['project']
+	fields = { 
+		"Boss": e['boss'],
+		"OpsNode": e['ops'],
+		"Domain": e['domain'],
+		"FileServer": e['fileServer'],
+		"EventServer": e['eventServer'],
+		"Project": unpack_id(p['name'])
+		}
+	if (label != None): print >> out, "[%s]" % label
+
+	for l, v in fields.iteritems():
+	    print >>out, "%s: %s" % (l, v)
+
+	for u in p['user']:
+	    print >>out, "User: %s" % unpack_id(u['userID'])
+
+	for a in e['fedAttr']:
+	    print >>out, "%s: %s" % (a['attribute'], a['value'])
+
+    def __call__(self):
+	access_keys = []
+	node_descs = []
+	proj = None
+
+	# Process the options using the customized option parser defined above
+	parser = fedd_access_opts(access_keys, node_descs, self.add_ssh_key,
+		self.add_x509_cert, self.add_node_desc)
+
+	(opts, args) = parser.parse_args()
+
+	if opts.testbed == None:
+	    parser.error("--testbed is required")
+
+	if opts.trusted != None:
+	    if ( not os.access(opts.trusted, os.R_OK) ) :
+		sys.exit("Cannot read trusted certificates (%s)" % opts.trusted)
+	else:
+	    parser.error("--trusted is required")
+
+	if opts.debug > 0: opts.tracefile=sys.stderr
+
+	(user, cert) = self.get_user_info(access_keys)
+
+	if opts.user: user = opts.user
+
+	if opts.cert != None: cert = opts.cert
+
+	if cert == None:
+	    sys.exit("No certificate given (--cert) or found")
+
+	if os.access(cert, os.R_OK):
+	    fid = fedid(file=cert)
+	    if opts.use_fedid == True:
+		user = fid
+	else:
+	    sys.exit("Cannot read certificate (%s)" % cert)
+
+	msg = {
+		'allocID': pack_id('test alloc'),
+		'destinationTestbed': pack_id(opts.testbed),
+		'access' : [ { a.type: a.buf } for a in access_keys ],
+		}
+
+	if len(node_descs) > 0:
+	    msg['resources'] = { 
+		    'node': [ 
+			{ 
+			    'image':  n.image ,
+			    'hardware':  n.hardware,
+			    'count': n.count,
+			} for n in node_descs],
+		    }
+
+	if opts.project != None:
+	    if not opts.anonymous and user != None:
+		msg['project'] = {
+			'name': pack_id(opts.project),
+			'user': [ { 'userID': pack_id(user) } ],
+			}
+	    else:
+		msg['project'] = { 'name': pack_id(opts.project) }
+	else:
+	    if not opts.anonymous and user != None:
+		msg['user'] = [ { 'userID': pack_id(user) } ]
+	    else:
+		msg['user'] = [];
+
+	if opts.debug > 1: print >>sys.stderr, msg
+
+	try:
+	    resp_dict = self.do_rpc(msg, 
+		    opts.url, opts.transport, cert, opts.trusted, 
+		    serialize_only=opts.serialize_only,
+		    tracefile=opts.tracefile)
+	except self.RPCException, e:
+	    exit_with_fault(\
+		    {'desc': e.desc, 'errstr': e.errstr, 'code': e.code})
+	except RuntimeError, e:
+	    sys.exit("Error processing RPC: %s" % e.message)
+
+	if opts.debug > 1: print >>sys.stderr, resp_dict
+	self.print_response_as_testbed(resp_dict, opts.label)
+
+cmds = {\
+	'create': create(),\
+	'access': access(),\
+	'vtopo': exp_data('Vtopo'),\
+	'vis': exp_data('Vis'),\
+    }
+
+operation = cmds.get(sys.argv[1], None)
+if operation:
+    del sys.argv[1]
+    operation()
 else:
-    parser.error("--trusted is required")
-
-if opts.debug > 0: opts.tracefile=sys.stderr
-
-(user, cert) = get_user_info(access_keys)
-
-if opts.user: user = opts.user
-
-if opts.cert != None: cert = opts.cert
-
-if cert == None:
-    sys.exit("No certificate given (--cert) or found")
-
-if os.access(cert, os.R_OK):
-    fid = fedid(file=cert)
-    if opts.use_fedid == True:
-	user = fid
-else:
-    sys.exit("Cannot read certificate (%s)" % cert)
-
-context = None
-while context == None:
-    try:
-	context = fedd_ssl_context(cert, opts.trusted)
-    except SSL.SSLError, e:
-	# Yes, doing this on message type is not ideal.  The string comes from
-	# OpenSSL, so check there is this stops working.
-	if str(e) == "bad decrypt": 
-	    print >>sys.stderr, "Bad Passphrase given."
-	else: raise
-
-msg = {
-	'allocID': pack_id('test alloc'),
-	'destinationTestbed': pack_id(opts.testbed),
-	'access' : [ { a.type: a.buf } for a in access_keys ],
-	}
-
-if len(node_descs) > 0:
-    msg['resources'] = { 
-	    'node': [ 
-		{ 
-		    'image':  n.image ,
-		    'hardware':  n.hardware,
-		    'count': n.count,
-		} for n in node_descs],
-	    }
-
-if opts.project != None:
-    if not opts.anonymous and user != None:
-	msg['project'] = {
-		'name': pack_id(opts.project),
-		'user': [ { 'userID': pack_id(user) } ],
-		}
-    else:
-	msg['project'] = { 'name': pack_id(opts.project) }
-else:
-    if not opts.anonymous and user != None:
-	msg['user'] = [ { 'userID': pack_id(user) } ]
-    else:
-	msg['user'] = [];
-
-if opts.debug > 1: print >>sys.stderr, msg
-
-if opts.transport == "soap":
-    loc = feddServiceLocator();
-    port = loc.getfeddPortType(opts.url,
-	    transport=M2Crypto.httpslib.HTTPSConnection, 
-	    transdict={ 'ssl_context' : context },
-	    tracefile=opts.tracefile)
-
-    req = RequestAccessRequestMessage()
-
-    req.set_element_RequestAccessRequestBody(
-	    pack_soap(req, "RequestAccessRequestBody", msg))
-
-    if opts.serialize_only:
-	sw = SoapWriter()
-	sw.serialize(req)
-	print str(sw)
-	sys.exit(0)
-
-    try:
-	resp = port.RequestAccess(req)
-    except ZSI.ParseException, e:
-	sys.exit("Malformed response (XMLPRC?): %s" % e)
-    except ZSI.FaultException, e:
-	resp = e.fault.detail[0]
-
-    if (resp != None):
-	if 'get_element_RequestAccessResponseBody' in dir(resp): 
-	    resp_body = resp.get_element_RequestAccessResponseBody()
-	    if ( resp_body != None): 
-		try:
-		    resp_dict = unpack_soap(resp_body)
-		    if opts.debug > 1: print >>sys.stderr, resp_dict
-		    print_response_as_testbed(resp_dict, opts.label)
-		except RuntimeError, e:
-		    sys.exit("Bad response. %s" % e.message)
-	elif 'get_element_FeddFaultBody' in dir(resp): 
-	    resp_body = resp.get_element_FeddFaultBody()
-	    if resp_body != None: 
-		exit_with_fault(unpack_soap(resp_body))
-	else: sys.exit("No body in response!?")
-    else: sys.exit("No response?!?")
-elif opts.transport == "xmlrpc":
-    if opts.serialize_only:
-	ser = dumps((msg,))
-	sys.exit(0)
-
-    transport = SSL_Transport(context)
-    port = ServerProxy(opts.url, transport=transport)
-
-    try:
-	resp = port.RequestAccess({ 'RequestAccessRequestBody': msg})
-	resp, method = loads(resp)
-    except Error, e:
-	resp = { 'FeddFaultBody': \
-		{ 'errstr' : e.faultCode, 'desc' : e.faultString } }
-
-
-    if (resp != None):
-	if resp.has_key('RequestAccessReponseBody'): 
-	    try:
-		resp_dict = resp[0]['RequestAccessResponseBody']
-		if opts.debug > 1: print >>sys.stderr, resp_dict
-		print_response_as_testbed(resp_dict, opts.label)
-	    except RuntimeError, e:
-		sys.exit("Bad response. %s" % e.messgae)
-	elif resp.has_key('FeddFaultBody'):
-	    exit_with_fault(resp['FeddFaultBody'])
-	else: sys.exit("No body in response!?")
-
-    else: sys.exit("No response?!?")
+    sys.exit("Bad command: %s.  Valid ones are: %s" % \
+	    (sys.argv[1], ", ".join(cmds.keys())))
+
Index: fedd/fedd_create.py
===================================================================
--- fedd/fedd_create.py	(revision 45ebc4d93e220aff2f18e6f5e5dee6bf5fdc85db)
+++ 	(revision )
@@ -1,481 +1,0 @@
-#!/usr/local/bin/python
-
-import sys
-import os
-import pwd
-
-from fedd_services import *
-
-from M2Crypto import SSL, X509
-from M2Crypto.m2xmlrpclib import SSL_Transport
-import M2Crypto.httpslib
-
-from xmlrpclib import ServerProxy, Error, dumps, loads
-from ZSI import SoapWriter
-from ZSI.TC import QName, String, URI, AnyElement, UNBOUNDED, Any
-from ZSI.wstools.Namespaces import SOAP
-from ZSI.fault import FaultType, Detail
-
-import xmlrpclib
-
-from fedd_util import fedid, fedd_ssl_context, pack_soap, unpack_soap, \
-	pack_id, unpack_id, encapsulate_binaries, decapsulate_binaries
-
-from optparse import OptionParser, OptionValueError
-
-import parse_detail
-
-# Turn off the matching of hostname to certificate ID
-SSL.Connection.clientPostConnectionCheck = None
-
-class IDFormatException(RuntimeError): pass
-
-class access_method:
-    """Encapsulates an access method generically."""
-    (type_ssh, type_x509, type_pgp) = ('sshPubkey', 'X509', 'pgpPubkey')
-    default_type = type_ssh
-    def __init__(self, buf=None, type=None, file=None):
-	self.buf = buf
-
-	if type != None: self.type = type
-	else: self.type = access_method.default_type
-
-	if file != None:
-	    self.readfile(file)
-    
-    def readfile(self, file, type=None):
-	f = open(file, "r")
-	self.buf = f.read();
-	f.close()
-	if type == None:
-	    if self.type == None:
-		self.type = access_method.default_type
-	else:
-	    self.type = type;
-    
-class node_desc:
-    def __init__(self, image, hardware, count=1):
-	if getattr(image, "__iter__", None) == None:
-	    if image == None: self.image = [ ]
-	    else: self.image = [ image ]
-	else:
-	    self.image = image
-
-	if getattr(hardware, "__iter__", None) == None: 
-	    if hardware == None: self.hardware = [ ]
-	    else: self.hardware = [ hardware ]
-	else:
-	    self.hardware = hardware
-	if count != None: self.count = int(count)
-	else: self.count = 1
-
-class fedd_client_opts(OptionParser):
-    """Encapsulate option processing in this class, rather than in main"""
-    def __init__(self):
-	OptionParser.__init__(self, usage="%prog [opts] (--help for details)",
-		version="0.1")
-
-	self.add_option("-c","--cert", action="store", dest="cert",
-		type="string", help="my certificate file")
-	self.add_option("-d", "--debug", action="count", dest="debug", 
-		default=0, help="Set debug.  Repeat for more information")
-	self.add_option("-s", "--serializeOnly", action="store_true", 
-		dest="serialize_only", default=False,
-		help="Print the SOAP request that would be sent and exit")
-	self.add_option("-T","--trusted", action="store", dest="trusted",
-		type="string", help="Trusted certificates (required)")
-	self.add_option("-u", "--url", action="store", dest="url",
-		type="string",default="https://localhost:23235",  
-		help="URL to connect to (default %default)")
-	self.add_option("-x","--transport", action="store", type="choice",
-		choices=("xmlrpc", "soap"), default="soap",
-		help="Transport for request (xmlrpc|soap) (Default: %default)")
-	self.add_option("--trace", action="store_const", dest="tracefile", 
-		const=sys.stderr, help="Print SOAP exchange to stderr")
-
-class fedd_create_opts(fedd_client_opts):
-    def __init__(self, access_keys, add_key_callback=None, 
-	    add_cert_callback=None):
-	fedd_client_opts.__init__(self)
-	self.add_option("-e", "--experiment_cert", dest="out_certfile",
-		type="string", help="output certificate file")
-	self.add_option("-F","--useFedid", action="store_true",
-		dest="use_fedid", default=False,
-		help="Use a fedid derived from my certificate as user identity")
-	self.add_option("-f", "--file", dest="file", 
-		help="experiment description file")
-	if add_key_callback:
-	    self.add_option("-k", "--sshKey", action="callback", type="string", 
-		    callback=add_key_callback, callback_args=(access_keys,),
-		    help="ssh key for access (can be supplied more than once")
-	if add_cert_callback:
-	    self.add_option("-K", "--x509Key", action="callback",
-		    type="string", callback=add_cert_callback,
-		    callback_args=(access_keys,),
-		    help="X509 certificate for access " + \
-			"(can be supplied more than once")
-	self.add_option("-m", "--master", dest="master",
-		help="Master testbed in the federation")
-	self.add_option("-U", "--username", action="store", dest="user",
-		type="string", help="Use this username instead of the uid")
-
-def exit_with_fault(dict, out=sys.stderr):
-    """ Print an error message and exit.
-
-    The dictionary contains the FeddFaultBody elements."""
-    codestr = ""
-
-    if dict.has_key('errstr'):
-	codestr = "Error: %s" % dict['errstr']
-
-    if dict.has_key('code'):
-	if len(codestr) > 0 : 
-	    codestr += " (%d)" % dict['code']
-	else:
-	    codestr = "Error Code: %d" % dict['code']
-
-    print>>out, codestr
-    print>>out, "Description: %s" % dict['desc']
-    sys.exit(dict.get('code', 20))
-
-class fedd_exp_data_opts(fedd_client_opts):
-    def __init__(self):
-	fedd_client_opts.__init__(self)
-	self.add_option("-e", "--experiment_cert", dest="exp_certfile",
-		type="string", help="output certificate file")
-
-# Base class that will do a the SOAP/XMLRPC exchange for a request.
-class fedd_rpc:
-    class RPCException:
-	def __init__(self, fb):
-	    self.desc = fb.get('desc', None)
-	    self.code = fb.get('code', None)
-	    self.errstr = fb.get('errstr', None)
-
-    def __init__(self, pre): 
-	"""
-	Specialize the class for the prc method
-	"""
-	self.RequestMessage = globals()["%sRequestMessage" % pre]
-	self.ResponseMessage = globals()["%sResponseMessage" % pre]
-	self.RequestBody="%sRequestBody" % pre
-	self.ResponseBody="%sResponseBody" % pre
-	self.method = pre
-	self.RPCException = fedd_rpc.RPCException
-
-    def do_rpc(self, req_dict, url, transport, cert, trusted, tracefile=None,
-	    serialize_only=False):
-	"""
-	The work of sending and parsing the RPC as either XMLRPC or SOAP
-	"""
-
-	context = None
-	while context == None:
-	    try:
-		context = fedd_ssl_context(cert, trusted)
-	    except SSL.SSLError, e:
-		# Yes, doing this on message type is not ideal.  The string
-		# comes from OpenSSL, so check there is this stops working.
-		if str(e) == "bad decrypt": 
-		    print >>sys.stderr, "Bad Passphrase given."
-		else: raise
-
-	if transport == "soap":
-	    loc = feddServiceLocator();
-	    port = loc.getfeddPortType(url,
-		    transport=M2Crypto.httpslib.HTTPSConnection, 
-		    transdict={ 'ssl_context' : context },
-		    tracefile=tracefile)
-
-	    req = self.RequestMessage()
-
-	    set_req = getattr(req, "set_element_%s" % self.RequestBody, None)
-	    set_req(pack_soap(req, self.RequestBody, req_dict))
-
-	    if serialize_only:
-		sw = SoapWriter()
-		sw.serialize(req)
-		print str(sw)
-		sys.exit(0)
-
-	    try:
-		method_call = getattr(port, self.method, None)
-		resp = method_call(req)
-	    except ZSI.ParseException, e:
-		raise RuntimeError("Malformed response (XMLPRC?): %s" % e)
-	    except ZSI.FaultException, e:
-		resp = e.fault.detail[0]
-
-	    if resp:
-		resp_call = getattr(resp, "get_element_%s" %self.ResponseBody,
-			None)
-		if resp_call: 
-		    resp_body = resp_call()
-		    if ( resp_body != None): 
-			try:
-			    return unpack_soap(resp_body)
-			except RuntimeError, e:
-			    raise RuntimeError("Bad response. %s" % e.message)
-		elif 'get_element_FeddFaultBody' in dir(resp): 
-		    resp_body = resp.get_element_FeddFaultBody()
-		    if resp_body != None: 
-			try:
-			    fb = unpack_soap(resp_body)
-			except RuntimeError, e:
-			    raise RuntimeError("Bad response. %s" % e.message)
-			raise self.RPCException(fb)
-		else: 
-		    raise RuntimeError("No body in response!?")
-	    else: 
-		raise RuntimeError("No response?!?")
-	elif transport == "xmlrpc":
-	    if serialize_only:
-		ser = dumps((req_dict,))
-		print ser
-		sys.exit(0)
-
-	    xtransport = SSL_Transport(context)
-	    port = ServerProxy(url, transport=xtransport)
-
-	    try:
-		method_call = getattr(port, self.method, None)
-		resp = method_call(
-			encapsulate_binaries({ self.RequestBody: msg},\
-			    ('fedid',)))
-	    except Error, e:
-		resp = { 'FeddFaultBody': \
-			{ 'errstr' : e.faultCode, 'desc' : e.faultString } }
-	    if resp:
-		if resp.has_key(self.ResponseBody): 
-		    return resp[self.ResponseBody]
-		elif resp.has_key('FeddFaultBody'):
-		    raise self.RPCException(resp['FeddFaultBody'])
-		else: 
-		    raise RuntimeError("No body in response!?")
-	    else: 
-		raise RuntimeError("No response?!?")
-	else:
-	    raise RuntimeError("Unknown RPC transport: %s" % transport)
-
-# Querying experiment data follows the same control flow regardless of the
-# specific data retrieved.  This class encapsulates that control flow.
-class exp_data(fedd_rpc):
-    def __init__(self, op): 
-	"""
-	Specialize the class for the type of data requested (op)
-	"""
-
-	fedd_rpc.__init__(self, op)
-	if op =='Vtopo':
-	    self.key="vtopo"
-	    self.xml='experiment'
-	elif op == 'Vis':
-	    self.key="vis"
-	    self.xml='vis'
-	else:
-	    raise TypeError("Bad op: %s" % op)
-
-    def print_xml(self, d, out=sys.stdout):
-	"""
-	Print the retrieved data is a simple xml representation of the dict.
-	"""
-	str = "<%s>\n" % self.xml
-	for t in ('node', 'lan'):
-	    if d.has_key(t): 
-		for x in d[t]:
-		    str += "<%s>" % t
-		    for k in x.keys():
-			str += "<%s>%s</%s>" % (k, x[k],k)
-		    str += "</%s>\n" % t
-	str+= "</%s>" % self.xml
-	print >>out, str
-
-    def __call__(self):
-	"""
-	The control flow.  Compose the request and print the response.
-	"""
-	# Process the options using the customized option parser defined above
-	parser = fedd_exp_data_opts()
-
-	(opts, args) = parser.parse_args()
-
-	if opts.trusted != None:
-	    if ( not os.access(opts.trusted, os.R_OK) ) :
-		sys.exit("Cannot read trusted certificates (%s)" % opts.trusted)
-	else:
-	    parser.error("--trusted is required")
-
-	if opts.debug > 0: opts.tracefile=sys.stderr
-
-	if opts.cert != None: cert = opts.cert
-
-	if cert == None:
-	    sys.exit("No certificate given (--cert) or found")
-
-	if os.access(cert, os.R_OK):
-	    fid = fedid(file=cert)
-	else:
-	    sys.exit("Cannot read certificate (%s)" % cert)
-
-	if opts.exp_certfile:
-	    exp_fedid = fedid(file=opts.exp_certfile)
-	else:
-	    sys.exit("Experiment certfile required")
-
-	try:
-	    resp_dict = self.do_rpc({ 'experiment': { 'fedid': exp_fedid } }, 
-		    opts.url, opts.transport, cert, opts.trusted, 
-		    serialize_only=opts.serialize_only,
-		    tracefile=opts.tracefile)
-	except self.RPCException, e:
-	    exit_with_fault(\
-		    {'desc': e.desc, 'errstr': e.errstr, 'code': e.code})
-	except RuntimeError, e:
-	    sys.exit("Error processing RPC: %s" % e.message)
-
-	try:
-	    if resp_dict.has_key(self.key):
-		self.print_xml(resp_dict[self.key])
-	except RuntimeError, e:
-	    sys.exit("Bad response. %s" % e.message)
-
-class create(fedd_rpc):
-    def __init__(self): 
-	fedd_rpc.__init__(self, "Create")
-
-    def add_ssh_key(self, option, opt_str, value, parser, access_keys):
-	try:
-	    access_keys.append(access_method(file=value,
-		type=access_method.type_ssh))
-	except IOError, (errno, strerror):
-	    raise OptionValueError("Cannot generate sshPubkey from %s: "\
-		    "%s (%d)" % (value,strerror,errno))
-
-    def add_x509_cert(self, option, opt_str, value, parser, access_keys):
-	try:
-	    access_keys.append(access_method(file=value,
-		type=access_method.type_x509))
-	except IOError, (errno, strerror):
-	    raise OptionValueError("Cannot read x509 cert from %s: %s (%d)" %
-		    (value,strerror,errno))
-
-    def get_user_info(self, access_keys):
-	pw = pwd.getpwuid(os.getuid());
-	try_cert=None
-	user = None
-
-	if pw != None:
-	    user = pw[0]
-	    try_cert = "%s/.ssl/emulab.pem" % pw[5];
-	    if not os.access(try_cert, os.R_OK):
-		try_cert = None
-	    if len(access_keys) == 0:
-		for k in ["%s/.ssh/id_rsa.pub", "%s/.ssh/id_dsa.pub", 
-			"%s/.ssh/identity.pub"]:
-		    try_key = k % pw[5];
-		    if os.access(try_key, os.R_OK):
-			access_keys.append(access_method(file=try_key,
-			    type=access_method.type_ssh))
-			break
-	return (user, try_cert)
-
-    def __call__(self):
-	access_keys = []
-	# Process the options using the customized option parser defined above
-	parser = fedd_create_opts(access_keys, self.add_ssh_key,
-		self.add_x509_cert)
-
-	(opts, args) = parser.parse_args()
-
-	if opts.trusted != None:
-	    if ( not os.access(opts.trusted, os.R_OK) ) :
-		sys.exit("Cannot read trusted certificates (%s)" % opts.trusted)
-	else:
-	    parser.error("--trusted is required")
-
-	if opts.debug > 0: opts.tracefile=sys.stderr
-
-	(user, cert) = self.get_user_info(access_keys)
-
-	if opts.user: user = opts.user
-
-	if opts.cert != None: cert = opts.cert
-
-	if cert == None:
-	    sys.exit("No certificate given (--cert) or found")
-
-	if os.access(cert, os.R_OK):
-	    fid = fedid(file=cert)
-	    if opts.use_fedid == True:
-		user = fid
-	else:
-	    sys.exit("Cannot read certificate (%s)" % cert)
-
-	if opts.file:
-	    exp_desc = ""
-	    try:
-		f = open(opts.file, 'r')
-		for line in f:
-		    exp_desc += line
-		f.close()
-	    except IOError:
-		sys.exit("Cannot read description file (%s)" %opts.file)
-	else:
-	    sys.exit("Must specify an experiment description (--file)")
-
-	if not opts.master:
-	    sys.exit("Must specify a master testbed (--master)")
-
-	out_certfile = opts.out_certfile
-
-	msg = {
-		'experimentdescription': exp_desc,
-		'master': opts.master,
-		'user' : [ {\
-			'userID': pack_id(user), \
-			'access': [ { a.type: a.buf } for a in access_keys]\
-			} ]
-		}
-
-	if opts.debug > 1: print >>sys.stderr, msg
-
-	try:
-	    resp_dict = self.do_rpc(msg, 
-		    opts.url, opts.transport, cert, opts.trusted, 
-		    serialize_only=opts.serialize_only,
-		    tracefile=opts.tracefile)
-	except self.RPCException, e:
-	    exit_with_fault(\
-		    {'desc': e.desc, 'errstr': e.errstr, 'code': e.code})
-	except RuntimeError, e:
-	    sys.exit("Error processing RPC: %s" % e.message)
-
-	if opts.debug > 1: print >>sys.stderr, resp_dict
-
-	ea = resp_dict.get('experimentAccess', None)
-	if out_certfile and ea and ea.has_key('X509'):
-	    try:
-		f = open(out_certfile, "w")
-		print >>f, ea['X509']
-		f.close()
-	    except IOError:
-		sys.exit('Could not write to %s' %  out_certfile)
-
-valid_cmds = ['create']
-
-f = None
-if sys.argv[1] == 'create':
-    del sys.argv[1]
-    f = create()
-elif sys.argv[1] == 'vtopo':
-    del sys.argv[1]
-    f = exp_data('Vtopo')
-elif sys.argv[1] == 'vis':
-    del sys.argv[1]
-    f = exp_data('Vis')
-else:
-    sys.exit("Bad command: %s.  Valid ones are: %s" % \
-	    (sys.argv[1], ", ".join(valid_cmds)))
-
-if f: f()
-else: sys.exit("Null function?!?")
