diff --git a/common/src/stack/storage-config/bin/initialize-storage.py b/common/src/stack/storage-config/bin/initialize-storage.py index 58482a207..c1e5b928b 100755 --- a/common/src/stack/storage-config/bin/initialize-storage.py +++ b/common/src/stack/storage-config/bin/initialize-storage.py @@ -28,6 +28,28 @@ ## functions ## +# util wrapper around subprocess +def _exec(cmd, *args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, encoding='utf-8', shlexsplit=False, **kwargs): + ''' + wrapper around subprocess to default common arguments while allowing overriding. + ''' + if shlexsplit: + cmd = shlex.split(cmd) + return subprocess.run(cmd, **kwargs, stdout=stdout, stderr=stderr, encoding=encoding) + + +# util to try to guess the truthiness of a string +def str2bool(s): + """Converts an on/off, yes/no, true/false string to + True/False.""" + if type(s) == bool: + return s + if s and s.upper() in [ 'ON', 'YES', 'Y', 'TRUE', '1' ]: + return True + else: + return False + + def nukeLVM(volumegroup): for (display, remove) in [ ('lvdisplay --all -c', 'lvremove --force'), @@ -48,6 +70,7 @@ def nukeLVM(volumegroup): stdout = FNULL, stderr = subprocess.STDOUT) + def stopMD(): # # we need to stop all MDs before we can remove them @@ -63,34 +86,51 @@ def nukeMD(part): stderr = subprocess.STDOUT) -def nukeDisk(disk): - if 'disklabel' in attributes: - disklabel = attributes['disklabel'] - else: - disklabel = 'gpt' +def nukeDisk(disk, disklabel, halt_on_error): + ''' + destroy the master boot record (via dd), + create a new partition label (msdos/gpt) based on the 'disklabel' attribute + attempts to unmount any partitions on that disk that may be mounted + ''' + + # unmount everything on the disk first. + # NOTE: sles11 does not have the version of umount that allows recursive `umount -A /dev/some/` + # so instead, iterate over partitions per disk, umounting parts only if mounted. + + subproc_args = {'stdout': subprocess.PIPE, 'stderr': subprocess.STDOUT, 'check': halt_on_error} + + cmd = f'lsblk --raw --noheadings -o name,mountpoint /dev/{disk}' + proc = _exec(cmd, shlexsplit=True, **subproc_args) + + cmd = 'umount -f /dev/{}' + for line in proc.stdout.splitlines(): + line = line.split() + + if len(line) == 2: + _exec(cmd.format(f'{line[0]}'), shlexsplit=True, **subproc_args) - # # Clear out the master boot record of the drive - # cmd = 'dd if=/dev/zero of=/dev/%s count=512 bs=1' % disk - subprocess.call(shlex.split(cmd), - stdout = FNULL, stderr = subprocess.STDOUT) + _exec(cmd, shlexsplit=True, **subproc_args) + # install new partition table cmd = 'parted -s /dev/%s mklabel %s' % (disk, disklabel) - subprocess.call(shlex.split(cmd), - stdout = FNULL, stderr = subprocess.STDOUT) - - return + _exec(cmd, shlexsplit=True, **subproc_args) ## ## MAIN ## +# get info about attributes + if 'nukecontroller' in attributes: nukecontroller = attributes['nukecontroller'] else: nukecontroller = 'false' +halt_on_error = str2bool(attributes.get('halt_install_on_error', True)) +disklabel = attributes.get('disklabel', 'gpt') + if 'nukedisks' in attributes: n = attributes['nukedisks'] @@ -199,5 +239,9 @@ def nukeDisk(disk): # for disk in disks: if disk['nuke']: - nukeDisk(disk['device']) - + try: + nukeDisk(disk['device'], disklabel, halt_on_error) + except subprocess.CalledProcessError as e: + print(' '.join(e.cmd)) + print(f'output: {e.stdout}') + sys.exit(1) diff --git a/common/src/stack/storage-config/lib/stacki_storage.py b/common/src/stack/storage-config/lib/stacki_storage.py index 2e2160c15..eb1d9d603 100644 --- a/common/src/stack/storage-config/lib/stacki_storage.py +++ b/common/src/stack/storage-config/lib/stacki_storage.py @@ -320,12 +320,12 @@ def get_sles11_media_type(dev_name): arr = l.strip().split() # line 0 - if len(arr) == 1 and arr[0] == 'partition': + if len(arr) == 1 and arr[0] == 'partition:': blk_type = 'part' continue # line 0 - if len(arr) == 1 and arr[0] == 'disk': + if len(arr) == 1 and arr[0] == 'disk:': blk_type = 'disk' continue diff --git a/sles/src/stack/images/common/sles-stacki.img-patches/usr/lib/YaST2/startup/First-Stage/F08-stacki b/sles/src/stack/images/common/sles-stacki.img-patches/usr/lib/YaST2/startup/First-Stage/F08-stacki index 030413597..fe6c0dde1 100755 --- a/sles/src/stack/images/common/sles-stacki.img-patches/usr/lib/YaST2/startup/First-Stage/F08-stacki +++ b/sles/src/stack/images/common/sles-stacki.img-patches/usr/lib/YaST2/startup/First-Stage/F08-stacki @@ -13,6 +13,20 @@ unset PYTHONPATH export LD_LIBRARY_PATH=/opt/stack/lib +# util func to pause the install, alert the console user, alert the MQ +function halt_install { + console_err_msg=$1 + mq_health_msg=$2 + + touch /tmp/wait + echo $console_err_msg + while [ -f /tmp/wait ] + do + sleep 1 + /opt/stack/bin/smq-publish -chealth $mq_health_msg + done +} + /opt/stack/bin/stacki-profile.py # @@ -54,6 +68,11 @@ echo "tracker = ${FRONTEND}:3825" > /tmp/stack.conf # nuke the disks, if appropriate /opt/stack/bin/initialize-storage.py +if [ $? -ne 0 ] +then + halt_install "Unable to initialize internal storage configuration." \ + '{"state": "nukedisk failed - check console or reinstall with halt_install_on_error=False"}' +fi # # configure the hardware disk array controller first @@ -61,16 +80,10 @@ echo "tracker = ${FRONTEND}:3825" > /tmp/stack.conf /opt/stack/bin/configure-controllers.py if [ $? -ne 0 ] then - touch /tmp/wait - echo "Unable to complete storage controller configuration." - while [ -f /tmp/wait ] - do - sleep 1 - /opt/stack/bin/smq-publish -chealth '{"state": "controller config failed - check console or reinstall with halt_install_on_error=False"}' - done + halt_install "Unable to complete storage controller configuration." \ + '{"state": "controller config failed - check console or reinstall with halt_install_on_error=False"}' fi - udevadm settle --timeout=60 # NOTE: we initialize storage twice in RHEL, so do the same thing here, too @@ -80,6 +93,11 @@ udevadm settle --timeout=60 # master boot record on a LUN may be corrupted and require initialization. /opt/stack/bin/initialize-storage.py +if [ $? -ne 0 ] +then + halt_install "Unable to initialize internal storage configuration after storage controller config." \ + '{"state": "nukedisk failed - check console or reinstall with halt_install_on_error=False"}' +fi # # then configure the partitions @@ -90,17 +108,11 @@ udevadm settle --timeout=60 /opt/stack/bin/output-bootloader.py > /tmp/bootloader.xml # give ourselves the ability to hold the installation prior to the start of yast -# grep stack-debug /proc/cmdline 2>&1 > /dev/null if [ $? -eq 0 ] then - touch /tmp/wait - echo "Stacki debug wait loop - remove /tmp/wait to continue" - while [ -f /tmp/wait ] - do - sleep 1 - /opt/stack/bin/smq-publish -chealth '{"state": "install wait"}' - done + halt_install "Stacki debug wait loop - remove /tmp/wait to continue" \ + '{"state": "install wait"}' fi if [[ -n $YUMSERVER ]]