Beispiel #1
0
def display_output(data, out=None, opts=None):
    '''
    Print the passed data using the desired output
    '''
    if opts is None:
        opts = {}
    display_data = try_printout(data, out, opts)

    output_filename = opts.get('output_file', None)
    log.trace('data = {0}'.format(data))
    try:
        # output filename can be either '' or None
        if output_filename:
            with salt.utils.fopen(output_filename, 'a') as ofh:
                fdata = display_data
                if isinstance(fdata, six.text_type):
                    try:
                        fdata = fdata.encode('utf-8')
                    except (UnicodeDecodeError, UnicodeEncodeError):
                        # try to let the stream write
                        # even if we didn't encode it
                        pass
                ofh.write(fdata)
                ofh.write('\n')
            return
        if display_data:
            print_cli(display_data)
    except IOError as exc:
        # Only raise if it's NOT a broken pipe
        if exc.errno != errno.EPIPE:
            raise exc
Beispiel #2
0
 def _print_errors_summary(self, errors):
     if errors:
         print_cli('\n')
         print_cli('---------------------------')
         print_cli('Errors')
         print_cli('---------------------------')
         for minion in errors:
             print_cli(self._format_error(minion))
Beispiel #3
0
 def _print_errors_summary(self, errors):
     if errors:
         print_cli("\n")
         print_cli("---------------------------")
         print_cli("Errors")
         print_cli("---------------------------")
         for error in errors:
             print_cli(self._format_error(error))
Beispiel #4
0
 def print_docs(self):
     '''
     Pick up the documentation for all of the modules and print it out.
     '''
     docs = {}
     for name, func in six.iteritems(self.minion.functions):
         if name not in docs:
             if func.__doc__:
                 docs[name] = func.__doc__
     for name in sorted(docs):
         if name.startswith(self.opts.get('fun', '')):
             print_cli('{0}:\n{1}\n'.format(name, docs[name]))
Beispiel #5
0
Datei: cp.py Projekt: DaveQB/salt
 def _load_files(self):
     '''
     Parse the files indicated in opts['src'] and load them into a python
     object for transport
     '''
     files = {}
     for fn_ in self.opts['src']:
         if os.path.isfile(fn_):
             files.update(self._file_dict(fn_))
         elif os.path.isdir(fn_):
             print_cli(fn_ + ' is a directory, only files are supported.')
             #files.update(self._recurse_dir(fn_))
     return files
Beispiel #6
0
def display_output(data, out=None, opts=None, **kwargs):
    '''
    Print the passed data using the desired output
    '''
    if opts is None:
        opts = {}
    display_data = try_printout(data, out, opts, **kwargs)

    output_filename = opts.get('output_file', None)
    log.trace('data = {0}'.format(data))
    try:
        # output filename can be either '' or None
        if output_filename:
            if not hasattr(output_filename, 'write'):
                ofh = salt.utils.fopen(output_filename, 'a')
                fh_opened = True
            else:
                # Filehandle/file-like object
                ofh = output_filename
                fh_opened = False

            try:
                fdata = display_data
                if isinstance(fdata, six.text_type):
                    try:
                        fdata = fdata.encode('utf-8')
                    except (UnicodeDecodeError, UnicodeEncodeError):
                        # try to let the stream write
                        # even if we didn't encode it
                        pass
                if fdata:
                    if six.PY3:
                        ofh.write(fdata.decode())
                    else:
                        ofh.write(fdata)
                    ofh.write('\n')
            finally:
                if fh_opened:
                    ofh.close()
            return
        if display_data:
            print_cli(display_data)
    except IOError as exc:
        # Only raise if it's NOT a broken pipe
        if exc.errno != errno.EPIPE:
            raise exc
Beispiel #7
0
 def get_bnum(self):
     '''
     Return the active number of minions to maintain
     '''
     partition = lambda x: float(x) / 100.0 * len(self.minions)
     try:
         if '%' in self.opts['batch']:
             res = partition(float(self.opts['batch'].strip('%')))
             if res < 1:
                 return int(math.ceil(res))
             else:
                 return int(res)
         else:
             return int(self.opts['batch'])
     except ValueError:
         if not self.quiet:
             print_cli('Invalid batch data sent: {0}\nData must be in the '
                       'form of %10, 10% or 3'.format(self.opts['batch']))
Beispiel #8
0
 def _print_docs(self, ret):
     '''
     Print out the docstrings for all of the functions on the minions
     '''
     docs = {}
     if not ret:
         self.exit(2, 'No minions found to gather docs from\n')
     if isinstance(ret, str):
         self.exit(2, '{0}\n'.format(ret))
     for host in ret:
         for fun in ret[host]:
             if fun not in docs:
                 if ret[host][fun]:
                     docs[fun] = ret[host][fun]
     for fun in sorted(docs):
         salt.output.display_output(fun + ':', 'text', self.config)
         print_cli(docs[fun])
         print_cli('')
 def _print_docs(self, ret):
     """
     Print out the docstrings for all of the functions on the minions
     """
     docs = {}
     if not ret:
         self.exit(2, "No minions found to gather docs from\n")
     if isinstance(ret, str):
         self.exit(2, "{0}\n".format(ret))
     for host in ret:
         if ret[host] == "Minion did not return. [Not connected]":
             continue
         for fun in ret[host]:
             if fun not in docs:
                 if ret[host][fun]:
                     docs[fun] = ret[host][fun]
     for fun in sorted(docs):
         salt.output.display_output(fun + ":", "text", self.config)
         print_cli(docs[fun])
         print_cli("")
Beispiel #10
0
 def _print_docs(self, ret):
     '''
     Print out the docstrings for all of the functions on the minions
     '''
     import salt.output
     docs = {}
     if not ret:
         self.exit(2, 'No minions found to gather docs from\n')
     if isinstance(ret, str):
         self.exit(2, '{0}\n'.format(ret))
     for host in ret:
         if ret[host] == 'Minion did not return. [Not connected]':
             continue
         for fun in ret[host]:
             if fun not in docs:
                 if ret[host][fun]:
                     docs[fun] = ret[host][fun]
     for fun in sorted(docs):
         salt.output.display_output(fun + ':', 'text', self.config)
         print_cli(docs[fun])
         print_cli('')
Beispiel #11
0
 def _print_docs(self, ret):
     '''
     Print out the docstrings for all of the functions on the minions
     '''
     import salt.output
     docs = {}
     if not ret:
         self.exit(2, 'No minions found to gather docs from\n')
     if isinstance(ret, str):
         self.exit(2, '{0}\n'.format(ret))
     for host in ret:
         if isinstance(ret[host], string_types) and ret[host].startswith(
                 "Minion did not return"):
             continue
         for fun in ret[host]:
             if fun not in docs and ret[host][fun]:
                 docs[fun] = ret[host][fun]
     if self.options.output:
         for fun in sorted(docs):
             salt.output.display_output({fun: docs[fun]}, 'nested',
                                        self.config)
     else:
         for fun in sorted(docs):
             print_cli('{0}:'.format(fun))
             print_cli(docs[fun])
             print_cli('')
Beispiel #12
0
    def _print_docs(self, ret):
        """
        Print out the docstrings for all of the functions on the minions
        """
        import salt.output

        docs = {}
        if not ret:
            self.exit(2, "No minions found to gather docs from\n")
        if isinstance(ret, str):
            self.exit(2, "{0}\n".format(ret))
        for host in ret:
            if isinstance(ret[host], string_types) and ret[host].startswith("Minion did not return"):
                continue
            for fun in ret[host]:
                if fun not in docs and ret[host][fun]:
                    docs[fun] = ret[host][fun]
        if self.options.output:
            for fun in sorted(docs):
                salt.output.display_output({fun: docs[fun]}, "nested", self.config)
        else:
            for fun in sorted(docs):
                print_cli("{0}:".format(fun))
                print_cli(docs[fun])
                print_cli("")
Beispiel #13
0
    def __gather_minions(self):
        '''
        Return a list of minions to use for the batch run
        '''
        args = [self.opts['tgt'],
                'test.ping',
                [],
                self.opts['timeout'],
                ]

        selected_target_option = self.opts.get('selected_target_option', None)
        if selected_target_option is not None:
            args.append(selected_target_option)
        else:
            args.append(self.opts.get('tgt_type', 'glob'))

        self.pub_kwargs['yield_pub_data'] = True
        ping_gen = self.local.cmd_iter(*args,
                                       gather_job_timeout=self.opts['gather_job_timeout'],
                                       **self.pub_kwargs)

        # Broadcast to targets
        fret = set()
        nret = set()
        for ret in ping_gen:
            if ('minions' and 'jid') in ret:
                for minion in ret['minions']:
                    nret.add(minion)
                continue
            else:
                try:
                    m = next(six.iterkeys(ret))
                except StopIteration:
                    if not self.quiet:
                        print_cli('No minions matched the target.')
                    break
                if m is not None:
                    fret.add(m)
        return (list(fret), ping_gen, nret.difference(fret))
Beispiel #14
0
    def __gather_minions(self):
        '''
        Return a list of minions to use for the batch run
        '''
        args = [self.opts['tgt'],
                'test.ping',
                [],
                self.opts['timeout'],
                ]

        selected_target_option = self.opts.get('selected_target_option', None)
        if selected_target_option is not None:
            args.append(selected_target_option)
        else:
            args.append(self.opts.get('expr_form', 'glob'))

        fret = []
        for ret in self.local.cmd_iter(*args, **self.eauth):
            for minion in ret:
                if not self.quiet:
                    print_cli('{0} Detected for this batch run'.format(minion))
                fret.append(minion)
        return sorted(fret)
Beispiel #15
0
    def __gather_minions(self):
        '''
        Return a list of minions to use for the batch run
        '''
        args = [self.opts['tgt'],
                'test.ping',
                [],
                self.opts['timeout'],
                ]

        selected_target_option = self.opts.get('selected_target_option', None)
        if selected_target_option is not None:
            args.append(selected_target_option)
        else:
            args.append(self.opts.get('tgt_type', 'glob'))

        self.pub_kwargs['yield_pub_data'] = True
        ping_gen = self.local.cmd_iter(*args, **self.pub_kwargs)

        # Broadcast to targets
        fret = set()
        nret = set()
        try:
            for ret in ping_gen:
                if ('minions' and 'jid') in ret:
                    for minion in ret['minions']:
                        nret.add(minion)
                    continue
                else:
                    m = next(six.iterkeys(ret))
                    if m is not None:
                        fret.add(m)
            return (list(fret), ping_gen, nret.difference(fret))
        except StopIteration:
            if not self.quiet:
                print_cli('No minions matched the target.')
        return list(fret), ping_gen
Beispiel #16
0
    def __gather_minions(self):
        '''
        Return a list of minions to use for the batch run
        '''
        args = [
            self.opts['tgt'],
            'test.ping',
            [],
            self.opts['timeout'],
        ]

        selected_target_option = self.opts.get('selected_target_option', None)
        if selected_target_option is not None:
            args.append(selected_target_option)
        else:
            args.append(self.opts.get('expr_form', 'glob'))

        fret = []
        for ret in self.local.cmd_iter(*args, **self.eauth):
            for minion in ret:
                if not self.quiet:
                    print_cli('{0} Detected for this batch run'.format(minion))
                fret.append(minion)
        return sorted(fret)
Beispiel #17
0
def display_output(data, out=None, opts=None):
    '''
    Print the passed data using the desired output
    '''
    if opts is None:
        opts = {}
    try:
        display_data = get_printout(out, opts)(data).rstrip()
    except (KeyError, AttributeError):
        log.debug(traceback.format_exc())
        opts.pop('output', None)
        display_data = get_printout('nested', opts)(data).rstrip()

    output_filename = opts.get('output_file', None)
    log.trace('data = {0}'.format(data))
    try:
        # output filename can be either '' or None
        if output_filename:
            with salt.utils.fopen(output_filename, 'a') as ofh:
                fdata = display_data
                if isinstance(fdata, six.text_type):
                    try:
                        fdata = fdata.encode('utf-8')
                    except (UnicodeDecodeError, UnicodeEncodeError):
                        # try to let the stream write
                        # even if we didn't encode it
                        pass
                ofh.write(fdata)
                ofh.write('\n')
            return
        if display_data:
            print_cli(display_data)
    except IOError as exc:
        # Only raise if it's NOT a broken pipe
        if exc.errno != errno.EPIPE:
            raise exc
