Merge branch 'master' into senslab2
[sfa.git] / sfa / client / sfi.py
index 8b02ccd..43e5b98 100644 (file)
@@ -1,30 +1,36 @@
-
-# xxx NOTE this will soon be reviewed to take advantage of sfaclientlib
+#
+# sfi.py - basic SFA command-line client
+# this module is also used in sfascan
+#
 
 import sys
 sys.path.append('.')
 
 import os, os.path
 import socket
 
 import sys
 sys.path.append('.')
 
 import os, os.path
 import socket
+import re
 import datetime
 import codecs
 import pickle
 import datetime
 import codecs
 import pickle
+import json
 from lxml import etree
 from StringIO import StringIO
 from optparse import OptionParser
 from lxml import etree
 from StringIO import StringIO
 from optparse import OptionParser
+from pprint import PrettyPrinter
 
 from sfa.trust.certificate import Keypair, Certificate
 from sfa.trust.gid import GID
 from sfa.trust.credential import Credential
 from sfa.trust.sfaticket import SfaTicket
 
 
 from sfa.trust.certificate import Keypair, Certificate
 from sfa.trust.gid import GID
 from sfa.trust.credential import Credential
 from sfa.trust.sfaticket import SfaTicket
 
+from sfa.util.faults import SfaInvalidArgument
 from sfa.util.sfalogging import sfi_logger
 from sfa.util.sfalogging import sfi_logger
-from sfa.util.xrn import get_leaf, get_authority, hrn_to_urn
+from sfa.util.xrn import get_leaf, get_authority, hrn_to_urn, Xrn
 from sfa.util.config import Config
 from sfa.util.version import version_core
 from sfa.util.cache import Cache
 
 from sfa.util.config import Config
 from sfa.util.version import version_core
 from sfa.util.cache import Cache
 
-from sfa.storage.record import SfaRecord, UserRecord, SliceRecord, NodeRecord, AuthorityRecord
+from sfa.storage.record import Record
 
 from sfa.rspecs.rspec import RSpec
 from sfa.rspecs.rspec_converter import RSpecConverter
 
 from sfa.rspecs.rspec import RSpec
 from sfa.rspecs.rspec_converter import RSpecConverter
@@ -38,6 +44,30 @@ from sfa.client.return_value import ReturnValue
 CM_PORT=12346
 
 # utility methods here
 CM_PORT=12346
 
 # utility methods here
+def optparse_listvalue_callback(option, option_string, value, parser):
+    setattr(parser.values, option.dest, value.split(','))
+
+# a code fragment that could be helpful for argparse which unfortunately is 
+# available with 2.7 only, so this feels like too strong a requirement for the client side
+#class ExtraArgAction  (argparse.Action):
+#    def __call__ (self, parser, namespace, values, option_string=None):
+# would need a try/except of course
+#        (k,v)=values.split('=')
+#        d=getattr(namespace,self.dest)
+#        d[k]=v
+#####
+#parser.add_argument ("-X","--extra",dest='extras', default={}, action=ExtraArgAction,
+#                     help="set extra flags, testbed dependent, e.g. --extra enabled=true")
+    
+def optparse_dictvalue_callback (option, option_string, value, parser):
+    try:
+        (k,v)=value.split('=',1)
+        d=getattr(parser.values, option.dest)
+        d[k]=v
+    except:
+        parser.print_help()
+        sys.exit(1)
+
 # display methods
 def display_rspec(rspec, format='rspec'):
     if format in ['dns']:
 # display methods
 def display_rspec(rspec, format='rspec'):
     if format in ['dns']:
@@ -67,7 +97,7 @@ def display_records(recordList, dump=False):
 
 def display_record(record, dump=False):
     if dump:
 
 def display_record(record, dump=False):
     if dump:
-        record.dump()
+        record.dump(sort=True)
     else:
         info = record.getdict()
         print "%s (%s)" % (info['hrn'], info['type'])
     else:
         info = record.getdict()
         print "%s (%s)" % (info['hrn'], info['type'])
@@ -83,16 +113,28 @@ def filter_records(type, records):
 
 
 # save methods
 
 
 # save methods
-def save_variable_to_file(var, filename, format="text"):
-    f = open(filename, "w")
+def save_raw_to_file(var, filename, format="text", banner=None):
+    if filename == "-":
+        # if filename is "-", send it to stdout
+        f = sys.stdout
+    else:
+        f = open(filename, "w")
+    if banner:
+        f.write(banner+"\n")
     if format == "text":
         f.write(str(var))
     elif format == "pickled":
         f.write(pickle.dumps(var))
     if format == "text":
         f.write(str(var))
     elif format == "pickled":
         f.write(pickle.dumps(var))
+    elif format == "json":
+        if hasattr(json, "dumps"):
+            f.write(json.dumps(var))   # python 2.6
+        else:
+            f.write(json.write(var))   # python 2.5
     else:
         # this should never happen
         print "unknown output format", format
     else:
         # this should never happen
         print "unknown output format", format
-
+    if banner:
+        f.write('\n'+banner+"\n")
 
 def save_rspec_to_file(rspec, filename):
     if not filename.endswith(".rspec"):
 
 def save_rspec_to_file(rspec, filename):
     if not filename.endswith(".rspec"):
@@ -102,58 +144,84 @@ def save_rspec_to_file(rspec, filename):
     f.close()
     return
 
     f.close()
     return
 
-def save_records_to_file(filename, recordList, format="xml"):
+def save_records_to_file(filename, record_dicts, format="xml"):
     if format == "xml":
         index = 0
     if format == "xml":
         index = 0
-        for record in recordList:
+        for record_dict in record_dicts:
             if index > 0:
             if index > 0:
-                save_record_to_file(filename + "." + str(index), record)
+                save_record_to_file(filename + "." + str(index), record_dict)
             else:
             else:
-                save_record_to_file(filename, record)
+                save_record_to_file(filename, record_dict)
             index = index + 1
     elif format == "xmllist":
         f = open(filename, "w")
         f.write("<recordlist>\n")
             index = index + 1
     elif format == "xmllist":
         f = open(filename, "w")
         f.write("<recordlist>\n")
-        for record in recordList:
-            record = SfaRecord(dict=record)
-            f.write('<record hrn="' + record.get_name() + '" type="' + record.get_type() + '" />\n')
+        for record_dict in record_dicts:
+            record_obj=Record(dict=record_dict)
+            f.write('<record hrn="' + record_obj.hrn + '" type="' + record_obj.type + '" />\n')
         f.write("</recordlist>\n")
         f.close()
     elif format == "hrnlist":
         f = open(filename, "w")
         f.write("</recordlist>\n")
         f.close()
     elif format == "hrnlist":
         f = open(filename, "w")
-        for record in recordList:
-            record = SfaRecord(dict=record)
-            f.write(record.get_name() + "\n")
+        for record_dict in record_dicts:
+            record_obj=Record(dict=record_dict)
+            f.write(record_obj.hrn + "\n")
         f.close()
     else:
         # this should never happen
         print "unknown output format", format
 
         f.close()
     else:
         # this should never happen
         print "unknown output format", format
 
