Revision a396b2d6 tools/move-instance
b/tools/move-instance | ||
---|---|---|
39 | 39 |
from ganeti import objects |
40 | 40 |
from ganeti import compat |
41 | 41 |
from ganeti import rapi |
42 |
from ganeti import errors |
|
42 | 43 |
|
43 | 44 |
import ganeti.rapi.client # pylint: disable=W0611 |
44 | 45 |
import ganeti.rapi.client_utils |
... | ... | |
301 | 302 |
def __init__(self, src_instance_name, dest_instance_name, |
302 | 303 |
dest_pnode, dest_snode, compress, dest_iallocator, |
303 | 304 |
dest_disk_template, hvparams, |
304 |
beparams, osparams, nics): |
|
305 |
beparams, osparams, nics, opportunistic_tries, |
|
306 |
opportunistic_delay): |
|
305 | 307 |
"""Initializes this class. |
306 | 308 |
|
307 | 309 |
@type src_instance_name: string |
... | ... | |
327 | 329 |
@param osparams: OS parameters to override |
328 | 330 |
@type nics: dict or None |
329 | 331 |
@param nics: NICs to override |
332 |
@type opportunistic_tries: int or None |
|
333 |
@param opportunistic_tries: Number of opportunistic creation attempts to |
|
334 |
perform |
|
335 |
@type opportunistic_delay: int or None |
|
336 |
@param opportunistic_delay: Delay between successive creation attempts, in |
|
337 |
seconds |
|
330 | 338 |
|
331 | 339 |
""" |
332 | 340 |
self.src_instance_name = src_instance_name |
... | ... | |
341 | 349 |
self.osparams = osparams |
342 | 350 |
self.nics = nics |
343 | 351 |
|
352 |
if opportunistic_tries is not None: |
|
353 |
self.opportunistic_tries = opportunistic_tries |
|
354 |
else: |
|
355 |
self.opportunistic_tries = 0 |
|
356 |
|
|
357 |
if opportunistic_delay is not None: |
|
358 |
self.opportunistic_delay = opportunistic_delay |
|
359 |
else: |
|
360 |
self.opportunistic_delay = constants.DEFAULT_OPPORTUNISTIC_RETRY_INTERVAL |
|
361 |
|
|
344 | 362 |
self.error_message = None |
345 | 363 |
|
346 | 364 |
|
... | ... | |
462 | 480 |
|
463 | 481 |
logging.info("Creating instance %s in remote-import mode", |
464 | 482 |
mrt.move.dest_instance_name) |
465 |
job_id = self._CreateInstance(dest_client, mrt.move.dest_instance_name, |
|
466 |
mrt.move.dest_pnode, mrt.move.dest_snode, |
|
467 |
mrt.move.compress, |
|
468 |
mrt.move.dest_iallocator, |
|
469 |
mrt.move.dest_disk_template, |
|
470 |
mrt.src_instinfo, mrt.src_expinfo, |
|
471 |
mrt.move.hvparams, mrt.move.beparams, |
|
472 |
mrt.move.beparams, mrt.move.nics) |
|
473 |
mrt.PollJob(dest_client, job_id, |
|
474 |
remote_import_fn=compat.partial(self._SetImportInfo, mrt)) |
|
475 |
|
|
476 |
logging.info("Import successful") |
|
483 |
|
|
484 |
# Depending on whether opportunistic tries are enabled, we may have to |
|
485 |
# make multiple creation attempts |
|
486 |
creation_attempts = [True] * mrt.move.opportunistic_tries |
|
487 |
|
|
488 |
# But the last one is never opportunistic, and will block until completion |
|
489 |
# or failure |
|
490 |
creation_attempts.append(False) |
|
491 |
|
|
492 |
for is_attempt_opportunistic in creation_attempts: |
|
493 |
job_id = self._CreateInstance(dest_client, mrt.move.dest_instance_name, |
|
494 |
mrt.move.dest_pnode, mrt.move.dest_snode, |
|
495 |
mrt.move.compress, |
|
496 |
mrt.move.dest_iallocator, |
|
497 |
mrt.move.dest_disk_template, |
|
498 |
mrt.src_instinfo, mrt.src_expinfo, |
|
499 |
mrt.move.hvparams, mrt.move.beparams, |
|
500 |
mrt.move.beparams, mrt.move.nics, |
|
501 |
is_attempt_opportunistic |
|
502 |
) |
|
503 |
|
|
504 |
try: |
|
505 |
# The completion of this block signifies that the import has been |
|
506 |
# completed successfullly |
|
507 |
mrt.PollJob(dest_client, job_id, |
|
508 |
remote_import_fn=compat.partial(self._SetImportInfo, mrt)) |
|
509 |
logging.info("Import successful") |
|
510 |
return |
|
511 |
except errors.OpPrereqError, err: |
|
512 |
# Any exception in the non-opportunistic creation is to be passed on, |
|
513 |
# as well as exceptions apart from resources temporarily unavailable |
|
514 |
if not is_attempt_opportunistic or \ |
|
515 |
err.args[1] != rapi.client.ECODE_TEMP_NORES: |
|
516 |
raise |
|
517 |
|
|
518 |
logging.info("Opportunistic attempt unsuccessful, waiting %d seconds" |
|
519 |
" before another creation attempt is made", |
|
520 |
mrt.move.opportunistic_delay) |
|
521 |
time.sleep(mrt.move.opportunistic_delay) |
|
477 | 522 |
|
478 | 523 |
@staticmethod |
479 | 524 |
def _SetImportInfo(mrt, impinfo): |
... | ... | |
494 | 539 |
@staticmethod |
495 | 540 |
def _CreateInstance(cl, name, pnode, snode, compress, iallocator, |
496 | 541 |
dest_disk_template, instance, expinfo, override_hvparams, |
497 |
override_beparams, override_osparams, override_nics): |
|
542 |
override_beparams, override_osparams, override_nics, |
|
543 |
is_attempt_opportunistic): |
|
498 | 544 |
"""Starts the instance creation in remote import mode. |
499 | 545 |
|
500 | 546 |
@type cl: L{rapi.client.GanetiRapiClient} |
... | ... | |
523 | 569 |
@param override_osparams: OS parameters to override |
524 | 570 |
@type override_nics: dict or None |
525 | 571 |
@param override_nics: NICs to override |
572 |
@type is_attempt_opportunistic: bool |
|
573 |
@param is_attempt_opportunistic: Whether to use opportunistic locking or not |
|
526 | 574 |
@return: Job ID |
527 | 575 |
|
528 | 576 |
""" |
... | ... | |
602 | 650 |
hvparams=objects.FillDict(inst_hvparams, |
603 | 651 |
override_hvparams), |
604 | 652 |
osparams=objects.FillDict(inst_osparams, |
605 |
override_osparams)) |
|
653 |
override_osparams), |
|
654 |
opportunistic_locking=is_attempt_opportunistic |
|
655 |
) |
|
606 | 656 |
|
607 | 657 |
|
608 | 658 |
class MoveSourceExecutor(object): |
... | ... | |
961 | 1011 |
options.hvparams, |
962 | 1012 |
options.beparams, |
963 | 1013 |
options.osparams, |
964 |
options.nics)) |
|
1014 |
options.nics, |
|
1015 |
options.opportunistic_tries, |
|
1016 |
options.opportunistic_delay)) |
|
965 | 1017 |
|
966 | 1018 |
assert len(moves) == len(instance_names) |
967 | 1019 |
|
Also available in: Unified diff