Merge pull request #186 from CanonicalLtd/mwhudson/cleanups

assorted cleanups
This commit is contained in:
Michael Hudson-Doyle 2017-01-17 11:34:07 +13:00 committed by GitHub
commit 5d667b16fe
26 changed files with 49 additions and 248 deletions

View File

@ -19,9 +19,9 @@ import os
from subiquitycore.controller import BaseController, view
from subiquitycore.ui.dummy import DummyView
from subiquitycore.ui.error import ErrorView
from subiquitycore.curtin import (curtin_write_storage_actions,
curtin_write_preserved_actions)
from subiquity.curtin import (curtin_write_storage_actions,
curtin_write_preserved_actions)
from subiquity.models.actions import preserve_action
from subiquity.models import (FilesystemModel, RaidModel)
from subiquity.models.filesystem import (_humanize_size)

View File

@ -20,12 +20,12 @@ from tornado.gen import coroutine
from subiquitycore import utils
from subiquitycore.controller import BaseController
from subiquitycore.curtin import (CURTIN_CONFIGS,
from subiquity.curtin import (CURTIN_CONFIGS,
CURTIN_INSTALL_LOG,
CURTIN_POSTINSTALL_LOG,
curtin_reboot,
curtin_install_cmd)
from subiquity.models import InstallProgressModel
from subiquity.ui.views import ProgressView
@ -112,21 +112,18 @@ class InstallProgressController(BaseController):
raise Exception('AIEEE!')
self.install_spawned = True
shell = False
if self.opts.dry_run:
log.debug("Installprogress: this is a dry-run")
curtin_cmd = ["top", "-d", "0.5", "-n", "20", "-b", "-p",
str(os.getpid()),
'>', self.install_log,
'2>', self.install_log]
shell = True
curtin_cmd = [
"bash", "-c",
"i=0;while [ $i -le 10 ];do i=$((i+1)); echo line $i; sleep 1; done > %s 2>&1"%self.install_log]
else:
log.debug("Installprogress: this is the *REAL* thing")
configs = [CURTIN_CONFIGS['storage']]
curtin_cmd = curtin_install_cmd(configs)
log.debug('Curtin install cmd: {}'.format(curtin_cmd))
result = yield utils.run_command_async(curtin_cmd, shell=shell)
result = yield utils.run_command_async(self.pool, curtin_cmd)
log.debug('curtin_install: result: {}'.format(result))
if result['status'] > 0:
msg = ("Problem with curtin "
@ -155,16 +152,13 @@ class InstallProgressController(BaseController):
log.error('Attempting to spawn curtin install without a config')
raise Exception('AIEEE!')
shell = False
self.postinstall_spawned = True
self.install_log = CURTIN_POSTINSTALL_LOG
if self.opts.dry_run:
log.debug("Installprogress: this is a dry-run")
curtin_cmd = ["top", "-d", "0.5", "-n", "20", "-b", "-p",
str(os.getpid()),
'>', self.install_log,
'2>', self.install_log]
shell = True
curtin_cmd = [
"bash", "-c",
"i=0;while [ $i -le 10 ];do i=$((i+1)); echo line $i; sleep 1; done > %s 2>&1"%self.install_log]
else:
log.debug("Installprogress: this is the *REAL* thing")
configs = [
@ -174,7 +168,7 @@ class InstallProgressController(BaseController):
curtin_cmd = curtin_install_cmd(configs)
log.debug('Curtin postinstall cmd: {}'.format(curtin_cmd))
result = yield utils.run_command_async(curtin_cmd, shell=shell)
result = yield utils.run_command_async(self.pool, curtin_cmd)
if result['status'] > 0:
msg = ("Problem with curtin "
"post-install: {}".format(result))

View File

@ -22,7 +22,7 @@ import yaml
from subiquitycore import utils
log = logging.getLogger("subiquitycore.curtin")
log = logging.getLogger("subiquity.curtin")
TMPDIR = '/tmp'
CURTIN_SEARCH_PATH = ['/usr/local/curtin/bin', '/usr/bin']

View File

@ -15,20 +15,13 @@
import logging
from subiquitycore.model import BaseModel
log = logging.getLogger('subiquity.models.ceph_disk')
class CephDiskModel(BaseModel):
class CephDiskModel(object):
""" Model representing iscsi Ceph storage
"""
prev_signal = (
'Back to filesystem view',
'filesystem:show',
'filesystem'
)
signals = [
('Ceph view',

View File

@ -19,8 +19,6 @@ import math
import os
import re
from subiquitycore.model import BaseModel
from .blockdev import (Bcachedev,
Blockdev,
LVMDev,
@ -37,7 +35,7 @@ class AttrDict(dict):
__setattr__ = dict.__setitem__
class FilesystemModel(BaseModel):
class FilesystemModel(object):
""" Model representing storage options
"""

View File

@ -14,13 +14,12 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import logging
from subiquitycore.model import BaseModel
log = logging.getLogger("subiquity.models.installpath")
class InstallpathModel(BaseModel):
class InstallpathModel(object):
""" Model representing install options
List of install paths in the form of:

View File

@ -14,13 +14,12 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import logging
from subiquitycore.model import BaseModel
log = logging.getLogger('subiquity.models.installprogress')
class InstallProgressModel(BaseModel):
class InstallProgressModel(object):
""" Model representing install progress
"""
# FIXME: Decide what to do here if ESC is pressed, it's probably in

View File

@ -15,20 +15,13 @@
import logging
from subiquitycore.model import BaseModel
log = logging.getLogger('subiquity.models.iscsi_disk')
class IscsiDiskModel(BaseModel):
class IscsiDiskModel(object):
""" Model representing iscsi network disk
"""
prev_signal = (
'Back to filesystem view',
'filesystem:show',
'filesystem'
)
menu = [
('Discover volumes now', 'iscsi:discover-volumes'),

View File

@ -14,13 +14,12 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import logging
from subiquitycore.model import BaseModel
log = logging.getLogger('subiquity.models.raid')
class RaidModel(BaseModel):
class RaidModel(object):
""" Model representing software raid
"""

View File

@ -17,7 +17,6 @@ import logging
from urwid import Pile, Columns, Text, ListBox
from subiquitycore.curtin import curtin_write_postinst_config
from subiquitycore.ui.buttons import done_btn, cancel_btn
from subiquitycore.ui.interactive import (PasswordEditor,
RealnameEditor,
@ -27,6 +26,7 @@ from subiquitycore.ui.utils import Padding, Color
from subiquitycore.user import create_user
from subiquitycore.view import BaseView
from subiquity.curtin import curtin_write_postinst_config
log = logging.getLogger("subiquity.views.identity")

View File

@ -1,47 +0,0 @@
# 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/>.
""" Async Handler
Provides async operations for various api calls and other non-blocking
work.
The way this works is you create your non-blocking thread:
.. code::
def my_async_method(self):
pool.submit(func, *args)
# In your controller you would then call using coroutines
@coroutine
def do_async_action(self):
try:
yield my_async_method()
# Move to next coroutine or return if finish
self.do_second_async_action()
except Exeception as e:
log.exception("Failed in our non-blocking code.")
"""
import logging
from concurrent.futures import ThreadPoolExecutor
log = logging.getLogger("subiquitycore.async")
class Async:
log.debug('instantiating ThreadPoolExector')
pool = ThreadPoolExecutor(1)
log.debug('pool={}'.format(pool))

View File

@ -40,6 +40,7 @@ class BaseController(ABC):
self.loop = common['loop']
self.prober = common['prober']
self.controllers = common['controllers']
self.pool = common['pool']
self.view_stack = []
def register_signals(self):

View File

@ -27,7 +27,6 @@ import yaml
from probert.network import UdevObserver
from subiquitycore.async import Async
from subiquitycore.models import NetworkModel
from subiquitycore.ui.views import (NetworkView,
NetworkSetDefaultRouteView,
@ -134,8 +133,9 @@ class WaitForDefaultRouteTask(BackgroundTask):
class TaskSequence:
def __init__(self, loop, tasks, watcher):
def __init__(self, loop, pool, tasks, watcher):
self.loop = loop
self.pool = pool
self.tasks = tasks
self.watcher = watcher
self.canceled = False
@ -163,7 +163,7 @@ class TaskSequence:
# Vomiting a traceback all over the console is nasty, but not as
# nasty as silently doing nothing.
fut.result()
Async.pool.submit(self.curtask.run, self).add_done_callback(cb)
self.pool.submit(self.curtask.run, self).add_done_callback(cb)
def call_from_thread(self, func, *args):
log.debug('call_from_thread %s %s', func, args)
@ -384,7 +384,7 @@ class NetworkController(BaseController):
self.acw = ApplyingConfigWidget(len(tasks), cancel)
self.ui.frame.body.show_overlay(self.acw)
self.cs = TaskSequence(self.loop, tasks, self)
self.cs = TaskSequence(self.loop, self.pool, tasks, self)
self.cs.run()
def task_complete(self, stage):

View File

@ -13,10 +13,13 @@
# 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 concurrent import futures
import logging
import urwid
from tornado.ioloop import IOLoop
from tornado.util import import_object
from subiquitycore.signals import Signal
from subiquitycore.palette import STYLES, STYLES_MONO
from subiquitycore.prober import Prober, ProberException
@ -60,7 +63,8 @@ class Application:
"opts": opts,
"signal": Signal(),
"prober": prober,
"loop": None
"loop": None,
"pool": futures.ThreadPoolExecutor(1),
}
self.common['controllers'] = dict.fromkeys(self.controllers)
self.controller_index = -1
@ -70,7 +74,6 @@ class Application:
"""
signals = []
# Add quit signal
signals.append(('quit', self.exit))
if self.common['opts'].dry_run:
signals.append(('control-x-quit', self.exit))
@ -104,20 +107,12 @@ class Application:
# EventLoop -------------------------------------------------------------------
def redraw_screen(self):
if hasattr(self, 'loop'):
if self.common['loop'] is not None:
try:
self.common['loop'].draw_screen()
except AssertionError as e:
log.critical("Redraw screen error: {}".format(e))
def set_alarm_in(self, interval, cb):
self.common['loop'].set_alarm_in(interval, cb)
return
def update(self, *args, **kwds):
""" Update loop """
pass
def exit(self):
raise urwid.ExitMainLoop()
@ -146,7 +141,7 @@ class Application:
self.common['loop'].event_loop))
try:
self.set_alarm_in(0.05, self.next_screen)
self.common['loop'].set_alarm_in(0.05, self.next_screen)
for k in self.common['controllers']:
log.debug("Importing controller: {}".format(k))
klass = import_object(

View File

@ -18,11 +18,8 @@ import os
import sys
from logging.handlers import TimedRotatingFileHandler
LOGDIR = "/writable/.subiquity"
LOGFILE = os.path.join(LOGDIR, "subiquity-debug.log")
def setup_logger(name=__name__, dir=LOGDIR):
def setup_logger(dir):
LOGFILE = os.path.join(dir, "subiquity-debug.log")
try:
os.makedirs(dir, exist_ok=True)

View File

@ -1,14 +0,0 @@
# 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/>.

View File

@ -1,26 +0,0 @@
# 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/>.
""" Model Policy
"""
from abc import ABC
class BaseModel(ABC):
"""Expected contract for defining models. """
# Back navigation
prev_signal = None

View File

@ -14,7 +14,6 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import logging
from subiquitycore.model import BaseModel
from subiquitycore.utils import crypt_password
@ -55,7 +54,7 @@ class LocalUser(object):
return "%s <%s>" % (self._realname, self._username)
class IdentityModel(BaseModel):
class IdentityModel(object):
""" Model representing user identity
"""

View File

@ -14,16 +14,14 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import logging
from subiquitycore.model import BaseModel
log = logging.getLogger('subiquitycore.login')
class LoginModel(BaseModel):
class LoginModel(object):
""" Model representing Final login screen
"""
prev_signal = 'menu:identity:main'
signals = [
("Login view",

View File

@ -23,7 +23,6 @@ from socket import AF_INET, AF_INET6
import yaml, yaml.reader
from subiquitycore.model import BaseModel
NETDEV_IGNORED_IFACE_NAMES = ['lo']
NETDEV_IGNORED_IFACE_TYPES = ['bridge', 'tun', 'tap', 'dummy', 'sit']
@ -338,7 +337,7 @@ def valid_ipv4_address(addr):
return ip
class NetworkModel(BaseModel):
class NetworkModel(object):
""" Model representing network interfaces
"""

View File

@ -14,16 +14,14 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import logging
from subiquitycore.model import BaseModel
log = logging.getLogger('subiquitycore.welcome')
class WelcomeModel(BaseModel):
class WelcomeModel(object):
""" Model representing language selection
"""
prev_signal = None
supported_languages = ['English',
'Belgian',

View File

@ -29,7 +29,6 @@ class SignalException(Exception):
class Signal:
known_signals = []
signal_stack = []
default_signal = None
def register_signals(self, signals):
if type(signals) is list:

View File

@ -14,7 +14,6 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from urwid import WidgetWrap, Pile, Text, ProgressBar
from collections import deque
from subiquitycore.ui.utils import Padding, Color
from subiquitycore.ui.lists import SimpleList
@ -54,12 +53,12 @@ class Footer(WidgetWrap):
ProgressBar(normal='progress_incomplete',
complete='progress_complete',
current=completion, done=100))
status = deque([
status = [
Padding.line_break(""),
message_widget
])
message_widget,
]
if completion > 0:
status.appendleft(progress_bar)
status.insert(0, progress_bar)
super().__init__(Pile(status))
@ -68,8 +67,4 @@ class Body(WidgetWrap):
"""
def __init__(self):
text = [
Padding.line_break(""),
]
w = (SimpleList(text))
super().__init__(w)
super().__init__(SimpleList([Text("")]))

View File

@ -23,7 +23,7 @@ class SimpleList(WidgetWrap):
super().__init__(self._build_widget())
def _build_widget(self):
lw = SimpleListWalker([x for x in self.contents])
lw = SimpleListWalker(list(self.contents))
return ListBox(lw)

View File

@ -1,22 +0,0 @@
# 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 urwid import (LineBox, ListBox)
def Box(items, title=""):
""" Draws a linebox around a set of items """
container = ListBox(items)
return LineBox(container, title=title)

View File

@ -18,10 +18,8 @@ import errno
import logging
import os
import random
import sys
import yaml
from subprocess import Popen, PIPE, call
from subiquitycore.async import Async
from subprocess import Popen, PIPE
log = logging.getLogger("subiquitycore.utils")
SYS_CLASS_NET = "/sys/class/net/"
@ -86,9 +84,9 @@ def environment_check(check):
return env_ok
def run_command_async(cmd, timeout=None, shell=False):
def run_command_async(pool, cmd, timeout=None, shell=False):
log.debug('calling Async command: {}'.format(cmd))
return Async.pool.submit(run_command, cmd, timeout, shell)
return pool.submit(run_command, cmd, timeout, shell)
def run_command_start(command, timeout=None, shell=False):
@ -150,32 +148,6 @@ def run_command(command, timeout=None, shell=False):
return run_command_summarize(p, stdout, stderr)
def sys_dev_path(devname, path=""):
return SYS_CLASS_NET + devname + "/" + path
def read_sys_net(devname, path, translate=None, enoent=None, keyerror=None):
try:
contents = ""
with open(sys_dev_path(devname, path), "r") as fp:
contents = fp.read().strip()
if translate is None:
return contents
try:
return translate.get(contents)
except KeyError:
log.debug("found unexpected value '%s' in '%s/%s'", contents,
devname, path)
if keyerror is not None:
return keyerror
raise
except OSError as e:
if e.errno == errno.ENOENT and enoent is not None:
return enoent
raise
# FIXME: replace with passlib and update package deps
def crypt_password(passwd, algo='SHA-512'):
# encryption algo - id pairs for crypt()
@ -192,24 +164,6 @@ def crypt_password(passwd, algo='SHA-512'):
return crypt.crypt(passwd, algos[algo] + salt)
def is_root():
""" Returns root or if sudo user exists
"""
euid = os.geteuid()
log.debug('is_root: euid={}'.format(euid))
if euid != 0:
return False
return True
def sudo_user():
""" Returns the value of env['SUDO_USER']
"""
sudo_user = os.getenv('SUDO_USER', None)
return sudo_user
def disable_first_boot_service():
""" Stop firstboot service; which also restores getty service """
log.info('disabling first boot service')