Beispiel #18
0
    def run(self):
        # '''
        # Execute the salt command line
        # '''
        import salt.client
        # self.parse_args()

        # Setup file logging!
        self.setup_logfile_logger()
        verify_log(self.config)

        try:
            # We don't need to bail on config file permission errors
            # if the CLI
            # process is run with the -a flag
            skip_perm_errors = self.options.eauth != ''

            self.local_client = salt.client.get_local_client(
                self.get_config_file_path(),
                skip_perm_errors=skip_perm_errors,
                auto_reconnect=True)
        except SaltClientError as exc:
            self.exit(2, '{0}\n'.format(exc))
            return

        if self.options.batch or self.options.static:
            # _run_batch() will handle all output and
            # exit with the appropriate error condition
            # Execution will not continue past this point
            # in batch mode.
            self._run_batch()
            return

        if self.options.preview_target:
            self._preview_target()
            return

        if self.options.timeout <= 0:
            self.options.timeout = self.local_client.opts['timeout']

        kwargs = {
            'tgt': self.config['tgt'],
            'fun': self.config['fun'],
            'arg': self.config['arg'],
            'timeout': self.options.timeout,
            'show_timeout': self.options.show_timeout,
            'show_jid': self.options.show_jid
        }

        if 'token' in self.config:
            try:
                with salt.utils.fopen(
                        os.path.join(self.config['cachedir'], '.root_key'),
                        'r') as fp_:
                    kwargs['key'] = fp_.readline()
            except IOError:
                kwargs['token'] = self.config['token']

        kwargs['delimiter'] = self.options.delimiter

        if self.selected_target_option:
            kwargs['tgt_type'] = self.selected_target_option
        else:
            kwargs['tgt_type'] = 'glob'

        if getattr(self.options, 'return'):
            kwargs['ret'] = getattr(self.options, 'return')

        if getattr(self.options, 'return_config'):
            kwargs['ret_config'] = getattr(self.options, 'return_config')

        if getattr(self.options, 'return_kwargs'):
            kwargs['ret_kwargs'] = yamlify_arg(
                getattr(self.options, 'return_kwargs'))

        if getattr(self.options, 'module_executors'):
            kwargs['module_executors'] = yamlify_arg(
                getattr(self.options, 'module_executors'))

        if getattr(self.options, 'metadata'):
            kwargs['metadata'] = yamlify_arg(getattr(self.options, 'metadata'))

        # If using eauth and a token hasn't already been loaded into
        # kwargs, prompt the user to enter auth credentials
        if 'token' not in kwargs and 'key' not in kwargs and self.options.eauth:
            # This is expensive. Don't do it unless we need to.
            import salt.auth
            resolver = salt.auth.Resolver(self.config)
            res = resolver.cli(self.options.eauth)
            if self.options.mktoken and res:
                tok = resolver.token_cli(self.options.eauth, res)
                if tok:
                    kwargs['token'] = tok.get('token', '')
            if not res:
                sys.stderr.write('ERROR: Authentication failed\n')
                sys.exit(2)
            kwargs.update(res)
            kwargs['eauth'] = self.options.eauth

        if self.config['async']:
            jid = self.local_client.cmd_async(**kwargs)
            print_cli('Executed command with job ID: {0}'.format(jid))
            return

        # local will be None when there was an error
        if not self.local_client:
            return

        retcodes = []
        errors = []
        try:
            if self.options.subset:
                cmd_func = self.local_client.cmd_subset
                kwargs['sub'] = self.options.subset
                kwargs['cli'] = True
            else:
                cmd_func = self.local_client.cmd_cli

            if self.options.progress:
                kwargs['progress'] = True
                self.config['progress'] = True
                ret = {}
                for progress in cmd_func(**kwargs):
                    out = 'progress'
                    try:
                        self._progress_ret(progress, out)
                    except salt.exceptions.LoaderError as exc:
                        raise salt.exceptions.SaltSystemExit(exc)
                    if 'return_count' not in progress:
                        ret.update(progress)
                self._progress_end(out)
                self._print_returns_summary(ret)
            elif self.config['fun'] == 'sys.doc':
                ret = {}
                out = ''
                for full_ret in self.local_client.cmd_cli(**kwargs):
                    ret_, out, retcode = self._format_ret(full_ret)
                    ret.update(ret_)
                self._output_ret(ret, out)
            else:
                if self.options.verbose:
                    kwargs['verbose'] = True
                ret = {}

                # TODO: delete debug code start=============================
                # import re
                # import subprocess
                # from salt.newrun import (json, byteify, MessageType)

                # oriArr = []
                # executeArr = []
                # def executeSaltCmd(cmd, msg_in=''):
                #     try:
                #         proc = subprocess.Popen(cmd, shell=True, stdin=subprocess.PIPE,
                #                                 stdout=subprocess.PIPE, stderr=subprocess.PIPE,)
                #         stdout_value, stderr_value = proc.communicate(msg_in)

                #         return stdout_value, stderr_value
                #     except Exception, e:
                #         log.error(traceback.format_exc())
                #         #print('traceback.format_exc():\n%s' % traceback.format_exc())

                # def getAcceptIp():
                #     stdout_val, stderr_val = executeSaltCmd("salt-key -l acc")
                #     syndicList = re.findall(
                #         r"\b(?:[0-9]{1,3}\.){3}[0-9]{1,3}\b", stdout_val, re.M)
                #     return syndicList

                # oriArr = getAcceptIp()
                # loopi = 0
                # TODO: delete debug code end=============================
                for full_ret in cmd_func(**kwargs):
                    try:
                        ret_, out, retcode = self._format_ret(full_ret)
                        # print('full_ret=: %s, ret_=: %s, out=: %s' % (full_ret, ret_, out))

                        retcodes.append(retcode)
                        self._output_ret(ret_, out)

                        # TODO: delete debug code start=============================
                        # ret_ = byteify(ret_)
                        # ssList = re.findall(r"\b(?:[0-9]{1,3}\.){3}[0-9]{1,3}\b", json.dumps(ret_), re.M)
                        # executeArr = executeArr + ssList
                        # loopi = loopi +1
                        # if loopi > 2516:
                        #     eprint = [i for i in oriArr if i not in executeArr]
                        #     print(eprint)
                        # TODO: delete debug code end=============================

                        ret.update(full_ret)
                    except KeyError:
                        errors.append(full_ret)

            # Returns summary
            if self.config['cli_summary'] is True:
                if self.config['fun'] != 'sys.doc':
                    if self.options.output is None:
                        self._print_returns_summary(ret)
                        self._print_errors_summary(errors)

            # NOTE: Return code is set here based on if all minions
            # returned 'ok' with a retcode of 0.
            # This is the final point before the 'salt' cmd returns,
            # which is why we set the retcode here.
            if retcodes.count(0) < len(retcodes):
                sys.stderr.write(
                    'ERROR: Minions returned with non-zero exit code\n')
                sys.exit(11)

        except (SaltInvocationError, EauthAuthenticationError,
                SaltClientError) as exc:
            ret = str(exc)
            self._output_ret(ret, '')
Beispiel #19
0
    def run(self):
        """
        Execute the salt command line
        """
        import salt.client

        self.parse_args()

        # Setup file logging!
        self.setup_logfile_logger()
        verify_log(self.config)

        try:
            # We don't need to bail on config file permission errors
            # if the CLI
            # process is run with the -a flag
            skip_perm_errors = self.options.eauth != ""

            self.local_client = salt.client.get_local_client(
                self.get_config_file_path(), skip_perm_errors=skip_perm_errors, auto_reconnect=True
            )
        except SaltClientError as exc:
            self.exit(2, "{0}\n".format(exc))
            return

        if self.options.batch or self.options.static:
            # _run_batch() will handle all output and
            # exit with the appropriate error condition
            # Execution will not continue past this point
            # in batch mode.
            self._run_batch()
            return

        if self.options.timeout <= 0:
            self.options.timeout = self.local_client.opts["timeout"]

        kwargs = {
            "tgt": self.config["tgt"],
            "fun": self.config["fun"],
            "arg": self.config["arg"],
            "timeout": self.options.timeout,
            "show_timeout": self.options.show_timeout,
            "show_jid": self.options.show_jid,
        }

        if "token" in self.config:
            try:
                with salt.utils.fopen(os.path.join(self.config["cachedir"], ".root_key"), "r") as fp_:
                    kwargs["key"] = fp_.readline()
            except IOError:
                kwargs["token"] = self.config["token"]

        kwargs["delimiter"] = self.options.delimiter

        if self.selected_target_option:
            kwargs["tgt_type"] = self.selected_target_option
        else:
            kwargs["tgt_type"] = "glob"

        if getattr(self.options, "return"):
            kwargs["ret"] = getattr(self.options, "return")

        if getattr(self.options, "return_config"):
            kwargs["ret_config"] = getattr(self.options, "return_config")

        if getattr(self.options, "return_kwargs"):
            kwargs["ret_kwargs"] = yamlify_arg(getattr(self.options, "return_kwargs"))

        if getattr(self.options, "module_executors"):
            kwargs["module_executors"] = yamlify_arg(getattr(self.options, "module_executors"))

        if getattr(self.options, "metadata"):
            kwargs["metadata"] = yamlify_arg(getattr(self.options, "metadata"))

        # If using eauth and a token hasn't already been loaded into
        # kwargs, prompt the user to enter auth credentials
        if "token" not in kwargs and "key" not in kwargs and self.options.eauth:
            # This is expensive. Don't do it unless we need to.
            import salt.auth

            resolver = salt.auth.Resolver(self.config)
            res = resolver.cli(self.options.eauth)
            if self.options.mktoken and res:
                tok = resolver.token_cli(self.options.eauth, res)
                if tok:
                    kwargs["token"] = tok.get("token", "")
            if not res:
                sys.stderr.write("ERROR: Authentication failed\n")
                sys.exit(2)
            kwargs.update(res)
            kwargs["eauth"] = self.options.eauth

        if self.config["async"]:
            jid = self.local_client.cmd_async(**kwargs)
            print_cli("Executed command with job ID: {0}".format(jid))
            return

        # local will be None when there was an error
        if not self.local_client:
            return

        retcodes = []
        errors = []

        try:
            if self.options.subset:
                cmd_func = self.local_client.cmd_subset
                kwargs["sub"] = True
                kwargs["cli"] = True
            else:
                cmd_func = self.local_client.cmd_cli

            if self.options.progress:
                kwargs["progress"] = True
                self.config["progress"] = True
                ret = {}
                for progress in cmd_func(**kwargs):
                    out = "progress"
                    try:
                        self._progress_ret(progress, out)
                    except salt.exceptions.LoaderError as exc:
                        raise salt.exceptions.SaltSystemExit(exc)
                    if "return_count" not in progress:
                        ret.update(progress)
                self._progress_end(out)
                self._print_returns_summary(ret)
            elif self.config["fun"] == "sys.doc":
                ret = {}
                out = ""
                for full_ret in self.local_client.cmd_cli(**kwargs):
                    ret_, out, retcode = self._format_ret(full_ret)
                    ret.update(ret_)
                self._output_ret(ret, out)
            else:
                if self.options.verbose:
                    kwargs["verbose"] = True
                ret = {}
                for full_ret in cmd_func(**kwargs):
                    try:
                        ret_, out, retcode = self._format_ret(full_ret)
                        retcodes.append(retcode)
                        self._output_ret(ret_, out)
                        ret.update(full_ret)
                    except KeyError:
                        errors.append(full_ret)

            # Returns summary
            if self.config["cli_summary"] is True:
                if self.config["fun"] != "sys.doc":
                    if self.options.output is None:
                        self._print_returns_summary(ret)
                        self._print_errors_summary(errors)

            # NOTE: Return code is set here based on if all minions
            # returned 'ok' with a retcode of 0.
            # This is the final point before the 'salt' cmd returns,
            # which is why we set the retcode here.
            if retcodes.count(0) < len(retcodes):
                sys.stderr.write("ERROR: Minions returned with non-zero exit code\n")
                sys.exit(11)

        except (SaltInvocationError, EauthAuthenticationError, SaltClientError) as exc:
            ret = str(exc)
            self._output_ret(ret, "")
Beispiel #20
0
 def _print_returns_summary(self, ret):
     '''
     Display returns summary
     '''
     return_counter = 0
     not_return_counter = 0
     not_return_minions = []
     for each_minion in ret:
         minion_ret = ret[each_minion]
         if (isinstance(minion_ret, string_types)
                 and minion_ret.startswith("Minion did not return")):
             not_return_counter += 1
             not_return_minions.append(each_minion)
         else:
             return_counter += 1
     print_cli('\n')
     print_cli('-------------------------------------------')
     print_cli('Summary')
     print_cli('-------------------------------------------')
     print_cli('# of Minions Targeted: {0}'.format(return_counter +
                                                   not_return_counter))
     print_cli('# of Minions Returned: {0}'.format(return_counter))
     print_cli(
         '# of Minions Did Not Return: {0}'.format(not_return_counter))
     if self.options.verbose:
         print_cli('Minions Which Did Not Return: {0}'.format(
             " ".join(not_return_minions)))
     print_cli('-------------------------------------------')
Beispiel #21
0
 def _print_returns_summary(self, ret):
     '''
     Display returns summary
     '''
     return_counter = 0
     not_return_counter = 0
     not_return_minions = []
     for each_minion in ret:
         minion_ret = ret[each_minion]
         if (
                 isinstance(minion_ret, string_types)
                 and minion_ret.startswith("Minion did not return")
         ):
             not_return_counter += 1
             not_return_minions.append(each_minion)
         else:
             return_counter += 1
     print_cli('\n')
     print_cli('-------------------------------------------')
     print_cli('Summary')
     print_cli('-------------------------------------------')
     print_cli('# of Minions Targeted: {0}'.format(return_counter + not_return_counter))
     print_cli('# of Minions Returned: {0}'.format(return_counter))
     print_cli('# of Minions Did Not Return: {0}'.format(not_return_counter))
     if self.options.verbose:
         print_cli('Minions Which Did Not Return: {0}'.format(" ".join(not_return_minions)))
     print_cli('-------------------------------------------')
Beispiel #22
0
    def run(self):
        '''
        Execute the batch run
        '''
        args = [[],
                self.opts['fun'],
                self.opts['arg'],
                self.opts['timeout'],
                'list',
                ]
        bnum = self.get_bnum()
        to_run = copy.deepcopy(self.minions)
        active = []
        ret = {}
        iters = []

        # the minion tracker keeps track of responses and iterators
        # - it removes finished iterators from iters[]
        # - if a previously detected minion does not respond, its
        #   added with an empty answer to ret{} once the timeout is reached
        # - unresponsive minions are removed from active[] to make
        #   sure that the main while loop finishes even with unresp minions
        minion_tracker = {}

        # Iterate while we still have things to execute
        while len(ret) < len(self.minions):
            next_ = []
            if len(to_run) <= bnum and not active:
                # last bit of them, add them all to next iterator
                while to_run:
                    next_.append(to_run.pop())
            else:
                for i in range(bnum - len(active)):
                    if to_run:
                        next_.append(to_run.pop())

            active += next_
            args[0] = next_

            if next_:
                if not self.quiet:
                    print_cli('\nExecuting run on {0}\n'.format(next_))
                # create a new iterator for this batch of minions
                new_iter = self.local.cmd_iter_no_block(
                                *args,
                                raw=self.opts.get('raw', False),
                                ret=self.opts.get('return', ''),
                                **self.eauth)
                # add it to our iterators and to the minion_tracker
                iters.append(new_iter)
                minion_tracker[new_iter] = {}
                # every iterator added is 'active' and has its set of minions
                minion_tracker[new_iter]['minions'] = next_
                minion_tracker[new_iter]['active'] = True

            else:
                time.sleep(0.02)
            parts = {}

            for queue in iters:
                try:
                    # Gather returns until we get to the bottom
                    ncnt = 0
                    while True:
                        part = next(queue)
                        if part is None:
                            time.sleep(0.01)
                            ncnt += 1
                            if ncnt > 5:
                                break
                            continue
                        if self.opts.get('raw'):
                            parts.update({part['id']: part})
                        else:
                            parts.update(part)
                except StopIteration:
                    # if a iterator is done:
                    # - set it to inactive
                    # - add minions that have not responded to parts{}

                    # check if the tracker contains the iterator
                    if queue in minion_tracker:
                        minion_tracker[queue]['active'] = False

                        # add all minions that belong to this iterator and
                        # that have not responded to parts{} with an empty response
                        for minion in minion_tracker[queue]['minions']:
                            if minion not in parts:
                                parts[minion] = {}
                                parts[minion]['ret'] = {}

            for minion, data in parts.items():
                active.remove(minion)
                if self.opts.get('raw'):
                    yield data
                else:
                    ret[minion] = data['ret']
                    yield {minion: data['ret']}
                if not self.quiet:
                    ret[minion] = data['ret']
                    data[minion] = data.pop('ret')
                    if 'out' in data:
                        out = data.pop('out')
                    else:
                        out = None
                    salt.output.display_output(
                            data,
                            out,
                            self.opts)

            # remove inactive iterators from the iters list
            for queue in minion_tracker:
                # only remove inactive queues
                if not minion_tracker[queue]['active'] and queue in iters:
                    iters.remove(queue)
                    # also remove the iterator's minions from the active list
                    for minion in minion_tracker[queue]['minions']:
                        if minion in active:
                            active.remove(minion)
