26 |
26 |
# W0614: Unused import %s from wildcard import (since we need cli)
|
27 |
27 |
# C0103: Invalid name gnt-node
|
28 |
28 |
|
|
29 |
import itertools
|
|
30 |
|
29 |
31 |
from ganeti.cli import *
|
30 |
32 |
from ganeti import cli
|
31 |
33 |
from ganeti import bootstrap
|
... | ... | |
263 |
265 |
@return: the desired exit code
|
264 |
266 |
|
265 |
267 |
"""
|
266 |
|
cl = GetClient()
|
267 |
|
force = opts.force
|
|
268 |
if opts.dst_node is not None:
|
|
269 |
ToStderr("New secondary node given (disabling iallocator), hence evacuating"
|
|
270 |
" secondary instances only.")
|
|
271 |
opts.secondary_only = True
|
|
272 |
opts.primary_only = False
|
|
273 |
|
|
274 |
if opts.secondary_only and opts.primary_only:
|
|
275 |
raise errors.OpPrereqError("Only one of the --primary-only and"
|
|
276 |
" --secondary-only options can be passed",
|
|
277 |
errors.ECODE_INVAL)
|
|
278 |
elif opts.primary_only:
|
|
279 |
mode = constants.IALLOCATOR_NEVAC_PRI
|
|
280 |
elif opts.secondary_only:
|
|
281 |
mode = constants.IALLOCATOR_NEVAC_SEC
|
|
282 |
else:
|
|
283 |
mode = constants.IALLOCATOR_NEVAC_ALL
|
268 |
284 |
|
269 |
|
dst_node = opts.dst_node
|
270 |
|
iallocator = opts.iallocator
|
|
285 |
# Determine affected instances
|
|
286 |
fields = []
|
271 |
287 |
|
272 |
|
op = opcodes.OpNodeEvacStrategy(nodes=args,
|
273 |
|
iallocator=iallocator,
|
274 |
|
remote_node=dst_node)
|
|
288 |
if not opts.secondary_only:
|
|
289 |
fields.append("pinst_list")
|
|
290 |
if not opts.primary_only:
|
|
291 |
fields.append("sinst_list")
|
275 |
292 |
|
276 |
|
result = SubmitOpCode(op, cl=cl, opts=opts)
|
277 |
|
if not result:
|
278 |
|
# no instances to migrate
|
279 |
|
ToStderr("No secondary instances on node(s) %s, exiting.",
|
|
293 |
cl = GetClient()
|
|
294 |
|
|
295 |
result = cl.QueryNodes(names=args, fields=fields, use_locking=False)
|
|
296 |
instances = set(itertools.chain(*itertools.chain(*itertools.chain(result))))
|
|
297 |
|
|
298 |
if not instances:
|
|
299 |
# No instances to evacuate
|
|
300 |
ToStderr("No instances to evacuate on node(s) %s, exiting.",
|
280 |
301 |
utils.CommaJoin(args))
|
281 |
302 |
return constants.EXIT_SUCCESS
|
282 |
303 |
|
283 |
|
if not force and not AskUser("Relocate instance(s) %s from node(s) %s?" %
|
284 |
|
(",".join("'%s'" % name[0] for name in result),
|
285 |
|
utils.CommaJoin(args))):
|
|
304 |
if not (opts.force or
|
|
305 |
AskUser("Relocate instance(s) %s from node(s) %s?" %
|
|
306 |
(utils.CommaJoin(utils.NiceSort(instances)),
|
|
307 |
utils.CommaJoin(args)))):
|
286 |
308 |
return constants.EXIT_CONFIRMATION
|
287 |
309 |
|
|
310 |
# Evacuate node
|
|
311 |
op = opcodes.OpNodeEvacuate(node_name=args[0], mode=mode,
|
|
312 |
remote_node=opts.dst_node,
|
|
313 |
iallocator=opts.iallocator,
|
|
314 |
early_release=opts.early_release)
|
|
315 |
result = SubmitOpCode(op, cl=cl, opts=opts)
|
|
316 |
|
|
317 |
# Keep track of submitted jobs
|
288 |
318 |
jex = JobExecutor(cl=cl, opts=opts)
|
289 |
|
for row in result:
|
290 |
|
iname = row[0]
|
291 |
|
node = row[1]
|
292 |
|
ToStdout("Will relocate instance %s to node %s", iname, node)
|
293 |
|
op = opcodes.OpInstanceReplaceDisks(instance_name=iname,
|
294 |
|
remote_node=node, disks=[],
|
295 |
|
mode=constants.REPLACE_DISK_CHG,
|
296 |
|
early_release=opts.early_release)
|
297 |
|
jex.QueueJob(iname, op)
|
|
319 |
|
|
320 |
for (status, job_id) in result[constants.JOB_IDS_KEY]:
|
|
321 |
jex.AddJobId(None, status, job_id)
|
|
322 |
|
298 |
323 |
results = jex.GetResults()
|
299 |
324 |
bad_cnt = len([row for row in results if not row[0]])
|
300 |
325 |
if bad_cnt == 0:
|
301 |
|
ToStdout("All %d instance(s) failed over successfully.", len(results))
|
|
326 |
ToStdout("All instances evacuated successfully.")
|
302 |
327 |
rcode = constants.EXIT_SUCCESS
|
303 |
328 |
else:
|
304 |
|
ToStdout("There were errors during the failover:\n"
|
305 |
|
"%d error(s) out of %d instance(s).", bad_cnt, len(results))
|
|
329 |
ToStdout("There were %s errors during the evacuation.", bad_cnt)
|
306 |
330 |
rcode = constants.EXIT_FAILURE
|
|
331 |
|
307 |
332 |
return rcode
|
308 |
333 |
|
309 |
334 |
|
... | ... | |
835 |
860 |
" [--no-node-setup] [--verbose]"
|
836 |
861 |
" <node_name>",
|
837 |
862 |
"Add a node to the cluster"),
|
838 |
|
'evacuate': (
|
839 |
|
EvacuateNode, [ArgNode(min=1)],
|
|
863 |
"evacuate": (
|
|
864 |
EvacuateNode, ARGS_ONE_NODE,
|
840 |
865 |
[FORCE_OPT, IALLOCATOR_OPT, NEW_SECONDARY_OPT, EARLY_RELEASE_OPT,
|
841 |
|
PRIORITY_OPT],
|
|
866 |
PRIORITY_OPT, PRIMARY_ONLY_OPT, SECONDARY_ONLY_OPT],
|
842 |
867 |
"[-f] {-I <iallocator> | -n <dst>} <node>",
|
843 |
868 |
"Relocate the secondary instances from a node"
|
844 |
|
" to other nodes (only for instances with drbd disk template)"),
|
|
869 |
" to other nodes"),
|
845 |
870 |
'failover': (
|
846 |
871 |
FailoverNode, ARGS_ONE_NODE, [FORCE_OPT, IGNORE_CONSIST_OPT,
|
847 |
872 |
IALLOCATOR_OPT, PRIORITY_OPT],
|