Revision 3636400f

b/lib/cmdlib.py
53 53
import ganeti.masterd.instance # pylint: disable-msg=W0611
54 54

  
55 55

  
56
# need to define these here before the actual LUs
56
# Modifiable default values; need to define these here before the
57
# actual LUs
57 58

  
58 59
def _EmptyList():
59 60
  """Returns an empty list.
......
69 70
  return {}
70 71

  
71 72

  
73
# Some basic types
74
def _TNotNone(val):
75
  """Checks if the given value is not None.
76

  
77
  """
78
  return val is not None
79

  
80

  
81
def _TNone(val):
82
  """Checks if the given value is None.
83

  
84
  """
85
  return val is None
86

  
87

  
88
def _TBool(val):
89
  """Checks if the given value is a boolean.
90

  
91
  """
92
  return isinstance(val, bool)
93

  
94

  
95
def _TInt(val):
96
  """Checks if the given value is an integer.
97

  
98
  """
99
  return isinstance(val, int)
100

  
101

  
102
def _TFloat(val):
103
  """Checks if the given value is a float.
104

  
105
  """
106
  return isinstance(val, float)
107

  
108

  
109
def _TString(val):
110
  """Checks if the given value is a string.
111

  
112
  """
113
  return isinstance(val, basestring)
114

  
115

  
116
def _TTrue(val):
117
  """Checks if a given value evaluates to a boolean True value.
118

  
119
  """
120
  return bool(val)
121

  
122

  
123
def _TElemOf(target_list):
124
  """Builds a function that checks if a given value is a member of a list.
125

  
126
  """
127
  return lambda val: val in target_list
128

  
129

  
130
# Container types
131
def _TList(val):
132
  """Checks if the given value is a list.
133

  
134
  """
135
  return isinstance(val, list)
136

  
137

  
138
def _TDict(val):
139
  """Checks if the given value is a dictionary.
140

  
141
  """
142
  return isinstance(val, dict)
143

  
144

  
145
# Combinator types
146
def _TAnd(*args):
147
  """Combine multiple functions using an AND operation.
148

  
149
  """
150
  def fn(val):
151
    return compat.all(t(val) for t in args)
152
  return fn
153

  
154

  
155
def _TOr(*args):
156
  """Combine multiple functions using an AND operation.
157

  
158
  """
159
  def fn(val):
160
    return compat.any(t(val) for t in args)
161
  return fn
162

  
163

  
164
# Type aliases
165

  
166
# non-empty string
167
_TNEString = _TAnd(_TString, _TTrue)
168

  
169

  
170
# positive integer
171
_TPInt = _TAnd(_TInt, lambda v: v >= 0)
172

  
173

  
174
def _TListOf(my_type):
175
  """Checks if a given value is a list with all elements of the same type.
176

  
177
  """
178
  return _TAnd(_TList,
179
               lambda lst: compat.all(lst, my_type))
180

  
181

  
182
def _TDictOf(key_type, val_type):
183
  """Checks a dict type for the type of its key/values.
184

  
185
  """
186
  return _TAnd(_TDict,
187
               lambda my_dict: (compat.all(my_dict.keys(), key_type) and
188
                                compat.all(my_dict.values(), val_type)))
189

  
190

  
191
# End types
72 192
class LogicalUnit(object):
73 193
  """Logical Unit base class.
74 194

  
......
138 258
          dval = aval
139 259
        setattr(self.op, aname, dval)
140 260

  
141
    for attr_name in self._OP_REQP:
142
      attr_val = getattr(op, attr_name, None)
143
      if attr_val is None:
261
    for attr_name, test in self._OP_REQP:
262
      if not hasattr(op, attr_name):
144 263
        raise errors.OpPrereqError("Required parameter '%s' missing" %
145 264
                                   attr_name, errors.ECODE_INVAL)
265
      attr_val = getattr(op, attr_name, None)
266
      if not callable(test):
267
        raise errors.ProgrammerError("Validation for parameter '%s' failed,"
268
                                     " given type is not a proper type (%s)" %
269
                                     (attr_name, test))
270
      if not test(attr_val):
271
        raise errors.OpPrereqError("Parameter '%s' has invalid type" %
272
                                   attr_name, errors.ECODE_INVAL)
146 273

  
147 274
    self.CheckArguments()
148 275

  
......
466 593
  @raise errors.ProgrammerError: if the nodes parameter is wrong type
467 594

  
468 595
  """
469
  if not isinstance(nodes, list):
470
    raise errors.OpPrereqError("Invalid argument type 'nodes'",
471
                               errors.ECODE_INVAL)
472

  
473 596
  if not nodes:
474 597
    raise errors.ProgrammerError("_GetWantedNodes should only be called with a"
475 598
      " non-empty list of nodes whose name is to be expanded.")
......
491 614
  @raise errors.OpPrereqError: if any of the passed instances is not found
492 615

  
493 616
  """
494
  if not isinstance(instances, list):
495
    raise errors.OpPrereqError("Invalid argument type 'instances'",
496
                               errors.ECODE_INVAL)
497

  
498 617
  if instances:
499 618
    wanted = [_ExpandInstanceName(lu.cfg, name) for name in instances]
500 619
  else:
......
659 778
                               errors.ECODE_INVAL)
660 779
  if storage_type == constants.ST_FILE:
