really fixed the redundant logging issue this time.
[sfa.git] / sfa / client / sfi.py
index 7faa4d5..750d873 100755 (executable)
@@ -10,19 +10,22 @@ import traceback
 import socket
 import random
 import datetime
 import socket
 import random
 import datetime
+import zlib
 from lxml import etree
 from StringIO import StringIO
 from types import StringTypes, ListType
 from optparse import OptionParser
 from lxml import etree
 from StringIO import StringIO
 from types import StringTypes, ListType
 from optparse import OptionParser
+from sfa.util.sfalogging import info_logger
 from sfa.trust.certificate import Keypair, Certificate
 from sfa.trust.certificate import Keypair, Certificate
+from sfa.trust.gid import GID
 from sfa.trust.credential import Credential
 from sfa.util.sfaticket import SfaTicket
 from sfa.trust.credential import Credential
 from sfa.util.sfaticket import SfaTicket
-from sfa.util.record import *
-from sfa.util.namespace import *
-from sfa.util.xmlrpcprotocol import ServerException
+from sfa.util.record import SfaRecord, UserRecord, SliceRecord, NodeRecord, AuthorityRecord
+from sfa.util.xrn import Xrn, get_leaf, get_authority, hrn_to_urn
 import sfa.util.xmlrpcprotocol as xmlrpcprotocol
 from sfa.util.config import Config
 import sfa.util.xmlrpcprotocol as xmlrpcprotocol
 from sfa.util.config import Config
-import zlib
+from sfa.util.version import version_core
+from sfa.util.cache import Cache
 
 AGGREGATE_PORT=12346
 CM_PORT=12346
 
 AGGREGATE_PORT=12346
 CM_PORT=12346
@@ -114,24 +117,41 @@ def load_record_from_file(filename):
     return record
 
 
     return record
 
 
+import uuid
+def unique_call_id(): return uuid.uuid4().urn
 
 class Sfi:
 
 class Sfi:
+    
+    required_options=['verbose',  'debug',  'registry',  'sm',  'auth',  'user']
+
+    # dummy to meet Sfi's expectations for its 'options' field
+    # i.e. s/t we can do setattr on
+    class DummyOptions:
+        pass
 
 
-    slicemgr = None
-    registry = None
-    user = None
-    authority = None
-    options = None
-    hashrequest = False
+    def __init__ (self,options=None):
+        if options is None: options=Sfi.DummyOptions()
+        for opt in Sfi.required_options:
+            if not hasattr(options,opt): setattr(options,opt,None)
+        if not hasattr(options,'sfi_dir'): options.sfi_dir=os.path.expanduser("~/.sfi/")
+        self.sfi_dir = options.sfi_dir
+        self.options = options
+        self.slicemgr = None
+        self.registry = None
+        self.user = None
+        self.authority = None
+        self.hashrequest = False
+        self.logger = info_logger
    
     def create_cmd_parser(self, command, additional_cmdargs=None):
    
     def create_cmd_parser(self, command, additional_cmdargs=None):
-        cmdargs = {"list": "name",
+        cmdargs = {"list": "authority",
                   "show": "name",
                   "remove": "name",
                   "add": "record",
                   "update": "record",
                   "aggregates": "[name]",
                   "registries": "[name]",
                   "show": "name",
                   "remove": "name",
                   "add": "record",
                   "update": "record",
                   "aggregates": "[name]",
                   "registries": "[name]",
+                  "get_gid": [],  
                   "get_trusted_certs": "cred",
                   "slices": "",
                   "resources": "[name]",
                   "get_trusted_certs": "cred",
                   "slices": "",
                   "resources": "[name]",
@@ -153,24 +173,28 @@ class Sfi:
             cmdargs.update(additional_cmdargs)
 
         if command not in cmdargs:
             cmdargs.update(additional_cmdargs)
 
         if command not in cmdargs:
-            print "Invalid command\n"
-            print "Commands: ",
-            for key in cmdargs.keys():
-                print key + ",",
-            print ""
+            msg="Invalid command\n"
+            msg+="Commands: "
+            msg += ','.join(cmdargs.keys())            
+            self.logger.critical(msg)
             sys.exit(2)
 
         parser = OptionParser(usage="sfi [sfi_options] %s [options] %s" \
                                      % (command, cmdargs[command]))
 
         # user specifies remote aggregate/sm/component                          
             sys.exit(2)
 
         parser = OptionParser(usage="sfi [sfi_options] %s [options] %s" \
                                      % (command, cmdargs[command]))
 
         # user specifies remote aggregate/sm/component                          
-        if command in ("resources", "slices", "create", "delete", "start", "stop", "restart", "get_ticket", "redeem_ticket"):
+        if command in ("resources", "slices", "create", "delete", "start", "stop", 
+                       "restart", "shutdown",  "get_ticket", "renew", "status"):
             parser.add_option("-a", "--aggregate", dest="aggregate",
                              default=None, help="aggregate host")
             parser.add_option("-p", "--port", dest="port",
                              default=AGGREGATE_PORT, help="aggregate port")
             parser.add_option("-c", "--component", dest="component", default=None,
                              help="component hrn")
             parser.add_option("-a", "--aggregate", dest="aggregate",
                              default=None, help="aggregate host")
             parser.add_option("-p", "--port", dest="port",
                              default=AGGREGATE_PORT, help="aggregate port")
             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"+\
+                                  "authority in set of credentials for this call")  
         
         # registy filter option    
         if command in ("list", "show", "remove"):
         
         # registy filter option    
         if command in ("list", "show", "remove"):
@@ -180,9 +204,15 @@ class Sfi:
                             default="all")
         # display formats
         if command in ("resources"):
                             default="all")
         # display formats
         if command in ("resources"):
+            parser.add_option("-r", "--rspec-version", dest="rspec_version", default="SFA 1",
+                              help="schema type and version of resulting RSpec")
             parser.add_option("-f", "--format", dest="format", type="choice",
                              help="display format ([xml]|dns|ip)", default="xml",
                              choices=("xml", "dns", "ip"))
             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",
