sfaprotocol is renamed into sfaserverproxy, with class SfaServerProxy
[sfa.git] / sfa / client / sfi.py
old mode 100755 (executable)
new mode 100644 (file)
index fc6a7b4..c9bde73
@@ -1,11 +1,10 @@
-#! /usr/bin/env python
 
 
-# sfi -- slice-based facility interface
+# xxx NOTE this will soon be reviewed to take advantage of sfaclientlib
 
 import sys
 sys.path.append('.')
 
 import sys
 sys.path.append('.')
+
 import os, os.path
 import os, os.path
-import tempfile
 import socket
 import datetime
 import codecs
 import socket
 import datetime
 import codecs
@@ -13,21 +12,27 @@ import pickle
 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 sfa.client.client_helper import pg_users_arg, sfa_users_arg
-from sfa.util.sfalogging import sfi_logger
+
 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.record import SfaRecord, UserRecord, SliceRecord, NodeRecord, AuthorityRecord
-from sfa.rspecs.rspec import RSpec
-from sfa.rspecs.rspec_converter import RSpecConverter
+
+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
-import sfa.client.xmlrpcprotocol as xmlrpcprotocol
 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.rspecs.rspec import RSpec
+from sfa.rspecs.rspec_converter import RSpecConverter
 from sfa.rspecs.version_manager import VersionManager
 from sfa.rspecs.version_manager import VersionManager
+from sfa.client.return_value import ReturnValue
+
+from sfa.client.sfaserverproxy import SfaServerProxy, ServerException
+from sfa.client.client_helper import pg_users_arg, sfa_users_arg
 
 AGGREGATE_PORT=12346
 CM_PORT=12346
 
 AGGREGATE_PORT=12346
 CM_PORT=12346
@@ -158,6 +163,13 @@ class Sfi:
     
     required_options=['verbose',  'debug',  'registry',  'sm',  'auth',  'user']
 
     
     required_options=['verbose',  'debug',  'registry',  'sm',  'auth',  'user']
 
+    @staticmethod
+    def default_sfi_dir ():
+        if os.path.isfile("./sfi_config"): 
+            return os.getcwd()
+        else:
+            return os.path.expanduser("~/.sfi/")
+
     # dummy to meet Sfi's expectations for its 'options' field
     # i.e. s/t we can do setattr on
     class DummyOptions:
     # dummy to meet Sfi's expectations for its 'options' field
     # i.e. s/t we can do setattr on
     class DummyOptions:
