-#!/bin/sh
+#!/bin/bash
set -e
-# Configuration Fallbacks. All can(must for some of them) be overwritten by /etc/ganeti/dnshook.conf
+# Configuration Fallbacks. All can(must for some of them) be overwritten by /etc/default/snf-network
TTL=300
+# the bind server IP/FQDN
SERVER=""
-FZONE="" # Leave empty if only reverse dns management is needed. Don't forget the trailing dot
+# this is the .vm.synnefo.live.
+# Leave empty if only reverse dns management is needed.
+# TODO: make this zone to be instance specific!!!
+FZONE=""
+# the file with dns authorization keys
KEYFILE=""
MAC2EUI64="/usr/bin/mac2eui64"
-if [ -e /etc/ganeti/dnshook.conf ]; then
- . /etc/ganeti/dnshook.conf
-else
- exit 0
+source /etc/default/snf-network
+
+if [ -z "$SERVER" -o -z "$FZONE" -o -z "$KEYFILE" ]; then
+ exit 0
fi
update () {
EOF
}
-addremove () {
- local action=$1
- local REVZONE=$2
- local REV6ZONE=$3
- local REVLPART=$4
- local REV6LPART=$5
-
- update $REVZONE "update $action $REVLPART.$REVZONE. $TTL PTR $GANETI_INSTANCE_NAME.$FZONE"
- update $REV6ZONE "update $action $REV6LPART$REV6ZONE. $TTL PTR $GANETI_INSTANCE_NAME.$FZONE"
-
- if [ ! -z "$7" ]; then
- EUI64=$6
- FORZONE=$7
- update $FORZONE "update $action $GANETI_INSTANCE_NAME.$FORZONE $TTL A $GANETI_INSTANCE_NIC0_IP"
- update $FORZONE "update $action $GANETI_INSTANCE_NAME.$FORZONE $TTL AAAA $EUI64"
- fi
+
+# ommit zone statement
+# nsupdate will attempt determine the correct zone to update based on the rest of the input
+send_command () {
+
+ local command="$1"
+ nsupdate -k $KEYFILE > /dev/null << EOF
+ server $SERVER
+ $command
+ send
+EOF
+
}
+
+addremove_arecord () {
+
+ local action=$1
+ local command=
+ if [ -n "$IP" ]; then
+ command="update $action $GANETI_INSTANCE_NAME.$FZONE $TTL A $IP"
+ send_command "$command"
+ fi
+ if [ -n "$EUI64" ]; then
+ command="update $action $GANETI_INSTANCE_NAME.$FZONE $TTL AAAA $EUI64"
+ send_command "$command"
+ fi
+
+}
+
+addremove_ptrrecord () {
+
+ local action=$1
+ local command=
+ if [ -n "$IP" ]; then
+ command="update $action $RLPART.$RZONE. $TTL PTR $GANETI_INSTANCE_NAME.$FZONE"
+ send_command "$command"
+ fi
+ if [ -n "$EUI64" ]; then
+ command="update $action $R6LPART.$R6ZONE. $TTL PTR $GANETI_INSTANCE_NAME.$FZONE"
+ send_command "$command"
+ fi
+
+}
+
+
+# first argument is an eui64 (IPv6)
+# sets GLOBAL args R6REC, R6ZONE, R6LPART
+# lets assume eui64=eui64=2001:648:2ffc:1::1
+# the following commands produce:
+# R6REC=1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.1.0.0.0.c.f.f.2.8.4.6.0.1.0.0.2.ip6.arpa
+# R6ZONE=1.0.0.0.c.f.f.2.8.4.6.0.1.0.0.2.ip6.arpa
+# R6LPART=1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.
+get_rev6_info () {
+
+ local eui64=$1
+ if [ -z "$eui64" ]; then
+ R6REC= ; R6ZONE= ; R6LPART= ;
+ else
+ R6REC=$(host $eui64 | egrep -o '([[:alnum:]]\.){32}ip6.arpa' )
+ R6ZONE=$(echo $R6REC | awk -F. 'BEGIN{rpart="";} { for (i=32;i>16;i=i-1) rpart=$i "." rpart; } END{print rpart "ip6.arpa";}')
+ R6LPART=$(echo $R6REC | awk -F. 'BEGIN{lpart="";} { for (i=16;i>0;i=i-1) lpart=$i "." lpart; } END{print lpart;}')
+ fi
+
+}
+
+
+# first argument is an ipv4
+# sets args RZONE, RLPART
+# lets assume IP=203.0.113.1
+# RZONE="113.0.203.in-add.arpa"
+# RLPART="1"
+get_rev4_info () {
+
+ local ip=$1
+ if [ -z "$ip" ]; then
+ RZONE= ; RLPART= ;
+ else
+ OLDIFS=$IFS
+ IFS=". "
+ set -- $ip
+ a=$1 ; b=$2; c=$3; d=$4;
+ IFS=$OLDIFS
+ RZONE="$c.$b.$a.in-addr.arpa"
+ RLPART="$d"
+ fi
+
+}
+
+
+update_dns () {
+
+ if [ "x$GANETI_OP_CODE" = "xOP_INSTANCE_CREATE" ]; then
+ update_arecord add
+ update_ptrrecord add
+ elif [ "x$GANETI_OP_CODE" = "xOP_INSTANCE_REMOVE" ]; then
+ update_arecord delete
+ update_ptrrecord delete
+ elif [ "x$GANETI_OP_CODE" = "xOP_INSTANCE_RENAME" ]; then
+ update_arecord delete
+ update_ptrrecord delete
+ # Let's override a variable and add ourselves
+ GANETI_INSTANCE_NAME=$GANETI_INSTANCE_NEW_NAME
+ update_arecord add
+ update_ptrrecord add
+ elif [ "x$GANETI_OP_CODE" = "xOP_INSTANCE_STARTUP" ]; then
+ update_arecord add
+ update_ptrrecord add
+ elif [ "x$GANETI_OP_CODE" = "xOP_INSTANCE_SHUTDOWN" ]; then
+ update_arecord delete
+ update_ptrrecord delete
+ elif [ "x$GANETI_OP_CODE" = "xOP_INSTANCE_REBOOT" ]; then
+ update_arecord add
+ update_ptrrecord add
+ elif [ "x$GANETI_OP_CODE" = "xOP_INSTANCE_SET_PARAMS" ]; then
+ update_arecord add
+ update_ptrrecord add
+ fi
+
+}
+
+
+# Query nameserver for entries related to the specific instance
+# An example output is the following:
+# www.google.com has address 173.194.113.114
+# www.google.com has address 173.194.113.115
+# www.google.com has address 173.194.113.116
+# www.google.com has address 173.194.113.112
+# www.google.com has address 173.194.113.113
+# www.google.com has IPv6 address 2a00:1450:4001:80b::1012
+query_dns () {
+
+ HOSTQ="host -s -R 3 -W 3"
+ HOST_IP_ALL=$($HOSTQ $GANETI_INSTANCE_NAME.$FZONE $SERVER | sed -n 's/.*has address //p')
+ HOST_IP6_ALL=$($HOSTQ $GANETI_INSTANCE_NAME.$FZONE $SERVER | sed -n 's/.*has IPv6 address //p')
+
+}
+
+
+# Reset all entries related to the specific instance
+# This should be invoced only during instance modification
+# because we do not know which nics have been modify
+reset_dns () {
+
+ if [ "x$GANETI_OP_CODE" = "xOP_INSTANCE_SET_PARAMS" ]; then
+ query_dns
+ # This should remove the A, AAAA, CNAME entries
+ run_action "update delete $GANETI_INSTANCE_NAME.$FZONE"
+ for ip in $HOST_IP_ALL; do
+ get_rev4_info $ip
+ # This should remove the IPv4 reverse entry
+ run_action "update delete $RLPART.$RZONE"
+ done
+ for ip6 in $HOST_IP6_ALL; do
+ get_rev6_info $ip6
+ # This should remove the IPv6 reverse entry
+ run_action "update delete $R6LPART$R6ZONE."
+ done
+ fi
+
+}
+
+
+# Because we do not have IPv6 value in our environment
+# we caclulate it based on the NIC's MAC and the IPv6 subnet (if any)
+# first argument MAC second IPv6 subnet
+# Changes global value EUI64
+get_eui64 () {
+
+ local mac=$1
+ local prefix=$2
+
+ if [ -z "$prefix" ]; then
+ EUI64=
+ else
+ EUI64=$($MAC2EUI64 $MAC $SUBNET6)
+ fi
+
+}
+
+
# Main starts here
-if [ "x" = "x$GANETI_INSTANCE_NIC0_IP" ]; then
- exit 1
-else
- OLDIFS=$IFS
- IFS=". "
- set -- $GANETI_INSTANCE_NIC0_IP
- a=$1 ; b=$2; c=$3; d=$4;
- IFS=$OLDIFS
- RZONE="$c.$b.$a.in-addr.arpa"
- RLPART="$d"
-
- # NOTE: We are going to assume one simple thing. /64s ...
- # A mistake but good enough for alpha and autoconfiguration
- prefix=$(ip -6 route list table $GANETI_INSTANCE_NIC0_LINK | awk '/\/64/ {print $1; exit}')
- eui64=$($MAC2EUI64 $GANETI_INSTANCE_NIC0_MAC $prefix)
- R6REC=$(host $eui64 | egrep -o '([[:alnum:]]\.){32}ip6.arpa' )
- R6ZONE=$(echo $R6REC | awk -F. 'BEGIN{rpart="";} { for (i=32;i>16;i=i-1) rpart=$i "." rpart; } END{print rpart "ip6.arpa";}')
- R6LPART=$(echo $R6REC | awk -F. 'BEGIN{lpart="";} { for (i=16;i>0;i=i-1) lpart=$i "." lpart; } END{print lpart;}')
-fi
-if [ "x" = "x$GANETI_INSTANCE_NAME" ]; then
- exit 1
+# Exit if we do not have instance name.
+# It should be exported to hooks for instance related opcodes.
+if [ -z "$GANETI_INSTNACE_NAME" ]; then
+ exit 0
fi
-if [ "x$GANETI_OP_CODE" = "xOP_INSTANCE_CREATE" ]; then
- addremove add $RZONE $R6ZONE $RLPART $R6LPART $eui64 $FZONE
-elif [ "x$GANETI_OP_CODE" = "xOP_INSTANCE_REMOVE" ]; then
- addremove delete $RZONE $R6ZONE $RLPART $R6LPART $eui64 $FZONE
-elif [ "x$GANETI_OP_CODE" = "xOP_INSTANCE_RENAME" ]; then
- addremove delete $RZONE $R6ZONE $RLPART $R6LPART $eui64 $FZONE
- # Let's override a variable and add ourselves
- GANETI_INSTANCE_NAME=$GANETI_INSTANCE_NEW_NAME
- addremove add $RZONE $R6ZONE $RLPART $R6LPART $eui64 $FZONE
-elif [ "x$GANETI_OP_CODE" = "xOP_INSTANCE_STARTUP" ]; then
- addremove add $RZONE $R6ZONE $RLPART $R6LPART $eui64 $FZONE
-elif [ "x$GANETI_OP_CODE" = "xOP_INSTANCE_SHUTDOWN" ]; then
- addremove delete $RZONE $R6ZONE $RLPART $R6LPART $eui64 $FZONE
-elif [ "x$GANETI_OP_CODE" = "xOP_INSTANCE_REBOOT" ]; then
- addremove delete $RZONE $R6ZONE $RLPART $R6LPART $eui64 $FZONE
- addremove add $RZONE $R6ZONE $RLPART $R6LPART $eui64 $FZONE
-fi
+# This runs only for instance modification
+reset_dns
+
+# If GANETI_INSTANCE_NIC_COUNT is not set then nothing happens
+FIRST=0
+LAST=$((GANETI_INSTANCE_NIC_COUNT - 1))
+for idx in $(seq $FIRST $LAST); do
+ ip=GANETI_INSTANCE_NIC${idx}_IP
+ mac=GANETI_INSTANCE_NIC${idx}_MAC
+ mode=GANETI_INSTANCE_NIC${idx}_MODE
+ link=GANETI_INSTANCE_NIC${idx}_LINK
+ subnet=GANETI_INSTANCE_NIC${idx}_NETWORK_SUBNET
+ subnet6=GANETI_INSTANCE_NIC${idx}_NETWORK_SUBNET6
+ tags=GANETI_INSTANCE_NIC${idx}_NETWORK_TAGS
+ eval IP=\$$ip
+ eval MAC=\$$mac
+ eval MODE=\$$mode
+ eval LINK=\$$link
+ eval SUBNET=\$$subnet
+ eval SUBNET6=\$$subnet6
+ eval TAGS=\$$tags
+
+ for tag in $TAGS; do
+ case $tag in
+ $DNS_TAG)
+
+ get_rev4_info "$IP"
+ get_eui64 "$MAC" "$SUBNET6"
+ get_rev6_info "$EUI64"
+ update_dns
+
+ ;;
+ esac
+
+ done
+
+done