def run_migration_with_file_transfer(test, params, env):
    """
    KVM migration test:
    1) Get a live VM and clone it.
    2) Verify that the source VM supports migration.  If it does, proceed with
            the test.
    3) Reboot the VM
    4) Send a migration command to the source VM and wait until it's finished.
    5) Kill off the source VM.
    6) Log into the destination VM after the migration is finished.

    @param test: kvm test object.
    @param params: Dictionary with test parameters.
    @param env: Dictionary with the test environment.
    """

    def transfer_test(vm, host_path, guest_path, timeout=120):
        """
        vm.copy_files_to does not raise exception, so we need a wrapper
        in order to make it to be used by BackgroundTest.
        """
        if not vm.copy_files_to(host_path, guest_path, timeout=timeout):
            raise error.TestError("Fail to do the file transfer!")

    vm = kvm_test_utils.get_living_vm(env, params.get("main_vm"))
    timeout = int(params.get("login_timeout", 360))
    session = kvm_test_utils.wait_for_login(vm, timeout=timeout)

    mig_timeout = float(params.get("mig_timeout", "3600"))
    mig_protocol = params.get("migration_protocol", "tcp")

    guest_path = params.get("guest_path", "/tmp")
    file_size = params.get("file_size", "1000")
    transfer_timeout = int(params.get("transfer_timeout", "240"))
    bg = None

    try:
        utils.run("dd if=/dev/zero of=/tmp/file bs=1M count=%s" % file_size)

        # Transfer file from host to guest
        bg = kvm_test_utils.BackgroundTest(transfer_test,
                                           (vm, "/tmp/file", guest_path,
                                            transfer_timeout))
        bg.start()

        while bg.is_alive():
            logging.info("File transfer is not ended, start a round of migration ...")
            # Migrate the VM
            dest_vm = kvm_test_utils.migrate(vm, env, mig_timeout, mig_protocol, False)
            vm = dest_vm
    finally:
        if bg: bg.join()
        session.close()
        utils.run("rm -rf /tmp/zero")
def run_migration_with_reboot(test, params, env):
    """
    KVM migration test:
    1) Get a live VM and clone it.
    2) Verify that the source VM supports migration.  If it does, proceed with
            the test.
    3) Reboot the VM
    4) Send a migration command to the source VM and wait until it's finished.
    5) Kill off the source VM.
    6) Log into the destination VM after the migration is finished.

    @param test: kvm test object.
    @param params: Dictionary with test parameters.
    @param env: Dictionary with the test environment.
    """
    vm = kvm_test_utils.get_living_vm(env, params.get("main_vm"))
    timeout = int(params.get("login_timeout", 360))
    session = kvm_test_utils.wait_for_login(vm, timeout=timeout)

    mig_timeout = float(params.get("mig_timeout", "3600"))
    mig_protocol = params.get("migration_protocol", "tcp")
    mig_cancel = bool(params.get("mig_cancel"))
    bg = None

    try:
        # reboot the VM in background
        bg = kvm_test_utils.BackgroundTest(kvm_test_utils.reboot, (vm, session))
        bg.start()

        while bg.is_alive():
            # Migrate the VM
            dest_vm = kvm_test_utils.migrate(vm, env, mig_timeout, mig_protocol,
                                             False)
            vm = dest_vm

    finally:
        if bg:
            bg.join()
        session.close()
def run_migration_multi_host(test, params, env):
    """
    KVM multi-host migration test:

    Migration execution progress:

    source host                       dest host
    ----------------------------------------------------------------------------
    log into guest
    ----------------------------------------------------------------------------
    start socket server

    wait 30 secs -------------------- wait login_timeout+30 secs ---------------

    accept connection                 connect to socket server,send mig_port
    ----------------------------------------------------------------------------
    start migration

    wait 30 secs -------------------- wait mig_timeout+30 secs -----------------

    try to log into migrated guest    check VM's status via monitor cmd
    ----------------------------------------------------------------------------

    @param test: kvm test object.
    @param params: Dictionary with test parameters.
    @param env: Dictionary with the test environment.
    """
    def guest_active(vm):
        o = vm.monitor.info("status")
        if isinstance(o, str):
            return "status: running" in o
        else:
            return o.get("status") == "running"

    vm = kvm_test_utils.get_living_vm(env, params.get("main_vm"))
    login_timeout = int(params.get("login_timeout", 360))
    role = params.get("role")
    srchost = params.get("srchost")
    dsthost = params.get("dsthost")
    mig_timeout = int(params.get("mig_timeout"))
    # Port used to communicate info between source and destination
    comm_port = int(params.get("comm_port", 12324))
    regain_ip_cmd = params.get("regain_ip_cmd", "dhclient")
    if role == 'source':
        session = kvm_test_utils.wait_for_login(vm, timeout=login_timeout)

        # Listen on a port to get the migration port received from
        # dest machine
        s_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s_socket.bind(('', comm_port))
        s_socket.listen(1)

        # Wait 30 seconds for source and dest to reach this point
        test.job.barrier(srchost,'socket_started', 30).rendezvous(srchost,
                                                                  dsthost)

        c_socket, addr = s_socket.accept()
        mig_port = int(c_socket.recv(6))
        logging.info("Received from destination the migration port %s",
                     mig_port)
        c_socket.close()

        logging.info("Start migrating now...")
        kvm_test_utils.migrate(vm=vm, dest_host=dsthost, mig_port=mig_port,
                               env=env)

        # Wait up to 30 seconds for dest to reach this point
        test.job.barrier(srchost, 'mig_finished', 30).rendezvous(srchost,
                                                                 dsthost)

    elif role == 'destination':
        # Wait up to login_timeout + 30 seconds for the source to
        # reach this point
        test.job.barrier(dsthost, 'socket_started',
                         login_timeout + 30).rendezvous(srchost,
                                                        dsthost)

        c_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        c_socket.connect((srchost, comm_port))
        logging.info("Communicating to source migration port %s",
                     vm.migration_port)
        c_socket.send("%d" % vm.migration_port)
        c_socket.close()

        # Wait up to mig_timeout + 30 seconds for the source to
        # reach this point: migration finished
        test.job.barrier(dsthost, 'mig_finished',
                         mig_timeout + 30).rendezvous(srchost,
                                                      dsthost)

        if not guest_active(vm):
            raise error.TestFail("Guest not active after migration")

        logging.info("Migrated guest appears to be running")

        # Log into the guest again
        logging.info("Logging into migrated guest after migration...")
        session_serial = kvm_test_utils.wait_for_login(vm, timeout=login_timeout, serial=True)
        session_serial.cmd(regain_ip_cmd)
        session = kvm_test_utils.wait_for_login(vm, timeout=login_timeout)

    else:
        raise error.TestError('Invalid role specified')
