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