Пример #1
0
class VatTerminal:
    """VAT interactive terminal.

    :param node: Node to open VAT terminal on.
    :param json_param: Defines if outputs from VAT are in JSON format.
        Default is True.
    :type node: dict
    :type json_param: bool

    """

    __VAT_PROMPT = (u"vat# ", )
    __LINUX_PROMPT = (u":~# ", u":~$ ", u"~]$ ", u"~]# ")

    def __init__(self, node, json_param=True):
        json_text = u" json" if json_param else u""
        self.json = json_param
        self._node = node
        self._ssh = SSH()
        self._ssh.connect(self._node)
        try:
            self._tty = self._ssh.interactive_terminal_open()
        except Exception:
            raise RuntimeError(f"Cannot open interactive terminal on node "
                               f"{self._node[u'host']}")

        for _ in range(3):
            try:
                self._ssh.interactive_terminal_exec_command(
                    self._tty, f"sudo -S {Constants.VAT_BIN_NAME}{json_text}",
                    self.__VAT_PROMPT)
            except Exception:
                continue
            else:
                break
        else:
            vpp_pid = get_vpp_pid(self._node)
            if vpp_pid:
                if isinstance(vpp_pid, int):
                    logger.trace(f"VPP running on node {self._node[u'host']}")
                else:
                    logger.error(f"More instances of VPP running "
                                 f"on node {self._node[u'host']}.")
            else:
                logger.error(f"VPP not running on node {self._node[u'host']}.")
            raise RuntimeError(
                f"Failed to open VAT console on node {self._node[u'host']}")

        self._exec_failure = False
        self.vat_stdout = None

    def __enter__(self):
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.vat_terminal_close()

    def vat_terminal_exec_cmd(self, cmd):
        """Execute command on the opened VAT terminal.

        :param cmd: Command to be executed.

        :returns: Command output in python representation of JSON format or
            None if not in JSON mode.
        """
        PapiHistory.add_to_papi_history(self._node, cmd, papi=False)
        logger.debug(f"Executing command in VAT terminal: {cmd}")
        try:
            out = self._ssh.interactive_terminal_exec_command(
                self._tty, cmd, self.__VAT_PROMPT)
            self.vat_stdout = out
        except Exception:
            self._exec_failure = True
            vpp_pid = get_vpp_pid(self._node)
            if vpp_pid:
                if isinstance(vpp_pid, int):
                    msg = f"VPP running on node {self._node[u'host']} " \
                        f"but VAT command {cmd} execution failed."
                else:
                    msg = f"More instances of VPP running on node " \
                        f"{self._node[u'host']}. VAT command {cmd} " \
                        f"execution failed."
            else:
                msg = f"VPP not running on node {self._node[u'host']}. " \
                    f"VAT command {cmd} execution failed."
            raise RuntimeError(msg)

        logger.debug(f"VAT output: {out}")
        if self.json:
            obj_start = out.find(u"{")
            obj_end = out.rfind(u"}")
            array_start = out.find(u"[")
            array_end = out.rfind(u"]")

            if obj_start == -1 and array_start == -1:
                raise RuntimeError(f"VAT command {cmd}: no JSON data.")

            if obj_start < array_start or array_start == -1:
                start = obj_start
                end = obj_end + 1
            else:
                start = array_start
                end = array_end + 1
            out = out[start:end]
            json_out = json.loads(out)
            return json_out

        return None

    def vat_terminal_close(self):
        """Close VAT terminal."""
        # interactive terminal is dead, we only need to close session
        if not self._exec_failure:
            try:
                self._ssh.interactive_terminal_exec_command(
                    self._tty, u"quit", self.__LINUX_PROMPT)
            except Exception:
                vpp_pid = get_vpp_pid(self._node)
                if vpp_pid:
                    if isinstance(vpp_pid, int):
                        logger.trace(
                            f"VPP running on node {self._node[u'host']}.")
                    else:
                        logger.error(f"More instances of VPP running "
                                     f"on node {self._node[u'host']}.")
                else:
                    logger.error(
                        f"VPP not running on node {self._node[u'host']}.")
                raise RuntimeError(f"Failed to close VAT console "
                                   f"on node {self._node[u'host']}")
        try:
            self._ssh.interactive_terminal_close(self._tty)
        except Exception:
            raise RuntimeError(f"Cannot close interactive terminal "
                               f"on node {self._node[u'host']}")

    def vat_terminal_exec_cmd_from_template(self, vat_template_file, **args):
        """Execute VAT script from a file.

        :param vat_template_file: Template file name of a VAT script.
        :param args: Dictionary of parameters for VAT script.
        :returns: List of JSON objects returned by VAT.
        """
        file_path = f"{Constants.RESOURCES_TPL_VAT}/{vat_template_file}"

        with open(file_path, u"rt") as template_file:
            cmd_template = template_file.readlines()
        ret = list()
        for line_tmpl in cmd_template:
            vat_cmd = line_tmpl.format(**args)
            ret.append(self.vat_terminal_exec_cmd(vat_cmd.replace(u"\n", u"")))
        return ret
