Only keep the name and description of activable services

The u-a-c returns a set of information about each service. After
filtering out the services that we don't want using the fields
"entitled" and "available", we now only keep the name and the
description of the service.

Signed-off-by: Olivier Gayot <olivier.gayot@canonical.com>
This commit is contained in:
Olivier Gayot 2022-02-04 15:17:58 +01:00
parent 98b887d696
commit 8f024eb038
4 changed files with 90 additions and 13 deletions

View File

@ -401,11 +401,17 @@ class UbuntuAdvantageCheckTokenStatus(enum.Enum):
UNKNOWN_ERROR = enum.auto() UNKNOWN_ERROR = enum.auto()
@attr.s(auto_attribs=True)
class UbuntuAdvantageService:
name: str
description: str
@attr.s(auto_attribs=True) @attr.s(auto_attribs=True)
class UbuntuAdvantageCheckTokenAnswer: class UbuntuAdvantageCheckTokenAnswer:
status: UbuntuAdvantageCheckTokenStatus status: UbuntuAdvantageCheckTokenStatus
services: Optional[List[dict]] services: Optional[List[UbuntuAdvantageService]]
class ShutdownMode(enum.Enum): class ShutdownMode(enum.Enum):

View File

@ -15,8 +15,9 @@
from subprocess import CalledProcessError, CompletedProcess from subprocess import CalledProcessError, CompletedProcess
import unittest import unittest
from unittest.mock import patch from unittest.mock import patch, AsyncMock
from subiquity.common.types import UbuntuAdvantageService
from subiquity.server.ubuntu_advantage import ( from subiquity.server.ubuntu_advantage import (
InvalidUATokenError, InvalidUATokenError,
ExpiredUATokenError, ExpiredUATokenError,
@ -141,10 +142,65 @@ class TestUAInterface(unittest.TestCase):
run_coro(interface.get_activable_services(token="xpiredToken")) run_coro(interface.get_activable_services(token="xpiredToken"))
# Other tokens are considered valid in dry-run mode. # Other tokens are considered valid in dry-run mode.
run_coro(interface.get_activable_services(token="validToken"))
def test_get_activable_services(self):
# We use the standard strategy but don't actually run it
strategy = UAClientUAInterfaceStrategy()
interface = UAInterface(strategy)
subscription = {
"expires": "2035-12-31T00:00:00+00:00",
"services": [
{
"name": "cis",
"description": "Center for Internet Security Audit Tools",
"entitled": "no",
"auto_enabled": "no",
"available": "yes"
},
{
"name": "esm-apps",
"description":
"UA Apps: Extended Security Maintenance (ESM)",
"entitled": "yes",
"auto_enabled": "yes",
"available": "no"
},
{
"name": "esm-infra",
"description":
"UA Infra: Extended Security Maintenance (ESM)",
"entitled": "yes",
"auto_enabled": "yes",
"available": "yes"
},
{
"name": "fips",
"description": "NIST-certified core packages",
"entitled": "yes",
"auto_enabled": "no",
"available": "yes"
},
]
}
interface.get_subscription = AsyncMock(return_value=subscription)
services = run_coro( services = run_coro(
interface.get_activable_services(token="validToken")) interface.get_activable_services(token="XXX"))
for service in services:
self.assertIn("name", service) self.assertIn(UbuntuAdvantageService(
self.assertIn("description", service) name="esm-infra",
self.assertEqual(service["available"], "yes") description="UA Infra: Extended Security Maintenance (ESM)",
self.assertEqual(service["entitled"], "yes") ), services)
self.assertIn(UbuntuAdvantageService(
name="fips",
description="NIST-certified core packages",
), services)
self.assertNotIn(UbuntuAdvantageService(
name="esm-apps",
description="UA Apps: Extended Security Maintenance (ESM)",
), services)
self.assertNotIn(UbuntuAdvantageService(
name="cis",
description="Center for Internet Security Audit Tools",
), services)

View File

@ -23,6 +23,7 @@ from subprocess import CalledProcessError, CompletedProcess
from typing import List, Sequence, Union from typing import List, Sequence, Union
import asyncio import asyncio
from subiquity.common.types import UbuntuAdvantageService
from subiquitycore import utils from subiquitycore import utils
@ -147,7 +148,8 @@ class UAInterface:
""" Return a dictionary containing the subscription information. """ """ Return a dictionary containing the subscription information. """
return await self.strategy.query_info(token) return await self.strategy.query_info(token)
async def get_activable_services(self, token: str) -> List[dict]: async def get_activable_services(self, token: str) \
-> List[UbuntuAdvantageService]:
""" Return a list of activable services (i.e. services that are """ Return a list of activable services (i.e. services that are
entitled to the subscription and available on the current hardware). entitled to the subscription and available on the current hardware).
""" """
@ -165,4 +167,16 @@ class UAInterface:
return service["available"] == "yes" \ return service["available"] == "yes" \
and service["entitled"] == "yes" and service["entitled"] == "yes"
return [svc for svc in info["services"] if is_activable_service(svc)] def service_from_dict(service: dict) -> UbuntuAdvantageService:
return UbuntuAdvantageService(
name=service["name"],
description=service["description"],
)
activable_services: List[UbuntuAdvantageService] = []
for service in info["services"]:
if not is_activable_service(service):
continue
activable_services.append(service_from_dict(service))
return activable_services

View File

@ -25,6 +25,7 @@ from urwid import (
Widget, Widget,
) )
from subiquity.common.types import UbuntuAdvantageService as UAService
from subiquitycore.view import BaseView from subiquitycore.view import BaseView
from subiquitycore.ui.buttons import ( from subiquitycore.ui.buttons import (
back_btn, back_btn,
@ -189,7 +190,7 @@ class UbuntuAdvantageView(BaseView):
self.remove_overlay() self.remove_overlay()
self.show_stretchy_overlay(ContinueAnywayWidget(self)) self.show_stretchy_overlay(ContinueAnywayWidget(self))
def show_activable_services(self, services: List[dict]) -> None: def show_activable_services(self, services: List[UAService]) -> None:
""" Display an overlay with the list of services that can be enabled """ Display an overlay with the list of services that can be enabled
via Ubuntu Advantage subscription. After the user confirms, we will via Ubuntu Advantage subscription. After the user confirms, we will
quit the current view and move on. """ quit the current view and move on. """
@ -200,7 +201,7 @@ class UbuntuAdvantageView(BaseView):
class ShowServicesWidget(Stretchy): class ShowServicesWidget(Stretchy):
""" Widget to show the activable services for UA subscription. """ """ Widget to show the activable services for UA subscription. """
def __init__(self, parent: UbuntuAdvantageView, def __init__(self, parent: UbuntuAdvantageView,
services: List[dict]) -> None: services: List[UAService]) -> None:
""" Initializes the widget by including the list of services as a """ Initializes the widget by including the list of services as a
bullet-point list. """ bullet-point list. """
self.parent = parent self.parent = parent
@ -214,7 +215,7 @@ class ShowServicesWidget(Stretchy):
widgets: List[Widget] = [ widgets: List[Widget] = [
Text(header), Text(header),
Text(""), Text(""),
Pile([Text(f"* {svc['description']}") for svc in services]), Pile([Text(f"* {svc.description}") for svc in services]),
Text(""), Text(""),
Text("Once the installation has finished, you can enable these " Text("Once the installation has finished, you can enable these "
"services using the `ua` command-line tool."), "services using the `ua` command-line tool."),