Index: fedd/fedd_client.py
===================================================================
--- fedd/fedd_client.py	(revision 67c0e157b6511d6edb22bf3f7e89a8376dec8c53)
+++ fedd/fedd_client.py	(revision 281c0ca5ee2db4e1cb2a2c26d3e41513080dc4fc)
@@ -8,4 +8,5 @@
 import re
 import xml.parsers.expat
+import time
 
 from federation import fedid, service_error
@@ -88,5 +89,5 @@
 		type="string", help="output certificate file")
 	self.add_option("-E", "--experiment_name", dest="exp_name",
-		type="string", help="output certificate file")
+		type="string", help="Suggested experiment name")
 	self.add_option("-F","--useFedid", action="store_true",
 		dest="use_fedid", default=False,
@@ -148,7 +149,23 @@
 	fedd_client_opts.__init__(self)
 	self.add_option("-e", "--experiment_cert", dest="exp_certfile",
-		type="string", help="output certificate file")
+		type="string", help="experiment certificate file")
 	self.add_option("-E", "--experiment_name", dest="exp_name",
-		type="string", help="output certificate file")
+		type="string", help="human readable experiment name")
+	self.add_option("--data", dest="data", default=[],
+		action="append", type="choice",
+		choices=("id", "federant", "vtopo", "vis", "log", "status"),
+		help="data to extract")
+
+class fedd_spew_opts(fedd_client_opts):
+    def __init__(self):
+	fedd_client_opts.__init__(self)
+	self.add_option("-e", "--experiment_cert", dest="exp_certfile",
+		type="string", help="experiment name certificate file")
+	self.add_option("-E", "--experiment_name", dest="exp_name",
+		type="string", help="human readable experiment name")
+	self.add_option("--logfile", dest="logfile", default=None,
+		help="File to write log to")
+	self.add_option('--update_time', dest='update', type='int', default=10,
+		help='how often to update the printed log')
 
 class fedd_image_opts(fedd_exp_data_opts):
@@ -339,34 +356,50 @@
 # 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'