661 780
    _RequireFileStorage()
781
  return True
662 782

  
663 783

  
664 784
def _GetClusterDomainSecret():
......
685 805
                               (instance.name, reason), errors.ECODE_STATE)
686 806

  
687 807

  
688
def _CheckExportMode(mode):
689
  """Ensures that a given export mode is valid.
690

  
691
  @param mode: the export mode to check
692
  @raise errors.OpPrereqError: when the export mode is not valid
693

  
694
  """
695
  if mode not in constants.EXPORT_MODES:
696
    raise errors.OpPrereqError("Invalid export mode %r" % mode,
697
                               errors.ECODE_INVAL)
698

  
699

  
700 808
def _ExpandItemName(fn, name, kind):
701 809
  """Expand an item name.
702 810

  
......
1126 1234
  """
1127 1235
  HPATH = "cluster-verify"
1128 1236
  HTYPE = constants.HTYPE_CLUSTER
1129
  _OP_REQP = ["skip_checks", "verbose", "error_codes", "debug_simulate_errors"]
1237
  _OP_REQP = [
1238
    ("skip_checks", _TListOf(_TElemOf(constants.VERIFY_OPTIONAL_CHECKS))),
1239
    ("verbose", _TBool),
1240
    ("error_codes", _TBool),
1241
    ("debug_simulate_errors", _TBool),
1242
    ]
1130 1243
  REQ_BGL = False
1131 1244

  
1132 1245
  TCLUSTER = "cluster"
......
1800 1913
          _ErrorIf(True, self.ENODERPC, node,
1801 1914
                   "node returned invalid LVM info, check LVM status")
1802 1915

  
1803
  def CheckArguments(self):
1804
    """Check arguments.
1805

  
1806
    Transform the list of checks we're going to skip into a set and check that
1807
    all its members are valid.
1808

  
1809
    """
1810
    self.skip_set = frozenset(self.op.skip_checks)
1811
    if not constants.VERIFY_OPTIONAL_CHECKS.issuperset(self.skip_set):
1812
      raise errors.OpPrereqError("Invalid checks to be skipped specified",
1813
                                 errors.ECODE_INVAL)
1814

  
1815 1916
  def BuildHooksEnv(self):
1816 1917
    """Build hooks env.
1817 1918

  
......
2044 2145
    feedback_fn("* Verifying orphan instances")
2045 2146
    self._VerifyOrphanInstances(instancelist, node_image)
2046 2147

  
2047
    if constants.VERIFY_NPLUSONE_MEM not in self.skip_set:
2148
    if constants.VERIFY_NPLUSONE_MEM not in self.op.skip_checks:
2048 2149
      feedback_fn("* Verifying N+1 Memory redundancy")
2049 2150
      self._VerifyNPlusOneMemory(node_image, instanceinfo)
2050 2151

  
......
2191 2292
  """Verifies the cluster disks sizes.
2192 2293

  
2193 2294
  """
2194
  _OP_REQP = ["instances"]
2295
  _OP_REQP = [("instances", _TListOf(_TNEString))]
2195 2296
  REQ_BGL = False
2196 2297

  
2197
  def CheckArguments(self):
2198
    if not isinstance(self.op.instances, list):
2199
      raise errors.OpPrereqError("Invalid argument type 'instances'",
2200
                                 errors.ECODE_INVAL)
2201

  
2202 2298
  def ExpandNames(self):
2203 2299
    if self.op.instances:
2204 2300
      self.wanted_names = []
......
2314 2410
  """
2315 2411
  HPATH = "cluster-rename"
2316 2412
  HTYPE = constants.HTYPE_CLUSTER
2317
  _OP_REQP = ["name"]
2413
  _OP_REQP = [("name", _TNEString)]
2318 2414

  
2319 2415
  def BuildHooksEnv(self):
2320 2416
    """Build hooks env.
......
2414 2510
  """
2415 2511
  HPATH = "cluster-modify"
2416 2512
  HTYPE = constants.HTYPE_CLUSTER
2417
  _OP_REQP = []
2513
  _OP_REQP = [
2514
    ("hvparams", _TOr(_TDictOf(_TNEString, _TDict), _TNone)),
2515
    ("os_hvp", _TOr(_TDictOf(_TNEString, _TDict), _TNone)),
2516
    ("osparams", _TOr(_TDictOf(_TNEString, _TDict), _TNone)),
2517
    ("enabled_hypervisors",
2518
     _TOr(_TAnd(_TListOf(_TElemOf(constants.HYPER_TYPES)), _TTrue), _TNone)),
2519
    ]
2418 2520
  _OP_DEFS = [
2419 2521
    ("candidate_pool_size", None),
2420 2522
    ("uid_pool", None),
2421 2523
    ("add_uids", None),
2422 2524
    ("remove_uids", None),
2525
    ("hvparams", None),
2526
    ("ov_hvp", None),
2423 2527
    ]
2424 2528
  REQ_BGL = False
2425 2529

  
......
2539 2643
    # hypervisor list/parameters
2540 2644
    self.new_hvparams = new_hvp = objects.FillDict(cluster.hvparams, {})
2541 2645
    if self.op.hvparams:
2542
      if not isinstance(self.op.hvparams, dict):
2543
        raise errors.OpPrereqError("Invalid 'hvparams' parameter on input",
2544
                                   errors.ECODE_INVAL)
