keepalived: add uci config support
authorAlexandru Ardelean <redacted>
Wed, 2 Dec 2015 08:32:54 +0000 (10:32 +0200)
committerAlexandru Ardelean <redacted>
Sat, 31 Dec 2016 10:15:54 +0000 (12:15 +0200)
Adding @scrpi (Ben Kelly).
Initial UCI config support was written by me (@commodo)

Updates & fixes added by Ben.

Signed-off-by: Ben Kelly <redacted>
Signed-off-by: Alexandru Ardelean <redacted>
net/keepalived/Makefile
net/keepalived/files/keepalived.config [new file with mode: 0644]
net/keepalived/files/keepalived.init

index b29b111a5fbf2b9250a95e7401ed205972f64ff6..78f75f92c371557788881efcb73a6bd2b581c3dc 100644 (file)
@@ -63,6 +63,8 @@ define Package/keepalived/install
        $(CP) $(PKG_INSTALL_DIR)/etc/keepalived/keepalived.conf $(1)/etc/keepalived/
        $(INSTALL_DIR) $(1)/etc/init.d
        $(INSTALL_BIN) ./files/keepalived.init $(1)/etc/init.d/keepalived
+       $(INSTALL_DIR) $(1)/etc/config
+       $(INSTALL_CONF) ./files/keepalived.config $(1)/etc/config/keepalived
 endef
 
 $(eval $(call BuildPackage,keepalived))
