Commit fb60bc6a authored by Michael Hanselmann's avatar Michael Hanselmann
Browse files

iallocator: Add node whitelist



In the future instance creations might have a lock on all nodes as was
the case until the implementation of opportunistic locking. Nodes for
which the lock is not held will be shown to the iallocator plugin as if
they were marked offline.

This patch adds a new parameter named “node_whitelist” to
“IAReqInstanceAlloc”. If set to a list, only nodes contained within are
shown as online.
Signed-off-by: default avatarMichael Hanselmann <hansmi@google.com>
Reviewed-by: default avatarHelga Velroyen <helgav@google.com>
parent d5b031dc
......@@ -153,6 +153,7 @@ class IAReqInstanceAlloc(IARequestBase):
("nics", ht.TListOf(ht.TDict)),
("vcpus", ht.TInt),
("hypervisor", ht.TString),
("node_whitelist", ht.TMaybeListOf(ht.TNonEmptyString)),
]
REQ_RESULT = ht.TList
......@@ -421,10 +422,13 @@ class IAllocator(object):
if isinstance(self.req, IAReqInstanceAlloc):
hypervisor_name = self.req.hypervisor
node_whitelist = self.req.node_whitelist
elif isinstance(self.req, IAReqRelocate):
hypervisor_name = cfg.GetInstanceInfo(self.req.name).hypervisor
node_whitelist = None
else:
hypervisor_name = cluster_info.primary_hypervisor
node_whitelist = None
node_data = self.rpc.call_node_info(node_list, [cfg.GetVGName()],
[hypervisor_name])
......@@ -434,7 +438,7 @@ class IAllocator(object):
data["nodegroups"] = self._ComputeNodeGroupData(cfg)
config_ndata = self._ComputeBasicNodeData(cfg, ninfo)
config_ndata = self._ComputeBasicNodeData(cfg, ninfo, node_whitelist)
data["nodes"] = self._ComputeDynamicNodeData(ninfo, node_data, node_iinfo,
i_list, config_ndata)
assert len(data["nodes"]) == len(ninfo), \
......@@ -461,7 +465,7 @@ class IAllocator(object):
return ng
@staticmethod
def _ComputeBasicNodeData(cfg, node_cfg):
def _ComputeBasicNodeData(cfg, node_cfg, node_whitelist):
"""Compute global node data.
@rtype: dict
......@@ -473,7 +477,9 @@ class IAllocator(object):
"tags": list(ninfo.GetTags()),
"primary_ip": ninfo.primary_ip,
"secondary_ip": ninfo.secondary_ip,
"offline": ninfo.offline,
"offline": (ninfo.offline or
not (node_whitelist is None or
ninfo.name in node_whitelist)),
"drained": ninfo.drained,
"master_candidate": ninfo.master_candidate,
"group": ninfo.group,
......
......@@ -26,6 +26,7 @@ import unittest
from ganeti import compat
from ganeti import constants
from ganeti import errors
from ganeti import objects
from ganeti import ht
from ganeti.masterd import iallocator
......@@ -88,5 +89,94 @@ class TestIARequestBase(unittest.TestCase):
stub.ValidateResult(_StubIAllocator(False), "foo")
class _FakeConfigWithNdParams:
def GetNdParams(self, _):
return None
class TestComputeBasicNodeData(unittest.TestCase):
def setUp(self):
self.fn = compat.partial(iallocator.IAllocator._ComputeBasicNodeData,
_FakeConfigWithNdParams())
def testEmpty(self):
self.assertEqual(self.fn({}, None), {})
def testSimple(self):
node1 = objects.Node(name="node1",
primary_ip="192.0.2.1",
secondary_ip="192.0.2.2",
offline=False,
drained=False,
master_candidate=True,
master_capable=True,
group="11112222",
vm_capable=False)
node2 = objects.Node(name="node2",
primary_ip="192.0.2.3",
secondary_ip="192.0.2.4",
offline=True,
drained=False,
master_candidate=False,
master_capable=False,
group="11112222",
vm_capable=True)
assert node1 != node2
ninfo = {
"#unused-1#": node1,
"#unused-2#": node2,
}
self.assertEqual(self.fn(ninfo, None), {
"node1": {
"tags": [],
"primary_ip": "192.0.2.1",
"secondary_ip": "192.0.2.2",
"offline": False,
"drained": False,
"master_candidate": True,
"group": "11112222",
"master_capable": True,
"vm_capable": False,
"ndparams": None,
},
"node2": {
"tags": [],
"primary_ip": "192.0.2.3",
"secondary_ip": "192.0.2.4",
"offline": True,
"drained": False,
"master_candidate": False,
"group": "11112222",
"master_capable": False,
"vm_capable": True,
"ndparams": None,
},
})
def testOfflineNode(self):
for whitelist in [None, [], set(), ["node1"], ["node2"]]:
result = self.fn({
"node1": objects.Node(name="node1", offline=True)
}, whitelist)
self.assertEqual(len(result), 1)
self.assertTrue(result["node1"]["offline"])
def testWhitelist(self):
for whitelist in [None, [], set(), ["node1"], ["node2"]]:
result = self.fn({
"node1": objects.Node(name="node1", offline=False)
}, whitelist)
self.assertEqual(len(result), 1)
if whitelist is None or "node1" in whitelist:
self.assertFalse(result["node1"]["offline"])
else:
self.assertTrue(result["node1"]["offline"])
if __name__ == "__main__":
testutils.GanetiTestProgram()
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment