#!/usr/bin/env python

# Copyright 2010 OpenStack LLC.
# All Rights Reserved.
#
#    Licensed under the Apache License, Version 2.0 (the "License"); you may
#    not use this file except in compliance with the License. You may obtain
#    a copy of the License at
#
#         http://www.apache.org/licenses/LICENSE-2.0
#
#    Unless required by applicable law or agreed to in writing, software
#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
#    License for the specific language governing permissions and limitations
#    under the License.

"""
XenAPI Plugin for transfering data between host nodes
"""

import os
import os.path
import pickle
import shlex
import shutil
import subprocess

import XenAPIPlugin

from pluginlib_nova import *
configure_logging('migration')


def move_vhds_into_sr(session, args):
    """Moves the VHDs from their copied location to the SR"""
    params = pickle.loads(exists(args, 'params'))
    instance_uuid = params['instance_uuid']

    sr_path = params['sr_path']
    sr_temp_path = "%s/tmp" % sr_path
    temp_vhd_path = "%s/instance%s" % (sr_temp_path, instance_uuid)

    logging.debug('Creating temporary SR path %s' % temp_vhd_path)
    os.makedirs(temp_vhd_path)

    # Discover the copied VHDs locally, and then set up paths to copy
    # them to under the SR
    source_image_path = "/images/instance%s" % instance_uuid

    old_base_copy_uuid = params['old_base_copy_uuid']
    new_base_copy_uuid = params['new_base_copy_uuid']
    source_base_copy_path = "%s/%s.vhd" % (source_image_path,
            old_base_copy_uuid)
    new_base_copy_path = "%s/%s.vhd" % (temp_vhd_path, new_base_copy_uuid)

    logging.debug('Moving base %s into %s' % (source_base_copy_path,
                                              temp_vhd_path))
    shutil.move(source_base_copy_path, new_base_copy_path)

    if 'old_cow_uuid' in params:
        old_cow_uuid = params['old_cow_uuid']
        new_cow_uuid = params['new_cow_uuid']

        source_cow_path = "%s/%s.vhd" % (source_image_path, old_cow_uuid)
        new_cow_path = "%s/%s.vhd" % (temp_vhd_path, new_cow_uuid)

        logging.debug('Moving COW %s into %s' % (source_cow_path,
                                                 temp_vhd_path))
        shutil.move(source_cow_path, new_cow_path)

        # Link the COW to the base copy
        logging.debug('Attaching COW to the base %s -> %s' %
                      (new_cow_path, new_base_copy_path))
        subprocess.call(['/usr/sbin/vhd-util', 'modify',
                         '-n', new_cow_path, '-p', new_base_copy_path])

        # NOTE(sirp): COW should be copied before base_copy to avoid
        # snapwatchd GC'ing an unreferenced base copy VDI
        logging.debug('Moving COW %s to %s' % (new_cow_path, sr_path))
        shutil.move(new_cow_path, sr_path)

    logging.debug('Moving base %s to %s' % (new_base_copy_path, sr_path))
    shutil.move(new_base_copy_path, sr_path)

    logging.debug('Cleaning up source path %s' % source_image_path)
    os.rmdir(source_image_path)

    logging.debug('Cleaning up temporary SR path %s' % temp_vhd_path)
    os.rmdir(temp_vhd_path)
    return ""


def transfer_vhd(session, args):
    """Rsyncs a VHD to an adjacent host"""
    params = pickle.loads(exists(args, 'params'))
    instance_uuid = params['instance_uuid']
    host = params['host']
    vdi_uuid = params['vdi_uuid']
    sr_path = params['sr_path']
    vhd_path = "%s.vhd" % vdi_uuid

    source_path = "%s/%s" % (sr_path, vhd_path)
    dest_path = '%s:/images/instance%s/' % (host, instance_uuid)

    logging.debug("Preparing to transmit %s to %s" % (source_path,
            dest_path))

    ssh_cmd = '\"ssh -o StrictHostKeyChecking=no\"'

    rsync_args = shlex.split('nohup /usr/bin/rsync -av -e %s %s %s'
            % (ssh_cmd, source_path, dest_path))

    logging.debug('rsync %s' % (' '.join(rsync_args, )))

    rsync_proc = subprocess.Popen(rsync_args, stdout=subprocess.PIPE)
    logging.debug('Rsync output: \n %s' % rsync_proc.communicate()[0])
    logging.debug('Rsync return: %d' % rsync_proc.returncode)
    if rsync_proc.returncode != 0:
        raise Exception("Unexpected VHD transfer failure")
    return ""


if __name__ == '__main__':
    XenAPIPlugin.dispatch({'transfer_vhd': transfer_vhd,
            'move_vhds_into_sr': move_vhds_into_sr, })
