[Libguestfs] [PATCH 2/2] New APIs: Query the relationship between LVM objects.

Richard W.M. Jones
Thu, 18 Mar 2010 14:00:19 -0000

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 2001
From: 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