Skip to content

Commit

Permalink
contract: send activityInfo after attach
Browse files Browse the repository at this point in the history
  • Loading branch information
orndorffgrant committed Jun 21, 2023
1 parent 8b45f6f commit e1c796a
Show file tree
Hide file tree
Showing 7 changed files with 73 additions and 1 deletion.
3 changes: 3 additions & 0 deletions uaclient/actions.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ def attach_with_token(
"""
from uaclient.timer.update_messaging import update_motd_messages

contract_client = contract.UAContractClient(cfg)
attached_at = datetime.datetime.now(tz=datetime.timezone.utc)

try:
Expand All @@ -67,12 +68,14 @@ def attach_with_token(
attachment_data_file.write(AttachmentData(attached_at=attached_at))
ua_status.status(cfg=cfg)
update_motd_messages(cfg)
contract_client.update_activity_token()
raise exc
except exceptions.UserFacingError as exc:
# Persist updated status in the event of partial attach
attachment_data_file.write(AttachmentData(attached_at=attached_at))
ua_status.status(cfg=cfg)
update_motd_messages(cfg)
contract_client.update_activity_token()
# raise this exception in case we cannot enable all services
raise exc

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,9 @@ def test_enable_services_by_name(
@mock.patch("uaclient.files.notices.add")
@mock.patch("uaclient.files.notices.remove")
class TestFullAutoAttachV1:
@mock.patch(
M_PATH + "contract.UAContractClient.update_activity_token",
)
@mock.patch(
"uaclient.actions.enable_entitlement_by_name",
)
Expand All @@ -170,6 +173,7 @@ def test_error_invalid_ent_names(
_auto_attach,
_get_cloud_instance,
m_enable_ent_by_name,
_m_update_activity_token,
_notice_remove,
_notice_add,
FakeConfig,
Expand All @@ -192,6 +196,9 @@ def enable_ent_side_effect(cfg, name, assume_yes, allow_beta):

assert 5 == m_enable_ent_by_name.call_count

@mock.patch(
M_PATH + "contract.UAContractClient.update_activity_token",
)
@mock.patch(
"uaclient.actions.enable_entitlement_by_name",
return_value=(False, None),
Expand All @@ -203,6 +210,7 @@ def test_error_full_auto_attach_fail(
_auto_attach,
_get_cloud_instance,
enable_ent_by_name,
_m_update_activity_token,
_notice_remove,
_notice_add,
FakeConfig,
Expand Down Expand Up @@ -242,6 +250,7 @@ def test_lock_held(
"enable_services_by_name_side_effect",
"expected_enable_services_by_name_call_args",
"raise_expectation",
"expect_activity_call",
"expected_error_message",
"expected_ret",
],
Expand All @@ -255,6 +264,7 @@ def test_lock_held(
[],
[],
pytest.raises(exceptions.AlreadyAttachedError),
False,
messages.ALREADY_ATTACHED.format(
account_name="test_account"
).msg,
Expand All @@ -269,6 +279,7 @@ def test_lock_held(
[],
[],
pytest.raises(exceptions.AutoAttachDisabledError),
False,
messages.AUTO_ATTACH_DISABLED_ERROR.msg,
None,
),
Expand All @@ -281,6 +292,7 @@ def test_lock_held(
[],
[],
does_not_raise(),
True,
None,
FullAutoAttachResult(),
),
Expand All @@ -293,6 +305,7 @@ def test_lock_held(
[[]],
[mock.call(mock.ANY, ["cis"], allow_beta=False)],
does_not_raise(),
True,
None,
FullAutoAttachResult(),
),
Expand All @@ -305,6 +318,7 @@ def test_lock_held(
[[]],
[mock.call(mock.ANY, ["cis"], allow_beta=True)],
does_not_raise(),
True,
None,
FullAutoAttachResult(),
),
Expand All @@ -320,6 +334,7 @@ def test_lock_held(
mock.call(mock.ANY, ["cis"], allow_beta=True),
],
does_not_raise(),
True,
None,
FullAutoAttachResult(),
),
Expand All @@ -338,11 +353,15 @@ def test_lock_held(
mock.call(mock.ANY, ["cis"], allow_beta=True),
],
pytest.raises(exceptions.EntitlementsNotEnabledError),
True,
messages.ENTITLEMENTS_NOT_ENABLED_ERROR.msg,
None,
),
],
)
@mock.patch(
M_PATH + "contract.UAContractClient.update_activity_token",
)
@mock.patch(M_PATH + "_enable_services_by_name")
@mock.patch(M_PATH + "actions.auto_attach")
@mock.patch(M_PATH + "actions.get_cloud_instance")
Expand All @@ -353,6 +372,7 @@ def test_full_auto_attach_v1(
m_get_cloud_instance,
m_auto_attach,
m_enable_services_by_name,
m_update_activity_token,
_notice_remove,
_notice_add,
options,
Expand All @@ -362,6 +382,7 @@ def test_full_auto_attach_v1(
enable_services_by_name_side_effect,
expected_enable_services_by_name_call_args,
raise_expectation,
expect_activity_call,
expected_error_message,
expected_ret,
mode,
Expand All @@ -386,3 +407,7 @@ def test_full_auto_attach_v1(
assert e.value.msg == expected_error_message
if expected_ret is not None:
assert ret == expected_ret
if expect_activity_call:
assert 1 == m_update_activity_token.call_count
else:
assert 0 == m_update_activity_token.call_count
5 changes: 4 additions & 1 deletion uaclient/api/u/pro/attach/auto/full_auto_attach/v1.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from typing import List, Optional, Tuple

from uaclient import actions, event_logger, lock, messages, util
from uaclient import actions, contract, event_logger, lock, messages, util
from uaclient.api import exceptions
from uaclient.api.api import APIEndpoint
from uaclient.api.data_types import AdditionalInfo
Expand Down Expand Up @@ -118,6 +118,9 @@ def _full_auto_attach_in_lock(
cfg, options.enable_beta, allow_beta=True
)

contract_client = contract.UAContractClient(cfg)
contract_client.update_activity_token()

if len(failed) > 0:
raise exceptions.EntitlementsNotEnabledError(failed)

Expand Down
4 changes: 4 additions & 0 deletions uaclient/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -1557,6 +1557,10 @@ def action_attach(args, *, cfg):
event.info(msg.msg, file_type=sys.stderr)
event.error(error_msg=msg.msg, error_code=msg.name)
ret = 1

contract_client = contract.UAContractClient(cfg)
contract_client.update_activity_token()

_post_cli_attach(cfg)
return ret

Expand Down
13 changes: 13 additions & 0 deletions uaclient/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,19 @@ def util_we_are_currently_root():
yield original


@pytest.yield_fixture(scope="session", autouse=True)
def urllib_request_urlopen():
"""
A fixture that mocks urlopen for all tests.
This prevents us from accidentally making requests in unit tests
"""
from urllib.request import urlopen

original = urlopen
with mock.patch("urllib.request.urlopen"):
yield original


@pytest.fixture
def caplog_text(request):
"""
Expand Down
5 changes: 5 additions & 0 deletions uaclient/tests/test_actions.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ class TestAttachWithToken:
),
],
)
@mock.patch(
M_PATH + "contract.UAContractClient.update_activity_token",
)
@mock.patch("uaclient.files.state_files.attachment_data_file.write")
@mock.patch(M_PATH + "identity.get_instance_id", return_value="my-iid")
@mock.patch("uaclient.timer.update_messaging.update_motd_messages")
Expand All @@ -57,6 +60,7 @@ def test_attach_with_token(
m_update_apt_and_motd_msgs,
_m_get_instance_id,
m_attachment_data_file_write,
m_update_activity_token,
request_updated_contract_side_effect,
expected_error_class,
expect_status_call,
Expand All @@ -69,6 +73,7 @@ def test_attach_with_token(
if expected_error_class:
with pytest.raises(expected_error_class):
attach_with_token(cfg, "token", False)
assert 1 == m_update_activity_token.call_count
else:
attach_with_token(cfg, "token", False)
if expect_status_call:
Expand Down
19 changes: 19 additions & 0 deletions uaclient/tests/test_cli_attach.py
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,9 @@ def fake_request_updated_contract(
), "Did not persist on disk status during attach failure"
assert [mock.call(cfg)] == m_update_apt_and_motd_msgs.call_args_list

@mock.patch(
M_PATH + "contract.UAContractClient.update_activity_token",
)
@mock.patch("uaclient.files.state_files.attachment_data_file.write")
@mock.patch("uaclient.system.should_reboot", return_value=False)
@mock.patch("uaclient.files.notices.NoticesManager.remove")
Expand All @@ -297,6 +300,7 @@ def test_happy_path_with_token_arg(
_m_remove_notice,
_m_should_reboot,
_m_attachment_data_file_write,
m_update_activity_token,
FakeConfig,
event,
):
Expand All @@ -323,6 +327,7 @@ def fake_contract_attach(contract_token, attachment_dt):
]
assert expected_calls == contract_machine_attach.call_args_list
assert [mock.call(cfg)] == m_update_apt_and_motd_msgs.call_args_list
assert 1 == m_update_activity_token.call_count

# We need to do that since all config objects in this
# test will share the same data dir. Since this will
Expand Down Expand Up @@ -357,6 +362,9 @@ def fake_contract_attach(contract_token, attachment_dt):
assert expected == json.loads(fake_stdout.getvalue())

@pytest.mark.parametrize("auto_enable", (True, False))
@mock.patch(
M_PATH + "contract.UAContractClient.update_activity_token",
)
@mock.patch("uaclient.files.state_files.attachment_data_file.write")
@mock.patch("uaclient.system.should_reboot", return_value=False)
@mock.patch("uaclient.files.notices.NoticesManager.remove")
Expand All @@ -369,6 +377,7 @@ def test_auto_enable_passed_through_to_request_updated_contract(
_m_remove_notice,
_m_should_reboot,
_m_attachment_data_file_write,
_m_update_activity_token,
auto_enable,
FakeConfig,
):
Expand Down Expand Up @@ -406,12 +415,16 @@ def test_attach_config_and_token_mutually_exclusive(
action_attach(args, cfg=cfg)
assert e.value.msg == messages.ATTACH_TOKEN_ARG_XOR_CONFIG.msg

@mock.patch(
M_PATH + "contract.UAContractClient.update_activity_token",
)
@mock.patch(M_PATH + "_post_cli_attach")
@mock.patch(M_PATH + "actions.attach_with_token")
def test_token_from_attach_config(
self,
m_attach_with_token,
_m_post_cli_attach,
m_update_activity_token,
FakeConfig,
):
args = mock.MagicMock(
Expand All @@ -423,6 +436,7 @@ def test_token_from_attach_config(
assert [
mock.call(mock.ANY, token="faketoken", allow_enable=True)
] == m_attach_with_token.call_args_list
assert 1 == m_update_activity_token.call_count

def test_attach_config_invalid_config(
self,
Expand Down Expand Up @@ -480,6 +494,9 @@ def test_attach_config_invalid_config(
assert expected == json.loads(capsys.readouterr()[0])

@pytest.mark.parametrize("auto_enable", (True, False))
@mock.patch(
M_PATH + "contract.UAContractClient.update_activity_token",
)
@mock.patch(
M_PATH + "actions.enable_entitlement_by_name",
return_value=(True, None),
Expand All @@ -499,6 +516,7 @@ def test_attach_config_enable_services(
m_handle_unicode,
m_attach_with_token,
m_enable,
m_update_activity_token,
auto_enable,
FakeConfig,
event,
Expand All @@ -525,6 +543,7 @@ def test_attach_config_enable_services(
] == m_enable.call_args_list
else:
assert [] == m_enable.call_args_list
assert 1 == m_update_activity_token.call_count

args.attach_config = FakeFile(
safe_dump({"token": "faketoken", "enable_services": ["cis"]})
Expand Down

0 comments on commit e1c796a

Please sign in to comment.