Exemple #1
0
    def unhandled_input_dry_run(self, key):
        if key == 'ctrl g':
            import asyncio
            from systemd import journal

            async def mock_install():
                async with self.install_lock_file.exclusive():
                    self.install_lock_file.write_content("nowhere")
                    journal.send("starting install",
                                 SYSLOG_IDENTIFIER="subiquity")
                    await asyncio.sleep(5)

            schedule_task(mock_install())
        elif key in ['ctrl e', 'ctrl r']:
            interrupt = key == 'ctrl e'
            try:
                1 / 0
            except ZeroDivisionError:
                self.make_apport_report(ErrorReportKind.UNKNOWN,
                                        "example",
                                        interrupt=interrupt)
        elif key == 'ctrl u':
            1 / 0
        else:
            super().unhandled_input(key)
Exemple #2
0
 async def _probe(self):
     with self.context.child("_probe") as context:
         self._crash_reports = {}
         if isinstance(self.ui.body, ProbingFailed):
             self.ui.set_body(SlowProbing(self))
             schedule_task(self._wait_for_probing())
         for (restricted, kind) in [
                 (False, ErrorReportKind.BLOCK_PROBE_FAIL),
                 (True,  ErrorReportKind.DISK_PROBE_FAIL),
                 ]:
             try:
                 desc = "restricted={}".format(restricted)
                 with context.child("probe_once", desc):
                     await self._probe_once_task.start(restricted)
                     # We wait on the task directly here, not
                     # self._probe_once_task.wait as if _probe_once_task
                     # gets cancelled, we should be cancelled too.
                     await asyncio.wait_for(self._probe_once_task.task, 5.0)
             except Exception:
                 block_discover_log.exception(
                     "block probing failed restricted=%s", restricted)
                 report = self.app.make_apport_report(
                     kind, "block probing", interrupt=False)
                 self._crash_reports[restricted] = report
                 continue
             break
     log.debug("self.ai_data = %s", self.ai_data)
     if 'layout' in self.ai_data:
         with self.context.child("applying_autoinstall"):
             meth = getattr(
                 self, "guided_" + self.ai_data['layout']['name'])
             disks = self.model.all_disks()
             disks.sort(key=lambda x: x.size)
             meth(disks[-1])
Exemple #3
0
 async def _probe(self):
     with self.context.child("_probe") as context:
         async with self.app.install_lock_file.shared():
             self._crash_reports = {}
             if isinstance(self.ui.body, ProbingFailed):
                 self.ui.set_body(SlowProbing(self))
                 schedule_task(self._wait_for_probing())
             for (restricted, kind) in [
                 (False, ErrorReportKind.BLOCK_PROBE_FAIL),
                 (True, ErrorReportKind.DISK_PROBE_FAIL),
             ]:
                 try:
                     desc = "restricted={}".format(restricted)
                     with context.child("probe_once", desc):
                         await self._probe_once_task.start(restricted)
                         # We wait on the task directly here, not
                         # self._probe_once_task.wait as if _probe_once_task
                         # gets cancelled, we should be cancelled too.
                         await asyncio.wait_for(self._probe_once_task.task,
                                                15.0)
                 except asyncio.CancelledError:
                     # asyncio.CancelledError is a subclass of Exception in
                     # Python 3.6 (sadface)
                     raise
                 except Exception:
                     block_discover_log.exception(
                         "block probing failed restricted=%s", restricted)
                     report = self.app.make_apport_report(kind,
                                                          "block probing",
                                                          interrupt=False)
                     self._crash_reports[restricted] = report
                     continue
                 break
