Merge pull request #19374 from jempatel/improve_keepalived-uci-sync

keepalived: high-availability files and data sync
This commit is contained in:
Florian Eckert 2022-10-17 14:47:32 +02:00 committed by GitHub
commit 05b0d3fc12
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 912 additions and 15 deletions

View file

@ -274,4 +274,103 @@ endif
endef endef
define Package/keepalived-sync
SECTION:=net
CATEGORY:=Network
TITLE:=Keepalived Master and Backup Synchronization
DEPENDS:= +keepalived +rsync +inotifywait +sudo +@BUSYBOX_CUSTOM +@BUSYBOX_CONFIG_TIMEOUT
endef
define Package/keepalived-sync/description
Keepalived HA with Master to Backup files and data Synchronization
endef
define Package/keepalived-sync/conffiles
/etc/keepalived/scripts
/etc/keepalived/keys
endef
define Package/keepalived-sync/install
$(INSTALL_DIR) $(1)/etc/init.d
$(INSTALL_BIN) ./files/etc/init.d/keepalived-inotify \
$(1)/etc/init.d/keepalived-inotify
$(INSTALL_DIR) $(1)/usr/share/keepalived/scripts
$(INSTALL_BIN) ./files/usr/share/keepalived/scripts/rsync.sh \
$(1)/usr/share/keepalived/scripts/rsync.sh
$(INSTALL_DIR) $(1)/etc/keepalived/scripts
$(LN) /usr/share/keepalived/scripts/rsync.sh \
$(1)/etc/keepalived/scripts/rsync.sh
$(INSTALL_DIR) $(1)/usr/bin
$(INSTALL_BIN) ./files/usr/bin/keepalived-rsync-inotify \
$(1)/usr/bin/keepalived-rsync-inotify
$(INSTALL_DIR) $(1)/lib/functions/keepalived
$(INSTALL_DATA) ./files/lib/functions/keepalived/hotplug.sh \
$(1)/lib/functions/keepalived/hotplug.sh
$(INSTALL_DATA) ./files/lib/functions/keepalived/common.sh \
$(1)/lib/functions/keepalived/common.sh
$(INSTALL_DIR) $(1)/usr/libexec/keepalived/rpc
$(INSTALL_DATA) ./files/usr/libexec/keepalived/rpc/sync.sh \
$(1)/usr/libexec/keepalived/rpc/sync.sh
$(INSTALL_DIR) $(1)/etc/hotplug.d/keepalived
$(CP) ./files/etc/hotplug.d/keepalived/* \
$(1)/etc/hotplug.d/keepalived
endef
USER=keepalived
USER_ID=60001
USER_HOME=/usr/share/keepalived/rsync
SUDO_DIR=/etc/sudoers.d
SUDO_FILE=$(SUDO_DIR)/$(USER)
KEYS_DIR=/etc/keepalived/keys
define Package/keepalived-sync/postinst
#!/bin/sh
mkdir -p "$${IPKG_INSTROOT}/etc/uci-defaults"
DEFAULT_SCRIPT="$${IPKG_INSTROOT}/etc/uci-defaults/99-keepalived-sync"
cat << EOF > $${DEFAULT_SCRIPT}
#!/bin/sh
. /lib/functions.sh
mkdir -p $(KEYS_DIR)
group_add "$(USER)" "$(USER_ID)"
user_add "$(USER)" "$(USER_ID)" "$(USER_ID)" "$(USER)" "$(USER_HOME)" "/bin/ash"
mkdir -m 700 -p "$(USER_HOME)"
mkdir -m 700 -p "$(USER_HOME)/.ssh"
chown "$(USER)":"$(USER)" "$(USER_HOME)" -R
[ ! -d "$(SUDO_DIR)" ] && mkdir "$(SUDO_DIR)"
echo "$(USER) ALL= NOPASSWD:/usr/bin/rsync" > "$(SUDO_FILE)"
EOF
[ -z "$${IPKG_INSTROOT}" ] && [ -f "$${DEFAULT_SCRIPT}" ] && sh "$${DEFAULT_SCRIPT}"
exit 0
endef
define Package/keepalived-sync/postrm
#!/bin/sh
[ -n "$${IPKG_INSTROOT}" ] && exit 0
[ -d "$(KEYS_DIR)" ] && rm -rf "$(KEYS_DIR)"
[ -d "$(USER_HOME)" ] && rm -rf "$(USER_HOME)"
[ -f "$(SUDO_FILE)" ] && rm -f "$(SUDO_FILE)"
sed -i -e "/^$(USER):/d" /etc/passwd /etc/shadow /etc/group
exit 0
endef
$(eval $(call BuildPackage,keepalived)) $(eval $(call BuildPackage,keepalived))
$(eval $(call BuildPackage,keepalived-sync))

View file

@ -0,0 +1,12 @@
#!/bin/sh
# shellcheck source=/dev/null
. /lib/functions/keepalived/hotplug.sh
set_service_name rpcd
set_reload_if_sync
add_sync_file /etc/config/rpcd
keepalived_hotplug

View file

@ -0,0 +1,12 @@
#!/bin/sh
# shellcheck source=/dev/null
. /lib/functions/keepalived/hotplug.sh
set_service_name system
set_reload_if_sync
add_sync_file /etc/config/system
keepalived_hotplug

View file

@ -0,0 +1,12 @@
#!/bin/sh
# shellcheck source=/dev/null
. /lib/functions/keepalived/hotplug.sh
set_service_name ucitrack
set_reload_if_sync
add_sync_file /etc/config/ucitrack
keepalived_hotplug

View file

@ -0,0 +1,12 @@
#!/bin/sh
# shellcheck source=/dev/null
. /lib/functions/keepalived/hotplug.sh
set_service_name firewall
set_reload_if_sync
add_sync_file /etc/config/firewall
keepalived_hotplug

View file

@ -0,0 +1,15 @@
#!/bin/sh
# shellcheck source=/dev/null
. /lib/functions/keepalived/hotplug.sh
set_service_name dnsmasq
set_restart_if_master
set_stop_if_backup
set_reload_if_sync
add_sync_file /etc/config/dhcp
add_sync_file /tmp/dhcp.leases
keepalived_hotplug

View file

@ -0,0 +1,15 @@
#!/bin/sh
# shellcheck source=/dev/null
. /lib/functions/keepalived/hotplug.sh
set_service_name dropbear
set_reload_if_backup
set_reload_if_sync
add_sync_file /etc/config/dropbear
add_sync_file /etc/dropbear/dropbear_ed25519_host_key
add_sync_file /etc/dropbear/dropbear_rsa_host_key
keepalived_hotplug

View file

@ -0,0 +1,14 @@
#!/bin/sh
# shellcheck source=/dev/null
. /lib/functions/keepalived/hotplug.sh
set_service_name uhttpd
set_restart_if_sync
add_sync_file /etc/config/uhttpd
add_sync_file /etc/uhttpd.crt
add_sync_file /etc/uhttpd.key
keepalived_hotplug

View file

@ -0,0 +1,8 @@
#!/bin/sh
# shellcheck source=/dev/null
. /lib/functions/keepalived/hotplug.sh
add_sync_file /etc/config/luci
keepalived_hotplug

View file

@ -0,0 +1,18 @@
#!/bin/sh
# shellcheck source=/dev/null
. /lib/functions/keepalived/hotplug.sh
add_sync_file /etc/group
add_sync_file /etc/hosts
add_sync_file /etc/inittab
add_sync_file /etc/passwd
add_sync_file /etc/rc.local
add_sync_file /etc/profile
add_sync_file /etc/shadow
add_sync_file /etc/shell
add_sync_file /etc/shinit
add_sync_file /etc/sysctl.conf
add_sync_file /tmp/dhcp.leases
keepalived_hotplug

View file

@ -0,0 +1,65 @@
#!/bin/sh /etc/rc.common
START=99
USE_PROCD=1
PROG="/usr/bin/keepalived-rsync-inotify"
KEEPALIVED_USER=keepalived
KEEPALIVED_HOME=$(awk -F: "/^$KEEPALIVED_USER/{print \$6}" /etc/passwd)
start_instance() {
local cfg=$1
local vrrp_instance=$2
local peer=$3
config_get name $cfg name
[ -z "$name" ] && return
[ "$name" != "$peer" ] && return
config_get sync $cfg sync 0
[ "$sync" = "0" ] && return
config_get sync_mode $cfg sync_mode
[ "$sync_mode" != "receive" ] && return
config_get sync_dir $cfg sync_dir $KEEPALIVED_HOME
[ -z "$sync_dir" ] && return
[ ! -d "$sync_dir" ] && mkdir -m 755 -p "$sync_dir"
procd_open_instance "$name"
procd_set_param command /bin/sh "$PROG" "$vrrp_instance" "$name" "$sync_dir"
procd_set_param pidfile /var/run/keepalived-inotify-$name.pid
procd_close_instance
}
process_unicast_peer() {
local peer=$1
local vrrp_instance=$2
config_foreach start_instance peer "$vrrp_instance" "$peer"
}
process_vrrp_instance() {
local cfg=$1
local peer_instance=$2
local name unicast_peer
config_get name $cfg name
config_get unicast_peer $cfg unicast_peer
if [ -n "$peer_instance" ]; then
list_contains unicast_peer "$peer_instance" || return
process_unicast_peer "$peer_instance" "$name"
else
config_list_foreach $cfg unicast_peer process_unicast_peer "$name"
fi
}
start_service() {
local peer_instance=$1
config_load keepalived
config_foreach process_vrrp_instance vrrp_instance "$peer_instance"
}

View file

@ -256,6 +256,21 @@ print_track_bfd_indent() {
printf '\n' >> "$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() { static_routes() {
local route local route
config_get route "$1" route config_get route "$1" route
@ -403,7 +418,13 @@ vrrp_instance() {
# Handle simple lists of strings (with no spaces in between) # Handle simple lists of strings (with no spaces in between)
for opt in unicast_peer; do for opt in unicast_peer; do
config_get "$opt" "$1" "$opt" config_get "$opt" "$1" "$opt"
print_list_indent "$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 done
unset optval unset optval

View file

@ -0,0 +1,47 @@
#!/bin/sh
# shellcheck disable=SC2039
__FILE__="$(basename "$0")"
KEEPALIVED_USER=keepalived
KEEPALIVED_DEBUG=0
__function__() {
type "$1" > /dev/null 2>&1
}
log() {
local facility=$1
shift
logger -t "${__FILE__}[$$]" -p "$facility" "$*"
}
log_info() {
log info "$*"
}
log_debug() {
[ "$KEEPALIVED_DEBUG" = "0" ] && return
log debug "$*"
}
log_notice() {
log notice "$*"
}
log_warn() {
log warn "$*"
}
log_err() {
log err "$*"
}
get_rsync_user() {
echo "$KEEPALIVED_USER"
}
get_rsync_user_home() {
awk -F: "/^$KEEPALIVED_USER/{print \$6}" /etc/passwd
}

View file

@ -0,0 +1,257 @@
#!/bin/sh
# shellcheck disable=SC2039
# shellcheck source=/dev/null
. /lib/functions/keepalived/common.sh
set_var() {
export "$1=$2"
}
get_var() {
eval echo "\"\${${1}}\""
}
get_var_flag() {
local value
value=$(get_var "$1")
value=${value:-0}
[ "$value" = "0" ] && return 1
return 0
}
_service() {
[ -z "$SERVICE_NAME" ] && return
local rc="/etc/init.d/$SERVICE_NAME"
[ ! -x "$rc" ] && return
case $1 in
start) $rc running || $rc start ;;
stop) $rc running && $rc stop ;;
reload)
if $rc running; then
$rc reload
else
$rc start
fi
;;
restart)
if $rc running; then
$rc restart
else
$rc start
fi
;;
esac
}
_start_service() {
_service start
}
_stop_service() {
_service stop
}
_restart_service() {
_service restart
}
_reload_service() {
_service reload
}
set_service_name() {
set_var SERVICE_NAME "$1"
}
add_sync_file() {
append SYNC_FILES_LIST "$1"
}
is_sync_file() {
list_contains SYNC_FILES_LIST "$1"
}
set_update_target() {
set_var UPDATE_TARGET "${1:-1}"
}
get_update_target() {
get_var UPDATE_TARGET
}
unset_update_target() {
set_var UPDATE_TARGET
}
is_update_target() {
get_var_flag UPDATE_TARGET
}
set_master_cb() {
set_var MASTER_CB "$1"
}
get_master_cb() {
get_var MASTER_CB
}
set_backup_cb() {
set_var BACKUP_CB "$1"
}
get_backup_cb() {
get_var BACKUP_CB
}
set_fault_cb() {
set_var FAULT_CB "$1"
}
get_fault_cb() {
get_var FAULT_CB
}
set_sync_cb() {
set_var SYNC_CB "$1"
}
get_sync_cb() {
get_var SYNC_CB
}
set_reload_if_master() {
set_var NOTIFY_MASTER_RELOAD 1
}
master_and_reload() {
get_var_flag NOTIFY_MASTER_RELOAD
}
set_restart_if_master() {
set_var NOTIFY_MASTER_RESTART 1
}
master_and_restart() {
get_var_flag NOTIFY_MASTER_RESTART
}
set_reload_if_backup() {
set_var NOTIFY_BACKUP_RELOAD 1
}
backup_and_reload() {
get_var_flag NOTIFY_BACKUP_RELOAD
}
set_stop_if_backup() {
set_var NOTIFY_BACKUP_STOP 1
}
backup_and_stop() {
get_var_flag NOTIFY_BACKUP_STOP 1
}
set_reload_if_sync() {
set_var NOTIFY_SYNC_RELOAD "${1:-1}"
}
get_reload_if_sync() {
get_var NOTIFY_SYNC_RELOAD
}
sync_and_reload() {
get_var_flag NOTIFY_SYNC_RELOAD
}
set_restart_if_sync() {
set_var NOTIFY_SYNC_RESTART 1
}
sync_and_restart() {
get_var_flag NOTIFY_SYNC_RESTART
}
_notify_master() {
if master_and_reload; then
log_debug "reload service $SERVICE_NAME"
_reload_service
elif master_and_restart; then
log_debug "restart service $SERVICE_NAME"
_restart_service
fi
}
_notify_backup() {
if backup_and_stop; then
log_debug "stop service $SERVICE_NAME"
_stop_service
elif backup_and_reload; then
log_debug "restart service $SERVICE_NAME"
_restart_service
fi
}
_notify_fault() {
return 0
}
_notify_sync() {
[ -z "$RSYNC_SOURCE" ] && return
[ -z "$RSYNC_TARGET" ] && return
if ! is_update_target; then
log_notice "skip $RSYNC_TARGET. Update target not set. To set use \"set_update_target 1\""
return
fi
is_sync_file "$RSYNC_TARGET" || return
if ! cp -a "$RSYNC_SOURCE" "$RSYNC_TARGET"; then
log_err "can not copy $RSYNC_SOURCE => $RSYNC_TARGET"
return
fi
log_debug "updated $RSYNC_SOURCE to $RSYNC_TARGET"
if sync_and_reload; then
log_debug "reload service $SERVICE_NAME"
_reload_service
elif sync_and_restart; then
log_debug "restart service $SERVICE_NAME"
_restart_service
fi
}
call_cb() {
[ $# -eq 0 ] && return
if __function__ "$1"; then
log_debug "calling function \"$1\""
"$1"
else
log_err "function \"$1\" not defined"
fi
}
keepalived_hotplug() {
[ -z "$(get_master_cb)" ] && set_master_cb _notify_master
[ -z "$(get_backup_cb)" ] && set_backup_cb _notify_backup
[ -z "$(get_fault_cb)" ] && set_fault_cb _notify_fault
[ -z "$(get_sync_cb)" ] && set_sync_cb _notify_sync
[ -z "$(get_update_target)" ] && set_update_target "$@"
[ -z "$(get_reload_if_sync)" ] && set_reload_if_sync "$@"
case $ACTION in
NOTIFY_MASTER) call_cb "$(get_master_cb)" ;;
NOTIFY_BACKUP) call_cb "$(get_backup_cb)" ;;
NOTIFY_FAULT) call_cb "$(get_fault_cb)" ;;
NOTIFY_SYNC) call_cb "$(get_sync_cb)" ;;
esac
}

View file

@ -0,0 +1,54 @@
#!/bin/sh
# shellcheck shell=ash
# shellcheck source=/dev/null
. /lib/functions/keepalived/common.sh
if [ $# -lt 3 ]; then
echo "$0 <vrrp_instance> <peer> <rsync_dir>"
exit 1
fi
VRRP_INSTANCE=$1
PEER=$2
RSYNC_DIR=$3
INOTIFY_ACTIONS="create,delete,modify,move,moved_to,moved_from"
INOTIFY_PID=""
TMP_DIR=/tmp/keepalived
FIFO_FILE="$TMP_DIR"/inotifywait-$PEER.fifo
daemonize_inotifywait() {
/usr/bin/inotifywait -q -r --exclude '/\..+' -o "$FIFO_FILE" -m "$RSYNC_DIR" -e ${INOTIFY_ACTIONS} 2> /dev/null &
INOTIFY_PID="$!"
}
main() {
local inotify_action inotify_dir inotify_file
local source_file target_file
[ ! -d "$TMP_DIR" ] && mkdir "$TMP_DIR"
mkfifo "${FIFO_FILE}" || exit 1
daemonize_inotifywait
while read -r inotify_dir inotify_action inotify_file; do
source_file="${inotify_dir}${inotify_file}"
target_file=$(echo "${inotify_dir}" | sed -e "s:${RSYNC_DIR}::g")"${inotify_file}"
log_debug "received $target_file ($inotify_action) in $source_file"
ACTION=NOTIFY_SYNC TYPE=peer NAME=$PEER INSTANCE=$VRRP_INSTANCE \
RSYNC_SOURCE="${source_file}" RSYNC_TARGET="${target_file}" \
/sbin/hotplug-call keepalived
done < "$FIFO_FILE"
}
TRAP() {
[ -n "$INOTIFY_PID" ] && kill "$INOTIFY_PID"
[ -e "$FIFO_FILE" ] && rm -f "$FIFO_FILE"
}
trap TRAP TERM INT
main "$@"

View file

@ -0,0 +1,59 @@
#!/bin/sh
# shellcheck disable=SC2039
# shellcheck source=/dev/null
. /usr/share/libubox/jshn.sh
# shellcheck source=/dev/null
. /lib/functions.sh
peer() {
local cfg=$1
local c_name=$2
local name last_sync_time last_sync_status
config_get name "$cfg" name
[ "$name" != "$c_name" ] && return
config_get last_sync_time "$cfg" last_sync_time 0
config_get last_sync_status "$cfg" last_sync_status NA
json_add_object unicast_peer
json_add_string name "$name"
json_add_int time "$last_sync_time"
json_add_string status "$last_sync_status"
json_close_array
}
unicast_peer() {
config_foreach peer peer "$1"
}
vrrp_instance() {
local cfg=$1
local name
config_get name "$cfg" name
json_add_object vrrp_instance
json_add_string name "$name"
json_add_array unicast_peer
config_list_foreach "$cfg" unicast_peer unicast_peer
json_close_array
json_close_object
}
rsync_status() {
config_load keepalived
json_init
json_add_array vrrp_instance
config_foreach vrrp_instance vrrp_instance
json_close_array
json_dump
}
sync_help() {
json_add_object rsync_status
json_close_object
}

View file

@ -1,6 +1,10 @@
#!/bin/sh #!/bin/sh
# shellcheck disable=SC2039
# shellcheck source=/dev/null
. /lib/functions.sh . /lib/functions.sh
# shellcheck source=/dev/null
. /usr/share/libubox/jshn.sh . /usr/share/libubox/jshn.sh
RPC_SCRIPTS=/usr/libexec/keepalived/rpc RPC_SCRIPTS=/usr/libexec/keepalived/rpc
@ -16,21 +20,22 @@ foreach_extra() {
[ ! -d $RPC_SCRIPTS ] && return [ ! -d $RPC_SCRIPTS ] && return
for file in $RPC_SCRIPTS/*; do for file in "$RPC_SCRIPTS"/*; do
obj="${file##*/}" obj="${file##*/}"
$1 "${obj%%.*}" $1 "${obj%%.*}"
done done
} }
keepalived_dump() { keepalived_dump() {
local stats_file="/tmp/keepalived.json" local stats_file pids
local pids
stats_file="/tmp/keepalived.json"
[ -f "$stats_file" ] && rm -f "$stats_file" [ -f "$stats_file" ] && rm -f "$stats_file"
pids=$(pidof /usr/sbin/keepalived) pids=$(pidof /usr/sbin/keepalived)
if [ -n "$pids" ]; then if [ -n "$pids" ]; then
kill -37 $pids > /dev/null 2>&1 kill -37 "$pids" > /dev/null 2>&1
json_load "{ \"status\" : $(cat $stats_file) }" json_load "{ \"status\" : $(cat $stats_file) }"
else else
json_init json_init
@ -50,21 +55,28 @@ call_extra() {
} }
call_method() { call_method() {
case "$1" in local cmd=$1
case "$cmd" in
dump) dump)
keepalived_dump keepalived_dump
;; ;;
*) *)
call_extra $1 call_extra "$cmd"
;; ;;
esac esac
} }
list_extra() { list_extra() {
if __function__ "${1}_help"; then local arg func
${1}_help
arg=$1
func="${arg}_help"
if __function__ "$func"; then
$func
else else
json_add_object "$1" json_add_object "$arg"
json_close_object json_close_object
fi fi
} }
@ -77,18 +89,21 @@ list_methods() {
json_add_object dump json_add_object dump
json_close_object json_close_object
foreach_extra list_extra ${1} foreach_extra list_extra "${1}"
json_dump json_dump
} }
main () { main() {
case "$1" in local cmd=$1
shift
case "$cmd" in
list) list)
list_methods list_methods "$@"
;; ;;
call) call)
call_method $2 call_method "$@"
;; ;;
esac esac
} }

