Exemplo n.º 1
0
 def shutdown(self, signum=signal.SIGTERM, timeout=10, wait_for_orphans=0):
     '''Shutdown a running daemon'''
     if not self._shutdown:
         try:
             pid = self.wait_for_daemon_pid(timeout)
             terminate_process(pid=pid, kill_children=True)
         except TimeoutError:
             pass
     if self.process:
         terminate_process(pid=self.process.pid, kill_children=True)
         self.process.wait()
         if wait_for_orphans:
             # NOTE: The process for finding orphans is greedy, it just
             # looks for processes with the same cmdline which are owned by
             # PID 1.
             orphans = self.find_orphans(self.argv)
             last = time.time()
             while True:
                 if orphans:
                     log.debug('Terminating orphaned child processes: %s',
                               orphans)
                     terminate_process_list(orphans)
                     last = time.time()
                 if (time.time() - last) >= wait_for_orphans:
                     break
                 time.sleep(0.25)
                 orphans = self.find_orphans(self.argv)
         self.process = None
     self._shutdown = True
Exemplo n.º 2
0
 def shutdown(self, signum=signal.SIGTERM, timeout=10):
     '''Shutdown a running daemon'''
     if not self._shutdown:
         try:
             pid = self.wait_for_daemon_pid(timeout)
             terminate_process(pid=pid)
         except TimeoutError:
             pass
     if self.process:
         terminate_process(pid=self.process.pid)
         self.process.wait()
         self.process = None
     self._shutdown = True
Exemplo n.º 3
0
    def test_master_startup(self):
        proc = NonBlockingPopen(
            [
                self.get_script_path("master"),
                "-c",
                RUNTIME_VARS.TMP_CONF_DIR,
                "-l",
                "info",
            ],
            stdout=subprocess.PIPE,
            stderr=subprocess.STDOUT,
        )
        out = six.b("")
        err = six.b("")

        # Testing this should never be longer than 1 minute
        max_time = time.time() + 60
        try:
            while True:
                if time.time() > max_time:
                    assert False, "Max timeout ocurred"
                time.sleep(0.5)
                _out = proc.recv()
                _err = proc.recv_err()
                if _out:
                    out += _out
                if _err:
                    err += _err

                if six.b("DeprecationWarning: object() takes no parameters") in out:
                    self.fail(
                        "'DeprecationWarning: object() takes no parameters' was seen in output"
                    )

                if six.b("TypeError: object() takes no parameters") in out:
                    self.fail(
                        "'TypeError: object() takes no parameters' was seen in output"
                    )

                if six.b("Setting up the master communication server") in out:
                    # We got past the place we need, stop the process
                    break

                if out is None and err is None:
                    break

                if proc.poll() is not None:
                    break
        finally:
            terminate_process(proc.pid, kill_children=True)
Exemplo n.º 4
0
    def test_master_startup(self):
        proc = NonBlockingPopen(
            [
                self.get_script_path('master'),
                '-c',
                self.config_dir,
                '-l',
                'info'
            ],
            stdout=subprocess.PIPE,
            stderr=subprocess.STDOUT
        )
        out = six.b('')
        err = six.b('')

        # Testing this should never be longer than 1 minute
        max_time = time.time() + 60
        try:
            while True:
                if time.time() > max_time:
                    assert False, 'Max timeout ocurred'
                time.sleep(0.5)
                _out = proc.recv()
                _err = proc.recv_err()
                if _out:
                    out += _out
                if _err:
                    err += _err

                if six.b('DeprecationWarning: object() takes no parameters') in out:
                    self.fail('\'DeprecationWarning: object() takes no parameters\' was seen in output')

                if six.b('TypeError: object() takes no parameters') in out:
                    self.fail('\'TypeError: object() takes no parameters\' was seen in output')

                if six.b('Setting up the master communication server') in out:
                    # We got past the place we need, stop the process
                    break

                if out is None and err is None:
                    break

                if proc.poll() is not None:
                    break
        finally:
            terminate_process(proc.pid, kill_children=True)
Exemplo n.º 5
0
 def finalize(self, exit_code=0):
     '''
     Run the finalization procedures. Show report, clean-up file-system, etc
     '''
     # Collect any child processes still laying around
     children = processes.collect_child_processes(os.getpid())
     if self.options.no_report is False:
         self.print_overall_testsuite_report()
     self.post_execution_cleanup()
     # Brute force approach to terminate this process and its children
     if children:
         log.info('Terminating test suite child processes: %s', children)
         processes.terminate_process(children=children, kill_children=True)
         children = processes.collect_child_processes(os.getpid())
         if children:
             log.info('Second run at terminating test suite child processes: %s', children)
             processes.terminate_process(children=children, kill_children=True)
     exit_msg = 'Test suite execution finalized with exit code: {}'.format(exit_code)
     log.info(exit_msg)
     self.exit(status=exit_code, msg=exit_msg + '\n')
