Merge pull request #94 from CanonicalLtd/start_env_check
Start env check
This commit is contained in:
commit
ef43a3d81e
|
@ -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())
|
||||||
|
|
|
@ -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 -----------------------------------------------
|
||||||
|
|
|
@ -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'],
|
||||||
|
|
|
@ -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):
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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'),
|
||||||
|
|
|
@ -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):
|
||||||
|
|
Loading…
Reference in New Issue