+                                help="optional component information", default=None)
+
 
         if command in ("resources", "show", "list"):
            parser.add_option("-o", "--output", dest="file",
 
         if command in ("resources", "show", "list"):
            parser.add_option("-o", "--output", dest="file",
@@ -200,6 +230,18 @@ class Sfi:
            parser.add_option("-s", "--slice", dest="delegate_slice",
                             help="delegate slice credential", metavar="HRN", default=None)
         
            parser.add_option("-s", "--slice", dest="delegate_slice",
                             help="delegate slice credential", metavar="HRN", default=None)
         
+        if command in ("version"):
+            parser.add_option("-a", "--aggregate", dest="aggregate",
+                             default=None, help="aggregate host")
+            parser.add_option("-p", "--port", dest="port",
+                             default=AGGREGATE_PORT, help="aggregate port")
+            parser.add_option("-R","--registry-version",
+                              action="store_true", dest="version_registry", default=False,
+                              help="probe registry version instead of slicemgr")
+            parser.add_option("-l","--local",
+                              action="store_true", dest="version_local", default=False,
+                              help="display version of the local client")
+
         return parser
 
         
         return parser
 
         
@@ -220,14 +262,12 @@ class Sfi:
                          help="user name", metavar="HRN", default=None)
         parser.add_option("-a", "--auth", dest="auth",
                          help="authority name", metavar="HRN", default=None)
                          help="user name", metavar="HRN", default=None)
         parser.add_option("-a", "--auth", dest="auth",
                          help="authority name", metavar="HRN", default=None)
-        parser.add_option("-v", "--verbose",
-                         action="store_true", dest="verbose", default=False,
-                         help="verbose mode")
+        parser.add_option("-v", "--verbose", action="count", dest="verbose", default=0,
+                         help="verbose mode - cumulative")
         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",
