Merge pull request #1217 from ogayot/ua-rebranding

Rename UbuntuAdvantage -> UbuntuPro
This commit is contained in:
Olivier Gayot 2022-03-17 09:20:43 +01:00
commit 2bf39f02ca
32 changed files with 250 additions and 139 deletions

View File

@ -260,7 +260,7 @@
}
]
},
"ubuntu-advantage": {
"ubuntu-pro": {
"type": "object",
"properties": {
"token": {
@ -272,6 +272,20 @@
}
}
},
"ubuntu-advantage": {
"type": "object",
"properties": {
"token": {
"type": "string",
"minLength": 24,
"maxLength": 30,
"pattern": "^C[1-9A-HJ-NP-Za-km-z]+$",
"description": "A valid token starts with a C and is followed by 23 to 29 Base58 characters.\nSee https://pkg.go.dev/github.com/btcsuite/btcutil/base58#CheckEncode"
}
},
"deprecated": true,
"description": "Compatibility only - use ubuntu-pro instead"
},
"proxy": {
"type": [
"string",

View File

@ -45,7 +45,7 @@ Identity:
hostname: ubuntu-server
# ubuntu
password: '$6$wdAcoXrU039hKYPd$508Qvbe7ObUnxoj15DRCkzC3qO7edjH0VV7BPNRDYK4QR8ofJaEEF2heacn0QgD.f8pO8SNp83XNdWG6tocBM1'
UbuntuAdvantage:
UbuntuPro:
token: ""
SSH:
install_server: false

View File

@ -21,7 +21,7 @@ Identity:
hostname: ubuntu-server
# ubuntu
password: '$6$wdAcoXrU039hKYPd$508Qvbe7ObUnxoj15DRCkzC3qO7edjH0VV7BPNRDYK4QR8ofJaEEF2heacn0QgD.f8pO8SNp83XNdWG6tocBM1'
UbuntuAdvantage:
UbuntuPro:
token: C1NWcZTHLteJXGVMM6YhvHDpGrhyy7
SSH:
install_server: false

View File

@ -20,7 +20,7 @@ Identity:
hostname: ubuntu-server
# ubuntu
password: '$6$wdAcoXrU039hKYPd$508Qvbe7ObUnxoj15DRCkzC3qO7edjH0VV7BPNRDYK4QR8ofJaEEF2heacn0QgD.f8pO8SNp83XNdWG6tocBM1'
UbuntuAdvantage:
UbuntuPro:
token: C1NWcZTHLteJXGVMM6YhvHDpGrhyy7
SSH:
install_server: true

View File

@ -64,7 +64,7 @@ Identity:
hostname: ubuntu-server
# ubuntu
password: '$6$wdAcoXrU039hKYPd$508Qvbe7ObUnxoj15DRCkzC3qO7edjH0VV7BPNRDYK4QR8ofJaEEF2heacn0QgD.f8pO8SNp83XNdWG6tocBM1'
UbuntuAdvantage:
UbuntuPro:
token: C1NWcZTHLteJXGVMM6YhvHDpGrhyy7
SSH:
install_server: true

View File

@ -45,7 +45,7 @@ Filesystem:
fstype: ext4
mount: /
- action: done
UbuntuAdvantage:
UbuntuPro:
token: C1NWcZTHLteJXGVMM6YhvHDpGrhyy7
Identity:
realname: Ubuntu

View File

@ -25,7 +25,7 @@ Identity:
hostname: ubuntu-server
# ubuntu
password: '$6$wdAcoXrU039hKYPd$508Qvbe7ObUnxoj15DRCkzC3qO7edjH0VV7BPNRDYK4QR8ofJaEEF2heacn0QgD.f8pO8SNp83XNdWG6tocBM1'
UbuntuAdvantage:
UbuntuPro:
token: ""
SSH:
install_server: true

View File

@ -96,7 +96,7 @@ Identity:
hostname: ubuntu-server
# ubuntu
password: '$6$wdAcoXrU039hKYPd$508Qvbe7ObUnxoj15DRCkzC3qO7edjH0VV7BPNRDYK4QR8ofJaEEF2heacn0QgD.f8pO8SNp83XNdWG6tocBM1'
UbuntuAdvantage:
UbuntuPro:
token: C1NWcZTHLteJXGVMM6YhvHDpGrhyy7
SSH:
install_server: false

View File

@ -55,7 +55,7 @@ Identity:
hostname: ubuntu-server
# ubuntu
password: '$6$wdAcoXrU039hKYPd$508Qvbe7ObUnxoj15DRCkzC3qO7edjH0VV7BPNRDYK4QR8ofJaEEF2heacn0QgD.f8pO8SNp83XNdWG6tocBM1'
UbuntuAdvantage:
UbuntuPro:
token: C1NWcZTHLteJXGVMM6YhvHDpGrhyy7
SSH:
install_server: false

View File

@ -24,7 +24,7 @@ Identity:
hostname: ubuntu-server
# ubuntu
password: '$6$wdAcoXrU039hKYPd$508Qvbe7ObUnxoj15DRCkzC3qO7edjH0VV7BPNRDYK4QR8ofJaEEF2heacn0QgD.f8pO8SNp83XNdWG6tocBM1'
UbuntuAdvantage:
UbuntuPro:
token: ""
SSH:
install_server: true

View File

@ -28,7 +28,7 @@ Identity:
hostname: ubuntu-server
# ubuntu
password: '$6$wdAcoXrU039hKYPd$508Qvbe7ObUnxoj15DRCkzC3qO7edjH0VV7BPNRDYK4QR8ofJaEEF2heacn0QgD.f8pO8SNp83XNdWG6tocBM1'
UbuntuAdvantage:
UbuntuPro:
token: C1NWcZTHLteJXGVMM6YhvHDpGrhyy7
SSH:
install_server: false

View File

@ -22,7 +22,7 @@ Identity:
# ubuntu
password: '$6$wdAcoXrU039hKYPd$508Qvbe7ObUnxoj15DRCkzC3qO7edjH0VV7BPNRDYK4QR8ofJaEEF2heacn0QgD.f8pO8SNp83XNdWG6tocBM1'
ssh-import-id: gh:mwhudson
UbuntuAdvantage:
UbuntuPro:
token: ""
SnapList:
snaps:

View File

@ -48,7 +48,7 @@ snaps:
channel: 3.2/stable
updates: all
timezone: Pacific/Guam
ubuntu-advantage:
ubuntu-pro:
# Token that passes the basic format checking but is invalid (i.e. contains more than 16 bytes of random data)
token: C1NWcZTHLteJXGVMM6YhvHDpGrhyy7
storage:

View File

@ -111,7 +111,7 @@ class SubiquityClient(TuiApplication):
"Refresh",
"Filesystem",
"Identity",
"UbuntuAdvantage",
"UbuntuPro",
"SSH",
"SnapList",
"Progress",

View File

@ -26,7 +26,7 @@ from .serial import SerialController
from .snaplist import SnapListController
from .source import SourceController
from .ssh import SSHController
from .ubuntu_advantage import UbuntuAdvantageController
from .ubuntu_pro import UbuntuProController
from .welcome import WelcomeController
from .zdev import ZdevController
@ -45,7 +45,7 @@ __all__ = [
'SnapListController',
'SourceController',
'SSHController',
'UbuntuAdvantageController',
'UbuntuProController',
'WelcomeController',
'ZdevController',
]

View File

@ -12,8 +12,7 @@
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
""" Module that defines the client-side controller class for Ubuntu Advantage.
"""
""" Module that defines the client-side controller class for Ubuntu Pro. """
import asyncio
import logging
@ -23,21 +22,21 @@ from subiquitycore.async_helpers import schedule_task
from subiquity.client.controller import SubiquityTuiController
from subiquity.common.types import (
UbuntuAdvantageInfo,
UbuntuAdvantageCheckTokenStatus as TokenStatus,
UbuntuProInfo,
UbuntuProCheckTokenStatus as TokenStatus,
)
from subiquity.ui.views.ubuntu_advantage import UbuntuAdvantageView
from subiquity.ui.views.ubuntu_pro import UbuntuProView
from subiquitycore.lsb_release import lsb_release
from subiquitycore.tuicontroller import Skip
log = logging.getLogger("subiquity.client.controllers.ubuntu_advantage")
log = logging.getLogger("subiquity.client.controllers.ubuntu_pro")
class UbuntuAdvantageController(SubiquityTuiController):
""" Client-side controller for Ubuntu Advantage configuration. """
class UbuntuProController(SubiquityTuiController):
""" Client-side controller for Ubuntu Pro configuration. """
endpoint_name = "ubuntu_advantage"
endpoint_name = "ubuntu_pro"
def __init__(self, app) -> None:
""" Initializer for the client-side UA controller. """
@ -45,7 +44,7 @@ class UbuntuAdvantageController(SubiquityTuiController):
super().__init__(app)
async def make_ui(self) -> UbuntuAdvantageView:
async def make_ui(self) -> UbuntuProView:
""" Generate the UI, based on the data provided by the model. """
dry_run: bool = self.app.opts.dry_run
@ -57,8 +56,8 @@ class UbuntuAdvantageController(SubiquityTuiController):
await self.endpoint.skip.POST()
raise Skip("Not running LTS version")
ubuntu_advantage_info = await self.endpoint.GET()
return UbuntuAdvantageView(self, ubuntu_advantage_info.token)
ubuntu_pro_info = await self.endpoint.GET()
return UbuntuProView(self, ubuntu_pro_info.token)
def run_answers(self) -> None:
if "token" in self.answers:
@ -69,16 +68,16 @@ class UbuntuAdvantageController(SubiquityTuiController):
async def inner() -> None:
answer = await self.endpoint.check_token.GET(token)
if answer.status == TokenStatus.INVALID_TOKEN:
if isinstance(self.ui.body, UbuntuAdvantageView):
if isinstance(self.ui.body, UbuntuProView):
self.ui.body.show_invalid_token()
elif answer.status == TokenStatus.EXPIRED_TOKEN:
if isinstance(self.ui.body, UbuntuAdvantageView):
if isinstance(self.ui.body, UbuntuProView):
self.ui.body.show_expired_token()
elif answer.status == TokenStatus.UNKNOWN_ERROR:
if isinstance(self.ui.body, UbuntuAdvantageView):
if isinstance(self.ui.body, UbuntuProView):
self.ui.body.show_unknown_error()
else:
if isinstance(self.ui.body, UbuntuAdvantageView):
if isinstance(self.ui.body, UbuntuProView):
self.ui.body.show_activable_services(answer.services)
self._check_task = schedule_task(inner())
@ -93,5 +92,5 @@ class UbuntuAdvantageController(SubiquityTuiController):
def done(self, token: str) -> None:
self.app.next_screen(
self.endpoint.POST(UbuntuAdvantageInfo(token=token))
self.endpoint.POST(UbuntuProInfo(token=token))
)

View File

@ -33,7 +33,19 @@ def make_schema(app):
cschema = getattr(controller, "autoinstall_schema", None)
if cschema is None:
continue
schema['properties'][ckey] = cschema
ckey_alias = getattr(controller, 'autoinstall_key_alias', None)
if ckey_alias is None:
continue
cschema = cschema.copy()
cschema["deprecated"] = True
cschema["description"] = f"Compatibility only - use {ckey} instead"
schema['properties'][ckey_alias] = cschema
return schema

View File

@ -50,8 +50,8 @@ from subiquity.common.types import (
StorageResponse,
StorageResponseV2,
TimeZoneInfo,
UbuntuAdvantageInfo,
UbuntuAdvantageCheckTokenAnswer,
UbuntuProInfo,
UbuntuProCheckTokenAnswer,
WLANSupportInstallState,
ZdevInfo,
WSLConfigurationBase,
@ -321,16 +321,16 @@ class API:
def GET() -> List[str]: ...
def POST(data: Payload[List[str]]): ...
class ubuntu_advantage:
def GET() -> UbuntuAdvantageInfo: ...
def POST(data: Payload[UbuntuAdvantageInfo]) -> None: ...
class ubuntu_pro:
def GET() -> UbuntuProInfo: ...
def POST(data: Payload[UbuntuProInfo]) -> None: ...
class skip:
def POST() -> None: ...
class check_token:
def GET(token: Payload[str]) \
-> UbuntuAdvantageCheckTokenAnswer: ...
-> UbuntuProCheckTokenAnswer: ...
class LinkAction(enum.Enum):

View File

@ -416,11 +416,11 @@ class TimeZoneInfo:
@attr.s(auto_attribs=True)
class UbuntuAdvantageInfo:
class UbuntuProInfo:
token: str = attr.ib(repr=False)
class UbuntuAdvantageCheckTokenStatus(enum.Enum):
class UbuntuProCheckTokenStatus(enum.Enum):
VALID_TOKEN = enum.auto()
INVALID_TOKEN = enum.auto()
EXPIRED_TOKEN = enum.auto()
@ -428,16 +428,16 @@ class UbuntuAdvantageCheckTokenStatus(enum.Enum):
@attr.s(auto_attribs=True)
class UbuntuAdvantageService:
class UbuntuProService:
name: str
description: str
@attr.s(auto_attribs=True)
class UbuntuAdvantageCheckTokenAnswer:
status: UbuntuAdvantageCheckTokenStatus
class UbuntuProCheckTokenAnswer:
status: UbuntuProCheckTokenStatus
services: Optional[List[UbuntuAdvantageService]]
services: Optional[List[UbuntuProService]]
class ShutdownMode(enum.Enum):

View File

@ -43,7 +43,7 @@ from .snaplist import SnapListModel
from .source import SourceModel
from .ssh import SSHModel
from .timezone import TimeZoneModel
from .ubuntu_advantage import UbuntuAdvantageModel
from .ubuntu_pro import UbuntuProModel
from .updates import UpdatesModel
@ -147,7 +147,7 @@ class SubiquityModel:
self.ssh = SSHModel()
self.source = SourceModel()
self.timezone = TimeZoneModel()
self.ubuntu_advantage = UbuntuAdvantageModel()
self.ubuntu_pro = UbuntuProModel()
self.updates = UpdatesModel()
self.userdata = {}

View File

@ -15,12 +15,12 @@
import unittest
from subiquity.models.ubuntu_advantage import UbuntuAdvantageModel
from subiquity.models.ubuntu_pro import UbuntuProModel
class TestUbuntuAdvantageModel(unittest.TestCase):
class TestUbuntuProModel(unittest.TestCase):
def test_make_cloudconfig_(self):
model = UbuntuAdvantageModel()
model = UbuntuProModel()
# Test with a token
model.token = "0a1b2c3d4e5f6"

View File

@ -12,16 +12,16 @@
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
""" Module that defines the model for Ubuntu Advantage configuration. """
""" Module that defines the model for Ubuntu Pro configuration. """
import logging
log = logging.getLogger("subiquity.models.ubuntu_advantage")
log = logging.getLogger("subiquity.models.ubuntu_pro")
class UbuntuAdvantageModel:
class UbuntuProModel:
"""
Model that represents the Ubuntu Advantage configuration.
Model that represents the Ubuntu Pro configuration.
Currently, we rely only on cloud-init so we have no means to validate that
the provided token is correct ; nor to retrieve information about the
subscription.

View File

@ -38,6 +38,11 @@ class SubiquityController(BaseController):
autoinstall_default: Any = None
endpoint: Optional[type] = None
# If we want to update the autoinstall_key, we can add the old value
# here to keep being backwards compatible. The old value will be marked
# deprecated in favor of autoinstall_key.
autoinstall_key_alias: Optional[str] = None
def __init__(self, app):
super().__init__(app)
self.context.set('controller', self)
@ -46,9 +51,19 @@ class SubiquityController(BaseController):
if not self.app.autoinstall_config:
return
with self.context.child("load_autoinstall_data"):
ai_data = self.app.autoinstall_config.get(
self.autoinstall_key,
self.autoinstall_default)
key_candidates = [self.autoinstall_key]
if self.autoinstall_key_alias is not None:
key_candidates.append(self.autoinstall_key_alias)
for key in key_candidates:
try:
ai_data = self.app.autoinstall_config[key]
break
except KeyError:
pass
else:
ai_data = self.autoinstall_default
if ai_data is not None and self.autoinstall_schema is not None:
jsonschema.validate(ai_data, self.autoinstall_schema)
self.load_autoinstall_data(ai_data)
@ -77,7 +92,15 @@ class SubiquityController(BaseController):
return True
i_sections = self.app.autoinstall_config.get(
'interactive-sections', [])
return '*' in i_sections or self.autoinstall_key in i_sections
if "*" in i_sections:
return True
if self.autoinstall_key in i_sections:
return True
return (self.autoinstall_key_alias is not None
and self.autoinstall_key_alias in i_sections)
async def configured(self):
"""Let the world know that this controller's model is now configured.

View File

@ -33,7 +33,7 @@ from .snaplist import SnapListController
from .source import SourceController
from .ssh import SSHController
from .timezone import TimeZoneController
from .ubuntu_advantage import UbuntuAdvantageController
from .ubuntu_pro import UbuntuProController
from .updates import UpdatesController
from .userdata import UserdataController
from .zdev import ZdevController
@ -61,7 +61,7 @@ __all__ = [
'SourceController',
'SSHController',
'TimeZoneController',
'UbuntuAdvantageController',
'UbuntuProController',
'UpdatesController',
'UserdataController',
'ZdevController',

View File

@ -15,15 +15,15 @@
import unittest
from subiquity.server.controllers.ubuntu_advantage import (
UbuntuAdvantageController,
from subiquity.server.controllers.ubuntu_pro import (
UbuntuProController,
)
from subiquitycore.tests.mocks import make_app
class TestUbuntuAdvantageController(unittest.TestCase):
class TestUbuntuProController(unittest.TestCase):
def setUp(self):
self.controller = UbuntuAdvantageController(make_app())
self.controller = UbuntuProController(make_app())
def test_serialize(self):
self.controller.model.token = "1a2b3C"

View File

@ -19,13 +19,13 @@ import os
from subiquity.common.apidef import API
from subiquity.common.types import (
UbuntuAdvantageInfo,
UbuntuAdvantageCheckTokenAnswer,
UbuntuAdvantageCheckTokenStatus,
UbuntuProInfo,
UbuntuProCheckTokenAnswer,
UbuntuProCheckTokenStatus,
)
from subiquity.server.ubuntu_advantage import (
InvalidUATokenError,
ExpiredUATokenError,
InvalidTokenError,
ExpiredTokenError,
CheckSubscriptionError,
UAInterface,
UAInterfaceStrategy,
@ -34,20 +34,21 @@ from subiquity.server.ubuntu_advantage import (
)
from subiquity.server.controller import SubiquityController
log = logging.getLogger("subiquity.server.controllers.ubuntu_advantage")
log = logging.getLogger("subiquity.server.controllers.ubuntu_pro")
TOKEN_DESC = """\
A valid token starts with a C and is followed by 23 to 29 Base58 characters.
See https://pkg.go.dev/github.com/btcsuite/btcutil/base58#CheckEncode"""
class UbuntuAdvantageController(SubiquityController):
""" Represent the server-side Ubuntu Advantage controller. """
class UbuntuProController(SubiquityController):
""" Represent the server-side Ubuntu Pro controller. """
endpoint = API.ubuntu_advantage
endpoint = API.ubuntu_pro
model_name = "ubuntu_advantage"
autoinstall_key = "ubuntu-advantage"
model_name = "ubuntu_pro"
autoinstall_key = "ubuntu-pro"
autoinstall_key_alias = "ubuntu-advantage"
autoinstall_schema = {
"type": "object",
"properties": {
@ -62,7 +63,7 @@ class UbuntuAdvantageController(SubiquityController):
}
def __init__(self, app) -> None:
""" Initializer for server-side UA controller. """
""" Initializer for server-side Ubuntu Pro controller. """
strategy: UAInterfaceStrategy
if app.opts.dry_run:
strategy = MockedUAInterfaceStrategy(scale_factor=app.scale_factor)
@ -84,7 +85,7 @@ class UbuntuAdvantageController(SubiquityController):
def make_autoinstall(self) -> dict:
""" Return a dictionary that can be used as an autoinstall snippet for
Ubuntu Advantage.
Ubuntu Pro.
"""
if not self.model.token:
return {}
@ -102,11 +103,11 @@ class UbuntuAdvantageController(SubiquityController):
""" Loads the last-known state of the model. """
self.model.token = token
async def GET(self) -> UbuntuAdvantageInfo:
async def GET(self) -> UbuntuProInfo:
""" Handle a GET request coming from the client-side controller. """
return UbuntuAdvantageInfo(token=self.model.token)
return UbuntuProInfo(token=self.model.token)
async def POST(self, data: UbuntuAdvantageInfo) -> None:
async def POST(self, data: UbuntuProInfo) -> None:
""" Handle a POST request coming from the client-side controller and
then call .configured().
"""
@ -119,7 +120,7 @@ class UbuntuAdvantageController(SubiquityController):
await self.configured()
async def check_token_GET(self, token: str) \
-> UbuntuAdvantageCheckTokenAnswer:
-> UbuntuProCheckTokenAnswer:
""" Handle a GET request asking whether the contract token is valid or
not. If it is valid, we provide the list of activable services
associated with the subscription.
@ -128,14 +129,13 @@ class UbuntuAdvantageController(SubiquityController):
try:
services = await \
self.ua_interface.get_activable_services(token=token)
except InvalidUATokenError:
status = UbuntuAdvantageCheckTokenStatus.INVALID_TOKEN
except ExpiredUATokenError:
status = UbuntuAdvantageCheckTokenStatus.EXPIRED_TOKEN
except InvalidTokenError:
status = UbuntuProCheckTokenStatus.INVALID_TOKEN
except ExpiredTokenError:
status = UbuntuProCheckTokenStatus.EXPIRED_TOKEN
except CheckSubscriptionError:
status = UbuntuAdvantageCheckTokenStatus.UNKNOWN_ERROR
status = UbuntuProCheckTokenStatus.UNKNOWN_ERROR
else:
status = UbuntuAdvantageCheckTokenStatus.VALID_TOKEN
status = UbuntuProCheckTokenStatus.VALID_TOKEN
return UbuntuAdvantageCheckTokenAnswer(status=status,
services=services)
return UbuntuProCheckTokenAnswer(status=status, services=services)

View File

@ -207,7 +207,7 @@ POSTINSTALL_MODEL_NAMES = ModelNames({
"packages",
"snaplist",
"ssh",
"ubuntu_advantage",
"ubuntu_pro",
"userdata",
},
desktop={"timezone"})
@ -246,7 +246,7 @@ class SubiquityServer(Application):
"Zdev",
"Source",
"Network",
"UbuntuAdvantage",
"UbuntuPro",
"Proxy",
"Mirror",
"Filesystem",

View File

@ -0,0 +1,62 @@
# Copyright 2022 Canonical, Ltd.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import contextlib
from unittest.mock import patch
from subiquitycore.tests import SubiTestCase
from subiquitycore.tests.mocks import make_app
from subiquity.server.controller import SubiquityController
class TestController(SubiTestCase):
def setUp(self):
self.controller = SubiquityController(make_app())
self.controller.context.child = contextlib.nullcontext
@patch.object(SubiquityController, "load_autoinstall_data")
def test_setup_autoinstall(self, mock_load):
# No autoinstall data
self.controller.app.autoinstall_config = None
self.controller.setup_autoinstall()
mock_load.assert_not_called()
# Make sure the autoinstall_key has precedence over
# autoinstall_key_alias if both are present.
self.controller.app.autoinstall_config = {
"dummy": "some-dummy-data",
"dummy-alias": "some-dummy-alias-data",
}
self.controller.autoinstall_key = "dummy"
self.controller.autoinstall_key_alias = "dummy-alias"
self.controller.autoinstall_default = "default-data"
self.controller.setup_autoinstall()
mock_load.assert_called_once_with("some-dummy-data")
# Make sure we failover to autoinstall_key_alias if autoinstall_key is
# not present
mock_load.reset_mock()
self.controller.autoinstall_key = "inexistent"
self.controller.setup_autoinstall()
mock_load.assert_called_once_with("some-dummy-alias-data")
# Make sure we failover to autoinstall_default otherwise
mock_load.reset_mock()
self.controller.autoinstall_key = "inexistent"
self.controller.autoinstall_key_alias = "inexistent"
self.controller.setup_autoinstall()
mock_load.assert_called_once_with("default-data")

View File

@ -17,10 +17,10 @@ from subprocess import CalledProcessError, CompletedProcess
import unittest
from unittest.mock import patch, AsyncMock
from subiquity.common.types import UbuntuAdvantageService
from subiquity.common.types import UbuntuProService
from subiquity.server.ubuntu_advantage import (
InvalidUATokenError,
ExpiredUATokenError,
InvalidTokenError,
ExpiredTokenError,
CheckSubscriptionError,
UAInterface,
MockedUAInterfaceStrategy,
@ -36,7 +36,7 @@ class TestMockedUAInterfaceStrategy(unittest.TestCase):
def test_query_info_invalid(self):
# Tokens starting with "i" in dry-run mode cause the token to be
# reported as invalid.
with self.assertRaises(InvalidUATokenError):
with self.assertRaises(InvalidTokenError):
run_coro(self.strategy.query_info(token="invalidToken"))
def test_query_info_failure(self):
@ -130,7 +130,7 @@ class TestUAInterface(unittest.TestCase):
strategy = MockedUAInterfaceStrategy(scale_factor=1_000_000)
interface = UAInterface(strategy)
with self.assertRaises(InvalidUATokenError):
with self.assertRaises(InvalidTokenError):
run_coro(interface.get_activable_services(token="invalidToken"))
# Tokens starting with "f" in dry-run mode simulate an "internal"
# error.
@ -138,7 +138,7 @@ class TestUAInterface(unittest.TestCase):
run_coro(interface.get_activable_services(token="failure"))
# Tokens starting with "x" is dry-run mode simulate an expired token.
with self.assertRaises(ExpiredUATokenError):
with self.assertRaises(ExpiredTokenError):
run_coro(interface.get_activable_services(token="xpiredToken"))
# Other tokens are considered valid in dry-run mode.
@ -188,19 +188,19 @@ class TestUAInterface(unittest.TestCase):
services = run_coro(
interface.get_activable_services(token="XXX"))
self.assertIn(UbuntuAdvantageService(
self.assertIn(UbuntuProService(
name="esm-infra",
description="UA Infra: Extended Security Maintenance (ESM)",
), services)
self.assertIn(UbuntuAdvantageService(
self.assertIn(UbuntuProService(
name="fips",
description="NIST-certified core packages",
), services)
self.assertNotIn(UbuntuAdvantageService(
self.assertNotIn(UbuntuProService(
name="esm-apps",
description="UA Apps: Extended Security Maintenance (ESM)",
), services)
self.assertNotIn(UbuntuAdvantageService(
self.assertNotIn(UbuntuProService(
name="cis",
description="Center for Internet Security Audit Tools",
), services)

View File

@ -12,8 +12,8 @@
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
""" This module defines utilities to interface with Ubuntu Advantage
subscriptions. """
""" This module defines utilities to interface with the ubuntu-advantage-tools
helper. """
from abc import ABC, abstractmethod
from datetime import datetime as dt
@ -23,14 +23,14 @@ from subprocess import CalledProcessError, CompletedProcess
from typing import List, Sequence, Union
import asyncio
from subiquity.common.types import UbuntuAdvantageService
from subiquity.common.types import UbuntuProService
from subiquitycore import utils
log = logging.getLogger("subiquity.server.ubuntu_advantage")
class InvalidUATokenError(Exception):
class InvalidTokenError(Exception):
""" Exception to be raised when the supplied token is invalid. """
def __init__(self, token: str, message: str = "") -> None:
self.token = token
@ -38,7 +38,7 @@ class InvalidUATokenError(Exception):
super().__init__(message)
class ExpiredUATokenError(Exception):
class ExpiredTokenError(Exception):
""" Exception to be raised when the supplied token has expired. """
def __init__(self, token: str, expires: str, message: str = "") -> None:
self.token = token
@ -85,7 +85,7 @@ class MockedUAInterfaceStrategy(UAInterfaceStrategy):
if token[0] == "x":
path = "examples/uaclient-status-expired.json"
elif token[0] == "i":
raise InvalidUATokenError(token)
raise InvalidTokenError(token)
elif token[0] == "f":
raise CheckSubscriptionError(token)
else:
@ -149,7 +149,7 @@ class UAInterface:
return await self.strategy.query_info(token)
async def get_activable_services(self, token: str) \
-> List[UbuntuAdvantageService]:
-> List[UbuntuProService]:
""" Return a list of activable services (i.e. services that are
entitled to the subscription and available on the current hardware).
"""
@ -160,7 +160,7 @@ class UAInterface:
# See https://bugs.python.org/issue35829
expiration = dt.fromisoformat(info["expires"].replace("Z", "+00:00"))
if expiration.timestamp() <= dt.utcnow().timestamp():
raise ExpiredUATokenError(token, expires=info["expires"])
raise ExpiredTokenError(token, expires=info["expires"])
def is_activable_service(service: dict) -> bool:
# - the available field for a service refers to its availability on
@ -170,13 +170,13 @@ class UAInterface:
return service["available"] == "yes" \
and service["entitled"] == "yes"
def service_from_dict(service: dict) -> UbuntuAdvantageService:
return UbuntuAdvantageService(
def service_from_dict(service: dict) -> UbuntuProService:
return UbuntuProService(
name=service["name"],
description=service["description"],
)
activable_services: List[UbuntuAdvantageService] = []
activable_services: List[UbuntuProService] = []
for service in info["services"]:
if not is_activable_service(service):

View File

@ -235,7 +235,7 @@ class TestFlow(TestAPI):
ua_params = {
"token": "a1b2c3d4e6f7g8h9I0K1",
}
await inst.post('/ubuntu_advantage', ua_params)
await inst.post('/ubuntu_pro', ua_params)
for state in 'RUNNING', 'POST_WAIT', 'POST_RUNNING', 'UU_RUNNING':
await inst.get('/meta/status', cur=state)

View File

@ -12,7 +12,7 @@
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
""" Module that defines the view class for Ubuntu Advantage configuration. """
""" Module that defines the view class for Ubuntu Pro configuration. """
import logging
import re
@ -25,7 +25,7 @@ from urwid import (
Widget,
)
from subiquity.common.types import UbuntuAdvantageService as UAService
from subiquity.common.types import UbuntuProService
from subiquitycore.view import BaseView
from subiquitycore.ui.buttons import (
back_btn,
@ -56,15 +56,15 @@ from subiquitycore.ui.utils import (
from subiquitycore.ui.interactive import StringEditor
log = logging.getLogger('subiquity.ui.views.ubuntu_advantage')
log = logging.getLogger('subiquity.ui.views.ubuntu_pro')
ua_help = _("If you want to enroll this system using your Ubuntu Advantage "
"subscription, enter your Ubuntu Advantage token here. "
ua_help = _("If you want to enroll this system using your Ubuntu Pro "
"subscription, enter your Ubuntu Pro token here. "
"Otherwise, leave this blank.")
class UATokenEditor(StringEditor, WantsToKnowFormField):
""" Represent a text-box editor for the Ubuntu Advantage Token. """
""" Represent a text-box editor for the Ubuntu Pro Token. """
def __init__(self):
""" Initialize the text-field editor for UA token. """
self.valid_char_pat = r"[a-zA-Z0-9]"
@ -83,26 +83,26 @@ class UATokenEditor(StringEditor, WantsToKnowFormField):
return super().valid_char(ch)
class UbuntuAdvantageForm(Form):
class UbuntuProForm(Form):
"""
Represents a form requesting Ubuntu Advantage information
Represents a form requesting Ubuntu Pro information
"""
cancel_label = _("Back")
UATokenField = simple_field(UATokenEditor)
token = UATokenField(_("Ubuntu Advantage token:"), help=ua_help)
token = UATokenField(_("Ubuntu Pro token:"), help=ua_help)
class CheckingUAToken(WidgetWrap):
""" Widget displaying a loading animation while checking ubuntu advantage
""" Widget displaying a loading animation while checking ubuntu pro
subscription. """
def __init__(self, parent: BaseView):
""" Initializes the loading animation widget. """
self.parent = parent
spinner = Spinner(parent.controller.app.aio_loop, style="dots")
spinner.start()
text = _("Checking Ubuntu Advantage subscription...")
text = _("Checking Ubuntu Pro subscription...")
button = cancel_btn(label=_("Cancel"), on_press=self.cancel)
self.width = len(text) + 4
super().__init__(
@ -119,20 +119,20 @@ class CheckingUAToken(WidgetWrap):
self.parent.remove_overlay()
class UbuntuAdvantageView(BaseView):
""" Represent the view of the Ubuntu Advantage configuration. """
class UbuntuProView(BaseView):
""" Represent the view of the Ubuntu Pro configuration. """
title = _("Enable Ubuntu Advantage")
excerpt = _("Enter your Ubuntu Advantage token if you want to enroll "
title = _("Enable Ubuntu Pro")
excerpt = _("Enter your Ubuntu Pro token if you want to enroll "
"this system.")
def __init__(self, controller, token: str):
""" Initialize the view with the default value for the token. """
self.controller = controller
self.form = UbuntuAdvantageForm(initial={"token": token})
self.form = UbuntuProForm(initial={"token": token})
def on_cancel(_: UbuntuAdvantageForm):
def on_cancel(_: UbuntuProForm):
self.cancel()
connect_signal(self.form, 'submit', self.done)
@ -140,7 +140,7 @@ class UbuntuAdvantageView(BaseView):
super().__init__(self.form.as_screen(excerpt=_(self.excerpt)))
def done(self, form: UbuntuAdvantageForm) -> None:
def done(self, form: UbuntuProForm) -> None:
""" If no token was supplied, move on to the next screen.
If a token was provided, open the loading dialog and
asynchronously check if the token is valid. """
@ -165,7 +165,7 @@ class UbuntuAdvantageView(BaseView):
self.show_stretchy_overlay(
SomethingFailed(self,
"Invalid token.",
"The Ubuntu Advantage token that you provided"
"The Ubuntu Pro token that you provided"
" is invalid. Please make sure that you typed"
" your token correctly."))
@ -176,7 +176,7 @@ class UbuntuAdvantageView(BaseView):
self.show_stretchy_overlay(
SomethingFailed(self,
"Token expired.",
"The Ubuntu Advantage token that you provided"
"The Ubuntu Pro token that you provided"
" has expired. Please use a different token."))
def show_unknown_error(self) -> None:
@ -188,9 +188,10 @@ class UbuntuAdvantageView(BaseView):
self.remove_overlay()
self.show_stretchy_overlay(ContinueAnywayWidget(self))
def show_activable_services(self, services: List[UAService]) -> None:
def show_activable_services(self,
services: List[UbuntuProService]) -> None:
""" Display an overlay with the list of services that can be enabled
via Ubuntu Advantage subscription. After the user confirms, we will
via Ubuntu Pro subscription. After the user confirms, we will
quit the current view and move on. """
self.remove_overlay()
self.show_stretchy_overlay(ShowServicesWidget(self, services))
@ -198,8 +199,8 @@ class UbuntuAdvantageView(BaseView):
class ShowServicesWidget(Stretchy):
""" Widget to show the activable services for UA subscription. """
def __init__(self, parent: UbuntuAdvantageView,
services: List[UAService]) -> None:
def __init__(self, parent: UbuntuProView,
services: List[UbuntuProService]) -> None:
""" Initializes the widget by including the list of services as a
bullet-point list. """
self.parent = parent
@ -208,7 +209,7 @@ class ShowServicesWidget(Stretchy):
title = _("Activable Services")
header = _("List of services that are activable through your "
"Ubuntu Advantage subscription:")
"Ubuntu Pro subscription:")
widgets: List[Widget] = [
Text(header),
@ -231,7 +232,7 @@ class ShowServicesWidget(Stretchy):
class ContinueAnywayWidget(Stretchy):
""" Widget that requests the user if he wants to go back or continue
anyway. """
def __init__(self, parent: UbuntuAdvantageView) -> None:
def __init__(self, parent: UbuntuProView) -> None:
""" Initializes the widget by showing two buttons, one to go back and
one to move forward anyway. """
self.parent = parent