def test_non_root_users_are_rejected(self, m_getuid, _m_prompt, FakeConfig,
                                         event, capsys):
        """Check that a UID != 0 will receive a message and exit non-zero"""
        m_getuid.return_value = 1
        args = mock.MagicMock()

        cfg = FakeConfig.for_attached_machine()
        with pytest.raises(exceptions.NonRootUserError):
            action_detach(args, cfg=cfg)

        with pytest.raises(SystemExit):
            with mock.patch.object(event, "_event_logger_mode",
                                   event_logger.EventLoggerMode.JSON):
                main_error_handler(action_detach)(args, cfg)

        expected_message = messages.NONROOT_USER
        expected = {
            "_schema_version":
            event_logger.JSON_SCHEMA_VERSION,
            "result":
            "failure",
            "errors": [{
                "message": expected_message.msg,
                "message_code": expected_message.name,
                "service": None,
                "type": "system",
            }],
            "failed_services": [],
            "needs_reboot":
            False,
            "processed_services": [],
            "warnings": [],
        }
        assert expected == json.loads(capsys.readouterr()[0])
    def test_correct_message_emitted(
        self,
        m_update_apt_and_motd_msgs,
        m_client,
        m_entitlements,
        m_getuid,
        _m_prompt,
        capsys,
        FakeConfig,
        tmpdir,
    ):
        m_getuid.return_value = 0
        m_entitlements.ENTITLEMENT_CLASSES = []

        fake_client = FakeContractClient(FakeConfig.for_attached_machine())
        m_client.return_value = fake_client

        m_cfg = mock.MagicMock()
        m_cfg.check_lock_info.return_value = (-1, "")
        m_cfg.data_path.return_value = tmpdir.join("lock").strpath
        action_detach(mock.MagicMock(), m_cfg)

        out, _err = capsys.readouterr()

        assert messages.DETACH_SUCCESS + "\n" == out
        assert [mock.call(m_cfg)] == m_update_apt_and_motd_msgs.call_args_list
    def test_unattached_error_message(self, m_getuid, _m_prompt, FakeConfig,
                                      capsys, event):
        """Check that root user gets unattached message."""

        m_getuid.return_value = 0
        cfg = FakeConfig()
        args = mock.MagicMock()
        with pytest.raises(exceptions.UnattachedError) as err:
            action_detach(args, cfg=cfg)
        assert messages.UNATTACHED.msg == err.value.msg

        with pytest.raises(SystemExit):
            with mock.patch.object(event, "_event_logger_mode",
                                   event_logger.EventLoggerMode.JSON):
                main_error_handler(action_detach)(args, cfg)

        expected_message = messages.UNATTACHED
        expected = {
            "_schema_version":
            event_logger.JSON_SCHEMA_VERSION,
            "result":
            "failure",
            "errors": [{
                "message": expected_message.msg,
                "message_code": expected_message.name,
                "service": None,
                "type": "system",
            }],
            "failed_services": [],
            "needs_reboot":
            False,
            "processed_services": [],
            "warnings": [],
        }
        assert expected == json.loads(capsys.readouterr()[0])
    def test_non_root_users_are_rejected(self, m_getuid, _m_prompt):
        """Check that a UID != 0 will receive a message and exit non-zero"""
        m_getuid.return_value = 1

        cfg = FakeConfig.for_attached_machine()
        with pytest.raises(exceptions.NonRootUserError):
            action_detach(mock.MagicMock(), cfg)
Beispiel #5
0
def _prompt_for_new_token(cfg: UAConfig) -> bool:
    """Prompt for attach a new subscription token to the user.

    :return: True if attach performed.
    """
    import argparse

    from uaclient import cli

    _inform_ubuntu_pro_existence_if_applicable()
    print(messages.SECURITY_UPDATE_NOT_INSTALLED_EXPIRED)
    choice = util.prompt_choices(
        "Choose: [R]enew your subscription (at {}) [C]ancel".format(
            BASE_UA_URL
        ),
        valid_choices=["r", "c"],
    )
    if choice == "r":
        print(messages.PROMPT_EXPIRED_ENTER_TOKEN)
        token = input("> ")
        print(colorize_commands([["ua", "detach"]]))
        cli.action_detach(
            argparse.Namespace(assume_yes=True, format="cli"), cfg
        )
        return _run_ua_attach(cfg, token)

    return False
