Skip to content

Commit 5d4d61f

Browse files
committed
BUGFIX: attempt to umount all partitions on a disk before nuking.
If we are unable to unmount the partitions, raise an error unless attribute 'halt_install_on_error=False'.
1 parent c791f0d commit 5d4d61f

3 files changed

Lines changed: 89 additions & 33 deletions

File tree

common/src/stack/storage-config/bin/initialize-storage.py

Lines changed: 59 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,28 @@
2828
## functions
2929
##
3030

31+
# util wrapper around subprocess
32+
def _exec(cmd, *args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, encoding='utf-8', shlexsplit=False, **kwargs):
33+
'''
34+
wrapper around subprocess to default common arguments while allowing overriding.
35+
'''
36+
if shlexsplit:
37+
cmd = shlex.split(cmd)
38+
return subprocess.run(cmd, **kwargs, stdout=stdout, stderr=stderr, encoding=encoding)
39+
40+
41+
# util to try to guess the truthiness of a string
42+
def str2bool(s):
43+
"""Converts an on/off, yes/no, true/false string to
44+
True/False."""
45+
if type(s) == bool:
46+
return s
47+
if s and s.upper() in [ 'ON', 'YES', 'Y', 'TRUE', '1' ]:
48+
return True
49+
else:
50+
return False
51+
52+
3153
def nukeLVM(volumegroup):
3254
for (display, remove) in [
3355
('lvdisplay --all -c', 'lvremove --force'),
@@ -48,6 +70,7 @@ def nukeLVM(volumegroup):
4870
stdout = FNULL,
4971
stderr = subprocess.STDOUT)
5072

73+
5174
def stopMD():
5275
#
5376
# we need to stop all MDs before we can remove them
@@ -63,34 +86,51 @@ def nukeMD(part):
6386
stderr = subprocess.STDOUT)
6487

6588

66-
def nukeDisk(disk):
67-
if 'disklabel' in attributes:
68-
disklabel = attributes['disklabel']
69-
else:
70-
disklabel = 'gpt'
89+
def nukeDisk(disk, disklabel, halt_on_error):
90+
'''
91+
destroy the master boot record (via dd),
92+
create a new partition label (msdos/gpt) based on the 'disklabel' attribute
93+
attempts to unmount any partitions on that disk that may be mounted
94+
'''
95+
96+
# unmount everything on the disk first.
97+
# NOTE: sles11 does not have the version of umount that allows recursive `umount -A /dev/some/`
98+
# so instead, iterate over partitions per disk, umounting parts only if mounted.
99+
100+
subproc_args = {'stdout': subprocess.PIPE, 'stderr': subprocess.STDOUT, 'check': halt_on_error}
101+
102+
cmd = f'lsblk --raw --noheadings -o name,mountpoint /dev/{disk}'
103+
proc = _exec(cmd, shlexsplit=True, **subproc_args)
104+
105+
cmd = 'umount -f /dev/{}'
106+
for line in proc.stdout.splitlines():
107+
line = line.split()
108+
109+
if len(line) == 2:
110+
_exec(cmd.format(f'{line[0]}'), shlexsplit=True, **subproc_args)
71111

72-
#
73112
# Clear out the master boot record of the drive
74-
#
75113
cmd = 'dd if=/dev/zero of=/dev/%s count=512 bs=1' % disk
76-
subprocess.call(shlex.split(cmd),
77-
stdout = FNULL, stderr = subprocess.STDOUT)
114+
_exec(cmd, shlexsplit=True, **subproc_args)
78115

116+
# install new partition table
79117
cmd = 'parted -s /dev/%s mklabel %s' % (disk, disklabel)
80-
subprocess.call(shlex.split(cmd),
81-
stdout = FNULL, stderr = subprocess.STDOUT)
82-
83-
return
118+
_exec(cmd, shlexsplit=True, **subproc_args)
84119

85120
##
86121
## MAIN
87122
##
88123

124+
# get info about attributes
125+
89126
if 'nukecontroller' in attributes:
90127
nukecontroller = attributes['nukecontroller']
91128
else:
92129
nukecontroller = 'false'
93130

131+
halt_on_error = str2bool(attributes.get('halt_install_on_error', True))
132+
disklabel = attributes.get('disklabel', 'gpt')
133+
94134
if 'nukedisks' in attributes:
95135
n = attributes['nukedisks']
96136

