Revision fb60bc6a

b/lib/masterd/iallocator.py
153 153
    ("nics", ht.TListOf(ht.TDict)),
154 154
    ("vcpus", ht.TInt),
155 155
    ("hypervisor", ht.TString),
156
    ("node_whitelist", ht.TMaybeListOf(ht.TNonEmptyString)),
156 157
    ]
157 158
  REQ_RESULT = ht.TList
158 159

  
......
421 422

  
422 423
    if isinstance(self.req, IAReqInstanceAlloc):
423 424
      hypervisor_name = self.req.hypervisor
425
      node_whitelist = self.req.node_whitelist
424 426
    elif isinstance(self.req, IAReqRelocate):
425 427
      hypervisor_name = cfg.GetInstanceInfo(self.req.name).hypervisor
428
      node_whitelist = None
426 429
    else:
427 430
      hypervisor_name = cluster_info.primary_hypervisor
431
      node_whitelist = None
428 432

  
429 433
    node_data = self.rpc.call_node_info(node_list, [cfg.GetVGName()],
430 434
                                        [hypervisor_name])
......
434 438

  
435 439
    data["nodegroups"] = self._ComputeNodeGroupData(cfg)
436 440

  
437
    config_ndata = self._ComputeBasicNodeData(cfg, ninfo)
441
    config_ndata = self._ComputeBasicNodeData(cfg, ninfo, node_whitelist)
438 442
    data["nodes"] = self._ComputeDynamicNodeData(ninfo, node_data, node_iinfo,
439 443
                                                 i_list, config_ndata)
440 444
    assert len(data["nodes"]) == len(ninfo), \
......
461 465
    return ng
462 466

  
463 467
  @staticmethod
464
  def _ComputeBasicNodeData(cfg, node_cfg):
468
  def _ComputeBasicNodeData(cfg, node_cfg, node_whitelist):
465 469
    """Compute global node data.
466 470

  
467 471
    @rtype: dict
......
473 477
      "tags": list(ninfo.GetTags()),
474 478
      "primary_ip": ninfo.primary_ip,
475 479
      "secondary_ip": ninfo.secondary_ip,
476
      "offline": ninfo.offline,
480
      "offline": (ninfo.offline or
481
                  not (node_whitelist is None or
482
                       ninfo.name in node_whitelist)),
477 483
      "drained": ninfo.drained,
478 484
      "master_candidate": ninfo.master_candidate,
479 485
      "group": ninfo.group,
b/test/ganeti.masterd.iallocator_unittest.py
26 26
from ganeti import compat
27 27
from ganeti import constants
28 28
from ganeti import errors
29
from ganeti import objects
29 30
from ganeti import ht
30 31
from ganeti.masterd import iallocator
31 32

  
......
88 89
    stub.ValidateResult(_StubIAllocator(False), "foo")
89 90

  
90 91

  
92
class _FakeConfigWithNdParams:
93
  def GetNdParams(self, _):
94
    return None
95

  
96

  
97
class TestComputeBasicNodeData(unittest.TestCase):
98
  def setUp(self):
99
    self.fn = compat.partial(iallocator.IAllocator._ComputeBasicNodeData,
100
                             _FakeConfigWithNdParams())
101

  
102
  def testEmpty(self):
103
    self.assertEqual(self.fn({}, None), {})
104

  
105
  def testSimple(self):
106
    node1 = objects.Node(name="node1",
107
                         primary_ip="192.0.2.1",
108
                         secondary_ip="192.0.2.2",
109
                         offline=False,
110
                         drained=False,
111
                         master_candidate=True,
112
                         master_capable=True,
113
                         group="11112222",
114
                         vm_capable=False)
115

  
116
    node2 = objects.Node(name="node2",
117
                         primary_ip="192.0.2.3",
118
                         secondary_ip="192.0.2.4",
119
                         offline=True,
120
                         drained=False,
121
                         master_candidate=False,
122
                         master_capable=False,
123
                         group="11112222",
124
                         vm_capable=True)
125

  
126
    assert node1 != node2
127

  
128
    ninfo = {
129
      "#unused-1#": node1,
130
      "#unused-2#": node2,
131
      }
132

  
133
    self.assertEqual(self.fn(ninfo, None), {
134
      "node1": {
135
        "tags": [],
136
        "primary_ip": "192.0.2.1",
137
        "secondary_ip": "192.0.2.2",
138
        "offline": False,
139
        "drained": False,
140
        "master_candidate": True,
141
        "group": "11112222",
142
        "master_capable": True,
143
        "vm_capable": False,
144
        "ndparams": None,
145
        },
146
      "node2": {
147
        "tags": [],
148
        "primary_ip": "192.0.2.3",
149
        "secondary_ip": "192.0.2.4",
150
        "offline": True,
151
        "drained": False,
152
        "master_candidate": False,
153
        "group": "11112222",
154
        "master_capable": False,
155
        "vm_capable": True,
156
        "ndparams": None,
157
        },
158
      })
159

  
160
  def testOfflineNode(self):
161
    for whitelist in [None, [], set(), ["node1"], ["node2"]]:
162
      result = self.fn({
163
        "node1": objects.Node(name="node1", offline=True)
164
        }, whitelist)
165
      self.assertEqual(len(result), 1)
166
      self.assertTrue(result["node1"]["offline"])
167

  
168
  def testWhitelist(self):
169
    for whitelist in [None, [], set(), ["node1"], ["node2"]]:
170
      result = self.fn({
171
        "node1": objects.Node(name="node1", offline=False)
172
        }, whitelist)
173
      self.assertEqual(len(result), 1)
174

  
175
      if whitelist is None or "node1" in whitelist:
176
        self.assertFalse(result["node1"]["offline"])
177
      else:
178
        self.assertTrue(result["node1"]["offline"])
179

  
180

  
91 181
if __name__ == "__main__":
92 182
  testutils.GanetiTestProgram()

Also available in: Unified diff