Beispiel #6
0
    def test_informational_message_emitted(
        self,
        m_client,
        m_entitlements,
        m_getuid,
        _m_prompt,
        capsys,
        classes,
        expected_message,
        FakeConfig,
        tmpdir,
    ):
        m_getuid.return_value = 0
        m_entitlements.ENTITLEMENT_CLASSES = classes

        fake_client = FakeContractClient(FakeConfig.for_attached_machine())
        m_client.return_value = fake_client

        m_cfg = mock.MagicMock()
        m_cfg.data_path.return_value = tmpdir.join("lock").strpath

        action_detach(mock.MagicMock(), m_cfg)

        out, _err = capsys.readouterr()

        assert expected_message in out
    def test_config_cache_deleted(self, m_entitlements, m_getuid, _m_prompt):
        m_getuid.return_value = 0
        m_entitlements.ENTITLEMENT_CLASSES = []

        cfg = mock.MagicMock()
        action_detach(mock.MagicMock(), cfg)

        assert [mock.call()] == cfg.delete_cache.call_args_list
Beispiel #8
0
    def test_unattached_error_message(self, m_getuid, _m_prompt, FakeConfig):
        """Check that root user gets unattached message."""

        m_getuid.return_value = 0
        cfg = FakeConfig()
        with pytest.raises(exceptions.UnattachedError) as err:
            action_detach(mock.MagicMock(), cfg)
        assert status.MESSAGE_UNATTACHED == err.value.msg
    def test_correct_message_emitted(
        self, m_entitlements, m_getuid, _m_prompt, capsys
    ):
        m_getuid.return_value = 0
        m_entitlements.ENTITLEMENT_CLASSES = []

        action_detach(mock.MagicMock(), mock.MagicMock())

        out, _err = capsys.readouterr()

        assert status.MESSAGE_DETACH_SUCCESS + "\n" == out
Beispiel #10
0
 def test_lock_file_exists(self, m_subp, m_getuid, m_prompt, FakeConfig):
     """Check when an operation holds a lock file, detach cannot run."""
     m_getuid.return_value = 0
     cfg = FakeConfig.for_attached_machine()
     with open(cfg.data_path("lock"), "w") as stream:
         stream.write("123:ua enable")
     with pytest.raises(exceptions.LockHeldError) as err:
         action_detach(mock.MagicMock(), cfg)
     assert [mock.call(["ps", "123"])] == m_subp.call_args_list
     assert ("Unable to perform: ua detach.\n"
             "Operation in progress: ua enable (pid:123)") == err.value.msg
Beispiel #11
0
    def test_config_cache_deleted(self, m_client, m_entitlements, m_getuid,
                                  _m_prompt, FakeConfig):
        m_getuid.return_value = 0
        m_entitlements.ENTITLEMENT_CLASSES = []

        fake_client = FakeContractClient(FakeConfig.for_attached_machine())
        m_client.return_value = fake_client

        cfg = mock.MagicMock()
        action_detach(mock.MagicMock(), cfg)

        assert [mock.call()] == cfg.delete_cache.call_args_list
Beispiel #12
0
    def test_correct_message_emitted(self, m_client, m_entitlements, m_getuid,
                                     _m_prompt, capsys, FakeConfig):
        m_getuid.return_value = 0
        m_entitlements.ENTITLEMENT_CLASSES = []

        fake_client = FakeContractClient(FakeConfig.for_attached_machine())
        m_client.return_value = fake_client

        action_detach(mock.MagicMock(), mock.MagicMock())

        out, _err = capsys.readouterr()

        assert status.MESSAGE_DETACH_SUCCESS + "\n" == out
