Merge branch 'master' into senslab2
[sfa.git] / sfa / client / sfi.py
index 2ec43fb..a9725f4 100644 (file)
@@ -1,7 +1,6 @@
 #
 # 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
@@ -41,6 +40,7 @@ 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.candidates import Candidates
 
 CM_PORT=12346
 
@@ -113,6 +113,21 @@ def filter_records(type, records):
     return filtered_records
 
 
+def credential_printable (credential_string):
+    credential=Credential(string=credential_string)
+    result=""
+    result += credential.get_summary_tostring()
+    result += "\n"
+    rights = credential.get_privileges()
+    result += "rights=%s"%rights
+    result += "\n"
+    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 == "-":
@@ -279,8 +294,8 @@ class Sfi:
         ("get_ticket", "slice_hrn rspec"),
         ("redeem_ticket", "ticket"),
         ("delegate", "name"),
-        ("create_gid", "[name]"),
-        ("get_trusted_certs", "cred"),
+        ("gid", "[name]"),
+        ("trusted", "cred"),
         ("config", ""),
         ]
 
@@ -351,15 +366,22 @@ class Sfi:
                              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","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")
+        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"):
             # rspec version
-            parser.add_option("-r", "--rspec-version", dest="rspec_version", default="GENI",
+            parser.add_option("-r", "--rspec-version", dest="rspec_version", default="SFA 1",
                               help="schema type and version of resulting RSpec")
             # disable/enable cached rspecs
             parser.add_option("-c", "--current", dest="current", default=False,
@@ -379,7 +401,7 @@ class Sfi:
 
 
         # '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", "show", "list", "gid", 'create'):
            parser.add_option("-o", "--output", dest="file",
                             help="output XML to file", metavar="FILE", default=None)
 
@@ -455,7 +477,9 @@ class Sfi:
         
 
     def print_help (self):
+        print "==================== Generic sfi usage"
         self.sfi_parser.print_help()
+        print "==================== Specific command usage"
         self.command_parser.print_help()
 
     #
@@ -479,22 +503,28 @@ class Sfi:
             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.logger.info("Command=%s" % command)
+        self.logger.debug("Command=%s" % command)
 
         try:
             self.dispatch(command, command_options, command_args)
         except KeyError:
             self.logger.critical ("Unknown command %s"%command)
-            raise
             sys.exit(1)
-    
+
         return
     
     ####################
@@ -578,7 +608,8 @@ class Sfi:
     
     # 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)
@@ -799,6 +830,8 @@ or version information about sfi itself
         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:
@@ -825,6 +858,16 @@ or version information about sfi itself
         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)  
@@ -836,6 +879,8 @@ or version information about sfi itself
     def add(self, options, args):
         "add record into registry from xml file (Register)"
         auth_cred = self.my_authority_credential_string()
+        if options.show_credential:
+            show_credentials(auth_cred)
         record_dict = {}
         if len(args) > 0:
             record_filepath = args[0]
@@ -879,7 +924,7 @@ or version information about sfi itself
                 cred = self.my_authority_credential_string()
         elif record_dict['type'] in ["slice"]:
             try:
-                cred = self.slice_credential_string(record.hrn)
+                cred = self.slice_credential_string(record_dict['hrn'])
             except ServerException, e:
                # XXX smbaker -- once we have better error return codes, update this
                # to do something better than a string compare
@@ -893,6 +938,8 @@ or version information about sfi itself
             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):
@@ -905,6 +952,8 @@ or version information about sfi itself
         type = options.type 
         if type in ['all']:
             type = '*'
+        if options.show_credential:
+            show_credentials(auth_cred)
         return self.registry().Remove(hrn, auth_cred, type)
     
     # ==================================================================
@@ -922,6 +971,8 @@ or version information about sfi itself
         # options and call_id when supported
         api_options = {}
        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:
@@ -946,6 +997,8 @@ or with an slice hrn, shows currently provisioned resources
             creds.append(self.my_credential_string)
         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
@@ -1000,6 +1053,7 @@ or with an slice hrn, shows currently provisioned resources
 
         # 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':
@@ -1011,6 +1065,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']))
 
+        if options.show_credential:
+            show_credentials(creds)
+
         # rspec
         rspec_file = self.get_rspec_file(args[1])
         rspec = open(rspec_file).read()
@@ -1035,6 +1092,7 @@ or with an slice hrn, shows currently provisioned resources
                 rspec.filter({'component_manager_id': server_version['urn']})
                 rspec = RSpecConverter.to_pg_rspec(rspec.toxml(), content_type='request')
             else:
+                print >>sys.stderr, "\r\n \r\n \r\n WOOOOOO"
                 users = sfa_users_arg(user_records, slice_record)
 
         # do not append users, keys, or slice tags. Anything
@@ -1076,6 +1134,8 @@ or with an slice hrn, shows currently provisioned resources
         # options and call_id when supported
         api_options = {}
         api_options ['call_id'] = unique_call_id()
+        if options.show_credential:
+            show_credentials(creds)
         result = server.DeleteSliver(slice_urn, creds, *self.ois(server, api_options ) )
         value = ReturnValue.get_value(result)
         if self.options.raw:
@@ -1104,6 +1164,8 @@ or with an slice hrn, shows currently provisioned resources
         # options and call_id when supported
         api_options = {}
         api_options['call_id']=unique_call_id()
+        if options.show_credential:
+            show_credentials(creds)
         result = server.SliverStatus(slice_urn, creds, *self.ois(server,api_options))
         value = ReturnValue.get_value(result)
         if self.options.raw:
@@ -1186,21 +1248,25 @@ or with an slice hrn, shows currently provisioned resources
         renew slice (RenewSliver)
         """
         server = self.sliceapi()
+        if len(args) != 2:
+            self.print_help()
+            sys.exit(1)
+        [ slice_hrn, input_time ] = args
         # slice urn    
-        slice_hrn = args[0]
         slice_urn = hrn_to_urn(slice_hrn, 'slice') 
+        # time: don't try to be smart on the time format, server-side will
         # creds
         slice_cred = self.slice_credential_string(args[0])
         creds = [slice_cred]
         if options.delegate:
             delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
             creds.append(delegated_cred)
-        # time
-        time = args[1]
         # 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))
+        if options.show_credential:
+            show_credentials(creds)
+        result =  server.RenewSliver(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)
@@ -1301,7 +1367,7 @@ or with an slice hrn, shows currently provisioned resources
                 self.logger.log_exc(e.message)
         return
 
-    def create_gid(self, options, args):
+    def gid(self, options, args):
         """
         Create a GID (CreateGid)
         """
@@ -1344,7 +1410,7 @@ or with an slice hrn, shows currently provisioned resources
 
         self.logger.info("delegated credential for %s to %s and wrote to %s"%(object_hrn, delegee_hrn,dest_fn))
     
-    def get_trusted_certs(self, options, args):
+    def trusted(self, options, args):
         """
         return uhe trusted certs at this interface (get_trusted_certs)
         """ 
@@ -1353,7 +1419,7 @@ or with an slice hrn, shows currently provisioned resources
             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):