Beispiel #23
0
    def run(self):
        '''
        Execute the batch run
        '''
        args = [[],
                self.opts['fun'],
                self.opts['arg'],
                self.opts['timeout'],
                'list',
                ]
        bnum = self.get_bnum()
        # No targets to run
        if not self.minions:
            return
        to_run = copy.deepcopy(self.minions)
        active = []
        ret = {}
        iters = []
        # wait the specified time before decide a job is actually done
        bwait = self.opts.get('batch_wait', 0)
        wait = []

        if self.options:
            show_jid = self.options.show_jid
            show_verbose = self.options.verbose
        else:
            show_jid = False
            show_verbose = False

        # the minion tracker keeps track of responses and iterators
        # - it removes finished iterators from iters[]
        # - if a previously detected minion does not respond, its
        #   added with an empty answer to ret{} once the timeout is reached
        # - unresponsive minions are removed from active[] to make
        #   sure that the main while loop finishes even with unresp minions
        minion_tracker = {}

        # We already know some minions didn't respond to the ping, so inform
        # the user we won't be attempting to run a job on them
        for down_minion in self.down_minions:
            print_cli('Minion {0} did not respond. No job will be sent.'.format(down_minion))

        # Iterate while we still have things to execute
        while len(ret) < len(self.minions):
            next_ = []
            if bwait and wait:
                self.__update_wait(wait)
            if len(to_run) <= bnum - len(wait) and not active:
                # last bit of them, add them all to next iterator
                while to_run:
                    next_.append(to_run.pop())
            else:
                for i in range(bnum - len(active) - len(wait)):
                    if to_run:
                        minion_id = to_run.pop()
                        if isinstance(minion_id, dict):
                            next_.append(minion_id.keys()[0])
                        else:
                            next_.append(minion_id)

            active += next_
            args[0] = next_

            if next_:
                if not self.quiet:
                    print_cli('\nExecuting run on {0}\n'.format(next_))
                # create a new iterator for this batch of minions
                new_iter = self.local.cmd_iter_no_block(
                                *args,
                                raw=self.opts.get('raw', False),
                                ret=self.opts.get('return', ''),
                                show_jid=show_jid,
                                verbose=show_verbose,
                                **self.eauth)
                # add it to our iterators and to the minion_tracker
                iters.append(new_iter)
                minion_tracker[new_iter] = {}
                # every iterator added is 'active' and has its set of minions
                minion_tracker[new_iter]['minions'] = next_
                minion_tracker[new_iter]['active'] = True

            else:
                time.sleep(0.02)
            parts = {}

            # see if we found more minions
            for ping_ret in self.ping_gen:
                if ping_ret is None:
                    break
                m = next(ping_ret.iterkeys())
                if m not in self.minions:
                    self.minions.append(m)
                    to_run.append(m)

            for queue in iters:
                try:
                    # Gather returns until we get to the bottom
                    ncnt = 0
                    while True:
                        part = next(queue)
                        if part is None:
                            time.sleep(0.01)
                            ncnt += 1
                            if ncnt > 5:
                                break
                            continue
                        if self.opts.get('raw'):
                            parts.update({part['data']['id']: part})
                            if part['data']['id'] in minion_tracker[queue]['minions']:
                                minion_tracker[queue]['minions'].remove(part['data']['id'])
                            else:
                                print_cli('minion {0} was already deleted from tracker, probably a duplicate key'.format(part['id']))
                        else:
                            parts.update(part)
                            for id in part.keys():
                                if id in minion_tracker[queue]['minions']:
                                    minion_tracker[queue]['minions'].remove(id)
                                else:
                                    print_cli('minion {0} was already deleted from tracker, probably a duplicate key'.format(id))
                except StopIteration:
                    # if a iterator is done:
                    # - set it to inactive
                    # - add minions that have not responded to parts{}

                    # check if the tracker contains the iterator
                    if queue in minion_tracker:
                        minion_tracker[queue]['active'] = False

                        # add all minions that belong to this iterator and
                        # that have not responded to parts{} with an empty response
                        for minion in minion_tracker[queue]['minions']:
                            if minion not in parts:
                                parts[minion] = {}
                                parts[minion]['ret'] = {}

            for minion, data in six.iteritems(parts):
                if minion in active:
                    active.remove(minion)
                    if bwait:
                        wait.append(datetime.now() + timedelta(seconds=bwait))
                if self.opts.get('raw'):
                    ret[minion] = data
                    yield data
                else:
                    ret[minion] = data
                    yield {minion: data}
                if not self.quiet:
                    ret[minion] = data['ret']
                    data[minion] = data.pop('ret')
                    if 'out' in data:
                        out = data.pop('out')
                    else:
                        out = None
                    salt.output.display_output(
                            data,
                            out,
                            self.opts)

            # remove inactive iterators from the iters list
            for queue in minion_tracker:
                # only remove inactive queues
                if not minion_tracker[queue]['active'] and queue in iters:
                    iters.remove(queue)
                    # also remove the iterator's minions from the active list
                    for minion in minion_tracker[queue]['minions']:
                        if minion in active:
                            active.remove(minion)
                            if bwait:
                                wait.append(datetime.now() + timedelta(seconds=bwait))
Beispiel #24
0
    def call(self):
        '''
        Call the module
        '''
        ret = {}
        fun = self.opts['fun']
        ret['jid'] = salt.utils.jid.gen_jid()
        proc_fn = os.path.join(
            salt.minion.get_proc_dir(self.opts['cachedir']),
            ret['jid']
        )
        if fun not in self.minion.functions:
            sys.stderr.write(self.minion.functions.missing_fun_string(fun))
            mod_name = fun.split('.')[0]
            if mod_name in self.minion.function_errors:
                sys.stderr.write(' Possible reasons: {0}\n'.format(self.minion.function_errors[mod_name]))
            else:
                sys.stderr.write('\n')
            sys.exit(-1)
        try:
            sdata = {
                'fun': fun,
                'pid': os.getpid(),
                'jid': ret['jid'],
                'tgt': 'salt-call'}
            args, kwargs = salt.minion.load_args_and_kwargs(
                self.minion.functions[fun],
                salt.utils.args.parse_input(self.opts['arg']),
                data=sdata)
            try:
                with salt.utils.fopen(proc_fn, 'w+b') as fp_:
                    fp_.write(self.serial.dumps(sdata))
            except NameError:
                # Don't require msgpack with local
                pass
            except IOError:
                sys.stderr.write(
                    'Cannot write to process directory. '
                    'Do you have permissions to '
                    'write to {0} ?\n'.format(proc_fn))
            func = self.minion.functions[fun]
            try:
                ret['return'] = func(*args, **kwargs)
            except TypeError as exc:
                sys.stderr.write('\nPassed invalid arguments: {0}.\n\nUsage:\n'.format(exc))
                print_cli(func.__doc__)
                active_level = LOG_LEVELS.get(
                    self.opts['log_level'].lower(), logging.ERROR)
                if active_level <= logging.DEBUG:
                    trace = traceback.format_exc()
                    sys.stderr.write(trace)
                sys.exit(salt.defaults.exitcodes.EX_GENERIC)
            try:
                ret['retcode'] = sys.modules[
                    func.__module__].__context__.get('retcode', 0)
            except AttributeError:
                ret['retcode'] = 1
        except (CommandExecutionError) as exc:
            msg = 'Error running \'{0}\': {1}\n'
            active_level = LOG_LEVELS.get(
                self.opts['log_level'].lower(), logging.ERROR)
            if active_level <= logging.DEBUG:
                sys.stderr.write(traceback.format_exc())
            sys.stderr.write(msg.format(fun, str(exc)))
            sys.exit(salt.defaults.exitcodes.EX_GENERIC)
        except CommandNotFoundError as exc:
            msg = 'Command required for \'{0}\' not found: {1}\n'
            sys.stderr.write(msg.format(fun, str(exc)))
            sys.exit(salt.defaults.exitcodes.EX_GENERIC)
        try:
            os.remove(proc_fn)
        except (IOError, OSError):
            pass
        if hasattr(self.minion.functions[fun], '__outputter__'):
            oput = self.minion.functions[fun].__outputter__
            if isinstance(oput, six.string_types):
                ret['out'] = oput
        is_local = self.opts['local'] or self.opts.get(
            'file_client', False) == 'local'
        returners = self.opts.get('return', '').split(',')
        if (not is_local) or returners:
            ret['id'] = self.opts['id']
            ret['fun'] = fun
            ret['fun_args'] = self.opts['arg']

        for returner in returners:
            if not returner:  # if we got an empty returner somehow, skip
                continue
            try:
                ret['success'] = True
                self.minion.returners['{0}.returner'.format(returner)](ret)
            except Exception:
                pass

        # return the job infos back up to the respective minion's master

        if not is_local:
            try:
                mret = ret.copy()
                mret['jid'] = 'req'
                self.return_pub(mret)
            except Exception:
                pass
        # close raet channel here
        return ret
Beispiel #25
0
    def run(self):
        '''
        Execute the salt command line
        '''
        import salt.client
        self.parse_args()

        # Setup file logging!
        self.setup_logfile_logger()
        verify_log(self.config)

        try:
            # We don't need to bail on config file permission errors
            # if the CLI process is run with the -a flag
            skip_perm_errors = self.options.eauth != ''

            self.local_client = salt.client.get_local_client(
                self.get_config_file_path(),
                skip_perm_errors=skip_perm_errors,
                auto_reconnect=True)
        except SaltClientError as exc:
            self.exit(2, '{0}\n'.format(exc))
            return

        if self.options.batch or self.options.static:
            # _run_batch() will handle all output and
            # exit with the appropriate error condition
            # Execution will not continue past this point
            # in batch mode.
            self._run_batch()
            return

        if self.options.preview_target:
            minion_list = self._preview_target()
            self._output_ret(minion_list, self.config.get('output', 'nested'))
            return

        if self.options.timeout <= 0:
            self.options.timeout = self.local_client.opts['timeout']

        kwargs = {
            'tgt': self.config['tgt'],
            'fun': self.config['fun'],
            'arg': self.config['arg'],
            'timeout': self.options.timeout,
            'show_timeout': self.options.show_timeout,
            'show_jid': self.options.show_jid
        }

        if 'token' in self.config:
            try:
                with salt.utils.fopen(
                        os.path.join(self.config['cachedir'], '.root_key'),
                        'r') as fp_:
                    kwargs['key'] = fp_.readline()
            except IOError:
                kwargs['token'] = self.config['token']

        kwargs['delimiter'] = self.options.delimiter

        if self.selected_target_option:
            kwargs['tgt_type'] = self.selected_target_option
        else:
            kwargs['tgt_type'] = 'glob'

        # If batch_safe_limit is set, check minions matching target and
        # potentially switch to batch execution
        if self.options.batch_safe_limit > 1:
            if len(self._preview_target()) >= self.options.batch_safe_limit:
                print_cli(
                    '\nNOTICE: Too many minions targeted, switching to batch execution.'
                )
                self.options.batch = self.options.batch_safe_size
                self._run_batch()
                return

        if getattr(self.options, 'return'):
            kwargs['ret'] = getattr(self.options, 'return')

        if getattr(self.options, 'return_config'):
            kwargs['ret_config'] = getattr(self.options, 'return_config')

        if getattr(self.options, 'return_kwargs'):
            kwargs['ret_kwargs'] = yamlify_arg(
                getattr(self.options, 'return_kwargs'))

        if getattr(self.options, 'module_executors'):
            kwargs['module_executors'] = yamlify_arg(
                getattr(self.options, 'module_executors'))

        if getattr(self.options, 'executor_opts'):
            kwargs['executor_opts'] = yamlify_arg(
                getattr(self.options, 'executor_opts'))

        if getattr(self.options, 'metadata'):
            kwargs['metadata'] = yamlify_arg(getattr(self.options, 'metadata'))

        # If using eauth and a token hasn't already been loaded into
        # kwargs, prompt the user to enter auth credentials
        if 'token' not in kwargs and 'key' not in kwargs and self.options.eauth:
            # This is expensive. Don't do it unless we need to.
            import salt.auth
            resolver = salt.auth.Resolver(self.config)
            res = resolver.cli(self.options.eauth)
            if self.options.mktoken and res:
                tok = resolver.token_cli(self.options.eauth, res)
                if tok:
                    kwargs['token'] = tok.get('token', '')
            if not res:
                sys.stderr.write('ERROR: Authentication failed\n')
                sys.exit(2)
            kwargs.update(res)
            kwargs['eauth'] = self.options.eauth

        if self.config['async']:
            jid = self.local_client.cmd_async(**kwargs)
            print_cli('Executed command with job ID: {0}'.format(jid))
            return

        # local will be None when there was an error
        if not self.local_client:
            return

        retcodes = []
        errors = []

        try:
            if self.options.subset:
                cmd_func = self.local_client.cmd_subset
                kwargs['sub'] = self.options.subset
                kwargs['cli'] = True
            else:
                cmd_func = self.local_client.cmd_cli

            if self.options.progress:
                kwargs['progress'] = True
                self.config['progress'] = True
                ret = {}
                for progress in cmd_func(**kwargs):
                    out = 'progress'
                    try:
                        self._progress_ret(progress, out)
                    except salt.exceptions.LoaderError as exc:
                        raise salt.exceptions.SaltSystemExit(exc)
                    if 'return_count' not in progress:
                        ret.update(progress)
                self._progress_end(out)
                self._print_returns_summary(ret)
            elif self.config['fun'] == 'sys.doc':
                ret = {}
                out = ''
                for full_ret in self.local_client.cmd_cli(**kwargs):
                    ret_, out, retcode = self._format_ret(full_ret)
                    ret.update(ret_)
                self._output_ret(ret, out)
            else:
                if self.options.verbose:
                    kwargs['verbose'] = True
                ret = {}
                for full_ret in cmd_func(**kwargs):
                    try:
                        ret_, out, retcode = self._format_ret(full_ret)
                        retcodes.append(retcode)
                        self._output_ret(ret_, out)
                        ret.update(full_ret)
                    except KeyError:
                        errors.append(full_ret)

            # Returns summary
            if self.config['cli_summary'] is True:
                if self.config['fun'] != 'sys.doc':
                    if self.options.output is None:
                        self._print_returns_summary(ret)
                        self._print_errors_summary(errors)

            # NOTE: Return code is set here based on if all minions
            # returned 'ok' with a retcode of 0.
            # This is the final point before the 'salt' cmd returns,
            # which is why we set the retcode here.
            if retcodes.count(0) < len(retcodes):
                sys.stderr.write(
                    'ERROR: Minions returned with non-zero exit code\n')
                sys.exit(11)

        except (SaltInvocationError, EauthAuthenticationError,
                SaltClientError) as exc:
            ret = str(exc)
            self._output_ret(ret, '')
    def run(self):
        """
        Execute the salt command line
        """
        self.parse_args()

        if self.config["verify_env"]:
            if not self.config["log_file"].startswith(("tcp://", "udp://", "file://")):
                # Logfile is not using Syslog, verify
                verify_files([self.config["log_file"]], self.config["user"])

        # Setup file logging!
        self.setup_logfile_logger()

        try:
            # We don't need to bail on config file permission errors
            # if the CLI
            # process is run with the -a flag
            skip_perm_errors = self.options.eauth != ""

            local = salt.client.get_local_client(self.get_config_file_path(), skip_perm_errors=skip_perm_errors)
        except SaltClientError as exc:
            self.exit(2, "{0}\n".format(exc))
            return

        if self.options.batch:
            eauth = {}
            if "token" in self.config:
                eauth["token"] = self.config["token"]

            # If using eauth and a token hasn't already been loaded into
            # kwargs, prompt the user to enter auth credentials
            if "token" not in eauth and self.options.eauth:
                resolver = salt.auth.Resolver(self.config)
                res = resolver.cli(self.options.eauth)
                if self.options.mktoken and res:
                    tok = resolver.token_cli(self.options.eauth, res)
                    if tok:
                        eauth["token"] = tok.get("token", "")
                if not res:
                    sys.exit(2)
                eauth.update(res)
                eauth["eauth"] = self.options.eauth

            if self.options.static:

                batch = salt.cli.batch.Batch(self.config, eauth=eauth, quiet=True)

                ret = {}

                for res in batch.run():
                    ret.update(res)

                self._output_ret(ret, "")

            else:
                batch = salt.cli.batch.Batch(self.config, eauth=eauth)
                # Printing the output is already taken care of in run() itself
                for res in batch.run():
                    pass

        else:
            if self.options.timeout <= 0:
                self.options.timeout = local.opts["timeout"]

            kwargs = {
                "tgt": self.config["tgt"],
                "fun": self.config["fun"],
                "arg": self.config["arg"],
                "timeout": self.options.timeout,
                "show_timeout": self.options.show_timeout,
                "show_jid": self.options.show_jid,
            }

            if "token" in self.config:
                try:
                    with salt.utils.fopen(os.path.join(self.config["cachedir"], ".root_key"), "r") as fp_:
                        kwargs["key"] = fp_.readline()
                except IOError:
                    kwargs["token"] = self.config["token"]

            if self.selected_target_option:
                kwargs["expr_form"] = self.selected_target_option
            else:
                kwargs["expr_form"] = "glob"

            if getattr(self.options, "return"):
                kwargs["ret"] = getattr(self.options, "return")

            # If using eauth and a token hasn't already been loaded into
            # kwargs, prompt the user to enter auth credentials
            if "token" not in kwargs and self.options.eauth:
                resolver = salt.auth.Resolver(self.config)
                res = resolver.cli(self.options.eauth)
                if self.options.mktoken and res:
                    tok = resolver.token_cli(self.options.eauth, res)
                    if tok:
                        kwargs["token"] = tok.get("token", "")
                if not res:
                    sys.exit(2)
                kwargs.update(res)
                kwargs["eauth"] = self.options.eauth

            if self.config["async"]:
                jid = local.cmd_async(**kwargs)
                print_cli("Executed command with job ID: {0}".format(jid))
                return
            retcodes = []
            try:
                # local will be None when there was an error
                if local:
                    if self.options.subset:
                        cmd_func = local.cmd_subset
                        kwargs["sub"] = self.options.subset
                        kwargs["cli"] = True
                    else:
                        cmd_func = local.cmd_cli
                    if self.options.static:
                        if self.options.verbose:
                            kwargs["verbose"] = True
                        full_ret = local.cmd_full_return(**kwargs)
                        ret, out, retcode = self._format_ret(full_ret)
                        self._output_ret(ret, out)
                    elif self.config["fun"] == "sys.doc":
                        ret = {}
                        out = ""
                        for full_ret in local.cmd_cli(**kwargs):
                            ret_, out, retcode = self._format_ret(full_ret)
                            ret.update(ret_)
                        self._output_ret(ret, out)
                    else:
                        if self.options.verbose:
                            kwargs["verbose"] = True
                        ret = {}
                        for full_ret in cmd_func(**kwargs):
                            ret_, out, retcode = self._format_ret(full_ret)
                            retcodes.append(retcode)
                            self._output_ret(ret_, out)
                            ret.update(ret_)

                    # Returns summary
                    if self.config["cli_summary"] is True:
                        if self.config["fun"] != "sys.doc":
                            if self.options.output is None:
                                self._print_returns_summary(ret)

                    # NOTE: Return code is set here based on if all minions
                    # returned 'ok' with a retcode of 0.
                    # This is the final point before the 'salt' cmd returns,
                    # which is why we set the retcode here.
                    if retcodes.count(0) < len(retcodes):
                        sys.exit(11)

            except (SaltInvocationError, EauthAuthenticationError) as exc:
                ret = str(exc)
                out = ""
                self._output_ret(ret, out)
