Commit 84d7e26b authored by Dmitry Chernyak's avatar Dmitry Chernyak Committed by Iustin Pop
Browse files

Make rpc.call_lv_list() VG-aware

Changes to backend.GetVolumeList():
- now accepts a list of VGs instead of one VG
- returns LV names in the form "vg_name/lv_name"

Corresponding changes are done in: VerifyDisks, VerifyNode,
LUCreateInstance (for both disk creation and adoption cases)

Now the syntax
"gnt-instance add ... --disk N:adopt=LV_NAME,vg=VG_NAME"
as was described earlier in the man page works.
Signed-off-by: default avatarDmitry Chernyak <>
[ QA changes for reserved LVs, style fixes and a few
 extra error checks, reviewed by hansmi/rn]
Signed-off-by: default avatarIustin Pop <>
Reviewed-by: default avatarIustin Pop <>
parent d1b6262e
......@@ -77,7 +77,7 @@ _IES_PID_FILE = "pid"
_IES_CA_FILE = "ca"
#: Valid LVS output line regex
_LVSLINE_REGEX = re.compile("^ *([^|]+)\|([0-9.]+)\|([^|]{6})\|?$")
_LVSLINE_REGEX = re.compile("^ *([^|]+)\|([^|]+)\|([0-9.]+)\|([^|]{6})\|?$")
class RPCFail(Exception):
......@@ -554,7 +554,7 @@ def VerifyNode(what, cluster_name):
if constants.NV_LVLIST in what and vm_capable:
val = GetVolumeList(what[constants.NV_LVLIST])
val = GetVolumeList(utils.ListVolumeGroups().keys())
except RPCFail, err:
val = str(err)
result[constants.NV_LVLIST] = val
......@@ -622,17 +622,17 @@ def VerifyNode(what, cluster_name):
return result
def GetVolumeList(vg_name):
def GetVolumeList(vg_names):
"""Compute list of logical volumes and their size.
@type vg_name: str
@param vg_name: the volume group whose LVs we should list
@type vg_names: list
@param vg_names: the volume groups whose LVs we should list
@rtype: dict
dictionary of all partions (key) with value being a tuple of
their size (in MiB), inactive and online status::
{'test1': ('20.06', True, True)}
{'xenvg/test1': ('20.06', True, True)}
in case of errors, a string is returned with the error
......@@ -642,7 +642,7 @@ def GetVolumeList(vg_name):
sep = '|'
result = utils.RunCmd(["lvs", "--noheadings", "--units=m", "--nosuffix",
"--separator=%s" % sep,
"-olv_name,lv_size,lv_attr", vg_name])
"-ovg_name,lv_name,lv_size,lv_attr"] + vg_names)
if result.failed:
_Fail("Failed to list logical volumes, lvs output: %s", result.output)
......@@ -652,7 +652,7 @@ def GetVolumeList(vg_name):
if not match:
logging.error("Invalid line returned from lvs output: '%s'", line)
name, size, attr = match.groups()
vg_name, name, size, attr = match.groups()
inactive = attr[4] == '-'
online = attr[5] == 'o'
virtual = attr[0] == 'v'
......@@ -660,7 +660,7 @@ def GetVolumeList(vg_name):
# we don't want to report such volumes as existing, since they
# don't really hold data
lvs[name] = (size, inactive, online)
lvs[vg_name+"/"+name] = (size, inactive, online)
return lvs
......@@ -2399,7 +2399,6 @@ class LUVerifyDisks(NoHooksLU):
result = res_nodes, res_instances, res_missing = {}, [], {}
vg_name = self.cfg.GetVGName()
nodes = utils.NiceSort(self.cfg.GetNodeList())
instances = [self.cfg.GetInstanceInfo(name)
for name in self.cfg.GetInstanceList()]
......@@ -2419,11 +2418,13 @@ class LUVerifyDisks(NoHooksLU):
if not nv_dict:
return result
node_lvs = self.rpc.call_lv_list(nodes, vg_name)
vg_names = self.rpc.call_vg_list(nodes)
vg_names.Raise("Cannot get list of VGs")
for node in nodes:
# node_volume
node_res = node_lvs[node]
node_res = self.rpc.call_lv_list([node],
if node_res.offline:
msg = node_res.fail_msg
......@@ -7678,23 +7679,28 @@ class LUCreateInstance(LogicalUnit):
_CheckNodesFreeDiskPerVG(self, nodenames, req_sizes)
else: # instead, we must check the adoption data
all_lvs = set([i["adopt"] for i in self.disks])
all_lvs = set([i["vg"] + "/" + i["adopt"] for i in self.disks])
if len(all_lvs) != len(self.disks):
raise errors.OpPrereqError("Duplicate volume names given for adoption",
for lv_name in all_lvs:
# FIXME: VG must be provided here. Else all LVs with the
# same name will be locked on all VGs.
# FIXME: lv_name here is "vg/lv" need to ensure that other calls
# to ReserveLV uses the same syntax
self.cfg.ReserveLV(lv_name, self.proc.GetECId())
except errors.ReservationError:
raise errors.OpPrereqError("LV named %s used by another instance" %
lv_name, errors.ECODE_NOTUNIQUE)
vg_names = self.rpc.call_vg_list([])
vg_names.Raise("Cannot get VG information from node %s" %
node_lvs = self.rpc.call_lv_list([],
node_lvs.Raise("Cannot get LV information from node %s" %
node_lvs = node_lvs.payload
delta = all_lvs.difference(node_lvs.keys())
if delta:
raise errors.OpPrereqError("Missing logical volume(s): %s" %
......@@ -7707,7 +7713,7 @@ class LUCreateInstance(LogicalUnit):
# update the size of disk based on what is found
for dsk in self.disks:
dsk["size"] = int(float(node_lvs[dsk["adopt"]][0]))
dsk["size"] = int(float(node_lvs[dsk["vg"] + "/" + dsk["adopt"]][0]))
_CheckHVParams(self, nodenames, self.op.hypervisor, self.op.hvparams)
......@@ -768,8 +768,10 @@ class Instance(TaggableObject):
@param lvmap: optional dictionary to receive the
'node' : ['lv', ...] data.
@return: None if lvmap arg is given, otherwise, a dictionary
of the form { 'nodename' : ['volume1', 'volume2', ...], ... }
@return: None if lvmap arg is given, otherwise, a dictionary of
the form { 'nodename' : ['volume1', 'volume2', ...], ... };
volumeN is of the form "vg_name/lv_name", compatible with
if node == None:
......@@ -788,7 +790,7 @@ class Instance(TaggableObject):
for dev in devs:
if dev.dev_type == constants.LD_LV:
elif dev.dev_type in constants.LDS_DRBD:
if dev.children:
......@@ -136,9 +136,10 @@ def TestClusterReservedLvs():
(False, ["gnt-cluster", "modify", "--reserved-lvs", ""]),
(False, ["lvcreate", "-L1G", "-nqa-test", "xenvg"]),
(True, CVERIFY),
(False, ["gnt-cluster", "modify", "--reserved-lvs", "qa-test,other-test"]),
(False, ["gnt-cluster", "modify", "--reserved-lvs",
(False, CVERIFY),
(False, ["gnt-cluster", "modify", "--reserved-lvs", "qa-.*"]),
(False, ["gnt-cluster", "modify", "--reserved-lvs", ".*/qa-.*"]),
(False, CVERIFY),
(False, ["gnt-cluster", "modify", "--reserved-lvs", ""]),
(True, CVERIFY),
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment