diff options
| author | mail_redacted_for_web | 2018-07-09 18:13:03 +0200 | 
|---|---|---|
| committer | mail_redacted_for_web | 2018-07-09 18:13:03 +0200 | 
| commit | 8682d695ed430956752a000de79674261b63f19f (patch) | |
| tree | d81305f969800abe5369a5a23ea47b828b79b7e9 | |
| parent | acedee054e3427880b10b0537f971b8eec9f99e5 (diff) | |
| download | systemd-units-8682d695ed430956752a000de79674261b63f19f.tar.bz2 | |
Initial commit of kvm core script
| -rwxr-xr-x | usr/local/bin/kvmhelper | 215 | 
1 files changed, 215 insertions, 0 deletions
| diff --git a/usr/local/bin/kvmhelper b/usr/local/bin/kvmhelper new file mode 100755 index 0000000..e24e6f5 --- /dev/null +++ b/usr/local/bin/kvmhelper @@ -0,0 +1,215 @@ +#!/bin/env bash + +# Script starts or stops KVM machines or networks in your environment through virsh. +# I.e. your environment must be set up already so you +# - either are able to administer the system's KVM environment (qemu:///system), or +# - have your environment variables set up so you aim at the right KVM environment +# +# Future versions may explicitly ask for the QEMU URI variable and default to qemu:///system, but for +# now we take this for granted that virsh works right for you without specific connection parameters. +# +# The maximum time in seconds to wait for the net-* commands to be successful: +KHNTWAIT=10 +# The maximum time in seconds to wait for the machine commands to be successful: +KHVMWAIT=60 +# The interval in seconds a network should be polled for status change when executing a start/shutdown - +# while it is called *NT*, this will also be used for starting a VM: +KHNTIVAL="5" +# The interval in seconds a VM should be polled for status change when executing a shutdown: +KHVMIVAL="10" + +##### SCRIPT FROM HERE ##### + + +export SHUDDUP=0 +prsopt=$(getopt -n "$0" -o q -- "$@") +eval "set -- $prsopt" +while [ "$#" -gt 0 ];do +	case "$1" in +		(-q) SHUDDUP=1;shift;; +		(--) shift;break;; +		(*) exit 1;; +	esac +done + +RETVAL=0 +KHCMD="$1" +shift +KHTARGS=( "$@" ) +declare -x INFOCMD STARTCMD STOPCMD ACTGREP ACTYES ACTNO KILLCMD QWAIT QSTATE +export QLISTNPARMS=( "--name" "--all" ) + +command -V virsh >/dev/null||exit 255 +command -V tput >/dev/null||exit 255 + +kh_help() { +	[ "$SHUDDUP" -eq 1 ]&&return +	echo -n "USAGE: $(basename "$0") vm-start|vm-stop|net-start|net-stop" +	echo " VMNAME|NETNAME [VMNAME|NETNAME ...]" +} + +case "$KHCMD" in +	"net-start"|"net-stop"|"vm-start"|"vm-stop") +		[ "${#KHTARGS[@]}" -eq 0 ]&&echo "Please specify a target."&&kh_help&&exit 127 +	;; +	"") +		echo "Please specify a command." +		kh_help +		exit 127 +	;; +	*) +		echo "$KHCMD is not a valid command." >&2 +		kh_help +		exit 127 +	;; +esac + +kh_status() { +	# Function should be called with exit status of stop/start command or +	# "start name"/"stop name" for the initial message. +	case "$1" in +		"start") +			[ "$SHUDDUP" -eq 0 ]&&echo -ne "$(tput cub 666)[....] Starting $2...\\033[s\\033[K"||: +		;; +		"stop") +			[ "$SHUDDUP" -eq 0 ]&&echo -ne "$(tput cub 666)[....] Shutting down $2...\\033[s\\033[K"||: +		;; +		255) +			[ "$SHUDDUP" -eq 0 ]&&echo -ne "$(tput cub 666)[$(tput setaf 3)WARN$(tput sgr0)]" +			[ "$SHUDDUP" -eq 0 ]&&echo -e "\\033[u\\033[K successfully force-killed. ($(tput setaf 3)warn$(tput sgr0))"||: +		;; +		0) +			[ "$SHUDDUP" -eq 0 ]&&echo -ne "$(tput cub 666)[$(tput setaf 2) OK $(tput sgr0)]" +			[ "$SHUDDUP" -eq 0 ]&&echo -e "\\033[u\\033[K done."||: +		;; +		10) +			[ "$SHUDDUP" -eq 0 ]&&echo -ne "$(tput cub 666)[$(tput setaf 7)DONE$(tput sgr0)]" +			[ "$SHUDDUP" -eq 0 ]&&echo -e "\\033[u\\033[K already done."||: +		;; +		*) +			[ "$SHUDDUP" -eq 0 ]&&echo -ne "$(tput cub 666)[$(tput setaf 1)FAIL$(tput sgr0)]" +			[ "$SHUDDUP" -eq 0 ]&&echo -e "\\033[u\\033[K $(tput setaf 1)failed$(tput sgr0)."||: +		;; +	esac +} +kh_qstate() { +	case "$ACTGREP" in +		"") QSTATE="$(virsh "$INFOCMD" "$2" 2>/dev/null)";; +		*) QSTATE="$(virsh "$INFOCMD" "$2" 2>&1|grep "$ACTGREP"|awk '{print $NF}')";; +	esac +	case "$1" in +		"start") +			[ "$QSTATE" == "$ACTYES" ]&&return 0||return 1 +		;; +		"stop") +			[ "$QSTATE" == "$ACTNO" ]&&return 0||return 1 +		;; +	esac +} +kh_exec() { +	# Function expects exactly two arguments: command and KVM net name to be started/stopped. +	# RC: +	# 	1 if no argument passed or arguments invalid +	# 	2 if start is unsuccessful or times out. +	FN="kh_exec" +	[ -z "$1" ]&&echo "Critical exception in $FN(): no argument passed!" >&2&&exit 1 +	[ -z "$2" ]&&echo "Critical exception in $FN(): no network name passed!" >&2&&exit 1 +	if ! virsh "$LISTCMD" "${QLISTNPARMS[@]}"|grep "$2" >/dev/null;then +		echo "Critical exception in $FN(): Network/VM $2 unknown!" >&2&&exit 2 +	fi +	case "$1" in +		"start") kh_status start "$2";; +		"stop") kh_status stop "$2";; +	esac +	case "$1" in +		"start") +			kh_qstate start "$2"&&kh_status 10 "$2"&&return 0 +		;; +		"stop") +			kh_qstate stop "$2"&&kh_status 10 "$2"&&return 0 +		;; +	esac +	TOELAPSE="0" +	while [ "$TOELAPSE" -lt "$QWAIT" ];do +		case "$1" in +			"start") virsh "$STARTCMD" "$2" >/dev/null 2>&1;; +			"stop") virsh "$STOPCMD" "$2" >/dev/null 2>&1;; +		esac +		TOELAPSE=$((TOELAPSE+QIVAL)) +		sleep "$QIVAL" +		[ "$SHUDDUP" -eq 0 ]&&echo -n "." +		case "$1" in +			"start")kh_qstate start "$2"&&break;; +			"stop")kh_qstate stop "$2"&&break;; +		esac +	done +	case "$1" in +		"start") +			if kh_qstate start "$2";then +				kh_status 0 +			else +				kh_status 1;RETVAL=20 +			fi +		;; +		"stop") +			if kh_qstate stop "$2";then +				kh_status 0 +			else +				virsh "$KILLCMD" "$2" >/dev/null 2>&1 +				if kh_qstate stop "$2";then +					kh_status 255;RETVAL=255 +				else +					kh_status 1;RETVAL=20 +				fi +			fi +		;; +	esac +} +kh_filter() { +	# Function expects exactly two arguments: command and KVM net name to be started/stopped. +	# This works as a pre-filter for knstart and knstop +	# RC: +	# 	1 if no argument, no network name passed, or wrong syntax +	# 	2 if network/VM does not exist +	#	3 if network/VM cannot be started +	#	4 if network/VM state is not determinable +	FN="kh_filter" +	[ -z "$1" ]&&echo "Critical exception in $FN(): no argument passed!" >&2&&exit 1 +	[ -z "$2" ]&&echo "Critical exception in $FN(): no action specified!" >&2&&exit 1 +	[ -z "$3" ]&&echo "Critical exception in $FN(): no network/VM name passed!" >&2&&exit 1 +	case "$1" in +		"net") +			INFOCMD="net-info";	STARTCMD="net-start" +			STOPCMD="net-destroy";	ACTGREP="^Active:" +			ACTYES="yes";		ACTNO="no" +			KILLCMD="$STOPCMD";	LISTCMD="net-list" +			QWAIT="$KHNTWAIT";	QIVAL="$KHNTIVAL" +		;; +		"vm") +			INFOCMD="domstate";	STARTCMD="start" +			STOPCMD="shutdown";	#ACTGREP="^State:" +			ACTYES="running";	ACTNO="shut off" +			KILLCMD="destroy";	LISTCMD="list" +			QWAIT="$KHVMWAIT"	QIVAL="$KHVMIVAL" +			[ "$2" == "start" ]&&QIVAL="$KHNTIVAL" +		;; +	esac +	case "$2" in +		"start") kh_exec start "$3";; +		"stop") kh_exec stop "$3";; +		*) echo "Invalid action $2 to $FN()!" >&2&&exit 1;; +	esac +} + +[ ${#KHTARGS} -eq 0 ]&&echo "No VM/network specified, aborting." >&2&&exit 127 +for i in "${KHTARGS[@]}";do +	case "$KHCMD" in +		"net-stop") kh_filter net stop "$i"||RETVAL="$((RETVAL+1))";; +		"net-start") kh_filter net start "$i"||RETVAL="$((RETVAL+1))";; +		"vm-stop") kh_filter vm stop "$i"||RETVAL="$((RETVAL+1))";; +		"vm-start") kh_filter vm start "$i"||RETVAL="$((RETVAL+1))";; +	esac + +done + +exit "$RETVAL" | 