Beispiel #27
0
 def _print_returns_summary(self, ret):
     '''
     Display returns summary
     '''
     return_counter = 0
     not_return_counter = 0
     not_return_minions = []
     for each_minion in ret:
         if ret[each_minion] == "Minion did not return":
             not_return_counter += 1
             not_return_minions.append(each_minion)
         else:
             return_counter += 1
     print_cli('\n')
     print_cli('-------------------------------------------')
     print_cli('Summary')
     print_cli('-------------------------------------------')
     print_cli('# of Minions Targeted: {0}'.format(return_counter + not_return_counter))
     print_cli('# of Minions Returned: {0}'.format(return_counter))
     print_cli('# of Minions Did Not Return: {0}'.format(not_return_counter))
     if self.options.verbose:
         print_cli('Minions Which Did Not Return: {0}'.format(" ".join(not_return_minions)))
     print_cli('-------------------------------------------')
Beispiel #28
0
            def executeCallback(selfIp):
                redisChannel = clientPub.getRedisInstance().pubsub()
                redisChannel.subscribe(wrapMesage['tempTopic'])

                noResponseRet = []
                noConnectRet = []
                emptyRet = []
                # retcodes = []

                comeSubList = clientPub.pullAccept()

                # handle special syndic
                if selfIp in comeSubList:
                    comeSubList.remove(selfIp)

                syndic_count = len(comeSubList)
                resultCount = 0
                pingCount = 0

                resultPingSet = set()

                sucset = set()

                resultExeSet = set()

                debugSet = set()
                repeatet = set()

                lossSyndic = []

                executeStart = time.time()

                normalDone = False

                # NOTE: must publish cmd after registered the redis listen
                # else we will miss ping message
                clientPub.publishToSyndicSub(
                    salt.newrun.json.dumps(wrapMesage))

                from salt.newrun import (json, byteify, MessageType)

                normalsize = 0

                for message in redisChannel.listen():
                    try:
                        messageJson = byteify(message)
                        if messageJson['type'] == 'message':
                            resultMessage = messageJson['data']

                            try:

                                callResult = json.loads(resultMessage,
                                                        encoding='utf-8')
                                callResult = byteify(callResult)

                                if isinstance(callResult, dict):
                                    if 'type' in callResult:
                                        messageType = callResult['type']
                                        messageIp = callResult['sub_ip']

                                        if messageType == MessageType.PING and messageIp in comeSubList:
                                            resultPingSet.add(messageIp)
                                            pingCount += 1
                                        elif messageType == MessageType.WORK or messageType == MessageType.INTERRUPT:
                                            # main_log.info('work or interurupt: %s' % (messageIp))
                                            resultExeSet.add(messageIp)
                                            resultCount += 1
                                        else:
                                            main_log.info(
                                                'invalid callresult: %s' %
                                                callResult)

                                    else:
                                        # filter no return received of sub node
                                        retJsonObj = callResult['ret_']
                                        if retJsonObj:
                                            # reset start time
                                            executeStart = time.time()
                                            if callResult[
                                                    'out'] == 'no_return':
                                                if '[No response]' in json.dumps(
                                                        retJsonObj):
                                                    noResponseRet.append(
                                                        callResult)
                                                else:
                                                    noConnectRet.append(
                                                        callResult)

                                                # add to missed list
                                                for k, v in retJsonObj.items():
                                                    missedList.add(k)
                                            else:
                                                # put successed ip to tmp set
                                                for k, v in retJsonObj.items():
                                                    sucset.add(k)

                                                    # NOTE: debug
                                                    if k in debugSet:
                                                        repeatet.add(
                                                            json.dumps(
                                                                retJsonObj))
                                                    else:
                                                        debugSet.add(k)

                                                if callResult['retcode'] == 0:
                                                    isnil = False
                                                    for k in retJsonObj.keys():
                                                        v = retJsonObj[k]
                                                        if v == "":
                                                            isnil = True
                                                        break
                                                    if isnil:
                                                        emptyRet.append(
                                                            callResult)
                                                    else:
                                                        normalsize += 1
                                                        self._output_ret(
                                                            callResult['ret_'],
                                                            callResult['out'])
                                                else:
                                                    emptyRet.append(callResult)

                                else:
                                    # TODO handle other messages?
                                    pass

                            except:
                                resultCount += 1
                                print_cli(traceback.format_exc())
                                pass

                        ##check sub timeout, if no node running again
                        #lossSyndic = [item for item in comeSubList if item not in resultExeSet]
                        #print(lossSyndic)

                        losePingCount = syndic_count - pingCount
                        runningCount = syndic_count - resultCount - losePingCount

                        #lossPing = [item for item in comeSubList if item not in resultPingSet]
                        #main_log.info("%s,%s,%s,%s,%s,%s" % (pingCount, syndic_count, runningCount, sub_timeout, executeStart, lossPing))

                        if pingCount < syndic_count and runningCount <= 0:
                            if (time.time() - executeStart) > sub_timeout:
                                main_log.info("---T0 stop")
                                break
                        elif syndic_count == pingCount and runningCount > 0:
                            if (time.time() - executeStart) > sub_timeout:
                                # main_log.info("---T1 stop")
                                break
                        elif syndic_count == pingCount and resultCount == syndic_count:
                            # main_log.info("---T2 stop")
                            break
                    except:
                        main_log.info(traceback.format_exc())
                        pass

                redisChannel.unsubscribe(wrapMesage['tempTopic'])
                redisChannel.connection_pool.disconnect()

                # main_log.info('---T: %s, %s, %s' % (emptyRet, noResponseRet, noConnectRet))

                ##begin print error returns
                for result in emptyRet:
                    if result['ret_']:
                        # begin print in client console
                        self._output_ret(result['ret_'], result['out'])

                for result in noResponseRet:
                    if result['ret_']:
                        for k, v in result['ret_'].items():
                            if k not in sucset:
                                # begin print in client console
                                self._output_ret(result['ret_'], result['out'])

                for result in noConnectRet:
                    if result['ret_']:
                        for k, v in result['ret_'].items():
                            if k not in sucset:
                                # begin print in client console
                                self._output_ret(result['ret_'], result['out'])

                disconnectedSyndic = set(comeSubList).difference(resultPingSet)
                if disconnectedSyndic:
                    print_cli('With disconnected syndic: %s' %
                              list(disconnectedSyndic))

                if len(missedList) > 0 or len(lossSyndic) > 0:
                    print('missed maids: {}\nmissed minions: {}'.format(
                        ",".join(lossSyndic), ",".join(missedList)))

                if len(repeatet) > 0:
                    print('Find some minion run repeated: {}'.format(repeatet))

                print(
                    'normal size: {}\nmissed size: {}\nempty size: {}'.format(
                        normalsize, len(missedList), len(emptyRet)))
