diff --git a/lib/cmdlib.py b/lib/cmdlib.py index 596b0deef0e6d4f4e45748d2c135247eba28d350..4cc1f41c38fb4893c49362c337d647943fdf9103 100644 --- a/lib/cmdlib.py +++ b/lib/cmdlib.py @@ -3937,6 +3937,88 @@ class LUReplaceDisks(LogicalUnit): return ret +class LUGrowDisk(LogicalUnit): + """Grow a disk of an instance. + + """ + HPATH = "disk-grow" + HTYPE = constants.HTYPE_INSTANCE + _OP_REQP = ["instance_name", "disk", "amount"] + + def BuildHooksEnv(self): + """Build hooks env. + + This runs on the master, the primary and all the secondaries. + + """ + env = { + "DISK": self.op.disk, + "AMOUNT": self.op.amount, + } + env.update(_BuildInstanceHookEnvByObject(self.instance)) + nl = [ + self.sstore.GetMasterNode(), + self.instance.primary_node, + ] + return env, nl, nl + + def CheckPrereq(self): + """Check prerequisites. + + This checks that the instance is in the cluster. + + """ + instance = self.cfg.GetInstanceInfo( + self.cfg.ExpandInstanceName(self.op.instance_name)) + if instance is None: + raise errors.OpPrereqError("Instance '%s' not known" % + self.op.instance_name) + self.instance = instance + self.op.instance_name = instance.name + + if instance.disk_template not in (constants.DT_PLAIN, constants.DT_DRBD8): + raise errors.OpPrereqError("Instance's disk layout does not support" + " growing.") + + if instance.FindDisk(self.op.disk) is None: + raise errors.OpPrereqError("Disk '%s' not found for instance '%s'" % + (name, instance.name)) + + nodenames = [instance.primary_node] + list(instance.secondary_nodes) + nodeinfo = rpc.call_node_info(nodenames, self.cfg.GetVGName()) + for node in nodenames: + info = nodeinfo.get(node, None) + if not info: + raise errors.OpPrereqError("Cannot get current information" + " from node '%s'" % node) + vg_free = info.get('vg_free', None) + if not isinstance(vg_free, int): + raise errors.OpPrereqError("Can't compute free disk space on" + " node %s" % node) + if self.op.amount > info['vg_free']: + raise errors.OpPrereqError("Not enough disk space on target node %s:" + " %d MiB available, %d MiB required" % + (node, info['vg_free'], self.op.amount)) + + def Exec(self, feedback_fn): + """Execute disk grow. + + """ + instance = self.instance + disk = instance.FindDisk(self.op.disk) + for node in (instance.secondary_nodes + (instance.primary_node,)): + self.cfg.SetDiskID(disk, node) + result = rpc.call_blockdev_grow(node, disk, self.op.amount) + if not result or not isinstance(result, tuple) or len(result) != 2: + raise errors.OpExecError("grow request failed to node %s" % node) + elif not result[0]: + raise errors.OpExecError("grow request failed to node %s: %s" % + (node, result[1])) + disk.RecordGrow(self.op.amount) + self.cfg.Update(instance) + return + + class LUQueryInstanceData(NoHooksLU): """Query runtime instance data. diff --git a/lib/mcpu.py b/lib/mcpu.py index b9b06f63127f567a9b2ca6e5f9776eb3dee001ce..2e7f3039c5b93d8cf0044f42224863314870f9d7 100644 --- a/lib/mcpu.py +++ b/lib/mcpu.py @@ -74,6 +74,7 @@ class Processor(object): opcodes.OpQueryInstances: cmdlib.LUQueryInstances, opcodes.OpQueryInstanceData: cmdlib.LUQueryInstanceData, opcodes.OpSetInstanceParams: cmdlib.LUSetInstanceParams, + opcodes.OpGrowDisk: cmdlib.LUGrowDisk, # os lu opcodes.OpDiagnoseOS: cmdlib.LUDiagnoseOS, # exports lu diff --git a/lib/opcodes.py b/lib/opcodes.py index 094d0858ee8d421483092ad789e9ab3e4ca025c3..11385c013d989236d52d5e74de57c03292c27762 100644 --- a/lib/opcodes.py +++ b/lib/opcodes.py @@ -370,6 +370,12 @@ class OpSetInstanceParams(OpCode): ] +class OpGrowDisk(OpCode): + """Grow a disk of an instance.""" + OP_ID = "OP_INSTANCE_GROW_DISK" + __slots__ = ["instance_name", "disk", "amount"] + + # OS opcodes class OpDiagnoseOS(OpCode): """Compute the list of guest operating systems."""