Merge Master in geni-v3 conflict resolution
[sfa.git] / sfa / client / sfi.py
index 72f15b3..53d655b 100644 (file)
@@ -1,7 +1,6 @@
 #
 # sfi.py - basic SFA command-line client
 #
 # sfi.py - basic SFA command-line client
-# the actual binary in sfa/clientbin essentially runs main()
-# this module is used in sfascan
+# this module is also used in sfascan
 #
 
 import sys
 #
 
 import sys
@@ -14,10 +13,12 @@ import datetime
 import codecs
 import pickle
 import json
 import codecs
 import pickle
 import json
+import shutil
 from lxml import etree
 from StringIO import StringIO
 from optparse import OptionParser
 from pprint import PrettyPrinter
 from lxml import etree
 from StringIO import StringIO
 from optparse import OptionParser
 from pprint import PrettyPrinter
+from tempfile import mkstemp
 
 from sfa.trust.certificate import Keypair, Certificate
 from sfa.trust.gid import GID
 
 from sfa.trust.certificate import Keypair, Certificate
 from sfa.trust.gid import GID
@@ -41,33 +42,12 @@ from sfa.client.sfaclientlib import SfaClientBootstrap
 from sfa.client.sfaserverproxy import SfaServerProxy, ServerException
 from sfa.client.client_helper import pg_users_arg, sfa_users_arg
 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
 from sfa.client.return_value import ReturnValue
+from sfa.client.candidates import Candidates
 
 CM_PORT=12346
 
 
 CM_PORT=12346
 
-# utility methods here
-def optparse_listvalue_callback(option, option_string, value, parser):
-    setattr(parser.values, option.dest, value.split(','))
-
-# a code fragment that could be helpful for argparse which unfortunately is 
-# available with 2.7 only, so this feels like too strong a requirement for the client side
-#class ExtraArgAction  (argparse.Action):
-#    def __call__ (self, parser, namespace, values, option_string=None):
-# would need a try/except of course
-#        (k,v)=values.split('=')
-#        d=getattr(namespace,self.dest)
-#        d[k]=v
-#####
-#parser.add_argument ("-X","--extra",dest='extras', default={}, action=ExtraArgAction,
-#                     help="set extra flags, testbed dependent, e.g. --extra enabled=true")
-    
-def optparse_dictvalue_callback (option, option_string, value, parser):
-    try:
-        (k,v)=value.split('=',1)
-        d=getattr(parser.values, option.dest)
-        d[k]=v
-    except:
-        parser.print_help()
-        sys.exit(1)
+from sfa.client.common import optparse_listvalue_callback, optparse_dictvalue_callback, \
+    terminal_render, filter_records 
 
 # display methods
 def display_rspec(rspec, format='rspec'):
 
 # display methods
 def display_rspec(rspec, format='rspec'):
@@ -113,6 +93,22 @@ def filter_records(type, records):
     return filtered_records
 
 
     return filtered_records
 
 
+def credential_printable (cred):
+    credential=Credential(cred=cred)
+    result=""
+    result += credential.get_summary_tostring()
+    result += "\n"
+    rights = credential.get_privileges()
+    result += "type=%s\n" % credential.type    
+    result += "version=%s\n" % credential.version    
+    result += "rights=%s\n"%rights
+    return result
+
+def show_credentials (cred_s):
+    if not isinstance (cred_s,list): cred_s = [cred_s]
+    for cred in cred_s:
+        print "Using Credential %s"%credential_printable(cred)
+
 # save methods
 def save_raw_to_file(var, filename, format="text", banner=None):
     if filename == "-":
 # save methods
 def save_raw_to_file(var, filename, format="text", banner=None):
     if filename == "-":
@@ -263,24 +259,24 @@ class Sfi:
         ("version", ""),  
         ("list", "authority"),
         ("show", "name"),
         ("version", ""),  
         ("list", "authority"),
         ("show", "name"),
-        ("add", "record"),
-        ("update", "record"),
+        ("add", "[record]"),
+        ("update", "[record]"),
         ("remove", "name"),
         ("remove", "name"),
-        ("slices", ""),
-        ("resources", "[slice_hrn]"),
+        ("resources", ""),
+        ("describe", "slice_hrn"),
         ("create", "slice_hrn rspec"),
         ("create", "slice_hrn rspec"),
+        ("allocate", "slice_hrn rspec"),
+        ("provision", "slice_hrn"),
+        ("action", "slice_hrn action"), 
         ("delete", "slice_hrn"),
         ("status", "slice_hrn"),
         ("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"),
         ("renew", "slice_hrn time"),
         ("shutdown", "slice_hrn"),
         ("get_ticket", "slice_hrn rspec"),
         ("redeem_ticket", "ticket"),
-        ("delegate", "name"),
-        ("create_gid", "[name]"),
-        ("get_trusted_certs", "cred"),
+        ("delegate", "to_hrn"),
+        ("gid", "[name]"),
+        ("trusted", "cred"),
         ("config", ""),
         ]
 
         ("config", ""),
         ]
 
@@ -323,41 +319,41 @@ class Sfi:
             parser.add_option('-x', '--xrn', dest='xrn', metavar='<xrn>', help='object hrn/urn (mandatory)')
             parser.add_option('-t', '--type', dest='type', metavar='<type>', help='object type', default=None)
             parser.add_option('-e', '--email', dest='email', default="",  help="email (mandatory for users)") 
             parser.add_option('-x', '--xrn', dest='xrn', metavar='<xrn>', help='object hrn/urn (mandatory)')
             parser.add_option('-t', '--type', dest='type', metavar='<type>', help='object type', default=None)
             parser.add_option('-e', '--email', dest='email', default="",  help="email (mandatory for users)") 
-# use --extra instead
-#            parser.add_option('-u', '--url', dest='url', metavar='<url>', default=None, help="URL, useful for slices") 
-#            parser.add_option('-d', '--description', dest='description', metavar='<description>', 
-#                              help='Description, useful for slices', default=None)
             parser.add_option('-k', '--key', dest='key', metavar='<key>', help='public key string or file', 
                               default=None)
             parser.add_option('-k', '--key', dest='key', metavar='<key>', help='public key string or file', 
                               default=None)
