Add GetInstanceNetworks() config method
[ganeti-local] / lib / storage.py
index cf87686..d77d80b 100644 (file)
@@ -1,7 +1,7 @@
 #
 #
 
-# Copyright (C) 2009, 2011 Google Inc.
+# Copyright (C) 2009, 2011, 2012 Google 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
@@ -23,7 +23,7 @@
 
 """
 
-# pylint: disable-msg=W0232,R0201
+# pylint: disable=W0232,R0201
 
 # W0232, since we use these as singletons rather than object holding
 # data
@@ -58,7 +58,7 @@ class _Base:
     """
     raise NotImplementedError()
 
-  def Modify(self, name, changes): # pylint: disable-msg=W0613
+  def Modify(self, name, changes): # pylint: disable=W0613
     """Modifies an entity within the storage unit.
 
     @type name: string
@@ -84,7 +84,7 @@ class _Base:
     raise NotImplementedError()
 
 
-class FileStorage(_Base): # pylint: disable-msg=W0223
+class FileStorage(_Base): # pylint: disable=W0223
   """File storage unit.
 
   """
@@ -161,7 +161,7 @@ class FileStorage(_Base): # pylint: disable-msg=W0223
     return values
 
 
-class _LvmBase(_Base): # pylint: disable-msg=W0223
+class _LvmBase(_Base): # pylint: disable=W0223
   """Base class for LVM storage containers.
 
   @cvar LIST_FIELDS: list of tuples consisting of three elements: SF_*
@@ -256,7 +256,7 @@ class _LvmBase(_Base): # pylint: disable-msg=W0223
 
         if callable(mapper):
           # we got a function, call it with all the declared fields
-          val = mapper(*values) # pylint: disable-msg=W0142
+          val = mapper(*values) # pylint: disable=W0142
         elif len(values) == 1:
           assert mapper is None, ("Invalid mapper value (neither callable"
                                   " nor None) for one-element fields")
@@ -347,7 +347,7 @@ def _LvmPvGetAllocatable(attr):
     return False
 
 
-class LvmPvStorage(_LvmBase): # pylint: disable-msg=W0223
+class LvmPvStorage(_LvmBase): # pylint: disable=W0223
   """LVM Physical Volume storage unit.
 
   """
@@ -406,6 +406,7 @@ class LvmVgStorage(_LvmBase):
 
   """
   LIST_COMMAND = "vgs"
+  VGREDUCE_COMMAND = "vgreduce"
 
   # Make sure to update constants.VALID_STORAGE_FIELDS when changing field
   # definitions.
@@ -418,7 +419,7 @@ class LvmVgStorage(_LvmBase):
     (constants.SF_ALLOCATABLE, [], True),
     ]
 
-  def _RemoveMissing(self, name):
+  def _RemoveMissing(self, name, _runcmd_fn=utils.RunCmd):
     """Runs "vgreduce --removemissing" on a volume group.
 
     @type name: string
@@ -428,13 +429,23 @@ class LvmVgStorage(_LvmBase):
     # Ignoring vgreduce exit code. Older versions exit with an error even tough
     # the VG is already consistent. This was fixed in later versions, but we
     # cannot depend on it.
-    result = utils.RunCmd(["vgreduce", "--removemissing", name])
+    result = _runcmd_fn([self.VGREDUCE_COMMAND, "--removemissing", name])
 
     # Keep output in case something went wrong
     vgreduce_output = result.output
 
-    result = utils.RunCmd(["vgs", "--noheadings", "--nosuffix", name])
-    if result.failed:
+    # work around newer LVM version
+    if ("Wrote out consistent volume group" not in vgreduce_output or
+        "vgreduce --removemissing --force" in vgreduce_output):
+      # we need to re-run with --force
+      result = _runcmd_fn([self.VGREDUCE_COMMAND, "--removemissing",
+                           "--force", name])
+      vgreduce_output += "\n" + result.output
+
+    result = _runcmd_fn([self.LIST_COMMAND, "--noheadings",
+                         "--nosuffix", name])
+    # we also need to check the output
+    if result.failed or "Couldn't find device with uuid" in result.output:
       raise errors.StorageError(("Volume group '%s' still not consistent,"
                                  " 'vgreduce' output: %r,"
                                  " 'vgs' output: %r") %