diff --git a/net/keepalived/files/keepalived.config b/net/keepalived/files/keepalived.config
new file mode 100644 (file)
index 0000000..383895b
--- /dev/null
@@ -0,0 +1,147 @@
+#config global_defs
+#      option alt_config_file          "/etc/keepalived/keepalived.conf"
+#      list notification_email         "acassen@firewall.loc"
+#      list notification_email         "failover@firewall.loc"
+#      list notification_email         "sysadmin@firewall.loc"
+#      option notification_email_from  "Alexandre.Cassen@firewall.loc"
+#      option smtp_server              "192.168.200.1"
+#      option smtp_connect_timeout     "30"
+#      option router_id                "LVS_DEVEL"
+#      option vrrp_mcast_group4        "224.0.0.18" # optional, default 224.0.0.18
+#      option vrrp_mcast_group6        "f02::12"    # optional, default ff02::12
+#      option linkbeat_use_polling     "1"
+
+#config ipaddress
+#      option name     "ipaddress0"
+#      option address  "192.168.1.1/24"
+#      option device   "eth0"
+#      option scope    "global"
+
+#config ipaddress
+#      option name     "ipaddress1"
+#      option address  "192.168.1.2/24"
+#      option device   "eth1"
+#      option scope    "global"
+
+#config ipaddress
+#      option name     "ipaddress2"
+#      option address  "192.168.1.1/24"
+#      option device   "eth0"
+#      option scope    "link"
+
+#config ipaddress
+#      option name     "ipaddress3"
+#      option address  "192.168.1.2/24"
+#      option device   "eth2"
+#      option scope    "site"
+
+#config ipaddress
+#      option name     "ipaddress4"
+#      option address  "192.168.1.1/24"
+#      option device   "eth0"
+#      option scope    "host"
+
+#config ipaddress
+#      option name     "ipaddress5"
+#      option address  "192.168.1.2/24"
+#      option device   "eth0"
+#      option scope    "nowhere"
+
+#config route
+#      option name     "route0"
+#      option address  "192.168.1.1/24"
+#      option gateway  "192.168.0.1"
+#      option device   "eth0"
+
+#config route
+#      option name     "route1"
+#      option address  "192.168.2.1/24"
+#      option gateway  "192.168.0.1"
+#      option device   "eth0"
+
+#config route
+#      option name             "route2"
+#      option address          "127.0.0.1"
+#      option blackhole        "1"
+
+#config static_ipaddress
+#      list address    "ipaddress0"
+#      list address    "ipaddress1"
+
+#config static_routes
+#      list route      "route0"
+#      list route      "route1"
+
+#config vrrp_sync_group
+#      option name             "VI_sync_group_1"
+#      list group              "VI_1"
+#      list group              "VI_2"
+#      option smtp_alert       "1"
+#      option notify_backup    "<switch-backup-state-script>"
+#      option notify_master    "<switch-master-state-script>"
+#      option notify_fault     "<switch-fault-state-script>"
+#      option notify           "<switch-any-state-script>"
+#      option global_tracking  1
+
+#config track_interface
+#      option name     "track_intf1"
+#      option value    "eth0"
+#      option weight   "1"
+
+#config track_interface
+#      option name     "track_intf2"
+#      option value    "eth1"
+#      option weight   "2"
+
+#config track_script
+#      option name     "track_script1"
+#      option value    "<script-file1>"
+#      option weight   "1"
+
+#config track_script
+#      option name     "track_script2"
+#      option value    "<script-file2>"
+#      option weight   "2"
+
+#config vrrp_instance
+#      option name                     "VI_1"
+#      option use_vmac                 "eth0"
+#      option native_ipv6              "1"
+#      option state                    "MASTER"
+#      option interface                "eth0"
+#      list track_interface            "track_intf1"
+#      list track_interface            "track_intf2"
+#      list track_script               "track_script1"
+#      list track_script               "track_script2"
+#      option dont_track_primary       "1"
+#      list unicast_peer               "192.168.0.1"
+#      list unicast_peer               "192.168.1.1"
+#      list virtual_ipaddress          "ipaddress2"
+#      list virtual_ipaddress          "ipaddress3"
+#      list virtual_ipaddress_excluded "ipaddress4"
+#      list virtual_ipaddress_excluded "ipaddress5"
+#      list virtual_routes             "route1"
+#      list virtual_routes             "route2"
+#      option mcast_src_ip             "224.0.0.1"
+#      option unicast_src_ip           "192.168.0.1"
+#      option virtual_router_id        "128"
+#      option priority                 "128"
+#      option advert_int               "5"
+#      option nopreempt                "1"
+#      option preempt_delay            "500"
+#      option debug                    "2"
+#      option notify_backup            "<switch-backup-state-script>"
+#      option notify_master            "<switch-master-state-script>"
+#      option notify_fault             "<switch-fault-state-script>"
+#      option notify_stop              "<switch-stop-state-script>"
+#      option notify                   "<switch-any-state-script>"
+#      option smtp_alert               "1"
+#      option accept                   "1"
+
+#config vrrp_script
+#      option script           "<script-file>"
+#      option interval         "5"
+#      option weight           "10"
+#      option fall             "2"
+#      option rise             "3"
+
index cc0535ab42da1c2ddc9cb90566f786587513a484..b8a7e26c4a89d71d4313fef7052fed2eab36c7e3 100644 (file)
@@ -6,10 +6,385 @@ STOP=01
 
 USE_PROCD=1
 
