From 02f2da11ae21cfae5be6ebc2e05ff5bf6612b44d Mon Sep 17 00:00:00 2001
From: Mitchell E Berger <mitchb@mit.edu>
Date: Tue, 8 Nov 2011 21:58:02 -0500
Subject: [PATCH] Add DB/LVM disk consistency checker and web/checkdisks
 remctl

---
 debian/changelog                    |    6 +++
 debian/control                      |    4 +-
 host/usr/sbin/invirt-check-disks    |   71 +++++++++++++++++++++++++++++++++++
 host/usr/sbin/invirt-remote         |    3 ++
 server/usr/sbin/invirt-remote-proxy |    2 +-
 5 files changed, 83 insertions(+), 3 deletions(-)
 create mode 100755 host/usr/sbin/invirt-check-disks

diff --git a/debian/changelog b/debian/changelog
index 1ad3152..32bc4a7 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+invirt-remote (0.4.12) unstable; urgency=low
+
+  * Add DB/LVM disk consistency checker and web/checkdisks remctl
+
+ -- Mitchell Berger <mitchb@mit.edu>  Tue, 08 Nov 2011 21:52:00 -0500
+
 invirt-remote (0.4.11) unstable; urgency=low
 
   * Don't let the janitor try to cleanup nonexistent LVs
diff --git a/debian/control b/debian/control
index 69dceb9..4d8bd96 100644
--- a/debian/control
+++ b/debian/control
@@ -22,8 +22,8 @@ Description: Invirt remote-control server
 Package: invirt-remote-host
 Architecture: all
 Depends: ${misc:Depends}, daemon, remctl-server, invirt-console-host,
- invirt-vnc-server, python-cjson, python-pyinotify, python-yaml,
- util-linux, openbsd-inetd
+ invirt-vnc-server, python-cjson, python-pyinotify, python-sqlalchemy,
+ python-yaml, util-linux, openbsd-inetd
 Description: Installs the Invirt host remctl configuration
  This is the remctl configuration for an Invirt host. It allows any
  commands to be run from the Invirt remote server
diff --git a/host/usr/sbin/invirt-check-disks b/host/usr/sbin/invirt-check-disks
new file mode 100755
index 0000000..b118dfa
--- /dev/null
+++ b/host/usr/sbin/invirt-check-disks
@@ -0,0 +1,71 @@
+#!/usr/bin/env python
+
+from invirt import database as db
+from invirt.config import structs as config
+import sqlalchemy as sa
+from subprocess import Popen, PIPE
+
+prefix = 'd_'
+
+# First figure out what the database thinks our sets of disks and sizes are
+db.connect()
+s = sa.sql.select([db.machine_table.c.name, db.disk_table.c.guest_device_name,
+                   db.disk_table.c.size],
+                  db.machine_table.c.machine_id == db.disk_table.c.machine_id,
+                  [db.machine_table, db.disk_table])
+dbresult = db.session.execute(s)
+db_disks = {}
+for (machine, device, size) in dbresult.fetchall():
+    db_disks['d_' + machine + '_' + device] = int(size)
+
+# Now figure out what the disk images actually in existence look like
+p = Popen(['/sbin/lvs', '--noheadings', '-o', 'lv_name,lv_size', '--units', 'm',
+           '--unbuffered', '--nosuffix', '--separator', ':', config.lvm.vg],
+          stdout=PIPE)
+lvresult = p.communicate()[0]
+lv_disks = {}
+for lv in lvresult.split():
+    (lvname, size) = lv.split(':')
+    if not lvname.startswith(prefix):
+        continue
+    # We only want the whole number of MiB, to match the database
+    lv_disks[lvname] = int(float(size))
+
+missing_disks = []
+orphaned_disks = []
+size_discrepancies = []
+
+for disk in db_disks:
+    if disk not in lv_disks:
+        missing_disks.append(disk)
+    elif db_disks[disk] != lv_disks[disk]:
+        size_discrepancies.append(disk)
+for disk in lv_disks:
+    if disk not in db_disks:
+        orphaned_disks.append(disk)
+
+if missing_disks:
+    print '===== The following disks are in the DB but the LVs do not exist'
+    missing_disks.sort()
+    for disk in missing_disks:
+        print disk.ljust(45) + 'DB: %s' % str(db_disks[disk]).rjust(6)
+    print '\n'
+if orphaned_disks:
+    print '===== The following LVs exist but are not assigned to a VM'
+    orphaned_disks.sort()
+    for disk in orphaned_disks:
+        print disk.ljust(59) + 'LVM: %s' % str(lv_disks[disk]).rjust(6)
+    print '\n'
+if size_discrepancies:
+    print '===== The following disks have different sizes in the DB and LVM'
+    size_discrepancies.sort()
+    for disk in size_discrepancies:
+        print disk.ljust(45) +\
+              'DB: %s    LVM: %s' % (str(db_disks[disk]).rjust(6),
+                                     str(lv_disks[disk]).rjust(6))
+    print '\n'
+print 'There are %i inconsistencies between the DB and LVM at this time.' %\
+      (missing_disks.__len__() +
+       orphaned_disks.__len__() +
+       size_discrepancies.__len__())
+
diff --git a/host/usr/sbin/invirt-remote b/host/usr/sbin/invirt-remote
index ceb8182..5168da8 100755
--- a/host/usr/sbin/invirt-remote
+++ b/host/usr/sbin/invirt-remote
@@ -26,6 +26,9 @@ case "$TYPE" in
             vnccert)
                 COMMAND=/usr/bin/invirt-vnc-getcert
                 ;;
+            checkdisks)
+                COMMAND=/usr/sbin/invirt-check-disks
+                ;;
             *)
                 echo "ERROR: invalid subcommand"
                 exit 34
diff --git a/server/usr/sbin/invirt-remote-proxy b/server/usr/sbin/invirt-remote-proxy
index b70eb4d..ca7dcf8 100755
--- a/server/usr/sbin/invirt-remote-proxy
+++ b/server/usr/sbin/invirt-remote-proxy
@@ -18,7 +18,7 @@ case "$TYPE/$SERVICE" in
         invirt-remote-vnccert "$@" ;;
     web/availability | web/avail )
         invirt-remote-availability "$@" ;;
-    web/lvcreate | web/lvremove | web/lvrename | web/lvresize | web/vgcapacity )
+    web/lvcreate | web/lvremove | web/lvrename | web/lvresize | web/vgcapacity | web/checkdisks )
         invirt-remote-lvm "$SERVICE" "$@"
         ;;
     control/help )
-- 
1.7.9.5