+        parser.add_option("-p", "--protocol", dest="protocol", default="xmlrpc",
                          help="RPC protocol (xmlrpc or soap)")
         parser.add_option("-k", "--hashrequest",
                          action="store_true", dest="hashrequest", default=False,
                          help="RPC protocol (xmlrpc or soap)")
         parser.add_option("-k", "--hashrequest",
                          action="store_true", dest="hashrequest", default=False,
@@ -236,40 +276,37 @@ class Sfi:
 
         return parser
         
 
         return parser
         
-    #
-    # Establish Connection to SliceMgr and Registry Servers
-    #
-    def set_servers(self):
+
+    def read_config(self):
        config_file = self.options.sfi_dir + os.sep + "sfi_config"
        try:
           config = Config (config_file)
        except:
        config_file = self.options.sfi_dir + os.sep + "sfi_config"
        try:
           config = Config (config_file)
        except:
-          print "Failed to read configuration file", config_file
-          print "Make sure to remove the export clauses and to add quotes"
-          if not self.options.verbose:
-             print "Re-run with -v for more details"
+          self.logger.critical("Failed to read configuration file %s"%config_file)
+          self.logger.info("Make sure to remove the export clauses and to add quotes")
+          if self.options.verbose==0:
+              self.logger.info("Re-run with -v for more details")
           else:
           else:
-             traceback.print_exc()
+              self.logger.log_exc("Could not read config file %s"%config_file)
           sys.exit(1)
     
        errors = 0
        # Set SliceMgr URL
        if (self.options.sm is not None):
           sys.exit(1)
     
        errors = 0
        # Set SliceMgr URL
        if (self.options.sm is not None):
-          sm_url = self.options.sm
+          self.sm_url = self.options.sm
        elif hasattr(config, "SFI_SM"):
        elif hasattr(config, "SFI_SM"):
-          sm_url = config.SFI_SM
+          self.sm_url = config.SFI_SM
        else:
        else:
-          print "You need to set e.g. SFI_SM='http://your.slicemanager.url:12347/' in %s" % config_file
+          self.logger.error("You need to set e.g. SFI_SM='http://your.slicemanager.url:12347/' in %s" % config_file)
           errors += 1 
     
        # Set Registry URL
        if (self.options.registry is not None):
           errors += 1 
     
        # Set Registry URL
        if (self.options.registry is not None):
-          reg_url = self.options.registry
+          self.reg_url = self.options.registry
        elif hasattr(config, "SFI_REGISTRY"):
        elif hasattr(config, "SFI_REGISTRY"):
-          reg_url = config.SFI_REGISTRY
+          self.reg_url = config.SFI_REGISTRY
        else:
        else:
-          print "You need to set e.g. SFI_REGISTRY='http://your.registry.url:12345/' in %s" % config_file
+          self.logger.errors("You need to set e.g. SFI_REGISTRY='http://your.registry.url:12345/' in %s" % config_file)
           errors += 1 
           
 
           errors += 1 
           
 
@@ -279,7 +316,7 @@ class Sfi:
        elif hasattr(config, "SFI_USER"):
           self.user = config.SFI_USER
        else:
        elif hasattr(config, "SFI_USER"):
           self.user = config.SFI_USER
        else:
-          print "You need to set e.g. SFI_USER='plc.princeton.username' in %s" % config_file
+          self.logger.errors("You need to set e.g. SFI_USER='plc.princeton.username' in %s" % config_file)
           errors += 1 
     
        # Set authority HRN
           errors += 1 
     
        # Set authority HRN
@@ -288,29 +325,73 @@ class Sfi:
        elif hasattr(config, "SFI_AUTH"):
           self.authority = config.SFI_AUTH
        else:
        elif hasattr(config, "SFI_AUTH"):
           self.authority = config.SFI_AUTH
        else:
-          print "You need to set e.g. SFI_AUTH='plc.princeton' in %s" % config_file
+          self.logger.error("You need to set e.g. SFI_AUTH='plc.princeton' in %s" % config_file)
           errors += 1 
     
        if errors:
           sys.exit(1)
           errors += 1 
     
        if errors:
           sys.exit(1)
-    
-       if self.options.verbose :
-          print "Contacting Slice Manager at:", sm_url
-          print "Contacting Registry at:", reg_url
-    
+
+
+    #
+    # Establish Connection to SliceMgr and Registry Servers
+    #
+    def set_servers(self):
+
+       self.read_config() 
        # Get key and certificate
        key_file = self.get_key_file()
        cert_file = self.get_cert_file(key_file)
        self.key = Keypair(filename=key_file) 
        self.key_file = key_file
        self.cert_file = cert_file
        # Get key and certificate
        key_file = self.get_key_file()
        cert_file = self.get_cert_file(key_file)
        self.key = Keypair(filename=key_file) 
        self.key_file = key_file
        self.cert_file = cert_file
-       self.cert = Certificate(filename=cert_file) 
-       # Establish connection to server(s)
-       self.registry = xmlrpcprotocol.get_server(reg_url, key_file, cert_file, self.options.debug)  
-       self.slicemgr = xmlrpcprotocol.get_server(sm_url, key_file, cert_file, self.options.debug)
-
+       self.cert = GID(filename=cert_file)
+       self.logger.info("Contacting Registry at: %s"%self.reg_url)
+       self.registry = xmlrpcprotocol.get_server(self.reg_url, key_file, cert_file, self.options)  
+       self.logger.info("Contacting Slice Manager at: %s"%self.sm_url)
+       self.slicemgr = xmlrpcprotocol.get_server(self.sm_url, key_file, cert_file, self.options)
        return
        return
-    
+
+    def get_cached_server_version(self, server):
+        # check local cache first
+        cache = None
+        version = None 
+        cache_file = self.sfi_dir + os.path.sep + 'sfi_cache.dat'
+        cache_key = server.url + "-version"
+        try:
+            cache = Cache(cache_file)
+        except IOError:
+            cache = Cache()
+            self.logger.info("Local cache not found at: %s" % cache_file)
+
+        if cache:
+            version = cache.get(cache_key)
+            
+        if not version: 
+            version = server.GetVersion()
+            # cache version for 24 hours
+            cache.add(cache_key, version, ttl= 60*60*24)
+
+
+        return version   
+        
+
+    def server_supports_call_id_arg(self, server):
+        """
+        Returns true if server support the optional call_id arg, false otherwise. 
+        """
+        server_version = self.get_cached_server_version(server)
+        if 'sfa' in server_version:
+            code_tag = server_version['code_tag']
+            code_tag_parts = code_tag.split("-")
+            
+            version_parts = code_tag_parts[0].split(".")
+            major, minor = version_parts[0], version_parts[1]
+            rev = code_tag_parts[1]
+            if int(major) > 1:
+                if int(minor) > 0 or int(rev) > 20:
+                    return True
+        return False                
+             
     #
     # Get various credential and spec files
     #
     #
     # Get various credential and spec files
     #
@@ -327,31 +408,99 @@ class Sfi:
     
     def get_key_file(self):
        file = os.path.join(self.options.sfi_dir, self.user.replace(self.authority + '.', '') + ".pkey")
     
     def get_key_file(self):
        file = os.path.join(self.options.sfi_dir, self.user.replace(self.authority + '.', '') + ".pkey")
-       #file = os.path.join(self.options.sfi_dir, get_leaf(self.user) + ".pkey")
        if (os.path.isfile(file)):
           return file
        else:
        if (os.path.isfile(file)):
           return file
        else:
-          print "Key file", file, "does not exist"
+          self.logger.error("Key file %s does not exist"%file)
           sys.exit(-1)
        return
     
     def get_cert_file(self, key_file):
     
           sys.exit(-1)
        return
     
     def get_cert_file(self, key_file):
     
-       #file = os.path.join(self.options.sfi_dir, get_leaf(self.user) + ".cert")
-       file = os.path.join(self.options.sfi_dir, self.user.replace(self.authority + '.', '') + ".cert")
-       if (os.path.isfile(file)):
-          return file
-       else:
-          k = Keypair(filename=key_file)
-          cert = Certificate(subject=self.user)
-          cert.set_pubkey(k)
-          cert.set_issuer(k, self.user)
-          cert.sign()
-          if self.options.verbose :
-             print "Writing self-signed certificate to", file
-          cert.save_to_file(file)
-          return file
-   
+        cert_file = os.path.join(self.options.sfi_dir, self.user.replace(self.authority + '.', '') + ".cert")
+        if (os.path.isfile(cert_file)):
+            # we'd perfer to use Registry issued certs instead of self signed certs. 
+            # if this is a Registry cert (GID) then we are done 
+            gid = GID(filename=cert_file)
+            if gid.get_urn():
+                return cert_file
+
+        # generate self signed certificate
+        k = Keypair(filename=key_file)
+        cert = Certificate(subject=self.user)
+        cert.set_pubkey(k)
+        cert.set_issuer(k, self.user)
+        cert.sign()
+        self.logger.info("Writing self-signed certificate to %s"%cert_file)
+        cert.save_to_file(cert_file)
+        self.cert = cert
+        # try to get registry issued cert
+        try:
+            self.logger.info("Getting Registry issued cert")
+            self.read_config()
+            # *hack.  need to set registyr before _get_gid() is called 
+            self.registry = xmlrpcprotocol.get_server(self.reg_url, key_file, cert_file, self.options)
+            gid = self._get_gid(type='user')
+            self.registry = None 
+            self.logger.info("Writing certificate to %s"%cert_file)
+            gid.save_to_file(cert_file)
+        except:
+            self.logger.info("Failed to download Registry issued cert")
+
+        return cert_file
+
+    def get_cached_gid(self, file):
+        """
+        Return a cached gid    
+        """
+        gid = None 
+        if (os.path.isfile(file)):
+            gid = GID(filename=file)
+        return gid
+
+    # xxx opts unused
+    def get_gid(self, opts, args):
+        """
+        Get the specify gid and save it to file
+        """
+        hrn = None
+        if args:
+            hrn = args[0]
+        gid = self._get_gid(hrn)
+        self.logger.debug("Sfi.get_gid-> %s",gid.save_to_string(save_parents=True))
+        return gid
+
+    def _get_gid(self, hrn=None, type=None):
+        """
+        git_gid helper. Retrive the gid from the registry and save it to file.
+        """
+        
+        if not hrn:
+            hrn = self.user
+        gidfile = os.path.join(self.options.sfi_dir, hrn + ".gid")
+        print gidfile
+        gid = self.get_cached_gid(gidfile)
+        if not gid:
+            user_cred = self.get_user_cred()
+            records = self.registry.Resolve(hrn, user_cred.save_to_string(save_parents=True))
+            if not records:
+                raise RecordNotFound(args[0])
+            record = records[0]
+            if type:
+                record=None
+                for rec in records:
+                   if type == rec['type']:
+                        record = rec 
+            if not record:
+                raise RecordNotFound(args[0])
+            
+            gid = GID(string=record['gid'])
+            self.logger.info("Writing gid to %s"%gidfile)
+            gid.save_to_file(filename=gidfile)
+        return gid   
+                
+     
     def get_cached_credential(self, file):
         """
         Return a cached credential only if it hasn't expired.
     def get_cached_credential(self, file):
         """
         Return a cached credential only if it hasn't expired.
@@ -359,21 +508,20 @@ class Sfi:
         if (os.path.isfile(file)):
             credential = Credential(filename=file)
             # make sure it isnt expired 
         if (os.path.isfile(file)):
             credential = Credential(filename=file)
             # make sure it isnt expired 
-            if not credential.get_lifetime or \
-               datetime.datetime.today() < credential.get_lifetime():
+            if not credential.get_expiration or \
+               datetime.datetime.today() < credential.get_expiration():
                 return credential
         return None 
  
     def get_user_cred(self):
                 return credential
         return None 
  
     def get_user_cred(self):
-        #file = os.path.join(self.options.sfi_dir, get_leaf(self.user) + ".cred")
         file = os.path.join(self.options.sfi_dir, self.user.replace(self.authority + '.', '') + ".cred")
         return self.get_cred(file, 'user', self.user)
 
     def get_auth_cred(self):
         if not self.authority:
         file = os.path.join(self.options.sfi_dir, self.user.replace(self.authority + '.', '') + ".cred")
         return self.get_cred(file, 'user', self.user)
 
     def get_auth_cred(self):
         if not self.authority:
-            print "no authority specified. Use -a or set SF_AUTH"
+            self.logger.critical("no authority specified. Use -a or set SF_AUTH")
             sys.exit(-1)
             sys.exit(-1)
-        file = os.path.join(self.options.sfi_dir, get_leaf("authority") + ".cred")
+        file = os.path.join(self.options.sfi_dir, self.authority + ".cred")
         return self.get_cred(file, 'authority', self.authority)
 
     def get_slice_cred(self, name):
         return self.get_cred(file, 'authority', self.authority)
 
     def get_slice_cred(self, name):
@@ -390,20 +538,19 @@ class Sfi:
                 if user_name.count(".") > 0:
                     user_name = user_name.replace(".", '_')
                     self.user = self.authority + "." + user_name
                 if user_name.count(".") > 0:
                     user_name = user_name.replace(".", '_')
                     self.user = self.authority + "." + user_name
-                cred_str = self.registry.get_self_credential(cert_string, "user", hrn)
+                cred_str = self.registry.GetSelfCredential(cert_string, hrn, "user")
             else:
                 # bootstrap slice credential from user credential
                 user_cred = self.get_user_cred().save_to_string(save_parents=True)
             else:
                 # bootstrap slice credential from user credential
                 user_cred = self.get_user_cred().save_to_string(save_parents=True)
-                cred_str = self.registry.get_credential(user_cred, type, hrn)
+                cred_str = self.registry.GetCredential(user_cred, hrn, type)
             
             if not cred_str:
             
             if not cred_str:
-                print "Failed to get %s credential" % (type)
+                self.logger.critical("Failed to get %s credential" % type)
                 sys.exit(-1)
                 
             cred = Credential(string=cred_str)
             cred.save_to_file(file, save_parents=True)
                 sys.exit(-1)
                 
             cred = Credential(string=cred_str)
             cred.save_to_file(file, save_parents=True)
-            if self.options.verbose:
-                print "Writing %s credential to %s" %(type, file)
+            self.logger.info("Writing %s credential to %s" %(type, file))
 
         return cred
  
 
         return cred
  
@@ -416,7 +563,7 @@ class Sfi:
        if (os.path.isfile(file)):
           return file
        else:
        if (os.path.isfile(file)):
           return file
        else:
-          print "No such rspec file", rspec
+          self.logger.critical("No such rspec file %s"%rspec)
           sys.exit(1)
     
     def get_record_file(self, record):
           sys.exit(1)
     
     def get_record_file(self, record):
@@ -427,7 +574,7 @@ class Sfi:
        if (os.path.isfile(file)):
           return file
        else:
        if (os.path.isfile(file)):
           return file
        else:
-          print "No such registry record file", record
+          self.logger.critical("No such registry record file %s"%record)
           sys.exit(1)
     
     def load_publickey_string(self, fn):
           sys.exit(1)
     
     def load_publickey_string(self, fn):
@@ -445,25 +592,30 @@ class Sfi:
     
        return key_string
 
     
        return key_string
 
+    # xxx opts undefined
     def get_component_server_from_hrn(self, hrn):
         # direct connection to the nodes component manager interface
         user_cred = self.get_user_cred().save_to_string(save_parents=True)
     def get_component_server_from_hrn(self, hrn):
         # direct connection to the nodes component manager interface
         user_cred = self.get_user_cred().save_to_string(save_parents=True)
-        records = self.registry.resolve(user_cred, hrn)
+        records = self.registry.Resolve(hrn, user_cred)
         records = filter_records('node', records)
         if not records:
         records = filter_records('node', records)
         if not records:
-            print "No such component:", opts.component
+            self.logger.warning("No such component:%r"% opts.component)
         record = records[0]
   
         record = records[0]
   
-        return self.get_server(record['hostname'], CM_PORT, self.key_file, \
-                               self.cert_file, self.options.debug)
+        return self.get_server(record['hostname'], CM_PORT, self.key_file, self.cert_file)
  
  
-    def get_server(self, host, port, keyfile, certfile, debug):
+    def get_server(self, host, port, keyfile, certfile):
         """
         """
-        Return an instnace of an xmlrpc server connection    
+        Return an instance of an xmlrpc server connection    
         """
         """
-        url = "http://%s:%s" % (host, port)
-        return xmlrpcprotocol.get_server(url, keyfile, certfile, debug)
+        # port is appended onto the domain, before the path. Should look like:
+        # http://domain:port/path
+        host_parts = host.split('/')
+        host_parts[0] = host_parts[0] + ":" + str(port)
+        url =  "http://%s" %  "/".join(host_parts)    
+        return xmlrpcprotocol.get_server(url, keyfile, certfile, self.options)
 
 
+    # xxx opts could be retrieved in self.options
     def get_server_from_opts(self, opts):
         """
         Return instance of an xmlrpc connection to a slice manager, aggregate
     def get_server_from_opts(self, opts):
         """
         Return instance of an xmlrpc connection to a slice manager, aggregate
@@ -472,8 +624,7 @@ class Sfi:
         server = self.slicemgr
         # direct connection to an aggregate
         if hasattr(opts, 'aggregate') and opts.aggregate:
         server = self.slicemgr
         # direct connection to an aggregate
         if hasattr(opts, 'aggregate') and opts.aggregate:
-            server = self.get_server(opts.aggregate, opts.port, self.key_file, \
-                                     self.cert_file, self.options.debug)
+            server = self.get_server(opts.aggregate, opts.port, self.key_file, self.cert_file)
         # direct connection to the nodes component manager interface
         if hasattr(opts, 'component') and opts.component:
             server = self.get_component_server_from_hrn(opts.component)    
         # direct connection to the nodes component manager interface
         if hasattr(opts, 'component') and opts.component:
             server = self.get_component_server_from_hrn(opts.component)    
@@ -486,14 +637,17 @@ class Sfi:
     #==========================================================================
   
     def dispatch(self, command, cmd_opts, cmd_args):
     #==========================================================================
   
     def dispatch(self, command, cmd_opts, cmd_args):
-        getattr(self, command)(cmd_opts, cmd_args)
+        return getattr(self, command)(cmd_opts, cmd_args)
  
     # list entires in named authority registry
     def list(self, opts, args):
  
     # list entires in named authority registry
     def list(self, opts, args):
-        user_cred = self.get_user_cred().save_to_string(save_parents=True)
+        if len(args)!= 1:
+            self.print_help()
+            sys.exit(1)
         hrn = args[0]
         hrn = args[0]
+        user_cred = self.get_user_cred().save_to_string(save_parents=True)
         try:
         try:
-            list = self.registry.list(user_cred, hrn)
+            list = self.registry.List(hrn, user_cred)
         except IndexError:
             raise Exception, "Not enough parameters for the 'list' command"
           
         except IndexError:
             raise Exception, "Not enough parameters for the 'list' command"
           
@@ -511,9 +665,12 @@ class Sfi:
     
     # show named registry record
     def show(self, opts, args):
     
     # show named registry record
     def show(self, opts, args):
-        user_cred = self.get_user_cred().save_to_string(save_parents=True)
+        if len(args)!= 1:
+            self.print_help()
+            sys.exit(1)
         hrn = args[0]
         hrn = args[0]
-        records = self.registry.resolve(user_cred, hrn)
+        user_cred = self.get_user_cred().save_to_string(save_parents=True)
+        records = self.registry.Resolve(hrn, user_cred)
         records = filter_records(opts.type, records)
         if not records:
             print "No record of type", opts.type
         records = filter_records(opts.type, records)
         if not records:
             print "No record of type", opts.type
@@ -524,7 +681,7 @@ class Sfi:
                 record = SliceRecord(dict=record)
             elif record['type'] in ['node']:
                 record = NodeRecord(dict=record)
                 record = SliceRecord(dict=record)
             elif record['type'] in ['node']:
                 record = NodeRecord(dict=record)
-            elif record['type'] in ['authority', 'ma', 'sa']:
+            elif record['type'].startswith('authority'):
                 record = AuthorityRecord(dict=record)
             else:
                 record = SfaRecord(dict=record)
                 record = AuthorityRecord(dict=record)
             else:
                 record = SfaRecord(dict=record)
@@ -532,7 +689,7 @@ class Sfi:
                 record.dump()  
             else:
                 print record.save_to_string() 
                 record.dump()  
             else:
                 print record.save_to_string() 
-       
         if opts.file:
             file = opts.file
             if not file.startswith(os.sep):
         if opts.file:
             file = opts.file
             if not file.startswith(os.sep):
@@ -541,82 +698,83 @@ class Sfi:
         return
     
     def delegate(self, opts, args):
         return
     
     def delegate(self, opts, args):
-       user_cred = self.get_user_cred()
-       if opts.delegate_user:
-           object_cred = user_cred
-       elif opts.delegate_slice:
-           object_cred = self.get_slice_cred(opts.delegate_slice)
-       else:
-           print "Must specify either --user or --slice <hrn>"
-           return
-    
-       # the gid and hrn of the object we are delegating
-       object_gid = object_cred.get_gid_object()
-       object_hrn = object_gid.get_hrn()
-    
-       if not object_cred.get_privileges().get_all_delegate():
-           print "Error: Object credential", object_hrn, "does not have delegate bit set"
-           return
-    
-       records = self.registry.resolve(user_cred.save_to_string(save_parents=True), args[0])
-       records = filter_records("user", records)
-    
-       if not records:
-           print "Error: Didn't find a user record for", args[0]
-           return
-    
-       # the gid of the user who will be delegated to
-       delegee_gid = GID(string=records[0]['gid'])
-       delegee_hrn = delegee_gid.get_hrn()
-   
-       # the key and hrn of the user who will be delegating
-       user_key = Keypair(filename=self.get_key_file())
-       user_hrn = user_cred.get_gid_caller().get_hrn()
-       subject_string = "%s delegated to %s" % (object_hrn, delegee_hrn)
-       dcred = Credential(subject=subject_string)
-       dcred.set_gid_caller(delegee_gid)
-       dcred.set_gid_object(object_gid)
-       privs = object_cred.get_privileges()
-       dcred.set_privileges(object_cred.get_privileges())
-       dcred.get_privileges().delegate_all_privileges(True)
-       dcred.set_pubkey(object_gid.get_pubkey())
-       dcred.set_issuer(user_key, user_hrn)
-       dcred.set_parent(object_cred)
-       dcred.encode()
-       dcred.sign()
-    
-       if opts.delegate_user:
-           dest_fn = os.path.join(self.options.sfi_dir, get_leaf(delegee_hrn) + "_" 
+
+        delegee_hrn = args[0]
+        if opts.delegate_user:
+            user_cred = self.get_user_cred()
+            cred = self.delegate_cred(user_cred, delegee_hrn)
+        elif opts.delegate_slice:
+            slice_cred = self.get_slice_cred(opts.delegate_slice)
+            cred = self.delegate_cred(slice_cred, delegee_hrn)
+        else:
+            self.logger.warning("Must specify either --user or --slice <hrn>")
+            return
+        delegated_cred = Credential(string=cred)
+        object_hrn = delegated_cred.get_gid_object().get_hrn()
+        if opts.delegate_user:
+            dest_fn = os.path.join(self.options.sfi_dir, get_leaf(delegee_hrn) + "_"
                                   + get_leaf(object_hrn) + ".cred")
                                   + get_leaf(object_hrn) + ".cred")
-       elif opts.delegate_slice:
-           dest_fn = os.path_join(self.options.sfi_dir, get_leaf(delegee_hrn) + "_slice_" 
+        elif opts.delegate_slice:
+            dest_fn = os.path.join(self.options.sfi_dir, get_leaf(delegee_hrn) + "_slice_"
                                   + get_leaf(object_hrn) + ".cred")
                                   + get_leaf(object_hrn) + ".cred")
+
+        delegated_cred.save_to_file(dest_fn, save_parents=True)
+
+        self.logger.info("delegated credential for %s to %s and wrote to %s"%(object_hrn, delegee_hrn,dest_fn))
     
     
-       dcred.save_to_file(dest_fn, save_parents=True)
-    
-       print "delegated credential for", object_hrn, "to", delegee_hrn, "and wrote to", dest_fn
+    def delegate_cred(self, object_cred, hrn):
+        # the gid and hrn of the object we are delegating
+        if isinstance(object_cred, str):
+            object_cred = Credential(string=object_cred) 
+        object_gid = object_cred.get_gid_object()
+        object_hrn = object_gid.get_hrn()
     
     
+        if not object_cred.get_privileges().get_all_delegate():
+            self.logger.error("Object credential %s does not have delegate bit set"%object_hrn)
+            return
+
+        # the delegating user's gid
+        caller_gid = self._get_gid(self.user)
+        caller_gidfile = os.path.join(self.options.sfi_dir, self.user + ".gid")
+  
+        # the gid of the user who will be delegated to
+        delegee_gid = self._get_gid(hrn)
+        delegee_hrn = delegee_gid.get_hrn()
+        delegee_gidfile = os.path.join(self.options.sfi_dir, delegee_hrn + ".gid")
+        delegee_gid.save_to_file(filename=delegee_gidfile)
+        dcred = object_cred.delegate(delegee_gidfile, self.get_key_file(), caller_gidfile)
+        return dcred.save_to_string(save_parents=True)
+     
     # removed named registry record
     #   - have to first retrieve the record to be removed
     def remove(self, opts, args):
         auth_cred = self.get_auth_cred().save_to_string(save_parents=True)
     # removed named registry record
     #   - have to first retrieve the record to be removed
     def remove(self, opts, args):
         auth_cred = self.get_auth_cred().save_to_string(save_parents=True)
+        if len(args)!=1:
+            self.print_help()
+            sys.exit(1)
         hrn = args[0]
         type = opts.type 
         if type in ['all']:
             type = '*'
         hrn = args[0]
         type = opts.type 
         if type in ['all']:
             type = '*'
-        return self.registry.remove(auth_cred, type, hrn)
+        return self.registry.Remove(hrn, auth_cred, type)
     
     # add named registry record
     def add(self, opts, args):
         auth_cred = self.get_auth_cred().save_to_string(save_parents=True)
     
     # add named registry record
     def add(self, opts, args):
         auth_cred = self.get_auth_cred().save_to_string(save_parents=True)
+        if len(args)!=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()
         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(auth_cred, record)
+        return self.registry.Register(record, auth_cred)
     
     # update named registry entry
     def update(self, opts, args):
         user_cred = self.get_user_cred()
     
     # update named registry entry
     def update(self, opts, args):
         user_cred = self.get_user_cred()
+        if len(args)!=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":
         rec_file = self.get_record_file(args[0])
         record = load_record_from_file(rec_file)
         if record['type'] == "user":
@@ -627,7 +785,7 @@ class Sfi:
         elif record['type'] in ["slice"]:
             try:
                 cred = self.get_slice_cred(record.get_name()).save_to_string(save_parents=True)
         elif record['type'] in ["slice"]:
             try:
                 cred = self.get_slice_cred(record.get_name()).save_to_string(save_parents=True)
-            except ServerException, e:
+            except xmlrpcprotocol.ServerException, e:
                # XXX smbaker -- once we have better error return codes, update this
                # to do something better than a string compare
                if "Permission error" in e.args[0]:
                # XXX smbaker -- once we have better error return codes, update this
                # to do something better than a string compare
                if "Permission error" in e.args[0]:
@@ -641,16 +799,18 @@ class Sfi:
         else:
             raise "unknown record type" + record.get_type()
         record = record.as_dict()
         else:
             raise "unknown record type" + record.get_type()
         record = record.as_dict()
-        return self.registry.update(cred, record)
+        return self.registry.Update(record, cred)
   
     def get_trusted_certs(self, opts, args):
         """
   
     def get_trusted_certs(self, opts, args):
         """
-        return the trusted certs at this interface 
+        return uhe trusted certs at this interface 
         """ 
         trusted_certs = self.registry.get_trusted_certs()
         for trusted_cert in trusted_certs:
         """ 
         trusted_certs = self.registry.get_trusted_certs()
         for trusted_cert in trusted_certs:
+            gid = GID(string=trusted_cert)
+            gid.dump()
             cert = Certificate(string=trusted_cert)
             cert = Certificate(string=trusted_cert)
-            print cert.get_subject()
+            self.logger.debug('Sfi.get_trusted_certs -> %r'%cert.get_subject())
         return 
 
     def aggregates(self, opts, args):
         return 
 
     def aggregates(self, opts, args):
@@ -682,12 +842,18 @@ class Sfi:
     # ==================================================================
     # Slice-related commands
     # ==================================================================
     # ==================================================================
     # Slice-related commands
     # ==================================================================
-    
 
     def version(self, opts, args):
 
     def version(self, opts, args):
-        server = self.get_server_from_opts(opts)
-        
-        print server.GetVersion()
+        if opts.version_local:
+            version=version_core()
+        else:
+            if opts.version_registry:
+                server=self.registry
+            else:
+                server = self.get_server_from_opts(opts)
+            version=server.GetVersion()
+        for (k,v) in version.iteritems():
+            print "%-20s: %s"%(k,v)
 
     # list instantiated slices
     def slices(self, opts, args):
 
     # list instantiated slices
     def slices(self, opts, args):
@@ -695,8 +861,13 @@ class Sfi:
         list instantiated slices
         """
         user_cred = self.get_user_cred().save_to_string(save_parents=True)
         list instantiated slices
         """
         user_cred = self.get_user_cred().save_to_string(save_parents=True)
+        creds = [user_cred]
+        if opts.delegate:
+            delegated_cred = self.delegate_cred(user_cred, get_authority(self.authority))
+            creds.append(delegated_cred)  
         server = self.get_server_from_opts(opts)
         server = self.get_server_from_opts(opts)
-        results = server.ListSlices([user_cred])
+        #results = server.ListSlices(creds, unique_call_id())
+        results = server.ListSlices(creds)
         display_list(results)
         return
     
         display_list(results)
         return
     
@@ -710,15 +881,29 @@ class Sfi:
         if args:
             cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
             hrn = args[0]
         if args:
             cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
             hrn = args[0]
-            call_options = {'geni_slice_urn': hrn_to_urn(hrn, 'slice')}
+           call_options = {'geni_slice_urn': hrn_to_urn(hrn, 'slice')}
         else:
             cred = user_cred
             hrn = None
         else:
             cred = user_cred
             hrn = None
-        
-        result = server.ListResources([cred], call_options)
+     
+        creds = [cred]
+        if opts.delegate:
+            delegated_cred = self.delegate_cred(cred, get_authority(self.authority))
+            creds.append(delegated_cred)
+        if opts.rspec_version:
+            call_options['rspec_version'] = opts.rspec_version 
+        #panos add info options
+        if opts.info:
+            call_options['info'] = opts.info 
+
+        call_args = [creds, call_options]
+        if self.server_supports_call_id_arg(server):
+            call_args.append(unique_call_id())
+        result = server.ListResources(*call_args)
         format = opts.format
         format = opts.format
-        display_rspec(result, format)
-        if (opts.file is not None):
+        if opts.file is None:
+            display_rspec(result, format)
+        else:
             file = opts.file
             if not file.startswith(os.sep):
                 file = os.path.join(self.options.sfi_dir, file)
             file = opts.file
             if not file.startswith(os.sep):
                 file = os.path.join(self.options.sfi_dir, file)
@@ -731,10 +916,42 @@ class Sfi:
         slice_urn = hrn_to_urn(slice_hrn, 'slice') 
         user_cred = self.get_user_cred()
         slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
         slice_urn = hrn_to_urn(slice_hrn, 'slice') 
         user_cred = self.get_user_cred()
         slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
+        creds = [slice_cred]
+        if opts.delegate:
+            delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
+            creds.append(delegated_cred)
         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()
+
+        # users = [
+        #  { urn: urn:publicid:IDN+emulab.net+user+alice
+        #    keys: [<ssh key A>, <ssh key B>] 
+        #  }]
+        users = []
         server = self.get_server_from_opts(opts)
         server = self.get_server_from_opts(opts)
-        result =  server.CreateSliver(slice_urn, [slice_cred], rspec, [])
+        version = server.GetVersion()
+        if 'sfa' not in version:
+            # need to pass along user keys if this request is going to a ProtoGENI aggregate 
+            # ProtoGeni Aggregates will only install the keys of the user that is issuing the
+            # request. So we will only pass in one user that contains the keys for all
+            # users of the slice 
+            user = {'urn': user_cred.get_gid_caller().get_urn(),
+                    'keys': []}
+            slice_record = self.registry.Resolve(slice_urn, creds)
+            if slice_record and 'researchers' in slice_record:
+                user_hrns = slice_record['researchers']
+                user_urns = [hrn_to_urn(hrn, 'user') for hrn in user_hrns] 
+                user_records = self.registry.Resolve(user_urns, creds)
+                for user_record in user_records:
+                    if 'keys' in user_record:
+                        user['keys'].extend(user_record['keys'])
+            users.append(user)
+
+        call_args = [slice_urn, creds, rspec, users]
+        if self.server_supports_call_id_arg(server):
+            call_args.append(unique_call_id())
+             
+        result =  server.CreateSliver(*call_args)
         print result
         return result
 
         print result
         return result
 
@@ -744,12 +961,16 @@ class Sfi:
         slice_urn = hrn_to_urn(slice_hrn, 'slice')
         user_cred = self.get_user_cred()
         slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
         slice_urn = hrn_to_urn(slice_hrn, 'slice')
         user_cred = self.get_user_cred()
         slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
+        creds = [slice_cred]
+        if opts.delegate:
+            delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
+            creds.append(delegated_cred)
         rspec_file = self.get_rspec_file(rspec_path) 
         rspec = open(rspec_file).read()
         server = self.get_server_from_opts(opts)
         rspec_file = self.get_rspec_file(rspec_path) 
         rspec = open(rspec_file).read()
         server = self.get_server_from_opts(opts)
-        ticket_string = server.GetTicket(slice_urn, [slice_cred], rspec, [])
+        ticket_string = server.GetTicket(slice_urn, creds, rspec, [])
         file = os.path.join(self.options.sfi_dir, get_leaf(slice_hrn) + ".ticket")
         file = os.path.join(self.options.sfi_dir, get_leaf(slice_hrn) + ".ticket")
-        print "writing ticket to ", file        
+        self.logger.info("writing ticket to %s"%file)
         ticket = SfaTicket(string=ticket_string)
         ticket.save_to_file(filename=file, save_parents=True)
 
         ticket = SfaTicket(string=ticket_string)
         ticket.save_to_file(filename=file, save_parents=True)
 
@@ -776,16 +997,15 @@ class Sfi:
         connections = {}
         for hostname in hostnames:
             try:
         connections = {}
         for hostname in hostnames:
             try:
-                print "Calling redeem_ticket at %(hostname)s " % locals(),
+                self.logger.info("Calling redeem_ticket at %(hostname)s " % locals())
                 server = self.get_server(hostname, CM_PORT, self.key_file, \
                                          self.cert_file, self.options.debug)
                 server.RedeemTicket(ticket.save_to_string(save_parents=True), slice_cred)
                 server = self.get_server(hostname, CM_PORT, self.key_file, \
                                          self.cert_file, self.options.debug)
                 server.RedeemTicket(ticket.save_to_string(save_parents=True), slice_cred)
-                print "Success"
+                self.logger.info("Success")
             except socket.gaierror:
             except socket.gaierror:
-                print "Failed:",
-                print "Componet Manager not accepting requests" 
+                self.logger.error("redeem_ticket failed: Component Manager not accepting requests")
             except Exception, e:
             except Exception, e:
-                print "Failed:", e.message
+                self.logger.log_exc(e.message)
         return
  
     # delete named slice
         return
  
     # delete named slice
@@ -793,24 +1013,40 @@ class Sfi:
         slice_hrn = args[0]
         slice_urn = hrn_to_urn(slice_hrn, 'slice') 
         slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
         slice_hrn = args[0]
         slice_urn = hrn_to_urn(slice_hrn, 'slice') 
         slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
+        creds = [slice_cred]
+        if opts.delegate:
+            delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
+            creds.append(delegated_cred)
         server = self.get_server_from_opts(opts)
         server = self.get_server_from_opts(opts)
-        return server.DeleteSliver(slice_urn, [slice_cred])
-    
+
+        call_args = [slice_urn, creds]
+        if self.server_supports_call_id_arg(server):
+            call_args.append(unique_call_id())
+        return server.DeleteSliver(*call_args) 
+  
     # start named slice
     def start(self, opts, args):
         slice_hrn = args[0]
         slice_urn = hrn_to_urn(slice_hrn, 'slice') 
         slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
     # start named slice
     def start(self, opts, args):
         slice_hrn = args[0]
         slice_urn = hrn_to_urn(slice_hrn, 'slice') 
         slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
+        creds = [slice_cred]
+        if opts.delegate:
+            delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
+            creds.append(delegated_cred)
         server = self.get_server_from_opts(opts)
         server = self.get_server_from_opts(opts)
-        return server.Start(slice_urn, [slice_cred])
+        return server.Start(slice_urn, creds)
     
     # stop named slice
     def stop(self, opts, args):
         slice_hrn = args[0]
         slice_urn = hrn_to_urn(slice_hrn, 'slice') 
         slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
     
     # stop named slice
     def stop(self, opts, args):
         slice_hrn = args[0]
         slice_urn = hrn_to_urn(slice_hrn, 'slice') 
         slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
+        creds = [slice_cred]
+        if opts.delegate:
+            delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
+            creds.append(delegated_cred)
         server = self.get_server_from_opts(opts)
         server = self.get_server_from_opts(opts)
-        return server.Stop(slice_urn, [slice_cred])
+        return server.Stop(slice_urn, creds)
     
     # reset named slice
     def reset(self, opts, args):
     
     # reset named slice
     def reset(self, opts, args):
@@ -818,70 +1054,94 @@ class Sfi:
         slice_urn = hrn_to_urn(slice_hrn, 'slice') 
         server = self.get_server_from_opts(opts)
         slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
         slice_urn = hrn_to_urn(slice_hrn, 'slice') 
         server = self.get_server_from_opts(opts)
         slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
-        return server.reset_slice(slice_cred, slice_urn)
+        creds = [slice_cred]
+        if opts.delegate:
+            delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
+            creds.append(delegated_cred)
+        return server.reset_slice(creds, slice_urn)
 
     def renew(self, opts, args):
         slice_hrn = args[0]
         slice_urn = hrn_to_urn(slice_hrn, 'slice') 
         server = self.get_server_from_opts(opts)
         slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
 
     def renew(self, opts, args):
         slice_hrn = args[0]
         slice_urn = hrn_to_urn(slice_hrn, 'slice') 
         server = self.get_server_from_opts(opts)
         slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
+        creds = [slice_cred]
+        if opts.delegate:
+            delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
+            creds.append(delegated_cred)
         time = args[1]
         time = args[1]
-        return server.RenewSliver(slice_urn, [slice_cred], time)
+        
+        call_args = [slice_urn, creds, time]
+        if self.server_supports_call_id_arg(server):
+            call_args.append(unique_call_id())
+        return server.RenewSliver(*call_args)
 
 
     def status(self, opts, args):
         slice_hrn = args[0]
         slice_urn = hrn_to_urn(slice_hrn, 'slice') 
         slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
 
 
     def status(self, opts, args):
         slice_hrn = args[0]
         slice_urn = hrn_to_urn(slice_hrn, 'slice') 
         slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
+        creds = [slice_cred]
+        if opts.delegate:
+            delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
+            creds.append(delegated_cred)
         server = self.get_server_from_opts(opts)
         server = self.get_server_from_opts(opts)
-        print server.SliverStatus(slice_urn, [slice_cred])
+        call_args = [slice_urn, creds]
+        if self.server_supports_call_id_arg(server):
+            call_args.append(unique_call_id())
+        print server.SliverStatus(*call_args)
 
 
     def shutdown(self, opts, args):
         slice_hrn = args[0]
         slice_urn = hrn_to_urn(slice_hrn, 'slice') 
         slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
 
 
     def shutdown(self, opts, args):
         slice_hrn = args[0]
         slice_urn = hrn_to_urn(slice_hrn, 'slice') 
         slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
+        creds = [slice_cred]
+        if opts.delegate:
+            delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
+            creds.append(delegated_cred)
         server = self.get_server_from_opts(opts)
         server = self.get_server_from_opts(opts)
-        return server.Shutdown(slice_urn, [slice_cred])         
+        return server.Shutdown(slice_urn, creds)         
     
     
+    def print_help (self):
+        self.sfi_parser.print_help()
+        self.cmd_parser.print_help()
+
     #
     # Main: parse arguments and dispatch to command
     #
     def main(self):
     #
     # Main: parse arguments and dispatch to command
     #
     def main(self):
-        parser = self.create_parser()
-        (options, args) = parser.parse_args()
+        self.sfi_parser = self.create_parser()
+        (options, args) = self.sfi_parser.parse_args()
         self.options = options
         self.options = options
-   
+
+        self.logger.setLevelFromOptVerbose(self.options.verbose)
         if options.hashrequest:
             self.hashrequest = True
  
         if len(args) <= 0:
         if options.hashrequest:
             self.hashrequest = True
  
         if len(args) <= 0:
-            print "No command given. Use -h for help."
-            return - 1
+            self.logger.critical("No command given. Use -h for help.")
+            return -1
     
         command = args[0]
     
         command = args[0]
-        (cmd_opts, cmd_args) = self.create_cmd_parser(command).parse_args(args[1:])
-        if self.options.verbose :
-            print "Registry %s, sm %s, dir %s, user %s, auth %s" % (options.registry, options.sm,
-                                                                   options.sfi_dir, options.user,
-                                                                   options.auth)
-            print "Command %s" % command
-            if command in ("resources"):
-                print "resources cmd_opts %s" % cmd_opts.format
-            elif command in ("list", "show", "remove"):
-                print "cmd_opts.type %s" % cmd_opts.type
-            print "cmd_args %s" % cmd_args
-    
+        self.cmd_parser = self.create_cmd_parser(command)
+        (cmd_opts, cmd_args) = self.cmd_parser.parse_args(args[1:])
+
         self.set_servers()
         self.set_servers()
-    
+        self.logger.info("Command=%s" % command)
+        if command in ("resources"):
+            self.logger.debug("resources cmd_opts %s" % cmd_opts.format)
+        elif command in ("list", "show", "remove"):
+            self.logger.debug("cmd_opts.type %s" % cmd_opts.type)
+        self.logger.debug('cmd_args %s' % cmd_args)
+
         try:
             self.dispatch(command, cmd_opts, cmd_args)
         except KeyError:
         try:
             self.dispatch(command, cmd_opts, cmd_args)
         except KeyError:
-            raise 
-            print "Command not found:", command
+            self.logger.critical ("Unknown command %s"%command)
             sys.exit(1)
     
         return
     
 if __name__ == "__main__":
             sys.exit(1)
     
         return
     
 if __name__ == "__main__":
-   Sfi().main()
+    Sfi().main()