X-Git-Url: http://git.onelab.eu/?p=sfa.git;a=blobdiff_plain;f=sfa%2Fclient%2Fsfi.py;h=9ed3c9192fb7a659056f5c73cd8ccadacb300a9b;hp=845b2b134092b2dda292cb5ac90518111a79c178;hb=b8596ce95578bf77158db2a5dacbaab36bdf6b16;hpb=d58bbc6238ee07a3e386b2627aa64ccb2dce352f diff --git a/sfa/client/sfi.py b/sfa/client/sfi.py old mode 100755 new mode 100644 index 845b2b13..9ed3c919 --- a/sfa/client/sfi.py +++ b/sfa/client/sfi.py @@ -1,12 +1,13 @@ -#! /usr/bin/env python - -# sfi -- slice-based facility interface +# +# sfi.py - basic SFA command-line client +# the actual binary in sfa/clientbin essentially runs main() +# this module is used in sfascan +# import sys sys.path.append('.') import os, os.path -import tempfile import socket import datetime import codecs @@ -14,6 +15,7 @@ import pickle from lxml import etree from StringIO import StringIO from optparse import OptionParser +from pprint import PrettyPrinter from sfa.trust.certificate import Keypair, Certificate from sfa.trust.gid import GID @@ -31,12 +33,12 @@ from sfa.storage.record import SfaRecord, UserRecord, SliceRecord, NodeRecord, A from sfa.rspecs.rspec import RSpec from sfa.rspecs.rspec_converter import RSpecConverter from sfa.rspecs.version_manager import VersionManager -from sfa.client.return_value import ReturnValue -import sfa.client.xmlrpcprotocol as xmlrpcprotocol +from sfa.client.sfaclientlib import SfaClientBootstrap +from sfa.client.sfaserverproxy import SfaServerProxy, ServerException from sfa.client.client_helper import pg_users_arg, sfa_users_arg +from sfa.client.return_value import ReturnValue -AGGREGATE_PORT=12346 CM_PORT=12346 # utility methods here @@ -165,6 +167,13 @@ class Sfi: required_options=['verbose', 'debug', 'registry', 'sm', 'auth', 'user'] + @staticmethod + def default_sfi_dir (): + if os.path.isfile("./sfi_config"): + return os.getcwd() + else: + return os.path.expanduser("~/.sfi/") + # dummy to meet Sfi's expectations for its 'options' field # i.e. s/t we can do setattr on class DummyOptions: @@ -174,66 +183,78 @@ class Sfi: 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=os.path.expanduser("~/.sfi/") - # xxx oops, this is dangerous, sounds like ww sometimes have discrepency - # would be safer to remove self.sfi_dir altogether - self.sfi_dir = options.sfi_dir + if not hasattr(options,'sfi_dir'): options.sfi_dir=Sfi.default_sfi_dir() self.options = options - self.slicemgr = None - self.registry = None self.user = None self.authority = None - self.hashrequest = False self.logger = sfi_logger self.logger.enable_console() + self.available_names = [ tuple[0] for tuple in Sfi.available ] + self.available_dict = dict (Sfi.available) - def create_cmd_parser(self, command, additional_cmdargs=None): - cmdargs = {"list": "authority", - "show": "name", - "remove": "name", - "add": "record", - "update": "record", - "aggregates": "[name]", - "registries": "[name]", - "create_gid": "[name]", - "get_gid": [], - "get_trusted_certs": "cred", - "slices": "", - "resources": "[name]", - "create": "name rspec", - "get_ticket": "name rspec", - "redeem_ticket": "ticket", - "delete": "name", - "reset": "name", - "start": "name", - "stop": "name", - "delegate": "name", - "status": "name", - "renew": "name", - "shutdown": "name", - "version": "", - } - - if additional_cmdargs: - cmdargs.update(additional_cmdargs) - - if command not in cmdargs: + # tuples command-name expected-args in the order in which they should appear in the help + available = [ + ("version", ""), + ("list", "authority"), + ("show", "name"), + ("add", "record"), + ("update", "record"), + ("remove", "name"), + ("slices", ""), + ("resources", "[slice_hrn]"), + ("create", "slice_hrn rspec"), + ("delete", "slice_hrn"), + ("status", "slice_hrn"), + ("start", "slice_hrn"), + ("stop", "slice_hrn"), + ("reset", "slice_hrn"), + ("renew", "slice_hrn time"), + ("shutdown", "slice_hrn"), + ("get_ticket", "slice_hrn rspec"), + ("redeem_ticket", "ticket"), + ("delegate", "name"), + ("create_gid", "[name]"), + ("get_trusted_certs", "cred"), + ] + + def print_command_help (self, options): + verbose=getattr(options,'verbose') + format3="%18s %-15s %s" + line=80*'-' + if not verbose: + print format3%("command","cmd_args","description") + print line + else: + print line + self.create_parser().print_help() + for command in self.available_names: + args=self.available_dict[command] + method=getattr(self,command,None) + doc="" + if method: doc=getattr(method,'__doc__',"") + if not doc: doc="*** no doc found ***" + doc=doc.strip(" \t\n") + doc=doc.replace("\n","\n"+35*' ') + if verbose: + print line + print format3%(command,args,doc) + if verbose: + self.create_command_parser(command).print_help() + + def create_command_parser(self, command): + if command not in self.available_dict: msg="Invalid command\n" msg+="Commands: " - msg += ','.join(cmdargs.keys()) + msg += ','.join(self.available_names) self.logger.critical(msg) sys.exit(2) - parser = OptionParser(usage="sfi [sfi_options] %s [options] %s" \ - % (command, cmdargs[command])) + parser = OptionParser(usage="sfi [sfi_options] %s [cmd_options] %s" \ + % (command, self.available_dict[command])) # user specifies remote aggregate/sm/component if command in ("resources", "slices", "create", "delete", "start", "stop", "restart", "shutdown", "get_ticket", "renew", "status"): - parser.add_option("-a", "--aggregate", dest="aggregate", - default=None, help="aggregate host") - parser.add_option("-p", "--port", dest="port", - default=AGGREGATE_PORT, help="aggregate port") parser.add_option("-c", "--component", dest="component", default=None, help="component hrn") parser.add_option("-d", "--delegate", dest="delegate", default=None, @@ -288,13 +309,9 @@ class Sfi: help="delegate slice credential", metavar="HRN", default=None) if command in ("version"): - parser.add_option("-a", "--aggregate", dest="aggregate", - default=None, help="aggregate host") - parser.add_option("-p", "--port", dest="port", - default=AGGREGATE_PORT, help="aggregate port") parser.add_option("-R","--registry-version", action="store_true", dest="version_registry", default=False, - help="probe registry version instead of slicemgr") + 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") @@ -305,16 +322,15 @@ class Sfi: def create_parser(self): # Generate command line parser - parser = OptionParser(usage="sfi [options] command [command_options] [command_args]", - description="Commands: gid,list,show,remove,add,update,nodes,slices,resources,create,delete,start,stop,reset") + parser = OptionParser(usage="sfi [sfi_options] command [cmd_options] [cmd_args]", + description="Commands: %s"%(" ".join(self.available_names))) parser.add_option("-r", "--registry", dest="registry", help="root registry", metavar="URL", default=None) - parser.add_option("-s", "--slicemgr", dest="sm", - help="slice manager", metavar="URL", default=None) - default_sfi_dir = os.path.expanduser("~/.sfi/") + parser.add_option("-s", "--sliceapi", dest="sm", default=None, metavar="URL", + help="slice API - in general a SM URL, but can be used to talk to an aggregate") parser.add_option("-d", "--dir", dest="sfi_dir", - help="config & working directory - default is " + default_sfi_dir, - metavar="PATH", default=default_sfi_dir) + help="config & working directory - default is %default", + metavar="PATH", default=Sfi.default_sfi_dir()) parser.add_option("-u", "--user", dest="user", help="user name", metavar="HRN", default=None) parser.add_option("-a", "--auth", dest="auth", @@ -324,91 +340,221 @@ class Sfi: parser.add_option("-D", "--debug", action="store_true", dest="debug", default=False, help="Debug (xml-rpc) protocol messages") - parser.add_option("-p", "--protocol", dest="protocol", default="xmlrpc", - help="RPC protocol (xmlrpc or soap)") - parser.add_option("-k", "--hashrequest", - action="store_true", dest="hashrequest", default=False, - help="Create a hash of the request that will be authenticated on the server") + # would it make sense to use ~/.ssh/id_rsa as a default here ? + parser.add_option("-k", "--private-key", + action="store", dest="user_private_key", default=None, + help="point to the private key file to use if not yet installed in sfi_dir") parser.add_option("-t", "--timeout", dest="timeout", default=None, - help="Amout of time tom wait before timing out the request") + help="Amout of time to wait before timing out the request") + parser.add_option("-?", "--commands", + action="store_true", dest="command_help", default=False, + help="one page summary on commands & exit") parser.disable_interspersed_args() return parser - def read_config(self): - config_file = os.path.join(self.options.sfi_dir,"sfi_config") - try: - config = Config (config_file) - except: - self.logger.critical("Failed to read configuration file %s"%config_file) - self.logger.info("Make sure to remove the export clauses and to add quotes") - 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 %s"%config_file) - sys.exit(1) - - errors = 0 - # Set SliceMgr URL - if (self.options.sm is not None): - self.sm_url = self.options.sm - elif hasattr(config, "SFI_SM"): - self.sm_url = config.SFI_SM - else: - self.logger.error("You need to set e.g. SFI_SM='http://your.slicemanager.url:12347/' in %s" % config_file) - errors += 1 + def print_help (self): + self.sfi_parser.print_help() + self.command_parser.print_help() + + # + # Main: parse arguments and dispatch to command + # + def dispatch(self, command, command_options, command_args): + return getattr(self, command)(command_options, command_args) + + def main(self): + self.sfi_parser = self.create_parser() + (options, args) = self.sfi_parser.parse_args() + if options.command_help: + self.print_command_help(options) + sys.exit(1) + self.options = options + + self.logger.setLevelFromOptVerbose(self.options.verbose) + + if len(args) <= 0: + self.logger.critical("No command given. Use -h for help.") + self.print_command_help(options) + return -1 - # Set Registry URL - if (self.options.registry is not None): - self.reg_url = self.options.registry - elif hasattr(config, "SFI_REGISTRY"): - self.reg_url = config.SFI_REGISTRY - else: - self.logger.errors("You need to set e.g. SFI_REGISTRY='http://your.registry.url:12345/' in %s" % config_file) - errors += 1 - - - # Set user HRN - if (self.options.user is not None): - self.user = self.options.user - elif hasattr(config, "SFI_USER"): - self.user = config.SFI_USER - else: - self.logger.errors("You need to set e.g. SFI_USER='plc.princeton.username' in %s" % config_file) - errors += 1 + command = args[0] + self.command_parser = self.create_command_parser(command) + (command_options, command_args) = self.command_parser.parse_args(args[1:]) + self.command_options = command_options + + self.read_config () + self.bootstrap () + self.logger.info("Command=%s" % command) + + try: + self.dispatch(command, command_options, command_args) + except KeyError: + self.logger.critical ("Unknown command %s"%command) + raise + sys.exit(1) - # Set authority HRN - if (self.options.auth is not None): - self.authority = self.options.auth - elif hasattr(config, "SFI_AUTH"): - self.authority = config.SFI_AUTH - else: - self.logger.error("You need to set e.g. SFI_AUTH='plc.princeton' in %s" % config_file) - errors += 1 + return - if errors: - sys.exit(1) + #################### + def read_config(self): + config_file = os.path.join(self.options.sfi_dir,"sfi_config") + try: + config = Config (config_file) + except: + self.logger.critical("Failed to read configuration file %s"%config_file) + self.logger.info("Make sure to remove the export clauses and to add quotes") + 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 %s"%config_file) + sys.exit(1) + + errors = 0 + # Set SliceMgr URL + if (self.options.sm is not None): + self.sm_url = self.options.sm + elif hasattr(config, "SFI_SM"): + self.sm_url = config.SFI_SM + else: + self.logger.error("You need to set e.g. SFI_SM='http://your.slicemanager.url:12347/' in %s" % config_file) + errors += 1 + + # Set Registry URL + if (self.options.registry is not None): + self.reg_url = self.options.registry + elif hasattr(config, "SFI_REGISTRY"): + self.reg_url = config.SFI_REGISTRY + else: + self.logger.errors("You need to set e.g. SFI_REGISTRY='http://your.registry.url:12345/' in %s" % config_file) + errors += 1 + + # Set user HRN + if (self.options.user is not None): + self.user = self.options.user + elif hasattr(config, "SFI_USER"): + self.user = config.SFI_USER + else: + self.logger.errors("You need to set e.g. SFI_USER='plc.princeton.username' in %s" % config_file) + errors += 1 + + # Set authority HRN + if (self.options.auth is not None): + self.authority = self.options.auth + elif hasattr(config, "SFI_AUTH"): + self.authority = config.SFI_AUTH + else: + self.logger.error("You need to set e.g. SFI_AUTH='plc.princeton' in %s" % config_file) + errors += 1 + if errors: + sys.exit(1) # - # Establish Connection to SliceMgr and Registry Servers + # Get various credential and spec files + # + # Establishes limiting conventions + # - conflates MAs and SAs + # - assumes last token in slice name is unique + # + # Bootstraps credentials + # - bootstrap user credential from self-signed certificate + # - bootstrap authority credential from user credential + # - bootstrap slice credential from user credential # - def set_servers(self): - - self.read_config() - # Get key and certificate - key_file = self.get_key_file() - cert_file = self.get_cert_file(key_file) - self.key = Keypair(filename=key_file) - self.key_file = key_file - self.cert_file = cert_file - self.cert = GID(filename=cert_file) - self.logger.info("Contacting Registry at: %s"%self.reg_url) - self.registry = xmlrpcprotocol.server_proxy(self.reg_url, key_file, cert_file, timeout=self.options.timeout, verbose=self.options.debug) - self.logger.info("Contacting Slice Manager at: %s"%self.sm_url) - self.slicemgr = xmlrpcprotocol.server_proxy(self.sm_url, key_file, cert_file, timeout=self.options.timeout, verbose=self.options.debug) - return + + # init self-signed cert, user credentials and gid + def bootstrap (self): + bootstrap = SfaClientBootstrap (self.user, self.reg_url, self.options.sfi_dir) + # if -k is provided, use this to initialize private key + if self.options.user_private_key: + 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(bootstrap.private_key_filename()): + self.logger.info ("private key not found, trying legacy name") + try: + legacy_private_key = os.path.join (self.options.sfi_dir, "%s.pkey"%get_leaf(self.user)) + self.logger.debug("legacy_private_key=%s"%legacy_private_key) + bootstrap.init_private_key_if_missing (legacy_private_key) + self.logger.info("Copied private key from legacy location %s"%legacy_private_key) + except: + self.logger.log_exc("Can't find private key ") + sys.exit(1) + + # make it bootstrap + bootstrap.bootstrap_my_gid() + # extract what's needed + self.private_key = bootstrap.private_key() + self.my_credential_string = bootstrap.my_credential_string () + self.my_gid = bootstrap.my_gid () + self.bootstrap = bootstrap + + + def my_authority_credential_string(self): + if not self.authority: + self.logger.critical("no authority specified. Use -a or set SF_AUTH") + sys.exit(-1) + return self.bootstrap.authority_credential_string (self.authority) + + def slice_credential_string(self, name): + return self.bootstrap.slice_credential_string (name) + + # xxx should be supported by sfaclientbootstrap as well + def delegate_cred(self, object_cred, hrn, type='authority'): + # the gid and hrn of the object we are delegating + if isinstance(object_cred, str): + object_cred = Credential(string=object_cred) + object_gid = object_cred.get_gid_object() + object_hrn = object_gid.get_hrn() + + if not object_cred.get_privileges().get_all_delegate(): + self.logger.error("Object credential %s does not have delegate bit set"%object_hrn) + return + + # the delegating user's gid + caller_gidfile = self.my_gid() + + # the gid of the user who will be delegated to + delegee_gid = self.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) + + # + # Management of the servers + # + + def registry (self): + # cache the result + if not hasattr (self, 'registry_proxy'): + self.logger.info("Contacting Registry at: %s"%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): + # cache the result + 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: + # resolve the hrn at the registry + node_hrn = self.command_options.component + records = self.registry().Resolve(node_hrn, self.my_credential_string) + records = filter_records('node', records) + if not records: + self.logger.warning("No such component:%r"% opts.component) + record = records[0] + cm_url = "http://%s:%d/"%(record['hostname'],CM_PORT) + 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 + self.logger.info("Contacting Slice Manager at: %s"%self.sm_url) + self.sliceapi_proxy = SfaServerProxy(self.sm_url, self.private_key, self.my_gid, + timeout=self.options.timeout, verbose=self.options.debug) + return self.sliceapi_proxy def get_cached_server_version(self, server): # check local cache first @@ -428,193 +574,56 @@ class Sfi: if not version: result = server.GetVersion() version= ReturnValue.get_value(result) - # cache version for 24 hours - cache.add(cache_key, version, ttl= 60*60*24) + # cache version for 20 minutes + cache.add(cache_key, version, ttl= 60*20) self.logger.info("Updating cache file %s" % cache_file) cache.save_to_file(cache_file) return version - + ### resurrect this temporarily so we can support V1 aggregates for a while def server_supports_options_arg(self, server): """ Returns true if server support the optional call_id arg, false otherwise. """ server_version = self.get_cached_server_version(server) + result = False + # xxx need to rewrite this + if int(server_version.get('geni_api')) >= 2: + result = True + return result + + def server_supports_call_id_arg(self, server): + server_version = self.get_cached_server_version(server) + result = False if 'sfa' in server_version and 'code_tag' in server_version: code_tag = server_version['code_tag'] code_tag_parts = code_tag.split("-") - version_parts = code_tag_parts[0].split(".") major, minor = version_parts[0], version_parts[1] rev = code_tag_parts[1] - if int(major) >= 1: - if int(minor) >= 2: - return True - return False - - # - # Get various credential and spec files - # - # Establishes limiting conventions - # - conflates MAs and SAs - # - assumes last token in slice name is unique - # - # Bootstraps credentials - # - bootstrap user credential from self-signed certificate - # - bootstrap authority credential from user credential - # - bootstrap slice credential from user credential - # - - - def get_key_file(self): - file = os.path.join(self.options.sfi_dir, self.user.replace(self.authority + '.', '') + ".pkey") - if (os.path.isfile(file)): - return file - else: - self.logger.error("Key file %s does not exist"%file) - sys.exit(-1) - return - - def get_cert_file(self, key_file): - - cert_file = os.path.join(self.options.sfi_dir, self.user.replace(self.authority + '.', '') + ".cert") - if (os.path.isfile(cert_file)): - # we'd perfer to use Registry issued certs instead of self signed certs. - # if this is a Registry cert (GID) then we are done - gid = GID(filename=cert_file) - if gid.get_urn(): - return cert_file - - # generate self signed certificate - k = Keypair(filename=key_file) - cert = Certificate(subject=self.user) - cert.set_pubkey(k) - cert.set_issuer(k, self.user) - cert.sign() - self.logger.info("Writing self-signed certificate to %s"%cert_file) - cert.save_to_file(cert_file) - self.cert = cert - # try to get registry issued cert - try: - self.logger.info("Getting Registry issued cert") - self.read_config() - # *hack. need to set registyr before _get_gid() is called - self.registry = xmlrpcprotocol.server_proxy(self.reg_url, key_file, cert_file, timeout=self.options.timeout, verbose=self.options.debug) - gid = self._get_gid(type='user') - self.registry = None - self.logger.info("Writing certificate to %s"%cert_file) - gid.save_to_file(cert_file) - except: - self.logger.info("Failed to download Registry issued cert") - - return cert_file - - def get_cached_gid(self, file): - """ - Return a cached gid - """ - gid = None - if (os.path.isfile(file)): - gid = GID(filename=file) - return gid - - # xxx opts unused - def get_gid(self, opts, args): - """ - Get the specify gid and save it to file - """ - hrn = None - if args: - hrn = args[0] - gid = self._get_gid(hrn) - self.logger.debug("Sfi.get_gid-> %s" % gid.save_to_string(save_parents=True)) - return gid - - def _get_gid(self, hrn=None, type=None): - """ - git_gid helper. Retrive the gid from the registry and save it to file. - """ - - if not hrn: - hrn = self.user - - gidfile = os.path.join(self.options.sfi_dir, hrn + ".gid") - gid = self.get_cached_gid(gidfile) - if not gid: - user_cred = self.get_user_cred() - records = self.registry.Resolve(hrn, user_cred.save_to_string(save_parents=True)) - if not records: - raise RecordNotFound(args[0]) - record = records[0] - if type: - record=None - for rec in records: - if type == rec['type']: - record = rec - if not record: - raise RecordNotFound(args[0]) - - gid = GID(string=record['gid']) - self.logger.info("Writing gid to %s"%gidfile) - gid.save_to_file(filename=gidfile) - return gid - - - def get_cached_credential(self, file): - """ - Return a cached credential only if it hasn't expired. - """ - if (os.path.isfile(file)): - credential = Credential(filename=file) - # make sure it isnt expired - if not credential.get_expiration or \ - datetime.datetime.today() < credential.get_expiration(): - return credential - return None - - def get_user_cred(self): - file = os.path.join(self.options.sfi_dir, self.user.replace(self.authority + '.', '') + ".cred") - return self.get_cred(file, 'user', self.user) - - def get_auth_cred(self): - if not self.authority: - self.logger.critical("no authority specified. Use -a or set SF_AUTH") - sys.exit(-1) - file = os.path.join(self.options.sfi_dir, self.authority + ".cred") - return self.get_cred(file, 'authority', self.authority) - - def get_slice_cred(self, name): - file = os.path.join(self.options.sfi_dir, "slice_" + get_leaf(name) + ".cred") - return self.get_cred(file, 'slice', name) - - def get_cred(self, file, type, hrn): - # attempt to load a cached credential - cred = self.get_cached_credential(file) - if not cred: - if type in ['user']: - cert_string = self.cert.save_to_string(save_parents=True) - user_name = self.user.replace(self.authority + ".", '') - if user_name.count(".") > 0: - user_name = user_name.replace(".", '_') - self.user = self.authority + "." + user_name - cred_str = self.registry.GetSelfCredential(cert_string, hrn, "user") - else: - # bootstrap slice credential from user credential - user_cred = self.get_user_cred().save_to_string(save_parents=True) - cred_str = self.registry.GetCredential(user_cred, hrn, type) - - if not cred_str: - self.logger.critical("Failed to get %s credential" % type) - sys.exit(-1) - - cred = Credential(string=cred_str) - cred.save_to_file(file, save_parents=True) - self.logger.info("Writing %s credential to %s" %(type, file)) + if int(major) == 1 and minor == 0 and build >= 22: + result = True + 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): + return [option_dict] + 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): + return [ unique_call_id ] + else: + return [] - return cred - - + ######################################## miscell utilities def get_rspec_file(self, rspec): if (os.path.isabs(rspec)): file = rspec @@ -637,115 +646,66 @@ class Sfi: self.logger.critical("No such registry record file %s"%record) sys.exit(1) - def load_publickey_string(self, fn): - f = file(fn, "r") - key_string = f.read() - - # if the filename is a private key file, then extract the public key - if "PRIVATE KEY" in key_string: - outfn = tempfile.mktemp() - cmd = "openssl rsa -in " + fn + " -pubout -outform PEM -out " + outfn - os.system(cmd) - f = file(outfn, "r") - key_string = f.read() - os.remove(outfn) - - return key_string - - # xxx opts undefined - def get_component_proxy_from_hrn(self, hrn): - # direct connection to the nodes component manager interface - user_cred = self.get_user_cred().save_to_string(save_parents=True) - records = self.registry.Resolve(hrn, user_cred) - records = filter_records('node', records) - if not records: - self.logger.warning("No such component:%r"% opts.component) - record = records[0] - - return self.server_proxy(record['hostname'], CM_PORT, self.key_file, self.cert_file) - - def server_proxy(self, host, port, keyfile, certfile): - """ - Return an instance of an xmlrpc server connection - """ - # port is appended onto the domain, before the path. Should look like: - # http://domain:port/path - host_parts = host.split('/') - host_parts[0] = host_parts[0] + ":" + str(port) - url = "http://%s" % "/".join(host_parts) - return xmlrpcprotocol.server_proxy(url, keyfile, certfile, timeout=self.options.timeout, verbose=self.options.debug) - - # xxx opts could be retrieved in self.options - def server_proxy_from_opts(self, opts): - """ - Return instance of an xmlrpc connection to a slice manager, aggregate - or component server depending on the specified opts - """ - server = self.slicemgr - # direct connection to an aggregate - if hasattr(opts, 'aggregate') and opts.aggregate: - server = self.server_proxy(opts.aggregate, opts.port, self.key_file, self.cert_file) - # direct connection to the nodes component manager interface - if hasattr(opts, 'component') and opts.component: - server = self.get_component_proxy_from_hrn(opts.component) - - return server + #========================================================================== # Following functions implement the commands # # Registry-related commands #========================================================================== - def dispatch(self, command, cmd_opts, cmd_args): - return getattr(self, command)(cmd_opts, cmd_args) - - def create_gid(self, opts, args): - if len(args) < 1: - self.print_help() - sys.exit(1) - target_hrn = args[0] - user_cred = self.get_user_cred().save_to_string(save_parents=True) - gid = self.registry.CreateGid(user_cred, target_hrn, self.cert.save_to_string()) - if opts.file: - filename = opts.file + def version(self, options, args): + """ + display an SFA server version (GetVersion) +or version information about sfi itself + """ + if options.version_local: + version=version_core() else: - filename = os.sep.join([self.sfi_dir, '%s.gid' % target_hrn]) - self.logger.info("writing %s gid to %s" % (target_hrn, filename)) - GID(string=gid).save_to_file(filename) - - - # list entires in named authority registry - def list(self, opts, args): + if options.version_registry: + server=self.registry() + else: + server = self.sliceapi() + result = server.GetVersion() + version = ReturnValue.get_value(result) + pprinter = PrettyPrinter(indent=4) + pprinter.pprint(version) + if options.file: + save_variable_to_file(version, options.file, options.fileformat) + + def list(self, options, args): + """ + list entries in named authority registry (List) + """ if len(args)!= 1: self.print_help() sys.exit(1) hrn = args[0] - user_cred = self.get_user_cred().save_to_string(save_parents=True) try: - list = self.registry.List(hrn, user_cred) + list = self.registry().List(hrn, self.my_credential_string) except IndexError: 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(opts.type, list) + list = filter_records(options.type, list) for record in list: print "%s (%s)" % (record['hrn'], record['type']) - if opts.file: - save_records_to_file(opts.file, list, opts.fileformat) + if options.file: + save_records_to_file(options.file, list, options.fileformat) return - # show named registry record - def show(self, opts, args): + def show(self, options, args): + """ + show details about named registry record (Resolve) + """ if len(args)!= 1: self.print_help() sys.exit(1) hrn = args[0] - user_cred = self.get_user_cred().save_to_string(save_parents=True) - records = self.registry.Resolve(hrn, user_cred) - records = filter_records(opts.type, records) + records = self.registry().Resolve(hrn, self.my_credential_string) + records = filter_records(options.type, records) if not records: - print "No record of type", opts.type + self.logger.error("No record of type %s"% options.type) for record in records: if record['type'] in ['user']: record = UserRecord(dict=record) @@ -757,491 +717,479 @@ class Sfi: record = AuthorityRecord(dict=record) else: record = SfaRecord(dict=record) - if (opts.format == "text"): + if (options.format == "text"): record.dump() else: print record.save_to_string() - if opts.file: - save_records_to_file(opts.file, records, opts.fileformat) + if options.file: + save_records_to_file(options.file, records, options.fileformat) return - def delegate(self, opts, args): - - delegee_hrn = args[0] - if opts.delegate_user: - user_cred = self.get_user_cred() - cred = self.delegate_cred(user_cred, delegee_hrn) - elif opts.delegate_slice: - slice_cred = self.get_slice_cred(opts.delegate_slice) - cred = self.delegate_cred(slice_cred, delegee_hrn) - else: - self.logger.warning("Must specify either --user or --slice ") - return - delegated_cred = Credential(string=cred) - object_hrn = delegated_cred.get_gid_object().get_hrn() - if opts.delegate_user: - dest_fn = os.path.join(self.options.sfi_dir, get_leaf(delegee_hrn) + "_" - + get_leaf(object_hrn) + ".cred") - elif opts.delegate_slice: - dest_fn = os.path.join(self.options.sfi_dir, get_leaf(delegee_hrn) + "_slice_" - + get_leaf(object_hrn) + ".cred") - - delegated_cred.save_to_file(dest_fn, save_parents=True) - - self.logger.info("delegated credential for %s to %s and wrote to %s"%(object_hrn, delegee_hrn,dest_fn)) - - def delegate_cred(self, object_cred, hrn): - # the gid and hrn of the object we are delegating - if isinstance(object_cred, str): - object_cred = Credential(string=object_cred) - object_gid = object_cred.get_gid_object() - object_hrn = object_gid.get_hrn() - - if not object_cred.get_privileges().get_all_delegate(): - self.logger.error("Object credential %s does not have delegate bit set"%object_hrn) - return - - # the delegating user's gid - caller_gid = self._get_gid(self.user) - caller_gidfile = os.path.join(self.options.sfi_dir, self.user + ".gid") - - # the gid of the user who will be delegated to - delegee_gid = self._get_gid(hrn) - delegee_hrn = delegee_gid.get_hrn() - delegee_gidfile = os.path.join(self.options.sfi_dir, delegee_hrn + ".gid") - delegee_gid.save_to_file(filename=delegee_gidfile) - dcred = object_cred.delegate(delegee_gidfile, self.get_key_file(), caller_gidfile) - return dcred.save_to_string(save_parents=True) - - # removed named registry record - # - have to first retrieve the record to be removed - def remove(self, opts, args): - auth_cred = self.get_auth_cred().save_to_string(save_parents=True) - if len(args)!=1: - self.print_help() - sys.exit(1) - hrn = args[0] - type = opts.type - if type in ['all']: - type = '*' - return self.registry.Remove(hrn, auth_cred, type) - - # add named registry record - def add(self, opts, args): - auth_cred = self.get_auth_cred().save_to_string(save_parents=True) + def add(self, options, args): + "add record into registry from xml file (Register)" + auth_cred = self.my_authority_credential_string() if len(args)!=1: self.print_help() sys.exit(1) record_filepath = args[0] rec_file = self.get_record_file(record_filepath) record = load_record_from_file(rec_file).as_dict() - return self.registry.Register(record, auth_cred) + return self.registry().Register(record, auth_cred) - # update named registry entry - def update(self, opts, args): - user_cred = self.get_user_cred() + def update(self, options, args): + "update record into registry from xml file (Update)" if len(args)!=1: self.print_help() sys.exit(1) rec_file = self.get_record_file(args[0]) record = load_record_from_file(rec_file) if record['type'] == "user": - if record.get_name() == user_cred.get_gid_object().get_hrn(): - cred = user_cred.save_to_string(save_parents=True) + if record.get_name() == self.user: + cred = self.my_credential_string else: - cred = self.get_auth_cred().save_to_string(save_parents=True) + cred = self.my_authority_credential_string() elif record['type'] in ["slice"]: try: - cred = self.get_slice_cred(record.get_name()).save_to_string(save_parents=True) - except xmlrpcprotocol.ServerException, e: + cred = self.slice_credential_string(record.get_name()) + except ServerException, 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]: - cred = self.get_auth_cred().save_to_string(save_parents=True) + cred = self.my_authority_credential_string() else: raise elif record.get_type() in ["authority"]: - cred = self.get_auth_cred().save_to_string(save_parents=True) + cred = self.my_authority_credential_string() elif record.get_type() == 'node': - cred = self.get_auth_cred().save_to_string(save_parents=True) + cred = self.my_authority_credential_string() else: raise "unknown record type" + record.get_type() record = record.as_dict() - return self.registry.Update(record, cred) + return self.registry().Update(record, cred) - def get_trusted_certs(self, opts, args): - """ - return uhe trusted certs at this interface - """ - trusted_certs = self.registry.get_trusted_certs() - for trusted_cert in trusted_certs: - gid = GID(string=trusted_cert) - gid.dump() - cert = Certificate(string=trusted_cert) - self.logger.debug('Sfi.get_trusted_certs -> %r'%cert.get_subject()) - return - - def aggregates(self, opts, args): - """ - return a list of details about known aggregates - """ - user_cred = self.get_user_cred().save_to_string(save_parents=True) - hrn = None - if args: - hrn = args[0] - - result = self.registry.get_aggregates(user_cred, hrn) - display_list(result) - return - - def registries(self, opts, args): - """ - return a list of details about known registries - """ - user_cred = self.get_user_cred().save_to_string(save_parents=True) - hrn = None - if args: - hrn = args[0] - result = self.registry.get_registries(user_cred, hrn) - display_list(result) - return - - + def remove(self, options, args): + "remove registry record by name (Remove)" + auth_cred = self.my_authority_credential_string() + if len(args)!=1: + self.print_help() + sys.exit(1) + hrn = args[0] + type = options.type + if type in ['all']: + type = '*' + return self.registry().Remove(hrn, auth_cred, type) + # ================================================================== # Slice-related commands # ================================================================== - def version(self, opts, args): - if opts.version_local: - version=version_core() - else: - if opts.version_registry: - server=self.registry - else: - server = self.server_proxy_from_opts(opts) - result = server.GetVersion() - version = ReturnValue.get_value(result) - for (k,v) in version.iteritems(): - print "%-20s: %s"%(k,v) - if opts.file: - save_variable_to_file(version, opts.file, opts.fileformat) - - # list instantiated slices - def slices(self, opts, args): - """ - list instantiated slices - """ - user_cred = self.get_user_cred().save_to_string(save_parents=True) - creds = [user_cred] - if opts.delegate: - delegated_cred = self.delegate_cred(user_cred, get_authority(self.authority)) + def slices(self, options, args): + "list instantiated slices (ListSlices) - returns urn's" + server = self.sliceapi() + # creds + creds = [self.my_credential_string] + if options.delegate: + delegated_cred = self.delegate_cred(self.my_credential_string, get_authority(self.authority)) creds.append(delegated_cred) - server = self.server_proxy_from_opts(opts) - call_args = [creds] - if self.server_supports_options_arg(server): - options = {'call_id': unique_call_id()} - call_args.append(options) - result = server.ListSlices(*call_args) + # options and call_id when supported + api_options = {} + api_options['call_id']=unique_call_id() + result = server.ListSlices(creds, *self.ois(server,api_options)) value = ReturnValue.get_value(result) display_list(value) return # show rspec for named slice - def resources(self, opts, args): - user_cred = self.get_user_cred().save_to_string(save_parents=True) - server = self.slicemgr - server = self.server_proxy_from_opts(opts) - - options = {'call_id': unique_call_id()} - #panos add info options - if opts.info: - options['info'] = opts.info - + def resources(self, options, args): + """ + with no arg, discover available resources, (ListResources) +or with an slice hrn, shows currently provisioned resources + """ + server = self.sliceapi() + + # set creds + creds = [] if args: - cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True) - hrn = args[0] - options['geni_slice_urn'] = hrn_to_urn(hrn, 'slice') + creds.append(self.slice_credential_string(args[0])) else: - cred = user_cred - - creds = [cred] - if opts.delegate: - delegated_cred = self.delegate_cred(cred, get_authority(self.authority)) - creds.append(delegated_cred) - if opts.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 - options['geni_rspec_version'] = version_manager.get_version(opts.rspec_version).to_dict() + creds.append(self.my_credential_string) + if options.delegate: + creds.append(self.delegate_cred(cred, get_authority(self.authority))) + + # V2 API + if self.server_supports_options_arg(server): + # with v2 everything goes in options inclusing the subject slice + api_options = {} + if args: + hrn = args[0] + api_options['geni_slice_urn'] = hrn_to_urn(hrn, 'slice') + if options.info: + api_options['info'] = options.info + 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: + # this must be a protogeni aggregate. We should request a v2 ad rspec + # regardless of what the client user requested + api_options['geni_rspec_version'] = version_manager.get_version('ProtoGENI 2').to_dict() else: - # this must be a protogeni aggregate. We should request a v2 ad rspec - # regardless of what the client user requested - options['geni_rspec_version'] = version_manager.get_version('ProtoGENI 2').to_dict() + api_options['geni_rspec_version'] = {'type': 'geni', 'version': '3.0'} + # always send call_id to v2 servers + api_options ['call_id'] = unique_call_id() + # the V2 form + result = server.ListResources (creds, api_options) + # V1 else: - options['geni_rspec_version'] = {'type': 'geni', 'version': '3.0'} - - call_args = [creds, options] - result = server.ListResources(*call_args) + # with an argument + if args: + hrn = args[0] + # xxx looks like we can pass a hrn and not a urn here ?? + # last arg. is a raw call_id when supported + result = server.ListResources (creds, hrn, *self.cis(server)) + else: + result = server.ListResources (creds, *self.cis(server)) value = ReturnValue.get_value(result) - if opts.file is None: - display_rspec(value, opts.format) + if options.file is None: + display_rspec(value, options.format) else: - save_rspec_to_file(value, opts.file) + save_rspec_to_file(value, options.file) return - # created named slice with given rspec - def create(self, opts, args): - server = self.server_proxy_from_opts(opts) - server_version = self.get_cached_server_version(server) + def create(self, options, args): + """ + create or update named slice with given rspec + """ + server = self.sliceapi() + + # xxx do we need to check usage (len(args)) ? + # slice urn slice_hrn = args[0] slice_urn = hrn_to_urn(slice_hrn, 'slice') - user_cred = self.get_user_cred() - slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True) - - if hasattr(opts, 'aggregate') and opts.aggregate: - delegated_cred = None - else: - # delegate the cred to the callers root authority - delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority)+'.slicemanager') - #delegated_cred = self.delegate_cred(slice_cred, get_authority(slice_hrn)) - #creds.append(delegated_cred) + # credentials + creds = [self.slice_credential_string(slice_hrn)] + delegated_cred = None + server_version = self.get_cached_server_version(server) + if server_version.get('interface') == 'slicemgr': + # delegate our cred to the slice manager + # do not delegate cred to slicemgr...not working at the moment + pass + #if server_version.get('hrn'): + # delegated_cred = self.delegate_cred(slice_cred, server_version['hrn']) + #elif server_version.get('urn'): + # delegated_cred = self.delegate_cred(slice_cred, urn_to_hrn(server_version['urn'])) + + # rspec rspec_file = self.get_rspec_file(args[1]) rspec = open(rspec_file).read() + # users # need to pass along user keys to the aggregate. # users = [ # { urn: urn:publicid:IDN+emulab.net+user+alice # keys: [, ] # }] users = [] - slice_records = self.registry.Resolve(slice_urn, [user_cred.save_to_string(save_parents=True)]) + 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']!=[]: slice_record = slice_records[0] user_hrns = slice_record['researcher'] user_urns = [hrn_to_urn(hrn, 'user') for hrn in user_hrns] - user_records = self.registry.Resolve(user_urns, [user_cred.save_to_string(save_parents=True)]) + user_records = self.registry().Resolve(user_urns, [self.my_credential_string]) if 'sfa' not in server_version: users = pg_users_arg(user_records) rspec = RSpec(rspec) rspec.filter({'component_manager_id': server_version['urn']}) rspec = RSpecConverter.to_pg_rspec(rspec.toxml(), content_type='request') - creds = [slice_cred] else: + print >>sys.stderr, "\r\n \r\n \r\n WOOOOOO" users = sfa_users_arg(user_records, slice_record) - creds = [slice_cred] - if delegated_cred: - creds.append(delegated_cred) - call_args = [slice_urn, creds, rspec, users] - if self.server_supports_options_arg(server): - options = {'call_id': unique_call_id()} - call_args.append(options) - result = server.CreateSliver(*call_args) + + # do not append users, keys, or slice tags. Anything + # not contained in this request will be removed from the slice + + # CreateSliver has supported the options argument for a while now so it should + # be safe to assume this server support it + api_options = {} + api_options ['append'] = False + api_options ['call_id'] = unique_call_id() + + result = server.CreateSliver(slice_urn, creds, rspec, users, *self.ois(server, api_options)) value = ReturnValue.get_value(result) - if opts.file is None: + if options.file is None: print value else: - save_rspec_to_file (value, opts.file) + save_rspec_to_file (value, options.file) return value - # get a ticket for the specified slice - def get_ticket(self, opts, args): - slice_hrn, rspec_path = args[0], args[1] - slice_urn = hrn_to_urn(slice_hrn, 'slice') - user_cred = self.get_user_cred() - slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True) + def delete(self, options, args): + """ + delete named slice (DeleteSliver) + """ + server = self.sliceapi() + + # slice urn + slice_hrn = args[0] + slice_urn = hrn_to_urn(slice_hrn, 'slice') + + # creds + slice_cred = self.slice_credential_string(slice_hrn) creds = [slice_cred] - if opts.delegate: + if options.delegate: delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority)) creds.append(delegated_cred) - rspec_file = self.get_rspec_file(rspec_path) - rspec = open(rspec_file).read() - server = self.server_proxy_from_opts(opts) - ticket_string = server.GetTicket(slice_urn, creds, rspec, []) - file = os.path.join(self.options.sfi_dir, get_leaf(slice_hrn) + ".ticket") - self.logger.info("writing ticket to %s"%file) - ticket = SfaTicket(string=ticket_string) - ticket.save_to_file(filename=file, save_parents=True) - - def redeem_ticket(self, opts, args): - ticket_file = args[0] - # get slice hrn from the ticket - # use this to get the right slice credential - ticket = SfaTicket(filename=ticket_file) - ticket.decode() - slice_hrn = ticket.gidObject.get_hrn() - slice_urn = hrn_to_urn(slice_hrn, 'slice') - #slice_hrn = ticket.attributes['slivers'][0]['hrn'] - user_cred = self.get_user_cred() - slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True) - - # get a list of node hostnames from the RSpec - tree = etree.parse(StringIO(ticket.rspec)) - root = tree.getroot() - hostnames = root.xpath("./network/site/node/hostname/text()") - - # create an xmlrpc connection to the component manager at each of these - # components and gall redeem_ticket - connections = {} - for hostname in hostnames: - try: - self.logger.info("Calling redeem_ticket at %(hostname)s " % locals()) - server = self.server_proxy(hostname, CM_PORT, self.key_file, \ - self.cert_file, self.options.debug) - server.RedeemTicket(ticket.save_to_string(save_parents=True), slice_cred) - self.logger.info("Success") - except socket.gaierror: - self.logger.error("redeem_ticket failed: Component Manager not accepting requests") - except Exception, e: - self.logger.log_exc(e.message) - return - - # delete named slice - def delete(self, opts, args): + # options and call_id when supported + api_options = {} + api_options ['call_id'] = unique_call_id() + result = server.DeleteSliver(slice_urn, creds, *self.ois(server, api_options ) ) + # xxx no ReturnValue ?? + return result + + def status(self, options, args): + """ + retrieve slice status (SliverStatus) + """ + server = self.sliceapi() + + # slice urn slice_hrn = args[0] slice_urn = hrn_to_urn(slice_hrn, 'slice') - slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True) + + # creds + slice_cred = self.slice_credential_string(slice_hrn) creds = [slice_cred] - if opts.delegate: + if options.delegate: delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority)) creds.append(delegated_cred) - server = self.server_proxy_from_opts(opts) - call_args = [slice_urn, creds] - if self.server_supports_options_arg(server): - options = {'call_id': unique_call_id()} - call_args.append(options) - return server.DeleteSliver(*call_args) - - # start named slice - def start(self, opts, args): + + # options and call_id when supported + api_options = {} + api_options['call_id']=unique_call_id() + result = server.SliverStatus(slice_urn, creds, *self.ois(server,api_options)) + value = ReturnValue.get_value(result) + print value + if options.file: + save_variable_to_file(value, options.file, options.fileformat) + + def start(self, options, args): + """ + start named slice (Start) + """ + server = self.sliceapi() + + # the slice urn slice_hrn = args[0] slice_urn = hrn_to_urn(slice_hrn, 'slice') - slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True) + + # cred + slice_cred = self.slice_credential_string(args[0]) creds = [slice_cred] - if opts.delegate: + if options.delegate: delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority)) creds.append(delegated_cred) - server = self.server_proxy_from_opts(opts) + # xxx Thierry - does this not need an api_options as well ? return server.Start(slice_urn, creds) - # stop named slice - def stop(self, opts, args): + def stop(self, options, args): + """ + stop named slice (Stop) + """ + server = self.sliceapi() + # slice urn slice_hrn = args[0] slice_urn = hrn_to_urn(slice_hrn, 'slice') - slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True) + # cred + slice_cred = self.slice_credential_string(args[0]) creds = [slice_cred] - if opts.delegate: + if options.delegate: delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority)) creds.append(delegated_cred) - server = self.server_proxy_from_opts(opts) return server.Stop(slice_urn, creds) # reset named slice - def reset(self, opts, args): + def reset(self, options, args): + """ + reset named slice (reset_slice) + """ + server = self.sliceapi() + # slice urn slice_hrn = args[0] slice_urn = hrn_to_urn(slice_hrn, 'slice') - server = self.server_proxy_from_opts(opts) - slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True) + # cred + slice_cred = self.slice_credential_string(args[0]) creds = [slice_cred] - if opts.delegate: + if options.delegate: delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority)) creds.append(delegated_cred) return server.reset_slice(creds, slice_urn) - def renew(self, opts, args): + def renew(self, options, args): + """ + renew slice (RenewSliver) + """ + server = self.sliceapi() + # slice urn slice_hrn = args[0] slice_urn = hrn_to_urn(slice_hrn, 'slice') - server = self.server_proxy_from_opts(opts) - slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True) + # creds + slice_cred = self.slice_credential_string(args[0]) creds = [slice_cred] - if opts.delegate: + if options.delegate: delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority)) creds.append(delegated_cred) + # time time = args[1] - - call_args = [slice_urn, creds, time] - if self.server_supports_options_arg(server): - options = {'call_id': unique_call_id()} - call_args.append(options) - result = server.RenewSliver(*call_args) + # options and call_id when supported + api_options = {} + api_options['call_id']=unique_call_id() + result = server.RenewSliver(slice_urn, creds, time, *self.ois(server,api_options)) value = ReturnValue.get_value(result) return value - def status(self, opts, args): + def shutdown(self, options, args): + """ + shutdown named slice (Shutdown) + """ + server = self.sliceapi() + # slice urn slice_hrn = args[0] slice_urn = hrn_to_urn(slice_hrn, 'slice') - slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True) + # creds + slice_cred = self.slice_credential_string(slice_hrn) creds = [slice_cred] - if opts.delegate: + if options.delegate: delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority)) creds.append(delegated_cred) - server = self.server_proxy_from_opts(opts) - call_args = [slice_urn, creds] - if self.server_supports_options_arg(server): - options = {'call_id': unique_call_id()} - call_args.append(options) - result = server.SliverStatus(*call_args) - value = ReturnValue.get_value(result) - print value - if opts.file: - save_variable_to_file(value, opts.file, opts.fileformat) - + return server.Shutdown(slice_urn, creds) + - def shutdown(self, opts, args): - slice_hrn = args[0] - slice_urn = hrn_to_urn(slice_hrn, 'slice') - slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True) + def get_ticket(self, options, args): + """ + get a ticket for the specified slice + """ + server = self.sliceapi() + # slice urn + slice_hrn, rspec_path = args[0], args[1] + slice_urn = hrn_to_urn(slice_hrn, 'slice') + # creds + slice_cred = self.slice_credential_string(slice_hrn) creds = [slice_cred] - if opts.delegate: + if options.delegate: delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority)) creds.append(delegated_cred) - server = self.server_proxy_from_opts(opts) - return server.Shutdown(slice_urn, creds) - - def print_help (self): - self.sfi_parser.print_help() - self.cmd_parser.print_help() - - # - # Main: parse arguments and dispatch to command - # - def main(self): - self.sfi_parser = self.create_parser() - (options, args) = self.sfi_parser.parse_args() - self.options = options + # rspec + rspec_file = self.get_rspec_file(rspec_path) + rspec = open(rspec_file).read() + # options and call_id when supported + api_options = {} + api_options['call_id']=unique_call_id() + # get ticket at the server + ticket_string = server.GetTicket(slice_urn, creds, rspec, *self.ois(server,api_options)) + # save + file = os.path.join(self.options.sfi_dir, get_leaf(slice_hrn) + ".ticket") + self.logger.info("writing ticket to %s"%file) + ticket = SfaTicket(string=ticket_string) + ticket.save_to_file(filename=file, save_parents=True) - self.logger.setLevelFromOptVerbose(self.options.verbose) - if options.hashrequest: - self.hashrequest = True - - if len(args) <= 0: - self.logger.critical("No command given. Use -h for help.") - return -1 - - command = args[0] - self.cmd_parser = self.create_cmd_parser(command) - (cmd_opts, cmd_args) = self.cmd_parser.parse_args(args[1:]) + def redeem_ticket(self, options, args): + """ + Connects to nodes in a slice and redeems a ticket +(slice hrn is retrieved from the ticket) + """ + ticket_file = args[0] + + # get slice hrn from the ticket + # use this to get the right slice credential + ticket = SfaTicket(filename=ticket_file) + ticket.decode() + ticket_string = ticket.save_to_string(save_parents=True) - self.set_servers() - self.logger.info("Command=%s" % command) - if command in ("resources"): - self.logger.debug("resources cmd_opts %s" % cmd_opts.format) - elif command in ("list", "show", "remove"): - self.logger.debug("cmd_opts.type %s" % cmd_opts.type) - self.logger.debug('cmd_args %s' % cmd_args) + slice_hrn = ticket.gidObject.get_hrn() + slice_urn = hrn_to_urn(slice_hrn, 'slice') + #slice_hrn = ticket.attributes['slivers'][0]['hrn'] + slice_cred = self.slice_credential_string(slice_hrn) + + # get a list of node hostnames from the RSpec + tree = etree.parse(StringIO(ticket.rspec)) + root = tree.getroot() + hostnames = root.xpath("./network/site/node/hostname/text()") + + # create an xmlrpc connection to the component manager at each of these + # components and gall redeem_ticket + connections = {} + for hostname in hostnames: + try: + self.logger.info("Calling redeem_ticket at %(hostname)s " % locals()) + cm_url="http://%s:%s/"%(hostname,CM_PORT) + server = SfaServerProxy(cm_url, self.private_key, self.my_gid) + server = self.server_proxy(hostname, CM_PORT, self.private_key, + timeout=self.options.timeout, verbose=self.options.debug) + server.RedeemTicket(ticket_string, slice_cred) + self.logger.info("Success") + except socket.gaierror: + self.logger.error("redeem_ticket failed on %s: Component Manager not accepting requests"%hostname) + except Exception, e: + self.logger.log_exc(e.message) + return - try: - self.dispatch(command, cmd_opts, cmd_args) - except KeyError: - self.logger.critical ("Unknown command %s"%command) - raise + def create_gid(self, options, args): + """ + Create a GID (CreateGid) + """ + if len(args) < 1: + self.print_help() sys.exit(1) + target_hrn = args[0] + gid = self.registry().CreateGid(self.my_credential_string, target_hrn, self.bootstrap.my_gid_string()) + if options.file: + filename = options.file + else: + filename = os.sep.join([self.options.sfi_dir, '%s.gid' % target_hrn]) + self.logger.info("writing %s gid to %s" % (target_hrn, filename)) + GID(string=gid).save_to_file(filename) + + + def delegate(self, options, args): + """ + (locally) create delegate credential for use by given hrn + """ + delegee_hrn = args[0] + if options.delegate_user: + cred = self.delegate_cred(self.my_credential_string, delegee_hrn, 'user') + elif options.delegate_slice: + slice_cred = self.slice_credential_string(options.delegate_slice) + cred = self.delegate_cred(slice_cred, delegee_hrn, 'slice') + else: + self.logger.warning("Must specify either --user or --slice ") + return + delegated_cred = Credential(string=cred) + object_hrn = delegated_cred.get_gid_object().get_hrn() + if options.delegate_user: + dest_fn = os.path.join(self.options.sfi_dir, get_leaf(delegee_hrn) + "_" + + get_leaf(object_hrn) + ".cred") + elif options.delegate_slice: + dest_fn = os.path.join(self.options.sfi_dir, get_leaf(delegee_hrn) + "_slice_" + + get_leaf(object_hrn) + ".cred") + + delegated_cred.save_to_file(dest_fn, save_parents=True) + + self.logger.info("delegated credential for %s to %s and wrote to %s"%(object_hrn, delegee_hrn,dest_fn)) - return - -if __name__ == "__main__": - Sfi().main() + def get_trusted_certs(self, options, args): + """ + return uhe trusted certs at this interface (get_trusted_certs) + """ + trusted_certs = self.registry().get_trusted_certs() + for trusted_cert in trusted_certs: + gid = GID(string=trusted_cert) + gid.dump() + cert = Certificate(string=trusted_cert) + self.logger.debug('Sfi.get_trusted_certs -> %r'%cert.get_subject()) + return +