2545 2646
      for hv_name, hv_dict in self.op.hvparams.items():
2546 2647
        if hv_name not in self.new_hvparams:
2547 2648
          self.new_hvparams[hv_name] = hv_dict
......
2551 2652
    # os hypervisor parameters
2552 2653
    self.new_os_hvp = objects.FillDict(cluster.os_hvp, {})
2553 2654
    if self.op.os_hvp:
2554
      if not isinstance(self.op.os_hvp, dict):
2555
        raise errors.OpPrereqError("Invalid 'os_hvp' parameter on input",
2556
                                   errors.ECODE_INVAL)
2557 2655
      for os_name, hvs in self.op.os_hvp.items():
2558
        if not isinstance(hvs, dict):
2559
          raise errors.OpPrereqError(("Invalid 'os_hvp' parameter on"
2560
                                      " input"), errors.ECODE_INVAL)
2561 2656
        if os_name not in self.new_os_hvp:
2562 2657
          self.new_os_hvp[os_name] = hvs
2563 2658
        else:
......
2570 2665
    # os parameters
2571 2666
    self.new_osp = objects.FillDict(cluster.osparams, {})
2572 2667
    if self.op.osparams:
2573
      if not isinstance(self.op.osparams, dict):
2574
        raise errors.OpPrereqError("Invalid 'osparams' parameter on input",
2575
                                   errors.ECODE_INVAL)
2576 2668
      for os_name, osp in self.op.osparams.items():
2577
        if not isinstance(osp, dict):
2578
          raise errors.OpPrereqError(("Invalid 'osparams' parameter on"
2579
                                      " input"), errors.ECODE_INVAL)
2580 2669
        if os_name not in self.new_osp:
2581 2670
          self.new_osp[os_name] = {}
2582 2671

  
......
2594 2683
    # changes to the hypervisor list
2595 2684
    if self.op.enabled_hypervisors is not None:
2596 2685
      self.hv_list = self.op.enabled_hypervisors
2597
      if not self.hv_list:
2598
        raise errors.OpPrereqError("Enabled hypervisors list must contain at"
2599
                                   " least one member",
2600
                                   errors.ECODE_INVAL)
2601
      invalid_hvs = set(self.hv_list) - constants.HYPER_TYPES
2602
      if invalid_hvs:
2603
        raise errors.OpPrereqError("Enabled hypervisors contains invalid"
2604
                                   " entries: %s" %
2605
                                   utils.CommaJoin(invalid_hvs),
2606
                                   errors.ECODE_INVAL)
2607 2686
      for hv in self.hv_list:
2608 2687
        # if the hypervisor doesn't already exist in the cluster
2609 2688
        # hvparams, we initialize it to empty, and then (in both
......
2871 2950
  """Logical unit for OS diagnose/query.
2872 2951

  
2873 2952
  """
2874
  _OP_REQP = ["output_fields", "names"]
2953
  _OP_REQP = [
2954
    ("output_fields", _TListOf(_TNEString)),
2955
    ("names", _TListOf(_TNEString)),
2956
    ]
2875 2957
  REQ_BGL = False
2876 2958
  _FIELDS_STATIC = utils.FieldSet()
