+
+
+def GetMaster():
+ """Returns the current master node.
+
+ This is a separate function in bootstrap since it's needed by
+ gnt-cluster, and instead of importing directly ssconf, it's better
+ to abstract it in bootstrap, where we do use ssconf in other
+ functions too.
+
+ """
+ sstore = ssconf.SimpleStore()
+
+ old_master, _ = ssconf.GetMasterAndMyself(sstore)
+
+ return old_master
+
+
+def GatherMasterVotes(node_list):
+ """Check the agreement on who is the master.
+
+ This function will return a list of (node, number of votes), ordered
+ by the number of votes. Errors will be denoted by the key 'None'.
+
+ Note that the sum of votes is the number of nodes this machine
+ knows, whereas the number of entries in the list could be different
+ (if some nodes vote for another master).
+
+ We remove ourselves from the list since we know that (bugs aside)
+ since we use the same source for configuration information for both
+ backend and boostrap, we'll always vote for ourselves.
+
+ @type node_list: list
+ @param node_list: the list of nodes to query for master info; the current
+ node will be removed if it is in the list
+ @rtype: list
+ @return: list of (node, votes)
+
+ """
+ myself = utils.HostInfo().name
+ try:
+ node_list.remove(myself)
+ except ValueError:
+ pass
+ if not node_list:
+ # no nodes left (eventually after removing myself)
+ return []
+ results = rpc.RpcRunner.call_master_info(node_list)
+ if not isinstance(results, dict):
+ # this should not happen (unless internal error in rpc)
+ logging.critical("Can't complete rpc call, aborting master startup")
+ return [(None, len(node_list))]
+ votes = {}
+ for node in results:
+ nres = results[node]
+ data = nres.payload
+ msg = nres.fail_msg
+ fail = False
+ if msg:
+ logging.warning("Error contacting node %s: %s", node, msg)
+ fail = True
+ elif not isinstance(data, (tuple, list)) or len(data) < 3:
+ logging.warning("Invalid data received from node %s: %s", node, data)
+ fail = True
+ if fail:
+ if None not in votes:
+ votes[None] = 0
+ votes[None] += 1
+ continue
+ master_node = data[2]
+ if master_node not in votes:
+ votes[master_node] = 0
+ votes[master_node] += 1
+
+ vote_list = [v for v in votes.items()]
+ # sort first on number of votes then on name, since we want None
+ # sorted later if we have the half of the nodes not responding, and
+ # half voting all for the same master
+ vote_list.sort(key=lambda x: (x[1], x[0]), reverse=True)
+
+ return vote_list