[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#462396: Multiple disks support for partman-auto-lvm



On Thursday 24 January 2008, Grégory Oestreicher wrote:
> I finally managed to write a more general patch[1] to have multiple disks
> support in partman-auto-lvm.

Attaching patch and especially the example recipes to ensure they remain 
available. Recipes will be useful as documentation.

Index: partman-auto-lvm/debian/partman-auto-lvm.templates
===================================================================
--- partman-auto-lvm/debian/partman-auto-lvm.templates	(révision 50997)
+++ partman-auto-lvm/debian/partman-auto-lvm.templates	(copie de travail)
@@ -42,3 +42,19 @@
  the volume group.
  .
  Check /var/log/syslog or see virtual console 4 for the details.
+
+Template: partman-auto-lvm/no_such_pv
+Type: error
+_Description: Inexistant PV declared
+ A Volume Group definition contains a reference to a Physical Volume
+ that is not present. 
+ .
+ Check for you connectivity or the recipe.
+
+Template: partman-auto-lvm/no_pv_in_vg
+Type: error
+_Description: No PV defined for creating VG
+ The recipe contains the definition of a Volume Group without
+ any Physical Volume in it.
+ .
+ Review the recipe.
Index: partman-auto-lvm/lib/auto-lvm.sh
===================================================================
--- partman-auto-lvm/lib/auto-lvm.sh	(révision 50997)
+++ partman-auto-lvm/lib/auto-lvm.sh	(copie de travail)
@@ -10,14 +10,48 @@
 	exit 1
 }
 
