Revision 1c3231aa lib/cmdlib/common.py

b/lib/cmdlib/common.py
48 48
  ]))
49 49

  
50 50

  
51
def _ExpandItemName(fn, name, kind):
51
def _ExpandItemName(expand_fn, name, kind):
52 52
  """Expand an item name.
53 53

  
54
  @param fn: the function to use for expansion
54
  @param expand_fn: the function to use for expansion
55 55
  @param name: requested item name
56 56
  @param kind: text description ('Node' or 'Instance')
57
  @return: the resolved (full) name
57
  @return: the result of the expand_fn, if successful
58 58
  @raise errors.OpPrereqError: if the item is not found
59 59

  
60 60
  """
61
  full_name = fn(name)
61
  full_name = expand_fn(name)
62 62
  if full_name is None:
63 63
    raise errors.OpPrereqError("%s '%s' not known" % (kind, name),
64 64
                               errors.ECODE_NOENT)
......
70 70
  return _ExpandItemName(cfg.ExpandInstanceName, name, "Instance")
71 71

  
72 72

  
73
def ExpandNodeName(cfg, name):
74
  """Wrapper over L{_ExpandItemName} for nodes."""
75
  return _ExpandItemName(cfg.ExpandNodeName, name, "Node")
73
def ExpandNodeUuidAndName(cfg, expected_uuid, name):
74
  """Expand a short node name into the node UUID and full name.
75

  
76
  @type cfg: L{config.ConfigWriter}
77
  @param cfg: The cluster configuration
78
  @type expected_uuid: string
79
  @param expected_uuid: expected UUID for the node (or None if there is no
80
        expectation). If it does not match, a L{errors.OpPrereqError} is
81
        raised.
82
  @type name: string
83
  @param name: the short node name
84

  
85
  """
86
  (uuid, full_name) = _ExpandItemName(cfg.ExpandNodeName, name, "Node")
87
  if expected_uuid is not None and uuid != expected_uuid:
88
    raise errors.OpPrereqError(
89
      "The nodes UUID '%s' does not match the expected UUID '%s' for node"
90
      " '%s'. Maybe the node changed since you submitted this job." %
91
      (uuid, expected_uuid, full_name), errors.ECODE_NOTUNIQUE)
92
  return (uuid, full_name)
76 93

  
77 94

  
78 95
def ShareAll():
......
106 123
  return wanted_instances
107 124

  
108 125

  
109
def GetWantedNodes(lu, nodes):
126
def GetWantedNodes(lu, short_node_names):
110 127
  """Returns list of checked and expanded node names.
111 128

  
112 129
  @type lu: L{LogicalUnit}
113 130
  @param lu: the logical unit on whose behalf we execute
114
  @type nodes: list
115
  @param nodes: list of node names or None for all nodes
116
  @rtype: list
117
  @return: the list of nodes, sorted
131
  @type short_node_names: list
132
  @param short_node_names: list of node names or None for all nodes
133
  @rtype: tuple of lists
134
  @return: tupe with (list of node UUIDs, list of node names)
118 135
  @raise errors.ProgrammerError: if the nodes parameter is wrong type
119 136

  
120 137
  """
121
  if nodes:
122
    return [ExpandNodeName(lu.cfg, name) for name in nodes]
138
  if short_node_names:
139
    node_uuids = [ExpandNodeUuidAndName(lu.cfg, None, name)[0]
140
                  for name in short_node_names]
141
  else:
142
    node_uuids = lu.cfg.GetNodeList()
123 143

  
124
  return utils.NiceSort(lu.cfg.GetNodeList())
144
  return (node_uuids, [lu.cfg.GetNodeInfo(uuid).name for uuid in node_uuids])
