Пример #1
0
    def pre_start(self):
        """
        Create mandatory directories and install files from given templates
        using the drivers context before starting the application binary.
        """
        super(App, self).pre_start()

        self._make_dirs()
        if self.cfg.binary_copy:
            if self.cfg.path_cleanup is True:
                name = os.path.basename(self.cfg.binary)
            else:
                name = '{}-{}'.format(os.path.basename(self.cfg.binary),
                                      uuid.uuid4())

            target = os.path.join(self._binpath, name)
            shutil.copyfile(self.cfg.binary, target)
            self.binary = target
        else:
            self.binary = self.cfg.binary

        makedirs(self.app_path)
        self.std = StdFiles(self.app_path)

        if self.cfg.install_files:
            self._install_files()
Пример #2
0
    def pre_start(self):
        """
        Create mandatory directories and install files from given templates
        using the drivers context before starting the application binary.
        """
        super(App, self).pre_start()

        self._make_dirs()

        if self.cfg.path_cleanup is True:
            name = os.path.basename(self.cfg.binary)
        else:
            name = "{}-{}".format(os.path.basename(self.cfg.binary),
                                  uuid.uuid4())

        self.binary = self._prepare_binary(self.cfg.binary)
        if os.path.isfile(self.binary):
            target = os.path.join(self._binpath, name)
            if self.cfg.binary_strategy == "copy":
                shutil.copyfile(self.binary, target)
                self.binary = target
            elif self.cfg.binary_strategy == "link" and not IS_WIN:
                os.symlink(os.path.abspath(self.binary), target)
                self.binary = target
            # else binary_strategy is noop then we don't do anything

        makedirs(self.app_path)
        self.std = StdFiles(self.app_path)

        if self.cfg.install_files:
            self._install_files()
Пример #3
0
    def starting(self):
        """
        Create mandatory directories, install files from given templates
        using the drivers context and starts the application binary.
        """
        super(App, self).starting()
        self._make_dirs()
        if self.cfg.binary_copy:
            if self.cfg.path_cleanup is True:
                name = os.path.basename(self.cfg.binary)
            else:
                name = '{}-{}'.format(os.path.basename(self.cfg.binary),
                                      uuid.uuid4())

            target = os.path.join(self._binpath, name)
            shutil.copyfile(self.cfg.binary, target)
            self.binary = target
        else:
            self.binary = self.cfg.binary

        makedirs(self.app_path)
        self.std = StdFiles(self.app_path)

        if self.cfg.install_files:
            self._install_files()

        cmd = ' '.join(self.cmd) if self.cfg.shell else self.cmd
        cwd = self.cfg.working_dir or self.runpath
        try:
            self.logger.debug('{driver} driver command: {cmd},{linesep}'
                              '\trunpath: {runpath}{linesep}'
                              '\tout/err files {out} - {err}'.format(
                                  driver=self.uid(),
                                  cmd=cmd,
                                  runpath=self.runpath,
                                  linesep=os.linesep,
                                  out=self.std.out_path,
                                  err=self.std.err_path))
            self.proc = subprocess.Popen(cmd,
                                         shell=self.cfg.shell,
                                         stdout=self.std.out,
                                         stderr=self.std.err,
                                         cwd=cwd,
                                         env=self.cfg.env)
        except Exception:
            TESTPLAN_LOGGER.error(
                'Error while App[%s] driver executed command: %s',
                self.cfg.name, cmd if self.cfg.shell else ' '.join(cmd))
            raise
Пример #4
0
    def starting(self):
        """Starts the Zookeeper instance."""
        super(ZookeeperStandalone, self).starting()
        start_cmd = [self.cfg.binary, "start", self.config]
        self.std = StdFiles(self.runpath)

        execute_cmd(
            start_cmd,
            label=self.uid(),
            check=True,
            stdout=self.std.out,
            stderr=self.std.err,
            logger=self.logger,
            env=self.env,
        )
