Revision d8784f7d

b/lib/hypervisor/hv_xen.py
336 336
    self._cmd = _cmd
337 337

  
338 338
  def _GetCommand(self):
339
    """Returns Xen command to use.
340

  
341
    """
339 342
    if self._cmd is None:
340 343
      # TODO: Make command a hypervisor parameter
341 344
      cmd = constants.XEN_CMD
......
663 666
    @param live: perform a live migration
664 667

  
665 668
    """
666
    if self.GetInstanceInfo(instance.name) is None:
669
    port = instance.hvparams[constants.HV_MIGRATION_PORT]
670

  
671
    # TODO: Pass cluster name via RPC
672
    cluster_name = ssconf.SimpleStore().GetClusterName()
673

  
674
    return self._MigrateInstance(cluster_name, instance.name, target, port,
675
                                 live)
676

  
677
  def _MigrateInstance(self, cluster_name, instance_name, target, port, live,
678
                       _ping_fn=netutils.TcpPing):
679
    """Migrate an instance to a target node.
680

  
681
    @see: L{MigrateInstance} for details
682

  
683
    """
684
    if self.GetInstanceInfo(instance_name) is None:
667 685
      raise errors.HypervisorError("Instance not running, cannot migrate")
668 686

  
669
    port = instance.hvparams[constants.HV_MIGRATION_PORT]
687
    cmd = self._GetCommand()
670 688

  
671
    if (self._cmd == constants.XEN_CMD_XM and
672
        not netutils.TcpPing(target, port, live_port_needed=True)):
689
    if (cmd == constants.XEN_CMD_XM and
690
        not _ping_fn(target, port, live_port_needed=True)):
673 691
      raise errors.HypervisorError("Remote host %s not listening on port"
674 692
                                   " %s, cannot migrate" % (target, port))
675 693

  
676 694
    args = ["migrate"]
677 695

  
678
    if self._cmd == constants.XEN_CMD_XM:
696
    if cmd == constants.XEN_CMD_XM:
679 697
      args.extend(["-p", "%d" % port])
680 698
      if live:
681 699
        args.append("-l")
682 700

  
683
    elif self._cmd == constants.XEN_CMD_XL:
684
      cluster_name = ssconf.SimpleStore().GetClusterName()
685
      args.extend(["-s", constants.XL_SSH_CMD % cluster_name])
686
      args.extend(["-C", self._ConfigFileName(instance.name)])
701
    elif cmd == constants.XEN_CMD_XL:
702
      args.extend([
703
        "-s", constants.XL_SSH_CMD % cluster_name,
704
        "-C", self._ConfigFileName(instance_name),
705
        ])
687 706

  
688 707
    else:
689
      raise errors.HypervisorError("Unsupported xen command: %s" % self._cmd)
708
      raise errors.HypervisorError("Unsupported Xen command: %s" % self._cmd)
690 709

  
691
    args.extend([instance.name, target])
710
    args.extend([instance_name, target])
692 711

  
693 712
    result = self._RunXen(args)
694 713
    if result.failed:
695 714
      raise errors.HypervisorError("Failed to migrate instance %s: %s" %
696
                                   (instance.name, result.output))
715
                                   (instance_name, result.output))
697 716

  
698 717
  def FinalizeMigrationSource(self, instance, success, live):
699 718
    """Finalize the instance migration on the source node.
b/test/py/ganeti.hypervisor.hv_xen_unittest.py
366 366
                           "", "This command failed", None,
367 367
                           NotImplemented, NotImplemented)
368 368

  
369
  def _FakeTcpPing(self, expected, result, target, port, **kwargs):
370
    self.assertEqual((target, port), expected)
371
    return result
372

  
369 373
  def testReadingNonExistentConfigFile(self):
370 374
    hv = self._GetHv()
371 375

  
......
588 592
          hv._StopInstance(name, force)
589 593
          self.assertFalse(os.path.exists(cfgfile))
590 594

  
595
  def _MigrateNonRunningInstCmd(self, cmd):
596
    if cmd == [self.CMD, "list"]:
597
      output = testutils.ReadTestData("xen-xm-list-4.0.1-dom0-only.txt")
598
    else:
599
      self.fail("Unhandled command: %s" % (cmd, ))
600

  
601
    return self._SuccessCommand(output, cmd)
602

  
603
  def testMigrateInstanceNotRunning(self):
604
    name = "nonexistinginstance.example.com"
605
    target = constants.IP4_ADDRESS_LOCALHOST
