Bash: Duplicate Logical Volume Configuration for a Volume Group

Bash: Duplicate Logical Volume Configuration for a Volume Group

I recently ran into a situation where I needed to create a large number of Logical Volumes for a server replacement situation.  I could have done some manual data input, but why not take the opportunity to quickly write a script to do the hard work for me?

For my situation this was a server that pulls data from other servers in order to optimize getting that data to tape.  So we had 2 VGs, one for the system and one for the data we wanted to move.  We planned on simply performing a rsync to move the data itself, but the volumes had to be pre-staged.

Here is the full script.  Nothing fancy, but very effective.

for line in `ssh root@oldserver.domain 'lvs --noheadings -o lv_name,lv_size,vg_name --separator , | tr -d " " | grep oldserver-vg | grep -v unneeded-lv'`
do
lvname=`echo $line | cut -d , -f 1`
lvsize=`echo $line | cut -d , -f 2`
lvcreate -L${lvsize} newserver-vg -n ${lvname}
mkfs.reiserfs -q /dev/newserver-vg/${lvname}
mkdir /backups/${lvname}
done

Gather Existing Configuration

Lets break it down…  The core of this script is gathering and formatting the existing LV configuration.

lvs --noheadings -o lv_name,lv_size,vg_name --separator , | tr -d " " | grep oldserver-vg | grep -v unneeded-lv

You will notice we are using lvs to show all of our logical volumes, but we are also telling it that we don’t want the headings to be displayed, and we only want the lv_name, lv_size, and vg_name columes to be displayed.  Additionally we want to use a comma as the separator, which makes our output easier to parse.  This gives us the core of the data we need, however we have some white space to remove, so we just pipe it through tr to get rid of that.  Now we just want to trim out some of the extra data from our output using grep.  We have two statements, one where we only include anything that contains the string oldserver-vg, and the other where we specifically exclude (with the -v) something that is not needed but previously included in our case unneeded-lv.  This would also work if you had a vgname which matched more than it should have.

Build “For” Loop

So now that we have a command to gather our original configuration, we need to wrap it in a for loop, and run it through SSH.

for line in `ssh root@oldserver.domain 'lvs --noheadings -o lv_name,lv_size,vg_name --separator , | tr -d " " | grep oldserver-vg | grep -v unneeded-lv'`

The way a “for” loop works is that you define a variable which represents each item in an array of data.  In our case our array of data is coming from another command (the boundaries of this command is delineated by the back-ticks) which happens to be an SSH command to the original server where the LVM configuration is intact (the boundaries of this command is delineated by the single-quotes).

Inside the “For” Loop

This is simple, as it goes through each line of output it will do everything between do and done.  Once it reaches done it goes back and increments to the next ${item} and starts again.  When there are no more $item then the for loop is complete, and we move on to the next part of the script.  In this particular script there is nothing after the “For” loop so the script will now be complete and your prompt will be returned.

Inside the “For” Loop…  Define Variables

Here we simply define our variables based on the content of $line.

lvname=`echo $line | cut -d , -f 1`
lvsize=`echo $line | cut -d , -f 2`

The core of each of these commands is the cut command.  The -d option sets the deliminator to “,” the -f option sets the field to the field which contains the data we need.  Which gives us the appropriate variables to actually do stuff.  So lets do it…

Inside the “For” Loop…  Create the Logical Volumes, Format, and Make a Mounting Directory

Now we actually do work.  If you are running this code I recommend you test it in your environment first, by inserting some debugging code instead of doing this stuff on your first run.  Unless you don’t care about the machine.  Make sure you look for pre-existing file systems and what not, if you accidently format your root you won’t be very happy…  Moving on.

lvcreate -L${lvsize} newserver-vg -n ${lvname}

Here we are simply creating the LVs.  You will need to hardcode the VG Name on your server which is being built up.

mkfs.reiserfs -q /dev/newserver-vg/${lvname}

Here we are formatting the file systems as we create them.  This particular environment prefers reiser, use your choice.

mkdir /backups/${lvname}

And finally to make the directories which will have the LVs mounted into.

Final Thoughts

The final step is to copy over the /etc/fstab and update the VG names in it from oldserver-vg to newserver-vg.  Which can be done with sed.  You could also manually mount the file systems as part of the script, or create the fstab by hand.