def test_delta_in_instance_id_forces_detach(
        self,
        cloud_instance_factory,
        request_auto_attach_contract_token,
        get_instance_id,
        iid_response,
        calls_detach,
        FakeConfig,
    ):
        """When instance-id changes since last attach, call detach."""

        get_instance_id.return_value = iid_response
        cloud_instance_factory.side_effect = self.fake_instance_factory

        def fake_contract_token(instance):
            return {"contractToken": "myPKCS7-token"}

        request_auto_attach_contract_token.side_effect = fake_contract_token

        account_name = "test_account"
        cfg = FakeConfig.for_attached_machine(account_name=account_name)
        # persist old instance-id value
        cfg.write_cache("instance-id", "old-iid")

        if calls_detach:
            with mock.patch(M_PATH + "_detach") as m_detach:
                m_detach.return_value = 0
                assert ("myPKCS7-token" ==
                        _get_contract_token_from_cloud_identity(cfg))
            assert [mock.call(cfg, assume_yes=True)] == m_detach.call_args_list
        else:
            with pytest.raises(AlreadyAttachedError):
                _get_contract_token_from_cloud_identity(cfg)
        # current instance-id is persisted for next auto-attach call
        assert iid_response == cfg.read_cache("instance-id")
 def test_non_aws_cloud_type_raises_error(self, m_get_cloud_type,
                                          cloud_type):
     """Non-aws clouds will error."""
     m_get_cloud_type.return_value = cloud_type
     with pytest.raises(NonAutoAttachImageError) as excinfo:
         _get_contract_token_from_cloud_identity(FakeConfig())
     assert status.MESSAGE_UNSUPPORTED_AUTO_ATTACH_CLOUD_TYPE.format(
         cloud_type=cloud_type) == str(excinfo.value)
    def test_failed_detach_on_changed_instance_id_raises_errors(
        self,
        cloud_instance_factory,
        request_auto_attach_contract_token,
        get_instance_id,
        m_detach,
        FakeConfig,
    ):
        """When instance-id changes since last attach, call detach."""

        get_instance_id.return_value = "new-iid"
        cloud_instance_factory.side_effect = self.fake_instance_factory

        def fake_contract_token(instance):
            return {"contractToken": "myPKCS7-token"}

        request_auto_attach_contract_token.side_effect = fake_contract_token
        m_detach.return_value = 1  # Failure to auto-detach

        account_name = "test_account"
        cfg = FakeConfig.for_attached_machine(account_name=account_name)
        # persist old instance-id value
        cfg.write_cache("instance-id", "old-iid")

        with pytest.raises(UserFacingError) as err:
            assert "myPKCS7-token" == _get_contract_token_from_cloud_identity(
                cfg)
        assert status.MESSAGE_DETACH_AUTOMATION_FAILURE == str(err.value)
    def test_aws_cloud_type_non_auto_attach_returns_no_token(
        self,
        _get_cloud_type,
        cloud_instance_factory,
        request_aws_contract_token,
    ):
        """AWS clouds on non-auto-attach images not return a token."""

        cloud_instance_factory.side_effect = self.fake_instance_factory
        request_aws_contract_token.side_effect = ContractAPIError(
            util.UrlError("Server error",
                          code=500,
                          url="http://me",
                          headers={}),
            error_response={"message": "missing instance information"},
        )
        with pytest.raises(NonAutoAttachImageError) as excinfo:
            _get_contract_token_from_cloud_identity(FakeConfig())
        assert status.MESSAGE_UNSUPPORTED_AUTO_ATTACH == str(excinfo.value)
    def test_raise_unexpected_errors(
        self,
        _get_cloud_type,
        cloud_instance_factory,
        request_auto_attach_contract_token,
        FakeConfig,
    ):
        """Any unexpected errors will be raised."""

        cloud_instance_factory.side_effect = self.fake_instance_factory
        unexpected_error = ContractAPIError(
            util.UrlError(
                "Server error", code=500, url="http://me", headers={}
            ),
            error_response={"message": "something unexpected"},
        )
        request_auto_attach_contract_token.side_effect = unexpected_error

        with pytest.raises(ContractAPIError) as excinfo:
            _get_contract_token_from_cloud_identity(FakeConfig())
        assert unexpected_error == excinfo.value
 def test_aws_cloud_type_non_auto_attach_returns_no_token(
     self,
     cloud_instance_factory,
     get_instance_id,
     request_auto_attach_contract_token,
     http_msg,
     http_code,
     http_response,
     FakeConfig,
 ):
     """VMs running on non-auto-attach images do not return a token."""
     cloud_instance_factory.side_effect = self.fake_instance_factory
     request_auto_attach_contract_token.side_effect = ContractAPIError(
         util.UrlError(
             http_msg, code=http_code, url="http://me", headers={}
         ),
         error_response=http_response,
     )
     with pytest.raises(NonAutoAttachImageError) as excinfo:
         _get_contract_token_from_cloud_identity(FakeConfig())
     assert status.MESSAGE_UNSUPPORTED_AUTO_ATTACH == str(excinfo.value)
    def test_return_token_from_contract_server_using_identity_doc(
        self,
        _get_cloud_type,
        cloud_instance_factory,
        request_aws_contract_token,
    ):
        """Return token from the contract server using the identity."""

        cloud_instance_factory.side_effect = self.fake_instance_factory

        def fake_aws_contract_token(contract_token):
            return {"contractToken": "myPKCS7-token"}

        request_aws_contract_token.side_effect = fake_aws_contract_token

        cfg = FakeConfig()
        assert "myPKCS7-token" == _get_contract_token_from_cloud_identity(cfg)
    def test_return_token_from_contract_server_using_identity_doc(
        self,
        cloud_instance_factory,
        request_auto_attach_contract_token,
        get_instance_id,
        FakeConfig,
    ):
        """Return token from the contract server using the identity."""

        cloud_instance_factory.side_effect = self.fake_instance_factory

        def fake_contract_token(instance):
            return {"contractToken": "myPKCS7-token"}

        request_auto_attach_contract_token.side_effect = fake_contract_token

        cfg = FakeConfig()
        assert "myPKCS7-token" == _get_contract_token_from_cloud_identity(cfg)
        # instance-id is persisted for next auto-attach call
        assert 1 == get_instance_id.call_count
        assert "my-iid" == cfg.read_cache("instance-id")