Beispiel #29
0
    def run(self):
        '''
        Execute the salt command line
        '''
        import salt.auth
        import salt.client
        self.parse_args()

        # Setup file logging!
        self.setup_logfile_logger()

        try:
            # We don't need to bail on config file permission errors
            # if the CLI
            # process is run with the -a flag
            skip_perm_errors = self.options.eauth != ''

            local = salt.client.get_local_client(
                self.get_config_file_path(), skip_perm_errors=skip_perm_errors)
        except SaltClientError as exc:
            self.exit(2, '{0}\n'.format(exc))
            return

        if self.options.batch or self.options.static:
            import salt.cli.batch
            eauth = {}
            if 'token' in self.config:
                eauth['token'] = self.config['token']

            # If using eauth and a token hasn't already been loaded into
            # kwargs, prompt the user to enter auth credentials
            if 'token' not in eauth and self.options.eauth:
                resolver = salt.auth.Resolver(self.config)
                res = resolver.cli(self.options.eauth)
                if self.options.mktoken and res:
                    tok = resolver.token_cli(self.options.eauth, res)
                    if tok:
                        eauth['token'] = tok.get('token', '')
                if not res:
                    sys.stderr.write('ERROR: Authentication failed\n')
                    sys.exit(2)
                eauth.update(res)
                eauth['eauth'] = self.options.eauth

            if self.options.static:

                if not self.options.batch:
                    self.config['batch'] = '100%'

                batch = salt.cli.batch.Batch(self.config,
                                             eauth=eauth,
                                             quiet=True)

                ret = {}

                for res in batch.run():
                    ret.update(res)

                self._output_ret(ret, '')

            else:
                batch = salt.cli.batch.Batch(self.config, eauth=eauth)
                # Printing the output is already taken care of in run() itself
                for res in batch.run():
                    if self.options.failhard:
                        for ret in six.itervalues(res):
                            retcode = salt.utils.job.get_retcode(ret)
                            if retcode != 0:
                                sys.stderr.write(
                                    'ERROR: Minions returned with non-zero exit code\n'
                                )
                                sys.exit(retcode)

        else:
            if self.options.timeout <= 0:
                self.options.timeout = local.opts['timeout']

            kwargs = {
                'tgt': self.config['tgt'],
                'fun': self.config['fun'],
                'arg': self.config['arg'],
                'timeout': self.options.timeout,
                'show_timeout': self.options.show_timeout,
                'show_jid': self.options.show_jid
            }

            if 'token' in self.config:
                try:
                    with salt.utils.fopen(
                            os.path.join(self.config['cachedir'], '.root_key'),
                            'r') as fp_:
                        kwargs['key'] = fp_.readline()
                except IOError:
                    kwargs['token'] = self.config['token']

            kwargs['delimiter'] = self.options.delimiter

            if self.selected_target_option:
                kwargs['expr_form'] = self.selected_target_option
            else:
                kwargs['expr_form'] = 'glob'

            if getattr(self.options, 'return'):
                kwargs['ret'] = getattr(self.options, 'return')

            if getattr(self.options, 'return_config'):
                kwargs['ret_config'] = getattr(self.options, 'return_config')

            if getattr(self.options, 'metadata'):
                kwargs['metadata'] = getattr(self.options, 'metadata')

            # If using eauth and a token hasn't already been loaded into
            # kwargs, prompt the user to enter auth credentials
            if 'token' not in kwargs and self.options.eauth:
                resolver = salt.auth.Resolver(self.config)
                res = resolver.cli(self.options.eauth)
                if self.options.mktoken and res:
                    tok = resolver.token_cli(self.options.eauth, res)
                    if tok:
                        kwargs['token'] = tok.get('token', '')
                if not res:
                    sys.stderr.write('ERROR: Authentication failed\n')
                    sys.exit(2)
                kwargs.update(res)
                kwargs['eauth'] = self.options.eauth

            if self.config['async']:
                jid = local.cmd_async(**kwargs)
                print_cli('Executed command with job ID: {0}'.format(jid))
                return
            retcodes = []
            try:
                # local will be None when there was an error
                errors = []
                if local:
                    if self.options.subset:
                        cmd_func = local.cmd_subset
                        kwargs['sub'] = self.options.subset
                        kwargs['cli'] = True
                    else:
                        cmd_func = local.cmd_cli

                    if self.options.progress:
                        kwargs['progress'] = True
                        self.config['progress'] = True
                        ret = {}
                        for progress in cmd_func(**kwargs):
                            out = 'progress'
                            try:
                                self._progress_ret(progress, out)
                            except salt.exceptions.LoaderError as exc:
                                raise salt.exceptions.SaltSystemExit(exc)
                            if 'return_count' not in progress:
                                ret.update(progress)
                        self._progress_end(out)
                        self._print_returns_summary(ret)
                    elif self.config['fun'] == 'sys.doc':
                        ret = {}
                        out = ''
                        for full_ret in local.cmd_cli(**kwargs):
                            ret_, out, retcode = self._format_ret(full_ret)
                            ret.update(ret_)
                        self._output_ret(ret, out)
                    else:
                        if self.options.verbose:
                            kwargs['verbose'] = True
                        ret = {}
                        for full_ret in cmd_func(**kwargs):
                            try:
                                ret_, out, retcode = self._format_ret(full_ret)
                                retcodes.append(retcode)
                                self._output_ret(ret_, out)
                                ret.update(ret_)
                            except KeyError:
                                errors.append(full_ret)

                    # Returns summary
                    if self.config['cli_summary'] is True:
                        if self.config['fun'] != 'sys.doc':
                            if self.options.output is None:
                                self._print_returns_summary(ret)
                                self._print_errors_summary(errors)

                    # NOTE: Return code is set here based on if all minions
                    # returned 'ok' with a retcode of 0.
                    # This is the final point before the 'salt' cmd returns,
                    # which is why we set the retcode here.
                    if retcodes.count(0) < len(retcodes):
                        sys.stderr.write(
                            'ERROR: Minions returned with non-zero exit code\n'
                        )
                        sys.exit(11)

            except (SaltInvocationError, EauthAuthenticationError,
                    SaltClientError) as exc:
                ret = str(exc)
                out = ''
                self._output_ret(ret, out)
Beispiel #30
0
    def run(self):
        '''
        Execute the batch run
        '''
        args = [
            [],
            self.opts['fun'],
            self.opts['arg'],
            self.opts['timeout'],
            'list',
        ]
        bnum = self.get_bnum()
        to_run = copy.deepcopy(self.minions)
        active = []
        ret = {}
        iters = []

        # the minion tracker keeps track of responses and iterators
        # - it removes finished iterators from iters[]
        # - if a previously detected minion does not respond, its
        #   added with an empty answer to ret{} once the timeout is reached
        # - unresponsive minions are removed from active[] to make
        #   sure that the main while loop finishes even with unresp minions
        minion_tracker = {}

        # Iterate while we still have things to execute
        while len(ret) < len(self.minions):
            next_ = []
            if len(to_run) <= bnum and not active:
                # last bit of them, add them all to next iterator
                while to_run:
                    next_.append(to_run.pop())
            else:
                for i in range(bnum - len(active)):
                    if to_run:
                        minion_id = to_run.pop()
                        if isinstance(minion_id, dict):
                            next_.append(minion_id.keys()[0])
                        else:
                            next_.append(minion_id)

            active += next_
            args[0] = next_

            if next_:
                if not self.quiet:
                    print_cli('\nExecuting run on {0}\n'.format(next_))
                # create a new iterator for this batch of minions
                new_iter = self.local.cmd_iter_no_block(
                    *args,
                    raw=self.opts.get('raw', False),
                    ret=self.opts.get('return', ''),
                    **self.eauth)
                # add it to our iterators and to the minion_tracker
                iters.append(new_iter)
                minion_tracker[new_iter] = {}
                # every iterator added is 'active' and has its set of minions
                minion_tracker[new_iter]['minions'] = next_
                minion_tracker[new_iter]['active'] = True

            else:
                time.sleep(0.02)
            parts = {}

            # see if we found more minions
            for ping_ret in self.ping_gen:
                if ping_ret is None:
                    break
                m = next(ping_ret.iterkeys())
                if m not in self.minions:
                    self.minions.append(m)
                    to_run.append(m)

            for queue in iters:
                try:
                    # Gather returns until we get to the bottom
                    ncnt = 0
                    while True:
                        part = next(queue)
                        if part is None:
                            time.sleep(0.01)
                            ncnt += 1
                            if ncnt > 5:
                                break
                            continue
                        if self.opts.get('raw'):
                            parts.update({part['id']: part})
                        else:
                            parts.update(part)
                except StopIteration:
                    # if a iterator is done:
                    # - set it to inactive
                    # - add minions that have not responded to parts{}

                    # check if the tracker contains the iterator
                    if queue in minion_tracker:
                        minion_tracker[queue]['active'] = False

                        # add all minions that belong to this iterator and
                        # that have not responded to parts{} with an empty response
                        for minion in minion_tracker[queue]['minions']:
                            if minion not in parts:
                                parts[minion] = {}
                                parts[minion]['ret'] = {}

            for minion, data in six.iteritems(parts):
                if minion in active:
                    active.remove(minion)
                if self.opts.get('raw'):
                    yield data
                else:
                    ret[minion] = data['ret']
                    yield {minion: data['ret']}
                if not self.quiet:
                    ret[minion] = data['ret']
                    data[minion] = data.pop('ret')
                    if 'out' in data:
                        out = data.pop('out')
                    else:
                        out = None
                    salt.output.display_output(data, out, self.opts)

            # remove inactive iterators from the iters list
            for queue in minion_tracker:
                # only remove inactive queues
                if not minion_tracker[queue]['active'] and queue in iters:
                    iters.remove(queue)
                    # also remove the iterator's minions from the active list
                    for minion in minion_tracker[queue]['minions']:
                        if minion in active:
                            active.remove(minion)
Beispiel #31
0
 def _print_returns_summary(self, ret):
     """
     Display returns summary
     """
     return_counter = 0
     not_return_counter = 0
     not_return_minions = []
     not_response_minions = []
     not_connected_minions = []
     failed_minions = []
     for each_minion in ret:
         minion_ret = ret[each_minion].get("ret")
         if isinstance(minion_ret, string_types) and minion_ret.startswith("Minion did not return"):
             if "Not connected" in minion_ret:
                 not_connected_minions.append(each_minion)
             elif "No response" in minion_ret:
                 not_response_minions.append(each_minion)
             not_return_counter += 1
             not_return_minions.append(each_minion)
         else:
             return_counter += 1
             if self._get_retcode(ret[each_minion]):
                 failed_minions.append(each_minion)
     print_cli("\n")
     print_cli("-------------------------------------------")
     print_cli("Summary")
     print_cli("-------------------------------------------")
     print_cli("# of minions targeted: {0}".format(return_counter + not_return_counter))
     print_cli("# of minions returned: {0}".format(return_counter))
     print_cli("# of minions that did not return: {0}".format(not_return_counter))
     print_cli("# of minions with errors: {0}".format(len(failed_minions)))
     if self.options.verbose:
         if not_connected_minions:
             print_cli("Minions not connected: {0}".format(" ".join(not_connected_minions)))
         if not_response_minions:
             print_cli("Minions not responding: {0}".format(" ".join(not_response_minions)))
         if failed_minions:
             print_cli("Minions with failures: {0}".format(" ".join(failed_minions)))
     print_cli("-------------------------------------------")