def run_timedrift_with_migration(test, params, env):
    """
    Time drift test with migration:

    1) Log into a guest.
    2) Take a time reading from the guest and host.
    3) Migrate the guest.
    4) Take a second time reading.
    5) If the drift (in seconds) is higher than a user specified value, fail.

    @param test: KVM test object.
    @param params: Dictionary with test parameters.
    @param env: Dictionary with the test environment.
    """
    vm = kvm_test_utils.get_living_vm(env, params.get("main_vm"))
    timeout = int(params.get("login_timeout", 360))
    session = kvm_test_utils.wait_for_login(vm, timeout=timeout)

    # Collect test parameters:
    # Command to run to get the current time
    time_command = params.get("time_command")
    # Filter which should match a string to be passed to time.strptime()
    time_filter_re = params.get("time_filter_re")
    # Time format for time.strptime()
    time_format = params.get("time_format")
    drift_threshold = float(params.get("drift_threshold", "10"))
    drift_threshold_single = float(params.get("drift_threshold_single", "3"))
    migration_iterations = int(params.get("migration_iterations", 1))

    try:
        # Get initial time
        # (ht stands for host time, gt stands for guest time)
        (ht0, gt0) = kvm_test_utils.get_time(session, time_command,
                                             time_filter_re, time_format)

        # Migrate
        for i in range(migration_iterations):
            # Get time before current iteration
            (ht0_, gt0_) = kvm_test_utils.get_time(session, time_command,
                                                   time_filter_re, time_format)
            session.close()
            # Run current iteration
            logging.info("Migrating: iteration %d of %d..." %
                         (i + 1, migration_iterations))
            vm = kvm_test_utils.migrate(vm, env)
            # Log in
            logging.info("Logging in after migration...")
            session = kvm_utils.wait_for(vm.remote_login, 30, 0, 2)
            if not session:
                raise error.TestFail("Could not log in after migration")
            logging.info("Logged in after migration")
            # Get time after current iteration
            (ht1_, gt1_) = kvm_test_utils.get_time(session, time_command,
                                                   time_filter_re, time_format)
            # Report iteration results
            host_delta = ht1_ - ht0_
            guest_delta = gt1_ - gt0_
            drift = abs(host_delta - guest_delta)
            logging.info("Host duration (iteration %d): %.2f" %
                         (i + 1, host_delta))
            logging.info("Guest duration (iteration %d): %.2f" %
                         (i + 1, guest_delta))
            logging.info("Drift at iteration %d: %.2f seconds" %
                         (i + 1, drift))
            # Fail if necessary
            if drift > drift_threshold_single:
                raise error.TestFail("Time drift too large at iteration %d: "
                                     "%.2f seconds" % (i + 1, drift))

        # Get final time
        (ht1, gt1) = kvm_test_utils.get_time(session, time_command,
                                             time_filter_re, time_format)

    finally:
        if session:
            session.close()

    # Report results
    host_delta = ht1 - ht0
    guest_delta = gt1 - gt0
    drift = abs(host_delta - guest_delta)
    logging.info("Host duration (%d migrations): %.2f" %
                 (migration_iterations, host_delta))
    logging.info("Guest duration (%d migrations): %.2f" %
                 (migration_iterations, guest_delta))
    logging.info("Drift after %d migrations: %.2f seconds" %
                 (migration_iterations, drift))

    # Fail if necessary
    if drift > drift_threshold:
        raise error.TestFail("Time drift too large after %d migrations: "
                             "%.2f seconds" % (migration_iterations, drift))