@@ -167,10 +179,7 @@ class Sfi:
         if options is None: options=Sfi.DummyOptions()
         for opt in Sfi.required_options:
             if not hasattr(options,opt): setattr(options,opt,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/")
-        # xxx oops, this is dangerous, sounds like ww sometimes have discrepency
-        # would be safer to remove self.sfi_dir altogether
-        self.sfi_dir = options.sfi_dir
+        if not hasattr(options,'sfi_dir'): options.sfi_dir=Sfi.default_sfi_dir()
         self.options = options
         self.slicemgr = None
         self.registry = None
         self.options = options
         self.slicemgr = None
         self.registry = None
@@ -179,46 +188,68 @@ class Sfi:
         self.hashrequest = False
         self.logger = sfi_logger
         self.logger.enable_console()
         self.hashrequest = False
         self.logger = sfi_logger
         self.logger.enable_console()
+        self.available_names = [ tuple[0] for tuple in Sfi.available ]
+        self.available_dict = dict (Sfi.available)
    
    
-    def create_cmd_parser(self, command, additional_cmdargs=None):
-        cmdargs = {"list": "authority",
-                  "show": "name",
-                  "remove": "name",
-                  "add": "record",
-                  "update": "record",
-                  "aggregates": "[name]",
-                  "registries": "[name]",
-                  "create_gid": "[name]",
-                  "get_gid": [],  
-                  "get_trusted_certs": "cred",
-                  "slices": "",
-                  "resources": "[name]",
-                  "create": "name rspec",
-                  "get_ticket": "name rspec",
-                  "redeem_ticket": "ticket",
-                  "delete": "name",
-                  "reset": "name",
-                  "start": "name",
-                  "stop": "name",
-                  "delegate": "name",
-                  "status": "name",
-                  "renew": "name",
-                  "shutdown": "name",
-                  "version": "",  
-                 }
-
-        if additional_cmdargs:
-            cmdargs.update(additional_cmdargs)
-
-        if command not in cmdargs:
+    # tuples command-name expected-args in the order in which they should appear in the help
+    available = [ 
+        ("version", ""),  
+        ("list", "authority"),
+        ("show", "name"),
+        ("add", "record"),
+        ("update", "record"),
+        ("remove", "name"),
+        ("slices", ""),
+        ("resources", "[slice_hrn]"),
+        ("create", "slice_hrn rspec"),
+        ("delete", "slice_hrn"),
+        ("status", "slice_hrn"),
+        ("start", "slice_hrn"),
+        ("stop", "slice_hrn"),
+        ("reset", "slice_hrn"),
+        ("renew", "slice_hrn time"),
+        ("shutdown", "slice_hrn"),
+        ("get_ticket", "slice_hrn rspec"),
+        ("redeem_ticket", "ticket"),
+        ("delegate", "name"),
+        ("create_gid", "[name]"),
+        ("get_trusted_certs", "cred"),
+        ]
+
+    def print_command_help (self, options):
+        verbose=getattr(options,'verbose')
+        format3="%18s %-15s %s"
+        line=80*'-'
+        if not verbose:
+            print format3%("command","cmd_args","description")
+            print line
+        else:
+            print line
+            self.create_parser().print_help()
+        for command in self.available_names:
+            args=self.available_dict[command]
+            method=getattr(self,command,None)
+            doc=""
+            if method: doc=getattr(method,'__doc__',"")
+            if not doc: doc="*** no doc found ***"
+            doc=doc.strip(" \t\n")
+            doc=doc.replace("\n","\n"+35*' ')
+            if verbose:
+                print line
+            print format3%(command,args,doc)
+            if verbose:
+                self.create_cmd_parser(command).print_help()
+
+    def create_cmd_parser(self, command):
+        if command not in self.available_dict:
             msg="Invalid command\n"
             msg+="Commands: "
             msg="Invalid command\n"
             msg+="Commands: "
-            msg += ','.join(cmdargs.keys())            
+            msg += ','.join(self.available_names)            
             self.logger.critical(msg)
             sys.exit(2)
 
             self.logger.critical(msg)
             sys.exit(2)
 
-        parser = OptionParser(usage="sfi [sfi_options] %s [options] %s" \
-                                     % (command, cmdargs[command]))
+        parser = OptionParser(usage="sfi [sfi_options] %s [cmd_options] %s" \
+                                     % (command, self.available_dict[command]))
 
         # user specifies remote aggregate/sm/component                          
         if command in ("resources", "slices", "create", "delete", "start", "stop", 
 
         # user specifies remote aggregate/sm/component                          
         if command in ("resources", "slices", "create", "delete", "start", "stop", 
@@ -298,16 +329,15 @@ class Sfi:
     def create_parser(self):
 
         # Generate command line parser
     def create_parser(self):
 
         # Generate command line parser
-        parser = OptionParser(usage="sfi [options] command [command_options] [command_args]",
-                             description="Commands: gid,list,show,remove,add,update,nodes,slices,resources,create,delete,start,stop,reset")
+        parser = OptionParser(usage="sfi [sfi_options] command [cmd_options] [cmd_args]",
+                             description="Commands: %s"%(" ".join(self.available_names)))
         parser.add_option("-r", "--registry", dest="registry",
                          help="root registry", metavar="URL", default=None)
         parser.add_option("-s", "--slicemgr", dest="sm",
                          help="slice manager", metavar="URL", default=None)
         parser.add_option("-r", "--registry", dest="registry",
                          help="root registry", metavar="URL", default=None)
         parser.add_option("-s", "--slicemgr", dest="sm",
                          help="slice manager", metavar="URL", default=None)
-        default_sfi_dir = os.path.expanduser("~/.sfi/")
         parser.add_option("-d", "--dir", dest="sfi_dir",
         parser.add_option("-d", "--dir", dest="sfi_dir",
-                         help="config & working directory - default is " + default_sfi_dir,
-                         metavar="PATH", default=default_sfi_dir)
+                         help="config & working directory - default is %default",
+                         metavar="PATH", default=Sfi.default_sfi_dir())
         parser.add_option("-u", "--user", dest="user",
                          help="user name", metavar="HRN", default=None)
         parser.add_option("-a", "--auth", dest="auth",
         parser.add_option("-u", "--user", dest="user",
                          help="user name", metavar="HRN", default=None)
         parser.add_option("-a", "--auth", dest="auth",
@@ -323,12 +353,64 @@ class Sfi:
                          action="store_true", dest="hashrequest", default=False,
                          help="Create a hash of the request that will be authenticated on the server")
         parser.add_option("-t", "--timeout", dest="timeout", default=None,
                          action="store_true", dest="hashrequest", default=False,
                          help="Create a hash of the request that will be authenticated on the server")
         parser.add_option("-t", "--timeout", dest="timeout", default=None,
-                         help="Amout of time tom wait before timing out the request")
+                         help="Amout of time to wait before timing out the request")
+        parser.add_option("-?", "--commands", 
+                         action="store_true", dest="command_help", default=False,
+                         help="one page summary on commands & exit")
         parser.disable_interspersed_args()
 
         return parser
         
 
         parser.disable_interspersed_args()
 
         return parser
         
 
+    def print_help (self):
+        self.sfi_parser.print_help()
+        self.cmd_parser.print_help()
+
+    #
+    # Main: parse arguments and dispatch to command
+    #
+    def dispatch(self, command, cmd_opts, cmd_args):
+        return getattr(self, command)(cmd_opts, cmd_args)
+
+    def main(self):
+        self.sfi_parser = self.create_parser()
+        (options, args) = self.sfi_parser.parse_args()
+        if options.command_help: 
+            self.print_command_help(options)
+            sys.exit(1)
+        self.options = options
+
+        self.logger.setLevelFromOptVerbose(self.options.verbose)
+        if options.hashrequest:
+            self.hashrequest = True
+        if len(args) <= 0:
+            self.logger.critical("No command given. Use -h for help.")
+            self.print_command_help(options)
+            return -1
+    
+        command = args[0]
+        self.cmd_parser = self.create_cmd_parser(command)
+        (cmd_opts, cmd_args) = self.cmd_parser.parse_args(args[1:])
+
+        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:
+            self.logger.critical ("Unknown command %s"%command)
+            raise
+            sys.exit(1)
+    
+        return
+    
+    ####################
     def read_config(self):
        config_file = os.path.join(self.options.sfi_dir,"sfi_config")
        try:
     def read_config(self):
        config_file = os.path.join(self.options.sfi_dir,"sfi_config")
        try:
@@ -393,14 +475,13 @@ class Sfi:
        # Get key and certificate
        key_file = self.get_key_file()
        cert_file = self.get_cert_file(key_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 = GID(filename=cert_file)
        self.logger.info("Contacting Registry at: %s"%self.reg_url)
        self.key_file = key_file
        self.cert_file = cert_file
        self.cert = GID(filename=cert_file)
        self.logger.info("Contacting Registry at: %s"%self.reg_url)
-       self.registry = xmlrpcprotocol.server_proxy(self.reg_url, key_file, cert_file, timeout=self.options.timeout, verbose=self.options.debug)  
+       self.registry = SfaServerProxy(self.reg_url, key_file, cert_file, timeout=self.options.timeout, verbose=self.options.debug)  
        self.logger.info("Contacting Slice Manager at: %s"%self.sm_url)
        self.logger.info("Contacting Slice Manager at: %s"%self.sm_url)
-       self.slicemgr = xmlrpcprotocol.server_proxy(self.sm_url, key_file, cert_file, timeout=self.options.timeout, verbose=self.options.debug)
+       self.slicemgr = SfaServerProxy(self.sm_url, key_file, cert_file, timeout=self.options.timeout, verbose=self.options.debug)
        return
 
     def get_cached_server_version(self, server):
        return
 
     def get_cached_server_version(self, server):
@@ -417,19 +498,19 @@ class Sfi:
 
         if cache:
             version = cache.get(cache_key)
 
         if cache:
             version = cache.get(cache_key)
-            
+
         if not version: 
         if not version: 
-            version = server.GetVersion()
+            result = server.GetVersion()
+            version= ReturnValue.get_value(result)
             # cache version for 24 hours
             cache.add(cache_key, version, ttl= 60*60*24)
             self.logger.info("Updating cache file %s" % cache_file)
             cache.save_to_file(cache_file)
 
             # cache version for 24 hours
             cache.add(cache_key, version, ttl= 60*60*24)
             self.logger.info("Updating cache file %s" % cache_file)
             cache.save_to_file(cache_file)
 
-
         return version   
         
 
         return version   
         
 
-    def server_supports_call_id_arg(self, server):
+    def server_supports_options_arg(self, server):
         """
         Returns true if server support the optional call_id arg, false otherwise. 
         """
         """
         Returns true if server support the optional call_id arg, false otherwise. 
         """
@@ -441,11 +522,11 @@ class Sfi:
             version_parts = code_tag_parts[0].split(".")
             major, minor = version_parts[0], version_parts[1]
             rev = code_tag_parts[1]
             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:
+            if int(major) >= 1:
+                if int(minor) >= 2:
                     return True
         return False                
                     return True
         return False                
-             
+        
     #
     # Get various credential and spec files
     #
     #
     # Get various credential and spec files
     #
@@ -492,8 +573,9 @@ class Sfi:
         try:
             self.logger.info("Getting Registry issued cert")
             self.read_config()
         try:
             self.logger.info("Getting Registry issued cert")
             self.read_config()
-            # *hack.  need to set registyr before _get_gid() is called 
-            self.registry = xmlrpcprotocol.server_proxy(self.reg_url, key_file, cert_file, timeout=self.options.timeout, verbose=self.options.debug)
+            # *hack.  need to set registry before _get_gid() is called 
+            self.registry = SfaServerProxy(self.reg_url, key_file, cert_file, 
+                                                     timeout=self.options.timeout, verbose=self.options.debug)
             gid = self._get_gid(type='user')
             self.registry = None 
             self.logger.info("Writing certificate to %s"%cert_file)
             gid = self._get_gid(type='user')
             self.registry = None 
             self.logger.info("Writing certificate to %s"%cert_file)
@@ -512,17 +594,16 @@ class Sfi:
             gid = GID(filename=file)
         return gid
 
             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
+# seems useless
+#    # 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):
         """
 
     def _get_gid(self, hrn=None, type=None):
         """
@@ -608,6 +689,30 @@ class Sfi:
         return cred
  
     
         return cred
  
     
+    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)
+     
+    ######################################## miscell utilities
     def get_rspec_file(self, rspec):
        if (os.path.isabs(rspec)):
           file = rspec
     def get_rspec_file(self, rspec):
        if (os.path.isabs(rspec)):
           file = rspec
@@ -630,21 +735,6 @@ class Sfi:
           self.logger.critical("No such registry record file %s"%record)
           sys.exit(1)
     
           self.logger.critical("No such registry record file %s"%record)
           sys.exit(1)
     
-    def load_publickey_string(self, fn):
-       f = file(fn, "r")
-       key_string = f.read()
-    
-       # if the filename is a private key file, then extract the public key
-       if "PRIVATE KEY" in key_string:
-           outfn = tempfile.mktemp()
-           cmd = "openssl rsa -in " + fn + " -pubout -outform PEM -out " + outfn
-           os.system(cmd)
-           f = file(outfn, "r")
-           key_string = f.read()
-           os.remove(outfn)
-    
-       return key_string
-
     # xxx opts undefined
     def get_component_proxy_from_hrn(self, hrn):
         # direct connection to the nodes component manager interface
     # xxx opts undefined
     def get_component_proxy_from_hrn(self, hrn):
         # direct connection to the nodes component manager interface
@@ -666,7 +756,8 @@ class Sfi:
         host_parts = host.split('/')
         host_parts[0] = host_parts[0] + ":" + str(port)
         url =  "http://%s" %  "/".join(host_parts)    
         host_parts = host.split('/')
         host_parts[0] = host_parts[0] + ":" + str(port)
         url =  "http://%s" %  "/".join(host_parts)    
-        return xmlrpcprotocol.server_proxy(url, keyfile, certfile, timeout=self.options.timeout, verbose=self.options.debug)
+        return SfaServerProxy(url, keyfile, certfile, timeout=self.options.timeout, 
+                                        verbose=self.options.debug)
 
     # xxx opts could be retrieved in self.options
     def server_proxy_from_opts(self, opts):
 
     # xxx opts could be retrieved in self.options
     def server_proxy_from_opts(self, opts):
@@ -689,26 +780,29 @@ class Sfi:
     # Registry-related commands
     #==========================================================================
   
     # Registry-related commands
     #==========================================================================
   
-    def dispatch(self, command, cmd_opts, cmd_args):
-        return getattr(self, command)(cmd_opts, cmd_args)
-
-    def create_gid(self, opts, args):
-        if len(args) < 1:
-            self.print_help()
-            sys.exit(1)
-        target_hrn = args[0]
-        user_cred = self.get_user_cred().save_to_string(save_parents=True)
-        gid = self.registry.CreateGid(user_cred, target_hrn, self.cert.save_to_string())
-        if opts.file:
-            filename = opts.file
+    def version(self, opts, args):
+        """
+        display an SFA server version (GetVersion) 
+or version information about sfi itself
+        """
+        if opts.version_local:
+            version=version_core()
         else:
         else:
-            filename = os.sep.join([self.sfi_dir, '%s.gid' % target_hrn])
-        self.logger.info("writing %s gid to %s" % (target_hrn, filename))
-        GID(string=gid).save_to_file(filename)
-         
-     
-    # list entires in named authority registry
+            if opts.version_registry:
+                server=self.registry
+            else:
+                server = self.server_proxy_from_opts(opts)
+            result = server.GetVersion()
+            version = ReturnValue.get_value(result)
+        for (k,v) in version.iteritems():
+            print "%-20s: %s"%(k,v)
+        if opts.file:
+            save_variable_to_file(version, opts.file, opts.fileformat)
+
     def list(self, opts, args):
     def list(self, opts, args):
+        """
+        list entries in named authority registry (List)
+        """
         if len(args)!= 1:
             self.print_help()
             sys.exit(1)
         if len(args)!= 1:
             self.print_help()
             sys.exit(1)
@@ -728,8 +822,10 @@ class Sfi:
             save_records_to_file(opts.file, list, opts.fileformat)
         return
     
             save_records_to_file(opts.file, list, opts.fileformat)
         return
     
-    # show named registry record
     def show(self, opts, args):
     def show(self, opts, args):
+        """
+        show details about named registry record (Resolve)
+        """
         if len(args)!= 1:
             self.print_help()
             sys.exit(1)
         if len(args)!= 1:
             self.print_help()
             sys.exit(1)
@@ -738,7 +834,7 @@ class Sfi:
         records = self.registry.Resolve(hrn, user_cred)
         records = filter_records(opts.type, records)
         if not records:
         records = self.registry.Resolve(hrn, user_cred)
         records = filter_records(opts.type, records)
         if not records:
-            print "No record of type", opts.type
+            self.logger.error("No record of type %s"% opts.type)
         for record in records:
             if record['type'] in ['user']:
                 record = UserRecord(dict=record)
         for record in records:
             if record['type'] in ['user']:
                 record = UserRecord(dict=record)
@@ -758,69 +854,8 @@ class Sfi:
             save_records_to_file(opts.file, records, opts.fileformat)
         return
     
             save_records_to_file(opts.file, records, opts.fileformat)
         return
     
-    def delegate(self, opts, args):
-
-        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")
-        elif opts.delegate_slice:
-            dest_fn = os.path.join(self.options.sfi_dir, get_leaf(delegee_hrn) + "_slice_"
-                                  + 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))
-    
-    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)
-        if len(args)!=1:
-            self.print_help()
-            sys.exit(1)
-        hrn = args[0]
-        type = opts.type 
-        if type in ['all']:
-            type = '*'
-        return self.registry.Remove(hrn, auth_cred, type)
-    
-    # add named registry record
     def add(self, opts, args):
     def add(self, opts, args):
+        "add record into registry from xml file (Register)"
         auth_cred = self.get_auth_cred().save_to_string(save_parents=True)
         if len(args)!=1:
             self.print_help()
         auth_cred = self.get_auth_cred().save_to_string(save_parents=True)
         if len(args)!=1:
             self.print_help()
@@ -830,8 +865,8 @@ class Sfi:
         record = load_record_from_file(rec_file).as_dict()
         return self.registry.Register(record, auth_cred)
     
         record = load_record_from_file(rec_file).as_dict()
         return self.registry.Register(record, auth_cred)
     
-    # update named registry entry
     def update(self, opts, args):
     def update(self, opts, args):
+        "update record into registry from xml file (Update)"
         user_cred = self.get_user_cred()
         if len(args)!=1:
             self.print_help()
         user_cred = self.get_user_cred()
         if len(args)!=1:
             self.print_help()
@@ -846,7 +881,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 xmlrpcprotocol.ServerException, e:
+            except 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]:
@@ -862,92 +897,59 @@ class Sfi:
         record = record.as_dict()
         return self.registry.Update(record, cred)
   
         record = record.as_dict()
         return self.registry.Update(record, cred)
   