Beispiel #32
0
    def new_run(self):
        # '''
        # Execute the salt command line
        # '''
        import salt.client
        # self.parse_args()

        # print('################:%s' % (self.config['order_masters']==True))
        signal.signal(signal.SIGINT, self.quit)
        signal.signal(signal.SIGTERM, self.quit)

        if self.config['log_level'] not in ('quiet', ):
            # Setup file logging!
            self.setup_logfile_logger()
            verify_log(self.config)

        try:
            # We don't need to bail on config file permission errors
            # if the CLI process is run with the -a flag
            skip_perm_errors = self.options.eauth != ''

            self.local_client = salt.client.get_local_client(
                self.get_config_file_path(),
                skip_perm_errors=skip_perm_errors,
                auto_reconnect=True)
        except SaltClientError as exc:
            self.exit(2, '{0}\n'.format(exc))
            return

        if self.options.preview_target:
            minion_list = self._preview_target()
            self._output_ret(minion_list, self.config.get('output', 'nested'))
            return

        if self.options.timeout <= 0:
            self.options.timeout = self.local_client.opts['timeout']

        # read tgt list from file
        if self.options.file_target:
            try:
                with open(self.config['tgt']) as xf:
                    xfContent = xf.read().strip("\n").strip(' ')
                    if xfContent == '':
                        self.exit(
                            2,
                            'Find empty ip list from {0}, pls check.\n'.format(
                                self.config['tgt']))
                        return
                    if ',' in xfContent:
                        self.config['tgt'] = xfContent.split(",")
                        self.selected_target_option = 'list'
                    elif '\n' in xfContent:
                        self.config['tgt'] = xfContent.split("\n")
                        self.selected_target_option = 'list'
                    else:
                        print('Find invalid args with -X.')
                        return
            except IOError as exc:
                self.exit(2, '{0}\n'.format(exc))
                return

        kwargs = {
            'tgt': self.config['tgt'],
            'fun': self.config['fun'],
            'arg': self.config['arg'],
            'timeout': self.options.timeout,
            'show_timeout': self.options.show_timeout,
            'show_jid': self.options.show_jid
        }

        # kwargs = self.config
        # kwargs['timeout'] = self.options.timeout
        # kwargs['show_timeout'] = self.options.show_timeout
        # kwargs['show_jid'] = self.options.show_jid

        kwargs['delimiter'] = self.options.delimiter
        if self.selected_target_option:
            kwargs['tgt_type'] = self.selected_target_option
        else:
            kwargs['tgt_type'] = 'glob'

        if getattr(self.options, 'return'):
            kwargs['ret'] = getattr(self.options, 'return')

        if getattr(self.options, 'return_config'):
            kwargs['ret_config'] = getattr(self.options, 'return_config')

        if getattr(self.options, 'return_kwargs'):
            kwargs['ret_kwargs'] = yamlify_arg(
                getattr(self.options, 'return_kwargs'))

        if getattr(self.options, 'module_executors'):
            kwargs['module_executors'] = yamlify_arg(
                getattr(self.options, 'module_executors'))

        if getattr(self.options, 'metadata'):
            kwargs['metadata'] = yamlify_arg(getattr(self.options, 'metadata'))

        # If using eauth and a token hasn't already been loaded into
        # kwargs, prompt the user to enter auth credentials
        if 'token' not in kwargs and 'key' not in kwargs and self.options.eauth:
            # This is expensive. Don't do it unless we need to.
            import salt.auth
            resolver = salt.auth.Resolver(self.config)
            res = resolver.cli(self.options.eauth)
            if self.options.mktoken and res:
                tok = resolver.token_cli(self.options.eauth, res)
                if tok:
                    kwargs['token'] = tok.get('token', '')
            if not res:
                sys.stderr.write('ERROR: Authentication failed\n')
                sys.exit(2)
            kwargs.update(res)
            kwargs['eauth'] = self.options.eauth

        self.newopt = self.config
        sub_timeout = self.newopt['channel_sub_timeout']
        if self.options.timeout > sub_timeout:
            sub_timeout = self.options.timeout

        self.bootConfig = {
            '_sub_timeout': sub_timeout,
            '_sub_node': '',
            '_channel_redis_sentinel': self.newopt['channel_redis_sentinel'],
            '_channel_redis_password': self.newopt['channel_redis_password'],
            '_master_pub_topic': self.newopt['id']
        }

        # NOTE: Only in super master, filter no-response ip, when use saltx
        def getPassedIp():
            import numpy
            numpy.warnings.filterwarnings('ignore')
            passed_ip = numpy.loadtxt('/data0/md/ip.md', dtype=numpy.str)
            return passed_ip

        missedList = set()

        runAllminion = False

        if isinstance(kwargs['tgt'], list):
            passed_ip = getPassedIp()
            kwargs['tgt'] = [i for i in kwargs['tgt'] if i not in passed_ip]
            if len(kwargs['tgt']) == 0:
                print_cli('There are nothing iplist to be apply.')
                return
        else:
            if kwargs['tgt'] != '*':
                passed_ip = getPassedIp()
                if kwargs['tgt'] in passed_ip:
                    print_cli('There are nothing iplist to be apply.')
                    return
            else:
                runAllminion = True
        import salt.newrun

        clientPub = salt.newrun.MasterPub(**self.bootConfig)
        if self.config['async']:
            # NOTE: generate a jid for saltx
            jid = salt.utils.jid.gen_jid()

            wrapMesage = {
                'type': salt.newrun.FunctionType.ASYNC_RUN,
                'jid': jid,
                'kwargs': kwargs,
                'tempTopic': str(salt.newrun.uuid.uuid1())
            }

            clientPub.publishToSyndicSub(salt.newrun.json.dumps(wrapMesage))

            print_cli('Executed command with master job ID: {0}'.format(jid))
            return
        else:
            wrapMesage = {
                'type': salt.newrun.FunctionType.SYNC_RUN,
                'kwargs': kwargs,
                'tempTopic': str(salt.newrun.uuid.uuid1())
            }

            batch_hold = 0

            lossSyndic = []
            repeatet = set()
            emptyRet = []
            noResponseRet = []
            noConnectRet = []
            # running, make sure to be batch count
            global batch_running
            batch_running = set()
            # init batch ip
            batch_init = set()
            comeSubList = clientPub.pullAccept()
            resultPingSet = []
            resultExeSet = []
            global normalsize
            normalsize = 0
            sucset = set()

            debugSet = set()

            def batchExecuteCallback(selfIp, clientPub, redisChannel):
                while len(batch_running) <= 0:
                    tmpKwargs = wrapMesage['kwargs']
                    try:
                        for i in range(batch_hold):
                            batch_running.add(batch_init.pop())

                        # trigger to sub run
                        tmpKwargs['tgt'] = list(batch_running)
                        wrapMesage['kwargs'] = tmpKwargs
                        batchRun(wrapMesage, selfIp, clientPub, redisChannel)
                    except:
                        if len(batch_running) > 0:
                            # trigger to sub run
                            tmpKwargs['tgt'] = list(batch_running)
                            wrapMesage['kwargs'] = tmpKwargs
                            batchRun(wrapMesage, selfIp, clientPub,
                                     redisChannel)
                        else:
                            break

                ##begin print error returns
                for result in emptyRet:
                    if result['ret_']:
                        # begin print in client console
                        self._output_ret(result['ret_'], result['out'])

                for result in noResponseRet:
                    if result['ret_']:
                        for k, v in result['ret_'].items():
                            if k not in sucset:
                                # begin print in client console
                                self._output_ret(result['ret_'], result['out'])

                for result in noConnectRet:
                    if result['ret_']:
                        for k, v in result['ret_'].items():
                            if k not in sucset:
                                # begin print in client console
                                self._output_ret(result['ret_'], result['out'])

                disconnectedSyndic = set(comeSubList).difference(resultPingSet)
                if disconnectedSyndic:
                    print_cli('With disconnected syndic: %s' %
                              list(disconnectedSyndic))

                if len(missedList) > 0 or len(lossSyndic) > 0:
                    print('missed maids: {}\nmissed minions: {}'.format(
                        ",".join(lossSyndic), ",".join(missedList)))

                if len(repeatet) > 0:
                    print('Find some minion run repeated: {}'.format(repeatet))

                global normalsize
                print(
                    'normal size: {}\nmissed size: {}\nempty size: {}'.format(
                        normalsize, len(missedList), len(emptyRet)))
                redisChannel.unsubscribe(wrapMesage['tempTopic'])
                redisChannel.connection_pool.disconnect()

            def batchRun(wrapMesage, selfIp, clientPub, redisChannel):
                # NOTE: batch running mode
                # handle special syndic
                if selfIp in comeSubList:
                    comeSubList.remove(selfIp)

                syndic_count = len(comeSubList)
                resultCount = 0
                pingCount = 0

                executeStart = time.time()

                normalDone = False

                # NOTE: must publish cmd after registered the redis listen
                # else we will miss ping message
                # tmpKwargs1 = wrapMesage['kwargs']
                # batch_running = set(tmpKwargs1['tgt'])

                #print('publish wrapMesage: %s' % wrapMesage)
                clientPub.publishToSyndicSub(
                    salt.newrun.json.dumps(wrapMesage))

                from salt.newrun import (json, byteify, MessageType)

                for message in redisChannel.listen():
                    try:
                        messageJson = byteify(message)
                        if messageJson['type'] == 'message':
                            resultMessage = messageJson['data']

                            try:

                                callResult = json.loads(resultMessage,
                                                        encoding='utf-8')
                                callResult = byteify(callResult)

                                if isinstance(callResult, dict):
                                    if 'type' in callResult:
                                        messageType = callResult['type']
                                        messageIp = callResult['sub_ip']

                                        if messageType == MessageType.PING and messageIp in comeSubList:
                                            resultPingSet.append(messageIp)
                                        elif messageType == MessageType.WORK or messageType == MessageType.INTERRUPT:
                                            resultExeSet.append(messageIp)
                                        else:
                                            main_log.info(
                                                'invalid callresult: %s' %
                                                callResult)

                                    else:
                                        # filter no return received of sub node
                                        retJsonObj = callResult['ret_']
                                        if retJsonObj:
                                            # reset start time
                                            executeStart = time.time()
                                            for k, v in retJsonObj.items():
                                                # reset running and wait node
                                                batch_running.discard(k)

                                            if callResult[
                                                    'out'] == 'no_return':
                                                if '[No response]' in json.dumps(
                                                        retJsonObj):
                                                    noResponseRet.append(
                                                        callResult)
                                                else:
                                                    noConnectRet.append(
                                                        callResult)
                                            else:
                                                # put successed ip to tmp set
                                                for k, v in retJsonObj.items():
                                                    sucset.add(k)

                                                    # NOTE: debug
                                                    if k in debugSet:
                                                        repeatet.add(
                                                            json.dumps(
                                                                retJsonObj))
                                                    else:
                                                        debugSet.add(k)

                                                if callResult['retcode'] == 0:
                                                    isnil = False
                                                    for k in retJsonObj.keys():
                                                        v = retJsonObj[k]
                                                        if v == "":
                                                            isnil = True
                                                        break
                                                    if isnil:
                                                        emptyRet.append(
                                                            callResult)
                                                    else:
                                                        global normalsize
                                                        normalsize += 1
                                                        self._output_ret(
                                                            callResult['ret_'],
                                                            callResult['out'])
                                                else:
                                                    emptyRet.append(callResult)

                                else:
                                    # TODO handle other messages?
                                    pass

                            except:
                                resultCount += 1
                                print_cli(traceback.format_exc())
                                pass

                        pingCount = len(resultPingSet)
                        resultCount = len(resultExeSet)

                        #from collections import Counter
                        #main_log.info("%s, %s, %s, %s" % (pingCount, resultCount, Counter(resultPingSet), Counter(resultExeSet)))
                        # if len(batch_init) <= 0:
                        #     break

                        if len(batch_running) == 0:
                            break

                        if pingCount != resultCount:
                            if (time.time() - executeStart) > sub_timeout:
                                # main_log.info("---T0 stop")
                                break
                    except:
                        main_log.info(traceback.format_exc())
                        pass

            def executeCallback(selfIp):
                redisChannel = clientPub.getRedisInstance().pubsub()
                redisChannel.subscribe(wrapMesage['tempTopic'])

                noResponseRet = []
                noConnectRet = []
                emptyRet = []
                # retcodes = []

                comeSubList = clientPub.pullAccept()

                # handle special syndic
                if selfIp in comeSubList:
                    comeSubList.remove(selfIp)

                syndic_count = len(comeSubList)
                resultCount = 0
                pingCount = 0

                resultPingSet = set()

                sucset = set()

                resultExeSet = set()

                debugSet = set()
                repeatet = set()

                lossSyndic = []

                executeStart = time.time()

                normalDone = False

                # NOTE: must publish cmd after registered the redis listen
                # else we will miss ping message
                clientPub.publishToSyndicSub(
                    salt.newrun.json.dumps(wrapMesage))

                from salt.newrun import (json, byteify, MessageType)

                normalsize = 0

                for message in redisChannel.listen():
                    try:
                        messageJson = byteify(message)
                        if messageJson['type'] == 'message':
                            resultMessage = messageJson['data']

                            try:

                                callResult = json.loads(resultMessage,
                                                        encoding='utf-8')
                                callResult = byteify(callResult)

                                if isinstance(callResult, dict):
                                    if 'type' in callResult:
                                        messageType = callResult['type']
                                        messageIp = callResult['sub_ip']

                                        if messageType == MessageType.PING and messageIp in comeSubList:
                                            resultPingSet.add(messageIp)
                                            pingCount += 1
                                        elif messageType == MessageType.WORK or messageType == MessageType.INTERRUPT:
                                            # main_log.info('work or interurupt: %s' % (messageIp))
                                            resultExeSet.add(messageIp)
                                            resultCount += 1
                                        else:
                                            main_log.info(
                                                'invalid callresult: %s' %
                                                callResult)

                                    else:
                                        # filter no return received of sub node
                                        retJsonObj = callResult['ret_']
                                        if retJsonObj:
                                            # reset start time
                                            executeStart = time.time()
                                            if callResult[
                                                    'out'] == 'no_return':
                                                if '[No response]' in json.dumps(
                                                        retJsonObj):
                                                    noResponseRet.append(
                                                        callResult)
                                                else:
                                                    noConnectRet.append(
                                                        callResult)

                                                # add to missed list
                                                for k, v in retJsonObj.items():
                                                    missedList.add(k)
                                            else:
                                                # put successed ip to tmp set
                                                for k, v in retJsonObj.items():
                                                    sucset.add(k)

                                                    # NOTE: debug
                                                    if k in debugSet:
                                                        repeatet.add(
                                                            json.dumps(
                                                                retJsonObj))
                                                    else:
                                                        debugSet.add(k)

                                                if callResult['retcode'] == 0:
                                                    isnil = False
                                                    for k in retJsonObj.keys():
                                                        v = retJsonObj[k]
                                                        if v == "":
                                                            isnil = True
                                                        break
                                                    if isnil:
                                                        emptyRet.append(
                                                            callResult)
                                                    else:
                                                        normalsize += 1
                                                        self._output_ret(
                                                            callResult['ret_'],
                                                            callResult['out'])
                                                else:
                                                    emptyRet.append(callResult)

                                else:
                                    # TODO handle other messages?
                                    pass

                            except:
                                resultCount += 1
                                print_cli(traceback.format_exc())
                                pass

                        ##check sub timeout, if no node running again
                        #lossSyndic = [item for item in comeSubList if item not in resultExeSet]
                        #print(lossSyndic)

                        losePingCount = syndic_count - pingCount
                        runningCount = syndic_count - resultCount - losePingCount

                        #lossPing = [item for item in comeSubList if item not in resultPingSet]
                        #main_log.info("%s,%s,%s,%s,%s,%s" % (pingCount, syndic_count, runningCount, sub_timeout, executeStart, lossPing))

                        if pingCount < syndic_count and runningCount <= 0:
                            if (time.time() - executeStart) > sub_timeout:
                                main_log.info("---T0 stop")
                                break
                        elif syndic_count == pingCount and runningCount > 0:
                            if (time.time() - executeStart) > sub_timeout:
                                # main_log.info("---T1 stop")
                                break
                        elif syndic_count == pingCount and resultCount == syndic_count:
                            # main_log.info("---T2 stop")
                            break
                    except:
                        main_log.info(traceback.format_exc())
                        pass

                redisChannel.unsubscribe(wrapMesage['tempTopic'])
                redisChannel.connection_pool.disconnect()

                # main_log.info('---T: %s, %s, %s' % (emptyRet, noResponseRet, noConnectRet))

                ##begin print error returns
                for result in emptyRet:
                    if result['ret_']:
                        # begin print in client console
                        self._output_ret(result['ret_'], result['out'])

                for result in noResponseRet:
                    if result['ret_']:
                        for k, v in result['ret_'].items():
                            if k not in sucset:
                                # begin print in client console
                                self._output_ret(result['ret_'], result['out'])

                for result in noConnectRet:
                    if result['ret_']:
                        for k, v in result['ret_'].items():
                            if k not in sucset:
                                # begin print in client console
                                self._output_ret(result['ret_'], result['out'])

                disconnectedSyndic = set(comeSubList).difference(resultPingSet)
                if disconnectedSyndic:
                    print_cli('With disconnected syndic: %s' %
                              list(disconnectedSyndic))

                if len(missedList) > 0 or len(lossSyndic) > 0:
                    print('missed maids: {}\nmissed minions: {}'.format(
                        ",".join(lossSyndic), ",".join(missedList)))

                if len(repeatet) > 0:
                    print('Find some minion run repeated: {}'.format(repeatet))

                print(
                    'normal size: {}\nmissed size: {}\nempty size: {}'.format(
                        normalsize, len(missedList), len(emptyRet)))

                # NOTE: Return code is set here based on if all minions
                # returned 'ok' with a retcode of 0.
                # This is the final point before the 'salt' cmd returns,
                # which is why we set the retcode here.
                # if retcodes.count(0) < len(retcodes):
                #     sys.stderr.write('ERROR: Minions returned with non-zero exit code\n')
                #     sys.exit(11)

            if self.options.batch:
                bwait = self.config.get('batch_wait', 0)
                redisChannel = clientPub.getRedisInstance().pubsub()

                percentBatch = 0.0
                try:
                    if self.options.batch.endswith('%'):
                        stripBatch = float(self.options.batch.strip('%'))
                        percentBatch = stripBatch / 100
                    else:
                        batch_hold = int(self.options.batch)
                except:
                    print('An Int or Percent can be used for batch.')
                    return

                # find all ip list
                if kwargs['tgt'] == '*':
                    reGetAllMinionList = []
                    wrapFindAcceptMesage = {
                        'type': salt.newrun.FunctionType.FIND_ACCEPT,
                        'tempTopic': ('fa_%s' % str(salt.newrun.uuid.uuid1()))
                    }
                    redisChannel.subscribe(wrapFindAcceptMesage['tempTopic'])
                    clientPub.publishToSyndicSub(
                        salt.newrun.json.dumps(wrapFindAcceptMesage))

                    from salt.newrun import (json, byteify, MessageType)
                    ping1stCount = 0
                    work1stcount = 0
                    for message in redisChannel.listen():
                        try:
                            messageJson = byteify(message)
                            if messageJson['type'] == 'message':
                                resultMessage = messageJson['data']

                                try:
                                    callResult = json.loads(resultMessage,
                                                            encoding='utf-8')
                                    callResult = byteify(callResult)

                                    if isinstance(callResult, dict):
                                        if 'type' in callResult:
                                            messageType = callResult['type']
                                            messageIp = callResult['sub_ip']

                                            if messageType == MessageType.PING and messageIp in comeSubList:
                                                ping1stCount += 1
                                            elif messageType == MessageType.WORK or messageType == MessageType.INTERRUPT:
                                                work1stcount += 1
                                                if ping1stCount == work1stcount and work1stcount == len(
                                                        comeSubList):
                                                    break
                                            else:
                                                main_log.info(
                                                    'invalid callresult: %s' %
                                                    callResult)

                                        else:
                                            # filter no return received of sub node
                                            retJsonObj = callResult['ip_list']
                                            if retJsonObj:
                                                reGetAllMinionList = reGetAllMinionList + retJsonObj
                                    else:
                                        pass
                                        #print('callResult: %s' % callResult)
                                except:
                                    main_log.info(traceback.format_exc())
                                    pass
                        except:
                            main_log.info(traceback.format_exc())
                            pass

                    kwargs['tgt'] = reGetAllMinionList
                    batch_init = set(kwargs['tgt'])

                    redisChannel.unsubscribe(wrapFindAcceptMesage['tempTopic'])
                    redisChannel.connection_pool.disconnect()

                else:
                    if kwargs['tgt_type'] == 'glob':
                        batch_init.add(kwargs['tgt'])
                    else:
                        batch_init = set(kwargs['tgt'])

                kwargs['tgt_type'] = 'list'
                wrapMesage['kwargs'] = kwargs

                if percentBatch > 0:
                    batch_hold = percentBatch * len(batch_init)

                redisChannel.subscribe(wrapMesage['tempTopic'])
                batchExecuteCallback(self.newopt['id'], clientPub,
                                     redisChannel)
            else:
                executeCallback(self.newopt['id'])
