diff --git a/lib/cmdlib.py b/lib/cmdlib.py index bd2f5a5d84c38fd92e5eaabd9714882178ca2c04..09d2bbcf247575f0a15f2031db4fe0cfbe15aebf 100644 --- a/lib/cmdlib.py +++ b/lib/cmdlib.py @@ -6441,6 +6441,62 @@ class TLReplaceDisks(Tasklet): self._RemoveOldStorage(self.target_node, iv_names) +class LURepairNodeStorage(NoHooksLU): + """Repairs the volume group on a node. + + """ + _OP_REQP = ["node_name"] + REQ_BGL = False + + def CheckArguments(self): + node_name = self.cfg.ExpandNodeName(self.op.node_name) + if node_name is None: + raise errors.OpPrereqError("Invalid node name '%s'" % self.op.node_name) + + self.op.node_name = node_name + + def ExpandNames(self): + self.needed_locks = { + locking.LEVEL_NODE: [self.op.node_name], + } + + def _CheckFaultyDisks(self, instance, node_name): + if _FindFaultyInstanceDisks(self.cfg, self.rpc, instance, + node_name, True): + raise errors.OpPrereqError("Instance '%s' has faulty disks on" + " node '%s'" % (inst.name, node_name)) + + def CheckPrereq(self): + """Check prerequisites. + + """ + storage_type = self.op.storage_type + + if (constants.SO_FIX_CONSISTENCY not in + constants.VALID_STORAGE_OPERATIONS.get(storage_type, [])): + raise errors.OpPrereqError("Storage units of type '%s' can not be" + " repaired" % storage_type) + + # Check whether any instance on this node has faulty disks + for inst in _GetNodeInstances(self.cfg, self.op.node_name): + check_nodes = set(inst.all_nodes) + check_nodes.discard(self.op.node_name) + for inst_node_name in check_nodes: + self._CheckFaultyDisks(inst, inst_node_name) + + def Exec(self, feedback_fn): + feedback_fn("Repairing storage unit '%s' on %s ..." % + (self.op.name, self.op.node_name)) + + st_args = _GetStorageTypeArgs(self.cfg, self.op.storage_type) + result = self.rpc.call_storage_execute(self.op.node_name, + self.op.storage_type, st_args, + self.op.name, + constants.SO_FIX_CONSISTENCY) + result.Raise("Failed to repair storage unit '%s' on %s" % + (self.op.name, self.op.node_name)) + + class LUGrowDisk(LogicalUnit): """Grow a disk of an instance. diff --git a/lib/mcpu.py b/lib/mcpu.py index 1c1579b503be2e07a59ce45568f85fe4600178ea..ff5f5c3a3e626fdd0f7743e3f2494dcf61857254 100644 --- a/lib/mcpu.py +++ b/lib/mcpu.py @@ -58,6 +58,7 @@ class Processor(object): opcodes.OpQueryNodeVolumes: cmdlib.LUQueryNodeVolumes, opcodes.OpQueryNodeStorage: cmdlib.LUQueryNodeStorage, opcodes.OpModifyNodeStorage: cmdlib.LUModifyNodeStorage, + opcodes.OpRepairNodeStorage: cmdlib.LURepairNodeStorage, opcodes.OpRemoveNode: cmdlib.LURemoveNode, opcodes.OpSetNodeParams: cmdlib.LUSetNodeParams, opcodes.OpPowercycleNode: cmdlib.LUPowercycleNode, diff --git a/lib/opcodes.py b/lib/opcodes.py index dc2882ba3c6f2fe201175a573e33760ba61c7cf0..a08549ca73e9485fcd6e10f88bc43f18f5481b2b 100644 --- a/lib/opcodes.py +++ b/lib/opcodes.py @@ -381,6 +381,17 @@ class OpModifyNodeStorage(OpCode): ] +class OpRepairNodeStorage(OpCode): + """Repairs the volume group on a node.""" + OP_ID = "OP_REPAIR_NODE_STORAGE" + OP_DSC_FIELD = "node_name" + __slots__ = OpCode.__slots__ + [ + "node_name", + "storage_type", + "name", + ] + + class OpSetNodeParams(OpCode): """Change the parameters of a node.""" OP_ID = "OP_NODE_SET_PARAMS" @@ -680,6 +691,7 @@ class OpTestAllocator(OpCode): "os", "tags", "nics", "vcpus", "hypervisor", ] + OP_MAPPING = dict([(v.OP_ID, v) for v in globals().values() if (isinstance(v, type) and issubclass(v, OpCode) and hasattr(v, "OP_ID"))])