Files
vmcreate/vmcreate1.sh
2025-10-26 08:56:11 +00:00

224 lines
8.0 KiB
Bash
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/bin/bash
### МЫСЛИ ПО ФИЧАМ
# Сделать проверку, какие правила НА существуют, и вывести выбор /etc/pve/ha/rules.cfg
# Сделать добавление кастомного полльзователя с паролем
# Сделать замену тега влан
# Сделать проверку наличия ВМ перед клонированием.
# Добавить переезд на ноду, выбор ноды. Статистика загрузки нод - в хелп.
# Добавить тег прокса
# ИЗУЧИТЬ!!!! /usr/share/pve-docs/examples/guest-example-hookscript.pl
storage="syno-tigra"
#path="/mnt/pve/$storage/snippets"
path="./snippets"
node=3
show_help()
echo 'Usage:'
echo 'vmcreate [-h][-a rule_name][-k pub_keyfile][-u][-p][-f filename]'
echo 'Arguments:'
echo '-h - show this help;'
echo '-a - add hosts to HA affinity rules;'
echo "-k - embed custom public key or create new if `pub_keyfile` not specified"
echo "-u - specify user instead of default `root`"
echo "-p - specify password instead of default"
echo "-f - get IP addresses and Hostnames from `flilename`;"
echo "\nIf file not specified, script will use arguments as a list of IP addresses."
echo "In this case Hostname will be inherited from 2 last IP octets. Example for 10.10.35.20: `vm035020`."
echo "IP address should be 10.10.*.*"
# Обрабатываем опции
while getopts "a:f:h" opt; do
case $opt in
a) harule="$OPTARG";;
f) file="$OPTARG" ;;
h) show_help ; exit 0;;
k) pubkey="$OPTARG";;
u) username="$OPTARG";;
p) password="$OPTARG";;
# *) noopts=true
esac
done
# Вывод переменных для дебага:
if [[ -v file ]]; then echo "File: $file"; fi
if [[ -v pubkey ]]; then echo "Public key: $pubkey"; fi
if [[ -v username ]]; then echo "User: $file"; fi
# Если файл не задан, но флаг есть
if [[ $# -eq 0 && -v "$file" && ! -f "$file" ]]; then
input=y
read -p "File `$file` does not exist. Use default `hosts` file? Y/n: " input
case $input in
y) file=hosts;;
Y) file=hosts;;
n) read -p "Enter file name: " file;;
N) read -p "Enter file name: " file;;
*) echo "Use '-f' flag for help"; exit 0;;
esac
if [[ ! -f "$file" ]]; then echo "File `$file` does not exist. Exiting."; exit 1; fi
fi
# Если заданы аргументы И файл
if [[ $# -ne 0 && -v "$file" ]]; then echo "Please enter file OR arguments. Use '-f' flag for help"; exit 2; fi
# Проверка файла на соответствие шаблону IPv4 адреса и hostname, создаём временный файл из валидных строк
if [[ -e "$file" ]]; then
touch hosts.tmp
echo -n "" > hosts.tmp
for line in $(cat "$file"); do
ip=$(echo $line | cut -d ' ' -f 1)
hostname=$(echo $line | cut -d ' ' -f 2)
if [[ $? -eq 0 ]]; then
hostcheck "$hostname"
if [[ $? -eq 0 ]];
then
echo $line >> hosts.tmp
else
echo "Hostname `$hostname` is not valid. Should contain only letters, numbers and dash. Aborting."
rm hosts.tmp
exit 3
fi
else
echo "`$ip` is not a valid IPv4 address (10.10.*.*). Aborting."
rm hosts.tmp
exit 4
fi
done
fi
# Если заданы аргументы, то создаем временный файл
if [[ $# -ne 0 ]] then
touch hosts.tmp
echo -n "" > hosts.tmp
for arg in "$@"; do
ipcheck "$arg"
if [ $? -eq 0 ]
then
echo -n "$arg " >> ./hosts.tmp
echo -n "vm" >> ./hosts.tmp
printf "%03d\n" "$(echo -n $arg | cut -d '.' -f 3)" >> ./hosts.tmp
printf "%03d\n" "$(echo -n $arg | cut -d '.' -f 4)" >> ./hosts.tmp
echo >> hosts.tmp
else
echo "Argument `$arg` is not a valid IPv4 address (10.10.*.*). Aborting."
rm hosts.tmp
exit 5
fi
done
fi
# Функция для проверки IP адреса по шаблону 10.10.*.*, написана гуглом
ipcheck() {
local ip=$1
local stat=1
oldIFS=$IFS
# Check if the IP matches the general IPv4 pattern
if [[ $ip =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then
# Split the IP into octets
IFS='.' read -r -a octets <<< "$ip"
# Check if each octet is within the valid range (0-255)
if [[ ${octets[0]} -eq 10 && ${octets[1]} -eq 10 && ${octets[2]} -le 252 && ${octets[3]} -le 252 && ${octets[3]} -ne 0 ]]; then
stat=0
fi
fi
return $stat
IFS=$oldIFS
}
# Функция для проверки hostname на валидные символы (буквы, цифры, дефис)
hostcheck (){
local hostname=$1
local pattern="^[a-zA-Z0-9-]+$"
if [[ "$hostname" =~ $pattern ]]; then return 0; else return 1; fi
}
# Проверяем ключ
if [ -v pubkey ]; then
if [[ ! -f pubkey ]]; then
input=y
echo "Private key does not exist. Generate new pair? y/n"
read input
case $input in
y) read -p "Enter name for your private key: " privkey && keypair_generate ("$privkey");;
Y) read -p "Enter name for your private key: " privkey && keypair_generate ("$privkey");;
n) echo "Public key is necessary to continue. Please specify or generate new pair.";;
N) echo "Public key is necessary to continue. Please specify or generate new pair.";;
*) echo "Use '-h' flag for help"; exit 6;;
esac
fi
else
pubkey="key.pub"
if [[ ! -e key.pub ]]; then echo "`key.pub` does not exist. Please use `-k` flag to specify public key."; exit 7; fi
fi
###DEBUG 1
echo "File `hosts.tmp`:"
cat hosts.tmp; echo
keypair_generate (){
ssh-keygen -t rsa -N "" -f $privkey
pubkey="$privkey".pub
}
mksnippet (){
snippet="${path}${vmnum}_user.yaml"
cp ./user.yaml "$snippet"
sed -i "s/HOSTNAME/$hostname/g" "$snippet"
if [[ -n $username ]];
then sed -i "s|user: root|user: ${username}\nsudo: ALL=(ALL) NOPASSWD:ALL|" "$snippet"
fi
if [[ -n $password ]];
phash=$(cat $password | mkpasswd -m sha-256 -s)
then sed -i "s|.*password.*| - ${phash}|" "$snippet"
fi
sed -i "s|.*ssh-rsa.*| - ${pubkey}|" "$snippet"
}
for line in $(cat hosts.tmp)
do
ip=$(echo $line | cut -d ' ' -f 1)
vlan=$(echo $ip | cut -d '.' -f 3)
if [[ vlan -eq 0 ]]; then mask=23; gw="10.10.0.1"; vlan=100; else mask=24; gw="10.10.${vlan}.1"; fi
hostname=$(echo $line | cut -d ' ' -f 2)
vmnum="$vlan(printf "%03d\n" "$(echo -n $ip | cut -d '.' -f 4)")"
if [[ $vlan -eq 0 ]]; then $vlan=100; fi
mksnippet
#### DEBUG 2
echo "IP: $ip"
echo "hostname: $hostname"
echo "VMID: $vmnum"
echo "VLAN: $vlan"
echo "Snippet:"
cat "$snippet"
read -p "Press Enter"
####
echo -n "Now cloning VM $vmnum from a template....."
qm clone 5000 $vmnum --name $hostname --full &>/dev/null
if [ $? -eq 0 ]
then echo "OK"
else "ERROR"; exit 8
fi
qm set $vmnum --tags $node,gfx
qm resize $vmnum scsi0 +50G
qm set $vmnum --cicustom "user=${storage}:snippets/${vmnum}_user.yaml"
qm set $vmnum --ipconfig0 ip=$ip/24,gw=10.10.35.1
qm cloudinit update $vmnum
qm start $vmnum
if [ -v harule ]
then
ha-manager add vm:$vmnum --state started --max_relocate 2
ha-manager rules add node-affinity $harule --resources vm:$vmnum --nodes pve1,pve2,pve3 --strict 1
echo "HA rule added"
# ОБЯЗАТЕЛЬНО ПРОВЕРИТЬ КОМАНДУ!!!
fi
done
# Финальная часть
rm hosts.tmp
if [ -v $privkey ]
then
echo "\nGenerated private key `$privkey`"
echo "SAVE IT IMMEDIATELY!!!"
fi