diff --git a/python/pacemaker/_cts/tests/maintenancemode.py b/python/pacemaker/_cts/tests/maintenancemode.py index 9791e44ce7..f9ed8678bd 100644 --- a/python/pacemaker/_cts/tests/maintenancemode.py +++ b/python/pacemaker/_cts/tests/maintenancemode.py @@ -1,217 +1,228 @@ """ Toggle nodes in and out of maintenance mode """ __all__ = ["MaintenanceMode"] __copyright__ = "Copyright 2000-2023 the Pacemaker project contributors" __license__ = "GNU General Public License version 2 or later (GPLv2+) WITHOUT ANY WARRANTY" import re from pacemaker._cts.audits import AuditResource from pacemaker._cts.tests.ctstest import CTSTest from pacemaker._cts.tests.simulstartlite import SimulStartLite from pacemaker._cts.tests.starttest import StartTest from pacemaker._cts.timer import Timer +# Disable various pylint warnings that occur in so many places throughout this +# file it's easiest to just take care of them globally. This does introduce the +# possibility that we'll miss some other cause of the same warning, but we'll +# just have to be careful. + +# pylint doesn't understand that self._rsh is callable. +# pylint: disable=not-callable + class MaintenanceMode(CTSTest): """ A concrete test that toggles nodes in and out of maintenance mode """ def __init__(self, cm): """ Create a new MaintenanceMode instance Arguments: cm -- A ClusterManager instance """ CTSTest.__init__(self, cm) - self.action = "asyncmon" self.benchmark = True - self.interval = 0 - self.max = 30 self.name = "MaintenanceMode" - self.rid = "maintenanceDummy" + self._action = "asyncmon" + self._rid = "maintenanceDummy" self._start = StartTest(cm) self._startall = SimulStartLite(cm) - def toggleMaintenanceMode(self, node, action): + def _toggle_maintenance_mode(self, node, enabled): """ Toggle maintenance mode on the given node """ - pats = [] - pats.append(self.templates["Pat:DC_IDLE"]) + pats = [ self.templates["Pat:DC_IDLE"] ] + + if enabled: + action = "On" + else: + action = "Off" # fail the resource right after turning Maintenance mode on # verify it is not recovered until maintenance mode is turned off - if action == "On": - pats.append(self.templates["Pat:RscOpFail"] % (self.action, self.rid)) + if enabled: + pats.append(self.templates["Pat:RscOpFail"] % (self._action, self._rid)) else: - pats.append(self.templates["Pat:RscOpOK"] % ("stop", self.rid)) - pats.append(self.templates["Pat:RscOpOK"] % ("start", self.rid)) + pats.extend([ self.templates["Pat:RscOpOK"] % ("stop", self._rid), + self.templates["Pat:RscOpOK"] % ("start", self._rid) ]) watch = self.create_watch(pats, 60) watch.set_watch() self.debug("Turning maintenance mode %s" % action) - self._rsh(node, self.templates["MaintenanceMode%s" % (action)]) + self._rsh(node, self.templates["MaintenanceMode%s" % action]) - if (action == "On"): - self._rsh(node, "crm_resource -V -F -r %s -H %s &>/dev/null" % (self.rid, node)) + if enabled: + self._rsh(node, "crm_resource -V -F -r %s -H %s &>/dev/null" % (self._rid, node)) with Timer(self._logger, self.name, "recover%s" % action): watch.look_for_all() if watch.unmatched: self.debug("Failed to find patterns when turning maintenance mode %s" % action) return repr(watch.unmatched) return "" - def insertMaintenanceDummy(self, node): + def _insert_maintenance_dummy(self, node): """ Create a dummy resource on the given node """ - pats = [] - pats.append(("%s.*" % node) + (self.templates["Pat:RscOpOK"] % ("start", self.rid))) + pats = [ ("%s.*" % node) + (self.templates["Pat:RscOpOK"] % ("start", self._rid)) ] watch = self.create_watch(pats, 60) watch.set_watch() - self._cm.AddDummyRsc(node, self.rid) + self._cm.AddDummyRsc(node, self._rid) with Timer(self._logger, self.name, "addDummy"): watch.look_for_all() if watch.unmatched: self.debug("Failed to find patterns when adding maintenance dummy resource") return repr(watch.unmatched) return "" - def removeMaintenanceDummy(self, node): + def _remove_maintenance_dummy(self, node): """ Remove the previously created dummy resource on the given node """ - pats = [] - pats.append(self.templates["Pat:RscOpOK"] % ("stop", self.rid)) + pats = [ self.templates["Pat:RscOpOK"] % ("stop", self._rid) ] watch = self.create_watch(pats, 60) watch.set_watch() - self._cm.RemoveDummyRsc(node, self.rid) + self._cm.RemoveDummyRsc(node, self._rid) with Timer(self._logger, self.name, "removeDummy"): watch.look_for_all() if watch.unmatched: self.debug("Failed to find patterns when removing maintenance dummy resource") return repr(watch.unmatched) return "" - def managedRscList(self, node): + def _managed_rscs(self, node): """ Return a list of all resources managed by the cluster """ - rscList = [] + rscs = [] (_, lines) = self._rsh(node, "crm_resource -c", verbose=1) for line in lines: if re.search("^Resource", line): tmp = AuditResource(self._cm, line) if tmp.managed: - rscList.append(tmp.id) + rscs.append(tmp.id) - return rscList + return rscs - def verifyResources(self, node, rscList, managed): + def _verify_resources(self, node, rscs, managed): """ Verify that all resources in rscList are managed if they are expected to be, or unmanaged if they are expected to be. """ - managedList = list(rscList) + managed_rscs = rscs managed_str = "managed" if not managed: managed_str = "unmanaged" (_, lines) = self._rsh(node, "crm_resource -c", verbose=1) for line in lines: if re.search("^Resource", line): tmp = AuditResource(self._cm, line) if managed and not tmp.managed: continue - elif not managed and tmp.managed: + + if not managed and tmp.managed: continue - elif managedList.count(tmp.id): - managedList.remove(tmp.id) - if len(managedList) == 0: + if managed_rscs.count(tmp.id): + managed_rscs.remove(tmp.id) + + if not managed_rscs: self.debug("Found all %s resources on %s" % (managed_str, node)) return True - self._logger.log("Could not find all %s resources on %s. %s" % (managed_str, node, managedList)) + self._logger.log("Could not find all %s resources on %s. %s" % (managed_str, node, managed_rscs)) return False def __call__(self, node): """ Perform this test """ self.incr("calls") verify_managed = False verify_unmanaged = False - failPat = "" + fail_pat = "" - ret = self._startall(None) - if not ret: + if not self._startall(None): return self.failure("Setup failed") # get a list of all the managed resources. We use this list # after enabling maintenance mode to verify all managed resources # become un-managed. After maintenance mode is turned off, we use # this list to verify all the resources become managed again. - managedResources = self.managedRscList(node) - if len(managedResources) == 0: + managed_rscs = self._managed_rscs(node) + if not managed_rscs: self._logger.log("No managed resources on %s" % node) return self.skipped() # insert a fake resource we can fail during maintenance mode # so we can verify recovery does not take place until after maintenance # mode is disabled. - failPat = failPat + self.insertMaintenanceDummy(node) + fail_pat += self._insert_maintenance_dummy(node) # toggle maintenance mode ON, then fail dummy resource. - failPat = failPat + self.toggleMaintenanceMode(node, "On") + fail_pat += self._toggle_maintenance_mode(node, True) # verify all the resources are now unmanaged - if self.verifyResources(node, managedResources, False): + if self._verify_resources(node, managed_rscs, False): verify_unmanaged = True # Toggle maintenance mode OFF, verify dummy is recovered. - failPat = failPat + self.toggleMaintenanceMode(node, "Off") + fail_pat += self._toggle_maintenance_mode(node, False) # verify all the resources are now managed again - if self.verifyResources(node, managedResources, True): + if self._verify_resources(node, managed_rscs, True): verify_managed = True # Remove our maintenance dummy resource. - failPat = failPat + self.removeMaintenanceDummy(node) + fail_pat += self._remove_maintenance_dummy(node) self._cm.cluster_stable() - if failPat != "": - return self.failure("Unmatched patterns: %s" % (failPat)) - elif verify_unmanaged is False: + if fail_pat != "": + return self.failure("Unmatched patterns: %s" % fail_pat) + + if not verify_unmanaged: return self.failure("Failed to verify resources became unmanaged during maintenance mode") - elif verify_managed is False: + + if not verify_managed: return self.failure("Failed to verify resources switched back to managed after disabling maintenance mode") return self.success() @property def errors_to_ignore(self): """ Return list of errors which should be ignored """ - return [ r"Updating failcount for %s" % self.rid, - r"schedulerd.*: Recover\s+%s\s+\(.*\)" % self.rid, + return [ r"Updating failcount for %s" % self._rid, + r"schedulerd.*: Recover\s+%s\s+\(.*\)" % self._rid, r"Unknown operation: fail", - self.templates["Pat:RscOpOK"] % (self.action, self.rid), - r"(ERROR|error).*: Action %s_%s_%d .* initiated outside of a transition" % (self.rid, self.action, self.interval) ] + self.templates["Pat:RscOpOK"] % (self._action, self._rid), + r"(ERROR|error).*: Action %s_%s_%d .* initiated outside of a transition" % (self._rid, self._action, 0) ]