From ae222b4231f521711884e36ea8e0d6a61df78d14 Mon Sep 17 00:00:00 2001 From: nemo Date: Sun, 5 May 2019 19:23:45 +0200 Subject: [PATCH] Initial commit, based on old erispoe VM deploy script --- LICENSE | 5 + README.md | 18 ++ creds | 3 + deploy_vm.conf | 22 ++ deploy_vm.sh | 544 +++++++++++++++++++++++++++++++++++++++++++++++ vm-template.conf | 21 ++ 6 files changed, 613 insertions(+) create mode 100644 LICENSE create mode 100644 README.md create mode 100644 creds create mode 100644 deploy_vm.conf create mode 100755 deploy_vm.sh create mode 100644 vm-template.conf diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..00d9714 --- /dev/null +++ b/LICENSE @@ -0,0 +1,5 @@ +MIT License +Copyright (c) +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..9347375 --- /dev/null +++ b/README.md @@ -0,0 +1,18 @@ +# deploy_vm + +Script to deploy a VM based on debian template (in our case). +The script add IPAM entry for an IPv4 address and an IPv6 range, and deploy/configure a VM based on the VM conf file (see vm-template.conf). + +# How to use + * Define your IPAM credentials and adjust parameters in deploy_vm.conf file + * Copy the VM conf file template : cp vm-template.conf vm-user123.conf + * Adjust all parameters in new file vm-user123.conf + * WARNING : if the SSH public key isn't correct, nobody would be able to log on the VM after deploy. + * Run the script : ./deploy_vm.sh + +# If problems + * If the script fail and add already do updates in IPAM or on the VM, you can manually finish the deploy OR delete IPAM entries (1 IPv4 and 1 IPv6 range), delete the VM, rectify to avoir the problem and retry deploy. + +# To do + * Verify if VM conf file parameters are numbers before test the interval (actually in the same line) + * Verify deploy_vm.conf parameters. diff --git a/creds b/creds new file mode 100644 index 0000000..4b28d7b --- /dev/null +++ b/creds @@ -0,0 +1,3 @@ +# User and password to request a token on phpIPAM API +USER_IPAM='user' +PASSWORD_IPAM='password' diff --git a/deploy_vm.conf b/deploy_vm.conf new file mode 100644 index 0000000..7c15393 --- /dev/null +++ b/deploy_vm.conf @@ -0,0 +1,22 @@ +# URL of the API +URL="https://ipam.example.conf/api/${USER_IPAM}" + +VM_BRIDGE_DEV="vmbr99" +IPV6_GATEWAY="fe80::123:123:123:123" + +# ID of the ranges, you can put multiple ranges per AFI +ID_RANGES_V4='123 234' +ID_RANGES_V6='345' + +# Only one value in next params +ID_RANGE_V4_TO_CREATE_VM='123' +ID_RANGE_V6_TO_CREATE_VM='345' + +VM_DISK_MIN=32 +VM_DISK_MAX=64 + +VM_CPU_MIN=1 +VM_CPU_MAX=4 + +VM_RAM_MIN=512 +VM_RAM_MAX=2048 diff --git a/deploy_vm.sh b/deploy_vm.sh new file mode 100755 index 0000000..00ccba0 --- /dev/null +++ b/deploy_vm.sh @@ -0,0 +1,544 @@ +#!/bin/bash + +# Script to deploy a VM based on debian template +# You need to provide a VM conf file with all params defined (see vm-template.conf) + +echo -e "\n---------- SCRIPT ${0} ----------\n" +echo "INFO : the script ${0} started..." + +# Get ID for new VM +VM_ID=$(pvesh get /cluster/nextid) +echo "INFO : the VM_ID for the new VM will be ${VM_ID}" + +usage() { + printf "Usage of ${0} : ${0} \n" + printf "\tvm-conf-file has to contain variables VM_HOSTNAME, USER_MAIL, USER_SSH_PUB_KEY, VM_DISK, VM_CPU, VM_RAM and VM_TEMPLATE_ID\n" + printf "\t-h, --help\tPrint this help\n" +} + +echo -e "\n---------- CHECK REQUIREMENTS ----------\n" + +# Check if file is provided or help asked +echo "INFO : Check if VM conf file provided..." +if [ $1 ]; then + if [ $1 = '-h' ] || [ $1 = '--help' ]; then + usage + exit 0 + elif [ $# -lt 1 ]; then + echo 'ERROR : VM conf file not specified' + usage + exit 1 + else + # Verification of the presence of VM conf file + if [ -f "$1" ]; then + VM_CONF_FILE=$1 + . ${VM_CONF_FILE} + + if [ $? -ne 0 ] + then + echo 'ERROR : problem during read VM conf file, please check the VM conf file' + exit 1 + fi + else + echo 'ERROR : VM conf file not found, check path' + exit 1 + fi + fi +else + echo 'ERROR : No parameter specified' + usage + exit 1 +fi + +# INFO : Check if creds file is found +echo "INFO : Check if creds file is found (IPAM credentials)..." +CREDS_FILE='./creds' +if [ -f $CREDS_FILE ]; then + . $CREDS_FILE + CURL='curl -s -k -sS' +else + echo 'ERROR : The file creds doesn’t exist' + exit 1 +fi + +# Check if general script params file is found +echo "INFO : Check if general script params file is found..." +CONF_FILE='./deploy_vm.conf' +if [ -f $CONF_FILE ]; then + . $CONF_FILE +else + echo "ERROR : The file ${CONF_FILE} doesn’t exist" + exit 1 +fi + +# Check if all required params are provided and not empty +echo "INFO : Check if all required params are provided and not empty in VM conf file..." +if [ -z "${VM_HOSTNAME}" ] || [ -z "${USER_MAIL}" ] || [ -z "${USER_SSH_PUB_KEY}" ] || [ -z "${VM_DISK}" ] || [ -z "${VM_CPU}" ] || [ -z "${VM_RAM}" ] || [ -z "${VM_TEMPLATE_ID}" ] +then + echo 'ERROR : all required params not defined in VM conf file, required params : VM_HOSTNAME, USER_MAIL, USER_SSH_PUB_KEY, VM_DISK, VM_CPU, VM_RAM and VM_TEMPLATE_ID.' + exit 1 +fi + +# Delete space from hostname and truncate to 32 chars +VM_HOSTNAME_TRUNCATE=$(echo ${VM_HOSTNAME} | cut -c 1-32) + +echo "INFO : Check VM_HOSTNAME param format (after truncate if necessary)..." +# Check VM_HOSTNAME_TRUNCATE +echo ${VM_HOSTNAME_TRUNCATE} | grep "^[-a-zA-Z0-9]*$" > /dev/null +if [ $? -ne 0 ]; then + echo 'ERROR : the VM hostname can only contain "a-z", "A-Z", "0-9" or "-" chars (no space or other special chars)' + exit 1 +fi + +echo "INFO : Check USER_MAIL param format..." +# Check USER_MAIL +if [[ ! "${USER_MAIL}" =~ ^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$ ]]; then + echo 'ERROR : Email address is invalid' + exit 1 +fi + +# Regex to check if value is a number +RE='^[0-9]+$' + +# Var to contain size to extend disk +VM_DISK_EXTEND=0 + +echo "INFO : Check VM_DISK param format and size limits..." +# Check VM_DISK +if [ ${VM_DISK} -lt ${VM_DISK_MIN} ] || [ ${VM_DISK} -gt ${VM_DISK_MAX} ] || [[ ! ${VM_DISK} =~ ${RE} ]]; then + echo "ERROR : the disk size has to be between ${VM_DISK_MIN} and ${VM_DISK_MAX}" + exit 1 +fi + +echo "INFO : Get the size to extend disk if necessary..." +# Set the size to extend disk if necessary +if [ ${VM_DISK} -gt ${VM_DISK_MIN} ]; then + VM_DISK_EXTEND=$(( ${VM_DISK}-${VM_DISK_MIN} )) +fi + +echo "INFO : Check VM_CPU param format and number limits..." +# Check VM_CPU +if [ ${VM_CPU} -lt ${VM_CPU_MIN} ] || [ ${VM_CPU} -gt ${VM_CPU_MAX} ] || [[ ! ${VM_CPU} =~ ${RE} ]]; then + echo "ERROR : the vCPU core number has to be between ${VM_CPU_MIN} and ${VM_CPU_MAX}" + exit 1 +fi + +echo "INFO : Check VM_RAM param format and size limits..." +# Check VM_RAM +if [ ${VM_RAM} -lt ${VM_RAM_MIN} ] || [ ${VM_RAM} -gt ${VM_RAM_MAX} ] || [[ ! ${VM_RAM} =~ ${RE} ]]; then + echo "ERROR : the RAM size has to be between ${VM_RAM_MIN} and ${VM_RAM_MAX}" + exit 1 +fi + +echo "INFO : Check VM_TEMPLATE_ID param format..." +# Check VM_TEMPLATE_ID +if [[ ! ${VM_TEMPLATE_ID} =~ ${RE} ]]; then + echo "ERROR : VM template ID provided is not a number" + exit 1 +fi + +echo "INFO : Check if VM_TEMPLATE_ID param match with a VM template on this HV..." +# Check if VM_TEMPLATE_ID is a VM template on this HV +qm config ${VM_TEMPLATE_ID} | grep "^template: 1$" > /dev/null +if [ $? -ne 0 ]; then + echo "ERROR : VM template ID does not match with a template VM on this HV" + exit 1 +fi + +# Connection to IPAM API +echo 'INFO : Connecting to the IPAM API...' +RES_AUTHENT=$(${CURL} -X POST --user ${USER_IPAM}:${PASSWORD_IPAM} ${URL}/user/) +CODE_RETOUR_RES_AUTHENT=$(echo ${RES_AUTHENT} | jq '.code') +if [ ${CODE_RETOUR_RES_AUTHENT} != 200 ]; then + echo "ERROR : Wrong HTTP code from the API : ${CODE_RETOUR_RES_AUTHENT} ${RES_AUTHENT}" + echo "ERROR : Unable to join/connect IPAM (to register VM IPs)" + exit 1 +fi + +# Get IPAM API Token +echo 'INFO : Getting IPAM API token...' +TOKEN=$(echo ${RES_AUTHENT} | jq -r '.data.token') +if [ ! -n "${TOKEN}" ]; then + echo 'ERROR : Empty IPAM API token' + exit 1 +fi + +# Check if VM_ID is already used by an IPAM IPv4 +echo "INFO : Check if VM_ID is already used by an IPAM IPv4..." +for ID_RANGE_V4 in ${ID_RANGES_V4}; do + # Get IPV4 informations and check HTTP code + INFOS_V4=$(${CURL} --header "Content-type: application/x-www-form-urlencoded" --header "token: $TOKEN" -X GET "${URL}/subnets/${ID_RANGE_V4}/addresses") + CODE_RETOUR_INFOS_V4=$(echo ${INFOS_V4} | jq '.code') + + if [ ${CODE_RETOUR_INFOS_V4} != 200 ]; then + echo "ERROR : Wrong code returned for IPv4 range ${ID_RANGE_V4}: ${CODE_RETOUR_INFOS_V4}" + exit 1 + fi + + VM_IPV4=$(echo ${INFOS_V4} | jq -r ".data[] | select(.custom_vm_id==\"${VM_ID}\") | .ip") + + if [ ! -z "${VM_IPV4}" ] + then + + echo "ERROR : the next VM ID is already used by an IPv4 in IPAM (${VM_IPV4}), please check an delete all IPAM's entries associated to the new vm_id ${VM_ID} before run this script." + exit 1 + fi + +done + +# Check if VM_ID is already used by an IPAM IPv6 range +echo "INFO : Check if VM_ID is already used by an IPAM IPv6 range..." +for ID_RANGE_V6 in ${ID_RANGES_V6}; do + # Get IPV6 ranges informations and check HTTP code + INFOS_RANGES_V6=$(${CURL} --header "Content-type: application/x-www-form-urlencoded" --header "token: $TOKEN" -X GET ${URL}/subnets/${ID_RANGE_V6}/slaves/) + CODE_RETOUR_INFOS_RANGES_V6=$(echo ${INFOS_RANGES_V6} | jq '.code') + + if [ ${CODE_RETOUR_INFOS_RANGES_V6} != 200 ]; then + echo "ERROR : Wrong code returned for IPv4 range ${ID_RANGE_V6}: ${CODE_RETOUR_INFOS_RANGES_V6}" + exit 1 + fi + + VM_IPV6=$( echo ${INFOS_RANGES_V6} | jq -r ".data[] | select(.custom_vm_id==\"${VM_ID}\") | .subnet") + + if [ ! -z "${VM_IPV6}" ] + then + + echo "ERROR : the next VM ID is already used by an IPv6 range in IPAM (${VM_IPV6}/48), please check an delete all IPAM's entries associated to the new vm_id ${VM_ID} before run this script." + exit 1 + fi + +done + +echo -e "\n---------- CHECK REQUIREMENTS OK ----------" + +echo -e "\n---------- CREATE IPAM ENTRIES ----------\n" + +# Add IPv4 in IPAM for the new VM +echo "INFO : Add IPv4 in IPAM... (UPDATE IPAM)" +ADD_V4=$(${CURL} --data "description"="VM ${VM_HOSTNAME_TRUNCATE}" --data "custom_vm_id"="${VM_ID}" --header "Content-type: application/x-www-form-urlencoded" --header "token: $TOKEN" -X POST "${URL}/addresses/first_free/${ID_RANGE_V4_TO_CREATE_VM}") +CODE_RETOUR_ADD_V4=$(echo ${ADD_V4} | jq '.code') + +if [ ${CODE_RETOUR_ADD_V4} != 201 ]; then + echo "ERROR : Wrong code returned for IPv4 ADD on range ${ID_RANGE_V4_TO_CREATE_VM} : ${CODE_RETOUR_ADD_V4} ${ADD_V4}" + exit 1 +fi + +VM_IPV4_NEW=$(echo ${ADD_V4} | jq -r '.data') + +echo "INFO : VM IPv4 is ${VM_IPV4_NEW}" + +# Get the subnet ID of the VM +echo "INFO : Get the subnet mask and gateway for the VM..." +IPAM_NEW_IPV4_DETAILS=$(${CURL} --header "Content-type: application/x-www-form-urlencoded" --header "token: $TOKEN" -X GET "${URL}/addresses/search/${VM_IPV4_NEW}/") +CODE_RETOUR_IPAM_NEW_IPV4_DETAILS=$(echo ${IPAM_NEW_IPV4_DETAILS} | jq '.code') + +if [ ${CODE_RETOUR_IPAM_NEW_IPV4_DETAILS} != 200 ]; then + echo "ERROR : Wrong code returned while getting subnet for ${VM_IPV4_NEW} : ${CODE_RETOUR_IPAM_NEW_IPV4_DETAILS}" + exit 1 +fi + +VM_IPV4_NEW_SUBNET_ID=$(echo ${IPAM_NEW_IPV4_DETAILS} | jq -r ".data[] | .subnetId") + +echo "INFO : IPAM Subnet ID of the VM is ${VM_IPV4_NEW_SUBNET_ID}" + +# Get the gateway and the mask of the VM +echo "INFO : Get the gateway and the mask of the VM..." +IPAM_NEW_IPV4_SUBNET=$(${CURL} --header "Content-type: application/x-www-form-urlencoded" --header "token: $TOKEN" -X GET "${URL}/subnets/${VM_IPV4_NEW_SUBNET_ID}/") +CODE_RETOUR_IPAM_NEW_IPV4_SUBNET=$(echo ${IPAM_NEW_IPV4_SUBNET} | jq '.code') + +if [ ${CODE_RETOUR_IPAM_NEW_IPV4_SUBNET} != 200 ]; then + echo "ERROR : Wrong code returned for IPv4 subnet ${VM_IPV4_NEW_SUBNET_ID} : ${CODE_RETOUR_IPAM_NEW_IPV4_SUBNET}" + exit 1 +fi + +VM_IPV4_NEW_SUBNET_GW=$(echo ${IPAM_NEW_IPV4_SUBNET} | jq -r ".data.gateway.ip_addr") +VM_IPV4_NEW_SUBNET_MASK=$(echo ${IPAM_NEW_IPV4_SUBNET} | jq -r ".data.mask") + +echo "INFO : IPv4 Gateway for the VM is ${VM_IPV4_NEW_SUBNET_GW}" +echo "INFO : IPv4 Mask of the VM is ${VM_IPV4_NEW_SUBNET_MASK}" + +# Add IPv6 range in IPAM for the new VM +echo "INFO : Add IPv6 range in IPAM... (UPDATE IPAM)" +ADD_RANGES_V6=$(${CURL} --data "custom_vm_id"="${VM_ID}" --data "isFull"="1" --data "description"="VM ${VM_HOSTNAME_TRUNCATE}" --header "Content-type: application/x-www-form-urlencoded" --header "token: $TOKEN" -X POST ${URL}/subnets/${ID_RANGE_V6_TO_CREATE_VM}/first_subnet/48/) +CODE_RETOUR_ADD_RANGES_V6=$(echo ${ADD_RANGES_V6} | jq '.code') + +if [ ${CODE_RETOUR_ADD_RANGES_V6} != 201 ]; then + echo "ERROR : Wrong code returned for IPv6 range ${ID_RANGE_V6_TO_CREATE_VM}: ${CODE_RETOUR_ADD_RANGES_V6} ${ADD_RANGES_V6}" + echo "ERROR : Before retry, don't forget to DELETE previously registered IPv4 in IPAM : {VM_IPV4_NEW}." + exit 1 +fi + +RANGE_IPV6_NEW=$(echo ${ADD_RANGES_V6} | jq -r '.data') + +RANGE_IPV6_NEW_WITHOUT_MASK=$(echo ${RANGE_IPV6_NEW} | cut -d'/' -f1) +RANGE_IPV6_NEW_MASK=$(echo ${RANGE_IPV6_NEW} | cut -d'/' -f2) + +echo "INFO : IPv6 range for the VM : ${RANGE_IPV6_NEW_WITHOUT_MASK}/${RANGE_IPV6_NEW_MASK}" + +echo -e "\n---------- CREATE IPAM ENTRIES OK ----------" + +echo -e "\n---------- CREATE VM ----------\n" + +# Clone template to new VM +echo "INFO : create new VM by cloning template (more than 1min to wait)... (CREATE NEW VM ${VM_ID} ${VM_HOSTNAME_TRUNCATE})" +qm clone ${VM_TEMPLATE_ID} ${VM_ID} -full -name ${VM_HOSTNAME_TRUNCATE} -storage local_data &> /dev/null +if [ $? -ne 0 ]; then + echo 'ERROR : problem during cloning, please finish manually the deploy OR delete VM and IPAM information' + exit 1 +fi + +# Wait some seconds to be sure the cloning is finished (else problems occurs) +sleep 60 + +# Change CPU number if necessary +if [ "${VM_CPU}" -ne 1 ]; then + echo "INFO : Change vCPU core number to ${VM_CPU} core(s)..." + qm set ${VM_ID} --cores ${VM_CPU} &> /dev/null + + if [ $? -ne 0 ]; then + echo 'ERROR : problem during changing vCPU core number, please finish manually the deploy OR delete VM and IPAM information' + exit 1 + fi +else + echo "INFO : No need to change vCPU core number, value is ${VM_CPU} core(s)" +fi + +# Change RAM size if necessary +if [ "${VM_RAM}" -ne 512 ]; then + echo "INFO : Extend RAM (resize to ${VM_RAM}MB)..." + qm set ${VM_ID} --memory ${VM_RAM} &> /dev/null + + if [ $? -ne 0 ]; then + echo 'ERROR : problem during resizing RAM, please finish manually the deploy OR delete VM and IPAM information' + exit 1 + fi +else + echo "INFO : No need to resize RAM, value is ${VM_RAM}MB" +fi + +# Change Disk size if necessary +if [ "${VM_DISK_EXTEND}" -ne 0 ]; then + echo "INFO : Extend disk (resize to ${VM_DISK}GB)..." + qm resize ${VM_ID} virtio0 +${VM_DISK_EXTEND}G #&> /dev/null + + if [ $? -ne 0 ]; then + echo 'ERROR : problem during resizing disk, please finish manually the deploy OR delete VM and IPAM information' + exit 1 + fi +else + echo "INFO : No need to resize disk, value is ${VM_DISK}GB" +fi + +# Start VM +echo "INFO : start the new VM..." +qm start ${VM_ID} +if [ $? -ne 0 ]; then + echo 'ERROR : problem during starting the VM, please finish manually the deploy OR delete VM and IPAM information' + exit 1 +fi + +# Wait the VM starting +sleep 20 + +# Define SSH params +SSH_OPT="-6 -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no" + +# Get the FE80 IPv6 of the new VM +echo "INFO : Get the FE80 IPv6 of the new VM..." +VM_MAC=$(grep net0 /etc/pve/qemu-server/${VM_ID}.conf | cut -d '=' -f 2 | cut -d ',' -f 1) +VM_FE80=$(ipv6calc --action prefixmac2ipv6 --in prefix+mac --out ipv6addr fe80:: $VM_MAC) + +# Define SSH host +SSH_HOST="root@${VM_FE80}%${VM_BRIDGE_DEV}" + +# Create network configuration file for new VM +echo "INFO : Create network configuration file for new VM..." +echo "# This file describes the network interfaces available on your system +# and how to activate them. For more information, see interfaces(5). + +source /etc/network/interfaces.d/* + +# The loopback network interface +auto lo +iface lo inet loopback + +# The primary network interface +auto ens18 +allow-hotplug ens18 +iface ens18 inet static + address ${VM_IPV4_NEW}/${VM_IPV4_NEW_SUBNET_MASK} + gateway ${VM_IPV4_NEW_SUBNET_GW} + +iface ens18 inet6 static + address ${RANGE_IPV6_NEW_WITHOUT_MASK}1/${RANGE_IPV6_NEW_MASK} + gateway ${IPV6_GATEWAY}" > /tmp/interfaces_vm${VM_ID} + +# Replace network configuration file on new VM +echo "INFO : Replace network configuration file on new VM... (VM NETWORK CONF UPDATE)" +scp ${SSH_OPT} /tmp/interfaces_vm${VM_ID} root@[${VM_FE80}%${VM_BRIDGE_DEV}]:/etc/network/interfaces &> /dev/null +if [ $? -ne 0 ]; then + echo 'ERROR : problem during copy of the new network conf file, please finish manually the deploy OR delete VM and IPAM information' + + # Clean temp file + echo "INFO : Clean temp file" + rm /tmp/interfaces_vm${VM_ID} + + exit 1 +fi + +# Clean temp file +echo "INFO : Clean temp file" +rm /tmp/interfaces_vm${VM_ID} + +# Restart networking service on VM to apply new network configuration +echo "INFO : Restart networking service on VM to apply new network configuration... (systemctl restart networking)" +ssh ${SSH_OPT} ${SSH_HOST} "systemctl restart networking" &> /dev/null +if [ $? -ne 0 ]; then + echo 'ERROR : problem during restart networking service on VM, please finish manually the deploy OR delete VM and IPAM information' + exit 1 +fi + +# Regenerate SSH host keys for the VM and restart SSHD +echo "INFO : Regenerate SSH host keys for the VM and restart SSHD..." +ssh ${SSH_OPT} ${SSH_HOST} "/bin/rm -v /etc/ssh/ssh_host_* && dpkg-reconfigure openssh-server && systemctl restart ssh" &> /dev/null +if [ $? -ne 0 ]; then + echo 'ERROR : problem during regenerate SSH host keys for the VM, please finish manually the deploy OR delete VM and IPAM information' + exit 1 +fi + +# Get FingerPrint +echo "INFO : Get SSH FingerPrint of the new VM..." +file=$(mktemp) +sleep 1 +ssh-keyscan ${VM_FE80}%${VM_BRIDGE_DEV} >${file} 2>/dev/null +sleep 1 +SSH_FP="$(ssh-keygen -l -f ${file})" +sleep 1 +rm ${file} + +# Resize disk and LV if disk has been extended +if [ "${VM_DISK_EXTEND}" -ne 0 ]; then + + echo "INFO : Create new primary partition to extend VG... (Create new partition)" + + ssh ${SSH_OPT} ${SSH_HOST} "echo -e \"n\np\n\n\n\nt\n\n8e\nw\n\" | fdisk /dev/vda" &> /dev/null + + # Don't check errors because return code in error (system has to reboot) + + echo "INFO : Reboot the system to reload partition table etc... (reboot)" + + ssh ${SSH_OPT} ${SSH_HOST} "reboot" &> /dev/null + + # Wait for system reboot + sleep 20 + + echo "INFO : Create new PV... (pvcreate /dev/vda3)" + + ssh ${SSH_OPT} ${SSH_HOST} "pvcreate /dev/vda3" &> /dev/null + + if [ $? -ne 0 ]; then + echo 'ERROR : problem during create PV, please finish manually the deploy OR delete VM and IPAM information' + exit 1 + fi + + echo "INFO : Add new PV to VG default_vg... (vgextend default_vg /dev/vda3)" + + ssh ${SSH_OPT} ${SSH_HOST} "vgextend default_vg /dev/vda3" &> /dev/null + + if [ $? -ne 0 ]; then + echo 'ERROR : problem during add new PV in VG, please finish manually the deploy OR delete VM and IPAM information' + exit 1 + fi + + echo "INFO : Resize LV on disk... (RESIZE VM LV)" + + ssh ${SSH_OPT} ${SSH_HOST} "lvextend -l +100%FREE /dev/mapper/default_vg-root_1" &> /dev/null + + if [ $? -ne 0 ]; then + echo 'ERROR : problem during resizing LV, please finish manually the deploy OR delete VM and IPAM information' + exit 1 + fi + + echo "INFO : resize2fs the LV... (RESIZE VM LV FS)" + + ssh ${SSH_OPT} ${SSH_HOST} "resize2fs /dev/mapper/default_vg-root_1" &> /dev/null + + if [ $? -ne 0 ]; then + echo 'ERROR : problem during resize2fs, please finish manually the deploy OR delete VM and IPAM information' + exit 1 + fi +else + echo "INFO : No need to resize LV on disk" +fi + +# Update VM system +echo "INFO : Update VM OS, this can take some minutes... (apt update -q && apt upgrade -y -q)" +ssh ${SSH_OPT} ${SSH_HOST} "apt update -q && apt upgrade -y -q" &> /dev/null +if [ $? -ne 0 ]; then + echo 'ERROR : problem during updating the VM, please finish manually the deploy OR delete VM and IPAM information' + exit 1 +fi + +# Delete root .bash_history +echo "INFO : Delete root user .bash_history... (rm /root/.bash_history)" +ssh ${SSH_OPT} ${SSH_HOST} "rm /root/.bash_history" &> /dev/null +if [ $? -ne 0 ]; then + echo 'ERROR : problem during deleting root .bash_history, please finish manually the deploy OR delete VM and IPAM information' + exit 1 +fi + +# Add user SSH Pub key to root (and erase HV pub key) and reboot +echo "INFO : Add user SSH Pub key to root (and erase HV pub key) and reboot in 1 minute... (WARN : if you provided incorrect SSH pub key, nobody could log in the VM...)" +ssh ${SSH_OPT} ${SSH_HOST} "shutdown --reboot +1 'System is going down for reboot in 1 minute'; echo ${USER_SSH_PUB_KEY} > /root/.ssh/authorized_keys" &> /dev/null +if [ $? -ne 0 ]; then + echo 'ERROR : problem during replace HV SSH pub keys by user SSH pub key or during reboot programming, please finish manually the deploy OR delete VM and IPAM information' + exit 1 +fi + +echo -e "\n---------- CREATE VM OK ----------\n" + +echo "INFO : Send the final mail..." + +SUBJECT=$(perl -wse "use utf8; use Encode qw(encode); print encode(\"MIME-Q\",\ + \"Votre machine virtuelle GRIFON vient d’être créée\");") + +echo "From: Adminsys GRIFON +To: ${USER_MAIL} +Cc: adminsys@grifon.fr +Content-Type: text/plain; charset=UTF-8 +Subject: ${SUBJECT} + +Bonjour, + +Votre machine virtuelle vient d’être créée. + +La clé publique SSH que vous nous avez fournie a été mise sur le compte root. +Vous pouvez vous connecter en SSH via +ssh root@${VM_IPV4_NEW} +ssh root@${RANGE_IPV6_NEW_WITHOUT_MASK}1 + +Votre range IPv6 est ${RANGE_IPV6_NEW} + +Nous vous recommandons très vivement de changer les mots de passe root et debian01 (utilisateur par défaut) ainsi que +d’interdire la connexion par SSH en tant que root. + +Voir pouvez donc vous connecter, démarrer votre machine virtuelle +et la configurer comme vous le souhaitez. + +Le fingerprint SSH de votre VM est : +${SSH_FP} + +Si vous souhaitez avoir un reverse DNS, vous pouvez contacter +adminsys@grifon.fr en précisant si vous souhaitez une délagation ou en donnant +le FQDN. + +Cordialement, +-- +Les adminsys de GRIFON" #| /usr/sbin/sendmail -f adminsys@grifon.fr -t + +echo "INFO : script finished, mail sent to the user and adminsys@grifon.fr" + +echo -e "\n---------- END OF SCRIPT ${0} ---------\n" + +exit 0 + diff --git a/vm-template.conf b/vm-template.conf new file mode 100644 index 0000000..71af053 --- /dev/null +++ b/vm-template.conf @@ -0,0 +1,21 @@ +# Name of the VM (ex : jdoe) NO SPACE HERE OR ORTHER SPECIAL CHAR +VM_HOSTNAME="vm-of-user123" + +# Mail to send VM infos to the user (ex : john.doe@example.net) +USER_MAIL="user@example.net" + +# SSH public key of the user (ex : ssh-rsa Ihu87QZDIuh[...] user@host) +# WARNING, if this value is incorrect, nobody could connect the deployed VM... +USER_SSH_PUB_KEY="ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCZWqqdey/B95uiSAXJUFo56UHCsk5b3AxRw+SfnuOGyP15tGwOT4AhCyx2XXcxAlnuTNYhONfHg82wVN581suF3w2wnWkJdYqlwmCB20CQENuFXIIcw1ZYTyVcLfdSNhMAO1VuvkvyTEDac2Mh9epMe3lcgYpM/+YZiRfuInDYzixOJOuSz+NFMCm9XHhQDZ3CxZSMjKCV3+yW6vcQ/QfWs749C1JwdTiEMSrwpMm+IwtVnO5Tv4EA/jUs6a+CVo4GtfwIVWH5CGtrc4SYfbfFwoITS3UKDUGgx1YKU81bXrzldlofPxpbBoXozwHi6n6orTu81pKRiok3oN/Vhuhb john@host" + +# Disk size in GB (ex : 32) +VM_DISK=32 + +# vCPU number (ex : 1) +VM_CPU=1 + +# RAM size in MB (ex : 512) +VM_RAM=512 + +# VM Proxmox ID of template (ex : 123) +VM_TEMPLATE_ID=123