core: validate container ID before pct create to prevent failures (#10729)

* feat: validate container ID before pct create to prevent failures

Add validation to ensure container IDs are not already in use before attempting to create containers. This prevents pct create failures when an ID is already assigned to a VM/LXC or used in LVM volumes.

Changes:
- Add validate_container_id() and get_valid_container_id() functions to build.func
- Validate ID in base_settings() for default installation method
- Validate ID in advanced_settings() dialog with user prompt for next available ID
- Add validation to turnkey.sh with interactive dialog
- Add validation to all-templates.sh with automatic ID correction

Checks performed:
- Container config file existence (/etc/pve/lxc/*.conf)
- VM config file existence (/etc/pve/qemu-server/*.conf)
- LVM logical volume usage

Fixes issue where container creation would fail if the suggested/chosen ID was already in use.

* feat: validate container ID before pct create to prevent failures

Add validation to ensure container IDs are not already in use before attempting to create containers. This prevents pct create failures when an ID is already assigned to a VM/LXC or used in LVM volumes.

Changes:
- Add validate_container_id() and get_valid_container_id() functions to build.func
- Validate ID in base_settings() for default installation method
- Validate ID in advanced_settings() dialog with user prompt for next available ID
- Add validation to turnkey.sh with interactive dialog
- Add validation to all-templates.sh with automatic ID correction

Checks performed:
- Container config file existence (/etc/pve/lxc/*.conf)
- VM config file existence (/etc/pve/qemu-server/*.conf)
- LVM logical volume usage

Fixes issue where container creation would fail if the suggested/chosen ID was already in use.

* Update turnkey.sh

* Update build.func
This commit is contained in:
CanbiZ (MickLesk)
2026-01-12 14:04:28 +01:00
committed by GitHub
parent 97c6c4558a
commit 1ccf90cb27
3 changed files with 197 additions and 6 deletions

View File

@@ -231,6 +231,100 @@ install_ssh_keys_into_ct() {
return 0 return 0
} }
# ------------------------------------------------------------------------------
# validate_container_id()
#
# - Validates if a container ID is available for use
# - Checks if ID is already used by VM or LXC container
# - Checks if ID is used in LVM logical volumes
# - Returns 0 if ID is available, 1 if already in use
# ------------------------------------------------------------------------------
validate_container_id() {
local ctid="$1"
# Check if ID is numeric
if ! [[ "$ctid" =~ ^[0-9]+$ ]]; then
return 1
fi
# Check if config file exists for VM or LXC
if [[ -f "/etc/pve/qemu-server/${ctid}.conf" ]] || [[ -f "/etc/pve/lxc/${ctid}.conf" ]]; then
return 1
fi
# Check if ID is used in LVM logical volumes
if lvs --noheadings -o lv_name 2>/dev/null | grep -qE "(^|[-_])${ctid}($|[-_])"; then
return 1
fi
return 0
}
# ------------------------------------------------------------------------------
# get_valid_container_id()
#
# - Returns a valid, unused container ID
# - If provided ID is valid, returns it
# - Otherwise increments from suggested ID until a free one is found
# - Calls validate_container_id() to check availability
# ------------------------------------------------------------------------------
get_valid_container_id() {
local suggested_id="${1:-$(pvesh get /cluster/nextid)}"
while ! validate_container_id "$suggested_id"; do
suggested_id=$((suggested_id + 1))
done
echo "$suggested_id"
}
# ------------------------------------------------------------------------------
# validate_container_id()
#
# - Validates if a container ID is available for use
# - Checks if ID is already used by VM or LXC container
# - Checks if ID is used in LVM logical volumes
# - Returns 0 if ID is available, 1 if already in use
# ------------------------------------------------------------------------------
validate_container_id() {
local ctid="$1"
# Check if ID is numeric
if ! [[ "$ctid" =~ ^[0-9]+$ ]]; then
return 1
fi
# Check if config file exists for VM or LXC
if [[ -f "/etc/pve/qemu-server/${ctid}.conf" ]] || [[ -f "/etc/pve/lxc/${ctid}.conf" ]]; then
return 1
fi
# Check if ID is used in LVM logical volumes
if lvs --noheadings -o lv_name 2>/dev/null | grep -qE "(^|[-_])${ctid}($|[-_])"; then
return 1
fi
return 0
}
# ------------------------------------------------------------------------------
# get_valid_container_id()
#
# - Returns a valid, unused container ID
# - If provided ID is valid, returns it
# - Otherwise increments from suggested ID until a free one is found
# - Calls validate_container_id() to check availability
# ------------------------------------------------------------------------------
get_valid_container_id() {
local suggested_id="${1:-$(pvesh get /cluster/nextid)}"
while ! validate_container_id "$suggested_id"; do
suggested_id=$((suggested_id + 1))
done
echo "$suggested_id"
}
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# find_host_ssh_keys() # find_host_ssh_keys()
# #
@@ -483,7 +577,15 @@ base_settings() {
RAM_SIZE="${final_ram}" RAM_SIZE="${final_ram}"
VERBOSE=${var_verbose:-"${1:-no}"} VERBOSE=${var_verbose:-"${1:-no}"}
PW=${var_pw:-""} PW=${var_pw:-""}
CT_ID=${var_ctid:-$NEXTID}
# Validate and set Container ID
local requested_id="${var_ctid:-$NEXTID}"
if ! validate_container_id "$requested_id"; then
msg_warn "Container ID $requested_id is already in use. Using next available ID: $(get_valid_container_id "$requested_id")"
requested_id=$(get_valid_container_id "$requested_id")
fi
CT_ID="$requested_id"
HN=${var_hostname:-$NSAPP} HN=${var_hostname:-$NSAPP}
BRG=${var_brg:-"vmbr0"} BRG=${var_brg:-"vmbr0"}
NET=${var_net:-"dhcp"} NET=${var_net:-"dhcp"}
@@ -1308,7 +1410,25 @@ advanced_settings() {
--ok-button "Next" --cancel-button "Back" \ --ok-button "Next" --cancel-button "Back" \
--inputbox "\nSet Container ID" 10 58 "$_ct_id" \ --inputbox "\nSet Container ID" 10 58 "$_ct_id" \
3>&1 1>&2 2>&3); then 3>&1 1>&2 2>&3); then
_ct_id="${result:-$NEXTID}" local input_id="${result:-$NEXTID}"
# Validate that ID is numeric
if ! [[ "$input_id" =~ ^[0-9]+$ ]]; then
whiptail --backtitle "Proxmox VE Helper Scripts" --title "Invalid ID" --msgbox "Container ID must be numeric." 8 58
continue
fi
# Check if ID is already in use
if ! validate_container_id "$input_id"; then
if whiptail --backtitle "Proxmox VE Helper Scripts" --title "ID Already In Use" \
--yesno "Container/VM ID $input_id is already in use.\n\nWould you like to use the next available ID ($(get_valid_container_id "$input_id"))?" 10 58; then
_ct_id=$(get_valid_container_id "$input_id")
else
continue
fi
else
_ct_id="$input_id"
fi
((STEP++)) ((STEP++))
else else
((STEP--)) ((STEP--))

View File

@@ -42,6 +42,29 @@ function msg() {
local TEXT="$1" local TEXT="$1"
echo -e "$TEXT" echo -e "$TEXT"
} }
function validate_container_id() {
local ctid="$1"
# Check if ID is numeric
if ! [[ "$ctid" =~ ^[0-9]+$ ]]; then
return 1
fi
# Check if config file exists for VM or LXC
if [[ -f "/etc/pve/qemu-server/${ctid}.conf" ]] || [[ -f "/etc/pve/lxc/${ctid}.conf" ]]; then
return 1
fi
# Check if ID is used in LVM logical volumes
if lvs --noheadings -o lv_name 2>/dev/null | grep -qE "(^|[-_])${ctid}($|[-_])"; then
return 1
fi
return 0
}
function get_valid_container_id() {
local suggested_id="${1:-$(pvesh get /cluster/nextid)}"
while ! validate_container_id "$suggested_id"; do
suggested_id=$((suggested_id + 1))
done
echo "$suggested_id"
}
function cleanup_ctid() { function cleanup_ctid() {
if pct status $CTID &>/dev/null; then if pct status $CTID &>/dev/null; then
if [ "$(pct status $CTID | awk '{print $2}')" == "running" ]; then if [ "$(pct status $CTID | awk '{print $2}')" == "running" ]; then
@@ -76,7 +99,15 @@ TEMPLATE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "All Templat
# Setup script environment # Setup script environment
NAME=$(echo "$TEMPLATE" | grep -oE '^[^-]+-[^-]+') NAME=$(echo "$TEMPLATE" | grep -oE '^[^-]+-[^-]+')
PASS="$(openssl rand -base64 8)" PASS="$(openssl rand -base64 8)"
# Get valid Container ID
CTID=$(pvesh get /cluster/nextid) CTID=$(pvesh get /cluster/nextid)
if ! validate_container_id "$CTID"; then
warn "Container ID $CTID is already in use."
CTID=$(get_valid_container_id "$CTID")
info "Using next available ID: $CTID"
fi
PCT_OPTIONS=" PCT_OPTIONS="
-features keyctl=1,nesting=1 -features keyctl=1,nesting=1
-hostname $NAME -hostname $NAME

View File

@@ -42,6 +42,29 @@ function msg() {
local TEXT="$1" local TEXT="$1"
echo -e "$TEXT" echo -e "$TEXT"
} }
function validate_container_id() {
local ctid="$1"
# Check if ID is numeric
if ! [[ "$ctid" =~ ^[0-9]+$ ]]; then
return 1
fi
# Check if config file exists for VM or LXC
if [[ -f "/etc/pve/qemu-server/${ctid}.conf" ]] || [[ -f "/etc/pve/lxc/${ctid}.conf" ]]; then
return 1
fi
# Check if ID is used in LVM logical volumes
if lvs --noheadings -o lv_name 2>/dev/null | grep -qE "(^|[-_])${ctid}($|[-_])"; then
return 1
fi
return 0
}
function get_valid_container_id() {
local suggested_id="${1:-$(pvesh get /cluster/nextid)}"
while ! validate_container_id "$suggested_id"; do
suggested_id=$((suggested_id + 1))
done
echo "$suggested_id"
}
function cleanup_ctid() { function cleanup_ctid() {
if pct status $CTID &>/dev/null; then if pct status $CTID &>/dev/null; then
if [ "$(pct status $CTID | awk '{print $2}')" == "running" ]; then if [ "$(pct status $CTID | awk '{print $2}')" == "running" ]; then
@@ -99,9 +122,26 @@ turnkey=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "TurnKey LXCs
# Setup script environment # Setup script environment
PASS="$(openssl rand -base64 8)" PASS="$(openssl rand -base64 8)"
# Prompt user to confirm container ID # Prompt user to confirm container ID
CTID=$(whiptail --backtitle "Container ID" --title "Choose the Container ID" --inputbox "Enter the conatiner ID..." 8 40 $(pvesh get /cluster/nextid) 3>&1 1>&2 2>&3) while true; do
CTID=$(whiptail --backtitle "Container ID" --title "Choose the Container ID" --inputbox "Enter the container ID..." 8 40 $(pvesh get /cluster/nextid) 3>&1 1>&2 2>&3)
# Check if user cancelled
[ -z "$CTID" ] && die "No Container ID selected"
# Validate Container ID
if ! validate_container_id "$CTID"; then
SUGGESTED_ID=$(get_valid_container_id "$CTID")
if whiptail --backtitle "Container ID" --title "ID Already In Use" --yesno "Container/VM ID $CTID is already in use.\n\nWould you like to use the next available ID ($SUGGESTED_ID)?" 10 58; then
CTID="$SUGGESTED_ID"
break
fi
# User declined, loop back to input
else
break
fi
done
# Prompt user to confirm Hostname # Prompt user to confirm Hostname
HOST_NAME=$(whiptail --backtitle "Hostname" --title "Choose the Hostname" --inputbox "Enter the containers Hostname..." 8 40 "turnkey-${turnkey}" 3>&1 1>&2 2>&3) HOST_NAME=$(whiptail --backtitle "Hostname" --title "Choose the Hostname" --inputbox "Enter the containers Hostname..." 8 40 "turnkey-${turnkey}" 3>&1 1>&2 2>&3)
PCT_OPTIONS=" PCT_OPTIONS="
-features keyctl=1,nesting=1 -features keyctl=1,nesting=1
-hostname $HOST_NAME -hostname $HOST_NAME
@@ -206,8 +246,8 @@ echo "TurnKey ${turnkey} password: ${PASS}" >>~/turnkey-${turnkey}.creds # file
TUN_DEVICE_REQUIRED=("openvpn") # Setup this way in case future turnkeys also need tun access TUN_DEVICE_REQUIRED=("openvpn") # Setup this way in case future turnkeys also need tun access
if printf '%s\n' "${TUN_DEVICE_REQUIRED[@]}" | grep -qw "${turnkey}"; then if printf '%s\n' "${TUN_DEVICE_REQUIRED[@]}" | grep -qw "${turnkey}"; then
info "${turnkey} requires access to /dev/net/tun on the host. Modifying the container configuration to allow this." info "${turnkey} requires access to /dev/net/tun on the host. Modifying the container configuration to allow this."
echo "lxc.cgroup2.devices.allow: c 10:200 rwm" >> /etc/pve/lxc/${CTID}.conf echo "lxc.cgroup2.devices.allow: c 10:200 rwm" >>/etc/pve/lxc/${CTID}.conf
echo "lxc.mount.entry: /dev/net/tun dev/net/tun none bind,create=file 0 0" >> /etc/pve/lxc/${CTID}.conf echo "lxc.mount.entry: /dev/net/tun dev/net/tun none bind,create=file 0 0" >>/etc/pve/lxc/${CTID}.conf
sleep 5 sleep 5
fi fi