Merge remote-tracking branch 'upstream/main'

This commit is contained in:
Sam Heinz
2025-06-22 19:54:13 +10:00
190 changed files with 5344 additions and 3045 deletions

View File

@@ -1,867 +0,0 @@
#!/usr/bin/env bash
# Copyright (c) 2021-2025 community-scripts ORG
# Author: MickLesk (Canbiz) && Desert_Gamer
# License: MIT
# Source: https://github.com/gitsang/iptag
function header_info {
clear
cat <<"EOF"
___ ____ _____
|_ _| _ \ _ |_ _|_ _ __ _
| || |_) (_) | |/ _` |/ _` |
| || __/ _ | | (_| | (_| |
|___|_| (_) |_|\__,_|\__, |
|___/
EOF
}
clear
header_info
APP="IP-Tag"
hostname=$(hostname)
# Farbvariablen
YW=$(echo "\033[33m")
GN=$(echo "\033[1;92m")
RD=$(echo "\033[01;31m")
CL=$(echo "\033[m")
BFR="\\r\\033[K"
HOLD=" "
CM=" ✔️ ${CL}"
CROSS=" ✖️ ${CL}"
# This function enables error handling in the script by setting options and defining a trap for the ERR signal.
catch_errors() {
set -Eeuo pipefail
trap 'error_handler $LINENO "$BASH_COMMAND"' ERR
}
# This function is called when an error occurs. It receives the exit code, line number, and command that caused the error, and displays an error message.
error_handler() {
if [ -n "$SPINNER_PID" ] && ps -p $SPINNER_PID >/dev/null; then
kill $SPINNER_PID >/dev/null
fi
printf "\e[?25h"
local exit_code="$?"
local line_number="$1"
local command="$2"
local error_message="${RD}[ERROR]${CL} in line ${RD}$line_number${CL}: exit code ${RD}$exit_code${CL}: while executing command ${YW}$command${CL}"
echo -e "\n$error_message\n"
}
# This function displays a spinner.
spinner() {
local frames=('⠋' '⠙' '⠹' '⠸' '⠼' '⠴' '⠦' '⠧' '⠇' '⠏')
local spin_i=0
local interval=0.1
printf "\e[?25l"
local color="${YWB}"
while true; do
printf "\r ${color}%s${CL}" "${frames[spin_i]}"
spin_i=$(((spin_i + 1) % ${#frames[@]}))
sleep "$interval"
done
}
# This function displays an informational message with a yellow color.
msg_info() {
local msg="$1"
echo -ne "${TAB}${YW}${HOLD}${msg}${HOLD}"
spinner &
SPINNER_PID=$!
}
# This function displays a success message with a green color.
msg_ok() {
if [ -n "$SPINNER_PID" ] && ps -p $SPINNER_PID >/dev/null; then
kill $SPINNER_PID >/dev/null
fi
printf "\e[?25h"
local msg="$1"
echo -e "${BFR}${CM}${GN}${msg}${CL}"
}
# This function displays a error message with a red color.
msg_error() {
if [ -n "$SPINNER_PID" ] && ps -p $SPINNER_PID >/dev/null; then
kill $SPINNER_PID >/dev/null
fi
printf "\e[?25h"
local msg="$1"
echo -e "${BFR}${CROSS}${RD}${msg}${CL}"
}
# Check if service exists
check_service_exists() {
if systemctl is-active --quiet iptag.service; then
return 0
else
return 1
fi
}
# Migrate configuration from old path to new
migrate_config() {
local old_config="/opt/lxc-iptag"
local new_config="/opt/iptag/iptag.conf"
if [[ -f "$old_config" ]]; then
msg_info "Migrating configuration from old path"
if cp "$old_config" "$new_config" &>/dev/null; then
rm -rf "$old_config" &>/dev/null
msg_ok "Configuration migrated and old config removed"
else
msg_error "Failed to migrate configuration"
fi
fi
}
# Update existing installation
update_installation() {
msg_info "Updating IP-Tag Scripts"
systemctl stop iptag.service &>/dev/null
# Create directory if it doesn't exist
if [[ ! -d "/opt/iptag" ]]; then
mkdir -p /opt/iptag
fi
# Migrate config if needed
migrate_config
# Update main script
cat <<'EOF' >/opt/iptag/iptag
#!/bin/bash
# =============== CONFIGURATION =============== #
readonly CONFIG_FILE="/opt/iptag/iptag.conf"
readonly DEFAULT_TAG_FORMAT="full"
readonly DEFAULT_CHECK_INTERVAL=60
# Load the configuration file if it exists
if [ -f "$CONFIG_FILE" ]; then
# shellcheck source=./iptag.conf
source "$CONFIG_FILE"
fi
# Convert IP to integer for comparison
ip_to_int() {
local ip="$1"
local a b c d
IFS=. read -r a b c d <<< "${ip}"
echo "$((a << 24 | b << 16 | c << 8 | d))"
}
# Check if IP is in CIDR
ip_in_cidr() {
local ip="$1" cidr="$2"
ipcalc -c "$ip" "$cidr" >/dev/null 2>&1 || return 1
local network prefix ip_parts net_parts
network=$(echo "$cidr" | cut -d/ -f1)
prefix=$(echo "$cidr" | cut -d/ -f2)
IFS=. read -r -a ip_parts <<< "$ip"
IFS=. read -r -a net_parts <<< "$network"
case $prefix in
8) [[ "${ip_parts[0]}" == "${net_parts[0]}" ]] ;;
16) [[ "${ip_parts[0]}.${ip_parts[1]}" == "${net_parts[0]}.${net_parts[1]}" ]] ;;
24) [[ "${ip_parts[0]}.${ip_parts[1]}.${ip_parts[2]}" == "${net_parts[0]}.${net_parts[1]}.${net_parts[2]}" ]] ;;
32) [[ "$ip" == "$network" ]] ;;
*) return 1 ;;
esac
}
# Format IP address according to the configuration
format_ip_tag() {
local ip="$1"
local format="${TAG_FORMAT:-$DEFAULT_TAG_FORMAT}"
case "$format" in
"last_octet") echo "${ip##*.}" ;;
"last_two_octets") echo "${ip#*.*.}" ;;
*) echo "$ip" ;;
esac
}
# Check if IP is in any CIDRs
ip_in_cidrs() {
local ip="$1" cidrs="$2"
[[ -z "$cidrs" ]] && return 1
local IFS=' '
for cidr in $cidrs; do ip_in_cidr "$ip" "$cidr" && return 0; done
return 1
}
# Check if IP is valid
is_valid_ipv4() {
local ip="$1"
[[ "$ip" =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}$ ]] || return 1
local IFS='.' parts
read -ra parts <<< "$ip"
for part in "${parts[@]}"; do
(( part >= 0 && part <= 255 )) || return 1
done
return 0
}
lxc_status_changed() {
current_lxc_status=$(pct list 2>/dev/null)
if [ "${last_lxc_status}" == "${current_lxc_status}" ]; then
return 1
else
last_lxc_status="${current_lxc_status}"
return 0
fi
}
vm_status_changed() {
current_vm_status=$(qm list 2>/dev/null)
if [ "${last_vm_status}" == "${current_vm_status}" ]; then
return 1
else
last_vm_status="${current_vm_status}"
return 0
fi
}
fw_net_interface_changed() {
current_net_interface=$(ifconfig | grep "^fw")
if [ "${last_net_interface}" == "${current_net_interface}" ]; then
return 1
else
last_net_interface="${current_net_interface}"
return 0
fi
}
# Get VM IPs using MAC addresses and ARP table
get_vm_ips() {
local vmid=$1 ips="" macs found_ip=false
qm status "$vmid" 2>/dev/null | grep -q "status: running" || return
macs=$(qm config "$vmid" 2>/dev/null | grep -E 'net[0-9]+' | grep -oE '[a-fA-F0-9]{2}(:[a-fA-F0-9]{2}){5}')
[[ -z "$macs" ]] && return
for mac in $macs; do
local ip
ip=$(arp -an 2>/dev/null | grep -i "$mac" | grep -oE '([0-9]{1,3}\.){3}[0-9]{1,3}')
[[ -n "$ip" ]] && { ips+="$ip "; found_ip=true; }
done
if ! $found_ip; then
local agent_ip
agent_ip=$(qm agent "$vmid" network-get-interfaces 2>/dev/null | grep -oE '([0-9]{1,3}\.){3}[0-9]{1,3}' || true)
[[ -n "$agent_ip" ]] && ips+="$agent_ip "
fi
echo "${ips% }"
}
# Update tags
update_tags() {
local type="$1" vmid="$2" config_cmd="pct"
[[ "$type" == "vm" ]] && config_cmd="qm"
local current_ips_full
if [[ "$type" == "lxc" ]]; then
current_ips_full=$(lxc-info -n "${vmid}" -i 2>/dev/null | grep -E "^IP:" | awk '{print $2}')
else
current_ips_full=$(get_vm_ips "${vmid}")
fi
[[ -z "$current_ips_full" ]] && return
local current_tags=() next_tags=() current_ip_tags=()
mapfile -t current_tags < <($config_cmd config "${vmid}" 2>/dev/null | grep tags | awk '{print $2}' | sed 's/;/\n/g')
# Separate IP and non-IP tags
for tag in "${current_tags[@]}"; do
if is_valid_ipv4 "${tag}" || [[ "$tag" =~ ^[0-9]+(\.[0-9]+)*$ ]]; then
current_ip_tags+=("${tag}")
else
next_tags+=("${tag}")
fi
done
local formatted_ips=() needs_update=false added_ips=()
for ip in ${current_ips_full}; do
if is_valid_ipv4 "$ip" && ip_in_cidrs "$ip" "${CIDR_LIST[*]}"; then
local formatted_ip=$(format_ip_tag "$ip")
formatted_ips+=("$formatted_ip")
if [[ ! " ${current_ip_tags[*]} " =~ " ${formatted_ip} " ]]; then
needs_update=true
added_ips+=("$formatted_ip")
next_tags+=("$formatted_ip")
fi
fi
done
[[ ${#formatted_ips[@]} -eq 0 ]] && return
# Add existing IP tags that are still valid
for tag in "${current_ip_tags[@]}"; do
if [[ " ${formatted_ips[*]} " =~ " ${tag} " ]]; then
if [[ ! " ${next_tags[*]} " =~ " ${tag} " ]]; then
next_tags+=("$tag")
fi
fi
done
if [[ "$needs_update" == true ]]; then
echo "${type^} ${vmid}: adding IP tags: ${added_ips[*]}"
$config_cmd set "${vmid}" -tags "$(IFS=';'; echo "${next_tags[*]}")" &>/dev/null
elif [[ ${#current_ip_tags[@]} -gt 0 ]]; then
echo "${type^} ${vmid}: IP tags already set: ${current_ip_tags[*]}"
else
echo "${type^} ${vmid}: setting initial IP tags: ${formatted_ips[*]}"
$config_cmd set "${vmid}" -tags "$(IFS=';'; echo "${formatted_ips[*]}")" &>/dev/null
fi
}
# Check if status changed
check_status() {
local type="$1" current
case "$type" in
"lxc") current=$(pct list 2>/dev/null | grep -v VMID) ;;
"vm") current=$(qm list 2>/dev/null | grep -v VMID) ;;
"fw") current=$(ifconfig 2>/dev/null | grep "^fw") ;;
esac
local last_var="last_${type}_status"
[[ "${!last_var}" == "$current" ]] && return 1
eval "$last_var='$current'"
return 0
}
# Update all instances
update_all() {
local type="$1" list_cmd="pct" vmids count=0
[[ "$type" == "vm" ]] && list_cmd="qm"
vmids=$($list_cmd list 2>/dev/null | grep -v VMID | awk '{print $1}')
for vmid in $vmids; do ((count++)); done
echo "Found ${count} running ${type}s"
[[ $count -eq 0 ]] && return
for vmid in $vmids; do
update_tags "$type" "$vmid"
done
}
# Main check function
check() {
local current_time changes_detected=false
current_time=$(date +%s)
for type in "lxc" "vm"; do
local interval_var="${type^^}_STATUS_CHECK_INTERVAL"
local last_check_var="last_${type}_check_time"
local last_update_var="last_update_${type}_time"
if [[ "${!interval_var}" -gt 0 ]] && (( current_time - ${!last_check_var} >= ${!interval_var} )); then
echo "Checking ${type^^} status..."
eval "${last_check_var}=\$current_time"
if check_status "$type"; then
changes_detected=true
update_all "$type"
eval "${last_update_var}=\$current_time"
fi
fi
if (( current_time - ${!last_update_var} >= FORCE_UPDATE_INTERVAL )); then
echo "Force updating ${type} tags..."
changes_detected=true
update_all "$type"
eval "${last_update_var}=\$current_time"
fi
done
if [[ "${FW_NET_INTERFACE_CHECK_INTERVAL}" -gt 0 ]] && \
(( current_time - last_fw_check_time >= FW_NET_INTERFACE_CHECK_INTERVAL )); then
echo "Checking network interfaces..."
last_fw_check_time=$current_time
if check_status "fw"; then
changes_detected=true
update_all "lxc"
update_all "vm"
last_update_lxc_time=$current_time
last_update_vm_time=$current_time
fi
fi
$changes_detected || echo "No changes detected in system status"
}
# Initialize time variables
declare -g last_lxc_status="" last_vm_status="" last_fw_status=""
declare -g last_lxc_check_time=0 last_vm_check_time=0 last_fw_check_time=0
declare -g last_update_lxc_time=0 last_update_vm_time=0
# Main loop
main() {
while true; do
check
sleep "${LOOP_INTERVAL:-$DEFAULT_CHECK_INTERVAL}"
done
}
main
EOF
chmod +x /opt/iptag/iptag
# Update service file
cat <<EOF >/lib/systemd/system/iptag.service
[Unit]
Description=IP-Tag service
After=network.target
[Service]
Type=simple
ExecStart=/opt/iptag/iptag
Restart=always
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload &>/dev/null
systemctl enable -q --now iptag.service &>/dev/null
msg_ok "Updated IP-Tag Scripts"
}
# Main installation process
if check_service_exists; then
while true; do
read -p "IP-Tag service is already installed. Do you want to update it? (y/n): " yn
case $yn in
[Yy]*)
update_installation
exit 0
;;
[Nn]*)
msg_error "Installation cancelled."
exit 0
;;
*)
msg_error "Please answer yes or no."
;;
esac
done
fi
while true; do
read -p "This will install ${APP} on ${hostname}. Proceed? (y/n): " yn
case $yn in
[Yy]*)
break
;;
[Nn]*)
msg_error "Installation cancelled."
exit
;;
*)
msg_error "Please answer yes or no."
;;
esac
done
if ! pveversion | grep -Eq "pve-manager/8\.[0-4](\.[0-9]+)*"; then
msg_error "This version of Proxmox Virtual Environment is not supported"
msg_error "⚠️ Requires Proxmox Virtual Environment Version 8.0 or later."
msg_error "Exiting..."
sleep 2
exit
fi
FILE_PATH="/usr/local/bin/iptag"
if [[ -f "$FILE_PATH" ]]; then
msg_info "The file already exists: '$FILE_PATH'. Skipping installation."
exit 0
fi
msg_info "Installing Dependencies"
apt-get update &>/dev/null
apt-get install -y ipcalc net-tools &>/dev/null
msg_ok "Installed Dependencies"
msg_info "Setting up IP-Tag Scripts"
mkdir -p /opt/iptag
msg_ok "Setup IP-Tag Scripts"
# Migrate config if needed
migrate_config
msg_info "Setup Default Config"
if [[ ! -f /opt/iptag/iptag.conf ]]; then
cat <<EOF >/opt/iptag/iptag.conf
# Configuration file for LXC IP tagging
# List of allowed CIDRs
CIDR_LIST=(
192.168.0.0/16
172.16.0.0/12
10.0.0.0/8
100.64.0.0/10
)
# Tag format options:
# - "full": full IP address (e.g., 192.168.0.100)
# - "last_octet": only the last octet (e.g., 100)
# - "last_two_octets": last two octets (e.g., 0.100)
TAG_FORMAT="full"
# Interval settings (in seconds)
LOOP_INTERVAL=60
VM_STATUS_CHECK_INTERVAL=60
FW_NET_INTERFACE_CHECK_INTERVAL=60
LXC_STATUS_CHECK_INTERVAL=60
FORCE_UPDATE_INTERVAL=1800
EOF
msg_ok "Setup default config"
else
msg_ok "Default config already exists"
fi
msg_info "Setup Main Function"
if [[ ! -f /opt/iptag/iptag ]]; then
cat <<'EOF' >/opt/iptag/iptag
#!/bin/bash
# =============== CONFIGURATION =============== #
CONFIG_FILE="/opt/iptag/iptag.conf"
# Load the configuration file if it exists
if [ -f "$CONFIG_FILE" ]; then
# shellcheck source=./iptag.conf
source "$CONFIG_FILE"
fi
# Convert IP to integer for comparison
ip_to_int() {
local ip="$1"
local a b c d
IFS=. read -r a b c d <<< "${ip}"
echo "$((a << 24 | b << 16 | c << 8 | d))"
}
# Check if IP is in CIDR
ip_in_cidr() {
local ip="$1"
local cidr="$2"
# Use ipcalc with the -c option (check), which returns 0 if the IP is in the network
if ipcalc -c "$ip" "$cidr" >/dev/null 2>&1; then
# Get network address and mask from CIDR
local network prefix
network=$(echo "$cidr" | cut -d/ -f1)
prefix=$(echo "$cidr" | cut -d/ -f2)
# Check if IP is in the network
local ip_a ip_b ip_c ip_d net_a net_b net_c net_d
IFS=. read -r ip_a ip_b ip_c ip_d <<< "$ip"
IFS=. read -r net_a net_b net_c net_d <<< "$network"
# Check octets match based on prefix length
local result=0
if (( prefix >= 8 )); then
[[ "$ip_a" != "$net_a" ]] && result=1
fi
if (( prefix >= 16 )); then
[[ "$ip_b" != "$net_b" ]] && result=1
fi
if (( prefix >= 24 )); then
[[ "$ip_c" != "$net_c" ]] && result=1
fi
return $result
fi
return 1
}
# Format IP address according to the configuration
format_ip_tag() {
local ip="$1"
local format="${TAG_FORMAT:-full}"
case "$format" in
"last_octet")
echo "${ip##*.}"
;;
"last_two_octets")
echo "${ip#*.*.}"
;;
*)
echo "$ip"
;;
esac
}
# Check if IP is in any CIDRs
ip_in_cidrs() {
local ip="$1"
local cidrs="$2"
# Check that cidrs is not empty
[[ -z "$cidrs" ]] && return 1
local IFS=' '
for cidr in $cidrs; do
ip_in_cidr "$ip" "$cidr" && return 0
done
return 1
}
# Check if IP is valid
is_valid_ipv4() {
local ip="$1"
[[ "$ip" =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}$ ]] || return 1
local IFS='.'
read -ra parts <<< "$ip"
for part in "${parts[@]}"; do
[[ "$part" =~ ^[0-9]+$ ]] && ((part >= 0 && part <= 255)) || return 1
done
return 0
}
lxc_status_changed() {
current_lxc_status=$(pct list 2>/dev/null)
if [ "${last_lxc_status}" == "${current_lxc_status}" ]; then
return 1
else
last_lxc_status="${current_lxc_status}"
return 0
fi
}
vm_status_changed() {
current_vm_status=$(qm list 2>/dev/null)
if [ "${last_vm_status}" == "${current_vm_status}" ]; then
return 1
else
last_vm_status="${current_vm_status}"
return 0
fi
}
fw_net_interface_changed() {
current_net_interface=$(ifconfig | grep "^fw")
if [ "${last_net_interface}" == "${current_net_interface}" ]; then
return 1
else
last_net_interface="${current_net_interface}"
return 0
fi
}
# Get VM IPs using MAC addresses and ARP table
get_vm_ips() {
local vmid=$1
local ips=""
# Check if VM is running
qm status "$vmid" 2>/dev/null | grep -q "status: running" || return
# Get MAC addresses from VM configuration
local macs
macs=$(qm config "$vmid" 2>/dev/null | grep -E 'net[0-9]+' | grep -o -E '[a-fA-F0-9]{2}(:[a-fA-F0-9]{2}){5}')
# Look up IPs from ARP table using MAC addresses
for mac in $macs; do
local ip
ip=$(arp -an 2>/dev/null | grep -i "$mac" | grep -o -E '([0-9]{1,3}\.){3}[0-9]{1,3}')
if [ -n "$ip" ]; then
ips+="$ip "
fi
done
echo "$ips"
}
# Update tags for container or VM
update_tags() {
local type="$1"
local vmid="$2"
local config_cmd="pct"
[[ "$type" == "vm" ]] && config_cmd="qm"
# Get current IPs
local current_ips_full
if [[ "$type" == "lxc" ]]; then
# Redirect error output to suppress AppArmor warnings
current_ips_full=$(lxc-info -n "${vmid}" -i 2>/dev/null | grep -E "^IP:" | awk '{print $2}')
else
current_ips_full=$(get_vm_ips "${vmid}")
fi
# Parse current tags and get valid IPs
local current_tags=()
local next_tags=()
mapfile -t current_tags < <($config_cmd config "${vmid}" 2>/dev/null | grep tags | awk '{print $2}' | sed 's/;/\n/g')
for tag in "${current_tags[@]}"; do
# Skip tag if it looks like an IP (full or partial)
if ! is_valid_ipv4 "${tag}" && ! [[ "$tag" =~ ^[0-9]+(\.[0-9]+)*$ ]]; then
next_tags+=("${tag}")
fi
done
# Add valid IPs to tags
local added_ips=()
local skipped_ips=()
for ip in ${current_ips_full}; do
if is_valid_ipv4 "${ip}"; then
if ip_in_cidrs "${ip}" "${CIDR_LIST[*]}"; then
local formatted_ip=$(format_ip_tag "$ip")
next_tags+=("${formatted_ip}")
added_ips+=("${formatted_ip}")
else
skipped_ips+=("${ip}")
fi
fi
done
# Log only if there are changes
if [ ${#added_ips[@]} -gt 0 ]; then
echo "${type^} ${vmid}: added IP tags: ${added_ips[*]}"
fi
# Update if changed
if [[ "$(IFS=';'; echo "${current_tags[*]}")" != "$(IFS=';'; echo "${next_tags[*]}")" ]]; then
$config_cmd set "${vmid}" -tags "$(IFS=';'; echo "${next_tags[*]}")" &>/dev/null
fi
}
# Check if status changed
check_status_changed() {
local type="$1"
local current_status
case "$type" in
"lxc")
current_status=$(pct list 2>/dev/null | grep -v VMID)
[[ "${last_lxc_status}" == "${current_status}" ]] && return 1
last_lxc_status="${current_status}"
;;
"vm")
current_status=$(qm list 2>/dev/null | grep -v VMID)
[[ "${last_vm_status}" == "${current_status}" ]] && return 1
last_vm_status="${current_status}"
;;
"fw")
current_status=$(ifconfig 2>/dev/null | grep "^fw")
[[ "${last_net_interface}" == "${current_status}" ]] && return 1
last_net_interface="${current_status}"
;;
esac
return 0
}
check() {
current_time=$(date +%s)
# Check LXC status
time_since_last_lxc_status_check=$((current_time - last_lxc_status_check_time))
if [[ "${LXC_STATUS_CHECK_INTERVAL}" -gt 0 ]] \
&& [[ "${time_since_last_lxc_status_check}" -ge "${LXC_STATUS_CHECK_INTERVAL}" ]]; then
echo "Checking LXC status..."
last_lxc_status_check_time=${current_time}
if check_status_changed "lxc"; then
update_all_tags "lxc"
last_update_lxc_time=${current_time}
fi
fi
# Check VM status
time_since_last_vm_status_check=$((current_time - last_vm_status_check_time))
if [[ "${VM_STATUS_CHECK_INTERVAL}" -gt 0 ]] \
&& [[ "${time_since_last_vm_status_check}" -ge "${VM_STATUS_CHECK_INTERVAL}" ]]; then
echo "Checking VM status..."
last_vm_status_check_time=${current_time}
if check_status_changed "vm"; then
update_all_tags "vm"
last_update_vm_time=${current_time}
fi
fi
# Check network interface changes
time_since_last_fw_net_interface_check=$((current_time - last_fw_net_interface_check_time))
if [[ "${FW_NET_INTERFACE_CHECK_INTERVAL}" -gt 0 ]] \
&& [[ "${time_since_last_fw_net_interface_check}" -ge "${FW_NET_INTERFACE_CHECK_INTERVAL}" ]]; then
echo "Checking network interfaces..."
last_fw_net_interface_check_time=${current_time}
if check_status_changed "fw"; then
update_all_tags "lxc"
update_all_tags "vm"
last_update_lxc_time=${current_time}
last_update_vm_time=${current_time}
fi
fi
# Force update if needed
for type in "lxc" "vm"; do
local last_update_var="last_update_${type}_time"
local time_since_last_update=$((current_time - ${!last_update_var}))
if [ ${time_since_last_update} -ge ${FORCE_UPDATE_INTERVAL} ]; then
echo "Force updating ${type} tags..."
update_all_tags "$type"
eval "${last_update_var}=${current_time}"
fi
done
}
# Initialize time variables
last_lxc_status_check_time=0
last_vm_status_check_time=0
last_fw_net_interface_check_time=0
last_update_lxc_time=0
last_update_vm_time=0
# main: Set the IP tags for all LXC containers and VMs
main() {
while true; do
check
sleep "${LOOP_INTERVAL}"
done
}
main
EOF
msg_ok "Setup Main Function"
else
msg_ok "Main Function already exists"
fi
chmod +x /opt/iptag/iptag
msg_info "Creating Service"
if [[ ! -f /lib/systemd/system/iptag.service ]]; then
cat <<EOF >/lib/systemd/system/iptag.service
[Unit]
Description=IP-Tag service
After=network.target
[Service]
Type=simple
ExecStart=/opt/iptag/iptag
Restart=always
[Install]
WantedBy=multi-user.target
EOF
msg_ok "Created Service"
else
msg_ok "Service already exists."
fi
msg_ok "Setup IP-Tag Scripts"
msg_info "Starting Service"
systemctl daemon-reload &>/dev/null
systemctl enable -q --now iptag.service &>/dev/null
msg_ok "Started Service"
SPINNER_PID=""
echo -e "\n${APP} installation completed successfully! ${CL}\n"

