Revision 6906a9d8

b/daemons/ganeti-noded
403 403
    return backend.StartInstance(instance, extra_args)
404 404

  
405 405
  @staticmethod
406
  def perspective_migration_info(params):
407
    """Gather information about an instance to be migrated.
408

  
409
    """
410
    instance = objects.Instance.FromDict(params[0])
411
    return backend.MigrationInfo(instance)
412

  
413
  @staticmethod
414
  def perspective_accept_instance(params):
415
    """Prepare the node to accept an instance.
416

  
417
    """
418
    instance, info, target = params
419
    instance = objects.Instance.FromDict(instance)
420
    return backend.AcceptInstance(instance, info, target)
421

  
422
  @staticmethod
423
  def perspective_finalize_migration(params):
424
    """Finalize the instance migration.
425

  
426
    """
427
    instance, info, success = params
428
    instance = objects.Instance.FromDict(instance)
429
    return backend.FinalizeMigration(instance, info, success)
430

  
431
  @staticmethod
406 432
  def perspective_instance_migrate(params):
407 433
    """Migrates an instance.
408 434

  
b/lib/backend.py
973 973
  return True
974 974

  
975 975

  
976
def MigrationInfo(instance):
977
  """Gather information about an instance to be migrated.
978

  
979
  @type instance: L{objects.Instance}
980
  @param instance: the instance definition
981

  
982
  """
983
  return (True, '')
984

  
985

  
986
def AcceptInstance(instance, info, target):
987
  """Prepare the node to accept an instance.
988

  
989
  @type instance: L{objects.Instance}
990
  @param instance: the instance definition
991
  @type info: string/data (opaque)
992
  @param info: migration information, from the source node
993
  @type target: string
994
  @param target: target host (usually ip), on this node
995

  
996
  """
997
  return (True, "Accept successfull")
998

  
999

  
1000
def FinalizeMigration(instance, info, success):
1001
  """Finalize any preparation to accept an instance.
1002

  
1003
  @type instance: L{objects.Instance}
1004
  @param instance: the instance definition
1005
  @type info: string/data (opaque)
1006
  @param info: migration information, from the source node
1007
  @type success: boolean
1008
  @param success: whether the migration was a success or a failure
1009

  
1010
  """
1011
  return (True, "Migration Finalized")
1012

  
1013

  
976 1014
def MigrateInstance(instance, target, live):
977 1015
  """Migrates an instance to another node.
978 1016

  
b/lib/cmdlib.py
3631 3631

  
3632 3632
    self.feedback_fn("* done")
3633 3633

  
3634
  def _RevertDiskStatus(self):
3635
    """Try to revert the disk status after a failed migration.
3636

  
3637
    """
3638
    target_node = self.target_node
3639
    try:
3640
      self._EnsureSecondary(target_node)
3641
      self._GoStandalone()
3642
      self._GoReconnect(False)
3643
      self._WaitUntilSync()
3644
    except errors.OpExecError, err:
3645
      self.LogWarning("Migration failed and I can't reconnect the"
3646
                      " drives: error '%s'\n"
3647
                      "Please look and recover the instance status" %
3648
                      str(err))
3649

  
3650
  def _AbortMigration(self):
3651
    """Call the hypervisor code to abort a started migration.
3652

  
3653
    """
3654
    instance = self.instance
3655
    target_node = self.target_node
3656
    migration_info = self.migration_info
3657

  
3658
    abort_result = self.rpc.call_finalize_migration(target_node,
3659
                                                    instance,
3660
                                                    migration_info,
3661
                                                    False)
3662
    abort_msg = abort_result.RemoteFailMsg()
3663
    if abort_msg:
3664
      logging.error("Aborting migration failed on target node %s: %s" %
3665
                    (target_node, abort_msg))
3666
      # Don't raise an exception here, as we stil have to try to revert the
3667
      # disk status, even if this step failed.
3668

  
3634 3669
  def _ExecMigration(self):
