proxmox_routing/creationRoutesVM.sh

255 lines
7.4 KiB
Bash
Raw Normal View History

2019-01-21 14:36:50 +01:00
#!/bin/sh
2019-01-21 10:57:10 +01:00
# Script ajout de routes VM
# A CONFIGURER/VERIFIER :
# - USER_IPAM
# - PASSWORD_IPAM
# - ID_RANGES_V4
# - ID_RANGES_V6
# - LOG_PLACE
# - CHEMIN_CACHE
2019-01-21 11:27:10 +01:00
write_log() {
2019-01-21 14:36:50 +01:00
# $1: log level (INFO, ERROR, etc.)
2019-01-21 11:27:10 +01:00
# $2: message
printf "$(date -Isecond) - $1: $2\n" >> \
${LOG_PLACE}/$(date -Idate)_vm_routing.log
2019-01-21 14:36:50 +01:00
if [ $1 = 'ERROR' ] || [ $1 = 'FATAL' ] || [ $1 = 'WARN' ]; then
printf "$1: $2\n"
fi
2019-01-21 11:27:10 +01:00
}
2019-01-21 11:02:27 +01:00
# IPAM creds
2019-01-24 19:55:03 +01:00
CREDS_FILE='/usr/local/etc/proxmox-routing/creds'
if [ -f $CREDS_FILE ]; then
. $CREDS_FILE
2019-01-21 14:36:50 +01:00
CURL='curl -s -k -sS'
2019-01-21 11:02:27 +01:00
else
2019-01-21 17:32:54 +01:00
write_log FATAL 'The file creds doesnt exist'
2019-01-21 17:26:17 +01:00
exit 1
2019-01-21 11:02:27 +01:00
fi
2019-01-21 11:08:57 +01:00
# check for commands in the path
2019-01-21 14:36:50 +01:00
for bin in curl ip ipv6calc jq; do
2019-01-21 11:08:57 +01:00
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
2019-01-21 10:57:10 +01:00
# Chemin fichier de LOG (et création du répertoire s'il n'existe pas)
LOG_PLACE='/var/local/log/vm_id_log/'
2019-01-21 10:57:10 +01:00
if [ ! -d "${LOG_PLACE}" ];then
mkdir -p ${LOG_PLACE}
2019-01-21 11:27:10 +01:00
write_log INFO 'Creation of the log dir'
2019-01-21 10:57:10 +01:00
fi
2019-01-21 11:27:10 +01:00
write_log INFO 'Beginning of the script execution'
2019-01-21 10:57:10 +01:00
# Chemin fichier de CACHE (et création du répertoire s'il n'existe pas)
CHEMIN_CACHE='/var/local/cache/vm_id_cache/'
2019-01-21 10:57:10 +01:00
if [ ! -d "${CHEMIN_CACHE}" ];then
mkdir -p ${CHEMIN_CACHE}
2019-01-21 11:27:10 +01:00
write_log INFO 'Creation of the cache dir'
2019-01-21 10:57:10 +01:00
fi
# Fonction d'aide
usage() {
printf "Usage: ./creationRoutesVM.sh <VM_ID>\n"
printf "VM_ID est l'id d'une VM dans PROXMOX, un entier supérieur à 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
2019-01-21 14:36:50 +01:00
write_log FATAL 'VM ID not specified'
2019-01-21 10:57:10 +01:00
usage
exit 1
2019-01-21 14:36:50 +01:00
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
2019-01-21 10:57:10 +01:00
fi
else
2019-01-21 14:36:50 +01:00
write_log FATAL 'No parameter specified'
2019-01-21 10:57:10 +01:00
usage
exit 1
fi
2019-01-24 15:56:16 +01:00
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})"
if [ "${IP4_NEIGH}" ] && [ "${IP6_NEIGH}" ] && [ "${IP4_ROUTE}" ] && [ "${IP6_ROUTE}" ]; then
write_log INFO 'Nothing to do'
exit 0
fi
2019-01-21 10:57:10 +01:00
# Récupération d'un TOKEN pour utiliser IPAM via l'API
2019-01-21 14:36:50 +01:00
write_log DEBUG 'Connecting to API'
RES_AUTHENT=$(${CURL} -X POST --user ${USER_IPAM}:${PASSWORD_IPAM} ${URL}/user/)
2019-01-21 10:57:10 +01:00
CODE_RETOUR_RES_AUTHENT=$(echo ${RES_AUTHENT} | jq '.code')
# Si OK, on utilise l'IPAM, sinon on passe par le fichier de cache
2019-01-21 14:36:50 +01:00
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
2019-01-21 10:57:10 +01:00
2019-01-21 14:36:50 +01:00
# 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')
2019-01-21 10:57:10 +01:00
if [ ! -n "${TOKEN}" ]; then
2019-01-21 14:36:50 +01:00
write_log FATAL 'Empty token'
2019-01-21 10:57:10 +01:00
exit 1
fi
2019-01-21 14:36:50 +01:00
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')
2019-01-21 10:57:10 +01:00
2019-01-21 14:36:50 +01:00
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
2019-01-21 10:57:10 +01:00
fi
2019-01-21 14:36:50 +01:00
# Mise à jour du fichier de cache pour ce ID de subnet
echo ${INFOS_V4} > ${CHEMIN_CACHE}/${ID_RANGE_V4}
2019-01-21 10:57:10 +01:00
done
2019-01-21 14:36:50 +01:00
# 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')
2019-01-21 17:36:02 +01:00
if [ ${CODE_RETOUR_INFOS_RANGES_V6} != 200 ]; then
2019-01-21 14:36:50 +01:00
write_log FATAL "Wrong code returned for IPv4 range ${ID_RANGE_V6}: ${INFOS_RANGES_V6}"
exit 1
2019-01-21 10:57:10 +01:00
fi
2019-01-21 14:36:50 +01:00
echo ${INFOS_RANGES_V6} > ${CHEMIN_CACHE}/${ID_RANGE_V6}
2019-01-21 10:57:10 +01:00
done
2019-01-21 14:36:50 +01:00
# Freeing RAM
INFOS_RANGES_V6=''
CODE_RETOUR_INFOS_RANGES_V6=''
2019-01-21 10:57:10 +01:00
fi
2019-01-21 14:36:50 +01:00
MAC=$(grep 'vmbr1$' /etc/pve/nodes/*/qemu-server/${VM_ID}.conf | \
2019-01-21 14:36:50 +01:00
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})
# Si la valeur n'est pas vide et correspond à une IPV4
if [ -n "${VM_IPV4}" ]; then
# Ajout de la route associée
2019-01-24 15:56:16 +01:00
COMMAND="ip -4 route add ${VM_IPV4}/32 dev ${IFACE}"
2019-01-21 14:36:50 +01:00
echo "${COMMAND}"
write_log INFO "${COMMAND}"
${COMMAND}
# Updating ARP
2019-01-24 15:56:16 +01:00
COMMAND="ip neigh add ${VM_IPV4} lladdr ${MAC} dev ${IFACE}"
2019-01-21 14:36:50 +01:00
echo "${COMMAND}"
write_log INFO "${COMMAND}"
${COMMAND}
# If the previous command fails, its because trafic has
# already be sent to the VM
2019-01-22 15:09:02 +01:00
if [ $? = 2 ]; then
2019-01-24 15:56:16 +01:00
ip neigh replace ${VM_IPV4} lladdr ${MAC} dev ${IFACE}
fi
GW_IPv4=$(jq -r ".data[] | select(.is_gateway==\"1\") | .ip" ${CHEMIN_CACHE}/${ID_RANGE_V4})
2019-01-21 14:36:50 +01:00
else
# En cas d'echec, on continue de parcourir les autres RANGES
write_log WARN 'Empty value or doent correspond to an IPv4'
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})
# 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
2019-01-24 15:56:16 +01:00
sysctl net.ipv6.conf.${IFACE}.disable_ipv6=0
2019-01-21 14:36:50 +01:00
# Ajout de la route associée
2019-01-24 15:56:16 +01:00
COMMAND="ip -6 route add ${VM_IPV6}/48 via ${VM_NH} dev ${IFACE}"
2019-01-21 14:36:50 +01:00
echo "${COMMAND}"
write_log INFO "${COMMAND}"
${COMMAND}
# Updating NDP
2019-01-24 15:56:16 +01:00
COMMAND="ip neigh add ${VM_NH} lladdr ${MAC} dev ${IFACE}"
2019-01-21 14:36:50 +01:00
echo "${COMMAND}"
write_log INFO "${COMMAND}"
${COMMAND}
# If the previous command fails, its because trafic has
# already be sent to the VM
2019-01-22 15:09:02 +01:00
if [ $? = 2 ]; then
2019-01-24 15:56:16 +01:00
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} &
2019-01-21 14:36:50 +01:00
else
# En cas d'echec, on continue de parcourir les autres RANGES
echo "Valeur vide ou ne correspond pas à un range IPV6"
fi
done
2019-01-21 11:27:10 +01:00
write_log INFO 'Script ended'
2019-01-21 10:57:10 +01:00
exit 0