Break out controllers into separate modules
Signed-off-by: Adam Stokes <adam.stokes@ubuntu.com>
This commit is contained in:
parent
dbf83a4edb
commit
079098f749
|
@ -0,0 +1,40 @@
|
||||||
|
# Copyright 2015 Canonical, Ltd.
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU Affero General Public License as
|
||||||
|
# published by the Free Software Foundation, either version 3 of the
|
||||||
|
# License, or (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU Affero General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Affero General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
""" Controller Policy
|
||||||
|
"""
|
||||||
|
|
||||||
|
import logging
|
||||||
|
|
||||||
|
log = logging.getLogger("subiquity.controller")
|
||||||
|
|
||||||
|
|
||||||
|
class ControllerPolicyException(Exception):
|
||||||
|
"Problem in Controller policy"
|
||||||
|
|
||||||
|
|
||||||
|
class ControllerPolicy:
|
||||||
|
""" Expected contract for defining controllers
|
||||||
|
"""
|
||||||
|
|
||||||
|
def register_signals(self):
|
||||||
|
""" Defines signals associated with controller from model """
|
||||||
|
if hasattr(self, 'model'):
|
||||||
|
signals = []
|
||||||
|
for name, sig, cb in self.model.get_signals():
|
||||||
|
signals.append((sig, getattr(self, cb)))
|
||||||
|
self.signal.connect_signals(signals)
|
||||||
|
else:
|
||||||
|
log.debug("No model signals found for {}".format(self))
|
|
@ -0,0 +1,20 @@
|
||||||
|
# Copyright 2015 Canonical, Ltd.
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU Affero General Public License as
|
||||||
|
# published by the Free Software Foundation, either version 3 of the
|
||||||
|
# License, or (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU Affero General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Affero General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
from .welcome import WelcomeController
|
||||||
|
from .installpath import InstallpathController
|
||||||
|
from .network import NetworkController
|
||||||
|
from .filesystem import FilesystemController
|
||||||
|
from .installprogress import InstallProgressController
|
|
@ -0,0 +1,133 @@
|
||||||
|
# Copyright 2015 Canonical, Ltd.
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU Affero General Public License as
|
||||||
|
# published by the Free Software Foundation, either version 3 of the
|
||||||
|
# License, or (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU Affero General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Affero General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import logging
|
||||||
|
import urwid
|
||||||
|
from subiquity.controller import ControllerPolicy
|
||||||
|
from subiquity.models import FilesystemModel
|
||||||
|
from subiquity.ui.views import (DiskPartitionView, AddPartitionView,
|
||||||
|
FilesystemView)
|
||||||
|
from subiquity.ui.dummy import DummyView
|
||||||
|
from subiquity.curtin import (curtin_write_storage_actions,
|
||||||
|
curtin_write_postinst_config)
|
||||||
|
|
||||||
|
|
||||||
|
log = logging.getLogger("subiquity.controller.filesystem")
|
||||||
|
|
||||||
|
BIOS_GRUB_SIZE_BYTES = 2 * 1024 * 1024 # 2MiB
|
||||||
|
|
||||||
|
|
||||||
|
class FilesystemController(ControllerPolicy):
|
||||||
|
def __init__(self, ui, signal):
|
||||||
|
self.ui = ui
|
||||||
|
self.signal = signal
|
||||||
|
self.model = FilesystemModel()
|
||||||
|
|
||||||
|
def filesystem(self, reset=False):
|
||||||
|
# FIXME: Is this the best way to zero out this list for a reset?
|
||||||
|
if reset:
|
||||||
|
log.info("Resetting Filesystem model")
|
||||||
|
self.model.reset()
|
||||||
|
|
||||||
|
title = "Filesystem setup"
|
||||||
|
footer = ("Select available disks to format and mount")
|
||||||
|
self.ui.set_header(title)
|
||||||
|
self.ui.set_footer(footer)
|
||||||
|
self.ui.set_body(FilesystemView(self.model,
|
||||||
|
self.signal))
|
||||||
|
|
||||||
|
def filesystem_handler(self, reset=False, actions=None):
|
||||||
|
if actions is None and reset is False:
|
||||||
|
urwid.emit_signal(self.signal, 'network:show')
|
||||||
|
|
||||||
|
log.info("Rendering curtin config from user choices")
|
||||||
|
curtin_write_storage_actions(actions=actions)
|
||||||
|
log.info("Generating post-install config")
|
||||||
|
curtin_write_postinst_config()
|
||||||
|
# self.install_progress()
|
||||||
|
|
||||||
|
# Filesystem/Disk partition -----------------------------------------------
|
||||||
|
def disk_partition(self, disk):
|
||||||
|
log.debug("In disk partition view, using {} as the disk.".format(disk))
|
||||||
|
title = ("Partition, format, and mount {}".format(disk))
|
||||||
|
footer = ("Partition the disk, or format the entire device "
|
||||||
|
"without partitions.")
|
||||||
|
self.ui.set_header(title)
|
||||||
|
self.ui.set_footer(footer)
|
||||||
|
dp_view = DiskPartitionView(self.model,
|
||||||
|
self.signal,
|
||||||
|
disk)
|
||||||
|
|
||||||
|
self.ui.set_body(dp_view)
|
||||||
|
|
||||||
|
def disk_partition_handler(self, spec=None):
|
||||||
|
log.debug("Disk partition: {}".format(spec))
|
||||||
|
if spec is None:
|
||||||
|
urwid.emit_signal(self.signal, 'filesystem:show', [])
|
||||||
|
urwid.emit_signal(self.signal, 'filesystem:show-disk-partition', [])
|
||||||
|
|
||||||
|
def add_disk_partition(self, disk):
|
||||||
|
log.debug("Adding partition to {}".format(disk))
|
||||||
|
footer = ("Select whole disk, or partition, to format and mount.")
|
||||||
|
self.ui.set_footer(footer)
|
||||||
|
adp_view = AddPartitionView(self.model,
|
||||||
|
self.signal,
|
||||||
|
disk)
|
||||||
|
self.ui.set_body(adp_view)
|
||||||
|
|
||||||
|
def add_disk_partition_handler(self, disk, spec):
|
||||||
|
current_disk = self.model.get_disk(disk)
|
||||||
|
|
||||||
|
''' create a gpt boot partition if one doesn't exist '''
|
||||||
|
if current_disk.parttype == 'gpt' and \
|
||||||
|
len(current_disk.disk.partitions) == 0:
|
||||||
|
log.debug('Adding grub_bios gpt partition first')
|
||||||
|
current_disk.add_partition(partnum=1,
|
||||||
|
size=BIOS_GRUB_SIZE_BYTES,
|
||||||
|
fstype=None,
|
||||||
|
flag='bios_grub')
|
||||||
|
|
||||||
|
if spec["fstype"] in ["swap"]:
|
||||||
|
current_disk.add_partition(partnum=spec["partnum"],
|
||||||
|
size=spec["bytes"],
|
||||||
|
fstype=spec["fstype"])
|
||||||
|
else:
|
||||||
|
current_disk.add_partition(partnum=spec["partnum"],
|
||||||
|
size=spec["bytes"],
|
||||||
|
fstype=spec["fstype"],
|
||||||
|
mountpoint=spec["mountpoint"])
|
||||||
|
log.debug("FS Table: {}".format(current_disk.get_fs_table()))
|
||||||
|
self.signal.emit_signal('filesystem:show-disk-partition', disk)
|
||||||
|
|
||||||
|
def connect_iscsi_disk(self, *args, **kwargs):
|
||||||
|
self.ui.set_body(DummyView(self.signal))
|
||||||
|
|
||||||
|
def connect_ceph_disk(self, *args, **kwargs):
|
||||||
|
self.ui.set_body(DummyView(self.signal))
|
||||||
|
|
||||||
|
def create_volume_group(self, *args, **kwargs):
|
||||||
|
self.ui.set_body(DummyView(self.signal))
|
||||||
|
|
||||||
|
def create_raid(self, *args, **kwargs):
|
||||||
|
self.ui.set_body(DummyView(self.signal))
|
||||||
|
|
||||||
|
def setup_bcache(self, *args, **kwargs):
|
||||||
|
self.ui.set_body(DummyView(self.signal))
|
||||||
|
|
||||||
|
def add_first_gpt_partition(self, *args, **kwargs):
|
||||||
|
self.ui.set_body(DummyView(self.signal))
|
||||||
|
|
||||||
|
def create_swap_entire_device(self, *args, **kwargs):
|
||||||
|
self.ui.set_body(DummyView(self.signal))
|
|
@ -0,0 +1,58 @@
|
||||||
|
# Copyright 2015 Canonical, Ltd.
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU Affero General Public License as
|
||||||
|
# published by the Free Software Foundation, either version 3 of the
|
||||||
|
# License, or (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU Affero General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Affero General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import logging
|
||||||
|
from subiquity.controller import ControllerPolicy
|
||||||
|
from subiquity.models import InstallpathModel
|
||||||
|
from subiquity.ui.views import InstallpathView
|
||||||
|
from subiquity.ui.dummy import DummyView
|
||||||
|
|
||||||
|
log = logging.getLogger('subiquity.controller.installpath')
|
||||||
|
|
||||||
|
|
||||||
|
class InstallpathController(ControllerPolicy):
|
||||||
|
def __init__(self, ui, signal):
|
||||||
|
self.ui = ui
|
||||||
|
self.signal = signal
|
||||||
|
self.model = InstallpathModel()
|
||||||
|
|
||||||
|
def installpath(self):
|
||||||
|
title = "15.10"
|
||||||
|
excerpt = ("Welcome to Ubuntu! The world's favourite platform "
|
||||||
|
"for clouds, clusters and amazing internet things. "
|
||||||
|
"This is the installer for Ubuntu on servers and "
|
||||||
|
"internet devices.")
|
||||||
|
footer = ("Use UP, DOWN arrow keys, and ENTER, to "
|
||||||
|
"navigate options")
|
||||||
|
|
||||||
|
self.ui.set_header(title, excerpt)
|
||||||
|
self.ui.set_footer(footer)
|
||||||
|
self.ui.set_body(InstallpathView(self.model, self.signal))
|
||||||
|
|
||||||
|
def install_ubuntu(self):
|
||||||
|
log.debug("Installing Ubuntu path chosen.")
|
||||||
|
self.signal.emit_signal('network:show')
|
||||||
|
|
||||||
|
def install_maas_region_server(self):
|
||||||
|
self.ui.set_body(DummyView(self.signal))
|
||||||
|
|
||||||
|
def install_maas_cluster_server(self):
|
||||||
|
self.ui.set_body(DummyView(self.signal))
|
||||||
|
|
||||||
|
def test_media(self):
|
||||||
|
self.ui.set_body(DummyView(self.signal))
|
||||||
|
|
||||||
|
def test_memory(self):
|
||||||
|
self.ui.set_body(DummyView(self.signal))
|
|
@ -0,0 +1,57 @@
|
||||||
|
# Copyright 2015 Canonical, Ltd.
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU Affero General Public License as
|
||||||
|
# published by the Free Software Foundation, either version 3 of the
|
||||||
|
# License, or (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU Affero General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Affero General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import logging
|
||||||
|
import subprocess
|
||||||
|
from subiquity.ui.views import ProgressView, ProgressOutput
|
||||||
|
from subiquity.controller import ControllerPolicy
|
||||||
|
|
||||||
|
log = logging.getLogger("subiquity.controller.installprogress")
|
||||||
|
|
||||||
|
|
||||||
|
class InstallProgressController(ControllerPolicy):
|
||||||
|
def __init__(self, ui, signal):
|
||||||
|
self.ui = ui
|
||||||
|
self.signal = signal
|
||||||
|
|
||||||
|
def install_progress(self):
|
||||||
|
title = ("Installing system")
|
||||||
|
excerpt = ("Please wait for the installation "
|
||||||
|
"to finish before rebooting.")
|
||||||
|
footer = ("Thank you for using Ubuntu!")
|
||||||
|
self.ui.set_header(title, excerpt)
|
||||||
|
self.ui.set_footer(footer)
|
||||||
|
if self.opts.dry_run:
|
||||||
|
log.debug("Filesystem: this is a dry-run")
|
||||||
|
banner = [
|
||||||
|
"**** DRY_RUN ****",
|
||||||
|
"NOT calling:"
|
||||||
|
"subprocess.check_call(/usr/local/bin/curtin_wrap.sh)"
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
"Press (Q) to Quit."
|
||||||
|
]
|
||||||
|
self.progress_output_w = ProgressOutput("\n".join(banner))
|
||||||
|
else:
|
||||||
|
log.debug("filesystem: this is the *real* thing")
|
||||||
|
subprocess.Popen(["/usr/local/bin/curtin_wrap.sh"],
|
||||||
|
stdout=self.install_progress_fd,
|
||||||
|
bufsize=1,
|
||||||
|
universal_newlines=True)
|
||||||
|
self.progress_output_w = ProgressOutput("Wait for it...\n\n")
|
||||||
|
self.ui.set_body(ProgressView(self.signal, self.progress_output_w))
|
||||||
|
|
||||||
|
def install_progress_status(self, data):
|
||||||
|
self.progress_output_w.set_text(data)
|
|
@ -0,0 +1,45 @@
|
||||||
|
# Copyright 2015 Canonical, Ltd.
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU Affero General Public License as
|
||||||
|
# published by the Free Software Foundation, either version 3 of the
|
||||||
|
# License, or (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU Affero General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Affero General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
from subiquity.controller import ControllerPolicy
|
||||||
|
from subiquity.models import NetworkModel
|
||||||
|
from subiquity.ui.views import NetworkView
|
||||||
|
from subiquity.ui.dummy import DummyView
|
||||||
|
|
||||||
|
|
||||||
|
class NetworkController(ControllerPolicy):
|
||||||
|
def __init__(self, ui, signal):
|
||||||
|
self.ui = ui
|
||||||
|
self.signal = signal
|
||||||
|
self.model = NetworkModel()
|
||||||
|
|
||||||
|
def network(self):
|
||||||
|
title = "Network connections"
|
||||||
|
excerpt = ("Configure at least the main interface this server will "
|
||||||
|
"use to talk to other machines, and preferably provide "
|
||||||
|
"sufficient access for updates.")
|
||||||
|
footer = ("Additional networking info here")
|
||||||
|
self.ui.set_header(title, excerpt)
|
||||||
|
self.ui.set_footer(footer)
|
||||||
|
self.ui.set_body(NetworkView(self.model, self.signal))
|
||||||
|
|
||||||
|
def set_default_route(self):
|
||||||
|
self.ui.set_body(DummyView(self.signal))
|
||||||
|
|
||||||
|
def bond_interfaces(self):
|
||||||
|
self.ui.set_body(DummyView(self.signal))
|
||||||
|
|
||||||
|
def install_network_driver(self):
|
||||||
|
self.ui.set_body(DummyView(self.signal))
|
|
@ -0,0 +1,36 @@
|
||||||
|
# Copyright 2015 Canonical, Ltd.
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU Affero General Public License as
|
||||||
|
# published by the Free Software Foundation, either version 3 of the
|
||||||
|
# License, or (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU Affero General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Affero General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
|
||||||
|
from subiquity.ui.views import WelcomeView
|
||||||
|
from subiquity.models import WelcomeModel
|
||||||
|
from subiquity.controller import ControllerPolicy
|
||||||
|
|
||||||
|
|
||||||
|
class WelcomeController(ControllerPolicy):
|
||||||
|
def __init__(self, ui, signal):
|
||||||
|
self.ui = ui
|
||||||
|
self.model = WelcomeModel()
|
||||||
|
self.signal = signal
|
||||||
|
|
||||||
|
def welcome(self):
|
||||||
|
title = "Wilkommen! Bienvenue! Welcome! Zdrastvutie! Welkom!"
|
||||||
|
excerpt = "Please choose your preferred language"
|
||||||
|
footer = ("Use UP, DOWN arrow keys, and ENTER, to "
|
||||||
|
"select your language.")
|
||||||
|
self.ui.set_header(title, excerpt)
|
||||||
|
self.ui.set_footer(footer)
|
||||||
|
view = WelcomeView(self.model, self.signal)
|
||||||
|
self.ui.set_body(view)
|
|
@ -16,22 +16,16 @@
|
||||||
import logging
|
import logging
|
||||||
import urwid
|
import urwid
|
||||||
import urwid.curses_display
|
import urwid.curses_display
|
||||||
import subprocess
|
|
||||||
from subiquity.signals import Signal
|
from subiquity.signals import Signal
|
||||||
from subiquity.palette import STYLES, STYLES_MONO
|
from subiquity.palette import STYLES, STYLES_MONO
|
||||||
from subiquity.curtin import (curtin_write_storage_actions,
|
|
||||||
curtin_write_postinst_config)
|
|
||||||
|
|
||||||
# Modes import ----------------------------------------------------------------
|
# Modes import ----------------------------------------------------------------
|
||||||
from subiquity.models import (WelcomeModel, NetworkModel, InstallpathModel,
|
from subiquity.controllers import (WelcomeController,
|
||||||
FilesystemModel)
|
InstallpathController,
|
||||||
from subiquity.ui.views import (WelcomeView, NetworkView, InstallpathView,
|
NetworkController,
|
||||||
DiskPartitionView, AddPartitionView,
|
FilesystemController,
|
||||||
FilesystemView, ProgressView, ProgressOutput)
|
InstallProgressController)
|
||||||
from subiquity.ui.dummy import DummyView
|
|
||||||
|
|
||||||
|
|
||||||
BIOS_GRUB_SIZE_BYTES = 2 * 1024 * 1024 # 2MiB
|
|
||||||
log = logging.getLogger('subiquity.core')
|
log = logging.getLogger('subiquity.core')
|
||||||
|
|
||||||
|
|
||||||
|
@ -44,30 +38,28 @@ class Controller:
|
||||||
def __init__(self, ui, opts):
|
def __init__(self, ui, opts):
|
||||||
self.ui = ui
|
self.ui = ui
|
||||||
self.opts = opts
|
self.opts = opts
|
||||||
self.models = {
|
|
||||||
"welcome": WelcomeModel(),
|
|
||||||
"network": NetworkModel(),
|
|
||||||
"installpath": InstallpathModel(),
|
|
||||||
"filesystem": FilesystemModel()
|
|
||||||
}
|
|
||||||
self.signal = Signal()
|
self.signal = Signal()
|
||||||
# self.signal.register_signals()
|
self.controllers = {
|
||||||
self._connect_signals()
|
"welcome": WelcomeController(self.ui, self.signal),
|
||||||
|
"installpath": InstallpathController(self.ui, self.signal),
|
||||||
|
"network": NetworkController(self.ui, self.signal),
|
||||||
|
"filesystem": FilesystemController(self.ui, self.signal),
|
||||||
|
"progress": InstallProgressController(self.ui, self.signal),
|
||||||
|
}
|
||||||
|
self._connect_base_signals()
|
||||||
|
|
||||||
def _connect_signals(self):
|
def _connect_base_signals(self):
|
||||||
""" Connect signals used in the core controller
|
""" Connect signals used in the core controller
|
||||||
"""
|
"""
|
||||||
signals = []
|
signals = []
|
||||||
|
|
||||||
# Add quit signal
|
# Add quit signal
|
||||||
signals.append(('quit', self.exit))
|
signals.append(('quit', self.exit))
|
||||||
|
|
||||||
# Pull signals emitted from welcome path selections
|
|
||||||
for model, model_class in self.models.items():
|
|
||||||
for name, sig, cb in model_class.get_signals():
|
|
||||||
signals.append((sig, getattr(self, cb)))
|
|
||||||
|
|
||||||
self.signal.connect_signals(signals)
|
self.signal.connect_signals(signals)
|
||||||
|
|
||||||
|
# Registers signals from each controller
|
||||||
|
for controller, controller_class in self.controllers.items():
|
||||||
|
controller_class.register_signals()
|
||||||
log.debug(self.signal)
|
log.debug(self.signal)
|
||||||
|
|
||||||
# EventLoop -------------------------------------------------------------------
|
# EventLoop -------------------------------------------------------------------
|
||||||
|
@ -113,214 +105,15 @@ class Controller:
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.set_alarm_in(0.05, self.welcome)
|
self.set_alarm_in(0.05, self.welcome)
|
||||||
self.install_progress_fd = self.loop.watch_pipe(
|
# self.install_progress_fd = self.loop.watch_pipe(
|
||||||
self.install_progress_status)
|
# self.install_progress_status)
|
||||||
self.loop.run()
|
self.loop.run()
|
||||||
except:
|
except:
|
||||||
log.exception("Exception in controller.run():")
|
log.exception("Exception in controller.run():")
|
||||||
raise
|
raise
|
||||||
|
|
||||||
# Base UI Actions -------------------------------------------------------------
|
# Welcome Mode ------------------------------------------------------------
|
||||||
def set_body(self, w):
|
#
|
||||||
self.ui.set_body(w)
|
# Starts the initial UI view.
|
||||||
self.redraw_screen()
|
|
||||||
|
|
||||||
def set_header(self, title=None, excerpt=None):
|
|
||||||
self.ui.set_header(title, excerpt)
|
|
||||||
self.redraw_screen()
|
|
||||||
|
|
||||||
def set_footer(self, message):
|
|
||||||
self.ui.set_footer(message)
|
|
||||||
self.redraw_screen()
|
|
||||||
|
|
||||||
# Modes ----------------------------------------------------------------------
|
|
||||||
# Welcome -----------------------------------------------------------------
|
|
||||||
def welcome(self, *args, **kwargs):
|
def welcome(self, *args, **kwargs):
|
||||||
title = "Wilkommen! Bienvenue! Welcome! Zdrastvutie! Welkom!"
|
self.controllers['welcome'].welcome()
|
||||||
excerpt = "Please choose your preferred language"
|
|
||||||
footer = ("Use UP, DOWN arrow keys, and ENTER, to "
|
|
||||||
"select your language.")
|
|
||||||
self.ui.set_header(title, excerpt)
|
|
||||||
self.ui.set_footer(footer)
|
|
||||||
view = WelcomeView(self.models['welcome'], self.signal)
|
|
||||||
self.ui.set_body(view)
|
|
||||||
|
|
||||||
# InstallPath -------------------------------------------------------------
|
|
||||||
def installpath(self):
|
|
||||||
title = "15.10"
|
|
||||||
excerpt = ("Welcome to Ubuntu! The world's favourite platform "
|
|
||||||
"for clouds, clusters and amazing internet things. "
|
|
||||||
"This is the installer for Ubuntu on servers and "
|
|
||||||
"internet devices.")
|
|
||||||
footer = ("Use UP, DOWN arrow keys, and ENTER, to "
|
|
||||||
"navigate options")
|
|
||||||
|
|
||||||
self.ui.set_header(title, excerpt)
|
|
||||||
self.ui.set_footer(footer)
|
|
||||||
self.ui.set_body(InstallpathView(self.models["installpath"],
|
|
||||||
self.signal))
|
|
||||||
|
|
||||||
def install_ubuntu(self):
|
|
||||||
log.debug("Installing Ubuntu path chosen.")
|
|
||||||
self.signal.emit_signal('network:show')
|
|
||||||
|
|
||||||
def install_maas_region_server(self):
|
|
||||||
self.ui.set_body(DummyView(self.signal))
|
|
||||||
|
|
||||||
def install_maas_cluster_server(self):
|
|
||||||
self.ui.set_body(DummyView(self.signal))
|
|
||||||
|
|
||||||
def test_media(self):
|
|
||||||
self.ui.set_body(DummyView(self.signal))
|
|
||||||
|
|
||||||
def test_memory(self):
|
|
||||||
self.ui.set_body(DummyView(self.signal))
|
|
||||||
|
|
||||||
# Network -----------------------------------------------------------------
|
|
||||||
def network(self):
|
|
||||||
title = "Network connections"
|
|
||||||
excerpt = ("Configure at least the main interface this server will "
|
|
||||||
"use to talk to other machines, and preferably provide "
|
|
||||||
"sufficient access for updates.")
|
|
||||||
footer = ("Additional networking info here")
|
|
||||||
self.ui.set_header(title, excerpt)
|
|
||||||
self.ui.set_footer(footer)
|
|
||||||
self.ui.set_body(NetworkView(self.models["network"], self.signal))
|
|
||||||
|
|
||||||
def set_default_route(self):
|
|
||||||
self.ui.set_body(DummyView(self.signal))
|
|
||||||
|
|
||||||
def bond_interfaces(self):
|
|
||||||
self.ui.set_body(DummyView(self.signal))
|
|
||||||
|
|
||||||
def install_network_driver(self):
|
|
||||||
self.ui.set_body(DummyView(self.signal))
|
|
||||||
|
|
||||||
# Filesystem --------------------------------------------------------------
|
|
||||||
def filesystem(self, reset=False):
|
|
||||||
# FIXME: Is this the best way to zero out this list for a reset?
|
|
||||||
if reset:
|
|
||||||
log.info("Resetting Filesystem model")
|
|
||||||
self.models["filesystem"].reset()
|
|
||||||
|
|
||||||
title = "Filesystem setup"
|
|
||||||
footer = ("Select available disks to format and mount")
|
|
||||||
self.ui.set_header(title)
|
|
||||||
self.ui.set_footer(footer)
|
|
||||||
self.ui.set_body(FilesystemView(self.models["filesystem"],
|
|
||||||
self.signal))
|
|
||||||
|
|
||||||
def filesystem_handler(self, reset=False, actions=None):
|
|
||||||
if actions is None and reset is False:
|
|
||||||
urwid.emit_signal(self.signal, 'network:show')
|
|
||||||
|
|
||||||
log.info("Rendering curtin config from user choices")
|
|
||||||
curtin_write_storage_actions(actions=actions)
|
|
||||||
log.info("Generating post-install config")
|
|
||||||
curtin_write_postinst_config()
|
|
||||||
self.install_progress()
|
|
||||||
|
|
||||||
# Filesystem/Disk partition -----------------------------------------------
|
|
||||||
def disk_partition(self, disk):
|
|
||||||
log.debug("In disk partition view, using {} as the disk.".format(disk))
|
|
||||||
title = ("Partition, format, and mount {}".format(disk))
|
|
||||||
footer = ("Partition the disk, or format the entire device "
|
|
||||||
"without partitions.")
|
|
||||||
self.ui.set_header(title)
|
|
||||||
self.ui.set_footer(footer)
|
|
||||||
dp_view = DiskPartitionView(self.models["filesystem"],
|
|
||||||
self.signal,
|
|
||||||
disk)
|
|
||||||
|
|
||||||
self.ui.set_body(dp_view)
|
|
||||||
|
|
||||||
def disk_partition_handler(self, spec=None):
|
|
||||||
log.debug("Disk partition: {}".format(spec))
|
|
||||||
if spec is None:
|
|
||||||
urwid.emit_signal(self.signal, 'filesystem:show', [])
|
|
||||||
urwid.emit_signal(self.signal, 'filesystem:show-disk-partition', [])
|
|
||||||
|
|
||||||
def add_disk_partition(self, disk):
|
|
||||||
log.debug("Adding partition to {}".format(disk))
|
|
||||||
footer = ("Select whole disk, or partition, to format and mount.")
|
|
||||||
self.ui.set_footer(footer)
|
|
||||||
adp_view = AddPartitionView(self.models["filesystem"],
|
|
||||||
self.signal,
|
|
||||||
disk)
|
|
||||||
self.ui.set_body(adp_view)
|
|
||||||
|
|
||||||
def add_disk_partition_handler(self, disk, spec):
|
|
||||||
current_disk = self.models["filesystem"].get_disk(disk)
|
|
||||||
|
|
||||||
''' create a gpt boot partition if one doesn't exist '''
|
|
||||||
if current_disk.parttype == 'gpt' and \
|
|
||||||
len(current_disk.disk.partitions) == 0:
|
|
||||||
log.debug('Adding grub_bios gpt partition first')
|
|
||||||
current_disk.add_partition(partnum=1,
|
|
||||||
size=BIOS_GRUB_SIZE_BYTES,
|
|
||||||
fstype=None,
|
|
||||||
flag='bios_grub')
|
|
||||||
|
|
||||||
if spec["fstype"] in ["swap"]:
|
|
||||||
current_disk.add_partition(partnum=spec["partnum"],
|
|
||||||
size=spec["bytes"],
|
|
||||||
fstype=spec["fstype"])
|
|
||||||
else:
|
|
||||||
current_disk.add_partition(partnum=spec["partnum"],
|
|
||||||
size=spec["bytes"],
|
|
||||||
fstype=spec["fstype"],
|
|
||||||
mountpoint=spec["mountpoint"])
|
|
||||||
log.debug("FS Table: {}".format(current_disk.get_fs_table()))
|
|
||||||
self.signal.emit_signal('filesystem:show-disk-partition', disk)
|
|
||||||
|
|
||||||
def connect_iscsi_disk(self, *args, **kwargs):
|
|
||||||
self.ui.set_body(DummyView(self.signal))
|
|
||||||
|
|
||||||
def connect_ceph_disk(self, *args, **kwargs):
|
|
||||||
self.ui.set_body(DummyView(self.signal))
|
|
||||||
|
|
||||||
def create_volume_group(self, *args, **kwargs):
|
|
||||||
self.ui.set_body(DummyView(self.signal))
|
|
||||||
|
|
||||||
def create_raid(self, *args, **kwargs):
|
|
||||||
self.ui.set_body(DummyView(self.signal))
|
|
||||||
|
|
||||||
def setup_bcache(self, *args, **kwargs):
|
|
||||||
self.ui.set_body(DummyView(self.signal))
|
|
||||||
|
|
||||||
def add_first_gpt_partition(self, *args, **kwargs):
|
|
||||||
self.ui.set_body(DummyView(self.signal))
|
|
||||||
|
|
||||||
def create_swap_entire_device(self, *args, **kwargs):
|
|
||||||
self.ui.set_body(DummyView(self.signal))
|
|
||||||
|
|
||||||
# Progress View -----------------------------------------------------------
|
|
||||||
def install_progress(self):
|
|
||||||
title = ("Installing system")
|
|
||||||
excerpt = ("Please wait for the installation "
|
|
||||||
"to finish before rebooting.")
|
|
||||||
footer = ("Thank you for using Ubuntu!")
|
|
||||||
self.ui.set_header(title, excerpt)
|
|
||||||
self.ui.set_footer(footer)
|
|
||||||
if self.opts.dry_run:
|
|
||||||
log.debug("Filesystem: this is a dry-run")
|
|
||||||
banner = [
|
|
||||||
"**** DRY_RUN ****",
|
|
||||||
"NOT calling:"
|
|
||||||
"subprocess.check_call(/usr/local/bin/curtin_wrap.sh)"
|
|
||||||
"",
|
|
||||||
"",
|
|
||||||
"Press (Q) to Quit."
|
|
||||||
]
|
|
||||||
self.progress_output_w = ProgressOutput("\n".join(banner))
|
|
||||||
else:
|
|
||||||
log.debug("filesystem: this is the *real* thing")
|
|
||||||
subprocess.Popen(["/usr/local/bin/curtin_wrap.sh"],
|
|
||||||
stdout=self.install_progress_fd,
|
|
||||||
bufsize=1,
|
|
||||||
universal_newlines=True)
|
|
||||||
self.progress_output_w = ProgressOutput("Wait for it...\n\n")
|
|
||||||
self.ui.set_body(ProgressView(self.signal, self.progress_output_w))
|
|
||||||
|
|
||||||
def install_progress_status(self, data):
|
|
||||||
self.progress_output_w.set_text(data)
|
|
||||||
|
|
Loading…
Reference in New Issue