-	elif op == 'Info': pass
-	else:
-	    raise TypeError("Bad op: %s" % op)
-
-    def print_xml(self, d, out=sys.stdout):
+    def __init__(self): 
+	"""
+	Init the various conversions
+	"""
+
+	fedd_rpc.__init__(self, 'Info')
+	# List of things one could ask for and what formatting routine is
+	# called.
+	self.params = {
+		'vis': ('vis', self.print_xml('vis')),
+		'vtopo': ('vtopo', self.print_xml('vtopo')),
+		'federant': ('federant', self.print_xml),
+		'id': ('experimentID', self.print_id),
+		'status': ('experimentStatus', self.print_string),
+		'log': ('allocationLog', self.print_string),
+		'access': ('experimentAccess', self.print_string),
+	    }
+
+
+    def print_string(self, d, out=sys.stdout):
+	print >>out, d
+
+    def print_id(self, d, out=sys.stdout):
+	if d:
+	    for id in d:
+		for k in id.keys():
+		    print >>out, "%s: %s" % (k, id[k])
+
+    class print_xml:
 	"""
 	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 __init__(self, top):
+	    self.xml = top
+
+	def __call__(self, d, out=sys.stdout):
+	    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):
@@ -421,105 +454,53 @@
 	    sys.exit("Error processing RPC: %s" % e)
 
-	if getattr(self, 'key', None):
+	for d in opts.data:
+	    key, output = self.params[d]
 	    try:
-		if resp_dict.has_key(self.key):
-		    self.print_xml(resp_dict[self.key])
+		if resp_dict.has_key(key):
+		    output(resp_dict[key])
 	    except RuntimeError, e:
 		sys.exit("Bad response. %s" % e.message)
-	else:
-	    print resp_dict
-
-
-# Querying experiment data follows the same control flow regardless of the
-# specific data retrieved.  This class encapsulates that control flow.
-class simple_info(fedd_rpc):
-    def __init__(self): 
-	"""
-	Specialize the class for the type of data requested (op)
-	"""
-
-	fedd_rpc.__init__(self, 'Info')
-
-    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
-
+
+class vtopo(exp_data):
+    """
+    vtopo is just an info --data=vtopo request, so this adds that parameter to
+    the arguments and executes exp_info when called.
+    """
+    def __init__(self):
+	exp_data.__init__(self)
     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:
-	    if ( not os.access(opts.trusted, os.R_OK) ) :
-		sys.exit("Cannot read trusted certificates (%s)" % opts.trusted)
-
-	if opts.debug > 0: opts.tracefile=sys.stderr
-
-	(user, cert) = self.get_user_info([])
-
-	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_name and opts.exp_certfile:
-	    sys.exit("Only one of --experiment_cert and " +\
-		    "--experiment_name permitted");
-
-	if opts.exp_certfile:
-	    exp_id = { 'fedid': fedid(file=opts.exp_certfile) }
-
-	if opts.exp_name:
-	    exp_id = { 'localname' : opts.exp_name }
-
-	req = { 'experiment': exp_id }
-
-	status = "active"
-	try:
-	    resp_dict = self.do_rpc(req,
-		    opts.url, opts.transport, cert, opts.trusted, 
-		    serialize_only=opts.serialize_only,
-		    tracefile=opts.tracefile)
-	except self.RPCException, e:
-	    if e.code == 5:
-		status = "swapping"
-	    elif e.code == 1:
-		status = "inactive"
-	    else:
-		status = "unknown"
-	except RuntimeError, e:
-	    print e
-	    sys.exit("Error processing RPC: %s" % e)
-
-	print status
-
+	sys.argv.append('--data=vtopo')
+	exp_data.__call__(self)
+
+
+class vis(exp_data):
+    """
+    vis is just an info --data=vis request, so this adds that parameter to
+    the arguments and executes exp_info when called.
+    """
+    def __init__(self):
+	exp_data.__init__(self)
+    def __call__(self):
+	sys.argv.append('--data=vis')
+	exp_data.__call__(self)
+
+class status(exp_data):
+    """
+    status is just an info --data=status request, so this adds that parameter
+    to the arguments and executes exp_info when called.
+    """
+    def __init__(self):
+	exp_data.__init__(self)
+    def __call__(self):
+	sys.argv.append('--data=status')
+	exp_data.__call__(self)
 
 class image(fedd_rpc):
-    def __init__(self, op): 
+    def __init__(self, op='Vtopo'): 
 	"""
 	Null constructor
 	"""
 
-	fedd_rpc.__init__(self, op)
+	fedd_rpc.__init__(self, 'Vtopo')
 
     def gen_image(self, d, file, fmt, neato, labels, pix=None):
@@ -709,10 +690,10 @@
 
 class ns_image(image):
-    def __init__(self, op): 
+    def __init__(self, op='Ns2Split'): 
 	"""
 	Null constructor
 	"""
 
-	image.__init__(self, op)
+	image.__init__(self, 'Ns2Split')
 
     def generate_topo_dict(self, splitout):
@@ -1032,4 +1013,7 @@
 		for k in id.keys():
 		    print "%s: %s" % (k, id[k])
+	st = resp_dict.get('experimentStatus', None)
+	if st:
+	    print "status: %s" % st
 
 class split(fedd_rpc):
@@ -1219,15 +1203,107 @@
 	self.print_response_as_testbed(resp_dict, opts.label)
 
+# Keep requesting experiment status and printing updates to the log until the
+# experiment is done being created.
+class spew_log(fedd_rpc):
+    def __init__(self): 
+	"""
+	Init the superclass
+	"""
+
+	fedd_rpc.__init__(self, 'Info')
+
+    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_spew_opts()
+
+	(opts, args) = parser.parse_args()
+
+	if opts.trusted:
+	    if ( not os.access(opts.trusted, os.R_OK) ) :
+		sys.exit("Cannot read trusted certificates (%s)" % opts.trusted)
+
+	if opts.debug > 0: opts.tracefile=sys.stderr
+
+	(user, cert) = self.get_user_info([])
+
+	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_name and opts.exp_certfile:
+	    sys.exit("Only one of --experiment_cert and " +\
+		    "--experiment_name permitted");
+
+	if opts.exp_certfile:
+	    exp_id = { 'fedid': fedid(file=opts.exp_certfile) }
+
+	if opts.exp_name:
+	    exp_id = { 'localname' : opts.exp_name }
+
+	if opts.logfile:
+	    try:
+		out = open(opts.logfile, "w")
+	    except IOError,e:
+		sys.exit("Cannot open logfile: %s" %e)
+	else:
+	    out = sys.stdout
+
+	req = { 'experiment': exp_id }
+
+	status = "starting"
+	log = ""
+	log_offset = 0
+	update = opts.update
+	while status == 'starting':
+	    try:
+		resp_dict = self.do_rpc(req,
+			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)
+
+	    status = resp_dict.get('experimentStatus', None)
+	    log = resp_dict.get('allocationLog', None)
+	    if not status:
+		sys.exit("No status in Info response??")
+	    if not log:
+		sys.exit("No log in Info response??")
+
+	    if len(log) > log_offset:
+		print >>out, log[log_offset:],
+		out.flush()
+		log_offset = len(log)
+	    time.sleep(update)
+
+	print >>out
+	print >>out, status
+	out.close()
+
+
 cmds = {\
 	'create': create(),\
 	'split': split(),\
 	'access': access(),\
-	'vtopo': exp_data('Vtopo'),\
-	'vis': exp_data('Vis'),\
-	'image': image('Vtopo'),\
-	'ns_image': ns_image('Ns2Split'),\
-	'info': exp_data('Info'),\
-	'status': simple_info(),\
+	'vtopo': vtopo(),\
+	'vis': vis(),\
+	'info': exp_data(),\
+	'image': image(),\
+	'ns_image': ns_image(),\
+	'status': status(),\
 	'terminate': terminate(),\
+	'spewlog': spew_log(),
     }
 