Пример #5
0
 def pre_start(self) -> None:
     """
     Before service start.
     """
     self.make_runpath_dirs()
     self.std = StdFiles(self.runpath)
     self._prepare_remote()
Пример #6
0
class BaseDriver(Driver):
    """Base class of vulnerable driver which can raise exception."""
    @property
    def outpath(self):
        return self.std.out_path

    @property
    def errpath(self):
        return self.std.err_path

    def starting(self):
        super(BaseDriver, self).starting()
        self.std = StdFiles(self.runpath)

    def stopping(self):
        super(BaseDriver, self).stopping()
        self.std.close()
Пример #7
0
class App(Driver):
    """
    Binary application driver.

    :param binary: Path the to application binary.
    :type binary: ``str``
    :param pre_args: Arguments to be prepended to binary command. An argument
        can be a :py:class:`~testplan.common.utils.context.ContextValue`
        and will be expanded on runtime.
    :type pre_args: ``list`` or ``str``
    :param args: Arguments to be appended to binary command. An argument
        can be a :py:class:`~testplan.common.utils.context.ContextValue`
        and will be expanded on runtime.
    :type args: ``list`` of ``str``
    :param shell: Invoke shell for command execution.
    :type shell: ``bool``
    :param env: Environmental variables to be made available to child process.
    :type env: ``dict``
    :param binary_copy: Copy binary to a local binary path.
    :type binary_copy: ``bool``
    :param app_dir_name: Application directory name.
    :type app_dir_name: ``str``
    :param working_dir: Application working directory. Default: runpath
    :type working_dir: ``str``

    Also inherits all
    :py:class:`~testplan.testing.multitest.driver.base.DriverConfig` options.
    """

    CONFIG = AppConfig

    def __init__(self, **options):
        super(App, self).__init__(**options)
        self.proc = None
        self.std = None
        self.binary = None
        self._binpath = None
        self._etcpath = None
        self._retcode = None

    @property
    def pid(self):
        """
        Return pid of the child process if available, ``None`` otherwise.

        :rtype: ``int`` or ``NoneType``
        """
        if self.proc:
            return self.proc.pid
        else:
            return None

    @property
    def retcode(self):
        """
        Return return code of the app process or ``None``.

        :rtype: ``int`` or ``NoneType``
        """
        if self._retcode is None:
            if self.proc:
                self._retcode = self.proc.poll()
        return self._retcode

    @property
    def cmd(self):
        """Command that starts the application."""
        args = self.cfg.args or []
        pre_args = self.cfg.pre_args or []
        cmd = []
        cmd.extend(pre_args)
        cmd.append(self.binary or self.cfg.binary)
        cmd.extend(args)
        cmd = [expand(arg, self.context, str) if is_context(arg) else arg
               for arg in cmd]
        return cmd

    @property
    def env(self):
        """Environment variables."""
        if isinstance(self.cfg.env, dict):
            return {key: expand(val, self.context, str)
                    if is_context(val) else val
                    for key, val in self.cfg.env.items()}
        else:
            return self.cfg.env

    @property
    def logpath(self):
        """Path for log regex matching."""
        if self.cfg.logfile:
            return os.path.join(self.app_path, self.cfg.logfile)
        return self.outpath

    @property
    def outpath(self):
        """Path for stdout file regex matching."""
        return self.std.out_path

    @property
    def errpath(self):
        """Path for stderr file regex matching."""
        return self.std.err_path

    @property
    def app_path(self):
        """Application directory path."""
        if self.cfg.app_dir_name:
            return os.path.join(self.runpath, self.cfg.app_dir_name)
        return self.runpath

    @property
    def binpath(self):
        """'bin' directory under runpath."""
        return self._binpath

    @property
    def etcpath(self):
        """'etc' directory under runpath."""
        return self._etcpath

    def pre_start(self):
        """
        Create mandatory directories and install files from given templates
        using the drivers context before starting the application binary.
        """
        super(App, self).pre_start()

        self._make_dirs()
        if self.cfg.binary_copy:
            if self.cfg.path_cleanup is True:
                name = os.path.basename(self.cfg.binary)
            else:
                name = '{}-{}'.format(os.path.basename(self.cfg.binary),
                                      uuid.uuid4())

            target = os.path.join(self._binpath, name)
            shutil.copyfile(self.cfg.binary, target)
            self.binary = target
        else:
            self.binary = self.cfg.binary

        makedirs(self.app_path)
        self.std = StdFiles(self.app_path)

        if self.cfg.install_files:
            self._install_files()

    def starting(self):
        """Starts the application binary."""
        super(App, self).starting()

        cmd = ' '.join(self.cmd) if self.cfg.shell else self.cmd
        cwd = self.cfg.working_dir or self.runpath
        try:
            self.logger.debug('{driver} driver command: {cmd},{linesep}'
                              '\trunpath: {runpath}{linesep}'
                              '\tout/err files {out} - {err}'.format(
                driver=self.uid(),
                cmd=cmd, runpath=self.runpath, linesep=os.linesep,
                out=self.std.out_path, err=self.std.err_path))
            self.proc = subprocess.Popen(cmd, shell=self.cfg.shell,
                stdout=self.std.out, stderr=self.std.err,
                cwd=cwd, env=self.env)
        except Exception:
            TESTPLAN_LOGGER.error(
                'Error while App[%s] driver executed command: %s',
                self.cfg.name, cmd if self.cfg.shell else ' '.join(cmd))
            raise

    def stopping(self):
        """Stops the application binary process."""
        super(App, self).stopping()
        try:
            self._retcode = kill_process(self.proc)
        except Exception as exc:
            warnings.warn('On killing driver {} process - {}'.format(
                self.cfg.name, exc))
            self._retcode = self.proc.poll()
        self.proc = None
        if self.std:
            self.std.close()

    def _make_dirs(self):
        bin_dir = os.path.join(self.runpath, 'bin')
        etc_dir = os.path.join(self.runpath, 'etc')
        for directory in (bin_dir, etc_dir):
            makedirs(directory)
        self._binpath = bin_dir
        self._etcpath = etc_dir

    def _install_target(self):
        return self.etcpath

    def aborting(self):
        """Abort logic to force kill the child binary."""
        if self.proc:
            self.logger.debug('Killing process id {}'.format(self.proc.pid))
            kill_process(self.proc)