@@ -199,5 +239,9 @@ def nukeDisk(disk):
199239
#
200240
for disk in disks:
201241
if disk['nuke']:
202-
nukeDisk(disk['device'])
203-
242+
try:
243+
nukeDisk(disk['device'], disklabel, halt_on_error)
244+
except subprocess.CalledProcessError as e:
245+
print(' '.join(e.cmd))
246+
print(f'output: {e.stdout}')
247+
sys.exit(1)

common/src/stack/storage-config/lib/stacki_storage.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -320,12 +320,12 @@ def get_sles11_media_type(dev_name):
320320
arr = l.strip().split()
321321

322322
# line 0
323-
if len(arr) == 1 and arr[0] == 'partition':
323+
if len(arr) == 1 and arr[0] == 'partition:':
324324
blk_type = 'part'
325325
continue
326326

327327
# line 0
328-
if len(arr) == 1 and arr[0] == 'disk':
328+
if len(arr) == 1 and arr[0] == 'disk:':
329329
blk_type = 'disk'
330330
continue
331331

sles/src/stack/images/common/sles-stacki.img-patches/usr/lib/YaST2/startup/First-Stage/F08-stacki

Lines changed: 28 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,20 @@
1313
unset PYTHONPATH
1414
export LD_LIBRARY_PATH=/opt/stack/lib
1515

16+
# util func to pause the install, alert the console user, alert the MQ
17+
function halt_install {
18+
console_err_msg=$1
19+
mq_health_msg=$2
20+
21+
touch /tmp/wait
22+
echo $console_err_msg
23+
while [ -f /tmp/wait ]
24+
do
25+
sleep 1
26+
/opt/stack/bin/smq-publish -chealth $mq_health_msg
27+
done
28+
}
29+
1630
/opt/stack/bin/stacki-profile.py
1731

1832
#
@@ -54,23 +68,22 @@ echo "tracker = ${FRONTEND}:3825" > /tmp/stack.conf
5468

5569
# nuke the disks, if appropriate
5670
/opt/stack/bin/initialize-storage.py
71+
if [ $? -ne 0 ]
72+
then
73+
halt_install "Unable to initialize internal storage configuration." \
74+
'{"state": "nukedisk failed - check console or reinstall with halt_install_on_error=False"}'
75+
fi
5776

5877
#
5978
# configure the hardware disk array controller first
6079
#
6180
/opt/stack/bin/configure-controllers.py
6281
if [ $? -ne 0 ]
6382
then
64-
touch /tmp/wait
65-
echo "Unable to complete storage controller configuration."
66-
while [ -f /tmp/wait ]
67-
do
68-
sleep 1
69-
/opt/stack/bin/smq-publish -chealth '{"state": "controller config failed - check console or reinstall with halt_install_on_error=False"}'
70-
done
83+
halt_install "Unable to complete storage controller configuration." \
84+
'{"state": "controller config failed - check console or reinstall with halt_install_on_error=False"}'
7185
fi
7286

73-
7487
udevadm settle --timeout=60
7588

7689
# NOTE: we initialize storage twice in RHEL, so do the same thing here, too
@@ -80,6 +93,11 @@ udevadm settle --timeout=60
8093
# master boot record on a LUN may be corrupted and require initialization.
8194

8295
/opt/stack/bin/initialize-storage.py
96+
if [ $? -ne 0 ]
97+
then
98+
halt_install "Unable to initialize internal storage configuration after storage controller config." \
99+
'{"state": "nukedisk failed - check console or reinstall with halt_install_on_error=False"}'
100+
fi
83101

84102
#
85103
# then configure the partitions
@@ -90,17 +108,11 @@ udevadm settle --timeout=60
90108
/opt/stack/bin/output-bootloader.py > /tmp/bootloader.xml
91109

92110
# give ourselves the ability to hold the installation prior to the start of yast
93-
#
94111
grep stack-debug /proc/cmdline 2>&1 > /dev/null
95112
if [ $? -eq 0 ]
96113
then
97-
touch /tmp/wait
98-
echo "Stacki debug wait loop - remove /tmp/wait to continue"
99-
while [ -f /tmp/wait ]
100-
do
101-
sleep 1
102-
/opt/stack/bin/smq-publish -chealth '{"state": "install wait"}'
103-
done
114+
halt_install "Stacki debug wait loop - remove /tmp/wait to continue" \
115+
'{"state": "install wait"}'
104116
fi
105117

106118
if [[ -n $YUMSERVER ]]

0 commit comments

Comments
 (0)