Merge branch 'master' into mwhudson/curtin-logging

This commit is contained in:
Michael Hudson-Doyle 2017-04-06 12:44:57 +12:00
commit d27367465f
23 changed files with 118 additions and 106 deletions

View File

@ -89,6 +89,8 @@ The {keytype} host key fingerprints is:
def host_key_info():
fingerprints = host_key_fingerprints()
if len(fingerprints) == 0:
return []
if len(fingerprints) == 1:
[(keytype, fingerprint)] = fingerprints
return single_host_key_tmpl.format(keytype=keytype, fingerprint=fingerprint)

View File

@ -100,7 +100,7 @@ class IdentityView(BaseView):
]
return Pile(buttons)
def cancel(self, button):
def cancel(self, button=None):
self.controller.cancel()
def done(self, button):

41
snapcraft.yaml Normal file
View File

@ -0,0 +1,41 @@
name: subiquity
version: "0.0.35"
summary: Ubuntu installer
description: The Ubuntu server installer
confinement: classic
apps:
subiquity:
command: usr/bin/subiquity
console-conf:
command: usr/bin/console-conf
probert:
command: bin/probert
parts:
subiquity:
plugin: python
build-packages: [python-setuptools]
stage-packages: [curtin]
python-packages:
- urwid
- pyyaml
- pyudev
- attrs
source: https://github.com/CanonicalLtd/subiquity.git
source-branch: cyphermox/snap
source-type: git
wrappers:
plugin: dump
source: https://github.com/CanonicalLtd/subiquity.git
source-type: git
organize:
'bin/console-conf-tui': usr/bin/console-conf
'bin/subiquity-tui': usr/bin/subiquity
snap:
- usr/bin
probert:
plugin: python
build-packages: [python-setuptools, libnl-3-dev, libnl-genl-3-dev, libnl-route-3-dev]
source: https://github.com/CanonicalLtd/probert.git
source-type: git

View File

@ -16,7 +16,7 @@
import logging
import os
from subiquitycore.controller import BaseController, view
from subiquitycore.controller import BaseController
from subiquitycore.ui.dummy import DummyView
from subiquitycore.ui.error import ErrorView
@ -48,7 +48,6 @@ class FilesystemController(BaseController):
self.raid_model = RaidModel()
self.model.probe() # probe before we complete
@view
def default(self, reset=False):
# FIXME: Is this the best way to zero out this list for a reset?
if reset:
@ -64,7 +63,6 @@ class FilesystemController(BaseController):
def reset(self):
log.info("Resetting Filesystem model")
self.model.reset()
self.view_stack = []
self.default()
def cancel(self):
@ -113,7 +111,6 @@ class FilesystemController(BaseController):
self.signal.emit_signal('next-screen')
# Filesystem/Disk partition -----------------------------------------------
@view
def partition_disk(self, disk):
log.debug("In disk partition view, using {} as the disk.".format(disk.path))
title = ("Partition, format, and mount {}".format(disk.path))
@ -125,7 +122,6 @@ class FilesystemController(BaseController):
self.ui.set_body(dp_view)
@view
def add_disk_partition(self, disk):
log.debug("Adding partition to {}".format(disk))
footer = ("Select whole disk, or partition, to format and mount.")
@ -166,9 +162,9 @@ class FilesystemController(BaseController):
self.model.add_mount(fs, spec['mountpoint'])
log.info("Successfully added partition")
self.prev_view()
self.partition_disk(disk)
def add_format_handler(self, volume, spec):
def add_format_handler(self, volume, spec, back):
log.debug('add_format_handler')
if spec['fstype'] is not None:
fs = self.model.add_filesystem(volume, spec['fstype'])
@ -178,7 +174,7 @@ class FilesystemController(BaseController):
if fs is None:
raise Exception("{} is not formatted".format(volume.path))
self.model.add_mount(fs, spec['mountpoint'])
self.prev_view()
back()
def connect_iscsi_disk(self, *args, **kwargs):
# title = ("Disk and filesystem setup")
@ -199,7 +195,6 @@ class FilesystemController(BaseController):
# self.signal))
self.ui.set_body(DummyView(self.signal))
@view
def create_volume_group(self, *args, **kwargs):
title = ("Create Logical Volume Group (\"LVM2\") disk")
footer = ("ENTER on a disk will show detailed "
@ -210,7 +205,6 @@ class FilesystemController(BaseController):
self.ui.set_footer(footer)
self.ui.set_body(LVMVolumeGroupView(self.model, self.signal))
@view
def create_raid(self, *args, **kwargs):
title = ("Create software RAID (\"MD\") disk")
footer = ("ENTER on a disk will show detailed "
@ -224,7 +218,6 @@ class FilesystemController(BaseController):
self.ui.set_body(RaidView(self.model,
self.signal))
@view
def create_bcache(self, *args, **kwargs):
title = ("Create hierarchical storage (\"bcache\") disk")
footer = ("ENTER on a disk will show detailed "
@ -242,17 +235,15 @@ class FilesystemController(BaseController):
self.model.add_raid_device(result)
self.signal.prev_signal()
@view
def format_entire(self, disk):
log.debug("format_entire {}".format(disk))
header = ("Format and/or mount {}".format(disk.path))
footer = ("Format or mount whole disk.")
self.ui.set_header(header)
self.ui.set_footer(footer)
afv_view = AddFormatView(self.model, self, disk)
afv_view = AddFormatView(self.model, self, disk, lambda : self.partition_disk(disk))
self.ui.set_body(afv_view)
@view
def format_mount_partition(self, partition):
log.debug("format_entire {}".format(partition))
if partition.fs() is not None:
@ -263,7 +254,7 @@ class FilesystemController(BaseController):
footer = ("Format and mount partition.")
self.ui.set_header(header)
self.ui.set_footer(footer)
afv_view = AddFormatView(self.model, self, partition)
afv_view = AddFormatView(self.model, self, partition, self.default)
self.ui.set_body(afv_view)
def show_disk_information_next(self, disk):

View File

@ -24,7 +24,7 @@ log = logging.getLogger("subiquity.curtin")
TMPDIR = '/tmp'
CURTIN_SEARCH_PATH = ['/usr/local/curtin/bin', '/usr/bin']
CURTIN_INSTALL_PATH = ['/media/root-ro', '/']
CURTIN_INSTALL_PATH = ['/media/root-ro', '/rofs', '/']
CURTIN_INSTALL_LOG = '/tmp/subiquity-curtin-install.log'
CURTIN_POSTINSTALL_LOG = '/tmp/subiquity-curtin-postinstall.log'
CONF_PREFIX = os.path.join(TMPDIR, 'subiquity-config-')
@ -59,12 +59,16 @@ POST_INSTALL_CONFIG = {
'write_files': {
'postinst_metadata': {
'path': 'var/lib/cloud/seed/nocloud-net/meta-data',
'content': 'instance-id: inst-3011',
'content': 'instance-id: inst-3011\n',
},
'postinst_userdata': {
'path': 'var/lib/cloud/seed/nocloud-net/user-data',
# 'content' gets filled in later
},
'postinst_enable_cloudinit': {
'path': 'etc/cloud/ds-identify.cfg',
'content': 'policy: enabled\n',
},
}
}

View File

@ -46,10 +46,11 @@ class AddFormatForm(Form):
class AddFormatView(BaseView):
def __init__(self, model, controller, volume):
def __init__(self, model, controller, volume, back):
self.model = model
self.controller = controller
self.volume = volume
self.back = back
self.form = AddFormatForm(model)
if self.volume.fs() is not None:
@ -71,8 +72,8 @@ class AddFormatView(BaseView):
format_box = Padding.center_50(ListBox(body))
super().__init__(format_box)
def cancel(self, button):
self.controller.prev_view()
def cancel(self, button=None):
self.back()
def done(self, result):
""" format spec
@ -97,4 +98,4 @@ class AddFormatView(BaseView):
result['fstype'] = None
log.debug("Add Format Result: {}".format(result))
self.controller.add_format_handler(self.volume, result)
self.controller.add_format_handler(self.volume, result, self.back)

View File

@ -20,11 +20,9 @@ configuration.
"""
import logging
import os
import re
from urwid import connect_signal, Text
from subiquitycore.ui.container import Columns, ListBox
from subiquitycore.ui.container import ListBox
from subiquitycore.ui.form import (
Form,
FormField,
@ -114,8 +112,8 @@ class AddPartitionView(BaseView):
partition_box = Padding.center_50(ListBox(body))
super().__init__(partition_box)
def cancel(self, button):
self.controller.prev_view()
def cancel(self, button=None):
self.controller.partition_disk(self.disk)
def done(self, result):

View File

@ -63,5 +63,5 @@ class DiskInfoView(BaseView):
''' Return to FilesystemView '''
self.controller.partition_disk(self.disk)
def cancel(self, button):
def cancel(self, button=None):
self.controller.partition_disk(self.disk)

View File

@ -150,7 +150,7 @@ class DiskPartitionView(BaseView):
def done(self, result):
''' Return to FilesystemView '''
self.controller.prev_view()
self.controller.default()
def cancel(self, button):
self.controller.prev_view()
def cancel(self, button=None):
self.controller.default()

View File

@ -203,7 +203,7 @@ class FilesystemView(BaseView):
user_data=sig)))
return Pile(opts)
def cancel(self, button):
def cancel(self, button=None):
self.controller.cancel()
def reset(self, button):

View File

@ -102,14 +102,13 @@ class IdentityView(BaseView):
self.form = IdentityForm()
connect_signal(self.form, 'submit', self.done)
connect_signal(self.form, 'cancel', self.cancel)
self.ssh_import_confirmed = True
body = [
Padding.center_90(self.form.as_rows(self)),
Padding.line_break(""),
Padding.fixed_10(self.form.buttons),
Padding.fixed_10(self.form.buttons[0]),
]
super().__init__(ListBox(body))
@ -136,6 +135,3 @@ class IdentityView(BaseView):
log.debug("User input: {}".format(result))
self.controller.create_user(result)
def cancel(self, button):
self.controller.cancel()

View File

@ -63,5 +63,5 @@ class InstallpathView(BaseView):
def confirm(self, result, sig):
self.signal.emit_signal(sig)
def cancel(self, button):
def cancel(self, button=None):
self.signal.emit_signal('prev-screen')

View File

@ -20,14 +20,6 @@ import os
log = logging.getLogger("subiquitycore.controller")
def view(func):
n = func.__name__
def f(self, *args, **kw):
m = getattr(self, n)
self.view_stack.append((m, args, kw))
return func(self, *args, **kw)
return f
class BaseController(ABC):
"""Base class for controllers."""
@ -42,7 +34,6 @@ class BaseController(ABC):
self.prober = common['prober']
self.controllers = common['controllers']
self.pool = common['pool']
self.view_stack = []
def register_signals(self):
"""Defines signals associated with controller from model."""
@ -51,11 +42,6 @@ class BaseController(ABC):
signals.append((sig, getattr(self, cb)))
self.signal.connect_signals(signals)
def prev_view(self):
self.view_stack.pop()
meth, args, kw = self.view_stack.pop()
meth(*args, **kw)
def run_in_bg(self, func, callback):
"""Run func() in a thread and call callback on UI thread.

View File

@ -36,7 +36,7 @@ from subiquitycore.ui.views import (NetworkView,
NetworkConfigureWLANView)
from subiquitycore.ui.views.network import ApplyingConfigWidget
from subiquitycore.ui.dummy import DummyView
from subiquitycore.controller import BaseController, view
from subiquitycore.controller import BaseController
from subiquitycore.utils import run_command_start, run_command_summarize
log = logging.getLogger("subiquitycore.controller.network")
@ -341,17 +341,9 @@ class NetworkController(BaseController):
self.observer.wlan_listener.trigger_scan(dev.ifindex)
def cancel(self):
if len(self.view_stack) <= 1:
self.signal.emit_signal('prev-screen')
else:
self.prev_view()
self.signal.emit_signal('prev-screen')
def default(self):
self.view_stack = []
self.start()
@view
def start(self):
title = "Network connections"
excerpt = ("Configure at least one interface this server can use to talk to "
"other machines, and which preferably provides sufficient access for "
@ -428,45 +420,37 @@ class NetworkController(BaseController):
self.signal.emit_signal('network-config-written', self.netplan_path)
self.signal.emit_signal('next-screen')
@view
def set_default_v4_route(self):
self.ui.set_header("Default route")
self.ui.set_body(NetworkSetDefaultRouteView(self.model, socket.AF_INET, self))
@view
def set_default_v6_route(self):
self.ui.set_header("Default route")
self.ui.set_body(NetworkSetDefaultRouteView(self.model, socket.AF_INET6, self))
@view
def bond_interfaces(self):
self.ui.set_header("Bond interfaces")
self.ui.set_body(NetworkBondInterfacesView(self.model, self))
@view
def network_configure_interface(self, iface):
self.ui.set_header("Network interface {}".format(iface))
self.ui.set_body(NetworkConfigureInterfaceView(self.model, self, iface))
@view
def network_configure_ipv4_interface(self, iface):
self.ui.set_header("Network interface {} manual IPv4 "
"configuration".format(iface))
self.ui.set_body(NetworkConfigureIPv4InterfaceView(self.model, self, iface))
@view
def network_configure_wlan_interface(self, iface):
self.ui.set_header("Network interface {} WIFI "
"configuration".format(iface))
self.ui.set_body(NetworkConfigureWLANView(self.model, self, iface))
@view
def network_configure_ipv6_interface(self, iface):
self.ui.set_header("Network interface {} manual IPv6 "
"configuration".format(iface))
self.ui.set_body(NetworkConfigureIPv6InterfaceView(self.model, self, iface))
@view
def install_network_driver(self):
self.ui.set_body(DummyView(self))

View File

@ -243,11 +243,6 @@ class _HelpDisplay(WidgetWrap):
self._closer = closer
button = Color.button(PlainButton(label="Close", on_press=lambda btn:self._closer()))
super().__init__(LineBox(Pile([Text(help_text), Padding.fixed_10(button)]), title="Help"))
def keypress(self, size, key):
if key == 'esc':
self._closer()
else:
return super().keypress(size, key)
class Help(WidgetWrap):

View File

@ -260,5 +260,5 @@ class NetworkView(BaseView):
def done(self, result):
self.controller.network_finish(self.model.render())
def cancel(self, button):
def cancel(self, button=None):
self.controller.cancel()

View File

@ -127,8 +127,8 @@ class NetworkBondInterfacesView(BaseView):
return
log.debug('bond: successful bond creation')
self.controller.prev_view()
self.controller.default()
def cancel(self, button):
log.debug('bond: button_cancel')
self.controller.prev_view()
self.controller.default()

View File

@ -115,7 +115,7 @@ class NetworkConfigureInterfaceView(BaseView):
self.dev = self.model.get_netdev_by_name(self.dev.name)
except KeyError:
# The interface is gone
self.controller.prev_view()
self.controller.default()
return
if self.dev.type == 'wlan':
self.wifi_info.contents = [ (obj, ('pack', None)) for obj in _build_wifi_info(self.dev) ]
@ -155,5 +155,8 @@ class NetworkConfigureInterfaceView(BaseView):
def show_ipv6_configuration(self, btn):
self.controller.network_configure_ipv6_interface(self.dev.name)
def cancel(self):
self.controller.default()
def done(self, result):
self.controller.prev_view()
self.controller.default()

View File

@ -146,8 +146,7 @@ class BaseNetworkConfigureManualView(BaseView):
self.dev = self.model.get_netdev_by_name(self.dev.name)
except KeyError:
# The interface is gone
self.controller.prev_view()
self.controller.prev_view()
self.controller.default()
return
def _build_set_as_default_gw_button(self):
@ -193,11 +192,11 @@ class BaseNetworkConfigureManualView(BaseView):
self.dev.add_network(self.ip_version, result)
# return
self.controller.prev_view()
self.controller.network_configure_interface(self.dev.name)
def cancel(self, sender):
def cancel(self, sender=None):
self.model.default_gateway = None
self.controller.prev_view()
self.controller.network_configure_interface(self.dev.name)
class NetworkConfigureIPv4InterfaceView(BaseNetworkConfigureManualView):
ip_version = 4

View File

@ -82,13 +82,6 @@ class NetworkConfigureWLANView(BaseView):
self.orig_w = None
super().__init__(ListBox(self.body))
def keypress(self, size, key):
if key == 'esc':
if self.orig_w is not None:
self.remove_overlay()
return
return super().keypress(size, key)
def show_ssid_list(self, sender):
self.show_overlay(NetworkList(self, self.dev.actual_ssids))
@ -138,8 +131,7 @@ class NetworkConfigureWLANView(BaseView):
self.dev = self.model.get_netdev_by_name(self.dev.name)
except KeyError:
# The interface is gone
self.controller.prev_view()
self.controller.prev_view()
self.controller.default()
return
self.inputs.contents = [ (obj, ('pack', None)) for obj in self._build_iface_inputs() ]
@ -156,7 +148,7 @@ class NetworkConfigureWLANView(BaseView):
else:
psk = None
self.dev.set_ssid_psk(ssid, psk)
self.controller.prev_view()
self.controller.network_configure_interface(self.dev.name)
def cancel(self, sender):
self.controller.prev_view()
def cancel(self, sender=None):
self.controller.network_configure_interface(self.dev.name)

View File

@ -139,7 +139,7 @@ class NetworkSetDefaultRouteView(BaseView):
except ValueError:
# FIXME: raise UX error message
pass
self.controller.prev_view()
self.controller.default()
def cancel(self, button):
self.controller.prev_view()
def cancel(self, button=None):
self.controller.default()

View File

@ -68,10 +68,18 @@ def environment_check(check):
for ftype, items in checks[check_type].items():
for i in items:
if not os.path.exists(i):
log.error('FAIL: {} is not found on the'
' filesystem'.format(i))
env_ok = False
continue
if 'SNAP' in os.environ:
log.warn("Adjusting path for snaps: {}".format(os.environ.get('SNAP')))
i = os.environ.get('SNAP') + i
if not os.path.exists(i):
env_ok = False
else:
env_ok = False
if not env_ok:
log.error('FAIL: {} is not found on the'
' filesystem'.format(i))
continue
if check_map[ftype](i) is False:
log.error('FAIL: {} is NOT of type: {}'.format(i, ftype))
env_ok = False

View File

@ -22,6 +22,11 @@ from urwid import Overlay, WidgetWrap
class BaseView(WidgetWrap):
def __init__(self, w):
self.orig_w = None
super().__init__(w)
def show_overlay(self, overlay_widget, **kw):
self.orig_w = self._w
args = dict(
@ -38,12 +43,19 @@ class BaseView(WidgetWrap):
self._w = self.orig_w
self.orig_w = None
def cancel(self):
pass
def keypress(self, size, key):
if key in ['ctrl x']:
self.controller.signal.emit_signal('control-x-quit')
return None
key = super().keypress(size, key)
if key == 'esc':
self.controller.cancel()
return None
if self.orig_w is not None:
self.remove_overlay()
return None
else:
self.cancel()
return None
return key