Ip failover with keepalived using a Bcfg2/Genshi template

Mar 30, 2010  

Following my previous post about Ip failover with Ucarp, i decided to use Keepalived instead of Ucarp as it is easier to setup and integrate. Keepalived implemented the Vrrp protocol instead of the Carp protocol. Carp is a patent free implementation of the ideas behind Vrrp.

To generate the keepalived config file i used TGenshi template and the bcfg2 Properties plugin.

This plugin allows you to define your custom XML config file and then use its content in your template.

Here is my /etc/bcfg2/Properties/vips.xml

<vips>
  <group name="axel">
    <vip iface="eth0" vid="10" ip="10.201.4.101" netmask="16" broadcast="10.201.255.255" password="mypass1">
      <host name="axel-01" master="yes"/>
      <host name="axel-02" master="no"/>
    </vip>
    <vip iface="vlan501" vid="11" ip="42.42.121.111" netmask"26" broadcast="42.42.121.127" password="mypass2">
      <host name="axel-01" master="yes"/>
      <host name="axel-02" master="no"/>
    </vip>
    <vip iface="vlan501" vid="12" ip="42.42.121.112" netmask="26" broadcast="42.42.121.127" password="mypass3">
      <host name="axel-01" master="no"/>
      <host name="axel-02" master="yes"/>
    </vip>
  </group>
</vips>

Now the template /etc/bcfg2/TGenshi/keepalived/keepalived.conf/template.newtxt

{% python
vips = []

try:
    hostname = list(metadata.aliases)[0].split('.',1)[0]
    for vip_info in metadata.Properties['vips.xml'].data.find(".//group[@name='%s']" % (hostname.split('-')[0])):
        vip = vip_info.attrib
        print vip
        for host_info in vip_info:
            if host_info.attrib['name'] == hostname:
               vip.update({'state' : host_info.attrib['master'] == 'yes' and 'MASTER' or 'BACKUP' })
               vips.append(vip)
except:
    pass
%}\
# ${hostname}

{% for index, vip in enumerate(vips) %}\
vrrp_instance VI_${index} {
    state ${vip['state']}
    interface ${vip['iface']}
    virtual_router_id ${vip['vid']}
    priority 100
    authentication {
        auth_type PASS
        auth_pass ${vip['password']}
    }

    virtual_ipaddress {
        ${vip['ip']}/${vip['netmask']} brd ${vip['broadcast']} dev ${vip['iface']}
    }
}
{% end %}

This will generate this kind of config file:

# axel-01

vrrp_instance VI_0 {
    state MASTER
    interface eth0
    virtual_router_id 10
    priority 100
    authentication {
        auth_type PASS
        auth_pass mypass1
    }

    virtual_ipaddress {
        10.201.4.101/16 brd 10.201.255.255 dev eth0
    }
}
vrrp_instance VI_1 {
    state MASTER
    interface vlan501
    virtual_router_id 11
    priority 100
    authentication {
        auth_type PASS
        auth_pass mypass2
    }

    virtual_ipaddress {
        42.42.121.111/26 brd 42.42.121.127 dev vlan501
    }
}
vrrp_instance VI_2 {
    state BACKUP
    interface vlan501
    virtual_router_id 12
    priority 100
    authentication {
        auth_type PASS
        auth_pass mypass3
    }

    virtual_ipaddress {
        42.42.121.112/26 brd 42.42.121.127 dev vlan501
    }
}