-    def get_trusted_certs(self, opts, args):
-        """
-        return uhe trusted certs at this interface 
-        """ 
-        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)
-            self.logger.debug('Sfi.get_trusted_certs -> %r'%cert.get_subject())
-        return 
-
-    def aggregates(self, opts, args):
-        """
-        return a list of details about known aggregates
-        """
-        user_cred = self.get_user_cred().save_to_string(save_parents=True)
-        hrn = None
-        if args:
-            hrn = args[0]
-
-        result = self.registry.get_aggregates(user_cred, hrn)
-        display_list(result)
-        return 
-
-    def registries(self, opts, args):
-        """
-        return a list of details about known registries
-        """
-        user_cred = self.get_user_cred().save_to_string(save_parents=True)
-        hrn = None
-        if args:
-            hrn = args[0]
-        result = self.registry.get_registries(user_cred, hrn)
-        display_list(result)
-        return
-
+    def remove(self, opts, args):
+        "remove registry record by name (Remove)"
+        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 = '*'
+        return self.registry.Remove(hrn, auth_cred, type)
+    
     # ==================================================================
     # Slice-related commands
     # ==================================================================
 
     # ==================================================================
     # Slice-related commands
     # ==================================================================
 
-    def version(self, opts, args):
-        if opts.version_local:
-            version=version_core()
-        else:
-            if opts.version_registry:
-                server=self.registry
-            else:
-                server = self.server_proxy_from_opts(opts)
-            version=server.GetVersion()
-        for (k,v) in version.iteritems():
-            print "%-20s: %s"%(k,v)
-        if opts.file:
-            save_variable_to_file(version, opts.file, opts.fileformat)
-
-    # list instantiated slices
     def slices(self, opts, args):
     def slices(self, opts, args):