Пример #8
0
class App(Driver):
    """
    Binary application driver.

    :param name: Driver name. Also uid.
    :type name: ``str``
    :param binary: Path the to application binary.
    :type binary: ``str``
    :param pre_args: Arguments to be prepended to binary command. An argument
        can be a :py:class:`~testplan.common.utils.context.ContextValue`
        and will be expanded on runtime.
    :type pre_args: ``list`` or ``str``
    :param args: Arguments to be appended to binary command. An argument
        can be a :py:class:`~testplan.common.utils.context.ContextValue`
        and will be expanded on runtime.
    :type args: ``list`` of ``str``
    :param shell: Invoke shell for command execution.
    :type shell: ``bool``
    :param env: Environmental variables to be made available to child process.
    :type env: ``dict``
    :param binary_strategy: Whether to copy / link binary to runpath.
    :type binary_strategy: one of ("copy", "link", "noop")
    :param app_dir_name: Application directory name.
    :type app_dir_name: ``str``
    :param working_dir: Application working directory. Default: runpath
    :type working_dir: ``str``

    Also inherits all
    :py:class:`~testplan.testing.multitest.driver.base.Driver` options.
    """

    CONFIG = AppConfig

    def __init__(self,
                 name,
                 binary,
                 pre_args=None,
                 args=None,
                 shell=False,
                 env=None,
                 binary_strategy="link",
                 app_dir_name=None,
                 working_dir=None,
                 **options):
        options.update(self.filter_locals(locals()))
        super(App, self).__init__(**options)
        self.proc = None
        self.std = None
        self.binary = None
        self._binpath = None
        self._etcpath = None
        self._retcode = None

    @property
    def pid(self):
        """
        Return pid of the child process if available, ``None`` otherwise.

        :rtype: ``int`` or ``NoneType``
        """
        if self.proc:
            return self.proc.pid
        else:
            return None

    @property
    def retcode(self):
        """
        Return return code of the app process or ``None``.

        :rtype: ``int`` or ``NoneType``
        """
        if self._retcode is None:
            if self.proc:
                self._retcode = self.proc.poll()
        return self._retcode

    @property
    def cmd(self):
        """Command that starts the application."""
        args = self.cfg.args or []
        pre_args = self.cfg.pre_args or []
        cmd = []
        cmd.extend(pre_args)
        cmd.append(self.binary or self.cfg.binary)
        cmd.extend(args)
        cmd = [
            expand(arg, self.context, str) if is_context(arg) else arg
            for arg in cmd
        ]
        return cmd

    @property
    def env(self):
        """Environment variables."""
        if isinstance(self.cfg.env, dict):
            return {
                key: expand(val, self.context, str) if is_context(val) else val
                for key, val in self.cfg.env.items()
            }
        else:
            return self.cfg.env

    @property
    def logpath(self):
        """Path for log regex matching."""
        if self.cfg.logname:
            return os.path.join(self.app_path, self.cfg.logname)
        return self.outpath

    @property
    def outpath(self):
        """Path for stdout file regex matching."""
        return self.std.out_path

    @property
    def errpath(self):
        """Path for stderr file regex matching."""
        return self.std.err_path

    @property
    def app_path(self):
        """Application directory path."""
        if self.cfg.app_dir_name:
            return os.path.join(self.runpath, self.cfg.app_dir_name)
        return self.runpath

    @property
    def binpath(self):
        """'bin' directory under runpath."""
        return self._binpath

    @property
    def etcpath(self):
        """'etc' directory under runpath."""
        return self._etcpath

    def _prepare_binary(self, path):
        """prepare binary path"""
        return path

    @property
    def hostname(self):
        """
        :return: hostname where the ETSApp is running
        :rtype: ``str``
        """
        return socket.gethostname()

    def pre_start(self):
        """
        Create mandatory directories and install files from given templates
        using the drivers context before starting the application binary.
        """
        super(App, self).pre_start()

        self._make_dirs()

        if self.cfg.path_cleanup is True:
            name = os.path.basename(self.cfg.binary)
        else:
            name = "{}-{}".format(os.path.basename(self.cfg.binary),
                                  uuid.uuid4())

        self.binary = self._prepare_binary(self.cfg.binary)
        if os.path.isfile(self.binary):
            target = os.path.join(self._binpath, name)
            if self.cfg.binary_strategy == "copy":
                shutil.copyfile(self.binary, target)
                self.binary = target
            elif self.cfg.binary_strategy == "link" and not IS_WIN:
                os.symlink(os.path.abspath(self.binary), target)
                self.binary = target
            # else binary_strategy is noop then we don't do anything

        makedirs(self.app_path)
        self.std = StdFiles(self.app_path)

        if self.cfg.install_files:
            self._install_files()

    def starting(self):
        """Starts the application binary."""
        super(App, self).starting()

        cmd = " ".join(self.cmd) if self.cfg.shell else self.cmd
        cwd = self.cfg.working_dir or self.runpath
        try:
            self.logger.debug(
                "%(driver)s driver command: %(cmd)s\n"
                "\tRunpath: %(runpath)s\n"
                "\tOut file: %(out)s\n"
                "\tErr file: %(err)s\n",
                {
                    "driver": self.uid(),
                    "cmd": cmd,
                    "runpath": self.runpath,
                    "out": self.std.out_path,
                    "err": self.std.err_path,
                },
            )
            self.proc = subprocess_popen(
                cmd,
                shell=self.cfg.shell,
                stdin=subprocess.PIPE,
                stdout=self.std.out,
                stderr=self.std.err,
                cwd=cwd,
                env=self.env,
            )
        except Exception:
            self.logger.error(
                "Error while App[%s] driver executed command: %s",
                self.cfg.name,
                cmd if self.cfg.shell else " ".join(cmd),
            )
            if self.proc is not None:
                if self.proc.poll() is None:
                    kill_process(self.proc)
                assert self.proc.returncode is not None
                self._proc = None
            raise

    def stopping(self):
        """Stops the application binary process."""
        super(App, self).stopping()
        try:
            self._retcode = kill_process(self.proc)
        except Exception as exc:
            warnings.warn("On killing driver {} process - {}".format(
                self.cfg.name, exc))
            self._retcode = self.proc.poll() if self.proc else 0
        self.proc = None
        if self.std:
            self.std.close()

    def _make_dirs(self):
        bin_dir = os.path.join(self.runpath, "bin")
        etc_dir = os.path.join(self.runpath, "etc")
        for directory in (bin_dir, etc_dir):
            makedirs(directory)
        self._binpath = bin_dir
        self._etcpath = etc_dir

    def _install_target(self):
        return self.etcpath

    def restart(self, clean=True):
        """
        Stop the driver, archive the app_dir or rename std/log, and then restart
        the driver.

        :param clean: set to False to not archive app_dir or rotate std/log.
        :type clean: ``bool``

        """
        self.stop()
        self.wait(self.status.STOPPED)
        if clean:
            if self.cfg.app_dir_name:
                self._move_app_path()
            else:
                self._rename_std_and_log()

        # we don't want to cleanup runpath during restart
        path_cleanup = self.cfg.path_cleanup
        self.cfg._options["path_cleanup"] = False
        self.start()
        self.wait(self.status.STARTED)
        self.cfg._options["path_cleanup"] = path_cleanup

    def _move_app_path(self):
        """
        Move app_path directory to an archive location
        """
        snapshot_path = self.app_path + datetime.datetime.now().strftime(
            "_%Y%m%d_%H%M%S")

        shutil.move(self.app_path, snapshot_path)
        os.makedirs(self.app_path)

    def _rename_std_and_log(self):
        """
        Rename std and log files
        """
        timestamp = datetime.datetime.now().strftime("_%Y%m%d_%H%M%S")

        for file in (self.outpath, self.errpath, self.logpath):
            if os.path.isfile(file):
                os.rename(file, file + timestamp)

    def aborting(self):
        """Abort logic to force kill the child binary."""
        if self.proc:
            self.logger.debug("Killing process id {}".format(self.proc.pid))
            kill_process(self.proc)
        if self.std:
            self.std.close()
