Revision 64c7b383
b/lib/backend.py | ||
---|---|---|
520 | 520 |
what[constants.NV_FILELIST]) |
521 | 521 |
|
522 | 522 |
if constants.NV_NODELIST in what: |
523 |
result[constants.NV_NODELIST] = tmp = {} |
|
524 |
random.shuffle(what[constants.NV_NODELIST]) |
|
525 |
for node in what[constants.NV_NODELIST]: |
|
523 |
(nodes, bynode) = what[constants.NV_NODELIST] |
|
524 |
|
|
525 |
# Add nodes from other groups (different for each node) |
|
526 |
try: |
|
527 |
nodes.extend(bynode[my_name]) |
|
528 |
except KeyError: |
|
529 |
pass |
|
530 |
|
|
531 |
# Use a random order |
|
532 |
random.shuffle(nodes) |
|
533 |
|
|
534 |
# Try to contact all nodes |
|
535 |
val = {} |
|
536 |
for node in nodes: |
|
526 | 537 |
success, message = _GetSshRunner(cluster_name).VerifyNodeHostname(node) |
527 | 538 |
if not success: |
528 |
tmp[node] = message |
|
539 |
val[node] = message |
|
540 |
|
|
541 |
result[constants.NV_NODELIST] = val |
|
529 | 542 |
|
530 | 543 |
if constants.NV_NODENETTEST in what: |
531 | 544 |
result[constants.NV_NODENETTEST] = tmp = {} |
b/lib/cmdlib.py | ||
---|---|---|
2542 | 2542 |
|
2543 | 2543 |
return instdisk |
2544 | 2544 |
|
2545 |
@staticmethod |
|
2546 |
def _SshNodeSelector(group_uuid, all_nodes): |
|
2547 |
"""Create endless iterators for all potential SSH check hosts. |
|
2548 |
|
|
2549 |
""" |
|
2550 |
nodes = [node for node in all_nodes |
|
2551 |
if (node.group != group_uuid and |
|
2552 |
not node.offline)] |
|
2553 |
keyfunc = operator.attrgetter("group") |
|
2554 |
|
|
2555 |
return map(itertools.cycle, |
|
2556 |
[sorted(map(operator.attrgetter("name"), names)) |
|
2557 |
for _, names in itertools.groupby(sorted(nodes, key=keyfunc), |
|
2558 |
keyfunc)]) |
|
2559 |
|
|
2560 |
@classmethod |
|
2561 |
def _SelectSshCheckNodes(cls, group_nodes, group_uuid, all_nodes): |
|
2562 |
"""Choose which nodes should talk to which other nodes. |
|
2563 |
|
|
2564 |
We will make nodes contact all nodes in their group, and one node from |
|
2565 |
every other group. |
|
2566 |
|
|
2567 |
@warning: This algorithm has a known issue if one node group is much |
|
2568 |
smaller than others (e.g. just one node). In such a case all other |
|
2569 |
nodes will talk to the single node. |
|
2570 |
|
|
2571 |
""" |
|
2572 |
online_nodes = sorted(node.name for node in group_nodes if not node.offline) |
|
2573 |
sel = cls._SshNodeSelector(group_uuid, all_nodes) |
|
2574 |
|
|
2575 |
return (online_nodes, |
|
2576 |
dict((name, sorted([i.next() for i in sel])) |
|
2577 |
for name in online_nodes)) |
|
2578 |
|
|
2545 | 2579 |
def BuildHooksEnv(self): |
2546 | 2580 |
"""Build hooks env. |
2547 | 2581 |
|
... | ... | |
2605 | 2639 |
|
2606 | 2640 |
feedback_fn("* Gathering data (%d nodes)" % len(self.my_node_names)) |
2607 | 2641 |
|
2608 |
# We will make nodes contact all nodes in their group, and one node from |
|
2609 |
# every other group. |
|
2610 |
# TODO: should it be a *random* node, different every time? |
|
2611 |
online_nodes = [node.name for node in node_data_list if not node.offline] |
|
2612 |
other_group_nodes = {} |
|
2613 |
|
|
2614 |
for name in sorted(self.all_node_info): |
|
2615 |
node = self.all_node_info[name] |
|
2616 |
if (node.group not in other_group_nodes |
|
2617 |
and node.group != self.group_uuid |
|
2618 |
and not node.offline): |
|
2619 |
other_group_nodes[node.group] = node.name |
|
2620 |
|
|
2621 | 2642 |
node_verify_param = { |
2622 | 2643 |
constants.NV_FILELIST: |
2623 | 2644 |
utils.UniqueSequence(filename |
2624 | 2645 |
for files in filemap |
2625 | 2646 |
for filename in files), |
2626 |
constants.NV_NODELIST: online_nodes + other_group_nodes.values(), |
|
2647 |
constants.NV_NODELIST: |
|
2648 |
self._SelectSshCheckNodes(node_data_list, self.group_uuid, |
|
2649 |
self.all_node_info.values()), |
|
2627 | 2650 |
constants.NV_HYPERVISOR: hypervisors, |
2628 | 2651 |
constants.NV_HVPARAMS: |
2629 | 2652 |
_GetAllHypervisorParameters(cluster, self.all_inst_info.values()), |
b/test/ganeti.cmdlib_unittest.py | ||
---|---|---|
27 | 27 |
import time |
28 | 28 |
import tempfile |
29 | 29 |
import shutil |
30 |
import operator |
|
30 | 31 |
|
31 | 32 |
from ganeti import constants |
32 | 33 |
from ganeti import mcpu |
... | ... | |
207 | 208 |
self.assertEqual(set(["inst3c"]), set(prev)) |
208 | 209 |
|
209 | 210 |
|
211 |
class TestClusterVerifySsh(unittest.TestCase): |
|
212 |
def testMultipleGroups(self): |
|
213 |
fn = cmdlib.LUClusterVerifyGroup._SelectSshCheckNodes |
|
214 |
mygroupnodes = [ |
|
215 |
objects.Node(name="node20", group="my", offline=False), |
|
216 |
objects.Node(name="node21", group="my", offline=False), |
|
217 |
objects.Node(name="node22", group="my", offline=False), |
|
218 |
objects.Node(name="node23", group="my", offline=False), |
|
219 |
objects.Node(name="node24", group="my", offline=False), |
|
220 |
objects.Node(name="node25", group="my", offline=False), |
|
221 |
objects.Node(name="node26", group="my", offline=True), |
|
222 |
] |
|
223 |
nodes = [ |
|
224 |
objects.Node(name="node1", group="g1", offline=True), |
|
225 |
objects.Node(name="node2", group="g1", offline=False), |
|
226 |
objects.Node(name="node3", group="g1", offline=False), |
|
227 |
objects.Node(name="node4", group="g1", offline=True), |
|
228 |
objects.Node(name="node5", group="g1", offline=False), |
|
229 |
objects.Node(name="node10", group="xyz", offline=False), |
|
230 |
objects.Node(name="node11", group="xyz", offline=False), |
|
231 |
objects.Node(name="node40", group="alloff", offline=True), |
|
232 |
objects.Node(name="node41", group="alloff", offline=True), |
|
233 |
objects.Node(name="node50", group="aaa", offline=False), |
|
234 |
] + mygroupnodes |
|
235 |
assert not utils.FindDuplicates(map(operator.attrgetter("name"), nodes)) |
|
236 |
|
|
237 |
(online, perhost) = fn(mygroupnodes, "my", nodes) |
|
238 |
self.assertEqual(online, ["node%s" % i for i in range(20, 26)]) |
|
239 |
self.assertEqual(set(perhost.keys()), set(online)) |
|
240 |
|
|
241 |
self.assertEqual(perhost, { |
|
242 |
"node20": ["node10", "node2", "node50"], |
|
243 |
"node21": ["node11", "node3", "node50"], |
|
244 |
"node22": ["node10", "node5", "node50"], |
|
245 |
"node23": ["node11", "node2", "node50"], |
|
246 |
"node24": ["node10", "node3", "node50"], |
|
247 |
"node25": ["node11", "node5", "node50"], |
|
248 |
}) |
|
249 |
|
|
250 |
def testSingleGroup(self): |
|
251 |
fn = cmdlib.LUClusterVerifyGroup._SelectSshCheckNodes |
|
252 |
nodes = [ |
|
253 |
objects.Node(name="node1", group="default", offline=True), |
|
254 |
objects.Node(name="node2", group="default", offline=False), |
|
255 |
objects.Node(name="node3", group="default", offline=False), |
|
256 |
objects.Node(name="node4", group="default", offline=True), |
|
257 |
] |
|
258 |
assert not utils.FindDuplicates(map(operator.attrgetter("name"), nodes)) |
|
259 |
|
|
260 |
(online, perhost) = fn(nodes, "default", nodes) |
|
261 |
self.assertEqual(online, ["node2", "node3"]) |
|
262 |
self.assertEqual(set(perhost.keys()), set(online)) |
|
263 |
|
|
264 |
self.assertEqual(perhost, { |
|
265 |
"node2": [], |
|
266 |
"node3": [], |
|
267 |
}) |
|
268 |
|
|
269 |
|
|
210 | 270 |
if __name__ == "__main__": |
211 | 271 |
testutils.GanetiTestProgram() |
Also available in: Unified diff