def _reformat_low(self, low): """ Format the low data for RunnerClient()'s master_call() function The master_call function here has a different function signature than on WheelClient. So extract all the eauth keys and the fun key and assume everything else is a kwarg to pass along to the runner function to be called. """ auth_creds = dict([(i, low.pop(i)) for i in ["username", "password", "eauth", "token", "client"] if i in low]) fun = low.pop("fun") reformatted_low = {"fun": fun} reformatted_low.update(auth_creds) # Support old style calls where arguments could be specified in 'low' top level if not low.get("args") and not low.get("kwargs"): # not specified or empty verify_fun(self.functions, fun) args, kwargs = salt.minion.load_args_and_kwargs( self.functions[fun], salt.utils.args.condition_input([], low), self.opts, ignore_invalid=True ) low["args"] = args low["kwargs"] = kwargs if "kwargs" not in low: low["kwargs"] = {} if "args" not in low: low["args"] = [] reformatted_low["kwarg"] = low return reformatted_low
def _reformat_low(self, low): ''' Format the low data for RunnerClient()'s master_call() function The master_call function here has a different function signature than on WheelClient. So extract all the eauth keys and the fun key and assume everything else is a kwarg to pass along to the runner function to be called. ''' auth_creds = dict([(i, low.pop(i)) for i in [ 'username', 'password', 'eauth', 'token', 'client', 'user', 'key' ] if i in low]) fun = low.pop('fun') reformatted_low = {'fun': fun} reformatted_low.update(auth_creds) # Support old style calls where arguments could be specified in 'low' top level if not low.get('arg') and not low.get( 'kwarg'): # not specified or empty verify_fun(self.functions, fun) merged_args_kwargs = salt.utils.args.condition_input([], low) parsed_input = salt.utils.args.parse_input(merged_args_kwargs) args, kwargs = salt.minion.load_args_and_kwargs( self.functions[fun], parsed_input, self.opts, ignore_invalid=True) low['arg'] = args low['kwarg'] = kwargs if 'kwarg' not in low: low['kwarg'] = {} if 'arg' not in low: low['arg'] = [] reformatted_low['kwarg'] = low return reformatted_low
def _reformat_low(self, low): ''' Format the low data for RunnerClient()'s master_call() function The master_call function here has a different function signature than on WheelClient. So extract all the eauth keys and the fun key and assume everything else is a kwarg to pass along to the runner function to be called. ''' auth_creds = dict([(i, low.pop(i)) for i in [ 'username', 'password', 'eauth', 'token', 'client', 'user', 'key' ] if i in low]) fun = low.pop('fun') reformatted_low = {'fun': fun} reformatted_low.update(auth_creds) # Support old style calls where arguments could be specified in 'low' top level if not low.get('arg') and not low.get('kwarg'): # not specified or empty verify_fun(self.functions, fun) merged_args_kwargs = salt.utils.args.condition_input([], low) parsed_input = salt.utils.args.parse_input(merged_args_kwargs) args, kwargs = salt.minion.load_args_and_kwargs( self.functions[fun], parsed_input, self.opts, ignore_invalid=True ) low['arg'] = args low['kwarg'] = kwargs if 'kwarg' not in low: low['kwarg'] = {} if 'arg' not in low: low['arg'] = [] reformatted_low['kwarg'] = low return reformatted_low
def _reformat_low(self, low): ''' Format the low data for RunnerClient()'s master_call() function This also normalizes the following low data formats to a single, common low data structure. Old-style low: ``{'fun': 'jobs.lookup_jid', 'jid': '1234'}`` New-style: ``{'fun': 'jobs.lookup_jid', 'kwarg': {'jid': '1234'}}`` CLI-style: ``{'fun': 'jobs.lookup_jid', 'arg': ['jid="1234"']}`` ''' fun = low.pop(u'fun') verify_fun(self.functions, fun) eauth_creds = dict([(i, low.pop(i)) for i in [ u'username', u'password', u'eauth', u'token', u'client', u'user', u'key', ] if i in low]) # Run name=value args through parse_input. We don't need to run kwargs # through because there is no way to send name=value strings in the low # dict other than by including an `arg` array. _arg, _kwarg = salt.utils.args.parse_input(low.pop(u'arg', []), condition=False) _kwarg.update(low.pop(u'kwarg', {})) # If anything hasn't been pop()'ed out of low by this point it must be # an old-style kwarg. _kwarg.update(low) # Finally, mung our kwargs to a format suitable for the byzantine # load_args_and_kwargs so that we can introspect the function being # called and fish for invalid kwargs. munged = [] munged.extend(_arg) munged.append(dict(__kwarg__=True, **_kwarg)) arg, kwarg = salt.minion.load_args_and_kwargs(self.functions[fun], munged, self.opts, ignore_invalid=True) return dict(fun=fun, kwarg={ u'kwarg': kwarg, u'arg': arg }, **eauth_creds)
def run(self): ''' Execute the runner sequence ''' ret, async_pub = {}, {} if self.opts.get('doc', False): self.print_docs() else: low = {'fun': self.opts['fun']} try: verify_fun(self.functions, low['fun']) args, kwargs = salt.minion.load_args_and_kwargs( self.functions[low['fun']], salt.utils.args.parse_input(self.opts['arg']), self.opts, ) low['arg'] = args low['kwarg'] = kwargs user = salt.utils.get_specific_user() # Run the runner! if self.opts.get('async', False): async_pub = self. async (self.opts['fun'], low, user=user) # by default: info will be not enougth to be printed out ! log.warning( 'Running in async mode. Results of this execution may ' 'be collected by attaching to the master event bus or ' 'by examing the master job cache, if configured. ' 'This execution is running under tag {tag}'.format( **async_pub)) return async_pub['jid'] # return the jid # otherwise run it in the main process async_pub = self._gen_async_pub() ret = self._proc_function(self.opts['fun'], low, user, async_pub['tag'], async_pub['jid'], daemonize=False) except salt.exceptions.SaltException as exc: ret = '{0}'.format(exc) if not self.opts.get('quiet', False): display_output(ret, 'nested', self.opts) return ret log.debug('Runner return: {0}'.format(ret)) return ret
def run(self): ''' Execute the runner sequence ''' ret, async_pub = {}, {} if self.opts.get('doc', False): self.print_docs() else: low = {'fun': self.opts['fun']} try: verify_fun(self.functions, low['fun']) args, kwargs = salt.minion.load_args_and_kwargs( self.functions[low['fun']], salt.utils.args.parse_input(self.opts['arg']), self.opts, ) low['args'] = args low['kwargs'] = kwargs user = salt.utils.get_specific_user() # Run the runner! if self.opts.get('async', False): async_pub = self.async(self.opts['fun'], low, user=user) # by default: info will be not enougth to be printed out ! log.warn('Running in async mode. Results of this execution may ' 'be collected by attaching to the master event bus or ' 'by examing the master job cache, if configured. ' 'This execution is running under tag {tag}'.format(**async_pub)) return async_pub['jid'] # return the jid # otherwise run it in the main process async_pub = self._gen_async_pub() ret = self._proc_function(self.opts['fun'], low, user, async_pub['tag'], async_pub['jid'], False) # Don't daemonize except salt.exceptions.SaltException as exc: ret = '{0}'.format(exc) if not self.opts.get('quiet', False): salt.output.display_output(ret, 'nested', self.opts) return ret log.debug('Runner return: {0}'.format(ret)) return ret
def _reformat_low(self, low): ''' Format the low data for RunnerClient()'s master_call() function This also normalizes the following low data formats to a single, common low data structure. Old-style low: ``{'fun': 'jobs.lookup_jid', 'jid': '1234'}`` New-style: ``{'fun': 'jobs.lookup_jid', 'kwarg': {'jid': '1234'}}`` CLI-style: ``{'fun': 'jobs.lookup_jid', 'arg': ['jid="1234"']}`` ''' fun = low.pop('fun') verify_fun(self.functions, fun) reserved_kwargs = dict([(i, low.pop(i)) for i in [ 'username', 'password', 'eauth', 'token', 'client', 'user', 'key', '__current_eauth_groups', '__current_eauth_user', ] if i in low]) # Run name=value args through parse_input. We don't need to run kwargs # through because there is no way to send name=value strings in the low # dict other than by including an `arg` array. arg, kwarg = salt.utils.args.parse_input(low.pop('arg', []), condition=False, no_parse=self.opts.get( 'no_parse', [])) kwarg.update(low.pop('kwarg', {})) # If anything hasn't been pop()'ed out of low by this point it must be # an old-style kwarg. kwarg.update(low) return dict(fun=fun, kwarg={ 'kwarg': kwarg, 'arg': arg }, **reserved_kwargs)
def run(self): """ Execute the runner sequence """ ret, async_pub = {}, {} if self.opts.get("doc", False): self.print_docs() else: low = {"fun": self.opts["fun"]} try: verify_fun(self.functions, low["fun"]) args, kwargs = salt.minion.load_args_and_kwargs( self.functions[low["fun"]], salt.utils.args.parse_input(self.opts["arg"]), self.opts ) low["args"] = args low["kwargs"] = kwargs user = salt.utils.get_specific_user() # Run the runner! if self.opts.get("async", False): async_pub = self.async(self.opts["fun"], low, user=user) # by default: info will be not enougth to be printed out ! log.warn( "Running in async mode. Results of this execution may " "be collected by attaching to the master event bus or " "by examing the master job cache, if configured. " "This execution is running under tag {tag}".format(**async_pub) ) return async_pub["jid"] # return the jid # otherwise run it in the main process async_pub = self._gen_async_pub() ret = self._proc_function( self.opts["fun"], low, user, async_pub["tag"], async_pub["jid"], False ) # Don't daemonize except salt.exceptions.SaltException as exc: ret = "{0}".format(exc) if not self.opts.get("quiet", False): display_output(ret, "nested", self.opts) return ret log.debug("Runner return: {0}".format(ret)) return ret
def _reformat_low(self, low): ''' Format the low data for RunnerClient()'s master_call() function This also normalizes the following low data formats to a single, common low data structure. Old-style low: ``{'fun': 'jobs.lookup_jid', 'jid': '1234'}`` New-style: ``{'fun': 'jobs.lookup_jid', 'kwarg': {'jid': '1234'}}`` CLI-style: ``{'fun': 'jobs.lookup_jid', 'arg': ['jid="1234"']}`` ''' fun = low.pop('fun') verify_fun(self.functions, fun) eauth_creds = dict([(i, low.pop(i)) for i in [ 'username', 'password', 'eauth', 'token', 'client', 'user', 'key', ] if i in low]) # Separate the new-style args/kwargs. pre_arg = low.pop('arg', []) pre_kwarg = low.pop('kwarg', {}) # Anything not pop'ed from low should hopefully be an old-style kwarg. low['__kwarg__'] = True pre_kwarg.update(low) # Normalize old- & new-style args in a format suitable for # load_args_and_kwargs old_new_normalized_input = [] old_new_normalized_input.extend(pre_arg) old_new_normalized_input.append(pre_kwarg) arg, kwarg = salt.minion.load_args_and_kwargs(self.functions[fun], old_new_normalized_input, self.opts, ignore_invalid=True) return dict(fun=fun, kwarg={'kwarg': kwarg, 'arg': arg}, **eauth_creds)
def _low(self, fun, low): ''' Execute a function from low data Low data includes: required: - fun: the name of the function to run optional: - args: a list of args to pass to fun - kwargs: kwargs for fun - __user__: user who is running the command - __jid__: jid to run under - __tag__: tag to run under ''' # fire the mminion loading (if not already done) here # this is not to clutter the output with the module loading # if we have a high debug level. self.mminion # pylint: disable=W0104 jid = low.get('__jid__', salt.utils.jid.gen_jid()) tag = low.get('__tag__', tagify(jid, prefix=self.tag_prefix)) data = { 'fun': '{0}.{1}'.format(self.client, fun), 'jid': jid, 'user': low.get('__user__', 'UNKNOWN'), } event = salt.utils.event.get_event('master', self.opts['sock_dir'], self.opts['transport'], opts=self.opts, listen=False) namespaced_event = salt.utils.event.NamespacedEvent( event, tag, print_func=self.print_async_event if hasattr( self, 'print_async_event') else None) # TODO: document these, and test that they exist # TODO: Other things to inject?? func_globals = { '__jid__': jid, '__user__': data['user'], '__tag__': tag, # weak ref to avoid the Exception in interpreter # teardown of event '__jid_event__': weakref.proxy(namespaced_event), } func_globals['__jid_event__'].fire_event(data, 'new') try: verify_fun(self.functions, fun) # Inject some useful globals to *all* the function's global # namespace only once per module-- not per func completed_funcs = [] for mod_name in six.iterkeys(self.functions): if '.' not in mod_name: continue mod, _ = mod_name.split('.', 1) if mod in completed_funcs: continue completed_funcs.append(mod) for global_key, value in six.iteritems(func_globals): self.functions[mod_name].__globals__[global_key] = value # There are some descrepencies of what a "low" structure is in the # publisher world it is a dict including stuff such as jid, fun, # arg (a list of args, with kwargs packed in). Historically this # particular one has had no "arg" and just has had all the kwargs # packed into the top level object. The plan is to move away from # that since the caller knows what is an arg vs a kwarg, but while # we make the transition we will load "kwargs" using format_call if # there are no kwargs in the low object passed in f_call = None if 'arg' not in low: f_call = salt.utils.format_call( self.functions[fun], low, expected_extra_kws=CLIENT_INTERNAL_KEYWORDS) args = f_call.get('arg', ()) else: args = low['arg'] if 'kwarg' not in low: if f_call is None: f_call = salt.utils.format_call( self.functions[fun], low, expected_extra_kws=CLIENT_INTERNAL_KEYWORDS) kwargs = f_call.get('kwarg', {}) # throw a warning for the badly formed low data if we found # kwargs using the old mechanism if kwargs: salt.utils.warn_until( 'Carbon', 'kwargs must be passed inside the low under "kwargs"') else: kwargs = low['kwarg'] # Initialize a context for executing the method. with tornado.stack_context.StackContext( self.functions.context_dict.clone): data['return'] = self.functions[fun](*args, **kwargs) data['success'] = True except (Exception, SystemExit) as ex: if isinstance(ex, salt.exceptions.NotImplemented): data['return'] = str(ex) else: data['return'] = 'Exception occurred in {0} {1}: {2}'.format( self.client, fun, traceback.format_exc(), ) data['success'] = False namespaced_event.fire_event(data, 'ret') try: salt.utils.job.store_job( self.opts, { 'id': self.opts['id'], 'tgt': self.opts['id'], 'jid': data['jid'], 'return': data, }, event=None, mminion=self.mminion, ) except salt.exceptions.SaltCacheError: log.error( 'Could not store job cache info. Job details for this run may be unavailable.' ) # if we fired an event, make sure to delete the event object. # This will ensure that we call destroy, which will do the 0MQ linger log.info('Runner completed: {0}'.format(data['jid'])) del event del namespaced_event return data['return']
def run(self): """ Execute the runner sequence """ import salt.minion ret = {} if self.opts.get("doc", False): self.print_docs() else: low = {"fun": self.opts["fun"]} try: # Allocate a jid async_pub = self._gen_async_pub() self.jid = async_pub["jid"] fun_args = salt.utils.args.parse_input(self.opts["arg"], no_parse=self.opts.get( "no_parse", [])) verify_fun(self.functions, low["fun"]) args, kwargs = salt.minion.load_args_and_kwargs( self.functions[low["fun"]], fun_args) low["arg"] = args low["kwarg"] = kwargs if self.opts.get("eauth"): if "token" in self.opts: try: with salt.utils.files.fopen( os.path.join(self.opts["cachedir"], ".root_key"), "r") as fp_: low["key"] = salt.utils.stringutils.to_unicode( fp_.readline()) except IOError: low["token"] = self.opts["token"] # If using eauth and a token hasn't already been loaded into # low, prompt the user to enter auth credentials if "token" not in low and "key" not in low and self.opts[ "eauth"]: # This is expensive. Don't do it unless we need to. import salt.auth resolver = salt.auth.Resolver(self.opts) res = resolver.cli(self.opts["eauth"]) if self.opts["mktoken"] and res: tok = resolver.token_cli(self.opts["eauth"], res) if tok: low["token"] = tok.get("token", "") if not res: log.error("Authentication failed") return ret low.update(res) low["eauth"] = self.opts["eauth"] else: user = salt.utils.user.get_specific_user() if low["fun"] in [ "state.orchestrate", "state.orch", "state.sls" ]: low["kwarg"]["orchestration_jid"] = async_pub["jid"] # Run the runner! if self.opts.get("async", False): if self.opts.get("eauth"): async_pub = self.cmd_async(low) else: async_pub = self.asynchronous(self.opts["fun"], low, user=user, pub=async_pub) # by default: info will be not enougth to be printed out ! log.warning( "Running in asynchronous mode. Results of this execution may " "be collected by attaching to the master event bus or " "by examing the master job cache, if configured. " "This execution is running under tag %s", async_pub["tag"], ) return async_pub["jid"] # return the jid # otherwise run it in the main process if self.opts.get("eauth"): ret = self.cmd_sync(low) if isinstance(ret, dict) and set(ret) == {"data", "outputter"}: outputter = ret["outputter"] ret = ret["data"] else: outputter = None display_output(ret, outputter, self.opts) else: ret = self._proc_function( self.opts["fun"], low, user, async_pub["tag"], async_pub["jid"], daemonize=False, ) except salt.exceptions.SaltException as exc: with salt.utils.event.get_event("master", opts=self.opts) as evt: evt.fire_event( { "success": False, "return": "{0}".format(exc), "retcode": 254, "fun": self.opts["fun"], "fun_args": fun_args, "jid": self.jid, }, tag="salt/run/{0}/ret".format(self.jid), ) # Attempt to grab documentation if "fun" in low: ret = self.get_docs("{0}*".format(low["fun"])) else: ret = None # If we didn't get docs returned then # return the `not availble` message. if not ret: ret = "{0}".format(exc) if not self.opts.get("quiet", False): display_output(ret, "nested", self.opts) else: log.debug("Runner return: %s", ret) return ret
def run(self): ''' Execute the runner sequence ''' import salt.minion ret = {} if self.opts.get('doc', False): self.print_docs() else: low = {'fun': self.opts['fun']} try: verify_fun(self.functions, low['fun']) args, kwargs = salt.minion.load_args_and_kwargs( self.functions[low['fun']], salt.utils.args.parse_input(self.opts['arg']), self.opts, ) low['arg'] = args low['kwarg'] = kwargs if self.opts.get('eauth'): if 'token' in self.opts: try: with salt.utils.fopen( os.path.join(self.opts['cachedir'], '.root_key'), 'r') as fp_: low['key'] = fp_.readline() except IOError: low['token'] = self.opts['token'] # If using eauth and a token hasn't already been loaded into # low, prompt the user to enter auth credentials if 'token' not in low and 'key' not in low and self.opts[ 'eauth']: # This is expensive. Don't do it unless we need to. import salt.auth resolver = salt.auth.Resolver(self.opts) res = resolver.cli(self.opts['eauth']) if self.opts['mktoken'] and res: tok = resolver.token_cli(self.opts['eauth'], res) if tok: low['token'] = tok.get('token', '') if not res: log.error('Authentication failed') return ret low.update(res) low['eauth'] = self.opts['eauth'] else: user = salt.utils.get_specific_user() # Allocate a jid async_pub = self._gen_async_pub() self.jid = async_pub['jid'] if low['fun'] == 'state.orchestrate': low['kwarg']['orchestration_jid'] = async_pub['jid'] # Run the runner! if self.opts.get('async', False): if self.opts.get('eauth'): async_pub = self.cmd_async(low) else: async_pub = self. async (self.opts['fun'], low, user=user, pub=async_pub) # by default: info will be not enougth to be printed out ! log.warning( 'Running in async mode. Results of this execution may ' 'be collected by attaching to the master event bus or ' 'by examing the master job cache, if configured. ' 'This execution is running under tag {tag}'.format( **async_pub)) return async_pub['jid'] # return the jid # otherwise run it in the main process if self.opts.get('eauth'): ret = self.cmd_sync(low) if isinstance(ret, dict) and set(ret) == set( ('data', 'outputter')): outputter = ret['outputter'] ret = ret['data'] else: outputter = None display_output(ret, outputter, self.opts) else: ret = self._proc_function(self.opts['fun'], low, user, async_pub['tag'], async_pub['jid'], daemonize=False) except salt.exceptions.SaltException as exc: ret = '{0}'.format(exc) if not self.opts.get('quiet', False): display_output(ret, 'nested', self.opts) else: log.debug('Runner return: {0}'.format(ret)) return ret
def run(self): ''' Execute the runner sequence ''' import salt.minion ret = {} if self.opts.get('doc', False): self.print_docs() else: low = {'fun': self.opts['fun']} try: # Allocate a jid async_pub = self._gen_async_pub() self.jid = async_pub['jid'] fun_args = salt.utils.args.parse_input(self.opts['arg'], no_parse=self.opts.get( 'no_parse', [])) verify_fun(self.functions, low['fun']) args, kwargs = salt.minion.load_args_and_kwargs( self.functions[low['fun']], fun_args) low['arg'] = args low['kwarg'] = kwargs if self.opts.get('eauth'): if 'token' in self.opts: try: with salt.utils.files.fopen( os.path.join(self.opts['cachedir'], '.root_key'), 'r') as fp_: low['key'] = salt.utils.stringutils.to_unicode( fp_.readline()) except IOError: low['token'] = self.opts['token'] # If using eauth and a token hasn't already been loaded into # low, prompt the user to enter auth credentials if 'token' not in low and 'key' not in low and self.opts[ 'eauth']: # This is expensive. Don't do it unless we need to. import salt.auth resolver = salt.auth.Resolver(self.opts) res = resolver.cli(self.opts['eauth']) if self.opts['mktoken'] and res: tok = resolver.token_cli(self.opts['eauth'], res) if tok: low['token'] = tok.get('token', '') if not res: log.error('Authentication failed') return ret low.update(res) low['eauth'] = self.opts['eauth'] else: user = salt.utils.user.get_specific_user() if low['fun'] in [ 'state.orchestrate', 'state.orch', 'state.sls' ]: low['kwarg']['orchestration_jid'] = async_pub['jid'] # Run the runner! if self.opts.get('async', False): if self.opts.get('eauth'): async_pub = self.cmd_async(low) else: async_pub = self.asynchronous(self.opts['fun'], low, user=user, pub=async_pub) # by default: info will be not enougth to be printed out ! log.warning( 'Running in asynchronous mode. Results of this execution may ' 'be collected by attaching to the master event bus or ' 'by examing the master job cache, if configured. ' 'This execution is running under tag %s', async_pub['tag']) return async_pub['jid'] # return the jid # otherwise run it in the main process if self.opts.get('eauth'): ret = self.cmd_sync(low) if isinstance(ret, dict) and set(ret) == set( ('data', 'outputter')): outputter = ret['outputter'] ret = ret['data'] else: outputter = None display_output(ret, outputter, self.opts) else: ret = self._proc_function(self.opts['fun'], low, user, async_pub['tag'], async_pub['jid'], daemonize=False) except salt.exceptions.SaltException as exc: evt = salt.utils.event.get_event('master', opts=self.opts) evt.fire_event( { 'success': False, 'return': '{0}'.format(exc), 'retcode': 254, 'fun': self.opts['fun'], 'fun_args': fun_args, 'jid': self.jid }, tag='salt/run/{0}/ret'.format(self.jid)) # Attempt to grab documentation if 'fun' in low: ret = self.get_docs('{0}*'.format(low['fun'])) else: ret = None # If we didn't get docs returned then # return the `not availble` message. if not ret: ret = '{0}'.format(exc) if not self.opts.get('quiet', False): display_output(ret, 'nested', self.opts) else: log.debug('Runner return: %s', ret) return ret
def low(self, fun, low): ''' Execute a function from low data Low data includes: required: - fun: the name of the function to run optional: - args: a list of args to pass to fun - kwargs: kwargs for fun - __user__: user who is running the command - __jid__: jid to run under - __tag__: tag to run under ''' # fire the mminion loading (if not already done) here # this is not to clutter the output with the module loading # if we have a high debug level. self.mminion # pylint: disable=W0104 jid = low.get('__jid__', salt.utils.jid.gen_jid()) tag = low.get('__tag__', tagify(jid, prefix=self.tag_prefix)) data = {'fun': '{0}.{1}'.format(self.client, fun), 'jid': jid, 'user': low.get('__user__', 'UNKNOWN'), } event = salt.utils.event.get_event( 'master', self.opts['sock_dir'], self.opts['transport'], opts=self.opts, listen=False) namespaced_event = salt.utils.event.NamespacedEvent( event, tag, print_func=self.print_async_event if hasattr(self, 'print_async_event') else None ) # TODO: document these, and test that they exist # TODO: Other things to inject?? func_globals = {'__jid__': jid, '__user__': data['user'], '__tag__': tag, # weak ref to avoid the Exception in interpreter # teardown of event '__jid_event__': weakref.proxy(namespaced_event), } func_globals['__jid_event__'].fire_event(data, 'new') try: verify_fun(self.functions, fun) # Inject some useful globals to *all* the funciton's global # namespace only once per module-- not per func completed_funcs = [] for mod_name in six.iterkeys(self.functions): if '.' not in mod_name: continue mod, _ = mod_name.split('.', 1) if mod in completed_funcs: continue completed_funcs.append(mod) for global_key, value in six.iteritems(func_globals): self.functions[mod_name].__globals__[global_key] = value # There are some descrepencies of what a "low" structure is in the # publisher world it is a dict including stuff such as jid, fun, # arg (a list of args, with kwargs packed in). Historically this # particular one has had no "arg" and just has had all the kwargs # packed into the top level object. The plan is to move away from # that since the caller knows what is an arg vs a kwarg, but while # we make the transition we will load "kwargs" using format_call if # there are no kwargs in the low object passed in f_call = None if 'args' not in low: f_call = salt.utils.format_call( self.functions[fun], low, expected_extra_kws=CLIENT_INTERNAL_KEYWORDS ) args = f_call.get('args', ()) else: args = low['args'] if 'kwargs' not in low: if f_call is None: f_call = salt.utils.format_call( self.functions[fun], low, expected_extra_kws=CLIENT_INTERNAL_KEYWORDS ) kwargs = f_call.get('kwargs', {}) # throw a warning for the badly formed low data if we found # kwargs using the old mechanism if kwargs: salt.utils.warn_until( 'Boron', 'kwargs must be passed inside the low under "kwargs"' ) else: kwargs = low['kwargs'] data['return'] = self.functions[fun](*args, **kwargs) data['success'] = True except (Exception, SystemExit): data['return'] = 'Exception occurred in {0} {1}: {2}'.format( self.client, fun, traceback.format_exc(), ) data['success'] = False namespaced_event.fire_event(data, 'ret') salt.utils.job.store_job( self.opts, {'id': self.opts['id'], 'tgt': self.opts['id'], 'jid': data['jid'], 'return': data, }, event=None, mminion=self.mminion, ) # if we fired an event, make sure to delete the event object. # This will ensure that we call destroy, which will do the 0MQ linger log.info('Runner completed: {0}'.format(data['jid'])) del event del namespaced_event return data['return']
def run(self): ''' Execute the runner sequence ''' import salt.minion ret = {} if self.opts.get('doc', False): self.print_docs() else: low = {'fun': self.opts['fun']} try: verify_fun(self.functions, low['fun']) args, kwargs = salt.minion.load_args_and_kwargs( self.functions[low['fun']], salt.utils.args.parse_input(self.opts['arg']), self.opts, ) low['arg'] = args low['kwarg'] = kwargs if self.opts.get('eauth'): if 'token' in self.opts: try: with salt.utils.fopen(os.path.join(self.opts['cachedir'], '.root_key'), 'r') as fp_: low['key'] = fp_.readline() except IOError: low['token'] = self.opts['token'] # If using eauth and a token hasn't already been loaded into # low, prompt the user to enter auth credentials if 'token' not in low and 'key' not in low and self.opts['eauth']: # This is expensive. Don't do it unless we need to. import salt.auth resolver = salt.auth.Resolver(self.opts) res = resolver.cli(self.opts['eauth']) if self.opts['mktoken'] and res: tok = resolver.token_cli( self.opts['eauth'], res ) if tok: low['token'] = tok.get('token', '') if not res: log.error('Authentication failed') return ret low.update(res) low['eauth'] = self.opts['eauth'] else: user = salt.utils.get_specific_user() # Allocate a jid async_pub = self._gen_async_pub() self.jid = async_pub['jid'] if low['fun'] == 'state.orchestrate': low['kwarg']['orchestration_jid'] = async_pub['jid'] # Run the runner! if self.opts.get('async', False): if self.opts.get('eauth'): async_pub = self.cmd_async(low) else: async_pub = self.async(self.opts['fun'], low, user=user, pub=async_pub) # by default: info will be not enougth to be printed out ! log.warning('Running in async mode. Results of this execution may ' 'be collected by attaching to the master event bus or ' 'by examing the master job cache, if configured. ' 'This execution is running under tag {tag}'.format(**async_pub)) return async_pub['jid'] # return the jid # otherwise run it in the main process if self.opts.get('eauth'): ret = self.cmd_sync(low) if isinstance(ret, dict) and set(ret) == set(('data', 'outputter')): outputter = ret['outputter'] ret = ret['data'] else: outputter = None display_output(ret, outputter, self.opts) else: ret = self._proc_function(self.opts['fun'], low, user, async_pub['tag'], async_pub['jid'], daemonize=False) except salt.exceptions.SaltException as exc: ret = '{0}'.format(exc) if not self.opts.get('quiet', False): display_output(ret, 'nested', self.opts) else: log.debug('Runner return: {0}'.format(ret)) return ret