+KEEPALIVED_CONF=/tmp/keepalived.conf
+
+INDENT_1=\\t
+INDENT_2=$INDENT_1$INDENT_1
+
+config_section_open() {
+       local tag=$1
+       local name=$2
+
+       printf "$tag" >> $KEEPALIVED_CONF
+       [ -n "$name" ] && printf " $name" >> $KEEPALIVED_CONF
+       printf " {\n" >> $KEEPALIVED_CONF
+}
+
+config_section_close() {
+       printf "}\n\n" >> $KEEPALIVED_CONF
+}
+
+config_foreach_wrapper() {
+       local section=$1
+       local function=$1
+
+       # Convention is that 'function' and 'section' are the same
+       config_foreach $function $section
+}
+
+print_elems_indent() {
+       local config=$1
+       shift
+       local indent=$1
+       shift
+       [ -z "$indent" ] && indent="$INDENT_1"
+       for opt in $*; do
+               local $opt
+               local no_val=0
+               if [ ${opt:0:7} == "no_val_" ]; then
+                       opt=${opt:7}
+                       no_val=1
+               fi
+               config_get $opt $config $opt
+               eval optval=\$$opt
+               [ -z "$optval" ] && continue
+               printf "$indent$opt" >> $KEEPALIVED_CONF
+               [ "$no_val" == "0" ] && printf " $optval" >> $KEEPALIVED_CONF
+               printf "\n" >> $KEEPALIVED_CONF
+       done
+       unset optval
+}
+
+print_list_indent() {
+       local lst=$1
+       local indent=$2
+       local lst_elems
+       [ -z "$indent" ] && indent=$INDENT_1
+
+       eval lst_elems=\$$lst
+       [ -z "$lst_elems" ] && return 0
+
+       printf "$indent$lst {\n" >> $KEEPALIVED_CONF
+       for e in $lst_elems; do
+               [ -n "$eval_item_func" ]
+               printf "$indent$INDENT_1$e\n" >> $KEEPALIVED_CONF
+       done
+       printf "$indent}\n" >> $KEEPALIVED_CONF
+}
+
+global_defs() {
+       local linkbeat_use_polling notification_email
+
+       config_get alt_config_file $1 alt_config_file
+       [ -z "$alt_config_file" ] || return 0
+
+       config_get_bool linkbeat_use_polling $1 linkbeat_use_polling 0
+       [ $linkbeat_use_polling -gt 0 ] && printf "linkbeat_use_polling\n\n" >> $KEEPALIVED_CONF
+
+       config_get notification_email $1 notification_email
+       print_list_indent notification_email
+
+       print_elems_indent $1 $INDENT_1 notification_email_from smtp_server smtp_connect_timeout \
+                  router_id vrrp_mcast_group4 vrrp_mcast_group6
+}
+
+print_ipaddress_indent() {
+       local section=$1
+       local curr_ipaddr=$2
+       local indent=$3
+
+       local address device scope name
+       config_get name    $section name
+       [ "$name" != "$curr_ipaddr" ] && return 0
+
+       config_get address $section address
+       config_get device  $section device
+       config_get scope   $section scope
+
+       # Default indent
+       [ -z "$indent" ] && indent=$INDENT_1
+
+       # If no address or device exit
+       [ -z "$address" -o -z "$device" ] && return 0
+
+       # Add IP address/netmask and device
+       printf "$indent$address dev $device" >> $KEEPALIVED_CONF
+       # Add scope
+       [ -n "$scope" ] && printf " scope $scope" >> $KEEPALIVED_CONF
+
+       printf "\n" >> $KEEPALIVED_CONF
+}
+
+static_ipaddress() {
+       local address
+       config_get address "$1" address
+       for a in $address; do
+               config_foreach print_ipaddress_indent ipaddress $a
+       done
+}
+
+print_route_indent() {
+       local section=$1
+       local curr_route=$2
+       local indent=$3
+
+       local name blackhole address src_addr gateway device scope table
+
+       config_get name           $section name
+       [ "$name" != "$curr_route" ] && return 0
+
+       config_get_bool blackhole $section blackhole 0
+       config_get address        $section address
+       config_get src_addr       $section src_addr
+       config_get gateway        $section gateway
+       config_get device         $section device
+       config_get table          $section table
+
+       # If no address exit
+       [ -z "$address" ] && return 0
+
+       # Default indent
+       [ -z "$indent" ] && indent=$INDENT_1
+
+       [ $blackhole -gt 0 ] && {
+               printf "${indent}blackhole $address\n" >> $KEEPALIVED_CONF
+               return 0
+       }
+       # Add src addr or address
+       if [ -n "$src_addr" ]; then
+               printf "${indent}src $src_addr $address" >> $KEEPALIVED_CONF
+       else
+               [ -z "$device" ] && return 0
+               printf "$indent$address" >> $KEEPALIVED_CONF
+       fi
+       # Add route/gateway
+       [ -n "$gateway" ] && printf " via $gateway" >> $KEEPALIVED_CONF
+       # Add device
+       printf " dev $device" >> $KEEPALIVED_CONF
+       # Add scope
+       [ -n "$scope" ] && printf " scope $scope" >> $KEEPALIVED_CONF
+       # Add table
+       [ -n "$table" ] && printf " table $table" >> $KEEPALIVED_CONF
+       printf "\n" >> $KEEPALIVED_CONF
+
+}
+
+print_track_elem_indent() {
+       local section=$1
+       local curr_track_elem=$2
+       local indent=$3
+
+       local script name value
+       config_get name    $section name
+       [ "$name" != "$curr_track_elem" ] && return 0
+
+       config_get value  $section value
+       config_get weight $section weight
+
+       [ -z "$value" ] && return 0
+
+       printf "$indent$value" >> $KEEPALIVED_CONF
+       [ -n "$weight" ] && printf " weight $weight" >> $KEEPALIVED_CONF
+       printf "\n" >> $KEEPALIVED_CONF
+}
+
+static_routes() {
+       local route
+       config_get route "$1" route
+       for r in $route; do
+               config_foreach print_route_indent route $r
+       done
+}
+
+# Count 'vrrp_instance' with the given name ; called by vrrp_instance_check()
+vrrp_instance_name_count() {
+       local name
+       config_get name $1 name
+       [ "$name" == "$2" ] && count=$((count + 1))
+}
+
+# Check if there's a 'vrrp_instance' section with the given name
+vrrp_instance_check() {
+       local count=0
+       local name=$1
+       config_foreach vrrp_instance_name_count vrrp_instance $name
+       [ $count -gt 0 ] && return 0 || return 1
+}
+
+vrrp_sync_group() {
+       local group name
+       local valid_group
+
+       # No name for group, exit
+       config_get name $1 name
+       [ -z "$name" ] && return 0
+
+       # No members for group, exit
+       config_get group $1 group
+       [ -z "$group" ] && return 0
+
+       # Check if we have 'vrrp_instance's defined for 
+       # each member and remove names with not vrrp_instance defined
+       for m in $group; do
+               vrrp_instance_check $m && valid_group="$valid_group $m"
+       done
+       [ -z "$valid_group" ] && return 0
+
+       config_section_open "vrrp_sync_group" "$name"
+
+       group="$valid_group"
+       print_list_indent group
+
+       print_elems_indent $1 $INDENT_1 notify_backup notify_master notify_fault \
+               notify no_val_smtp_alert no_val_global_tracking
+       config_section_close
+}
+
+vrrp_instance() {
+       local name auth_type auth_pass
+
+       config_get name $1 name
+       [ -z "$name" ] && return 0
+
+       config_section_open "vrrp_instance" "$name"
+
+       # Handle virtual_ipaddress & virtual_ipaddress_excluded lists
+       for opt in virtual_ipaddress virtual_ipaddress_excluded; do
+               config_get $opt $1 $opt
+               eval optval=\$$opt
+               [ -z "$optval" ] && continue
+               printf "$INDENT_1$opt {\n" >> $KEEPALIVED_CONF
+               for a in $optval; do
+                       config_foreach print_ipaddress_indent ipaddress $a $INDENT_2
+               done
+               printf "$INDENT_1}\n" >> $KEEPALIVED_CONF
+       done
+
+       # Handle virtual_routes
+       for opt in virtual_routes; do
+               config_get $opt $1 $opt
+               eval optval=\$$opt
+               [ -z "$optval" ] && continue
+               printf "$INDENT_1$opt {\n" >> $KEEPALIVED_CONF
+               for r in $optval; do
+                       config_foreach print_route_indent route $r $INDENT_2
+               done
+               printf "$INDENT_1}\n" >> $KEEPALIVED_CONF
+       done
+
+       # Handle track_interface & track_script lists
+       for opt in track_interface track_script; do
+               config_get $opt $1 $opt
+               eval optval=\$$opt
+               [ -z "$optval" ] && continue
+               printf "$INDENT_1$opt {\n" >> $KEEPALIVED_CONF
+               for t in $optval; do
+                       config_foreach print_track_elem_indent $opt $t $INDENT_2
+               done
+               printf "$INDENT_1}\n" >> $KEEPALIVED_CONF
+       done
+
+       # Handle simple lists of strings (with no spaces in between)
+       for opt in unicast_peer; do
+               config_get $opt $1 $opt
+               print_list_indent $opt
+       done
+       unset optval
+
+       config_get auth_type $1 auth_type
+       config_get auth_pass $1 auth_pass
+       [ -n "$auth_type" -a -n "$auth_pass" ] && {
+               printf "${INDENT_1}authentication {\n" >> $KEEPALIVED_CONF
+               printf "${INDENT_2}auth_type $auth_type\n" >> $KEEPALIVED_CONF
+               printf "${INDENT_2}auth_pass $auth_pass\n" >> $KEEPALIVED_CONF
+               printf "$INDENT_1}\n" >> $KEEPALIVED_CONF
+       }
+
+       print_elems_indent $1 $INDENT_1 use_vmac state interface \
+               mcast_src_ip unicast_src_ip virtual_router_id version priority \
+               advert_int preempt_delay debug notify_backup \
+               notify_master notify_fault notify_stop notify \
+               lvs_sync_daemon_interface garp_master_delay garp_master_refresh \
+               garp_master_repeat garp_master_refresh_repeat \
+               no_val_vmac_xmit_base no_val_native_ipv6 no_val_accept \
+               no_val_dont_track_primary no_val_smtp_alert no_val_nopreempt
+
+       config_section_close
+}
+
+vrrp_script() {
+       local name
+
+       config_get name $1 name
+       [ -z "$name" ] && return 0
+
+       config_section_open "vrrp_script" "$name"
+
+       print_elems_indent $1 $INDENT_1 script interval weight fall rise
+
+       config_section_close
+}
+
+process_config() {
+       local alt_config_file
+
+       rm -f $KEEPALIVED_CONF
+
+       # First line
+       printf "! Configuration File for keepalived (autogenerated via init script)\n\n" > $KEEPALIVED_CONF
+
+       [ -f /etc/config/keepalived ] || return 0
+       config_load 'keepalived'
+
+       config_section_open "global_defs"
+       config_foreach_wrapper global_defs
+       config_section_close
+
+       # If "alt_config_file" specified, use that instead
+       [ -n "$alt_config_file" ] && [ -f "$alt_config_file" ] && {
+               rm -f $KEEPALIVED_CONF
+               # Symlink "alt_config_file" since it's a bit easier and safer
+               ln -s $alt_config_file $KEEPALIVED_CONF
+               return 0
+       }
+
+       config_section_open "static_ipaddress"
+       config_foreach_wrapper static_ipaddress
+       config_section_close
+
+       config_section_open "static_routes"
+       config_foreach_wrapper static_routes
+       config_section_close
+
+       config_foreach_wrapper vrrp_sync_group
+       config_foreach_wrapper vrrp_instance
+       config_foreach_wrapper vrrp_script
+       return 0
+}
+
+service_running() {
+       pgrep -x /usr/sbin/keepalived &> /dev/null
+}
+
+reload_service() {
+       running && {
+               process_config
+               # SIGHUP is used by keepalived to do init.d reload
+               # Get the oldest process (assumption is that it's the parent process)
+               PID=$(pgrep -o /usr/sbin/keepalived)
+               kill -SIGHUP $PID
+               return 0
+       }
+       return 1
+}
+
 start_service() {
        procd_open_instance
        procd_set_param command /usr/sbin/keepalived
        procd_append_param command -n # don't daemonize, procd will handle that for us
+       procd_append_param command -f "$KEEPALIVED_CONF"
+
+       process_config
 
        # set auto respawn behavior
        procd_set_param respawn
git clone https://git.99rst.org/PROJECT