Exemplo n.º 6
0
 def tearDown(self):
     subprocess_list = self.subprocess_list
     processes = subprocess_list.processes
     self.schedule.reset()
     del self.schedule
     for proc in processes:
         if proc.is_alive():
             terminate_process(proc.pid, kill_children=True, slow_stop=True)
     subprocess_list.cleanup()
     processes = subprocess_list.processes
     if processes:
         for proc in processes:
             if proc.is_alive():
                 terminate_process(proc.pid,
                                   kill_children=True,
                                   slow_stop=False)
         subprocess_list.cleanup()
     processes = subprocess_list.processes
     if processes:
         log.warning("Processes left running: %s", processes)
Exemplo n.º 7
0
 def test_event_return(self):
     # Once salt is py3 only, the warnings part of this test no longer applies
     evt = None
     try:
         with warnings.catch_warnings(record=True) as w:
             # Cause all warnings to always be triggered.
             warnings.simplefilter("always")
             evt = None
             try:
                 evt = salt.utils.event.EventReturn(
                     salt.config.DEFAULT_MASTER_OPTS.copy())
                 evt.start()
             except TypeError as exc:
                 if "object" in str(exc):
                     self.fail("'{}' TypeError should have not been raised".
                               format(exc))
             for warning in w:
                 if warning.category is DeprecationWarning:
                     assert "object() takes no parameters" not in warning.message
     finally:
         if evt is not None:
             terminate_process(evt.pid, kill_children=True)
