uses utcnow() instead of now() when testing for credential validity
[sfa.git] / sfa / client / sfi.py
index 8d40a8b..0e8b8e1 100644 (file)
@@ -245,6 +245,7 @@ def register_command (args_string, example):
     def wrap(m): 
         name=getattr(m,'__name__')
         doc=getattr(m,'__doc__',"-- missing doc --")
+        doc=doc.strip(" \t\n")
         commands_list.append(name)
         commands_dict[name]=(doc, args_string, example)
         @wraps(m)
@@ -281,7 +282,11 @@ class Sfi:
         self.authority = None
         self.logger = sfi_logger
         self.logger.enable_console()
+        self.command=None
+        self.config=None
+        self.config_file=None
 
+    ### suitable if no reasonable command has been provided
     def print_commands_help (self, options):
         verbose=getattr(options,'verbose')
         format3="%18s %-15s %s"
@@ -292,14 +297,28 @@ class Sfi:
         else:
             print line
             self.create_parser().print_help()
-        for (command, (doc, args_string, example)) in commands_dict.iteritems():
+        # preserve order from the code
+        for command in commands_list:
+            (doc, args_string, example) = commands_dict[command]
             if verbose:
                 print line
-            doc=doc.strip(" \t\n")
             doc=doc.replace("\n","\n"+35*' ')
             print format3%(command,args_string,doc)
             if verbose:
                 self.create_command_parser(command).print_help()
+            
+    ### now if a known command was found we can be more verbose on that one
+    def print_help (self):
+        print "==================== Generic sfi usage"
+        self.sfi_parser.print_help()
+        (doc,_,example)=commands_dict[self.command]
+        print "\n==================== Purpose of %s"%self.command
+        print doc
+        print "\n==================== Specific usage for %s"%self.command
+        self.command_parser.print_help()
+        if example:
+            print "\n==================== %s example(s)"%self.command
+            print example
 
     def create_command_parser(self, command):
         if command not in commands_dict:
@@ -315,7 +334,7 @@ class Sfi:
         parser = OptionParser(add_help_option=False,
                               usage="sfi [sfi_options] %s [cmd_options] %s"
                               % (command, args_string))
-        parser.add_option ("-h","--help",dest='command_help',action='store_true',default=False,
+        parser.add_option ("-h","--help",dest='help',action='store_true',default=False,
                            help="Summary of one command usage")
 
         if command in ("add", "update"):
@@ -456,23 +475,13 @@ use this if you mean an authority instead""")
         parser.add_option("-t", "--timeout", dest="timeout", default=None,
                          help="Amout of time to wait before timing out the request")
         parser.add_option("-h", "--help", 
-                         action="store_true", dest="commands_help", default=False,
+                         action="store_true", dest="help", default=False,
                          help="one page summary on commands & exit")
         parser.disable_interspersed_args()
 
         return parser
         
 
-    def print_help (self):
-        print "==================== Generic sfi usage"
-        self.sfi_parser.print_help()
-        print "\n==================== Specific usage for %s"%self.command
-        self.command_parser.print_help()
-        (_,__,example)=commands_dict[self.command]
-        if example:
-            print "\n==================== %s example"%self.command
-            print example
-
     #
     # Main: parse arguments and dispatch to command
     #
@@ -486,7 +495,7 @@ use this if you mean an authority instead""")
     def main(self):
         self.sfi_parser = self.create_parser()
         (options, args) = self.sfi_parser.parse_args()
-        if options.commands_help: 
+        if options.help: 
             self.print_commands_help(options)
             sys.exit(1)
         self.options = options
@@ -509,6 +518,9 @@ use this if you mean an authority instead""")
         self.command=command
         self.command_parser = self.create_command_parser(command)
         (command_options, command_args) = self.command_parser.parse_args(args[1:])
+        if command_options.help:
+            self.print_help()
+            sys.exit(1)
         self.command_options = command_options
 
         self.read_config () 
@@ -541,7 +553,8 @@ use this if you mean an authority instead""")
                 config.add_section('sfi')
                 # sface users should be able to use this same file to configure their stuff
                 config.add_section('sface')
-                # manifold users should be able to specify their backend server here for sfi delegate
+                # manifold users should be able to specify the details 
+                # of their backend server here for 'sfi myslice'
                 config.add_section('myslice')
                 config.load(config_file)
                 # back up old config
@@ -558,6 +571,7 @@ use this if you mean an authority instead""")
                 self.logger.log_exc("Could not read config file %s"%config_file)
             sys.exit(1)
      
+        self.config=config
         errors = 0
         # Set SliceMgr URL
         if (self.options.sm is not None):
@@ -826,11 +840,16 @@ use this if you mean an authority instead""")
     # Registry-related commands
     #==========================================================================
 
+    @register_command("","")
+    def config (self, options, args):
+        "Display contents of current config"
+        self.show_config()
+
     @register_command("","")
     def version(self, options, args):
         """
         display an SFA server version (GetVersion)
-or version information about sfi itself
+  or version information about sfi itself
         """
         if options.version_local:
             version=version_core()
