Feat: Node orchestration UX improvements (#6848)

* improve nginx playbook

* improve configure-vm script

* improve initialise-vm script

* expand config naming options

* provide args docs

* syntax fix

* address rabbitai comments

* cleanup ansible

* document ansible changes

* fix review comments

* update scraed data

* fix max comment review
This commit is contained in:
import this
2026-06-04 12:59:50 +02:00
committed by GitHub
parent 4ad00dba3d
commit c7780d2d34
18 changed files with 376 additions and 268 deletions
+103 -62
View File
@@ -1,36 +1,101 @@
#!/bin/bash
# detect active network interface
INTERFACE=$(ip -o link show | awk -F': ' '{print $2}' | grep -v lo | head -n 1)
usage() {
local code="${1:-0}"
cat <<EOF
Usage: $0 [OPTIONS]
echo "Detected active network interface: $INTERFACE"
read -p "Is this correct? (y/n): " CONFIRM
if [[ "$CONFIRM" != "y" ]]; then
echo "Exiting. Please manually specify the correct network interface."
Options:
-i, --interface Network interface (optional; auto-detected if omitted)
-4, --ipv4 IPv4 address for the VM (optional)
-6, --ipv6 IPv6 address for the VM (optional)
-g, --gateway4 IPv4 gateway of the host server (optional)
-G, --gateway6 IPv6 gateway of the host server (optional)
-y, --yes Skip all confirmation prompts (auto-confirm)
-h, --help Show this help message
Example:
$0 --ipv4 192.168.1.100 --gateway4 192.168.1.1 --ipv6 2001:db8::1 --gateway6 2001:db8::fffe
$0 --ipv4 192.168.1.100 --gateway4 192.168.1.1 --yes
EOF
exit "$code"
}
# --- parse flags ---
INTERFACE=""
IPv4_VM=""
IPv6_VM=""
IPv4_GATEWAY_HOST_SERVER=""
IPv6_GATEWAY_HOST_SERVER=""
AUTO_YES=false
while [[ $# -gt 0 ]]; do
case "$1" in
-i|--interface)
[[ -n "${2:-}" && "${2:0:1}" != "-" ]] || { echo "Error: --interface requires a value."; exit 1; }
INTERFACE="$2"; shift 2 ;;
-4|--ipv4)
[[ -n "${2:-}" && "${2:0:1}" != "-" ]] || { echo "Error: --ipv4 requires a value."; exit 1; }
IPv4_VM="$2"; shift 2 ;;
-6|--ipv6)
[[ -n "${2:-}" && "${2:0:1}" != "-" ]] || { echo "Error: --ipv6 requires a value."; exit 1; }
IPv6_VM="$2"; shift 2 ;;
-g|--gateway4)
[[ -n "${2:-}" && "${2:0:1}" != "-" ]] || { echo "Error: --gateway4 requires a value."; exit 1; }
IPv4_GATEWAY_HOST_SERVER="$2"; shift 2 ;;
-G|--gateway6)
[[ -n "${2:-}" && "${2:0:1}" != "-" ]] || { echo "Error: --gateway6 requires a value."; exit 1; }
IPv6_GATEWAY_HOST_SERVER="$2"; shift 2 ;;
-y|--yes) AUTO_YES=true; shift ;;
-h|--help) usage ;;
*)
echo "Error: Unknown option: $1"
usage 1
;;
esac
done
# at least one of IPv4 or IPv6 must be provided
if [[ -z "$IPv4_VM" && -z "$IPv6_VM" ]]; then
echo "Error: At least one of --ipv4 or --ipv6 must be provided."
echo "Run '$0 --help' for usage."
exit 1
fi
# prompt for network settings
read -p "Enter IPv4 address for VM (leave blank if not used): " IPv4_VM
read -p "Enter IPv6 address for VM (leave blank if not used): " IPv6_VM
read -p "Enter IPv4 gateway (host server, leave blank if not used): " IPv4_GATEWAY_HOST_SERVER
read -p "Enter IPv6 gateway (host server, leave blank if not used): " IPv6_GATEWAY_HOST_SERVER
confirm() {
local prompt="$1"
if $AUTO_YES; then
echo "${prompt} [Y/n] (auto-confirmed)"
return 0
fi
read -p "${prompt} [Y/n]: " REPLY
[[ -z "$REPLY" || "$REPLY" == "y" || "$REPLY" == "Y" ]]
}
# resize partition
# --- detect or validate interface ---
if [[ -z "$INTERFACE" ]]; then
INTERFACE=$(ip -o link show | awk -F': ' '{print $2}' | grep -v lo | head -n 1)
echo "Detected active network interface: $INTERFACE"
if ! confirm "Is this correct?"; then
echo "Exiting. Re-run with --interface <name> to specify one manually."
exit 1
fi
else
echo "Using network interface: $INTERFACE"
fi
# --- resize partition ---
echo "Expanding partition and resizing filesystem..."
growpart /dev/vda 1
resize2fs /dev/vda1
df -h
# ask before continuing
read -p "Continue with network configuration? (y/n): " CONTINUE
if [[ "$CONTINUE" != "y" ]]; then
if ! confirm "Continue with network configuration?"; then
echo "Exiting."
exit 1
fi
# generate Netplan config
# --- generate Netplan config ---
NETPLAN_CONFIG="/etc/netplan/01-network-config.yaml"
echo "Creating Netplan configuration at $NETPLAN_CONFIG..."
@@ -45,28 +110,19 @@ network:
addresses:
EOF
# append IPv4 address if provided
if [[ -n "$IPv4_VM" ]]; then
echo " - $IPv4_VM/24" >> $NETPLAN_CONFIG
fi
[[ -n "$IPv4_VM" ]] && echo " - $IPv4_VM/24" >> $NETPLAN_CONFIG
[[ -n "$IPv6_VM" ]] && echo " - $IPv6_VM/64" >> $NETPLAN_CONFIG
# append IPv6 address if provided
if [[ -n "$IPv6_VM" ]]; then
echo " - $IPv6_VM/64" >> $NETPLAN_CONFIG
fi
echo " routes:" >> $NETPLAN_CONFIG
# append IPv4 route if provided
if [[ -n "$IPv4_GATEWAY_HOST_SERVER" ]]; then
echo " - to: default" >> $NETPLAN_CONFIG
echo " via: $IPv4_GATEWAY_HOST_SERVER" >> $NETPLAN_CONFIG
fi
# append IPv6 route if provided
if [[ -n "$IPv6_GATEWAY_HOST_SERVER" ]]; then
echo " - to: default" >> $NETPLAN_CONFIG
echo " via: $IPv6_GATEWAY_HOST_SERVER" >> $NETPLAN_CONFIG
if [[ -n "$IPv4_GATEWAY_HOST_SERVER" || -n "$IPv6_GATEWAY_HOST_SERVER" ]]; then
echo " routes:" >> $NETPLAN_CONFIG
if [[ -n "$IPv4_GATEWAY_HOST_SERVER" ]]; then
echo " - to: default" >> $NETPLAN_CONFIG
echo " via: $IPv4_GATEWAY_HOST_SERVER" >> $NETPLAN_CONFIG
fi
if [[ -n "$IPv6_GATEWAY_HOST_SERVER" ]]; then
echo " - to: default" >> $NETPLAN_CONFIG
echo " via: $IPv6_GATEWAY_HOST_SERVER" >> $NETPLAN_CONFIG
fi
fi
cat <<EOF >> $NETPLAN_CONFIG
@@ -78,58 +134,43 @@ cat <<EOF >> $NETPLAN_CONFIG
- 2001:4860:4860::8888 # Google IPv6 DNS
EOF
# secure Netplan config
chmod 600 $NETPLAN_CONFIG
# generate Netplan configuration
netplan generate
# ask before applying Netplan
read -p "Apply Netplan changes? (y/n): " CONTINUE
if [[ "$CONTINUE" != "y" ]]; then
if ! confirm "Apply Netplan changes?"; then
echo "Exiting."
exit 1
fi
# apply Netplan and verify settings
netplan --debug apply
# show IP configurations
ip -4 a
ip -6 a
ip -4 r
ip -6 r
# test network connectivity
echo "Testing IPv4 connectivity for 10 seconds..."
timeout 10 ping -4 google.com
echo "Testing IPv6 connectivity for 10 seconds..."
timeout 10 ping -6 google.com
# ask before updating system
read -p "Proceed with system update and upgrade? (y/n): " CONTINUE
if [[ "$CONTINUE" != "y" ]]; then
echo "Skipping updates."
else
if confirm "Proceed with system update and upgrade?"; then
apt update && apt upgrade -y
else
echo "Skipping updates."
fi
# generate SSH host keys without password
# --- SSH setup ---
echo "Generating SSH host keys..."
ssh-keygen -t rsa -f /etc/ssh/ssh_host_rsa_key -N ""
ssh-keygen -t dsa -f /etc/ssh/ssh_host_dsa_key -N ""
ssh-keygen -t ecdsa -f /etc/ssh/ssh_host_ecdsa_key -N ""
ssh-keygen -t rsa -f /etc/ssh/ssh_host_rsa_key -N ""
ssh-keygen -t dsa -f /etc/ssh/ssh_host_dsa_key -N ""
ssh-keygen -t ecdsa -f /etc/ssh/ssh_host_ecdsa_key -N ""
ssh-keygen -t ed25519 -f /etc/ssh/ssh_host_ed25519_key -N ""
# restart SSH service
systemctl restart ssh.service
# ensure ~/.ssh directory exists
mkdir -p ~/.ssh
# Open authorized_keys file for user input
echo "# Add your admin SSH keys here, save and exit!" > ~/.ssh/authorized_keys
nano ~/.ssh/authorized_keys
echo "Setup complete! Try to ping and ssh from the outside before killing this console"
echo "Setup complete! Try to ping and ssh from the outside before killing this console"
+101 -80
View File
@@ -1,6 +1,86 @@
#!/bin/bash
# check if noble-server-cloudimg-amd64.img is in working dir - if not, wget it
usage() {
local code="${1:-0}"
cat <<EOF
Usage: $0 [OPTIONS]
Options:
-n, --name VM name (required)
-p, --password Root password (required)
-c, --cpus Number of vCPUs (required)
-r, --ram RAM in MB (required); e.g. 2048, 4096, 8192
-s, --size Disk size to add in GB (required); e.g. 50, 100, 200
-h, --help Show this help message
Example:
$0 --name myvm --password secret --cpus 4 --ram 8192 --size 100
EOF
exit "$code"
}
# --- parse flags ---
VM_NAME=""
PASSWORD=""
VCPUS=""
RAM=""
SIZE=""
while [[ $# -gt 0 ]]; do
case "$1" in
-n|--name)
[[ -n "${2:-}" && "${2:0:1}" != "-" ]] || { echo "Error: --name requires a value."; exit 1; }
VM_NAME="$2"; shift 2 ;;
-p|--password)
[[ -n "${2:-}" && "${2:0:1}" != "-" ]] || { echo "Error: --password requires a value."; exit 1; }
PASSWORD="$2"; shift 2 ;;
-c|--cpus)
[[ -n "${2:-}" && "${2:0:1}" != "-" ]] || { echo "Error: --cpus requires a value."; exit 1; }
VCPUS="$2"; shift 2 ;;
-r|--ram)
[[ -n "${2:-}" && "${2:0:1}" != "-" ]] || { echo "Error: --ram requires a value."; exit 1; }
RAM="$2"; shift 2 ;;
-s|--size)
[[ -n "${2:-}" && "${2:0:1}" != "-" ]] || { echo "Error: --size requires a value."; exit 1; }
SIZE="$2"; shift 2 ;;
-h|--help) usage ;;
*)
echo "Error: Unknown option: $1"
usage 1
;;
esac
done
# --- validate required flags ---
MISSING=()
[[ -z "$VM_NAME" ]] && MISSING+=("--name")
[[ -z "$PASSWORD" ]] && MISSING+=("--password")
[[ -z "$VCPUS" ]] && MISSING+=("--cpus")
[[ -z "$RAM" ]] && MISSING+=("--ram")
[[ -z "$SIZE" ]] && MISSING+=("--size")
if [[ ${#MISSING[@]} -gt 0 ]]; then
echo "Error: Missing required flags: ${MISSING[*]}"
echo "Run '$0 --help' for usage."
exit 1
fi
if [[ ! "$VCPUS" =~ ^[0-9]+$ || "$VCPUS" -lt 1 ]]; then
echo "Error: --cpus must be a positive integer."
exit 1
fi
if [[ ! "$RAM" =~ ^[0-9]+$ || "$RAM" -lt 256 ]]; then
echo "Error: --ram must be a positive integer (minimum 256 MB)."
exit 1
fi
if [[ ! "$SIZE" =~ ^[0-9]+$ || "$SIZE" -lt 1 ]]; then
echo "Error: --size must be a positive integer in GB."
exit 1
fi
# --- check / download base image ---
if [[ ! -f noble-server-cloudimg-amd64.img ]]; then
echo "Base image not found. Downloading noble-server-cloudimg-amd64.img..."
wget https://cloud-images.ubuntu.com/noble/current/noble-server-cloudimg-amd64.img
@@ -10,99 +90,40 @@ if [[ ! -f noble-server-cloudimg-amd64.img ]]; then
fi
fi
# prompt for VM_NAME
read -p "Enter VM name: " VM_NAME
if [[ -z "$VM_NAME" ]]; then
echo "Error: VM_NAME cannot be empty. Exiting."
exit 1
fi
# prompt for PASSWORD w silent input
read -s -p "Enter password for the VM: " PASSWORD
echo
if [[ -z "$PASSWORD" ]]; then
echo "Error: PASSWORD cannot be empty. Exiting."
exit 1
fi
# prompt for number of vCPUs
read -p "Enter the number of vCPUs for the VM: " VCPUS
if [[ -z "$VCPUS" || ! "$VCPUS" =~ ^[0-9]+$ ]]; then
echo "Error: Invalid number of vCPUs. Exiting."
exit 1
fi
# prompt for RAM size with suggestions
DEFAULT_RAM=4096
HALF_RAM=$((DEFAULT_RAM / 2))
DOUBLE_RAM=$((DEFAULT_RAM * 2))
TRIPLE_RAM=$((DEFAULT_RAM * 3))
FOUR_TIMES_RAM=$((DEFAULT_RAM * 4))
SIX_TIMES_RAM=$((DEFAULT_RAM * 6))
EIGHT_TIMES_RAM=$((DEFAULT_RAM * 8))
echo "Choose the amount of RAM for the VM:"
echo "1) $HALF_RAM MB"
echo "2) $DEFAULT_RAM MB (recommended)"
echo "3) $DOUBLE_RAM MB"
echo "4) $TRIPLE_RAM MB"
echo "5) $FOUR_TIMES_RAM MB"
echo "6) $SIX_TIMES_RAM MB"
echo "7) $EIGHT_TIMES_RAM MB"
read -p "Enter your choice (1-7) or specify a custom amount in MB: " RAM_CHOICE
case $RAM_CHOICE in
1) RAM=$HALF_RAM ;;
2) RAM=$DEFAULT_RAM ;;
3) RAM=$DOUBLE_RAM ;;
4) RAM=$TRIPLE_RAM ;;
5) RAM=$FOUR_TIMES_RAM ;;
6) RAM=$SIX_TIMES_RAM ;;
7) RAM=$EIGHT_TIMES_RAM ;;
*)
if [[ "$RAM_CHOICE" =~ ^[0-9]+$ ]]; then
RAM=$RAM_CHOICE
else
echo "Invalid choice. Exiting."
exit 1
fi
;;
esac
# define image path
IMAGE_PATH="/var/lib/libvirt/images/${VM_NAME}.img"
# copy the base image
if [[ -e "$IMAGE_PATH" ]]; then
echo "Error: $IMAGE_PATH already exists. Choose a different --name or remove the old image first."
exit 1
fi
echo "Copying the base image to $IMAGE_PATH..."
cp noble-server-cloudimg-amd64.img "$IMAGE_PATH"
# install guestfs-tools if missing
echo "Checking and installing guestfs-tools if needed..."
if ! dpkg -l | grep -q guestfs-tools; then
sudo apt update && sudo apt install guestfs-tools -y
fi
# set root password inside the image
echo "Setting root password inside the VM image..."
virt-customize -a "$IMAGE_PATH" --root-password password:"$PASSWORD"
# resize the image
echo "Resizing the image by +100G..."
qemu-img resize "$IMAGE_PATH" +100G
echo "Resizing the image by +${SIZE}G..."
qemu-img resize "$IMAGE_PATH" +${SIZE}G
# install the VM and run log in prompt
echo "Starting VM installation..."
virt-install \
--name "$VM_NAME" \
--ram="$RAM" \
--vcpus="$VCPUS" \
--cpu host \
--hvm \
--disk bus=virtio,path="$IMAGE_PATH" \
--network bridge=br0 \
--graphics none \
--console pty,target_type=serial \
--osinfo ubuntunoble \
--import
--name "$VM_NAME" \
--ram="$RAM" \
--vcpus="$VCPUS" \
--cpu host \
--hvm \
--disk bus=virtio,path="$IMAGE_PATH" \
--network bridge=br0 \
--graphics none \
--console pty,target_type=serial \
--osinfo ubuntunoble \
--import
echo "VM $VM_NAME has been successfully installed!"
echo "VM $VM_NAME has been successfully installed!"