125 145

  
126 146

  
127 147
def GetWantedInstances(lu, instances):
......
150 170
  """
151 171
  hm = lu.proc.BuildHooksManager(lu)
152 172
  try:
153
    hm.RunPhase(constants.HOOKS_PHASE_POST, nodes=[node_name])
173
    node_names = [node_name]
174
    hm.RunPhase(constants.HOOKS_PHASE_POST, node_names=node_names)
154 175
  except Exception, err: # pylint: disable=W0703
155 176
    lu.LogWarning("Errors occurred running hooks on %s: %s",
156 177
                  node_name, err)
157 178

  
158 179

  
159
def RedistributeAncillaryFiles(lu, additional_nodes=None, additional_vm=True):
180
def RedistributeAncillaryFiles(lu):
160 181
  """Distribute additional files which are part of the cluster configuration.
161 182

  
162 183
  ConfigWriter takes care of distributing the config and ssconf files, but
163 184
  there are more files which should be distributed to all nodes. This function
164 185
  makes sure those are copied.
165 186

  
166
  @param lu: calling logical unit
167
  @param additional_nodes: list of nodes not in the config to distribute to
168
  @type additional_vm: boolean
169
  @param additional_vm: whether the additional nodes are vm-capable or not
170

  
171 187
  """
172 188
  # Gather target nodes
173 189
  cluster = lu.cfg.GetClusterInfo()
174 190
  master_info = lu.cfg.GetNodeInfo(lu.cfg.GetMasterNode())
175 191

  
176
  online_nodes = lu.cfg.GetOnlineNodeList()
177
  online_set = frozenset(online_nodes)
178
  vm_nodes = list(online_set.intersection(lu.cfg.GetVmCapableNodeList()))
179

  
180
  if additional_nodes is not None:
181
    online_nodes.extend(additional_nodes)
182
    if additional_vm:
183
      vm_nodes.extend(additional_nodes)
192
  online_node_uuids = lu.cfg.GetOnlineNodeList()
193
  online_node_uuid_set = frozenset(online_node_uuids)
194
  vm_node_uuids = list(online_node_uuid_set.intersection(
195
                         lu.cfg.GetVmCapableNodeList()))
184 196

  
185 197
  # Never distribute to master node
186
  for nodelist in [online_nodes, vm_nodes]:
187
    if master_info.name in nodelist:
188
      nodelist.remove(master_info.name)
198
  for node_uuids in [online_node_uuids, vm_node_uuids]:
199
    if master_info.uuid in node_uuids:
200
      node_uuids.remove(master_info.uuid)
189 201

  
190 202
  # Gather file lists
191 203
  (files_all, _, files_mc, files_vm) = \
......
197 209
  assert not files_mc, "Master candidates not handled in this function"
198 210

  
199 211
  filemap = [
200
    (online_nodes, files_all),
201
    (vm_nodes, files_vm),
212
    (online_node_uuids, files_all),
213
    (vm_node_uuids, files_vm),
202 214
    ]
203 215

  
204 216
  # Upload the files
205
  for (node_list, files) in filemap:
217
  for (node_uuids, files) in filemap:
206 218
    for fname in files:
207
      UploadHelper(lu, node_list, fname)
219
      UploadHelper(lu, node_uuids, fname)
208 220

  
209 221

  
210 222
def ComputeAncillaryFiles(cluster, redist):
......
286 298
  return (files_all, files_opt, files_mc, files_vm)
287 299

  
288 300

  
289
def UploadHelper(lu, nodes, fname):
301
def UploadHelper(lu, node_uuids, fname):
290 302
  """Helper for uploading a file and showing warnings.
291 303

  
292 304
  """
293 305
  if os.path.exists(fname):
294
    result = lu.rpc.call_upload_file(nodes, fname)
295
    for to_node, to_result in result.items():
306
    result = lu.rpc.call_upload_file(node_uuids, fname)
307
    for to_node_uuids, to_result in result.items():
296 308
      msg = to_result.fail_msg
297 309
      if msg:
298 310
        msg = ("Copy of file %s to node %s failed: %s" %
299
               (fname, to_node, msg))
311
               (fname, lu.cfg.GetNodeName(to_node_uuids), msg))
300 312
        lu.LogWarning(msg)
301 313

  
302 314

  
......
345 357
  return None
346 358

  
347 359

  
348
def CheckOSParams(lu, required, nodenames, osname, osparams):
360
def CheckOSParams(lu, required, node_uuids, osname, osparams):
349 361
  """OS parameters validation.