-            parser.add_option('-s', '--slices', dest='slices', metavar='<slices>', help='slice xrns',
+            parser.add_option('-s', '--slices', dest='slices', metavar='<slices>', help='Set/replace slice xrns',
                               default='', type="str", action='callback', callback=optparse_listvalue_callback)
             parser.add_option('-r', '--researchers', dest='researchers', metavar='<researchers>', 
                               default='', type="str", action='callback', callback=optparse_listvalue_callback)
             parser.add_option('-r', '--researchers', dest='researchers', metavar='<researchers>', 
-                              help='slice researchers', default='', type="str", action='callback', 
+                              help='Set/replace slice researchers', default='', type="str", action='callback', 
                               callback=optparse_listvalue_callback)
                               callback=optparse_listvalue_callback)
-            parser.add_option('-p', '--pis', dest='pis', metavar='<PIs>', help='Principal Investigators/Project Managers',
+            parser.add_option('-p', '--pis', dest='pis', metavar='<PIs>', help='Set/replace Principal Investigators/Project Managers',
                               default='', type="str", action='callback', callback=optparse_listvalue_callback)
                               default='', type="str", action='callback', callback=optparse_listvalue_callback)
-# use --extra instead
-#            parser.add_option('-f', '--firstname', dest='firstname', metavar='<firstname>', help='user first name')
-#            parser.add_option('-l', '--lastname', dest='lastname', metavar='<lastname>', help='user last name')
             parser.add_option ('-X','--extra',dest='extras',default={},type='str',metavar="<EXTRA_ASSIGNS>",
                                action="callback", callback=optparse_dictvalue_callback, nargs=1,
                                help="set extra/testbed-dependent flags, e.g. --extra enabled=true")
 
         # user specifies remote aggregate/sm/component                          
             parser.add_option ('-X','--extra',dest='extras',default={},type='str',metavar="<EXTRA_ASSIGNS>",
                                action="callback", callback=optparse_dictvalue_callback, nargs=1,
                                help="set extra/testbed-dependent flags, e.g. --extra enabled=true")
 
         # user specifies remote aggregate/sm/component                          
-        if command in ("resources", "slices", "create", "delete", "start", "stop", 
-                       "restart", "shutdown",  "get_ticket", "renew", "status"):
+        if command in ("resources", "describe", "allocate", "provision", "create", "delete", "allocate", "provision", 
+                       "action", "shutdown",  "get_ticket", "renew", "status"):
             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")
 
             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")
 
+        # show_credential option
+        if command in ("list","resources", "describe", "provision", "allocate", "create","add","update","remove","slices","delete","status","renew"):
+            parser.add_option("-C","--credential",dest='show_credential',action='store_true',default=False,
+                              help="show credential(s) used in human-readable form")
         # registy filter option
         if command in ("list", "show", "remove"):
             parser.add_option("-t", "--type", dest="type", type="choice",
                             help="type filter ([all]|user|slice|authority|node|aggregate)",
                             choices=("all", "user", "slice", "authority", "node", "aggregate"),
                             default="all")
         # registy filter option
         if command in ("list", "show", "remove"):
             parser.add_option("-t", "--type", dest="type", type="choice",
                             help="type filter ([all]|user|slice|authority|node|aggregate)",
                             choices=("all", "user", "slice", "authority", "node", "aggregate"),
                             default="all")
-        if command in ("resources"):
+        if command in ("show"):
+            parser.add_option("-k","--key",dest="keys",action="append",default=[],
+                              help="specify specific keys to be displayed from record")
+        if command in ("resources", "describe"):
             # rspec version
             parser.add_option("-r", "--rspec-version", dest="rspec_version", default="SFA 1",
                               help="schema type and version of resulting RSpec")
             # rspec version
             parser.add_option("-r", "--rspec-version", dest="rspec_version", default="SFA 1",
                               help="schema type and version of resulting RSpec")
@@ -379,7 +375,7 @@ class Sfi:
 
 
         # 'create' does return the new rspec, makes sense to save that too
 
 
         # 'create' does return the new rspec, makes sense to save that too
-        if command in ("resources", "show", "list", "create_gid", 'create'):
+        if command in ("resources", "describe", "allocate", "provision", "show", "list", "gid", 'create'):
            parser.add_option("-o", "--output", dest="file",
                             help="output XML to file", metavar="FILE", default=None)
 
            parser.add_option("-o", "--output", dest="file",
                             help="output XML to file", metavar="FILE", default=None)
 
@@ -394,12 +390,22 @@ class Sfi:
         if command == 'list':
            parser.add_option("-r", "--recursive", dest="recursive", action='store_true',
                              help="list all child records", default=False)
         if command == 'list':
            parser.add_option("-r", "--recursive", dest="recursive", action='store_true',
                              help="list all child records", default=False)