-        """
-        list instantiated slices
-        """
+        "list instantiated slices (ListSlices) - returns urn's"
         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.server_proxy_from_opts(opts)
         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.server_proxy_from_opts(opts)
-        #results = server.ListSlices(creds, unique_call_id())
-        results = server.ListSlices(creds)
-        display_list(results)
+        call_args = [creds]
+        if self.server_supports_options_arg(server):
+            options = {'call_id': unique_call_id()}
+            call_args.append(options)
+        result = server.ListSlices(*call_args)
+        value = ReturnValue.get_value(result)
+        display_list(value)
         return
     
     # show rspec for named slice
     def resources(self, opts, args):
         return
     
     # show rspec for named slice
     def resources(self, opts, args):
+        """
+        with no arg, discover available resources,
+or currently provisioned resources  (ListResources)
+        """
         user_cred = self.get_user_cred().save_to_string(save_parents=True)
         user_cred = self.get_user_cred().save_to_string(save_parents=True)
-        server = self.slicemgr
-        call_options = {}
         server = self.server_proxy_from_opts(opts)
         server = self.server_proxy_from_opts(opts)
+   
+        options = {'call_id': unique_call_id()}
+        #panos add info options
+        if opts.info:
+            options['info'] = opts.info
         
         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')}
+            options['geni_slice_urn'] = hrn_to_urn(hrn, 'slice')
         else:
             cred = user_cred
         else:
             cred = user_cred