350 362

  
351 363
  @type lu: L{LogicalUnit}
......
353 365
  @type required: boolean
354 366
  @param required: whether the validation should fail if the OS is not
355 367
      found
356
  @type nodenames: list
357
  @param nodenames: the list of nodes on which we should check
368
  @type node_uuids: list
369
  @param node_uuids: the list of nodes on which we should check
358 370
  @type osname: string
359 371
  @param osname: the name of the hypervisor we should use
360 372
  @type osparams: dict
......
362 374
  @raise errors.OpPrereqError: if the parameters are not valid
363 375

  
364 376
  """
365
  nodenames = _FilterVmNodes(lu, nodenames)
366
  result = lu.rpc.call_os_validate(nodenames, required, osname,
377
  node_uuids = _FilterVmNodes(lu, node_uuids)
378
  result = lu.rpc.call_os_validate(node_uuids, required, osname,
367 379
                                   [constants.OS_VALIDATE_PARAMETERS],
368 380
                                   osparams)
369
  for node, nres in result.items():
381
  for node_uuid, nres in result.items():
370 382
    # we don't check for offline cases since this should be run only
371 383
    # against the master node and/or an instance's nodes
372
    nres.Raise("OS Parameters validation failed on node %s" % node)
384
    nres.Raise("OS Parameters validation failed on node %s" %
385
               lu.cfg.GetNodeName(node_uuid))
373 386
    if not nres.payload:
374 387
      lu.LogInfo("OS %s not found on node %s, validation skipped",
375
                 osname, node)
388
                 osname, lu.cfg.GetNodeName(node_uuid))
376 389

  
377 390

  
378
def CheckHVParams(lu, nodenames, hvname, hvparams):
391
def CheckHVParams(lu, node_uuids, hvname, hvparams):
379 392
  """Hypervisor parameter validation.
380 393

  
381 394
  This function abstract the hypervisor parameter validation to be
......
383 396

  
384 397
  @type lu: L{LogicalUnit}
385 398
  @param lu: the logical unit for which we check
386
  @type nodenames: list
387
  @param nodenames: the list of nodes on which we should check
399
  @type node_uuids: list
400
  @param node_uuids: the list of nodes on which we should check
388 401
  @type hvname: string
389 402
  @param hvname: the name of the hypervisor we should use
390 403
  @type hvparams: dict
......
392 405
  @raise errors.OpPrereqError: if the parameters are not valid
393 406

  
394 407
  """
395
  nodenames = _FilterVmNodes(lu, nodenames)
408
  node_uuids = _FilterVmNodes(lu, node_uuids)
396 409

  
397 410
  cluster = lu.cfg.GetClusterInfo()
398 411
  hvfull = objects.FillDict(cluster.hvparams.get(hvname, {}), hvparams)
399 412

  
400
  hvinfo = lu.rpc.call_hypervisor_validate_params(nodenames, hvname, hvfull)
401
  for node in nodenames:
402
    info = hvinfo[node]
413
  hvinfo = lu.rpc.call_hypervisor_validate_params(node_uuids, hvname, hvfull)
414
  for node_uuid in node_uuids:
415
    info = hvinfo[node_uuid]
403 416
    if info.offline:
404 417
      continue
405
    info.Raise("Hypervisor parameter validation failed on node %s" % node)
418
    info.Raise("Hypervisor parameter validation failed on node %s" %
419
               lu.cfg.GetNodeName(node_uuid))
406 420

  
407 421

  
408 422
def AdjustCandidatePool(lu, exceptions):
......
413 427
  if mod_list:
414 428
    lu.LogInfo("Promoted nodes to master candidate role: %s",
415 429
               utils.CommaJoin(node.name for node in mod_list))
416
    for name in mod_list:
417
      lu.context.ReaddNode(name)
430
    for node in mod_list:
431
      lu.context.ReaddNode(node)
418 432
  mc_now, mc_max, _ = lu.cfg.GetMasterCandidateStats(exceptions)
419 433
  if mc_now > mc_max:
420 434
    lu.LogInfo("Note: more nodes are candidates (%d) than desired (%d)" %
......
548 562
  be_full = cfg.GetClusterInfo().FillBE(instance)
549 563
  mem_size = be_full[constants.BE_MAXMEM]
550 564
  cpu_count = be_full[constants.BE_VCPUS]
551
  es_flags = rpc.GetExclusiveStorageForNodeNames(cfg, instance.all_nodes)
565
  es_flags = rpc.GetExclusiveStorageForNodes(cfg, instance.all_nodes)
552 566
  if any(es_flags.values()):
553 567
    # With exclusive storage use the actual spindles
554 568
    try:
......
736 750
  return ret
737 751

  
738 752

  
739
def _FilterVmNodes(lu, nodenames):
753
def _FilterVmNodes(lu, node_uuids):
740 754
  """Filters out non-vm_capable nodes from a list.
