Revision 4a89c54a lib/config.py
b/lib/config.py | ||
---|---|---|
227 | 227 |
|
228 | 228 |
return result |
229 | 229 |
|
230 |
@locking.ssynchronized(_config_lock, shared=1) |
|
231 |
def VerifyConfig(self): |
|
230 |
def _UnlockedVerifyConfig(self): |
|
232 | 231 |
"""Verify function. |
233 | 232 |
|
233 |
@rtype: list |
|
234 |
@return: a list of error messages; a non-empty list signifies |
|
235 |
configuration errors |
|
236 |
|
|
234 | 237 |
""" |
235 | 238 |
result = [] |
236 | 239 |
seen_macs = [] |
... | ... | |
290 | 293 |
if not data.nodes[data.cluster.master_node].master_candidate: |
291 | 294 |
result.append("Master node is not a master candidate") |
292 | 295 |
|
296 |
# master candidate checks |
|
293 | 297 |
mc_now, mc_max = self._UnlockedGetMasterCandidateStats() |
294 | 298 |
if mc_now < mc_max: |
295 | 299 |
result.append("Not enough master candidates: actual %d, target %d" % |
296 | 300 |
(mc_now, mc_max)) |
297 | 301 |
|
302 |
# drbd minors check |
|
303 |
d_map, duplicates = self._UnlockedComputeDRBDMap() |
|
304 |
for node, minor, instance_a, instance_b in duplicates: |
|
305 |
result.append("DRBD minor %d on node %s is assigned twice to instances" |
|
306 |
" %s and %s" % (minor, node, instance_a, instance_b)) |
|
307 |
|
|
298 | 308 |
return result |
299 | 309 |
|
310 |
@locking.ssynchronized(_config_lock, shared=1) |
|
311 |
def VerifyConfig(self): |
|
312 |
"""Verify function. |
|
313 |
|
|
314 |
This is just a wrapper over L{_UnlockedVerifyConfig}. |
|
315 |
|
|
316 |
@rtype: list |
|
317 |
@return: a list of error messages; a non-empty list signifies |
|
318 |
configuration errors |
|
319 |
|
|
320 |
""" |
|
321 |
return self._UnlockedVerifyConfig() |
|
322 |
|
|
300 | 323 |
def _UnlockedSetDiskID(self, disk, node_name): |
301 | 324 |
"""Convert the unique ID to the ID needed on the target nodes. |
302 | 325 |
|
... | ... | |
392 | 415 |
def _UnlockedComputeDRBDMap(self): |
393 | 416 |
"""Compute the used DRBD minor/nodes. |
394 | 417 |
|
418 |
@rtype: (dict, list) |
|
395 | 419 |
@return: dictionary of node_name: dict of minor: instance_name; |
396 | 420 |
the returned dict will have all the nodes in it (even if with |
397 |
an empty list). |
|
421 |
an empty list), and a list of duplicates; if the duplicates |
|
422 |
list is not empty, the configuration is corrupted and its caller |
|
423 |
should raise an exception |
|
398 | 424 |
|
399 | 425 |
""" |
400 | 426 |
def _AppendUsedPorts(instance_name, disk, used): |
427 |
duplicates = [] |
|
401 | 428 |
if disk.dev_type == constants.LD_DRBD8 and len(disk.logical_id) >= 5: |
402 | 429 |
nodeA, nodeB, dummy, minorA, minorB = disk.logical_id[:5] |
403 | 430 |
for node, port in ((nodeA, minorA), (nodeB, minorB)): |
404 |
assert node in used, "Instance node not found in node list" |
|
431 |
assert node in used, ("Node '%s' of instance '%s' not found" |
|
432 |
" in node list" % (node, instance_name)) |
|
405 | 433 |
if port in used[node]: |
406 |
raise errors.ProgrammerError("DRBD minor already used:" |
|
407 |
" %s/%s, %s/%s" % |
|
408 |
(node, port, instance_name, |
|
409 |
used[node][port])) |
|
410 |
|
|
411 |
used[node][port] = instance_name |
|
434 |
duplicates.append((node, port, instance_name, used[node][port])) |
|
435 |
else: |
|
436 |
used[node][port] = instance_name |
|
412 | 437 |
if disk.children: |
413 | 438 |
for child in disk.children: |
414 |
_AppendUsedPorts(instance_name, child, used) |
|
439 |
duplicates.extend(_AppendUsedPorts(instance_name, child, used)) |
|
440 |
return duplicates |
|
415 | 441 |
|
442 |
duplicates = [] |
|
416 | 443 |
my_dict = dict((node, {}) for node in self._config_data.nodes) |
417 | 444 |
for (node, minor), instance in self._temporary_drbds.iteritems(): |
418 |
my_dict[node][minor] = instance |
|
445 |
if minor in my_dict[node]: |
|
446 |
duplicates.append((node, minor, instance, my_dict[node][minor])) |
|
447 |
else: |
|
448 |
my_dict[node][minor] = instance |
|
419 | 449 |
for instance in self._config_data.instances.itervalues(): |
420 | 450 |
for disk in instance.disks: |
421 |
_AppendUsedPorts(instance.name, disk, my_dict)
|
|
422 |
return my_dict |
|
451 |
duplicates.extend(_AppendUsedPorts(instance.name, disk, my_dict))
|
|
452 |
return my_dict, duplicates
|
|
423 | 453 |
|
424 | 454 |
@locking.ssynchronized(_config_lock) |
425 | 455 |
def ComputeDRBDMap(self): |
... | ... | |
432 | 462 |
an empty list). |
433 | 463 |
|
434 | 464 |
""" |
435 |
return self._UnlockedComputeDRBDMap() |
|
465 |
d_map, duplicates = self._UnlockedComputeDRBDMap() |
|
466 |
if duplicates: |
|
467 |
raise errors.ConfigurationError("Duplicate DRBD ports detected: %s" % |
|
468 |
str(duplicates)) |
|
469 |
return d_map |
|
436 | 470 |
|
437 | 471 |
@locking.ssynchronized(_config_lock) |
438 | 472 |
def AllocateDRBDMinor(self, nodes, instance): |
... | ... | |
448 | 482 |
|
449 | 483 |
""" |
450 | 484 |
assert isinstance(instance, basestring), \ |
451 |
"Invalid argument passed to AllocateDRBDMinor"
|
|
485 |
"Invalid argument '%s' passed to AllocateDRBDMinor" % instance
|
|
452 | 486 |
|
453 |
d_map = self._UnlockedComputeDRBDMap() |
|
487 |
d_map, duplicates = self._UnlockedComputeDRBDMap() |
|
488 |
if duplicates: |
|
489 |
raise errors.ConfigurationError("Duplicate DRBD ports detected: %s" % |
|
490 |
str(duplicates)) |
|
454 | 491 |
result = [] |
455 | 492 |
for nname in nodes: |
456 | 493 |
ndata = d_map[nname] |
... | ... | |
469 | 506 |
minor = keys[-1] + 1 |
470 | 507 |
else: |
471 | 508 |
minor = ffree |
472 |
result.append(minor) |
|
509 |
# double-check minor against current instances |
|
510 |
assert minor not in d_map[nname], \ |
|
511 |
("Attempt to reuse allocated DRBD minor %d on node %s," |
|
512 |
" already allocated to instance %s" % |
|
513 |
(minor, nname, d_map[nname][minor])) |
|
473 | 514 |
ndata[minor] = instance |
474 |
assert (nname, minor) not in self._temporary_drbds, \ |
|
475 |
"Attempt to reuse reserved DRBD minor" |
|
476 |
self._temporary_drbds[(nname, minor)] = instance |
|
515 |
# double-check minor against reservation |
|
516 |
r_key = (nname, minor) |
|
517 |
assert r_key not in self._temporary_drbds, \ |
|
518 |
("Attempt to reuse reserved DRBD minor %d on node %s," |
|
519 |
" reserved for instance %s" % |
|
520 |
(minor, nname, self._temporary_drbds[r_key])) |
|
521 |
self._temporary_drbds[r_key] = instance |
|
522 |
result.append(minor) |
|
477 | 523 |
logging.debug("Request to allocate drbd minors, input: %s, returning %s", |
478 | 524 |
nodes, result) |
479 | 525 |
return result |
... | ... | |
973 | 1019 |
"""Write the configuration data to persistent storage. |
974 | 1020 |
|
975 | 1021 |
""" |
1022 |
config_errors = self._UnlockedVerifyConfig() |
|
1023 |
if config_errors: |
|
1024 |
raise errors.ConfigurationError("Configuration data is not" |
|
1025 |
" consistent: %s" % |
|
1026 |
(", ".join(config_errors))) |
|
976 | 1027 |
if destination is None: |
977 | 1028 |
destination = self._cfg_file |
978 | 1029 |
self._BumpSerialNo() |
Also available in: Unified diff