X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=sfa%2Fclient%2Fsfi.py;h=95acf1813842e91d9710c1c0953d2cd8cffe501f;hb=5a6cbf4fa6837c81354b616d4cfa0352ec5367be;hp=3fc44da871555d8b2674b27016ff2e6db305fa3a;hpb=0eb2fd645abe02f4fbb79d9ebc5a17b292b8dd2d;p=sfa.git diff --git a/sfa/client/sfi.py b/sfa/client/sfi.py index 3fc44da8..95acf181 100644 --- a/sfa/client/sfi.py +++ b/sfa/client/sfi.py @@ -3,6 +3,8 @@ # this module is also used in sfascan # +from __future__ import print_function + import sys sys.path.append('.') @@ -15,7 +17,6 @@ import pickle import json import shutil from lxml import etree -from StringIO import StringIO from optparse import OptionParser from pprint import PrettyPrinter from tempfile import mkstemp @@ -32,6 +33,7 @@ from sfa.util.config import Config from sfa.util.version import version_core from sfa.util.cache import Cache from sfa.util.printable import printable +from sfa.util.py23 import StringIO from sfa.storage.record import Record @@ -67,12 +69,12 @@ def display_rspec(rspec, format='rspec'): else: result = rspec - print result + print(result) return def display_list(results): for result in results: - print result + print(result) def display_records(recordList, dump=False): ''' Print all fields in the record''' @@ -84,7 +86,7 @@ def display_record(record, dump=False): record.dump(sort=True) else: info = record.getdict() - print "{} ({})".format(info['hrn'], info['type']) + print("{} ({})".format(info['hrn'], info['type'])) return @@ -96,9 +98,9 @@ def filter_records(type, records): return filtered_records -def credential_printable (cred): +def credential_printable(cred): credential = Credential(cred=cred) - result="" + result = "" result += credential.pretty_cred() result += "\n" rights = credential.get_privileges() @@ -107,10 +109,10 @@ def credential_printable (cred): result += "rights={}\n".format(rights) return result -def show_credentials (cred_s): - if not isinstance (cred_s,list): cred_s = [cred_s] +def show_credentials(cred_s): + if not isinstance(cred_s, list): cred_s = [cred_s] for cred in cred_s: - print "Using Credential {}".format(credential_printable(cred)) + print("Using Credential {}".format(credential_printable(cred))) ########## save methods @@ -121,7 +123,7 @@ def save_raw_to_file(var, filename, format='text', banner=None): else: with open(filename, w) as fileobj: _save_raw_to_file(var, fileobj, format, banner) - print "(Over)wrote {}".format(filename) + print("(Over)wrote {}".format(filename)) def _save_raw_to_file(var, f, format, banner): if format == "text": @@ -134,7 +136,7 @@ def _save_raw_to_file(var, f, format, banner): f.write(json.dumps(var)) # python 2.6 else: # this should never happen - print "unknown output format", format + print("unknown output format", format) ### def save_rspec_to_file(rspec, filename): @@ -142,14 +144,14 @@ def save_rspec_to_file(rspec, filename): filename = filename + ".rspec" with open(filename, 'w') as f: f.write("{}".format(rspec)) - print "(Over)wrote {}".format(filename) + print("(Over)wrote {}".format(filename)) def save_record_to_file(filename, record_dict): record = Record(dict=record_dict) xml = record.save_as_xml() - with codecs.open(filename, encoding='utf-8',mode="w") as f: + with codecs.open(filename, encoding='utf-8', mode="w") as f: f.write(xml) - print "(Over)wrote {}".format(filename) + print("(Over)wrote {}".format(filename)) def save_records_to_file(filename, record_dicts, format="xml"): if format == "xml": @@ -162,26 +164,26 @@ def save_records_to_file(filename, record_dicts, format="xml"): record_obj = Record(dict=record_dict) f.write('\n') f.write("\n") - print "(Over)wrote {}".format(filename) + print("(Over)wrote {}".format(filename)) elif format == "hrnlist": with open(filename, "w") as f: for record_dict in record_dicts: record_obj = Record(dict=record_dict) f.write(record_obj.hrn + "\n") - print "(Over)wrote {}".format(filename) + print("(Over)wrote {}".format(filename)) else: # this should never happen - print "unknown output format", format + print("unknown output format", format) # minimally check a key argument -def check_ssh_key (key): +def check_ssh_key(key): good_ssh_key = r'^.*(?:ssh-dss|ssh-rsa)[ ]+[A-Za-z0-9+/=]+(?: .*)?$' return re.match(good_ssh_key, key, re.IGNORECASE) # load methods -def normalize_type (type): +def normalize_type(type): if type.startswith('au'): return 'authority' elif type.startswith('us'): @@ -195,7 +197,7 @@ def normalize_type (type): elif type.startswith('al'): return 'all' else: - print 'unknown type {} - should start with one of au|us|sl|no|ag|al'.format(type) + print('unknown type {} - should start with one of au|us|sl|no|ag|al'.format(type)) return None def load_record_from_opts(options): @@ -213,8 +215,8 @@ def load_record_from_opts(options): pubkey = open(options.key, 'r').read() except IOError: pubkey = options.key - if not check_ssh_key (pubkey): - raise SfaInvalidArgument(name='key',msg="Could not find file, or wrong key format") + if not check_ssh_key(pubkey): + raise SfaInvalidArgument(name='key', msg="Could not find file, or wrong key format") record_dict['reg-keys'] = [pubkey] if hasattr(options, 'slices') and options.slices: record_dict['slices'] = options.slices @@ -257,27 +259,27 @@ from functools import wraps commands_list=[] commands_dict={} -def declare_command (args_string, example,aliases=None): +def declare_command(args_string, example, aliases=None): def wrap(m): - name=getattr(m,'__name__') - doc=getattr(m,'__doc__',"-- missing doc --") + name=getattr(m, '__name__') + doc=getattr(m, '__doc__', "-- missing doc --") doc=doc.strip(" \t\n") commands_list.append(name) # last item is 'canonical' name, so we can know which commands are aliases - command_tuple=(doc, args_string, example,name) + 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) + def new_method(*args, **kwds): return m(*args, **kwds) return new_method return wrap -def remove_none_fields (record): - none_fields=[ k for (k,v) in record.items() if v is None ] +def remove_none_fields(record): + none_fields=[ k for (k, v) in record.items() if v is None ] for k in none_fields: del record[k] ########## @@ -288,7 +290,7 @@ class Sfi: required_options=['verbose', 'debug', 'registry', 'sm', 'auth', 'user', 'user_private_key'] @staticmethod - def default_sfi_dir (): + def default_sfi_dir(): if os.path.isfile("./sfi_config"): return os.getcwd() else: @@ -299,11 +301,13 @@ class Sfi: class DummyOptions: pass - def __init__ (self,options=None): + def __init__(self, options=None): if options is None: options=Sfi.DummyOptions() for opt in Sfi.required_options: - if not hasattr(options,opt): setattr(options,opt,None) - if not hasattr(options,'sfi_dir'): options.sfi_dir=Sfi.default_sfi_dir() + if not hasattr(options, opt): + setattr(options, opt, None) + if not hasattr(options, 'sfi_dir'): + options.sfi_dir = Sfi.default_sfi_dir() self.options = options self.user = None self.authority = None @@ -312,55 +316,55 @@ class Sfi: ### various auxiliary material that we keep at hand self.command=None # need to call this other than just 'config' as we have a command/method with that name - self.config_instance=None - self.config_file=None - self.client_bootstrap=None + self.config_instance = None + self.config_file = None + self.client_bootstrap = None ### suitable if no reasonable command has been provided - def print_commands_help (self, options): - verbose=getattr(options,'verbose') - format3="%10s %-35s %s" - format3offset=47 - line=80*'-' + def print_commands_help(self, options): + verbose = getattr(options, 'verbose') + format3 = "%10s %-35s %s" + format3offset = 47 + line = 80*'-' if not verbose: - print format3%("command", "cmd_args", "description") - print line + print(format3%("command", "cmd_args", "description")) + print(line) else: - print line + print(line) self.create_parser_global().print_help() # preserve order from the code for command in commands_list: try: (doc, args_string, example, canonical) = commands_dict[command] except: - print "Cannot find info on command %s - skipped"%command + print("Cannot find info on command %s - skipped"%command) continue if verbose: - print line + print(line) if command==canonical: doc = doc.replace("\n", "\n" + format3offset * ' ') - print format3 % (command,args_string,doc) + print(format3 % (command, args_string, doc)) if verbose: self.create_parser_command(command).print_help() else: - print format3 % (command,"<>"%canonical,"") + 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" + def print_help(self): + print("==================== Generic sfi usage") self.sfi_parser.print_help() (doc, _, example, canonical) = commands_dict[self.command] if canonical != self.command: - print "\n==================== NOTE: {} is an alias for genuine {}"\ - .format(self.command, canonical) + print("\n==================== NOTE: {} is an alias for genuine {}" + .format(self.command, canonical)) self.command = canonical - print "\n==================== Purpose of {}".format(self.command) - print doc - print "\n==================== Specific usage for {}".format(self.command) + print("\n==================== Purpose of {}".format(self.command)) + print(doc) + print("\n==================== Specific usage for {}".format(self.command)) self.command_parser.print_help() if example: - print "\n==================== {} example(s)".format(self.command) - print example + print("\n==================== {} example(s)".format(self.command)) + print(example) def create_parser_global(self): # Generate command line parser @@ -413,12 +417,12 @@ class Sfi: sys.exit(2) # retrieve args_string - (_, args_string, __,canonical) = commands_dict[command] + (_, args_string, __, canonical) = commands_dict[command] parser = OptionParser(add_help_option=False, usage="sfi [sfi_options] {} [cmd_options] {}"\ .format(command, args_string)) - parser.add_option ("-h","--help",dest='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 canonical in ("config"): @@ -430,7 +434,7 @@ class Sfi: action="store_true", dest="version_local", default=False, help="display version of the local client") - if canonical in ("version", "trusted"): + if canonical in ("version", "trusted", "introspect"): parser.add_option("-R","--registry_interface", action="store_true", dest="registry_interface", default=False, help="target the registry interface instead of slice interface") @@ -449,7 +453,7 @@ class Sfi: callback=optparse_listvalue_callback) parser.add_option('-p', '--pis', dest='reg_pis', metavar='', help='Set/replace Principal Investigators/Project Managers', default='', type="str", action='callback', callback=optparse_listvalue_callback) - parser.add_option ('-X','--extra',dest='extras',default={},type='str',metavar="", + parser.add_option('-X','--extra',dest='extras',default={},type='str',metavar="", action="callback", callback=optparse_dictvalue_callback, nargs=1, help="set extra/testbed-dependent flags, e.g. --extra enabled=true") @@ -551,7 +555,7 @@ use this if you mean an authority instead""") (doc, args_string, example, canonical) = commands_dict[command] method=getattr(self, canonical, None) if not method: - print "sfi: unknown command {}".format(command) + print("sfi: unknown command {}".format(command)) raise SystemExit("Unknown command {}".format(command)) for arg in command_args: if 'help' in arg or arg == '-h': @@ -575,14 +579,14 @@ use this if you mean an authority instead""") return -1 # complete / find unique match with command set - command_candidates = Candidates (commands_list) + command_candidates = Candidates(commands_list) input = args[0] command = command_candidates.only_match(input) if not command: self.print_commands_help(options) sys.exit(1) # second pass options parsing - self.command=command + self.command = command self.command_parser = self.create_parser_command(command) (command_options, command_args) = self.command_parser.parse_args(args[1:]) if command_options.help: @@ -596,8 +600,8 @@ use this if you mean an authority instead""") if not command_options.type: sys.exit(1) - self.read_config () - self.bootstrap () + self.read_config() + self.bootstrap() self.logger.debug("Command={}".format(self.command)) try: @@ -605,17 +609,17 @@ use this if you mean an authority instead""") except SystemExit: return 1 except: - self.logger.log_exc ("sfi command {} failed".format(command)) + self.logger.log_exc("sfi command {} failed".format(command)) return 1 return retcod #################### 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") + 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: if Config.is_ini(config_file): - config = Config (config_file) + config = Config(config_file) else: # try upgrading from shell config format fp, fn = mkstemp(suffix='sfi_config', text=True) @@ -637,13 +641,13 @@ use this if you mean an authority instead""") except: self.logger.critical("Failed to read configuration file {}".format(config_file)) self.logger.info("Make sure to remove the export clauses and to add quotes") - if self.options.verbose==0: + 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 {}".format(config_file)) sys.exit(1) - self.config_instance=config + self.config_instance = config errors = 0 # Set SliceMgr URL if (self.options.sm is not None): @@ -681,7 +685,7 @@ use this if you mean an authority instead""") self.logger.error("You need to set e.g. SFI_AUTH='plc.princeton' in {}".format(config_file)) errors += 1 - self.config_file=config_file + self.config_file = config_file if errors: sys.exit(1) @@ -699,25 +703,25 @@ use this if you mean an authority instead""") # # init self-signed cert, user credentials and gid - def bootstrap (self): + def bootstrap(self): if self.options.verbose: self.logger.info("Initializing SfaClientBootstrap with {}".format(self.reg_url)) - 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) + client_bootstrap.init_private_key_if_missing(self.options.user_private_key) else: # trigger legacy compat code if needed # the name has changed from just .pkey to .pkey if not os.path.isfile(client_bootstrap.private_key_filename()): - self.logger.info ("private key not found, trying legacy name") + self.logger.info("private key not found, trying legacy name") try: - legacy_private_key = os.path.join (self.options.sfi_dir, "{}.pkey" + legacy_private_key = os.path.join(self.options.sfi_dir, "{}.pkey" .format(Xrn.unescape(get_leaf(self.user)))) self.logger.debug("legacy_private_key={}" .format(legacy_private_key)) - client_bootstrap.init_private_key_if_missing (legacy_private_key) + client_bootstrap.init_private_key_if_missing(legacy_private_key) self.logger.info("Copied private key from legacy location {}" .format(legacy_private_key)) except: @@ -728,11 +732,11 @@ use this if you mean an authority instead""") client_bootstrap.bootstrap_my_gid() # extract what's needed self.private_key = client_bootstrap.private_key() - self.my_credential_string = client_bootstrap.my_credential_string () + self.my_credential_string = client_bootstrap.my_credential_string() self.my_credential = {'geni_type': 'geni_sfa', 'geni_version': '3', 'geni_value': self.my_credential_string} - self.my_gid = client_bootstrap.my_gid () + self.my_gid = client_bootstrap.my_gid() self.client_bootstrap = client_bootstrap @@ -740,13 +744,13 @@ use this if you mean an authority instead""") if not self.authority: self.logger.critical("no authority specified. Use -a or set SF_AUTH") sys.exit(-1) - return self.client_bootstrap.authority_credential_string (self.authority) + 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) + return self.client_bootstrap.authority_credential_string(auth_hrn) def slice_credential_string(self, name): - return self.client_bootstrap.slice_credential_string (name) + return self.client_bootstrap.slice_credential_string(name) def slice_credential(self, name): return {'geni_type': 'geni_sfa', @@ -770,7 +774,7 @@ use this if you mean an authority instead""") caller_gidfile = self.my_gid() # the gid of the user who will be delegated to - delegee_gid = self.client_bootstrap.gid(hrn,type) + delegee_gid = self.client_bootstrap.gid(hrn, type) delegee_hrn = delegee_gid.get_hrn() dcred = object_cred.delegate(delegee_gid, self.private_key, caller_gidfile) return dcred.save_to_string(save_parents=True) @@ -779,20 +783,20 @@ use this if you mean an authority instead""") # Management of the servers # - def registry (self): + def registry(self): # cache the result - if not hasattr (self, 'registry_proxy'): + if not hasattr(self, 'registry_proxy'): self.logger.info("Contacting Registry at: {}".format(self.reg_url)) self.registry_proxy \ = SfaServerProxy(self.reg_url, self.private_key, self.my_gid, timeout=self.options.timeout, verbose=self.options.debug) return self.registry_proxy - def sliceapi (self): + def sliceapi(self): # cache the result - if not hasattr (self, 'sliceapi_proxy'): + if not hasattr(self, 'sliceapi_proxy'): # if the command exposes the --component option, figure it's hostname and connect at CM_PORT - if hasattr(self.command_options,'component') and self.command_options.component: + if hasattr(self.command_options, 'component') and self.command_options.component: # resolve the hrn at the registry node_hrn = self.command_options.component records = self.registry().Resolve(node_hrn, self.my_credential_string) @@ -801,7 +805,7 @@ use this if you mean an authority instead""") self.logger.warning("No such component:{}".format(opts.component)) record = records[0] cm_url = "http://{}:{}/".format(record['hostname'], CM_PORT) - self.sliceapi_proxy=SfaServerProxy(cm_url, self.private_key, self.my_gid) + self.sliceapi_proxy = SfaServerProxy(cm_url, self.private_key, self.my_gid) else: # otherwise use what was provided as --sliceapi, or SFI_SM in the config if not self.sm_url.startswith('http://') or self.sm_url.startswith('https://'): @@ -816,7 +820,7 @@ use this if you mean an authority instead""") # check local cache first cache = None version = None - cache_file = os.path.join(self.options.sfi_dir,'sfi_cache.dat') + cache_file = os.path.join(self.options.sfi_dir, 'sfi_cache.dat') cache_key = server.url + "-version" try: cache = Cache(cache_file) @@ -829,9 +833,9 @@ use this if you mean an authority instead""") if not version: result = server.GetVersion() - version= ReturnValue.get_value(result) + version = ReturnValue.get_value(result) # cache version for 20 minutes - cache.add(cache_key, version, ttl= 60*20) + cache.add(cache_key, version, ttl=60*20) self.logger.info("Updating cache file {}".format(cache_file)) cache.save_to_file(cache_file) @@ -863,18 +867,18 @@ use this if you mean an authority instead""") return result ### ois = options if supported - # to be used in something like serverproxy.Method (arg1, arg2, *self.ois(api_options)) - def ois (self, server, option_dict): - if self.server_supports_options_arg (server): + # to be used in something like serverproxy.Method(arg1, arg2, *self.ois(api_options)) + def ois(self, server, option_dict): + if self.server_supports_options_arg(server): return [option_dict] - elif self.server_supports_call_id_arg (server): - return [ unique_call_id () ] + elif self.server_supports_call_id_arg(server): + return [ unique_call_id() ] else: return [] ### cis = call_id if supported - like ois - def cis (self, server): - if self.server_supports_call_id_arg (server): + def cis(self, server): + if self.server_supports_call_id_arg(server): return [ unique_call_id ] else: return [] @@ -905,14 +909,14 @@ use this if you mean an authority instead""") # helper function to analyze raw output # for main : return 0 if everything is fine, something else otherwise (mostly 1 for now) - def success (self, raw): - return_value=ReturnValue (raw) - output=ReturnValue.get_output(return_value) + def success(self, raw): + return_value = ReturnValue(raw) + output = ReturnValue.get_output(return_value) # means everything is fine if not output: return 0 # something went wrong - print 'ERROR:',output + print('ERROR:', output) return 1 #========================================================================== @@ -921,43 +925,53 @@ use this if you mean an authority instead""") # Registry-related commands #========================================================================== - @declare_command("","") - def config (self, options, args): - "Display contents of current config" - print "# From configuration file {}".format(self.config_file) - flags=[ ('sfi', [ ('registry','reg_url'), - ('auth','authority'), - ('user','user'), - ('sm','sm_url'), - ]), + @declare_command("", "") + def config(self, options, args): + """ + Display contents of current config + """ + if len(args) != 0: + self.print_help() + sys.exit(1) + + print("# From configuration file {}".format(self.config_file)) + flags = [ ('sfi', [ ('registry', 'reg_url'), + ('auth', 'authority'), + ('user', 'user'), + ('sm', 'sm_url'), + ]), ] if options.myslice: - flags.append ( ('myslice', ['backend', 'delegate', 'platform', 'username'] ) ) + flags.append( ('myslice', ['backend', 'delegate', 'platform', 'username'] ) ) for (section, tuples) in flags: - print "[{}]".format(section) + print("[{}]".format(section)) try: - for (external_name, internal_name) in tuples: - print "{:-20} = {}".format(external_name, getattr(self, internal_name)) + for external_name, internal_name in tuples: + print("{:<20} = {}".format(external_name, getattr(self, internal_name))) except: - for name in tuples: - varname = "{}_{}".format(section.upper(), name.upper()) - value = getattr(self.config_instance,varname) - print "{:-20} = {}".format(name, value) + for external_name, internal_name in tuples: + varname = "{}_{}".format(section.upper(), external_name.upper()) + value = getattr(self.config_instance, varname) + print("{:<20} = {}".format(external_name, value)) # xxx should analyze result return 0 - @declare_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 len(args) != 0: + self.print_help() + sys.exit(1) + if options.version_local: - version=version_core() + version = version_core() else: if options.registry_interface: - server=self.registry() + server = self.registry() else: server = self.sliceapi() result = server.GetVersion() @@ -970,14 +984,15 @@ use this if you mean an authority instead""") # xxx should analyze result return 0 - @declare_command("authority","") + @declare_command("authority", "") def list(self, options, args): """ list entries in named authority registry (List) """ - if len(args)!= 1: + if len(args) != 1: self.print_help() sys.exit(1) + hrn = args[0] opts = {} if options.recursive: @@ -988,29 +1003,31 @@ use this if you mean an authority instead""") try: list = self.registry().List(hrn, self.my_credential_string, options) except IndexError: - raise Exception, "Not enough parameters for the 'list' command" + 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... list = filter_records(options.type, list) - terminal_render (list, options) + terminal_render(list, options) if options.file: save_records_to_file(options.file, list, options.fileformat) # xxx should analyze result return 0 - @declare_command("name","") + @declare_command("name", "") def show(self, options, args): """ show details about named registry record (Resolve) """ - if len(args)!= 1: + if len(args) != 1: self.print_help() sys.exit(1) + hrn = args[0] # explicitly require Resolve to run in details mode - resolve_options={} - if not options.no_details: resolve_options['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: @@ -1018,43 +1035,45 @@ use this if you mean an authority instead""") return # user has required to focus on some keys if options.keys: - def project (record): - projected={} + def project(record): + projected = {} for key in options.keys: - try: projected[key]=record[key] + try: projected[key] = record[key] except: pass return projected - record_dicts = [ project (record) for record in record_dicts ] + 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) - else: print record.save_as_xml() + else: print(record.save_as_xml()) if options.file: save_records_to_file(options.file, record_dicts, options.fileformat) # xxx should analyze result return 0 # this historically was named 'add', it is now 'register' with an alias for legacy - @declare_command("[xml-filename]","",['add']) + @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""" + """ + create new record in registry (Register) + from command line options (recommended) + old-school method involving an xml file still supported + """ + if len(args) > 1: + self.print_help() + sys.exit(1) auth_cred = self.my_authority_credential_string() if options.show_credential: show_credentials(auth_cred) record_dict = {} - if len(args) > 1: - self.print_help() - sys.exit(1) - if len(args)==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).record_to_dict()) except: - print "Cannot load record file {}".format(record_filepath) + print("Cannot load record file {}".format(record_filepath)) sys.exit(1) if options: record_dict.update(load_record_from_opts(options).record_to_dict()) @@ -1075,13 +1094,19 @@ use this if you mean an authority instead""") # xxx should analyze result return 0 - @declare_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""" + """ + update record into registry (Update) + from command line options (recommended) + old-school method involving an xml file still supported + """ + if len(args) > 1: + self.print_help() + sys.exit(1) + record_dict = {} - if len(args) > 0: + if len(args) == 1: record_filepath = args[0] rec_file = self.get_record_file(record_filepath) record_dict.update(load_record_from_file(rec_file).record_to_dict()) @@ -1102,7 +1127,7 @@ use this if you mean an authority instead""") elif record_dict['type'] in ['slice']: try: cred = self.slice_credential_string(record_dict['hrn']) - except ServerException, e: + except ServerException as e: # XXX smbaker -- once we have better error return codes, update this # to do something better than a string compare if "Permission error" in e.args[0]: @@ -1123,13 +1148,16 @@ use this if you mean an authority instead""") # xxx should analyze result return 0 - @declare_command("hrn","") + @declare_command("hrn", "") def remove(self, options, args): - "remove registry record by name (Remove)" + """ + remove registry record by name (Remove) + """ auth_cred = self.my_authority_credential_string() - if len(args)!=1: + if len(args) != 1: self.print_help() sys.exit(1) + hrn = args[0] type = options.type if type in ['all']: @@ -1147,13 +1175,16 @@ use this if you mean an authority instead""") # ================================================================== # show rspec for named slice - @declare_command("","",['discover']) + @declare_command("", "", ['discover']) def resources(self, options, args): """ discover available resources (ListResources) """ - server = self.sliceapi() + if len(args) != 0: + self.print_help() + sys.exit(1) + server = self.sliceapi() # set creds creds = [self.my_credential] if options.delegate: @@ -1177,17 +1208,10 @@ use this if you mean an authority instead""") api_options['cached'] = False else: api_options['cached'] = True - 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'} - else: - api_options['geni_rspec_version'] = {'type': 'geni', 'version': '3'} - list_resources = server.ListResources (creds, api_options) + version_manager = VersionManager() + api_options['geni_rspec_version'] = version_manager.get_version(options.rspec_version).to_dict() + + list_resources = server.ListResources(creds, api_options) value = ReturnValue.get_value(list_resources) if self.options.raw: save_raw_to_file(list_resources, self.options.raw, self.options.rawformat, self.options.rawbanner) @@ -1197,14 +1221,17 @@ use this if you mean an authority instead""") display_rspec(value, options.format) return self.success(list_resources) - @declare_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() + if len(args) != 1: + self.print_help() + sys.exit(1) + server = self.sliceapi() # set creds creds = [self.slice_credential(args[0])] if options.delegate: @@ -1239,15 +1266,18 @@ use this if you mean an authority instead""") save_rspec_to_file(value['geni_rspec'], options.file) if (self.options.raw is None) and (options.file is None): display_rspec(value['geni_rspec'], options.format) - return self.success (describe) + return self.success(describe) - @declare_command("slice_hrn [...]","") + @declare_command("slice_hrn [...]", "") def delete(self, options, args): """ de-allocate and de-provision all or named slivers of the named slice (Delete) """ - server = self.sliceapi() + if len(args) == 0: + self.print_help() + sys.exit(1) + server = self.sliceapi() # slice urn slice_hrn = args[0] slice_urn = hrn_to_urn(slice_hrn, 'slice') @@ -1273,19 +1303,20 @@ use this if you mean an authority instead""") if self.options.raw: save_raw_to_file(delete, self.options.raw, self.options.rawformat, self.options.rawbanner) else: - print value - return self.success (delete) + print(value) + return self.success(delete) - @declare_command("slice_hrn rspec","") + @declare_command("slice_hrn rspec", "") def allocate(self, options, args): """ allocate resources to the named slice (Allocate) """ - server = self.sliceapi() - server_version = self.get_cached_server_version(server) if len(args) != 2: self.print_help() sys.exit(1) + + server = self.sliceapi() + server_version = self.get_cached_server_version(server) slice_hrn = args[0] rspec_file = self.get_rspec_file(args[1]) @@ -1315,7 +1346,7 @@ use this if you mean an authority instead""") geni_users = [] slice_records = self.registry().Resolve(slice_urn, [self.my_credential_string]) remove_none_fields(slice_records[0]) - if slice_records and 'reg-researchers' in slice_records[0] and slice_records[0]['reg-researchers']!=[]: + 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] @@ -1333,16 +1364,20 @@ use this if you mean an authority instead""") if self.options.raw: save_raw_to_file(allocate, self.options.raw, self.options.rawformat, self.options.rawbanner) if options.file is not None: - save_rspec_to_file (value['geni_rspec'], options.file) + save_rspec_to_file(value['geni_rspec'], options.file) if (self.options.raw is None) and (options.file is None): - print value + print(value) return self.success(allocate) - @declare_command("slice_hrn [...]","") + @declare_command("slice_hrn [...]", "") def provision(self, options, args): """ provision all or named already allocated slivers of the named slice (Provision) """ + if len(args) == 0: + self.print_help() + sys.exit(1) + server = self.sliceapi() server_version = self.get_cached_server_version(server) slice_hrn = args[0] @@ -1385,7 +1420,7 @@ use this if you mean an authority instead""") # }] 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']!=[]: + 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] @@ -1398,18 +1433,21 @@ use this if you mean an authority instead""") if self.options.raw: save_raw_to_file(provision, self.options.raw, self.options.rawformat, self.options.rawbanner) if options.file is not None: - save_rspec_to_file (value['geni_rspec'], options.file) + save_rspec_to_file(value['geni_rspec'], options.file) if (self.options.raw is None) and (options.file is None): - print value + print(value) return self.success(provision) - @declare_command("slice_hrn","") + @declare_command("slice_hrn", "") def status(self, options, args): """ retrieve the status of the slivers belonging to the named slice (Status) """ - server = self.sliceapi() + if len(args) != 1: + self.print_help() + sys.exit(1) + server = self.sliceapi() # slice urn slice_hrn = args[0] slice_urn = hrn_to_urn(slice_hrn, 'slice') @@ -1420,22 +1458,26 @@ use this if you mean an authority instead""") # 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) - status = server.Status([slice_urn], creds, *self.ois(server,api_options)) + status = server.Status([slice_urn], creds, *self.ois(server, api_options)) value = ReturnValue.get_value(status) if self.options.raw: save_raw_to_file(status, self.options.raw, self.options.rawformat, self.options.rawbanner) else: - print value - return self.success (status) + print(value) + return self.success(status) - @declare_command("slice_hrn [...] action","") + @declare_command("slice_hrn [...] action", "") def action(self, options, args): """ Perform the named operational action on all or named slivers of the named slice """ + if len(args) == 0: + self.print_help() + sys.exit(1) + server = self.sliceapi() api_options = {} # slice urn @@ -1460,8 +1502,8 @@ use this if you mean an authority instead""") if self.options.raw: save_raw_to_file(perform_action, self.options.raw, self.options.rawformat, self.options.rawbanner) else: - print value - return self.success (perform_action) + print(value) + return self.success(perform_action) @declare_command("slice_hrn [...] time", "\n".join(["sfi renew onelab.ple.heartbeat 2015-04-31", @@ -1471,12 +1513,13 @@ use this if you mean an authority instead""") "sfi renew onelab.ple.heartbeat +2m",])) def renew(self, options, args): """ - renew slice (Renew) + renew slice(Renew) """ - server = self.sliceapi() if len(args) < 2: self.print_help() sys.exit(1) + + server = self.sliceapi() slice_hrn = args[0] slice_urn = Xrn(slice_hrn, type='slice').get_urn() @@ -1494,24 +1537,28 @@ use this if you mean an authority instead""") creds = [slice_cred] # options and call_id when supported api_options = {} - api_options['call_id']=unique_call_id() + api_options['call_id'] = unique_call_id() if options.alap: - api_options['geni_extend_alap']=True + api_options['geni_extend_alap'] = True if options.show_credential: show_credentials(creds) - renew = server.Renew(sliver_urns, creds, input_time, *self.ois(server,api_options)) + renew = server.Renew(sliver_urns, creds, input_time, *self.ois(server, api_options)) value = ReturnValue.get_value(renew) if self.options.raw: save_raw_to_file(renew, self.options.raw, self.options.rawformat, self.options.rawbanner) else: - print value + print(value) return self.success(renew) - @declare_command("slice_hrn","") + @declare_command("slice_hrn", "") def shutdown(self, options, args): """ shutdown named slice (Shutdown) """ + if len(args) != 1: + self.print_help() + sys.exit(1) + server = self.sliceapi() # slice urn slice_hrn = args[0] @@ -1524,10 +1571,10 @@ use this if you mean an authority instead""") if self.options.raw: save_raw_to_file(shutdown, self.options.raw, self.options.rawformat, self.options.rawbanner) else: - print value - return self.success (shutdown) + print(value) + return self.success(shutdown) - @declare_command("[name]","") + @declare_command("[name]", "") def gid(self, options, args): """ Create a GID (CreateGid) @@ -1535,6 +1582,7 @@ use this if you mean an authority instead""") if len(args) < 1: self.print_help() sys.exit(1) + target_hrn = args[0] my_gid_string = open(self.client_bootstrap.my_gid()).read() gid = self.registry().CreateGid(self.my_credential_string, target_hrn, my_gid_string) @@ -1548,7 +1596,7 @@ use this if you mean an authority instead""") return 0 #################### - @declare_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 @@ -1561,7 +1609,7 @@ use this if you mean an authority instead""") because of the two -s options """) - def delegate (self, options, args): + 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 @@ -1570,6 +1618,7 @@ use this if you mean an authority instead""") 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 @@ -1577,33 +1626,33 @@ use this if you mean an authority instead""") for slice_hrn in options.delegate_slices: message = "{}.slice".format(slice_hrn) original = self.slice_credential_string(slice_hrn) - tuples.append ( (message, original,) ) + tuples.append( (message, original,) ) if options.delegate_pi: - my_authority=self.authority + my_authority = self.authority message = "{}.pi".format(my_authority) original = self.my_authority_credential_string() - tuples.append ( (message, original,) ) + tuples.append( (message, original,) ) for auth_hrn in options.delegate_auths: message = "{}.auth".format(auth_hrn) original = self.authority_credential_string(auth_hrn) - tuples.append ( (message, original, ) ) + tuples.append( (message, original, ) ) # if nothing was specified at all at this point, let's assume -u - if not tuples: options.delegate_user=True + if not tuples: + options.delegate_user = True # this user cred if options.delegate_user: message = "{}.user".format(self.user) original = self.my_credential_string - tuples.append ( (message, original, ) ) + tuples.append( (message, original, ) ) # default type for beneficial is user unless -A - if options.delegate_to_authority: to_type='authority' - else: to_type='user' + to_type = 'authority' if options.delegate_to_authority else 'user' # let's now handle all this # it's all in the filenaming scheme - for (message,original) in tuples: + for (message, original) in tuples: delegated_string = self.client_bootstrap.delegate_credential_string(original, to_hrn, to_type) - delegated_credential = Credential (string=delegated_string) + delegated_credential = Credential(string=delegated_string) filename = os.path.join(self.options.sfi_dir, "{}_for_{}.{}.cred".format(message, to_hrn, to_type)) delegated_credential.save_to_file(filename, save_parents=True) @@ -1611,7 +1660,7 @@ use this if you mean an authority instead""") .format(message, to_hrn, filename)) #################### - @declare_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 @@ -1636,17 +1685,18 @@ $ sfi m -b http://mymanifold.foo.com:7080/ and uses a custom backend for this one call """ ) # declare_command - def myslice (self, options, args): + 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""" + and namely the 'backend', 'delegate' and 'user' settings + """ ########## - if len(args)>0: + if len(args) > 0: self.print_help() sys.exit(1) # enable info by default @@ -1656,30 +1706,30 @@ $ sfi m -b http://mymanifold.foo.com:7080/ self.client_bootstrap.my_pkcs12() # (a) rain check for sufficient config in sfi_config - myslice_dict={} - myslice_keys=[ 'backend', 'delegate', 'platform', 'username'] + myslice_dict = {} + myslice_keys = [ 'backend', 'delegate', 'platform', 'username'] for key in myslice_keys: - value=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) + 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) + full_key = "MYSLICE_" + key.upper() + value = getattr(self.config_instance, full_key, None) if value: - myslice_dict[key]=value + myslice_dict[key] = value else: - print "Unsufficient config, missing key {} in [myslice] section of sfi_config"\ - .format(key) + print("Unsufficient config, missing key {} in [myslice] section of sfi_config" + .format(key)) if len(myslice_dict) != len(myslice_keys): sys.exit(1) # (b) figure whether we are PI for the authority where we belong self.logger.info("Resolving our own id {}".format(self.user)) - my_records=self.registry().Resolve(self.user,self.my_credential_string) + my_records = self.registry().Resolve(self.user, self.my_credential_string) if len(my_records) != 1: - print "Cannot Resolve {} -- exiting".format(self.user) + print("Cannot Resolve {} -- exiting".format(self.user)) sys.exit(1) my_record = my_records[0] my_auths_all = my_record['reg-pi-authorities'] @@ -1692,7 +1742,7 @@ $ sfi m -b http://mymanifold.foo.com:7080/ self.logger.debug("Restricted to user-provided auths {}".format(my_auths)) # (c) get the set of slices that we are in - my_slices_all=my_record['reg-slices'] + my_slices_all = my_record['reg-slices'] self.logger.info("Found {} slices that we are member of".format(len(my_slices_all))) self.logger.debug("They are: {}".format(my_slices_all)) @@ -1703,49 +1753,53 @@ $ sfi m -b http://mymanifold.foo.com:7080/ self.logger.debug("Restricted to user-provided slices: {}".format(my_slices)) # (d) make sure we have *valid* credentials for all these - hrn_credentials=[] - hrn_credentials.append ( (self.user, 'user', self.my_credential_string,) ) + hrn_credentials = [] + hrn_credentials.append( (self.user, 'user', self.my_credential_string,) ) for auth_hrn in my_auths: - hrn_credentials.append ( (auth_hrn, 'auth', self.authority_credential_string(auth_hrn),) ) + hrn_credentials.append( (auth_hrn, 'auth', self.authority_credential_string(auth_hrn),) ) for slice_hrn in my_slices: - hrn_credentials.append ( (slice_hrn, 'slice', self.slice_credential_string (slice_hrn),) ) + try: + hrn_credentials.append( (slice_hrn, 'slice', self.slice_credential_string(slice_hrn),) ) + except: + print("WARNING: could not get slice credential for slice {}" + .format(slice_hrn)) # (e) check for the delegated version of these # xxx todo add an option -a/-A? like for 'sfi delegate' for when we ever # switch to myslice using an authority instead of a user - delegatee_type='user' - delegatee_hrn=myslice_dict['delegate'] + delegatee_type = 'user' + delegatee_hrn = myslice_dict['delegate'] hrn_delegated_credentials = [] for (hrn, htype, credential) in hrn_credentials: - delegated_credential = 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, + filename = os.path.join( self.options.sfi_dir, "{}.{}_for_{}.{}.cred"\ .format(hrn, htype, delegatee_hrn, delegatee_type)) - with file(filename,'w') as f: + with open(filename, 'w') as f: f.write(delegated_credential) self.logger.debug("(Over)wrote {}".format(filename)) - hrn_delegated_credentials.append ((hrn, htype, delegated_credential, 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 self.logger.info("Uploading on backend at {}".format(myslice_dict['backend'])) - uploader = ManifoldUploader (logger=self.logger, + uploader = ManifoldUploader(logger=self.logger, url=myslice_dict['backend'], platform=myslice_dict['platform'], username=myslice_dict['username'], password=options.password) uploader.prompt_all() - (count_all,count_success)=(0,0) - for (hrn,htype,delegated_credential,filename) in hrn_delegated_credentials: + (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="{} ({}) [exp:{}]".format(hrn, htype, expire_datetime) - if uploader.upload(delegated_credential,message=message): - count_success+=1 - count_all+=1 + inspect = Credential(string=delegated_credential) + expire_datetime = inspect.get_expiration() + message = "{} ({}) [exp:{}]".format(hrn, htype, expire_datetime) + if uploader.upload(delegated_credential, message=message): + count_success += 1 + count_all += 1 self.logger.info("Successfully uploaded {}/{} credentials" .format(count_success, count_all)) @@ -1753,17 +1807,18 @@ $ sfi m -b http://mymanifold.foo.com:7080/ # 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) + if count_success != count_all: + sys.exit(1) # xxx should analyze result return 0 - @declare_command("cred","") + @declare_command("cred", "") def trusted(self, options, args): """ return the trusted certs at this interface (get_trusted_certs) """ if options.registry_interface: - server=self.registry() + server = self.registry() else: server = self.sliceapi() cred = self.my_authority_credential_string() @@ -1772,11 +1827,39 @@ $ sfi m -b http://mymanifold.foo.com:7080/ trusted_certs = ReturnValue.get_value(trusted_certs) for trusted_cert in trusted_certs: - print "\n===========================================================\n" + print("\n===========================================================\n") gid = GID(string=trusted_cert) gid.dump() cert = Certificate(string=trusted_cert) self.logger.debug('Sfi.trusted -> {}'.format(cert.get_subject())) - print "Certificate:\n{}\n\n".format(trusted_cert) + print("Certificate:\n{}\n\n".format(trusted_cert)) # xxx should analyze result return 0 + + @declare_command("", "") + def introspect(self, options, args): + """ + If remote server supports XML-RPC instrospection API, allows + to list supported methods + """ + if options.registry_interface: + server = self.registry() + else: + server = self.sliceapi() + results = server.serverproxy.system.listMethods() + # at first sight a list here means it's fine, + # and a dict suggests an error (no support for introspection?) + if isinstance(results, list): + results = [ name for name in results if 'system.' not in name ] + results.sort() + print("== methods supported at {}".format(server.url)) + if 'Discover' in results: + print("== has support for 'Discover' - most likely a v3") + else: + print("== has no support for 'Discover' - most likely a v2") + for name in results: + print(name) + else: + print("Got return of type {}, expected a list".format(type(results))) + print("This suggests the remote end does not support introspection") + print(results)