342 lines
15 KiB
Bash
Executable File
342 lines
15 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
#getting the config
|
|
source /etc/nlvmi/nlvmi.conf
|
|
if [ $LOGLEVEL -gt "1" ]; then echo "configuration loaded"; fi
|
|
|
|
#checking directories
|
|
#echo $VMDIRECTORY | while read line; do IFS='|' read -r -a array
|
|
# for dir in "${array[@]}"; do
|
|
# if [ ! -d $dir ]; then echo "VMDIRECTORY wrong, $dir does not exist"; exit 1; fi
|
|
# done
|
|
#done <<< "$line"
|
|
|
|
#check if we are root and wrap if we are not
|
|
U=`/usr/bin/whoami`
|
|
if [ $U != "root" ]; then
|
|
if [ ! -z $1 ]; then A=$1; else A="bla"; fi
|
|
if [ ! -z $2 ]; then B=$2; else B="bla"; fi
|
|
if [ ! -z $3 ]; then C=$3; else C="bla"; fi
|
|
/usr/bin/wrap-nlvmi $A $B $C && exit
|
|
fi
|
|
|
|
if [ ! -d $RUNDIRECTORY ]; then if [ $LOGLEVEL -gt "1" ]; then echo "creating $RUNDIRECTORY"; fi; mkdir -p $RUNDIRECTORY; chown root:nlvmi -R $RUNDIRECTORY; chmod g+w $RUNDIRECTORY; fi
|
|
|
|
#checking database
|
|
function checkdb {
|
|
if [ $DATABASETYPE == "sqlite" ]; then
|
|
if [ ! -e $SQLITEFILE ]; then echo "sqlite configured, but db-file not present! create the db first!"; exit 1; fi
|
|
SQCHECK=`sqlite3 $SQLITEFILE "SELECT name FROM sqlite_master WHERE type='table' AND name='vms'"`
|
|
if [ $SQCHECK == "vms" ]; then
|
|
if [ $LOGLEVEL -gt "1" ]; then echo "DB ready to use"; fi
|
|
else
|
|
echo "error accessing sqlite!"
|
|
exit 1;
|
|
fi
|
|
echo "sqlite ready to use";
|
|
elif [ $DATABASETYPE == "mariadb" ]; then
|
|
DBCON="mysql --disable-pager -u $MARIAUSER -p$MARIAPASS -h $MARIAHOST $MARIADB"
|
|
declare -a DBC=`echo "SHOW TABLES FROM $MARIADB; " | $DBCON | sed 1d`
|
|
if [ -z $DBC ]; then
|
|
echo "mariadb connection failed"; exit 1
|
|
fi
|
|
fi
|
|
return 0
|
|
}
|
|
|
|
|
|
#creating database
|
|
function createdb {
|
|
if [ $LOGLEVEL -gt "1" ]; then echo "going to create the db"; fi
|
|
if [ $DATABASETYPE == "sqlite" ]; then
|
|
sqlite3 $SQLITEFILE "CREATE TABLE vms (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
vmname VARCHAR(50) NOT NULL,
|
|
user VARCHAR(50) NOT NULL,
|
|
server VARCHAR(50),
|
|
arch VARCHAR(50) NOT NULL,
|
|
cputype VARCHAR(50),
|
|
cpus INTEGER,
|
|
memory INTEGER,
|
|
usbdev VARCHAR(50),
|
|
kblang VARCHAR(50),
|
|
custom VARCHAR(50),
|
|
bootoption VARCHAR(2) NOT NULL,
|
|
autostart INTEGER,
|
|
drive1 VARCHAR(50),
|
|
format1 VARCHAR(50),
|
|
drive2 VARCHAR(50),
|
|
format2 VARCHAR(50),
|
|
drive3 VARCHAR(50),
|
|
format3 VARCHAR(50),
|
|
cdrom VARCHAR(50),
|
|
tapdev1 VARCHAR(50),
|
|
macaddr1 VARCHAR(50),
|
|
brdev1 VARCHAR(50),
|
|
tapdev2 VARCHAR(50),
|
|
macaddr2 VARCHAR(50),
|
|
brdev2 VARCHAR(50),
|
|
tapdev3 VARCHAR(50),
|
|
macaddr3 VARCHAR(50),
|
|
brdev3 VARCHAR(50),
|
|
vncport INTEGER,
|
|
websocket INTEGER,
|
|
vncpassword VARCHAR(50)
|
|
);"
|
|
sqlite3 $SQLITEFILE "CREATE TABLE users (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
username VARCHAR(50) NOT NULL,
|
|
password VARCHAR(255),
|
|
admin INTEGER
|
|
);"
|
|
sqlite3 $SQLITEFILE "CREATE TABLE servers (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
hostname VARCHAR(50) NOT NULL,
|
|
connectstring VARCHAR(50),
|
|
vmdirectory VARCHAR(255),
|
|
isodirectory VARCHAR(255)
|
|
);"
|
|
|
|
chown -R nobody $SQLITEFILE
|
|
fi
|
|
checkdb && echo "DB creation successful!" || (echo "Failed to create the DB"; exit 1)
|
|
}
|
|
#create signing key
|
|
function createkey {
|
|
openssl req -nodes -x509 -sha256 -newkey rsa:4096 -keyout "/etc/nlvmi/nlvmi_priv.key" -out "/etc/nlvmi/nlvmi_sign.crt" -days 9999 -subj "/CN=nlvmi_signing"
|
|
}
|
|
|
|
#check if VM is running
|
|
function checkvm {
|
|
if [ -z $1 ]; then echo "checkvm needs one argument!"; exit 1; fi
|
|
sqlite3 $SQLITEFILE "SELECT connectstring from vms LEFT JOIN servers ON vms.server = servers.hostname WHERE vmname='$1'" | while read line; do
|
|
CONN=$line
|
|
if [ ! -z $CONN ]; then
|
|
su nlvmi -c "ssh $CONN \"RPID=\\\$(<\\\"$RUNDIRECTORY/$1.pid\\\"); ps -ef | grep -v grep | grep \\\$RPID | grep qemu\"" &>/dev/null && echo "VM is running" || echo "VM is not running"
|
|
else
|
|
ps -ef | grep `cat $RUNDIRECTORY/$1.pid` | grep -v grep >/dev/null && echo "VM is running" || echo "VM is not running"
|
|
|
|
fi
|
|
done
|
|
}
|
|
|
|
|
|
|
|
#autostart VMs
|
|
function vmautostart {
|
|
if [ -z $MASTERSERVER ]; then
|
|
for startfile in /home/nlvmi/start*.tmp; do
|
|
vmname=`echo $startfile | cut -d "." -f1 | rev | cut -d "/" -f 1 | rev | sed 's/start//g'`
|
|
checkvm ${vmname} | grep "is not running" >/dev/null && sh $startfile;
|
|
done
|
|
else
|
|
for startsign in /home/nlvmli/start*.tmp.sha512; do
|
|
startfile=`echo $startsign | cut -d "." -f 1-2`
|
|
vmname=`echo $startfile | cut -d "." -f1 | rev | cut -d "/" -f1 | rev | sed 's/start//g'`
|
|
checkvm ${vmname} | grep "is not running" >/dev/null && if [ -e $startfile ]; then
|
|
openssl dgst -sha512 -verify <(openssl x509 -in "/etc/nlvmi/nlvmi_sign.crt" -pubkey -noout) -signature $startsign $startfile >/dev/null && /bin/bash $2 || echo "signature failed!!"
|
|
fi
|
|
done
|
|
fi
|
|
}
|
|
|
|
#start single VM
|
|
function vmstart {
|
|
if [ -z $1 ]; then echo "function start needs an id!"; exit 1; fi
|
|
if [ $LOGLEVEL -gt "1" ]; then echo "startvm function entered for vmid $1"; fi
|
|
sqlite3 $SQLITEFILE "SELECT * FROM vms LEFT JOIN servers on vms.server = servers.hostname WHERE vms.id=$1" | while read line; do
|
|
IFS='|' read -r -a array <<< "$line"
|
|
#prepare tmpfile
|
|
TMPF=/home/nlvmi/start${array[1]}.tmp
|
|
rm $TMPF &>/dev/null
|
|
#add user if necessary
|
|
echo "if ! \`id -u ${array[2]} &>/dev/null\`; then useradd ${array[2]} -d /run/nlvmi -g nlvmi -M -s /bin/false -G kvm; fi" >>$TMPF
|
|
#chown mon and pid files
|
|
echo "if [ -e $RUNDIRECTORY/${array[1]}.mon ] || [ -e $RUNDIRECTORY/${array[1]}.pid ]; then chown ${array[2]}:nlvmi $RUNDIRECTORY/${array[1]}.*; fi" >>$TMPF
|
|
if [ ! -z ${array[5]} ]; then CPUTYPE="-cpu ${array[5]}"; fi
|
|
if [ ! -z ${array[6]} ]; then SMP="-smp ${array[6]}"; fi
|
|
if [ ! -z ${array[7]} ]; then MEMORY="-m ${array[7]}"; fi
|
|
if [ ! -z ${array[8]} ]; then USBDEV="-usb -device usb-ehci,id=ehci -device usb-${array[8]},bus=usb-bus.0"; fi
|
|
if [ ! -z ${array[9]} ]; then KB="-k ${array[9]}"; fi
|
|
if [ ! -z ${array[10]} ]; then CUSTOM="${array[10]}"; fi
|
|
if [ ! -z ${array[13]} ]; then DRIVE1="-drive file=${array[13]}"; echo "chown ${array[2]}:nlvmi ${array[13]}" >>$TMPF; fi
|
|
if [ ! -z ${array[14]} ]; then FORMAT1=",format=${array[14]},if=virtio"; fi
|
|
if [ ! -z ${array[15]} ]; then DRIVE2="-drive file=${array[15]}"; echo "chown ${array[2]}:nlvmi ${array[15]}" >>$TMPF; fi
|
|
if [ ! -z ${array[16]} ]; then FORMAT2=",format=${array[16]},if=virtio"; fi
|
|
if [ ! -z ${array[17]} ]; then DRIVE3="-drive file=${array[17]}"; echo "chown ${array[2]}:nlvmi ${array[17]}" >>$TMPF; fi
|
|
if [ ! -z ${array[18]} ]; then FORMAT3=",format=${array[18]},if=virtio"; fi
|
|
if [ ! -z ${array[19]} ]; then CDROM="-cdrom ${array[19]}"; fi
|
|
if [ ! -z ${array[20]} ]; then TAPDEV1="-netdev tap,ifname=${array[20]},script=no,id=net0"; echo "tunctl -t ${array[20]} -u ${array[2]} && ifconfig ${array[20]} up" >>$TMPF; fi
|
|
if [ ! -z ${array[21]} ]; then MACADDR1="-net nic,macaddr=${array[21]},model=virtio,netdev=net0"; fi
|
|
if [ ! -z ${array[22]} ]; then BRDEV1="${array[22]}"; echo "/sbin/brctl addif ${array[22]} ${array[20]}" >>$TMPF; fi
|
|
if [ ! -z ${array[23]} ]; then TAPDEV2="-netdev tap,ifname=${array[23]},script=no,id=net1"; echo "tunctl -t ${array[23]} -u ${array[2]} && ifconfig ${array[23]} up" >>$TMPF; fi
|
|
if [ ! -z ${array[24]} ]; then MACADDR2="-net nic,macaddr=${array[24]},model=virtio,netdev=net1"; fi
|
|
if [ ! -z ${array[25]} ]; then BRDEV2="${array[25]}"; echo "/sbin/brctl addif ${array[25]} ${array[23]}" >>$TMPF; fi
|
|
if [ ! -z ${array[26]} ]; then TAPDEV3="-netdev tap,ifname=${array[26]},script=no,id=net2"; echo "tunctl -t ${array[26]} -u ${array[2]} && ifconfig ${array[26]} up" >>$TMPF; fi
|
|
if [ ! -z ${array[27]} ]; then MACADDR3="-net nic,macaddr=${array[27]},model=virtio,netdev=net2"; fi
|
|
if [ ! -z ${array[28]} ]; then BRDEV3="${array[28]}"; echo "/sbin/brctl addif ${array[28]} ${array[26]}" >>$TMPF; fi
|
|
if [ ! -z ${array[30]} ]; then WEBSOCK=",websocket=${array[30]}"; else WEBSOCK=""; fi
|
|
if [ ! -z ${array[31]} ]; then VNCPASS=",password"; fi
|
|
if [ ! -z ${array[29]} ]; then VNCPORT="-vnc :${array[29]}$WEBSOCK$VNCPASS"; fi
|
|
COMMAND=(su - ${array[2]} -s /bin/bash -c \"${array[4]} -name ${array[1]} -enable-kvm ${array[10]} $CPUTYPE $MEMORY $SMP -device virtio-rng-pci -boot ${array[11]} $USBDEV $KB -daemonize $DRIVE1$FORMAT1 $DRIVE2$FORMAT2 $DRIVE3$FORMAT3 $CDROM $MACADDR1 $TAPDEV1 $MACADDR2 $TAPDEV2 $MACADDR3 $TAPDEV3 $VNCPORT $CUSTOM -pidfile $RUNDIRECTORY/${array[1]}.pid -monitor unix:$RUNDIRECTORY/${array[1]}.mon,server,nowait\")
|
|
if [ $LOGLEVEL -gt "1" ]; then echo ${COMMAND[@]}; fi
|
|
echo "${COMMAND[@]}" >>$TMPF
|
|
#Set VNC Password
|
|
echo "echo \"change vnc password ${array[31]}\" | socat - unix-connect:$RUNDIRECTORY/${array[1]}.mon >/dev/null" >>$TMPF
|
|
if [ ! -z "${array[34]}" ]; then
|
|
echo "chmod g+w $RUNDIRECTORY/${array[1]}.mon" >>$TMPF
|
|
echo "chmod g+r $RUNDIRECTORY/${array[1]}.pid" >>$TMPF
|
|
openssl dgst -sha512 -sign "/etc/nlvmi/nlvmi_priv.key" -out /home/nlvmi/${array[1]}.tmp.sha512 $TMPF
|
|
su nlvmi -c "scp $TMPF* ${array[34]}:/home/nlvmi/"
|
|
su nlvmi -c "ssh ${array[34]} \"/usr/bin/nlvmi remote $TMPF run\""
|
|
if [ ${array[12]} == "0" ]; then
|
|
su nlvmi -c "ssh ${array[34]} \"rm $TMPF $TMPF.sha512\""
|
|
fi
|
|
rm $TMPF $TMPF.sha512
|
|
else
|
|
/bin/bash $TMPF
|
|
if [ ${array[12]} == "0" ]; then
|
|
rm $TMPF
|
|
fi
|
|
fi
|
|
done
|
|
export VMFOUND="yes"
|
|
}
|
|
|
|
#stop VM
|
|
function vmstop {
|
|
if [ $LOGLEVEL -gt "1" ]; then echo "stopvm function entered for VM $1"; fi
|
|
sqlite3 $SQLITEFILE "SELECT vms.id AS vid,vmname,connectstring FROM vms LEFT JOIN servers ON vms.server = servers.hostname WHERE vmname='$1'" | while read line; do
|
|
IFS='|' read -r -a array <<< "$line"
|
|
if [ -z ${array[2]} ]; then
|
|
if [ ! -e $RUNDIRECTORY/$1.pid ]; then echo "pidfile $RUNDIRECTORY/$1.pid does not exist"; exit 1; fi
|
|
echo "system_powerdown" | socat - unix-connect:$RUNDIRECTORY/${array[1]}.mon >/dev/null
|
|
else
|
|
su nlvmi -c "ssh ${array[2]} \"echo \\\"system_powerdown\\\" | socat - unix-connect:$RUNDIRECTORY/${array[1]}.mon >/dev/null\""
|
|
fi
|
|
sleep 5s
|
|
STOPPED="no"
|
|
COUNTER=0
|
|
while [ $STOPPED = "no" ]; do
|
|
if [ $COUNTER == 10 ]; then
|
|
if [ -z ${array[2]} ]; then
|
|
kill `cat $RUNDIRECTORY/${array[1]}.pid`
|
|
echo "${array[1]} forcefully killed!";
|
|
STOPPED="yes"
|
|
else
|
|
TMPF=/home/nlvmi/${array[1]}.tmp
|
|
echo "kill \$(<\"$RUNDIRECTORY/${array[1]}.pid\")" >$TMPF
|
|
openssl dgst -sha512 -sign "/etc/nlvmi/nlvmi_priv.key" -out $TMPF.sha512 $TMPF
|
|
su nlvmi -c "scp $TMPF* ${array[2]}:/home/nlvmi/"
|
|
su nlvmi -c "ssh ${array[2]} \"/usr/bin/nlvmi remote /home/nlvmi/${array[1]}.tmp stop\""
|
|
su nlvmi -c "ssh ${array[2]} \"rm $TMPF $TMPF.sha512\""
|
|
rm $TMPF $TMPF.sha512
|
|
echo "remotekill"
|
|
STOPPED="yes"
|
|
fi
|
|
fi
|
|
((COUNTER++))
|
|
checkvm ${array[1]} | grep "is not running" >/dev/null && STOPPED="yes"
|
|
sleep 1s
|
|
done
|
|
done
|
|
}
|
|
|
|
|
|
#stop local vm
|
|
function vmlocalstop {
|
|
if [ ! -e $RUNDIRECTORY/$1.pid ]; then echo "pidfile $RUNDIRECTORY/$1.pid does not exist"; exit 1; fi
|
|
echo "system_powerdown" | socat - unix-connect:$RUNDIRECTORY/$1.mon >/dev/null
|
|
sleep 5s
|
|
STOPPED="no"
|
|
COUNTER=0
|
|
while [ $STOPPED = "no" ]; do
|
|
if [ $COUNTER == 10 ]; then
|
|
kill `cat $RUNDIRECTORY/$1.pid`
|
|
echo "$1 forcefully killed!";
|
|
STOPPED="yes"
|
|
fi
|
|
((COUNTER++))
|
|
ps -ef | grep `cat $RUNDIRECTORY/$1.pid` | grep -v grep >/dev/null || STOPPED="yes"
|
|
sleep 1s
|
|
done
|
|
}
|
|
|
|
#stopall local vms
|
|
function stopall {
|
|
for vms in $RUNDIRECTORY/*.pid; do
|
|
vmname=`echo ${vms} | rev | cut -d "/" -f1 | rev | sed 's/.pid//g'`
|
|
vmlocalstop ${vmname}
|
|
done
|
|
}
|
|
|
|
function listdir {
|
|
#echo $1 $2
|
|
sqlite3 $SQLITEFILE "SELECT $2,connectstring FROM servers WHERE hostname='$1'" | while read line; do
|
|
IFS='|' read -r -a array <<< "$line"
|
|
IFS=';' read -r -a dirs <<< "${array[0]}"
|
|
for di in ${dirs[@]}; do
|
|
if [ -z ${array[1]} ]; then
|
|
ls -lrt -d -1 $di/{*,.*}
|
|
else
|
|
su nlvmi -c "ssh ${array[1]} \"ls -lrt -d -1 $di/{*,.*}\""
|
|
fi
|
|
done
|
|
done
|
|
}
|
|
|
|
#mainloop
|
|
if [ $# -gt 0 ]; then
|
|
if [ $1 == "createdb" ]; then
|
|
createdb
|
|
elif [ $1 == "autostart" ]; then
|
|
vmautostart
|
|
elif [ $1 == "checkvm" ]; then
|
|
if [ -z $2 ]; then echo "checkvm needs two arguments"; fi
|
|
checkvm $2
|
|
elif [ $1 == "start" ]; then
|
|
if [ -z $2 ]; then echo "start needs a vmname!"; exit 1; fi
|
|
VMFOUND="no"
|
|
if [ $LOGLEVEL -gt "1" ]; then echo "searching for vmname $2"; fi
|
|
sqlite3 $SQLITEFILE "SELECT id FROM vms WHERE vmname='$2'" | (while read line; do
|
|
IFS='|' read -r -a arrays <<< "$line"
|
|
declare VMFOUND="yes"
|
|
export "$VMFOUND"
|
|
vmstart $arrays
|
|
done
|
|
if [[ $VMFOUND == "no" ]]; then echo "no VM with that name found!"; exit 1; fi)
|
|
elif [ $1 == "stop" ]; then
|
|
if [ -z $2 ]; then echo "stop needs a vmname!"; exit 1; fi
|
|
VMFOUND="no"
|
|
if [ $LOGLEVEL -gt "1" ]; then echo "searching for vmname $2"; fi
|
|
sqlite3 $SQLITEFILE "SELECT id FROM vms WHERE vmname='$2'" | (while read line; do
|
|
IFS='|' read -r -a arrays <<< "$line"
|
|
declare VMFOUND="yes"
|
|
export "$VMFOUND"
|
|
vmstop $2
|
|
done
|
|
if [[ $VMFOUND == "no" ]]; then echo "no VM with that name found!"; exit 1; fi)
|
|
elif [ $1 == "stopall" ]; then
|
|
stopall
|
|
elif [ $1 == "listdir" ]; then
|
|
if [ -z $2 ] || [ -z $3 ]; then echo listdir needs two more arguments; exit 1; fi
|
|
listdir $2 $3
|
|
elif [ $1 == "remote" ]; then
|
|
if [ ! -z $MASTERSERVER ]; then
|
|
if `echo $SSH_CLIENT | grep "$MASTERSERVER " &>/dev/null`; then
|
|
if [ -e $2 ]; then
|
|
openssl dgst -sha512 -verify <(openssl x509 -in "/etc/nlvmi/nlvmi_sign.crt" -pubkey -noout) -signature $2.sha512 $2 >/dev/null && /bin/bash $2 || echo "signature failed!!"
|
|
fi
|
|
else
|
|
echo "not allowed";
|
|
fi
|
|
fi
|
|
elif [ $1 == "createkey" ]; then
|
|
if [ ! -z $MASTERSERVER ]; then
|
|
createkey
|
|
fi
|
|
fi
|
|
else
|
|
checkdb
|
|
fi
|