-            hrn = None
      
         creds = [cred]
         if opts.delegate:
      
         creds = [cred]
         if opts.delegate:
@@ -958,42 +960,43 @@ class Sfi:
             server_version = self.get_cached_server_version(server)
             if 'sfa' in server_version:
                 # just request the version the client wants 
             server_version = self.get_cached_server_version(server)
             if 'sfa' in server_version:
                 # just request the version the client wants 
-                call_options['rspec_version'] = version_manager.get_version(opts.rspec_version).to_dict()
+                options['geni_rspec_version'] = version_manager.get_version(opts.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 
             else:
                 # this must be a protogeni aggregate. We should request a v2 ad rspec
                 # regardless of what the client user requested 
-                call_options['rspec_version'] = version_manager.get_version('ProtoGENI 2').to_dict()     
-        #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())
+                options['geni_rspec_version'] = version_manager.get_version('ProtoGENI 2').to_dict()     
+        else:
+            options['geni_rspec_version'] = {'type': 'geni', 'version': '3.0'}
+        call_args = [creds, options]
         result = server.ListResources(*call_args)
         result = server.ListResources(*call_args)
+        value = ReturnValue.get_value(result)
         if opts.file is None:
         if opts.file is None:
-            display_rspec(result, opts.format)
+            display_rspec(value, opts.format)
         else:
         else:
-            save_rspec_to_file(result, opts.file)
+            save_rspec_to_file(value, opts.file)
         return
 
         return
 
-    # created named slice with given rspec
     def create(self, opts, args):
     def create(self, opts, args):
+        """
+        create or update named slice with given rspec
+        """
         server = self.server_proxy_from_opts(opts)
         server_version = self.get_cached_server_version(server)
         slice_hrn = args[0]
         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)
         server = self.server_proxy_from_opts(opts)
         server_version = self.get_cached_server_version(server)
         slice_hrn = args[0]
         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)