606
    port = 14618
607

  
608
    hv = self._GetHv(run_cmd=self._MigrateNonRunningInstCmd)
609

  
610
    for live in [False, True]:
611
      try:
612
        hv._MigrateInstance(NotImplemented, name, target, port, live,
613
                            _ping_fn=NotImplemented)
614
      except errors.HypervisorError, err:
615
        self.assertEqual(str(err), "Instance not running, cannot migrate")
616
      else:
617
        self.fail("Exception was not raised")
618

  
619
  def _MigrateInstTargetUnreachCmd(self, cmd):
620
    if cmd == [self.CMD, "list"]:
621
      output = testutils.ReadTestData("xen-xm-list-4.0.1-four-instances.txt")
622
    else:
623
      self.fail("Unhandled command: %s" % (cmd, ))
624

  
625
    return self._SuccessCommand(output, cmd)
626

  
627
  def testMigrateTargetUnreachable(self):
628
    name = "server01.example.com"
629
    target = constants.IP4_ADDRESS_LOCALHOST
630
    port = 28349
631

  
632
    hv = self._GetHv(run_cmd=self._MigrateInstTargetUnreachCmd)
633

  
634
    for live in [False, True]:
635
      if self.CMD == constants.XEN_CMD_XL:
636
        # TODO: Detect unreachable targets
637
        pass
638
      else:
639
        try:
640
          hv._MigrateInstance(NotImplemented, name, target, port, live,
641
                              _ping_fn=compat.partial(self._FakeTcpPing,
642
                                                      (target, port), False))
643
        except errors.HypervisorError, err:
644
          wanted = "Remote host %s not" % target
645
          self.assertTrue(str(err).startswith(wanted))
646
        else:
647
          self.fail("Exception was not raised")
648

  
649
  def _MigrateInstanceCmd(self, cluster_name, instance_name, target, port,
650
                          live, fail, cmd):
651
    if cmd == [self.CMD, "list"]:
652
      output = testutils.ReadTestData("xen-xm-list-4.0.1-four-instances.txt")
653
    elif cmd[:2] == [self.CMD, "migrate"]:
654
      if self.CMD == constants.XEN_CMD_XM:
655
        args = ["-p", str(port)]
656

  
657
        if live:
658
          args.append("-l")
659

  
660
      elif self.CMD == constants.XEN_CMD_XL:
661
        args = [
662
          "-s", constants.XL_SSH_CMD % cluster_name,
663
          "-C", utils.PathJoin(self.tmpdir, instance_name),
664
          ]
665

  
666
      else:
667
        self.fail("Unknown Xen command '%s'" % self.CMD)
668

  
669
      args.extend([instance_name, target])
670
      self.assertEqual(cmd[2:], args)
671

  
672
      if fail:
673
        return self._FailingCommand(cmd)
674

  
675
      output = ""
676
    else:
677
      self.fail("Unhandled command: %s" % (cmd, ))
678

  
679
    return self._SuccessCommand(output, cmd)
680

  
681
  def testMigrateInstance(self):
682
    clustername = "cluster.example.com"
683
    instname = "server01.example.com"
684
    target = constants.IP4_ADDRESS_LOCALHOST
685
    port = 22364
686

  
687
    for live in [False, True]:
688
      for fail in [False, True]:
689
        ping_fn = \
690
          testutils.CallCounter(compat.partial(self._FakeTcpPing,
691
                                               (target, port), True))
692

  
693
        run_cmd = \
694
          compat.partial(self._MigrateInstanceCmd,
695
                         clustername, instname, target, port, live,
696
                         fail)
697

  
698
        hv = self._GetHv(run_cmd=run_cmd)
699

  
700
        if fail:
701
          try:
702
            hv._MigrateInstance(clustername, instname, target, port, live,
703
                                _ping_fn=ping_fn)
704
          except errors.HypervisorError, err:
705
            self.assertTrue(str(err).startswith("Failed to migrate instance"))
706
          else:
707
            self.fail("Exception was not raised")
708
        else:
709
          hv._MigrateInstance(clustername, instname, target, port, live,
710
                              _ping_fn=ping_fn)
711

  
712
        if self.CMD == constants.XEN_CMD_XM:
713
          expected_pings = 1
714
        else:
715
          expected_pings = 0
716

  
717
        self.assertEqual(ping_fn.Count(), expected_pings)
718

  
591 719

  
592 720
def _MakeTestClass(cls, cmd):
593 721
  """Makes a class for testing.

Also available in: Unified diff