741 755

  
742 756
  @type lu: L{LogicalUnit}
743 757
  @param lu: the logical unit for which we check
744
  @type nodenames: list
745
  @param nodenames: the list of nodes on which we should check
758
  @type node_uuids: list
759
  @param node_uuids: the list of nodes on which we should check
746 760
  @rtype: list
747 761
  @return: the list of vm-capable nodes
748 762

  
749 763
  """
750 764
  vm_nodes = frozenset(lu.cfg.GetNonVmCapableNodeList())
751
  return [name for name in nodenames if name not in vm_nodes]
765
  return [uuid for uuid in node_uuids if uuid not in vm_nodes]
752 766

  
753 767

  
754 768
def GetDefaultIAllocator(cfg, ialloc):
......
774 788
  return ialloc
775 789

  
776 790

  
777
def CheckInstancesNodeGroups(cfg, instances, owned_groups, owned_nodes,
791
def CheckInstancesNodeGroups(cfg, instances, owned_groups, owned_node_uuids,
778 792
                             cur_group_uuid):
779 793
  """Checks if node groups for locked instances are still correct.
780 794

  
......
784 798
  @param instances: Dictionary, instance name as key, instance object as value
785 799
  @type owned_groups: iterable of string
786 800
  @param owned_groups: List of owned groups
787
  @type owned_nodes: iterable of string
788
  @param owned_nodes: List of owned nodes
801
  @type owned_node_uuids: iterable of string
802
  @param owned_node_uuids: List of owned nodes
789 803
  @type cur_group_uuid: string or None
790 804
  @param cur_group_uuid: Optional group UUID to check against instance's groups
791 805

  
792 806
  """
793 807
  for (name, inst) in instances.items():
794
    assert owned_nodes.issuperset(inst.all_nodes), \
808
    assert owned_node_uuids.issuperset(inst.all_nodes), \
795 809
      "Instance %s's nodes changed while we kept the lock" % name
796 810

  
797 811
    inst_groups = CheckInstanceNodeGroups(cfg, name, owned_groups)
......
855 869

  
856 870
  if moved:
857 871
    lu.LogInfo("Instances to be moved: %s",
858
               utils.CommaJoin("%s (to %s)" %
859
                               (name, _NodeEvacDest(use_nodes, group, nodes))
860
                               for (name, group, nodes) in moved))
872
               utils.CommaJoin(
873
                 "%s (to %s)" %
874
                 (name, _NodeEvacDest(use_nodes, group, node_names))
875
                 for (name, group, node_names) in moved))
861 876

  
862 877
  return [map(compat.partial(_SetOpEarlyRelease, early_release),
863 878
              map(opcodes.OpCode.LoadOpCode, ops))
864 879
          for ops in jobs]
865 880

  
866 881

  
867
def _NodeEvacDest(use_nodes, group, nodes):
882
def _NodeEvacDest(use_nodes, group, node_names):
868 883
  """Returns group or nodes depending on caller's choice.
869 884

  
870 885
  """
871 886
  if use_nodes:
872
    return utils.CommaJoin(nodes)
887
    return utils.CommaJoin(node_names)
873 888
  else:
874 889
    return group
875 890

  
......
890 905
  """Creates a map from (node, volume) to instance name.
891 906

  
892 907
  @type instances: list of L{objects.Instance}