-
-        if hasattr(opts, 'aggregate') and opts.aggregate:
-            delegated_cred = None
-        else:
-            # delegate the cred to the callers root authority
-            delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority)+'.slicemanager')
-            #delegated_cred = self.delegate_cred(slice_cred, get_authority(slice_hrn))
-            #creds.append(delegated_cred)
-
+        delegated_cred = None
+        if server_version.get('interface') == 'slicemgr':
+            # delegate our cred to the slice manager
+            # do not delegate cred to slicemgr...not working at the moment
+            pass
+            #if server_version.get('hrn'):
+            #    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']))
+                 
         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()
 
@@ -1021,72 +1024,42 @@ class Sfi:
                 creds = [slice_cred]
                 if delegated_cred:
                     creds.append(delegated_cred)
                 creds = [slice_cred]
                 if delegated_cred:
                     creds.append(delegated_cred)
-        call_args = [slice_urn, creds, rspec, users]
-        if self.server_supports_call_id_arg(server):
-            call_args.append(unique_call_id())
-
+        # do not append users, keys, or slice tags. Anything 
+        # not contained in this request will be removed from the slice 
+        options = {'append': False}
+        if self.server_supports_options_arg(server):
+            options['call_id'] = unique_call_id()
+        call_args = [slice_urn, creds, rspec, users, options]
         result = server.CreateSliver(*call_args)
         result = server.CreateSliver(*call_args)
+        value = ReturnValue.get_value(result)
         if opts.file is None:
         if opts.file is None:
-            print result
+            print value
         else:
         else:
-            save_rspec_to_file (result, opts.file)
-        return result
+            save_rspec_to_file (value, opts.file)
+        return value
 
 
-    # get a ticket for the specified slice
-    def get_ticket(self, opts, args):
-        slice_hrn, rspec_path = args[0], args[1]
-        slice_urn = hrn_to_urn(slice_hrn, 'slice')
-        user_cred = self.get_user_cred()
+    def delete(self, opts, args):
+        """
+        delete named slice (DeleteSliver)
+        """
+        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)
         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.server_proxy_from_opts(opts)
         server = self.server_proxy_from_opts(opts)
