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