Esempio n. 1
0
    def _ssh(self, command, stdin=None):
        """Run a command via SSH.

        Args:
            command: string or list of the command to run
            stdin: optional, values to be passed in

        Returns:
            tuple of stdout, stderr and the return code

        """
        client = self._ssh_connect()

        cmd = shell_pack(command)
        fp_in, fp_out, fp_err = client.exec_command(cmd)
        channel = fp_in.channel

        if stdin is not None:
            fp_in.write(stdin)
            fp_in.close()

        channel.shutdown_write()

        out = fp_out.read()
        err = fp_err.read()
        return_code = channel.recv_exit_status()

        out = '' if not out else out.rstrip().decode("utf-8")
        err = '' if not err else err.rstrip().decode("utf-8")

        return Result(out, err, return_code)
Esempio n. 2
0
    def test_happy_path(self, m_subp):
        """Command succeeds and returns valid YAML."""
        image_id = "my:image_id"
        content = {"my": "data"}
        m_subp.return_value = Result(yaml.dump(content), "", 0)

        ret = LXDVirtualMachine(tag="test")._lxc_image_info(image_id)

        assert content == ret
        expected_call = mock.call(["lxc", "image", "info", image_id], rcs=())
        assert [expected_call] == m_subp.call_args_list
Esempio n. 3
0
    def _ssh(self, command, stdin=None):
        """Run a command via SSH.

        Args:
            command: string or list of the command to run
            stdin: optional, values to be passed in

        Returns:
            tuple of stdout, stderr and the return code

        """
        cmd = shell_pack(command)
        for _ in range(10):
            try:
                client = self._ssh_connect()
                fp_in, fp_out, fp_err = client.exec_command(cmd)
                break
            except (ConnectionResetError, NoValidConnectionsError) as e:
                last_error = e
            # On OCI instances, attempting to re-connect without a longer
            # sleep leaves you locked out of ssh completely
            time.sleep(5)
        else:
            raise last_error  # noqa
        channel = fp_in.channel

        if stdin is not None:
            fp_in.write(stdin)
            fp_in.close()

        channel.shutdown_write()

        out = fp_out.read()
        err = fp_err.read()
        return_code = channel.recv_exit_status()

        out = '' if not out else out.rstrip().decode("utf-8")
        err = '' if not err else err.rstrip().decode("utf-8")

        return Result(out, err, return_code)
Esempio n. 4
0
    def test_invalid_yaml_returns_empty_dict(self, m_subp):
        """Invalid YAML even with command success returns empty dict."""
        m_subp.return_value = Result("{:a}", "", 0)

        assert {} == LXDVirtualMachine(tag="test")._lxc_image_info("image_id")
Esempio n. 5
0
    def test_command_failure_returns_empty_dict(self, m_subp):
        """Command failure even with valid YAML returns empty dict."""
        content = {"my": "data"}
        m_subp.return_value = Result(yaml.dump(content), "", 1)

        assert {} == LXDVirtualMachine(tag="test")._lxc_image_info("image_id")
Esempio n. 6
0
def subp(args,
         data=None,
         env=None,
         shell=False,
         rcs=(0, ),
         shortcircuit_stdin=True):
    """Subprocess wrapper.

    Args:
        args: command to run
        data: data to pass
        env: optional env to use
        shell: optional shell to use
        rcs: tuple of successful exit codes, default: (0)
        shortcircuit_stdin: bind stdin to /dev/null if no data is given

    Returns:
        Tuple of out, err, return_code

    """
    devnull_fp = None

    if data is not None:
        stdin = subprocess.PIPE
        if not isinstance(data, bytes):
            data = data.encode()
    elif shortcircuit_stdin:
        # using devnull assures any reads get null, rather
        # than possibly waiting on input.
        devnull_fp = open(os.devnull)
        stdin = devnull_fp
    else:
        stdin = None

    bytes_args = _convert_args(args)

    try:
        process = subprocess.Popen(bytes_args,
                                   stdout=subprocess.PIPE,
                                   stderr=subprocess.PIPE,
                                   stdin=stdin,
                                   env=env,
                                   shell=shell)
        (out, err) = process.communicate(data)
    finally:
        if devnull_fp:
            devnull_fp.close()

    rc = process.returncode
    out = '' if not out else out.rstrip().decode("utf-8")
    err = '' if not err else err.rstrip().decode("utf-8")

    if rcs and rc not in rcs:
        if err:
            errmsg = err
        elif out:
            errmsg = out
        else:
            errmsg = "command failed silently"
        errmsg = "Failure (rc=%s): %s" % (rc, errmsg)
        raise RuntimeError(errmsg)

    return Result(out, err, rc)