X-Git-Url: https://code.grnet.gr/git/ganeti-local/blobdiff_plain/620a85fdb0b9221dbbb32ef1366deded932c83e1..3234695b0e09d78b79d2e3df076e4a9c646ef6d0:/lib/storage.py diff --git a/lib/storage.py b/lib/storage.py index 7f73100..d77d80b 100644 --- a/lib/storage.py +++ b/lib/storage.py @@ -1,7 +1,7 @@ # # -# Copyright (C) 2009 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,6 +23,14 @@ """ +# pylint: disable=W0232,R0201 + +# W0232, since we use these as singletons rather than object holding +# data + +# R0201, for the same reason + +# TODO: FileStorage initialised with paths whereas the others not import logging @@ -50,7 +58,7 @@ class _Base: """ raise NotImplementedError() - def Modify(self, name, changes): + def Modify(self, name, changes): # pylint: disable=W0613 """Modifies an entity within the storage unit. @type name: string @@ -76,7 +84,7 @@ class _Base: raise NotImplementedError() -class FileStorage(_Base): +class FileStorage(_Base): # pylint: disable=W0223 """File storage unit. """ @@ -153,7 +161,7 @@ class FileStorage(_Base): return values -class _LvmBase(_Base): +class _LvmBase(_Base): # pylint: disable=W0223 """Base class for LVM storage containers. @cvar LIST_FIELDS: list of tuples consisting of three elements: SF_* @@ -248,8 +256,10 @@ class _LvmBase(_Base): if callable(mapper): # we got a function, call it with all the declared fields - val = mapper(*values) + 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") # we don't have a function, but we had a single field # declared, pass it unchanged val = values[0] @@ -324,17 +334,23 @@ class _LvmBase(_Base): yield fields -class LvmPvStorage(_LvmBase): - """LVM Physical Volume storage unit. +def _LvmPvGetAllocatable(attr): + """Determines whether LVM PV is allocatable. + + @rtype: bool """ - def _GetAllocatable(attr): - if attr: - return (attr[0] == "a") - else: - logging.warning("Invalid PV attribute: %r", attr) - return False + if attr: + return (attr[0] == "a") + else: + logging.warning("Invalid PV attribute: %r", attr) + return False + + +class LvmPvStorage(_LvmBase): # pylint: disable=W0223 + """LVM Physical Volume storage unit. + """ LIST_COMMAND = "pvs" # Make sure to update constants.VALID_STORAGE_FIELDS when changing field @@ -344,7 +360,7 @@ class LvmPvStorage(_LvmBase): (constants.SF_SIZE, ["pv_size"], _ParseSize), (constants.SF_USED, ["pv_used"], _ParseSize), (constants.SF_FREE, ["pv_free"], _ParseSize), - (constants.SF_ALLOCATABLE, ["pv_attr"], _GetAllocatable), + (constants.SF_ALLOCATABLE, ["pv_attr"], _LvmPvGetAllocatable), ] def _SetAllocatable(self, name, allocatable): @@ -390,6 +406,7 @@ class LvmVgStorage(_LvmBase): """ LIST_COMMAND = "vgs" + VGREDUCE_COMMAND = "vgreduce" # Make sure to update constants.VALID_STORAGE_FIELDS when changing field # definitions. @@ -402,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 @@ -412,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") %