-        ticket_string = server.GetTicket(slice_urn, creds, rspec, [])
-        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)
-        ticket.save_to_file(filename=file, save_parents=True)
-
-    def redeem_ticket(self, opts, args):
-        ticket_file = args[0]
-        
-        # get slice hrn from the ticket
-        # use this to get the right slice credential 
-        ticket = SfaTicket(filename=ticket_file)
-        ticket.decode()
-        slice_hrn = ticket.gidObject.get_hrn()
-        slice_urn = hrn_to_urn(slice_hrn, 'slice') 
-        #slice_hrn = ticket.attributes['slivers'][0]['hrn']
-        user_cred = self.get_user_cred()
-        slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
-        
-        # get a list of node hostnames from the RSpec 
-        tree = etree.parse(StringIO(ticket.rspec))
-        root = tree.getroot()
-        hostnames = root.xpath("./network/site/node/hostname/text()")
-        
-        # create an xmlrpc connection to the component manager at each of these
-        # components and gall redeem_ticket
-        connections = {}
-        for hostname in hostnames:
-            try:
-                self.logger.info("Calling redeem_ticket at %(hostname)s " % locals())
-                server = self.server_proxy(hostname, CM_PORT, self.key_file, \
-                                         self.cert_file, self.options.debug)
-                server.RedeemTicket(ticket.save_to_string(save_parents=True), slice_cred)
-                self.logger.info("Success")
-            except socket.gaierror:
-                self.logger.error("redeem_ticket failed: Component Manager not accepting requests")
-            except Exception, e:
-                self.logger.log_exc(e.message)
-        return
-    # delete named slice
-    def delete(self, opts, args):
+        call_args = [slice_urn, creds]
+        if self.server_supports_options_arg(server):
+            options = {'call_id': unique_call_id()}
+            call_args.append(options)
+        return server.DeleteSliver(*call_args) 
+  
+    def status(self, opts, args):
+        """
+        retrieve slice status (SliverStatus)
+        """
         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)
@@ -1095,14 +1068,20 @@ class Sfi:
             delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
             creds.append(delegated_cred)
         server = self.server_proxy_from_opts(opts)
             delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
             creds.append(delegated_cred)
         server = self.server_proxy_from_opts(opts)
-
         call_args = [slice_urn, creds]
         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
+        if self.server_supports_options_arg(server):
+            options = {'call_id': unique_call_id()}
+            call_args.append(options)
+        result = server.SliverStatus(*call_args)
+        value = ReturnValue.get_value(result)
+        print value
+        if opts.file:
+            save_variable_to_file(value, opts.file, opts.fileformat)
+
     def start(self, opts, args):
     def start(self, opts, args):
+        """
+        start named slice (Start)
+        """
         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)
         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)
@@ -1113,8 +1092,10 @@ class Sfi:
         server = self.server_proxy_from_opts(opts)
         return server.Start(slice_urn, creds)
     
         server = self.server_proxy_from_opts(opts)
         return server.Start(slice_urn, creds)
     
-    # stop named slice
     def stop(self, opts, args):
     def stop(self, opts, args):
+        """
+        stop named slice (Stop)
+        """
         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)
         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)
@@ -1127,6 +1108,9 @@ class Sfi:
     
     # reset named slice
     def reset(self, opts, args):
     
     # reset named slice
     def reset(self, opts, args):
+        """
+        reset named slice (reset_slice)
+        """
         slice_hrn = args[0]
         slice_urn = hrn_to_urn(slice_hrn, 'slice') 
         server = self.server_proxy_from_opts(opts)
         slice_hrn = args[0]
         slice_urn = hrn_to_urn(slice_hrn, 'slice') 
         server = self.server_proxy_from_opts(opts)
@@ -1138,6 +1122,9 @@ class Sfi:
         return server.reset_slice(creds, slice_urn)
 
     def renew(self, opts, args):
         return server.reset_slice(creds, slice_urn)
 
     def renew(self, opts, args):
+        """
+        renew slice (RenewSliver)
+        """
         slice_hrn = args[0]
         slice_urn = hrn_to_urn(slice_hrn, 'slice') 
         server = self.server_proxy_from_opts(opts)
         slice_hrn = args[0]
         slice_urn = hrn_to_urn(slice_hrn, 'slice') 
         server = self.server_proxy_from_opts(opts)
@@ -1149,12 +1136,18 @@ class Sfi:
         time = args[1]
         
         call_args = [slice_urn, creds, time]
         time = args[1]
         
         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)
+        if self.server_supports_options_arg(server):
+            options = {'call_id': unique_call_id()}
+            call_args.append(options)
+        result =  server.RenewSliver(*call_args)
+        value = ReturnValue.get_value(result)
+        return value
 
 
 
 
-    def status(self, opts, args):
+    def shutdown(self, opts, args):
+        """
+        shutdown named slice (Shutdown)
+        """
         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)
