Beispiel #1
0
 def test_stop_warning(self, m_log_warning, m_subp):
     err = exceptions.ProcessExecutionError("cmd")
     m_subp.side_effect = err
     stop()
     assert [mock.call(["systemctl", "stop", "ubuntu-advantage.service"])
             ] == m_subp.call_args_list
     assert [mock.call(err)] == m_log_warning.call_args_list
 def fake_subp(cmd):
     if cmd[0] == "git":
         # Not matching tag on git-ubuntu pkg branches
         raise exceptions.ProcessExecutionError(
             "fatal: No names found, cannot describe anything.")
     if cmd[0] == "dpkg-parsechangelog":
         return ("24.1\n", "")
     assert False, "Unexpected subp cmd {}".format(cmd)
Beispiel #3
0
    def test_status_command_retry_on_application_status(
            self, m_which, m_sleep, entitlement):
        from uaclient import util

        with mock.patch.object(util, "_subp") as m_subp:
            m_subp.side_effect = exceptions.ProcessExecutionError("error msg")
            status, details = entitlement.application_status()

            assert m_subp.call_count == 3
            assert m_sleep.call_count == 2
            assert status == ApplicationStatus.DISABLED
            assert "error msg" in details.msg
    def test_remove_packages_output_message_when_fail(self,
                                                      m_get_installed_packages,
                                                      m_subp, _m_get_platform,
                                                      entitlement):
        m_get_installed_packages.return_value = ["ubuntu-fips"]
        m_subp.side_effect = exceptions.ProcessExecutionError(cmd="test")
        expected_msg = "Could not disable {}.".format(entitlement.title)

        with pytest.raises(exceptions.UserFacingError) as exc_info:
            entitlement.remove_packages()

        assert exc_info.value.msg.strip() == expected_msg
Beispiel #5
0
    def test_enable_alerts_user_that_snapd_does_not_wait_command(
        self,
        m_subp,
        m_installed_pkgs,
        m_which,
        m_livepatch_proxy,
        m_snap_proxy,
        m_validate_proxy,
        entitlement,
        capsys,
        caplog_text,
    ):
        m_which.side_effect = [True, False]
        m_installed_pkgs.return_value = ["snapd"]
        stderr_msg = (
            "error: Unknown command `wait'. Please specify one command of: "
            "abort, ack, buy, change, changes, connect, create-user, disable,"
            " disconnect, download, enable, find, help, install, interfaces, "
            "known, list, login, logout, refresh, remove, run or try")

        m_subp.side_effect = [
            exceptions.ProcessExecutionError(
                cmd="snapd wait system seed.loaded",
                exit_code=-1,
                stdout="",
                stderr=stderr_msg,
            ),
            True,
        ]

        fake_stdout = io.StringIO()

        with mock.patch.object(entitlement, "can_enable") as m_can_enable:
            m_can_enable.return_value = (True, None)
            with mock.patch.object(
                    entitlement,
                    "setup_livepatch_config") as m_setup_livepatch:
                with contextlib.redirect_stdout(fake_stdout):
                    entitlement.enable()

                assert 1 == m_can_enable.call_count
                assert 1 == m_setup_livepatch.call_count

        assert ("Installing canonical-livepatch snap"
                in fake_stdout.getvalue().strip())

        for msg in messages.SNAPD_DOES_NOT_HAVE_WAIT_CMD.split("\n"):
            assert msg in caplog_text()

        assert m_validate_proxy.call_count == 2
        assert m_snap_proxy.call_count == 1
        assert m_livepatch_proxy.call_count == 1
Beispiel #6
0
    def test_run_apt_command_with_invalid_repositories(self, m_subp,
                                                       error_list,
                                                       output_list):
        error_msg = "\n".join(error_list)

        m_subp.side_effect = exceptions.ProcessExecutionError(cmd="apt update",
                                                              stderr=error_msg)

        with pytest.raises(exceptions.UserFacingError) as excinfo:
            run_apt_update_command()

        expected_message = "\n".join(output_list) + "."
        assert expected_message == excinfo.value.msg
Beispiel #7
0
class TestGetCloudType:
    @mock.patch(M_PATH + "util.which", return_value="/usr/bin/cloud-id")
    @mock.patch(M_PATH + "util.subp", return_value=("somecloud\n", ""))
    def test_use_cloud_id_when_available(self, m_subp, m_which):
        """Use cloud-id utility to discover cloud type."""
        assert ("somecloud", None) == get_cloud_type.__wrapped__()
        assert [mock.call("cloud-id")] == m_which.call_args_list

    @mock.patch(M_PATH + "util.which", return_value="/usr/bin/cloud-id")
    @mock.patch(
        M_PATH + "util.subp",
        side_effect=exceptions.ProcessExecutionError("cloud-id"),
    )
    def test_error_when_cloud_id_fails(self, m_subp, m_which):
        assert (
            None,
            NoCloudTypeReason.CLOUD_ID_ERROR,
        ) == get_cloud_type.__wrapped__()

    @pytest.mark.parametrize(
        "settings_overrides",
        (
            ("""
                settings_overrides:
                  cloud_type: "azure"
                """),
            ("""
                settings_overrides:
                  other_setting: "blah"
                """),
        ),
    )
    @mock.patch("uaclient.util.load_file")
    @mock.patch(M_PATH + "util.which", return_value="/usr/bin/cloud-id")
    @mock.patch(M_PATH + "util.subp", return_value=("test", ""))
    def test_cloud_type_when_using_settings_override(self, m_subp, m_which,
                                                     m_load_file,
                                                     settings_overrides):
        if "azure" in settings_overrides:
            expected_value = "azure"
        else:
            expected_value = "test"

        m_load_file.return_value = settings_overrides
        assert get_cloud_type.__wrapped__() == (expected_value, None)
