X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=sfa%2Fclient%2Fsfi.py;h=2ce796b01cd10ee435730bc125be0a4da2db95cd;hb=dcec4892ea998e7df5297ba08a7a93da0e8d7053;hp=dcd168800613381b8db6f449a3f669801c20e601;hpb=f9ca4f5241efee10e93801df459e0b764cc0d912;p=sfa.git diff --git a/sfa/client/sfi.py b/sfa/client/sfi.py index dcd16880..2ce796b0 100644 --- a/sfa/client/sfi.py +++ b/sfa/client/sfi.py @@ -138,7 +138,7 @@ def save_rspec_to_file(rspec, filename): if not filename.endswith(".rspec"): filename = filename + ".rspec" f = open(filename, 'w') - f.write(rspec) + f.write("%s"%rspec) f.close() return @@ -203,7 +203,7 @@ def load_record_from_opts(options): record_dict['keys'] = [pubkey] if hasattr(options, 'slices') and options.slices: record_dict['slices'] = options.slices - if hasattr(options, 'researchers') and options.researchers: + if hasattr(options, 'researchers') and options.researchers is not None: record_dict['researcher'] = options.researchers if hasattr(options, 'email') and options.email: record_dict['email'] = options.email @@ -241,13 +241,19 @@ from functools import wraps commands_list=[] commands_dict={} -def register_command (args_string, example): +def declare_command (args_string, example,aliases=None): 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) + # last item is 'canonical' name, so we can know which commands are aliases + command_tuple=(doc, args_string, example,name) + commands_dict[name]=command_tuple + if aliases is not None: + for alias in aliases: + commands_list.append(alias) + commands_dict[alias]=command_tuple @wraps(m) def new_method (*args, **kwds): return m(*args, **kwds) return new_method @@ -292,7 +298,8 @@ class Sfi: ### suitable if no reasonable command has been provided def print_commands_help (self, options): verbose=getattr(options,'verbose') - format3="%18s %-15s %s" + format3="%10s %-30s %s" + format3offset=42 line=80*'-' if not verbose: print format3%("command","cmd_args","description") @@ -302,19 +309,29 @@ class Sfi: self.create_parser_global().print_help() # preserve order from the code for command in commands_list: - (doc, args_string, example) = commands_dict[command] + try: + (doc, args_string, example, canonical) = commands_dict[command] + except: + print "Cannot find info on command %s - skipped"%command + continue if verbose: print line - doc=doc.replace("\n","\n"+35*' ') - print format3%(command,args_string,doc) - if verbose: - self.create_parser_command(command).print_help() + if command==canonical: + doc=doc.replace("\n","\n"+format3offset*' ') + print format3%(command,args_string,doc) + if verbose: + self.create_parser_command(command).print_help() + else: + print format3%(command,"<>"%canonical,"") ### 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] + (doc,_,example,canonical)=commands_dict[self.command] + if canonical != self.command: + print "\n==================== NOTE: %s is an alias for genuine %s"%(self.command,canonical) + self.command=canonical print "\n==================== Purpose of %s"%self.command print doc print "\n==================== Specific usage for %s"%self.command @@ -374,7 +391,7 @@ class Sfi: sys.exit(2) # retrieve args_string - (_, args_string, __) = commands_dict[command] + (_, args_string, __,___) = commands_dict[command] parser = OptionParser(add_help_option=False, usage="sfi [sfi_options] %s [cmd_options] %s" @@ -387,14 +404,16 @@ class Sfi: help='how myslice config variables as well') if command in ("version"): - parser.add_option("-R","--registry-version", - action="store_true", dest="version_registry", default=False, - help="probe registry version instead of sliceapi") parser.add_option("-l","--local", action="store_true", dest="version_local", default=False, help="display version of the local client") - if command in ("add", "update"): + if command in ("version", "trusted"): + parser.add_option("-R","--registry_interface", + action="store_true", dest="registry_interface", default=False, + help="target the registry interface instead of slice interface") + + if command in ("register", "update"): parser.add_option('-x', '--xrn', dest='xrn', metavar='', help='object hrn/urn (mandatory)') parser.add_option('-t', '--type', dest='type', metavar='', help='object type', default=None) parser.add_option('-e', '--email', dest='email', default="", help="email (mandatory for users)") @@ -403,7 +422,7 @@ class Sfi: parser.add_option('-s', '--slices', dest='slices', metavar='', help='Set/replace slice xrns', default='', type="str", action='callback', callback=optparse_listvalue_callback) parser.add_option('-r', '--researchers', dest='researchers', metavar='', - help='Set/replace slice researchers', default='', type="str", action='callback', + help='Set/replace slice researchers - use -r none to reset', default='', type="str", action='callback', callback=optparse_listvalue_callback) parser.add_option('-p', '--pis', dest='pis', metavar='', help='Set/replace Principal Investigators/Project Managers', default='', type="str", action='callback', callback=optparse_listvalue_callback) @@ -420,7 +439,7 @@ class Sfi: "authority in set of credentials for this call") # show_credential option - if command in ("list","resources", "describe", "provision", "allocate", "add","update","remove","delete","status","renew"): + if command in ("list","resources", "describe", "provision", "allocate", "register","update","remove","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 @@ -432,9 +451,11 @@ class Sfi: if command in ("show"): parser.add_option("-k","--key",dest="keys",action="append",default=[], help="specify specific keys to be displayed from record") + parser.add_option("-n","--no-details",dest="no_details",action="store_true",default=False, + help="call Resolve without the 'details' option") if command in ("resources", "describe"): # rspec version - parser.add_option("-r", "--rspec-version", dest="rspec_version", default="SFA 1", + parser.add_option("-r", "--rspec-version", dest="rspec_version", default="GENI 3", help="schema type and version of resulting RSpec") # disable/enable cached rspecs parser.add_option("-c", "--current", dest="current", default=False, @@ -845,7 +866,7 @@ use this if you mean an authority instead""") # Registry-related commands #========================================================================== - @register_command("","") + @declare_command("","") def config (self, options, args): "Display contents of current config" print "# From configuration file %s"%self.config_file @@ -869,16 +890,16 @@ use this if you mean an authority instead""") value=getattr(self.config_instance,varname) print "%-20s = %s"%(name,value) - @register_command("","") + @declare_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() else: - if options.version_registry: + if options.registry_interface: server=self.registry() else: server = self.sliceapi() @@ -890,7 +911,7 @@ use this if you mean an authority instead""") pprinter = PrettyPrinter(indent=4) pprinter.pprint(version) - @register_command("authority","") + @declare_command("authority","") def list(self, options, args): """ list entries in named authority registry (List) @@ -918,7 +939,7 @@ use this if you mean an authority instead""") save_records_to_file(options.file, list, options.fileformat) return - @register_command("name","") + @declare_command("name","") def show(self, options, args): """ show details about named registry record (Resolve) @@ -928,7 +949,9 @@ use this if you mean an authority instead""") sys.exit(1) hrn = args[0] # explicitly require Resolve to run in details mode - record_dicts = self.registry().Resolve(hrn, self.my_credential_string, {'details':True}) + resolve_options={} + if not options.no_details: resolve_options['details']=True + record_dicts = self.registry().Resolve(hrn, self.my_credential_string, resolve_options) record_dicts = filter_records(options.type, record_dicts) if not record_dicts: self.logger.error("No record of type %s"% options.type) @@ -950,11 +973,12 @@ use this if you mean an authority instead""") save_records_to_file(options.file, record_dicts, options.fileformat) return - @register_command("[xml-filename]","") - def add(self, options, args): - """add record into registry (Register) - from command line options (recommended) - old-school method involving an xml file still supported""" + # this historically was named 'add', it is now 'register' with an alias for legacy + @declare_command("[xml-filename]","",['add']) + def register(self, options, args): + """create new record in 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: @@ -986,11 +1010,11 @@ use this if you mean an authority instead""") record_dict['last_name'] = record_dict['hrn'] return self.registry().Register(record_dict, auth_cred) - @register_command("[xml-filename]","") + @declare_command("[xml-filename]","") def update(self, options, args): """update record into registry (Update) - from command line options (recommended) - old-school method involving an xml file still supported""" + from command line options (recommended) + old-school method involving an xml file still supported""" record_dict = {} if len(args) > 0: record_filepath = args[0] @@ -1030,7 +1054,7 @@ use this if you mean an authority instead""") show_credentials(cred) return self.registry().Update(record_dict, cred) - @register_command("hrn","") + @declare_command("hrn","") def remove(self, options, args): "remove registry record by name (Remove)" auth_cred = self.my_authority_credential_string() @@ -1050,7 +1074,7 @@ use this if you mean an authority instead""") # ================================================================== # show rspec for named slice - @register_command("","") + @declare_command("","") def resources(self, options, args): """ discover available resources (ListResources) @@ -1101,11 +1125,11 @@ use this if you mean an authority instead""") return - @register_command("slice_hrn","") + @declare_command("slice_hrn","") def describe(self, options, args): """ shows currently allocated/provisioned resources - of the named slice or set of slivers (Describe) + of the named slice or set of slivers (Describe) """ server = self.sliceapi() @@ -1118,10 +1142,13 @@ use this if you mean an authority instead""") api_options = {'call_id': unique_call_id(), 'cached': True, - 'info': options.info, + #'info': options.info, 'list_leases': options.list_leases, 'geni_rspec_version': {'type': 'geni', 'version': '3'}, } + if options.info: + api_options['info'] = options.info + if options.rspec_version: version_manager = VersionManager() server_version = self.get_cached_server_version(server) @@ -1136,16 +1163,16 @@ use this if you mean an authority instead""") 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) + save_rspec_to_file(value['geni_rspec'], options.file) if (self.options.raw is None) and (options.file is None): display_rspec(value, options.format) return - @register_command("slice_hrn","") + @declare_command("slice_hrn [...]","") def delete(self, options, args): """ - de-allocate and de-provision all or named slivers of the slice (Delete) + de-allocate and de-provision all or named slivers of the named slice (Delete) """ server = self.sliceapi() @@ -1153,6 +1180,13 @@ use this if you mean an authority instead""") slice_hrn = args[0] slice_urn = hrn_to_urn(slice_hrn, 'slice') + if len(args) > 1: + # we have sliver urns + sliver_urns = args[1:] + else: + # we provision all the slivers of the slice + sliver_urns = [slice_urn] + # creds slice_cred = self.slice_credential(slice_hrn) creds = [slice_cred] @@ -1162,7 +1196,7 @@ use this if you mean an authority instead""") api_options ['call_id'] = unique_call_id() if options.show_credential: show_credentials(creds) - result = server.Delete([slice_urn], creds, *self.ois(server, api_options ) ) + result = server.Delete(sliver_urns, 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) @@ -1170,7 +1204,7 @@ use this if you mean an authority instead""") print value return value - @register_command("slice_hrn rspec","") + @declare_command("slice_hrn rspec","") def allocate(self, options, args): """ allocate resources to the named slice (Allocate) @@ -1221,21 +1255,27 @@ use this if you mean an authority instead""") 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) + save_rspec_to_file (value['geni_rspec'], options.file) if (self.options.raw is None) and (options.file is None): print value return value - @register_command("slice_hrn","") + @declare_command("slice_hrn [...]","") def provision(self, options, args): """ - provision already allocated resources of named slice (Provision) + provision all or named already allocated slivers of the named slice (Provision) """ server = self.sliceapi() server_version = self.get_cached_server_version(server) slice_hrn = args[0] slice_urn = Xrn(slice_hrn, type='slice').get_urn() + if len(args) > 1: + # we have sliver urns + sliver_urns = args[1:] + else: + # we provision all the slivers of the slice + sliver_urns = [slice_urn] # credentials creds = [self.slice_credential(slice_hrn)] @@ -1276,20 +1316,20 @@ use this if you mean an authority instead""") users = pg_users_arg(user_records) api_options['geni_users'] = users - result = server.Provision([slice_urn], creds, api_options) + result = server.Provision(sliver_urns, 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) + save_rspec_to_file (value['geni_rspec'], options.file) if (self.options.raw is None) and (options.file is None): print value return value - @register_command("slice_hrn","") + @declare_command("slice_hrn","") def status(self, options, args): """ - retrieve the status of the slivers belonging to tne named slice (Status) + retrieve the status of the slivers belonging to the named slice (Status) """ server = self.sliceapi() @@ -1315,17 +1355,23 @@ use this if you mean an authority instead""") # Thierry: seemed to be missing return value - @register_command("slice_hrn action","") + @declare_command("slice_hrn [...] action","") def action(self, options, args): """ - Perform the named operational action on these slivers + Perform the named operational action on all or named slivers of the named slice """ server = self.sliceapi() api_options = {} # slice urn slice_hrn = args[0] - action = args[1] - slice_urn = Xrn(slice_hrn, type='slice').get_urn() + slice_urn = Xrn(slice_hrn, type='slice').get_urn() + if len(args) > 2: + # we have sliver urns + sliver_urns = args[1:-1] + else: + # we provision all the slivers of the slice + sliver_urns = [slice_urn] + action = args[-1] # cred slice_cred = self.slice_credential(args[0]) creds = [slice_cred] @@ -1333,7 +1379,7 @@ use this if you mean an authority instead""") delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority)) creds.append(delegated_cred) - result = server.PerformOperationalAction([slice_urn], creds, action , api_options) + result = server.PerformOperationalAction(sliver_urns, 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) @@ -1341,18 +1387,26 @@ use this if you mean an authority instead""") print value return value - @register_command("slice_hrn time","") + @declare_command("slice_hrn [...] time","") def renew(self, options, args): """ - renew slice (RenewSliver) + renew slice (Renew) """ server = self.sliceapi() - if len(args) != 2: + if len(args) < 2: self.print_help() sys.exit(1) - [ slice_hrn, input_time ] = args - # slice urn - slice_urn = hrn_to_urn(slice_hrn, 'slice') + slice_hrn = args[0] + slice_urn = Xrn(slice_hrn, type='slice').get_urn() + + if len(args) > 2: + # we have sliver urns + sliver_urns = args[1:-1] + else: + # we provision all the slivers of the slice + sliver_urns = [slice_urn] + input_time = args[-1] + # time: don't try to be smart on the time format, server-side will # creds slice_cred = self.slice_credential(args[0]) @@ -1362,7 +1416,7 @@ use this if you mean an authority instead""") 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)) + result = server.Renew(sliver_urns, 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) @@ -1371,7 +1425,7 @@ use this if you mean an authority instead""") return value - @register_command("slice_hrn","") + @declare_command("slice_hrn","") def shutdown(self, options, args): """ shutdown named slice (Shutdown) @@ -1392,7 +1446,7 @@ use this if you mean an authority instead""") return value - @register_command("[name]","") + @declare_command("[name]","") def gid(self, options, args): """ Create a GID (CreateGid) @@ -1411,7 +1465,7 @@ use this if you mean an authority instead""") GID(string=gid).save_to_file(filename) #################### - @register_command("to_hrn","""$ sfi delegate -u -p -s ple.inria.heartbeat -s ple.inria.omftest ple.upmc.slicebrowser + @declare_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 @@ -1427,8 +1481,8 @@ use this if you mean an authority instead""") 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 + make sure to check for 'sfi myslice' instead if you plan + on using MySlice """ if len(args) != 1: self.print_help() @@ -1473,7 +1527,7 @@ use this if you mean an authority instead""") self.logger.info("delegated credential for %s to %s and wrote to %s"%(message,to_hrn,filename)) #################### - @register_command("","""$ less +/myslice sfi_config + @declare_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 @@ -1497,15 +1551,15 @@ $ sfi m -b http://mymanifold.foo.com:7080/ is synonym to sfi myslice as no other command starts with an 'm' and uses a custom backend for this one call """ -) # register_command +) # declare_command def myslice (self, options, args): """ This helper is for refreshing your credentials at myslice; it will - * compute all the slices that you currently have credentials on - * refresh all your credentials (you as a user and pi, your slices) - * upload them to the manifold backend server - for last phase, sfi_config is read to look for the [myslice] section, - and namely the 'backend', 'delegate' and 'user' settings""" + * compute all the slices that you currently have credentials on + * refresh all your credentials (you as a user and pi, your slices) + * upload them to the manifold backend server + for last phase, sfi_config is read to look for the [myslice] section, + and namely the 'backend', 'delegate' and 'user' settings""" ########## if len(args)>0: @@ -1611,12 +1665,20 @@ $ sfi m -b http://mymanifold.foo.com:7080/ if count_success != count_all: sys.exit(1) return - @register_command("cred","") + @declare_command("cred","") def trusted(self, options, args): """ return the trusted certs at this interface (get_trusted_certs) """ - trusted_certs = self.registry().get_trusted_certs() + if options.registry_interface: + server=self.registry() + else: + server = self.sliceapi() + cred = self.my_authority_credential_string() + trusted_certs = server.get_trusted_certs(cred) + if not options.registry_interface: + trusted_certs = ReturnValue.get_value(trusted_certs) + for trusted_cert in trusted_certs: print "\n===========================================================\n" gid = GID(string=trusted_cert)