X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=sfa%2Fclient%2Fsfi.py;h=8aec7c1e77693f4d5372c610d9c2614c6cecef42;hb=e7605f6cb1ebbdb7cd4c6e7495d58d03aeda863b;hp=2a6b7adda3c0191314c2b155ef9049c5ad95fa17;hpb=ce9ed15d73152a0e9b061fefcf3fb23e20b5821d;p=sfa.git diff --git a/sfa/client/sfi.py b/sfa/client/sfi.py index 2a6b7add..8aec7c1e 100644 --- a/sfa/client/sfi.py +++ b/sfa/client/sfi.py @@ -14,6 +14,7 @@ import codecs import pickle import json import shutil + from lxml import etree from StringIO import StringIO from optparse import OptionParser @@ -299,7 +300,7 @@ class Sfi: print line else: print line - self.create_global_parser().print_help() + self.create_parser_global().print_help() # preserve order from the code for command in commands_list: (doc, args_string, example) = commands_dict[command] @@ -308,7 +309,7 @@ class Sfi: doc=doc.replace("\n","\n"+35*' ') print format3%(command,args_string,doc) if verbose: - self.create_command_parser(command).print_help() + self.create_parser_command(command).print_help() ### now if a known command was found we can be more verbose on that one def print_help (self): @@ -323,7 +324,7 @@ class Sfi: print "\n==================== %s example(s)"%self.command print example - def create_global_parser(self): + def create_parser_global(self): # Generate command line parser parser = OptionParser(add_help_option=False, usage="sfi [sfi_options] command [cmd_options] [cmd_args]", @@ -365,7 +366,7 @@ class Sfi: return parser - def create_command_parser(self, command): + def create_parser_command(self, command): if command not in commands_dict: msg="Invalid command\n" msg+="Commands: " @@ -386,6 +387,14 @@ class Sfi: parser.add_option('-m', '--myslice', dest='myslice', action='store_true', default=False, 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"): 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) @@ -412,7 +421,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","slices","delete","status","renew"): + if command in ("list","resources", "describe", "provision", "allocate", "add","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 @@ -476,15 +485,17 @@ class Sfi: 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", - 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 ("myslice"): + parser.add_option("-p","--password",dest='password',action='store',default=None, + help="specify mainfold password on the command line") + 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 PI cred for auth HRN") + parser.add_option('-d', '--delegate', dest='delegate', help="Override 'delegate' from the config file") + parser.add_option('-b', '--backend', dest='backend', help="Override 'backend' from the config file") + return parser @@ -499,7 +510,7 @@ use this if you mean an authority instead""") return method(command_options, command_args) def main(self): - self.sfi_parser = self.create_global_parser() + self.sfi_parser = self.create_parser_global() (options, args) = self.sfi_parser.parse_args() if options.help: self.print_commands_help(options) @@ -522,7 +533,7 @@ use this if you mean an authority instead""") sys.exit(1) # second pass options parsing self.command=command - self.command_parser = self.create_command_parser(command) + self.command_parser = self.create_parser_command(command) (command_options, command_args) = self.command_parser.parse_args(args[1:]) if command_options.help: self.print_help() @@ -659,7 +670,7 @@ use this if you mean an authority instead""") 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_version': '3', 'geni_value': self.my_credential_string} self.my_gid = client_bootstrap.my_gid () self.client_bootstrap = client_bootstrap @@ -679,7 +690,7 @@ use this if you mean an authority instead""") def slice_credential(self, name): return {'geni_type': 'geni_sfa', - 'geni_version': '3.0', + 'geni_version': '3', 'geni_value': self.slice_credential_string(name)} # xxx should be supported by sfaclientbootstrap as well @@ -1039,25 +1050,6 @@ use this if you mean an authority instead""") # Slice-related commands # ================================================================== - @register_command("","") - def slices(self, options, args): - "list instantiated slices (ListSlices) - returns urn's" - server = self.sliceapi() - # creds - creds = [self.my_credential_string] - # 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: - save_raw_to_file(result, self.options.raw, self.options.rawformat, self.options.rawbanner) - else: - display_list(value) - return - # show rspec for named slice @register_command("","") def resources(self, options, args): @@ -1096,9 +1088,9 @@ use this if you mean an authority instead""") # 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'} + api_options['geni_rspec_version'] = {'type': 'geni', 'version': '3'} else: - api_options['geni_rspec_version'] = {'type': 'geni', 'version': '3.0'} + api_options['geni_rspec_version'] = {'type': 'geni', 'version': '3'} result = server.ListResources (creds, api_options) value = ReturnValue.get_value(result) if self.options.raw: @@ -1129,7 +1121,7 @@ use this if you mean an authority instead""") 'cached': True, 'info': options.info, 'list_leases': options.list_leases, - 'geni_rspec_version': {'type': 'geni', 'version': '3.0'}, + 'geni_rspec_version': {'type': 'geni', 'version': '3'}, } if options.rspec_version: version_manager = VersionManager() @@ -1138,7 +1130,7 @@ use this if you mean an authority instead""") # 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'} + api_options['geni_rspec_version'] = {'type': 'geni', 'version': '3'} urn = Xrn(args[0], type='slice').get_urn() result = server.Describe([urn], creds, api_options) value = ReturnValue.get_value(result) @@ -1210,6 +1202,21 @@ use this if you mean an authority instead""") rspec = open(rspec_file).read() api_options = {} api_options ['call_id'] = unique_call_id() + # users + sfa_users = [] + geni_users = [] + slice_records = self.registry().Resolve(slice_urn, [self.my_credential_string]) + if slice_records and 'reg-researchers' in slice_records[0] and slice_records[0]['reg-researchers']!=[]: + slice_record = slice_records[0] + 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]) + sfa_users = sfa_users_arg(user_records, slice_record) + geni_users = pg_users_arg(user_records) + + api_options['sfa_users'] = sfa_users + api_options['geni_users'] = geni_users + result = server.Allocate(slice_urn, creds, rspec, api_options) value = ReturnValue.get_value(result) if self.options.raw: @@ -1251,7 +1258,7 @@ use this if you mean an authority instead""") # set the requtested rspec version version_manager = VersionManager() - rspec_version = version_manager._get_version('geni', '3.0').to_dict() + rspec_version = version_manager._get_version('geni', '3').to_dict() api_options['geni_rspec_version'] = rspec_version # users @@ -1262,9 +1269,9 @@ use this if you mean an authority instead""") # }] 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']!=[]: + if slice_records and 'reg-researchers' in slice_records[0] and slice_records[0]['reg-researchers']!=[]: 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]) users = pg_users_arg(user_records) @@ -1487,8 +1494,9 @@ $ sfi myslice $ sfi -v myslice -- or sfi -vv myslice same but with more and more verbosity -$ sfi m +$ 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 def myslice (self, options, args): @@ -1504,33 +1512,53 @@ $ sfi m if len(args)>0: self.print_help() sys.exit(1) - + # enable info by default + self.logger.setLevelFromOptVerbose(self.options.verbose+1) ### the rough sketch goes like this + # (0) produce a p12 file + self.client_bootstrap.my_pkcs12() + # (a) rain check for sufficient config in sfi_config - # we don't allow to override these settings for now myslice_dict={} - myslice_keys=['backend', 'delegate', 'platform', 'username'] + myslice_keys=[ 'backend', 'delegate', 'platform', 'username'] for key in myslice_keys: - full_key="MYSLICE_" + key.upper() - value=getattr(self.config_instance,full_key,None) + value=None + # oct 2013 - I'm finding myself juggling with config files + # so a couple of command-line options can now override config + if hasattr(options,key) and getattr(options,key) is not None: + value=getattr(options,key) + else: + full_key="MYSLICE_" + key.upper() + value=getattr(self.config_instance,full_key,None) if value: myslice_dict[key]=value else: print "Unsufficient config, missing key %s in [myslice] section of sfi_config"%key if len(myslice_dict) != len(myslice_keys): sys.exit(1) # (b) figure whether we are PI for the authority where we belong - sfi_logger.info("Resolving our own id") + self.logger.info("Resolving our own id %s"%self.user) my_records=self.registry().Resolve(self.user,self.my_credential_string) if len(my_records)!=1: print "Cannot Resolve %s -- exiting"%self.user; sys.exit(1) my_record=my_records[0] - my_auths = my_record['reg-pi-authorities'] - sfi_logger.info("Found %d authorities that we are PI for"%len(my_auths)) - sfi_logger.debug("They are %s"%(my_auths)) + my_auths_all = my_record['reg-pi-authorities'] + self.logger.info("Found %d authorities that we are PI for"%len(my_auths_all)) + self.logger.debug("They are %s"%(my_auths_all)) + + my_auths = my_auths_all + if options.delegate_auths: + my_auths = list(set(my_auths_all).intersection(set(options.delegate_auths))) + self.logger.debug("Restricted to user-provided auths"%(my_auths)) # (c) get the set of slices that we are in - my_slices=my_record['reg-slices'] - sfi_logger.info("Found %d slices that we are member of"%len(my_slices)) - sfi_logger.debug("They are: %s"%(my_slices)) + my_slices_all=my_record['reg-slices'] + self.logger.info("Found %d slices that we are member of"%len(my_slices_all)) + self.logger.debug("They are: %s"%(my_slices_all)) + + my_slices = my_slices_all + # if user provided slices, deal only with these - if they are found + if options.delegate_slices: + my_slices = list(set(my_slices_all).intersection(set(options.delegate_slices))) + self.logger.debug("Restricted to user-provided slices: %s"%(my_slices)) # (d) make sure we have *valid* credentials for all these hrn_credentials=[] @@ -1547,37 +1575,55 @@ $ sfi m delegatee_hrn=myslice_dict['delegate'] hrn_delegated_credentials = [] for (hrn, htype, credential) in hrn_credentials: - sfi_logger.info("Computing delegated credential for %s (%s)"%(hrn,htype)) - hrn_delegated_credentials.append ((hrn, htype, self.client_bootstrap.delegate_credential_string (credential, delegatee_hrn, delegatee_type),)) + delegated_credential = self.client_bootstrap.delegate_credential_string (credential, delegatee_hrn, delegatee_type) + # save these so user can monitor what she's uploaded + filename = os.path.join ( self.options.sfi_dir, + "%s.%s_for_%s.%s.cred"%(hrn,htype,delegatee_hrn,delegatee_type)) + with file(filename,'w') as f: + f.write(delegated_credential) + self.logger.debug("(Over)wrote %s"%filename) + hrn_delegated_credentials.append ((hrn, htype, delegated_credential, filename, )) # (f) and finally upload them to manifold server # xxx todo add an option so the password can be set on the command line # (but *NOT* in the config file) so other apps can leverage this - uploader = ManifoldUploader (logger=sfi_logger, + self.logger.info("Uploading on backend at %s"%myslice_dict['backend']) + uploader = ManifoldUploader (logger=self.logger, url=myslice_dict['backend'], platform=myslice_dict['platform'], - username=myslice_dict['username']) + username=myslice_dict['username'], + password=options.password) uploader.prompt_all() - for (hrn,htype,delegated_credential) in hrn_delegated_credentials: - sfi_logger.info("Uploading delegated credential for %s (%s)"%(hrn,htype)) - uploader.upload(delegated_credential,message=hrn) + (count_all,count_success)=(0,0) + for (hrn,htype,delegated_credential,filename) in hrn_delegated_credentials: + # inspect + inspect=Credential(string=delegated_credential) + expire_datetime=inspect.get_expiration() + message="%s (%s) [exp:%s]"%(hrn,htype,expire_datetime) + if uploader.upload(delegated_credential,message=message): + count_success+=1 + count_all+=1 + self.logger.info("Successfully uploaded %d/%d credentials"%(count_success,count_all)) + # at first I thought we would want to save these, # like 'sfi delegate does' but on second thought # it is probably not helpful as people would not # need to run 'sfi delegate' at all anymore + if count_success != count_all: sys.exit(1) return -# Thierry: I'm turning this off as a command, no idea what it's used for -# @register_command("cred","") + @register_command("cred","") def trusted(self, options, args): """ return the trusted certs at this interface (get_trusted_certs) """ trusted_certs = self.registry().get_trusted_certs() for trusted_cert in trusted_certs: + print "\n===========================================================\n" gid = GID(string=trusted_cert) gid.dump() cert = Certificate(string=trusted_cert) self.logger.debug('Sfi.trusted -> %r'%cert.get_subject()) + print "Certificate:\n%s\n\n"%trusted_cert return