+# This function was copied from another file (partman-auto/lib/initial_auto).
+# Maybe it should be useful to put it in auto-shared.sh or in base.sh
+dev_to_partman () {
+	local dev_name="$1"
+	local dev
+
+	local mapped_dev_name="$(mapdevfs $dev_name)"
+	if [ -n "$mapped_dev_name" ]; then
+		dev_name="$mapped_dev_name"
+	fi
+
+	for dev in $DEVICES/*; do
+		[ -d "$dev" ] || continue
+
+		# mapdevfs both to allow for different ways to refer to the
+		# same device using devfs, and to allow user input in
+		# non-devfs form
+		if [ "$(mapdevfs $(cat $dev/device))" = "$dev_name" ]; then
+			echo $dev
+		fi
+	done
+}
+
 auto_lvm_prepare() {
-	local dev method size free_size normalscheme target
+	local dev method size free_size normalscheme target extra_devices tmpdev tmpdevdir physdev
 	dev=$1
 	method=$2
 
 	[ -f $dev/size ] || return 1
 	size=$(cat $dev/size)
 
+	extra_devices=''
+	if db_get partman-auto-lvm/extra_devices && [ "$RET" ]; then
+		for tmpdev in "$RET"; do
+			tmpdevdir="$(dev_to_partman $tmpdev)"
+			if [ -d $tmpdevdir ]; then
+				size=$(($size + $(cat $tmpdevdir/size)))
+				extra_devices="$extra_devices $tmpdevdir"
+			fi
+		done
+	fi
+
 	# Be sure the modules are loaded
 	modprobe dm-mod >/dev/null 2>&1 || true
 	modprobe lvm-mod >/dev/null 2>&1 || true
@@ -26,21 +60,32 @@
 		log-output -t update-dev update-dev
 	fi
 
-	target="$(humandev $(cat $dev/device)) - $(cat $dev/model)"
+	if [ $extra_devices ]; then
+		for extradev in $dev $extra_devices; do
+			extradev_str="$extradev_str $(cat $extradev/device)"
+		done
+		target="Multiple disks ($extradev_str)"
+	else
+		target="$(humandev $(cat $dev/device)) - $(cat $dev/model)"
+	fi
 	target="$target: $(longint2human $size)"
 	free_size=$(expr 0000000"$size" : '0*\(..*\)......$') # convert to megabytes
 
 	choose_recipe lvm "$target" "$free_size" || return $?
 
-	auto_init_disk "$dev" || return $?
+	size=0
+	for tmpdev in $dev $extra_devices; do
+		auto_init_disk "$tmpdev" || return $?
+		size=$(($size + $free_size))
 
-	# Check if partition is usable; use existing partman-auto template as we depend on it
-	if [ "$free_type" = unusable ]; then
-		db_input critical partman-auto/unusable_space || true
-		db_go || true
-		return 1
-	fi
-	free_size=$(expr 0000000"$free_size" : '0*\(..*\)......$') # convert to megabytes
+		# Check if partition is usable; use existing partman-auto template as we depend on it
+		if [ "$free_type" = unusable ]; then
+			db_input critical partman-auto/unusable_space || true
+			db_go || true
+			return 1
+		fi
+	done
+	free_size=$(expr 0000000"$size" : '0*\(..*\)......$') # convert to megabytes
 
 	decode_recipe $recipe lvm
 
@@ -88,11 +133,6 @@
 		;;
 	esac
 
-	# Creating envelope
-	scheme="$normalscheme${NL}100 1000 1000000000 ext3 \$primary{ } method{ $method }"
-
-	expand_scheme
-
 	clean_method
 
 	# This variable will be used to store the partitions that will be LVM
@@ -101,27 +141,65 @@
 	# (still one atm)
 	devfspv_devices=''
 
-	create_primary_partitions
+	# Creating envelope
+	# Only if one does not already exist (identified by 'method{ lvm }' and by 
+	# the current device in the scheme)
+	physdev=$(cat $dev/device)
+	if ! echo "$normalscheme" | grep "method{ lvm }" | grep -q "device{ $physdev[[:digit:]]* }" && \
+	   ! echo "$normalscheme" | grep "method{ lvm }" | grep -q -v "device{"; then
+		normalscheme="$normalscheme${NL}100 1000 1000000000 ext3 \$primary{ } method{ $method }"
+	fi
 
-	create_partitions
+	# Creating the partitions that have no device declared on the default device
+	# and partitions declared on it
+	scheme=$(echo "$normalscheme" | grep -v 'device{')
+	scheme=${scheme}${NL}$(echo "$normalscheme" | grep "device{ $physdev[[:digit:]]* }" )
+	auto_lvm_create_partitions $dev
 
+	# Creating the partitions declared on each of the extra devices
+	for tmpdev in $extra_devices; do
+		physdev=$(cat $tmpdev/device)
+		scheme=$(echo "$normalscheme" | grep "device{ $physdev[[:digit:]]* }" )
+		auto_lvm_create_partitions $tmpdev
+	done
+
 	if ! confirm_changes partman-lvm; then
 		return 30
 	fi
 
+	disable_swap
 	# Write the partition tables
-	disable_swap
-	cd $dev
-	open_dialog COMMIT
-	close_dialog
+	for tmpdev in $dev $extra_devices; do
+		cd $tmpdev
+		open_dialog COMMIT
+		close_dialog
+		device_cleanup_partitions
+	done
 
-	device_cleanup_partitions
 	update_all
 }
 
+# This function  depends on the existence of $scheme and $devfspv_devices in scope
+auto_lvm_create_partitions() {
+	local dev free_size
+	dev=$1
+	
+	get_disk_infos $dev;
+	free_size=$(expr 0000000"$free_size" : '0*\(..*\)......$') # convert to megabytes
+
+	expand_scheme
+
+	create_primary_partitions
+	create_partitions
+}
+
 auto_lvm_perform() {
+	local IFS physdev defvgname schemeline schemevg schemedev targetdir targetvg pvdevice
+	physdev=$(cat $1/device)
+	targetdir="/tmp/auto_lvm_perform"
+	mkdir $targetdir || exit 1
+	
 	# Use hostname as default vg name (if available)
-	local defvgname pv
 	db_get partman-auto-lvm/new_vg_name
 	if [ -z "$RET" ]; then
 		if [ -s /etc/hostname ]; then
@@ -150,13 +228,89 @@
 		db_register partman-auto-lvm/new_vg_name_exists partman-auto-lvm/new_vg_name
 	done
 
-	if vg_create "$VG_name" $pv_devices; then
-		perform_recipe_by_lvm $VG_name $recipe
-	else
-		bail_out vg_create_error
+	# The recipe contains all the necessary informations about eventuals
+	# extra VGs to create
+	# The VGs to create are :
+	#   - the default one if some partitions don't have the invg{ } tag
+	#   - the ones present in vgname{ } tags of PVs
+	decode_recipe $recipe lvm
+	
+	# Recreating the envelope if needed
+	if ! echo "$scheme" | grep "method{ lvm }" | grep -q "device{ $physdev[[:digit:]]* }" && \
+	   ! echo "$scheme" | grep "method{ lvm }" | grep -q -v "device{"; then
+		scheme="$scheme${NL}100 1000 1000000000 ext3 \$primary{ } method{ $method }"
 	fi
-	vg_lock_pvs "$VG_name" $pv_devices
 
+	# Extracting the VGs to create, and on which devices
+	# Physical devices will be stored in /tmp/$VGNAME, one per line
+	IFS="$NL"
+	for schemeline in $scheme; do
+		restore_ifs
+		# Type of the line : PV or partition
+		if echo $schemeline | grep -q '\$lvmok{'; then
+			# It's a partition
+			# Check if a VG name is given
+			schemevg=$(echo $schemeline | grep 'invg{' | sed -e 's!.*invg{ *\([^ }]*\) *}.*!\1!g')
+			# If not, it will be in the default VG
+			# The file are touch()'ed to have an error generated later
+			# if they are empty
+			if [ -z "$schemevg" ]; then
+				touch $targetdir/$VG_name
+			else
+				touch $targetdir/$schemevg
+			fi
+		elif echo $schemeline | grep -v -q 'mountpoint{'; then
+			# It's a PV
+			# Check if a VG name is given
+			schemevg=$(echo $schemeline | grep 'method{ lvm }' | grep 'vgname{' | sed -e 's!.*vgname{ *\([^ }]*\) *}.*!\1!g')
+			# Check if a device is given
+			schemedev=$(echo $schemeline | grep 'method{ lvm }' | grep 'device{' | sed -e 's!.*device{ *\([^ }]*\) *}.*!\1!g')
+
+			# If no VG is given, then it will be in the default one
+			if [ -z "$schemevg" ]; then
+				tmpschemename=$VG_name
+			else
+				tmpschemename=$schemevg
+			fi
+
+			# If no physical device is given, then it is created on the default one
+			if [ -z "$schemedev" ]; then
+				tmpdevname=$physdev
+			else
+				tmpdevname=$schemedev
+			fi
+
+			# Getting the partition name from $pv_devices
+			pvdev_found=''
+			for pvdevice in $pv_devices; do
+				tmppvdev=$(echo $pvdevice | sed -re 's/[[:digit:]]+$//g')
+				if [ $tmpdevname = $tmppvdev ] || [ $tmpdevname = $pvdevice ]; then
+					tmpdevname=$(mapdevfs $pvdevice)
+					pvdev_found='yes'
+				fi
+			done
+
+			if [ "$pvdev_found" = yes ]; then
+				echo $tmpdevname >> $targetdir/$tmpschemename
+			else
+				# Should exit with a more descriptive message, ie
+				# "Asked to add a non existant PV in a VG"
+				bail_out no_such_pv
+			fi
+		fi
+	done
+	
+	for targetvg in $targetdir/*; do
+		pv_devices=$(cat $targetvg)
+		[ -z "$pv_devices" ] && bail_out no_pv_in_vg
+		if vg_create "$(basename $targetvg)" $pv_devices; then
+			perform_recipe_by_lvm $(basename $targetvg) $recipe
+		else
+			bail_out vg_create_error
+		fi
+		vg_lock_pvs "$VG_name" $pv_devices
+	done
+
 	# Default to accepting the autopartitioning
 	menudir_default_choice /lib/partman/choose_partition finish finish || true
 }
Index: partman-auto-lvm/perform_recipe_by_lvm
===================================================================
--- partman-auto-lvm/perform_recipe_by_lvm	(révision 50997)
+++ partman-auto-lvm/perform_recipe_by_lvm	(copie de travail)
@@ -7,10 +7,18 @@
 VG_name=$1
 recipe=$2
 
+db_get partman-auto-lvm/new_vg_name
+default_vgname="$RET"
+
 decode_recipe $recipe lvm
+tmpscheme=$(echo "$scheme" | grep lvmok)
+scheme=$(echo "$tmpscheme" | grep "invg{ *$VG_name *}")
+if [ $VG_name = $default_vgname ]; then
+	# Adding in the scheme the partitions that have no VG declared
+	extraschemelines=$(echo "$tmpscheme" | grep lvmok | grep -v 'invg{')
+	scheme="${scheme:+$scheme$NL}$extraschemelines"
+fi
 
-scheme=$(echo "$scheme" | grep lvmok)
-
 partstep=$(echo "$scheme" | wc -l)
 partstep=$(expr $partstep + 3)
 
Index: partman-auto-lvm/autopartition-lvm
===================================================================
--- partman-auto-lvm/autopartition-lvm	(révision 50997)
+++ partman-auto-lvm/autopartition-lvm	(copie de travail)
@@ -13,4 +13,4 @@
 	pv_devices="$pv_devices $realpath"
 done
 
-auto_lvm_perform || exit 1
+auto_lvm_perform $dev || exit 1
Index: partman-auto/lib/auto-shared.sh
===================================================================
--- partman-auto/lib/auto-shared.sh	(révision 50997)
+++ partman-auto/lib/auto-shared.sh	(copie de travail)
@@ -1,5 +1,4 @@
 ## Shared code for all guided partitioning components
-
 auto_init_disk() {
 	local dev
 	dev="$1"
@@ -7,7 +6,14 @@
 	# Create new disk label; don't prompt for label
 	. /lib/partman/lib/disk-label.sh
 	create_new_label "$dev" no || return 1
+	
+	get_disk_infos $dev
+}
 
+get_disk_infos() {
+	local dev
+	dev="$1"
+	
 	cd $dev
 
 	free_space=''
test-recipe ::

128 512 256 ext3
	$defaultignore{ }
	$primary{ }
	$bootable{ }
	method{ format }
	format{ }
	use_filesystem{ }
	filesystem{ ext3 }
	mountpoint{ /boot } .

100 1000 1000000000 ext3
	$defaultignore{ }
	$primary{ }
	device{ /dev/hda }
	vgname{ vg00 }
	method{ lvm } .

100 1000 1000000000 ext3
	$defaultignore{ }
	$primary{ }
	device{ /dev/hdb }
	vgname{ vg01 }
	method{ lvm } .

70 800 280 ext3
	$lvmok{ }
	$primary{ }
	$bootable{ }
	invg{ vg00 }
	method{ format }
	format{ }
	use_filesystem{ }
	filesystem{ ext3 }
	mountpoint{ / } .

500 3000 5000 ext3
	$lvmok{ }
	invg{ vg00 }
	method{ format }
	format{ }
	use_filesystem{ }
	filesystem{ ext3 }
	mountpoint{ /usr } .

70 1500 3000 ext3
	$lvmok{ }
	invg{ vg00 }
	method{ format }
	format{ }
	use_filesystem{ }
	filesystem{ ext3 }
	mountpoint{ /var } .

96 512 300% linux-swap
	$lvmok{ }
	invg{ vg00 }
	method{ swap }
	format{ } .

20 300 400 ext3
	$lvmok{ }
	invg{ vg00 }
	method{ format }
	format{ }
	use_filesystem{ }
	filesystem{ ext3 }
	mountpoint{ /tmp } .

300 3000 1000000000 ext3
	$lvmok{ }
	invg{ vg01 }
	method{ format }
	format{ }
	use_filesystem{ }
	filesystem{ ext3 }
	mountpoint{ /home } .

test-recipe ::

128 512 256 ext3
	$defaultignore{ }
	$primary{ }
	$bootable{ }
	method{ format }
	format{ }
	use_filesystem{ }
	filesystem{ ext3 }
	mountpoint{ /boot } .

100 1000 1000000000 ext3
	$defaultignore{ }
	$primary{ }
	device{ /dev/hda }
	method{ lvm } .

100 1000 1000000000 ext3
	$defaultignore{ }
	$primary{ }
	device{ /dev/hdb }
	method{ lvm } .

70 800 280 ext3
	$lvmok{ }
	$primary{ }
	$bootable{ }
	method{ format }
	format{ }
	use_filesystem{ }
	filesystem{ ext3 }
	mountpoint{ / } .

500 3000 5000 ext3
	$lvmok{ }
	method{ format }
	format{ }
	use_filesystem{ }
	filesystem{ ext3 }
	mountpoint{ /usr } .

70 1500 3000 ext3
	$lvmok{ }
	method{ format }
	format{ }
	use_filesystem{ }
	filesystem{ ext3 }
	mountpoint{ /var } .

96 512 300% linux-swap
	$lvmok{ }
	method{ swap }
	format{ } .

20 300 400 ext3
	$lvmok{ }
	method{ format }
	format{ }
	use_filesystem{ }
	filesystem{ ext3 }
	mountpoint{ /tmp } .

300 3000 1000000000 ext3
	$lvmok{ }
	method{ format }
	format{ }
	use_filesystem{ }
	filesystem{ ext3 }
	mountpoint{ /home } .

test-recipe ::

128 512 256 ext3
	$defaultignore{ }
	$primary{ }
	$bootable{ }
	method{ format }
	format{ }
	use_filesystem{ }
	filesystem{ ext3 }
	mountpoint{ /boot } .

100 1000 1000000000 ext3
	$defaultignore{ }
	$primary{ }
	device{ /dev/hdb }
	vgname{ vg01 }
	method{ lvm } .

70 800 280 ext3
	$lvmok{ }
	$primary{ }
	$bootable{ }
	method{ format }
	format{ }
	use_filesystem{ }
	filesystem{ ext3 }
	mountpoint{ / } .

500 3000 5000 ext3
	$lvmok{ }
	method{ format }
	format{ }
	use_filesystem{ }
	filesystem{ ext3 }
	mountpoint{ /usr } .

70 1500 3000 ext3
	$lvmok{ }
	method{ format }
	format{ }
	use_filesystem{ }
	filesystem{ ext3 }
	mountpoint{ /var } .

96 512 300% linux-swap
	$lvmok{ }
	method{ swap }
	format{ } .

20 300 400 ext3
	$lvmok{ }
	method{ format }
	format{ }
	use_filesystem{ }
	filesystem{ ext3 }
	mountpoint{ /tmp } .

300 3000 1000000000 ext3
	$lvmok{ }
	invg{ vg01 }
	method{ format }
	format{ }
	use_filesystem{ }
	filesystem{ ext3 }
	mountpoint{ /home } .

test-recipe ::

128 512 256 ext3
	$defaultignore{ }
	$primary{ }
	$bootable{ }
	method{ format }
	format{ }
	use_filesystem{ }
	filesystem{ ext3 }
	mountpoint{ /boot } .

100 1000 1000000000 ext3
	$defaultignore{ }
	$primary{ }
	device{ /dev/hda2 }
	vgname{ vg00 }
	method{ lvm } .

100 1000 1000000000 ext3
	$defaultignore{ }
	$primary{ }
	device{ /dev/hdb1 }
	vgname{ vg00 }
	method{ lvm } .

70 800 280 ext3
	$lvmok{ }
	$primary{ }
	$bootable{ }
	invg{ vg00 }
	method{ format }
	format{ }
	use_filesystem{ }
	filesystem{ ext3 }
	mountpoint{ / } .

500 3000 5000 ext3
	$lvmok{ }
	invg{ vg00 }
	method{ format }
	format{ }
	use_filesystem{ }
	filesystem{ ext3 }
	mountpoint{ /usr } .

70 1500 3000 ext3
	$lvmok{ }
	invg{ vg00 }
	method{ format }
	format{ }
	use_filesystem{ }
	filesystem{ ext3 }
	mountpoint{ /var } .

96 512 300% linux-swap
	$lvmok{ }
	invg{ vg00 }
	method{ swap }
	format{ } .

20 300 400 ext3
	$lvmok{ }
	invg{ vg00 }
	method{ format }
	format{ }
	use_filesystem{ }
	filesystem{ ext3 }
	mountpoint{ /tmp } .

300 3000 1000000000 ext3
	$lvmok{ }
	invg{ vg00 }
	method{ format }
	format{ }
	use_filesystem{ }
	filesystem{ ext3 }
	mountpoint{ /home } .


Reply to: