Revision 250a9404
b/lib/cmdlib.py | ||
---|---|---|
1020 | 1020 |
% ",".join(delta), errors.ECODE_INVAL) |
1021 | 1021 |
|
1022 | 1022 |
|
1023 |
def _CheckGlobalHvParams(params):
|
|
1024 |
"""Validates that given hypervisor params are not global ones.
|
|
1023 |
def _CheckParamsNotGlobal(params, glob_pars, kind, bad_levels, good_levels):
|
|
1024 |
"""Make sure that none of the given paramters is global.
|
|
1025 | 1025 |
|
1026 |
This will ensure that instances don't get customised versions of |
|
1027 |
global params. |
|
1026 |
If a global parameter is found, an L{errors.OpPrereqError} exception is |
|
1027 |
raised. This is used to avoid setting global parameters for individual nodes. |
|
1028 |
|
|
1029 |
@type params: dictionary |
|
1030 |
@param params: Parameters to check |
|
1031 |
@type glob_pars: dictionary |
|
1032 |
@param glob_pars: Forbidden parameters |
|
1033 |
@type kind: string |
|
1034 |
@param kind: Kind of parameters (e.g. "node") |
|
1035 |
@type bad_levels: string |
|
1036 |
@param bad_levels: Level(s) at which the parameters are forbidden (e.g. |
|
1037 |
"instance") |
|
1038 |
@type good_levels: strings |
|
1039 |
@param good_levels: Level(s) at which the parameters are allowed (e.g. |
|
1040 |
"cluster or group") |
|
1028 | 1041 |
|
1029 | 1042 |
""" |
1030 |
used_globals = constants.HVC_GLOBALS.intersection(params)
|
|
1043 |
used_globals = glob_pars.intersection(params)
|
|
1031 | 1044 |
if used_globals: |
1032 |
msg = ("The following hypervisor parameters are global and cannot" |
|
1033 |
" be customized at instance level, please modify them at" |
|
1034 |
" cluster level: %s" % utils.CommaJoin(used_globals)) |
|
1045 |
msg = ("The following %s parameters are global and cannot" |
|
1046 |
" be customized at %s level, please modify them at" |
|
1047 |
" %s level: %s" % |
|
1048 |
(kind, bad_levels, good_levels, utils.CommaJoin(used_globals))) |
|
1035 | 1049 |
raise errors.OpPrereqError(msg, errors.ECODE_INVAL) |
1036 | 1050 |
|
1037 | 1051 |
|
... | ... | |
6129 | 6143 |
|
6130 | 6144 |
if self.op.ndparams: |
6131 | 6145 |
utils.ForceDictType(self.op.ndparams, constants.NDS_PARAMETER_TYPES) |
6146 |
_CheckParamsNotGlobal(self.op.ndparams, constants.NDC_GLOBALS, "node", |
|
6147 |
"node", "cluster or group") |
|
6132 | 6148 |
|
6133 | 6149 |
if self.op.hv_state: |
6134 | 6150 |
self.new_hv_state = _MergeAndVerifyHvState(self.op.hv_state, None) |
... | ... | |
6154 | 6170 |
if vg_name is not None: |
6155 | 6171 |
vparams = {constants.NV_PVLIST: [vg_name]} |
6156 | 6172 |
excl_stor = _IsExclusiveStorageEnabledNode(cfg, self.new_node) |
6157 |
if self.op.ndparams: |
|
6158 |
excl_stor = self.op.ndparams.get(constants.ND_EXCLUSIVE_STORAGE, |
|
6159 |
excl_stor) |
|
6160 | 6173 |
cname = self.cfg.GetClusterName() |
6161 | 6174 |
result = rpcrunner.call_node_verify_light([node], vparams, cname)[node] |
6162 | 6175 |
(errmsgs, _) = _CheckNodePVs(result.payload, excl_stor) |
... | ... | |
6554 | 6567 |
if self.op.ndparams: |
6555 | 6568 |
new_ndparams = _GetUpdatedParams(self.node.ndparams, self.op.ndparams) |
6556 | 6569 |
utils.ForceDictType(new_ndparams, constants.NDS_PARAMETER_TYPES) |
6570 |
_CheckParamsNotGlobal(self.op.ndparams, constants.NDC_GLOBALS, "node", |
|
6571 |
"node", "cluster or group") |
|
6557 | 6572 |
self.new_ndparams = new_ndparams |
6558 | 6573 |
|
6559 | 6574 |
if self.op.hv_state: |
... | ... | |
10592 | 10607 |
hv_type.CheckParameterSyntax(filled_hvp) |
10593 | 10608 |
self.hv_full = filled_hvp |
10594 | 10609 |
# check that we don't specify global parameters on an instance |
10595 |
_CheckGlobalHvParams(self.op.hvparams) |
|
10610 |
_CheckParamsNotGlobal(self.op.hvparams, constants.HVC_GLOBALS, "hypervisor", |
|
10611 |
"instance", "cluster") |
|
10596 | 10612 |
|
10597 | 10613 |
# fill and remember the beparams dict |
10598 | 10614 |
self.be_full = _ComputeFullBeParams(self.op, cluster) |
... | ... | |
13290 | 13306 |
raise errors.OpPrereqError("No changes submitted", errors.ECODE_INVAL) |
13291 | 13307 |
|
13292 | 13308 |
if self.op.hvparams: |
13293 |
_CheckGlobalHvParams(self.op.hvparams) |
|
13309 |
_CheckParamsNotGlobal(self.op.hvparams, constants.HVC_GLOBALS, |
|
13310 |
"hypervisor", "instance", "cluster") |
|
13294 | 13311 |
|
13295 | 13312 |
self.op.disks = self._UpgradeDiskNicMods( |
13296 | 13313 |
"disk", self.op.disks, opcodes.OpInstanceSetParams.TestDiskModifications) |
b/lib/constants.py | ||
---|---|---|
2023 | 2023 |
ND_EXCLUSIVE_STORAGE: False, |
2024 | 2024 |
} |
2025 | 2025 |
|
2026 |
NDC_GLOBALS = compat.UniqueFrozenset([ |
|
2027 |
ND_EXCLUSIVE_STORAGE, |
|
2028 |
]) |
|
2029 |
|
|
2026 | 2030 |
DISK_LD_DEFAULTS = { |
2027 | 2031 |
LD_DRBD8: { |
2028 | 2032 |
LDP_RESYNC_RATE: CLASSIC_DRBD_SYNC_SPEED, |
b/lib/objects.py | ||
---|---|---|
38 | 38 |
import ConfigParser |
39 | 39 |
import re |
40 | 40 |
import copy |
41 |
import logging |
|
41 | 42 |
import time |
42 | 43 |
from cStringIO import StringIO |
43 | 44 |
|
... | ... | |
1334 | 1335 |
|
1335 | 1336 |
if self.ndparams is None: |
1336 | 1337 |
self.ndparams = {} |
1338 |
# And remove any global parameter |
|
1339 |
for key in constants.NDC_GLOBALS: |
|
1340 |
if key in self.ndparams: |
|
1341 |
logging.warning("Ignoring %s node parameter for node %s", |
|
1342 |
key, self.name) |
|
1343 |
del self.ndparams[key] |
|
1337 | 1344 |
|
1338 | 1345 |
if self.powered is None: |
1339 | 1346 |
self.powered = True |
b/man/ganeti.rst | ||
---|---|---|
120 | 120 |
When this Boolean flag is enabled, physical disks on the node are |
121 | 121 |
assigned to instance disks in an exclusive manner, so as to lower I/O |
122 | 122 |
interference between instances. See the `Partitioned Ganeti |
123 |
<design-partitioned.rst>`_ design document for more details. |
|
123 |
<design-partitioned.rst>`_ design document for more details. This |
|
124 |
parameter cannot be set on individual nodes, as its value must be |
|
125 |
the same within each node group. |
|
124 | 126 |
|
125 | 127 |
|
126 | 128 |
Hypervisor State Parameters |
b/qa/ganeti-qa.py | ||
---|---|---|
452 | 452 |
node = qa_config.AcquireNode() |
453 | 453 |
try: |
454 | 454 |
old_es = qa_cluster.TestSetExclStorCluster(False) |
455 |
qa_cluster.TestExclStorSingleNode(node)
|
|
455 |
qa_node.TestExclStorSingleNode(node)
|
|
456 | 456 |
|
457 | 457 |
qa_cluster.TestSetExclStorCluster(True) |
458 | 458 |
qa_cluster.TestExclStorSharedPv(node) |
b/qa/qa_cluster.py | ||
---|---|---|
667 | 667 |
return oldvalue |
668 | 668 |
|
669 | 669 |
|
670 |
def _BuildSetESCmd(value, node_name): |
|
671 |
return ["gnt-node", "modify", "--node-parameters", |
|
672 |
"exclusive_storage=%s" % value, node_name] |
|
673 |
|
|
674 |
|
|
675 |
def TestExclStorSingleNode(node): |
|
676 |
"""cluster-verify reports exclusive_storage set only on one node. |
|
677 |
|
|
678 |
""" |
|
679 |
node_name = node["primary"] |
|
680 |
es_val = _GetBoolClusterField("exclusive_storage") |
|
681 |
assert not es_val |
|
682 |
AssertCommand(_BuildSetESCmd(True, node_name)) |
|
683 |
AssertClusterVerify(fail=True, errors=[constants.CV_EGROUPMIXEDESFLAG]) |
|
684 |
AssertCommand(_BuildSetESCmd("default", node_name)) |
|
685 |
AssertClusterVerify() |
|
686 |
|
|
687 |
|
|
688 | 670 |
def TestExclStorSharedPv(node): |
689 | 671 |
"""cluster-verify reports LVs that share the same PV with exclusive_storage. |
690 | 672 |
|
b/qa/qa_node.py | ||
---|---|---|
422 | 422 |
def TestNodeListDrbd(node): |
423 | 423 |
"""gnt-node list-drbd""" |
424 | 424 |
AssertCommand(["gnt-node", "list-drbd", node["primary"]]) |
425 |
|
|
426 |
|
|
427 |
def _BuildSetESCmd(action, value, node_name): |
|
428 |
cmd = ["gnt-node"] |
|
429 |
if action == "add": |
|
430 |
cmd.extend(["add", "--readd"]) |
|
431 |
else: |
|
432 |
cmd.append("modify") |
|
433 |
cmd.extend(["--node-parameters", "exclusive_storage=%s" % value, node_name]) |
|
434 |
return cmd |
|
435 |
|
|
436 |
|
|
437 |
def TestExclStorSingleNode(node): |
|
438 |
"""gnt-node add/modify cannot change the exclusive_storage flag. |
|
439 |
|
|
440 |
""" |
|
441 |
for action in ["add", "modify"]: |
|
442 |
for value in (True, False, "default"): |
|
443 |
AssertCommand(_BuildSetESCmd(action, value, node["primary"]), fail=True) |
b/test/py/ganeti.objects_unittest.py | ||
---|---|---|
351 | 351 |
self.assertEqual(node2.disk_state[constants.LD_LV]["lv2082"].total, 512) |
352 | 352 |
self.assertEqual(node2.disk_state[constants.LD_LV]["lv32352"].total, 128) |
353 | 353 |
|
354 |
def testFilterEsNdp(self): |
|
355 |
node1 = objects.Node(name="node11673.example.com", ndparams={ |
|
356 |
constants.ND_EXCLUSIVE_STORAGE: True, |
|
357 |
}) |
|
358 |
node2 = objects.Node(name="node11674.example.com", ndparams={ |
|
359 |
constants.ND_SPINDLE_COUNT: 3, |
|
360 |
constants.ND_EXCLUSIVE_STORAGE: False, |
|
361 |
}) |
|
362 |
self.assertTrue(constants.ND_EXCLUSIVE_STORAGE in node1.ndparams) |
|
363 |
node1.UpgradeConfig() |
|
364 |
self.assertFalse(constants.ND_EXCLUSIVE_STORAGE in node1.ndparams) |
|
365 |
self.assertTrue(constants.ND_EXCLUSIVE_STORAGE in node2.ndparams) |
|
366 |
self.assertTrue(constants.ND_SPINDLE_COUNT in node2.ndparams) |
|
367 |
node2.UpgradeConfig() |
|
368 |
self.assertFalse(constants.ND_EXCLUSIVE_STORAGE in node2.ndparams) |
|
369 |
self.assertTrue(constants.ND_SPINDLE_COUNT in node2.ndparams) |
|
370 |
|
|
354 | 371 |
|
355 | 372 |
if __name__ == "__main__": |
356 | 373 |
testutils.GanetiTestProgram() |
Also available in: Unified diff