From 7dfe722686c61e23ce967fc72e8a93ff4ecb3169 Mon Sep 17 00:00:00 2001 From: Olivier Gayot Date: Tue, 25 Jan 2022 18:46:48 +0100 Subject: [PATCH] Don't list UA services that are not entitled Instead of only checking if a given UA service is available, we now also check if it is entitled. - the available field for a service refers to its availability on the current machine (e.g. on Focal running on a amd64 CPU) ; whereas - the entitled field tells us if the contract covers the service. Therefore, we need to make sure that we only list the services that are both "available" and "entitled". Signed-off-by: Olivier Gayot --- examples/uaclient-status-valid.json | 4 ++-- .../client/controllers/ubuntu_advantage.py | 5 +++-- .../common/tests/test_ubuntu_advantage.py | 14 ++++++++------ subiquity/common/ubuntu_advantage.py | 18 +++++++++++------- subiquity/ui/views/ubuntu_advantage.py | 14 +++++++------- 5 files changed, 31 insertions(+), 24 deletions(-) diff --git a/examples/uaclient-status-valid.json b/examples/uaclient-status-valid.json index 58dd8199..97e4156d 100644 --- a/examples/uaclient-status-valid.json +++ b/examples/uaclient-status-valid.json @@ -6,7 +6,7 @@ { "name": "cis", "description": "Center for Internet Security Audit Tools", - "entitled": "yes", + "entitled": "no", "auto_enabled": "no", "available": "yes" }, @@ -15,7 +15,7 @@ "description": "UA Apps: Extended Security Maintenance (ESM)", "entitled": "yes", "auto_enabled": "yes", - "available": "yes" + "available": "no" }, { "name": "esm-infra", diff --git a/subiquity/client/controllers/ubuntu_advantage.py b/subiquity/client/controllers/ubuntu_advantage.py index 8613bf82..4913083c 100644 --- a/subiquity/client/controllers/ubuntu_advantage.py +++ b/subiquity/client/controllers/ubuntu_advantage.py @@ -78,7 +78,8 @@ class UbuntuAdvantageController(SubiquityTuiController): """ Asynchronously check the token passed as an argument. """ async def inner() -> None: try: - svcs = await self.ua_interface.get_avail_services(token=token) + svcs = await \ + self.ua_interface.get_activable_services(token=token) except InvalidUATokenError: if isinstance(self.ui.body, UbuntuAdvantageView): self.ui.body.show_invalid_token() @@ -90,7 +91,7 @@ class UbuntuAdvantageController(SubiquityTuiController): self.ui.body.show_unknown_error() else: if isinstance(self.ui.body, UbuntuAdvantageView): - self.ui.body.show_available_services(svcs) + self.ui.body.show_activable_services(svcs) self._check_task = schedule_task(inner()) diff --git a/subiquity/common/tests/test_ubuntu_advantage.py b/subiquity/common/tests/test_ubuntu_advantage.py index ac605aa2..fab9e3a8 100644 --- a/subiquity/common/tests/test_ubuntu_advantage.py +++ b/subiquity/common/tests/test_ubuntu_advantage.py @@ -125,24 +125,26 @@ class TestUAClientUAInterfaceStrategy(unittest.TestCase): class TestUAInterface(unittest.TestCase): - def test_mocked_get_avail_services(self): + def test_mocked_get_activable_services(self): strategy = MockedUAInterfaceStrategy(scale_factor=1_000_000) interface = UAInterface(strategy) with self.assertRaises(InvalidUATokenError): - run_coro(interface.get_avail_services(token="invalidToken")) + run_coro(interface.get_activable_services(token="invalidToken")) # Tokens starting with "f" in dry-run mode simulate an "internal" # error. with self.assertRaises(CheckSubscriptionError): - run_coro(interface.get_avail_services(token="failure")) + run_coro(interface.get_activable_services(token="failure")) # Tokens starting with "x" is dry-run mode simulate an expired token. with self.assertRaises(ExpiredUATokenError): - run_coro(interface.get_avail_services(token="xpiredToken")) + run_coro(interface.get_activable_services(token="xpiredToken")) # Other tokens are considered valid in dry-run mode. - services = run_coro(interface.get_avail_services(token="validToken")) + services = run_coro( + interface.get_activable_services(token="validToken")) for service in services: self.assertIn("name", service) self.assertIn("description", service) - self.assertTrue(service["available"]) + self.assertEqual(service["available"], "yes") + self.assertEqual(service["entitled"], "yes") diff --git a/subiquity/common/ubuntu_advantage.py b/subiquity/common/ubuntu_advantage.py index f05ba632..3d9a9ec8 100644 --- a/subiquity/common/ubuntu_advantage.py +++ b/subiquity/common/ubuntu_advantage.py @@ -147,9 +147,9 @@ class UAInterface: """ Return a dictionary containing the subscription information. """ return await self.strategy.query_info(token) - async def get_avail_services(self, token: str) -> List[dict]: - """ Return a list of available services for the subscription - associated with the token provided. + async def get_activable_services(self, token: str) -> List[dict]: + """ Return a list of activable services (i.e. services that are + entitled to the subscription and available on the current hardware). """ info = await self.get_subscription(token) @@ -157,8 +157,12 @@ class UAInterface: if expiration.timestamp() <= dt.utcnow().timestamp(): raise ExpiredUATokenError(token, expires=info["expires"]) - def is_avail_service(service: dict) -> bool: - # TODO do we need to check for service["entitled"] as well? - return service["available"] == "yes" + def is_activable_service(service: dict) -> bool: + # - the available field for a service refers to its availability on + # the current machine (e.g. on Focal running on a amd64 CPU) ; + # whereas + # - the entitled field tells us if the contract covers the service. + return service["available"] == "yes" \ + and service["entitled"] == "yes" - return [svc for svc in info["services"] if is_avail_service(svc)] + return [svc for svc in info["services"] if is_activable_service(svc)] diff --git a/subiquity/ui/views/ubuntu_advantage.py b/subiquity/ui/views/ubuntu_advantage.py index ee171738..bdd7abe7 100644 --- a/subiquity/ui/views/ubuntu_advantage.py +++ b/subiquity/ui/views/ubuntu_advantage.py @@ -189,16 +189,16 @@ class UbuntuAdvantageView(BaseView): self.remove_overlay() self.show_stretchy_overlay(ContinueAnywayWidget(self)) - def show_available_services(self, services: List[dict]) -> None: - """ Display an overlay with the list of services that will be enabled - via Ubuntu Advantage subscription. After the user confirms, the next we - will quit the current view and move on. """ + def show_activable_services(self, services: List[dict]) -> None: + """ Display an overlay with the list of services that can be enabled + via Ubuntu Advantage subscription. After the user confirms, we will + quit the current view and move on. """ self.remove_overlay() self.show_stretchy_overlay(ShowServicesWidget(self, services)) class ShowServicesWidget(Stretchy): - """ Widget to show the available services for UA subscription. """ + """ Widget to show the activable services for UA subscription. """ def __init__(self, parent: UbuntuAdvantageView, services: List[dict]) -> None: """ Initializes the widget by including the list of services as a @@ -207,8 +207,8 @@ class ShowServicesWidget(Stretchy): ok = ok_btn(label=_("OK"), on_press=self.ok) - title = _("Available Services") - header = _("List of services that are available through your " + title = _("Activable Services") + header = _("List of services that are activable through your " "Ubuntu Advantage subscription:") widgets: List[Widget] = [