-def save_record_to_file(filename, record):
-    if record['type'] in ['user']:
-        record = UserRecord(dict=record)
-    elif record['type'] in ['slice']:
-        record = SliceRecord(dict=record)
-    elif record['type'] in ['node']:
-        record = NodeRecord(dict=record)
-    elif record['type'] in ['authority', 'ma', 'sa']:
-        record = AuthorityRecord(dict=record)
-    else:
-        record = SfaRecord(dict=record)
-    str = record.save_to_string()
+def save_record_to_file(filename, record_dict):
+    record = Record(dict=record_dict)
+    xml = record.save_as_xml()
     f=codecs.open(filename, encoding='utf-8',mode="w")
     f=codecs.open(filename, encoding='utf-8',mode="w")
-    f.write(str)
+    f.write(xml)
     f.close()
     return
 
     f.close()
     return
 
+# minimally check a key argument
+def check_ssh_key (key):
+    good_ssh_key = r'^.*(?:ssh-dss|ssh-rsa)[ ]+[A-Za-z0-9+/=]+(?: .*)?$'
+    return re.match(good_ssh_key, key, re.IGNORECASE)
 
 # load methods
 
 # load methods
+def load_record_from_opts(options):
+    record_dict = {}
+    if hasattr(options, 'xrn') and options.xrn:
+        if hasattr(options, 'type') and options.type:
+            xrn = Xrn(options.xrn, options.type)
+        else:
+            xrn = Xrn(options.xrn)
+        record_dict['urn'] = xrn.get_urn()
+        record_dict['hrn'] = xrn.get_hrn()
+        record_dict['type'] = xrn.get_type()
+    if hasattr(options, 'key') and options.key:
+        try:
+            pubkey = open(options.key, 'r').read()
+        except IOError:
+            pubkey = options.key
+        if not check_ssh_key (pubkey):
+            raise SfaInvalidArgument(name='key',msg="Could not find file, or wrong key format")
+        record_dict['keys'] = [pubkey]
+    if hasattr(options, 'slices') and options.slices:
+        record_dict['slices'] = options.slices
+    if hasattr(options, 'researchers') and options.researchers:
+        record_dict['researcher'] = options.researchers
+    if hasattr(options, 'email') and options.email:
+        record_dict['email'] = options.email
+    if hasattr(options, 'pis') and options.pis:
+        record_dict['pi'] = options.pis
+
+    # handle extra settings
+    record_dict.update(options.extras)
+    
+    return Record(dict=record_dict)
+
 def load_record_from_file(filename):
     f=codecs.open(filename, encoding="utf-8", mode="r")
 def load_record_from_file(filename):
     f=codecs.open(filename, encoding="utf-8", mode="r")
-    str = f.read()
+    xml_string = f.read()
     f.close()
     f.close()
-    record = SfaRecord(string=str)
-    return record
+    return Record(xml=xml_string)
 
 
 import uuid
 
 
 import uuid
@@ -161,7 +229,8 @@ def unique_call_id(): return uuid.uuid4().urn
 
 class Sfi:
     
 
 class Sfi:
     
-    required_options=['verbose',  'debug',  'registry',  'sm',  'auth',  'user']
+    # dirty hack to make this class usable from the outside
+    required_options=['verbose',  'debug',  'registry',  'sm',  'auth',  'user', 'user_private_key']
 
     @staticmethod
     def default_sfi_dir ():
 
     @staticmethod
     def default_sfi_dir ():
@@ -211,6 +280,7 @@ class Sfi:
         ("delegate", "name"),
         ("create_gid", "[name]"),
         ("get_trusted_certs", "cred"),
         ("delegate", "name"),
         ("create_gid", "[name]"),
         ("get_trusted_certs", "cred"),
+        ("config", ""),
         ]
 
     def print_command_help (self, options):
         ]
 
     def print_command_help (self, options):
@@ -248,11 +318,33 @@ class Sfi:
         parser = OptionParser(usage="sfi [sfi_options] %s [cmd_options] %s" \
                                      % (command, self.available_dict[command]))
 
         parser = OptionParser(usage="sfi [sfi_options] %s [cmd_options] %s" \
                                      % (command, self.available_dict[command]))
 
+        if command in ("add", "update"):
+            parser.add_option('-x', '--xrn', dest='xrn', metavar='<xrn>', help='object hrn/urn (mandatory)')
+            parser.add_option('-t', '--type', dest='type', metavar='<type>', help='object type', default=None)
+            parser.add_option('-e', '--email', dest='email', default="",  help="email (mandatory for users)") 
+# use --extra instead
+#            parser.add_option('-u', '--url', dest='url', metavar='<url>', default=None, help="URL, useful for slices") 
+#            parser.add_option('-d', '--description', dest='description', metavar='<description>', 
+#                              help='Description, useful for slices', default=None)
+            parser.add_option('-k', '--key', dest='key', metavar='<key>', help='public key string or file', 
+                              default=None)
+            parser.add_option('-s', '--slices', dest='slices', metavar='<slices>', help='slice xrns',
+                              default='', type="str", action='callback', callback=optparse_listvalue_callback)
+            parser.add_option('-r', '--researchers', dest='researchers', metavar='<researchers>', 
+                              help='slice researchers', default='', type="str", action='callback', 
+                              callback=optparse_listvalue_callback)
+            parser.add_option('-p', '--pis', dest='pis', metavar='<PIs>', help='Principal Investigators/Project Managers',
+                              default='', type="str", action='callback', callback=optparse_listvalue_callback)
+# use --extra instead
+#            parser.add_option('-f', '--firstname', dest='firstname', metavar='<firstname>', help='user first name')
+#            parser.add_option('-l', '--lastname', dest='lastname', metavar='<lastname>', help='user last name')
+            parser.add_option ('-X','--extra',dest='extras',default={},type='str',metavar="<EXTRA_ASSIGNS>",
+                               action="callback", callback=optparse_dictvalue_callback, nargs=1,
+                               help="set extra/testbed-dependent flags, e.g. --extra enabled=true")
+
         # user specifies remote aggregate/sm/component                          
         if command in ("resources", "slices", "create", "delete", "start", "stop", 
                        "restart", "shutdown",  "get_ticket", "renew", "status"):
         # user specifies remote aggregate/sm/component                          
         if command in ("resources", "slices", "create", "delete", "start", "stop", 
                        "restart", "shutdown",  "get_ticket", "renew", "status"):
-            parser.add_option("-c", "--component", dest="component", default=None,
-                             help="component hrn")
             parser.add_option("-d", "--delegate", dest="delegate", default=None, 
                              action="store_true",
                              help="Include a credential delegated to the user's root"+\
             parser.add_option("-d", "--delegate", dest="delegate", default=None, 
                              action="store_true",
                              help="Include a credential delegated to the user's root"+\
@@ -264,16 +356,25 @@ class Sfi:
                             help="type filter ([all]|user|slice|authority|node|aggregate)",
                             choices=("all", "user", "slice", "authority", "node", "aggregate"),
                             default="all")
                             help="type filter ([all]|user|slice|authority|node|aggregate)",
                             choices=("all", "user", "slice", "authority", "node", "aggregate"),
                             default="all")
-        # display formats
         if command in ("resources"):
         if command in ("resources"):
+            # rspec version
             parser.add_option("-r", "--rspec-version", dest="rspec_version", default="SFA 1",
                               help="schema type and version of resulting RSpec")
             parser.add_option("-r", "--rspec-version", dest="rspec_version", default="SFA 1",
                               help="schema type and version of resulting RSpec")
