Hetzner Failover Webservice/Script KVM/qemu/libvirt

Failover IPs via Webservice

https://robot.your-server.de/doc/webservice/de.html#failover

https://wiki.hetzner.de/index.php/Failover_Skript

Nice online Json formatter: https://jsonformatter.curiousconcept.com/

Setup

Webservice Commands

  • curl -s -u "username:password" https://robot-ws.your-server.de/failover
  • [
       {
          "failover":{
             "ip":"111.111.111.111",               #failover ip
             "netmask":"255.255.255.255",
             "server_ip":"222.222.222.222",        #base server
             "server_number":123456,
             "active_server_ip":"333.333.333.333"  #currently routed to
          }
       },
       {
          "failover":{
             "ip":"444.444.444.444",
             "netmask":"255.255.255.255",
             "server_ip":"222.222.222.222",
             "server_number":123456,
             "active_server_ip":"222.222.222.222"
          }
       }
    ]

Status for failover IP 111.111.111.111

  • curl -s -u "username:password" https://robot-ws.your-server.de/failover/111.111.111.111
  • { 
          "failover":{
    "ip":"111.111.111.111", #failover ip
    "netmask":"255.255.255.255",
    "server_ip":"222.222.222.222", #base server
    "server_number":123456,
    "active_server_ip":"333.333.333.333" #currently routed to
    }
    }
Switch failover IP 111.111.111.111 to server 222.222.222.222
  • curl -s -u "username:password" https://robot-ws.your-server.de/failover/111.111.111.111 -d active_server_ip=222.222.222.222
  • { 
          "failover":{
             "ip":"111.111.111.111",               #failover ip
             "netmask":"255.255.255.255",
             "server_ip":"222.222.222.222",        #base server
             "server_number":123456,
             "active_server_ip":"222.222.222.222"  #currently routed to
          }
    }

Template for a KVM/qemu/libvirt hook script

This is based on the following network configuration for Hetzner Failover IPs:

Hypervisor:

  • vi /etc/network/interfaces
    • auto eth0
        #hetzner default config
      
      # Bridge for KVM  - nice: VMs need no network config change and work on any hypervisor
      auto br0
      iface br0 inet static
        address 192.168.1.1
        netmask 255.255.255.255
        bridge_ports none
        bridge_stp off
        bridge_fd 0
        bridge_maxwait 1
        pre-up brctl addbr br0
        # Hetzner Failover IPs - this is now handled by hook script
        #up ip route add 111.111.111.111 via 192.168.1.1
  • virsh edit myserver.example.com
    • ...
          <interface type='bridge'>
            <source bridge='br0'/>
            <model type='virtio'/>
          </interface>
      ...

Virtual machine:

  • vi /etc/network/interfaces
    • iface eth0 inet static
              address 111.111.111.111 #hetzner failover ip
              netmask 255.255.255.255
              dns-nameservers 213.133.100.100 213.133.98.98
              post-up ip route add 192.168.1.1 dev eth0
              post-up ip route add default via 192.168.1.1 dev eth0

Hook script

  • apt-get install jq
  • vi /etc/libvirt/hooks/qemu
    • #!/bin/bash
      # kvm hetzner vm config script
      # add and remove routing
      # switch failover ip if necessary
      # 2018-01-29 klemens@ull.at
      
      # log script output
      exec 1>>/var/log/qemu-hooks.log 2>&1
      
      # Exit script immediately if a command exits with a nonzero exit value
      set -e
      
      # Activate debugging - echo on, display commands, outputs to stderr!
      #set -x
      
      echo "########################################################"
      date
      
      echo "vm: ${1}"
      echo "phase: ${2}"
      echo "begin/end: ${3}"
      
      LOCAL_IP=`ifconfig eth0 | grep -Eo 'inet (addr:)?([0-9]*\.){3}[0-9]*' | grep -Eo '([0-9]*\.){3}[0-9]*'`
      echo "local ip: $LOCAL_IP"
      
      if [ "$1" == "myserver.example.com" ]; then
              VM_IP="111.111.111.111"
              echo "myserver.example.com: $VM_IP"
      
              if [ "$2" == "start" ]; then
                      echo "adding local route"
                      ip route add $VM_IP via 192.168.1.1
      
                      ACTIVE_SERVER_IP=`curl -s -u "username:password" https://robot-ws.your-server.de/failover/$VM_IP | jq -r '.failover.active_server_ip'`
                      if [ "$ACTIVE_SERVER_IP" != "$LOCAL_IP" ]; then
                              echo "changing hetzner failover ip"
                              curl -s -u "username:password" https://robot-ws.your-server.de/failover/$VM_IP -d active_server_ip=$LOCAL_IP
                      fi
      
              elif [ $2 == "stopped" ]; then
                      echo "deleting local route"
                      ip route del $VM_IP
              fi
      fi
  • chmod 700 /etc/libvirt/hooks/qemu
  • ?necessary? service qemu-kvm restart
  • service libvirt-bin restart
  • cat /var/log/qemu-hooks.log