mirror of
https://github.com/flynx/proxmox-utils.git
synced 2025-10-28 18:50:08 +00:00
438 lines
8.1 KiB
Bash
438 lines
8.1 KiB
Bash
#!/usr/bin/bash
|
|
#----------------------------------------------------------------------
|
|
|
|
CT_DIR=${CT_DIR:=/etc/pve/lxc/}
|
|
|
|
|
|
|
|
#----------------------------------------------------------------------
|
|
# XXX this is quite generic, might be a good idea to move this to a
|
|
# seporate lib/file...
|
|
|
|
# Execute (optionally) and print a command.
|
|
#
|
|
#QUIET=
|
|
#DRY_RUN=
|
|
ECHO_PREFIX="### "
|
|
@(){
|
|
if [ -z $DRY_RUN ] ; then
|
|
! [ $QUIET ] \
|
|
&& echo "${ECHO_PREFIX}$@"
|
|
$@
|
|
else
|
|
echo $@
|
|
fi
|
|
return $?
|
|
}
|
|
|
|
|
|
|
|
#----------------------------------------------------------------------
|
|
# Fill section...
|
|
#
|
|
# XXX this is quite generic -- move to a more logical place...
|
|
|
|
fillsection(){ (
|
|
usage(){
|
|
echo "Usage:"
|
|
echo " ${FUNCNAME[0]} [-h]"
|
|
echo " ${FUNCNAME[0]} [-r] NAME FILE [CONTENT]"
|
|
echo
|
|
}
|
|
while true ; do
|
|
case $1 in
|
|
-h|--help)
|
|
usage
|
|
echo "Options:"
|
|
# . . .
|
|
echo " -h | --help print this help message and exit."
|
|
echo " -r | --return replace section markers with CONTENT."
|
|
echo
|
|
return 0
|
|
;;
|
|
-r|--replace)
|
|
local replace=1
|
|
shift
|
|
;;
|
|
|
|
*)
|
|
break
|
|
;;
|
|
esac
|
|
done
|
|
if [[ $# < 2 ]] ; then
|
|
usage
|
|
return 1
|
|
fi
|
|
|
|
name=$1
|
|
file=$2
|
|
content=$3
|
|
content=${content:=/dev/stdin}
|
|
|
|
# print file upto section marker...
|
|
if [ $replace ] ; then
|
|
sed "/${name^^} BEGIN/q" "$file" | sed '$d'
|
|
else
|
|
sed "/${name^^} BEGIN/q" "$file"
|
|
fi
|
|
# print content...
|
|
cat $content
|
|
# print file from section end marker...
|
|
if [ $replace ] ; then
|
|
sed -ne "/${name^^} END/,$ p" "$file" | sed '1d'
|
|
else
|
|
sed -ne "/${name^^} END/,$ p" "$file"
|
|
fi
|
|
) }
|
|
|
|
|
|
|
|
#----------------------------------------------------------------------
|
|
# CT hostname <-> CT id...
|
|
|
|
ct2hostname(){
|
|
local ct=${CT_DIR}/${1}.conf
|
|
local host=$(cat $ct | grep hostname | head -1)
|
|
echo ${host/hostname: /}
|
|
}
|
|
|
|
hostname2ct(){
|
|
if [ -e "${CT_DIR}/${1}.conf" ] ; then
|
|
echo $1
|
|
fi
|
|
local running=$2
|
|
running=${running:=any}
|
|
local ct
|
|
local host
|
|
for ct in "${CT_DIR}"/*.conf ; do
|
|
host=$(cat $ct | grep hostname | head -1)
|
|
host=${host/hostname: /}
|
|
if [ "$host" = $1 ] ; then
|
|
ct=${ct#${CT_DIR}}
|
|
ct=${ct%.conf}
|
|
ct=${ct#\/}
|
|
# filter results if needed...
|
|
if [ $running = "any" ] ; then
|
|
echo $ct
|
|
else
|
|
local status=`pct status $ct`
|
|
if [ "$running" = "${status/status: /}" ] ; then
|
|
echo $ct
|
|
fi
|
|
fi
|
|
fi
|
|
done
|
|
}
|
|
|
|
|
|
#----------------------------------------------------------------------
|
|
|
|
normpath(){
|
|
echo $1 \
|
|
| sed \
|
|
-e 's/\/\+/\//g' \
|
|
-e 's/\/.\//\//g' \
|
|
-e 's/[^\/]\+\/\.\.//g' \
|
|
-e 's/\/\+/\//g' \
|
|
-e 's/\/\.$/\//g'
|
|
}
|
|
|
|
|
|
#----------------------------------------------------------------------
|
|
|
|
#
|
|
# getLatestTemplate PATTERN [VAR]
|
|
#
|
|
# see:
|
|
# https://pve.proxmox.com/wiki/Linux_Container
|
|
getLatestTemplate(){
|
|
#IFS=$'\n'
|
|
#@ pveam update
|
|
|
|
local templates=($(pveam available | grep -o ''${1}'.*$'))
|
|
local latest=${templates[-1]}
|
|
|
|
@ pveam download local ${latest}
|
|
|
|
latest=$(pveam list local | grep -o "^.*$latest")
|
|
#latest=($(ls /var/lib/vz/template/cache/${1}*))
|
|
|
|
[ -z $2 ] \
|
|
|| eval "$2=${latest}"
|
|
}
|
|
|
|
#
|
|
# xread [-n] MSG VAR
|
|
#
|
|
xread(){
|
|
local non_empty=
|
|
if [[ $1 == '-n' ]] ; then
|
|
shift
|
|
local non_empty=1
|
|
fi
|
|
[ -z ${!2} ] \
|
|
&& eval 'read -ep "'$1'" -i "$DFL_'$2'" '${2}''
|
|
if [ -z $non_empty ] ; then
|
|
eval ''$2'=${'$2':=$DFL_'$2'}'
|
|
fi
|
|
[ $SCRIPTING ] \
|
|
&& echo "$2=${!2}"
|
|
}
|
|
|
|
#
|
|
# xreadpass VAR
|
|
#
|
|
xreadpass(){
|
|
local PASS1
|
|
local PASS2
|
|
for attempt in 1 2 3 ; do
|
|
read -sep "password (Enter to skip): " PASS1
|
|
echo
|
|
if [ -z $PASS1 ] ; then
|
|
return
|
|
fi
|
|
read -sep "retype password: " PASS2
|
|
echo
|
|
if [[ $PASS1 != $PASS2 ]] ; then
|
|
echo "ERR: passwords do not match."
|
|
continue
|
|
fi
|
|
eval ''$1'='${PASS1}''
|
|
return
|
|
done
|
|
return 1
|
|
}
|
|
|
|
|
|
#
|
|
# tklWaitForSetup MSG
|
|
#
|
|
tklWaitForSetup(){
|
|
printf "$1"
|
|
if [ -z $DRY_RUN ] ; then
|
|
while ! $(lxc-attach $ID -- test -e /etc/inithooks.conf) ; do
|
|
printf '.'
|
|
sleep 5
|
|
done
|
|
printf '+'
|
|
sleep 5
|
|
while ! [[ $(lxc-attach $ID -- cat /etc/inithooks.conf | wc -c) < 2 ]] ; do
|
|
printf '.'
|
|
sleep 5
|
|
done
|
|
else
|
|
printf '.+..'
|
|
fi
|
|
printf 'ready.\n'
|
|
sleep 5
|
|
}
|
|
|
|
|
|
#
|
|
# readConfig
|
|
#
|
|
readConfig(){
|
|
if [ -z $NO_DEFAULTS ] ; then
|
|
[ -e ../config.global ] \
|
|
&& source ../config.global
|
|
[ -e ./config ] \
|
|
&& source ./config
|
|
fi
|
|
}
|
|
|
|
#
|
|
# readVars
|
|
#
|
|
# Variables this handles:
|
|
# EMAIL
|
|
# DOMAIN
|
|
# ID
|
|
# CTHOSTNAME
|
|
# WAN_BRIDGE
|
|
# LAN_BRIDGE
|
|
# ADMIN_BRIDGE
|
|
# WAN_IP
|
|
# WAN_GATE
|
|
# LAN_IP
|
|
# LAN_GATE
|
|
# ADMIN_IP
|
|
# ADMIN_GATE
|
|
# ROOTPASS
|
|
# PCT_EXTRA
|
|
#
|
|
# Variables this sets:
|
|
# PASS
|
|
#
|
|
# Variables used:
|
|
# TMP_PASS_LEN
|
|
# ROOTPASS
|
|
#
|
|
readVars(){
|
|
xread -n "Email: " EMAIL
|
|
xread -n "Domain: " DOMAIN
|
|
xread "ID: " ID
|
|
xread "Hostname: " CTHOSTNAME
|
|
|
|
# hardware...
|
|
xread "CPU cores: " CORES
|
|
xread "RAM (MB): " RAM
|
|
xread "SWAP (MB): " SWAP
|
|
xread "DRIVE (GB): " DRIVE
|
|
|
|
# bridge config...
|
|
xread "WAN bridge: vmbr" WAN_BRIDGE
|
|
xread "LAN bridge: vmbr" LAN_BRIDGE
|
|
xread "ADMIN bridge: vmbr" ADMIN_BRIDGE
|
|
|
|
# gateway...
|
|
# IPs can be:
|
|
# <empty>
|
|
# <IP>/<mask>
|
|
# dhcp
|
|
# Gateways can be:
|
|
# <empty>
|
|
# <IP>
|
|
xread "WAN ip: " WAN_IP
|
|
xread "WAN gateway: " WAN_GATE
|
|
xread "LAN ip: " LAN_IP
|
|
xread "LAN gateway: " LAN_GATE
|
|
xread "ADMIN ip: " ADMIN_IP
|
|
xread "ADMIN gateway: " ADMIN_GATE
|
|
|
|
# root password...
|
|
if [ -z $ROOTPASS ] ; then
|
|
xreadpass PASS \
|
|
|| exit 1
|
|
else
|
|
PASS=$ROOTPASS
|
|
fi
|
|
|
|
# extra stuff...
|
|
xread "pct extra options: " PCT_EXTRA
|
|
}
|
|
|
|
|
|
#
|
|
# buildAssets [TEMPLATES [ASSETS]]
|
|
#
|
|
buildAssets(){
|
|
local TEMPLATE_DIR=$1
|
|
TEMPLATE_DIR=${TEMPLATE_DIR:=templates}
|
|
local ASSETS_DIR=$2
|
|
ASSETS_DIR=${ASSETS_DIR:=assets}
|
|
|
|
if ! [ -e $TEMPLATE_DIR ] ; then
|
|
return
|
|
fi
|
|
|
|
local TEMPLATES=($(find "$TEMPLATE_DIR" -type f))
|
|
for file in "${TEMPLATES[@]}" ; do
|
|
file=${file#${TEMPLATE_DIR}}
|
|
echo Generating: ${file}...
|
|
[ $DRY_RUN ] \
|
|
&& continue
|
|
# ensure the directory exists...
|
|
mkdir -p "$(dirname "${ASSETS_DIR}/${file}")"
|
|
cat "${TEMPLATE_DIR}/${file}" \
|
|
| sed \
|
|
-e 's/\${EMAIL}/'${EMAIL/\//\\/}'/g' \
|
|
-e 's/\${DOMAIN}/'${DOMAIN/\//\\/}'/g' \
|
|
-e 's/\${CTHOSTNAME}/'${CTHOSTNAME/\//\\/}'/g' \
|
|
-e 's/\${GATE_HOSTNAME}/'${GATE_HOSTNAME/\//\\/}'/g' \
|
|
-e 's/\${NS_HOSTNAME}/'${NS_HOSTNAME/\//\\/}'/g' \
|
|
-e 's/\${GATE_LAN_IP}/'${GATE_LAN_IP/\//\\/}'/g' \
|
|
-e 's/\${GATE_LAN_IPn}/'${GATE_LAN_IP/\/*}'/g' \
|
|
-e 's/\${GATE_ADMIN_IP}/'${GATE_ADMIN_IP/\//\\/}'/g' \
|
|
-e 's/\${GATE_ADMIN_IPn}/'${GATE_ADMIN_IP/\/*}'/g' \
|
|
-e 's/\${NS_LAN_IP}/'${NS_LAN_IP/\//\\/}'/g' \
|
|
-e 's/\${NS_LAN_IPn}/'${NS_LAN_IP/\/*}'/g' \
|
|
-e 's/\${NS_ADMIN_IP}/'${NS_ADMIN_IP/\//\\/}'/g' \
|
|
-e 's/\${NS_ADMIN_IPn}/'${NS_ADMIN_IP/\/*}'/g' \
|
|
-e 's/\${WAN_IP}/'${WAN_IP/\//\\/}'/g' \
|
|
-e 's/\${WAN_IPn}/'${WAN_IP/\/*}'/g' \
|
|
-e 's/\${WAN_GATE}/'${WAN_GATE/\//\\/}'/g' \
|
|
-e 's/\${LAN_IP}/'${LAN_IP/\//\\/}'/g' \
|
|
-e 's/\${LAN_IPn}/'${LAN_IP/\/*}'/g' \
|
|
-e 's/\${LAN_GATE}/'${LAN_GATE/\//\\/}'/' \
|
|
-e 's/\${ADMIN_IP}/'${ADMIN_IP/\//\\/}'/g' \
|
|
-e 's/\${ADMIN_IPn}/'${ADMIN_IP/\/*}'/g' \
|
|
-e 's/\${ADMIN_GATE}/'${ADMIN_GATE/\//\\/}'/g' \
|
|
> "${ASSETS_DIR}/${file}"
|
|
done
|
|
}
|
|
|
|
|
|
#
|
|
# pctCreate ID TEMPLATE ARGS [PASS]
|
|
#
|
|
pctCreate(){
|
|
local TMP_PASS=$(cat /dev/urandom | base64 | head -c ${TMP_PASS_LEN:=32})
|
|
# NOTE: we are not setting the password here to avoid printing it to the terminal...
|
|
@ pct create $1 \
|
|
${2} \
|
|
${3} \
|
|
--password="$TMP_PASS" \
|
|
--start 1 \
|
|
|| exit 1
|
|
# set actual root password...
|
|
if [ "$4" ] ; then
|
|
echo "root:$4" \
|
|
| @ lxc-attach $1 chpasswd
|
|
fi
|
|
}
|
|
|
|
#
|
|
# pctCreate<distro> ID ARGS [PASS]
|
|
#
|
|
pctCreateAlpine(){
|
|
local TEMPLATE
|
|
getLatestTemplate alpine TEMPLATE
|
|
|
|
pctCreate $1 "$TEMPLATE" "$2" "$3"
|
|
|
|
sleep ${TIMEOUT:=5}
|
|
|
|
@ lxc-attach $1 apk update
|
|
@ lxc-attach $1 apk upgrade
|
|
}
|
|
pctCreateDebian(){
|
|
local TEMPLATE
|
|
getLatestTemplate 'debian-12-standard' TEMPLATE
|
|
|
|
pctCreate $1 "$TEMPLATE" "$2" "$3"
|
|
|
|
sleep ${TIMEOUT:=5}
|
|
|
|
@ lxc-attach $1 apt update
|
|
@ lxc-attach $1 -- apt upgrade -y
|
|
}
|
|
pctCreateUbuntu(){
|
|
local TEMPLATE
|
|
getLatestTemplate ubuntu TEMPLATE
|
|
|
|
pctCreate $1 "$TEMPLATE" "$2" "$3"
|
|
|
|
sleep ${TIMEOUT:=5}
|
|
|
|
@ lxc-attach $1 apt update
|
|
@ lxc-attach $1 -- apt upgrade -y
|
|
}
|
|
|
|
|
|
#
|
|
# pctSet ID [ARGS [REBOOT]]
|
|
#
|
|
pctSet(){
|
|
[ "$2" ] \
|
|
&& @ pct set $1 \
|
|
${2}
|
|
[ "$3" ] \
|
|
&& @ pct reboot $1
|
|
}
|
|
|
|
|
|
|
|
#----------------------------------------------------------------------
|
|
# vim:set ts=4 sw=4 nowrap :
|