Merge pull request #94 from CanonicalLtd/start_env_check

Start env check
This commit is contained in:
Adam Stokes 2015-10-22 17:21:50 -04:00
commit ef43a3d81e
7 changed files with 128 additions and 8 deletions

View File

@ -18,10 +18,11 @@ import argparse
import sys import sys
import logging import logging
import signal import signal
from subiquity.log import setup_logger from subiquity.log import setup_logger, LOGFILE
from subiquity import __version__ as VERSION from subiquity import __version__ as VERSION
from subiquity.core import Controller as Subiquity from subiquity.core import Controller as Subiquity
from subiquity.ui.frame import SubiquityUI from subiquity.ui.frame import SubiquityUI
from subiquity.utils import environment_check
def parse_options(argv): def parse_options(argv):
@ -55,10 +56,15 @@ def main():
signal.signal(signal.SIGINT, control_c_handler) signal.signal(signal.SIGINT, control_c_handler)
env_ok = environment_check()
if env_ok is False:
print('Failed environment check. Check {} for errors.'.format(LOGFILE))
return 1
ui = SubiquityUI() ui = SubiquityUI()
subiquity_interface = Subiquity(ui, opts) subiquity_interface = Subiquity(ui, opts)
subiquity_interface.run() subiquity_interface.run()
if __name__ == '__main__': if __name__ == '__main__':
main() sys.exit(main())

View File

@ -24,6 +24,7 @@ from subiquity.ui.views import (DiskPartitionView, AddPartitionView,
RaidView) RaidView)
import subiquity.utils as utils import subiquity.utils as utils
from subiquity.ui.dummy import DummyView from subiquity.ui.dummy import DummyView
from subiquity.ui.error import ErrorView
from subiquity.curtin import (curtin_write_storage_actions, from subiquity.curtin import (curtin_write_storage_actions,
curtin_write_preserved_actions) curtin_write_preserved_actions)
@ -55,16 +56,37 @@ class FilesystemController(ControllerPolicy):
self.ui.set_body(FilesystemView(self.model, self.ui.set_body(FilesystemView(self.model,
self.signal)) self.signal))
def filesystem_error(self, error_fname):
title = "Filesystem error"
footer = ("Error while installing Ubuntu")
error_msg = "Failed to obtain write permissions to /tmp"
self.ui.set_header(title)
self.ui.set_footer(footer, 30)
self.ui.set_body(ErrorView(self.signal, error_msg))
def filesystem_handler(self, reset=False, actions=None): def filesystem_handler(self, reset=False, actions=None):
if actions is None and reset is False: if actions is None and reset is False:
self.signal.emit_signal('network:show') self.signal.emit_signal('network:show')
log.info("Rendering curtin config from user choices") log.info("Rendering curtin config from user choices")
try:
curtin_write_storage_actions(actions=actions) curtin_write_storage_actions(actions=actions)
except PermissionError:
log.exception('Failed to write storage actions')
self.signal.emit_signal('filesystem:error',
'curtin_write_storage_actions')
return None
log.info("Rendering preserved config for post install") log.info("Rendering preserved config for post install")
preserved_actions = [preserve_action(a) for a in actions] preserved_actions = [preserve_action(a) for a in actions]
try:
curtin_write_preserved_actions(actions=preserved_actions) curtin_write_preserved_actions(actions=preserved_actions)
except PermissionError:
log.exception('Failed to write preserved actions')
self.signal.emit_signal('filesystem:error',
'curtin_write_preserved_actions')
return None
self.signal.emit_signal('identity:show') self.signal.emit_signal('identity:show')
# Filesystem/Disk partition ----------------------------------------------- # Filesystem/Disk partition -----------------------------------------------

View File