3635 3670
    """Migrate an instance.
3636 3671

  
......
3654 3689
                                 " synchronized on target node,"
3655 3690
                                 " aborting migrate." % dev.iv_name)
3656 3691

  
3692
    # First get the migration information from the remote node
3693
    result = self.rpc.call_migration_info(source_node, instance)
3694
    msg = result.RemoteFailMsg()
3695
    if msg:
3696
      log_err = ("Failed fetching source migration information from %s: %s" %
3697
                  (source_node, msg))
3698
      logging.error(log_err)
3699
      raise errors.OpExecError(log_err)
3700

  
3701
    self.migration_info = migration_info = result.data[1]
3702

  
3703
    # Then switch the disks to master/master mode
3657 3704
    self._EnsureSecondary(target_node)
3658 3705
    self._GoStandalone()
3659 3706
    self._GoReconnect(True)
3660 3707
    self._WaitUntilSync()
3661 3708

  
3709
    self.feedback_fn("* preparing %s to accept the instance" % target_node)
3710
    result = self.rpc.call_accept_instance(target_node,
3711
                                           instance,
3712
                                           migration_info,
3713
                                           self.nodes_ip[target_node])
3714

  
3715
    msg = result.RemoteFailMsg()
3716
    if msg:
3717
      logging.error("Instance pre-migration failed, trying to revert"
3718
                    " disk status: %s", msg)
3719
      self._AbortMigration()
3720
      self._RevertDiskStatus()
3721
      raise errors.OpExecError("Could not pre-migrate instance %s: %s" %
3722
                               (instance.name, msg))
3723

  
3662 3724
    self.feedback_fn("* migrating instance to %s" % target_node)
3663 3725
    time.sleep(10)
3664 3726
    result = self.rpc.call_instance_migrate(source_node, instance,
......
3668 3730
    if msg:
3669 3731
      logging.error("Instance migration failed, trying to revert"
3670 3732
                    " disk status: %s", msg)
3671
      try:
3672
        self._EnsureSecondary(target_node)
3673
        self._GoStandalone()
3674
        self._GoReconnect(False)
3675
        self._WaitUntilSync()
3676
      except errors.OpExecError, err:
3677
        self.LogWarning("Migration failed and I can't reconnect the"
3678
                        " drives: error '%s'\n"
3679
                        "Please look and recover the instance status" %
3680
                        str(err))
3681

  
3733
      self._AbortMigration()
3734
      self._RevertDiskStatus()
3682 3735
      raise errors.OpExecError("Could not migrate instance %s: %s" %
3683 3736
                               (instance.name, msg))
3684 3737
    time.sleep(10)
......
3687 3740
    # distribute new instance config to the other nodes
3688 3741
    self.cfg.Update(instance)
3689 3742

  
3743
    result = self.rpc.call_finalize_migration(target_node,
3744
                                              instance,
3745
                                              migration_info,
3746
                                              True)
3747
    msg = result.RemoteFailMsg()
3748
    if msg:
3749
      logging.error("Instance migration succeeded, but finalization failed:"
3750
                    " %s" % msg)
3751
      raise errors.OpExecError("Could not finalize instance migration: %s" %
3752
                               msg)
3753

  
3690 3754
    self._EnsureSecondary(source_node)
3691 3755
    self._WaitUntilSync()
3692 3756
    self._GoStandalone()
b/lib/rpc.py
432 432
    return self._SingleNodeCall(node, "instance_shutdown",
433 433
                                [self._InstDict(instance)])
434 434

  
435
  def call_migration_info(self, node, instance):
436
    """Gather the information necessary to prepare an instance migration.
437

  
438
    This is a single-node call.
439

  
440
    @type node: string
441
    @param node: the node on which the instance is currently running
442
    @type instance: C{objects.Instance}
443
    @param instance: the instance definition
444

  
445
    """
446
    return self._SingleNodeCall(node, "migration_info",
447
                                [self._InstDict(instance)])
448

  
449
  def call_accept_instance(self, node, instance, info, target):
450
    """Prepare a node to accept an instance.
451

  
452
    This is a single-node call.
453

  
454
    @type node: string
455
    @param node: the target node for the migration
456
    @type instance: C{objects.Instance}
457
    @param instance: the instance definition
458
    @type info: opaque/hypervisor specific (string/data)
459
    @param info: result for the call_migration_info call
460
    @type target: string
461
    @param target: target hostname (usually ip address) (on the node itself)
462

  
463
    """
464
    return self._SingleNodeCall(node, "accept_instance",
465
                                [self._InstDict(instance), info, target])
466

  
467
  def call_finalize_migration(self, node, instance, info, success):
468
    """Finalize any target-node migration specific operation.
469

  
470
    This is called both in case of a successful migration and in case of error
471
    (in which case it should abort the migration).
472

  
473
    This is a single-node call.
474

  
475
    @type node: string
476
    @param node: the target node for the migration
477
    @type instance: C{objects.Instance}
478
    @param instance: the instance definition
479
    @type info: opaque/hypervisor specific (string/data)
480
    @param info: result for the call_migration_info call
481
    @type success: boolean
482
    @param success: whether the migration was a success or a failure
483

  
484
    """
485
    return self._SingleNodeCall(node, "finalize_migration",
486
                                [self._InstDict(instance), info, success])
487

  
435 488
  def call_instance_migrate(self, node, instance, target, live):
436 489
    """Migrate an instance.
437 490

  

Also available in: Unified diff