Revision 30e42c4e lib/hypervisor/hv_kvm.py

b/lib/hypervisor/hv_kvm.py
28 28
import re
29 29
import tempfile
30 30
import time
31
import logging
31 32
from cStringIO import StringIO
32 33

  
33 34
from ganeti import utils
......
53 54
    constants.HV_ACPI,
54 55
    ]
55 56

  
57
  _MIGRATION_STATUS_RE = re.compile('Migration\s+status:\s+(\w+)',
58
                                    re.M | re.I)
59

  
56 60
  def __init__(self):
57 61
    hv_base.BaseHypervisor.__init__(self)
58 62
    # Let's make sure the directories we need exist, even if the RUN_DIR lives
......
284 288
    serialized_form = serializer.Dump((kvm_cmd, serialized_nics))
285 289
    self._WriteKVMRuntime(instance.name, serialized_form)
286 290

  
287
  def _LoadKVMRuntime(self, instance):
291
  def _LoadKVMRuntime(self, instance, serialized_runtime=None):
288 292
    """Load an instance's KVM runtime
289 293

  
290 294
    """
291
    serialized_form = self._ReadKVMRuntime(instance.name)
292
    loaded_runtime = serializer.Load(serialized_form)
295
    if not serialized_runtime:
296
      serialized_runtime = self._ReadKVMRuntime(instance.name)
297
    loaded_runtime = serializer.Load(serialized_runtime)
293 298
    kvm_cmd, serialized_nics = loaded_runtime
294 299
    kvm_nics = [objects.NIC.FromDict(snic) for snic in serialized_nics]
295 300
    return (kvm_cmd, kvm_nics)
296 301

  
297
  def _ExecuteKVMRuntime(self, instance, kvm_runtime):
302
  def _ExecuteKVMRuntime(self, instance, kvm_runtime, incoming=None):
298 303
    """Execute a KVM cmd, after completing it with some last minute data
299 304

  
305
    @type incoming: tuple of strings
306
    @param incoming: (target_host_ip, port)
307

  
300 308
    """
301 309
    pidfile, pid, alive = self._InstancePidAlive(instance.name)
302 310
    if alive:
......
317 325
        kvm_cmd.extend(['-net', 'tap,script=%s' % script])
318 326
        temp_files.append(script)
319 327

  
328
    if incoming:
329
      target, port = incoming
330
      kvm_cmd.extend(['-incoming', 'tcp:%s:%s' % (target, port)])
331

  
320 332
    result = utils.RunCmd(kvm_cmd)
321 333
    if result.failed:
322 334
      raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
......
415 427
    self._SaveKVMRuntime(instance, kvm_runtime)
416 428
    self._ExecuteKVMRuntime(instance, kvm_runtime)
417 429

  
430
  def MigrationInfo(self, instance):
431
    """Get instance information to perform a migration.
432

  
433
    @type instance: L{objects.Instance}
434
    @param instance: instance to be migrated
435
    @rtype: string
436
    @return: content of the KVM runtime file
437

  
438
    """
439
    return self._ReadKVMRuntime(instance.name)
440

  
441
  def AcceptInstance(self, instance, info, target):
442
    """Prepare to accept an instance.
443

  
444
    @type instance: L{objects.Instance}
445
    @param instance: instance to be accepted
446
    @type info: string
447
    @param info: content of the KVM runtime file on the source node
448
    @type target: string
449
    @param target: target host (usually ip), on this node
450

  
451
    """
452
    kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
453
    incoming_address = (target, constants.KVM_MIGRATION_PORT)
454
    self._ExecuteKVMRuntime(instance, kvm_runtime, incoming=incoming_address)
455

  
456
  def FinalizeMigration(self, instance, info, success):
457
    """Finalize an instance migration.
458

  
459
    Stop the incoming mode KVM.
460

  
461
    @type instance: L{objects.Instance}
462
    @param instance: instance whose migration is being aborted
463

  
464
    """
465
    if success:
466
      self._WriteKVMRuntime(instance.name, info)
467
    else:
468
      self.StopInstance(instance, force=True)
469

  
470
  def MigrateInstance(self, instance_name, target, live):
471
    """Migrate an instance to a target node.
472

  
473
    The migration will not be attempted if the instance is not
474
    currently running.
475

  
476
    @type instance_name: string
477
    @param instance_name: name of the instance to be migrated
478
    @type target: string
479
    @param target: ip address of the target node
480
    @type live: boolean
481
    @param live: perform a live migration
482

  
483
    """
484
    pidfile, pid, alive = self._InstancePidAlive(instance_name)
485
    if not alive:
486
      raise errors.HypervisorError("Instance not running, cannot migrate")
487

  
488
    if not live:
489
      self._CallMonitorCommand(instance_name, 'stop')
490

  
491
    migrate_command = ('migrate -d tcp:%s:%s' %
492
                       (target, constants.KVM_MIGRATION_PORT))
493
    self._CallMonitorCommand(instance_name, migrate_command)
494

  
495
    info_command = 'info migrate'
496
    done = False
497
    while not done:
498
      result = self._CallMonitorCommand(instance_name, info_command)
499
      match = self._MIGRATION_STATUS_RE.search(result.stdout)
500
      if not match:
501
        raise errors.HypervisorError("Unknown 'info migrate' result: %s" %
502
                                     result.stdout)
503
      else:
504
        status = match.group(1)
505
        if status == 'completed':
506
          done = True
507
        elif status == 'active':
508
          time.sleep(2)
509
        else:
510
          logging.info("KVM: unknown migration status '%s'" % status)
511
          time.sleep(2)
512

  
513
    utils.KillProcess(pid)
514
    utils.RemoveFile(pidfile)
515
    utils.RemoveFile(self._InstanceMonitor(instance_name))
516
    utils.RemoveFile(self._InstanceSerial(instance_name))
517
    utils.RemoveFile(self._InstanceKVMRuntime(instance_name))
518

  
418 519
  def GetNodeInfo(self):
419 520
    """Return information about the node.
420 521

  

Also available in: Unified diff