@ -59,7 +59,13 @@ class InstallProgressController(ControllerPolicy):
log.debug('Curtin Install: calling curtin with ' log.debug('Curtin Install: calling curtin with '
'storage/net/postinstall config') 'storage/net/postinstall config')
try:
curtin_write_postinst_config(postconfig) curtin_write_postinst_config(postconfig)
except PermissionError:
log.exception('Failed to write curtin post-install config')
self.signal.emit_signal('filesystem:error',
'curtin_write_postinst_config')
return None
configs = [CURTIN_CONFIGS['network'], configs = [CURTIN_CONFIGS['network'],
CURTIN_CONFIGS['storage'], CURTIN_CONFIGS['storage'],

View File

@ -13,6 +13,7 @@
# You should have received a copy of the GNU Affero General Public License # 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/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
import logging
from subiquity.controller import ControllerPolicy from subiquity.controller import ControllerPolicy
from subiquity.models import NetworkModel from subiquity.models import NetworkModel
from subiquity.ui.views import (NetworkView, from subiquity.ui.views import (NetworkView,
@ -23,6 +24,7 @@ from subiquity.ui.dummy import DummyView
from subiquity.curtin import curtin_write_network_actions from subiquity.curtin import curtin_write_network_actions
log = logging.getLogger("subiquity.controller.network")
class NetworkController(ControllerPolicy): class NetworkController(ControllerPolicy):
def __init__(self, common): def __init__(self, common):
@ -40,7 +42,14 @@ class NetworkController(ControllerPolicy):
self.ui.set_body(NetworkView(self.model, self.signal)) self.ui.set_body(NetworkView(self.model, self.signal))
def network_finish(self, actions): def network_finish(self, actions):
try:
curtin_write_network_actions(actions) curtin_write_network_actions(actions)
except (PermissionError, FileNotFoundError):
log.exception('Failed to obtain write permission')
self.signal.emit_signal('filesystem:error',
'curtin_write_network_actions')
return None
self.signal.emit_signal('filesystem:show') self.signal.emit_signal('filesystem:show')
def set_default_route(self): def set_default_route(self):

View File

@ -17,10 +17,10 @@ import logging
import os import os
from logging.handlers import TimedRotatingFileHandler from logging.handlers import TimedRotatingFileHandler
LOGDIR = "logs"
LOGFILE = os.path.join(LOGDIR, "debug.log")
def setup_logger(name=__name__): def setup_logger(name=__name__):
LOGDIR = "logs"
LOGFILE = os.path.join(LOGDIR, "debug.log")
if not os.path.isdir(LOGDIR): if not os.path.isdir(LOGDIR):
os.makedirs(LOGDIR) os.makedirs(LOGDIR)
log = TimedRotatingFileHandler(LOGFILE, log = TimedRotatingFileHandler(LOGFILE,

View File

@ -44,6 +44,9 @@ class FilesystemModel(ModelPolicy):
('Filesystem view', ('Filesystem view',
'filesystem:show', 'filesystem:show',
'filesystem'), 'filesystem'),
('Filesystem error',
'filesystem:error',
'filesystem_error'),
('Filesystem finish', ('Filesystem finish',
'filesystem:finish', 'filesystem:finish',
'filesystem_handler'), 'filesystem_handler'),

View File

@ -18,11 +18,85 @@ import errno
import logging import logging
import os import os
import random import random
import yaml
from subprocess import Popen, PIPE from subprocess import Popen, PIPE
from subiquity.async import Async from subiquity.async import Async
log = logging.getLogger("subiquity.utils") log = logging.getLogger("subiquity.utils")
SYS_CLASS_NET = "/sys/class/net/" SYS_CLASS_NET = "/sys/class/net/"
ENVIRONMENT_CHECK = '''
checks:
read:
file:
- /var/log/syslog
write:
directory:
- /tmp
mount:
directory:
- /proc
- /sys
exec:
file:
- /sbin/hdparm
- /usr/bin/curtin
'''
def environment_check(check=ENVIRONMENT_CHECK):
''' Check the environment to ensure subiquity can run without issues.
'''
log.info('Checking environment for installer requirements...')
def is_file(x):
return os.path.isfile(x)
def is_directory(x):
return os.path.isdir(x)
def is_mount(x):
return os.path.ismount(x)
def is_writable(x):
return os.access(x, os.W_OK)
def is_readable(x):
return os.access(x, os.R_OK)
def is_executable(x):
return os.access(x, os.X_OK)
check_map = {
'read': is_readable,
'write': is_writable,
'exec': is_executable,
'file': is_file,
'directory': is_directory,
'mount': is_mount,
}
checks = yaml.safe_load(check).get('checks', None)
if not checks:
log.error('Invalid environment check configuration')
return False
env_ok = True
for check_type in [c for c in checks
if c in ['read', 'write', 'mount', 'exec']]:
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 check_map[ftype](i) is False:
log.error('FAIL: {} is NOT of type: {}'.format(i, ftype))
env_ok = False
continue
if check_map[check_type](i) is False:
log.error('FAIL: {} does NOT have required attr: {}'.format(i,
check_type))
env_ok = False
return env_ok
def run_command_async(cmd, timeout=None): def run_command_async(cmd, timeout=None):