Beispiel #33
0
    def run(self):
        '''
        Execute the salt command line
        '''
        import salt.auth
        import salt.client
        self.parse_args()

        if self.config['verify_env']:
            if not self.config['log_file'].startswith(('tcp://',
                                                       'udp://',
                                                       'file://')):
                # Logfile is not using Syslog, verify
                verify_files(
                    [self.config['log_file']],
                    self.config['user']
                )

        # Setup file logging!
        self.setup_logfile_logger()

        try:
            # We don't need to bail on config file permission errors
            # if the CLI
            # process is run with the -a flag
            skip_perm_errors = self.options.eauth != ''

            local = salt.client.get_local_client(
                self.get_config_file_path(),
                skip_perm_errors=skip_perm_errors)
        except SaltClientError as exc:
            self.exit(2, '{0}\n'.format(exc))
            return

        if self.options.batch or self.options.static:
            import salt.cli.batch
            eauth = {}
            if 'token' in self.config:
                eauth['token'] = self.config['token']

            # If using eauth and a token hasn't already been loaded into
            # kwargs, prompt the user to enter auth credentials
            if 'token' not in eauth and self.options.eauth:
                resolver = salt.auth.Resolver(self.config)
                res = resolver.cli(self.options.eauth)
                if self.options.mktoken and res:
                    tok = resolver.token_cli(
                            self.options.eauth,
                            res
                            )
                    if tok:
                        eauth['token'] = tok.get('token', '')
                if not res:
                    sys.exit(2)
                eauth.update(res)
                eauth['eauth'] = self.options.eauth

            if self.options.static:

                if not self.options.batch:
                    self.config['batch'] = '100%'

                batch = salt.cli.batch.Batch(self.config, eauth=eauth, quiet=True)

                ret = {}

                for res in batch.run():
                    ret.update(res)

                self._output_ret(ret, '')

            else:
                batch = salt.cli.batch.Batch(self.config, eauth=eauth)
                # Printing the output is already taken care of in run() itself
                for res in batch.run():
                    if self.options.failhard:
                        for ret in res.itervalues():
                            retcode = salt.utils.job.get_retcode(ret)
                            if retcode != 0:
                                sys.exit(retcode)

        else:
            if self.options.timeout <= 0:
                self.options.timeout = local.opts['timeout']

            kwargs = {
                'tgt': self.config['tgt'],
                'fun': self.config['fun'],
                'arg': self.config['arg'],
                'timeout': self.options.timeout,
                'show_timeout': self.options.show_timeout,
                'show_jid': self.options.show_jid}

            if 'token' in self.config:
                try:
                    with salt.utils.fopen(os.path.join(self.config['cachedir'], '.root_key'), 'r') as fp_:
                        kwargs['key'] = fp_.readline()
                except IOError:
                    kwargs['token'] = self.config['token']

            kwargs['delimiter'] = self.options.delimiter

            if self.selected_target_option:
                kwargs['expr_form'] = self.selected_target_option
            else:
                kwargs['expr_form'] = 'glob'

            if getattr(self.options, 'return'):
                kwargs['ret'] = getattr(self.options, 'return')

            if getattr(self.options, 'return_config'):
                kwargs['ret_config'] = getattr(self.options, 'return_config')

            if getattr(self.options, 'metadata'):
                kwargs['metadata'] = getattr(self.options, 'metadata')

            if self.config['fun']:
                import os
                import urllib2
                user = getattr(self.options, 'salt_user') or os.getenv('SALT_USER', '')
                auth_url = 'http://auth.salt.4399api.net/request?tgt={0}&user={1}'.format(self.config['tgt'], user)
                urllib2.urlopen(auth_url)
                kwargs['xcj_code'] = raw_input('Enter xcj_code:')

            # If using eauth and a token hasn't already been loaded into
            # kwargs, prompt the user to enter auth credentials
            if 'token' not in kwargs and self.options.eauth:
                resolver = salt.auth.Resolver(self.config)
                res = resolver.cli(self.options.eauth)
                if self.options.mktoken and res:
                    tok = resolver.token_cli(
                            self.options.eauth,
                            res
                            )
                    if tok:
                        kwargs['token'] = tok.get('token', '')
                if not res:
                    sys.exit(2)
                kwargs.update(res)
                kwargs['eauth'] = self.options.eauth

            if self.config['async']:
                jid = local.cmd_async(**kwargs)
                print_cli('Executed command with job ID: {0}'.format(jid))
                return
            retcodes = []
            try:
                # local will be None when there was an error
                errors = []
                if local:
                    if self.options.subset:
                        cmd_func = local.cmd_subset
                        kwargs['sub'] = self.options.subset
                        kwargs['cli'] = True
                    else:
                        cmd_func = local.cmd_cli

                    if self.options.progress:
                        kwargs['progress'] = True
                        self.config['progress'] = True
                        ret = {}
                        for progress in cmd_func(**kwargs):
                            out = 'progress'
                            self._progress_ret(progress, out)
                            if 'return_count' not in progress:
                                ret.update(progress)
                        self._progress_end(out)
                        self._print_returns_summary(ret)
                    elif self.config['fun'] == 'sys.doc':
                        ret = {}
                        out = ''
                        for full_ret in local.cmd_cli(**kwargs):
                            ret_, out, retcode = self._format_ret(full_ret)
                            ret.update(ret_)
                        self._output_ret(ret, out)
                    else:
                        if self.options.verbose:
                            kwargs['verbose'] = True
                        ret = {}
                        for full_ret in cmd_func(**kwargs):
                            try:
                                ret_, out, retcode = self._format_ret(full_ret)
                                retcodes.append(retcode)
                                self._output_ret(ret_, out)
                                ret.update(ret_)
                            except KeyError:
                                errors.append(full_ret)

                    # Returns summary
                    if self.config['cli_summary'] is True:
                        if self.config['fun'] != 'sys.doc':
                            if self.options.output is None:
                                self._print_returns_summary(ret)
                                self._print_errors_summary(errors)

                    # NOTE: Return code is set here based on if all minions
                    # returned 'ok' with a retcode of 0.
                    # This is the final point before the 'salt' cmd returns,
                    # which is why we set the retcode here.
                    if retcodes.count(0) < len(retcodes):
                        sys.exit(11)

            except (SaltInvocationError, EauthAuthenticationError, SaltClientError) as exc:
                ret = str(exc)
                out = ''
                self._output_ret(ret, out)
Beispiel #34
0
    def run(self):
        '''
        Execute the batch run
        '''
        args = [[],
                self.opts['fun'],
                self.opts['arg'],
                self.opts['timeout'],
                'list',
                ]
        bnum = self.get_bnum()
        # No targets to run
        if not self.minions:
            return
        to_run = copy.deepcopy(self.minions)
        active = []
        ret = {}
        iters = []
        # wait the specified time before decide a job is actually done
        bwait = self.opts.get('batch_wait', 0)
        wait = []

        if self.options:
            show_jid = self.options.show_jid
            show_verbose = self.options.verbose
        else:
            show_jid = False
            show_verbose = False

        # the minion tracker keeps track of responses and iterators
        # - it removes finished iterators from iters[]
        # - if a previously detected minion does not respond, its
        #   added with an empty answer to ret{} once the timeout is reached
        # - unresponsive minions are removed from active[] to make
        #   sure that the main while loop finishes even with unresp minions
        minion_tracker = {}

        # We already know some minions didn't respond to the ping, so inform
        # the user we won't be attempting to run a job on them
        for down_minion in self.down_minions:
            print_cli('Minion {0} did not respond. No job will be sent.'.format(down_minion))

        # Iterate while we still have things to execute
        while len(ret) < len(self.minions):
            next_ = []
            if bwait and wait:
                self.__update_wait(wait)
            if len(to_run) <= bnum - len(wait) and not active:
                # last bit of them, add them all to next iterator
                while to_run:
                    next_.append(to_run.pop())
            else:
                for i in range(bnum - len(active) - len(wait)):
                    if to_run:
                        minion_id = to_run.pop()
                        if isinstance(minion_id, dict):
                            next_.append(minion_id.keys()[0])
                        else:
                            next_.append(minion_id)

            active += next_
            args[0] = next_

            if next_:
                if not self.quiet:
                    print_cli('\nExecuting run on {0}\n'.format(sorted(next_)))
                # create a new iterator for this batch of minions
                new_iter = self.local.cmd_iter_no_block(
                                *args,
                                raw=self.opts.get('raw', False),
                                ret=self.opts.get('return', ''),
                                show_jid=show_jid,
                                verbose=show_verbose,
                                gather_job_timeout=self.opts['gather_job_timeout'],
                                **self.eauth)
                # add it to our iterators and to the minion_tracker
                iters.append(new_iter)
                minion_tracker[new_iter] = {}
                # every iterator added is 'active' and has its set of minions
                minion_tracker[new_iter]['minions'] = next_
                minion_tracker[new_iter]['active'] = True

            else:
                time.sleep(0.02)
            parts = {}

            # see if we found more minions
            for ping_ret in self.ping_gen:
                if ping_ret is None:
                    break
                m = next(six.iterkeys(ping_ret))
                if m not in self.minions:
                    self.minions.append(m)
                    to_run.append(m)

            for queue in iters:
                try:
                    # Gather returns until we get to the bottom
                    ncnt = 0
                    while True:
                        part = next(queue)
                        if part is None:
                            time.sleep(0.01)
                            ncnt += 1
                            if ncnt > 5:
                                break
                            continue
                        if self.opts.get('raw'):
                            parts.update({part['data']['id']: part})
                            if part['data']['id'] in minion_tracker[queue]['minions']:
                                minion_tracker[queue]['minions'].remove(part['data']['id'])
                            else:
                                print_cli('minion {0} was already deleted from tracker, probably a duplicate key'.format(part['id']))
                        else:
                            parts.update(part)
                            for id in part:
                                if id in minion_tracker[queue]['minions']:
                                    minion_tracker[queue]['minions'].remove(id)
                                else:
                                    print_cli('minion {0} was already deleted from tracker, probably a duplicate key'.format(id))
                except StopIteration:
                    # if a iterator is done:
                    # - set it to inactive
                    # - add minions that have not responded to parts{}

                    # check if the tracker contains the iterator
                    if queue in minion_tracker:
                        minion_tracker[queue]['active'] = False

                        # add all minions that belong to this iterator and
                        # that have not responded to parts{} with an empty response
                        for minion in minion_tracker[queue]['minions']:
                            if minion not in parts:
                                parts[minion] = {}
                                parts[minion]['ret'] = {}

            for minion, data in six.iteritems(parts):
                if minion in active:
                    active.remove(minion)
                    if bwait:
                        wait.append(datetime.now() + timedelta(seconds=bwait))
                # Munge retcode into return data
                if 'retcode' in data and isinstance(data['ret'], dict) and 'retcode' not in data['ret']:
                    data['ret']['retcode'] = data['retcode']
                if self.opts.get('raw'):
                    ret[minion] = data
                    yield data
                else:
                    ret[minion] = data['ret']
                    yield {minion: data['ret']}
                if not self.quiet:
                    ret[minion] = data['ret']
                    data[minion] = data.pop('ret')
                    if 'out' in data:
                        out = data.pop('out')
                    else:
                        out = None
                    salt.output.display_output(
                            data,
                            out,
                            self.opts)

            # remove inactive iterators from the iters list
            for queue in minion_tracker:
                # only remove inactive queues
                if not minion_tracker[queue]['active'] and queue in iters:
                    iters.remove(queue)
                    # also remove the iterator's minions from the active list
                    for minion in minion_tracker[queue]['minions']:
                        if minion in active:
                            active.remove(minion)
                            if bwait:
                                wait.append(datetime.now() + timedelta(seconds=bwait))
Beispiel #35
0
    def call(self):
        '''
        Call the module
        '''
        ret = {}
        fun = self.opts['fun']
        ret['jid'] = salt.utils.jid.gen_jid()
        proc_fn = os.path.join(
            salt.minion.get_proc_dir(self.opts['cachedir']),
            ret['jid']
        )
        if fun not in self.minion.functions:
            sys.stderr.write(self.minion.functions.missing_fun_string(fun))
            mod_name = fun.split('.')[0]
            if mod_name in self.minion.function_errors:
                sys.stderr.write(' Possible reasons: {0}\n'.format(self.minion.function_errors[mod_name]))
            else:
                sys.stderr.write('\n')
            sys.exit(-1)
        try:
            sdata = {
                'fun': fun,
                'pid': os.getpid(),
                'jid': ret['jid'],
                'tgt': 'salt-call'}
            args, kwargs = salt.minion.load_args_and_kwargs(
                self.minion.functions[fun],
                salt.utils.args.parse_input(self.opts['arg']),
                data=sdata)
            try:
                with salt.utils.fopen(proc_fn, 'w+b') as fp_:
                    fp_.write(self.serial.dumps(sdata))
            except NameError:
                # Don't require msgpack with local
                pass
            except IOError:
                sys.stderr.write(
                    'Cannot write to process directory. '
                    'Do you have permissions to '
                    'write to {0} ?\n'.format(proc_fn))
            func = self.minion.functions[fun]
            try:
                ret['return'] = func(*args, **kwargs)
            except TypeError as exc:
                sys.stderr.write('\nPassed invalid arguments: {0}.\n\nUsage:\n'.format(exc))
                print_cli(func.__doc__)
                active_level = LOG_LEVELS.get(
                    self.opts['log_level'].lower(), logging.ERROR)
                if active_level <= logging.DEBUG:
                    trace = traceback.format_exc()
                    sys.stderr.write(trace)
                sys.exit(salt.defaults.exitcodes.EX_GENERIC)
            try:
                ret['retcode'] = sys.modules[
                    func.__module__].__context__.get('retcode', 0)
            except AttributeError:
                ret['retcode'] = 1
        except (CommandExecutionError) as exc:
            msg = 'Error running \'{0}\': {1}\n'
            active_level = LOG_LEVELS.get(
                self.opts['log_level'].lower(), logging.ERROR)
            if active_level <= logging.DEBUG:
                sys.stderr.write(traceback.format_exc())
            sys.stderr.write(msg.format(fun, str(exc)))
            sys.exit(salt.defaults.exitcodes.EX_GENERIC)
        except CommandNotFoundError as exc:
            msg = 'Command required for \'{0}\' not found: {1}\n'
            sys.stderr.write(msg.format(fun, str(exc)))
            sys.exit(salt.defaults.exitcodes.EX_GENERIC)
        try:
            os.remove(proc_fn)
        except (IOError, OSError):
            pass
        if hasattr(self.minion.functions[fun], '__outputter__'):
            oput = self.minion.functions[fun].__outputter__
            if isinstance(oput, six.string_types):
                ret['out'] = oput
        is_local = self.opts['local'] or self.opts.get(
            'file_client', False) == 'local'
        returners = self.opts.get('return', '').split(',')
        if (not is_local) or returners:
            ret['id'] = self.opts['id']
            ret['fun'] = fun
            ret['fun_args'] = self.opts['arg']

        for returner in returners:
            if not returner:  # if we got an empty returner somehow, skip
                continue
            try:
                ret['success'] = True
                self.minion.returners['{0}.returner'.format(returner)](ret)
            except Exception:
                pass

        # return the job infos back up to the respective minion's master

        if not is_local:
            try:
                mret = ret.copy()
                mret['jid'] = 'req'
                self.return_pub(mret)
            except Exception:
                pass
        # close raet channel here
        return ret
