Put a file into a container

    name :
        Name of the container

    src :
        The source file or directory

    dst :
        The destination file or directory

    recursive :
        Decent into src directory

    overwrite :
        Replace destination if it exists

    mode :
        Set file mode to octal number

    uid :
        Set file uid (owner)

    gid :
        Set file gid (group)

    remote_addr :
        An URL to a remote Server, you also have to give cert and key if
        you provide remote_addr and its a TCP Address!

        Examples:
            https://myserver.lan:8443
            /var/lib/mysocket.sock

    cert :
        PEM Formatted SSL Certificate.

        Examples:
            ~/.config/lxc/client.crt

    key :
        PEM Formatted SSL Key.

        Examples:
            ~/.config/lxc/client.key

    verify_cert : True
        Wherever to verify the cert, this is by default True
        but in the most cases you want to set it off as LXD
        normaly uses self-signed certificates.

    CLI Example:

    .. code-block:: bash

        salt '*' lxd.container_file_put <container name> /var/tmp/foo /var/tmp/

def container_file_put(name, src, dst, recursive=False, overwrite=False,
                       mode=None, uid=None, gid=None, saltenv='base',
                       remote_addr=None,
                       cert=None, key=None, verify_cert=True):
    '''
    Put a file into a container

    name :
        Name of the container

    src :
        The source file or directory

    dst :
        The destination file or directory

    recursive :
        Decent into src directory

    overwrite :
        Replace destination if it exists

    mode :
        Set file mode to octal number

    uid :
        Set file uid (owner)

    gid :
        Set file gid (group)

    remote_addr :
        An URL to a remote Server, you also have to give cert and key if
        you provide remote_addr and its a TCP Address!

        Examples:
            https://myserver.lan:8443
            /var/lib/mysocket.sock

    cert :
        PEM Formatted SSL Certificate.

        Examples:
            ~/.config/lxc/client.crt

    key :
        PEM Formatted SSL Key.

        Examples:
            ~/.config/lxc/client.key

    verify_cert : True
        Wherever to verify the cert, this is by default True
        but in the most cases you want to set it off as LXD
        normaly uses self-signed certificates.

    CLI Example:

    .. code-block:: bash

        salt '*' lxd.container_file_put <container name> /var/tmp/foo /var/tmp/

    '''
    # Possibilities:
    #  (src, dst, dir, dir1, and dir2 are directories)
    #  cp /src/file1 /dst/file1
    #  cp /src/file1 /dst/file2
    #  cp /src/file1 /dst
    #  cp /src/file1 /dst/
    #  cp -r /src/dir /dst/
    #  cp -r /src/dir/ /dst/
    #  cp -r /src/dir1 /dst/dir2 (which is not /src/dir1 /dst/dir2/)
    #  cp -r /src/dir1 /dst/dir2/

    # Fix mode. Salt commandline doesn't use octals, so 0600 will be
    # the decimal integer 600 (and not the octal 0600). So, it it's
    # and integer, handle it as if it where a octal representation.
    mode = six.text_type(mode)
    if not mode.startswith('0'):
        mode = '0{0}'.format(mode)

    container = container_get(
        name, remote_addr, cert, key, verify_cert, _raw=True
    )

    src = os.path.expanduser(src)

    if not os.path.isabs(src):
        if src.find('://') >= 0:
            cached_file = __salt__['cp.cache_file'](src, saltenv=saltenv)
            if not cached_file:
                raise SaltInvocationError("File '{0}' not found".format(src))
            if not os.path.isabs(cached_file):
                raise SaltInvocationError('File path must be absolute.')
            src = cached_file

    # Make sure that src doesn't end with '/', unless it's '/'
    src = src.rstrip(os.path.sep)
    if not src:
        src = os.path.sep

    if not os.path.exists(src):
        raise CommandExecutionError(
            'No such file or directory \'{0}\''.format(src)
        )

    if os.path.isdir(src) and not recursive:
        raise SaltInvocationError(
            ("Cannot copy overwriting a directory "
             "without recursive flag set to true!")
        )

    try:
        dst_is_directory = False
        container.files.get(os.path.join(dst, '.'))
    except pylxd.exceptions.NotFound:
        pass
    except pylxd.exceptions.LXDAPIException as why:
        if six.text_type(why).find('Is a directory') >= 0:
            dst_is_directory = True

    if os.path.isfile(src):
        # Source is a file
        if dst_is_directory:
            dst = os.path.join(dst, os.path.basename(src))
            if not overwrite:
                found = True
                try:
                    container.files.get(os.path.join(dst))
                except pylxd.exceptions.NotFound:
                    found = False
                except pylxd.exceptions.LXDAPIException as why:
                    if six.text_type(why).find('not found') >= 0:
                        # Old version of pylxd
                        found = False
                    else:
                        raise
                if found:
                    raise SaltInvocationError(
                        "Destination exists and overwrite is false"
                    )
        if mode is not None or uid is not None or gid is not None:
            # Need to get file stats
            stat = os.stat(src)
            if mode is None:
                mode = oct(stat.st_mode)
            if uid is None:
                uid = stat.st_uid
            if gid is None:
                gid = stat.st_gid

        with salt.utils.files.fopen(src, 'rb') as src_fp:
            container.files.put(
                dst, src_fp.read(),
                mode=mode, uid=uid, gid=gid
            )
        return True
    elif not os.path.isdir(src):
        raise SaltInvocationError(
            "Source is neither file nor directory"
        )

    # Source is a directory
    # idx for dstdir = dst + src[idx:]
    if dst.endswith(os.sep):
        idx = len(os.path.dirname(src))
    elif dst_is_directory:
        idx = len(src)
    else:
        # Destination is not a directory and doesn't end with '/'
        # Check that the parent directory of dst exists
        # and is a directory
        try:
            container.files.get(os.path.join(os.path.dirname(dst), '.'))
        except pylxd.exceptions.NotFound:
            pass
        except pylxd.exceptions.LXDAPIException as why:
            if six.text_type(why).find('Is a directory') >= 0:
                dst_is_directory = True
                # destination is non-existent
                # cp -r /src/dir1 /scr/dir1
                # cp -r /src/dir1 /scr/dir2
                idx = len(src)
                overwrite = True

    # Copy src directory recursive
    if not overwrite:
        raise SaltInvocationError(
            "Destination exists and overwrite is false"
        )

    # Collect all directories first, to create them in one call
    # (for performance reasons)
    dstdirs = []
    for path, _, files in os.walk(src):
        dstdir = os.path.join(dst, path[idx:].lstrip(os.path.sep))
        dstdirs.append(dstdir)
    container.execute(['mkdir', '-p'] + dstdirs)

    set_mode = mode
    set_uid = uid
    set_gid = gid
    # Now transfer the files
    for path, _, files in os.walk(src):
        dstdir = os.path.join(dst, path[idx:].lstrip(os.path.sep))
        for name in files:
            src_name = os.path.join(path, name)
            dst_name = os.path.join(dstdir, name)

            if mode is not None or uid is not None or gid is not None:
                # Need to get file stats
                stat = os.stat(src_name)
                if mode is None:
                    set_mode = oct(stat.st_mode)
                if uid is None:
                    set_uid = stat.st_uid
                if gid is None:
                    set_gid = stat.st_gid

            with salt.utils.files.fopen(src_name, 'rb') as src_fp:
                container.files.put(
                    dst_name, src_fp.read(),
                    mode=set_mode, uid=set_uid, gid=set_gid
                )

    return True