proxmox_routing/creationRoutesVM.sh

288 lines
8.2 KiB
Bash
Executable File
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/sh
# Script ajout de routes VM
# A CONFIGURER/VERIFIER :
# - USER_IPAM
# - PASSWORD_IPAM
# - ID_RANGES_V4
# - ID_RANGES_V6
# - LOG_PLACE
# - CHEMIN_CACHE
write_log() {
# $1: log level (INFO, ERROR, etc.)
# $2: message
printf "$(date -Isecond) - $1: $2\n" >> \
${LOG_PLACE}/$(date -Idate)_vm_routing.log
if [ $1 = 'ERROR' ] || [ $1 = 'FATAL' ] || [ $1 = 'WARN' ]; then
printf "$1: $2\n"
fi
}
add_ipv4_route(){
VM_IPV4=$1
IFACE=$2
MAC=$3
# Ajout de la route associée
COMMAND="ip -4 route add ${VM_IPV4}/32 dev ${IFACE}"
echo "${COMMAND}"
write_log INFO "${COMMAND}"
${COMMAND}
# Updating ARP
COMMAND="ip neigh add ${VM_IPV4} lladdr ${MAC} dev ${IFACE}"
echo "${COMMAND}"
write_log INFO "${COMMAND}"
${COMMAND}
# If the previous command fails, its because trafic has
# already be sent to the VM
if [ $? = 2 ]; then
ip neigh replace ${VM_IPV4} lladdr ${MAC} dev ${IFACE}
fi
}
# IPAM creds
CREDS_FILE='/usr/local/etc/proxmox-routing/creds'
if [ -f $CREDS_FILE ]; then
. $CREDS_FILE
CURL='curl -s -k -sS'
else
write_log FATAL 'The file creds doesnt exist'
exit 1
fi
# check for commands in the path
for bin in curl ip ipv6calc jq; do
if [ -z $(which ${bin} 2>/dev/null) ]; then
MISSING="${MISSING} ${bin}"
fi
done
if [ ! -z "${MISSING}" ]; then
printf "Your missing this:${MISSING}\n"
exit 1
fi
# Chemin fichier de LOG (et création du répertoire s'il n'existe pas)
LOG_PLACE='/var/local/log/vm_id_log/'
if [ ! -d "${LOG_PLACE}" ];then
mkdir -p ${LOG_PLACE}
write_log INFO 'Creation of the log dir'
fi
write_log INFO 'Beginning of the script execution'
# Chemin fichier de CACHE (et création du répertoire s'il n'existe pas)
CHEMIN_CACHE='/var/local/cache/vm_id_cache/'
if [ ! -d "${CHEMIN_CACHE}" ];then
mkdir -p ${CHEMIN_CACHE}
write_log INFO 'Creation of the cache dir'
fi
# Fonction d'aide
usage() {
printf "Usage: ./creationRoutesVM.sh <VM_ID>\n"
printf "VM_ID est lid dune VM dans PROXMOX, un entier supérieur à"
printf "zéro\n"
printf "option : \t-h, --help Affiche ce message daide\n"
}
# On vérifie la bonne présence d'un paramètre VM_ID
if [ $1 ]; then
if [ $1 = '-h' ] || [ $1 = '--help' ]; then
usage
exit 0
elif [ $# -lt 1 ]; then
write_log FATAL 'VM ID not specified'
usage
exit 1
else
# Verification of the VM ID
expr $1 + 0 1>/dev/null 2>&1
if [ $? -lt 2 ] && [ $1 -gt 0 ]; then
VM_ID=$1
else
write_log FATAL 'The VM ID must a non-null integer'
exit 1
fi
fi
else
write_log FATAL 'No parameter specified'
usage
exit 1
fi
IFACE="tap${VM_ID}i0"
IP4_NEIGH="$(ip -4 neigh show dev ${IFACE})"
IP6_NEIGH="$(ip -6 neigh show dev ${IFACE})"
IP4_ROUTE="$(ip -4 route show dev ${IFACE})"
IP6_ROUTE="$(ip -6 route show dev ${IFACE} | grep -vF 'fe80::/64')"
if [ "${IP4_NEIGH}" ] && [ "${IP6_NEIGH}" ] && [ "${IP4_ROUTE}" ] && [ "${IP6_ROUTE}" ]; then
write_log INFO 'Nothing to do'
exit 0
fi
# Récupération d'un TOKEN pour utiliser IPAM via l'API
write_log DEBUG 'Connecting to API'
RES_AUTHENT=$(${CURL} -X POST --user ${USER_IPAM}:${PASSWORD_IPAM} ${URL}/user/)
CODE_RETOUR_RES_AUTHENT=$(echo ${RES_AUTHENT} | jq '.code')
# Si OK, on utilise l'IPAM, sinon on passe par le fichier de cache
if [ ${CODE_RETOUR_RES_AUTHENT} != 200 ]; then
write_log ERROR "Wrong HTTP code from the API: ${CODE_RETOUR_RES_AUTHENT}"
write_log INFO "Using cache instead"
else
FEED_CACHE=1
fi
# Mise du TOKEN dans une variable et retrait des éventuelles guillemets ajoutées
# lors de la récupération via jq
if [ ${FEED_CACHE} = 1 ]; then
write_log DEBUG 'Getting token'
TOKEN=$(echo ${RES_AUTHENT} | jq -r '.data.token')
if [ ! -n "${TOKEN}" ]; then
write_log FATAL 'Empty token'
exit 1
fi
write_log INFO 'Feeding cache'
# IPv4 addresses
for ID_RANGE_V4 in ${ID_RANGES_V4}; do
# Récupération des informations V4 et vérification du code HTTP
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
write_log FATAL "Wrong code returned for IPv4 range ${ID_RANGE_V4}: ${CODE_RETOUR_INFOS_V4}"
exit 1
fi
# Mise à jour du fichier de cache pour ce ID de subnet
echo ${INFOS_V4} > ${CHEMIN_CACHE}/${ID_RANGE_V4}
done
# Freeing RAM
INFOS_V4=''
CODE_RETOUR_INFOS_V4=''
# IPv6 ranges
for ID_RANGE_V6 in ${ID_RANGES_V6}; do
# Récupération des informations V6 et vérification du code HTTP
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
write_log FATAL "Wrong code returned for IPv4 range ${ID_RANGE_V6}: ${INFOS_RANGES_V6}"
exit 1
fi
echo ${INFOS_RANGES_V6} > ${CHEMIN_CACHE}/${ID_RANGE_V6}
done
# Freeing RAM
INFOS_RANGES_V6=''
CODE_RETOUR_INFOS_RANGES_V6=''
fi
MAC=$(grep 'vmbr1$' /etc/pve/nodes/*/qemu-server/${VM_ID}.conf | \
sed -E 's/.*([[:xdigit:]:]{17}).*/\1/')
# Pour chaque subnet V4
for ID_RANGE_V4 in ${ID_RANGES_V4}; do
# Récupération des informations V4 en cache pour cet ID de subnet si le
# fichier de cache associé existe
if [ ! -f "${CHEMIN_CACHE}/${ID_RANGE_V4}" ]; then
write_log FATAL "File not found: ${CHEMIN_CACHE}/${ID_RANGE_V4}"
exit 1
fi
VM_IPV4=$(jq -r ".data[] | select(.custom_vm_id==\"${VM_ID}\") | .ip" ${CHEMIN_CACHE}/${ID_RANGE_V4})
ADD_IPV4=$(jq -r ".data[] | select(.custom_vm_id==\"${VM_ID}\") | .custom_add_range" ${CHEMIN_CACHE}/${ID_RANGE_V4})
# Wait for the migration to finish
sleep 5
while [ -f /run/qemu-server/${VM_ID}.migrate ]; do
sleep 1
done
# Si la valeur n'est pas vide et correspond à une IPV4
if [ -n "${VM_IPV4}" ]; then
add_ipv4_route ${VM_IPV4} ${IFACE} ${MAC}
while [ "$( ip route sh dev ${IFACE})" = "" ]; do
add_ipv4_route ${VM_IPV4} ${IFACE} ${MAC}
sleep 1
done
GW_IPv4=$(jq -r ".data[] | select(.is_gateway==\"1\") | .ip" ${CHEMIN_CACHE}/${ID_RANGE_V4})
else
# En cas d'echec, on continue de parcourir les autres RANGES
write_log WARN 'Empty value or doent correspond to an IPv4'
fi
if [ -n "${ADD_IPV4}" ]; then
# Dont know why bird needs “onlink” to learn the route…
ip route add ${ADD_IPV4} via ${VM_IPV4} dev ${IFACE} onlink
fi
done
# Pour chaque subnet V6
for ID_RANGE_V6 in ${ID_RANGES_V6}; do
# Récupération des informations V6 en cache pour cet ID de subnet si le
# fichier de cache associé existe
if [ ! -f "${CHEMIN_CACHE}/${ID_RANGE_V6}" ]; then
write_log FATAL "File not found: ${CHEMIN_CACHE}/${ID_RANGE_V4}"
exit 1
fi
# Recherche des informations correspondants à la VM_ID
VM_IPV6=$(jq -r ".data[] | select(.custom_vm_id==\"${VM_ID}\") | .subnet" ${CHEMIN_CACHE}/${ID_RANGE_V6})
VM_NH=$(jq -r ".data[] | select(.custom_vm_id==\"${VM_ID}\") | .\"Next-hop\"" ${CHEMIN_CACHE}/${ID_RANGE_V6})
ADD_IPV6=$(jq -r ".data[] | select(.custom_vm_id==\"${VM_ID}\") | .custom_add_range" ${CHEMIN_CACHE}/${ID_RANGE_V6})
# Si la valeur n'est pas vide et correspond à un range IPV6
if [ -n "${VM_IPV6}" ]; then
if [ ${VM_NH} = 'null' ]; then
VM_NH=$(ipv6calc --action prefixmac2ipv6 --in prefix+mac --out ipv6addr fe80:: ${MAC})
fi
# Activation of IPv6 on the tap interface
sysctl net.ipv6.conf.${IFACE}.disable_ipv6=0
# Ajout de la route associée
COMMAND="ip -6 route add ${VM_IPV6}/48 via ${VM_NH} dev ${IFACE}"
echo "${COMMAND}"
write_log INFO "${COMMAND}"
${COMMAND}
# Updating NDP
COMMAND="ip neigh add ${VM_NH} lladdr ${MAC} dev ${IFACE}"
echo "${COMMAND}"
write_log INFO "${COMMAND}"
${COMMAND}
# If the previous command fails, its because trafic has
# already be sent to the VM
if [ $? = 2 ]; then
ip neigh replace ${VM_NH} lladdr ${MAC} dev ${IFACE}
fi
GW_IPv6="fe80::204:92:100:1"
# Send ICMP to update ARP/NDP cache
send-icmp.py ${MAC} ${IFACE} ${VM_IPV4} ${GW_IPv4} ${VM_NH} ${GW_IPv6} &
else
# En cas d'echec, on continue de parcourir les autres RANGES
echo "Valeur vide ou ne correspond pas à un range IPV6"
fi
if [ -n "${ADD_IPV6}" ]; then
ip -6 route add ${ADD_IPV6} via ${VM_NH} dev ${IFACE}
fi
done
write_log INFO 'Script ended'
exit 0