Expose endpoint to get list of UA activable services
The list of activable UA services was only retrieved from the client-side of Subiquity (using ubuntu-advantage-tools). Therefore, the desktop installer would need to reimplement the same logic should they need access to the list of services ; which is inconvenient. We now expose a new endpoint in the API that takes the token as a parameter and returns a status (+ a list of services if the token is valid and not expired). $ curl \ --unix-socket .subiquity/socket \ --header 'Content-Type: application/json' \ http://a/ubuntu_advantage/check_token \ -d '"C123456"' The token parameter is expected to be in the body of the request - rather than in the query string - to avoid ending up in the access logs. This new endpoint is a read-only GET endpoint. It is not designed as a replacement for the POST to /a/ubuntu_advantage that the client must (still) do to pass the token to the model. We now use this new endpoint internally in Subiquity so that the retrieval of the activable services is done on the server-side only. Signed-off-by: Olivier Gayot <olivier.gayot@canonical.com>
This commit is contained in:
parent
d158d4e701
commit
c171aac2c7
|
@ -16,21 +16,14 @@
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
import os
|
|
||||||
|
|
||||||
from subiquitycore.async_helpers import schedule_task
|
from subiquitycore.async_helpers import schedule_task
|
||||||
|
|
||||||
from subiquity.client.controller import SubiquityTuiController
|
from subiquity.client.controller import SubiquityTuiController
|
||||||
from subiquity.common.ubuntu_advantage import (
|
from subiquity.common.types import (
|
||||||
InvalidUATokenError,
|
UbuntuAdvantageInfo,
|
||||||
ExpiredUATokenError,
|
UbuntuAdvantageCheckTokenStatus as TokenStatus,
|
||||||
CheckSubscriptionError,
|
)
|
||||||
UAInterface,
|
|
||||||
UAInterfaceStrategy,
|
|
||||||
MockedUAInterfaceStrategy,
|
|
||||||
UAClientUAInterfaceStrategy,
|
|
||||||
)
|
|
||||||
from subiquity.common.types import UbuntuAdvantageInfo
|
|
||||||
from subiquity.ui.views.ubuntu_advantage import UbuntuAdvantageView
|
from subiquity.ui.views.ubuntu_advantage import UbuntuAdvantageView
|
||||||
|
|
||||||
from subiquitycore.lsb_release import lsb_release
|
from subiquitycore.lsb_release import lsb_release
|
||||||
|
@ -44,21 +37,6 @@ class UbuntuAdvantageController(SubiquityTuiController):
|
||||||
|
|
||||||
endpoint_name = "ubuntu_advantage"
|
endpoint_name = "ubuntu_advantage"
|
||||||
|
|
||||||
def __init__(self, app):
|
|
||||||
""" Initializer for client-side UA controller. """
|
|
||||||
strategy: UAInterfaceStrategy
|
|
||||||
if app.opts.dry_run:
|
|
||||||
strategy = MockedUAInterfaceStrategy(scale_factor=app.scale_factor)
|
|
||||||
else:
|
|
||||||
# Make sure we execute `$PYTHON "$SNAP/usr/bin/ubuntu-advantage"`.
|
|
||||||
executable = (
|
|
||||||
os.environ["PYTHON"],
|
|
||||||
os.path.join(os.environ["SNAP"], "usr/bin/ubuntu-advantage"),
|
|
||||||
)
|
|
||||||
strategy = UAClientUAInterfaceStrategy(executable=executable)
|
|
||||||
self.ua_interface = UAInterface(strategy)
|
|
||||||
super().__init__(app)
|
|
||||||
|
|
||||||
async def make_ui(self) -> UbuntuAdvantageView:
|
async def make_ui(self) -> UbuntuAdvantageView:
|
||||||
""" Generate the UI, based on the data provided by the model. """
|
""" Generate the UI, based on the data provided by the model. """
|
||||||
|
|
||||||
|
@ -77,21 +55,19 @@ class UbuntuAdvantageController(SubiquityTuiController):
|
||||||
def check_token(self, token: str):
|
def check_token(self, token: str):
|
||||||
""" Asynchronously check the token passed as an argument. """
|
""" Asynchronously check the token passed as an argument. """
|
||||||
async def inner() -> None:
|
async def inner() -> None:
|
||||||
try:
|
answer = await self.endpoint.check_token.GET(token)
|
||||||
svcs = await \
|
if answer.status == TokenStatus.INVALID_TOKEN:
|
||||||
self.ua_interface.get_activable_services(token=token)
|
|
||||||
except InvalidUATokenError:
|
|
||||||
if isinstance(self.ui.body, UbuntuAdvantageView):
|
if isinstance(self.ui.body, UbuntuAdvantageView):
|
||||||
self.ui.body.show_invalid_token()
|
self.ui.body.show_invalid_token()
|
||||||
except ExpiredUATokenError:
|
elif answer.status == TokenStatus.EXPIRED_TOKEN:
|
||||||
if isinstance(self.ui.body, UbuntuAdvantageView):
|
if isinstance(self.ui.body, UbuntuAdvantageView):
|
||||||
self.ui.body.show_expired_token()
|
self.ui.body.show_expired_token()
|
||||||
except CheckSubscriptionError:
|
elif answer.status == TokenStatus.UNKNOWN_ERROR:
|
||||||
if isinstance(self.ui.body, UbuntuAdvantageView):
|
if isinstance(self.ui.body, UbuntuAdvantageView):
|
||||||
self.ui.body.show_unknown_error()
|
self.ui.body.show_unknown_error()
|
||||||
else:
|
else:
|
||||||
if isinstance(self.ui.body, UbuntuAdvantageView):
|
if isinstance(self.ui.body, UbuntuAdvantageView):
|
||||||
self.ui.body.show_activable_services(svcs)
|
self.ui.body.show_activable_services(answer.services)
|
||||||
|
|
||||||
self._check_task = schedule_task(inner())
|
self._check_task = schedule_task(inner())
|
||||||
|
|
||||||
|
|
|
@ -49,6 +49,7 @@ from subiquity.common.types import (
|
||||||
StorageResponseV2,
|
StorageResponseV2,
|
||||||
TimeZoneInfo,
|
TimeZoneInfo,
|
||||||
UbuntuAdvantageInfo,
|
UbuntuAdvantageInfo,
|
||||||
|
UbuntuAdvantageCheckTokenAnswer,
|
||||||
WLANSupportInstallState,
|
WLANSupportInstallState,
|
||||||
ZdevInfo,
|
ZdevInfo,
|
||||||
WSLConfigurationBase,
|
WSLConfigurationBase,
|
||||||
|
@ -320,6 +321,10 @@ class API:
|
||||||
class skip:
|
class skip:
|
||||||
def POST() -> None: ...
|
def POST() -> None: ...
|
||||||
|
|
||||||
|
class check_token:
|
||||||
|
def GET(token: Payload[str]) \
|
||||||
|
-> UbuntuAdvantageCheckTokenAnswer: ...
|
||||||
|
|
||||||
|
|
||||||
class LinkAction(enum.Enum):
|
class LinkAction(enum.Enum):
|
||||||
NEW = enum.auto()
|
NEW = enum.auto()
|
||||||
|
|
|
@ -394,6 +394,20 @@ class UbuntuAdvantageInfo:
|
||||||
token: str
|
token: str
|
||||||
|
|
||||||
|
|
||||||
|
class UbuntuAdvantageCheckTokenStatus(enum.Enum):
|
||||||
|
VALID_TOKEN = enum.auto()
|
||||||
|
INVALID_TOKEN = enum.auto()
|
||||||
|
EXPIRED_TOKEN = enum.auto()
|
||||||
|
UNKNOWN_ERROR = enum.auto()
|
||||||
|
|
||||||
|
|
||||||
|
@attr.s(auto_attribs=True)
|
||||||
|
class UbuntuAdvantageCheckTokenAnswer:
|
||||||
|
status: UbuntuAdvantageCheckTokenStatus
|
||||||
|
|
||||||
|
services: Optional[List[dict]]
|
||||||
|
|
||||||
|
|
||||||
class ShutdownMode(enum.Enum):
|
class ShutdownMode(enum.Enum):
|
||||||
REBOOT = enum.auto()
|
REBOOT = enum.auto()
|
||||||
POWEROFF = enum.auto()
|
POWEROFF = enum.auto()
|
||||||
|
|
|
@ -15,9 +15,23 @@
|
||||||
""" Module defining the server-side controller class for Ubuntu Advantage. """
|
""" Module defining the server-side controller class for Ubuntu Advantage. """
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
import os
|
||||||
|
|
||||||
from subiquity.common.apidef import API
|
from subiquity.common.apidef import API
|
||||||
from subiquity.common.types import UbuntuAdvantageInfo
|
from subiquity.common.types import (
|
||||||
|
UbuntuAdvantageInfo,
|
||||||
|
UbuntuAdvantageCheckTokenAnswer,
|
||||||
|
UbuntuAdvantageCheckTokenStatus,
|
||||||
|
)
|
||||||
|
from subiquity.common.ubuntu_advantage import (
|
||||||
|
InvalidUATokenError,
|
||||||
|
ExpiredUATokenError,
|
||||||
|
CheckSubscriptionError,
|
||||||
|
UAInterface,
|
||||||
|
UAInterfaceStrategy,
|
||||||
|
MockedUAInterfaceStrategy,
|
||||||
|
UAClientUAInterfaceStrategy,
|
||||||
|
)
|
||||||
from subiquity.server.controller import SubiquityController
|
from subiquity.server.controller import SubiquityController
|
||||||
|
|
||||||
log = logging.getLogger("subiquity.server.controllers.ubuntu_advantage")
|
log = logging.getLogger("subiquity.server.controllers.ubuntu_advantage")
|
||||||
|
@ -47,6 +61,21 @@ class UbuntuAdvantageController(SubiquityController):
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def __init__(self, app) -> None:
|
||||||
|
""" Initializer for server-side UA controller. """
|
||||||
|
strategy: UAInterfaceStrategy
|
||||||
|
if app.opts.dry_run:
|
||||||
|
strategy = MockedUAInterfaceStrategy(scale_factor=app.scale_factor)
|
||||||
|
else:
|
||||||
|
# Make sure we execute `$PYTHON "$SNAP/usr/bin/ubuntu-advantage"`.
|
||||||
|
executable = (
|
||||||
|
os.environ["PYTHON"],
|
||||||
|
os.path.join(os.environ["SNAP"], "usr/bin/ubuntu-advantage"),
|
||||||
|
)
|
||||||
|
strategy = UAClientUAInterfaceStrategy(executable=executable)
|
||||||
|
self.ua_interface = UAInterface(strategy)
|
||||||
|
super().__init__(app)
|
||||||
|
|
||||||
def load_autoinstall_data(self, data: dict) -> None:
|
def load_autoinstall_data(self, data: dict) -> None:
|
||||||
""" Load autoinstall data and update the model. """
|
""" Load autoinstall data and update the model. """
|
||||||
if data is None:
|
if data is None:
|
||||||
|
@ -89,3 +118,25 @@ class UbuntuAdvantageController(SubiquityController):
|
||||||
""" When running on a non-LTS release, we want to call this so we can
|
""" When running on a non-LTS release, we want to call this so we can
|
||||||
skip the screen on the client side. """
|
skip the screen on the client side. """
|
||||||
await self.configured()
|
await self.configured()
|
||||||
|
|
||||||
|
async def check_token_GET(self, token: str) \
|
||||||
|
-> UbuntuAdvantageCheckTokenAnswer:
|
||||||
|
""" 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.
|
||||||
|
"""
|
||||||
|
services = None
|
||||||
|
try:
|
||||||
|
services = await \
|
||||||
|
self.ua_interface.get_activable_services(token=token)
|
||||||
|
except InvalidUATokenError:
|
||||||
|
status = UbuntuAdvantageCheckTokenStatus.INVALID_TOKEN
|
||||||
|
except ExpiredUATokenError:
|
||||||
|
status = UbuntuAdvantageCheckTokenStatus.EXPIRED_TOKEN
|
||||||
|
except CheckSubscriptionError:
|
||||||
|
status = UbuntuAdvantageCheckTokenStatus.UNKNOWN_ERROR
|
||||||
|
else:
|
||||||
|
status = UbuntuAdvantageCheckTokenStatus.VALID_TOKEN
|
||||||
|
|
||||||
|
return UbuntuAdvantageCheckTokenAnswer(status=status,
|
||||||
|
services=services)
|
||||||
|
|
Loading…
Reference in New Issue