Пример #9
0
class App(Driver):
    """
    Binary application driver.

    :param name: Driver name. Also uid.
    :type name: ``str``
    :param binary: Path to the application binary.
    :type binary: ``str``
    :param pre_args: Arguments to be prepended to binary command. An argument
        can be a :py:class:`~testplan.common.utils.context.ContextValue`
        and will be expanded on runtime.
    :type pre_args: ``list`` or ``str``
    :param args: Arguments to be appended to binary command. An argument
        can be a :py:class:`~testplan.common.utils.context.ContextValue`
        and will be expanded on runtime.
    :type args: ``list`` of ``str``
    :param shell: Invoke shell for command execution.
    :type shell: ``bool``
    :param env: Environmental variables to be made available to child process.
    :type env: ``dict``
    :param binary_strategy: Whether to copy / link binary to runpath.
    :type binary_strategy: one of ("copy", "link", "noop")
    :param logname: Base name of driver logfile under `app_path`, in which
        Testplan will look for `log_regexps` as driver start-up condition.
        Default to "stdout" (to match the output stream of binary).
    :type logname: ``str``
    :param app_dir_name: Application directory name.
    :type app_dir_name: ``str`` or ``NoneType``
    :param working_dir: Application working directory. Default: runpath
    :type working_dir: ``str`` or ``NoneType``
    :param expected_retcode: the expected return code of the subprocess.
        Default value is None meaning it won't be checked. Set it to 0 to
        ennsure the driver is always gracefully shut down.
    :type expected_retcode: ``Optional[int]``

    Also inherits all
    :py:class:`~testplan.testing.multitest.driver.base.Driver` options.
    """

    CONFIG = AppConfig

    def __init__(
        self,
        name,
        binary,
        pre_args=None,
        args=None,
        shell=False,
        env=None,
        binary_strategy="link",
        logname=None,
        app_dir_name=None,
        working_dir=None,
        expected_retcode=None,
        **options,
    ):
        options.update(self.filter_locals(locals()))
        super(App, self).__init__(**options)
        self.proc = None
        self.std = None
        self.binary = None
        self._binpath = None
        self._etcpath = None
        self._retcode = None
        self._log_matcher = None

    @property
    def pid(self):
        """
        Return pid of the child process if available, ``None`` otherwise.

        :rtype: ``int`` or ``NoneType``
        """
        if self.proc:
            return self.proc.pid
        else:
            return None

    @property
    def retcode(self):
        """
        Return return code of the app process or ``None``.

        :rtype: ``int`` or ``NoneType``
        """
        if self._retcode is None:
            if self.proc:
                self._retcode = self.proc.poll()
        return self._retcode

    @property
    def cmd(self):
        """Command that starts the application."""
        args = self.cfg.args or []
        pre_args = self.cfg.pre_args or []
        cmd = []
        cmd.extend(pre_args)
        cmd.append(self.binary or self.cfg.binary)
        cmd.extend(args)
        cmd = [
            expand(arg, self.context, str) if is_context(arg) else arg
            for arg in cmd
        ]
        return cmd

    @property
    def env(self):
        """Environment variables."""
        if isinstance(self.cfg.env, dict):
            return {
                key: expand(val, self.context, str) if is_context(val) else val
                for key, val in self.cfg.env.items()
            }
        else:
            return None

    @property
    def logname(self):
        """Configured logname."""
        return self.cfg.logname

    @property
    def logpath(self):
        """Path for log regex matching."""
        return (os.path.join(self.app_path, self.logname)
                if self.logname else self.outpath)

    @property
    def outpath(self):
        """Path for stdout file regex matching."""
        return self.std.out_path

    @property
    def errpath(self):
        """Path for stderr file regex matching."""
        return self.std.err_path

    @property
    def app_path(self):
        """Application directory path."""
        if self.cfg.app_dir_name:
            return os.path.join(self.runpath, self.cfg.app_dir_name)
        return self.runpath

    @property
    def binpath(self):
        """'bin' directory under runpath."""
        return self._binpath

    @property
    def etcpath(self):
        """'etc' directory under runpath."""
        return self._etcpath

    @property
    def log_matcher(self):
        """
        Create if not exist and return the LogMatcher object that reads the
        log / stdout of the driver.

        :return: LogMatcher instance
        :rtype: ``LogMatcher``
        """
        if not self._log_matcher:
            self._log_matcher = LogMatcher(self.logpath)
        return self._log_matcher

    def _prepare_binary(self, path):
        """prepare binary path"""
        return path

    @property
    def hostname(self):
        """
        :return: hostname where the ETSApp is running
        :rtype: ``str``
        """
        return socket.gethostname()

    def pre_start(self):
        """
        Create mandatory directories and install files from given templates
        using the drivers context before starting the application binary.
        """
        super(App, self).pre_start()

        self._make_dirs()

        if self.cfg.path_cleanup is True:
            name = os.path.basename(self.cfg.binary)
        else:
            name = "{}-{}".format(os.path.basename(self.cfg.binary),
                                  uuid.uuid4())

        self.binary = self._prepare_binary(self.cfg.binary)
        if os.path.isfile(self.binary):
            target = os.path.join(self._binpath, name)
            if self.cfg.binary_strategy == "copy":
                shutil.copyfile(self.binary, target)
                self.binary = target
            elif self.cfg.binary_strategy == "link" and not IS_WIN:
                os.symlink(os.path.abspath(self.binary), target)
                self.binary = target
            # else binary_strategy is noop then we don't do anything

        makedirs(self.app_path)
        self.std = StdFiles(self.app_path)

        if self.cfg.install_files:
            self._install_files()

    def starting(self):
        """Starts the application binary."""
        super(App, self).starting()

        cmd = " ".join(self.cmd) if self.cfg.shell else self.cmd
        cwd = self.cfg.working_dir or self.runpath
        try:
            self.logger.debug(
                "%(driver)s driver command: %(cmd)s\n"
                "\tRunpath: %(runpath)s\n"
                "\tOut file: %(out)s\n"
                "\tErr file: %(err)s\n",
                {
                    "driver": self.uid(),
                    "cmd": cmd,
                    "runpath": self.runpath,
                    "out": self.std.out_path,
                    "err": self.std.err_path,
                },
            )
            self.proc = subprocess_popen(
                cmd,
                shell=self.cfg.shell,
                stdin=subprocess.PIPE,
                stdout=self.std.out,
                stderr=self.std.err,
                cwd=cwd,
                env=self.env,
            )
        except Exception:
            self.logger.error(
                "Error while App[%s] driver executed command: %s",
                self.cfg.name,
                cmd if self.cfg.shell else " ".join(cmd),
            )
            if self.proc is not None:
                if self.proc.poll() is None:
                    kill_process(self.proc)
                assert self.proc.returncode is not None
                self._proc = None
            raise

    def started_check(self, timeout=None):
        """
        Checks if app has started. Extracts logs and captured stdout/stderr.

        :param timeout: timeout in seconds
        :type timeout: ``int`` or ``NoneType``
        """
        timeout = timeout if timeout is not None else self.cfg.timeout

        def ensure_app_running_while_extracting_values():
            proc_result = self.proc.poll()
            extract_values_result = self.extract_values()
            if proc_result is not None and not extract_values_result:
                raise RuntimeError(
                    f"App {self.name} has unexpectedly stopped with: {proc_result}"
                )
            return extract_values_result

        wait(
            ensure_app_running_while_extracting_values,
            timeout,
            raise_on_timeout=True,
        )

    def stopping(self):
        """Stops the application binary process."""
        super(App, self).stopping()
        #
        if self.proc is None:
            return
        try:
            self._retcode = kill_process(self.proc)
        except Exception as exc:
            warnings.warn("On killing driver {} process - {}".format(
                self.cfg.name, exc))
            self._retcode = self.proc.poll() if self.proc else 0
        self.proc = None
        if self.std:
            self.std.close()
        self._log_matcher = None

        if (self.cfg.expected_retcode
                is not None) and (self.cfg.expected_retcode != self.retcode):
            err_msg = (f"App driver error: {self.name},"
                       f" expected return code is {self.cfg.expected_retcode},"
                       f" but actual return code is {self.retcode}")
            raise RuntimeError(err_msg)

    def _make_dirs(self):
        bin_dir = os.path.join(self.runpath, "bin")
        etc_dir = os.path.join(self.runpath, "etc")
        for directory in (bin_dir, etc_dir):
            makedirs(directory)
        self._binpath = bin_dir
        self._etcpath = etc_dir

    def _install_target(self):
        return self.etcpath

    def restart(self, clean=True):
        """
        Stop the driver, archive the app_dir or rename std/log, and then restart
        the driver.

        :param clean: if set to ``True``, perform a 'clean' restart where
            all persistence is deleted, else a normal restart.
        :type clean: ``bool``

        """
        self.stop()
        if self.async_start:
            self.wait(self.status.STOPPED)

        if clean:
            self._move_app_path()
        else:
            self._move_std_and_logs()

        # we don't want to cleanup runpath during restart
        path_cleanup = self.cfg.path_cleanup
        self.cfg._options["path_cleanup"] = False

        self.start()
        if self.async_start:
            self.wait(self.status.STARTED)

        self.cfg._options["path_cleanup"] = path_cleanup

    def _move_app_path(self):
        """
        Move app_path directory to an archive location
        """
        snapshot_path = self.app_path + datetime.datetime.now().strftime(
            "_%Y%m%d_%H%M%S")

        shutil.move(self.app_path, snapshot_path)
        os.makedirs(self.app_path)

    def _move_std_and_logs(self):
        """
        Rename std and log files
        """
        timestamp = datetime.datetime.now().strftime("_%Y%m%d_%H%M%S")

        for file in (self.outpath, self.errpath, self.logpath):
            if os.path.isfile(file):
                archive(file, timestamp)

    def aborting(self):
        """Abort logic to force kill the child binary."""
        if self.proc:
            self.logger.debug("Killing process id {}".format(self.proc.pid))
            kill_process(self.proc)
        if self.std:
            self.std.close()
