#!/bin/bash
#
#bashvm.com
#
#Author: Kyle Schroeder "BabyWhale"

while true; do
    # Display the main menu
    echo -e "\n============================ Main Menu ============================"
    echo " 1. Virtual Machines  2. Storage Pools         3. Networks"
    echo " 4. Snapshots         5. Edit Properties       6. Firewall Settings"
    echo " 7. Port Forwarding   8. VNC / Console Access  9. System Monitor"   
    echo "10. VM Monitor       11. SQLite Editor         q. Exit"
    echo ""
    # Prompt user for input
    read -ep "Enter your choice: " main_choice
    case $main_choice in
        1)
            # Virtual Machines Menu    
            while true; do
                    echo -e "\n============================== Manage Virtual Machine =============================="
                    echo " s. Show all virtual machines  1. Show more details of a VM     2. Start a VM" 
                    echo " 3. Reboot a VM                4. Shutdown a VM (graceful)      5. Shutdown a VM (force)"     
                    echo " 6. Enable autostart of a VM   7. Disable autostart of a VM     8. Create a new / existing VM"
                    echo " 9. Undefine a VM             10. Create a new VM (Automated)  11. Console into a VM"        
                    echo "12. Change resources of a VM  13. Delete a VM                  14. Clone a VM"
                    echo "15. Rename a VM                q. Back to main menu"
                    echo ""
                    read -ep "Enter your choice: " vm_manage_choice
                    case $vm_manage_choice in
                    s)
                        # Show all virtual machines
                        virsh list --all
                        ;;

                    1)
                        # Show details of a virtual machine
                        read -ep "Enter the VM name: " vm_name
                        virsh dominfo "$vm_name"
                        virsh domblkinfo "$vm_name" --all --human
                        ;;

                    2)
                        # Start a virtual machine
                        read -ep "Enter the name of the virtual machine to start: " vm_name
                        virsh start "$vm_name"
                        ;;

                    3)
                        # Reboot a VM
                        read -ep "Enter the name of the virtual machine to restart: " vm_name
                        virsh reboot "$vm_name"
                        ;;

                    4)
                        # Shutdown a VM (graceful)
                        read -ep "Enter the name of the virtual machine to shutdown: " vm_name
                        virsh shutdown "$vm_name"
                        ;;

                    5)
                        # Shutdown a VM (force)
                        read -ep "Enter the name of the virtual machine to force shutdown: " vm_name
                        virsh destroy "$vm_name"
                        ;;

                    6)
                        # Enable autostart
                        read -ep "Enter the name of the virtual machine to autostart on boot: " vm_name
                        virsh autostart "$vm_name"
                        ;;
                    
                    7)
                        # Disable autostart
                        read -ep "Enter the name of the virtual machine to disable autostart on boot: " vm_name
                        virsh autostart --disable "$vm_name"
                        ;;
                        
                    8)
                        # Create a new VM
                        bash bashvm-create-vm.sh
                        ;;

                    9)
                        # Undefine a virtual machine
                        read -ep "Enter the name of the virtual machine to undefine: " vm_name
                        
                        vm_state=$(virsh list --all | grep "$vm_name" | awk '{print $3}')
                        
                        if [ "$vm_state" == "running" ];then
                            echo "Please shutdown the vm before running this again"
                            break
                        fi
                        
                        virsh destroy "$vm_name" > /dev/null 2>&1
                        virsh undefine "$vm_name"
                        ;;
                    
                    10)
                        # Create a VM (Automated)
                        bash bashvm-create-auto-vm.sh
                        ;;
                    
                    11)
                        # Console into a VM
                        read -ep "Enter the VM name to console into: " hostname
                        virsh console "$hostname"
                        ;;

                    12)
                        # Change resources of a VM
                        bash bashvm-change-resources.sh
                        ;;
                    13)
                        # Delete a VM
                        bash bashvm-delete-vm.sh
                        ;;

                    14)
                        # Clone a VM
                        read -ep "Enter the name of the vm to clone (e.g., test-vm): " vm_name
                        read -ep "Enter the amount of clones of this vm to create (e.g., 1): " clone_num
                        counter=1
                        while [ "$counter" -le "$clone_num" ]
                        do
                            virt-clone --original "$vm_name" --auto-clone
                            ((counter++))
                        done
                        ;;
                    15)
                        # Rename a VM
                        read -ep "Enter the name of the virtual machine: " vm_name
                        read -ep "Enter the new name of the virtual machine: " vm_name_new

                        virsh domrename "$vm_name" "$vm_name_new"
                        ;;
                        
                    q)
                        # Back to Menu
                        break
                        ;;

                    *)
                        echo "Invalid choice. Please enter a valid option."
                        ;;
                esac
            done
            ;;

        2)
            # Storage Pools Menu
            while true; do
                echo -e "\n============================== Manage Storage Pool =============================="
                echo "s. Show all storage pools     1. Show all volumes in a pool  2. Activate a storage pool"
                echo "3. Deactivate a storage pool  4. Create a storage pool       5. Delete a storage pool"
                echo "6. Create a storage volume    7. Delete a storage volume     8. Clone a storage volume"
                echo "q. Back to main menu"
                echo ""
                read -ep "Enter your choice: " storage_manage_choice

                case $storage_manage_choice in
                    s)
                        # Show all pools
                        virsh pool-list --details
                        ;;

                    1)
                        #Show all volumes in a pool
                        read -ep "Enter the name of the storage pool [default]: " pool_name
                        if [ -z "$pool_name" ]; then
                            pool_name="default"
                        fi
                        virsh vol-list --pool "$pool_name"
                        ;;
                    
                    2)
                        # Activate a storage pool
                        read -ep "Enter the name of the storage pool to activate [default]: " pool_name
                        if [ -z "$pool_name" ]; then
                            pool_name="default"
                        fi
                        virsh pool-start "$pool_name"
                        ;;
                        
                    3)
                        # Deactivate a storage pool
                        read -ep "Enter the name of the storage pool to deactivate [default]: " pool_name
                        if [ -z "$pool_name" ]; then
                            pool_name="default"
                        fi
                        virsh pool-destroy "$pool_name"
                        ;;

                    4)
                        # Create a new storage pool
                        read -ep "Enter the name of the new storage pool: " new_pool_name
                        read -ep "Enter the type of the new storage pool (e.g., dir, logical, fs): " pool_type
                        read -ep "Enter the target path or source for the new storage pool: " pool_source
                        virsh pool-define-as "$new_pool_name" "$pool_type" --target "$pool_source"
                        virsh pool-start "$new_pool_name"
                        virsh pool-autostart "$new_pool_name"
                        ;;

                    5)
                        # Delete a storage pool
                        read -ep "Enter the name of the storage pool to delete: " delete_pool_name

                        virsh pool-info "$delete_pool_name" >> /dev/null
                        if [ $? == 0 ]; then
                            virsh pool-destroy "$delete_pool_name"
                        else
                            break
                        fi

                        virsh pool-undefine "$delete_pool_name"
                        if [ ! $? == 0 ]; then
                            break
                        fi
                        ;;

                    6)
                        # Create a storage volume
                        read -ep "Enter the name of the storage pool to use [default]: " pool_name
                        if [ -z "$pool_name" ]; then
                            pool_name="default"
                        fi
                        read -ep "Enter the name of the new storage volume (e.g., new-vm): " volume_name
                        read -ep "Enter the size of the volume (e.g., 10G): " volume_capacity
                        virsh vol-create-as --pool "$pool_name" --name "$volume_name.qcow2" --capacity "$volume_capacity" --format qcow2
                        ;;
                    
                    7)
                        # Delete a storage volume
                        read -ep "Enter the storage pool name that the volume is under [default]: " pool_name
                        if [ -z "$pool_name" ]; then
                            pool_name="default"
                        fi
                        read -ep "Enter the name of the volume to delete (e.g., new-vm): " volume_name

                        # Delete the storage volume
                        virsh vol-delete --pool "$pool_name" "$volume_name.qcow2"
                        ;;
                    
                    8)
                        # Clone a storage volume
                        read -ep "Enter the name of the volume to clone (e.g., test-vm): " vm_name
                        read -ep "Enter the new volume name (e.g., new-test-vm): " new_vm_name
                        read -ep "Enter the storage pool name that the volume is under [default]: " pool_name
                        if [ -z "$pool_name" ]; then
                            pool_name="default"
                        fi                        

                        virsh vol-clone "$vm_name.qcow2" "$new_vm_name.qcow2" --pool "$pool_name"
                        ;;
                    
                    q)
                        # Back to Menu
                        break
                        ;;

                    *)
                        echo "Invalid choice. Please enter a valid option."
                        ;;
                esac
            done
            ;;
        3)
            # Networks Menu       
            while true; do
                echo -e "\n============================================== Manage Network =============================================="
                echo " s. Show all networks                   1. Show more details of a network   2. Start a network"
                echo " 3. Stop a network                      4. Create a NAT network             5. Create a macvtap network"
                echo " 6. Create a routed IPv4 network        7. Create a routed IPv6 network     8. Delete a network"
                echo " 9. Add a IPv4 reservation             10. Remove a IPv4 reservation       11. Add DHCPv6 to a NAT network"                   
                echo "12. Add a IPv6 reservation             13. Edit a network                   q. Back to main menu"
                echo ""
                read -ep "Enter your choice: " network_manage_choice

                case $network_manage_choice in
                    s)
                        # List all networks
                        virsh net-list --all
                        ;;

                    1)
                        # Show details of a network
                        read -ep "Enter the network name [default]: " network_name
                        if [ -z "$network_name" ]; then
                            network_name="default"
                        fi

                        virsh net-info "$network_name"
                        virsh net-dhcp-leases "$network_name"
                        ;;

                    2)
                        # Start a network
                        read -ep "Enter the name of the network to start [default]: " network_name
                        if [ -z "$network_name" ]; then
                            network_name="default"
                        fi
                        virsh net-start "$network_name"
                        virsh net-autostart "$network_name"
                        ;;

                    3)
                        # Stop a network
                        read -ep "Enter the name of the network to stop [default]: " network_name
                        if [ -z "$network_name" ]; then
                            network_name="default"
                        fi
                        virsh net-destroy "$network_name"
                        ;;

                    4)
                        # NAT network explanation
                        echo "A NAT network will create a seperate private network"
                        echo "Allows VMs to share host's IP address for outbound traffic"
                        echo "Provides network isolation with internal DHCP service"
                        echo "(Ctrl+C to exit)"
                        echo ""
                        
                        # Prompt user for NAT network configuration
                        read -ep "Enter the new network name (e.g., natbr0): " network_name
                        read -ep "Enter the virtual bridge name (e.g., natbr0): " bridge_name
                        read -ep "Enter the new gateway ip address (e.g., 192.168.100.1): " network_ip
                        read -ep "Enter the new subnet mask (e.g., 255.255.255.0): " netmask
                        read -ep "Enter the starting ip for the DHCP range (e.g., 192.168.100.2): " dhcp_start
                        read -ep "Enter the ending ip for the DHCP range (e.g., 192.168.100.254): " dhcp_end

                        # Create network XML file
                        network_xml="
                        <network>
                        <name>${network_name}</name>
                        <forward mode='nat'/>
                        <bridge name='${bridge_name}'/>
                        <ip address='${network_ip}' netmask='${netmask}'>
                            <dhcp>
                            <range start='${dhcp_start}' end='${dhcp_end}'/>
                            </dhcp>
                        </ip>
                        </network>"

                        # Save the network XML to a file
                        net_xml_file="/etc/libvirt/qemu/networks/$network_name.xml"
                        echo "${network_xml}" > "${net_xml_file}"

                        # Define and start network
                        virsh net-define "${net_xml_file}"
                        virsh net-start "${network_name}"
                        virsh net-autostart "${network_name}"
                        ;;

                    5) 
                        # macvtap network explanation
                        echo "A macvtap network will have direct network access to the bridged interface"
                        echo "Connects VMs directly to physical network interface"
                        echo "Each VM gets its own MAC address on the physical network"
                        echo "(Ctrl+C to exit)"
                        echo ""
                        
                        # Prompt user for macvtap network configuration
                        read -ep "Enter the new network name: " network_name
                        read -ep "Enter the physical network interface to bridge to: " int_name

                        network_xml="
                        <network>
                        <name>$network_name</name>
                        <forward mode='bridge'>
                            <interface dev='$int_name'/>
                        </forward>
                        </network>"

                        net_xml_file="/etc/libvirt/qemu/networks/$network_name.xml"
                        echo "${network_xml}" > "${net_xml_file}"

                        # Define and start network
                        virsh net-define "${net_xml_file}"
                        virsh net-start "${network_name}"
                        virsh net-autostart "${network_name}"
                        ;;

                    6)
                        # Routed network explanation
                        echo "A routed network is for static IPv4 and IPv6 configurations"
                        echo "Routes traffic between VMs and external network"
                        echo "No NAT translation or DHCP service"
                        echo "(Ctrl+C to exit)"
                        echo ""
                        
                        read -ep "Enter the new network name: " network_name
                        read -ep "Enter the new virtual bridge name: " bridge_name
                        read -ep "Enter the IPv4 address that would act as the gateway ( 123.123.123.123 ): " network_ip
                        read -ep "Enter the new subnet mask (e.g., 255.255.255.0): " netmask

                        ipv4_forward=$(cat /etc/sysctl.conf | grep "net.ipv4.ip_forward=1")
                        ipv4_forward_comment="#net.ipv4.ip_forward=1"

                        if [ "$ipv4_forward" == "$ipv4_forward_comment" ]; then
                            echo "net.ipv4.ip_forward=1" >> /etc/sysctl.conf
                        fi

                        network_xml="
                        <network>
                        <name>$network_name</name>
                        <forward mode='route' stp='off' delay='0'/>
                        <bridge name='$bridge_name'/>
                        <ip address='${network_ip}' netmask='${netmask}'>
                        </ip>
                        </network>"

                        net_xml_file="/etc/libvirt/qemu/networks/$network_name.xml"
                        echo "${network_xml}" > "${net_xml_file}"

                        # Define and start network
                        virsh net-define "${net_xml_file}"
                        virsh net-start "${network_name}"
                        virsh net-autostart "${network_name}"

                        echo "When adding a static IPv4 to a vm the gateway address will be "$network_ip""
                        echo "If no errors above then the new network "$network_name" is ready to use"
                        ;;
                    7)

                        # Route IPv6 network
                        bash bashvm-ipv6-route-network.sh
                        ;;


                    8)
                        # Delete a network
                        bash bashvm-delete-network.sh
                        ;;

                    9)
                        # Add a dhcpv4 reservation to a network
                        read -ep "Enter the virtual machines name: " vm_name
                        read -ep "Enter the virtual machines mac address: " vm_mac
                        read -ep "Enter the new ip address for the virtual machine: " vm_ip
                        read -ep "Enter the network name [default]: " vm_net

                        if [ -z "$vm_net" ]; then
                            vm_net="default"
                        fi
                        
                        echo "Setting DHCP reservation..."

                        virsh net-update "$vm_net" add ip-dhcp-host "<host mac='$vm_mac' name='$vm_name' ip='$vm_ip' />" --live --config
                        
                        if [ ! $? == 0 ]; then
                            echo "Failed to set DHCP reservation in $vm_net"
                        else
                            echo "You may need to start / stop the vm for the changes to take effect"
                        fi
                        ;;
                    10)
                        # Remove a dhcpv4 reservation
                        read -ep "Enter the VM name: " vm_name
                        read -ep "Enter the network name [default]: " net_name

                        if [ -z "$net_name" ]; then
                            net_name="default"
                        fi

                        echo "Removing DHCP reservation..."                        

                        vm_mac=$(virsh net-dumpxml "$net_name" | grep "$vm_name" | head -n 1 | awk '{print $2}'| cut -d"'" -f2)
                        vm_ip=$(virsh net-dumpxml "$net_name" | grep "$vm_name" | head -n 1 | awk '{print $4}'| cut -d"'" -f2)

                        virsh net-update "$net_name" delete ip-dhcp-host "<host mac='$vm_mac' name='$vm_name' ip='$vm_ip' />" --live --config
                        
                        if [ ! $? == 0 ]; then
                            echo "Failed to remove DHCP reservation from $net_name"
                        else
                            echo "You may need to start / stop the vm for the changes to take effect"
                        fi
                        ;;
                    
                    11)
                        # Add dhcpv6 to a network (manual)
                        bash bashvm-dhcpv6-network.sh
                        ;;

                    12)
                        # Add a dhcpv6 reservation to a network
                        read -ep "Enter the desired IPv6 address to assign the VM (e.g., xxxx::3): " net_address
                        read -ep "Enter the network name [default]: " net_name

                        if [ -z "$net_name" ]; then
                            net_name="default"
                        fi

                        echo ""

                        virsh net-dhcp-leases "$net_name"

                        read -ep "Enter the DUID of the VM: " vm_duid

                        echo ""

                        virsh net-update "$net_name" add-last ip-dhcp-host "<host id='$vm_duid' ip='$net_address'/>" --live --config --parent-index 1

                        if [ $? -eq 0 ]; then
                            echo "DHCPv6 reservation added successfully. You may need to restart the VM for changes to take effect."
                        else
                            echo "Failed to set DHCPv6 reservation in $net_name"
                        fi
                        ;;

                    13)
                        # Edit a network
                        read -ep "Enter the network name [default]: " net_name
                        if [ -z "$net_name" ]; then
                            net_name="default"
                        fi
                        virsh net-edit "$net_name"
                        ;;

                    q)
                        # Back to Menu
                        break
                        ;;

                    *)
                        echo "Invalid choice. Please enter a valid option."
                        ;;
                esac
            done
            ;;
        4)
            # Managing a snapshot
            while true; do
                echo -e "\n========================= Manage Snapshot ========================="
                echo "s. Show all snapshots of a VM  1. Create a snapshot  2. Delete a snapshot"
                echo "3. Revert to a snapshot        q. Back to main menu"
                echo ""
                read -ep "Enter your choice: " snapshot_manage_choice

                case $snapshot_manage_choice in
                    s)
                        # List all snapshots of a virtual machine
                        read -ep "Enter the name of the virtual machine: " vm_name

                        virsh snapshot-list "$vm_name"
                        ;;
                    1)
                        # Create a snapshot of a virtual machine
                        read -ep "Enter the name of the virtual machine: " vm_name
                        
                        virsh snapshot-list "$vm_name"
                        if [ ! $? == 0 ]; then
                            break
                        fi

                        read -ep "Enter the name for the new snapshot: " snapshot_name
                        
                        virsh snapshot-create-as "$vm_name" "$snapshot_name"
                        ;;
                    2)
                        # Delete a snapshot of a virtual machine
                        read -ep "Enter the name of the virtual machine: " vm_name

                        virsh snapshot-list "$vm_name"
                        if [ ! $? == 0 ]; then
                            break
                        fi

                        read -ep "Enter the name of the snapshot to delete: " snapshot_name
                        
                        virsh snapshot-delete "$vm_name" "$snapshot_name"
                        ;;
                    3)
                        # Revert to a snapshot of a virtual machine
                        read -ep "Enter the name of the virtual machine: " vm_name

                        virsh snapshot-list "$vm_name"
                        if [ ! $? == 0 ]; then
                            break
                        fi
                        
                        read -ep "Enter the name of the snapshot to revert to: " snapshot_name
                        
                        virsh snapshot-revert "$vm_name" "$snapshot_name"
                        if [ ! $? == 0 ]; then
                            echo "Failed to revert snapshot ""$snapshot_name"""
                            break
                        fi
                        ;;
                    q)
                        # Back to main menu
                        break
                        ;;
                    *)
                        echo "Invalid choice. Please enter a valid option."
                        ;;
                esac
            done
            ;;
        
        5)
            # Edit Properties
            while true; do
                echo -e "\n====================== Edit Properties ======================"
                echo "1. Edit a VM        2. Edit a storage pool  3. Edit a network"
                echo "4. Edit a snapshot  q. Back to main menu"
                echo ""
                echo ""
                read -ep "Enter your choice: " xml_manage_choice

                case $xml_manage_choice in
                    1)  
                        # edit a vm
                        read -ep "Enter the VM name: " vm_name
                        virsh edit "$vm_name"
                        ;;
                    2)
                        # edit a storage pool
                        read -ep "Enter the storage pool name [default]: " pool_name
                        if [ -z "$pool_name" ]; then
                            pool_name="default"
                        fi
                        virsh pool-edit "$pool_name"
                        ;;
                    3)
                        # edit a network
                        read -ep "Enter the network name [default]: " net_name
                        if [ -z "$net_name" ]; then
                            net_name="default"
                        fi
                        virsh net-edit "$net_name"
                        ;;
                    4)
                        # edit a snapshot
                        read -ep "Enter the VM name: " vm_name
                        read -ep "Enter the snapshot name: " snap_name
                        virsh snapshot-edit --snapshotname "$snap_name" --domain "$vm_name"
                        ;;
                    q)
                        # Back to Main Menu
                        break
                        ;;
                    *)
                        echo "Invalid choice. Please enter a valid option."
                        ;;
                esac
            done
            ;;
        
        6)

            # Firewall Settings
            while true; do
                echo -e "\n===================== Firewall Settings ====================="
                echo "s. Show ufw status  1. Show listening ports   2. Allow port range"
                echo "3. Deny port range  4. Allow single port      5. Deny single port"
                echo "6. Delete a rule    7. Enable and reload ufw  8. Disable and reset ufw"
                echo "q. Back to main menu"
                echo ""
                read -ep "Enter your choice: " firewall_choice

                case $firewall_choice in
                    s)  
                        # Show ufw status
                        ufw status numbered
                        ;;
                    1)
                        # Show listening ports
                        netstat -l | grep "tcp\|udp"
                        ;;
                    2)
                        # Allow port range
                        read -ep "Enter starting port: " port_start
                        read -ep "Enter ending port: " port_end
                        ufw allow "$port_start":"$port_end"/tcp
                        ufw allow "$port_start":"$port_end"/udp
                        ufw reload
                        ;;
                    3)
                        # Deny Port range
                        read -ep "Enter starting port: " port_start
                        read -ep "Enter ending port: " port_end
                        ufw deny "$port_start":"$port_end"/tcp
                        ufw deny "$port_start":"$port_end"/udp
                        ufw reload
                        ;;
                    4)
                        # Allow single port
                        read -ep "Enter the port number: " port
                        ufw allow "$port"
                        ufw reload
                        ;;
                    5)
                        # Deny single port
                        read -ep "Enter the port number: " port
                        ufw deny "$port"
                        ufw reload
                        ;;
                    6)
                        # Delete a rule
                        read -ep "Enter the rule number to delete: " rule_number
                        ufw delete "$rule_number"
                        ufw reload
                        ;;
                    7)
                        # ufw enable and reload
                        ufw enable
                        ufw reload
                        ;;
                    8)
                        # ufw disable and reset
                        ufw disable
                        ufw reset
                        ;;
                    q)
                        # Back to Main Menu
                        break
                        ;;
                    *)
                        echo "Invalid choice. Please enter a valid option."
                        ;;
                esac
            done
            ;;
        7) 
            # Manage Port forwarding
            while true; do
                echo -e "\n==================================== Manage Port Forwarding ===================================="
                echo "s. Show port forwarding rules        1. List DHCP leases from a network  2. Add port forwarding to a VM"  
                echo "3. Remove port forwarding from a VM  4. Edit port forwarding rule file   q. Back to main menu"
                echo ""
                read -ep "Enter your choice: " port_choice

                case $port_choice in
                    s)  
                        # Show port forwarding ruless
                        iptables -t nat -L -n -v
                        echo ""
                        bash bashvm-show-port-forwarding.sh
                        ;;

                    1)
                        # List DHCP leases
                        read -ep "Enter the network name [default]: " network_name
                        if [ -z "$network_name" ]; then
                            network_name="default"
                        fi

                        virsh net-dhcp-leases "$network_name"
                        ;;

                    2)
                        # Add port forwarding rules to a VM behind a NAT
                        bash bashvm-add-port-forwarding.sh
                        ;;


                    3)
                        # Delete port forwarding rules of vm
                        bash bashvm-remove-port-forwarding.sh
                        ;;

                    4)
                        # Edit port forwarding rules
                        nano /etc/libvirt/hooks/qemu || vim /etc/libvirt/hooks/qemu
                        ;;

                    q)
                        # Back to Main Menu
                        break
                        ;;

                    *)
                        echo "Invalid choice. Please enter a valid option."
                        ;;
                esac
            done
            ;;

        8)
            # VNC / Console Access
                        while true; do
                echo -e "\n======================== VNC / Console Access ========================"
                echo "s. Show assigned VNC ports  1. Add VNC port with password  2. Remove VNC port"        
                echo "3. Console into a vm        q. Back to main menu"
                echo ""
                read -ep "Enter your choice: " vnc_manage_choice

                case $vnc_manage_choice in

                    s)
                        # Show assigned VNC ports
                        echo ""
                        for vm in $(virsh list --all --name); do
                            vm_run=$(virsh domstate "$vm")
                            if [ "$vm_run" != "running" ]; then
                                echo "$vm is not running (state: $vm_run)"
                            else
                                port=$(virsh vncdisplay "$vm" 2>/dev/null | sed 's/^://')
                                if [ -z "$port" ]; then
                                    echo "VM: $vm, VNC Port: none"
                                else
                                    echo "VM: $vm, VNC Port: $((5900 + port))"
                                fi
                            fi
                            echo ""
                        done
                        ;;

                    1)
                        # Add vnc access with password
                        read -ep "Enter the name of the virtual machine (e.g., vm1): " vm_name
                        read -ep "Enter a VNC password to use (e.g., pass123): " vnc_pass

                        add_vnc=" <channel type='unix'>
                            <target type='virtio' name='org.qemu.guest_agent.0'/>
                            <address type='virtio-serial' controller='0' bus='0' port='1'/>
                            </channel>
                            <input type='tablet' bus='usb'>
                            <address type='usb' bus='0' port='1'/>
                            </input>
                            <input type='mouse' bus='ps2'/>
                            <input type='keyboard' bus='ps2'/>
                            <graphics type='vnc' port='-1' autoport='yes' listen='0.0.0.0' passwd='"$vnc_pass"'>
                            <listen type='address' address='0.0.0.0'/>
                            </graphics>
                            <sound model='ich9'>
                            <address type='pci' domain='0x0000' bus='0x00' slot='0x1b' function='0x0'/>
                            </sound>
                            <audio id='1' type='none'/>
                            <video>
                            <model type='qxl' ram='65536' vram='65536' vgamem='16384' heads='1' primary='yes'/>
                            <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x0'/>
                            </video>
                            <memballoon model='virtio'>
                            <address type='pci' domain='0x0000' bus='0x05' slot='0x00' function='0x0'/>
                            </memballoon>
                            <rng model='virtio'>
                            <backend model='random'>/dev/urandom</backend>
                            <address type='pci' domain='0x0000' bus='0x06' slot='0x00' function='0x0'/>
                            </rng>
                        </devices>
                        </domain>"

                        virsh dumpxml "$vm_name" | sed -n '/console/q;p' > "$vm_name".xml
                        echo "$add_vnc" >> "$vm_name".xml
                        virsh define "$vm_name".xml
                        rm "$vm_name".xml
                        echo "Please shutdown then start the vm for the changes to take effect"
                        ;;
                    2)
                        # Remove VNC Port
                        read -ep "Enter the name of the virtual machine: " vm_name
                        remove_vnc=" <channel type='unix'>
                            <target type='virtio' name='org.qemu.guest_agent.0'/>
                            <address type='virtio-serial' controller='0' bus='0' port='1'/>
                            </channel>
                            <input type='tablet' bus='usb'>
                            <address type='usb' bus='0' port='1'/>
                            </input>
                            <input type='mouse' bus='ps2'/>
                            <input type='keyboard' bus='ps2'/>
                            <sound model='ich9'>
                            <address type='pci' domain='0x0000' bus='0x00' slot='0x1b' function='0x0'/>
                            </sound>
                            <audio id='1' type='none'/>
                            <video>
                            <model type='qxl' ram='65536' vram='65536' vgamem='16384' heads='1' primary='yes'/>
                            <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x0'/>
                            </video>
                            <memballoon model='virtio'>
                            <address type='pci' domain='0x0000' bus='0x05' slot='0x00' function='0x0'/>
                            </memballoon>
                            <rng model='virtio'>
                            <backend model='random'>/dev/urandom</backend>
                            <address type='pci' domain='0x0000' bus='0x06' slot='0x00' function='0x0'/>
                            </rng>
                        </devices>
                        </domain>"

                        virsh dumpxml "$vm_name" | sed -n '/console/q;p' > "$vm_name".xml
                        echo "$remove_vnc" >> "$vm_name".xml
                        virsh define "$vm_name".xml
                        rm "$vm_name".xml
                        echo "Please shutdown then start the vm for the changes to take effect"
                        ;;

                    3)
                        # Console into a VM
                        read -ep "Enter the VM name to console into: " hostname
                        virsh console "$hostname"
                        ;;
                        
                    q)
                        # Back to Main Menu
                        break
                        ;;
                    *)
                        echo "Invalid choice. Please enter a valid option."
                        ;;
                esac
            done
            ;;
        9)
            # System Monitor
            btop
            ;;
        10)
            # Manage Port forwarding
            while true; do
                echo -e "\n==================================== VM Monitor ===================================="
                echo "s. Show all virtual machines  1. VCPU usage of a VM     2. Memory usage of a VM"  
                echo "3. Disk usage of a VM         4. Network usage of a VM  5. All usage metrics of a VM"
                echo "q. Back to main menu"
                echo ""
                read -ep "Enter your choice: " port_choice

                case $port_choice in
                    s)  
                        # Show all virtual machines
                        virsh list --all
                        ;;

                    1)
                        read -ep "Enter the name of the VM: " vm_name

                        vm_check=$(virsh dominfo "$vm_name")
                        if [ ! $? == 0 ];then
                            break
                        fi

                        # Setting the vcpu core count
                        cpu_count=$(virsh dominfo $vm_name | grep "CPU(s)" | awk '{print $2}')
                        # Counting starts at 0 so take away 1
                        cpu_count=$(( $cpu_count - 1 ))

                        # Loop through each core to output the usage
                        for ((i = 0; i <= $cpu_count; i++)); do
                            # Begin init time of vcpu
                            cpu_time_1=$(virsh domstats $vm_name | grep "vcpu.$i.time" | cut -d= -f2)
                            # Sleep
                            sleep 1
                            # End of init time of vcpu
                            cpu_time_2=$(virsh domstats $vm_name | grep "vcpu.$i.time" | cut -d= -f2)
                            # Delta is to be equal of time between recordings
                            delta_t=1
                            # Calculate the difference in CPU time (nanoseconds)
                            delta_cpu_time=$((cpu_time_2 - cpu_time_1))
                            # Normalize CPU usage as a percentage of total time available
                            cpu_usage=$(echo "scale=2; ($delta_cpu_time / ($delta_t * 1000000000)) * 100" | bc)
                            printf "CPU %d Usage: %.2f%%\n" "$i" "$cpu_usage"
                        done
                        ;;
                    2)
                        read -ep "Enter the name of the VM: " vm_name

                        vm_check=$(virsh dominfo "$vm_name")
                        if [ ! $? == 0 ];then
                            break
                        fi

                        # Set the memory reported by the guest as being actively used
                        mem_rss=$(virsh domstats $vm_name | grep "balloon.rss" | cut -d= -f2)
                        # Set the memory reported by the guest as being available
                        mem_ava=$(virsh domstats $vm_name | grep "balloon.available" | cut -d= -f2)
                        # Calculate the usage percentage
                        memory_usage=$(echo "scale=2; ($mem_rss / ($mem_rss + $mem_ava)) * 100" | bc)
                        echo "Memory Usage: $memory_usage%"
                    ;;

                    3)  
                        #Disk usage
                        read -ep "Enter the name of the VM: " vm_name

                        vm_check=$(virsh dominfo "$vm_name")
                        if [ ! $? == 0 ];then
                            break
                        fi

                        disk=$(virsh domblklist $vm_name | grep v | awk '{print $1}')
                        # Set the total allocated disk space
                        disk_total=$(virsh guestinfo $vm_name | grep fs.0 | grep "total" | cut -d: -f2)
                        # Set the used disk space
                        disk_used=$(virsh guestinfo $vm_name | grep fs.0 | grep "used" | cut -d: -f2)
                        # Calculate the percentage value of the used disk space
                        disk_usage=$(echo "scale=2; ($disk_used / $disk_total) * 100" | bc)
                        echo "Disk Usage: $disk_usage%"

                    ;;

                    4)
                        read -ep "Enter the name of the VM: " vm_name

                        vm_check=$(virsh dominfo "$vm_name")
                        if [ ! $? == 0 ];then
                            break
                        fi

                        # Show the virtual interface assigned to the vm and output the usage
                        interface=$(virsh domiflist $vm_name | grep v | awk '{print $1}')
                        ifstat -i $interface 1 1

                    ;;

                    5)
                        #show all metrics
                        bash bashvm-monitor.sh

                    ;;


                    q)
                        # Back to Main Menu
                        break
                        ;;

                    *)
                        echo "Invalid choice. Please enter a valid option."
                        ;;
                esac
            done
        ;;

        11)
            # sqlite editor
            bash bashvm-sqlite-editor.sh
            ;;

        q)
            # Exit the script
            echo "Exiting."
            exit 0
            ;;
        *)
            echo "Invalid choice. Please enter a valid option."
            ;;
    esac
done
