Index: fedd/fedd_create.py
===================================================================
--- fedd/fedd_create.py	(revision f1550c820d99e0482ebbc647b599b0e529aa86fb)
+++ fedd/fedd_create.py	(revision f1550c820d99e0482ebbc647b599b0e529aa86fb)
@@ -0,0 +1,163 @@
+#!/usr/local/bin/python
+
+import sys
+
+from federation.remote_service import service_caller
+from federation.client_lib import client_opts, exit_with_fault, RPCException, \
+	wrangle_standard_options, do_rpc, get_experiment_names, save_certfile
+
+class fedd_create_opts(client_opts):
+    """
+    Extra options that create needs.  Help entries should explain them.
+    """
+    def __init__(self):
+        client_opts.__init__(self)
+        self.add_option("--experiment_cert", dest="out_certfile",
+                type="string", help="output certificate file")
+        self.add_option("--experiment_name", dest="exp_name",
+                type="string", help="Suggested experiment name")
+        self.add_option("--file", dest="file", 
+                help="experiment description file")
+        self.add_option("--project", action="store", dest="project", 
+                type="string",
+                help="Project to export from master")
+        self.add_option("--master", dest="master",
+                help="Master testbed in the federation (pseudo project export)")
+	self.add_option("--service", dest="service", action="append",
+		type="string", default=[],
+		help="Service description name:exporters:importers:attrs")
+
+def parse_service(svc):
+    """
+    Pasre a service entry into a hash representing a service entry in a
+    message.  The format is:
+	svc_name:exporter(s):importer(s):attr=val,attr=val
+    The svc_name is teh service name, exporter is the exporting testbeds
+    (comma-separated) importer is the importing testbeds (if any) and the rest
+    are attr=val pairs that will become attributes of the service.  These
+    include parameters and other such stuff.
+    """
+
+    terms = svc.split(':')
+    svcd = { }
+    if len(terms) < 2 or len(terms[0]) == 0 or len(terms[1]) == 0:
+	sys.exit("Bad service description '%s': Not enough terms" % svc)
+    
+    svcd['name'] = terms[0]
+    svcd['export'] = terms[1].split(",")
+    if len(terms) > 2 and len(terms[2]) > 0:
+	svcd['import'] = terms[2].split(",")
+    if len(terms) > 3 and len(terms[3]) > 0:
+	svcd['fedAttr'] = [ ]
+	for t in terms[3].split(","):
+	    i = t.find("=")
+	    if i != -1 :
+		svcd['fedAttr'].append(
+			{'attribute': t[0:i], 'value': t[i+1:]})
+	    else:
+		sys.exit("Bad service attribute '%s': no equals sign" % t)
+    return svcd
+
+def project_export_service(master, project):
+    """
+    Output the dict representation of a project_export service for this project
+    and master.
+    """
+    return {
+	    'name': 'project_export', 
+	    'export': [master], 
+	    'importall': True,
+	    'fedAttr': [ 
+		{ 'attribute': 'project', 'value': project },
+		],
+	    }
+
+# Main line
+parser = fedd_create_opts()
+(opts, args) = parser.parse_args()
+
+
+cert, fid = wrangle_standard_options(opts)
+
+if opts.file:
+    try:
+	exp_desc = "".join([ line for line in open(opts.file, 'r')])
+    except EnvironmentError:
+	sys.exit("Cannot read description file (%s)" %opts.file)
+else:
+    sys.exit("Must specify an experiment description (--file)")
+
+out_certfile = opts.out_certfile
+
+# Fill in services
+svcs = []
+if opts.master and opts.project:
+    svcs.append(project_export_service(opts.master, opts.project))
+svcs.extend([ parse_service(s) for s in opts.service])
+if not svcs:
+    print >>sys.stderr, "Warning:Neither master/project nor services requested"
+
+
+msg = { }
+
+if opts.exp_name:
+    msg['experimentID'] = { 'localname': opts.exp_name }
+
+if opts.debug > 1: print >>sys.stderr, msg
+
+try:
+    resp_dict = do_rpc(msg, 
+	    opts.url, opts.transport, cert, opts.trusted, 
+	    serialize_only=opts.serialize_only,
+	    tracefile=opts.tracefile,
+	    caller=service_caller('New'), responseBody="NewResponseBody")
+except RPCException, e:
+    exit_with_fault(e)
+except RuntimeError, e:
+    sys.exit("Error processing RPC: %s" % e)
+
+if opts.debug > 1: print >>sys.stderr, resp_dict
+
+try:
+    save_certfile(opts.out_certfile, resp_dict.get('experimentAccess', None))
+except EnvironmentError, e:
+    sys.exit('Could not write to %s: %s' %  (opts.out_certfile, e))
+
+e_fedid, e_local = get_experiment_names(resp_dict.get('experimentID', None))
+if not e_fedid and not e_local and opts.serialize_only:
+    e_local = "serialize"
+
+msg = { 'experimentdescription': { 'ns2description': exp_desc }, }
+
+if svcs:
+    msg['service'] = svcs
+
+if e_fedid:
+    msg['experimentID'] = { 'fedid': e_fedid }
+elif e_local:
+    msg['experimentID'] = { 'localname': e_local }
+else:
+    sys.exit("New did not return an experiment ID??")
+
+if opts.debug > 1: print >>sys.stderr, msg
+
+try:
+    resp_dict = do_rpc(msg, 
+	    opts.url, opts.transport, cert, opts.trusted, 
+	    serialize_only=opts.serialize_only,
+	    tracefile=opts.tracefile,
+	    caller=service_caller('Create'), responseBody="CreateResponseBody")
+except RPCException, e:
+    exit_with_fault(e)
+except RuntimeError, e:
+    sys.exit("Error processing RPC: %s" % e)
+
+if opts.debug > 1: print >>sys.stderr, resp_dict
+
+e_fedid, e_local = get_experiment_names(resp_dict.get('experimentID', None))
+st = resp_dict.get('experimentStatus', None)
+
+if e_local: print "localname: %s" % e_local
+if e_fedid: print "fedid: %s" % e_fedid
+if st: print "status: %s" % st
+
