Update vmcreate.sh
This commit is contained in:
322
vmcreate.sh
Normal file
322
vmcreate.sh
Normal file
@@ -0,0 +1,322 @@
|
||||
#!/bin/bash
|
||||
### ВКЛЮЧИТЬ qm start !!!!!!!!!!!
|
||||
### МЫСЛИ ПО ФИЧАМ
|
||||
# Сделать проверку, какие правила НА существуют, и вывести выбор /etc/pve/ha/rules.cfg
|
||||
# Добавить переезд на ноду, выбор ноды. Статистика загрузки нод - в хелп.
|
||||
# ИЗУЧИТЬ!!!! /usr/share/pve-docs/examples/guest-example-hookscript.pl
|
||||
|
||||
storage="syno-tigra"
|
||||
#path="/mnt/pve/$storage/snippets"
|
||||
path="./snippets/" #SEE BELOW!!!
|
||||
mkdir $path #REMOVE AFTER CORRECT PATH!!!!!!!!
|
||||
node=3
|
||||
size=50
|
||||
|
||||
# Далее объявляю переменные, в цикле getopts это не получается
|
||||
harule=""
|
||||
pubkey=""
|
||||
username=""
|
||||
password=""
|
||||
tag=""
|
||||
file=""
|
||||
# Конец костыля
|
||||
|
||||
show_help () {
|
||||
echo
|
||||
echo 'Usage:'
|
||||
echo 'vmcreate [-h][-a rule_name][-k pub_keyfile][-u][-p][-d 50][-t][-f filename]'
|
||||
echo 'Arguments:'
|
||||
echo '-h - show this help.'
|
||||
echo '-a - add hosts to HA affinity rules with name 'rule_name'.'
|
||||
echo "-k - embed custom public key or create new if 'pub_keyfile' does not exist."
|
||||
echo "-u - specify user instead of default 'root'."
|
||||
echo "-p - specify password instead of default."
|
||||
echo "-d - add custom disk space (in gibibytes, integer). Default is 50."
|
||||
echo "-n - specify target node NUMBER to migrate VM to after creating. Default is '3'"
|
||||
echo "-t - add additional proxmox tag. Default is only pve node number."
|
||||
echo "-f - get IP addresses and Hostnames from 'flilename'."
|
||||
echo
|
||||
echo "If 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.XXX.YYY"
|
||||
echo
|
||||
}
|
||||
|
||||
#Функция создания VMID, аргумент - IPv4 адрес.
|
||||
get_vmid () {
|
||||
local vlan=$(echo -n $1 | cut -d '.' -f 3)
|
||||
local oct4=$(echo -n $1 | cut -d '.' -f 4)
|
||||
local vmid=""
|
||||
if [[ $vlan -eq 0 ]]; then
|
||||
vmid=100
|
||||
else
|
||||
vmid=$(printf "%02d\n" "$vlan")
|
||||
fi
|
||||
vmid+=$(printf "%03d\n" "$oct4")
|
||||
echo -n $vmid
|
||||
}
|
||||
|
||||
# Функция для проверки 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
|
||||
}
|
||||
|
||||
keypair_generate () {
|
||||
ssh-keygen -t rsa -N "" -f $privkey
|
||||
pubkey="$privkey".pub
|
||||
echo "Keypair generated."
|
||||
}
|
||||
|
||||
mksnippet () {
|
||||
snippet="${path}${vmid}_user.yaml"
|
||||
cp ./user.yaml "$snippet"
|
||||
sed -i "s/HOSTNAME/$hostname/g" "$snippet"
|
||||
if [ $username ]; then
|
||||
sed -i "s|user: root|user: ${username}\nsudo: ALL=(ALL) NOPASSWD:ALL|" "$snippet"
|
||||
fi
|
||||
if [ $password ]; then
|
||||
phash=$(cat $password | mkpasswd -m sha-256 -s)
|
||||
sed -i "s|.*password.*| - ${phash}|" "$snippet"
|
||||
fi
|
||||
if [ $pubkey ]; then
|
||||
sed -i "s|.*ssh-rsa.*| - (cat ${pubkey})|" "$snippet"
|
||||
fi
|
||||
echo "Snippet $snippet created"
|
||||
}
|
||||
|
||||
# Обрабатываем опции
|
||||
while getopts "a:f:hk:u:p:d:n:t:" 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};;
|
||||
d) size=${OPTARG};;
|
||||
n) node=${OPTARG};;
|
||||
t) tag=${OPTARG};;
|
||||
\?) echo "Invalid option."; show_help; exit 1;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [[ $node -lt 1 || $node -gt 4 ]]; then
|
||||
echo "Node number is not in [1..4]. Please specify correct node number. Aborting"
|
||||
fi
|
||||
|
||||
# DEBUG Print specified options
|
||||
if [ $harule ]; then echo "harule: $harule"; fi
|
||||
if [ $file ]; then echo "file: $file"; fi
|
||||
if [ $pubkey ]; then echo "pubkey: $pubkey"; fi
|
||||
if [ $username ]; then echo "username: $username"; fi
|
||||
if [ $password ]; then echo "password: $password"; fi
|
||||
if [ $size ]; then echo "size: $size"; fi
|
||||
if [ $tag ]; then echo "tag: $tag"; fi
|
||||
exit 102
|
||||
# END DEBUG
|
||||
|
||||
# Удаляем обработанные опции, оставляя только аргументы скрипта
|
||||
shift "$((OPTIND - 1))"
|
||||
echo "DEBUG arguments amount: $#"
|
||||
|
||||
### Проверка допустимости опций
|
||||
if ! [[ $size -ge 10 && $size -le 500 ]]; then echo "Disk size increment shoud be in range of 10..500. Aborting."; exit 2; fi
|
||||
|
||||
# Создаём hosts.tmp из аргументов/файла, попутно проверяя данные
|
||||
# Если заданы И аргументы, И файл - сразу нахуй
|
||||
if [[ $# -ne 0 && $use_file ]]; then
|
||||
echo "Please use EITHER file OR arguments. Use '-h' flag for help"
|
||||
exit 3
|
||||
else
|
||||
# Если файл задан
|
||||
if [ $file ]; then
|
||||
# Но не существует, то нахуй
|
||||
if [ ! -f "$file" ];then
|
||||
echo "File $file does not exist. Aborting."
|
||||
exit 4
|
||||
fi
|
||||
fi
|
||||
# Если заданы аргументы
|
||||
if [ $# -ne 0 ]; then
|
||||
echo "DEBUG using arguments"
|
||||
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
|
||||
get_vmid "$arg" >> 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
|
||||
# А если нет, то файл.
|
||||
else
|
||||
echo "DEBUG using file: $file"
|
||||
touch hosts.tmp
|
||||
echo -n "" > hosts.tmp
|
||||
echo "DEBUG cat file"
|
||||
cat "$file"
|
||||
for line in $(cat "$file"); do
|
||||
echo "DEBUG line:$line"
|
||||
ip=$(echo -n $line | cut -d ';' -f 1)
|
||||
hostname=$(echo -n $line | cut -d ';' -f 2)
|
||||
ipcheck "$ip"
|
||||
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 5
|
||||
fi
|
||||
else
|
||||
echo "$ip is not a valid IPv4 address (10.10.XXX.YYY). Aborting."
|
||||
rm hosts.tmp
|
||||
exit 5
|
||||
fi
|
||||
done
|
||||
fi
|
||||
fi
|
||||
# Закончили с вводными данными
|
||||
|
||||
# Проверяем ключ
|
||||
if [ $pubkey ]; then
|
||||
if [[ ! -f "$pubkey" ]]; then
|
||||
input=y
|
||||
echo "You specified public key but it 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 use default, specify or generate new pair."; exit 6;;
|
||||
N) echo "Public key is necessary to continue. Please use default, specify or generate new pair."; exit 6;;
|
||||
*) echo "Use '-h' flag for help"; exit 6;;
|
||||
esac
|
||||
fi
|
||||
else
|
||||
read -p "Public key not specified. Use default? Enter to continue or Ctrl+C to abort"
|
||||
fi
|
||||
|
||||
# Проверяем, что нет ВМ в списке и нет сниппетов
|
||||
for line in $(cat hosts.tmp)
|
||||
do
|
||||
ip=$(echo -n "$line" | cut -d ',' -f 1)
|
||||
vmid=$(get_vmid "$ip")
|
||||
snippet=
|
||||
if qm status "$vmid"; then
|
||||
echo "VM $vmid exists. Aborting"
|
||||
exit 7
|
||||
elif [[ -f "$snippet" ]]; then
|
||||
echo "Snippet $snippet exists. Aborting"
|
||||
exit 7
|
||||
fi
|
||||
done
|
||||
|
||||
|
||||
### DEBUG 1
|
||||
echo "DEBUG cat hosts.tmp:"
|
||||
cat hosts.tmp; echo
|
||||
###
|
||||
|
||||
# Подготовительные операции закончены, приступаем к выполнению.
|
||||
read -p "Script is ready to create $(cat hosts.tmp | wc -l) VMs. Press Enter"
|
||||
|
||||
for line in $(cat hosts.tmp)
|
||||
do
|
||||
ip=$(echo -n $line | cut -d ';' -f 1)
|
||||
vlan=$(echo -n $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 -n $line | cut -d ';' -f 2)
|
||||
vmid=$(get_vmid "$ip")
|
||||
mksnippet
|
||||
#### DEBUG 2
|
||||
echo "IP: $ip"
|
||||
echo "hostname: $hostname"
|
||||
echo "VMID: $vmid"
|
||||
echo "VLAN: $vlan"
|
||||
echo "TAG: $tag"
|
||||
echo "$snippet:"
|
||||
cat "$snippet"
|
||||
exit 100
|
||||
####
|
||||
echo -n "Now cloning VM $vmnum from a template....."
|
||||
qm clone 5000 $vmid --name $hostname --full &>/dev/null
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "OK"
|
||||
else
|
||||
echo "ERROR"
|
||||
exit 8
|
||||
fi
|
||||
qm set $vmid --tags "${node}${tag}"
|
||||
qm resize $vmid scsi0 +"$size"G
|
||||
qm set $vmid --cicustom "user=${storage}:snippets/${vmnum}_user.yaml"
|
||||
qm set $vmid --ipconfig0 ip="$ip"/"$mask",gw="$gw"
|
||||
sed -i "s|tag=35|tag=$vlan|" /etc/pve/qemu-server/${vmid}.conf
|
||||
qm cloudinit update $vmid
|
||||
### DEBUG
|
||||
echo "DEBUG: ${vmid}.conf"
|
||||
cat /etc/pve/qemu-server/${vmid}.conf
|
||||
exit 102
|
||||
###
|
||||
# # Migrate VM to target node
|
||||
# echo -n "Migrating VM $vmid to pve${node}....."
|
||||
# qm migrate $vmid pve${node} &&
|
||||
# if [ $? -eq 0 ]; then
|
||||
# echo "OK"
|
||||
# else
|
||||
# echo "ERROR"
|
||||
# exit 9
|
||||
# fi
|
||||
# qm start $vmid ВРЕМЕННО ОТКЛЮЧЕНО
|
||||
if [ $harule ]; then
|
||||
ha-manager add vm:$vmid --state started --max_relocate 2
|
||||
ha-manager rules add node-affinity $harule --resources vm:$vmid --nodes pve1,pve2,pve3 --strict 1
|
||||
echo "HA rule added"
|
||||
# ОБЯЗАТЕЛЬНО ПРОВЕРИТЬ КОМАНДУ!!!
|
||||
fi
|
||||
done
|
||||
|
||||
# Финальная часть
|
||||
rm hosts.tmp
|
||||
if [ $privkey ]; then
|
||||
echo
|
||||
echo "Generated private key: ./$privkey"
|
||||
echo "SAVE IT IMMEDIATELY!!!"
|
||||
fi
|
||||
Reference in New Issue
Block a user