From 3ad63953e8177727ebd08b0539f8971c43d7ff3a Mon Sep 17 00:00:00 2001 From: Giovanni Torres Date: Wed, 1 Nov 2017 11:29:35 -0400 Subject: [PATCH] Updated to use subcommands. - Now uses create|remove|list|help subcommands - "main" is now just one case statement - Updated README - Updated tests --- README.md | 42 ++--- kvm-install-vm | 345 +++++++++++++++++++++++++-------------- tests/check_options.bats | 6 +- 3 files changed, 250 insertions(+), 143 deletions(-) diff --git a/README.md b/README.md index 5dc9bbd..7d1b9e0 100644 --- a/README.md +++ b/README.md @@ -35,23 +35,33 @@ information. ### Usage ``` +$ kvm-install-vm help NAME kvm-install-vm - Install virtual guests using cloud-init on a local KVM hypervisor. SYNOPSIS - ./kvm-install-vm [OPTIONS] -n|-r vmname + kvm-install-vm COMMAND [OPTIONS] DESCRIPTION A bash wrapper around virt-install to build virtual machines on a local KVM hypervisor. You can run it as a normal user which will use qemu:///session to connect locally to your KVM domains. -MANDATORY ARGUMENTS - You must specify one of the following arguments to either create or delete - a VM: - -n vmname Name of VM to create - -r vmname Name of VM to delete +COMMANDS + help - show this help or help for a subcommand + create - create a new guest domain + list - list all domains, running and stopped + remove - delete a guest domain +``` + +``` +$ kvm-install-vm help create +NAME + kvm-install-vm create [OPTIONS] VMNAME + +DESCRIPTION + Create a new guest domain. OPTIONS -b Bridge (default: virbr0) @@ -60,14 +70,13 @@ OPTIONS -f CPU Model / Feature (default: host) -h Display help -i Custom QCOW2 Image - -k SSH Public Key (default: $HOME/.ssh/id_rsa.pub) - -l Location of Images (default: $HOME/virt/images) + -k SSH Public Key (default: /home/torresgi/.ssh/id_rsa.pub) + -l Location of Images (default: /home/torresgi/virt/images) -m Memory Size (MB) (default: 1024) -M mac Mac address (default: auto-assigned) -t Linux Distribution (default: centos7) -T Timezone (default: US/Eastern) - DISTRIBUTIONS NAME DESCRIPTION LOGIN centos7 CentOS 7 centos @@ -79,26 +88,21 @@ DISTRIBUTIONS ubuntu1604 Ubuntu 16.04 LTS (Xenial Xerus) ubuntu EXAMPLES - ./kvm-install-vm -n foo + kvm-install-vm create foo Create VM with the default parameters: CentOS 7, 1 vCPU, 1GB RAM, 10GB disk capacity. - ./kvm-install-vm -c 2 -m 2048 -d 20 -n foo + kvm-install-vm create -c 2 -m 2048 -d 20 foo Create VM with custom parameters: 2 vCPUs, 2GB RAM, and 20GB disk capacity. - ./kvm-install-vm -t debian9 -n foo + kvm-install-vm create -t debian9 foo Create a Debian 9 VM with the default parameters. - ./kvm-install-vm -r foo - Remove (destroy and undefine) a VM. WARNING: This will delete all - customizations in the VM! + kvm-install-vm create -T UTC foo + Create a default VM with UTC timezone. ``` -### Example - -[![asciicast](https://asciinema.org/a/bVgjJ3SHgvROX90iRuCCF1h4d.png)](https://asciinema.org/a/bVgjJ3SHgvROX90iRuCCF1h4d) - ### Notes 1. This script will download a qcow2 cloud image from the respective diff --git a/kvm-install-vm b/kvm-install-vm index 1704495..95d7d2f 100755 --- a/kvm-install-vm +++ b/kvm-install-vm @@ -11,18 +11,32 @@ NAME hypervisor. SYNOPSIS - $prog [OPTIONS] -n|-r vmname + $prog COMMAND [OPTIONS] DESCRIPTION A bash wrapper around virt-install to build virtual machines on a local KVM hypervisor. You can run it as a normal user which will use qemu:///session to connect locally to your KVM domains. -MANDATORY ARGUMENTS - You must specify one of the following arguments to either create or delete - a VM: - -n vmname Name of VM to create - -r vmname Name of VM to delete +COMMANDS + help - show this help or help for a subcommand + create - create a new guest domain + list - list all domains, running and stopped + remove - delete a guest domain + +EOF +} + +function usage_subcommand () +{ + case "$1" in + create) + cat << EOF +NAME + $prog create [OPTIONS] VMNAME + +DESCRIPTION + Create a new guest domain. OPTIONS -b Bridge (default: virbr0) @@ -49,24 +63,51 @@ DISTRIBUTIONS ubuntu1604 Ubuntu 16.04 LTS (Xenial Xerus) ubuntu EXAMPLES - $prog -n foo + $prog create foo Create VM with the default parameters: CentOS 7, 1 vCPU, 1GB RAM, 10GB disk capacity. - $prog -c 2 -m 2048 -d 20 -n foo + $prog create -c 2 -m 2048 -d 20 foo Create VM with custom parameters: 2 vCPUs, 2GB RAM, and 20GB disk capacity. - $prog -t debian9 -n foo + $prog create -t debian9 foo Create a Debian 9 VM with the default parameters. - $prog -T UTC -n foo + $prog create -T UTC foo Create a default VM with UTC timezone. - $prog -r foo - Remove (destroy and undefine) a VM. WARNING: This will delete the VM - from disk, erasing all your customizations! EOF + ;; + remove) + cat << EOF +NAME + $prog remove VMNAME + +DESCRIPTION + Destroys (stops) and undefines a guest domain. This also remove the + associated storage pool. + +EXAMPLE + $prog remove foo + Remove (destroy and undefine) a guest domain. WARNING: This will + delete the guest domain and any changes made inside it! +EOF + ;; + list) + cat << EOF +NAME + $prog list + +DESCRIPTION + Lists all running and stopped guest domains. +EOF + ;; + *) + printf "'$subcommand' is not a valid subcommand.\n" + exit 1 + ;; + esac } # Detect OS and set wget parameters @@ -211,10 +252,22 @@ function storpool_exists () function get_pkg_mgr () { case "${DISTRO}" in - centos? ) PKGMGR="yum" ;; - fedora?? ) PKGMGR="dnf" ;; - ubuntu*|debian? ) PKGMGR="apt-get" ;; - *) PKGMGR= ;; + centos? ) + PKGMGR="yum" + SUDOGROUP="wheel" + ;; + fedora?? ) + PKGMGR="dnf" + SUDOGROUP="wheel" + ;; + ubuntu*|debian? ) + PKGMGR="apt-get" + SUDOGROUP="sudo" + ;; + *) + PKGMGR= + SUDOGROUP= + ;; esac } @@ -381,112 +434,162 @@ _EOF_ popd > /dev/null } -#-------------------------------------------------- -# Main -#-------------------------------------------------- +# Delete VM +function remove () +{ + if [ "$#" != 1 ] + then + printf "Too many arguments.\n" + printf "Run '$prog help remove' for usage.\n" + exit 1 + else + # Check if domain exists and set DOMAIN_EXISTS variable. + domain_exists "${1}" -# Defaults are set here. Override using command line arguments. -CPUS=1 # Number of virtual CPUs -FEATURE=host # Use host cpu features to the guest -MEMORY=1024 # Amount of RAM in MB -DISK_SIZE=10 # Disk Size in GB -RESIZE_DISK=false # Resize disk (boolean) -IMAGEDIR=${HOME}/virt/images # Directory to store images -BRIDGE=virbr0 # Hypervisor bridge -PUBKEY=${HOME}/.ssh/id_rsa.pub # SSH public key -DISTRO=centos7 # Distribution -MACADDRESS= # MAC Address -TIMEZONE=US/Eastern # Timezone - -# Reset OPTIND -OPTIND=1 - -# Parse command line arguments -while getopts ":b:c:d:f:i:k:l:m:M:n:r:t:T:h" opt -do - case "$opt" in - b ) BRIDGE="${OPTARG}" ;; - c ) CPUS="${OPTARG}" ;; - d ) - if [ "${OPTARG}" -gt ${DISK_SIZE} ]; then - DISK_SIZE="${OPTARG}G" - RESIZE_DISK=true - else - DISK_SIZE="${DISK_SIZE}G" - fi - ;; - f ) FEATURE="${OPTARG}" ;; - i ) IMAGE="${OPTARG}" ;; - k ) PUBKEY="${OPTARG}" ;; - l ) IMAGEDIR="${OPTARG}" ;; - m ) MEMORY="${OPTARG}" ;; - M ) MACADDRESS="${OPTARG}" ;; - n ) VMNAME="${OPTARG}" ;; - r ) VMDEL="${OPTARG}" ;; - t ) DISTRO="${OPTARG}" ;; - T ) TIMEZONE="${OPTARG}" ;; - h|* ) usage; exit 1 ;; - esac -done - -shift $((OPTIND-1)) - -# cloud-init variables -USER_DATA=user-data -META_DATA=meta-data -CI_ISO=${VMNAME}-cidata.iso - -# Can't specify both -n and -r together -if [ ! -z "${VMNAME+x}" ] && [ ! -z "${VMDEL+x}" ] -then - echo "-n and -r are mutually exclusive." - exit 2 -fi - -# Delete VM if -r is set -if [ ! -z "${VMDEL+x}" ] -then - domain_exists "${VMDEL}" - storpool_exists "${VMDEL}" - delete_vm "${VMDEL}" - exit 0 -fi - -# VMNAME must be set -if [ -z "${VMNAME+x}" ] -then - echo "You must specify a name for the VM with -n. Use -h to see usage." - exit 2 -fi - -# Check for ssh key -check_ssh_key - -if [ ! -z "${IMAGE+x}" ] -then - echo "[$(date +%r)]----> Using custom QCOW2 image: ${IMAGE}." - OS_VARIANT="auto" - LOGIN_USER="" -else - fetch_images -fi - -# Check if domain already exists -domain_exists "${VMNAME}" - -if [ "${DOMAIN_EXISTS}" -eq 1 ]; then - echo -n "[WARNING] ${VMNAME} already exists. " - read -p "Do you want to overwrite ${VMNAME} [y/N]? " -r - if [[ $REPLY =~ ^[Yy]$ ]]; then - delete_vm ${VMNAME} + # Check if storage pool exists and set STORPOOL_EXISTS variable. + storpool_exists "${1}" + + delete_vm "${1}" + exit 0 + fi +} + +function help_func () +{ + : +} + +function set_defaults () +{ + # Defaults are set here. Override using command line arguments. + CPUS=1 # Number of virtual CPUs + FEATURE=host # Use host cpu features to the guest + MEMORY=1024 # Amount of RAM in MB + DISK_SIZE=10 # Disk Size in GB + RESIZE_DISK=false # Resize disk (boolean) + IMAGEDIR=${HOME}/virt/images # Directory to store images + BRIDGE=virbr0 # Hypervisor bridge + PUBKEY=${HOME}/.ssh/id_rsa.pub # SSH public key + DISTRO=centos7 # Distribution + MACADDRESS= # MAC Address + TIMEZONE=US/Eastern # Timezone + + # Reset OPTIND + OPTIND=1 +} + +function create () +{ + # Set default variables + set_defaults + + # Parse command line arguments + while getopts ":b:c:d:f:i:k:l:m:M:t:T:h" opt + do + case "$opt" in + b ) BRIDGE="${OPTARG}" ;; + c ) CPUS="${OPTARG}" ;; + d ) + if [ "${OPTARG}" -gt ${DISK_SIZE} ]; then + DISK_SIZE="${OPTARG}G" + RESIZE_DISK=true + else + DISK_SIZE="${DISK_SIZE}G" + fi + ;; + f ) FEATURE="${OPTARG}" ;; + i ) IMAGE="${OPTARG}" ;; + k ) PUBKEY="${OPTARG}" ;; + l ) IMAGEDIR="${OPTARG}" ;; + m ) MEMORY="${OPTARG}" ;; + M ) MACADDRESS="${OPTARG}" ;; + t ) DISTRO="${OPTARG}" ;; + T ) TIMEZONE="${OPTARG}" ;; + h|* ) usage; exit 1 ;; + esac + done + + shift $((OPTIND - 1)) + + if [ "$#" != 1 ] + then + printf "Too many options.\n" else - echo -e "\nNot overwriting ${VMNAME}. Exiting..." - exit 1 + VMNAME=$1 fi -fi -# Set package manager -get_pkg_mgr + # Set cloud-init variables after VMNAME is assigned + USER_DATA=user-data + META_DATA=meta-data + CI_ISO=${VMNAME}-cidata.iso + + # Check for ssh key + check_ssh_key + + if [ ! -z "${IMAGE+x}" ] + then + echo "[$(date +%r)]----> Using custom QCOW2 image: ${IMAGE}." + OS_VARIANT="auto" + LOGIN_USER="" + else + fetch_images + fi -# Finally, create requested VM -create_vm + # Check if domain already exists + domain_exists "${VMNAME}" + + if [ "${DOMAIN_EXISTS}" -eq 1 ]; then + echo -n "[WARNING] ${VMNAME} already exists. " + read -p "Do you want to overwrite ${VMNAME} [y/N]? " -r + if [[ $REPLY =~ ^[Yy]$ ]]; then + delete_vm ${VMNAME} + else + echo -e "\nNot overwriting ${VMNAME}. Exiting..." + exit 1 + fi + fi + + # Set package manager + get_pkg_mgr + + # Finally, create requested VM + create_vm +} + +#-------------------------------------------------- +# Main +#-------------------------------------------------- + +subcommand="${1:-none}" +[[ "${subcommand}" != "none" ]] && shift + +case "${subcommand}" in + none) + usage + exit 1 + ;; + help) + if [[ "${1:-none}" == "none" ]]; then + usage + elif [[ "$1" =~ ^create$|^remove$|^list$ ]]; then + usage_subcommand "$1" + else + printf "'$1' is not a valid subcommand.\n\n" + usage + exit 1 + fi + exit 0 + ;; + list) + virsh list --all + exit 0 + ;; + create|remove) + "${subcommand}" "$@" + exit $? + ;; + *) + echo "not valid" + exit 1 + ;; +esac diff --git a/tests/check_options.bats b/tests/check_options.bats index b88d9c4..63a5587 100644 --- a/tests/check_options.bats +++ b/tests/check_options.bats @@ -2,11 +2,11 @@ @test "Check for help usage message" { run kvm-install-vm - [ "$output" = "You must specify a name for the VM with -n. Use -h to see usage." ] + [[ "$output" =~ "NAME" ]] } @test "Install VM - batstestvm" { - run bash -c "kvm-install-vm -n batstestvm" + run bash -c "kvm-install-vm create batstestvm" [ "$status" -eq 0 ] } @@ -16,7 +16,7 @@ } @test "Delete VM - batstestvm" { - run bash -c "kvm-install-vm -r batstestvm" + run bash -c "kvm-install-vm remove batstestvm" [ "$status" -eq 0 ] }