Exemple #4
0
 def start_ui(self):
     if self._probe_task.task is None or not self._probe_task.task.done():
         self.ui.set_body(SlowProbing(self))
         schedule_task(self._wait_for_probing())
     elif True in self._crash_reports:
         self.ui.set_body(ProbingFailed(self))
         self.ui.body.show_error()
     else:
         # Once we've shown the filesystem UI, we stop listening for udev
         # events as merging system changes with configuration the user has
         # performed would be tricky.  Possibly worth doing though! Just
         # not today.
         self.convert_autoinstall_config()
         self.stop_listening_udev()
         self.ui.set_body(GuidedDiskSelectionView(self))
         pr = self._crash_reports.get(False)
         if pr is not None:
             self.app.show_error_report(pr)
         if self.answers['guided']:
             disk = self.model.all_disks()[self.answers['guided-index']]
             method = self.answers.get('guided-method')
             self.ui.body.form.guided_choice.value = {
                 'disk': disk,
                 'use_lvm': method == "lvm",
             }
             self.ui.body.done(self.ui.body.form)
         elif self.answers['manual']:
             self.manual()
Exemple #5
0
 def wait_load(self):
     spinner = Spinner(self.controller.app.aio_loop, style='dots')
     spinner.start()
     self._w = screen(
         [spinner], [ok_btn(label=_("Continue"), on_press=self.done)],
         excerpt=_("Loading server snaps from store, please wait..."))
     schedule_task(self._wait_load(spinner))
Exemple #6
0
 def select_screen(self, new):
     if new.interactive():
         super().select_screen(new)
     elif self.autoinstall_config and not new.autoinstall_applied:
         schedule_task(self._apply(new))
     else:
         raise Skip
Exemple #7
0
    def load_info(self):
        t = self.parent.controller.get_snap_info_task(self.snap)

        if t.done():
            self.loaded()
            return
        fi = FetchingInfo(self.parent, self.snap,
                          self.parent.controller.app.aio_loop)
        self.parent.show_overlay(fi, width=fi.width)
        schedule_task(self.wait(t, fi))
Exemple #8
0
 def load(self, sender=None):
     t = self.controller.get_snap_list_task()
     if t.done():
         self.loaded()
         return
     spinner = Spinner(self.controller.app.aio_loop, style='dots')
     spinner.start()
     self._w = screen(
         [spinner], [ok_btn(label=_("Continue"), on_press=self.done)],
         excerpt=_("Loading server snaps from store, please wait..."))
     schedule_task(self._wait(t, spinner))
Exemple #9
0
 async def _start(self):
     with self.context:
         task = self.tasks[None] = schedule_task(self._load_list())
         await task
         self.pending_snaps = self.model.get_snap_list()
         log.debug("fetched list of %s snaps", len(self.pending_snaps))
         while self.pending_snaps:
             snap = self.pending_snaps.pop(0)
             task = self.tasks[snap] = schedule_task(
                 self._fetch_info_for_snap(snap=snap))
             await task
Exemple #10
0
 def scan_crash_dir(self):
     filenames = os.listdir(self.crash_directory)
     to_load = []
     for filename in sorted(filenames, reverse=True):
         base, ext = os.path.splitext(filename)
         if ext != ".crash":
             continue
         path = os.path.join(self.crash_directory, filename)
         r = ErrorReport.from_file(self, path)
         self.reports.append(r)
         to_load.append(r)
     schedule_task(self._load_reports(to_load))
Exemple #11
0
 def start(self):
     if self.ai_data is not None:
         self.model.override_config = {'network': self.ai_data}
         self.apply_config()
         if self.interactive():
             # If interactive, we want edits in the UI to override
             # the provided config. If not, we just splat the
             # autoinstall config onto the target system.
             schedule_task(self.unset_override_config())
     elif not self.interactive():
         self.initial_config = schedule_task(self.wait_for_initial_config())
     super().start()
Exemple #12
0
 def subiquity_event(self, event):
     if event["MESSAGE"] == "starting install":
         if event["_PID"] == os.getpid():
             return
         if not self.install_lock_file.is_exclusively_locked():
             return
         from subiquity.ui.views.installprogress import (
             InstallRunning, )
         tty = self.install_lock_file.read_content()
         install_running = InstallRunning(self.ui.body, self, tty)
         self.add_global_overlay(install_running)
         schedule_task(self._hide_install_running(install_running))