893
  @rtype: dict; tuple of (node name, volume name) as key, instance name as value
908
  @rtype: dict; tuple of (node uuid, volume name) as key, instance name as value
894 909

  
895 910
  """
896
  return dict(((node, vol), inst.name)
911
  return dict(((node_uuid, vol), inst.name)
897 912
              for inst in instances
898
              for (node, vols) in inst.MapLVsByNode().items()
913
              for (node_uuid, vols) in inst.MapLVsByNode().items()
899 914
              for vol in vols)
900 915

  
901 916

  
......
960 975
                               errors.ECODE_STATE)
961 976

  
962 977
  if constants.ADMINST_UP not in req_states:
963
    pnode = instance.primary_node
964
    if not lu.cfg.GetNodeInfo(pnode).offline:
978
    pnode_uuid = instance.primary_node
979
    if not lu.cfg.GetNodeInfo(pnode_uuid).offline:
965 980
      all_hvparams = lu.cfg.GetClusterInfo().hvparams
966
      ins_l = lu.rpc.call_instance_list([pnode], [instance.hypervisor],
967
                                        all_hvparams)[pnode]
968
      ins_l.Raise("Can't contact node %s for instance information" % pnode,
981
      ins_l = lu.rpc.call_instance_list(
982
                [pnode_uuid], [instance.hypervisor], all_hvparams)[pnode_uuid]
983
      ins_l.Raise("Can't contact node %s for instance information" %
984
                  lu.cfg.GetNodeName(pnode_uuid),
969 985
                  prereq=True, ecode=errors.ECODE_ENVIRON)
970 986
      if instance.name in ins_l.payload:
971 987
        raise errors.OpPrereqError("Instance %s is running, %s" %
......
1011 1027
                                 " iallocator", errors.ECODE_INVAL)
1012 1028

  
1013 1029

  
1014
def FindFaultyInstanceDisks(cfg, rpc_runner, instance, node_name, prereq):
1030
def FindFaultyInstanceDisks(cfg, rpc_runner, instance, node_uuid, prereq):
1015 1031
  faulty = []
1016 1032

  
1017 1033
  for dev in instance.disks:
1018
    cfg.SetDiskID(dev, node_name)
1034
    cfg.SetDiskID(dev, node_uuid)
1019 1035

  
1020
  result = rpc_runner.call_blockdev_getmirrorstatus(node_name,
1021
                                                    (instance.disks,
1022
                                                     instance))
1023
  result.Raise("Failed to get disk status from node %s" % node_name,
1036
  result = rpc_runner.call_blockdev_getmirrorstatus(
1037
             node_uuid, (instance.disks, instance))
1038
  result.Raise("Failed to get disk status from node %s" %
1039
               cfg.GetNodeName(node_uuid),
1024 1040
               prereq=prereq, ecode=errors.ECODE_ENVIRON)
1025 1041

  
1026 1042
  for idx, bdev_status in enumerate(result.payload):
......
1030 1046
  return faulty
1031 1047

  
1032 1048

  
1033
def CheckNodeOnline(lu, node, msg=None):
1049
def CheckNodeOnline(lu, node_uuid, msg=None):
1034 1050
  """Ensure that a given node is online.
1035 1051

  
1036 1052
  @param lu: the LU on behalf of which we make the check
1037
  @param node: the node to check
1053
  @param node_uuid: the node to check
1038 1054
  @param msg: if passed, should be a message to replace the default one
1039 1055
  @raise errors.OpPrereqError: if the node is offline
1040 1056

  
1041 1057
  """
1042 1058
  if msg is None:
1043 1059
    msg = "Can't use offline node"
1044
  if lu.cfg.GetNodeInfo(node).offline:
1045
    raise errors.OpPrereqError("%s: %s" % (msg, node), errors.ECODE_STATE)
1060
  if lu.cfg.GetNodeInfo(node_uuid).offline:
1061
    raise errors.OpPrereqError("%s: %s" % (msg, lu.cfg.GetNodeName(node_uuid)),
1062
                               errors.ECODE_STATE)

Also available in: Unified diff