+           parser.add_option("-v", "--verbose", dest="verbose", action='store_true',
+                             help="gives details, like user keys", default=False)
         if command in ("delegate"):
            parser.add_option("-u", "--user",
         if command in ("delegate"):
            parser.add_option("-u", "--user",
-                            action="store_true", dest="delegate_user", default=False,
-                            help="delegate user credential")
-           parser.add_option("-s", "--slice", dest="delegate_slice",
-                            help="delegate slice credential", metavar="HRN", default=None)
+                             action="store_true", dest="delegate_user", default=False,
+                             help="delegate your own credentials; default if no other option is provided")
+           parser.add_option("-s", "--slice", dest="delegate_slices",action='append',default=[],
+                             metavar="slice_hrn", help="delegate cred. for slice HRN")
+           parser.add_option("-a", "--auths", dest='delegate_auths',action='append',default=[],
+                             metavar='auth_hrn', help="delegate cred for auth HRN")
+           # this primarily is a shorthand for -a my_hrn^
+           parser.add_option("-p", "--pi", dest='delegate_pi', default=None, action='store_true',
+                             help="delegate your PI credentials, so s.t. like -a your_hrn^")
+           parser.add_option("-A","--to-authority",dest='delegate_to_authority',action='store_true',default=False,
+                             help="""by default the mandatory argument is expected to be a user, 
+use this if you mean an authority instead""")
         
         if command in ("version"):
             parser.add_option("-R","--registry-version",
         
         if command in ("version"):
             parser.add_option("-R","--registry-version",
@@ -455,14 +461,20 @@ class Sfi:
         
 
     def print_help (self):
         
 
     def print_help (self):
+        print "==================== Generic sfi usage"
         self.sfi_parser.print_help()
         self.sfi_parser.print_help()
+        print "==================== Specific command usage"
         self.command_parser.print_help()
 
     #
     # Main: parse arguments and dispatch to command
     #
     def dispatch(self, command, command_options, command_args):
         self.command_parser.print_help()
 
     #
     # Main: parse arguments and dispatch to command
     #
     def dispatch(self, command, command_options, command_args):
-        return getattr(self, command)(command_options, command_args)
+        method=getattr(self, command,None)
+        if not method:
+            print "Unknown command %s"%command
+            return
+        return method(command_options, command_args)
 
     def main(self):
         self.sfi_parser = self.create_parser()
 
     def main(self):
         self.sfi_parser = self.create_parser()
@@ -479,37 +491,59 @@ class Sfi:
             self.print_command_help(options)
             return -1
     
             self.print_command_help(options)
             return -1
     
-        command = args[0]
+        # complete / find unique match with command set
+        command_candidates = Candidates (self.available_names)
+        input = args[0]
+        command = command_candidates.only_match(input)
+        if not command:
+            self.print_command_help(options)
+            sys.exit(1)
+        # second pass options parsing
         self.command_parser = self.create_command_parser(command)
         (command_options, command_args) = self.command_parser.parse_args(args[1:])
         self.command_options = command_options
 
         self.read_config () 
         self.bootstrap ()
         self.command_parser = self.create_command_parser(command)
         (command_options, command_args) = self.command_parser.parse_args(args[1:])
         self.command_options = command_options
 
         self.read_config () 
         self.bootstrap ()
-        self.logger.info("Command=%s" % command)
+        self.logger.debug("Command=%s" % command)
 
         try:
             self.dispatch(command, command_options, command_args)
 
         try:
             self.dispatch(command, command_options, command_args)
-        except KeyError:
-            self.logger.critical ("Unknown command %s"%command)
-            raise
+        except:
+            self.logger.log_exc ("sfi command %s failed"%command)
             sys.exit(1)
             sys.exit(1)
-    
+
         return
     
     ####################
     def read_config(self):
         config_file = os.path.join(self.options.sfi_dir,"sfi_config")
         return
     
     ####################
     def read_config(self):
         config_file = os.path.join(self.options.sfi_dir,"sfi_config")
+        shell_config_file  = os.path.join(self.options.sfi_dir,"sfi_config.sh")
         try:
         try:
-           config = Config (config_file)
+            if Config.is_ini(config_file):
+                config = Config (config_file)
+            else:
+                # try upgrading from shell config format
+                fp, fn = mkstemp(suffix='sfi_config', text=True)  
+                config = Config(fn)
+                # we need to preload the sections we want parsed 
+                # from the shell config
+                config.add_section('sfi')
+                config.add_section('sface')
+                config.load(config_file)
+                # back up old config
+                shutil.move(config_file, shell_config_file)
+                # write new config
+                config.save(config_file)
+                 
         except:
         except:
-           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:
-               self.logger.log_exc("Could not read config file %s"%config_file)
-           sys.exit(1)
+            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:
+                self.logger.log_exc("Could not read config file %s"%config_file)
+            sys.exit(1)
      
         errors = 0
         # Set SliceMgr URL
      
         errors = 0
         # Set SliceMgr URL
@@ -527,7 +561,7 @@ class Sfi:
         elif hasattr(config, "SFI_REGISTRY"):
            self.reg_url = config.SFI_REGISTRY
         else:
         elif hasattr(config, "SFI_REGISTRY"):
            self.reg_url = config.SFI_REGISTRY
         else:
-           self.logger.errors("You need to set e.g. SFI_REGISTRY='http://your.registry.url:12345/' in %s" % config_file)
+           self.logger.error("You need to set e.g. SFI_REGISTRY='http://your.registry.url:12345/' in %s" % config_file)
            errors += 1 
 
         # Set user HRN
            errors += 1 
 
         # Set user HRN
@@ -536,7 +570,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:
-           self.logger.errors("You need to set e.g. SFI_USER='plc.princeton.username' in %s" % config_file)
+           self.logger.error("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
@@ -578,7 +612,8 @@ class Sfi:
     
     # init self-signed cert, user credentials and gid
     def bootstrap (self):
     
     # init self-signed cert, user credentials and gid
     def bootstrap (self):
-        client_bootstrap = SfaClientBootstrap (self.user, self.reg_url, self.options.sfi_dir)
+        client_bootstrap = SfaClientBootstrap (self.user, self.reg_url, self.options.sfi_dir,
+                                               logger=self.logger)
         # if -k is provided, use this to initialize private key
         if self.options.user_private_key:
             client_bootstrap.init_private_key_if_missing (self.options.user_private_key)
         # if -k is provided, use this to initialize private key
         if self.options.user_private_key:
             client_bootstrap.init_private_key_if_missing (self.options.user_private_key)
@@ -588,7 +623,7 @@ class Sfi:
             if not os.path.isfile(client_bootstrap.private_key_filename()):
                 self.logger.info ("private key not found, trying legacy name")
                 try:
             if not os.path.isfile(client_bootstrap.private_key_filename()):
                 self.logger.info ("private key not found, trying legacy name")
                 try:
-                    legacy_private_key = os.path.join (self.options.sfi_dir, "%s.pkey"%get_leaf(self.user))
+                    legacy_private_key = os.path.join (self.options.sfi_dir, "%s.pkey"%Xrn.unescape(get_leaf(self.user)))
                     self.logger.debug("legacy_private_key=%s"%legacy_private_key)
                     client_bootstrap.init_private_key_if_missing (legacy_private_key)
                     self.logger.info("Copied private key from legacy location %s"%legacy_private_key)
                     self.logger.debug("legacy_private_key=%s"%legacy_private_key)
                     client_bootstrap.init_private_key_if_missing (legacy_private_key)
                     self.logger.info("Copied private key from legacy location %s"%legacy_private_key)
@@ -601,6 +636,9 @@ class Sfi:
         # extract what's needed
         self.private_key = client_bootstrap.private_key()
         self.my_credential_string = client_bootstrap.my_credential_string ()
         # extract what's needed
         self.private_key = client_bootstrap.private_key()
         self.my_credential_string = client_bootstrap.my_credential_string ()
+        self.my_credential = {'geni_type': 'geni_sfa',
+                              'geni_version': '3.0', 
+                              'geni_value': self.my_credential_string}
         self.my_gid = client_bootstrap.my_gid ()
         self.client_bootstrap = client_bootstrap
 
         self.my_gid = client_bootstrap.my_gid ()
         self.client_bootstrap = client_bootstrap
 
@@ -611,9 +649,17 @@ class Sfi:
             sys.exit(-1)
         return self.client_bootstrap.authority_credential_string (self.authority)
 
             sys.exit(-1)
         return self.client_bootstrap.authority_credential_string (self.authority)
 
+    def authority_credential_string(self, auth_hrn):
+        return self.client_bootstrap.authority_credential_string (auth_hrn)
+
     def slice_credential_string(self, name):
         return self.client_bootstrap.slice_credential_string (name)
 
     def slice_credential_string(self, name):
         return self.client_bootstrap.slice_credential_string (name)
 
+    def slice_credential(self, name):
+        return {'geni_type': 'geni_sfa',
+                'geni_version': '3.0',
+                'geni_value': self.slice_credential_string(name)}    
+
     # xxx should be supported by sfaclientbootstrap as well
     def delegate_cred(self, object_cred, hrn, type='authority'):
         # the gid and hrn of the object we are delegating
     # xxx should be supported by sfaclientbootstrap as well
     def delegate_cred(self, object_cred, hrn, type='authority'):
         # the gid and hrn of the object we are delegating
@@ -799,16 +845,17 @@ or version information about sfi itself
         if options.recursive:
             opts['recursive'] = options.recursive
         
         if options.recursive:
             opts['recursive'] = options.recursive
         
+        if options.show_credential:
+            show_credentials(self.my_credential_string)
         try:
             list = self.registry().List(hrn, self.my_credential_string, options)
         except IndexError:
             raise Exception, "Not enough parameters for the 'list' command"
 
         # filter on person, slice, site, node, etc.
         try:
             list = self.registry().List(hrn, self.my_credential_string, options)
         except IndexError:
             raise Exception, "Not enough parameters for the 'list' command"
 
         # filter on person, slice, site, node, etc.
-        # THis really should be in the self.filter_records funct def comment...
+        # This really should be in the self.filter_records funct def comment...
         list = filter_records(options.type, list)
         list = filter_records(options.type, list)
-        for record in list:
-            print "%s (%s)" % (record['hrn'], record['type'])
+        terminal_render (list, options)
         if options.file:
             save_records_to_file(options.file, list, options.fileformat)
         return
         if options.file:
             save_records_to_file(options.file, list, options.fileformat)
         return
@@ -821,10 +868,21 @@ or version information about sfi itself
             self.print_help()
             sys.exit(1)
         hrn = args[0]
             self.print_help()
             sys.exit(1)
         hrn = args[0]
-        record_dicts = self.registry().Resolve(hrn, self.my_credential_string)
+        # explicitly require Resolve to run in details mode
+        record_dicts = self.registry().Resolve(hrn, self.my_credential_string, {'details':True})
         record_dicts = filter_records(options.type, record_dicts)
         if not record_dicts:
             self.logger.error("No record of type %s"% options.type)
         record_dicts = filter_records(options.type, record_dicts)
         if not record_dicts:
             self.logger.error("No record of type %s"% options.type)
+            return
+        # user has required to focus on some keys
+        if options.keys:
+            def project (record):
+                projected={}
+                for key in options.keys:
+                    try: projected[key]=record[key]
+                    except: pass
+                return projected
+            record_dicts = [ project (record) for record in record_dicts ]
         records = [ Record(dict=record_dict) for record_dict in record_dicts ]
         for record in records:
             if (options.format == "text"):      record.dump(sort=True)  
         records = [ Record(dict=record_dict) for record_dict in record_dicts ]
         for record in records:
             if (options.format == "text"):      record.dump(sort=True)  
@@ -834,13 +892,22 @@ or version information about sfi itself
         return
     
     def add(self, options, args):
         return
     
     def add(self, options, args):
-        "add record into registry from xml file (Register)"
+        "add record into registry by using the command options (Recommended) or from xml file (Register)"
         auth_cred = self.my_authority_credential_string()
         auth_cred = self.my_authority_credential_string()
+        if options.show_credential:
+            show_credentials(auth_cred)
         record_dict = {}
         record_dict = {}
-        if len(args) > 0:
-            record_filepath = args[0]
-            rec_file = self.get_record_file(record_filepath)
-            record_dict.update(load_record_from_file(rec_file).todict())
+        if len(args) > 1:
+            self.print_help()
+            sys.exit(1)
+        if len(args)==1:
+            try:
+                record_filepath = args[0]
+                rec_file = self.get_record_file(record_filepath)
+                record_dict.update(load_record_from_file(rec_file).todict())
+            except:
+                print "Cannot load record file %s"%record_filepath
+                sys.exit(1)
         if options:
             record_dict.update(load_record_from_opts(options).todict())
         # we should have a type by now
         if options:
             record_dict.update(load_record_from_opts(options).todict())
         # we should have a type by now
@@ -857,7 +924,7 @@ or version information about sfi itself
         return self.registry().Register(record_dict, auth_cred)
     
     def update(self, options, args):
         return self.registry().Register(record_dict, auth_cred)
     
     def update(self, options, args):
-        "update record into registry from xml file (Update)"
+        "update record into registry by using the command options (Recommended) or from xml file (Update)"
         record_dict = {}
         if len(args) > 0:
             record_filepath = args[0]
         record_dict = {}
         if len(args) > 0:
             record_filepath = args[0]
@@ -893,6 +960,8 @@ or version information about sfi itself
             cred = self.my_authority_credential_string()
         else:
             raise "unknown record type" + record_dict['type']
             cred = self.my_authority_credential_string()
         else:
             raise "unknown record type" + record_dict['type']
+        if options.show_credential:
+            show_credentials(cred)
         return self.registry().Update(record_dict, cred)
   
     def remove(self, options, args):
         return self.registry().Update(record_dict, cred)
   
     def remove(self, options, args):
@@ -905,6 +974,8 @@ or version information about sfi itself
         type = options.type 
         if type in ['all']:
             type = '*'
         type = options.type 
         if type in ['all']:
             type = '*'
+        if options.show_credential:
+            show_credentials(auth_cred)
         return self.registry().Remove(hrn, auth_cred, type)
     
     # ==================================================================
         return self.registry().Remove(hrn, auth_cred, type)
     
     # ==================================================================
@@ -916,12 +987,11 @@ or version information about sfi itself
         server = self.sliceapi()
         # creds
         creds = [self.my_credential_string]
         server = self.sliceapi()
         # creds
         creds = [self.my_credential_string]
-        if options.delegate:
-            delegated_cred = self.delegate_cred(self.my_credential_string, get_authority(self.authority))
-            creds.append(delegated_cred)  
         # options and call_id when supported
         api_options = {}
         # options and call_id when supported
         api_options = {}
-       api_options['call_id']=unique_call_id()
+        api_options['call_id']=unique_call_id()
+        if options.show_credential:
+            show_credentials(creds)
         result = server.ListSlices(creds, *self.ois(server,api_options))
         value = ReturnValue.get_value(result)
         if self.options.raw:
         result = server.ListSlices(creds, *self.ois(server,api_options))
         value = ReturnValue.get_value(result)
         if self.options.raw:
@@ -933,19 +1003,17 @@ or version information about sfi itself
     # show rspec for named slice
     def resources(self, options, args):
         """
     # show rspec for named slice
     def resources(self, options, args):
         """
-        with no arg, discover available resources, (ListResources)
+        discover available resources
 or with an slice hrn, shows currently provisioned resources
         """
         server = self.sliceapi()
 
         # set creds
 or with an slice hrn, shows currently provisioned resources
         """
         server = self.sliceapi()
 
         # set creds
-        creds = []
-        if args:
-            creds.append(self.slice_credential_string(args[0]))
-        else:
-            creds.append(self.my_credential_string)
+        creds = [self.my_credential]
         if options.delegate:
             creds.append(self.delegate_cred(cred, get_authority(self.authority)))
         if options.delegate:
             creds.append(self.delegate_cred(cred, get_authority(self.authority)))
+        if options.show_credential:
+            show_credentials(creds)
 
         # no need to check if server accepts the options argument since the options has
         # been a required argument since v1 API
 
         # no need to check if server accepts the options argument since the options has
         # been a required argument since v1 API
@@ -954,9 +1022,6 @@ or with an slice hrn, shows currently provisioned resources
         api_options ['call_id'] = unique_call_id()
         # ask for cached value if available
         api_options ['cached'] = True
         api_options ['call_id'] = unique_call_id()
         # ask for cached value if available
         api_options ['cached'] = True
-        if args:
-            hrn = args[0]
-            api_options['geni_slice_urn'] = hrn_to_urn(hrn, 'slice')
         if options.info:
             api_options['info'] = options.info
         if options.list_leases:
         if options.info:
             api_options['info'] = options.info
         if options.list_leases:
@@ -987,6 +1052,45 @@ or with an slice hrn, shows currently provisioned resources
 
         return
 
 
         return
 
+    def describe(self, options, args):
+        """
+        Shows currently provisioned resources.
+        """
+        server = self.sliceapi()
+
+        # set creds
+        creds = [self.slice_credential(args[0])]
+        if options.delegate:
+            creds.append(self.delegate_cred(cred, get_authority(self.authority)))
+        if options.show_credential:
+            show_credentials(creds)
+
+        api_options = {'call_id': unique_call_id(),
+                       'cached': True,
+                       'info': options.info,
+                       'list_leases': options.list_leases,
+                       'geni_rspec_version': {'type': 'geni', 'version': '3.0'},
+                      }
+        if options.rspec_version:
+            version_manager = VersionManager()
+            server_version = self.get_cached_server_version(server)
+            if 'sfa' in server_version:
+                # just request the version the client wants
+                api_options['geni_rspec_version'] = version_manager.get_version(options.rspec_version).to_dict()
+            else:
+                api_options['geni_rspec_version'] = {'type': 'geni', 'version': '3.0'}
+        urn = Xrn(args[0], type='slice').get_urn()        
+        result = server.Describe([urn], creds, api_options)
+        value = ReturnValue.get_value(result)
+        if self.options.raw:
+            save_raw_to_file(result, self.options.raw, self.options.rawformat, self.options.rawbanner)
+        if options.file is not None:
+            save_rspec_to_file(value, options.file)
+        if (self.options.raw is None) and (options.file is None):
+            display_rspec(value, options.format)
+
+        return 
+
     def create(self, options, args):
         """
         create or update named slice with given rspec
     def create(self, options, args):
         """
         create or update named slice with given rspec
@@ -1000,6 +1104,7 @@ or with an slice hrn, shows currently provisioned resources
 
         # credentials
         creds = [self.slice_credential_string(slice_hrn)]
 
         # credentials
         creds = [self.slice_credential_string(slice_hrn)]
+
         delegated_cred = None
         server_version = self.get_cached_server_version(server)
         if server_version.get('interface') == 'slicemgr':
         delegated_cred = None
         server_version = self.get_cached_server_version(server)
         if server_version.get('interface') == 'slicemgr':
@@ -1011,6 +1116,9 @@ or with an slice hrn, shows currently provisioned resources
             #elif server_version.get('urn'):
             #    delegated_cred = self.delegate_cred(slice_cred, urn_to_hrn(server_version['urn']))
 
             #elif server_version.get('urn'):
             #    delegated_cred = self.delegate_cred(slice_cred, urn_to_hrn(server_version['urn']))
 
+        if options.show_credential:
+            show_credentials(creds)
+
         # rspec
         rspec_file = self.get_rspec_file(args[1])
         rspec = open(rspec_file).read()
         # rspec
         rspec_file = self.get_rspec_file(args[1])
         rspec = open(rspec_file).read()
@@ -1022,10 +1130,14 @@ or with an slice hrn, shows currently provisioned resources
         #    keys: [<ssh key A>, <ssh key B>]
         #  }]
         users = []
         #    keys: [<ssh key A>, <ssh key B>]
         #  }]
         users = []
+        # xxx Thierry 2012 sept. 21
+        # contrary to what I was first thinking, calling Resolve with details=False does not yet work properly here
+        # I am turning details=True on again on a - hopefully - temporary basis, just to get this whole thing to work again
         slice_records = self.registry().Resolve(slice_urn, [self.my_credential_string])
         slice_records = self.registry().Resolve(slice_urn, [self.my_credential_string])
-        if slice_records and 'researcher' in slice_records[0] and slice_records[0]['researcher']!=[]:
+        # slice_records = self.registry().Resolve(slice_urn, [self.my_credential_string], {'details':True})
+        if slice_records and 'reg-researchers' in slice_records[0] and slice_records[0]['reg-researchers']:
             slice_record = slice_records[0]
             slice_record = slice_records[0]
-            user_hrns = slice_record['researcher']
+            user_hrns = slice_record['reg-researchers']
             user_urns = [hrn_to_urn(hrn, 'user') for hrn in user_hrns]
             user_records = self.registry().Resolve(user_urns, [self.my_credential_string])
 
             user_urns = [hrn_to_urn(hrn, 'user') for hrn in user_hrns]
             user_records = self.registry().Resolve(user_urns, [self.my_credential_string])
 
@@ -1040,8 +1152,6 @@ or with an slice hrn, shows currently provisioned resources
         # do not append users, keys, or slice tags. Anything
         # not contained in this request will be removed from the slice
 
         # do not append users, keys, or slice tags. Anything
         # not contained in this request will be removed from the slice
 
-        # CreateSliver has supported the options argument for a while now so it should
-        # be safe to assume this server support it
         api_options = {}
         api_options ['append'] = False
         api_options ['call_id'] = unique_call_id()
         api_options = {}
         api_options ['append'] = False
         api_options ['call_id'] = unique_call_id()
@@ -1067,23 +1177,116 @@ or with an slice hrn, shows currently provisioned resources
         slice_urn = hrn_to_urn(slice_hrn, 'slice') 
 
         # creds
         slice_urn = hrn_to_urn(slice_hrn, 'slice') 
 
         # creds
-        slice_cred = self.slice_credential_string(slice_hrn)
+        slice_cred = self.slice_credential(slice_hrn)
         creds = [slice_cred]
         creds = [slice_cred]
-        if options.delegate:
-            delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
-            creds.append(delegated_cred)
         
         # options and call_id when supported
         api_options = {}
         api_options ['call_id'] = unique_call_id()
         
         # options and call_id when supported
         api_options = {}
         api_options ['call_id'] = unique_call_id()
-        result = server.DeleteSliver(slice_urn, creds, *self.ois(server, api_options ) )
+        if options.show_credential:
+            show_credentials(creds)
+        result = server.Delete([slice_urn], creds, *self.ois(server, api_options ) )
         value = ReturnValue.get_value(result)
         if self.options.raw:
             save_raw_to_file(result, self.options.raw, self.options.rawformat, self.options.rawbanner)
         else:
             print value
         value = ReturnValue.get_value(result)
         if self.options.raw:
             save_raw_to_file(result, self.options.raw, self.options.rawformat, self.options.rawbanner)
         else:
             print value
-        return value 
-  
+        return value
+
+    def allocate(self, options, args):
+        server = self.sliceapi()
+        server_version = self.get_cached_server_version(server)
+        slice_hrn = args[0]
+        slice_urn = Xrn(slice_hrn, type='slice').get_urn()
+
+        # credentials
+        creds = [self.slice_credential(slice_hrn)]
+
+        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']))
+
+        if options.show_credential:
+            show_credentials(creds)
+
+        # rspec
+        rspec_file = self.get_rspec_file(args[1])
+        rspec = open(rspec_file).read()
+        api_options = {}
+        api_options ['call_id'] = unique_call_id()
+        result = server.Allocate(slice_urn, creds, rspec, api_options)
+        value = ReturnValue.get_value(result)
+        if self.options.raw:
+            save_raw_to_file(result, self.options.raw, self.options.rawformat, self.options.rawbanner)
+        if options.file is not None:
+            save_rspec_to_file (value, options.file)
+        if (self.options.raw is None) and (options.file is None):
+            print value
+
+        return value
+        
+
+    def provision(self, options, args):
+        server = self.sliceapi()
+        server_version = self.get_cached_server_version(server)
+        slice_hrn = args[0]
+        slice_urn = Xrn(slice_hrn, type='slice').get_urn()
+
+        # credentials
+        creds = [self.slice_credential(slice_hrn)]
+        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']))
+
+        if options.show_credential:
+            show_credentials(creds)
+
+        api_options = {}
+        api_options ['call_id'] = unique_call_id()
+
+        # set the requtested rspec version
+        version_manager = VersionManager()
+        rspec_version = version_manager._get_version('geni', '3.0').to_dict()
+        api_options['geni_rspec_version'] = rspec_version
+
+        # users
+        # need to pass along user keys to the aggregate.
+        # users = [
+        #  { urn: urn:publicid:IDN+emulab.net+user+alice
+        #    keys: [<ssh key A>, <ssh key B>]
+        #  }]
+        users = []
+        slice_records = self.registry().Resolve(slice_urn, [self.my_credential_string])
+        if slice_records and 'researcher' in slice_records[0] and slice_records[0]['researcher']!=[]:
+            slice_record = slice_records[0]
+            user_hrns = slice_record['researcher']
+            user_urns = [hrn_to_urn(hrn, 'user') for hrn in user_hrns]
+            user_records = self.registry().Resolve(user_urns, [self.my_credential_string])
+            users = pg_users_arg(user_records)
+        
+        api_options['geni_users'] = users
+        result = server.Provision([slice_urn], creds, api_options)
+        value = ReturnValue.get_value(result)
+        if self.options.raw:
+            save_raw_to_file(result, self.options.raw, self.options.rawformat, self.options.rawbanner)
+        if options.file is not None:
+            save_rspec_to_file (value, options.file)
+        if (self.options.raw is None) and (options.file is None):
+            print value
+        return value     
+
     def status(self, options, args):
         """
         retrieve slice status (SliverStatus)
     def status(self, options, args):
         """
         retrieve slice status (SliverStatus)
@@ -1095,16 +1298,15 @@ or with an slice hrn, shows currently provisioned resources
         slice_urn = hrn_to_urn(slice_hrn, 'slice') 
 
         # creds 
         slice_urn = hrn_to_urn(slice_hrn, 'slice') 
 
         # creds 
-        slice_cred = self.slice_credential_string(slice_hrn)
+        slice_cred = self.slice_credential(slice_hrn)
         creds = [slice_cred]
         creds = [slice_cred]
-        if options.delegate:
-            delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
-            creds.append(delegated_cred)
 
         # options and call_id when supported
         api_options = {}
         api_options['call_id']=unique_call_id()
 
         # options and call_id when supported
         api_options = {}
         api_options['call_id']=unique_call_id()
-        result = server.SliverStatus(slice_urn, creds, *self.ois(server,api_options))
+        if options.show_credential:
+            show_credentials(creds)
+        result = server.Status([slice_urn], creds, *self.ois(server,api_options))
         value = ReturnValue.get_value(result)
         if self.options.raw:
             save_raw_to_file(result, self.options.raw, self.options.rawformat, self.options.rawbanner)
         value = ReturnValue.get_value(result)
         if self.options.raw:
             save_raw_to_file(result, self.options.raw, self.options.rawformat, self.options.rawbanner)
@@ -1124,9 +1326,6 @@ or with an slice hrn, shows currently provisioned resources
         # cred
         slice_cred = self.slice_credential_string(args[0])
         creds = [slice_cred]
         # cred
         slice_cred = self.slice_credential_string(args[0])
         creds = [slice_cred]
-        if options.delegate:
-            delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
-            creds.append(delegated_cred)
         # xxx Thierry - does this not need an api_options as well ?
         result = server.Start(slice_urn, creds)
         value = ReturnValue.get_value(result)
         # xxx Thierry - does this not need an api_options as well ?
         result = server.Start(slice_urn, creds)
         value = ReturnValue.get_value(result)
@@ -1147,9 +1346,6 @@ or with an slice hrn, shows currently provisioned resources
         # cred
         slice_cred = self.slice_credential_string(args[0])
         creds = [slice_cred]
         # cred
         slice_cred = self.slice_credential_string(args[0])
         creds = [slice_cred]
-        if options.delegate:
-            delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
-            creds.append(delegated_cred)
         result =  server.Stop(slice_urn, creds)
         value = ReturnValue.get_value(result)
         if self.options.raw:
         result =  server.Stop(slice_urn, creds)
         value = ReturnValue.get_value(result)
         if self.options.raw:
@@ -1159,21 +1355,24 @@ or with an slice hrn, shows currently provisioned resources
         return value
     
     # reset named slice
         return value
     
     # reset named slice
-    def reset(self, options, args):
+    def action(self, options, args):
         """
         """
-        reset named slice (reset_slice)
+        Perform the named operational action on the named slivers
         """
         server = self.sliceapi()
         """
         server = self.sliceapi()
+        api_options = {}
         # slice urn
         slice_hrn = args[0]
         # slice urn
         slice_hrn = args[0]
-        slice_urn = hrn_to_urn(slice_hrn, 'slice') 
+        action = args[1]
+        slice_urn = Xrn(slice_hrn, type='slice').get_urn() 
         # cred
         # cred
-        slice_cred = self.slice_credential_string(args[0])
+        slice_cred = self.slice_credential(args[0])
         creds = [slice_cred]
         if options.delegate:
             delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
             creds.append(delegated_cred)
         creds = [slice_cred]
         if options.delegate:
             delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
             creds.append(delegated_cred)
-        result = server.reset_slice(creds, slice_urn)
+        
+        result = server.PerformOperationalAction([slice_urn], creds, action , api_options)
         value = ReturnValue.get_value(result)
         if self.options.raw:
             save_raw_to_file(result, self.options.raw, self.options.rawformat, self.options.rawbanner)
         value = ReturnValue.get_value(result)
         if self.options.raw:
             save_raw_to_file(result, self.options.raw, self.options.rawformat, self.options.rawbanner)
@@ -1186,21 +1385,22 @@ or with an slice hrn, shows currently provisioned resources
         renew slice (RenewSliver)
         """
         server = self.sliceapi()
         renew slice (RenewSliver)
         """
         server = self.sliceapi()
+        if len(args) != 2:
+            self.print_help()
+            sys.exit(1)
+        [ slice_hrn, input_time ] = args
         # slice urn    
         # slice urn    
-        slice_hrn = args[0]
         slice_urn = hrn_to_urn(slice_hrn, 'slice') 
         slice_urn = hrn_to_urn(slice_hrn, 'slice') 
+        # time: don't try to be smart on the time format, server-side will
         # creds
         # creds
-        slice_cred = self.slice_credential_string(args[0])
+        slice_cred = self.slice_credential(args[0])
         creds = [slice_cred]
         creds = [slice_cred]
-        if options.delegate:
-            delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
-            creds.append(delegated_cred)
-        # time
-        time = args[1]
         # options and call_id when supported
         api_options = {}
         # options and call_id when supported
         api_options = {}
-       api_options['call_id']=unique_call_id()
-        result =  server.RenewSliver(slice_urn, creds, time, *self.ois(server,api_options))
+        api_options['call_id']=unique_call_id()
+        if options.show_credential:
+            show_credentials(creds)
+        result =  server.Renew([slice_urn], creds, input_time, *self.ois(server,api_options))
         value = ReturnValue.get_value(result)
         if self.options.raw:
             save_raw_to_file(result, self.options.raw, self.options.rawformat, self.options.rawbanner)
         value = ReturnValue.get_value(result)
         if self.options.raw:
             save_raw_to_file(result, self.options.raw, self.options.rawformat, self.options.rawbanner)
@@ -1218,11 +1418,8 @@ or with an slice hrn, shows currently provisioned resources
         slice_hrn = args[0]
         slice_urn = hrn_to_urn(slice_hrn, 'slice') 
         # creds
         slice_hrn = args[0]
         slice_urn = hrn_to_urn(slice_hrn, 'slice') 
         # creds
-        slice_cred = self.slice_credential_string(slice_hrn)
+        slice_cred = self.slice_credential(slice_hrn)
         creds = [slice_cred]
         creds = [slice_cred]
-        if options.delegate:
-            delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
-            creds.append(delegated_cred)
         result = server.Shutdown(slice_urn, creds)
         value = ReturnValue.get_value(result)
         if self.options.raw:
         result = server.Shutdown(slice_urn, creds)
         value = ReturnValue.get_value(result)
         if self.options.raw:
@@ -1243,15 +1440,12 @@ or with an slice hrn, shows currently provisioned resources
         # creds
         slice_cred = self.slice_credential_string(slice_hrn)
         creds = [slice_cred]
         # creds
         slice_cred = self.slice_credential_string(slice_hrn)
         creds = [slice_cred]
-        if options.delegate:
-            delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
-            creds.append(delegated_cred)
         # rspec
         rspec_file = self.get_rspec_file(rspec_path) 
         rspec = open(rspec_file).read()
         # options and call_id when supported
         api_options = {}
         # rspec
         rspec_file = self.get_rspec_file(rspec_path) 
         rspec = open(rspec_file).read()
         # options and call_id when supported
         api_options = {}
-       api_options['call_id']=unique_call_id()
+        api_options['call_id']=unique_call_id()
         # get ticket at the server
         ticket_string = server.GetTicket(slice_urn, creds, rspec, *self.ois(server,api_options))
         # save
         # get ticket at the server
         ticket_string = server.GetTicket(slice_urn, creds, rspec, *self.ois(server,api_options))
         # save
@@ -1301,7 +1495,7 @@ or with an slice hrn, shows currently provisioned resources
                 self.logger.log_exc(e.message)
         return
 
                 self.logger.log_exc(e.message)
         return
 
-    def create_gid(self, options, args):
+    def gid(self, options, args):
         """
         Create a GID (CreateGid)
         """
         """
         Create a GID (CreateGid)
         """
@@ -1309,7 +1503,8 @@ or with an slice hrn, shows currently provisioned resources
             self.print_help()
             sys.exit(1)
         target_hrn = args[0]
             self.print_help()
             sys.exit(1)
         target_hrn = args[0]
-        gid = self.registry().CreateGid(self.my_credential_string, target_hrn, self.client_bootstrap.my_gid_string())
+        my_gid_string = open(self.client_bootstrap.my_gid()).read() 
+        gid = self.registry().CreateGid(self.my_credential_string, target_hrn, my_gid_string)
         if options.file:
             filename = options.file
         else:
         if options.file:
             filename = options.file
         else:
@@ -1318,33 +1513,53 @@ or with an slice hrn, shows currently provisioned resources
         GID(string=gid).save_to_file(filename)
          
 
         GID(string=gid).save_to_file(filename)
          
 
-    def delegate(self, options, args):
+    def delegate (self, options, args):
         """
         (locally) create delegate credential for use by given hrn
         """
         """
         (locally) create delegate credential for use by given hrn
         """
-        delegee_hrn = args[0]
-        if options.delegate_user:
-            cred = self.delegate_cred(self.my_credential_string, delegee_hrn, 'user')
-        elif options.delegate_slice:
-            slice_cred = self.slice_credential_string(options.delegate_slice)
-            cred = self.delegate_cred(slice_cred, delegee_hrn, 'slice')
-        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 len(args) != 1:
+            self.print_help()
+            sys.exit(1)
+        to_hrn = args[0]
+        # support for several delegations in the same call
+        # so first we gather the things to do
+        tuples=[]
+        for slice_hrn in options.delegate_slices:
+            message="%s.slice"%slice_hrn
+            original = self.slice_credential_string(slice_hrn)
+            tuples.append ( (message, original,) )
+        if options.delegate_pi:
+            my_authority=self.authority
+            message="%s.pi"%my_authority
+            original = self.my_authority_credential_string()
+            tuples.append ( (message, original,) )
+        for auth_hrn in options.delegate_auths:
+            message="%s.auth"%auth_hrn
+            original=self.authority_credential_string(auth_hrn)
+            tuples.append ( (message, original, ) )
+        # if nothing was specified at all at this point, let's assume -u
+        if not tuples: options.delegate_user=True
+        # this user cred
         if options.delegate_user:
         if options.delegate_user:
-            dest_fn = os.path.join(self.options.sfi_dir, get_leaf(delegee_hrn) + "_"
-                                  + get_leaf(object_hrn) + ".cred")
-        elif options.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))
+            message="%s.user"%self.user
+            original = self.my_credential_string
+            tuples.append ( (message, original, ) )
+
+        # default type for beneficial is user unless -A
+        if options.delegate_to_authority:       to_type='authority'
+        else:                                   to_type='user'
+
+        # let's now handle all this
+        # it's all in the filenaming scheme
+        for (message,original) in tuples:
+            delegated_string = self.client_bootstrap.delegate_credential_string(original, to_hrn, to_type)
+            delegated_credential = Credential (string=delegated_string)
+            filename = os.path.join ( self.options.sfi_dir,
+                                      "%s_for_%s.%s.cred"%(message,to_hrn,to_type))
+            delegated_credential.save_to_file(filename, save_parents=True)
+            self.logger.info("delegated credential for %s to %s and wrote to %s"%(message,to_hrn,filename))
     
     
-    def get_trusted_certs(self, options, args):
+    def trusted(self, options, args):
         """
         return uhe trusted certs at this interface (get_trusted_certs)
         """ 
         """
         return uhe trusted certs at this interface (get_trusted_certs)
         """ 
@@ -1353,7 +1568,7 @@ or with an slice hrn, shows currently provisioned resources
             gid = GID(string=trusted_cert)
             gid.dump()
             cert = Certificate(string=trusted_cert)
             gid = GID(string=trusted_cert)
             gid.dump()
             cert = Certificate(string=trusted_cert)
-            self.logger.debug('Sfi.get_trusted_certs -> %r'%cert.get_subject())
+            self.logger.debug('Sfi.trusted -> %r'%cert.get_subject())
         return 
 
     def config (self, options, args):
         return 
 
     def config (self, options, args):