Make rpc.call_lv_list() VG-aware
authorDmitry Chernyak <dmi.chernyak@gmail.com>
Fri, 26 Nov 2010 19:57:00 +0000 (22:57 +0300)
committerIustin Pop <iustin@google.com>
Thu, 2 Dec 2010 13:46:42 +0000 (13:46 +0000)
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: Dmitry Chernyak <dmi.chernyak@gmail.com>
[iustin@google.com: QA changes for reserved LVs, style fixes and a few
 extra error checks, reviewed by hansmi/rn]
Signed-off-by: Iustin Pop <iustin@google.com>
Reviewed-by: Iustin Pop <iustin@google.com>

lib/backend.py
lib/cmdlib.py
lib/objects.py
qa/qa_cluster.py

index b6f7ceb..b42ebe7 100644 (file)
@@ -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:
     try:
-      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
   @return:
       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
       details.
@@ -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)
       continue
-    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
       continue
-    lvs[name] = (size, inactive, online)
+    lvs[vg_name+"/"+name] = (size, inactive, online)
 
   return lvs
 
index db0e82c..ab8cf39 100644 (file)
@@ -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],
+                                       vg_names[node].payload.keys())[node]
       if node_res.offline:
         continue
       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",
                                    errors.ECODE_INVAL)
       for lv_name in all_lvs:
         try:
-          # 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([pnode.name])
+      vg_names.Raise("Cannot get VG information from node %s" % pnode.name)
+
       node_lvs = self.rpc.call_lv_list([pnode.name],
-                                       self.cfg.GetVGName())[pnode.name]
+                                       vg_names[pnode.name].payload.keys()
+                                      )[pnode.name]
       node_lvs.Raise("Cannot get LV information from node %s" % pnode.name)
       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):
                                    errors.ECODE_STATE)
       # 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)
 
index 597469f..6e7c33f 100644 (file)
@@ -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
+        GetVolumeList()
 
     """
     if node == None:
@@ -788,7 +790,7 @@ class Instance(TaggableObject):
 
     for dev in devs:
       if dev.dev_type == constants.LD_LV:
-        lvmap[node].append(dev.logical_id[1])
+        lvmap[node].append(dev.logical_id[0]+"/"+dev.logical_id[1])
 
       elif dev.dev_type in constants.LDS_DRBD:
         if dev.children:
index dc5c79b..575d2d7 100644 (file)
@@ -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",
+             "xenvg/qa-test,.*/other-test"]),
     (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),