Beispiel #8
0
class TestGetInstanceID:
    @mock.patch(M_PATH + "util.subp", return_value=("my-iid\n", ""))
    def test_use_cloud_init_query(self, m_subp):
        """Get instance_id from cloud-init query."""
        assert "my-iid" == get_instance_id()
        assert [mock.call(["cloud-init", "query",
                           "instance_id"])] == m_subp.call_args_list

    @mock.patch(
        M_PATH + "util.subp",
        side_effect=exceptions.ProcessExecutionError(
            "cloud-init query instance_id"),
    )
    def test_none_when_cloud_init_query_fails(self, m_subp):
        """Return None when cloud-init query fails."""
        assert None is get_instance_id()
        assert [mock.call(["cloud-init", "query",
                           "instance_id"])] == m_subp.call_args_list
Beispiel #9
0
    def test_application_status(self, m_subp, m_which, subp_raise_exception,
                                which_result, entitlement):
        m_which.return_value = which_result

        if subp_raise_exception:
            m_subp.side_effect = exceptions.ProcessExecutionError("error msg")

        status, details = entitlement.application_status()

        if not which_result:
            assert status == ApplicationStatus.DISABLED
            assert "canonical-livepatch snap is not installed." in details.msg
        elif subp_raise_exception:
            assert status == ApplicationStatus.DISABLED
            assert "error msg" in details.msg
        else:
            assert status == ApplicationStatus.ENABLED
            assert details is None
Beispiel #10
0
    def test_errors_on_process_execution_errors(
        self,
        m_exists,
        m_subp,
        m_temporary_directory,
        exit_code,
        stderr,
        error_msg,
    ):
        """Raise the appropriate user facing error from apt-helper failure."""
        m_temporary_directory.return_value.__enter__.return_value = (
            "/does/not/exist")
        # Failure apt-helper response
        m_subp.side_effect = exceptions.ProcessExecutionError(
            cmd="apt-helper ",
            exit_code=exit_code,
            stdout="Err:1...",
            stderr=stderr,
        )

        with pytest.raises(exceptions.UserFacingError) as excinfo:
            assert_valid_apt_credentials(repo_url="http://fakerepo",
                                         username="******",
                                         password="******")
        assert error_msg == str(excinfo.value)
        exists_calls = [mock.call("/usr/lib/apt/apt-helper")]
        assert exists_calls == m_exists.call_args_list
        expected_path = os.path.join(
            m_temporary_directory.return_value.__enter__.return_value,
            "apt-helper-output",
        )
        apt_helper_call = mock.call(
            [
                "/usr/lib/apt/apt-helper",
                "download-file",
                "http://*****:*****@fakerepo/ubuntu/pool/",
                expected_path,
            ],
            timeout=60,
            retry_sleeps=APT_RETRIES,
        )
        assert [apt_helper_call] == m_subp.call_args_list
Beispiel #11
0
    def test_enable_raise_exception_for_unexpected_error_on_snapd_wait(
        self,
        m_subp,
        m_installed_pkgs,
        m_which,
        m_livepatch_proxy,
        m_snap_proxy,
        m_validate_proxy,
        entitlement,
    ):
        m_which.side_effect = [False, True]
        m_installed_pkgs.return_value = ["snapd"]
        stderr_msg = "test error"

        m_subp.side_effect = exceptions.ProcessExecutionError(
            cmd="snapd wait system seed.loaded",
            exit_code=-1,
            stdout="",
            stderr=stderr_msg,
        )

        with mock.patch.object(entitlement, "can_enable") as m_can_enable:
            m_can_enable.return_value = (True, None)
            with mock.patch.object(
                    entitlement,
                    "setup_livepatch_config") as m_setup_livepatch:
                with pytest.raises(
                        exceptions.ProcessExecutionError) as excinfo:
                    entitlement.enable()

            assert 1 == m_can_enable.call_count
            assert 0 == m_setup_livepatch.call_count

        expected_msg = "test error"
        assert expected_msg in str(excinfo)
        assert m_validate_proxy.call_count == 0
        assert m_snap_proxy.call_count == 0
        assert m_livepatch_proxy.call_count == 0
 def fake_subp(cmd, capture=None, retry_sleeps=None, env={}):
     if cmd == ["apt-get", "update"]:
         raise exceptions.ProcessExecutionError(
             "Failure", stderr="Could not get lock /var/lib/dpkg/lock")
     return "", ""
Beispiel #13
0
 def fake_subp(args, *other_args, **kwargs):
     if "install" in args:
         raise exceptions.ProcessExecutionError(args)
Beispiel #14
0
def _subp(
    args: Sequence[str],
    rcs: Optional[List[int]] = None,
    capture: bool = False,
    timeout: Optional[float] = None,
    env: Optional[Dict[str, str]] = None,
) -> Tuple[str, str]:
    """Run a command and return a tuple of decoded stdout, stderr.

    @param args: A list of arguments to feed to subprocess.Popen
    @param rcs: A list of allowed return_codes. If returncode not in rcs
        raise a ProcessExecutionError.
    @param capture: Boolean set True to log the command and response.
    @param timeout: Optional float indicating number of seconds to wait for
        subp to return.
    @param env: Optional dictionary of environment variable to pass to Popen.

    @return: Tuple of utf-8 decoded stdout, stderr
    @raises ProcessExecutionError on invalid command or returncode not in rcs.
    @raises subprocess.TimeoutError when timeout specified and the command
        exceeds that number of seconds.
    """
    bytes_args = [
        x if isinstance(x, bytes) else x.encode("utf-8") for x in args
    ]
    if env:
        env.update(os.environ)
    if rcs is None:
        rcs = [0]
    redacted_cmd = redact_sensitive_logs(" ".join(args))
    try:
        proc = subprocess.Popen(bytes_args,
                                stdout=subprocess.PIPE,
                                stderr=subprocess.PIPE,
                                env=env)
        (out, err) = proc.communicate(timeout=timeout)
    except OSError:
        try:
            raise exceptions.ProcessExecutionError(
                cmd=redacted_cmd,
                exit_code=proc.returncode,
                stdout=out.decode("utf-8"),
                stderr=err.decode("utf-8"),
            )
        except UnboundLocalError:
            raise exceptions.ProcessExecutionError(cmd=redacted_cmd)
    if proc.returncode not in rcs:
        raise exceptions.ProcessExecutionError(
            cmd=redacted_cmd,
            exit_code=proc.returncode,
            stdout=out.decode("utf-8"),
            stderr=err.decode("utf-8"),
        )
    if capture:
        logging.debug(
            "Ran cmd: %s, rc: %s stderr: %s",
            redacted_cmd,
            proc.returncode,
            err,
        )
    return out.decode("utf-8"), err.decode("utf-8")
 def fake_subp(cmd, *args, **kwargs):
     if "install" in cmd:
         raise exceptions.ProcessExecutionError(cmd)
     return ("", "")
Beispiel #16
0
class TestConfigureSnapProxy:
    @pytest.mark.parametrize(
        "http_proxy,https_proxy,retry_sleeps",
        (
            ("http_proxy", "https_proxy", [1, 2]),
            ("http_proxy", "", None),
            ("", "https_proxy", [1, 2]),
            ("http_proxy", None, [1, 2]),
            (None, "https_proxy", None),
            (None, None, [1, 2]),
        ),
    )
    @mock.patch("uaclient.util.subp")
    @mock.patch("uaclient.util.which", return_value=True)
    def test_configure_snap_proxy(self, m_which, m_subp, http_proxy,
                                  https_proxy, retry_sleeps, capsys):
        configure_snap_proxy(http_proxy, https_proxy, retry_sleeps)
        expected_calls = []
        if http_proxy:
            expected_calls.append(
                mock.call(
                    [
                        "snap",
                        "set",
                        "system",
                        "proxy.http={}".format(http_proxy),
                    ],
                    retry_sleeps=retry_sleeps,
                ))

        if https_proxy:
            expected_calls.append(
                mock.call(
                    [
                        "snap",
                        "set",
                        "system",
                        "proxy.https={}".format(https_proxy),
                    ],
                    retry_sleeps=retry_sleeps,
                ))

        assert m_subp.call_args_list == expected_calls

        out, _ = capsys.readouterr()
        if http_proxy or https_proxy:
            assert out.strip() == messages.SETTING_SERVICE_PROXY.format(
                service="snap")

    @pytest.mark.parametrize(
        "key, subp_side_effect, expected_ret",
        [
            (
                "proxy.http",
                exceptions.ProcessExecutionError("doesn't matter"),
                None,
            ),
            ("proxy.https", ("value", ""), "value"),
        ],
    )
    @mock.patch("uaclient.util.subp")
    def test_get_config_option_value(self, m_util_subp, key, subp_side_effect,
                                     expected_ret):
        m_util_subp.side_effect = [subp_side_effect]
        ret = get_config_option_value(key)
        assert ret == expected_ret
        assert [mock.call(["snap", "get", "system",
                           key])] == m_util_subp.call_args_list