@@ -1163,66 +1156,122 @@ class Sfi:
             delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
             creds.append(delegated_cred)
         server = self.server_proxy_from_opts(opts)
             delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
             creds.append(delegated_cred)
         server = self.server_proxy_from_opts(opts)
-        call_args = [slice_urn, creds]
-        if self.server_supports_call_id_arg(server):
-            call_args.append(unique_call_id())
-        result = server.SliverStatus(*call_args)
-        print result
-        if opts.file:
-            save_variable_to_file(result, opts.file, opts.fileformat)
-
+        return server.Shutdown(slice_urn, creds)         
+    
 
 
-    def shutdown(self, opts, args):
-        slice_hrn = args[0]
-        slice_urn = hrn_to_urn(slice_hrn, 'slice') 
+    def get_ticket(self, opts, args):
+        """
+        get a ticket for the specified slice
+        """
+        slice_hrn, rspec_path = args[0], args[1]
+        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)
         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.server_proxy_from_opts(opts)
         server = self.server_proxy_from_opts(opts)
-        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):
-        self.sfi_parser = self.create_parser()
-        (options, args) = self.sfi_parser.parse_args()
-        self.options = options
+        ticket_string = server.GetTicket(slice_urn, creds, rspec, [])
+        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)
+        ticket.save_to_file(filename=file, save_parents=True)
 
 
-        self.logger.setLevelFromOptVerbose(self.options.verbose)
-        if options.hashrequest:
-            self.hashrequest = True
+    def redeem_ticket(self, opts, args):
+        """
+        Connects to nodes in a slice and redeems a ticket
+(slice hrn is retrieved from the ticket)
+        """
+        ticket_file = args[0]
+        
+        # get slice hrn from the ticket
+        # use this to get the right slice credential 
+        ticket = SfaTicket(filename=ticket_file)
+        ticket.decode()
+        slice_hrn = ticket.gidObject.get_hrn()
+        slice_urn = hrn_to_urn(slice_hrn, 'slice') 
+        #slice_hrn = ticket.attributes['slivers'][0]['hrn']
+        user_cred = self.get_user_cred()
+        slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
+        
+        # get a list of node hostnames from the RSpec 
+        tree = etree.parse(StringIO(ticket.rspec))
+        root = tree.getroot()
+        hostnames = root.xpath("./network/site/node/hostname/text()")
+        
+        # create an xmlrpc connection to the component manager at each of these
+        # components and gall redeem_ticket
+        connections = {}
+        for hostname in hostnames:
+            try:
+                self.logger.info("Calling redeem_ticket at %(hostname)s " % locals())
+                server = self.server_proxy(hostname, CM_PORT, self.key_file, \
+                                               self.cert_file, self.options.debug)
+                server.RedeemTicket(ticket.save_to_string(save_parents=True), slice_cred)
+                self.logger.info("Success")
+            except socket.gaierror:
+                self.logger.error("redeem_ticket failed: Component Manager not accepting requests")
+            except Exception, e:
+                self.logger.log_exc(e.message)
+        return
  
  
-        if len(args) <= 0:
-            self.logger.critical("No command given. Use -h for help.")
-            return -1
-    
-        command = args[0]
-        self.cmd_parser = self.create_cmd_parser(command)
-        (cmd_opts, cmd_args) = self.cmd_parser.parse_args(args[1:])
+    def create_gid(self, opts, args):
+        """
+        Create a GID (CreateGid)
+        """
+        if len(args) < 1:
+            self.print_help()
+            sys.exit(1)
+        target_hrn = args[0]
+        user_cred = self.get_user_cred().save_to_string(save_parents=True)
+        gid = self.registry.CreateGid(user_cred, target_hrn, self.cert.save_to_string())
+        if opts.file:
+            filename = opts.file
+        else:
+            filename = os.sep.join([self.options.sfi_dir, '%s.gid' % target_hrn])
+        self.logger.info("writing %s gid to %s" % (target_hrn, filename))
+        GID(string=gid).save_to_file(filename)
+         
 
 
-        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)
+    def delegate(self, opts, args):
+        """
+        (locally) create delegate credential for use by given 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")
+        elif opts.delegate_slice:
+            dest_fn = os.path.join(self.options.sfi_dir, get_leaf(delegee_hrn) + "_slice_"
+                                  + get_leaf(object_hrn) + ".cred")
 
 
-        try:
-            self.dispatch(command, cmd_opts, cmd_args)
-        except KeyError:
-            self.logger.critical ("Unknown command %s"%command)
-            raise
-            sys.exit(1)
-    
-        return
+        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))
     
     
-if __name__ == "__main__":
-    Sfi().main()
+    def get_trusted_certs(self, opts, args):
+        """
+        return uhe trusted certs at this interface (get_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)
+            self.logger.debug('Sfi.get_trusted_certs -> %r'%cert.get_subject())
+        return 
+