Exemplo n.º 8
0
Arquivo: case.py Projeto: zxstar/salt
    def run_script(
            self,
            script,
            arg_str,
            catch_stderr=False,
            with_retcode=False,
            catch_timeout=False,
            # FIXME A timeout of zero or disabling timeouts may not return results!
            timeout=15,
            raw=False,
            popen_kwargs=None,
            log_output=None,
            **kwargs):
        """
        Execute a script with the given argument string

        The ``log_output`` argument is ternary, it can be True, False, or None.
        If the value is boolean, then it forces the results to either be logged
        or not logged. If it is None, then the return code of the subprocess
        determines whether or not to log results.
        """

        import salt.utils.platform

        script_path = self.get_script_path(script)
        if not os.path.isfile(script_path):
            return False
        popen_kwargs = popen_kwargs or {}

        if salt.utils.platform.is_windows():
            cmd = "python "
            if "cwd" not in popen_kwargs:
                popen_kwargs["cwd"] = os.getcwd()
            if "env" not in popen_kwargs:
                popen_kwargs["env"] = os.environ.copy()
                if sys.version_info[0] < 3:
                    popen_kwargs["env"][b"PYTHONPATH"] = CODE_DIR.encode()
                else:
                    popen_kwargs["env"]["PYTHONPATH"] = CODE_DIR
        else:
            cmd = "PYTHONPATH="
            python_path = os.environ.get("PYTHONPATH", None)
            if python_path is not None:
                cmd += "{0}:".format(python_path)

            if sys.version_info[0] < 3:
                cmd += "{0} ".format(":".join(sys.path[1:]))
            else:
                cmd += "{0} ".format(":".join(sys.path[0:]))
            cmd += "python{0}.{1} ".format(*sys.version_info)
        cmd += "{0} ".format(script_path)
        cmd += "{0} ".format(arg_str)
        if kwargs:
            # late import
            import salt.utils.json

            for key, value in kwargs.items():
                cmd += "'{0}={1} '".format(key, salt.utils.json.dumps(value))

        tmp_file = tempfile.SpooledTemporaryFile()

        popen_kwargs = dict(
            {
                "shell": True,
                "stdout": tmp_file,
                "universal_newlines": True
            }, **popen_kwargs)

        if catch_stderr is True:
            popen_kwargs["stderr"] = subprocess.PIPE

        if not sys.platform.lower().startswith("win"):
            popen_kwargs["close_fds"] = True

            def detach_from_parent_group():
                # detach from parent group (no more inherited signals!)
                os.setpgrp()

            popen_kwargs["preexec_fn"] = detach_from_parent_group

        def format_return(retcode, stdout, stderr=None, timed_out=False):
            """
            DRY helper to log script result if it failed, and then return the
            desired output based on whether or not stderr was desired, and
            wither or not a retcode was desired.
            """
            log_func = log.debug
            if timed_out:
                log.error(
                    "run_script timed out after %d seconds (process killed)",
                    timeout)
                log_func = log.error

            if log_output is True or timed_out or (log_output is None
                                                   and retcode != 0):
                log_func(
                    "run_script results for: %s %s\n"
                    "return code: %s\n"
                    "stdout:\n"
                    "%s\n\n"
                    "stderr:\n"
                    "%s",
                    script,
                    arg_str,
                    retcode,
                    stdout,
                    stderr,
                )

            stdout = stdout or ""
            stderr = stderr or ""

            if not raw:
                stdout = stdout.splitlines()
                stderr = stderr.splitlines()

            ret = [stdout]
            if catch_stderr:
                ret.append(stderr)
            if with_retcode:
                ret.append(retcode)
            if catch_timeout:
                ret.append(timed_out)

            return ret[0] if len(ret) == 1 else tuple(ret)

        process = subprocess.Popen(cmd, **popen_kwargs)

        if timeout is not None:
            stop_at = datetime.now() + timedelta(seconds=timeout)
            term_sent = False
            while True:
                process.poll()
                time.sleep(0.1)
                if datetime.now() <= stop_at:
                    # We haven't reached the timeout yet
                    if process.returncode is not None:
                        break
                else:
                    terminate_process(process.pid, kill_children=True)
                    return format_return(process.returncode,
                                         *process.communicate(),
                                         timed_out=True)

        tmp_file.seek(0)

        if sys.version_info >= (3, ):
            try:
                out = tmp_file.read().decode(__salt_system_encoding__)
            except (NameError, UnicodeDecodeError):
                # Let's cross our fingers and hope for the best
                out = tmp_file.read().decode("utf-8")
        else:
            out = tmp_file.read()

        if catch_stderr:
            if sys.version_info < (2, 7):
                # On python 2.6, the subprocess'es communicate() method uses
                # select which, is limited by the OS to 1024 file descriptors
                # We need more available descriptors to run the tests which
                # need the stderr output.
                # So instead of .communicate() we wait for the process to
                # finish, but, as the python docs state "This will deadlock
                # when using stdout=PIPE and/or stderr=PIPE and the child
                # process generates enough output to a pipe such that it
                # blocks waiting for the OS pipe buffer to accept more data.
                # Use communicate() to avoid that." <- a catch, catch situation
                #
                # Use this work around were it's needed only, python 2.6
                process.wait()
                err = process.stderr.read()
            else:
                _, err = process.communicate()
            # Force closing stderr/stdout to release file descriptors
            if process.stdout is not None:
                process.stdout.close()
            if process.stderr is not None:
                process.stderr.close()

            # pylint: disable=maybe-no-member
            try:
                return format_return(process.returncode, out, err or "")
            finally:
                try:
                    if os.path.exists(tmp_file.name):
                        if isinstance(tmp_file.name, six.string_types):
                            # tmp_file.name is an int when using SpooledTemporaryFiles
                            # int types cannot be used with os.remove() in Python 3
                            os.remove(tmp_file.name)
                        else:
                            # Clean up file handles
                            tmp_file.close()
                    process.terminate()
                except OSError as err:
                    # process already terminated
                    pass
            # pylint: enable=maybe-no-member

        # TODO Remove this?
        process.communicate()
        if process.stdout is not None:
            process.stdout.close()

        try:
            return format_return(process.returncode, out)
        finally:
            try:
                if os.path.exists(tmp_file.name):
                    if isinstance(tmp_file.name, six.string_types):
                        # tmp_file.name is an int when using SpooledTemporaryFiles
                        # int types cannot be used with os.remove() in Python 3
                        os.remove(tmp_file.name)
                    else:
                        # Clean up file handles
                        tmp_file.close()
                process.terminate()
            except OSError as err:
                # process already terminated
                pass
