From 2e123b1261fe6099b4787e2e8ef6637652b9d0f5 Mon Sep 17 00:00:00 2001 From: Igor Pashev Date: Thu, 11 Apr 2013 23:44:37 +0000 Subject: Use single-fs BE, install minimal system, create boto archive --- install | 147 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 131 insertions(+), 16 deletions(-) (limited to 'install') diff --git a/install b/install index 53c6f1b..98147dd 100755 --- a/install +++ b/install @@ -15,9 +15,10 @@ from lib.snack import * from snack import * from subprocess import Popen, PIPE, call from pprint import pprint -from tempfile import mkstemp +from tempfile import mkstemp, mkdtemp from urllib2 import urlopen, URLError, HTTPError from time import sleep +from os.path import basename import os import re import sys @@ -29,6 +30,12 @@ screen = None # List of disks installed on the system: hdds = [] +# List of zpools found on system: +zpools = [] + +# List of imported zpools, we should export them after installation: +imported_zpools = [] + # Name of the root ZFS pool: either existing or newly created rpool = None @@ -38,6 +45,9 @@ rslice = None # Created boot environment, e. g. rpoot/ROOT/osdy-0 bootenv = None +# Install root dir +rootdir = None + # Version to install: codename = 'bok' @@ -51,7 +61,7 @@ mirrors = [ # Stages of debootstraping in order. Debootstrap gives # progress for each stage, but we need entire progress. -# Format: mile : (a, z, desc), where: +# Format: mile : (a, z), where: # - mile is a stage name, e. g. DOWNDEBS; # - a, z - the start and the end position on progress bar, # e. i. a=0 z=100 - entire progress bar (100%); @@ -63,8 +73,8 @@ miles = { 'DOWNDEBS' : (10, 25), # Downloading packages (*.deb) 'EXTRACTPKGS' : (25, 45), # Extracting core packages 'INSTCORE' : (45, 50), # Installing core packages - 'UNPACKREQ' : (50, 60), # Unpacking required paclages - 'CONFREQ' : (60, 70), # Configuring required paclages + 'UNPACKREQ' : (50, 60), # Unpacking required packages + 'CONFREQ' : (60, 70), # Configuring required packages 'UNPACKBASE' : (70, 85), # Unpacking the base system 'CONFBASE' : (85, 100), # Configuring the base system } @@ -102,9 +112,16 @@ befs = [ 'setuid' : 'off', 'devices' : 'off', }}, - {'name':'/var/tmp', 'options':{}}, + {'name':'/var/tmp', 'options':{ + 'compression' : 'on', + 'setuid' : 'off', + 'devices' : 'off', + }}, ] +# XXX Not yet. +befs = [] + class Abort(Exception): ''' User clicked "Cancel" ''' pass @@ -198,7 +215,7 @@ def create_root_slice(hdd_name): ButtonChoiceWindow(screen, title='Creating of root slice failed', text=err, buttons = ['Ok'], width=70) return None - return '{}s0'.format(hdd_name) + return hdd_name + 's0' def create_rpool(hdd): global rslice @@ -224,6 +241,7 @@ def create_rpool(hdd): title='Creating of ZFS root pool failed', text=err, buttons = ['Ok'], width=70) return None + imported_zpools.append(pool_name) return pool_name def pool_is_imported(pool): @@ -251,6 +269,7 @@ def configure_rpool(): title='Importing of ZFS pool "{}" failed'.format(rpool), text=err, buttons=['Ok'], width=70) rpool = None + imported_zpools.append(rpool) def zfs_exists(fs): fs_exists = call(['zfs', 'list', '-H', fs], stdout=PIPE, stderr=PIPE) @@ -278,6 +297,7 @@ def zfs_create(fs, zvol=None, options={}): def configure_zfs(): global bootenv + global rootdir progress = ProgressBar(screen, title='Creating ZFS filesystems', top = 4 + len(befs), # 4 for ROOT, /swap, /home, and BE @@ -286,7 +306,7 @@ def configure_zfs(): root = rpool + '/ROOT' if not zfs_exists(root): progress.text = 'Creating ' + root - zfs_create(root, options={'canmount':'off'}) + zfs_create(root, options={'canmount':'off', 'mountpoint':'none'}) progress.advance() swap = rpool + '/swap' @@ -303,16 +323,16 @@ def configure_zfs(): progress.advance() # Make sure we are creating new boot environment - bootenv = None - for be_no in range(20): + for be_no in range(50): bootenv = root + '/osdy-' + str(be_no) if not zfs_exists(bootenv): break else: bootenv = None + rootdir = mkdtemp(prefix='install-', dir='/mnt/' + rpool) progress.text = 'Creating ' + bootenv - zfs_create(bootenv, options={'canmount':'noauto'}) + zfs_create(bootenv, options={'mountpoint':'/' + basename(rootdir)}) progress.advance() for fs in befs: @@ -321,6 +341,8 @@ def configure_zfs(): zfs_create(p, options=fs['options']) progress.advance() + call(['zfs', 'snapshot', '-r', bootenv + '@empty']) + def choose_hdd(number_of_zpools = 0): hdd_items = map(lambda x: '{}: {} {}'.format(x.name, x.capacity, x.description), hdds) choice = None @@ -445,7 +467,7 @@ def get_mirror(): def valid_mirror(mirror): - progress = ProgressMessage(screen, title='Please, wait', + progress = ProgressMessage(screen, title='Please, wait...', text='Checking APT mirror: ' + mirror) try: o = urlopen('{mirror}/dists/{codename}/Release'.format( @@ -482,6 +504,7 @@ def configure_mirror(): global mirror items = map(lambda x: '{url} ({info})'.format(url=x[0], info=x[1]), mirrors) items.append(('Enter another mirror', None)) + mirror = None while not mirror: (choice, m) = ListboxChoiceWindow(screen, title='Choose APT mirror', @@ -524,9 +547,10 @@ def debootstrap(): os.close(write) try: os.execl('/usr/sbin/debootstrap', 'debootstrap', + '--exclude=locales,gawk,aptitude,aptitude-common,libboost-iostreams1.48.0,libboost-iostreams1.49.0,libcwidget3', '--debian-installer', '--no-check-gpg', '--include=illumos-grub,illumos-kernel', - codename, '/mnt/' + bootenv, mirror) # bootenv includes zpool name + codename, rootdir, mirror) except OSError as e: sys.exit(e.errno) else: @@ -575,10 +599,100 @@ def debootstrap(): status = os.wait()[1] return os.WEXITSTATUS(status) +def install(): + while True: + configure_mirror() + code = debootstrap() + if code == 0: + return + choice = ButtonChoiceWindow(screen, title='Installation failed', + text='Debootstrap failed.', + buttons=[('Try again', 'again'), ('Cancel', 'cancel')], + width=40) + if choice == 'cancel': + raise Abort('debootstrap failed') + p = ProgressMessage(screen, title='Please, wait...', text='Undoing previous try...') + umount_in_bootenv() + call(['zfs', 'rollback', '-r', bootenv + '@empty']) + + +def umount(path): + call(['umount', path], stdout=PIPE, stderr=PIPE) +def umount_in_bootenv(): + '''unmount all FS mounted in BE on final cleanup. + These FS also may be left after interruption or debootstrap failure''' + global bootenv + global rootdir + + if not bootenv: + return + fslist = ['/dev/fd', '/proc', '/devices'] + progress = ProgressBar(screen, title='Unmounting filesystems', top=len(fslist)) + for fs in fslist: + progress.advance() + progress.text = 'Unmounting ' + fs + umount(rootdir + fs) def destroy_bootenv(): - pass + global bootenv + global rootdir + if not bootenv: + return + umount_in_bootenv() + progress = ProgressMessage(screen, title='Destroying boot environment', + text='Destroying "{}", please wait...'.format(bootenv)) + call(['zfs', 'destroy', '-r', bootenv], stdout=PIPE, stderr=PIPE) + bootenv = None + try: + os.rmdir(rootdir) + rootdir = None + except: + pass + +def in_bootenv(cmd): + chroot = ['chroot', rootdir] + chroot += cmd + return call(chroot, stderr=PIPE, stdout=PIPE) + +def configure_bootenv(): + progress = ProgressBar(screen, title='Configuring Dyson boot environment', width=50) + progress.text = 'Preparing chroot ...' + call(['mount', '-F' , 'lofs', '/devices', rootdir + '/devices'], stdout=PIPE, stderr=PIPE) + call(['mount', '-F' , 'fd', '-', rootdir + '/dev/fd'], stdout=PIPE, stderr=PIPE) + call(['mount', '-F' , 'proc', '-', rootdir + '/proc'], stdout=PIPE, stderr=PIPE) + progress.progress = 10 + progress.text = 'Updating devices ...' + in_bootenv(['/sbin/devfsadm']) + progress.progress = 40 + progress.text = 'Updating boot archive, please wait ...' + in_bootenv(['/sbin/bootadm', 'update-archive']) + progress.progress = 80 + + +def cleanup(): + '''Cleanup after successful installation''' + umount_in_bootenv() + progress = ProgressMessage(screen, title='Cleaning up') + progress.text = 'Unmounting boot environment ...' + call(['zfs', 'destroy', '-r', bootenv + '@empty'], stdout=PIPE, stderr=PIPE) + call(['zfs', 'unmount', bootenv], stdout=PIPE, stderr=PIPE) + call(['zfs', 'set', 'canmount=noauto', bootenv], stdout=PIPE, stderr=PIPE) + call(['zfs', 'set', 'mountpoint=/', bootenv], stdout=PIPE, stderr=PIPE) + try: + os.rmdir(rootdir) + except: + pass + + progress.text = 'Exporting ZFS pools ...' + for pool in imported_zpools: + call(['zpool', 'export', '-f', pool], stdout=PIPE, stderr=PIPE) + +def goodbye(): + ButtonChoiceWindow(screen, title='Success', + text='The Dyson system is successfully installed and configured. ' + 'Hopefully, it will boot :-)', + buttons=['Reboot']) screen = SnackScreen() screen.pushHelpLine(' ') @@ -586,13 +700,14 @@ try: welcome() find_hdds() configure_rpool() - configure_mirror() configure_zfs() - debootstrap() + install() + configure_bootenv() + cleanup() + goodbye() except Abort as e: destroy_bootenv() - pass except NoDisks as e: print (e) finally: -- cgit v1.2.3