-
Notifications
You must be signed in to change notification settings - Fork 75
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
3f16ee6
commit 14d1c5c
Showing
11 changed files
with
511 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,189 @@ | ||
Feature: u.pro.services.disable | ||
|
||
Scenario Outline: u.pro.services.disable.v1 container services | ||
Given a `<release>` `<machine_type>` machine with ubuntu-advantage-tools installed | ||
When I apt update | ||
# Requires attach | ||
When I verify that running `pro api u.pro.services.disable.v1 --args service=esm-infra` `with sudo` exits `1` | ||
Then API errors field output is: | ||
""" | ||
[ | ||
{ | ||
"code": "unattached", | ||
"meta": {}, | ||
"title": "This machine is not attached to an Ubuntu Pro subscription.\nSee https://ubuntu.com/pro" | ||
} | ||
] | ||
""" | ||
When I attach `contract_token` with sudo | ||
# Requires root | ||
When I verify that running `pro api u.pro.services.disable.v1 --args service=esm-infra` `as non-root` exits `1` | ||
Then API errors field output is: | ||
""" | ||
[ | ||
{ | ||
"code": "nonroot-user", | ||
"meta": {}, | ||
"title": "This command must be run as root (try using sudo)." | ||
} | ||
] | ||
""" | ||
# Basic disable | ||
When I run `pro api u.pro.services.disable.v1 --args service=esm-infra` with sudo | ||
Then API data field output is: | ||
""" | ||
{ | ||
"attributes": { | ||
"disabled": [ | ||
"esm-infra" | ||
] | ||
}, | ||
"meta": { | ||
"environment_vars": [] | ||
}, | ||
"type": "DisableService" | ||
} | ||
""" | ||
Then I verify that `esm-infra` is disabled | ||
# Disable already disabled service succeeds | ||
When I run `pro api u.pro.services.disable.v1 --args service=esm-infra` with sudo | ||
Then API data field output is: | ||
""" | ||
{ | ||
"attributes": { | ||
"disabled": [] | ||
}, | ||
"meta": { | ||
"environment_vars": [] | ||
}, | ||
"type": "DisableService" | ||
} | ||
""" | ||
# disables dependent services | ||
When I run `pro enable ros-updates --assume-yes` with sudo | ||
When I run `pro api u.pro.services.disable.v1 --args service=esm-apps` with sudo | ||
Then API data field output is: | ||
""" | ||
{ | ||
"attributes": { | ||
"disabled": [ | ||
"esm-apps", | ||
"ros", | ||
"ros-updates" | ||
] | ||
}, | ||
"meta": { | ||
"environment_vars": [] | ||
}, | ||
"type": "DisableService" | ||
} | ||
""" | ||
# purge works and post enable messages work | ||
When I apt install `curl` | ||
When I run `apt-cache policy curl` as non-root | ||
Then stdout matches regexp: | ||
""" | ||
\*\*\* <curl_version>\+esm.* 510 | ||
""" | ||
When I run `pro api u.pro.services.disable.v1 --data '{"service": "esm-infra", "purge": true}'` with sudo | ||
Then API data field output is: | ||
""" | ||
{ | ||
"attributes": { | ||
"disabled": [ | ||
"esm-infra" | ||
] | ||
}, | ||
"meta": { | ||
"environment_vars": [] | ||
}, | ||
"type": "DisableService" | ||
} | ||
""" | ||
When I run `apt-cache policy curl` as non-root | ||
Then stdout contains substring: | ||
""" | ||
*** <curl_version> 500 | ||
""" | ||
|
||
Examples: | ||
| release | machine_type | curl_version | | ||
| xenial | lxd-container | 7.47.0-1ubuntu2.19 | | ||
| bionic | lxd-container | 7.58.0-2ubuntu3.24 | | ||
|
||
Scenario Outline: u.pro.services.disable.v1 vm services | ||
Given a `<release>` `<machine_type>` machine with ubuntu-advantage-tools installed | ||
When I apt update | ||
And I attach `contract_token` with sudo | ||
# Basic disable | ||
And I run `pro api u.pro.services.disable.v1 --args service=livepatch` with sudo | ||
Then API data field output is: | ||
""" | ||
{ | ||
"attributes": { | ||
"disabled": [ | ||
"livepatch" | ||
] | ||
}, | ||
"meta": { | ||
"environment_vars": [] | ||
}, | ||
"type": "DisableService" | ||
} | ||
""" | ||
# fails when purge not supported | ||
When I run `pro enable realtime-kernel --access-only` with sudo | ||
When I verify that running `pro api u.pro.services.disable.v1 --data '{"service": "realtime-kernel", "purge": true}'` `with sudo` exits `1` | ||
Then API errors field output is: | ||
""" | ||
[ | ||
{ | ||
"code": "entitlement-not-disabled", | ||
"meta": { | ||
"reason": { | ||
"additional_info": null, | ||
"code": "disable-purge-not-supported", | ||
"title": "Real-time kernel does not support being disabled with --purge" | ||
} | ||
}, | ||
"title": "failed to disable realtime-kernel" | ||
} | ||
] | ||
""" | ||
|
||
Examples: | ||
| release | machine_type | | ||
| jammy | lxd-vm | | ||
|
||
Scenario Outline: u.pro.services.disable.v1 with progress | ||
Given a `<release>` `<machine_type>` machine with ubuntu-advantage-tools installed | ||
When I run `apt-get update` with sudo | ||
And I attach `contract_token` with sudo | ||
# Basic disable | ||
And I run shell command `pro api u.pro.services.disable.v1 --show-progress --args service=esm-infra` with sudo | ||
Then stdout contains substring: | ||
""" | ||
{"total_steps": 2, "done_steps": 0, "previous_step_message": null, "current_step_message": "Removing APT access to Ubuntu Pro: ESM Infra"} | ||
{"total_steps": 2, "done_steps": 1, "previous_step_message": "Removing APT access to Ubuntu Pro: ESM Infra", "current_step_message": "Updating package lists"} | ||
{"total_steps": 2, "done_steps": 2, "previous_step_message": "Updating package lists", "current_step_message": null} | ||
{"_schema_version": "v1", "data": {"attributes": {"disabled": ["esm-infra"]}, "meta": {"environment_vars": []}, "type": "DisableService"}, "errors": [], "result": "success" | ||
""" | ||
# Disabling multiple services shows steps correctly | ||
When I run `pro enable ros-updates --assume-yes` with sudo | ||
When I run `pro api u.pro.services.disable.v1 --show-progress --args service=esm-apps` with sudo | ||
Then stdout contains substring: | ||
""" | ||
{"total_steps": 6, "done_steps": 0, "previous_step_message": null, "current_step_message": "Removing APT access to ROS ESM All Updates"} | ||
{"total_steps": 6, "done_steps": 1, "previous_step_message": "Removing APT access to ROS ESM All Updates", "current_step_message": "Updating package lists"} | ||
{"total_steps": 6, "done_steps": 2, "previous_step_message": "Updating package lists", "current_step_message": "Removing APT access to ROS ESM Security Updates"} | ||
{"total_steps": 6, "done_steps": 3, "previous_step_message": "Removing APT access to ROS ESM Security Updates", "current_step_message": "Updating package lists"} | ||
{"total_steps": 6, "done_steps": 4, "previous_step_message": "Updating package lists", "current_step_message": "Removing APT access to Ubuntu Pro: ESM Apps"} | ||
{"total_steps": 6, "done_steps": 5, "previous_step_message": "Removing APT access to Ubuntu Pro: ESM Apps", "current_step_message": "Updating package lists"} | ||
{"total_steps": 6, "done_steps": 6, "previous_step_message": "Updating package lists", "current_step_message": null} | ||
{"_schema_version": "v1", "data": {"attributes": {"disabled": ["esm-apps", "ros", "ros-updates"]}, "meta": {"environment_vars": []}, "type": "DisableService"}, "errors": [], "result": "success" | ||
""" | ||
|
||
Examples: | ||
| release | machine_type | | ||
| xenial | lxd-container | | ||
| bionic | lxd-container | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
164 changes: 164 additions & 0 deletions
164
uaclient/api/tests/test_api_u_pro_services_disable_v1.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,164 @@ | ||
import mock | ||
import pytest | ||
|
||
from uaclient.api import exceptions | ||
from uaclient.api.u.pro.services.disable.v1 import ( | ||
DisableOptions, | ||
DisableResult, | ||
_disable, | ||
) | ||
from uaclient.testing.helpers import does_not_raise | ||
|
||
M_PATH = "uaclient.api.u.pro.services.disable.v1." | ||
|
||
|
||
class TestDisable: | ||
@pytest.mark.parametrize( | ||
[ | ||
"options", | ||
"we_are_currently_root", | ||
"is_attached", | ||
"enabled_services_names_before", | ||
"enabled_services_names_after", | ||
"disable_result", | ||
"expected_raises", | ||
"expected_result", | ||
], | ||
[ | ||
# not root | ||
( | ||
DisableOptions(service="s1"), | ||
False, | ||
False, | ||
None, | ||
None, | ||
None, | ||
pytest.raises(exceptions.NonRootUserError), | ||
None, | ||
), | ||
# not attached | ||
( | ||
DisableOptions(service="s1"), | ||
True, | ||
False, | ||
None, | ||
None, | ||
None, | ||
pytest.raises(exceptions.UnattachedError), | ||
None, | ||
), | ||
# generic disable failure | ||
( | ||
DisableOptions(service="s1"), | ||
True, | ||
True, | ||
["s1"], | ||
None, | ||
(False, None), | ||
pytest.raises(exceptions.EntitlementNotDisabledError), | ||
None, | ||
), | ||
# success | ||
( | ||
DisableOptions(service="s1"), | ||
True, | ||
True, | ||
["s1"], | ||
[], | ||
(True, None), | ||
does_not_raise(), | ||
DisableResult( | ||
disabled=["s1"], | ||
), | ||
), | ||
# success already disabled | ||
( | ||
DisableOptions(service="s1"), | ||
True, | ||
True, | ||
[], | ||
None, | ||
None, | ||
does_not_raise(), | ||
DisableResult( | ||
disabled=[], | ||
), | ||
), | ||
# success with additional disablements | ||
( | ||
DisableOptions(service="s1"), | ||
True, | ||
True, | ||
["s1", "s2", "s3"], | ||
["s2"], | ||
(True, None), | ||
does_not_raise(), | ||
DisableResult( | ||
disabled=["s1", "s3"], | ||
), | ||
), | ||
], | ||
) | ||
@mock.patch(M_PATH + "lock.clear_lock_file_if_present") | ||
@mock.patch(M_PATH + "lock.RetryLock") | ||
@mock.patch(M_PATH + "entitlements.entitlement_factory") | ||
@mock.patch(M_PATH + "_enabled_services_names") | ||
@mock.patch(M_PATH + "_is_attached") | ||
@mock.patch(M_PATH + "util.we_are_currently_root") | ||
def test_disable( | ||
self, | ||
m_we_are_currently_root, | ||
m_is_attached, | ||
m_enabled_services_names, | ||
m_entitlement_factory, | ||
m_spin_lock, | ||
m_clear_lock_file_if_present, | ||
options, | ||
we_are_currently_root, | ||
is_attached, | ||
enabled_services_names_before, | ||
enabled_services_names_after, | ||
disable_result, | ||
expected_raises, | ||
expected_result, | ||
FakeConfig, | ||
): | ||
m_we_are_currently_root.return_value = we_are_currently_root | ||
m_is_attached.return_value = mock.MagicMock(is_attached=is_attached) | ||
m_enabled_services_names.side_effect = [ | ||
enabled_services_names_before, | ||
enabled_services_names_after, | ||
] | ||
m_ent_class = m_entitlement_factory.return_value | ||
m_ent = m_ent_class.return_value | ||
m_ent_variant = m_ent.enabled_variant | ||
m_ent_variant.disable.return_value = disable_result | ||
|
||
cfg = FakeConfig() | ||
|
||
actual_result = None | ||
with expected_raises: | ||
actual_result = _disable( | ||
options, cfg, progress_object=mock.MagicMock() | ||
) | ||
|
||
assert actual_result == expected_result | ||
|
||
if expected_result is not None and len(expected_result.disabled) > 0: | ||
assert m_entitlement_factory.call_args_list == [ | ||
mock.call( | ||
cfg=cfg, | ||
name=options.service, | ||
) | ||
] | ||
assert m_ent_class.call_args_list == [ | ||
mock.call( | ||
cfg, | ||
assume_yes=True, | ||
called_name=options.service, | ||
purge=options.purge, | ||
) | ||
] | ||
assert m_ent_variant.disable.call_args_list == [ | ||
mock.call(mock.ANY) | ||
] |
Empty file.
Oops, something went wrong.