From d9286b1fd81a354eb4a1ddfd28dd104b9a3c4660 Mon Sep 17 00:00:00 2001 From: Pedro Alvarez Date: Thu, 4 Dec 2014 15:08:52 +0000 Subject: Add initial version of the Baserock installer script --- baserock-installer | 182 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 182 insertions(+) create mode 100755 baserock-installer diff --git a/baserock-installer b/baserock-installer new file mode 100755 index 0000000..8744884 --- /dev/null +++ b/baserock-installer @@ -0,0 +1,182 @@ +#!/usr/bin/python +# Copyright (C) 2014 Codethink Limited +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 of the License. +# +# 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + +'''A Baserock installer.''' + + + +import morphlib +import os +import re +import sys +import json +import yaml +import subprocess +import tempfile +import errno +import time +import stat +import traceback + + +config_file = '/etc/install.conf' +to_mount = ( + ('/proc', 'proc', 'none'), + ('/sys', 'sysfs', 'none'), + +) + +class NotDeviceError(Exception): + pass + +class FileNotExistsError(Exception): + pass + +class NotBaserockRootfsError(Exception): + pass + +def validate_install_values(disk_dest, rootfs): + if not os.path.exists(disk_dest): + print "ERROR: The device %s doesn't exist." % disk_dest + raise FileNotExistsError + if not is_device(disk_dest): + print "ERROR: Not deploying to a device" + raise NotDeviceError + if not is_baserock_rootfs(rootfs): + print "ERROR: The rootfs %s is not a baserock rootfs." % rootfs + raise NotBaserockRootfsError + +def is_baserock_rootfs(rootfs): + return os.path.isdir(os.path.join(rootfs, 'baserock')) + +def run_install(writeext_path, deployment_config, rootfs, disk_dest): + env = dict(os.environ) + env.update(deployment_config) + subprocess.check_call([writeext_path, rootfs, disk_dest], env=env) + +def finish_installation(postinstallcmd): + os.system("sync") + print "Executing `%s` in 5 seconds..." % postinstallcmd + time.sleep(5) + os.system(postinstallcmd) + +def mount(partition, mount_point, fstype): + return subprocess.call(['mount', partition, mount_point, '-t', fstype]) + +def do_mounts(to_mount): + mounted = [] + for mount_point, mount_type, source in to_mount: + print 'Mounting %s in %s' % (source, mount_point) + if not os.path.exists(mount_point): + os.makedirs(mount_point) + if mount(source, mount_point, mount_type) == 0: + mounted.append(mount_point) + return mounted + +def do_unmounts(to_unmount): + for path in reversed(to_unmount): + print 'Unmounting %s' % path + if subprocess.call(['umount', path]) != 0: + print 'WARNING: Failed to `umount %s`' % path + +def check_and_read_config(config_file): + print "Reading configuration from %s..." % config_file + + keys = ('INSTALLER_TARGET_STORAGE_DEVICE', + 'INSTALLER_ROOTFS_TO_INSTALL') + try: + with open(config_file) as f: + config = yaml.load(f) + except IOError as e: + if e.errno != errno.ENOENT: + raise + print "WARNING: Configuration file '%s' not found" % config_file + config = {} + + device, rootfs = (read_option(config, key) + for key in keys) + postinstallcmd = read_option(config, + 'INSTALLER_POST_INSTALL_COMMAND', + 'reboot -f') + return device, rootfs, postinstallcmd + +def read_option(config, option, default_value=None): + try: + value = config[option] + except KeyError as e: + if default_value: + value = default_value + else: + value = raw_input("Option '%s' missing, please enter a value: " + % option) + print "Option '%s' with value '%s'" % (option, value) + return value + +def get_deployment_config(rootfs): + print "Reading deployment.meta of the system to install..." + try: + meta = open(os.path.join(rootfs, 'baserock/deployment.meta')) + except IOError as e: + if e.errno != errno.ENOENT: + raise + print "Failed to read deployment.meta, it will be empty" + deployment_config = {} + else: + deployment_config = json.load(meta).get('configuration', {}) + meta.close() + print "################ Environment #################" + for key in deployment_config: + print "# %s: %s" % (key, deployment_config[key]) + print "##############################################" + return deployment_config + + +def install_system(install_script): + subprocess.check_call(['sh', install_script]) + +def is_device(location): + try: + st = os.stat(location) + return stat.S_ISBLK(st.st_mode) + except OSError as e: + if e.errno == errno.ENOENT: + return False + raise + + +try: + print "Baserock installation script begins..." + mounted = do_mounts(to_mount) + + writeext_path = morphlib.extensions._get_morph_extension_filename( + 'rawdisk', '.write') + + disk_dest, rootfs, postinstallcmd = check_and_read_config( + config_file) + validate_install_values(disk_dest, rootfs) + + deployment_config=get_deployment_config(rootfs) + + run_install(writeext_path, deployment_config, rootfs, disk_dest) + + do_unmounts(mounted) + finish_installation(postinstallcmd) +except BaseException as e: + print traceback.format_exc() + print "Something failed, opening shell..." + print "Once you have finished, use `reboot -f`" + os.execl('/bin/sh', 'sh') -- cgit v1.2.1