Exemple #13
0
 def start_ui(self):
     if self.install_state in [
             InstallState.NOT_STARTED,
             InstallState.RUNNING,
     ]:
         self.progress_view.title = _("Installing system")
     elif self.install_state == InstallState.DONE:
         self.progress_view.title = _("Install complete!")
     elif self.install_state == InstallState.ERROR:
         self.progress_view.title = (
             _('An error occurred during installation'))
     self.ui.set_body(self.progress_view)
     schedule_task(self.move_on())
Exemple #14
0
    def check_state_checking(self):
        self.spinner.start()

        rows = [self.spinner]

        buttons = [
            done_btn(_("Continue without updating"), on_press=self.done),
            other_btn(_("Back"), on_press=self.cancel),
        ]

        self.title = self.checking_title
        self.controller.ui.set_header(self.title)
        self._w = screen(rows, buttons, excerpt=_(self.checking_excerpt))
        schedule_task(self._wait_check_result())
Exemple #15
0
    def update(self, sender=None):
        self.spinner.stop()

        self.lb_tasks = ListBox([])
        self.task_to_bar = {}

        buttons = [
            other_btn(_("Cancel update"), on_press=self.check_state_available),
            ]

        self.controller.ui.set_header(_(self.progress_title))
        self._w = screen(
            self.lb_tasks, buttons, excerpt=_(self.progress_excerpt))
        schedule_task(self._update())
Exemple #16
0
 def load_reports(self):
     os.makedirs(self.crash_directory, exist_ok=True)
     filenames = os.listdir(self.crash_directory)
     to_load = []
     for filename in sorted(filenames, reverse=True):
         base, ext = os.path.splitext(filename)
         if ext != ".crash":
             continue
         if base not in self._reports_by_base:
             path = os.path.join(self.crash_directory, filename)
             r = ErrorReport.from_file(self, path)
             self.reports.append(r)
             self._reports_by_base[base] = r
             to_load.append(r)
     schedule_task(self._load_reports(to_load))
Exemple #17
0
    def __init__(self, opts, block_log_dir):
        if not opts.bootloader == 'none' and platform.machine() != 's390x':
            self.controllers.remove("Zdev")

        super().__init__(opts)
        self.block_log_dir = block_log_dir
        if opts.snaps_from_examples:
            connection = FakeSnapdConnection(
                os.path.join(os.path.dirname(os.path.dirname(__file__)),
                             "examples", "snaps"))
        else:
            connection = SnapdConnection(self.root, self.snapd_socket_path)
        self.snapd = AsyncSnapd(connection)
        self.signal.connect_signals([
            ('network-proxy-set', lambda: schedule_task(self._proxy_set())),
            ('network-change', self._network_change),
        ])
        self._apport_data = []
        self._apport_files = []

        self.autoinstall_config = {}
        self.merged_autoinstall_path = os.path.join(self.root,
                                                    'autoinstall.yaml')
        self.note_data_for_apport("SnapUpdated", str(self.updated))
        self.note_data_for_apport("UsingAnswers", str(bool(self.answers)))

        self.reboot_on_exit = False
Exemple #18
0
    def __init__(self, opts, block_log_dir):
        if not opts.bootloader == 'none' and platform.machine() != 's390x':
            self.controllers.remove("Zdev")

        self.journal_fd, self.journal_watcher = journald_listener(
            ["subiquity"], self.subiquity_event, seek=True)
        super().__init__(opts)
        self.event_listeners = []
        self.install_lock_file = Lockfile(self.state_path("installing"))
        self.global_overlays = []
        self.block_log_dir = block_log_dir
        self.kernel_cmdline = shlex.split(opts.kernel_cmdline)
        if opts.snaps_from_examples:
            connection = FakeSnapdConnection(
                os.path.join(os.path.dirname(os.path.dirname(__file__)),
                             "examples", "snaps"), self.scale_factor)
        else:
            connection = SnapdConnection(self.root, self.snapd_socket_path)
        self.snapd = AsyncSnapd(connection)
        self.signal.connect_signals([
            ('network-proxy-set', lambda: schedule_task(self._proxy_set())),
            ('network-change', self._network_change),
        ])
        self._apport_data = []
        self._apport_files = []

        self.autoinstall_config = {}
        self.report_to_show = None
        self.show_progress_handle = None
        self.progress_shown_time = self.aio_loop.time()
        self.progress_showing = False
        self.note_data_for_apport("SnapUpdated", str(self.updated))
        self.note_data_for_apport("UsingAnswers", str(bool(self.answers)))

        self.install_confirmed = False