Beispiel #13
0
    def test_config_cache_deleted(self, m_client, m_entitlements, m_getuid,
                                  _m_prompt, FakeConfig, tmpdir):
        m_getuid.return_value = 0
        m_entitlements.ENTITLEMENT_CLASSES = []

        fake_client = FakeContractClient(FakeConfig.for_attached_machine())
        m_client.return_value = fake_client

        m_cfg = mock.MagicMock()
        m_cfg.data_path.return_value = tmpdir.join("lock").strpath
        action_detach(mock.MagicMock(), m_cfg)

        assert [mock.call()] == m_cfg.delete_cache.call_args_list
    def test_informational_message_emitted(
        self,
        m_update_apt_and_motd_msgs,
        m_client,
        m_entitlements,
        m_getuid,
        _m_prompt,
        capsys,
        classes,
        expected_message,
        disabled_services,
        FakeConfig,
        tmpdir,
        event,
    ):
        m_getuid.return_value = 0
        m_entitlements.ENTITLEMENT_CLASSES = classes

        fake_client = FakeContractClient(FakeConfig.for_attached_machine())
        m_client.return_value = fake_client

        m_cfg = mock.MagicMock()
        m_cfg.check_lock_info.return_value = (-1, "")
        m_cfg.data_path.return_value = tmpdir.join("lock").strpath
        args = mock.MagicMock()

        action_detach(args, m_cfg)

        out, _err = capsys.readouterr()

        assert expected_message in out
        assert [mock.call(m_cfg)] == m_update_apt_and_motd_msgs.call_args_list

        cfg = FakeConfig.for_attached_machine()
        fake_stdout = io.StringIO()
        with contextlib.redirect_stdout(fake_stdout):
            with mock.patch.object(event, "_event_logger_mode",
                                   event_logger.EventLoggerMode.JSON):
                main_error_handler(action_detach)(args, cfg)

        expected = {
            "_schema_version": event_logger.JSON_SCHEMA_VERSION,
            "result": "success",
            "errors": [],
            "failed_services": [],
            "needs_reboot": False,
            "processed_services": disabled_services,
            "warnings": [],
        }
        assert expected == json.loads(fake_stdout.getvalue())
    def test_informational_message_emitted(
        self,
        m_entitlements,
        m_getuid,
        _m_prompt,
        capsys,
        classes,
        expected_message,
    ):
        m_getuid.return_value = 0
        m_entitlements.ENTITLEMENT_CLASSES = classes
        action_detach(mock.MagicMock(), mock.MagicMock())

        out, _err = capsys.readouterr()

        assert expected_message in out
    def test_returns_zero(self, m_entitlements, m_getuid, _m_prompt):
        m_getuid.return_value = 0
        m_entitlements.ENTITLEMENT_CLASSES = []

        ret = action_detach(mock.MagicMock(), mock.MagicMock())

        assert 0 == ret
Beispiel #17
0
    def test_entitlements_disabled_appropriately(
        self,
        m_client,
        m_entitlements,
        m_getuid,
        m_prompt,
        prompt_response,
        assume_yes,
        expect_disable,
        FakeConfig,
    ):
        # The three parameters:
        #   prompt_response: the user's response to the prompt
        #   assume_yes: the value of the --assume-yes flag in the args passed
        #               to the action
        #   expect_disable: whether or not the enabled entitlement is expected
        #                   to be disabled by the action
        m_getuid.return_value = 0

        cfg = FakeConfig.for_attached_machine()
        fake_client = FakeContractClient(cfg)
        m_client.return_value = fake_client

        m_prompt.return_value = prompt_response

        m_entitlements.ENTITLEMENT_CLASSES = [
            entitlement_cls_mock_factory(False),
            entitlement_cls_mock_factory(True),
            entitlement_cls_mock_factory(False),
        ]

        args = mock.MagicMock(assume_yes=assume_yes)
        return_code = action_detach(args, cfg)

        # Check that can_disable is called correctly
        for ent_cls in m_entitlements.ENTITLEMENT_CLASSES:
            assert [mock.call(silent=True)
                    ] == ent_cls.return_value.can_disable.call_args_list

        # Check that disable is only called when can_disable is true
        for undisabled_cls in [
                m_entitlements.ENTITLEMENT_CLASSES[0],
                m_entitlements.ENTITLEMENT_CLASSES[2],
        ]:
            assert 0 == undisabled_cls.return_value.disable.call_count
        disabled_cls = m_entitlements.ENTITLEMENT_CLASSES[1]
        if expect_disable:
            assert [mock.call(silent=True)
                    ] == disabled_cls.return_value.disable.call_args_list
            assert 0 == return_code
        else:
            assert 0 == disabled_cls.return_value.disable.call_count
            assert 1 == return_code
        assert [mock.call(assume_yes=assume_yes)] == m_prompt.call_args_list