Exemplo n.º 9
0
    def run(
        self,
        args=None,
        catch_stderr=False,
        with_retcode=False,
        timeout=None,
        raw=False,
        env=None,
        verbatim_args=False,
        verbatim_env=False,
    ):
        '''
        Execute a command possibly using a supplied environment.

        :param args:
            A command string or a command sequence of arguments for the program.

        :param catch_stderr: A boolean whether to capture and return stderr.

        :param with_retcode: A boolean whether to return the exit code.

        :param timeout: A float of how long to wait for the process to
            complete before it is killed.

        :param raw: A boolean whether to return buffer strings for stdout and
            stderr or sequences of output lines.

        :param env: A dictionary of environment key/value settings for the
            command.

        :param verbatim_args: A boolean whether to automatically add inferred arguments.

        :param verbatim_env: A boolean whether to automatically add inferred
            environment values.

        :return list: (stdout [,stderr] [,retcode])
        '''

        # unused for now
        _ = verbatim_args

        self.setup()

        if args is None:
            args = []

        if env is None:
            env = {}

        env_delta = {}
        env_delta.update(self.env)
        env_delta.update(env)

        if not verbatim_env:
            env_pypath = env_delta.get('PYTHONPATH',
                                       os.environ.get('PYTHONPATH'))
            if not env_pypath:
                env_pypath = sys.path
            else:
                env_pypath = env_pypath.split(':')
                for path in sys.path:
                    if path not in env_pypath:
                        env_pypath.append(path)
            # Always ensure that the test tree is searched first for python modules
            if RUNTIME_VARS.CODE_DIR != env_pypath[0]:
                env_pypath.insert(0, RUNTIME_VARS.CODE_DIR)
            if salt.utils.platform.is_windows():
                env_delta['PYTHONPATH'] = ';'.join(env_pypath)
            else:
                env_delta['PYTHONPATH'] = ':'.join(env_pypath)

        cmd_env = dict(os.environ)
        cmd_env.update(env_delta)

        if salt.utils.platform.is_windows() and six.PY2:
            for k, v in cmd_env.items():
                if isinstance(k, six.text_type) or isinstance(
                        v, six.text_type):
                    cmd_env[k.encode('ascii')] = v.encode('ascii')

        popen_kwargs = {
            'shell': self.shell,
            'stdout': subprocess.PIPE,
            'env': cmd_env,
        }

        if catch_stderr is True:
            popen_kwargs['stderr'] = subprocess.PIPE

        if not sys.platform.lower().startswith('win'):
            popen_kwargs['close_fds'] = True

            def detach_from_parent_group():
                '''
                A utility function that prevents child process from getting parent signals.
                '''
                os.setpgrp()

            popen_kwargs['preexec_fn'] = detach_from_parent_group

        if salt.utils.platform.is_windows():
            self.argv = ['python.exe', self.program]
        else:
            self.argv = [self.program]
        self.argv.extend(args)
        log.debug('TestProgram.run: %s Environment %s', self.argv, env_delta)
        process = subprocess.Popen(self.argv, **popen_kwargs)
        self.process = process

        if timeout is not None:
            stop_at = datetime.now() + timedelta(seconds=timeout)
            term_sent = False
            while True:
                process.poll()

                if datetime.now() > stop_at:
                    try:
                        terminate_process(pid=process.pid, kill_children=True)
                        process.wait()
                    except OSError as exc:
                        if exc.errno != errno.ESRCH:
                            raise

                    out = process.stdout.read().splitlines()
                    out.extend([
                        'Process took more than {0} seconds to complete. '
                        'Process Killed!'.format(timeout)
                    ])
                    if catch_stderr:
                        err = process.stderr.read().splitlines()
                        if with_retcode:
                            return out, err, process.returncode
                        else:
                            return out, err
                    if with_retcode:
                        return out, process.returncode
                    else:
                        return out

                if process.returncode is not None:
                    break

        if catch_stderr:
            if sys.version_info < (2, 7):
                # On python 2.6, the subprocess'es communicate() method uses
                # select which, is limited by the OS to 1024 file descriptors
                # We need more available descriptors to run the tests which
                # need the stderr output.
                # So instead of .communicate() we wait for the process to
                # finish, but, as the python docs state "This will deadlock
                # when using stdout=PIPE and/or stderr=PIPE and the child
                # process generates enough output to a pipe such that it
                # blocks waiting for the OS pipe buffer to accept more data.
                # Use communicate() to avoid that." <- a catch, catch situation
                #
                # Use this work around were it's needed only, python 2.6
                process.wait()
                out = process.stdout.read()
                err = process.stderr.read()
            else:
                out, err = process.communicate()
            # Force closing stderr/stdout to release file descriptors
            if process.stdout is not None:
                process.stdout.close()
            if process.stderr is not None:
                process.stderr.close()
            # pylint: disable=maybe-no-member
            try:
                if with_retcode:
                    if out is not None and err is not None:
                        if not raw:
                            return out.splitlines(), err.splitlines(
                            ), process.returncode
                        else:
                            return out, err, process.returncode
                    return out.splitlines(), [], process.returncode
                else:
                    if out is not None and err is not None:
                        if not raw:
                            return out.splitlines(), err.splitlines()
                        else:
                            return out, err
                    if not raw:
                        return out.splitlines(), []
                    else:
                        return out, []
            finally:
                try:
                    process.terminate()
                except OSError as err:
                    # process already terminated
                    pass
            # pylint: enable=maybe-no-member

        data = process.communicate()
        process.stdout.close()

        try:
            if with_retcode:
                if not raw:
                    return data[0].splitlines(), process.returncode
                else:
                    return data[0], process.returncode
            else:
                if not raw:
                    return data[0].splitlines()
                else:
                    return data[0]
        finally:
            try:
                process.terminate()
            except OSError as err:
                # process already terminated
                pass