From 32dbf287670a607c9a7e91dde5fd9afe15aab99c Mon Sep 17 00:00:00 2001 From: Michael Hudson-Doyle Date: Tue, 8 Dec 2020 21:43:38 +1300 Subject: [PATCH] only wait 10 minutes for cloud-init status --wait to complete, not forever and show a message to the user when this happens --- subiquity/client/client.py | 5 +++++ subiquity/cmd/server.py | 11 +++++++++-- subiquity/common/types.py | 1 + subiquity/server/server.py | 4 +++- subiquity/ui/views/welcome.py | 33 +++++++++++++++++++++++++++++++++ 5 files changed, 51 insertions(+), 3 deletions(-) diff --git a/subiquity/client/client.py b/subiquity/client/client.py index 6f01dc31..cb5ac283 100644 --- a/subiquity/client/client.py +++ b/subiquity/client/client.py @@ -54,6 +54,9 @@ from subiquity.ui.views.help import HelpMenu from subiquity.ui.views.installprogress import ( InstallConfirmation, ) +from subiquity.ui.views.welcome import ( + CloudInitFail, + ) log = logging.getLogger('subiquity.client.client') @@ -273,6 +276,8 @@ class SubiquityClient(TuiApplication): self.aio_loop, [status.log_syslog_id], self.controllers.Progress.log_line) + if not status.cloud_init_ok: + self.add_global_overlay(CloudInitFail(self)) self.error_reporter.load_reports() for report in self.error_reporter.reports: if report.kind == ErrorReportKind.UI and not report.seen: diff --git a/subiquity/cmd/server.py b/subiquity/cmd/server.py index ee46b029..1717fbcb 100644 --- a/subiquity/cmd/server.py +++ b/subiquity/cmd/server.py @@ -16,6 +16,7 @@ import argparse import logging import os +import subprocess import sys import time @@ -108,9 +109,15 @@ def main(): logger.info("Starting Subiquity server revision {}".format(version)) logger.info("Arguments passed: {}".format(sys.argv)) + cloud_init_ok = True if not opts.dry_run: ci_start = time.time() - status_txt = run_command(["cloud-init", "status", "--wait"]).stdout + try: + status_txt = run_command( + ["cloud-init", "status", "--wait"], timeout=600).stdout + except subprocess.TimeoutExpired: + status_txt = '' + cloud_init_ok = False logger.debug("waited %ss for cloud-init", time.time() - ci_start) if "status: done" in status_txt: logger.debug("loading cloud config") @@ -133,7 +140,7 @@ def main(): "cloud-init status: %r, assumed disabled", status_txt) - server = SubiquityServer(opts, block_log_dir) + server = SubiquityServer(opts, block_log_dir, cloud_init_ok) server.note_file_for_apport( "InstallerServerLog", logfiles['debug']) diff --git a/subiquity/common/types.py b/subiquity/common/types.py index caf4164d..d06c2987 100644 --- a/subiquity/common/types.py +++ b/subiquity/common/types.py @@ -35,6 +35,7 @@ class ApplicationState(enum.Enum): @attr.s(auto_attribs=True) class ApplicationStatus: state: ApplicationState + cloud_init_ok: bool early_commands_syslog_id: str log_syslog_id: str event_syslog_id: str diff --git a/subiquity/server/server.py b/subiquity/server/server.py index 2f2f7e86..0a305a46 100644 --- a/subiquity/server/server.py +++ b/subiquity/server/server.py @@ -74,6 +74,7 @@ class MetaController: await self.app.state_event.wait() return ApplicationStatus( self.app.state, + cloud_init_ok=self.app.cloud_init_ok, early_commands_syslog_id=self.app.early_commands_syslog_id, event_syslog_id=self.app.event_syslog_id, log_syslog_id=self.app.log_syslog_id) @@ -140,9 +141,10 @@ class SubiquityServer(Application): root = os.path.abspath('.subiquity') return SubiquityModel(root, self.opts.sources) - def __init__(self, opts, block_log_dir): + def __init__(self, opts, block_log_dir, cloud_init_ok): super().__init__(opts) self.block_log_dir = block_log_dir + self.cloud_init_ok = cloud_init_ok self._state = ApplicationState.STARTING self.state_event = asyncio.Event() self.confirming_tty = '' diff --git a/subiquity/ui/views/welcome.py b/subiquity/ui/views/welcome.py index e84bb41c..f7579796 100644 --- a/subiquity/ui/views/welcome.py +++ b/subiquity/ui/views/welcome.py @@ -25,6 +25,7 @@ from urwid import Text from subiquitycore.ui.buttons import forward_btn, other_btn from subiquitycore.ui.container import ListBox +from subiquitycore.ui.stretchy import Stretchy from subiquitycore.ui.utils import button_pile, rewrap, screen from subiquitycore.screen import is_linux_tty from subiquitycore.view import BaseView @@ -58,6 +59,13 @@ You can also connect to the installer over the network via SSH, which will allow use of rich mode. """ +CLOUD_INIT_FAIL_TEXT = """ +cloud-init failed to complete after 10 minutes of waiting. This +suggests a bug, which we would appreciate help understanding. If you +could file a bug at https://bugs.launchpad.net/subiquity/+filebug and +attach the contents of /var/log, it would be most appreciated. +""" + def get_languages(): base = os.environ.get("SNAP", ".") @@ -157,3 +165,28 @@ class WelcomeView(BaseView): def local_help(self): return _("Help choosing a language"), _(HELP) + + +class CloudInitFail(Stretchy): + def __init__(self, app): + self.app = app + self.shell_btn = other_btn( + _("Switch to a shell"), on_press=self._debug_shell) + self.close_btn = other_btn( + _("Close"), on_press=self._close) + widgets = [ + Text(rewrap(_(CLOUD_INIT_FAIL_TEXT))), + Text(''), + button_pile([self.shell_btn, self.close_btn]), + ] + super().__init__( + "", + widgets, + stretchy_index=0, + focus_index=2) + + def _debug_shell(self, sender): + self.app.debug_shell() + + def _close(self, sender): + self.app.remove_global_overlay(self)