|
| 1 | +#!/bin/sh |
| 2 | + |
| 3 | +# Check if hypervisor is installed |
| 4 | +if [ -z "$(which virsh)" ] |
| 5 | +then |
| 6 | + echo "libvirt is not installed." |
| 7 | + exit 1 |
| 8 | +# Check if running as root or privileged user |
| 9 | +elif [ -z "$(groups | tr ' ' '\n' | grep libvirt)" ] && [ "$EUID" -ne 0 ] |
| 10 | +then |
| 11 | + echo "Please run as root or user under 'libvirt' group." |
| 12 | + exit 2 |
| 13 | +fi |
| 14 | + |
| 15 | +# Set pool to default path |
| 16 | +if [ -z "${IMAGE_POOL}" ] |
| 17 | +then |
| 18 | + if [ "$EUID" -ne 0 ] |
| 19 | + then |
| 20 | + echo "Please run as root." |
| 21 | + exit 2 |
| 22 | + fi |
| 23 | + IMAGE_POOL=$(virsh pool-dumpxml default | awk -F'[<>]' '/path/ {print $3}') |
| 24 | +fi |
| 25 | + |
| 26 | +# Variables |
| 27 | +base_dir=$(dirname $0) |
| 28 | +vm_name=$1 |
| 29 | +image_uri=$2 |
| 30 | +new_dev=$3 |
| 31 | + |
| 32 | +# Read in array of current VMs |
| 33 | +read -r -a vms <<< "$(virsh list --name --all | tr '\n' ' ')" |
| 34 | + |
| 35 | +# Find specified VM |
| 36 | +vm_found=0 |
| 37 | +for vm in ${vms[@]} |
| 38 | +do |
| 39 | + if [ "${vm}" == "${vm_name}" ] |
| 40 | + then |
| 41 | + vm_found=1 |
| 42 | + break |
| 43 | + fi |
| 44 | +done |
| 45 | + |
| 46 | +# Throw error if specified VM is not found |
| 47 | +if [[ $vm_found -ne 1 ]] |
| 48 | +then |
| 49 | + echo "'${vm_name}' does not exist." |
| 50 | + exit 3 |
| 51 | +fi |
| 52 | + |
| 53 | +# Select target bus based on target device name, error if |
| 54 | +# device name prefix does not match a compatible bus. |
| 55 | +if [[ $new_dev = vd* ]] |
| 56 | +then |
| 57 | + targetbus=virtio |
| 58 | +elif [[ $new_dev = sd* ]] |
| 59 | +then |
| 60 | + targetbus=sata |
| 61 | +else |
| 62 | + echo "dev prefix '${new_dev:0:2}' is not valid." |
| 63 | + exit 4 |
| 64 | +fi |
| 65 | + |
| 66 | +# If uri to disk image is a local path append the file:// to uri (if not already there) |
| 67 | +if [[ ! $image_uri = http://* ]] && [[ ! $image_uri = https://* ]] && [[ ! $image_uri = file://* ]] |
| 68 | +then |
| 69 | + image_uri=$([[ $image_uri = /* ]] && echo "file://${image_uri}" || echo "file://${PWD}/${image_uri}") |
| 70 | +fi |
| 71 | + |
| 72 | +# Read all devices with same prefix as specified name for the new device |
| 73 | +read -r -a existing_dev <<< "$(virsh domblklist ${vm_name} | awk '{print $1}' | grep -e ${new_dev:0:2} | tr '\n' ' ')" |
| 74 | + |
| 75 | +# Check if specified device name match any existing ones, if so throw error to user |
| 76 | +for dev in ${existing_dev[@]} |
| 77 | +do |
| 78 | + if [ "${dev}" == "${new_dev}" ] |
| 79 | + then |
| 80 | + echo "'${new_dev}' already exists, please specific disk target labeled past '${existing_dev[-1]}'." |
| 81 | + exit 5 |
| 82 | + fi |
| 83 | +done |
| 84 | + |
| 85 | +# Make image path, /path/to/pool/{vm-name}_{random-hash-string}.qcow2 |
| 86 | +disk_path=${IMAGE_POOL}/${vm_name}_$(echo ${RANDOM} | md5sum | head -c 15; echo;).qcow2 |
| 87 | + |
| 88 | +# If disk path exists, regenerate a new until it does not exist |
| 89 | +while [ -f $disk_path ] |
| 90 | +do |
| 91 | + disk_path=${IMAGE_POOL}/${vm_name}_$(echo ${RANDOM} | md5sum | head -c 15; echo;).qcow2 |
| 92 | +done |
| 93 | + |
| 94 | +# Download / Copy template disk image from uri to disk path |
| 95 | +curl -L $image_uri -o $disk_path |
| 96 | + |
| 97 | +# Attach disk at disk path to the vm specified |
| 98 | +virsh attach-disk $vm_name $disk_path $new_dev --persistent --driver=qemu --subdriver=qcow2 --targetbus=$targetbus |
0 commit comments