def GetOnlineNodes(nodes, cl=None, nowarn=False, secondary_ips=False,
- filter_master=False):
+ filter_master=False, nodegroup=None):
"""Returns the names of online nodes.
This function will also log a warning on stderr with the names of
@param filter_master: if True, do not return the master node in the list
(useful in coordination with secondary_ips where we cannot check our
node name against the list)
+ @type nodegroup: string
+ @param nodegroup: If set, only return nodes in this node group
"""
if cl is None:
cl = GetClient()
- if secondary_ips:
- name_idx = 2
- else:
- name_idx = 0
+ filter_ = []
+
+ if nodes:
+ filter_.append(qlang.MakeSimpleFilter("name", nodes))
+
+ if nodegroup is not None:
+ filter_.append([qlang.OP_OR, [qlang.OP_EQUAL, "group", nodegroup],
+ [qlang.OP_EQUAL, "group.uuid", nodegroup]])
if filter_master:
- master_node = cl.QueryConfigValues(["master_node"])[0]
- filter_fn = lambda x: x != master_node
+ filter_.append([qlang.OP_NOT, [qlang.OP_TRUE, "master"]])
+
+ if filter_:
+ if len(filter_) > 1:
+ final_filter = [qlang.OP_AND] + filter_
+ else:
+ assert len(filter_) == 1
+ final_filter = filter_[0]
else:
- filter_fn = lambda _: True
+ final_filter = None
+
+ result = cl.Query(constants.QR_NODE, ["name", "offline", "sip"], final_filter)
+
+ def _IsOffline(row):
+ (_, (_, offline), _) = row
+ return offline
+
+ def _GetName(row):
+ ((_, name), _, _) = row
+ return name
+
+ def _GetSip(row):
+ (_, _, (_, sip)) = row
+ return sip
+
+ (offline, online) = compat.partition(result.data, _IsOffline)
- result = cl.QueryNodes(names=nodes, fields=["name", "offline", "sip"],
- use_locking=False)
- offline = [row[0] for row in result if row[1]]
if offline and not nowarn:
- ToStderr("Note: skipping offline node(s): %s" % utils.CommaJoin(offline))
- return [row[name_idx] for row in result if not row[1] and filter_fn(row[0])]
+ ToStderr("Note: skipping offline node(s): %s" %
+ utils.CommaJoin(map(_GetName, offline)))
+
+ if secondary_ips:
+ fn = _GetSip
+ else:
+ fn = _GetName
+
+ return map(fn, online)
def _ToStream(stream, txt, *args):
from ganeti import errors
from ganeti import utils
from ganeti import objects
+from ganeti import qlang
from ganeti.errors import OpPrereqError, ParameterError
self.assertTrue(result.endswith(")"))
+class TestGetOnlineNodes(unittest.TestCase):
+ class _FakeClient:
+ def __init__(self):
+ self._query = []
+
+ def AddQueryResult(self, *args):
+ self._query.append(args)
+
+ def CountPending(self):
+ return len(self._query)
+
+ def Query(self, res, fields, filter_):
+ if res != constants.QR_NODE:
+ raise Exception("Querying wrong resource")
+
+ (exp_fields, check_filter, result) = self._query.pop(0)
+
+ if exp_fields != fields:
+ raise Exception("Expected fields %s, got %s" % (exp_fields, fields))
+
+ if not (filter_ is None or check_filter(filter_)):
+ raise Exception("Filter doesn't match expectations")
+
+ return objects.QueryResponse(fields=None, data=result)
+
+ def testEmpty(self):
+ cl = self._FakeClient()
+
+ cl.AddQueryResult(["name", "offline", "sip"], None, [])
+ self.assertEqual(cli.GetOnlineNodes(None, cl=cl), [])
+ self.assertEqual(cl.CountPending(), 0)
+
+ def testNoSpecialFilter(self):
+ cl = self._FakeClient()
+
+ cl.AddQueryResult(["name", "offline", "sip"], None, [
+ [(constants.RS_NORMAL, "master.example.com"),
+ (constants.RS_NORMAL, False),
+ (constants.RS_NORMAL, "192.0.2.1")],
+ [(constants.RS_NORMAL, "node2.example.com"),
+ (constants.RS_NORMAL, False),
+ (constants.RS_NORMAL, "192.0.2.2")],
+ ])
+ self.assertEqual(cli.GetOnlineNodes(None, cl=cl),
+ ["master.example.com", "node2.example.com"])
+ self.assertEqual(cl.CountPending(), 0)
+
+ def testNoMaster(self):
+ cl = self._FakeClient()
+
+ def _CheckFilter(filter_):
+ self.assertEqual(filter_, [qlang.OP_NOT, [qlang.OP_TRUE, "master"]])
+ return True
+
+ cl.AddQueryResult(["name", "offline", "sip"], _CheckFilter, [
+ [(constants.RS_NORMAL, "node2.example.com"),
+ (constants.RS_NORMAL, False),
+ (constants.RS_NORMAL, "192.0.2.2")],
+ ])
+ self.assertEqual(cli.GetOnlineNodes(None, cl=cl, filter_master=True),
+ ["node2.example.com"])
+ self.assertEqual(cl.CountPending(), 0)
+
+ def testSecondaryIpAddress(self):
+ cl = self._FakeClient()
+
+ cl.AddQueryResult(["name", "offline", "sip"], None, [
+ [(constants.RS_NORMAL, "master.example.com"),
+ (constants.RS_NORMAL, False),
+ (constants.RS_NORMAL, "192.0.2.1")],
+ [(constants.RS_NORMAL, "node2.example.com"),
+ (constants.RS_NORMAL, False),
+ (constants.RS_NORMAL, "192.0.2.2")],
+ ])
+ self.assertEqual(cli.GetOnlineNodes(None, cl=cl, secondary_ips=True),
+ ["192.0.2.1", "192.0.2.2"])
+ self.assertEqual(cl.CountPending(), 0)
+
+ def testNoMasterFilterNodeName(self):
+ cl = self._FakeClient()
+
+ def _CheckFilter(filter_):
+ self.assertEqual(filter_,
+ [qlang.OP_AND,
+ [qlang.OP_OR] + [[qlang.OP_EQUAL, "name", name]
+ for name in ["node2", "node3"]],
+ [qlang.OP_NOT, [qlang.OP_TRUE, "master"]]])
+ return True
+
+ cl.AddQueryResult(["name", "offline", "sip"], _CheckFilter, [
+ [(constants.RS_NORMAL, "node2.example.com"),
+ (constants.RS_NORMAL, False),
+ (constants.RS_NORMAL, "192.0.2.12")],
+ [(constants.RS_NORMAL, "node3.example.com"),
+ (constants.RS_NORMAL, False),
+ (constants.RS_NORMAL, "192.0.2.13")],
+ ])
+ self.assertEqual(cli.GetOnlineNodes(["node2", "node3"], cl=cl,
+ secondary_ips=True, filter_master=True),
+ ["192.0.2.12", "192.0.2.13"])
+ self.assertEqual(cl.CountPending(), 0)
+
+ def testOfflineNodes(self):
+ cl = self._FakeClient()
+
+ cl.AddQueryResult(["name", "offline", "sip"], None, [
+ [(constants.RS_NORMAL, "master.example.com"),
+ (constants.RS_NORMAL, False),
+ (constants.RS_NORMAL, "192.0.2.1")],
+ [(constants.RS_NORMAL, "node2.example.com"),
+ (constants.RS_NORMAL, True),
+ (constants.RS_NORMAL, "192.0.2.2")],
+ [(constants.RS_NORMAL, "node3.example.com"),
+ (constants.RS_NORMAL, True),
+ (constants.RS_NORMAL, "192.0.2.3")],
+ ])
+ self.assertEqual(cli.GetOnlineNodes(None, cl=cl, nowarn=True),
+ ["master.example.com"])
+ self.assertEqual(cl.CountPending(), 0)
+
+ def testNodeGroup(self):
+ cl = self._FakeClient()
+
+ def _CheckFilter(filter_):
+ self.assertEqual(filter_,
+ [qlang.OP_OR, [qlang.OP_EQUAL, "group", "foobar"],
+ [qlang.OP_EQUAL, "group.uuid", "foobar"]])
+ return True
+
+ cl.AddQueryResult(["name", "offline", "sip"], _CheckFilter, [
+ [(constants.RS_NORMAL, "master.example.com"),
+ (constants.RS_NORMAL, False),
+ (constants.RS_NORMAL, "192.0.2.1")],
+ [(constants.RS_NORMAL, "node3.example.com"),
+ (constants.RS_NORMAL, False),
+ (constants.RS_NORMAL, "192.0.2.3")],
+ ])
+ self.assertEqual(cli.GetOnlineNodes(None, cl=cl, nodegroup="foobar"),
+ ["master.example.com", "node3.example.com"])
+ self.assertEqual(cl.CountPending(), 0)
+
+
if __name__ == '__main__':
testutils.GanetiTestProgram()