2877 2959
  _FIELDS_DYNAMIC = utils.FieldSet("name", "valid", "node_status", "variants",
......
2992 3074
  """
2993 3075
  HPATH = "node-remove"
2994 3076
  HTYPE = constants.HTYPE_NODE
2995
  _OP_REQP = ["node_name"]
3077
  _OP_REQP = [("node_name", _TNEString)]
2996 3078

  
2997 3079
  def BuildHooksEnv(self):
2998 3080
    """Build hooks env.
......
3085 3167

  
3086 3168
  """
3087 3169
  # pylint: disable-msg=W0142
3088
  _OP_REQP = ["output_fields", "names", "use_locking"]
3170
  _OP_REQP = [
3171
    ("output_fields", _TListOf(_TNEString)),
3172
    ("names", _TListOf(_TNEString)),
3173
    ("use_locking", _TBool),
3174
    ]
3089 3175
  REQ_BGL = False
3090 3176

  
3091 3177
  _SIMPLE_FIELDS = ["name", "serial_no", "ctime", "mtime", "uuid",
......
3238 3324
  """Logical unit for getting volumes on node(s).
3239 3325

  
3240 3326
  """
3241
  _OP_REQP = ["nodes", "output_fields"]
3327
  _OP_REQP = [
3328
    ("nodes", _TListOf(_TNEString)),
3329
    ("output_fields", _TListOf(_TNEString)),
3330
    ]
3242 3331
  REQ_BGL = False
3243 3332
  _FIELDS_DYNAMIC = utils.FieldSet("phys", "vg", "name", "size", "instance")
3244 3333
  _FIELDS_STATIC = utils.FieldSet("node")
......
3317 3406
  """Logical unit for getting information on storage units on node(s).
3318 3407

  
3319 3408
  """
3320
  _OP_REQP = ["nodes", "storage_type", "output_fields"]
3409
  _FIELDS_STATIC = utils.FieldSet(constants.SF_NODE)
3410
  _OP_REQP = [
3411
    ("nodes", _TListOf(_TNEString)),
3412
    ("storage_type", _CheckStorageType),
3413
    ("output_fields", _TListOf(_TNEString)),
3414
    ]
3321 3415
  _OP_DEFS = [("name", None)]
3322 3416
  REQ_BGL = False
3323
  _FIELDS_STATIC = utils.FieldSet(constants.SF_NODE)
3324 3417

  
3325 3418
  def CheckArguments(self):
3326
    _CheckStorageType(self.op.storage_type)
3327

  
3328 3419
    _CheckOutputFields(static=self._FIELDS_STATIC,
3329 3420
                       dynamic=utils.FieldSet(*constants.VALID_STORAGE_FIELDS),
3330 3421
                       selected=self.op.output_fields)
......
3404 3495
  """Logical unit for modifying a storage volume on a node.
3405 3496

  
3406 3497
  """
3407
  _OP_REQP = ["node_name", "storage_type", "name", "changes"]
3498
  _OP_REQP = [
3499
    ("node_name", _TNEString),
3500
    ("storage_type", _CheckStorageType),
3501
    ("name", _TNEString),
3502
    ("changes", _TDict),
3503
    ]
3408 3504
  REQ_BGL = False
3409 3505

  
3410 3506
  def CheckArguments(self):
3411 3507
    self.op.node_name = _ExpandNodeName(self.cfg, self.op.node_name)
3412 3508

  
3413
    _CheckStorageType(self.op.storage_type)
3414

  
3415 3509
    storage_type = self.op.storage_type
3416 3510

  
3417 3511
    try:
......
3451 3545
  """
3452 3546
  HPATH = "node-add"
3453 3547
  HTYPE = constants.HTYPE_NODE
3454
  _OP_REQP = ["node_name"]
3548
  _OP_REQP = [
3549
    ("node_name", _TNEString),
3550
    ]
3455 3551
  _OP_DEFS = [("secondary_ip", None)]
3456 3552

  
3457 3553
  def CheckArguments(self):
......
3682 3778
  """
3683 3779
  HPATH = "node-modify"
3684 3780
  HTYPE = constants.HTYPE_NODE
3685
  _OP_REQP = ["node_name"]
3781
  _OP_REQP = [("node_name", _TNEString)]
3686 3782
  REQ_BGL = False
3687 3783

  
3688 3784
  def CheckArguments(self):
......
3843 3939
  """Powercycles a node.
3844 3940

  
3845 3941
  """
3846
  _OP_REQP = ["node_name", "force"]
3942
  _OP_REQP = [
3943
    ("node_name", _TNEString),
3944
    ("force", _TBool),
3945
    ]
3847 3946
  REQ_BGL = False
3848 3947

  
3849 3948
  def CheckArguments(self):
......
3970 4069
  """Bring up an instance's disks.
3971 4070

  
3972 4071
  """
3973
  _OP_REQP = ["instance_name"]
4072
  _OP_REQP = [("instance_name", _TNEString)]
3974 4073
  _OP_DEFS = [("ignore_size", False)]
3975 4074
  REQ_BGL = False
3976 4075

  
......
4114 4213
  """Shutdown an instance's disks.
4115 4214

  
4116 4215
  """
4117
  _OP_REQP = ["instance_name"]
4216
  _OP_REQP = [("instance_name", _TNEString)]
4118 4217
  REQ_BGL = False
4119 4218

  
4120 4219
  def ExpandNames(self):
......
4277 4376
  """
4278 4377
  HPATH = "instance-start"
4279 4378
  HTYPE = constants.HTYPE_INSTANCE
4280
  _OP_REQP = ["instance_name", "force"]
4379
  _OP_REQP = [
4380
    ("instance_name", _TNEString),
4381
    ("force", _TBool),
4382
    ("beparams", _TDict),
4383
    ("hvparams", _TDict),
4384
    ]
4281 4385
  _OP_DEFS = [
4282 4386
    ("beparams", _EmptyDict),
4283 4387
    ("hvparams", _EmptyDict),
......
4287 4391
  def CheckArguments(self):
4288 4392
    # extra beparams
4289 4393
    if self.op.beparams:
4290
      if not isinstance(self.op.beparams, dict):
4291
        raise errors.OpPrereqError("Invalid beparams passed: %s, expected"
4292
                                   " dict" % (type(self.op.beparams), ),
4293
                                   errors.ECODE_INVAL)
4294 4394
      # fill the beparams dict
4295 4395
      utils.ForceDictType(self.op.beparams, constants.BES_PARAMETER_TYPES)
4296 4396

  
4297
    if self.op.hvparams:
4298
      if not isinstance(self.op.hvparams, dict):
4299
        raise errors.OpPrereqError("Invalid hvparams passed: %s, expected"
4300
                                   " dict" % (type(self.op.hvparams), ),
4301
                                   errors.ECODE_INVAL)
4302

  
4303 4397
  def ExpandNames(self):
4304 4398
    self._ExpandAndLockInstance()
4305 4399

  
......
4380 4474
  """
4381 4475
  HPATH = "instance-reboot"
4382 4476
  HTYPE = constants.HTYPE_INSTANCE
4383
  _OP_REQP = ["instance_name", "ignore_secondaries", "reboot_type"]
4477
  _OP_REQP = [
4478
    ("instance_name", _TNEString),
4479
    ("ignore_secondaries", _TBool),
4480
    ("reboot_type", _TElemOf(constants.REBOOT_TYPES)),
4481
    ]
4384 4482
  _OP_DEFS = [("shutdown_timeout", constants.DEFAULT_SHUTDOWN_TIMEOUT)]
4385 4483
  REQ_BGL = False
4386 4484

  
4387
  def CheckArguments(self):
4388
    if self.op.reboot_type not in constants.REBOOT_TYPES:
4389
      raise errors.OpPrereqError("Invalid reboot type '%s', not one of %s" %
4390
                                  (self.op.reboot_type,
4391
                                   utils.CommaJoin(constants.REBOOT_TYPES)),
4392
                                 errors.ECODE_INVAL)
4393

  
4394 4485
  def ExpandNames(self):
4395 4486
    self._ExpandAndLockInstance()
4396 4487

  
......
4464 4555
  """
4465 4556
  HPATH = "instance-stop"
4466 4557
  HTYPE = constants.HTYPE_INSTANCE
4467
  _OP_REQP = ["instance_name"]
4558
  _OP_REQP = [("instance_name", _TNEString)]
4468 4559
  _OP_DEFS = [("timeout", constants.DEFAULT_SHUTDOWN_TIMEOUT)]
4469 4560
  REQ_BGL = False
4470 4561

  
......
4515 4606
  """
4516 4607
  HPATH = "instance-reinstall"
4517 4608
  HTYPE = constants.HTYPE_INSTANCE
4518
  _OP_REQP = ["instance_name"]
4609
  _OP_REQP = [("instance_name", _TNEString)]
4519 4610
  _OP_DEFS = [
4520 4611
    ("os_type", None),
4521 4612
    ("force_variant", False),
......
4588 4679
  """
4589 4680
  HPATH = "instance-recreate-disks"
4590 4681
  HTYPE = constants.HTYPE_INSTANCE
4591
  _OP_REQP = ["instance_name", "disks"]
4682
  _OP_REQP = [
4683
    ("instance_name", _TNEString),
4684
    ("disks", _TListOf(_TPInt)),
4685
    ]
4592 4686
  REQ_BGL = False
4593 4687

  
4594
  def CheckArguments(self):
4595
    """Check the arguments.
4596

  
4597
    """
4598
    if not isinstance(self.op.disks, list):
4599
      raise errors.OpPrereqError("Invalid disks parameter", errors.ECODE_INVAL)
4600
    for item in self.op.disks:
4601
      if (not isinstance(item, int) or
4602
          item < 0):
4603
        raise errors.OpPrereqError("Invalid disk specification '%s'" %
4604
                                   str(item), errors.ECODE_INVAL)
4605

  
4606 4688
  def ExpandNames(self):
4607 4689
    self._ExpandAndLockInstance()
4608 4690

  
......
4661 4743
  """
4662 4744
  HPATH = "instance-rename"
4663 4745
  HTYPE = constants.HTYPE_INSTANCE
4664
  _OP_REQP = ["instance_name", "new_name"]
4746
  _OP_REQP = [
4747
    ("instance_name", _TNEString),
4748
    ("new_name", _TNEString),
4749
    ]
4665 4750
  _OP_DEFS = [("ignore_ip", False)]
4666 4751

  
4667 4752
  def BuildHooksEnv(self):
......
4752 4837
  """
4753 4838
  HPATH = "instance-remove"
4754 4839
  HTYPE = constants.HTYPE_INSTANCE
4755
  _OP_REQP = ["instance_name", "ignore_failures"]
4840
  _OP_REQP = [
4841
    ("instance_name", _TNEString),
4842
    ("ignore_failures", _TBool),
4843
    ]
4756 4844
  _OP_DEFS = [("shutdown_timeout", constants.DEFAULT_SHUTDOWN_TIMEOUT)]
4757 4845
  REQ_BGL = False
4758 4846

  
......
4836 4924

  
4837 4925
  """
4838 4926
  # pylint: disable-msg=W0142
4839
  _OP_REQP = ["output_fields", "names", "use_locking"]
4927
  _OP_REQP = [
4928
    ("output_fields", _TListOf(_TNEString)),
4929
    ("names", _TListOf(_TNEString)),
4930
    ("use_locking", _TBool),
4931
    ]
4840 4932
  REQ_BGL = False
4841 4933
  _SIMPLE_FIELDS = ["name", "os", "network_port", "hypervisor",
4842 4934
                    "serial_no", "ctime", "mtime", "uuid"]
......
5114 5206
  """
5115 5207
  HPATH = "instance-failover"
5116 5208
  HTYPE = constants.HTYPE_INSTANCE
5117
  _OP_REQP = ["instance_name", "ignore_consistency"]
5209
  _OP_REQP = [
5210
    ("instance_name", _TNEString),
5211
    ("ignore_consistency", _TBool),
5212
    ]
5118 5213
  _OP_DEFS = [("shutdown_timeout", constants.DEFAULT_SHUTDOWN_TIMEOUT)]
5119 5214
  REQ_BGL = False
5120 5215

  
......
5265 5360
  """
5266 5361
  HPATH = "instance-migrate"
5267 5362
  HTYPE = constants.HTYPE_INSTANCE
5268
  _OP_REQP = ["instance_name", "live", "cleanup"]
5363
  _OP_REQP = [
5364
    ("instance_name", _TNEString),
5365
    ("live", _TBool),
5366
    ("cleanup", _TBool),
5367
    ]
5269 5368

  
5270 5369
  REQ_BGL = False
5271 5370

  
......
5313 5412
  """
5314 5413
  HPATH = "instance-move"
5315 5414
  HTYPE = constants.HTYPE_INSTANCE
5316
  _OP_REQP = ["instance_name", "target_node"]
5415
  _OP_REQP = [
5416
    ("instance_name", _TNEString),
5417
    ("target_node", _TNEString),
5418
    ]
5317 5419
  _OP_DEFS = [("shutdown_timeout", constants.DEFAULT_SHUTDOWN_TIMEOUT)]
5318 5420
  REQ_BGL = False
5319 5421

  
......
5489 5591
  """
5490 5592
  HPATH = "node-migrate"
5491 5593
  HTYPE = constants.HTYPE_NODE
5492
  _OP_REQP = ["node_name", "live"]
5594
  _OP_REQP = [
5595
    ("node_name", _TNEString),
5596
    ("live", _TBool),
5597
    ]
5493 5598
  REQ_BGL = False
5494 5599

  
5495 5600
  def ExpandNames(self):
......
6223 6328
  """
6224 6329
  HPATH = "instance-add"
6225 6330
  HTYPE = constants.HTYPE_INSTANCE
6226
  _OP_REQP = ["instance_name", "disks",
6227
              "mode", "start",
6228
              "wait_for_sync", "ip_check", "nics",
6229
              "hvparams", "beparams", "osparams"]
6331
  _OP_REQP = [
6332
    ("instance_name", _TNEString),
6333
    ("mode", _TElemOf(constants.INSTANCE_CREATE_MODES)),
6334
    ("start", _TBool),
6335
    ("wait_for_sync", _TBool),
6336
    ("ip_check", _TBool),
6337
    ("disks", _TListOf(_TDict)),
6338
    ("nics", _TListOf(_TDict)),
6339
    ("hvparams", _TDict),
6340
    ("beparams", _TDict),
6341
    ("osparams", _TDict),
6342
    ]
6230 6343
  _OP_DEFS = [
6231 6344
    ("name_check", True),
6232 6345
    ("no_install", False),
......
6291 6404

  
6292 6405
    self.adopt_disks = has_adopt
6293 6406

  
6294
    # verify creation mode
6295
    if self.op.mode not in constants.INSTANCE_CREATE_MODES:
6296
      raise errors.OpPrereqError("Invalid instance creation mode '%s'" %
6297
                                 self.op.mode, errors.ECODE_INVAL)
6298

  
6299 6407
    # instance name verification
6300 6408
    if self.op.name_check:
6301 6409
      self.hostname1 = utils.GetHostInfo(self.op.instance_name)
......
7128 7236
  console.
7129 7237

  
7130 7238
  """
7131
  _OP_REQP = ["instance_name"]
7239
  _OP_REQP = [("instance_name", _TNEString)]
7132 7240
  REQ_BGL = False
7133 7241

  
7134 7242
  def ExpandNames(self):
......
7179 7287
  """
7180 7288
  HPATH = "mirrors-replace"
7181 7289
  HTYPE = constants.HTYPE_INSTANCE
7182
  _OP_REQP = ["instance_name", "mode", "disks"]
7290
  _OP_REQP = [
7291
    ("instance_name", _TNEString),
7292
    ("mode", _TElemOf(constants.REPLACE_MODES)),
7293
    ("disks", _TListOf(_TPInt)),
7294
    ]
7183 7295
  _OP_DEFS = [
7184 7296
    ("remote_node", None),
7185 7297
    ("iallocator", None),
......
7920 8032
  """Repairs the volume group on a node.
7921 8033

  
7922 8034
  """
7923
  _OP_REQP = ["node_name"]
8035
  _OP_REQP = [("node_name", _TNEString)]
7924 8036
  REQ_BGL = False
7925 8037

  
7926 8038
  def CheckArguments(self):
......
7985 8097
  """Computes the node evacuation strategy.
7986 8098

  
7987 8099
  """
7988
  _OP_REQP = ["nodes"]
8100
  _OP_REQP = [("nodes", _TListOf(_TNEString))]
7989 8101
  _OP_DEFS = [
7990 8102
    ("remote_node", None),
7991 8103
    ("iallocator", None),
......
8038 8150
  """
8039 8151
  HPATH = "disk-grow"
8040 8152
  HTYPE = constants.HTYPE_INSTANCE
8041
  _OP_REQP = ["instance_name", "disk", "amount", "wait_for_sync"]
8153
  _OP_REQP = [
8154
    ("instance_name", _TNEString),
8155
    ("disk", _TInt),
8156
    ("amount", _TInt),
8157
    ("wait_for_sync", _TBool),
8158
    ]
8042 8159
  REQ_BGL = False
8043 8160

  
8044 8161
  def ExpandNames(self):
......
8132 8249
  """Query runtime instance data.
8133 8250

  
8134 8251
  """
8135
  _OP_REQP = ["instances", "static"]
8252
  _OP_REQP = [
8253
    ("instances", _TListOf(_TNEString)),
8254
    ("static", _TBool),
8255
    ]
8136 8256
  REQ_BGL = False
8137 8257

  
8138
  def CheckArguments(self):
8139
    if not isinstance(self.op.instances, list):
8140
      raise errors.OpPrereqError("Invalid argument type 'instances'",
8141
                                 errors.ECODE_INVAL)
8142

  
8143 8258
  def ExpandNames(self):
8144 8259
    self.needed_locks = {}
8145 8260
    self.share_locks = dict.fromkeys(locking.LEVELS, 1)
......
8294 8409
  """
8295 8410
  HPATH = "instance-modify"
8296 8411
  HTYPE = constants.HTYPE_INSTANCE
8297
  _OP_REQP = ["instance_name"]
8412
  _OP_REQP = [("instance_name", _TNEString)]
8298 8413
  _OP_DEFS = [
8299 8414
    ("nics", _EmptyList),
8300 8415
    ("disks", _EmptyList),
......
8956 9071
  """Query the exports list
8957 9072

  
8958 9073
  """
8959
  _OP_REQP = ['nodes']
9074
  _OP_REQP = [("nodes", _TListOf(_TNEString))]
8960 9075
  REQ_BGL = False
8961 9076

  
8962 9077
  def ExpandNames(self):
......
8993 9108
  """Prepares an instance for an export and returns useful information.
8994 9109

  
8995 9110
  """
8996
  _OP_REQP = ["instance_name", "mode"]
9111
  _OP_REQP = [
9112
    ("instance_name", _TNEString),
9113
    ("mode", _TElemOf(constants.EXPORT_MODES)),
9114
    ]
8997 9115
  REQ_BGL = False
8998 9116

  
8999
  def CheckArguments(self):
9000
    """Check the arguments.
9001

  
9002
    """
9003
    _CheckExportMode(self.op.mode)
9004

  
9005 9117
  def ExpandNames(self):
9006 9118
    self._ExpandAndLockInstance()
9007 9119

  
......
9053 9165
  """
9054 9166
  HPATH = "instance-export"
9055 9167
  HTYPE = constants.HTYPE_INSTANCE
9056
  _OP_REQP = ["instance_name", "target_node", "shutdown"]
9168
  _OP_REQP = [
9169
    ("instance_name", _TNEString),
9170
    ("target_node", _TNEString),
9171
    ("shutdown", _TBool),
9172
    ("mode", _TElemOf(constants.EXPORT_MODES)),
9173
    ]
9057 9174
  _OP_DEFS = [
9058 9175
    ("shutdown_timeout", constants.DEFAULT_SHUTDOWN_TIMEOUT),
9059 9176
    ("remove_instance", False),
......
9075 9192
      raise errors.OpPrereqError("Can not remove instance without shutting it"
9076 9193
                                 " down before")
9077 9194

  
9078
    _CheckExportMode(self.op.mode)
9079

  
9080 9195
    if self.op.mode == constants.EXPORT_MODE_REMOTE:
9081 9196
      if not self.x509_key_name:
9082 9197
        raise errors.OpPrereqError("Missing X509 key name for encryption",
......
9339 9454
  """Remove exports related to the named instance.
9340 9455

  
9341 9456
  """
9342
  _OP_REQP = ["instance_name"]
9457
  _OP_REQP = [("instance_name", _TNEString)]
9343 9458
  REQ_BGL = False
9344 9459

  
9345 9460
  def ExpandNames(self):
......
9418 9533
  """Returns the tags of a given object.
9419 9534

  
9420 9535
  """
9421
  _OP_REQP = ["kind", "name"]
9536
  _OP_REQP = [
9537
    ("kind", _TElemOf(constants.VALID_TAG_TYPES)),
9538
    ("name", _TNEString),
9539
    ]
9422 9540
  REQ_BGL = False
9423 9541

  
9424 9542
  def Exec(self, feedback_fn):
......
9432 9550
  """Searches the tags for a given pattern.
9433 9551

  
9434 9552
  """
9435
  _OP_REQP = ["pattern"]
9553
  _OP_REQP = [("pattern", _TNEString)]
9436 9554
  REQ_BGL = False
9437 9555

  
9438 9556
  def ExpandNames(self):
......
9472 9590
  """Sets a tag on a given object.
9473 9591

  
9474 9592
  """
9475
  _OP_REQP = ["kind", "name", "tags"]
9593
  _OP_REQP = [
9594
    ("kind", _TElemOf(constants.VALID_TAG_TYPES)),
9595
    ("name", _TNEString),
9596
    ("tags", _TListOf(objects.TaggableObject.ValidateTag)),
9597
    ]
9476 9598
  REQ_BGL = False
9477 9599

  
9478 9600
  def CheckPrereq(self):
......
9501 9623
  """Delete a list of tags from a given object.
9502 9624

  
9503 9625
  """
9504
  _OP_REQP = ["kind", "name", "tags"]
9626
  _OP_REQP = [
9627
    ("kind", _TElemOf(constants.VALID_TAG_TYPES)),
9628
    ("name", _TNEString),
9629
    ("tags", _TListOf(objects.TaggableObject.ValidateTag)),
9630
    ]
9505 9631
  REQ_BGL = False
9506 9632

  
9507 9633
  def CheckPrereq(self):
......
9538 9664
  time.
9539 9665

  
9540 9666
  """
9541
  _OP_REQP = ["duration", "on_master", "on_nodes"]
9667
  _OP_REQP = [
9668
    ("duration", _TFloat),
9669
    ("on_master", _TBool),
9670
    ("on_nodes", _TListOf(_TNEString)),
9671
    ]
9542 9672
  REQ_BGL = False
9543 9673

  
9544 9674
  def CheckArguments(self):
......
9918 10048
  This LU runs the allocator tests
9919 10049

  
9920 10050
  """
9921
  _OP_REQP = ["direction", "mode", "name"]
10051
  _OP_REQP = [
10052
    ("direction", _TElemOf(constants.VALID_IALLOCATOR_DIRECTIONS)),
10053
    ("mode", _TElemOf(constants.VALID_IALLOCATOR_MODES)),
10054
    ("name", _TNEString),
10055
    ("nics", _TOr(_TNone, _TListOf(
10056
      _TDictOf(_TElemOf(["mac", "ip", "bridge"]), _TNEString)))),
10057
    ("disks", _TOr(_TNone, _TList)),
10058
    ]
9922 10059
  _OP_DEFS = [
9923 10060
    ("hypervisor", None),
9924 10061
    ("allocator", None),
10062
    ("nics", None),
10063
    ("disks", None),
9925 10064
    ]
9926 10065

  
9927 10066
  def CheckPrereq(self):
......
9931 10070

  
9932 10071
    """
9933 10072
    if self.op.mode == constants.IALLOCATOR_MODE_ALLOC:
9934
      for attr in ["name", "mem_size", "disks", "disk_template",
10073
      for attr in ["mem_size", "disks", "disk_template",
9935 10074
                   "os", "tags", "nics", "vcpus"]:
9936 10075
        if not hasattr(self.op, attr):
9937 10076
          raise errors.OpPrereqError("Missing attribute '%s' on opcode input" %
......
9943 10082
      if not isinstance(self.op.nics, list):
9944 10083
        raise errors.OpPrereqError("Invalid parameter 'nics'",
9945 10084
                                   errors.ECODE_INVAL)
9946
      for row in self.op.nics:
9947
        if (not isinstance(row, dict) or
9948
            "mac" not in row or
9949
            "ip" not in row or
9950
            "bridge" not in row):
9951
          raise errors.OpPrereqError("Invalid contents of the 'nics'"
9952
                                     " parameter", errors.ECODE_INVAL)
9953 10085
      if not isinstance(self.op.disks, list):
9954 10086
        raise errors.OpPrereqError("Invalid parameter 'disks'",
9955 10087
                                   errors.ECODE_INVAL)
......
9964 10096
      if self.op.hypervisor is None:
9965 10097
        self.op.hypervisor = self.cfg.GetHypervisorType()
9966 10098
    elif self.op.mode == constants.IALLOCATOR_MODE_RELOC:
9967
      if not hasattr(self.op, "name"):
9968
        raise errors.OpPrereqError("Missing attribute 'name' on opcode input",
9969
                                   errors.ECODE_INVAL)
9970 10099
      fname = _ExpandInstanceName(self.cfg, self.op.name)
9971 10100
      self.op.name = fname
9972 10101
      self.relocate_from = self.cfg.GetInstanceInfo(fname).secondary_nodes
b/lib/constants.py
353 353
REPLACE_DISK_SEC = "replace_on_secondary"  # replace disks on secondary
354 354
REPLACE_DISK_CHG = "replace_new_secondary" # change secondary node
355 355
REPLACE_DISK_AUTO = "replace_auto"
356
REPLACE_MODES = frozenset([
357
  REPLACE_DISK_PRI,
358
  REPLACE_DISK_SEC,
359
  REPLACE_DISK_CHG,
360
  REPLACE_DISK_AUTO,
361
  ])
356 362

  
357 363
# Instance export mode
358 364
EXPORT_MODE_LOCAL = "local"
......
414 420
TAG_CLUSTER = "cluster"
415 421
TAG_NODE = "node"
416 422
TAG_INSTANCE = "instance"
423
VALID_TAG_TYPES = frozenset([
424
  TAG_CLUSTER,
425
  TAG_NODE,
426
  TAG_INSTANCE,
427
  ])
417 428
MAX_TAG_LEN = 128
418 429
MAX_TAGS_PER_OBJ = 4096
419 430

  
......
718 729
IALLOCATOR_VERSION = 2
719 730
IALLOCATOR_DIR_IN = "in"
720 731
IALLOCATOR_DIR_OUT = "out"
732
VALID_IALLOCATOR_DIRECTIONS = frozenset([
733
  IALLOCATOR_DIR_IN,
734
  IALLOCATOR_DIR_OUT,
735
  ])
721 736
IALLOCATOR_MODE_ALLOC = "allocate"
722 737
IALLOCATOR_MODE_RELOC = "relocate"
723 738
IALLOCATOR_MODE_MEVAC = "multi-evacuate"
739
VALID_IALLOCATOR_MODES = frozenset([
740
  IALLOCATOR_MODE_ALLOC,
741
  IALLOCATOR_MODE_RELOC,
742
  IALLOCATOR_MODE_MEVAC,
743
  ])
724 744
IALLOCATOR_SEARCH_PATH = _autoconf.IALLOCATOR_SEARCH_PATH
725 745

  
726 746
# Job queue

Also available in: Unified diff