Common logic for copying files to containers

    path
        path to the container parent (for LXC only)
        default: /var/lib/lxc (system default)

    CLI Example:

    .. code-block:: bash

        salt myminion container_resource.copy_to mycontainer /local/file/path /container/file/path container_type=docker exec_driver=nsenter

def copy_to(name,
            source,
            dest,
            container_type=None,
            path=None,
            exec_driver=None,
            overwrite=False,
            makedirs=False):
    '''
    Common logic for copying files to containers

    path
        path to the container parent (for LXC only)
        default: /var/lib/lxc (system default)

    CLI Example:

    .. code-block:: bash

        salt myminion container_resource.copy_to mycontainer /local/file/path /container/file/path container_type=docker exec_driver=nsenter
    '''
    # Get the appropriate functions
    state = __salt__['{0}.state'.format(container_type)]

    def run_all(*args, **akwargs):
        akwargs = copy.deepcopy(akwargs)
        if container_type in ['lxc'] and 'path' not in akwargs:
            akwargs['path'] = path
        return __salt__['{0}.run_all'.format(container_type)](
            *args, **akwargs)

    state_kwargs = {}
    cmd_kwargs = {'ignore_retcode': True}
    if container_type in ['lxc']:
        cmd_kwargs['path'] = path
        state_kwargs['path'] = path

    def _state(name):
        if state_kwargs:
            return state(name, **state_kwargs)
        else:
            return state(name)

    c_state = _state(name)
    if c_state != 'running':
        raise CommandExecutionError(
            'Container \'{0}\' is not running'.format(name)
        )

    local_file = cache_file(source)
    source_dir, source_name = os.path.split(local_file)

    # Source file sanity checks
    if not os.path.isabs(local_file):
        raise SaltInvocationError('Source path must be absolute')
    elif not os.path.exists(local_file):
        raise SaltInvocationError(
            'Source file {0} does not exist'.format(local_file)
        )
    elif not os.path.isfile(local_file):
        raise SaltInvocationError('Source must be a regular file')

    # Destination file sanity checks
    if not os.path.isabs(dest):
        raise SaltInvocationError('Destination path must be absolute')
    if run_all(name,
               'test -d {0}'.format(pipes.quote(dest)),
               **cmd_kwargs)['retcode'] == 0:
        # Destination is a directory, full path to dest file will include the
        # basename of the source file.
        dest = os.path.join(dest, source_name)
    else:
        # Destination was not a directory. We will check to see if the parent
        # dir is a directory, and then (if makedirs=True) attempt to create the
        # parent directory.
        dest_dir, dest_name = os.path.split(dest)
        if run_all(name,
                   'test -d {0}'.format(pipes.quote(dest_dir)),
                   **cmd_kwargs)['retcode'] != 0:
            if makedirs:
                result = run_all(name,
                                 'mkdir -p {0}'.format(pipes.quote(dest_dir)),
                                 **cmd_kwargs)
                if result['retcode'] != 0:
                    error = ('Unable to create destination directory {0} in '
                             'container \'{1}\''.format(dest_dir, name))
                    if result['stderr']:
                        error += ': {0}'.format(result['stderr'])
                    raise CommandExecutionError(error)
            else:
                raise SaltInvocationError(
                    'Directory {0} does not exist on {1} container \'{2}\''
                    .format(dest_dir, container_type, name)
                )
    if not overwrite and run_all(name,
                                 'test -e {0}'.format(pipes.quote(dest)),
                                 **cmd_kwargs)['retcode'] == 0:
        raise CommandExecutionError(
            'Destination path {0} already exists. Use overwrite=True to '
            'overwrite it'.format(dest)
        )

    # Before we try to replace the file, compare checksums.
    source_md5 = __salt__['file.get_sum'](local_file, 'md5')
    if source_md5 == _get_md5(name, dest, run_all):
        log.debug('%s and %s:%s are the same file, skipping copy', source, name, dest)
        return True

    log.debug('Copying %s to %s container \'%s\' as %s',
              source, container_type, name, dest)

    # Using cat here instead of opening the file, reading it into memory,
    # and passing it as stdin to run(). This will keep down memory
    # usage for the minion and make the operation run quicker.
    if exec_driver == 'lxc-attach':
        lxcattach = 'lxc-attach'
        if path:
            lxcattach += ' -P {0}'.format(pipes.quote(path))
        copy_cmd = (
            'cat "{0}" | {4} --clear-env --set-var {1} -n {2} -- '
            'tee "{3}"'.format(local_file, PATH, name, dest, lxcattach)
        )
    elif exec_driver == 'nsenter':
        pid = __salt__['{0}.pid'.format(container_type)](name)
        copy_cmd = (
            'cat "{0}" | {1} env -i {2} tee "{3}"'
            .format(local_file, _nsenter(pid), PATH, dest)
        )
    elif exec_driver == 'docker-exec':
        copy_cmd = (
            'cat "{0}" | docker exec -i {1} env -i {2} tee "{3}"'
            .format(local_file, name, PATH, dest)
        )
    __salt__['cmd.run'](copy_cmd, python_shell=True, output_loglevel='quiet')
    return source_md5 == _get_md5(name, dest, run_all)