From 0bb4915c9f77bb11ade1c1f49626a046d1e3024a Mon Sep 17 00:00:00 2001 From: Olivier Gayot Date: Thu, 11 Apr 2024 10:55:07 +0200 Subject: [PATCH] mirror: if mirror test fails, suggest an offline install In the mirror screen, if the test fails and the user decides to ignore the failure, we used to continue the installation normally ; which in most scenarios resulted in an error at a later stage of the installation. Instead, we now revert to an installation without network (i.e., only packages from the pool are considered for installation) if the user decides to ignore the failure. Signed-off-by: Olivier Gayot --- subiquity/client/controllers/mirror.py | 29 +++++++++++++++++++++++--- subiquity/ui/views/mirror.py | 16 ++++++++------ 2 files changed, 36 insertions(+), 9 deletions(-) diff --git a/subiquity/client/controllers/mirror.py b/subiquity/client/controllers/mirror.py index 26082660..aab2ea93 100644 --- a/subiquity/client/controllers/mirror.py +++ b/subiquity/client/controllers/mirror.py @@ -15,6 +15,7 @@ import asyncio import logging +from typing import Optional from subiquity.client.controller import SubiquityTuiController from subiquity.common.types import MirrorCheckStatus, MirrorGet, MirrorPost @@ -42,6 +43,15 @@ class MirrorController(SubiquityTuiController): # Just in case there is no candidate at all. # In practise, it should seldom happen. url = next(iter(mirror_response.candidates), "") + + if not mirror_response.use_during_installation: + # If the user comes back to the mirror screen after accepting to + # do an installation without the archive (i.e., only fetching from + # the pool), the call to /network/has_network will return false. We + # need to reset the force_offline value if we want to run another + # mirror test. + await self.endpoint.POST(MirrorPost(use_during_installation=True)) + has_network = await self.app.client.network.has_network.GET() if has_network: check = await self.endpoint.check_mirror.progress.GET() @@ -69,6 +79,19 @@ class MirrorController(SubiquityTuiController): def cancel(self): self.app.prev_screen() - def done(self, mirror): - log.debug("MirrorController.done next_screen mirror=%s", mirror) - self.app.next_screen(self.endpoint.POST(MirrorPost(elected=mirror))) + def done(self, mirror, skip_archive: Optional[bool]): + if skip_archive is not None: + use_during_installation = not skip_archive + else: + use_during_installation = None + + data = MirrorPost( + elected=mirror, use_during_installation=use_during_installation + ) + + log.debug( + "MirrorController.done next_screen mirror=%s, use_during_installation=%s", + mirror, + use_during_installation, + ) + self.app.next_screen(self.endpoint.POST(data)) diff --git a/subiquity/ui/views/mirror.py b/subiquity/ui/views/mirror.py index 7a581aa1..28bd99b9 100644 --- a/subiquity/ui/views/mirror.py +++ b/subiquity/ui/views/mirror.py @@ -47,8 +47,10 @@ MIRROR_CHECK_CONFIRMATION_TEXTS = { MirrorCheckStatus.FAILED: ( _("Mirror check failed"), _( - "The check of the mirror URL failed. You can continue, but it is very" - " likely that the installation will fail." + "The check of the mirror URL failed. If you decide to continue, only" + " packages present on the installation media will be considered for" + " installation. Remember to install security updates after booting" + " your newly installed system." ), ), None: ( @@ -217,7 +219,7 @@ class MirrorView(BaseView): self.last_status = check_state.status def done(self, result): - async def confirm_continue_anyway() -> None: + async def confirm_continue_anyway(continue_skip_archive: bool) -> None: title, question = MIRROR_CHECK_CONFIRMATION_TEXTS[self.last_status] confirmed = await self.ask_confirmation( title=title, @@ -227,7 +229,8 @@ class MirrorView(BaseView): ) if confirmed: - self.controller.done(result.url.value) + skip_archive = True if continue_skip_archive else None + self.controller.done(result.url.value, skip_archive=skip_archive) log.debug("User input: {}".format(result.as_data())) if self.has_network and self.last_status in [ @@ -235,9 +238,10 @@ class MirrorView(BaseView): MirrorCheckStatus.FAILED, None, ]: - async_helpers.run_bg_task(confirm_continue_anyway()) + status_is_failed = self.last_status == MirrorCheckStatus.FAILED + async_helpers.run_bg_task(confirm_continue_anyway(status_is_failed)) else: - self.controller.done(result.url.value) + self.controller.done(result.url.value, skip_archive=None) def cancel(self, result=None): self.controller.cancel()