@@ -907,9 +926,12 @@ or version information about sfi itself
             save_records_to_file(options.file, record_dicts, options.fileformat)
         return
     
-    @register_command("[record]","")
+    @register_command("[xml-filename]","")
     def add(self, options, args):
-        "add record into registry by using the command options (Recommended) or from xml file (Register)"
+        """add record into registry (Register) 
+  from command line options (recommended) 
+  old-school method involving an xml file still supported"""
+
         auth_cred = self.my_authority_credential_string()
         if options.show_credential:
             show_credentials(auth_cred)
@@ -940,9 +962,11 @@ or version information about sfi itself
                 record_dict['last_name'] = record_dict['hrn'] 
         return self.registry().Register(record_dict, auth_cred)
     
-    @register_command("[record]","")
+    @register_command("[xml-filename]","")
     def update(self, options, args):
-        "update record into registry by using the command options (Recommended) or from xml file (Update)"
+        """update record into registry (Update) 
+  from command line options (recommended) 
+  old-school method involving an xml file still supported"""
         record_dict = {}
         if len(args) > 0:
             record_filepath = args[0]
@@ -1021,7 +1045,7 @@ or version information about sfi itself
         return
 
     # show rspec for named slice
-    @register_command("[slice_hrn]","")
+    @register_command("","")
     def resources(self, options, args):
         """
         discover available resources (ListResources)
@@ -1075,7 +1099,8 @@ or version information about sfi itself
     @register_command("slice_hrn","")
     def describe(self, options, args):
         """
-        shows currently allocated/provisioned resources of the named slice or set of slivers (Describe) 
+        shows currently allocated/provisioned resources 
+        of the named slice or set of slivers (Describe) 
         """
         server = self.sliceapi()
 
@@ -1366,10 +1391,24 @@ or version information about sfi itself
         GID(string=gid).save_to_file(filename)
          
 
-    @register_command("to_hrn","")
+    @register_command("to_hrn","""$ sfi delegate -u -p -s ple.inria.heartbeat -s ple.inria.omftest ple.upmc.slicebrowser
+
+  will locally create a set of delegated credentials for the benefit of ple.upmc.slicebrowser
+  the set of credentials in the scope for this call would be
+  (*) ple.inria.thierry_parmentelat.user_for_ple.upmc.slicebrowser.user.cred
+      as per -u/--user
+  (*) ple.inria.pi_for_ple.upmc.slicebrowser.user.cred
+      as per -p/--pi
+  (*) ple.inria.heartbeat.slice_for_ple.upmc.slicebrowser.user.cred
+  (*) ple.inria.omftest.slice_for_ple.upmc.slicebrowser.user.cred
+      because of the two -s options
+
+""")
     def delegate (self, options, args):
         """
         (locally) create delegate credential for use by given hrn
+  make sure to check for 'sfi myslice' instead if you plan
+  on using MySlice
         """
         if len(args) != 1:
             self.print_help()
@@ -1414,21 +1453,25 @@ or version information about sfi itself
             self.logger.info("delegated credential for %s to %s and wrote to %s"%(message,to_hrn,filename))
     
     ####################
-    @register_command("","""$ less +/myslice myslice sfi_config
+    @register_command("","""$ less +/myslice sfi_config
 [myslice]
 backend  = 'http://manifold.pl.sophia.inria.fr:7080'
+# the HRN that myslice uses, so that we are delegating to
 delegate = 'ple.upmc.slicebrowser'
+# platform - this is a myslice concept
+platform = 'ple'
+# username - as of this writing (May 2013) a simple login name
 user     = 'thierry'
 
 $ sfi myslice
 
   will first collect the slices that you are part of, then make sure
-  all your credentials are up-to-date (that is: refresh expired ones)
+  all your credentials are up-to-date (read: refresh expired ones)
   then compute delegated credentials for user 'ple.upmc.slicebrowser'
-  and upload them all on myslice backend, using manifold id as
-  specified in 'user'
+  and upload them all on myslice backend, using 'platform' and 'user'.
+  A password will be prompted for the upload part.
 """
-)
+) # register_command
     def myslice (self, options, args):
 
         """ This helper is for refreshing your credentials at myslice; it will
@@ -1445,7 +1488,8 @@ $ sfi myslice
         # ManifoldUploader
         pass
 
-    @register_command("cred","")
+# Thierry: I'm turning this off, no idea what it's used for
+#    @register_command("cred","")
     def trusted(self, options, args):
         """
         return the trusted certs at this interface (get_trusted_certs)
@@ -1458,7 +1502,3 @@ $ sfi myslice
             self.logger.debug('Sfi.trusted -> %r'%cert.get_subject())
         return 
 
-    @register_command("","")
-    def config (self, options, args):
-        "Display contents of current config"
-        self.show_config()