diff --git a/lib/backend.py b/lib/backend.py index 2ce1385270a2efbffcdbdfbac1a5b399c022ffbc..389d4ed35f0b7769144d2407519358663b9d1eb8 100644 --- a/lib/backend.py +++ b/lib/backend.py @@ -432,6 +432,14 @@ def VerifyNode(what, cluster_name): hyper = hypervisor.GetHypervisor(what[constants.NV_HVINFO]) result[constants.NV_HVINFO] = hyper.GetNodeInfo() + if constants.NV_DRBDLIST in what: + try: + used_minors = bdev.DRBD8.GetUsedDevs().keys() + except errors.BlockDeviceErrors: + logging.warning("Can't get used minors list", exc_info=True) + used_minors = [] + result[constants.NV_DRBDLIST] = used_minors + return result diff --git a/lib/bdev.py b/lib/bdev.py index 9207e2c06762223e8f2b9fd4bf3b97e08ea1b916..08551b2d849ba2b1d14c9b7cf1bae398040ebc45 100644 --- a/lib/bdev.py +++ b/lib/bdev.py @@ -692,7 +692,7 @@ class BaseDRBD(BlockDev): return "/dev/drbd%d" % minor @classmethod - def _GetUsedDevs(cls): + def GetUsedDevs(cls): """Compute the list of used DRBD devices. """ @@ -1343,7 +1343,7 @@ class DRBD8(BaseDRBD): /proc). """ - used_devs = self._GetUsedDevs() + used_devs = self.GetUsedDevs() if self._aminor in used_devs: minor = self._aminor else: diff --git a/lib/cmdlib.py b/lib/cmdlib.py index 2614f2413f20a62662256349c8a9f3e52da70d4a..01ad1fd8dfa5d057d3ea203b5797dddb11910fca 100644 --- a/lib/cmdlib.py +++ b/lib/cmdlib.py @@ -613,7 +613,8 @@ class LUVerifyCluster(LogicalUnit): self.share_locks = dict(((i, 1) for i in locking.LEVELS)) def _VerifyNode(self, nodeinfo, file_list, local_cksum, - node_result, feedback_fn, master_files): + node_result, feedback_fn, master_files, + drbd_map): """Run multiple tests against a node. Test list: @@ -630,6 +631,9 @@ class LUVerifyCluster(LogicalUnit): @param node_result: the results from the node @param feedback_fn: function used to accumulate results @param master_files: list of files that only masters should have + @param drbd_map: the useddrbd minors for this node, in + form of minor: (instance, must_exist) which correspond to instances + and their running status """ node = nodeinfo.name @@ -724,6 +728,19 @@ class LUVerifyCluster(LogicalUnit): if hv_result is not None: feedback_fn(" - ERROR: hypervisor %s verify failure: '%s'" % (hv_name, hv_result)) + + # check used drbd list + used_minors = node_result.get(constants.NV_DRBDLIST, []) + for minor, (iname, must_exist) in drbd_map.items(): + if minor not in used_minors and must_exist: + feedback_fn(" - ERROR: drbd minor %d of instance %s is not active" % + (minor, iname)) + bad = True + for minor in used_minors: + if minor not in drbd_map: + feedback_fn(" - ERROR: unallocated drbd minor %d is in use" % minor) + bad = True + return bad def _VerifyInstance(self, instance, instanceconfig, node_vol_is, @@ -867,6 +884,8 @@ class LUVerifyCluster(LogicalUnit): nodelist = utils.NiceSort(self.cfg.GetNodeList()) nodeinfo = [self.cfg.GetNodeInfo(nname) for nname in nodelist] instancelist = utils.NiceSort(self.cfg.GetInstanceList()) + instanceinfo = dict((iname, self.cfg.GetInstanceInfo(iname)) + for iname in instancelist) i_non_redundant = [] # Non redundant instances i_non_a_balanced = [] # Non auto-balanced instances n_offline = [] # List of offline nodes @@ -900,12 +919,15 @@ class LUVerifyCluster(LogicalUnit): constants.NV_VGLIST: None, constants.NV_VERSION: None, constants.NV_HVINFO: self.cfg.GetHypervisorType(), + constants.NV_DRBDLIST: None, } all_nvinfo = self.rpc.call_node_verify(nodelist, node_verify_param, self.cfg.GetClusterName()) cluster = self.cfg.GetClusterInfo() master_node = self.cfg.GetMasterNode() + all_drbd_map = self.cfg.ComputeDRBDMap() + for node_i in nodeinfo: node = node_i.name nresult = all_nvinfo[node].data @@ -928,8 +950,13 @@ class LUVerifyCluster(LogicalUnit): bad = True continue + node_drbd = {} + for minor, instance in all_drbd_map[node].items(): + instance = instanceinfo[instance] + node_drbd[minor] = (instance.name, instance.status == "up") result = self._VerifyNode(node_i, file_names, local_checksums, - nresult, feedback_fn, master_files) + nresult, feedback_fn, master_files, + node_drbd) bad = bad or result lvdata = nresult.get(constants.NV_LVLIST, "Missing LV data") @@ -985,7 +1012,7 @@ class LUVerifyCluster(LogicalUnit): for instance in instancelist: feedback_fn("* Verifying instance %s" % instance) - inst_config = self.cfg.GetInstanceInfo(instance) + inst_config = instanceinfo[instance] result = self._VerifyInstance(instance, inst_config, node_volume, node_instance, feedback_fn, n_offline) bad = bad or result diff --git a/lib/config.py b/lib/config.py index 29acbd16aa9cbda740fbab412b8bb42c3d5f1424..67b44906662f4a44623cce5045e5893ab1f621ce 100644 --- a/lib/config.py +++ b/lib/config.py @@ -389,7 +389,7 @@ class ConfigWriter: self._WriteConfig() return port - def _ComputeDRBDMap(self, instance): + def _UnlockedComputeDRBDMap(self): """Compute the used DRBD minor/nodes. @return: dictionary of node_name: dict of minor: instance_name; @@ -421,6 +421,19 @@ class ConfigWriter: _AppendUsedPorts(instance.name, disk, my_dict) return my_dict + @locking.ssynchronized(_config_lock) + def ComputeDRBDMap(self): + """Compute the used DRBD minor/nodes. + + This is just a wrapper over L{_UnlockedComputeDRBDMap}. + + @return: dictionary of node_name: dict of minor: instance_name; + the returned dict will have all the nodes in it (even if with + an empty list). + + """ + return self._UnlockedComputeDRBDMap() + @locking.ssynchronized(_config_lock) def AllocateDRBDMinor(self, nodes, instance): """Allocate a drbd minor. @@ -431,7 +444,7 @@ class ConfigWriter: order as the passed nodes. """ - d_map = self._ComputeDRBDMap(instance) + d_map = self._UnlockedComputeDRBDMap() result = [] for nname in nodes: ndata = d_map[nname] diff --git a/lib/constants.py b/lib/constants.py index a483165fb7df1d23ac33528248245bef06b27df1..7250b4f788a09b8ad7854a8c2d0470417881aadc 100644 --- a/lib/constants.py +++ b/lib/constants.py @@ -351,6 +351,7 @@ NV_NODELIST = "nodelist" NV_NODENETTEST = "node-net-test" NV_VERSION = "version" NV_VGLIST = "vglist" +NV_DRBDLIST = "drbd-list" # Allocator framework constants IALLOCATOR_DIR_IN = "in"