packages/net/keepalived/files/keepalived.init
Jaymin Patel 33398a38aa keepalived: high-availability files and data sync
add new package keepalived-sync to synchronize files and data
between master and backup node. The master node uses SSH over rsync
to send and the backup node will use inotifywatch to watch received files.

The master node can track rsync.sh script to send configuration file on
a backup node based on the vrrp_script configuration of the same script.

The backup node will have a keepalived-inotify service, which would watch
for newly received files and it would call hotplug event. Each service
can keep its respective script under the keepalived hotplug directory and
executes commands to stop, start service or update any config in real-time.

Whenever a switchover will happen, the backup node would have the latest
config and data files from the master node.

Hotplug events can be used to apply config when files are received.

Signed-off-by: Jaymin Patel <jem.patel@gmail.com>
2022-10-13 16:57:02 +05:30

633 lines
16 KiB
Bash

#!/bin/sh /etc/rc.common
# Copyright (C) 2007-2015 OpenWrt.org
START=70
STOP=01
USE_PROCD=1
KEEPALIVED_CONF=/tmp/keepalived.conf
INDENT_1="\t"
INDENT_2="${INDENT_1}${INDENT_1}"
INDENT_3="${INDENT_1}${INDENT_1}${INDENT_1}"
INDENT_4="${INDENT_1}${INDENT_1}${INDENT_1}${INDENT_1}"
config_section_open() {
local tag="$1"
local name="$2"
printf '%s' "$tag" >> "$KEEPALIVED_CONF"
[ -n "$name" ] && printf ' %s' "$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 optval
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 '%b%s' "$indent" "$opt" >> "$KEEPALIVED_CONF"
[ "$no_val" = "0" ] && {
local words=0
words="$(echo "$optval" | wc -w)"
if [ "$words" -gt 1 ]; then
printf ' "%s"' "$optval" >> "$KEEPALIVED_CONF"
else
printf ' %s' "$optval" >> "$KEEPALIVED_CONF"
fi
}
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 '%b%s {\n' "$indent" "$lst" >> "$KEEPALIVED_CONF"
for e in $lst_elems; do
printf '%b%s\n' "${indent}${INDENT_1}" "$e">> "$KEEPALIVED_CONF"
done
printf '%b}\n' "$indent" >> "$KEEPALIVED_CONF"
}
print_notify() {
local type="$1"
shift
local name="$1"
shift
for notify in "$@"; do
printf '%b%s' "${INDENT_1}" "$notify">> "$KEEPALIVED_CONF"
notify="$(echo "$notify" | tr 'a-z' 'A-Z')"
printf ' "/bin/busybox env -i ACTION=%s TYPE=%s NAME=%s /sbin/hotplug-call keepalived"\n' "$notify" "$type" "$name" >> "$KEEPALIVED_CONF"
done
}
globals() {
local notification_email
printf '%bscript_user root\n' "${INDENT_1}" >> "$KEEPALIVED_CONF"
printf '%benable_script_security\n' "${INDENT_1}" >> "$KEEPALIVED_CONF"
printf '%bprocess_names\n' "${INDENT_1}" >> "$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 \
vrrp_startup_delay
}
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
config_get label_suffix "$section" label_suffix vip
# Default indent
[ -z "$indent" ] && indent="$INDENT_1"
# If no address exit
[ -z "$address" ] && return 0
if [ -z "$device" ]; then
printf '%b%s' "$indent" "$address" >> "$KEEPALIVED_CONF"
else
# Add IP address/netmask and device
printf '%b%s dev %s label %s' "$indent" "$address" "$device" "$device:$label_suffix" >> "$KEEPALIVED_CONF"
# Add scope
[ -n "$scope" ] && printf ' scope %s' "$scope" >> "$KEEPALIVED_CONF"
fi
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 '%bblackhole %s\n' "$indent" "$address" >> "$KEEPALIVED_CONF"
return 0
}
# Add src addr or address
if [ -n "$src_addr" ]; then
printf '%bsrc %s %s' "$indent" "$src_addr" "$address" >> "$KEEPALIVED_CONF"
else
[ -z "$device" ] && return 0
printf '%b%s' "$indent" "$address" >> "$KEEPALIVED_CONF"
fi
# Add route/gateway
[ -n "$gateway" ] && printf ' via %s' "$gateway" >> "$KEEPALIVED_CONF"
# Add device
printf ' dev %s' "$device" >> "$KEEPALIVED_CONF"
# Add scope
[ -n "$scope" ] && printf ' scope %s' "$scope" >> "$KEEPALIVED_CONF"
# Add table
[ -n "$table" ] && printf ' table %s' "$table" >> "$KEEPALIVED_CONF"
printf '\n' >> "$KEEPALIVED_CONF"
}
print_track_script_indent() {
local section="$1"
local curr_track_elem="$2"
local indent="$3"
local name value weight direction
config_get name "$section" name
[ "$name" != "$curr_track_elem" ] && return 0
config_get value "$section" value
config_get weight "$section" weight
config_get direction "$section" direction
[ -z "$value" ] && return 0
[ "$direction" != "reverse" ] && [ "$direction" != "noreverse" ] && unset direction
printf '%b%s' "$indent" "$value" >> "$KEEPALIVED_CONF"
[ -n "$weight" ] && printf ' weight %s' "$weight ${direction:+${direction}}" >> "$KEEPALIVED_CONF"
printf '\n' >> "$KEEPALIVED_CONF"
}
print_track_elem_indent() {
local section="$1"
local curr_track_elem="$2"
local indent="$3"
local 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 '%b%s' "$indent" "$value" >> "$KEEPALIVED_CONF"
[ -n "$weight" ] && printf ' weight %s' "$weight" >> "$KEEPALIVED_CONF"
printf '\n' >> "$KEEPALIVED_CONF"
}
print_track_bfd_indent() {
local section="$1"
local curr_track_elem="$2"
local indent="$3"
local name
config_get name "$section" name
[ "$name" != "$curr_track_elem" ] && return 0
config_get weight "$section" weight
printf '%b%s' "$indent" "$name" >> "$KEEPALIVED_CONF"
[ -n "$weight" ] && printf ' weight %s' "$weight" >> "$KEEPALIVED_CONF"
printf '\n' >> "$KEEPALIVED_CONF"
}
print_unicast_peer_indent() {
local section="$1"
local curr_track_elem="$2"
local indent="$3"
local name address
config_get name "$section" name
[ "$name" != "$curr_track_elem" ] && return 0
config_get address "$section" address
[ -z "$address" ] && return 0
printf '%b%s\n' "${indent}" "$address">> "$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" no_val_smtp_alert no_val_global_tracking
print_notify "GROUP" "$name" notify_backup notify_master \
notify_fault notify
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"
config_get auth_type "$1" auth_type
config_get auth_pass "$1" auth_pass
[ -n "$auth_type" ] && [ -n "$auth_pass" ] && {
printf '%bauthentication {\n' "${INDENT_1}" >> "$KEEPALIVED_CONF"
printf '%bauth_type %s\n' "${INDENT_2}" "$auth_type" >> "$KEEPALIVED_CONF"
printf '%bauth_pass %s\n' "${INDENT_2}" "$auth_pass" >> "$KEEPALIVED_CONF"
printf '%b}\n' "${INDENT_1}" >> "$KEEPALIVED_CONF"
}
print_elems_indent "$1" "$INDENT_1" state interface \
mcast_src_ip unicast_src_ip virtual_router_id version priority \
advert_int preempt_delay debug \
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 \
no_val_use_vmac
print_notify "INSTANCE" "$name" notify_backup notify_master \
notify_fault notify_stop
# 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 '%b%s {\n' "${INDENT_1}" "$opt" >> "$KEEPALIVED_CONF"
for a in $optval; do
config_foreach print_ipaddress_indent ipaddress "$a" "$INDENT_2"
done
printf '%b}\n' "${INDENT_1}" >> "$KEEPALIVED_CONF"
done
# Handle virtual_routes
for opt in virtual_routes; do
config_get "$opt" "$1" "$opt"
eval optval=\$$opt
[ -z "$optval" ] && continue
printf '%b%s {\n' "${INDENT_1}" "$opt" >> "$KEEPALIVED_CONF"
for r in $optval; do
config_foreach print_route_indent route "$r" "$INDENT_2"
done
printf '%b}\n' "${INDENT_1}" >> "$KEEPALIVED_CONF"
done
# Handle track_script lists
for opt in track_script; do
config_get "$opt" "$1" "$opt"
eval optval=\$$opt
[ -z "$optval" ] && continue
printf '%b%s {\n' "${INDENT_1}" "$opt" >> "$KEEPALIVED_CONF"
for t in $optval; do
config_foreach print_track_script_indent track_script "$t" "$INDENT_2"
done
printf '%b}\n' "${INDENT_1}" >> "$KEEPALIVED_CONF"
done
# Handle track_interface lists
for opt in track_interface; do
config_get "$opt" "$1" "$opt"
eval optval=\$$opt
[ -z "$optval" ] && continue
printf '%b%s {\n' "${INDENT_1}" "$opt" >> "$KEEPALIVED_CONF"
for t in $optval; do
config_foreach print_track_elem_indent track_interface "$t" "$INDENT_2"
done
printf '%b}\n' "${INDENT_1}" >> "$KEEPALIVED_CONF"
done
# Handle track_bfd lists
for opt in track_bfd; do
config_get "$opt" "$1" "$opt"
eval optval=\$$opt
[ -z "$optval" ] && continue
printf '%b%s {\n' "${INDENT_1}" "$opt" >> "$KEEPALIVED_CONF"
for t in $optval; do
config_foreach print_track_bfd_indent bfd_instance "$t" "$INDENT_2"
done
printf '%b}\n' "${INDENT_1}" >> "$KEEPALIVED_CONF"
done
# Handle simple lists of strings (with no spaces in between)
for opt in unicast_peer; do
config_get "$opt" "$1" "$opt"
eval optval=\$$opt
[ -z "$optval" ] && continue
printf '%b%s {\n' "${INDENT_1}" "$opt" >> "$KEEPALIVED_CONF"
for t in $optval; do
config_foreach print_unicast_peer_indent peer "$t" "$INDENT_2"
done
printf '%b}\n' "${INDENT_1}" >> "$KEEPALIVED_CONF"
done
unset optval
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
}
bfd_instance() {
local name
config_get name "$1" name
[ -z "$name" ] && return 0
config_section_open "bfd_instance" "$name"
print_elems_indent "$1" "$INDENT_1" neighbor_ip source_ip min_rx min_tx idle_tx hoplimit max_hops
config_section_close
}
url() {
local url="$2"
local name path digest
config_get name "$1" name
[ "$url" = "$name" ] || return 0
config_get path "$1" path
config_get digest "$1" digest
[ -n "$digest" ] && [ -n "$path" ] && {
printf '%burl {\n' "${INDENT_3}" >> "$KEEPALIVED_CONF"
printf '%bpath %s\n' "${INDENT_4}" "$path" >> "$KEEPALIVED_CONF"
printf '%bdigest %s\n' "${INDENT_4}" "$digest" >> "$KEEPALIVED_CONF"
printf '%b}\n' "${INDENT_3}" >> "$KEEPALIVED_CONF"
}
}
url_list() {
config_foreach url url "$1"
}
real_server() {
local server="$2"
local enabled name weight ipaddr port check
config_get_bool enabled "$1" enabled 1
[ "$enabled" -eq 1 ] || return 0
config_get name "$1" name
[ "$server" = "$name" ] || return 0
config_get weight "$1" weight
[ -n "$weight" ] || return 0
config_get ipaddr "$1" ipaddr
config_get port "$1" port
config_get check "$1" check
[ -n "$ipaddr" ] && [ -n "$port" ] && {
printf '%breal_server %s %d {\n' "${INDENT_1}" "$ipaddr" "$port" >> "$KEEPALIVED_CONF"
printf '%bweight %d\n' "${INDENT_2}" "$weight" >> "$KEEPALIVED_CONF"
case "$check" in
TCP_CHECK)
printf '%b%s {\n' "${INDENT_2}" "$check" >> "$KEEPALIVED_CONF"
print_elems_indent "$1" "$INDENT_3" connect_timeout \
connect_port
printf '%b}\n' "${INDENT_2}" >> "$KEEPALIVED_CONF"
;;
MISC_CHECK)
printf '%b%s {\n' "${INDENT_2}" "$check" >> "$KEEPALIVED_CONF"
print_elems_indent "$1" "$INDENT_3" misc_path
printf '%b}\n' "${INDENT_2}" >> "$KEEPALIVED_CONF"
;;
HTTP_GET | SSL_GET)
printf '%b%s {\n' "${INDENT_2}" "$check" >> "$KEEPALIVED_CONF"
print_elems_indent "$1" "$INDENT_3" connect_timeout \
connect_port nb_get_retry delay_before_retry
# Handle url list
config_list_foreach "$1" url url_list
printf '%b}\n' "${INDENT_2}" >> "$KEEPALIVED_CONF"
;;
esac
printf '%b}\n' "${INDENT_1}" >> "$KEEPALIVED_CONF"
}
}
real_server_list() {
config_foreach real_server real_server "$1"
}
virtual_server() {
local enabled ipaddr port lb_algo sorry_server_ip sorry_server_port
config_get_bool enabled "$1" enabled 1
[ "$enabled" -eq 1 ] || return 0
config_get ipaddr "$1" ipaddr
[ -z "$ipaddr" ] && return 0
config_get port "$1" port
[ -z "$port" ] && return 0
config_section_open "virtual_server" "$ipaddr $port"
print_elems_indent "$1" "$INDENT_1" fwmark delay_loop \
lb_kind persistence_timeout persistence_granularity \
virtualhost protocol
config_get lb_algo "$1" lb_algo
[ -z "$lb_algo" ] && lb_algo="rr"
modprobe ip_vs_${lb_algo} 1>/dev/null 2>&1
printf '%blb_algo %s\n' "${INDENT_1}" "${lb_algo}" >> "$KEEPALIVED_CONF"
config_get sorry_server_ip "$1" sorry_server_ip
config_get sorry_server_port "$1" sorry_server_port
[ -n "$sorry_server_ip" ] && [ -n "$sorry_server_port" ] && {
printf '%bsorry_server %s %s\n' "${INDENT_1}" "$sorry_server_ip" "$sorry_server_port" >> "$KEEPALIVED_CONF"
}
# Handle real_server list
config_list_foreach "$1" real_server real_server_list
config_section_close
}
process_config() {
local alt_config_file linkbeat_use_polling
rm -f "$KEEPALIVED_CONF"
# First line
printf '! Configuration file for keepalived (autogenerated via init script)\n' > "$KEEPALIVED_CONF"
printf '! Written %s\n\n' "$(date +'%c')" >> "$KEEPALIVED_CONF"
[ -f /etc/config/keepalived ] || return 0
config_load 'keepalived'
config_get alt_config_file globals alt_config_file
# 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_get_bool linkbeat_use_polling globals linkbeat_use_polling 0
[ "$linkbeat_use_polling" -gt 0 ] && printf 'linkbeat_use_polling\n\n' >> "$KEEPALIVED_CONF"
config_section_open "global_defs"
config_foreach_wrapper globals
config_section_close
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_script
config_foreach_wrapper bfd_instance
config_foreach_wrapper vrrp_sync_group
config_foreach_wrapper vrrp_instance
config_foreach_wrapper virtual_server
return 0
}
service_triggers() {
procd_add_reload_trigger "keepalived"
}
reload_service() {
process_config
#SIGHUP is used by keepalived to do init.d reload
procd_send_signal keepalived
}
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
procd_close_instance
}