View file

@ -0,0 +1,162 @@
#!/bin/sh
# shellcheck disable=SC2039
# shellcheck source=/dev/null
. /lib/functions.sh
# shellcheck source=/dev/null
. /lib/functions/keepalived/common.sh
RSYNC_USER=$(get_rsync_user)
RSYNC_HOME=$(get_rsync_user_home)
utc_timestamp() {
date -u +%s
}
update_last_sync_time() {
uci_revert_state keepalived "$1" last_sync_time
uci_set_state keepalived "$1" last_sync_time "$(utc_timestamp)"
}
update_last_sync_status() {
local cfg="$1"
shift
local status="$*"
uci_revert_state keepalived "$cfg" last_sync_status
uci_set_state keepalived "$cfg" last_sync_status "$status"
}
ha_sync_send() {
local cfg=$1
local address ssh_key ssh_port sync_list sync_dir sync_file count
local ssh_options ssh_remote dirs_list files_list
local changelog="/tmp/changelog"
config_get address "$cfg" address
[ -z "$address" ] && return 0
config_get ssh_port "$cfg" ssh_port 22
config_get sync_dir "$cfg" sync_dir "$RSYNC_HOME"
[ -z "$sync_dir" ] && return 0
config_get ssh_key "$cfg" ssh_key "$sync_dir"/.ssh/id_rsa
config_get sync_list "$cfg" sync_list
for sync_file in $sync_list $(sysupgrade -l); do
[ -f "$sync_file" ] && {
dir="${sync_file%/*}"
list_contains files_list "${sync_file}" || append files_list "${sync_file}"
}
[ -d "$sync_file" ] && dir="${sync_file}"
list_contains dirs_list "${sync_dir}${dir}" || append dirs_list "${sync_dir}${dir}"
done
ssh_options="-y -y -i $ssh_key -p $ssh_port"
ssh_remote="$RSYNC_USER@$address"
# shellcheck disable=SC2086
timeout 10 ssh $ssh_options $ssh_remote mkdir -m 755 -p "$dirs_list /tmp" || {
log_err "can not connect to $address. check key or connection"
update_last_sync_time "$cfg"
update_last_sync_status "$cfg" "SSH Connection Failed"
return 0
}
# shellcheck disable=SC2086
if rsync --out-format='%n' --dry-run -a --relative ${files_list} -e "ssh $ssh_options" --rsync-path="sudo rsync" "$ssh_remote":"$sync_dir" > "$changelog"; then
count=$(wc -l "$changelog")
if [ "${count%% *}" = "0" ]; then
log_debug "all files are up to date"
update_last_sync_time "$cfg"
update_last_sync_status "$cfg" "Up to Date"
return 0
fi
else
log_err "rsync dry run failed for $address"
update_last_sync_time "$cfg"
update_last_sync_status "$cfg" "Rsync Detection Failed"
return 0
fi
# shellcheck disable=SC2086
rsync -a --relative ${files_list} ${changelog} -e "ssh $ssh_options" --rsync-path="sudo rsync" "$ssh_remote":"$sync_dir" || {
log_err "rsync transfer failed for $address"
update_last_sync_time "$cfg"
update_last_sync_status "$cfg" "Rsync Transfer Failed"
}
log_info "keepalived sync is compeleted for $address"
update_last_sync_time "$cfg"
update_last_sync_status "$cfg" "Successful"
}
ha_sync_receive() {
local cfg=$1
local ssh_pubkey
local name auth_file home_dir
config_get name "$cfg" name
config_get sync_dir "$cfg" sync_dir "$RSYNC_HOME"
[ -z "$sync_dir" ] && return 0
config_get ssh_pubkey "$cfg" ssh_pubkey
[ -z "$ssh_pubkey" ] && return 0
home_dir=$sync_dir
auth_file="$home_dir/.ssh/authorized_keys"
if ! grep -q "^$ssh_pubkey$" "$auth_file" 2> /dev/null; then
log_notice "public key not found. Updating"
echo "$ssh_pubkey" > "$auth_file"
chown "$RSYNC_USER":"$RSYNC_USER" "$auth_file"
fi
/etc/init.d/keepalived-inotify enabled || /etc/init.d/keepalived-inotify enable
/etc/init.d/keepalived-inotify running "$name" || /etc/init.d/keepalived-inotify start "$name"
}
ha_sync_each_peer() {
local cfg="$1"
local c_name="$2"
local name sync sync_mode
config_get name "$cfg" name
[ "$name" != "$c_name" ] && return 0
config_get sync "$cfg" sync 0
[ "$sync" = "0" ] && return 0
config_get sync_mode "$cfg" sync_mode
[ -z "$sync_mode" ] && return 0
case "$sync_mode" in
send) ha_sync_send "$cfg" ;;
receive) ha_sync_receive "$cfg" ;;
esac
}
ha_sync_peers() {
config_foreach ha_sync_each_peer peer "$1"
}
ha_sync() {
config_list_foreach "$1" unicast_peer ha_sync_peers
}
main() {
local lockfile="/var/lock/keepalived-rsync.lock"
if ! lock -n "$lockfile" > /dev/null 2>&1; then
log_info "another process is already running"
return 1
fi
config_load keepalived
config_foreach ha_sync vrrp_instance
lock -u "$lockfile"
return 0
}
main "$@"