Exemple #19
0
    def __init__(self, opts, block_log_dir):
        super().__init__(opts)
        self.block_log_dir = block_log_dir
        self.cloud_init_ok = None
        self._state = ApplicationState.STARTING_UP
        self.state_event = asyncio.Event()
        self.interactive = None
        self.confirming_tty = ''
        self.fatal_error = None
        self.running_error_commands = False

        self.echo_syslog_id = 'subiquity_echo.{}'.format(os.getpid())
        self.event_syslog_id = 'subiquity_event.{}'.format(os.getpid())
        self.log_syslog_id = 'subiquity_log.{}'.format(os.getpid())

        self.error_reporter = ErrorReporter(
            self.context.child("ErrorReporter"), self.opts.dry_run, self.root)
        self.prober = Prober(opts.machine_config, self.debug_flags)
        self.kernel_cmdline = shlex.split(opts.kernel_cmdline)
        if opts.snaps_from_examples:
            connection = FakeSnapdConnection(
                os.path.join(
                    os.path.dirname(os.path.dirname(
                        os.path.dirname(__file__))), "examples", "snaps"),
                self.scale_factor)
        else:
            connection = SnapdConnection(self.root, self.snapd_socket_path)
        self.snapd = AsyncSnapd(connection)
        self.note_data_for_apport("SnapUpdated", str(self.updated))
        self.event_listeners = []
        self.autoinstall_config = None
        self.signal.connect_signals([
            ('network-proxy-set', lambda: schedule_task(self._proxy_set())),
            ('network-change', self._network_change),
        ])
Exemple #20
0
 def start(self):
     if self.model.bootloader == Bootloader.PREP:
         self.supports_resilient_boot = False
     else:
         release = lsb_release()['release']
         self.supports_resilient_boot = release >= '20.04'
     self._start_task = schedule_task(self._start())
Exemple #21
0
 def start(self):
     if not self.active:
         return
     self.configure_task = schedule_task(self.configure_snapd())
     self.check_task = SingleInstanceTask(self.check_for_update,
                                          propagate_errors=False)
     self.check_task.start_sync()
Exemple #22
0
 def get_snap_info_task(self, snap):
     if snap not in self.tasks:
         if snap in self.pending_snaps:
             self.pending_snaps.remove(snap)
         self.tasks[snap] = schedule_task(
             self._fetch_info_for_snap(snap=snap))
     return self.tasks[snap]
Exemple #23
0
    def add_info(self, _bg_attach_hook, wait=False):
        def _bg_add_info():
            _bg_attach_hook()
            # Add basic info to report.
            self.pr.add_proc_info()
            self.pr.add_os_info()
            self.pr.add_hooks_info(None)
            apport.hookutils.attach_hardware(self.pr)
            # Because apport-cli will in general be run on a different
            # machine, we make some slightly obscure alterations to the report
            # to make this go better.

            # apport-cli gets upset if neither of these are present.
            self.pr['Package'] = 'subiquity ' + os.environ.get(
                "SNAP_REVISION", "SNAP_REVISION")
            self.pr['SourcePackage'] = 'subiquity'

            # If ExecutableTimestamp is present, apport-cli will try to check
            # that ExecutablePath hasn't changed. But it won't be there.
            del self.pr['ExecutableTimestamp']
            # apport-cli gets upset at the probert C extensions it sees in
            # here.  /proc/maps is very unlikely to be interesting for us
            # anyway.
            del self.pr['ProcMaps']
            self.pr.write(self._file)

        async def add_info():
            with self._context.child("add_info") as context:
                try:
                    await run_in_thread(_bg_add_info)
                except Exception:
                    self.state = ErrorReportState.ERROR_GENERATING
                    log.exception("adding info to problem report failed")
                else:
                    context.description = "written to " + self.path
                    self.state = ErrorReportState.DONE
                self._file.close()
                self._file = None
                urwid.emit_signal(self, "changed")

        if wait:
            with self._context.child("add_info") as context:
                _bg_add_info()
                context.description = "written to " + self.path
        else:
            schedule_task(add_info())