+            # disable/enable cached rspecs
+            parser.add_option("-c", "--current", dest="current", default=False,
+                              action="store_true",  
+                              help="Request the current rspec bypassing the cache. Cached rspecs are returned by default")
+            # display formats
             parser.add_option("-f", "--format", dest="format", type="choice",
                              help="display format ([xml]|dns|ip)", default="xml",
                              choices=("xml", "dns", "ip"))
             #panos: a new option to define the type of information about resources a user is interested in
             parser.add_option("-f", "--format", dest="format", type="choice",
                              help="display format ([xml]|dns|ip)", default="xml",
                              choices=("xml", "dns", "ip"))
             #panos: a new option to define the type of information about resources a user is interested in
-           parser.add_option("-i", "--info", dest="info",
+            parser.add_option("-i", "--info", dest="info",
                                 help="optional component information", default=None)
                                 help="optional component information", default=None)
+            # a new option to retreive or not reservation-oriented RSpecs (leases)
+            parser.add_option("-l", "--list_leases", dest="list_leases", type="choice",
+                                help="Retreive or not reservation-oriented RSpecs ([resources]|leases|all )",
+                                choices=("all", "resources", "leases"), default="resources")
 
 
         # 'create' does return the new rspec, makes sense to save that too
 
 
         # 'create' does return the new rspec, makes sense to save that too
@@ -289,14 +390,9 @@ class Sfi:
            parser.add_option("-F", "--fileformat", dest="fileformat", type="choice",
                              help="output file format ([xml]|xmllist|hrnlist)", default="xml",
                              choices=("xml", "xmllist", "hrnlist"))
            parser.add_option("-F", "--fileformat", dest="fileformat", type="choice",
                              help="output file format ([xml]|xmllist|hrnlist)", default="xml",
                              choices=("xml", "xmllist", "hrnlist"))
-
-        if command in ("status", "version"):
-           parser.add_option("-o", "--output", dest="file",
-                            help="output dictionary to file", metavar="FILE", default=None)
-           parser.add_option("-F", "--fileformat", dest="fileformat", type="choice",
-                             help="output file format ([text]|pickled)", default="text",
-                             choices=("text","pickled"))
-
+        if command == 'list':
+           parser.add_option("-r", "--recursive", dest="recursive", action='store_true',
+                             help="list all child records", default=False)
         if command in ("delegate"):
            parser.add_option("-u", "--user",
                             action="store_true", dest="delegate_user", default=False,
         if command in ("delegate"):
            parser.add_option("-u", "--user",
                             action="store_true", dest="delegate_user", default=False,
@@ -324,6 +420,13 @@ class Sfi:
                          help="root registry", metavar="URL", default=None)
         parser.add_option("-s", "--sliceapi", dest="sm", default=None, metavar="URL",
                          help="slice API - in general a SM URL, but can be used to talk to an aggregate")
                          help="root registry", metavar="URL", default=None)
         parser.add_option("-s", "--sliceapi", dest="sm", default=None, metavar="URL",
                          help="slice API - in general a SM URL, but can be used to talk to an aggregate")
+        parser.add_option("-R", "--raw", dest="raw", default=None,
+                          help="Save raw, unparsed server response to a file")
+        parser.add_option("", "--rawformat", dest="rawformat", type="choice",
+                          help="raw file format ([text]|pickled|json)", default="text",
+                          choices=("text","pickled","json"))
+        parser.add_option("", "--rawbanner", dest="rawbanner", default=None,
+                          help="text string to write before and after raw output")
         parser.add_option("-d", "--dir", dest="sfi_dir",
                          help="config & working directory - default is %default",
                          metavar="PATH", default=Sfi.default_sfi_dir())
         parser.add_option("-d", "--dir", dest="sfi_dir",
                          help="config & working directory - default is %default",
                          metavar="PATH", default=Sfi.default_sfi_dir())
@@ -336,8 +439,6 @@ class Sfi:
         parser.add_option("-D", "--debug",
                           action="store_true", dest="debug", default=False,
                           help="Debug (xml-rpc) protocol messages")
         parser.add_option("-D", "--debug",
                           action="store_true", dest="debug", default=False,
                           help="Debug (xml-rpc) protocol messages")
