diff --git a/app.py b/app.py index 099fb69..c6b1758 100644 --- a/app.py +++ b/app.py @@ -1,281 +1,105 @@ -#!/bin/bash +from flask import Flask, render_template, request, jsonify, url_for +import subprocess +import re +import time -# Vereiste packages installeren -sudo apt install libguestfs-tools jq -y +app = Flask(__name__) -# Functie om het eerstvolgende vrije VMID te bepalen -find_next_free_vmid() { - # Haal de lijst van bestaande VMIDs op uit het JSON-bestand - local existing_ids=$(jq -r '.ids | keys | .[]' /etc/pve/.vmlist | sort -n) - local vmid=100 # Begin bij een standaard VMID, bijvoorbeeld 100 +# Hier maak je een lijst van VM-taken die aan de gang zijn. +vm_status = {} - for id in $existing_ids; do - if [[ $vmid -lt $id ]]; then - # Als de huidige $vmid kleiner is dan de eerstvolgende in de lijst, is deze vrij - echo $vmid - return - fi - # Anders verhogen we $vmid om naar het volgende te kijken - ((vmid++)) - done +def get_network_bridges(): + try: + result = subprocess.run(['brctl', 'show'], capture_output=True, text=True, check=True) + bridges = [] + for line in result.stdout.splitlines(): + parts = line.split() + if len(parts) > 0 and not parts[0].startswith(("fwbr", "tap", "enp", "fwpr", "bridge")): + bridges.append(parts[0]) + return bridges + except subprocess.CalledProcessError as e: + print(f"Fout bij het ophalen van netwerkbridges: {e}") + return [] - # Als we geen vrije ID in de lijst vinden, retourneer de volgende beschikbare ID - echo $vmid -} +def get_storage_types(): + try: + result = subprocess.run(['pvesm', 'status'], capture_output=True, text=True, check=True) + storage_types = [] + for line in result.stdout.splitlines()[1:]: + parts = line.split() + if parts: + storage_types.append(parts[0]) + return storage_types + except subprocess.CalledProcessError as e: + print(f"Fout bij het ophalen van storage types: {e}") + return [] -# Configuratievariabelen -VMID=$(find_next_free_vmid) # VM ID -VMNAME="test" # Naam van de VM -VMUSER="test" # Gebruikersnaam -VMPASSWORD="test" # Wachtwoord voor de gebruiker (leeg voor alleen SSH-sleutels) -SSH_KEYS_PATH1="" -DISK_SIZE="20" # Disk grootte in GiB -BRIDGE="vmbr0" -MEMORY="4096" -CORES="4" -STORAGE="btrfs" # Opslaglocatie -OSKEUZE="5" # Naam en versie van het besturingssysteem, bijv. "Debian 12" -TEMPLATE="n" # Of de VM als template moet worden ingesteld (j/n) +def get_ip_addresses_from_output(output): + # Zoek naar zowel IPv4 als IPv6 adressen van eth0 in de output + ipv4_addresses = re.findall(r'eth0 - ipv4: (\d+\.\d+\.\d+\.\d+)', output) # Voor IPv4 adressen + ipv6_addresses = re.findall(r'eth0 - ipv6: ([a-f0-9:]+)', output) # Voor IPv6 adressen -SSH_KEY_TEXT="" + # Combineer beide lijsten van adressen + return ipv4_addresses + ipv6_addresses -# Parseer de argumenten met getopts -while getopts "n:u:p:k:d:b:m:c:s:o:t:" opt; do - case ${opt} in - n) VMNAME="${OPTARG}" ;; - u) VMUSER="${OPTARG}" ;; - p) VMPASSWORD="${OPTARG}" ;; - k) SSH_KEYS_PATH1="${OPTARG}" ;; - d) DISK_SIZE="${OPTARG}" ;; - b) BRIDGE="${OPTARG}" ;; - m) MEMORY="${OPTARG}" ;; - c) CORES="${OPTARG}" ;; - s) STORAGE="${OPTARG}" ;; - o) OSKEUZE="${OPTARG}" ;; - t) TEMPLATE="${OPTARG}" ;; - \?) echo "Usage: $0 [-n vmname] [-u username] [-p password] [-k ssh_key] [-d disk_size] [-b bridge] [-m memory] [-c cores] [-s storage] [-o oskeuze] [-t template]" ;; - esac -done +@app.route('/', methods=['GET']) +def index(): + bridges = get_network_bridges() + storage_types = get_storage_types() + return render_template('index.html', bridges=bridges, storage_types=storage_types) -# Echo de variabelen voor bevestiging -echo "VM Name: $VMNAME" -echo "VM User: $VMUSER" -echo "VM Password: $VMPASSWORD" -echo "SSH Key Path: $SSH_KEYS_PATH1" -echo "Disk Size: $DISK_SIZE" -echo "Bridge: $BRIDGE" -echo "Memory: $MEMORY" -echo "Cores: $CORES" -echo "Storage: $STORAGE" -echo "OS Choice: $OSKEUZE" -echo "Template: $TEMPLATE" +@app.route('/check_vm_status/', methods=['GET']) +def check_vm_status(vmnaam): + status = vm_status.get(vmnaam, 'running') # Zet de status op 'running' als deze er nog niet is + return jsonify({'status': status}) -# Controleer verplichte variabelen -if [[ -z "$VMID" || -z "$VMNAME" || -z "$VMUSER" || -z "$DISK_SIZE" || -z "$STORAGE" || -z "$OSKEUZE" ]]; then - echo "Error: Een of meer verplichte variabelen zijn niet ingesteld. Vul alle vereiste variabelen in." - exit 1 -fi +@app.route('/create_vm', methods=['POST']) +def create_vm(): + try: + vmnaam = request.form['vmnaam'] + + vm_status[vmnaam] = 'running' + + vmgebruiker = request.form['vmgebruiker'] + vmwachtwoord = request.form['vmwachtwoord'] + ssh_key = request.form.get('ssh_key', '') + vmdisk_size = request.form['vmdisk_size'] + network_bridge = request.form['network_bridge'] + ram = request.form['ram'] + vm_cores = request.form['vm_cores'] + storage = request.form['storage'] + os = request.form['os'] + + command = [ + './create.sh', + '-n', vmnaam, + '-u', vmgebruiker, + '-p', vmwachtwoord, + '-k', ssh_key, + '-d', vmdisk_size, + '-b', network_bridge, + '-m', ram, + '-c', vm_cores, + '-s', storage, + '-o', os, + '-t', 'y' + ] + + # Voer het create.sh script uit en vang de output op + result = subprocess.run(command, capture_output=True, text=True, check=True) + + vm_status[vmnaam] = 'completed' + + # Verwerk de output van het script en zoek naar IP-adressen + ip_addresses = get_ip_addresses_from_output(result.stdout) -# OS-specificatie en image-toewijzing -case "$OSKEUZE" in - "1") - IMAGE_URL="https://cloud.debian.org/images/cloud/bullseye/latest/debian-11-generic-amd64.qcow2" - IMAGE_NAME="debian-11-generic-amd64.qcow2" - ;; - "2") - IMAGE_URL="https://cloud.debian.org/images/cloud/bookworm/latest/debian-12-generic-amd64.qcow2" - IMAGE_NAME="debian-12-generic-amd64.qcow2" - ;; - "3") - IMAGE_URL="https://cloud-images.ubuntu.com/jammy/current/jammy-server-cloudimg-amd64.img" - IMAGE_NAME="jammy-server-cloudimg-amd64.img" - ;; - "4") - IMAGE_URL="https://cloud-images.ubuntu.com/noble/current/noble-server-cloudimg-amd64.img" - IMAGE_NAME="noble-server-cloudimg-amd64.img" - ;; - "5") - IMAGE_URL="https://repo.almalinux.org/almalinux/9/cloud/x86_64/images/AlmaLinux-9-GenericCloud-latest.x86_64.qcow2" - IMAGE_NAME="AlmaLinux-9-GenericCloud-latest.x86_64.qcow2" - ;; - *) - echo "Error: Ongeldige OS-keuze. Controleer de waarde van OSKEUZE." - exit 1 - ;; -esac + return jsonify({"success": True, "ip_addresses": ip_addresses}) + except Exception as e: + print(f"Fout bij het aanmaken van de VM: {e}") + return jsonify({"success": False, "error": str(e)}) + + vm_status[vmnaam] = 'failed' + return jsonify({'success': False, 'error': str(e)}) -# Download de OS image -mkdir -p /tmp -wget -O /tmp/"$IMAGE_NAME" "$IMAGE_URL" - -if [ -n "$SSH_KEYS_PATH1" ] && [ -f "$SSH_KEYS_PATH1" ]; then - touch /tmp/temporary_ssh_key.pub - echo "$SSH_KEYS_PATH1" > /tmp/temporary_ssh_key.pub - # Sla de naam van het tijdelijke bestand op in een variabele - SSH_KEYS_PATH="/tmp/temporary_ssh_key.pub" -else - SSH_KEYS_PATH="" -fi - -# Controleer de disk type -DISKTYPE=$(pvesm status | awk -v storage="$STORAGE" 'NR>1 && $1 == storage {print $2}') - -# Pas de image aan -case $OSKEUZE in - 1|2|3|4) # Debian en Ubuntu - virt-customize --run-command "apt update -y" -a /tmp/"$IMAGE_NAME" - virt-customize --install qemu-guest-agent,htop,curl,avahi-daemon,console-setup,cron,cifs-utils,mtr,bash-completion,bind9-utils,lsof,mc,mlocate,screen,sysstat,tmux,wget,zabbix-agent -a /tmp/"$IMAGE_NAME" - virt-customize --run-command "systemctl enable --now qemu-guest-agent" -a /tmp/"$IMAGE_NAME" - virt-customize --run-command "apt upgrade -y" -a /tmp/"$IMAGE_NAME" - - case $SSH_KEYS_PATH in - '') # leeg - virt-customize -a /tmp/"$IMAGE_NAME" \ - --run-command 'sed -i "s/^#PasswordAuthentication yes/PasswordAuthentication yes/" /etc/ssh/sshd_config' \ - --run-command 'sed -i "s/^PasswordAuthentication no/PasswordAuthentication yes/" /etc/ssh/sshd_config' \ - --run-command 'systemctl restart sshd' - ;; - /tmp/temporary_ssh_key.pub) # iets - ;; - esac - - virt-customize -a /tmp/"$IMAGE_NAME" --truncate /etc/machine-id --truncate /var/lib/dbus/machine-id - ;; - 5) # RHEL - virt-customize --install https://dl.fedoraproject.org/pub/epel/epel-release-latest-9.noarch.rpm -a /tmp/"$IMAGE_NAME" - virt-customize --run-command "dnf update -y" -a /tmp/"$IMAGE_NAME" - virt-customize --install qemu-guest-agent,htop,curl,cifs-utils,firewalld,mtr,bash-completion,bind-utils,lsof,mc,mlocate,perl,perl-Date-Calc,perl-Data-Dumper,perl-Getopt-Long,perl-libs,screen,sysstat,tmux,wget,zabbix-agent -a /tmp/"$IMAGE_NAME" - virt-customize --selinux-relabel -a /tmp/"$IMAGE_NAME" - virt-customize --run-command "systemctl enable --now firewalld" -a /tmp/"$IMAGE_NAME" - virt-customize --run-command "systemctl enable --now qemu-guest-agent" -a /tmp/"$IMAGE_NAME" - virt-customize --run-command "dnf update -y" -a /tmp/"$IMAGE_NAME" - - case $SSH_KEYS_PATH in - '') # leeg - virt-customize -a /tmp/"$IMAGE_NAME" \ - --run-command 'sed -i "s/^#PasswordAuthentication yes/PasswordAuthentication yes/" /etc/ssh/sshd_config' \ - --run-command 'sed -i "s/^PasswordAuthentication no/PasswordAuthentication yes/" /etc/ssh/sshd_config' \ - --run-command 'systemctl restart sshd' - ;; - /tmp/temporary_ssh_key.pub) # iets - ;; - esac - - ;; - *) # Anders - ;; -esac - - -virt-customize -a /tmp/"$IMAGE_NAME" --truncate /etc/machine-id --truncate /var/lib/dbus/machine-id - -# Maak een nieuwe VM -qm create $VMID --name $VMNAME --memory $MEMORY --cores $CORES --net0 virtio,bridge=$BRIDGE,firewall=1 --agent 1 - -# Importeer de aangepaste image -qm importdisk $VMID /tmp/"$IMAGE_NAME" $STORAGE - -# Configureer de VM disks -case $DISKTYPE in - dir|btrfs) #file en btrfs storage - qm set $VMID --scsihw virtio-scsi-single --scsi0 $STORAGE:$VMID/vm-$VMID-disk-0.raw,discard=on,iothread=1,ssd=1,format=raw - ;; - lvm|lvmthin|zfspool) #lvm en zfs storage - qm set $VMID --scsihw virtio-scsi-single --scsi0 $STORAGE:vm-$VMID-disk-0,discard=on,iothread=1,ssd=1,format=raw - ;; -esac - -qm set $VMID --ide0 $STORAGE:cloudinit,format=raw -qm set $VMID --ide2 none,media=cdrom -qm set $VMID --bios ovmf -qm set $VMID --machine q35 -qm set $VMID --tablet 0 -qm set $VMID --serial0 socket - -# Stel netwerkinstellingen en CPU-configuraties in -qm set $VMID --ipconfig0 ip=dhcp,ip6=auto -qm set $VMID --cpu cputype=host,flags="+md-clear;+spec-ctrl;+aes" -qm set $VMID --numa 1 -qm set $VMID --sockets 1 - -# Configureer Cloud-Init -qm set $VMID --ciuser $VMUSER -qm set $VMID --cipassword $VMPASSWORD -qm set $VMID --ciupgrade 1 -qm set $VMID --onboot 1 -[[ -n "$SSH_KEYS_PATH" && -f "$SSH_KEYS_PATH" ]] && qm set $VMID --sshkeys "$SSH_KEYS_PATH" - -#case $SSH_KEYS_PATH in -# '') # leeg -# ;; -# /tmp/temporary_ssh_key.pub) # iets -# qm set $VMID --sshkeys /tmp/temporary_ssh_key.pub -# ;; -#esac - -qm set $VMID --efidisk0 $STORAGE:0,format=raw,pre-enrolled-keys=1 - -# Stel de bootvolgorde en disk grootte in -qm set $VMID --boot order="scsi0;ide2;net0" -qm resize $VMID scsi0 "${DISK_SIZE}G" - -# Zet de VM om in een template als geselecteerd -if [[ "$TEMPLATE" == "j" ]]; then - qm template $VMID -fi - -# starten vm -rm -f /tmp/"$IMAGE_NAME" -rm -f /tmp/temporary_ssh_key.pub - -qm start $VMID - -# ip ophalen -# Maximum aantal pogingen (1 minuut / 5 seconden = 12 pogingen) -MAX_ATTEMPTS=24 # Aantal pogingen voordat de foutmelding wordt weergegeven -ATTEMPT=0 -ETH0_STATS="" # Zorg ervoor dat ETH0_STATS wordt geleegd bij elke iteratie - -# Probeer om de IP-informatie en statistieken op te halen -while [ -z "$ETH0_STATS" ] && [ $ATTEMPT -lt $MAX_ATTEMPTS ]; do - echo "Trying to retrieve IP and stats information... Attempt $((ATTEMPT + 1)) of $MAX_ATTEMPTS" - - # Haal de netwerkinformatie op - IP_INFO=$(qm agent $VMID network-get-interfaces 2>/dev/null) - - # Controleer of de QEMU guest agent beschikbaar is - if [[ "$IP_INFO" == *"QEMU guest agent is not running"* ]]; then - echo "QEMU guest agent is not running. Retrying..." - elif [[ -z "$IP_INFO" ]]; then - echo "No network information received. Retrying..." - else - # Controleer specifiek of eth0 bestaat en statistieken bevat - ETH0_STATS=$(echo "$IP_INFO" | jq -r '.[] | select(.name == "eth0" and .statistics != null)') - - if [ -n "$ETH0_STATS" ]; then - echo "Valid IP and statistics found for eth0!" - break # Als eth0 statistieken heeft, stop de poging - else - echo "No valid statistics found for eth0. Retrying..." - fi - fi - - # Wacht 1 seconde voordat je opnieuw probeert - sleep 1 - ((ATTEMPT++)) -done - -# Controleer of we een geldig resultaat hebben gekregen -if [ -z "$ETH0_STATS" ]; then - echo "Unable to retrieve IP or statistics for eth0 after $MAX_ATTEMPTS attempts." - exit 1 -else - # Parse en toon IPv4 en IPv6 adressen voor de eth0 interface met statistieken - echo "$ETH0_STATS" | jq -r '.["ip-addresses"][] | [.["ip-address-type"], .["ip-address"]] | @tsv' | \ - while IFS=$'\t' read -r ip_type ip; do - echo "eth0 - $ip_type: $ip" - done -fi - -# Opruimen -echo "VM $VMNAME met ID $VMID succesvol aangemaakt." +if __name__ == '__main__': + app.run(host='0.0.0.0', port=5000, debug=True)