Пример #2
0
class VatTerminal(object):
    """VAT interactive terminal.

    :param node: Node to open VAT terminal on.
    :param json_param: Defines if outputs from VAT are in JSON format.
        Default is True.
    :type node: dict
    :type json_param: bool

    """

    __VAT_PROMPT = ("vat# ", )
    __LINUX_PROMPT = (":~$ ", "~]$ ", "~]# ")

    def __init__(self, node, json_param=True):
        json_text = ' json' if json_param else ''
        self.json = json_param
        self._node = node
        self._ssh = SSH()
        self._ssh.connect(self._node)
        try:
            self._tty = self._ssh.interactive_terminal_open()
        except Exception:
            raise RuntimeError(
                "Cannot open interactive terminal on node {0}".format(
                    self._node))

        for _ in range(3):
            try:
                self._ssh.interactive_terminal_exec_command(
                    self._tty, 'sudo -S {0}{1}'.format(Constants.VAT_BIN_NAME,
                                                       json_text),
                    self.__VAT_PROMPT)
            except Exception:
                continue
            else:
                break
        else:
            vpp_pid = get_vpp_pid(self._node)
            if vpp_pid:
                if isinstance(vpp_pid, int):
                    logger.trace("VPP running on node {0}".format(
                        self._node['host']))
                else:
                    logger.error(
                        "More instances of VPP running on node {0}.".format(
                            self._node['host']))
            else:
                logger.error("VPP not running on node {0}.".format(
                    self._node['host']))
            raise RuntimeError("Failed to open VAT console on node {0}".format(
                self._node['host']))

        self._exec_failure = False
        self.vat_stdout = None

    def __enter__(self):
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.vat_terminal_close()

    def vat_terminal_exec_cmd(self, cmd):
        """Execute command on the opened VAT terminal.

        :param cmd: Command to be executed.

        :returns: Command output in python representation of JSON format or
            None if not in JSON mode.
        """
        VatHistory.add_to_vat_history(self._node, cmd)
        logger.debug("Executing command in VAT terminal: {0}".format(cmd))
        try:
            out = self._ssh.interactive_terminal_exec_command(
                self._tty, cmd, self.__VAT_PROMPT)
            self.vat_stdout = out
        except Exception:
            self._exec_failure = True
            vpp_pid = get_vpp_pid(self._node)
            if vpp_pid:
                if isinstance(vpp_pid, int):
                    raise RuntimeError(
                        "VPP running on node {0} but VAT command"
                        " {1} execution failed.".format(
                            self._node['host'], cmd))
                else:
                    raise RuntimeError(
                        "More instances of VPP running on node "
                        "{0}. VAT command {1} execution failed.".format(
                            self._node['host'], cmd))
            else:
                raise RuntimeError("VPP not running on node {0}. VAT command "
                                   "{1} execution failed.".format(
                                       self._node['host'], cmd))

        logger.debug("VAT output: {0}".format(out))
        if self.json:
            obj_start = out.find('{')
            obj_end = out.rfind('}')
            array_start = out.find('[')
            array_end = out.rfind(']')

            if obj_start == -1 and array_start == -1:
                raise RuntimeError(
                    "VAT command {0}: no JSON data.".format(cmd))

            if obj_start < array_start or array_start == -1:
                start = obj_start
                end = obj_end + 1
            else:
                start = array_start
                end = array_end + 1
            out = out[start:end]
            json_out = json.loads(out)
            return json_out
        else:
            return None

    def vat_terminal_close(self):
        """Close VAT terminal."""
        # interactive terminal is dead, we only need to close session
        if not self._exec_failure:
            try:
                self._ssh.interactive_terminal_exec_command(
                    self._tty, 'quit', self.__LINUX_PROMPT)
            except Exception:
                vpp_pid = get_vpp_pid(self._node)
                if vpp_pid:
                    if isinstance(vpp_pid, int):
                        logger.trace("VPP running on node {0}.".format(
                            self._node['host']))
                    else:
                        logger.error("More instances of VPP running on node "
                                     "{0}.".format(self._node['host']))
                else:
                    logger.error("VPP not running on node {0}.".format(
                        self._node['host']))
                raise RuntimeError(
                    "Failed to close VAT console on node {0}".format(
                        self._node['host']))
        try:
            self._ssh.interactive_terminal_close(self._tty)
        except:
            raise RuntimeError(
                "Cannot close interactive terminal on node {0}".format(
                    self._node['host']))

    def vat_terminal_exec_cmd_from_template(self, vat_template_file, **args):
        """Execute VAT script from a file.

        :param vat_template_file: Template file name of a VAT script.
        :param args: Dictionary of parameters for VAT script.
        :returns: List of JSON objects returned by VAT.
        """
        file_path = '{}/{}'.format(Constants.RESOURCES_TPL_VAT,
                                   vat_template_file)
        with open(file_path, 'r') as template_file:
            cmd_template = template_file.readlines()
        ret = []
        for line_tmpl in cmd_template:
            vat_cmd = line_tmpl.format(**args)
            ret.append(self.vat_terminal_exec_cmd(vat_cmd.replace('\n', '')))
        return ret