-        parser.add_option("-p", "--protocol", dest="protocol", default="xmlrpc",
-                         help="RPC protocol (xmlrpc or soap)")
         # would it make sense to use ~/.ssh/id_rsa as a default here ?
         parser.add_option("-k", "--private-key",
                          action="store", dest="user_private_key", default=None,
         # would it make sense to use ~/.ssh/id_rsa as a default here ?
         parser.add_option("-k", "--private-key",
                          action="store", dest="user_private_key", default=None,
@@ -446,9 +547,21 @@ class Sfi:
            self.logger.error("You need to set e.g. SFI_AUTH='plc.princeton' in %s" % config_file)
            errors += 1 
 
            self.logger.error("You need to set e.g. SFI_AUTH='plc.princeton' in %s" % config_file)
            errors += 1 
 
+        self.config_file=config_file
         if errors:
            sys.exit(1)
 
         if errors:
            sys.exit(1)
 
+    def show_config (self):
+        print "From configuration file %s"%self.config_file
+        flags=[ 
+            ('SFI_USER','user'),
+            ('SFI_AUTH','authority'),
+            ('SFI_SM','sm_url'),
+            ('SFI_REGISTRY','reg_url'),
+            ]
+        for (external_name, internal_name) in flags:
+            print "%s='%s'"%(external_name,getattr(self,internal_name))
+
     #
     # Get various credential and spec files
     #
     #
     # Get various credential and spec files
     #
@@ -464,41 +577,41 @@ class Sfi:
     
     # init self-signed cert, user credentials and gid
     def bootstrap (self):
     
     # init self-signed cert, user credentials and gid
     def bootstrap (self):
-        bootstrap = SfaClientBootstrap (self.user, self.reg_url, self.options.sfi_dir)
+        client_bootstrap = SfaClientBootstrap (self.user, self.reg_url, self.options.sfi_dir)
         # if -k is provided, use this to initialize private key
         if self.options.user_private_key:
         # if -k is provided, use this to initialize private key
         if self.options.user_private_key:
-            bootstrap.init_private_key_if_missing (self.options.user_private_key)
+            client_bootstrap.init_private_key_if_missing (self.options.user_private_key)
         else:
             # trigger legacy compat code if needed 
             # the name has changed from just <leaf>.pkey to <hrn>.pkey
         else:
             # trigger legacy compat code if needed 
             # the name has changed from just <leaf>.pkey to <hrn>.pkey
-            if not os.path.isfile(bootstrap.private_key_filename()):
+            if not os.path.isfile(client_bootstrap.private_key_filename()):
                 self.logger.info ("private key not found, trying legacy name")
                 try:
                     legacy_private_key = os.path.join (self.options.sfi_dir, "%s.pkey"%get_leaf(self.user))
                     self.logger.debug("legacy_private_key=%s"%legacy_private_key)
                 self.logger.info ("private key not found, trying legacy name")
                 try:
                     legacy_private_key = os.path.join (self.options.sfi_dir, "%s.pkey"%get_leaf(self.user))
                     self.logger.debug("legacy_private_key=%s"%legacy_private_key)
-                    bootstrap.init_private_key_if_missing (legacy_private_key)
+                    client_bootstrap.init_private_key_if_missing (legacy_private_key)
                     self.logger.info("Copied private key from legacy location %s"%legacy_private_key)
                 except:
                     self.logger.log_exc("Can't find private key ")
                     sys.exit(1)
             
         # make it bootstrap
                     self.logger.info("Copied private key from legacy location %s"%legacy_private_key)
                 except:
                     self.logger.log_exc("Can't find private key ")
                     sys.exit(1)
             
         # make it bootstrap
-        bootstrap.bootstrap_my_gid()
+        client_bootstrap.bootstrap_my_gid()
         # extract what's needed
         # extract what's needed
-        self.private_key = bootstrap.private_key()
-        self.my_credential_string = bootstrap.my_credential_string ()
-        self.my_gid = bootstrap.my_gid ()
-        self.bootstrap = bootstrap
+        self.private_key = client_bootstrap.private_key()
+        self.my_credential_string = client_bootstrap.my_credential_string ()
+        self.my_gid = client_bootstrap.my_gid ()
+        self.client_bootstrap = client_bootstrap
 
 
     def my_authority_credential_string(self):
         if not self.authority:
             self.logger.critical("no authority specified. Use -a or set SF_AUTH")
             sys.exit(-1)
 
 
     def my_authority_credential_string(self):
         if not self.authority:
             self.logger.critical("no authority specified. Use -a or set SF_AUTH")
             sys.exit(-1)
-        return self.bootstrap.authority_credential_string (self.authority)
+        return self.client_bootstrap.authority_credential_string (self.authority)
 
     def slice_credential_string(self, name):
 
     def slice_credential_string(self, name):
-        return self.bootstrap.slice_credential_string (name)
+        return self.client_bootstrap.slice_credential_string (name)
 
     # xxx should be supported by sfaclientbootstrap as well
     def delegate_cred(self, object_cred, hrn, type='authority'):
 
     # xxx should be supported by sfaclientbootstrap as well
     def delegate_cred(self, object_cred, hrn, type='authority'):
@@ -516,7 +629,7 @@ class Sfi:
         caller_gidfile = self.my_gid()
   
         # the gid of the user who will be delegated to
         caller_gidfile = self.my_gid()
   
         # the gid of the user who will be delegated to
-        delegee_gid = self.bootstrap.gid(hrn,type)
+        delegee_gid = self.client_bootstrap.gid(hrn,type)
         delegee_hrn = delegee_gid.get_hrn()
         dcred = object_cred.delegate(delegee_gid, self.private_key, caller_gidfile)
         return dcred.save_to_string(save_parents=True)
         delegee_hrn = delegee_gid.get_hrn()
         dcred = object_cred.delegate(delegee_gid, self.private_key, caller_gidfile)
         return dcred.save_to_string(save_parents=True)
@@ -549,6 +662,8 @@ class Sfi:
                 self.sliceapi_proxy=SfaServerProxy(cm_url, self.private_key, self.my_gid)
             else:
                 # otherwise use what was provided as --sliceapi, or SFI_SM in the config
                 self.sliceapi_proxy=SfaServerProxy(cm_url, self.private_key, self.my_gid)
             else:
                 # otherwise use what was provided as --sliceapi, or SFI_SM in the config
+                if not self.sm_url.startswith('http://') or self.sm_url.startswith('https://'):
+                    self.sm_url = 'http://' + self.sm_url
                 self.logger.info("Contacting Slice Manager at: %s"%self.sm_url)
                 self.sliceapi_proxy = SfaServerProxy(self.sm_url, self.private_key, self.my_gid, 
                                                      timeout=self.options.timeout, verbose=self.options.debug)  
                 self.logger.info("Contacting Slice Manager at: %s"%self.sm_url)
                 self.sliceapi_proxy = SfaServerProxy(self.sm_url, self.private_key, self.my_gid, 
                                                      timeout=self.options.timeout, verbose=self.options.debug)  
@@ -605,9 +720,21 @@ class Sfi:
         return result                 
 
     ### ois = options if supported
         return result                 
 
     ### ois = options if supported
+    # to be used in something like serverproxy.Method (arg1, arg2, *self.ois(api_options))
     def ois (self, server, option_dict):
     def ois (self, server, option_dict):
-        if self.server_supports_options_arg (server) : return [option_dict]
-        else: return []
+        if self.server_supports_options_arg (server): 
+            return [option_dict]
+        elif self.server_supports_call_id_arg (server):
+            return [ unique_call_id () ]
+        else: 
+            return []
+
+    ### cis = call_id if supported - like ois
+    def cis (self, server):
+        if self.server_supports_call_id_arg (server):
+            return [ unique_call_id ]
+        else:
+            return []
 
     ######################################## miscell utilities
     def get_rspec_file(self, rspec):
 
     ######################################## miscell utilities
     def get_rspec_file(self, rspec):
@@ -631,17 +758,17 @@ class Sfi:
        else:
           self.logger.critical("No such registry record file %s"%record)
           sys.exit(1)
        else:
           self.logger.critical("No such registry record file %s"%record)
           sys.exit(1)
-    
+
 
     #==========================================================================
     # Following functions implement the commands
     #
     # Registry-related commands
     #==========================================================================
 
     #==========================================================================
     # Following functions implement the commands
     #
     # Registry-related commands
     #==========================================================================
-  
+
     def version(self, options, args):
         """
     def version(self, options, args):
         """
-        display an SFA server version (GetVersion) 
+        display an SFA server version (GetVersion)
 or version information about sfi itself
         """
         if options.version_local:
 or version information about sfi itself
         """
         if options.version_local:
@@ -653,10 +780,11 @@ or version information about sfi itself
                 server = self.sliceapi()
             result = server.GetVersion()
             version = ReturnValue.get_value(result)
                 server = self.sliceapi()
             result = server.GetVersion()
             version = ReturnValue.get_value(result)
-        for (k,v) in version.iteritems():
-            print "%-20s: %s"%(k,v)
-        if options.file:
-            save_variable_to_file(version, options.file, options.fileformat)
+        if self.options.raw:
+            save_raw_to_file(result, self.options.raw, self.options.rawformat, self.options.rawbanner)
+        else:
+            pprinter = PrettyPrinter(indent=4)
+            pprinter.pprint(version)
 
     def list(self, options, args):
         """
 
     def list(self, options, args):
         """
@@ -666,8 +794,12 @@ or version information about sfi itself
             self.print_help()
             sys.exit(1)
         hrn = args[0]
             self.print_help()
             sys.exit(1)
         hrn = args[0]
+        opts = {}
+        if options.recursive:
+            opts['recursive'] = options.recursive
+        
         try:
         try:
-            list = self.registry().List(hrn, self.my_credential_string)
+            list = self.registry().List(hrn, self.my_credential_string, options)
         except IndexError:
             raise Exception, "Not enough parameters for the 'list' command"
 
         except IndexError:
             raise Exception, "Not enough parameters for the 'list' command"
 
@@ -688,55 +820,65 @@ or version information about sfi itself
             self.print_help()
             sys.exit(1)
         hrn = args[0]
             self.print_help()
             sys.exit(1)
         hrn = args[0]
-        records = self.registry().Resolve(hrn, self.my_credential_string)
-        records = filter_records(options.type, records)
-        if not records:
+        record_dicts = self.registry().Resolve(hrn, self.my_credential_string)
+        record_dicts = filter_records(options.type, record_dicts)
+        if not record_dicts:
             self.logger.error("No record of type %s"% options.type)
             self.logger.error("No record of type %s"% options.type)
+        records = [ Record(dict=record_dict) for record_dict in record_dicts ]
         for record in records:
         for record in records:
-            if record['type'] in ['user']:
-                record = UserRecord(dict=record)
-            elif record['type'] in ['slice']:
-                record = SliceRecord(dict=record)
-            elif record['type'] in ['node']:
-                record = NodeRecord(dict=record)
-            elif record['type'].startswith('authority'):
-                record = AuthorityRecord(dict=record)
-            else:
-                record = SfaRecord(dict=record)
-            if (options.format == "text"): 
-                record.dump()  
-            else:
-                print record.save_to_string() 
+            if (options.format == "text"):      record.dump(sort=True)  
+            else:                               print record.save_as_xml() 
         if options.file:
         if options.file:
-            save_records_to_file(options.file, records, options.fileformat)
+            save_records_to_file(options.file, record_dicts, options.fileformat)
         return
     
     def add(self, options, args):
         "add record into registry from xml file (Register)"
         auth_cred = self.my_authority_credential_string()
         return
     
     def add(self, options, args):
         "add record into registry from xml file (Register)"
         auth_cred = self.my_authority_credential_string()
-        if len(args)!=1:
+        record_dict = {}
+        if len(args) > 0:
+            record_filepath = args[0]
+            rec_file = self.get_record_file(record_filepath)
+            record_dict.update(load_record_from_file(rec_file).todict())
+        if options:
+            record_dict.update(load_record_from_opts(options).todict())
+        # we should have a type by now
+        if 'type' not in record_dict :
             self.print_help()
             sys.exit(1)
             self.print_help()
             sys.exit(1)
-        record_filepath = args[0]
-        rec_file = self.get_record_file(record_filepath)
-        record = load_record_from_file(rec_file).as_dict()
-        return self.registry().Register(record, auth_cred)
+        # this is still planetlab dependent.. as plc will whine without that
+        # also, it's only for adding
+        if record_dict['type'] == 'user':
+            if not 'first_name' in record_dict:
+                record_dict['first_name'] = record_dict['hrn']
+            if 'last_name' not in record_dict:
+                record_dict['last_name'] = record_dict['hrn'] 
+        return self.registry().Register(record_dict, auth_cred)
     
     def update(self, options, args):
         "update record into registry from xml file (Update)"
     
     def update(self, options, args):
         "update record into registry from xml file (Update)"
-        if len(args)!=1:
+        record_dict = {}
+        if len(args) > 0:
+            record_filepath = args[0]
+            rec_file = self.get_record_file(record_filepath)
+            record_dict.update(load_record_from_file(rec_file).todict())
+        if options:
+            record_dict.update(load_record_from_opts(options).todict())
+        # at the very least we need 'type' here
+        if 'type' not in record_dict:
             self.print_help()
             sys.exit(1)
             self.print_help()
             sys.exit(1)
-        rec_file = self.get_record_file(args[0])
-        record = load_record_from_file(rec_file)
-        if record['type'] == "user":
-            if record.get_name() == self.user:
+
+        # don't translate into an object, as this would possibly distort
+        # user-provided data; e.g. add an 'email' field to Users
+        if record_dict['type'] == "user":
+            if record_dict['hrn'] == self.user:
                 cred = self.my_credential_string
             else:
                 cred = self.my_authority_credential_string()
                 cred = self.my_credential_string
             else:
                 cred = self.my_authority_credential_string()
-        elif record['type'] in ["slice"]:
+        elif record_dict['type'] in ["slice"]:
             try:
             try:
-                cred = self.slice_credential_string(record.get_name())
+                cred = self.slice_credential_string(record_dict['hrn'])
             except ServerException, e:
                # XXX smbaker -- once we have better error return codes, update this
                # to do something better than a string compare
             except ServerException, e:
                # XXX smbaker -- once we have better error return codes, update this
                # to do something better than a string compare
@@ -744,14 +886,13 @@ or version information about sfi itself
                    cred = self.my_authority_credential_string()
                else:
                    raise
                    cred = self.my_authority_credential_string()
                else:
                    raise
-        elif record.get_type() in ["authority"]:
+        elif record_dict['type'] in ["authority"]:
             cred = self.my_authority_credential_string()
             cred = self.my_authority_credential_string()
-        elif record.get_type() == 'node':
+        elif record_dict['type'] == 'node':
             cred = self.my_authority_credential_string()
         else:
             cred = self.my_authority_credential_string()
         else:
-            raise "unknown record type" + record.get_type()
-        record = record.as_dict()
-        return self.registry().Update(record, cred)
+            raise "unknown record type" + record_dict['type']
+        return self.registry().Update(record_dict, cred)
   
     def remove(self, options, args):
         "remove registry record by name (Remove)"
   
     def remove(self, options, args):
         "remove registry record by name (Remove)"
@@ -772,77 +913,77 @@ or version information about sfi itself
     def slices(self, options, args):
         "list instantiated slices (ListSlices) - returns urn's"
         server = self.sliceapi()
     def slices(self, options, args):
         "list instantiated slices (ListSlices) - returns urn's"
         server = self.sliceapi()
-        call_args = []
+        # creds
         creds = [self.my_credential_string]
         if options.delegate:
             delegated_cred = self.delegate_cred(self.my_credential_string, get_authority(self.authority))
             creds.append(delegated_cred)  
         creds = [self.my_credential_string]
         if options.delegate:
             delegated_cred = self.delegate_cred(self.my_credential_string, get_authority(self.authority))
             creds.append(delegated_cred)  
-        call_args.append(creds)
-        if self.server_supports_options_arg(server):
-            api_options = {}
-            api_options ['call_id'] = unique_call_id()
-            args.append(api_options)
-        elif self.server_supports_call_id_arg(server):
-            args.append(unique_call_id())  
-        result = server.ListSlices(*call_args)
+        # options and call_id when supported
+        api_options = {}
+       api_options['call_id']=unique_call_id()
+        result = server.ListSlices(creds, *self.ois(server,api_options))
         value = ReturnValue.get_value(result)
         value = ReturnValue.get_value(result)
-        display_list(value)
+        if self.options.raw:
+            save_raw_to_file(result, self.options.raw, self.options.rawformat, self.options.rawbanner)
+        else:
+            display_list(value)
         return
         return
-    
+
     # show rspec for named slice
     def resources(self, options, args):
         """
     # show rspec for named slice
     def resources(self, options, args):
         """
-        with no arg, discover available resources,
-or currently provisioned resources  (ListResources)
+        with no arg, discover available resources, (ListResources)
+or with an slice hrn, shows currently provisioned resources
         """
         server = self.sliceapi()
         """
         server = self.sliceapi()
-        call_args = []
-        creds = []
 
         # set creds
 
         # set creds
+        creds = []
         if args:
             creds.append(self.slice_credential_string(args[0]))
         else:
             creds.append(self.my_credential_string)
         if options.delegate:
             creds.append(self.delegate_cred(cred, get_authority(self.authority)))
         if args:
             creds.append(self.slice_credential_string(args[0]))
         else:
             creds.append(self.my_credential_string)
         if options.delegate:
             creds.append(self.delegate_cred(cred, get_authority(self.authority)))
-        call_args.append(creds)
-        
-        # set options and callid
-        print self.server_supports_options_arg(server)
-        if self.server_supports_options_arg(server):
-            api_options = {}
-            if args:
-                hrn = args[0]
-                api_options['geni_slice_urn'] = hrn_to_urn(hrn, 'slice')
-            if options.info:
-                api_options['info'] = options.info
-            if options.rspec_version:
-                version_manager = VersionManager()
-                server_version = self.get_cached_server_version(server)
-                if 'sfa' in server_version:
-                    # just request the version the client wants
-                    api_options['geni_rspec_version'] = version_manager.get_version(options.rspec_version).to_dict()
-                else:
-                    # this must be a protogeni aggregate. We should request a v2 ad rspec
-                    # regardless of what the client user requested
-                    api_options['geni_rspec_version'] = version_manager.get_version('ProtoGENI 2').to_dict() 
+
+        # no need to check if server accepts the options argument since the options has
+        # been a required argument since v1 API
+        api_options = {}
+        # always send call_id to v2 servers
+        api_options ['call_id'] = unique_call_id()
+        # ask for cached value if available
+        api_options ['cached'] = True
+        if args:
+            hrn = args[0]
+            api_options['geni_slice_urn'] = hrn_to_urn(hrn, 'slice')
+        if options.info:
+            api_options['info'] = options.info
+        if options.list_leases:
+            api_options['list_leases'] = options.list_leases
+        if options.current:
+            if options.current == True:
+                api_options['cached'] = False
             else:
             else:
-                api_options['geni_rspec_version'] = {'type': 'geni', 'version': '3.0'}    
-                api_options ['call_id'] = unique_call_id()
-            call_args.append(api_options)
+                api_options['cached'] = True
+        if options.rspec_version:
+            version_manager = VersionManager()
+            server_version = self.get_cached_server_version(server)
+            if 'sfa' in server_version:
+                # just request the version the client wants
+                api_options['geni_rspec_version'] = version_manager.get_version(options.rspec_version).to_dict()
+            else:
+                api_options['geni_rspec_version'] = {'type': 'geni', 'version': '3.0'}
         else:
         else:
-            if args:
-                hrn = args[0]
-                call_args.append(hrn)
-            if self.server_supports_call_id_arg(server):
-                call_args.append(unique_call_id)
-        result = server.ListResources(*call_args)
+            api_options['geni_rspec_version'] = {'type': 'geni', 'version': '3.0'}
+        result = server.ListResources (creds, api_options)
         value = ReturnValue.get_value(result)
         value = ReturnValue.get_value(result)
-        if options.file is None:
-            display_rspec(value, options.format)
-        else:
+        if self.options.raw:
+            save_raw_to_file(result, self.options.raw, self.options.rawformat, self.options.rawbanner)
+        if options.file is not None:
             save_rspec_to_file(value, options.file)
             save_rspec_to_file(value, options.file)
+        if (self.options.raw is None) and (options.file is None):
+            display_rspec(value, options.format)
+
         return
 
     def create(self, options, args):
         return
 
     def create(self, options, args):
@@ -850,14 +991,14 @@ or currently provisioned resources  (ListResources)
         create or update named slice with given rspec
         """
         server = self.sliceapi()
         create or update named slice with given rspec
         """
         server = self.sliceapi()
-        call_args = []
-        # set slice urn
+
+        # xxx do we need to check usage (len(args)) ?
+        # slice urn
         slice_hrn = args[0]
         slice_urn = hrn_to_urn(slice_hrn, 'slice')
         slice_hrn = args[0]
         slice_urn = hrn_to_urn(slice_hrn, 'slice')
-        call_args.append(slice_urn)
-        # set credentials
+
+        # credentials
         creds = [self.slice_credential_string(slice_hrn)]
         creds = [self.slice_credential_string(slice_hrn)]
-        call_args.append(creds)
         delegated_cred = None
         server_version = self.get_cached_server_version(server)
         if server_version.get('interface') == 'slicemgr':
         delegated_cred = None
         server_version = self.get_cached_server_version(server)
         if server_version.get('interface') == 'slicemgr':
@@ -868,11 +1009,12 @@ or currently provisioned resources  (ListResources)
             #    delegated_cred = self.delegate_cred(slice_cred, server_version['hrn'])
             #elif server_version.get('urn'):
             #    delegated_cred = self.delegate_cred(slice_cred, urn_to_hrn(server_version['urn']))
             #    delegated_cred = self.delegate_cred(slice_cred, server_version['hrn'])
             #elif server_version.get('urn'):
             #    delegated_cred = self.delegate_cred(slice_cred, urn_to_hrn(server_version['urn']))
-                
-        # set rspec 
+
+        # rspec
         rspec_file = self.get_rspec_file(args[1])
         rspec = open(rspec_file).read()
         rspec_file = self.get_rspec_file(args[1])
         rspec = open(rspec_file).read()
-        # set users
+
+        # users
         # need to pass along user keys to the aggregate.
         # users = [
         #  { urn: urn:publicid:IDN+emulab.net+user+alice
         # need to pass along user keys to the aggregate.
         # users = [
         #  { urn: urn:publicid:IDN+emulab.net+user+alice
@@ -892,25 +1034,26 @@ or currently provisioned resources  (ListResources)
                 rspec.filter({'component_manager_id': server_version['urn']})
                 rspec = RSpecConverter.to_pg_rspec(rspec.toxml(), content_type='request')
             else:
                 rspec.filter({'component_manager_id': server_version['urn']})
                 rspec = RSpecConverter.to_pg_rspec(rspec.toxml(), content_type='request')
             else:
+                print >>sys.stderr, "\r\n \r\n \r\n WOOOOOO"
                 users = sfa_users_arg(user_records, slice_record)
                 users = sfa_users_arg(user_records, slice_record)
-        
-        call_args.append(rspec)
-        call_args.append(users)    
-        # do not append users, keys, or slice tags. Anything 
+
+        # do not append users, keys, or slice tags. Anything
         # not contained in this request will be removed from the slice
 
         # CreateSliver has supported the options argument for a while now so it should
         # not contained in this request will be removed from the slice
 
         # CreateSliver has supported the options argument for a while now so it should
-        # be safe to assume this server support it 
+        # be safe to assume this server support it
         api_options = {}
         api_options ['append'] = False
         api_options ['call_id'] = unique_call_id()
         api_options = {}
         api_options ['append'] = False
         api_options ['call_id'] = unique_call_id()
-        call_args.append(api_options)
-        result = server.CreateSliver(*call_args)
+        result = server.CreateSliver(slice_urn, creds, rspec, users, *self.ois(server, api_options))
         value = ReturnValue.get_value(result)
         value = ReturnValue.get_value(result)
-        if options.file is None:
-            print value
-        else:
+        if self.options.raw:
+            save_raw_to_file(result, self.options.raw, self.options.rawformat, self.options.rawbanner)
+        if options.file is not None:
             save_rspec_to_file (value, options.file)
             save_rspec_to_file (value, options.file)
+        if (self.options.raw is None) and (options.file is None):
+            print value
+
         return value
 
     def delete(self, options, args):
         return value
 
     def delete(self, options, args):
@@ -918,130 +1061,151 @@ or currently provisioned resources  (ListResources)
         delete named slice (DeleteSliver)
         """
         server = self.sliceapi()
         delete named slice (DeleteSliver)
         """
         server = self.sliceapi()
-        call_args = []
-        # set slice urn
+
+        # slice urn
         slice_hrn = args[0]
         slice_urn = hrn_to_urn(slice_hrn, 'slice') 
         slice_hrn = args[0]
         slice_urn = hrn_to_urn(slice_hrn, 'slice') 
-        call_args.append(slice_urn)
-        # set creds
+
+        # creds
         slice_cred = self.slice_credential_string(slice_hrn)
         creds = [slice_cred]
         if options.delegate:
             delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
             creds.append(delegated_cred)
         slice_cred = self.slice_credential_string(slice_hrn)
         creds = [slice_cred]
         if options.delegate:
             delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
             creds.append(delegated_cred)
-        call_args.append(creds)
-        if self.server_supports_options_arg(server):
-            api_options = {}
-            api_options ['call_id'] = unique_call_id()
-            call_args.append(api_options)
-        elif self.server_supports_call_id_arg(server):
-            call_args.append(unique_call_id())
-        return server.DeleteSliver(*call_args)
+        
+        # options and call_id when supported
+        api_options = {}
+        api_options ['call_id'] = unique_call_id()
+        result = server.DeleteSliver(slice_urn, creds, *self.ois(server, api_options ) )
+        value = ReturnValue.get_value(result)
+        if self.options.raw:
+            save_raw_to_file(result, self.options.raw, self.options.rawformat, self.options.rawbanner)
+        else:
+            print value
+        return value 
   
     def status(self, options, args):
         """
         retrieve slice status (SliverStatus)
         """
         server = self.sliceapi()
   
     def status(self, options, args):
         """
         retrieve slice status (SliverStatus)
         """
         server = self.sliceapi()
-        call_args = []
-        # set slice urn
+
+        # slice urn
         slice_hrn = args[0]
         slice_urn = hrn_to_urn(slice_hrn, 'slice') 
         slice_hrn = args[0]
         slice_urn = hrn_to_urn(slice_hrn, 'slice') 
-        call_args.append(slice_urn)
-        # set creds 
+
+        # creds 
         slice_cred = self.slice_credential_string(slice_hrn)
         creds = [slice_cred]
         if options.delegate:
             delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
             creds.append(delegated_cred)
         slice_cred = self.slice_credential_string(slice_hrn)
         creds = [slice_cred]
         if options.delegate:
             delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
             creds.append(delegated_cred)
-        call_args.append(creds)
-        # set options and call id
-        if self.server_supports_options_arg(server):
-            api_options = {}
-            api_options ['call_id'] = unique_call_id()
-            call_args.append(api_options)
-        elif self.server_supports_call_id_arg(server):
-            call_args.append(unique_call_id())
-        result = server.SliverStatus(*call_args)
+
+        # options and call_id when supported
+        api_options = {}
+        api_options['call_id']=unique_call_id()
+        result = server.SliverStatus(slice_urn, creds, *self.ois(server,api_options))
         value = ReturnValue.get_value(result)
         value = ReturnValue.get_value(result)
-        print value
-        if options.file:
-            save_variable_to_file(value, options.file, options.fileformat)
+        if self.options.raw:
+            save_raw_to_file(result, self.options.raw, self.options.rawformat, self.options.rawbanner)
+        else:
+            print value
 
     def start(self, options, args):
         """
         start named slice (Start)
         """
         server = self.sliceapi()
 
     def start(self, options, args):
         """
         start named slice (Start)
         """
         server = self.sliceapi()
-        call_args = []
-        # set the slice urn
+
+        # the slice urn
         slice_hrn = args[0]
         slice_urn = hrn_to_urn(slice_hrn, 'slice') 
         slice_hrn = args[0]
         slice_urn = hrn_to_urn(slice_hrn, 'slice') 
-        call_args.append(slice_urn)
+        
+        # cred
         slice_cred = self.slice_credential_string(args[0])
         creds = [slice_cred]
         if options.delegate:
             delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
             creds.append(delegated_cred)
         # xxx Thierry - does this not need an api_options as well ?
         slice_cred = self.slice_credential_string(args[0])
         creds = [slice_cred]
         if options.delegate:
             delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
             creds.append(delegated_cred)
         # xxx Thierry - does this not need an api_options as well ?
-        return server.Start(slice_urn, creds)
+        result = server.Start(slice_urn, creds)
+        value = ReturnValue.get_value(result)
+        if self.options.raw:
+            save_raw_to_file(result, self.options.raw, self.options.rawformat, self.options.rawbanner)
+        else:
+            print value
+        return value
     
     def stop(self, options, args):
         """
         stop named slice (Stop)
         """
     
     def stop(self, options, args):
         """
         stop named slice (Stop)
         """
+        server = self.sliceapi()
+        # slice urn
         slice_hrn = args[0]
         slice_urn = hrn_to_urn(slice_hrn, 'slice') 
         slice_hrn = args[0]
         slice_urn = hrn_to_urn(slice_hrn, 'slice') 
+        # cred
         slice_cred = self.slice_credential_string(args[0])
         creds = [slice_cred]
         if options.delegate:
             delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
             creds.append(delegated_cred)
         slice_cred = self.slice_credential_string(args[0])
         creds = [slice_cred]
         if options.delegate:
             delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
             creds.append(delegated_cred)
-        server = self.sliceapi()
-        return server.Stop(slice_urn, creds)
+        result =  server.Stop(slice_urn, creds)
+        value = ReturnValue.get_value(result)
+        if self.options.raw:
+            save_raw_to_file(result, self.options.raw, self.options.rawformat, self.options.rawbanner)
+        else:
+            print value
+        return value
     
     # reset named slice
     def reset(self, options, args):
         """
         reset named slice (reset_slice)
         """
     
     # reset named slice
     def reset(self, options, args):
         """
         reset named slice (reset_slice)
         """
+        server = self.sliceapi()
+        # slice urn
         slice_hrn = args[0]
         slice_urn = hrn_to_urn(slice_hrn, 'slice') 
         slice_hrn = args[0]
         slice_urn = hrn_to_urn(slice_hrn, 'slice') 
-        server = self.sliceapi()
+        # cred
         slice_cred = self.slice_credential_string(args[0])
         creds = [slice_cred]
         if options.delegate:
             delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
             creds.append(delegated_cred)
         slice_cred = self.slice_credential_string(args[0])
         creds = [slice_cred]
         if options.delegate:
             delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
             creds.append(delegated_cred)
-        return server.reset_slice(creds, slice_urn)
+        result = server.reset_slice(creds, slice_urn)
+        value = ReturnValue.get_value(result)
+        if self.options.raw:
+            save_raw_to_file(result, self.options.raw, self.options.rawformat, self.options.rawbanner)
+        else:
+            print value
+        return value
 
     def renew(self, options, args):
         """
         renew slice (RenewSliver)
         """
         server = self.sliceapi()
 
     def renew(self, options, args):
         """
         renew slice (RenewSliver)
         """
         server = self.sliceapi()
-        call_args = []
-        # set the slice urn    
+        # slice urn    
         slice_hrn = args[0]
         slice_urn = hrn_to_urn(slice_hrn, 'slice') 
         slice_hrn = args[0]
         slice_urn = hrn_to_urn(slice_hrn, 'slice') 
-        call_args.append(slice_urn)
-        # set the creds
+        # creds
         slice_cred = self.slice_credential_string(args[0])
         creds = [slice_cred]
         if options.delegate:
             delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
             creds.append(delegated_cred)
         slice_cred = self.slice_credential_string(args[0])
         creds = [slice_cred]
         if options.delegate:
             delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
             creds.append(delegated_cred)
-        call_args.append(creds)
+        # time
         time = args[1]
         time = args[1]
-        call_args.append(time)
-        if self.server_supports_options_arg(server):
-            api_options = {}
-            api_options ['call_id'] = unique_call_id()
-            call_args.append(api_options)
-        elif self.server_supports_call_id_arg(server):
-            call_args.append(unique_call_id())
-        result =  server.RenewSliver(*call_args)
+        # options and call_id when supported
+        api_options = {}
+       api_options['call_id']=unique_call_id()
+        result =  server.RenewSliver(slice_urn, creds, time, *self.ois(server,api_options))
         value = ReturnValue.get_value(result)
         value = ReturnValue.get_value(result)
+        if self.options.raw:
+            save_raw_to_file(result, self.options.raw, self.options.rawformat, self.options.rawbanner)
+        else:
+            print value
         return value
 
 
         return value
 
 
@@ -1049,32 +1213,48 @@ or currently provisioned resources  (ListResources)
         """
         shutdown named slice (Shutdown)
         """
         """
         shutdown named slice (Shutdown)
         """
+        server = self.sliceapi()
+        # slice urn
         slice_hrn = args[0]
         slice_urn = hrn_to_urn(slice_hrn, 'slice') 
         slice_hrn = args[0]
         slice_urn = hrn_to_urn(slice_hrn, 'slice') 
+        # creds
         slice_cred = self.slice_credential_string(slice_hrn)
         creds = [slice_cred]
         if options.delegate:
             delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
             creds.append(delegated_cred)
         slice_cred = self.slice_credential_string(slice_hrn)
         creds = [slice_cred]
         if options.delegate:
             delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
             creds.append(delegated_cred)
-        server = self.sliceapi()
-        return server.Shutdown(slice_urn, creds)         
+        result = server.Shutdown(slice_urn, creds)
+        value = ReturnValue.get_value(result)
+        if self.options.raw:
+            save_raw_to_file(result, self.options.raw, self.options.rawformat, self.options.rawbanner)
+        else:
+            print value
+        return value         
     
 
     def get_ticket(self, options, args):
         """
         get a ticket for the specified slice
         """
     
 
     def get_ticket(self, options, args):
         """
         get a ticket for the specified slice
         """
+        server = self.sliceapi()
+        # slice urn
         slice_hrn, rspec_path = args[0], args[1]
         slice_urn = hrn_to_urn(slice_hrn, 'slice')
         slice_hrn, rspec_path = args[0], args[1]
         slice_urn = hrn_to_urn(slice_hrn, 'slice')
+        # creds
         slice_cred = self.slice_credential_string(slice_hrn)
         creds = [slice_cred]
         if options.delegate:
             delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
             creds.append(delegated_cred)
         slice_cred = self.slice_credential_string(slice_hrn)
         creds = [slice_cred]
         if options.delegate:
             delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
             creds.append(delegated_cred)
+        # rspec
         rspec_file = self.get_rspec_file(rspec_path) 
         rspec = open(rspec_file).read()
         rspec_file = self.get_rspec_file(rspec_path) 
         rspec = open(rspec_file).read()
-        server = self.sliceapi()
-        ticket_string = server.GetTicket(slice_urn, creds, rspec, [])
+        # options and call_id when supported
+        api_options = {}
+       api_options['call_id']=unique_call_id()
+        # get ticket at the server
+        ticket_string = server.GetTicket(slice_urn, creds, rspec, *self.ois(server,api_options))
+        # save
         file = os.path.join(self.options.sfi_dir, get_leaf(slice_hrn) + ".ticket")
         self.logger.info("writing ticket to %s"%file)
         ticket = SfaTicket(string=ticket_string)
         file = os.path.join(self.options.sfi_dir, get_leaf(slice_hrn) + ".ticket")
         self.logger.info("writing ticket to %s"%file)
         ticket = SfaTicket(string=ticket_string)
@@ -1091,6 +1271,8 @@ or currently provisioned resources  (ListResources)
         # use this to get the right slice credential 
         ticket = SfaTicket(filename=ticket_file)
         ticket.decode()
         # use this to get the right slice credential 
         ticket = SfaTicket(filename=ticket_file)
         ticket.decode()
+        ticket_string = ticket.save_to_string(save_parents=True)
+
         slice_hrn = ticket.gidObject.get_hrn()
         slice_urn = hrn_to_urn(slice_hrn, 'slice') 
         #slice_hrn = ticket.attributes['slivers'][0]['hrn']
         slice_hrn = ticket.gidObject.get_hrn()
         slice_urn = hrn_to_urn(slice_hrn, 'slice') 
         #slice_hrn = ticket.attributes['slivers'][0]['hrn']
@@ -1107,12 +1289,14 @@ or currently provisioned resources  (ListResources)
         for hostname in hostnames:
             try:
                 self.logger.info("Calling redeem_ticket at %(hostname)s " % locals())
         for hostname in hostnames:
             try:
                 self.logger.info("Calling redeem_ticket at %(hostname)s " % locals())
-                server = self.server_proxy(hostname, CM_PORT, self.private_key, \
-                                               self.my_gid, verbose=self.options.debug)
-                server.RedeemTicket(ticket.save_to_string(save_parents=True), slice_cred)
+                cm_url="http://%s:%s/"%(hostname,CM_PORT)
+                server = SfaServerProxy(cm_url, self.private_key, self.my_gid)
+                server = self.server_proxy(hostname, CM_PORT, self.private_key, 
+                                           timeout=self.options.timeout, verbose=self.options.debug)
+                server.RedeemTicket(ticket_string, slice_cred)
                 self.logger.info("Success")
             except socket.gaierror:
                 self.logger.info("Success")
             except socket.gaierror:
-                self.logger.error("redeem_ticket failed: Component Manager not accepting requests")
+                self.logger.error("redeem_ticket failed on %s: Component Manager not accepting requests"%hostname)
             except Exception, e:
                 self.logger.log_exc(e.message)
         return
             except Exception, e:
                 self.logger.log_exc(e.message)
         return
@@ -1125,7 +1309,7 @@ or currently provisioned resources  (ListResources)
             self.print_help()
             sys.exit(1)
         target_hrn = args[0]
             self.print_help()
             sys.exit(1)
         target_hrn = args[0]
-        gid = self.registry().CreateGid(self.my_credential_string, target_hrn, self.bootstrap.my_gid_string())
+        gid = self.registry().CreateGid(self.my_credential_string, target_hrn, self.client_bootstrap.my_gid_string())
         if options.file:
             filename = options.file
         else:
         if options.file:
             filename = options.file
         else:
@@ -1172,3 +1356,6 @@ or currently provisioned resources  (ListResources)
             self.logger.debug('Sfi.get_trusted_certs -> %r'%cert.get_subject())
         return 
 
             self.logger.debug('Sfi.get_trusted_certs -> %r'%cert.get_subject())
         return 
 
+    def config (self, options, args):
+        "Display contents of current config"
+        self.show_config()