Exemple #24
0
    def run_command_in_foreground(self,
                                  cmd,
                                  before_hook=None,
                                  after_hook=None,
                                  **kw):
        if self.fg_proc is not None:
            raise Exception("cannot run two fg processes at once")
        screen = self.urwid_loop.screen

        async def _run():
            self.fg_proc = proc = await astart_command(cmd,
                                                       stdin=None,
                                                       stdout=None,
                                                       stderr=None,
                                                       **kw)
            await proc.communicate()
            self.fg_proc = None
            # One of the main use cases for this function is to run interactive
            # bash in a subshell. Interactive bash of course creates a process
            # group for itself and sets it as the foreground process group for
            # the controlling terminal. Usually on exit, our process group
            # becomes the foreground process group again but when the subshell
            # is killed for some reason it does not. This causes the tcsetattr
            # that screen.start() does to either cause SIGTTOU to be sent, or
            # if that is ignored (either because there is no shell around to do
            # job control things or we are ignoring it) fail with EIO. So we
            # force our process group back into the foreground with this
            # call. That's not quite enough though because tcsetpgrp *also*
            # causes SIGTTOU to be sent to a background process that calls it,
            # but fortunately if we ignore that (done in start_urwid below),
            # the call still succeeds.
            #
            # I would now like a drink.
            os.tcsetpgrp(0, os.getpgrp())
            screen.start()
            if after_hook is not None:
                after_hook()

        screen.stop()
        urwid.emit_signal(screen,
                          urwid.display_common.INPUT_DESCRIPTORS_CHANGED)
        if before_hook is not None:
            before_hook()
        schedule_task(_run())
Exemple #25
0
    def run_command_in_foreground(self,
                                  cmd,
                                  before_hook=None,
                                  after_hook=None,
                                  **kw):
        screen = self.urwid_loop.screen

        async def _run():
            await arun_command(cmd, stdin=None, stdout=None, stderr=None, **kw)
            screen.start()
            if after_hook is not None:
                after_hook()

        screen.stop()
        urwid.emit_signal(screen,
                          urwid.display_common.INPUT_DESCRIPTORS_CHANGED)
        if before_hook is not None:
            before_hook()
        schedule_task(_run())
Exemple #26
0
 def select_screen(self, new):
     if new.interactive():
         self._cancel_show_progress()
         if self.progress_showing:
             shown_for = self.aio_loop.time() - self.progress_shown_time
             remaining = 1.0 - shown_for
             if remaining > 0.0:
                 self.aio_loop.call_later(remaining, self.select_screen,
                                          new)
                 return
         self.progress_showing = False
         super().select_screen(new)
     elif self.autoinstall_config and not new.autoinstall_applied:
         if self.interactive() and self.show_progress_handle is None:
             self.ui.block_input = True
             self.show_progress_handle = self.aio_loop.call_later(
                 0.1, self._show_progress)
         schedule_task(self._apply(new))
     else:
         new.configured()
         raise Skip
Exemple #27
0
 def make_ui(self):
     if self._probe_task.task is None or not self._probe_task.task.done():
         schedule_task(self._wait_for_probing())
         return SlowProbing(self)
     elif True in self._crash_reports:
         pr = self._crash_reports[True]
         if pr is not None:
             self.app.show_error_report(pr.ref())
         return ProbingFailed(self)
     else:
         # Once we've shown the filesystem UI, we stop listening for udev
         # events as merging system changes with configuration the user has
         # performed would be tricky.  Possibly worth doing though! Just
         # not today.
         self.convert_autoinstall_config()
         self.stop_listening_udev()
         pr = self._crash_reports.get(False)
         if pr is not None:
             self.app.show_error_report(pr.ref())
         if self.answers:
             self.app.aio_loop.call_soon(self._start_answers)
         return GuidedDiskSelectionView(self)
Exemple #28
0
    def run_command_in_foreground(self,
                                  cmd,
                                  before_hook=None,
                                  after_hook=None,
                                  **kw):
        screen = self.urwid_loop.screen

        # Calling screen.stop() sends the INPUT_DESCRIPTORS_CHANGED
        # signal. This calls _reset_input_descriptors() which calls
        # unhook_event_loop / hook_event_loop on the screen. But this all
        # happens before _started is set to False on the screen and so this
        # does not actually do anything -- we end up attempting to read from
        # stdin while in a background process group, something that gets the
        # kernel upset at us.
        #
        # The cleanest fix seems to be to just send the signal again once
        # stop() has returned which, now that screen._started is False,
        # correctly stops listening from stdin.
        #
        # There is an exactly analagous problem with screen.start() except
        # there the symptom is that we are running in the foreground but not
        # listening to stdin! The fix is the same.
        async def _run():
            await arun_command(cmd, stdin=None, stdout=None, stderr=None, **kw)
            screen.start()
            urwid.emit_signal(screen,
                              urwid.display_common.INPUT_DESCRIPTORS_CHANGED)
            self.setraw()
            if after_hook is not None:
                after_hook()

        screen.stop()
        urwid.emit_signal(screen,
                          urwid.display_common.INPUT_DESCRIPTORS_CHANGED)
        if before_hook is not None:
            before_hook()
        schedule_task(_run())
Exemple #29
0
    def __init__(self, opts, block_log_dir):
        if is_linux_tty():
            self.input_filter = KeyCodesFilter()
        else:
            self.input_filter = DummyKeycodesFilter()

        self.help_menu = HelpMenu(self)
        super().__init__(opts)

        self.event_syslog_id = 'subiquity_event.{}'.format(os.getpid())
        self.log_syslog_id = 'subiquity_log.{}'.format(os.getpid())

        self.server_updated = None
        self.restarting_server = False
        self.prober = Prober(opts.machine_config, self.debug_flags)
        journald_listen(self.aio_loop, ["subiquity"],
                        self.subiquity_event,
                        seek=True)
        self.event_listeners = []
        self.install_lock_file = Lockfile(self.state_path("installing"))
        self.global_overlays = []
        self.block_log_dir = block_log_dir
        self.kernel_cmdline = shlex.split(opts.kernel_cmdline)
        if opts.snaps_from_examples:
            connection = FakeSnapdConnection(
                os.path.join(os.path.dirname(os.path.dirname(__file__)),
                             "examples", "snaps"), self.scale_factor)
        else:
            connection = SnapdConnection(self.root, self.snapd_socket_path)
        self.snapd = AsyncSnapd(connection)
        self.signal.connect_signals([
            ('network-proxy-set', lambda: schedule_task(self._proxy_set())),
            ('network-change', self._network_change),
        ])

        self.conn = aiohttp.UnixConnector(self.opts.socket)
        self.client = make_client_for_conn(API, self.conn, self.resp_hook)

        self.autoinstall_config = {}
        self.error_reporter = ErrorReporter(
            self.context.child("ErrorReporter"), self.opts.dry_run, self.root,
            self.client)

        self.note_data_for_apport("SnapUpdated", str(self.updated))
        self.note_data_for_apport("UsingAnswers", str(bool(self.answers)))
Exemple #30
0
 def fetch_ssh_keys(self, ssh_import_id, ssh_data):
     self._fetch_task = schedule_task(
         self._fetch_ssh_keys(ssh_import_id=ssh_import_id,
                              ssh_data=ssh_data))