#!/bin/bash # This function help to convert measures Bytes to/from Bits # Usage: [K|M|G|T]Byte|bit [K|M|G|T]Byte|bit function _convert_bit { echo $1 $2 | awk -F ' ' ' { # Manage arguments: in ################### i_number=gensub(/^([0-9]+(.[0-9]+)?)([kgmtKMGT]?)(.*)$/, "\\1", "g", $1); i_factor=gensub(/^([0-9]+(.[0-9]+)?)([kgmtKMGT]?)(.*)$/, "\\3", "g", $1); i_unit=gensub(/^([0-9]+(.[0-9]+)?)([kgmtKMGT]?)(.*)$/, "\\4", "g", $1); # Manage arguments: out ################### o_factor=gensub(/^([kgmtKMGT]?)(.*)$/, "\\1", "g", $2); o_unit=gensub(/^([kgmtKMGT]?)(.*)$/, "\\2", "g", $2); # Replace factor: in ################### switch (toupper(i_factor)) { case "K": i_number=i_number * 1024 ; break case "M": i_number=i_number * (1024 ^ 2 ) ; break case "G": i_number=i_number * (1024 ^ 3 ) ; break case "T": i_number=i_number * (1024 ^ 4 ) ; break } # Convert Bytes to Bits if necessary: in ################### if ( i_unit ~ /^B$|^[Bb]ytes?$/ || i_unit ~ /^[Oo](ctets?)?$/ ) i_number = i_number * 8; else if ( i_unit ~ /^$/ || i_unit ~ /^(b|[b|B]its?)$/ ) {} else { print "Error: " $1 " is not a valid argument."; exit 1 } # Remove factor: out ################### switch (toupper(o_factor)) { case "K": i_number=i_number / 1024 ; break case "M": i_number=i_number / (1024 ^ 2 ) ; break case "G": i_number=i_number / (1024 ^ 3 ) ; break case "T": i_number=i_number / (1024 ^ 4 ) ; break } # Convert Bits to Bytes if necessary: out ################### if ( o_unit ~ /^B$|^[Bb]ytes?$/ || o_unit ~ /^[Oo](ctets?)?$/ ) { print i_number / 8 } else if ( o_unit ~ /^$/ || o_unit ~ /^(b|[b|B]its?)$/ ) { print i_number } else { print "Error: " o_unit " is not a valid argument."; exit 1 } }' } # This function helps to colorize console output _shell_color () { # Easy RED='\033[31m' GREEN='\033[32m' YELLOW='\033[33m' BLUE='\033[34m' PURPLE='\033[35m' CYAN='\033[36m' WHITE='\033[37m' NIL='\033[00m' } # This function display an error and quit function _crit { local RC=$1 shift 1 local MSG=$@ _log crit "$MSG" exit $RC } # This function display log messages function _log { # Init local CODE=${1,,} shift 1 local MSG=$@ local COLOR="" # Detect level case $CODE in 0|emerg) CODE="emerg" COLOR=${RED} ;; 1|alert) CODE="alert" COLOR=${RED} ;; 2|crit) CODE="crit" COLOR=${RED} ;; 3|error|err) CODE="error" COLOR=${RED} ;; 4|warning|warn) CODE="warn" COLOR=${YELLOW} ;; 5|notice) CODE="notice" COLOR=${GREEN} ;; 6|info) CODE="info" COLOR=${CYAN} ;; 7|debug|*) CODE="debug" COLOR=${BLUE} ;; esac # Display message echo $CODE | grep -E "$LOG_LEVEL" >/dev/null ; local RC=$? if [ $RC -eq 0 ]; then printf "${COLOR}%-6s: %s${NIL}\n" "${CODE^^}" "$MSG" fi } function _help { echo "Aide: " } # Usage: # bin [-f] [-s ] [-t ] src_template dst_disk # -f : force # -s 15G : size # -t qcow|qcow2|raw : type of image # -c (compress) # -p (show progress) # -i/-o # #convert [-c] [-p] [-q] [-n] [-f fmt] [-t cache] [-T src_cache] [-O output_fmt] [-o options] [-s snapshot_id_or_name] [-l snapshot_param] [-S sparse_size] filename [filename2 [...]] output_filename # This function will create the volume instances function virt_disk_template { # Define default variables ################ local DISK_SRC= local DISK_DEST= local DISK_DEST_SIZE=0 local DISK_TYPE=qcow2 local DISK_COMPRESS=0 local DISK_PROGRESS=0 local DISK_FORCE=0 local DISK_HELP=0 local QEMU_IMG_BIN="$(whereis -b qemu-img | cut -d ' ' -f 2)" local QEMU_IMG_OPT="" # Get options ################ unset OPTIND while getopts o:i:t:s:fcp flag; do case $flag in # Required variables o) DISK_DEST=${OPTARG} ;; i) DISK_SRC=${OPTARG} ;; t) DISK_TYPE=${OPTARG} ;; s) DISK_DEST_SIZE="${OPTARG}" ;; f) DISK_FORCE=1 ;; c) DISK_COMPRESS=1 ;; p) DISK_PROGRESS=1 ;; *) _crit 1 "Argument $flag is not valid" esac done shift $(( OPTIND - 1 )); # Check the file i/o ################ if [[ -z "${DISK_SRC}" || ! -f "${DISK_SRC}" ]]; then _crit 1 "Source image $DISK_SRC is not valid" fi if [[ -z "${DISK_DEST}" ]]; then _crit 1 "Destination image is empty" fi # Get the template size (in G) ################ # get the size in BYTES ! local DISK_SRC_SIZE=$( qemu-img info ${DISK_SRC} \ | grep "virtual size" \ | awk '{ print gensub( /.*\((.*)bytes\)$/ , "\\1", "g" ) }' ) if [ -z "$DISK_SRC_SIZE" ]; then _log error "The output of qemu-img info ${DISK_SRC} may not return size in Gb?" _crit 1 "Impossible to get the disk template size" fi # Define options ################ if [ ${DISK_COMPRESS} -eq 1 ]; then QEMU_IMG_OPT="${QEMU_IMG_OPT} -c" fi if [ ${DISK_PROGRESS} -eq 1 ]; then QEMU_IMG_OPT="${QEMU_IMG_OPT} -p" fi # Set the final disk size ################ DISK_DEST_SIZE=$(_convert_bit ${DISK_DEST_SIZE} bit); RC=$? if [ $RC -ne 0 ]; then _crit 1 "Requested size for disk ${DISK_DEST} is not valid: ${DISK_DEST_SIZE}" else if [[ "${DISK_DEST_SIZE}" -ne 0 && "${DISK_DEST_SIZE}" -lt "${DISK_SRC_SIZE}" ]]; then _log warn "Requested disk size for ${DISK_DEST} is lesser than template. Disk size set to $( _convert_bit ${DISK_SRC_SIZE} Gb)Gb" else QEMU_IMG_OPT="${QEMU_IMG_OPT} -S ${DISK_DEST_SIZE}" fi fi # Create the disk ################ if [ "$DISK_TYPE" == "qcow2" ]; then # Check if the destination exists and is writable if [[ $DISK_FORCE -ne 1 && -f "$DISK_DEST" ]]; then _crit 1 "The destination file already exists: $DISK_DEST" else _log info "The VM disk will be created in $DISK_DEST" fi # Create disk local CMD="qemu-img convert \ ${QEMU_IMG_OPT} \ -O qcow2 \ ${DISK_SRC} ${DISK_DEST}" _log DEBUG "$CMD" $CMD fi } if [[ -z "${@}" || "${1}" =~ ^--?h(elp)?$ ]]; then _help else virt_disk_template $@ fi