Merge pull request #45 from CanonicalLtd/patch-queue-async

Add progress show final bits
This commit is contained in:
Adam Stokes 2015-09-25 16:08:12 -04:00
commit 3bb2a79c2e
7 changed files with 101 additions and 82 deletions

View File

@ -65,8 +65,6 @@ class FilesystemController(ControllerPolicy):
log.info("Rendering preserved config for post install")
preserved_actions = [preserve_action(a) for a in actions]
curtin_write_preserved_actions(actions=preserved_actions)
self.signal.emit_signal('installprogress:do-initial-install')
self.signal.emit_signal('identity:show')
# Filesystem/Disk partition -----------------------------------------------

View File

@ -17,9 +17,10 @@ import logging
from tornado.gen import coroutine
import subiquity.utils as utils
from subiquity.models import InstallProgressModel
from subiquity.ui.views import ProgressView, ProgressOutput
from subiquity.ui.views import ProgressView
from subiquity.controller import ControllerPolicy
from subiquity.curtin import (CURTIN_CONFIGS,
curtin_reboot,
curtin_install_cmd,
curtin_write_postinst_config)
@ -27,65 +28,75 @@ log = logging.getLogger("subiquity.controller.installprogress")
class InstallProgressController(ControllerPolicy):
KIRBY = ["(>'-')>",
"<('-'<)",
"<('-')>",
"(>'-')>",
"<('-'<)",
"<('-')>",
"(>'-')>",
"<('-'<)",
"<('-')>",
"(>'-')>",
"<('-'<)"]
def __init__(self, common):
super().__init__(common)
self.model = InstallProgressModel()
self.progress_output_w = ProgressOutput(self.signal, "Waiting...")
def install_progress_status(self, data):
self.progress_output_w.set_text(data)
self.signal.emit_signal('refresh')
self.progress_view = None
self.is_complete = False
self.alarm = None
self.kirby_pos = 0
@coroutine
def curtin_dispatch(self, postconfig):
''' one time curtin dispatch requires the use of
the preserved storage config which allows executing
in-target commands by remounting up the configured
storage.
'''
write_fd = self.loop.watch_pipe(self.install_progress_status)
def curtin_install(self, postconfig):
self.signal.emit_signal('installprogress:show')
log.debug('Curtin Install: calling curtin with '
'storage/net/postinstall config')
log.debug('writing out postinst config')
curtin_write_postinst_config(postconfig)
configs = [CURTIN_CONFIGS['preserved'], CURTIN_CONFIGS['postinstall']]
curtin_cmd = curtin_install_cmd(configs)
log.debug('Curtin postinstall install cmd: {}'.format(curtin_cmd))
if self.opts.dry_run:
log.debug("Install Progress: Curtin dispatch dry-run")
result = yield utils.run_command_async('cat /var/log/syslog',
write_fd)
else:
try:
result = yield utils.run_command_async(" ".join(curtin_cmd),
write_fd)
except:
log.error("Problem with curtin dispatch run")
raise Exception("Problem with curtin dispatch run")
return result
@coroutine
def initial_install(self):
log.debug('Initial Install: calling curtin with storage/net config')
write_fd = self.loop.watch_pipe(self.install_progress_status)
configs = [CURTIN_CONFIGS['network'], CURTIN_CONFIGS['storage']]
configs = [CURTIN_CONFIGS['network'],
CURTIN_CONFIGS['storage'],
CURTIN_CONFIGS['postinstall']]
curtin_cmd = curtin_install_cmd(configs)
log.debug('Curtin install cmd: {}'.format(curtin_cmd))
if self.opts.dry_run:
log.debug("Filesystem: this is a dry-run")
result = yield utils.run_command_async('cat /var/log/syslog',
write_fd)
result = yield utils.run_command_async('cat /var/log/syslog')
self.is_complete = True
else:
log.debug("filesystem: this is the *real* thing")
result = yield utils.run_command_async(" ".join(curtin_cmd))
if result['status'] > 0:
log.error("Problem with curtin "
"install: {}".format(result))
raise Exception("Problem with curtin install")
self.is_complete = True
def progress_indicator(self, *args, **kwargs):
if self.is_complete:
self.progress_view.text.set_text(
"Finished install!")
self.ui.set_footer("", 100)
self.progress_view.show_finished_button()
self.loop.remove_alarm(self.alarm)
else:
try:
log.debug("filesystem: this is the *real* thing")
result = yield utils.run_command_async(" ".join(curtin_cmd),
write_fd)
except:
log.error("Problem with initial curtin install")
raise Exception("Problem with initial curtin install")
return result
cur_kirby = self.KIRBY[self.kirby_pos]
except IndexError:
self.kirby_pos = 0
cur_kirby = self.KIRBY[self.kirby_pos]
self.progress_view.text.set_text(
"Still installing, watch kirby dance, {}".format(
cur_kirby))
self.alarm = self.loop.set_alarm_in(0.3, self.progress_indicator)
self.kirby_pos += 1
def reboot(self):
curtin_reboot()
@coroutine
def show_progress(self):
@ -96,7 +107,8 @@ class InstallProgressController(ControllerPolicy):
footer = ("Thank you for using Ubuntu!")
self.ui.set_header(title, excerpt)
self.ui.set_footer(footer, 90)
self.ui.set_body(ProgressView(self.signal, self.progress_output_w))
self.progress_view = ProgressView(self.signal)
self.ui.set_body(self.progress_view)
if self.opts.dry_run:
banner = [
@ -107,5 +119,8 @@ class InstallProgressController(ControllerPolicy):
"",
"Press (Q) to Quit."
]
self.install_progress_status("\n".join(banner))
self.ui.set_footer(footer, 100)
self.progress_view.text.set_text("\n".join(banner))
else:
self.alarm = self.loop.set_alarm_in(0.3, self.progress_indicator)
self.ui.set_footer(footer, 90)