View File

@@ -1,51 +1,13 @@
# Copyright (c) 2021-2025 tteck
# Copyright (c) 2021-2025 community-scripts ORG
# Author: tteck (tteckster)
# License: MIT
# https://github.com/asylumexp/Proxmox/raw/main/LICENSE
# This function sets color variables for formatting output in the terminal
color() {
# Colors
YW=$(echo "\033[33m")
BL=$(echo "\033[36m")
RD=$(echo "\033[01;31m")
GN=$(echo "\033[1;92m")
# Formatting
CL=$(echo "\033[m")
BFR="\\r\\033[K"
BOLD=$(echo "\033[1m")
TAB=" "
TAB3=" "
# System
RETRY_NUM=10
RETRY_EVERY=3
i=$RETRY_NUM
# Icons
CM="${TAB}✔️${TAB}${CL}"
CROSS="${TAB}✖️${TAB}${CL}"
INFO="${TAB}💡${TAB}${CL}"
NETWORK="${TAB}📡${TAB}${CL}"
OS="${TAB}🖥️${TAB}${CL}"
HOSTNAME="${TAB}🏠${TAB}${CL}"
GATEWAY="${TAB}🌐${TAB}${CL}"
}
# Function to set STD mode based on verbosity
set_std_mode() {
if [ "$VERBOSE" = "yes" ]; then
STD=""
else
STD="silent"
fi
}
# Silent execution function
silent() {
"$@" >/dev/null 2>&1
}
if ! command -v curl >/dev/null 2>&1; then
apk update && apk add curl >/dev/null 2>&1
fi
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/core.func)
load_functions
# This function enables IPv6 if it's not disabled and sets verbose mode
verb_ip6() {
@@ -73,33 +35,15 @@ error_handler() {
echo -e "\n$error_message\n"
}
# This function displays an informational message with a yellow color.
msg_info() {
local msg="$1"
echo -ne " ${TAB}${YW}${msg}"
}
# This function displays a success message with a green color.
msg_ok() {
local msg="$1"
echo -e "${BFR}${CM}${GN}${msg}${CL}"
}
# This function displays a error message with a red color.
msg_error() {
local msg="$1"
echo -e "${BFR}${CROSS}${RD}${msg}${CL}"
}
# This function sets up the Container OS by generating the locale, setting the timezone, and checking the network connection
setting_up_container() {
msg_info "Setting up Container OS"
while [ "$i" -gt 0 ]; do
while [ $i -gt 0 ]; do
if [ "$(ip addr show | grep 'inet ' | grep -v '127.0.0.1' | awk '{print $2}' | cut -d'/' -f1)" != "" ]; then
break
fi
echo 1>&2 -en "${CROSS}${RD} No Network! "
sleep "$RETRY_EVERY"
sleep $RETRY_EVERY
i=$((i - 1))
done
@@ -148,10 +92,9 @@ update_os() {
# This function modifies the message of the day (motd) and SSH settings
motd_ssh() {
# Set terminal to 256-color mode
echo "export TERM='xterm-256color'" >>/root/.bashrc
IP=$(ip -4 addr show eth0 | awk '/inet / {print $2}' | cut -d/ -f1 | head -n 1)
# Get OS information
if [ -f "/etc/os-release" ]; then
OS_NAME=$(grep ^NAME /etc/os-release | cut -d= -f2 | tr -d '"')
OS_VERSION=$(grep ^VERSION_ID /etc/os-release | cut -d= -f2 | tr -d '"')
@@ -212,6 +155,6 @@ EOF
msg_ok "Customized Container"
fi
echo "bash -c \"\$(curl -fsSL https://github.com/community-scripts/ProxmoxVE/raw/main/ct/${app}.sh)\"" >/usr/bin/update
echo "bash -c \"\$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/${app}.sh)\"" >/usr/bin/update
chmod +x /usr/bin/update
}

View File

@@ -4,7 +4,7 @@
post_to_api() {
if ! command -v curl &> /dev/null; then
if ! command -v curl &>/dev/null; then
return
fi
@@ -20,7 +20,8 @@ post_to_api() {
local pve_version="not found"
pve_version=$(pveversion | awk -F'[/ ]' '{print $2}')
JSON_PAYLOAD=$(cat <<EOF
JSON_PAYLOAD=$(
cat <<EOF
{
"ct_type": $CT_TYPE,
"type":"lxc",
@@ -37,12 +38,12 @@ post_to_api() {
"random_id": "$RANDOM_UUID"
}
EOF
)
)
if [[ "$DIAGNOSTICS" == "yes" ]]; then
RESPONSE=$(curl -s -w "%{http_code}" -L -X POST "$API_URL" --post301 --post302 \
-H "Content-Type: application/json" \
-d "$JSON_PAYLOAD") || true
-H "Content-Type: application/json" \
-d "$JSON_PAYLOAD") || true
fi
}
@@ -52,7 +53,7 @@ post_to_api_vm() {
return
fi
DIAGNOSTICS=$(grep -i "^DIAGNOSTICS=" /usr/local/community-scripts/diagnostics | awk -F'=' '{print $2}')
if ! command -v curl &> /dev/null; then
if ! command -v curl &>/dev/null; then
return
fi
@@ -70,7 +71,8 @@ post_to_api_vm() {
DISK_SIZE_API=${DISK_SIZE%G}
JSON_PAYLOAD=$(cat <<EOF
JSON_PAYLOAD=$(
cat <<EOF
{
"ct_type": 2,
"type":"vm",
@@ -87,42 +89,43 @@ post_to_api_vm() {
"random_id": "$RANDOM_UUID"
}
EOF
)
)
if [[ "$DIAGNOSTICS" == "yes" ]]; then
RESPONSE=$(curl -s -w "%{http_code}" -L -X POST "$API_URL" --post301 --post302 \
-H "Content-Type: application/json" \
-d "$JSON_PAYLOAD") || true
-H "Content-Type: application/json" \
-d "$JSON_PAYLOAD") || true
fi
}
POST_UPDATE_DONE=false
post_update_to_api() {
if ! command -v curl &> /dev/null; then
return
fi
if ! command -v curl &>/dev/null; then
return
fi
if [ "$POST_UPDATE_DONE" = true ]; then
return 0
fi
local API_URL="http://api.community-scripts.org/upload/updatestatus"
local status="${1:-failed}"
local error="${2:-No error message}"
if [ "$POST_UPDATE_DONE" = true ]; then
return 0
fi
local API_URL="http://api.community-scripts.org/upload/updatestatus"
local status="${1:-failed}"
local error="${2:-No error message}"
JSON_PAYLOAD=$(cat <<EOF
JSON_PAYLOAD=$(
cat <<EOF
{
"status": "$status",
"error": "$error",
"random_id": "$RANDOM_UUID"
}
EOF
)
)
if [[ "$DIAGNOSTICS" == "yes" ]]; then
RESPONSE=$(curl -s -w "%{http_code}" -L -X POST "$API_URL" --post301 --post302 \
-H "Content-Type: application/json" \
-d "$JSON_PAYLOAD") || true
-H "Content-Type: application/json" \
-d "$JSON_PAYLOAD") || true
fi
POST_UPDATE_DONE=true

View File

@@ -11,56 +11,20 @@ variables() {
DIAGNOSTICS="yes" # sets the DIAGNOSTICS variable to "yes", used for the API call.
METHOD="default" # sets the METHOD variable to "default", used for the API call.
RANDOM_UUID="$(cat /proc/sys/kernel/random/uuid)" # generates a random UUID and sets it to the RANDOM_UUID variable.
CT_TYPE=${var_unprivileged:-$CT_TYPE}
}
source <(curl -s https://raw.githubusercontent.com/asylumexp/Proxmox/main/misc/api.func)
# This function sets various color variables using ANSI escape codes for formatting text in the terminal.
color() {
# Colors
YW=$(echo "\033[33m")
YWB=$(echo "\033[93m")
BL=$(echo "\033[36m")
RD=$(echo "\033[01;31m")
BGN=$(echo "\033[4;92m")
GN=$(echo "\033[1;92m")
DGN=$(echo "\033[32m")
# Formatting
CL=$(echo "\033[m")
BOLD=$(echo "\033[1m")
HOLD=" "
TAB=" "
TAB3=" "
# Icons
CM="${TAB}✔️${TAB}"
CROSS="${TAB}✖️${TAB}"
INFO="${TAB}💡${TAB}${CL}"
OS="${TAB}🖥️${TAB}${CL}"
OSVERSION="${TAB}🌟${TAB}${CL}"
CONTAINERTYPE="${TAB}📦${TAB}${CL}"
DISKSIZE="${TAB}💾${TAB}${CL}"
CPUCORE="${TAB}🧠${TAB}${CL}"
RAMSIZE="${TAB}🛠️${TAB}${CL}"
SEARCH="${TAB}🔍${TAB}${CL}"
VERBOSE_CROPPED="🔍${TAB}"
VERIFYPW="${TAB}🔐${TAB}${CL}"
CONTAINERID="${TAB}🆔${TAB}${CL}"
HOSTNAME="${TAB}🏠${TAB}${CL}"
BRIDGE="${TAB}🌉${TAB}${CL}"
NETWORK="${TAB}📡${TAB}${CL}"
GATEWAY="${TAB}🌐${TAB}${CL}"
DISABLEIPV6="${TAB}🚫${TAB}${CL}"
DEFAULT="${TAB}⚙️${TAB}${CL}"
MACADDRESS="${TAB}🔗${TAB}${CL}"
VLANTAG="${TAB}🏷️${TAB}${CL}"
ROOTSSH="${TAB}🔑${TAB}${CL}"
CREATING="${TAB}🚀${TAB}${CL}"
ADVANCED="${TAB}🧩${TAB}${CL}"
FUSE="${TAB}🗂️${TAB}${CL}"
}
if command -v curl >/dev/null 2>&1; then
source <(curl -fsSL https://raw.githubusercontent.com/asylumexp/Proxmox/main/misc/core.func)
load_functions
#echo "(build.func) Loaded core.func via curl"
elif command -v wget >/dev/null 2>&1; then
source <(wget -qO- https://raw.githubusercontent.com/asylumexp/Proxmox/main/misc/core.func)
load_functions
#echo "(build.func) Loaded core.func via wget"
fi
# This function enables error handling in the script by setting options and defining a trap for the ERR signal.
catch_errors() {
set -Eeuo pipefail
@@ -70,7 +34,6 @@ catch_errors() {
# This function is called when an error occurs. It receives the exit code, line number, and command that caused the error, and displays an error message.
error_handler() {
source /dev/stdin <<<$(curl -fsSL https://raw.githubusercontent.com/asylumexp/Proxmox/main/misc/api.func)
if [ -n "$SPINNER_PID" ] && ps -p "$SPINNER_PID" >/dev/null; then kill "$SPINNER_PID" >/dev/null; fi
printf "\e[?25h"
local exit_code="$?"
local line_number="$1"
@@ -80,78 +43,6 @@ error_handler() {
echo -e "\n$error_message\n"
}
# This function displays an informational message with logging support.
declare -A MSG_INFO_SHOWN
SPINNER_ACTIVE=0
SPINNER_PID=""
SPINNER_MSG=""
trap 'stop_spinner' EXIT INT TERM HUP
start_spinner() {
local msg="$1"
local frames=(⠋ ⠙ ⠹ ⠸ ⠼ ⠴ ⠦ ⠧ ⠇ ⠏)
local spin_i=0
local interval=0.1
SPINNER_MSG="$msg"
printf "\r\e[2K" >&2
{
while [[ "$SPINNER_ACTIVE" -eq 1 ]]; do
printf "\r\e[2K%s %b" "${frames[spin_i]}" "${YW}${SPINNER_MSG}${CL}" >&2
spin_i=$(((spin_i + 1) % ${#frames[@]}))
sleep "$interval"
done
} &
SPINNER_PID=$!
disown "$SPINNER_PID"
}
stop_spinner() {
if [[ ${SPINNER_PID+v} && -n "$SPINNER_PID" ]] && kill -0 "$SPINNER_PID" 2>/dev/null; then
kill "$SPINNER_PID" 2>/dev/null
sleep 0.1
kill -0 "$SPINNER_PID" 2>/dev/null && kill -9 "$SPINNER_PID" 2>/dev/null
wait "$SPINNER_PID" 2>/dev/null || true
fi
SPINNER_ACTIVE=0
unset SPINNER_PID
}
spinner_guard() {
if [[ "$SPINNER_ACTIVE" -eq 1 ]] && [[ -n "$SPINNER_PID" ]]; then
kill "$SPINNER_PID" 2>/dev/null
wait "$SPINNER_PID" 2>/dev/null || true
SPINNER_ACTIVE=0
unset SPINNER_PID
fi
}
msg_info() {
local msg="$1"
[[ -n "${MSG_INFO_SHOWN["$msg"]+x}" ]] && return
MSG_INFO_SHOWN["$msg"]=1
spinner_guard
SPINNER_ACTIVE=1
start_spinner "$msg"
}
msg_ok() {
local msg="$1"
stop_spinner
printf "\r\e[2K%s %b\n" "${CM}" "${GN}${msg}${CL}" >&2
unset MSG_INFO_SHOWN["$msg"]
}
msg_error() {
stop_spinner
local msg="$1"
printf "\r\e[2K%s %b\n" "${CROSS}" "${RD}${msg}${CL}" >&2
}
# Check if the shell is using bash
shell_check() {
if [[ "$(basename "$SHELL")" != "bash" ]]; then
@@ -272,42 +163,6 @@ update_motd_ip() {
fi
}
# Function to download & save header files
get_header() {
local app_name=$(echo "${APP,,}" | tr -d ' ')
local header_url="https://raw.githubusercontent.com/asylumexp/Proxmox/main/ct/headers/${app_name}"
local local_header_path="/usr/local/community-scripts/headers/${app_name}"
mkdir -p "$(dirname "$local_header_path")"
if [ ! -s "$local_header_path" ]; then
if ! curl -fsSL "$header_url" -o "$local_header_path"; then
echo -e "Failed to download header for ${app_name}. No header will be displayed."
return 1
fi
fi
cat "$local_header_path"
}
# This function sets the APP-Name into an ASCII Header in Slant, figlet needed on proxmox main node.
header_info() {
local app_name=$(echo "${APP,,}" | tr -d ' ')
local header_content
# Download & save Header-File locally
header_content=$(get_header "$app_name")
if [ $? -ne 0 ]; then
# Fallback: Doesn't show Header
return 0
fi
# Show ASCII-Header
term_width=$(tput cols 2>/dev/null || echo 120)
clear
echo "$header_content"
}
# This function checks if the script is running through SSH and prompts the user to confirm if they want to proceed or exit.
ssh_check() {
if [ -n "${SSH_CLIENT:+x}" ]; then
@@ -345,8 +200,8 @@ base_settings() {
SSH="no"
SSH_AUTHORIZED_KEY=""
TAGS="community-script;"
ENABLE_FUSE="no"
ENABLE_TUN="no"
ENABLE_FUSE="${1:-no}"
ENABLE_TUN="${1:-no}"
# Override default settings with variables from ct script
CT_TYPE=${var_unprivileged:-$CT_TYPE}
@@ -369,7 +224,7 @@ base_settings() {
write_config() {
mkdir -p /opt/community-scripts
# This function writes the configuration to a file.
if whiptail --backtitle "[dev] Proxmox VE Helper Scripts" --defaultno --title "Write configfile" --yesno "Do you want to write the selections to a config file?" 10 60; then
if whiptail --backtitle "Proxmox VE Helper Scripts" --defaultno --title "Write configfile" --yesno "Do you want to write the selections to a config file?" 10 60; then
FILEPATH="/opt/community-scripts/${NSAPP}.conf"
if [[ ! -f $FILEPATH ]]; then
cat <<EOF >"$FILEPATH"
@@ -402,7 +257,7 @@ EOF
echo -e "${INFO}${BOLD}${GN}Writing configuration to ${FILEPATH}${CL}"
else
echo -e "${INFO}${BOLD}${RD}Configuration file already exists at ${FILEPATH}${CL}"
if whiptail --backtitle "[dev] Proxmox VE Helper Scripts" --defaultno --title "Overwrite configfile" --yesno "Do you want to overwrite the existing config file?" 10 60; then
if whiptail --backtitle "Proxmox VE Helper Scripts" --defaultno --title "Overwrite configfile" --yesno "Do you want to overwrite the existing config file?" 10 60; then
rm -f "$FILEPATH"
cat <<EOF >"$FILEPATH"
# ${NSAPP} Configuration File
@@ -517,30 +372,38 @@ advanced_settings() {
while true; do
if PW1=$(whiptail --backtitle "Proxmox VE Helper Scripts" --passwordbox "\nSet Root Password (needed for root ssh access)" 9 58 --title "PASSWORD (leave blank for automatic login)" 3>&1 1>&2 2>&3); then
if [[ ! -z "$PW1" ]]; then
if [[ "$PW1" == *" "* ]]; then
whiptail --msgbox "Password cannot contain spaces. Please try again." 8 58
elif [ ${#PW1} -lt 5 ]; then
whiptail --msgbox "Password must be at least 5 characters long. Please try again." 8 58
else
if PW2=$(whiptail --backtitle "Proxmox VE Helper Scripts" --passwordbox "\nVerify Root Password" 9 58 --title "PASSWORD VERIFICATION" 3>&1 1>&2 2>&3); then
if [[ "$PW1" == "$PW2" ]]; then
PW="-password $PW1"
echo -e "${VERIFYPW}${BOLD}${DGN}Root Password: ${BGN}********${CL}"
break
else
whiptail --msgbox "Passwords do not match. Please try again." 8 58
fi
else
exit_script
fi
fi
else
PW1="Automatic Login"
# Empty = Autologin
if [[ -z "$PW1" ]]; then
PW=""
PW1="Automatic Login"
echo -e "${VERIFYPW}${BOLD}${DGN}Root Password: ${BGN}$PW1${CL}"
break
fi
# Invalid: contains spaces
if [[ "$PW1" == *" "* ]]; then
whiptail --msgbox "Password cannot contain spaces." 8 58
continue
fi
# Invalid: too short
if ((${#PW1} < 5)); then
whiptail --msgbox "Password must be at least 5 characters." 8 58
continue
fi
# Confirm password
if PW2=$(whiptail --backtitle "Proxmox VE Helper Scripts" --passwordbox "\nVerify Root Password" 9 58 --title "PASSWORD VERIFICATION" 3>&1 1>&2 2>&3); then
if [[ "$PW1" == "$PW2" ]]; then
PW="-password $PW1"
echo -e "${VERIFYPW}${BOLD}${DGN}Root Password: ${BGN}********${CL}"
break
else
whiptail --msgbox "Passwords do not match. Please try again." 8 58
fi
else
exit_script
fi
else
exit_script
fi
@@ -557,53 +420,72 @@ advanced_settings() {
exit_script
fi
if CT_NAME=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set Hostname" 8 58 "$NSAPP" --title "HOSTNAME" 3>&1 1>&2 2>&3); then
if [ -z "$CT_NAME" ]; then
HN="$NSAPP"
while true; do
if CT_NAME=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set Hostname" 8 58 "$NSAPP" --title "HOSTNAME" 3>&1 1>&2 2>&3); then
if [ -z "$CT_NAME" ]; then
HN="$NSAPP"
else
HN=$(echo "${CT_NAME,,}" | tr -d ' ')
fi
# Hostname validate (RFC 1123)
if [[ "$HN" =~ ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ ]]; then
echo -e "${HOSTNAME}${BOLD}${DGN}Hostname: ${BGN}$HN${CL}"
break
else
whiptail --backtitle "Proxmox VE Helper Scripts" \
--msgbox "❌ Invalid hostname: '$HN'\n\nOnly lowercase letters, digits and hyphens (-) are allowed.\nUnderscores (_) or other characters are not permitted!" 10 70
fi
else
HN=$(echo "${CT_NAME,,}" | tr -d ' ')
exit_script
fi
echo -e "${HOSTNAME}${BOLD}${DGN}Hostname: ${BGN}$HN${CL}"
else
exit_script
fi
done
while true; do
DISK_SIZE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set Disk Size in GB" 8 58 "$var_disk" --title "DISK SIZE" 3>&1 1>&2 2>&3) || exit_script
if DISK_SIZE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set Disk Size in GB" 8 58 "$var_disk" --title "DISK SIZE" 3>&1 1>&2 2>&3); then
if [ -z "$DISK_SIZE" ]; then
DISK_SIZE="$var_disk"
echo -e "${DISKSIZE}${BOLD}${DGN}Disk Size: ${BGN}${DISK_SIZE} GB${CL}"
else
if ! [[ $DISK_SIZE =~ $INTEGER ]]; then
echo -e "{INFO}${HOLD}${RD} DISK SIZE MUST BE AN INTEGER NUMBER!${CL}"
advanced_settings
fi
echo -e "${DISKSIZE}${BOLD}${DGN}Disk Size: ${BGN}${DISK_SIZE} GB${CL}"
fi
else
exit_script
fi
if CORE_COUNT=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Allocate CPU Cores" 8 58 "$var_cpu" --title "CORE COUNT" 3>&1 1>&2 2>&3); then
if [[ "$DISK_SIZE" =~ ^[1-9][0-9]*$ ]]; then
echo -e "${DISKSIZE}${BOLD}${DGN}Disk Size: ${BGN}${DISK_SIZE} GB${CL}"
break
else
whiptail --msgbox "Disk size must be a positive integer!" 8 58
fi
done
while true; do
CORE_COUNT=$(whiptail --backtitle "Proxmox VE Helper Scripts" \
--inputbox "Allocate CPU Cores" 8 58 "$var_cpu" --title "CORE COUNT" 3>&1 1>&2 2>&3) || exit_script
if [ -z "$CORE_COUNT" ]; then
CORE_COUNT="$var_cpu"
echo -e "${CPUCORE}${BOLD}${DGN}CPU Cores: ${BGN}$CORE_COUNT${CL}"
else
echo -e "${CPUCORE}${BOLD}${DGN}CPU Cores: ${BGN}$CORE_COUNT${CL}"
fi
else
exit_script
fi
if RAM_SIZE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Allocate RAM in MiB" 8 58 "$var_ram" --title "RAM" 3>&1 1>&2 2>&3); then
if [[ "$CORE_COUNT" =~ ^[1-9][0-9]*$ ]]; then
echo -e "${CPUCORE}${BOLD}${DGN}CPU Cores: ${BGN}$CORE_COUNT${CL}"
break
else
whiptail --msgbox "CPU core count must be a positive integer!" 8 58
fi
done
while true; do
RAM_SIZE=$(whiptail --backtitle "Proxmox VE Helper Scripts" \
--inputbox "Allocate RAM in MiB" 8 58 "$var_ram" --title "RAM" 3>&1 1>&2 2>&3) || exit_script
if [ -z "$RAM_SIZE" ]; then
RAM_SIZE="$var_ram"
echo -e "${RAMSIZE}${BOLD}${DGN}RAM Size: ${BGN}${RAM_SIZE} MiB${CL}"
else
echo -e "${RAMSIZE}${BOLD}${DGN}RAM Size: ${BGN}${RAM_SIZE} MiB${CL}"
fi
else
exit_script
fi
if [[ "$RAM_SIZE" =~ ^[1-9][0-9]*$ ]]; then
echo -e "${RAMSIZE}${BOLD}${DGN}RAM Size: ${BGN}${RAM_SIZE} MiB${CL}"
break
else
whiptail --msgbox "RAM size must be a positive integer!" 8 58
fi
done
BRIDGES=""
IFACE_FILEPATH_LIST="/etc/network/interfaces"$'\n'$(find "/etc/network/interfaces.d/" -type f)
@@ -778,14 +660,14 @@ advanced_settings() {
exit_script
fi
SSH_AUTHORIZED_KEY="$(whiptail --backtitle "[dev] Proxmox VE Helper Scripts" --inputbox "SSH Authorized key for root (leave empty for none)" 8 58 --title "SSH Key" 3>&1 1>&2 2>&3)"
SSH_AUTHORIZED_KEY="$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "SSH Authorized key for root (leave empty for none)" 8 58 --title "SSH Key" 3>&1 1>&2 2>&3)"
if [[ -z "${SSH_AUTHORIZED_KEY}" ]]; then
SSH_AUTHORIZED_KEY=""
fi
if [[ "$PW" == -password* || -n "$SSH_AUTHORIZED_KEY" ]]; then
if (whiptail --backtitle "[dev] Proxmox VE Helper Scripts" --defaultno --title "SSH ACCESS" --yesno "Enable Root SSH Access?" 10 58); then
if (whiptail --backtitle "Proxmox VE Helper Scripts" --defaultno --title "SSH ACCESS" --yesno "Enable Root SSH Access?" 10 58); then
SSH="yes"
else
SSH="no"
@@ -804,11 +686,11 @@ advanced_settings() {
echo -e "${FUSE}${BOLD}${DGN}Enable FUSE Support: ${BGN}$ENABLE_FUSE${CL}"
if (whiptail --backtitle "Proxmox VE Helper Scripts" --defaultno --title "VERBOSE MODE" --yesno "Enable Verbose Mode?" 10 58); then
VERB="yes"
VERBOSE="yes"
else
VERB="no"
VERBOSE="no"
fi
echo -e "${SEARCH}${BOLD}${DGN}Verbose Mode: ${BGN}$VERB${CL}"
echo -e "${SEARCH}${BOLD}${DGN}Verbose Mode: ${BGN}$VERBOSE${CL}"
if (whiptail --backtitle "Proxmox VE Helper Scripts" --title "ADVANCED SETTINGS COMPLETE" --yesno "Ready to create ${APP} LXC?" 10 58); then
echo -e "${CREATING}${BOLD}${RD}Creating a ${APP} LXC using the above advanced settings${CL}"
@@ -832,7 +714,7 @@ diagnostics_check() {
DIAGNOSTICS=yes
#This file is used to store the diagnostics settings for the Community-Scripts API.
#https://github.com/community-scripts/ProxmoxVE/discussions/1836
#https://github.com/asylumexp/Proxmox/discussions/1836
#Your diagnostics will be sent to the Community-Scripts API for troubleshooting/statistical purposes.
#You can review the data at https://community-scripts.github.io/ProxmoxVE/data
#If you do not wish to send diagnostics, please set the variable 'DIAGNOSTICS' to "no" in /usr/local/community-scripts/diagnostics, or use the menue.
@@ -859,7 +741,7 @@ EOF
DIAGNOSTICS=no
#This file is used to store the diagnostics settings for the Community-Scripts API.
#https://github.com/community-scripts/ProxmoxVE/discussions/1836
#https://github.com/asylumexp/Proxmox/discussions/1836
#Your diagnostics will be sent to the Community-Scripts API for troubleshooting/statistical purposes.
#You can review the data at https://community-scripts.github.io/ProxmoxVE/data
#If you do not wish to send diagnostics, please set the variable 'DIAGNOSTICS' to "no" in /usr/local/community-scripts/diagnostics, or use the menue.
@@ -923,18 +805,18 @@ install_script() {
1)
header_info
echo -e "${DEFAULT}${BOLD}${BL}Using Default Settings on node $PVEHOST_NAME${CL}"
VERB="no"
VERBOSE="no"
METHOD="default"
base_settings "$VERB"
base_settings "$VERBOSE"
echo_default
break
;;
2)
header_info
echo -e "${DEFAULT}${BOLD}${BL}Using Default Settings on node $PVEHOST_NAME (${VERBOSE_CROPPED}Verbose)${CL}"
VERB="yes"
VERBOSE="yes"
METHOD="default"
base_settings "$VERB"
base_settings "$VERBOSE"
echo_default
break
;;
@@ -950,7 +832,7 @@ install_script() {
header_info
echo -e "${INFO}${HOLD} ${GN}Using Config File on node $PVEHOST_NAME${CL}"
METHOD="config_file"
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/config-file.func)
source <(curl -fsSL https://raw.githubusercontent.com/asylumexp/Proxmox/main/misc/config-file.func)
config_file
break
;;
@@ -1023,23 +905,17 @@ check_container_storage() {
}
start() {
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/tools.func)
source <(curl -fsSL https://raw.githubusercontent.com/asylumexp/Proxmox/main/misc/tools.func)
if ! command -v pveversion >/dev/null 2>&1; then
if [ -f /etc/debian_version ] || [ -f /etc/lsb-release ]; then
apt-get install -y whiptail &>/dev/null
elif [ -f /etc/alpine-release ]; then
apk add --no-cache whiptail &>/dev/null
fi
if command -v pveversion >/dev/null 2>&1; then
if ! (whiptail --backtitle "Proxmox VE Helper Scripts" --title "${APP} LXC" --yesno "This will create a New ${APP} LXC. Proceed?" 10 58); then
clear
exit_script
exit
fi
SPINNER_PID=""
install_script
fi
if ! command -v pveversion >/dev/null 2>&1; then
if [ -f /etc/debian_version ] || [ -f /etc/lsb-release ]; then
apt-get install -y whiptail &>/dev/null
elif [ -f /etc/alpine-release ]; then
apk add --no-cache whiptail &>/dev/null
fi
else
CHOICE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "${APP} LXC Update/Setting" --menu \
"Support/Update functions for ${APP} LXC. Choose an option:" \
12 60 3 \
@@ -1049,11 +925,11 @@ start() {
case "$CHOICE" in
1)
VERB="no"
VERBOSE="no"
set_std_mode
;;
2)
VERB="yes"
VERBOSE="yes"
set_std_mode
;;
3)
@@ -1062,15 +938,13 @@ start() {
exit
;;
esac
SPINNER_PID=""
update_script
fi
}
# This function collects user settings and integrates all the collected information.
build_container() {
# if [ "$VERB" == "yes" ]; then set -x; fi
# if [ "$VERBOSE" == "yes" ]; then set -x; fi
if [ "$CT_TYPE" == "1" ]; then
FEATURES="keyctl=1,nesting=1"
@@ -1103,7 +977,7 @@ build_container() {
export APPLICATION="$APP"
export app="$NSAPP"
export PASSWORD="$PW"
export VERBOSE="$VERB"
export VERBOSE="$VERBOSE"
export SSH_ROOT="${SSH}"
export SSH_AUTHORIZED_KEY
export CTID="$CT_ID"
@@ -1127,7 +1001,7 @@ build_container() {
$PW
"
# This executes create_lxc.sh and creates the container and .conf file
bash -c "$(curl -fsSL https://raw.githubusercontent.com/asylumexp/Proxmox/main/ct/create_lxc.sh)" $?
bash -c "$(curl -fsSL https://raw.githubusercontent.com/asylumexp/Proxmox/main/misc/create_lxc.sh)" $?
LXC_CONFIG=/etc/pve/lxc/${CTID}.conf
if [ "$CT_TYPE" == "0" ]; then
@@ -1188,16 +1062,30 @@ EOF
msg_info "Starting LXC Container"
pct start "$CTID"
msg_ok "Started LXC Container"
msg_info "Customizing LXC Container"
if [ "$var_os" == "alpine" ]; then
sleep 3
pct exec "$CTID" -- /bin/sh -c 'cat <<EOF >/etc/apk/repositories
http://dl-cdn.alpinelinux.org/alpine/latest-stable/main
http://dl-cdn.alpinelinux.org/alpine/latest-stable/community
EOF'
pct exec "$CTID" -- ash -c "apk add bash >/dev/null"
fi
lxc-attach -n "$CTID" -- bash -c "$(curl -fsSL https://raw.githubusercontent.com/asylumexp/Proxmox/main/install/"$var_install".sh)" $?
pct exec "$CTID" -- ash -c "apk add bash newt curl openssh nano mc ncurses >/dev/null"
else
sleep 3
# Set locale and timezone before update
pct exec "$CTID" -- bash -c "sed -i '/$LANG/ s/^# //' /etc/locale.gen"
pct exec "$CTID" -- bash -c "locale_line=\$(grep -v '^#' /etc/locale.gen | grep -E '^[a-zA-Z]' | awk '{print \$1}' | head -n 1) && \
echo LANG=\$locale_line >/etc/default/locale && \
locale-gen >/dev/null && \
export LANG=\$locale_line"
pct exec "$CTID" -- bash -c "echo $tz >/etc/timezone && ln -sf /usr/share/zoneinfo/$tz /etc/localtime"
# Install curl
pct exec "$CTID" -- bash -c "apt-get update >/dev/null && apt-get install -y sudo curl mc gnupg2 >/dev/null"
fi
msg_ok "Customized LXC Container"
lxc-attach -n "$CTID" -- bash -c "$(curl -fsSL https://raw.githubusercontent.com/asylumexp/Proxmox/main/install/"$var_install".sh)" $?
}
# This function sets the description of the container.
@@ -1246,23 +1134,6 @@ EOF
post_update_to_api "done" "none"
}
set_std_mode() {
if [ "$VERB" = "yes" ]; then
STD=""
else
STD="silent"
fi
}
# Silent execution function
silent() {
if [ "$VERB" = "no" ]; then
"$@" >/dev/null 2>&1 || return 1
else
"$@" || return 1
fi
}
api_exit_script() {
exit_code=$? # Capture the exit status of the last executed command
#200 exit codes indicate error in create_lxc.sh

View File

@@ -53,15 +53,15 @@ config_file() {
fi
else
if CT_ID=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set Container ID" 8 58 "$NEXTID" --title "CONTAINER ID" 3>&1 1>&2 2>&3); then
if [ -z "$CT_ID" ]; then
CT_ID="$NEXTID"
echo -e "${CONTAINERID}${BOLD}${DGN}Container ID: ${BGN}$CT_ID${CL}"
if [ -z "$CT_ID" ]; then
CT_ID="$NEXTID"
echo -e "${CONTAINERID}${BOLD}${DGN}Container ID: ${BGN}$CT_ID${CL}"
else
echo -e "${CONTAINERID}${BOLD}${DGN}Container ID: ${BGN}$CT_ID${CL}"
fi
else
echo -e "${CONTAINERID}${BOLD}${DGN}Container ID: ${BGN}$CT_ID${CL}"
exit_script
fi
else
exit_script
fi
fi
if [[ -n "${CT_TYPE-}" ]]; then
@@ -75,23 +75,22 @@ config_file() {
fi
echo -e "${CONTAINERTYPE}${BOLD}${DGN}Container Type: ${BGN}$CT_TYPE_DESC${CL}"
else
if CT_TYPE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "CONTAINER TYPE" --radiolist "Choose Type" 10 58 2 \
"1" "Unprivileged" ON \
"0" "Privileged" OFF \
3>&1 1>&2 2>&3); then
if [ -n "$CT_TYPE" ]; then
CT_TYPE_DESC="Unprivileged"
if [ "$CT_TYPE" -eq 0 ]; then
CT_TYPE_DESC="Privileged"
fi
echo -e "${CONTAINERTYPE}${BOLD}${DGN}Container Type: ${BGN}$CT_TYPE_DESC${CL}"
if CT_TYPE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "CONTAINER TYPE" --radiolist "Choose Type" 10 58 2 \
"1" "Unprivileged" ON \
"0" "Privileged" OFF \
3>&1 1>&2 2>&3); then
if [ -n "$CT_TYPE" ]; then
CT_TYPE_DESC="Unprivileged"
if [ "$CT_TYPE" -eq 0 ]; then
CT_TYPE_DESC="Privileged"
fi
else
exit_script
echo -e "${CONTAINERTYPE}${BOLD}${DGN}Container Type: ${BGN}$CT_TYPE_DESC${CL}"
fi
else
exit_script
fi
fi
if [[ -n "${PW-}" ]]; then
if [[ "$PW" == "none" ]]; then
PW=""
@@ -109,50 +108,50 @@ config_file() {
fi
else
while true; do
if PW1=$(whiptail --backtitle "Proxmox VE Helper Scripts" --passwordbox "\nSet Root Password (needed for root ssh access)" 9 58 --title "PASSWORD (leave blank for automatic login)" 3>&1 1>&2 2>&3); then
if [[ -n "$PW1" ]]; then
if [[ "$PW1" == *" "* ]]; then
whiptail --msgbox "Password cannot contain spaces. Please try again." 8 58
elif [ ${#PW1} -lt 5 ]; then
whiptail --msgbox "Password must be at least 5 characters long. Please try again." 8 58
else
if PW2=$(whiptail --backtitle "Proxmox VE Helper Scripts" --passwordbox "\nVerify Root Password" 9 58 --title "PASSWORD VERIFICATION" 3>&1 1>&2 2>&3); then
if [[ "$PW1" == "$PW2" ]]; then
PW="-password $PW1"
echo -e "${VERIFYPW}${BOLD}${DGN}Root Password: ${BGN}********${CL}"
break
else
whiptail --msgbox "Passwords do not match. Please try again." 8 58
fi
if PW1=$(whiptail --backtitle "Proxmox VE Helper Scripts" --passwordbox "\nSet Root Password (needed for root ssh access)" 9 58 --title "PASSWORD (leave blank for automatic login)" 3>&1 1>&2 2>&3); then
if [[ -n "$PW1" ]]; then
if [[ "$PW1" == *" "* ]]; then
whiptail --msgbox "Password cannot contain spaces. Please try again." 8 58
elif [ ${#PW1} -lt 5 ]; then
whiptail --msgbox "Password must be at least 5 characters long. Please try again." 8 58
else
exit_script
if PW2=$(whiptail --backtitle "Proxmox VE Helper Scripts" --passwordbox "\nVerify Root Password" 9 58 --title "PASSWORD VERIFICATION" 3>&1 1>&2 2>&3); then
if [[ "$PW1" == "$PW2" ]]; then
PW="-password $PW1"
echo -e "${VERIFYPW}${BOLD}${DGN}Root Password: ${BGN}********${CL}"
break
else
whiptail --msgbox "Passwords do not match. Please try again." 8 58
fi
else
exit_script
fi
fi
else
PW1="Automatic Login"
PW=""
echo -e "${VERIFYPW}${BOLD}${DGN}Root Password: ${BGN}$PW1${CL}"
break
fi
else
PW1="Automatic Login"
PW=""
echo -e "${VERIFYPW}${BOLD}${DGN}Root Password: ${BGN}$PW1${CL}"
break
exit_script
fi
else
exit_script
fi
done
done
fi
if [[ -n "${HN-}" ]]; then
echo -e "${HOSTNAME}${BOLD}${DGN}Hostname: ${BGN}$HN${CL}"
else
if CT_NAME=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set Hostname" 8 58 "$NSAPP" --title "HOSTNAME" 3>&1 1>&2 2>&3); then
if [ -z "$CT_NAME" ]; then
HN="$NSAPP"
if [ -z "$CT_NAME" ]; then
HN="$NSAPP"
else
HN=$(echo "${CT_NAME,,}" | tr -d ' ')
fi
echo -e "${HOSTNAME}${BOLD}${DGN}Hostname: ${BGN}$HN${CL}"
else
HN=$(echo "${CT_NAME,,}" | tr -d ' ')
exit_script
fi
echo -e "${HOSTNAME}${BOLD}${DGN}Hostname: ${BGN}$HN${CL}"
else
exit_script
fi
fi
if [[ -n "${DISK_SIZE-}" ]]; then
@@ -164,19 +163,19 @@ config_file() {
fi
else
if DISK_SIZE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set Disk Size in GB" 8 58 "$var_disk" --title "DISK SIZE" 3>&1 1>&2 2>&3); then
if [ -z "$DISK_SIZE" ]; then
DISK_SIZE="$var_disk"
echo -e "${DISKSIZE}${BOLD}${DGN}Disk Size: ${BGN}${DISK_SIZE} GB${CL}"
else
if ! [[ $DISK_SIZE =~ $INTEGER ]]; then
echo -e "{INFO}${HOLD}${RD} DISK SIZE MUST BE AN INTEGER NUMBER!${CL}"
advanced_settings
if [ -z "$DISK_SIZE" ]; then
DISK_SIZE="$var_disk"
echo -e "${DISKSIZE}${BOLD}${DGN}Disk Size: ${BGN}${DISK_SIZE} GB${CL}"
else
if ! [[ $DISK_SIZE =~ $INTEGER ]]; then
echo -e "{INFO}${HOLD}${RD} DISK SIZE MUST BE AN INTEGER NUMBER!${CL}"
advanced_settings
fi
echo -e "${DISKSIZE}${BOLD}${DGN}Disk Size: ${BGN}${DISK_SIZE} GB${CL}"
fi
echo -e "${DISKSIZE}${BOLD}${DGN}Disk Size: ${BGN}${DISK_SIZE} GB${CL}"
else
exit_script
fi
else
exit_script
fi
fi
if [[ -n "${CORE_COUNT-}" ]]; then
@@ -188,15 +187,15 @@ config_file() {
fi
else
if CORE_COUNT=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Allocate CPU Cores" 8 58 "$var_cpu" --title "CORE COUNT" 3>&1 1>&2 2>&3); then
if [ -z "$CORE_COUNT" ]; then
CORE_COUNT="$var_cpu"
echo -e "${CPUCORE}${BOLD}${DGN}CPU Cores: ${BGN}$CORE_COUNT${CL}"
if [ -z "$CORE_COUNT" ]; then
CORE_COUNT="$var_cpu"
echo -e "${CPUCORE}${BOLD}${DGN}CPU Cores: ${BGN}$CORE_COUNT${CL}"
else
echo -e "${CPUCORE}${BOLD}${DGN}CPU Cores: ${BGN}$CORE_COUNT${CL}"
fi
else
echo -e "${CPUCORE}${BOLD}${DGN}CPU Cores: ${BGN}$CORE_COUNT${CL}"
exit_script
fi
else
exit_script
fi
fi
if [[ -n "${RAM_SIZE-}" ]]; then
@@ -208,15 +207,15 @@ config_file() {
fi
else
if RAM_SIZE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Allocate RAM in MiB" 8 58 "$var_ram" --title "RAM" 3>&1 1>&2 2>&3); then
if [ -z "$RAM_SIZE" ]; then
RAM_SIZE="$var_ram"
echo -e "${RAMSIZE}${BOLD}${DGN}RAM Size: ${BGN}${RAM_SIZE} MiB${CL}"
if [ -z "$RAM_SIZE" ]; then
RAM_SIZE="$var_ram"
echo -e "${RAMSIZE}${BOLD}${DGN}RAM Size: ${BGN}${RAM_SIZE} MiB${CL}"
else
echo -e "${RAMSIZE}${BOLD}${DGN}RAM Size: ${BGN}${RAM_SIZE} MiB${CL}"
fi
else
echo -e "${RAMSIZE}${BOLD}${DGN}RAM Size: ${BGN}${RAM_SIZE} MiB${CL}"
exit_script
fi
else
exit_script
fi
fi
IFACE_FILEPATH_LIST="/etc/network/interfaces"$'\n'$(find "/etc/network/interfaces.d/" -type f)
@@ -227,20 +226,20 @@ config_file() {
for iface_filepath in ${IFACE_FILEPATH_LIST}; do
iface_indexes_tmpfile=$(mktemp -q -u '.iface-XXXX')
( grep -Pn '^\s*iface' "${iface_filepath}" | cut -d':' -f1 && wc -l "${iface_filepath}" | cut -d' ' -f1 ) | awk 'FNR==1 {line=$0; next} {print line":"$0-1; line=$0}' > "${iface_indexes_tmpfile}" || true
(grep -Pn '^\s*iface' "${iface_filepath}" | cut -d':' -f1 && wc -l "${iface_filepath}" | cut -d' ' -f1) | awk 'FNR==1 {line=$0; next} {print line":"$0-1; line=$0}' >"${iface_indexes_tmpfile}" || true
if [ -f "${iface_indexes_tmpfile}" ]; then
while read -r pair; do
start=$(echo "${pair}" | cut -d':' -f1)
end=$(echo "${pair}" | cut -d':' -f2)
if awk "NR >= ${start} && NR <= ${end}" "${iface_filepath}" | grep -qP '^\s*(bridge[-_](ports|stp|fd|vlan-aware|vids)|ovs_type\s+OVSBridge)\b'; then
iface_name=$(sed "${start}q;d" "${iface_filepath}" | awk '{print $2}')
BRIDGES="${iface_name}"$'\n'"${BRIDGES}"
fi
while read -r pair; do
start=$(echo "${pair}" | cut -d':' -f1)
end=$(echo "${pair}" | cut -d':' -f2)
if awk "NR >= ${start} && NR <= ${end}" "${iface_filepath}" | grep -qP '^\s*(bridge[-_](ports|stp|fd|vlan-aware|vids)|ovs_type\s+OVSBridge)\b'; then
iface_name=$(sed "${start}q;d" "${iface_filepath}" | awk '{print $2}')
BRIDGES="${iface_name}"$'\n'"${BRIDGES}"
fi
done < "${iface_indexes_tmpfile}"
rm -f "${iface_indexes_tmpfile}"
done <"${iface_indexes_tmpfile}"
rm -f "${iface_indexes_tmpfile}"
fi
done
@@ -296,7 +295,7 @@ config_file() {
done
fi
elif [[ "$NET" == *-* ]]; then
IFS="-" read -r ip_start ip_end <<< "$NET"
IFS="-" read -r ip_start ip_end <<<"$NET"
if [[ ! "$ip_start" =~ $ip_cidr_regex ]] || [[ ! "$ip_end" =~ $ip_cidr_regex ]]; then
msg_error "Invalid IP range format, was $NET should be 0.0.0.0/0-0.0.0.0/0"
@@ -309,21 +308,21 @@ config_file() {
ip_to_int() {
local IFS=.
read -r i1 i2 i3 i4 <<< "$1"
echo $(( (i1 << 24) + (i2 << 16) + (i3 << 8) + i4 ))
read -r i1 i2 i3 i4 <<<"$1"
echo $(((i1 << 24) + (i2 << 16) + (i3 << 8) + i4))
}
int_to_ip() {
local ip=$1
echo "$(( (ip >> 24) & 0xFF )).$(( (ip >> 16) & 0xFF )).$(( (ip >> 8) & 0xFF )).$(( ip & 0xFF ))"
echo "$(((ip >> 24) & 0xFF)).$(((ip >> 16) & 0xFF)).$(((ip >> 8) & 0xFF)).$((ip & 0xFF))"
}
start_int=$(ip_to_int "$ip1")
end_int=$(ip_to_int "$ip2")
for ((ip_int=start_int; ip_int<=end_int; ip_int++)); do
for ((ip_int = start_int; ip_int <= end_int; ip_int++)); do
ip=$(int_to_ip $ip_int)
msg_info "Checking IP: $ip"
msg_info "Checking IP: $ip"
if ! ping -c 2 -W 1 "$ip" >/dev/null 2>&1; then
NET="$ip/$cidr"
msg_ok "Using free IP Address: ${BGN}$NET${CL}"
@@ -363,37 +362,37 @@ config_file() {
fi
else
while true; do
NET=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set a Static IPv4 CIDR Address (/24)" 8 58 dhcp --title "IP ADDRESS" 3>&1 1>&2 2>&3)
exit_status=$?
if [ $exit_status -eq 0 ]; then
if [ "$NET" = "dhcp" ]; then
echo -e "${NETWORK}${BOLD}${DGN}IP Address: ${BGN}$NET${CL}"
break
else
if [[ "$NET" =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}/([0-9]|[1-2][0-9]|3[0-2])$ ]]; then
NET=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set a Static IPv4 CIDR Address (/24)" 8 58 dhcp --title "IP ADDRESS" 3>&1 1>&2 2>&3)
exit_status=$?
if [ $exit_status -eq 0 ]; then
if [ "$NET" = "dhcp" ]; then
echo -e "${NETWORK}${BOLD}${DGN}IP Address: ${BGN}$NET${CL}"
break
else
whiptail --backtitle "Proxmox VE Helper Scripts" --msgbox "$NET is an invalid IPv4 CIDR address. Please enter a valid IPv4 CIDR address or 'dhcp'" 8 58
if [[ "$NET" =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}/([0-9]|[1-2][0-9]|3[0-2])$ ]]; then
echo -e "${NETWORK}${BOLD}${DGN}IP Address: ${BGN}$NET${CL}"
break
else
whiptail --backtitle "Proxmox VE Helper Scripts" --msgbox "$NET is an invalid IPv4 CIDR address. Please enter a valid IPv4 CIDR address or 'dhcp'" 8 58
fi
fi
else
exit_script
fi
else
exit_script
fi
done
if [ "$NET" != "dhcp" ]; then
while true; do
GATE1=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Enter gateway IP address" 8 58 --title "Gateway IP" 3>&1 1>&2 2>&3)
if [ -z "$GATE1" ]; then
whiptail --backtitle "Proxmox VE Helper Scripts" --msgbox "Gateway IP address cannot be empty" 8 58
elif [[ ! "$GATE1" =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}$ ]]; then
whiptail --backtitle "Proxmox VE Helper Scripts" --msgbox "Invalid IP address format" 8 58
else
GATE=",gw=$GATE1"
echo -e "${GATEWAY}${BOLD}${DGN}Gateway IP Address: ${BGN}$GATE1${CL}"
break
fi
done
while true; do
GATE1=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Enter gateway IP address" 8 58 --title "Gateway IP" 3>&1 1>&2 2>&3)
if [ -z "$GATE1" ]; then
whiptail --backtitle "Proxmox VE Helper Scripts" --msgbox "Gateway IP address cannot be empty" 8 58
elif [[ ! "$GATE1" =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}$ ]]; then
whiptail --backtitle "Proxmox VE Helper Scripts" --msgbox "Invalid IP address format" 8 58
else
GATE=",gw=$GATE1"
echo -e "${GATEWAY}${BOLD}${DGN}Gateway IP Address: ${BGN}$GATE1${CL}"
break
fi
done
else
GATE=""
echo -e "${GATEWAY}${BOLD}${DGN}Gateway IP Address: ${BGN}Default${CL}"
@@ -406,8 +405,8 @@ config_file() {
else
if [[ -n "${APT_CACHER_IP-}" ]]; then
if [[ ! $APT_CACHER_IP == "none" ]]; then
APT_CACHER="yes"
echo -e "${NETWORK}${BOLD}${DGN}APT-CACHER IP Address: ${BGN}$APT_CACHER_IP${CL}"
APT_CACHER="yes"
echo -e "${NETWORK}${BOLD}${DGN}APT-CACHER IP Address: ${BGN}$APT_CACHER_IP${CL}"
else
APT_CACHER=""
echo -e "${NETWORK}${BOLD}${DGN}APT-Cacher IP Address: ${BGN}No${CL}"
@@ -416,7 +415,7 @@ config_file() {
if APT_CACHER_IP=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set APT-Cacher IP (leave blank for none)" 8 58 --title "APT-Cacher IP" 3>&1 1>&2 2>&3); then
APT_CACHER="${APT_CACHER_IP:+yes}"
echo -e "${NETWORK}${BOLD}${DGN}APT-Cacher IP Address: ${BGN}${APT_CACHER_IP:-Default}${CL}"
if [[ -n $APT_CACHER_IP ]]; then
if [[ -n $APT_CACHER_IP ]]; then
APT_CACHER_IP="none"
fi
else
@@ -506,7 +505,7 @@ config_file() {
fi
echo -e "${NETWORK}${BOLD}${DGN}DNS Server IP Address: ${BGN}$NX${CL}"
else
exit_script
exit_script
fi
fi
@@ -533,7 +532,7 @@ config_file() {
echo -e "${MACADDRESS}${BOLD}${DGN}MAC Address: ${BGN}$MAC1${CL}"
fi
else
exit_script
exit_script
fi
fi
@@ -582,7 +581,7 @@ config_file() {
fi
echo -e "${NETWORK}${BOLD}${DGN}Tags: ${BGN}$TAGS${CL}"
else
exit_script
exit_script
fi
fi
@@ -646,7 +645,7 @@ config_file() {
exit
fi
else
if (whiptail --backtitle "Proxmox VE Helper Scripts" --defaultno --title "VERBOSE MODE" --yesno "Enable Verbose Mode?" 10 58); then
if (whiptail --backtitle "Proxmox VE Helper Scripts" --defaultno --title "VERBOSE MODE" --yesno "Enable Verbose Mode?" 10 58); then
VERBOSE="yes"
else
VERBOSE="no"

View File

@@ -46,15 +46,26 @@ load_functions() {
on_error() {
local exit_code="$1"
local lineno="$2"
msg_error "Script failed at line $lineno with exit code $exit_code"
# Optionally log to your API or file here
stop_spinner
case "$exit_code" in
1) msg_error "Generic error occurred (line $lineno)" ;;
2) msg_error "Shell misuse (line $lineno)" ;;
126) msg_error "Command cannot execute (line $lineno)" ;;
127) msg_error "Command not found (line $lineno)" ;;
128) msg_error "Invalid exit argument (line $lineno)" ;;
130) msg_error "Script aborted by user (CTRL+C)" ;;
143) msg_error "Script terminated by SIGTERM" ;;
*) msg_error "Script failed at line $lineno with exit code $exit_code" ;;
esac
exit "$exit_code"
}
on_exit() {
# Always called on script exit, success or failure
cleanup_temp_files || true
msg_info "Script exited"
cleanup_spinner || true
[[ "${VERBOSE:-no}" == "yes" ]] && msg_info "Script exited"
}
on_interrupt() {
@@ -184,6 +195,7 @@ icons() {
CREATING="${TAB}🚀${TAB}${CL}"
ADVANCED="${TAB}🧩${TAB}${CL}"
FUSE="${TAB}🗂️${TAB}${CL}"
HOURGLASS="${TAB}${TAB}"
}
# ------------------------------------------------------------------------------
@@ -429,8 +441,14 @@ msg_info() {
local msg="$1"
[[ -z "$msg" || -n "${MSG_INFO_SHOWN["$msg"]+x}" ]] && return
MSG_INFO_SHOWN["$msg"]=1
stop_spinner
start_spinner "$msg"
if [[ "${VERBOSE:-no}" == "no" && -t 2 ]]; then
start_spinner "$msg"
else
printf "\r\e[2K%s %b" "$HOURGLASS" "${YW}${msg}${CL}" >&2
fi
}
msg_ok() {

261
misc/create_lxc.sh Normal file
View File

@@ -0,0 +1,261 @@
#!/usr/bin/env bash
# Copyright (c) 2021-2025 tteck
# Author: tteck (tteckster)
# Co-Author: MickLesk
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
# This sets verbose mode if the global variable is set to "yes"
# if [ "$VERBOSE" == "yes" ]; then set -x; fi
if command -v curl >/dev/null 2>&1; then
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/core.func)
load_functions
#echo "(create-lxc.sh) Loaded core.func via curl"
elif command -v wget >/dev/null 2>&1; then
source <(wget -qO- https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/core.func)
load_functions
#echo "(create-lxc.sh) Loaded core.func via wget"
fi
# This sets error handling options and defines the error_handler function to handle errors
set -Eeuo pipefail
trap 'error_handler $LINENO "$BASH_COMMAND"' ERR
# This function handles errors
function error_handler() {
printf "\e[?25h"
local exit_code="$?"
local line_number="$1"
local command="$2"
local error_message="${RD}[ERROR]${CL} in line ${RD}$line_number${CL}: exit code ${RD}$exit_code${CL}: while executing command ${YW}$command${CL}"
echo -e "\n$error_message\n"
exit 200
}
# This checks for the presence of valid Container Storage and Template Storage locations
msg_info "Validating Storage"
VALIDCT=$(pvesm status -content rootdir | awk 'NR>1')
if [ -z "$VALIDCT" ]; then
msg_error "Unable to detect a valid Container Storage location."
exit 1
fi
VALIDTMP=$(pvesm status -content vztmpl | awk 'NR>1')
if [ -z "$VALIDTMP" ]; then
msg_error "Unable to detect a valid Template Storage location."
exit 1
fi
# This function is used to select the storage class and determine the corresponding storage content type and label.
function select_storage() {
local CLASS=$1
local CONTENT
local CONTENT_LABEL
case $CLASS in
container)
CONTENT='rootdir'
CONTENT_LABEL='Container'
;;
template)
CONTENT='vztmpl'
CONTENT_LABEL='Container template'
;;
*) false || {
msg_error "Invalid storage class."
exit 201
} ;;
esac
# Collect storage options
local -a MENU
local MSG_MAX_LENGTH=0
while read -r TAG TYPE _ _ _ FREE _; do
local TYPE_PADDED
local FREE_FMT
TYPE_PADDED=$(printf "%-10s" "$TYPE")
FREE_FMT=$(numfmt --to=iec --from-unit=K --format %.2f <<<"$FREE")B
local ITEM="Type: $TYPE_PADDED Free: $FREE_FMT"
((${#ITEM} + 2 > MSG_MAX_LENGTH)) && MSG_MAX_LENGTH=$((${#ITEM} + 2))
MENU+=("$TAG" "$ITEM" "OFF")
done < <(pvesm status -content "$CONTENT" | awk 'NR>1')
local OPTION_COUNT=$((${#MENU[@]} / 3))
# Auto-select if only one option available
if [[ "$OPTION_COUNT" -eq 1 ]]; then
echo "${MENU[0]}"
return 0
fi
# Display selection menu
local STORAGE
while [[ -z "${STORAGE:+x}" ]]; do
STORAGE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "Storage Pools" --radiolist \
"Select the storage pool to use for the ${CONTENT_LABEL,,}.\nUse the spacebar to make a selection.\n" \
16 $((MSG_MAX_LENGTH + 23)) 6 \
"${MENU[@]}" 3>&1 1>&2 2>&3) || {
msg_error "Storage selection cancelled."
exit 202
}
done
echo "$STORAGE"
}
# Test if required variables are set
[[ "${CTID:-}" ]] || {
msg_error "You need to set 'CTID' variable."
exit 203
}
[[ "${PCT_OSTYPE:-}" ]] || {
msg_error "You need to set 'PCT_OSTYPE' variable."
exit 204
}
# Test if ID is valid
[ "$CTID" -ge "100" ] || {
msg_error "ID cannot be less than 100."
exit 205
}
# Test if ID is in use
if qm status "$CTID" &>/dev/null || pct status "$CTID" &>/dev/null; then
echo -e "ID '$CTID' is already in use."
unset CTID
msg_error "Cannot use ID that is already in use."
exit 206
fi
# Get template storage
TEMPLATE_STORAGE=$(select_storage template)
msg_ok "Using ${BL}$TEMPLATE_STORAGE${CL} ${GN}for Template Storage."
# Get container storage
CONTAINER_STORAGE=$(select_storage container)
msg_ok "Using ${BL}$CONTAINER_STORAGE${CL} ${GN}for Container Storage."
# Check free space on selected container storage
STORAGE_FREE=$(pvesm status | awk -v s="$CONTAINER_STORAGE" '$1 == s { print $6 }')
REQUIRED_KB=$((${PCT_DISK_SIZE:-8} * 1024 * 1024))
if [ "$STORAGE_FREE" -lt "$REQUIRED_KB" ]; then
msg_error "Not enough space on '$CONTAINER_STORAGE'. Needed: ${PCT_DISK_SIZE:-8}G."
exit 214
fi
# Check Cluster Quorum if in Cluster
if [ -f /etc/pve/corosync.conf ]; then
msg_info "Checking Proxmox cluster quorum status"
if ! pvecm status | awk -F':' '/^Quorate/ { exit ($2 ~ /Yes/) ? 0 : 1 }'; then
printf "\e[?25h"
msg_error "Cluster is not quorate. Start all nodes or configure quorum device (QDevice)."
exit 210
fi
msg_ok "Cluster is quorate"
fi
# Update LXC template list
msg_info "Updating LXC Template List"
if ! timeout 10 pveam update >/dev/null 2>&1; then
msg_error "Failed to update LXC template list. Please check your Proxmox host's internet connection and DNS resolution."
exit 201
fi
$STD msg_ok "LXC Template List Updated"
# Get LXC template string
TEMPLATE_SEARCH="${PCT_OSTYPE}-${PCT_OSVERSION:-}"
mapfile -t TEMPLATES < <(pveam available -section system | sed -n "s/.*\($TEMPLATE_SEARCH.*\)/\1/p" | sort -t - -k 2 -V)
if [ ${#TEMPLATES[@]} -eq 0 ]; then
msg_error "No matching LXC template found for '${TEMPLATE_SEARCH}'. Make sure your host can reach the Proxmox template repository."
exit 207
fi
TEMPLATE="${TEMPLATES[-1]}"
TEMPLATE_PATH="$(pvesm path $TEMPLATE_STORAGE:vztmpl/$TEMPLATE 2>/dev/null || echo "/var/lib/vz/template/cache/$TEMPLATE")"
# Check if template exists and is valid
if ! pveam list "$TEMPLATE_STORAGE" | grep -q "$TEMPLATE" || ! zstdcat "$TEMPLATE_PATH" | tar -tf - >/dev/null 2>&1; then
msg_warn "Template $TEMPLATE not found or appears to be corrupted. Re-downloading."
[[ -f "$TEMPLATE_PATH" ]] && rm -f "$TEMPLATE_PATH"
for attempt in {1..3}; do
msg_info "Attempt $attempt: Downloading LXC template..."
if timeout 120 pveam download "$TEMPLATE_STORAGE" "$TEMPLATE" >/dev/null 2>&1; then
msg_ok "Template download successful."
break
fi
if [ $attempt -eq 3 ]; then
msg_error "Failed after 3 attempts. Please check your Proxmox hosts internet access or manually run:\n pveam download $TEMPLATE_STORAGE $TEMPLATE"
exit 208
fi
sleep $((attempt * 5))
done
fi
msg_ok "LXC Template '$TEMPLATE' is ready to use."
# Check and fix subuid/subgid
grep -q "root:100000:65536" /etc/subuid || echo "root:100000:65536" >>/etc/subuid
grep -q "root:100000:65536" /etc/subgid || echo "root:100000:65536" >>/etc/subgid
# Combine all options
PCT_OPTIONS=(${PCT_OPTIONS[@]:-${DEFAULT_PCT_OPTIONS[@]}})
[[ " ${PCT_OPTIONS[@]} " =~ " -rootfs " ]] || PCT_OPTIONS+=(-rootfs "$CONTAINER_STORAGE:${PCT_DISK_SIZE:-8}")
# Secure creation of the LXC container with lock and template check
lockfile="/tmp/template.${TEMPLATE}.lock"
exec 9>"$lockfile"
flock -w 60 9 || {
msg_error "Timeout while waiting for template lock"
exit 211
}
msg_info "Creating LXC Container"
if ! pct create "$CTID" "${TEMPLATE_STORAGE}:vztmpl/${TEMPLATE}" "${PCT_OPTIONS[@]}" &>/dev/null; then
msg_error "Container creation failed. Checking if template is corrupted or incomplete."
if [[ ! -s "$TEMPLATE_PATH" || "$(stat -c%s "$TEMPLATE_PATH")" -lt 1000000 ]]; then
msg_error "Template file too small or missing re-downloading."
rm -f "$TEMPLATE_PATH"
elif ! zstdcat "$TEMPLATE_PATH" | tar -tf - &>/dev/null; then
msg_error "Template appears to be corrupted re-downloading."
rm -f "$TEMPLATE_PATH"
else
msg_error "Template is valid, but container creation still failed."
exit 209
fi
# Retry download
for attempt in {1..3}; do
msg_info "Attempt $attempt: Re-downloading template..."
if timeout 120 pveam download "$TEMPLATE_STORAGE" "$TEMPLATE" >/dev/null; then
msg_ok "Template re-download successful."
break
fi
if [ "$attempt" -eq 3 ]; then
msg_error "Three failed attempts. Aborting."
exit 208
fi
sleep $((attempt * 5))
done
sleep 1 # I/O-Sync-Delay
msg_ok "Re-downloaded LXC Template"
if ! pct create "$CTID" "${TEMPLATE_STORAGE}:vztmpl/${TEMPLATE}" "${PCT_OPTIONS[@]}" &>/dev/null; then
msg_error "Container creation failed after re-downloading template."
exit 200
fi
fi
if ! pct status "$CTID" &>/dev/null; then
msg_error "Container not found after pct create assuming failure."
exit 210
fi
msg_ok "LXC Container ${BL}$CTID${CL} ${GN}was successfully created."

View File

@@ -3,53 +3,13 @@
# License: MIT
# https://github.com/asylumexp/Proxmox/raw/main/LICENSE
# This function sets color variables for formatting output in the terminal
color() {
# Colors
YW=$(echo "\033[33m")
YWB=$(echo "\033[93m")
BL=$(echo "\033[36m")
RD=$(echo "\033[01;31m")
GN=$(echo "\033[1;92m")
# Formatting
CL=$(echo "\033[m")
BFR="\\r\\033[K"
BOLD=$(echo "\033[1m")
HOLD=" "
TAB=" "
TAB3=" "
# System
RETRY_NUM=10
RETRY_EVERY=3
# Icons
CM="${TAB}✔️${TAB}${CL}"
CROSS="${TAB}✖️${TAB}${CL}"
INFO="${TAB}💡${TAB}${CL}"
NETWORK="${TAB}📡${TAB}${CL}"
OS="${TAB}🖥️${TAB}${CL}"
OSVERSION="${TAB}🌟${TAB}${CL}"
HOSTNAME="${TAB}🏠${TAB}${CL}"
GATEWAY="${TAB}🌐${TAB}${CL}"
DEFAULT="${TAB}⚙️${TAB}${CL}"
}
# Function to set STD mode based on verbosity
set_std_mode() {
if [ "$VERBOSE" = "yes" ]; then
STD=""
else
STD="silent"
fi
}
# Silent execution function
silent() {
"$@" >/dev/null 2>&1
}
if ! command -v curl >/dev/null 2>&1; then
printf "\r\e[2K%b" '\033[93m Setup Source \033[m' >&2
apt-get update >/dev/null 2>&1
apt-get install -y curl >/dev/null 2>&1
fi
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/core.func)
load_functions
# This function enables IPv6 if it's not disabled and sets verbose mode
verb_ip6() {
set_std_mode # Set STD mode based on VERBOSE
@@ -69,7 +29,6 @@ catch_errors() {
# This function handles errors
error_handler() {
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/api.func)
if [ -n "$SPINNER_PID" ] && ps -p "$SPINNER_PID" >/dev/null; then kill "$SPINNER_PID" >/dev/null; fi
printf "\e[?25h"
local exit_code="$?"
local line_number="$1"
@@ -84,62 +43,15 @@ error_handler() {
fi
}
# This function displays a spinner.
spinner() {
local frames=('⠋' '⠙' '⠹' '⠸' '⠼' '⠴' '⠦' '⠧' '⠇' '⠏')
local spin_i=0
local interval=0.1
printf "\e[?25l"
local color="${YWB}"
while true; do
printf "\r ${color}%s${CL}" "${frames[spin_i]}"
spin_i=$(((spin_i + 1) % ${#frames[@]}))
sleep "$interval"
done
}
# This function displays an informational message with a yellow color.
msg_info() {
local msg="$1"
echo -ne "${TAB}${YW}${HOLD}${msg}${HOLD}"
spinner &
SPINNER_PID=$!
}
# This function displays a success message with a green color.
msg_ok() {
if [ -n "$SPINNER_PID" ] && ps -p "$SPINNER_PID" >/dev/null; then kill "$SPINNER_PID" >/dev/null; fi
printf "\e[?25h"
local msg="$1"
echo -e "${BFR}${CM}${GN}${msg}${CL}"
}
# This function displays a error message with a red color.
msg_error() {
if [ -n "$SPINNER_PID" ] && ps -p "$SPINNER_PID" >/dev/null; then kill "$SPINNER_PID" >/dev/null; fi
printf "\e[?25h"
local msg="$1"
echo -e "${BFR}${CROSS}${RD}${msg}${CL}"
}
# This function sets up the Container OS by generating the locale, setting the timezone, and checking the network connection
setting_up_container() {
msg_info "Setting up Container OS"
sed -i "/$LANG/ s/\(^# \)//" /etc/locale.gen
locale_line=$(grep -v '^#' /etc/locale.gen | grep -E '^[a-zA-Z]' | awk '{print $1}' | head -n 1)
echo "LANG=${locale_line}" >/etc/default/locale
locale-gen >/dev/null
export LANG=${locale_line}
echo "$tz" >/etc/timezone
ln -sf /usr/share/zoneinfo/"$tz" /etc/localtime
for ((i = RETRY_NUM; i > 0; i--)); do
if [ "$(hostname -I)" != "" ]; then
break
fi
echo 1>&2 -en "${CROSS}${RD} No Network! "
sleep "$RETRY_EVERY"
sleep $RETRY_EVERY
done
if [ "$(hostname -I)" = "" ]; then
echo 1>&2 -e "\n${CROSS}${RD} No Network After $RETRY_NUM Tries${CL}"
@@ -149,7 +61,7 @@ setting_up_container() {
rm -rf /usr/lib/python3.*/EXTERNALLY-MANAGED
systemctl disable -q --now systemd-networkd-wait-online.service
msg_ok "Set up Container OS"
msg_ok "Network Connected: ${BL}$(hostname -I)"
msg_custom "${CM}" "${GN}" "Network Connected: ${BL}$(hostname -I)"
}
# This function checks the network connection by pinging a known IP address and prompts the user to continue if the internet is not connected
@@ -177,7 +89,7 @@ network_check() {
# If both IPv4 and IPv6 checks fail, prompt the user
if [[ $ipv4_connected == false && $ipv6_connected == false ]]; then
read -r -p "No Internet detected,would you like to continue anyway? <y/N> " prompt
read -r -p "No Internet detected, would you like to continue anyway? <y/N> " prompt
if [[ "${prompt,,}" =~ ^(y|yes)$ ]]; then
echo -e "${INFO}${RD}Expect Issues Without Internet${CL}"
else
@@ -186,8 +98,26 @@ network_check() {
fi
fi
RESOLVEDIP=$(getent hosts github.com | awk '{ print $1 }')
if [[ -z "$RESOLVEDIP" ]]; then msg_error "DNS Lookup Failure"; else msg_ok "DNS Resolved github.com to ${BL}$RESOLVEDIP${CL}"; fi
# DNS resolution checks for GitHub-related domains (IPv4 and/or IPv6)
GITHUB_HOSTS=("github.com" "raw.githubusercontent.com" "api.github.com")
GITHUB_STATUS="GitHub DNS:"
DNS_FAILED=false
for HOST in "${GITHUB_HOSTS[@]}"; do
RESOLVEDIP=$(getent hosts "$HOST" | awk '{ print $1 }' | grep -E '(^([0-9]{1,3}\.){3}[0-9]{1,3}$)|(^[a-fA-F0-9:]+$)' | head -n1)
if [[ -z "$RESOLVEDIP" ]]; then
GITHUB_STATUS+="$HOST:($DNSFAIL)"
DNS_FAILED=true
else
GITHUB_STATUS+=" $HOST:($DNSOK)"
fi
done
if [[ "$DNS_FAILED" == true ]]; then
fatal "$GITHUB_STATUS"
else
msg_ok "$GITHUB_STATUS"
fi
set -e
trap 'error_handler $LINENO "$BASH_COMMAND"' ERR
}
@@ -215,8 +145,8 @@ EOF
msg_info "Installing core dependencies"
$STD apt-get update
$STD apt-get install -y sudo curl mc gnupg2 openssh-server wget
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/tools.func)
msg_ok "Core dependencies installed"
}
# This function modifies the message of the day (motd) and SSH settings

File diff suppressed because it is too large Load Diff