split root file systems out of HostVG onto separate partitions
[ovirt-node/TEMP.git] / scripts / ovirt-config-storage
blobaf13935287fa6b9029b14d60138b2b637522bad2
1 #!/bin/bash
3 # To automate the partitioning, pass in the specific fields in this order
4 # ovirt-config-storage [swap size] [boot size] [root size] [logging size] [data size]
6 # All sizes are in megabytes
9 . /etc/init.d/ovirt-functions
11 ME=$(basename "$0")
12 warn() { printf '%s: %s\n' "$ME" "$*" >&2; }
13 die() { warn "$*"; exit 1; }
15 trap '__st=$?; stop_log; exit $__st' 0
16 trap 'exit $?' 1 2 13 15
18 # check that we're not booted from local storage; if so then exit with an error
19 if is_booted_from_local_disk; then
20 die "You cannot configure storage on a running system. Please boot from CD/USB to configure local storage."
23 default_overcommit=0.5
25 default_boot_size=50
26 default_root_size=256
27 default_config_size=5
28 default_logging_size=2048
29 # -1 indicates data partition should use remaining disk
30 default_data_size=-1
32 boot_min_size=50
33 root_min_size=256
34 config_min_size=5
35 logging_min_size=5
36 data_min_size=5
37 swap_min_size=5
39 get_drive_size()
41 local drive=$1
42 local space_var=$2
44 local size=
45 local udi=$(hal-find-by-property --key block.device --string $drive)
46 # if more than one UDI was found then iterate over them to find the base device
47 if [[ "${udi}" =~ \$ ]]; then
48 udi=$(echo $udi | sed 's/\$/ /g')
49 for found in ${udi}; do
50 if [[ "false" == $(hal-get-property --udi $found --key block.is_volume) ]]; then
51 udi=$found
52 break
54 done
56 if [ -z "$udi" ]; then
57 # If hal didn't find the device, it could be a virtio block device
58 # In this case, use sfdisk -s to get the size
59 size=$(sfdisk -s $drive)
60 size=$(echo "scale=0; $size * 1024" | bc -l)
61 else
62 size=$(hal-get-property --udi "$udi" --key storage.size)
63 if [[ "${size}" == "0" ]]; then
64 # disk is probably hot-swappable, use different HAL key
65 # but first check that it is removeable media and that media is present
66 if [[ "true" == "$(hal-get-property --udi "$udi" --key storage.removable.media_available)" ]]; then
67 size=$(hal-get-property --udi "$udi" --key storage.removable.media_size)
72 size=$(echo "scale=0; $size / (1024 * 1024)" | bc -l)
73 echo "$drive ($size MB)"
74 echo "Disk Identifier: $(basename "$udi")"
75 if [ -n "$space_var" ]; then
76 eval $space_var=$size
80 check_partition_sizes()
82 local disk_size need_size
84 local min_data_size=$DATA_SIZE
85 if [ "$DATA_SIZE" = -1 ]; then
86 min_data_size=5
89 printf "\n"
90 get_drive_size $DRIVE SPACE
91 disk_size=$SPACE
92 need_size=$(echo "scale=0;" \
93 "$BOOT_SIZE + $SWAP_SIZE + $ROOT_SIZE * 2" \
94 "+ $CONFIG_SIZE + $LOGGING_SIZE + $min_data_size" | bc -l)
96 if [ $need_size -gt $disk_size ]; then
97 local gap_size=$(echo "scale=0; $need_size-$disk_size;" | bc -l)
98 printf "\n"
99 printf "=============================================================\n"
100 printf "The target storage device is too small for the desired sizes:\n"
101 printf " Size of target storage device: $disk_size MB\n"
102 printf " Total storage size to be used: $need_size MB\n"
103 printf "\n"
104 printf "You need an addition $gap_size MB of storage.\n"
105 printf "\n"
106 return 1
107 else
108 printf "Required Space : $need_size MB\n\n"
111 # check if an existing HostVG exists on a device other than the target
112 devices="$(pvs -o pv_name,vg_name --noheadings | \
113 grep "HostVG"|grep -v $DRIVE|awk '{ print $1 }')"
114 rc=0
115 if [ -n "$devices" ]; then
116 printf "\n"
117 printf "There appears to already be an installation on another device:\n"
118 for device in $devices; do
119 udi=$(hal-find-by-property --key block.device --string $device)
120 printf "\t$device ($(basename "$udi"))\n"
121 done
122 printf "We cannot proceed until either device is removed from the system\n"
123 printf "or until the HostVG volume group is removed.\n"
124 printf "\nTo re-install the node, please select \"Uninstall Node\" from the main\n"
125 printf "menu and then try to partition.\n"
126 printf "\n"
127 rc=1
130 return $rc
133 # Find a usable/selected storage device.
134 # If there are none, give a diagnostic and return nonzero.
135 # If there is just one, e.g., /dev/sda, treat it as selected (see below).
136 # and return 0. If there are two or more, make the user select one
137 # or decline. Upon decline, return nonzero. Otherwise, print the
138 # selected name, then return 0.
139 # Sample output: /dev/sda
140 get_dev_name()
142 local udi_list=$(hal-find-by-capability --capability storage)
143 if test -z "$udi_list"; then
144 warn "ERROR: no usable storage devices detected"
145 return 1
148 local d devices sizes
149 for d in $udi_list; do
150 local drive_type=$(hal-get-property --udi "$d" --key storage.drive_type)
151 test "X$drive_type" = Xdisk || continue
152 local block_dev=$(hal-get-property --udi "$d" --key block.device)
153 # Must start with a '/'.
154 case $block_dev in
155 *' '*)
156 # we use space as separator
157 warn "block device name '$block_dev' contains space; skipping";
158 continue;;
159 /*) ;;
160 *) warn "block device name $block_dev doesn't start with '/';" \
161 " skipping"; continue;;
162 esac
163 test -z "$devices" \
164 && devices="$block_dev" \
165 || devices="$devices $block_dev"
166 done
168 # FIXME: workaround for detecting virtio block devices
169 devices="$devices $(ls /dev/vd? 2> /dev/null | xargs)"
170 devices=$(echo $devices | tr ' ' '\n' | sort -u | xargs)
172 local num_devices=$(echo "$devices" | wc -w)
173 # If there's only one device, use it.
174 case $num_devices in
175 0) warn "ERROR: found no usable block device"; return 1;;
176 1) echo "$devices"; return 0;;
177 *) ;; # found more than one
178 esac
180 # There are two or more; make the user choose.
181 # display description for each disk
182 for d in $devices; do
183 get_drive_size $d >&2
184 done
185 local choices="$devices Abort"
186 select device in $choices
188 test "$device" = Abort && return 1
189 test -z "$device" && continue
190 echo "$device"
191 return 0
192 done
195 do_configure()
197 local name_and_size
198 DRIVE=$(get_dev_name) || return 0
199 get_drive_size $DRIVE SPACE
201 printf "\n\nPlease configure storage partitions.\n\n"
202 printf "* Enter partition sizes in MB.\n"
203 printf "* A value of 0 indicates the partition should be disabled.\n"
204 printf "* If the partition is enabled, it will have a minimum valid size.\n"
205 printf "* Size remaining value is approximate due to cylinder rounding\n"
206 printf " during partitioning.\n"
207 printf "* For the Data partition, a size of -1 indicates that the\n"
208 printf " partition should use up the remaining space on the disk.\n\n"
210 do_review
211 if ask_yes_or_no "Use these default values ([Y]es/[N]o)?"; then
212 return
215 local space_left=$SPACE
216 for part in boot swap root config logging data ; do
217 part_regexp="^0$"
218 if [ "$part" = "data" ]; then
219 part_regexp="^\-1|0$"
221 uc=$(echo $part|tr '[[:lower:]]' '[[:upper:]]')
222 size_var=${uc}_SIZE
223 eval "size=\$$size_var"
224 min_size_var=${part}_min_size
225 eval "min_size=\$$min_size_var"
227 while true; do
228 printf "\n"
229 read -ep "Change $part partition size. (Def. ${size}MB), Min. ${min_size}MB, Max. ~${space_left}MB? or Q to quit "
230 mb_input=$REPLY
231 test -z "$mb_input" && mb_input=$size
232 local size_used=0
233 if [[ $mb_input == "q" || $mb_input == "Q" ]]; then
234 printf "Aborting"
235 return
236 elif [[ $mb_input =~ ^-*[0-9]+$ ]]; then
237 if [[ $mb_input -ge $min_size || $mb_input =~ $part_regexp ]] \
238 && [[ $mb_input -le $space_left ]] ; then
239 eval "$size_var=$mb_input"
240 size_used=$mb_input
241 break;
242 else
243 printf "invalid $part size: $mb_input. "
244 printf "Does not fall into specified range.\n"
246 else
247 printf "invalid $part size: '$mb_input'.\n"
249 done
250 space_left=$(echo "scale=0;$space_left - $size_used" | bc -l)
251 done
253 if ! check_partition_sizes; then
254 printf "Please try partitioning again.\n"
255 DRIVE=
256 return 1
259 # save input variables
260 augtool <<EOF
261 set /files$OVIRT_DEFAULTS/OVIRT_INIT $DRIVE
262 set /files$OVIRT_DEFAULTS/OVIRT_VOL_BOOT_SIZE $BOOT_SIZE
263 set /files$OVIRT_DEFAULTS/OVIRT_VOL_SWAP_SIZE $SWAP_SIZE
264 set /files$OVIRT_DEFAULTS/OVIRT_VOL_ROOT_SIZE $ROOT_SIZE
265 set /files$OVIRT_DEFAULTS/OVIRT_VOL_CONFIG_SIZE $CONFIG_SIZE
266 set /files$OVIRT_DEFAULTS/OVIRT_VOL_LOGGING_SIZE $LOGGING_SIZE
267 set /files$OVIRT_DEFAULTS/OVIRT_VOL_DATA_SIZE $DATA_SIZE
271 do_review()
273 if [ -z "$DRIVE" ]; then
274 printf "\nNo storage device selected.\n"
275 return
278 local data_size_display="$DATA_SIZE MB"
279 if [ "$DATA_SIZE" = -1 ]; then
280 local remaining_mb=$(( $SPACE - $BOOT_SIZE - $SWAP_SIZE \
281 - $ROOT_SIZE * 2 - $CONFIG_SIZE - $LOGGING_SIZE ))
282 data_size_display="$remaining_mb MB"
285 cat <<EOF
287 The local disk will be repartitioned as follows:
288 ================================================
289 Physical Hard Disk: $(get_drive_size $DRIVE)
290 Boot partition size: $BOOT_SIZE MB
291 Swap partition size: $SWAP_SIZE MB
292 Installation partition size: $ROOT_SIZE * 2 MB
293 Configuration partition size: $CONFIG_SIZE MB
294 Logging partition size: $LOGGING_SIZE MB
295 Data partition size: $data_size_display
300 # cleanup lvms on selected disk
301 # - remove mounted filesystems
302 # - remove LVM volumes and groups
303 wipe_lvm_on_disk()
305 unmount_logging
306 for vg in $(pvs -o vg_name --noheadings $DRIVE* 2>/dev/null|sort -u); do
307 wipe_volume_group $vg
308 done
311 perform_partitioning()
313 log "Partitioning drive: $DRIVE"
314 if [ -z "$DRIVE" ]; then
315 printf "\nNo storage device selected.\n"
316 return
319 start_log
320 log "Starting partitioning of $DRIVE"
322 log "Saving parameters"
323 unmount_config /etc/default/ovirt
325 log "Removing old LVM partitions"
326 wipe_lvm_on_disk
328 # begin critical section
329 set -e
331 # FIXME: save a backup copy, just in case?
332 log "Wiping old boot sector"
333 dd if=/dev/zero of=$DRIVE bs=1024K count=1
334 blockdev --rereadpt $DRIVE
335 partprobe -s $DRIVE
337 MEM_SIZE_MB=$(echo "scale=0; $MEM_SIZE_MB / 1024;" | bc -l)
338 local boot_size_si=$(echo "scale=0; $BOOT_SIZE * (1024 * 1024) / (1000 * 1000)" | bc -l)
339 log "Labeling Drive"
340 parted $DRIVE -s "mklabel ${LABEL_TYPE}"
341 log "Creating boot partition"
342 parted $DRIVE -s "mkpartfs primary ext2 0M ${boot_size_si}M"
343 log "Creating Root and RootBackup Partitions"
344 let root1_end=${boot_size_si}+${ROOT_SIZE}
345 let root2_end=${root1_end}+${ROOT_SIZE}
346 parted $DRIVE -s "mkpartfs primary ext2 ${boot_size_si}M ${root1_end}M"
347 parted $DRIVE -s "mkpartfs primary ext2 ${root1_end}M ${root2_end}M"
348 # sleep to ensure filesystems are created before continuing
349 sleep 10
350 e2label ${DRIVE}2 Root
351 e2label ${DRIVE}3 RootBackup
352 tune2fs -c 0 -i 0 ${DRIVE}2
353 tune2fs -c 0 -i 0 ${DRIVE}3
354 log "Creating LVM partition"
355 parted $DRIVE -s "mkpart primary ext2 ${root2_end}M -1"
356 log "Toggling boot on"
357 parted $DRIVE -s "set 1 boot on"
358 log "Toggling LVM on"
359 parted $DRIVE -s "set 4 lvm on"
360 parted $DRIVE -s "print"
361 udevadm settle 2> /dev/null || udevsettle
363 # sync GPT to the legacy MBR partitions
364 if [ "gpt" == "$LABEL_TYPE" ]; then
365 log "Running gptsync to create legacy mbr"
366 gptsync $DRIVE
369 partboot=${DRIVE}1
370 partpv=${DRIVE}4
371 if [ ! -e "$partpv" ]; then
372 # e.g. /dev/cciss/c0d0p2
373 partboot=${DRIVE}p1
374 partpv=${DRIVE}p4
376 log "Creating physical volume"
377 if [ ! -e "$partpv" ]; then
378 log "$partpv is not available!"
379 exit 1
381 dd if=/dev/zero of=${partpv} bs=1024k count=1
382 pvcreate -ff -y "${partpv}"
383 log "Creating volume group"
384 vgcreate /dev/HostVG "${partpv}"
386 log "Creating boot filesystem"
387 if [ ! -e "$partboot" ]; then
388 log "$partboot is not available!"
389 exit 1
391 mke2fs -j "${partboot}" -L "BOOT"
392 tune2fs -c 0 -i 0 "${partboot}"
393 mkdir -p /dev/disk/by-label
394 ln -snf "${partboot}" /dev/disk/by-label/BOOT
396 if [ "$SWAP_SIZE" -gt 0 ]; then
397 log "Creating swap partition"
398 lvcreate --name Swap --size ${SWAP_SIZE}M /dev/HostVG
399 mkswap -L "SWAP" /dev/HostVG/Swap
400 echo "/dev/HostVG/Swap swap swap defaults 0 0" >> /etc/fstab
402 if [ "$CONFIG_SIZE" -gt 0 ]; then
403 log "Creating config partition"
404 lvcreate --name Config --size ${CONFIG_SIZE}M /dev/HostVG
405 mke2fs -j /dev/HostVG/Config -L "CONFIG"
406 tune2fs -c 0 -i 0 /dev/HostVG/Config
408 if [ "$LOGGING_SIZE" -gt 0 ]; then
409 log "Creating log partition"
410 lvcreate --name Logging --size ${LOGGING_SIZE}M /dev/HostVG
411 mke2fs -j /dev/HostVG/Logging -L "LOGGING"
412 tune2fs -c 0 -i 0 /dev/HostVG/Logging
413 echo "/dev/HostVG/Logging /var/log ext3 defaults 0 0" >> /etc/fstab
416 local use_data=1
417 if [ "$DATA_SIZE" -eq -1 ]; then
418 log "Creating data partition with remaining free space"
419 lvcreate --name Data -l 100%FREE /dev/HostVG
420 use_data=0
421 elif [ "$DATA_SIZE" -gt 0 ]; then
422 log "Creating data partition"
423 lvcreate --name Data --size ${DATA_SIZE}M /dev/HostVG
424 use_data=0
427 if [ "$use_data" = 0 ]; then
428 mke2fs -j /dev/HostVG/Data -L "DATA"
429 tune2fs -c 0 -i 0 /dev/HostVG/Data
430 echo "/dev/HostVG/Data /data ext3 defaults 0 0" >> /etc/fstab
431 echo "/data/images /var/lib/libvirt/images bind bind 0 0" >> /etc/fstab
432 echo "/data/core /var/log/core bind bind 0 0" >> /etc/fstab
435 # end critical section
436 set +e
438 log "Mounting config partition"
439 if mount_config; then
440 ovirt_store_config /etc/fstab
443 mount_logging
444 if [ "$use_data" = 0 ]; then
445 log "Mounting data partition"
446 mount_data
448 log "Completed!"
450 stop_log
453 do_confirm()
455 if [ -z "$DRIVE" ]; then
456 printf "\nNo storage device selected.\n"
457 return
460 while true; do
461 sp=' '
462 w='!!WARNING'
463 wb="$w"'!!'
464 w8="$w$w$w$w$w$w$w$w"
465 printf '%s!!\n' \
466 "$w8" \
467 "$w8" \
468 "$wb$sp$w" \
469 "$wb$sp$w" \
470 "$wb If you proceed, this will destroy all data on $w" \
471 "$wb your local system, and your hard disk will be $w" \
472 "$wb irreversably reconfigured $w" \
473 "$wb$sp$w" \
474 "$wb$sp$w" \
475 "$w8" \
476 "$w8"
478 if ask_yes_or_no "Do you wish to proceed ([Y]es/[N]o)?"; then
479 if check_partition_sizes; then
480 perform_partitioning
481 exit 0
483 else
484 return
486 done
489 MEM_SIZE_MB=$(awk '/MemTotal:/ { print $2 }' /proc/meminfo)
490 case $MEM_SIZE_MB in
491 ''|*[^0-9]*) die failed to get system memory size;;
492 esac
493 MEM_SIZE_MB=$(echo "scale=0; $MEM_SIZE_MB / 1024;" | bc -l)
495 overcommit=${OVIRT_OVERCOMMIT:-$default_overcommit}
496 # we multiply the overcommit coefficient by 10 then divide the
497 # product by 10 to avoid decimals in the result
498 OVERCOMMIT_SWAP_SIZE=$(echo "scale=0; (${MEM_SIZE_MB} * (${overcommit} * 10))/10;" | bc -l)
500 # add to the swap the amounts from http://kbase.redhat.com/faq/docs/DOC-15252
501 MEM_SIZE_GB=$(echo "scale=0; $MEM_SIZE_MB/1024;" | bc -l)
502 if [ $MEM_SIZE_GB -le 4 ]; then
503 BASE_SWAP_SIZE=2048
504 elif [ $MEM_SIZE_GB -le 16 ]; then
505 BASE_SWAP_SIZE=4096
506 elif [ $MEM_SIZE_GB -le 64 ]; then
507 BASE_SWAP_SIZE=8192
508 else
509 BASE_SWAP_SIZE=16384
512 CALC_SWAP_SIZE=$(echo "scale=0; ${BASE_SWAP_SIZE} + ${OVERCOMMIT_SWAP_SIZE};" | bc -l)
514 SWAP_SIZE=${OVIRT_VOL_SWAP_SIZE:-$CALC_SWAP_SIZE}
515 BOOT_SIZE=${OVIRT_VOL_BOOT_SIZE:-$default_boot_size}
516 ROOT_SIZE=${OVIRT_VOL_ROOT_SIZE:-$default_root_size}
517 CONFIG_SIZE=${OVIRT_VOL_CONFIG_SIZE:-$default_config_size}
518 LOGGING_SIZE=${OVIRT_VOL_LOGGING_SIZE:-$default_logging_size}
519 DATA_SIZE=${OVIRT_VOL_DATA_SIZE:-$default_data_size}
521 if [ -n "$OVIRT_INIT" ]; then
522 # if present, use the drive selected with 'ovirt_init' boot parameter
523 DRIVE=$OVIRT_INIT
524 get_drive_size $DRIVE SPACE
527 # if the node is Fedora then use GPT, otherwise use MBR
528 if [ -f /etc/fedora-release ]; then
529 LABEL_TYPE="gpt"
530 else
531 LABEL_TYPE="msdos"
534 if [ "$1" == "AUTO" ]; then
535 log "Beginning automatic disk partitioning.\n"
536 if [ -n "$OVIRT_INIT" ]; then
537 # do not format if HostVG exists on selected disk...
538 pvs -o vg_name --noheadings $DRIVE* 2>/dev/null|grep -q -m1 "HostVG"
539 existingHostVG=$?
540 # ... unless overridden by ovirt_firstboot parameter
541 if is_firstboot || [ $existingHostVG -ne 0 ]; then
542 if check_partition_sizes; then
543 log "Partitioning hard disk..."
544 perform_partitioning
546 else
547 log "Skip disk partitioning, HostVG exists"
549 else
550 log "Missing device parameter: unable to partition any disk"
552 else
553 OPTIONS="\"Configure\" \"Review\" \"Commit Changes And Quit\" \"Return To Menu\""
554 eval set $OPTIONS
555 PS3="Choose an option: "
557 while true; do
558 printf "\n\n Storage Configuration\n\n" >&2
560 select OPTION in "$@"
562 case "$OPTION" in
563 "Configure") do_configure ; break ;;
564 "Review") do_review ; break ;;
565 "Commit Changes And Quit") do_confirm ; break ;;
566 "Return To Menu") printf "\nExiting.\n"; exit ;;
567 esac
568 done
569 done