feed progress view via journal
this means curtin events go through the journal twice, but that has to happen when client and server get split
This commit is contained in:
parent
780cfe1e7c
commit
4364a7ad1a
|
@ -78,7 +78,6 @@ class InstallProgressController(SubiquityTuiController):
|
|||
super().__init__(app)
|
||||
self.model = app.base_model
|
||||
self.progress_view = ProgressView(self)
|
||||
app.add_event_listener(self)
|
||||
self.crash_report_ref = None
|
||||
self._install_state = InstallState.NOT_STARTED
|
||||
|
||||
|
@ -88,11 +87,24 @@ class InstallProgressController(SubiquityTuiController):
|
|||
|
||||
self.unattended_upgrades_proc = None
|
||||
self.unattended_upgrades_ctx = None
|
||||
self._event_syslog_identifier = 'curtin_event.%s' % (os.getpid(),)
|
||||
self._log_syslog_identifier = 'curtin_log.%s' % (os.getpid(),)
|
||||
self._event_syslog_id = 'curtin_event.%s' % (os.getpid(),)
|
||||
self.tb_extractor = TracebackExtractor()
|
||||
self.curtin_event_contexts = {}
|
||||
|
||||
def event(self, event):
|
||||
if event["SUBIQUITY_EVENT_TYPE"] == "start":
|
||||
self.progress_view.event_start(
|
||||
event["SUBIQUITY_CONTEXT_ID"],
|
||||
event.get("SUBIQUITY_CONTEXT_PARENT_ID"),
|
||||
event["MESSAGE"])
|
||||
elif event["SUBIQUITY_EVENT_TYPE"] == "finish":
|
||||
self.progress_view.event_finish(
|
||||
event["SUBIQUITY_CONTEXT_ID"])
|
||||
|
||||
def log_line(self, event):
|
||||
log_line = event['MESSAGE']
|
||||
self.progress_view.add_log_line(log_line)
|
||||
|
||||
def interactive(self):
|
||||
return self.app.interactive()
|
||||
|
||||
|
@ -112,36 +124,6 @@ class InstallProgressController(SubiquityTuiController):
|
|||
self._install_state = state
|
||||
self.progress_view.update_for_state(state)
|
||||
|
||||
def _push_to_progress(self, context):
|
||||
if not self.app.interactive():
|
||||
return False
|
||||
if context.get('hidden', False):
|
||||
return False
|
||||
controller = context.get('controller')
|
||||
if controller is None or controller.interactive():
|
||||
return False
|
||||
return True
|
||||
|
||||
def report_start_event(self, context, description):
|
||||
if self._push_to_progress(context):
|
||||
msg = context.full_name()
|
||||
if description:
|
||||
msg += ': ' + description
|
||||
if context.get('is-install-context'):
|
||||
indent = context.full_name().count('/') - 2
|
||||
if context.get('is-install-context'):
|
||||
indent -= 1
|
||||
msg = ' ' * indent + context.description
|
||||
else:
|
||||
return
|
||||
parent_id = None
|
||||
if context.parent:
|
||||
parent_id = context.parent.id
|
||||
self.progress_view.event_start(context.id, parent_id, msg)
|
||||
|
||||
def report_finish_event(self, context, description, status):
|
||||
self.progress_view.event_finish(context.id)
|
||||
|
||||
def tpath(self, *path):
|
||||
return os.path.join(self.model.target, *path)
|
||||
|
||||
|
@ -169,13 +151,10 @@ class InstallProgressController(SubiquityTuiController):
|
|||
|
||||
def logged_command(self, cmd):
|
||||
return ['systemd-cat', '--level-prefix=false',
|
||||
'--identifier=' + self._log_syslog_identifier] + cmd
|
||||
'--identifier=' + self.app.log_syslog_id] + cmd
|
||||
|
||||
def _journal_event(self, event):
|
||||
if event['SYSLOG_IDENTIFIER'] == self._event_syslog_identifier:
|
||||
self.curtin_event(event)
|
||||
elif event['SYSLOG_IDENTIFIER'] == self._log_syslog_identifier:
|
||||
self.curtin_log(event)
|
||||
def log_event(self, event):
|
||||
self.curtin_log(event)
|
||||
|
||||
def curtin_event(self, event):
|
||||
e = {
|
||||
|
@ -208,12 +187,10 @@ class InstallProgressController(SubiquityTuiController):
|
|||
status = getattr(Status, e["RESULT"], Status.WARN)
|
||||
curtin_ctx = self.curtin_event_contexts.pop(e["NAME"], None)
|
||||
if curtin_ctx is not None:
|
||||
curtin_ctx.exit(status)
|
||||
curtin_ctx.exit(result=status)
|
||||
|
||||
def curtin_log(self, event):
|
||||
log_line = event['MESSAGE']
|
||||
self.progress_view.add_log_line(log_line)
|
||||
self.tb_extractor.feed(log_line)
|
||||
self.tb_extractor.feed(event['MESSAGE'])
|
||||
|
||||
def _write_config(self, path, config):
|
||||
with open(path, 'w') as conf:
|
||||
|
@ -233,7 +210,7 @@ class InstallProgressController(SubiquityTuiController):
|
|||
event_file = "examples/curtin-events-fail.json"
|
||||
curtin_cmd = [
|
||||
"python3", "scripts/replay-curtin-log.py", event_file,
|
||||
self._event_syslog_identifier, log_location,
|
||||
self._event_syslog_id, log_location,
|
||||
]
|
||||
else:
|
||||
config_location = os.path.join('/var/log/installer',
|
||||
|
@ -242,9 +219,9 @@ class InstallProgressController(SubiquityTuiController):
|
|||
config_location, 'install']
|
||||
log_location = INSTALL_LOG
|
||||
|
||||
ident = self._event_syslog_identifier
|
||||
self._write_config(config_location,
|
||||
self.model.render(syslog_identifier=ident))
|
||||
self._write_config(
|
||||
config_location,
|
||||
self.model.render(syslog_identifier=self._event_syslog_id))
|
||||
|
||||
self.app.note_file_for_apport("CurtinConfig", config_location)
|
||||
self.app.note_file_for_apport("CurtinLog", log_location)
|
||||
|
@ -270,10 +247,12 @@ class InstallProgressController(SubiquityTuiController):
|
|||
log.debug('curtin_install')
|
||||
self.curtin_event_contexts[''] = context
|
||||
|
||||
journald_listen(
|
||||
self.app.aio_loop,
|
||||
[self._event_syslog_identifier, self._log_syslog_identifier],
|
||||
self._journal_event)
|
||||
loop = self.app.aio_loop
|
||||
|
||||
fds = [
|
||||
journald_listen(loop, [self.app.log_syslog_id], self.curtin_log),
|
||||
journald_listen(loop, [self._event_syslog_id], self.curtin_event),
|
||||
]
|
||||
|
||||
curtin_cmd = self._get_curtin_command()
|
||||
|
||||
|
@ -287,8 +266,12 @@ class InstallProgressController(SubiquityTuiController):
|
|||
our_tty = "/dev/not a tty"
|
||||
self.app.install_lock_file.write_content(our_tty)
|
||||
journal.send("starting install", SYSLOG_IDENTIFIER="subiquity")
|
||||
cp = await arun_command(
|
||||
self.logged_command(curtin_cmd), check=True)
|
||||
try:
|
||||
cp = await arun_command(
|
||||
self.logged_command(curtin_cmd), check=True)
|
||||
finally:
|
||||
for fd in fds:
|
||||
loop.remove_reader(fd)
|
||||
|
||||
log.debug('curtin_install completed: %s', cp.returncode)
|
||||
|
||||
|
|
|
@ -43,7 +43,6 @@ available_handlers.unregister_item('log')
|
|||
available_handlers.register_item('log', LogHandler)
|
||||
|
||||
INITIAL_CONFIG = {'logging': {'type': 'log'}}
|
||||
NON_INTERACTIVE_CONFIG = {'builtin': {'type': 'print'}}
|
||||
|
||||
|
||||
class ReportingController(SubiquityController):
|
||||
|
@ -69,7 +68,6 @@ class ReportingController(SubiquityController):
|
|||
def load_autoinstall_data(self, data):
|
||||
if self.app.interactive():
|
||||
return
|
||||
self.config.update(copy.deepcopy(NON_INTERACTIVE_CONFIG))
|
||||
if data is not None:
|
||||
self.config.update(copy.deepcopy(data))
|
||||
|
||||
|
|
|
@ -25,6 +25,8 @@ import aiohttp
|
|||
|
||||
import jsonschema
|
||||
|
||||
from systemd import journal
|
||||
|
||||
import yaml
|
||||
|
||||
from subiquitycore.async_helpers import (
|
||||
|
@ -146,6 +148,10 @@ class Subiquity(TuiApplication):
|
|||
|
||||
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)
|
||||
|
@ -314,6 +320,15 @@ class Subiquity(TuiApplication):
|
|||
raise Abort(report.ref())
|
||||
return response
|
||||
|
||||
def subiquity_event_noninteractive(self, event):
|
||||
if event['SUBIQUITY_EVENT_TYPE'] == 'start':
|
||||
print('start: ' + event["MESSAGE"])
|
||||
elif event['SUBIQUITY_EVENT_TYPE'] == 'finish':
|
||||
print('finish: ' + event["MESSAGE"])
|
||||
context_name = event.get('SUBIQUITY_CONTEXT_NAME', '')
|
||||
if context_name == 'subiquity/Reboot/reboot':
|
||||
self.exit()
|
||||
|
||||
async def connect(self):
|
||||
print("connecting...", end='', flush=True)
|
||||
while True:
|
||||
|
@ -338,8 +353,25 @@ class Subiquity(TuiApplication):
|
|||
await self.load_autoinstall_config()
|
||||
if not self.interactive() and not self.opts.dry_run:
|
||||
open('/run/casper-no-prompt', 'w').close()
|
||||
await super().start(start_urwid=self.interactive())
|
||||
if not self.interactive():
|
||||
interactive = self.interactive()
|
||||
if interactive:
|
||||
journald_listen(
|
||||
self.aio_loop,
|
||||
[self.event_syslog_id],
|
||||
self.controllers.InstallProgress.event)
|
||||
journald_listen(
|
||||
self.aio_loop,
|
||||
[self.log_syslog_id],
|
||||
self.controllers.InstallProgress.log_line)
|
||||
else:
|
||||
journald_listen(
|
||||
self.aio_loop,
|
||||
[self.event_syslog_id],
|
||||
self.subiquity_event_noninteractive,
|
||||
seek=True)
|
||||
await asyncio.sleep(1)
|
||||
await super().start(start_urwid=interactive)
|
||||
if not interactive:
|
||||
self.select_initial_screen()
|
||||
|
||||
def _exception_handler(self, loop, context):
|
||||
|
@ -402,10 +434,41 @@ class Subiquity(TuiApplication):
|
|||
def report_start_event(self, context, description):
|
||||
for listener in self.event_listeners:
|
||||
listener.report_start_event(context, description)
|
||||
self._maybe_push_to_journal('start', context, description)
|
||||
|
||||
def report_finish_event(self, context, description, status):
|
||||
for listener in self.event_listeners:
|
||||
listener.report_finish_event(context, description, status)
|
||||
self._maybe_push_to_journal('finish', context, description)
|
||||
|
||||
def _maybe_push_to_journal(self, event_type, context, description):
|
||||
if not context.get('is-install-context') and self.interactive():
|
||||
controller = context.get('controller')
|
||||
if controller is None or controller.interactive():
|
||||
return
|
||||
if context.get('request'):
|
||||
return
|
||||
indent = context.full_name().count('/') - 2
|
||||
if context.get('is-install-context') and self.interactive():
|
||||
indent -= 1
|
||||
msg = context.description
|
||||
else:
|
||||
msg = context.full_name()
|
||||
if description:
|
||||
msg += ': ' + description
|
||||
msg = ' ' * indent + msg
|
||||
if context.parent:
|
||||
parent_id = str(context.parent.id)
|
||||
else:
|
||||
parent_id = ''
|
||||
journal.send(
|
||||
msg,
|
||||
PRIORITY=context.level,
|
||||
SYSLOG_IDENTIFIER=self.event_syslog_id,
|
||||
SUBIQUITY_CONTEXT_NAME=context.full_name(),
|
||||
SUBIQUITY_EVENT_TYPE=event_type,
|
||||
SUBIQUITY_CONTEXT_ID=str(context.id),
|
||||
SUBIQUITY_CONTEXT_PARENT_ID=parent_id)
|
||||
|
||||
async def confirm_install(self):
|
||||
self.base_model.confirm()
|
||||
|
|
|
@ -32,3 +32,4 @@ def journald_listen(loop, identifiers, callback, seek=False):
|
|||
for event in reader:
|
||||
callback(event)
|
||||
loop.add_reader(reader.fileno(), watch)
|
||||
return reader.fileno()
|
||||
|
|
Loading…
Reference in New Issue