# This script include functions that allow guest image files customization
# before uploading them to OpenStack image service

# ensure we don't re-source this in the same environment
[[ -z "$_NEUTRON_TEMPEST_PLUGIN_CUSTOMIZE_IMAGE" ]] || return 0
declare -r -g _NEUTRON_TEMPEST_PLUGIN_CUSTOMIZE_IMAGE=1

source "${NEUTRON_TEMPEST_PLUGIN_DIR}/functions.sh"

# By default enable guest image customization. It will be automatically skipped
# for cirros images
CUSTOMIZE_IMAGE=${CUSTOMIZE_IMAGE:-False}

# Image customization is performed using virt-customize
# using direct backend by default
LIBGUESTFS_BACKEND=${LIBGUESTFS_BACKEND:-direct}

# Disable KVM hardware accelleration by default
LIBGUESTFS_BACKEND_SETTINGS=${LIBGUESTFS_BACKEND_SETTINGS:-force_tcg}

# Install tools required for customizing guest image files
function install_customize_image_tools {
    local do_customize=$(trueorfalse True CUSTOMIZE_IMAGE)
    if [ ${do_customize} == True ]; then
        # Make sure virt-customize is installed
        install_package libguestfs-tools
    fi
}

# Wraps upload_image function to eventually customize image file before
# uploading it via "openstack image create" command
save_function upload_image overridden_upload_image
function upload_image {
    local image_url=$1

    # Fork a subshell to have environment restored at the end of this function
    (
        # Check user configuration
        local customize_image=$(trueorfalse True CUSTOMIZE_IMAGE)
        if [ ${customize_image} == True ]; then
            # Temporarly wraps openstack command with openstack_image_create
            # function
            function openstack {
                IMAGE_URL=${image_url} upload_custom_image "$@"
            }
        fi

        # Execute original upload_image function
        overridden_upload_image "$@"
    )
}

# Wraps "openstack image create" command to customize image file before
# uploading it to OpenstackImage service.
# Called only when ${CUSTOMIZE_IMAGE} is True
function upload_custom_image {
    # Copy command arguments for later use
    local args=( "$@" )

    # Look for image create sub-command:
    # skip any argument before "image" and "create" words
    local i=0
    local subcommands=()
    for subcommand in image create; do
        for (( ; i < ${#args[@]}; )) {
            local arg=${args[i]}
            (( ++i ))
            if [ "${arg}" == "${subcommand}" ]; then
                subcommands+=( "${arg}" )
                break
            fi
        }
    done

    if [ "${subcommands[*]}" == "image create" ]; then
        # create image subcommand has been detected

        # Put here temporary files to be delete before exiting from this
        # function
        local temp_dir=$(mktemp -d)
        chmod 777 "${temp_dir}"

        # Parse openstack image create subcommand arguments
        local image_url="${IMAGE_URL}"
        local image_file=
        local disk_format=auto
        local container_format=bare

        for (( ; i < ${#args[@]}; )) {
            local arg=${args[$i]}
            (( ++i ))

            if [[ "${arg}" == --* ]]; then
                # Handle --<option_name>=<option_value> syntax
                local option_fields=(${arg//=/ })
                local option_name=${option_fields[0]}
                local option_value=${option_fields[1]:-}

                case "${option_name}" in

                    --container-format)  # Found container format
                        container_format=${option_value:-${args[ (( i++ )) ]}}
                        ;;

                    --disk-format)  # Found disk format
                        disk_format=${option_value:-${args[ (( i++ )) ]}}
                        ;;

                   --file)  # Found image file name
                        image_file=${option_value:-${args[ (( i++ )) ]}}
                        ;;
                esac
            fi
        }

        if [ "${image_file}" == "" ]; then
            # Copy image file from stdin to a temporary file
            image_file=${temp_dir}/$(basename "${image_url}")
            cat > "${image_file}"

            # Add option to load image from file
            args+=( --file "${image_file}" )
        fi

        # Make image file readable and writable by qemu user
        sudo chmod 666 "${image_file}"

        # Customize image file
        TEMP_DIR=${temp_dir} \
            DISK_FORMAT=${disk_format} \
            customize_image "${image_file}"
    fi

    # Upload custom image file
    overridden_openstack "${args[@]}" || local error=$?

    # Finally delete temporary files
    sudo rm -fR "${temp_dir}" || true

    return ${error:-0}
}

function overridden_openstack {
    "$(which openstack)" "$@"
}

# Execute customization commands on a VM with attached guest image file.
# Called only when ${CUSTOMIZE_IMAGE} is True
function customize_image {
    local image_file=$1
    local top_dir=$(dirname "${NEUTRON_TEMPEST_PLUGIN_DIR}")
    install_customize_image_tools
    (
        export TEMP_DIR DISK_FORMAT RC_DIR
        if [[ "$(basename ${image_file})" == ubuntu-* ]]; then
            "${top_dir}/tools/customize_ubuntu_image" "${image_file}"
        fi
    )
}