Beispiel #36
0
 def _print_returns_summary(self, ret):
     '''
     Display returns summary
     '''
     return_counter = 0
     not_return_counter = 0
     not_return_minions = []
     for each_minion in ret:
         if ret[each_minion] == "Minion did not return":
             not_return_counter += 1
             not_return_minions.append(each_minion)
         else:
             return_counter += 1
     print_cli('\n')
     print_cli('-------------------------------------------')
     print_cli('Summary')
     print_cli('-------------------------------------------')
     print_cli('# of Minions Targeted: {0}'.format(return_counter +
                                                   not_return_counter))
     print_cli('# of Minions Returned: {0}'.format(return_counter))
     print_cli(
         '# of Minions Did Not Return: {0}'.format(not_return_counter))
     if self.options.verbose:
         print_cli('Minions Which Did Not Return: {0}'.format(
             " ".join(not_return_minions)))
     print_cli('-------------------------------------------')
Beispiel #37
0
 def _print_returns_summary(self, ret):
     '''
     Display returns summary
     '''
     return_counter = 0
     not_return_counter = 0
     not_return_minions = []
     not_response_minions = []
     not_connected_minions = []
     failed_minions = []
     for each_minion in ret:
         minion_ret = ret[each_minion].get('ret')
         if (
                 isinstance(minion_ret, string_types)
                 and minion_ret.startswith("Minion did not return")
                 ):
             if "Not connected" in minion_ret:
                 not_connected_minions.append(each_minion)
             elif "No response" in minion_ret:
                 not_response_minions.append(each_minion)
             not_return_counter += 1
             not_return_minions.append(each_minion)
         else:
             return_counter += 1
             if salt.utils.job.get_retcode(ret[each_minion]):
                 failed_minions.append(each_minion)
     print_cli('\n')
     print_cli('-------------------------------------------')
     print_cli('Summary')
     print_cli('-------------------------------------------')
     print_cli('# of minions targeted: {0}'.format(return_counter + not_return_counter))
     print_cli('# of minions returned: {0}'.format(return_counter))
     print_cli('# of minions that did not return: {0}'.format(not_return_counter))
     print_cli('# of minions with errors: {0}'.format(len(failed_minions)))
     if self.options.verbose:
         if not_connected_minions:
             print_cli('Minions not connected: {0}'.format(" ".join(not_connected_minions)))
         if not_response_minions:
             print_cli('Minions not responding: {0}'.format(" ".join(not_response_minions)))
         if failed_minions:
             print_cli('Minions with failures: {0}'.format(" ".join(failed_minions)))
     print_cli('-------------------------------------------')
Beispiel #38
0
    def run(self):
        '''
        Execute the salt command line
        '''
        import salt.auth
        import salt.client
        self.parse_args()

        # Setup file logging!
        self.setup_logfile_logger()
        verify_log(self.config)

        try:
            # We don't need to bail on config file permission errors
            # if the CLI
            # process is run with the -a flag
            skip_perm_errors = self.options.eauth != ''

            local = salt.client.get_local_client(
                self.get_config_file_path(),
                skip_perm_errors=skip_perm_errors)
        except SaltClientError as exc:
            self.exit(2, '{0}\n'.format(exc))
            return

        if self.options.batch or self.options.static:
            self._run_batch()
        else:
            if self.options.timeout <= 0:
                self.options.timeout = local.opts['timeout']

            kwargs = {
                'tgt': self.config['tgt'],
                'fun': self.config['fun'],
                'arg': self.config['arg'],
                'timeout': self.options.timeout,
                'show_timeout': self.options.show_timeout,
                'show_jid': self.options.show_jid}

            if 'token' in self.config:
                try:
                    with salt.utils.fopen(os.path.join(self.config['cachedir'], '.root_key'), 'r') as fp_:
                        kwargs['key'] = fp_.readline()
                except IOError:
                    kwargs['token'] = self.config['token']

            kwargs['delimiter'] = self.options.delimiter

            if self.selected_target_option:
                kwargs['expr_form'] = self.selected_target_option
            else:
                kwargs['expr_form'] = 'glob'

            if getattr(self.options, 'return'):
                kwargs['ret'] = getattr(self.options, 'return')

            if getattr(self.options, 'return_config'):
                kwargs['ret_config'] = getattr(self.options, 'return_config')

            if getattr(self.options, 'return_kwargs'):
                kwargs['ret_kwargs'] = yamlify_arg(
                        getattr(self.options, 'return_kwargs'))

            if getattr(self.options, 'module_executors'):
                kwargs['module_executors'] = yamlify_arg(getattr(self.options, 'module_executors'))

            if getattr(self.options, 'metadata'):
                kwargs['metadata'] = yamlify_arg(
                        getattr(self.options, 'metadata'))

            # If using eauth and a token hasn't already been loaded into
            # kwargs, prompt the user to enter auth credentials
            if 'token' not in kwargs and 'key' not in kwargs and self.options.eauth:
                resolver = salt.auth.Resolver(self.config)
                res = resolver.cli(self.options.eauth)
                if self.options.mktoken and res:
                    tok = resolver.token_cli(
                            self.options.eauth,
                            res
                            )
                    if tok:
                        kwargs['token'] = tok.get('token', '')
                if not res:
                    sys.stderr.write('ERROR: Authentication failed\n')
                    sys.exit(2)
                kwargs.update(res)
                kwargs['eauth'] = self.options.eauth

            if self.config['async']:
                jid = local.cmd_async(**kwargs)
                print_cli('Executed command with job ID: {0}'.format(jid))
                return
            retcodes = []
            try:
                # local will be None when there was an error
                errors = []
                if local:
                    if self.options.subset:
                        cmd_func = local.cmd_subset
                        kwargs['sub'] = self.options.subset
                        kwargs['cli'] = True
                    else:
                        cmd_func = local.cmd_cli

                    if self.options.progress:
                        kwargs['progress'] = True
                        self.config['progress'] = True
                        ret = {}
                        for progress in cmd_func(**kwargs):
                            out = 'progress'
                            try:
                                self._progress_ret(progress, out)
                            except salt.exceptions.LoaderError as exc:
                                raise salt.exceptions.SaltSystemExit(exc)
                            if 'return_count' not in progress:
                                ret.update(progress)
                        self._progress_end(out)
                        self._print_returns_summary(ret)
                    elif self.config['fun'] == 'sys.doc':
                        ret = {}
                        out = ''
                        for full_ret in local.cmd_cli(**kwargs):
                            ret_, out, retcode = self._format_ret(full_ret)
                            ret.update(ret_)
                        self._output_ret(ret, out)
                    else:
                        if self.options.verbose:
                            kwargs['verbose'] = True
                        ret = {}
                        for full_ret in cmd_func(**kwargs):
                            try:
                                ret_, out, retcode = self._format_ret(full_ret)
                                retcodes.append(retcode)
                                self._output_ret(ret_, out)
                                ret.update(full_ret)
                            except KeyError:
                                errors.append(full_ret)

                    # Returns summary
                    if self.config['cli_summary'] is True:
                        if self.config['fun'] != 'sys.doc':
                            if self.options.output is None:
                                self._print_returns_summary(ret)
                                self._print_errors_summary(errors)

                    # NOTE: Return code is set here based on if all minions
                    # returned 'ok' with a retcode of 0.
                    # This is the final point before the 'salt' cmd returns,
                    # which is why we set the retcode here.
                    if retcodes.count(0) < len(retcodes):
                        sys.stderr.write('ERROR: Minions returned with non-zero exit code\n')
                        sys.exit(11)

            except (SaltInvocationError, EauthAuthenticationError, SaltClientError) as exc:
                ret = str(exc)
                out = ''
                self._output_ret(ret, out)
 def _print_returns_summary(self, ret):
     """
     Display returns summary
     """
     return_counter = 0
     not_return_counter = 0
     not_return_minions = []
     for each_minion in ret:
         if ret[each_minion] == "Minion did not return":
             not_return_counter += 1
             not_return_minions.append(each_minion)
         else:
             return_counter += 1
     print_cli("\n")
     print_cli("-------------------------------------------")
     print_cli("Summary")
     print_cli("-------------------------------------------")
     print_cli("# of Minions Targeted: {0}".format(return_counter + not_return_counter))
     print_cli("# of Minions Returned: {0}".format(return_counter))
     print_cli("# of Minions Did Not Return: {0}".format(not_return_counter))
     if self.options.verbose:
         print_cli("Minions Which Did Not Return: {0}".format(" ".join(not_return_minions)))
     print_cli("-------------------------------------------")
Beispiel #40
0
 def _print_returns_summary(self, ret):
     '''
     Display returns summary
     '''
     return_counter = 0
     not_return_counter = 0
     not_return_minions = []
     not_response_minions = []
     not_connected_minions = []
     for each_minion in ret:
         minion_ret = ret[each_minion]
         if (isinstance(minion_ret, string_types)
                 and minion_ret.startswith("Minion did not return")):
             if "Not connected" in ret[each_minion]:
                 not_connected_minions.append(each_minion)
             elif "No response" in ret[each_minion]:
                 not_response_minions.append(each_minion)
             not_return_counter += 1
             not_return_minions.append(each_minion)
         else:
             return_counter += 1
     print_cli('\n')
     print_cli('-------------------------------------------')
     print_cli('Summary')
     print_cli('-------------------------------------------')
     print_cli('# of minions targeted: {0}'.format(return_counter +
                                                   not_return_counter))
     print_cli('# of minions returned: {0}'.format(return_counter))
     print_cli(
         '# of minions that did not return: {0}'.format(not_return_counter))
     if self.options.verbose:
         if not_connected_minions:
             print_cli('Minions not connected: {0}'.format(
                 " ".join(not_connected_minions)))
         if not_response_minions:
             print_cli('Minions not responding: {0}'.format(
                 " ".join(not_response_minions)))
     print_cli('-------------------------------------------')
Beispiel #41
0
            def batchRun(wrapMesage, selfIp, clientPub, redisChannel):
                # NOTE: batch running mode
                # handle special syndic
                if selfIp in comeSubList:
                    comeSubList.remove(selfIp)

                syndic_count = len(comeSubList)
                resultCount = 0
                pingCount = 0

                executeStart = time.time()

                normalDone = False

                # NOTE: must publish cmd after registered the redis listen
                # else we will miss ping message
                # tmpKwargs1 = wrapMesage['kwargs']
                # batch_running = set(tmpKwargs1['tgt'])

                #print('publish wrapMesage: %s' % wrapMesage)
                clientPub.publishToSyndicSub(
                    salt.newrun.json.dumps(wrapMesage))

                from salt.newrun import (json, byteify, MessageType)

                for message in redisChannel.listen():
                    try:
                        messageJson = byteify(message)
                        if messageJson['type'] == 'message':
                            resultMessage = messageJson['data']

                            try:

                                callResult = json.loads(resultMessage,
                                                        encoding='utf-8')
                                callResult = byteify(callResult)

                                if isinstance(callResult, dict):
                                    if 'type' in callResult:
                                        messageType = callResult['type']
                                        messageIp = callResult['sub_ip']

                                        if messageType == MessageType.PING and messageIp in comeSubList:
                                            resultPingSet.append(messageIp)
                                        elif messageType == MessageType.WORK or messageType == MessageType.INTERRUPT:
                                            resultExeSet.append(messageIp)
                                        else:
                                            main_log.info(
                                                'invalid callresult: %s' %
                                                callResult)

                                    else:
                                        # filter no return received of sub node
                                        retJsonObj = callResult['ret_']
                                        if retJsonObj:
                                            # reset start time
                                            executeStart = time.time()
                                            for k, v in retJsonObj.items():
                                                # reset running and wait node
                                                batch_running.discard(k)

                                            if callResult[
                                                    'out'] == 'no_return':
                                                if '[No response]' in json.dumps(
                                                        retJsonObj):
                                                    noResponseRet.append(
                                                        callResult)
                                                else:
                                                    noConnectRet.append(
                                                        callResult)
                                            else:
                                                # put successed ip to tmp set
                                                for k, v in retJsonObj.items():
                                                    sucset.add(k)

                                                    # NOTE: debug
                                                    if k in debugSet:
                                                        repeatet.add(
                                                            json.dumps(
                                                                retJsonObj))
                                                    else:
                                                        debugSet.add(k)

                                                if callResult['retcode'] == 0:
                                                    isnil = False
                                                    for k in retJsonObj.keys():
                                                        v = retJsonObj[k]
                                                        if v == "":
                                                            isnil = True
                                                        break
                                                    if isnil:
                                                        emptyRet.append(
                                                            callResult)
                                                    else:
                                                        global normalsize
                                                        normalsize += 1
                                                        self._output_ret(
                                                            callResult['ret_'],
                                                            callResult['out'])
                                                else:
                                                    emptyRet.append(callResult)

                                else:
                                    # TODO handle other messages?
                                    pass

                            except:
                                resultCount += 1
                                print_cli(traceback.format_exc())
                                pass

                        pingCount = len(resultPingSet)
                        resultCount = len(resultExeSet)

                        #from collections import Counter
                        #main_log.info("%s, %s, %s, %s" % (pingCount, resultCount, Counter(resultPingSet), Counter(resultExeSet)))
                        # if len(batch_init) <= 0:
                        #     break

                        if len(batch_running) == 0:
                            break

                        if pingCount != resultCount:
                            if (time.time() - executeStart) > sub_timeout:
                                # main_log.info("---T0 stop")
                                break
                    except:
                        main_log.info(traceback.format_exc())
                        pass