Friday, April 22, 2011

Automating Yum Setup

Recently, as part of my employer's "employee development" programs, I took Red Hat's RH255 class so that I could prep for getting my RHCSA and RHCE (my opinions on the experience are grist for another post - and I don't know, yet, whether that post should be in this blog or one of my personal blogs). The RH255 class I took was based on RHEL 6. In the US, they moved to training based on RHEL 6.0 about six months ago. One of the interesting things (I thought) my instructor said was that RHEL 6.0 included a function that tried to automatically configure `yum` to take mounted CDROMs and ISOs and treat them as installation repositories.

I may have misheard or misinterpreted what he said. It may also be a case that, since my instructor is in the RHEL 6.1 beta program, he was referring to a feature in RHEL 6.1 and not RHEL 6.0. Whatever the case may be, popping an RHEL 6.0 DVD (or ISO) into and RHEL 6.0 machine does not (yet) cause that DVD to be automatically included in `yum`'s repository search. Fortunately, the RHEL 6.x media has been set up (prior RHELs may also have been, it's just been so long since I've built an RHEL 5 system from other than an automated-build system) so that it's easy enough to automatically set up the DVD or ISO for inclusion in `yum`'s seaches. All of the yum repository is already on the media. So, you needn't muck about with doing the createrepo stuff (and the time that running createrepo against a multi-gigabyte DVD can take). Below is the script I wrote to take this already-present data and make it available to `yum`:

#!/bin/sh
MNTDIR=${1:-UNDEF}
# Make sure we passed a location to check
if [ ${MNTDIR} == "UNDEF" ]
then
   echo "Usage: $0 <ISO Mount Location>"
   exit
fi
# Make sure it's actually a directory
if [ ! -d ${MNTDIR} ]
then
   echo "No such directory"
   exit
fi
#ID directories containing repository data
REPODIRS=$(find ${MNTDIR} -type d -name repodata)
if [ "${REPODIRS}" == "" ]
then
   echo "No repository data found"
   exit
fi
for DIR in ${REPODIRS}
to
   DIRNAME=$(echo ${DIR} | sed -e 's#'${MNTDIR}'/##' -e 's#/repodata##')
   BASEURL=$(dirname ${DIR})
   echo "[${DIRNAME}]"
   echo "baseurl=${BASEURL}"
   echo "enabled=1"
   echo
done

The above script takes a directory location (presumably where you mounted your DVD or ISO) and produces yum repository configuration output. I opted to have it output as a capturable stream rather than as a file. That way, I'd have to option of either capturing to a temp location or  directly into /etc/yum.repos.d. Doing so gave more flexibility in what to name a file (so that I didn't clobber any existing files). Granted, I could have parameterized the name and location of the output file, but chose not to. If you want to use the above and would rather have the output go directly to an output file in /etc/yum.repos.d (or elsewhere), it's a trivial modification to the above. Have at it.

At any rate, once you run the above and take the resultant output and move it into a file in /etc/yum.repos.d, subsequent invocations of the `yum` command should now include your DVD or ISO. If it fails to do so (or errors result) it's probably because the new .repo file contains section IDs that collide with exiting ones. Just edit your new file to eliminate any collisions.

While I've done some basic error-checking in the file (specifically: ensuring the user passed a location and that the location is a valid directory), I didn't write it to gracefully handle repository directories that have spaces in their path-names. It's also fairly trivial to fix the script to accommodate it. However, it's probably even easier to just make sure you don't mount your DVD or ISO with spaces in the path-names. I'm lazy, so, I'm choosing the latter option and avoiding the coding exercise. If you find you need to have spaces in your path-names and want to use my script, feel free to make the necessary modifications to accommodate your use of space-containing path names.

Tuesday, April 19, 2011

Handling Resized LUNs on RHEL 5

Perhaps it's a reflection of it being nearly two years since touching a non-Linux *NIX operating system, but I feel like I recall Solaris, Irix, HP/UX and AIX all handling resized LUNs far more gracefully than Linux currently seems to. I seem to recall that, if you resized a LUN on your storage array and presented it to your *N*X host, it was fairly non-disruptive to make that storage available to the filesystems residing on top of the LUN. Maybe I'm mis-remembering, but I can't help but feel that Linux is still showing it's lack of Enterprise-level maturity in this area.

Don't get me wrong, you can get Linux to make use of re-sized LUNs without having to reboot the box. So, that's definitely a good start. But, thus far, I haven't managed to tangle loose a method that doesn't require me to unmount a filesystem (and, if I'm using LVM or multipathd, having to disrupt them, as well).

That said, if you've ended up on this page, it's probably because you're trying to figure out "how do I get RedHat to make use of the extra space on the LUN my SAN administrator grew for me" and Google (et. al.) sent you here.

In sorting this issue out, it seems like the critically-deficient piece of the puzzle is the way in which Linux updates device geometry. As near as I can tell, it doesn't really notice geometry changes by itself, and, the tools available for making it see geometry changes aren't yet optimized for fully on-the-fly configuration changes. But, at least they do provide a method that saves you the several minutes that a physical host reboot can cost you.

In digging about an playing with my test system, what I've come up with is a workflow something like the following:

  1. Unmount any filesystems residing on the re-configured LUN (`umount`)
  2. Stop any logical volumes that are currently active on the LUN (`vgchange`)
  3. Nuke out any partitions that reference the last block of the LUN's previous geometry (`fdisk` for this)
  4. Tell linux to reread the geometry info for the LUN (`blockdev --rereadpt` for this)
  5. Re-create the previously-nuked partition, referencing the new ending-block  (typically `fdisk` - particularly if you have to do block offsets for your SAN solution - for this and add `kpartx` if you're using a multipathing solution)
  6. Grow any logical volume elements containing that re-created/grown partition (`pvresize` for this)
  7. Grow and restart any logical volumes containing that re-created/grown partition (`vgchange` and `lvresize` for this)
  8. Grow and remount any filesystems that were on the re-created/grown partition (`e2fsresize` for this - unless you're using an incompatible filesystem-type - and then `mount`)

Omitted from the list above, but should be inferred by the clueful reader is "stop and restart any processes that use the grown-LUN" (The `fuser` command is really helpful for this).

Obviously, if you're using something other than LVM for your logical volume managment (e.g., VxVM), the `vgchange`, `pvresize` and `lvresize` commands have to be replaced with the appropriate logical volume management system's equivalent commands.

At any rate, if anyone knows how I can call `blockdev --rereadpt` without needing to stop filesystems (etc.), please comment. I'm really trying to figure out the least disruptive way of accomodating resized LUNs and haven't quite got to where I think I should be able to get.