Пример #10
0
 def starting(self):
     super(BaseDriver, self).starting()
     self.std = StdFiles(self.runpath)
Пример #11
0
class ZookeeperStandalone(Driver):
    """
    Driver for starting a Zookeeper instance in standalone mode.

    :param template: Zookeeper config file template.
    :type template: ``str``
    :param binary: zkServer.sh file path.
    :type binary: ``str``
    :param port: Zookeeper listen port. Zookeeper doesn't support random port
    :type port: ``int``
    :param env: Environmental variables to be made available to Zookeeper process.
    :type env: ``dict``
    """

    CONFIG = ZookeeperStandaloneConfig

    def __init__(self,
                 name,
                 cfg_template,
                 binary=ZK_SERVER,
                 port=2181,
                 env=None,
                 **options):
        super(ZookeeperStandalone, self).__init__(name=name,
                                                  cfg_template=cfg_template,
                                                  binary=binary,
                                                  port=port,
                                                  env=env,
                                                  **options)
        self.port = port
        self.env = self.cfg.env.copy() if self.cfg.env else {}
        self.config = None
        self.zkdata_path = None
        self.zklog_path = None
        self.etc_path = None
        self.pid_file = None
        self.std = None

    @property
    def connection_str(self):
        return "{}:{}".format("localhost", self.port)

    def pre_start(self):
        """
        Create mandatory directories and install files from given templates
        using the drivers context before starting zookeeper.
        """
        super(ZookeeperStandalone, self).pre_start()
        self.zkdata_path = os.path.join(self.runpath, "zkdata")
        self.zklog_path = os.path.join(self.runpath, "zklog")
        self.etc_path = os.path.join(self.runpath, "etc")
        self.env["ZOO_LOG_DIR"] = self.zklog_path
        for directory in (self.zkdata_path, self.zklog_path, self.etc_path):
            if self.cfg.path_cleanup is False:
                makedirs(directory)
            else:
                makeemptydirs(directory)
        self.config = os.path.join(self.runpath, "etc", "zookeeper.cfg")
        if self.port == 0:
            raise RuntimeError("Zookeeper doesn't support random port")
        instantiate(self.cfg.cfg_template, self.context_input(), self.config)

    def starting(self):
        """Starts the Zookeeper instance."""
        super(ZookeeperStandalone, self).starting()
        start_cmd = [self.cfg.binary, "start", self.config]
        self.std = StdFiles(self.runpath)

        execute_cmd(
            start_cmd,
            label=self.uid(),
            check=True,
            stdout=self.std.out,
            stderr=self.std.err,
            logger=self.logger,
            env=self.env,
        )

    def stopping(self):
        """Stops the Zookeeper instance."""
        stop_cmd = [self.cfg.binary, "stop", self.config]
        try:
            execute_cmd(
                stop_cmd,
                label=self.uid(),
                check=True,
                stdout=self.std.out,
                stderr=self.std.err,
                logger=self.logger,
                env=self.env,
            )
        finally:
            self.std.close()