Richard W.M. Jones
2010-Mar-18 13:59 UTC
[Libguestfs] [PATCH 0/2] Add API for querying the relationship between LVM objects
Currently I found it it's hard to determine the relationship between LVM objects, by which I mean "what PVs contain a VG?", or "what LVs are contained in a VG?" This simple API exposes that to callers. {lv,vg,pv}uuid: Return the UUID of an LVM object. You can already get this using (eg.) lvs_full, but this is a lot less faffing around. vg{lv,pv}uuids: Return the LVs belonging to a VG, or the PVs containing a VG. It returns them as UUIDs, so if you build up a map using the previous calls, then you can map them back to names, or keep them as UUIDs as required. There's an example Perl program included which demonstrates how to do this. Rich. -- Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones virt-top is 'top' for virtual machines. Tiny program with many powerful monitoring features, net stats, disk stats, logging, etc. http://et.redhat.com/~rjones/virt-top
Richard W.M. Jones
2010-Mar-18 14:00 UTC
[Libguestfs] [PATCH 1/2] daemon: Add a trim utility function.
-- Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones Read my programming blog: http://rwmj.wordpress.com Fedora now supports 80 OCaml packages (the OPEN alternative to F#) http://cocan.org/getting_started_with_ocaml_on_red_hat_and_fedora -------------- next part -------------->From c17af108227b2f0104cf5fb81224f9b743843d73 Mon Sep 17 00:00:00 2001From: Richard Jones <rjones at redhat.com> Date: Thu, 18 Mar 2010 13:46:26 +0000 Subject: [PATCH 1/2] daemon: Add a trim utility function. This function trims the whitespace from around a string. It does this in-place, so it can be called for malloc'd strings. --- daemon/daemon.h | 2 ++ daemon/guestfsd.c | 22 ++++++++++++++++++++++ 2 files changed, 24 insertions(+), 0 deletions(-) diff --git a/daemon/daemon.h b/daemon/daemon.h index bb1ebb3..777cf33 100644 --- a/daemon/daemon.h +++ b/daemon/daemon.h @@ -66,6 +66,8 @@ extern int commandrvf (char **stdoutput, char **stderror, int flags, extern char **split_lines (char *str); +extern void trim (char *str); + extern int device_name_translation (char *device, const char *func); extern void udev_settle (void); diff --git a/daemon/guestfsd.c b/daemon/guestfsd.c index 0fc0128..ec3db58 100644 --- a/daemon/guestfsd.c +++ b/daemon/guestfsd.c @@ -928,6 +928,28 @@ split_lines (char *str) return lines; } +/* Skip leading and trailing whitespace, updating the original string + * in-place. + */ +void +trim (char *str) +{ + size_t len = strlen (str); + + while (len > 0 && c_isspace (str[len-1])) { + str[len-1] = '\0'; + len--; + } + + char *p = str; + while (*p && c_isspace (*p)) { + p++; + len--; + } + + memmove (str, p, len+1); +} + /* printf helper function so we can use %Q ("quoted") and %R to print * shell-quoted strings. See HACKING file for more details. */ -- 1.6.5.2
Richard W.M. Jones
2010-Mar-18 14:00 UTC
[Libguestfs] [PATCH 2/2] New APIs: Query the relationship between LVM objects.
-- Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones virt-df lists disk usage of guests without needing to install any software inside the virtual machine. Supports Linux and Windows. http://et.redhat.com/~rjones/virt-df/ -------------- next part -------------->From 3b30b640c9472adc3a2d1c57e8fa4a7664be9aff Mon Sep 17 00:00:00 2001From: Richard Jones <rjones at redhat.com> Date: Thu, 18 Mar 2010 13:48:03 +0000 Subject: [PATCH 2/2] New APIs: Query the relationship between LVM objects. These calls allow you to query the relationship between LVM objects, for example, which PVs contain a VG, or which LVs are contained in a VG. See the example / test program 'regressions/test-lvm-mapping.pl' for an example of how to do this from Perl. --- daemon/lvm.c | 87 +++++++++++++++++++++++++++++++++++ po/POTFILES.in | 1 + regressions/Makefile.am | 2 + regressions/test-lvm-mapping.pl | 95 +++++++++++++++++++++++++++++++++++++++ src/MAX_PROC_NR | 2 +- src/generator.ml | 42 +++++++++++++++++ 6 files changed, 228 insertions(+), 1 deletions(-) create mode 100755 regressions/test-lvm-mapping.pl diff --git a/daemon/lvm.c b/daemon/lvm.c index b100cd3..5c5846a 100644 --- a/daemon/lvm.c +++ b/daemon/lvm.c @@ -512,3 +512,90 @@ do_vgrename (const char *volgroup, const char *newvolgroup) return 0; } + +static char * +get_lvm_field (const char *cmd, const char *field, const char *device) +{ + char *out; + char *err; + int r; + + r = command (&out, &err, + "/sbin/lvm", cmd, + "--unbuffered", "--noheadings", "-o", field, + device, NULL); + if (r == -1) { + reply_with_error ("%s: %s", device, err); + free (out); + free (err); + return NULL; + } + + free (err); + + trim (out); + return out; /* Caller frees. */ +} + +char * +do_pvuuid (const char *device) +{ + return get_lvm_field ("pvs", "pv_uuid", device); +} + +char * +do_vguuid (const char *vgname) +{ + return get_lvm_field ("vgs", "vg_uuid", vgname); +} + +char * +do_lvuuid (const char *device) +{ + return get_lvm_field ("lvs", "lv_uuid", device); +} + +static char ** +get_lvm_fields (const char *cmd, const char *field, const char *device) +{ + char *out; + char *err; + int r; + + r = command (&out, &err, + "/sbin/lvm", cmd, + "--unbuffered", "--noheadings", "-o", field, + device, NULL); + if (r == -1) { + reply_with_error ("%s: %s", device, err); + free (out); + free (err); + return NULL; + } + + free (err); + + char **ret = split_lines (out); + free (out); + + if (ret == NULL) + return NULL; + + size_t i; + for (i = 0; ret[i] != NULL; ++i) + trim (ret[i]); + + return ret; +} + +char ** +do_vgpvuuids (const char *vgname) +{ + return get_lvm_fields ("vgs", "pv_uuid", vgname); +} + +char ** +do_vglvuuids (const char *vgname) +{ + return get_lvm_fields ("vgs", "lv_uuid", vgname); +} diff --git a/po/POTFILES.in b/po/POTFILES.in index 2caf376..c88abc5 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -90,6 +90,7 @@ perl/bindtests.pl perl/lib/Sys/Guestfs.pm perl/lib/Sys/Guestfs/Lib.pm python/guestfs-py.c +regressions/test-lvm-mapping.pl regressions/test-noexec-stack.pl ruby/ext/guestfs/_guestfs.c src/guestfs-actions.c diff --git a/regressions/Makefile.am b/regressions/Makefile.am index 4ac0ee0..2710e82 100644 --- a/regressions/Makefile.am +++ b/regressions/Makefile.am @@ -30,6 +30,7 @@ TESTS = \ test-cancellation-download-librarycancels.sh \ test-cancellation-upload-daemoncancels.sh \ test-find0.sh \ + test-lvm-mapping.pl \ test-noexec-stack.pl \ test-qemudie-killsub.sh \ test-qemudie-midcommand.sh \ @@ -51,6 +52,7 @@ TESTS_ENVIRONMENT = \ MALLOC_PERTURB_=$(random_val) \ LD_LIBRARY_PATH=$(top_builddir)/src/.libs \ LIBGUESTFS_PATH=$(top_builddir)/appliance \ + PERL5LIB=$(top_builddir)/perl/blib/lib:$(top_builddir)/perl/blib/arch \ NOEXEC_CHECK="$(top_builddir)/src/.libs/libguestfs.so $(top_builddir)/daemon/guestfsd" EXTRA_DIST = \ diff --git a/regressions/test-lvm-mapping.pl b/regressions/test-lvm-mapping.pl new file mode 100755 index 0000000..b988495 --- /dev/null +++ b/regressions/test-lvm-mapping.pl @@ -0,0 +1,95 @@ +#!/usr/bin/perl +# Copyright (C) 2010 Red Hat Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +# Test the discovery of relationships between LVM PVs, VGs and LVs. + +use strict; +use warnings; + +use Sys::Guestfs; + +unlink "test.img"; +open FILE, ">test.img" or die "test.img: $!"; +truncate FILE, 256*1024*1024 or die "test.img: truncate: $!"; +close FILE; + +my $g = Sys::Guestfs->new (); + +#$g->set_verbose (1); +#$g->set_trace (1); + +$g->add_drive ("test.img"); +$g->launch (); + +# Create an arrangement of PVs, VGs and LVs. +$g->sfdiskM ("/dev/sda", [",127", "128,"]); + +$g->pvcreate ("/dev/sda1"); +$g->pvcreate ("/dev/sda2"); +$g->vgcreate ("VG", ["/dev/sda1", "/dev/sda2"]); + +$g->lvcreate ("LV1", "VG", 32); +$g->lvcreate ("LV2", "VG", 32); +$g->lvcreate ("LV3", "VG", 32); + +# Now let's get the arrangement. +my @pvs = $g->pvs (); +my @lvs = $g->lvs (); + +my %pvuuids; +foreach (@pvs) { + my $uuid = $g->pvuuid ($_); + $pvuuids{$uuid} = $_; +} +my %lvuuids; +foreach (@lvs) { + my $uuid = $g->lvuuid ($_); + $lvuuids{$uuid} = $_; +} + +# In this case there is only one VG, called "VG", but in a real +# program you'd want to repeat these steps for each VG that you found. +my @pvuuids_in_VG = $g->vgpvuuids ("VG"); +my @lvuuids_in_VG = $g->vglvuuids ("VG"); + +my @pvs_in_VG; +foreach (@pvuuids_in_VG) { + push @pvs_in_VG, $pvuuids{$_}; +} + at pvs_in_VG = sort @pvs_in_VG; + +my @lvs_in_VG; +foreach (@lvuuids_in_VG) { + push @lvs_in_VG, $lvuuids{$_}; +} + at lvs_in_VG = sort @lvs_in_VG; + +die "unexpected set of PVs for volume group VG: [", + join (", ", @pvs_in_VG), "]\n" + unless @pvs_in_VG == 2 && + $pvs_in_VG[0] eq "/dev/vda1" && $pvs_in_VG[1] eq "/dev/vda2"; + +die "unexpected set of LVs for volume group VG: [", + join (", ", @lvs_in_VG), "]\n" + unless @lvs_in_VG == 3 && + $lvs_in_VG[0] eq "/dev/VG/LV1" && + $lvs_in_VG[1] eq "/dev/VG/LV2" && + $lvs_in_VG[2] eq "/dev/VG/LV3"; + +undef $g; + +unlink "test.img"; diff --git a/src/MAX_PROC_NR b/src/MAX_PROC_NR index 7b47338..f414671 100644 --- a/src/MAX_PROC_NR +++ b/src/MAX_PROC_NR @@ -1 +1 @@ -221 +226 diff --git a/src/generator.ml b/src/generator.ml index 83f307b..fdd228e 100755 --- a/src/generator.ml +++ b/src/generator.ml @@ -4290,6 +4290,48 @@ contained in a Linux initrd or initramfs image: See also C<guestfs_initrd_list>."); + ("pvuuid", (RString "uuid", [Device "device"]), 222, [], + [], + "get the UUID of a physical volume", + "\ +This command returns the UUID of the LVM PV C<device>."); + + ("vguuid", (RString "uuid", [String "vgname"]), 223, [], + [], + "get the UUID of a volume group", + "\ +This command returns the UUID of the LVM VG named C<vgname>."); + + ("lvuuid", (RString "uuid", [Device "device"]), 224, [], + [], + "get the UUID of a logical volume", + "\ +This command returns the UUID of the LVM LV C<device>."); + + ("vgpvuuids", (RStringList "uuids", [String "vgname"]), 225, [], + [], + "get the PV UUIDs containing the volume group", + "\ +Given a VG called C<vgname>, this returns the UUIDs of all +the physical volumes that this volume group resides on. + +You can use this along with C<guestfs_pvs> and C<guestfs_pvuuid> +calls to associate physical volumes and volume groups. + +See also C<guestfs_vglvuuids>."); + + ("vglvuuids", (RStringList "uuids", [String "vgname"]), 226, [], + [], + "get the LV UUIDs of all LVs in the volume group", + "\ +Given a VG called C<vgname>, this returns the UUIDs of all +the logical volumes created in this volume group. + +You can use this along with C<guestfs_lvs> and C<guestfs_lvuuid> +calls to associate logical volumes and volume groups. + +See also C<guestfs_vgpvuuids>."); + ] let all_functions = non_daemon_functions @ daemon_functions -- 1.6.5.2