bumped image size
[ovirt-node/TEMP.git] / scripts / ovirt-config-storage
blob57aaebdd41aba1ae11b584689fac792664b9765a
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_root_size=256
26 default_config_size=5
27 default_logging_size=2048
28 # -1 indicates data partition should use remaining disk
29 default_data_size=-1
31 root_min_size=256
32 config_min_size=5
33 logging_min_size=5
34 data_min_size=5
35 swap_min_size=5
37 get_drive_size()
39 local drive=$1
40 local space_var=$2
42 local size=
43 local udi=$(hal-find-by-property --key block.device --string $drive)
44 # if more than one UDI was found then iterate over them to find the base device
45 if [[ "${udi}" =~ \$ ]]; then
46 udi=$(echo $udi | sed 's/\$/ /g')
47 for found in ${udi}; do
48 if [[ "false" == $(hal-get-property --udi $found --key block.is_volume) ]]; then
49 udi=$found
50 break
52 done
54 if [ -z "$udi" ]; then
55 # If hal didn't find the device, it could be a virtio block device
56 # In this case, use sfdisk -s to get the size
57 size=$(sfdisk -s $drive)
58 size=$(echo "scale=0; $size * 1024" | bc -l)
59 else
60 size=$(hal-get-property --udi "$udi" --key storage.size)
61 if [[ "${size}" == "0" ]]; then
62 # disk is probably hot-swappable, use different HAL key
63 # but first check that it is removeable media and that media is present
64 if [[ "true" == "$(hal-get-property --udi "$udi" --key storage.removable.media_available)" ]]; then
65 size=$(hal-get-property --udi "$udi" --key storage.removable.media_size)
70 size=$(echo "scale=0; $size / (1024 * 1024)" | bc -l)
71 echo "$drive ($size MB)"
72 echo "Disk Identifier: $(basename "$udi")"
73 if [ -n "$space_var" ]; then
74 eval $space_var=$size
78 check_partition_sizes()
80 local disk_size need_size
82 local min_data_size=$DATA_SIZE
83 if [ "$DATA_SIZE" = -1 ]; then
84 min_data_size=5
87 printf "\n"
88 get_drive_size $ROOTDRIVE ROOTDRIVESPACE
89 get_drive_size $HOSTVGDRIVE HOSTVGDRIVESPACE
90 ROOT_NEED_SIZE=$(echo "scale=0; $ROOT_SIZE * 2"| bc -l)
91 HOSTVG_NEED_SIZE=$(echo "scale=0;" \
92 "$SWAP_SIZE + $CONFIG_SIZE + $LOGGING_SIZE + $min_data_size" | bc -l)
94 if [ $ROOTDRIVE == $HOSTVGDRIVE ]; then
95 drive_list="ROOT"
96 ROOT_NEED_SIZE=$(echo "scale=0; $ROOT_SIZE * 2 + $HOSTVG_NEED_SIZE"| bc -l)
97 else
98 drive_list="ROOT HOSTVG"
101 for drive in $drive_list; do
102 drive_need_size=$(eval "echo \${$(echo ${drive}_NEED_SIZE)"})
103 drive_disk_size=$(eval "echo \${$(echo ${drive}DRIVESPACE)"})
105 if [ $drive_need_size -gt $drive_disk_size ]; then
106 local gap_size=$(echo "scale=0; $drive_need_size-$drive_disk_size;" | bc -l)
107 printf "\n"
108 printf "=============================================================\n"
109 printf "The target storage device is too small for the desired sizes:\n"
110 printf " Disk Target: $drive \n"
111 printf " Size of target storage device: $drive_disk_size MB\n"
112 printf " Total storage size to be used: $drive_need_size MB\n"
113 printf "\n"
114 printf "You need an additional $gap_size MB of storage.\n"
115 printf "\n"
116 return 1
117 else
118 printf "Required Space : $drive_need_size MB\n\n"
120 done
122 # check if an existing HostVG exists on a device other than the target
123 devices="$(pvs -o pv_name,vg_name --noheadings | \
124 grep "HostVG"|grep -v $HOSTVGDRIVE|awk '{ print $1 }')"
125 rc=0
126 if [ -n "$devices" ]; then
127 printf "\n"
128 printf "There appears to already be an installation on another device:\n"
129 for device in $devices; do
130 udi=$(hal-find-by-property --key block.device --string $device)
131 printf "\t$device ($(basename "$udi"))\n"
132 done
133 printf "We cannot proceed until either device is removed from the system\n"
134 printf "or until the HostVG volume group is removed.\n"
135 printf "\nTo re-install the node, please select \"Uninstall Node\" from the main\n"
136 printf "menu and then try to partition.\n"
137 printf "\n"
138 rc=1
141 return $rc
144 # Find a usable/selected storage device.
145 # If there are none, give a diagnostic and return nonzero.
146 # If there is just one, e.g., /dev/sda, treat it as selected (see below).
147 # and return 0. If there are two or more, make the user select one
148 # or decline. Upon decline, return nonzero. Otherwise, print the
149 # selected name, then return 0.
150 # Sample output: /dev/sda
151 get_dev_name()
153 local udi_list=$(hal-find-by-capability --capability storage)
154 if test -z "$udi_list"; then
155 warn "ERROR: no usable storage devices detected"
156 return 1
159 local d devices sizes
160 for d in $udi_list; do
161 local drive_type=$(hal-get-property --udi "$d" --key storage.drive_type)
162 test "X$drive_type" = Xdisk || continue
163 local block_dev=$(hal-get-property --udi "$d" --key block.device)
164 # Must start with a '/'.
165 case $block_dev in
166 *' '*)
167 # we use space as separator
168 warn "block device name '$block_dev' contains space; skipping";
169 continue;;
170 /*) ;;
171 *) warn "block device name $block_dev doesn't start with '/';" \
172 " skipping"; continue;;
173 esac
174 test -z "$devices" \
175 && devices="$block_dev" \
176 || devices="$devices $block_dev"
177 done
179 # FIXME: workaround for detecting virtio block devices
180 devices="$devices $(ls /dev/vd? 2> /dev/null | xargs)"
181 devices=$(echo $devices | tr ' ' '\n' | sort -u | xargs)
183 local num_devices=$(echo "$devices" | wc -w)
184 # If there's only one device, use it.
185 case $num_devices in
186 0) warn "ERROR: found no usable block device"; return 1;;
187 1) echo "$devices"; return 0;;
188 *) ;; # found more than one
189 esac
191 # There are two or more; make the user choose.
192 # display description for each disk
193 for d in $devices; do
194 get_drive_size $d >&2
195 done
196 local choices="$devices Abort"
197 select device in $choices
199 test "$device" = Abort && return 1
200 test -z "$device" && continue
201 echo "$device"
202 return 0
203 done
206 do_configure()
208 local name_and_size
209 printf "\n\nPlease select the disk to use for the Root.\n\n"
210 ROOTDRIVE=$(get_dev_name) || return 0
211 get_drive_size $ROOTDRIVE ROOTDRIVESPACE
213 printf "\n\nPlease select the disk to use for the HostVG.\n\n"
214 HOSTVGDRIVE=$(get_dev_name) || return 0
215 get_drive_size $HOSTVGDRIVE HOSTVGDRIVESPACE
216 echo $HOSTVGDRIVESPACE
218 printf "\n\nPlease configure storage partitions.\n\n"
219 printf "* Enter partition sizes in MB.\n"
220 printf "* A value of 0 indicates the partition should be disabled.\n"
221 printf "* If the partition is enabled, it will have a minimum valid size.\n"
222 printf "* Size remaining value is approximate due to cylinder rounding\n"
223 printf " during partitioning.\n"
224 printf "* For the Data partition, a size of -1 indicates that the\n"
225 printf " partition should use up the remaining space on the disk.\n\n"
227 do_review
228 if ask_yes_or_no "Use these default values ([Y]es/[N]o)?"; then
229 return
232 local space_left=$HOSTVGDRIVESPACE
233 for part in swap root config logging data ; do
234 part_regexp="^0$"
235 if [ "$part" = "data" ]; then
236 part_regexp="^\-1|0$"
238 uc=$(echo $part|tr '[[:lower:]]' '[[:upper:]]')
239 size_var=${uc}_SIZE
240 eval "size=\$$size_var"
241 min_size_var=${part}_min_size
242 eval "min_size=\$$min_size_var"
244 while true; do
245 printf "\n"
246 read -ep "Change $part partition size. (Def. ${size}MB), Min. ${min_size}MB, Max. ~${space_left}MB? or Q to quit "
247 mb_input=$REPLY
248 test -z "$mb_input" && mb_input=$size
249 local size_used=0
250 if [[ $mb_input == "q" || $mb_input == "Q" ]]; then
251 printf "Aborting"
252 return
253 elif [[ $mb_input =~ ^-*[0-9]+$ ]]; then
254 if [[ $mb_input -ge $min_size || $mb_input =~ $part_regexp ]] \
255 && [[ $mb_input -le $space_left ]] ; then
256 eval "$size_var=$mb_input"
257 size_used=$mb_input
258 break;
259 else
260 printf "invalid $part size: $mb_input. "
261 printf "Does not fall into specified range.\n"
263 else
264 printf "invalid $part size: '$mb_input'.\n"
266 done
267 space_left=$(echo "scale=0;$space_left - $size_used" | bc -l)
268 done
270 if ! check_partition_sizes; then
271 printf "Please try partitioning again.\n"
272 ROOTDRIVE=
273 return 1
276 # save input variables
277 augtool <<EOF
278 set /files$OVIRT_DEFAULTS/OVIRT_INIT $ROOTDRIVE
279 set /files$OVIRT_DEFAULTS/OVIRT_VOL_SWAP_SIZE $SWAP_SIZE
280 set /files$OVIRT_DEFAULTS/OVIRT_VOL_ROOT_SIZE $ROOT_SIZE
281 set /files$OVIRT_DEFAULTS/OVIRT_VOL_CONFIG_SIZE $CONFIG_SIZE
282 set /files$OVIRT_DEFAULTS/OVIRT_VOL_LOGGING_SIZE $LOGGING_SIZE
283 set /files$OVIRT_DEFAULTS/OVIRT_VOL_DATA_SIZE $DATA_SIZE
287 do_review()
289 if [ -z "$ROOTDRIVE" ]; then
290 printf "\nNo Root storage device selected.\n"
291 return
294 local data_size_display="$DATA_SIZE MB"
295 if [ "$DATA_SIZE" = -1 ]; then
297 if [ $ROOTDRIVE == $HOSTVGDRIVE ]; then
298 local remaining_mb=$(( $ROOTDRIVESPACE - $SWAP_SIZE \
299 - $ROOT_SIZE * 2 - $CONFIG_SIZE - $LOGGING_SIZE ))
300 else
301 local remaining_mb=$(( $HOSTVGDRIVESPACE - $SWAP_SIZE - $CONFIG_SIZE - $LOGGING_SIZE ))
303 data_size_display="$remaining_mb MB"
306 cat <<EOF
308 The local disk will be repartitioned as follows:
309 ================================================
310 Root Drive: $(get_drive_size $ROOTDRIVE)
311 HostVG Drive: $(get_drive_size $HOSTVGDRIVE)
312 Swap partition size: $SWAP_SIZE MB
313 Installation partition size: $ROOT_SIZE * 2 MB
314 Configuration partition size: $CONFIG_SIZE MB
315 Logging partition size: $LOGGING_SIZE MB
316 Data partition size: $data_size_display
321 # cleanup lvms on selected disk
322 # - remove mounted filesystems
323 # - remove LVM volumes and groups
324 wipe_lvm_on_disk()
326 unmount_logging
327 for vg in $(pvs -o vg_name --noheadings $HOSTVGDRIVE* 2>/dev/null|sort -u); do
328 wipe_volume_group $vg
329 done
332 perform_partitioning()
334 log "Partitioning drive: $ROOTDRIVE"
335 if [ -z "$HOSTVGDRIVE" ]; then
336 printf "\nNo storage device selected.\n"
337 return
340 start_log
341 log "Starting partitioning of $ROOTDRIVE"
343 log "Saving parameters"
344 unmount_config /etc/default/ovirt
346 log "Removing old LVM partitions"
347 wipe_lvm_on_disk
349 # begin critical section
350 set -e
352 # FIXME: save a backup copy, just in case?
353 log "Wiping old boot sector"
354 dd if=/dev/zero of=$ROOTDRIVE bs=1024K count=1
355 blockdev --rereadpt $ROOTDRIVE
356 partprobe -s $ROOTDRIVE
358 MEM_SIZE_MB=$(echo "scale=0; $MEM_SIZE_MB / 1024;" | bc -l)
359 log "Labeling Drive: $ROOTDRIVE"
360 parted $ROOTDRIVE -s "mklabel ${LABEL_TYPE}"
361 if [ $ROOTDRIVE != $HOSTVGDRIVE ]; then
362 log "Labeling Drive: $HOSTVGDRIVE"
363 parted $HOSTVGDRIVE -s "mklabel ${LABEL_TYPE}"
365 log "Creating Root and RootBackup Partitions"
366 let RootBackup_end=${ROOT_SIZE}*2
367 parted $ROOTDRIVE -s "mkpartfs primary ext2 0M ${ROOT_SIZE}M"
368 parted $ROOTDRIVE -s "mkpartfs primary ext2 ${ROOT_SIZE}M ${RootBackup_end}M"
369 # sleep to ensure filesystems are created before continuing
370 sleep 10
371 e2label ${ROOTDRIVE}1 Root
372 e2label ${ROOTDRIVE}2 RootBackup
373 tune2fs -c 0 -i 0 ${ROOTDRIVE}1
374 tune2fs -c 0 -i 0 ${ROOTDRIVE}2
375 log "Creating LVM partition"
377 if [ $ROOTDRIVE == $HOSTVGDRIVE ]; then
378 parted $HOSTVGDRIVE -s "mkpart primary ext2 ${RootBackup_end}M -1"
379 hostvgpart="3"
380 else
381 parted $HOSTVGDRIVE -s "mkpart primary ext2 0M -1"
382 hostvgpart="1"
384 log "Toggling LVM on"
385 parted $HOSTVGDRIVE -s "set $hostvgpart lvm on"
386 parted $ROOTDRIVE -s "print"
387 udevadm settle 2> /dev/null || udevsettle
389 # sync GPT to the legacy MBR partitions
390 if [ "gpt" == "$LABEL_TYPE" ]; then
391 log "Running gptsync to create legacy mbr"
392 gptsync $ROOTDRIVE
395 partpv=${HOSTVGDRIVE}${hostvgpart}
396 if [ ! -e "$partpv" ]; then
397 # e.g. /dev/cciss/c0d0p2
398 partpv=${HOSTVGDRIVE}p${hostvgpart}
400 log "Creating physical volume"
401 if [ ! -e "$partpv" ]; then
402 log "$partpv is not available!"
403 exit 1
405 dd if=/dev/zero of=${partpv} bs=1024k count=1
406 pvcreate -ff -y "${partpv}"
407 log "Creating volume group"
408 vgcreate /dev/HostVG "${partpv}"
410 mkdir -p /dev/disk/by-label
412 if [ "$SWAP_SIZE" -gt 0 ]; then
413 log "Creating swap partition"
414 lvcreate --name Swap --size ${SWAP_SIZE}M /dev/HostVG
415 mkswap -L "SWAP" /dev/HostVG/Swap
416 echo "/dev/HostVG/Swap swap swap defaults 0 0" >> /etc/fstab
418 if [ "$CONFIG_SIZE" -gt 0 ]; then
419 log "Creating config partition"
420 lvcreate --name Config --size ${CONFIG_SIZE}M /dev/HostVG
421 mke2fs -j /dev/HostVG/Config -L "CONFIG"
422 tune2fs -c 0 -i 0 /dev/HostVG/Config
424 if [ "$LOGGING_SIZE" -gt 0 ]; then
425 log "Creating log partition"
426 lvcreate --name Logging --size ${LOGGING_SIZE}M /dev/HostVG
427 mke2fs -j /dev/HostVG/Logging -L "LOGGING"
428 tune2fs -c 0 -i 0 /dev/HostVG/Logging
429 echo "/dev/HostVG/Logging /var/log ext3 defaults 0 0" >> /etc/fstab
432 local use_data=1
433 if [ "$DATA_SIZE" -eq -1 ]; then
434 log "Creating data partition with remaining free space"
435 lvcreate --name Data -l 100%FREE /dev/HostVG
436 use_data=0
437 elif [ "$DATA_SIZE" -gt 0 ]; then
438 log "Creating data partition"
439 lvcreate --name Data --size ${DATA_SIZE}M /dev/HostVG
440 use_data=0
443 if [ "$use_data" = 0 ]; then
444 mke2fs -j /dev/HostVG/Data -L "DATA"
445 tune2fs -c 0 -i 0 /dev/HostVG/Data
446 echo "/dev/HostVG/Data /data ext3 defaults 0 0" >> /etc/fstab
447 echo "/data/images /var/lib/libvirt/images bind bind 0 0" >> /etc/fstab
448 echo "/data/core /var/log/core bind bind 0 0" >> /etc/fstab
451 # end critical section
452 set +e
454 log "Mounting config partition"
455 if mount_config; then
456 ovirt_store_config /etc/fstab
459 mount_logging
460 if [ "$use_data" = 0 ]; then
461 log "Mounting data partition"
462 mount_data
464 log "Completed!"
466 stop_log
469 do_confirm()
471 if [ -z "$ROOTDRIVE" ]; then
472 printf "\nNo storage device selected.\n"
473 return
476 while true; do
477 sp=' '
478 w='!!WARNING'
479 wb="$w"'!!'
480 w8="$w$w$w$w$w$w$w$w"
481 printf '%s!!\n' \
482 "$w8" \
483 "$w8" \
484 "$wb$sp$w" \
485 "$wb$sp$w" \
486 "$wb If you proceed, this will destroy all data on $w" \
487 "$wb your local system, and your hard disk will be $w" \
488 "$wb irreversably reconfigured $w" \
489 "$wb$sp$w" \
490 "$wb$sp$w" \
491 "$w8" \
492 "$w8"
494 if ask_yes_or_no "Do you wish to proceed ([Y]es/[N]o)?"; then
495 if check_partition_sizes; then
496 perform_partitioning
497 exit 0
499 else
500 return
502 done
505 MEM_SIZE_MB=$(awk '/MemTotal:/ { print $2 }' /proc/meminfo)
506 case $MEM_SIZE_MB in
507 ''|*[^0-9]*) die failed to get system memory size;;
508 esac
509 MEM_SIZE_MB=$(echo "scale=0; $MEM_SIZE_MB / 1024;" | bc -l)
511 overcommit=${OVIRT_OVERCOMMIT:-$default_overcommit}
512 # we multiply the overcommit coefficient by 10 then divide the
513 # product by 10 to avoid decimals in the result
514 OVERCOMMIT_SWAP_SIZE=$(echo "scale=0; (${MEM_SIZE_MB} * (${overcommit} * 10))/10;" | bc -l)
516 # add to the swap the amounts from http://kbase.redhat.com/faq/docs/DOC-15252
517 MEM_SIZE_GB=$(echo "scale=0; $MEM_SIZE_MB/1024;" | bc -l)
518 if [ $MEM_SIZE_GB -le 4 ]; then
519 BASE_SWAP_SIZE=2048
520 elif [ $MEM_SIZE_GB -le 16 ]; then
521 BASE_SWAP_SIZE=4096
522 elif [ $MEM_SIZE_GB -le 64 ]; then
523 BASE_SWAP_SIZE=8192
524 else
525 BASE_SWAP_SIZE=16384
528 CALC_SWAP_SIZE=$(echo "scale=0; ${BASE_SWAP_SIZE} + ${OVERCOMMIT_SWAP_SIZE};" | bc -l)
530 SWAP_SIZE=${OVIRT_VOL_SWAP_SIZE:-$CALC_SWAP_SIZE}
531 ROOT_SIZE=${OVIRT_VOL_ROOT_SIZE:-$default_root_size}
532 CONFIG_SIZE=${OVIRT_VOL_CONFIG_SIZE:-$default_config_size}
533 LOGGING_SIZE=${OVIRT_VOL_LOGGING_SIZE:-$default_logging_size}
534 DATA_SIZE=${OVIRT_VOL_DATA_SIZE:-$default_data_size}
536 if [ -n "$OVIRT_INIT" ]; then
537 # if present, use the drive selected with 'ovirt_init' boot parameter
538 # setting these the same until kernel cmdline argument implemented
539 ROOTDRIVE=$OVIRT_INIT
540 HOSTVGDRIVE=$OVIRT_INIT
541 get_drive_size $ROOTDRIVE ROOTDRIVESPACE
544 # if the node is Fedora then use GPT, otherwise use MBR
545 if [ -f /etc/fedora-release ]; then
546 LABEL_TYPE="gpt"
547 else
548 LABEL_TYPE="msdos"
551 if [ "$1" == "AUTO" ]; then
552 log "Beginning automatic disk partitioning.\n"
553 if [ -n "$OVIRT_INIT" ]; then
554 # do not format if HostVG exists on selected disk...
555 pvs -o vg_name --noheadings $HOSTVGDRIVE* 2>/dev/null|grep -q -m1 "HostVG"
556 existingHostVG=$?
557 # ... unless overridden by ovirt_firstboot parameter
558 if is_firstboot || [ $existingHostVG -ne 0 ]; then
559 if check_partition_sizes; then
560 log "Partitioning hard disk..."
561 perform_partitioning
563 else
564 log "Skip disk partitioning, HostVG exists"
566 else
567 log "Missing device parameter: unable to partition any disk"
569 else
570 OPTIONS="\"Configure Storage\" \"Review\" \"Commit Changes And Quit\" \"Return To Menu\""
571 eval set $OPTIONS
572 PS3="Choose an option: "
574 while true; do
575 printf "\n\n Storage Configuration\n\n" >&2
577 select OPTION in "$@"
579 case "$OPTION" in
580 "Configure Storage") do_configure ; break ;;
581 "Review") do_review ; break ;;
582 "Commit Changes And Quit") do_confirm ; break ;;
583 "Return To Menu") printf "\nExiting.\n"; exit ;;
584 esac
585 done
586 done