<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
   <channel>
      <title>Tech @ Thou Art Pop</title>
      <link>http://thouartpop.com/blog/</link>
      <description>I think I will keep my notes here.  I mean, there is just too much information to be dragging around in my head all the time.</description>
      <language>en</language>
      <copyright>Copyright 2010</copyright>
      <lastBuildDate>Sat, 23 Oct 2010 20:57:26 -0500</lastBuildDate>
      <generator>http://www.sixapart.com/movabletype/?v=3.2ysb5-20051201</generator>
      <docs>http://blogs.law.harvard.edu/tech/rss</docs> 

            <item>
         <title>Perl One Liners = Perl Is AWESOME!!!</title>
         <description><![CDATA[<p>Okay, so, I guess I am not a real blogger.&nbsp; Which kind of stinks because this is a &quot;tech&quot; blog, and I'm not much of a geek either.&nbsp; Anyway, it occurred to me that I wasn't updating my blog because I didn't really like the way it looked.&nbsp; So, I grabbed another Movable Type style (&quot;Minimalism&quot;, or something like that) and munged the style sheet to get a really wide page.&nbsp; I think it is probably pretty unusual to have such a wide page, but right now, I am loving it.</p><p>But, none of that is why I am posting this particular entry.&nbsp; Well, okay, the part about my site's style motivating me is probably the root cause for this entry.&nbsp; REGARDLESS, from this moment on and forever, this entry will be about how much I love Perl one-liner's!&nbsp; Or at least the one liner that helped me change my site's stylesheet.&nbsp; Are you ready?!</p><p><pre>[me@myhost ~]# perl -i.bak '-MPOSIX qw(floor)' \
>  -pe 'if (m/width *: *\d+ *px *;/){ $_ =~  s/(\d+)/floor( $1 * 1.8 )/ge; }' \
> site.css</pre></p><p>So, here is what that line does.  It calls perl (duh).  &quot;-i&quot; sets up an in place edit of the file given as the last argument to the command, site.css, and it gives it an extension of &quot;.bak.&quot; &quot;-MPOSIX qw(floor)&quot; imports the POSIX module with the &quot;floor&quot; subroutine (as in &quot;use POSIX qw(floor)&quot;).  &quot;-pe&quot; says to treat the given perl statement(s) as a standalone script and to wrap them in a &quot;while&quot; loop, reading the file given into the &quot;diamond&quot; (&lt;&gt;) operator.  Finally, the interesting part.  The if statement checks if the line being parsed as part of the current iteration has a string in it that looks like &quot;width: ###px&#59;&quot;.  If such a line is found, the next section searches for the number in the string and replaces it with a 1.8 multiple of itself rounded down to the nearest whole number.  Notice the letter &quot;e&quot; at the end of the search and replace operator?  The e tells the operator to wrap the replacement in an eval block to be executed as a piece of code such that the output replaces the string for which I searched.  In this case, it allowed me to extend all of the hardcoded width statements in my stylesheet by 80%.</p><p>AWESOME!!!</p>]]></description>
         <link>http://thouartpop.com/blog/2010/10/perl_one_liners_perl_is_awesom.html</link>
         <guid>http://thouartpop.com/blog/2010/10/perl_one_liners_perl_is_awesom.html</guid>
         <category>Perl</category>
         <pubDate>Sat, 23 Oct 2010 20:57:26 -0500</pubDate>
      </item>
            <item>
         <title>Backing Up Xen Guests via LVM</title>
         <description><![CDATA[<p>Okay, since I'm severely delinquent on my second, yes, that's right, <strong>second</strong> entry, I figured I would go ahead and put something useful out here.&nbsp; I intended the second entry to be a comparison of Linux and Windows, but I'm still working on that one.</p><p>Anyway, what follows is a script, called guest_lvm_mounter.sh, that I use to regularly perform an online backup of a Linux Xen guest using the Logical Volume Manager (LVM) and third-party backup software.&nbsp; The backup software calls the script with specific options for when a scheduled backup job starts and when it stops.&nbsp; I have tried to provide enough comments in the script below to allow you to follow it pretty easily.&nbsp; </p><p>Keep in mind, if your Linux system is running any sort of database, regardless of its claims of maintaining crash consistency, or any kind of application for which moving data from memory to disk is a critical but latency-riddled process, then you should find some other method to back up your database or application data in addition to this process.&nbsp; The problem with not backing up such data otherwise is this script uses LVM snapshots to enable backups, and LVM snapshots present your file system for backup much as it would be if you just yanked out the power cord (i.e. &quot;crash consistent&quot;).<br /></p><p>When calling the script, I assume several things.&nbsp; First, I assume a single Logical Volume (LV) on the host for each guest provides the single, entire physical disk of each guest I want to backup.&nbsp; Second, I assume the guest uses a single LV as the guest's block device underlying a monolithic / partition with no other partitions except for /boot.&nbsp; Third, I assume the / and /boot partitions are both formatted with a file system easily recognized by my system's &quot;mount&quot; command because I pass no special switches to it.&nbsp; In my case, this is always the ext3 file system.&nbsp; Keep in mind, though the script may work for more complex setups, I have not tested it such.</p><p>Beyond my assumptions, I made sure to name the Volume Groups (VGs) and LVs within the guest something different than the VGs used on the host.&nbsp; Otherwise, the kernel or LVM, I can't remember which, complains about conflicting VGs or LVs and won't map them.&nbsp; I got around this by installing the host with default VG and LV names, and I specified different names for my guests.&nbsp; After having done so, it occurred to me that it would have probably been better to specify different names for both on the host instead, as changing such things for each guest complicates automated deployments.&nbsp; However, if the guests each had the default VG and LV names, the names would have conflicted at script execution.<br /></p><p>The script sources some configuration files to set some needed environment variables.&nbsp; It then uses those environment variables to snapshot the intended volumes, load the guests' partitions in the host's kernel partition table, make the host aware of the guest LVs, then mount the volumes inside the snapshots.&nbsp; It includes three functions, one for the initial mount, one for the final umount, and one that respawns the script in a &quot;nohup'd&quot; process.&nbsp; I'll explain the nohup thing at the end.</p><pre>#!/bin/bash<br /># Author: Nathan Lannine<br /># Last Update: 2009-09-25<br /># Usage: ./guest_lvm_mount.sh {mount|umount|fork {mount|umount}}<br /># This is a specific-purpose shell script to allow mounting of virtualized<br /># guest logical volumes for backup from within a snapshot logical volume.<br /># You will likely need to modify this script to use in any other environment<br /># than mine.<br /><br /># Set the path and name of the program that sends logs to syslog, and<br /># set the name of the process that sends the logs to the logging program.<br />LOGGER=/bin/logger<br />LOG_PROG=guest_lvm_mounter<br /><br /># Initialize the return value to success (0).<br />RETVAL=0<br /><br /># Check if this is a debug run.&nbsp; Typically, debugging is off.&nbsp; To turn<br /># it on, run this script by prepending DEBUG=0 to your command line.<br />if [ -z $DEBUG ]; then<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DEBUG=0<br />fi<br /><br /># Check if this script is set to reboot the box if the script exits uncleanly.<br /># An unclean exit would indicate the snapshot volumes could not be unmounted<br /># and/or removed, which means no fresh backups can be made until they are<br /># cleaned up.&nbsp; Be very careful with this option.&nbsp; If you inadvertently initiate<br /># the reboot sequence, although it is configurable, this script is configured<br /># initially to wait 10 minutes to reboot.&nbsp; On RedHat-like Linuxes, that means you have<br /># 5 minutes to login and abort the shutdown.&nbsp; After 5 minutes, no new logins<br /># are allowed.&nbsp; That blackout window may be different on other systems.&nbsp; This<br /># option is set on the command line similarly to DEBUG above.<br />if [ -z $SHUTDOWN ]; then<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SHUTDOWN=0<br />fi<br /><br /># Check if this script is set to restart the backup services.&nbsp; This should<br /># not be set by the backup software, or unpredictable things might happen.<br /># This option is set on the command line similarly to DEBUG above.<br />if [ -z $SVC_SHUTDOWN ]; then<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SVC_SHUTDOWN=0<br />fi<br /><br /># Check if debugging is set to 0.&nbsp; If so, all messages will go to syslog.<br /># Otherwise, all messages will go to the terminal.&nbsp; The assumption is that<br /># one should only use debugging when running this command interactively.<br /># This behavior could easily be extended such that output could be &quot;tee&quot;d<br /># to the terminal and to syslog so debugging could be set during normal,<br /># non-interactive use.<br />if [ $DEBUG -eq 0 ]; then<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [[ -t 1 ]] &amp;&amp; echo &quot;Writing to syslog.&quot;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LOG_FACILITY=&quot;user.notice&quot;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; exec &gt; &gt;(&quot;$LOGGER&quot; -p &quot;$LOG_FACILITY&quot; -i -t &quot;$LOG_PROG&quot;)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; exec 2&gt; &gt;(&quot;$LOGGER&quot; -p &quot;$LOG_FACILITY&quot; -i -t &quot;$LOG_PROG&quot;)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; exec &lt; /dev/null 2&lt;&amp;1<br />fi<br /><br /># Set config directory.&nbsp; The host.conf file contains variables that should<br /># be set to usable values for your environment.&nbsp; The guests.conf file<br /># contains the names of the guests you want to backup.&nbsp; Some basic and<br /># significant assumptions are made based on the guests names, but I don't<br /># feel like documenting those assumptions here.&nbsp; Such assumptions are better<br /># documented in a README.&nbsp; I guess I have to write one of those now.<br />CONFIG_BASE=/usr/local/etc/xen_guests_backup<br />HOST_CONFIG=$CONFIG_BASE/host.conf<br />GUESTS_CONFIG=$CONFIG_BASE/guests.conf<br /><br /># Check for existence of the host configuration.&nbsp; If it exists, source it for<br /># variables.&nbsp; If it doesn't exist, then exit, because I've got no other<br /># defaults.<br />if [ -f $HOST_CONFIG ]; then<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; . $HOST_CONFIG<br />else<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; echo &quot;Host config file not found!&quot;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; RETVAL=78<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; exit $RETVAL<br />fi<br /><br /># Check for existence of the guests' configuration.&nbsp; If it exists, feed each<br /># line into the GUESTS array and set NUM_GUESTS to the number of items in the<br /># array.&nbsp; If it doesn't exist, then exit, because this script has no reason to<br /># run.<br />if [ -f $GUESTS_CONFIG ]; then<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; GUESTS=( `$CAT $GUESTS_CONFIG | $TR '\n' ' '` )<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; NUM_GUESTS=${#GUESTS[@]}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; RETVAL=$?<br />else<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; echo &quot;Guests config file not found!&quot;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; RETVAL=78<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; exit $RETVAL<br />fi<br /><br /># Check for existence of configured guests.&nbsp; If there are none, then this script<br /># has no reason to run.<br />if [ $NUM_GUESTS -eq 0 ]; then<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; echo &quot;You have no guests configured!&quot;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; RETVAL=78<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; exit $RETVAL<br />fi<br /><br /># Spout off how we were called.&nbsp; Maybe this should be moved to debugging.<br />echo &quot;Called as $0 $1 $2&quot;<br /><br /># The mount function.<br />mount() {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # Loop through the main mount functionality for each guest in the guests array.<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for ((i=0;i&lt;$NUM_GUESTS;i++)); do<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # Output a header line of &quot;&gt;&quot;.<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for ((j=0;j&lt;$($TPUT);j++)); do<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; echo -n &quot;&gt;&quot;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sleep .0001<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; done<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # Check for the existence of a file of variables for the current guest, and<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # pull in those variables.<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if [ -f $CONFIG_BASE/${GUESTS[${i}]}.source ]; then<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; . $CONFIG_BASE/${GUESTS[${i}]}.source<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # Go to dump_vars(), where I check for the value of DEBUG to determine whether<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # I need to dump the current variables.<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dump_vars<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # Create some output for logging.<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; echo -e &quot;\n&quot;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; echo $&quot;Creating snapshot logical volume \&quot;$SNAP_NAME\&quot; to mount to the host for backup.&quot;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # Create the snapshot.<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $LVCREATE -L ${SNAP_SIZE}G -s -n $SNAP_NAME $IMAGE<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # Add the partitions in the snapshot to the kernel's partition table.<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $KPARTX -av $HOST_VG/$SNAP_NAME<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # Scan for newly available volume groups.<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $VGSCAN<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # Activate the guest volume group that is newly available.<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $VGCHANGE -ay $GUEST_VG<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # Mount the configured volume from the guest group to the configured host mount<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # point.<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $MOUNT $GUEST_LVOLUME $MOUNT_DIR/$G_HOSTNAME<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # Mount the guest's non-LVM boot partition from inside the snapshot.&nbsp; This requires<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # a loop device with an offset into the snapshot because the beginning of the snapshot<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # contains the mbr and fat, which are of predetermined size and should never change.<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # Depending on the guest config, this should be an ext3 partition.<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $MOUNT $HOST_VG/$SNAP_NAME $MOUNT_DIR/$G_HOSTNAME/boot -o loop,offset=$[512*63]<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # Snag the return value.<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; RETVAL=$?<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # If no .source file exists for the current guest, then log it and/or tell the user.<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; echo -e &quot;\n&quot;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; echo -e &quot;${GUESTS[${i}]} is not configured for backup.\n&quot;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fi<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; done<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # Return from the mount subroutine with the return value.<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return $RETVAL;<br />}<br /><br /># The umount function.<br />umount() {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # If SVC_SHUTDOWN is set to 1, then wait a bit (default config of 300 seconds), stop the backup services,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # and wait a bit again before continuing.&nbsp; This is to allow expiration of hooks into the previously<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # mounted guest files systems.&nbsp; If something is still using them, then the umount function will fail.<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if [ $SVC_SHUTDOWN = 1 ]; then<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $SLEEP_CMD<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $BKUP_CMD stop<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $SLEEP_CMD<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fi<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # Loop through the main mount functionality for each guest in the guests array.<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for ((i=0;i&lt;$NUM_GUESTS;i++)); do<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # Output a header line of &quot;&gt;&quot;.<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for ((j=0;j&lt;$($TPUT);j++)); do<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; echo -n &quot;&gt;&quot;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sleep .0001<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; done<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # Check for the existence of a file of variables for the current guest, and<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # pull in those variables.<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if [ -f $CONFIG_BASE/${GUESTS[${i}]}.source ]; then<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; . $CONFIG_BASE/${GUESTS[${i}]}.source<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # Go to dump_vars(), where I check for the value of DEBUG to determine whether<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # I need to dump the current variables.<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dump_vars<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # Create some output for logging.<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; echo -e &quot;\n&quot;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; echo $&quot;Unmounting the snapshot logical volume \&quot;$SNAP_NAME\&quot; for removal after backup.&quot;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # Umount the guest's non-LVM boot partition from inside the snapshot.&nbsp; This requires<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # the &quot;-d&quot; flag because it was previously mounted as a loop device.<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $UMOUNT -d $MOUNT_DIR/$G_HOSTNAME/boot<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # Umount the configured volume of the guest group from the configured host mount<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # point.<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $UMOUNT $MOUNT_DIR/$G_HOSTNAME<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # Deactivate the configured guest VG.<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $VGCHANGE -an $GUEST_VG<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # Remove the partitions in the snapshot from the kernel's partition table.<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $KPARTX -dv $HOST_VG/$SNAP_NAME<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # Remove the snapshot.<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $LVREMOVE -f $HOST_VG/$SNAP_NAME<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # Snag the return value.<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; RETVAL=$?<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # If no .source file exists for the current guest, then log it and/or tell the user.<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; echo -e &quot;\n&quot;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; echo -e &quot;${GUESTS[${i}]} is not configured for backup.\n&quot;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fi<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; done<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # If SVC_SHUTDOWN is set to 1, then restart the backup services.<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if [ $SVC_SHUTDOWN = 1 ]; then<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $BKUP_CMD start<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fi<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # Return from the mount subroutine with the return value.<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return $RETVAL;<br />}<br /><br /># The fork function starts this script detached and in the background, ready to restart the<br /># backup services and restart the server if needed to deal with potential failures in the<br /># umount function's clean up.<br />fork() {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SVC_SHUTDOWN=1 SHUTDOWN=0 $NOHUP $0 $1 &amp;<br />}<br /><br /># This should be pretty obvious.&nbsp; If DEBUG equals 1, then dump some variables.<br />dump_vars() {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if [ $DEBUG -eq 1 ]; then<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; echo &quot;Now dumping variables&quot;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sleep 2<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; echo -e &quot;\n&quot;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; echo &quot;-----------------------------------------&quot;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; echo &quot;MOUNT_DIR = $MOUNT_DIR&quot;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; echo &quot;G_HOSTNAME&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = $G_HOSTNAME&quot;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; echo &quot;GUEST_VG&nbsp; = $GUEST_VG&quot;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; echo &quot;HOST_VG&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = $HOST_VG&quot;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; echo &quot;SNAP_NAME = $SNAP_NAME&quot;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; echo &quot;GUESTS&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = ${GUESTS[@]}&quot;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; echo &quot;NUM_GUESTS&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = $NUM_GUESTS&quot;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; echo &quot;-----------------------------------------&quot;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; echo -e &quot;\n&quot;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fi<br />}<br /><br /># See how we were called and head to the correct function or tell people how to use this script.<br />case &quot;$1&quot; in<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mount)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mount<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ;;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; umount)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; umount<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ;;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fork)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fork $2<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ;;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; echo $&quot;Usage: $0 {mount|umount|fork {mount|umount}}&quot;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; RETVAL=64<br />esac<br /><br /># If the return value from the mount or umount functions is not 0, then<br /># they did not exit cleanly, so log it.&nbsp; Additionally, if SHUTDOWN is set<br /># to 1, then initiate the configured shutdown command, which is configured<br /># by default to reboot the server after waiting 10 minutes.&nbsp; See the<br /># explanation of the SHUTDOWN variable at the top of this file.<br />if [ $RETVAL -ne 0 ]; then<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; echo &quot;$0 $1 exited uncleanly&quot;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if [ $SHUTDOWN -eq 1 ]; then<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # Log the shutdown sequence for monitoring.<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; echo &quot;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt; INITIATING SHUTDOWN SEQUENCE... &lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&quot;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # Detach and background the shutdown sequence to allow this invocation of the script to exit.<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $NOHUP $SHUTDOWN_CMD &amp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fi<br />fi<br /><br /># Log the exit with the return value.<br />echo &quot;Exiting: $RETVAL&quot;<br /><br /># Exit and return the return value.<br />exit $RETVAL</pre><p>The script refers to /usr/local/etc/xen_guests_backup/host.conf.&nbsp; Below, I have provided an obfuscated rendition of the host.conf file I use.&nbsp; The host.conf configuration file tells guest_lvm_mounter.sh where to find system utilities that it uses and what commands provide some of its functionality.</p><pre>#!/bin/bash<br />#<br /># Configuration directives for the host where you will backup<br /># the guests.<br /><br /><br />#<br /># Define the locations of executables required for operation.<br />#<br />LVCREATE=/usr/sbin/lvcreate<br />LVREMOVE=/usr/sbin/lvremove<br />KPARTX=/sbin/kpartx<br />VGSCAN=/sbin/vgscan<br />VGCHANGE=/sbin/vgchange<br />MOUNT=/bin/mount<br />UMOUNT=/bin/umount<br />TR=/usr/bin/tr<br />TPUT=&quot;/usr/bin/tput cols&quot;<br />CAT=/bin/cat<br />BKUP_CMD=&quot;/sbin/service your_backup_service&quot;<br />NOHUP=/usr/bin/nohup<br />SHUTDOWN_CMD=&quot;/sbin/shutdown -r +10&quot;<br />SLEEP_CMD=&quot;/bin/sleep 300&quot;<br /><br />#<br /># Define volume specific information below.<br />#<br />HOST_VG=/dev/your_host_volgroup<br />MOUNT_DIR=/path/to/where/your/guests/lvs/get/mounted<br /></pre><p>The next configuration file,&nbsp; /usr/local/etc/xen_guests_backup/guests.conf, is simply a list of each guest you would like to backup from the current host.&nbsp; Each line contains the name of exactly one guest, which assumes the name is the same as the LV name on the host that provides the underlying storage for the named guest.&nbsp; So, if you have a line in guests.conf that reads &quot;xen_guest1,&quot; then one of the LVs providing guest storage on your host should be named xen_guest1.&nbsp; For example:</p><pre>xen_guest1<br />xen_guest2</pre><p>Additionally, for each guest named in guests.conf, guest_lvm_mounter.sh looks for a respectively named configuration file.&nbsp; So, given a guests.conf file like the one indicated above, you would have two additional configuration files for each guest, one named  /usr/local/etc/xen_guests_backup/xen_guest1.source and one named  /usr/local/etc/xen_guests_backup/xen_guest2.source.&nbsp; I don't know why I chose &quot;.source&quot; as the file extension except both files contain variables that are sourced by guest_lvm_mounter.sh as follows.</p><pre>#!/bin/bash<br />#<br /># File to source variables per guest.&nbsp; You should have one of these per each<br /># guest you wish to backup.&nbsp; The main point is to configure appropriate values<br /># for the guests' logical volumes.<br /><br />G_HOSTNAME=xen_guest1<br />GUEST_VG=/dev/your_guest_vg_${G_HOSTNAME}<br />GUEST_LVOLUME=${GUEST_VG}/your_guest_lv<br />IMAGE=${HOST_VG}/${G_HOSTNAME}<br />SNAP_NAME=snap-${G_HOSTNAME}<br />SNAP_SIZE=50G </pre><p>The last step is to actually run the script.&nbsp; In my environment, my backup software invokes the script as</p><pre>/usr/bin/sudo /usr/local/sbin/guest_lvm_mounter.sh mount</pre><p>I have the software run the script via sudo (i.e. as root) to allow it to execute everything it needs.&nbsp; As such, I have the user the backup service runs as in the sudoers file with specific permissions to run this script.&nbsp; (I haven't looked into the security around the utilities the script calls, so I cannot speak much to any vulnerabilities this script might open up.)&nbsp; Once the backup job completes, it invokes the script again, this time as</p><pre>/usr/bin/sudo /usr/local/sbin/guest_lvm_mounter.sh fork umount</pre><p>The &quot;fork&quot; switch tells the script to invoke another detached instance of itself in the background, then exit.&nbsp; The fork function switches on the SVC_SHUTDOWN variable, which invokes a time delayed shutdown of the service prior to performing the umount, vgchange, and kpartx commands and prior to restarting the service.&nbsp; I chose to do this because I was unable to deactivate the VGs or remove them from the kernel mapping table while the backup service was running.&nbsp; You see, while the service is running, it maintains open file hooks into the activated VGs, which prevents their removal.&nbsp; The only option I could make work was to kill the backup service, but, I thought having the backup service kill itself just before the end of a backup job could cause me problems.&nbsp; So, I implemented the fork function to shutdown the service after a configurable delay, which, in my case, is 300 seconds (five minutes).&nbsp; Doing so allows the backup software to get a successful return code and end the job before shutting down to release its open file hooks into the VGs.&nbsp; I should mention, I implemented an additional 300-second delay after the service shuts down before trying to run the actual umount routine, as I was not sure how long it would take the kernel to expire the open file handles after the service stopped.&nbsp; I am sure that information is documented somewhere, but I figured five minutes was (and has been) adequate, so I never looked it up.</p><p>So, there you go.&nbsp; Feel free to use it as you like just as I used parts of it from examples others out there freely provided.&nbsp; I suppose it should be considered licensed under a Creative Commons license, just like the blog.<br /></p><p>Also, keep in mind the following.</p><ol><li>There are better ways to do this, such as image-based backups.&nbsp; You could still use LVM, but you would tar-gzip and backup the entire image instead of the files inside the image.&nbsp; I chose not to do so because the guests I am backing up are very large and contain databases that I previously discovered are somewhat susceptible to corruption. (More about that in another post.)</li><li>You could actually perform this same process on a Windows guest sitting inside an LV, but it would be akin to shooting one of your middle toes off.&nbsp; You know, definitely not the whole foot, not even a big toe, but more significant than the little guy at the end of the row.&nbsp; I'm guessing about 5% of the time, you would end up with a system that is unusable, either because an application on the system has thrown up its hands in frustration at your stupidity, or because the system has met its maker, you know, Bill.</li></ol><p>I also have some questions for anyone who actually comes across this.</p><ol><li>Do you have a good example of how to implement posixly correct command line switches for shell scripts?</li><li>Do you have any suggestions for improvement?</li><li>Are you going to use this, and, if so, how?&nbsp; Also, are you going to change it, and, if so, how?</li></ol><p>Thank you for taking the time to read this, and thank you for any feedback.</p><p>Sincerely,</p><p>N++ <br /></p>]]></description>
         <link>http://thouartpop.com/blog/2010/02/backing_up_xen_guests_via_lvm_1.html</link>
         <guid>http://thouartpop.com/blog/2010/02/backing_up_xen_guests_via_lvm_1.html</guid>
         <category>Shell Scripting</category>
         <pubDate>Mon, 22 Feb 2010 21:08:21 -0500</pubDate>
      </item>
            <item>
         <title>The First Entry</title>
         <description><![CDATA[<p>So, it would appear, at least as one way of looking at it, that there are three different ways to &quot;roll&quot; a blog.&nbsp; The way that seems  easiest is to open an account with one of many different blog providers (i.e. Blogger, Typepad, Wordpress, etc.).&nbsp; The way that seems a little harder is to setup a default blog platform install with a hosting provider, such as what I've done here.&nbsp; Yahoo! is my provider, and Yahoo! provides a choice of two blogging platforms.&nbsp; The way that seems hardest is to setup, from scratch, blogging software you've obtained from somewhere to install on your own server, a VPS (Virtual Private Server), or within a hosting service.</p><p>Well, here I am, and I must say, I haven't tried the first option.&nbsp; So, I can't really speak to it.&nbsp; But for the second and third options, I'm going with the second option in the short-term until I can setup my own blog per the third option on my own server.&nbsp; I tried the third option within my Yahoo! account...twice...and it didn't go so well.&nbsp; I know I shouldn't really leave it at that, but, maybe, I'll expound later.</p><p>Anyway, check back here ever so often for updates regarding Veganism, my family, and Linux.&nbsp; Of course, computing and networking in general are also open for discussion.</p><p>Until then...</p><p>N++ <br /></p>]]></description>
         <link>http://thouartpop.com/blog/2009/10/the_first_entry.html</link>
         <guid>http://thouartpop.com/blog/2009/10/the_first_entry.html</guid>
         <category>Ramblings</category>
         <pubDate>Sat, 03 Oct 2009 19:22:00 -0500</pubDate>
      </item>
      
   </channel>
</rss>