View File

@ -28,15 +28,15 @@ class InstallProgressModel(ModelPolicy):
prev_signal = None
signals = [
("Initial install routine",
'installprogress:do-initial-install',
'initial_install'),
("Run once curtin commands",
'installprogress:curtin-dispatch',
'curtin_dispatch'),
("Run curtin",
'installprogress:curtin-install',
'curtin_install'),
("Install progress final view",
'installprogress:show',
'show_progress')
'show_progress'),
("Reboot curtin",
"installprogress:curtin-reboot",
"reboot")
]
installprogress_menu = []

View File

@ -22,6 +22,6 @@ from .ceph import CephDiskView # NOQA
from .iscsi import IscsiDiskView # NOQA
from .network import NetworkView # NOQA
from .installpath import InstallpathView # NOQA
from .installprogress import ProgressOutput, ProgressView # NOQA
from .installprogress import ProgressView # NOQA
from .welcome import WelcomeView # NOQA
from .identity import IdentityView # NOQA

View File

@ -108,8 +108,7 @@ class IdentityView(ViewPolicy):
}
log.debug("User input: {}".format(result))
self.signal.emit_signal('installprogress:curtin-dispatch', result)
self.signal.emit_signal('installprogress:show')
self.signal.emit_signal('installprogress:curtin-install', result)
def cancel(self, button):
self.signal.emit_signal("quit")

View File

@ -15,32 +15,40 @@
import logging
from urwid import (Text, Filler,
ListBox, BoxAdapter)
Pile)
from subiquity.view import ViewPolicy
from subiquity.ui.utils import Color, Padding
from subiquity.ui.buttons import confirm_btn
from subiquity.ui.utils import Padding, Color
log = logging.getLogger("subiquity.ui.views.installprogress")
class ProgressOutput(ViewPolicy):
def __init__(self, signal, txt):
self.signal = signal
self.txt = Text(txt)
flr = Filler(Color.info_minor(self.txt),
valign="top")
super().__init__(BoxAdapter(flr, height=20))
def set_text(self, data):
self.txt.set_text(data)
class ProgressView(ViewPolicy):
def __init__(self, signal, output_w):
def __init__(self, signal):
"""
:param output_w: Filler widget to display updated status text
"""
self.signal = signal
self.text = Text("Wait for it ...", align="center")
self.body = [
Padding.center_79(output_w)
Padding.center_79(self.text)
]
super().__init__(ListBox(self.body))
self.pile = Pile(self.body)
super().__init__(Filler(self.pile, valign="middle"))
def show_finished_button(self):
w = Padding.center_20(
Color.button(confirm_btn(label="Reboot now",
on_press=self.reboot),
focus_map='button focus'))
self.pile.contents.append((w, self.pile.options()))
self.pile.focus_position = 1
def keypress(self, size, key):
super().keypress(size, key)
if key in ['q', 'Q']:
self.signal.emit_signal('installprogress:curtin-reboot')
def reboot(self, btn):
self.signal.emit_signal('installprogress:curtin-reboot')

View File

@ -25,15 +25,14 @@ log = logging.getLogger("subiquity.utils")
SYS_CLASS_NET = "/sys/class/net/"
def run_command_async(cmd, write_fd, timeout=None):
def run_command_async(cmd, timeout=None):
log.debug('calling Async command: {}'.format(cmd))
return Async.pool.submit(run_command, cmd, write_fd, timeout)
return Async.pool.submit(run_command, cmd, timeout)
def run_command(command, write_fd, timeout=None):
def run_command(command, timeout=None):
""" Execute command through system shell
:param command: command to run
:param write_fd: writable_fd for output updates
:param timeout: (optional) use 'timeout' to limit time. default 300
:type command: str
:returns: {status: returncode, output: stdout, err: stderr}
@ -52,7 +51,7 @@ def run_command(command, write_fd, timeout=None):
try:
log.debug('trying Popen...')
p = Popen(command, shell=True,
stdout=write_fd, stderr=PIPE,
stdout=PIPE, stderr=PIPE,
bufsize=-1, env=cmd_env, close_fds=True)
except OSError as e:
if e.errno == errno.ENOENT: