diff --git a/daemons/ganeti-noded b/daemons/ganeti-noded index 959dcf77d63b7294668b80fdd85d803b2726bacf..10705333fdee236399252c9293433d4e34c4eff1 100755 --- a/daemons/ganeti-noded +++ b/daemons/ganeti-noded @@ -472,6 +472,14 @@ class NodeHttpServer(http.server.HttpServer): """ return backend.NodeVolumes() + @staticmethod + def perspective_node_demote_from_mc(params): + """Demote a node from the master candidate role. + + """ + return backend.DemoteFromMC() + + # cluster -------------------------- @staticmethod diff --git a/lib/backend.py b/lib/backend.py index 0c1f23704f97a08a246ae91cc9c7f6c1430661f0..8a5aa8cb2fd7b734c63bb3e24fcf32da0257afdd 100644 --- a/lib/backend.py +++ b/lib/backend.py @@ -2051,6 +2051,26 @@ def ValidateHVParams(hvname, hvparams): return (False, str(err)) +def DemoteFromMC(): + """Demotes the current node from master candidate role. + + """ + # try to ensure we're not the master by mistake + master, myself = ssconf.GetMasterAndMyself() + if master == myself: + return (False, "ssconf status shows I'm the master node, will not demote") + pid_file = utils.DaemonPidFileName(constants.MASTERD_PID) + if utils.IsProcessAlive(utils.ReadPidFile(pid_file)): + return (False, "The master daemon is running, will not demote") + try: + utils.CreateBackup(constants.CLUSTER_CONF_FILE) + except EnvironmentError, err: + if err.errno != errno.ENOENT: + return (False, "Error while backing up cluster file: %s" % str(err)) + utils.RemoveFile(constants.CLUSTER_CONF_FILE) + return (True, "Done") + + class HooksRunner(object): """Hook runner. diff --git a/lib/cmdlib.py b/lib/cmdlib.py index 6e2f41cd2498ce5bc886708fabbdd4350570eaa2..f0521aa0a239703992978e53e1f64993be2e0fa3 100644 --- a/lib/cmdlib.py +++ b/lib/cmdlib.py @@ -2157,6 +2157,13 @@ class LUSetNodeParams(LogicalUnit): if self.op.master_candidate is not None: node.master_candidate = self.op.master_candidate result.append(("master_candidate", str(self.op.master_candidate))) + if self.op.master_candidate == False: + rrc = self.rpc.call_node_demote_from_mc(node.name) + if (rrc.failed or not isinstance(rrc.data, (tuple, list)) + or len(rrc.data) != 2): + self.LogWarning("Node rpc error: %s" % rrc.error) + elif not rrc.data[0]: + self.LogWarning("Node failed to demote itself: %s" % rrc.data[1]) # this will trigger configuration file update, if needed self.cfg.Update(node) diff --git a/lib/rpc.py b/lib/rpc.py index 11887e443a2ff7b652786290cc6e895cfdfbf846..86a6a3ff93092f68aa863df65735c03222edeed3 100644 --- a/lib/rpc.py +++ b/lib/rpc.py @@ -828,6 +828,14 @@ class RpcRunner(object): """ return self._MultiNodeCall(node_list, "node_volumes", []) + def call_node_demote_from_mc(self, node): + """Demote a node from the master candidate role. + + This is a single-node call. + + """ + return self._SingleNodeCall(node, "node_demote_from_mc", []) + def call_test_delay(self, node_list, duration): """Sleep for a fixed time on given node(s).