Beispiel #18
0
    def test_returns_zero(self, m_client, m_entitlements, m_getuid, _m_prompt,
                          FakeConfig):
        m_getuid.return_value = 0
        m_entitlements.ENTITLEMENT_CLASSES = []

        fake_client = FakeContractClient(FakeConfig.for_attached_machine())
        m_client.return_value = fake_client

        ret = action_detach(mock.MagicMock(), mock.MagicMock())

        assert 0 == ret
Beispiel #19
0
    def test_returns_zero(self, m_client, m_entitlements, m_getuid, _m_prompt,
                          FakeConfig, tmpdir):
        m_getuid.return_value = 0
        m_entitlements.ENTITLEMENT_CLASSES = []

        fake_client = FakeContractClient(FakeConfig.for_attached_machine())
        m_client.return_value = fake_client

        m_cfg = mock.MagicMock()
        m_cfg.data_path.return_value = tmpdir.join("lock").strpath
        ret = action_detach(mock.MagicMock(), m_cfg)

        assert 0 == ret
    def test_lock_file_exists(self, m_subp, m_getuid, m_prompt, FakeConfig,
                              capsys, event):
        """Check when an operation holds a lock file, detach cannot run."""
        m_getuid.return_value = 0
        cfg = FakeConfig.for_attached_machine()
        args = mock.MagicMock()
        with open(cfg.data_path("lock"), "w") as stream:
            stream.write("123:ua enable")
        with pytest.raises(exceptions.LockHeldError) as err:
            action_detach(args, cfg=cfg)
        assert [mock.call(["ps", "123"])] == m_subp.call_args_list
        expected_error_msg = messages.LOCK_HELD_ERROR.format(
            lock_request="ua detach", lock_holder="ua enable", pid="123")
        assert expected_error_msg.msg == err.value.msg

        with pytest.raises(SystemExit):
            with mock.patch.object(event, "_event_logger_mode",
                                   event_logger.EventLoggerMode.JSON):
                main_error_handler(action_detach)(args, cfg)

        expected = {
            "_schema_version":
            event_logger.JSON_SCHEMA_VERSION,
            "result":
            "failure",
            "errors": [{
                "message": expected_error_msg.msg,
                "message_code": expected_error_msg.name,
                "service": None,
                "type": "system",
            }],
            "failed_services": [],
            "needs_reboot":
            False,
            "processed_services": [],
            "warnings": [],
        }
        assert expected == json.loads(capsys.readouterr()[0])
    def test_returns_zero(
        self,
        m_update_apt_and_motd_msgs,
        m_client,
        m_entitlements,
        m_getuid,
        _m_prompt,
        FakeConfig,
        tmpdir,
    ):
        m_getuid.return_value = 0
        m_entitlements.ENTITLEMENT_CLASSES = []

        fake_client = FakeContractClient(FakeConfig.for_attached_machine())
        m_client.return_value = fake_client

        m_cfg = mock.MagicMock()
        m_cfg.check_lock_info.return_value = (-1, "")
        m_cfg.data_path.return_value = tmpdir.join("lock").strpath
        ret = action_detach(mock.MagicMock(), m_cfg)

        assert 0 == ret
        assert [mock.call(m_cfg)] == m_update_apt_and_motd_msgs.call_args_list
    def test_entitlements_disabled_if_can_disable_and_prompt_true(
        self, m_entitlements, m_getuid, m_prompt, prompt_response
    ):
        m_getuid.return_value = 0
        m_prompt.return_value = prompt_response

        m_entitlements.ENTITLEMENT_CLASSES = [
            entitlement_cls_mock_factory(False),
            entitlement_cls_mock_factory(True),
            entitlement_cls_mock_factory(False),
        ]

        return_code = action_detach(
            mock.MagicMock(), FakeConfig.for_attached_machine()
        )

        # Check that can_disable is called correctly
        for ent_cls in m_entitlements.ENTITLEMENT_CLASSES:
            assert [
                mock.call(silent=True)
            ] == ent_cls.return_value.can_disable.call_args_list

        # Check that disable is only called when can_disable is true
        for undisabled_cls in [
            m_entitlements.ENTITLEMENT_CLASSES[0],
            m_entitlements.ENTITLEMENT_CLASSES[2],
        ]:
            assert 0 == undisabled_cls.return_value.disable.call_count
        disabled_cls = m_entitlements.ENTITLEMENT_CLASSES[1]
        if prompt_response:
            assert [
                mock.call(silent=True)
            ] == disabled_cls.return_value.disable.call_args_list
            assert 0 == return_code
        else:
            assert 0 == disabled_cls.return_value.disable.call_count
            assert 1 == return_code
    def test_entitlements_disabled_appropriately(
        self,
        m_update_apt_and_motd_msgs,
        m_client,
        m_entitlements,
        m_getuid,
        m_prompt,
        prompt_response,
        assume_yes,
        expect_disable,
        FakeConfig,
        event,
        capsys,
    ):
        # The three parameters:
        #   prompt_response: the user's response to the prompt
        #   assume_yes: the value of the --assume-yes flag in the args passed
        #               to the action
        #   expect_disable: whether or not the enabled entitlement is expected
        #                   to be disabled by the action
        m_getuid.return_value = 0

        cfg = FakeConfig.for_attached_machine()
        fake_client = FakeContractClient(cfg)
        m_client.return_value = fake_client

        m_prompt.return_value = prompt_response

        m_entitlements.ENTITLEMENT_CLASSES = [
            entitlement_cls_mock_factory(False),
            entitlement_cls_mock_factory(True, name="test"),
            entitlement_cls_mock_factory(False),
        ]

        args = mock.MagicMock(assume_yes=assume_yes)
        return_code = action_detach(args, cfg=cfg)

        # Check that can_disable is called correctly
        for ent_cls in m_entitlements.ENTITLEMENT_CLASSES:
            assert [mock.call(ignore_dependent_services=True)
                    ] == ent_cls.return_value.can_disable.call_args_list

            assert [mock.call(cfg=cfg,
                              assume_yes=assume_yes)] == ent_cls.call_args_list

        # Check that disable is only called when can_disable is true
        for undisabled_cls in [
                m_entitlements.ENTITLEMENT_CLASSES[0],
                m_entitlements.ENTITLEMENT_CLASSES[2],
        ]:
            assert 0 == undisabled_cls.return_value.disable.call_count
        disabled_cls = m_entitlements.ENTITLEMENT_CLASSES[1]
        if expect_disable:
            assert [mock.call()
                    ] == disabled_cls.return_value.disable.call_args_list
            assert 0 == return_code
        else:
            assert 0 == disabled_cls.return_value.disable.call_count
            assert 1 == return_code
        assert [mock.call(assume_yes=assume_yes)] == m_prompt.call_args_list
        if expect_disable:
            assert [mock.call(cfg)
                    ] == m_update_apt_and_motd_msgs.call_args_list

        cfg = FakeConfig.for_attached_machine()
        fake_stdout = io.StringIO()
        # On json response, we will never prompt the user
        m_prompt.return_value = True
        with contextlib.redirect_stdout(fake_stdout):
            with mock.patch.object(event, "_event_logger_mode",
                                   event_logger.EventLoggerMode.JSON):
                main_error_handler(action_detach)(args, cfg)

        expected = {
            "_schema_version": event_logger.JSON_SCHEMA_VERSION,
            "result": "success",
            "errors": [],
            "failed_services": [],
            "needs_reboot": False,
            "processed_services": ["test"],
            "warnings": [],
        }
        assert expected == json.loads(fake_stdout.getvalue())