maybe chmod 0755 'cron.daily/mdadm'
maybe chmod 0755 'cron.daily/mlocate'
maybe chmod 0755 'cron.daily/passwd'
+maybe chmod 0755 'cron.daily/samba'
maybe chmod 0755 'cron.daily/ubuntu-advantage-tools'
maybe chmod 0755 'cron.daily/update-notifier-common'
maybe chmod 0755 'cron.hourly'
maybe chmod 0644 'cruft/filters-unex/etckeeper'
maybe chmod 0755 'cryptsetup-initramfs'
maybe chmod 0644 'cryptsetup-initramfs/conf-hook'
+maybe chmod 0755 'ctdb'
+maybe chmod 0755 'ctdb/ctdb-crash-cleanup.sh'
+maybe chmod 0644 'ctdb/ctdbd.conf'
+maybe chmod 0755 'ctdb/debug-hung-script.sh'
+maybe chmod 0755 'ctdb/debug_locks.sh'
+maybe chmod 0755 'ctdb/events.d'
+maybe chmod 0755 'ctdb/events.d/00.ctdb'
+maybe chmod 0755 'ctdb/events.d/01.reclock'
+maybe chmod 0755 'ctdb/events.d/05.system'
+maybe chmod 0755 'ctdb/events.d/06.nfs'
+maybe chmod 0644 'ctdb/events.d/10.external'
+maybe chmod 0755 'ctdb/events.d/10.interface'
+maybe chmod 0755 'ctdb/events.d/11.natgw'
+maybe chmod 0755 'ctdb/events.d/11.routing'
+maybe chmod 0755 'ctdb/events.d/13.per_ip_routing'
+maybe chmod 0755 'ctdb/events.d/20.multipathd'
+maybe chmod 0755 'ctdb/events.d/31.clamd'
+maybe chmod 0755 'ctdb/events.d/40.vsftpd'
+maybe chmod 0755 'ctdb/events.d/41.httpd'
+maybe chmod 0755 'ctdb/events.d/49.winbind'
+maybe chmod 0755 'ctdb/events.d/50.samba'
+maybe chmod 0755 'ctdb/events.d/60.nfs'
+maybe chmod 0755 'ctdb/events.d/70.iscsi'
+maybe chmod 0755 'ctdb/events.d/91.lvs'
+maybe chmod 0755 'ctdb/events.d/99.timeout'
+maybe chmod 0644 'ctdb/events.d/README'
+maybe chmod 0644 'ctdb/functions'
+maybe chmod 0755 'ctdb/gcore_trace.sh'
+maybe chmod 0755 'ctdb/nfs-checks.d'
+maybe chmod 0644 'ctdb/nfs-checks.d/00.portmapper.check'
+maybe chmod 0644 'ctdb/nfs-checks.d/10.status.check'
+maybe chmod 0644 'ctdb/nfs-checks.d/20.nfs.check'
+maybe chmod 0644 'ctdb/nfs-checks.d/30.nlockmgr.check'
+maybe chmod 0644 'ctdb/nfs-checks.d/40.mountd.check'
+maybe chmod 0644 'ctdb/nfs-checks.d/50.rquotad.check'
+maybe chmod 0644 'ctdb/nfs-checks.d/README'
+maybe chmod 0755 'ctdb/nfs-linux-kernel-callout'
+maybe chmod 0755 'ctdb/notify.d'
+maybe chmod 0644 'ctdb/notify.d/README'
+maybe chmod 0755 'ctdb/notify.sh'
+maybe chmod 0755 'ctdb/statd-callout'
maybe chgrp 'lp' 'cups'
maybe chmod 0755 'cups'
maybe chmod 0644 'cups/cups-browsed.conf'
maybe chmod 0644 'default/useradd'
maybe chmod 0644 'default/virtlockd'
maybe chmod 0644 'default/virtlogd'
+maybe chmod 0644 'default/winbind'
maybe chmod 0644 'deluser.conf'
maybe chmod 0755 'depmod.d'
maybe chmod 0644 'depmod.d/ubuntu.conf'
maybe chmod 0755 'init.d/cron'
maybe chmod 0755 'init.d/cryptdisks'
maybe chmod 0755 'init.d/cryptdisks-early'
+maybe chmod 0755 'init.d/ctdb'
maybe chmod 0755 'init.d/cups'
maybe chmod 0755 'init.d/cups-browsed'
maybe chmod 0755 'init.d/dbus'
maybe chmod 0755 'init.d/netfilter-persistent'
maybe chmod 0755 'init.d/network-manager'
maybe chmod 0755 'init.d/networking'
+maybe chmod 0755 'init.d/nmbd'
maybe chmod 0755 'init.d/openvpn'
maybe chmod 0755 'init.d/plymouth'
maybe chmod 0755 'init.d/plymouth-log'
maybe chmod 0755 'init.d/procps'
maybe chmod 0755 'init.d/rsync'
maybe chmod 0755 'init.d/rsyslog'
+maybe chmod 0755 'init.d/samba-ad-dc'
maybe chmod 0755 'init.d/saned'
maybe chmod 0755 'init.d/screen-cleanup'
maybe chmod 0755 'init.d/smartmontools'
+maybe chmod 0755 'init.d/smbd'
maybe chmod 0755 'init.d/speech-dispatcher'
maybe chmod 0755 'init.d/ssh'
maybe chmod 0755 'init.d/udev'
maybe chmod 0755 'init.d/ufw'
maybe chmod 0755 'init.d/uuidd'
maybe chmod 0755 'init.d/virtlogd'
+maybe chmod 0755 'init.d/winbind'
maybe chmod 0755 'init.d/x11-common'
maybe chmod 0644 'init/anacron.conf'
maybe chmod 0644 'init/lightdm.conf'
maybe chmod 0644 'logrotate.d/aptitude'
maybe chmod 0644 'logrotate.d/btmp'
maybe chmod 0644 'logrotate.d/chrony'
+maybe chmod 0644 'logrotate.d/ctdb'
maybe chmod 0644 'logrotate.d/cups-daemon'
maybe chmod 0644 'logrotate.d/dpkg'
maybe chmod 0644 'logrotate.d/libvirtd'
maybe chmod 0644 'logrotate.d/pm-utils'
maybe chmod 0644 'logrotate.d/ppp'
maybe chmod 0644 'logrotate.d/rsyslog'
+maybe chmod 0644 'logrotate.d/samba'
maybe chmod 0644 'logrotate.d/speech-dispatcher'
maybe chmod 0644 'logrotate.d/ufw'
+maybe chmod 0644 'logrotate.d/winbind'
maybe chmod 0644 'logrotate.d/wtmp'
maybe chmod 0644 'lsb-release'
maybe chmod 0644 'ltrace.conf'
maybe chmod 0755 'sudoers.d'
maybe chmod 0440 'sudoers.d/0pwfeedback'
maybe chmod 0440 'sudoers.d/README'
+maybe chmod 0440 'sudoers.d/ctdb'
maybe chmod 0440 'sudoers.d/mintupdate'
maybe chmod 0644 'sysctl.conf'
maybe chmod 0755 'sysctl.d'
maybe chmod 0644 'ufw/applications.d/cups'
maybe chmod 0644 'ufw/applications.d/openssh-server'
maybe chmod 0644 'ufw/applications.d/postfix'
+maybe chmod 0644 'ufw/applications.d/samba'
maybe chmod 0640 'ufw/before.init'
maybe chmod 0640 'ufw/before.rules'
maybe chmod 0640 'ufw/before6.rules'
--- /dev/null
+/usr/bin/tdbbackup.tdbtools
\ No newline at end of file
--- /dev/null
+/usr/share/man/man8/tdbbackup.tdbtools.8.gz
\ No newline at end of file
--- /dev/null
+#!/bin/sh
+#
+# cron script to save a backup copy of /etc/samba/smbpasswd in /var/backups.
+#
+# Written by Eloy A. Paris <peloy@debian.org> for the Debian project.
+#
+
+BAK=/var/backups
+
+umask 022
+if cd $BAK; then
+ # Make sure /etc/samba/smbpasswd exists
+ if [ -f /etc/samba/smbpasswd ]; then
+ cmp -s smbpasswd.bak /etc/samba/smbpasswd || cp -p /etc/samba/smbpasswd smbpasswd.bak
+ fi
+fi
--- /dev/null
+#!/bin/sh
+#
+# This script can be called from a cronjob to automatically drop/release
+# all public ip addresses if CTDBD has crashed or stopped running.
+#
+
+[ -n "$CTDB_BASE" ] || \
+ CTDB_BASE=$(d=$(dirname "$0") ; cd -P "$d" ; echo "$PWD")
+
+. "${CTDB_BASE}/functions"
+
+# If ctdb is running, just exit
+if service ctdb status >/dev/null 2>&1 ; then
+ exit 0
+fi
+
+loadconfig ctdb
+
+[ -n "$CTDB_PUBLIC_ADDRESSES" ] || \
+ CTDB_PUBLIC_ADDRESSES="$CTDB_BASE/public_addresses"
+
+[ -f "$CTDB_PUBLIC_ADDRESSES" ] || \
+ die "No public addresses file found. Can't clean up."
+
+drop_all_public_ips 2>&1 | script_log "ctdb-crash-cleanup.sh"
+
+if [ -n "$CTDB_NATGW_PUBLIC_IP" ] ; then
+ drop_ip "$CTDB_NATGW_PUBLIC_IP" "ctdb-crash-cleanup.sh"
+fi
--- /dev/null
+# Options to ctdbd, read by ctdbd_wrapper(1)
+#
+# See ctdbd.conf(5) for more information about CTDB configuration variables.
+
+# Shared recovery lock file to avoid split brain. No default.
+#
+# Do NOT run CTDB without a recovery lock file unless you know exactly
+# what you are doing.
+# CTDB_RECOVERY_LOCK=/some/place/on/shared/storage
+
+# List of nodes in the cluster. Default is below.
+# CTDB_NODES=/etc/ctdb/nodes
+
+# List of public addresses for providing NAS services. No default.
+# CTDB_PUBLIC_ADDRESSES=/etc/ctdb/public_addresses
+
+# What services should CTDB manage? Default is none.
+# CTDB_MANAGES_SAMBA=yes
+# CTDB_MANAGES_WINBIND=yes
+# CTDB_MANAGES_NFS=yes
+
+# Raise the file descriptor limit for CTDB?
+# CTDB_MAX_OPEN_FILES=10000
+
+# Default is to use the log file below instead of syslog.
+# CTDB_LOGGING=file:/var/log/log.ctdb
+
+# Default log level is NOTICE. Want less logging?
+# CTDB_DEBUGLEVEL=ERR
+
+# Set some CTDB tunable variables during CTDB startup?
+# CTDB_SET_TDBMutexEnabled=0
--- /dev/null
+#!/bin/sh
+
+# This script only works on Linux. Please modify (and submit patches)
+# for other operating systems.
+
+[ -n "$CTDB_BASE" ] || \
+ CTDB_BASE=$(d=$(dirname "$0") ; cd -P "$d" ; echo "$PWD")
+
+. "${CTDB_BASE}/functions"
+
+loadconfig ctdb
+
+# Testing hook
+if [ -n "$CTDB_DEBUG_HUNG_SCRIPT_LOGFILE" ] ; then
+ tmp="${CTDB_DEBUG_HUNG_SCRIPT_LOGFILE}.part"
+ exec >>"$tmp" 2>&1
+fi
+
+(
+ # No use running several of these in parallel if, say, "releaseip"
+ # event hangs for multiple IPs. In that case the output would be
+ # interleaved in the log and would just be confusing.
+ flock --wait 2 9 || exit 1
+
+ echo "===== Start of hung script debug for PID=\"$1\", event=\"$2\" ====="
+
+ echo "pstree -p -a ${1}:"
+ out=$(pstree -p -a "$1")
+ echo "$out"
+
+ # Check for processes matching a regular expression and print
+ # stack staces. This could help confirm that certain processes
+ # are stuck in certain places such as the cluster filesystem. The
+ # regexp must separate items with "|" and must not contain
+ # parentheses. The default pattern can be replaced for testing.
+ default_pat='exportfs|rpcinfo'
+ pat="${CTDB_DEBUG_HUNG_SCRIPT_STACKPAT:-${default_pat}}"
+ echo "$out" |
+ sed -r -n "s@.*-(.*(${pat}).*),([0-9]*).*@\3 \1@p" |
+ while read pid name ; do
+ trace=$(cat "/proc/${pid}/stack" 2>/dev/null)
+ if [ $? -eq 0 ] ; then
+ echo "---- Stack trace of interesting process ${pid}[${name}] ----"
+ echo "$trace"
+ fi
+ done
+
+ if [ "$2" != "init" ] ; then
+ echo "---- ctdb scriptstatus ${2}: ----"
+ $CTDB scriptstatus "$2"
+ fi
+
+ echo "===== End of hung script debug for PID=\"$1\", event=\"$2\" ====="
+
+ if [ -n "$CTDB_DEBUG_HUNG_SCRIPT_LOGFILE" ] ; then
+ mv "$tmp" "$CTDB_DEBUG_HUNG_SCRIPT_LOGFILE"
+ fi
+
+) 9>"${CTDB_SCRIPT_VARDIR}/debug-hung-script.lock"
--- /dev/null
+#!/bin/sh
+
+# This script parses /proc/locks and finds the processes that are holding
+# locks on CTDB databases. For all those processes the script dumps a
+# stack trace.
+#
+# This script can be used only if Samba is configured to use fcntl locks
+# rather than mutex locks.
+
+[ -n "$CTDB_BASE" ] || \
+ CTDB_BASE=$(d=$(dirname "$0") ; cd -P "$d" ; echo "$PWD")
+
+. "${CTDB_BASE}/functions"
+
+# Default fallback location for database directories.
+# These can be overwritten from CTDB configuration
+CTDB_DBDIR="${CTDB_VARDIR}"
+CTDB_DBDIR_PERSISTENT="${CTDB_VARDIR}/persistent"
+
+loadconfig ctdb
+
+(
+ flock -n 9 || exit 1
+
+ echo "===== Start of debug locks PID=$$ ====="
+
+ # Create sed expression to convert inodes to names.
+ # Filenames don't contain dashes and we want basenames
+ # shellcheck disable=SC2035
+ sed_cmd=$(cd "$CTDB_DBDIR" &&
+ stat -c "s#[0-9a-f]*:[0-9a-f]*:%i #%n #" *.tdb.* 2>/dev/null ;
+ cd "$CTDB_DBDIR_PERSISTENT" &&
+ stat -c "s#[0-9a-f]*:[0-9a-f]*:%i #%n #" *.tdb.* 2>/dev/null)
+
+ # Parse /proc/locks and extract following information
+ # pid process_name tdb_name offsets [W]
+ out=$( grep -F "POSIX ADVISORY WRITE" /proc/locks |
+ awk '{ if($2 == "->") { print $6, $7, $8, $9, "W" } else { print $5, $6, $7, $8 } }' |
+ while read pid rest ; do
+ pname=$(readlink "/proc/${pid}/exe")
+ echo "$pid $pname $rest"
+ done | sed -e "$sed_cmd" | grep "\.tdb" )
+
+ if [ -n "$out" ]; then
+ # Log information about locks
+ echo "$out"
+
+ # Find processes that are waiting for locks
+ dbs=$(echo "$out" | grep "W$" | awk '{print $3}')
+ all_pids=""
+ for db in $dbs ; do
+ pids=$(echo "$out" | grep -v "W$" | grep "$db" | grep -v ctdbd | awk '{print $1}')
+ all_pids="$all_pids $pids"
+ done
+ # Use word splitting to squash whitespace
+ # shellcheck disable=SC2086
+ pids=$(echo $all_pids | tr " " "\n" | sort -u)
+
+ # For each process waiting, log stack trace
+ for pid in $pids ; do
+ echo "----- Stack trace for PID=$pid -----"
+ # x is intentionally ignored
+ # shellcheck disable=SC2034
+ read x x state x <"/proc/${pid}/stat"
+ if [ "$state" = "D" ] ; then
+ # Don't run gstack on a process in D state since
+ # gstack will hang until the process exits D state.
+ # Although it is possible for a process to transition
+ # to D state after this check, it is unlikely because
+ # if a process is stuck in D state then it is probably
+ # the reason why this script was called. Note that a
+ # kernel stack almost certainly won't help diagnose a
+ # deadlock... but it will probably give us someone to
+ # blame!
+ echo "----- Process in D state, printing kernel stack only"
+ cat "/proc/${pid}/stack"
+ else
+ gstack "$pid"
+ # gcore -o /var/log/core-deadlock-ctdb $pid
+ fi
+ done
+ fi
+
+ echo "===== End of debug locks PID=$$ ====="
+)9>"${CTDB_SCRIPT_VARDIR}/debug_locks.lock" | script_log "ctdbd-lock"
+
+exit 0
--- /dev/null
+#!/bin/sh
+
+# Event script for ctdb-specific setup and other things that don't fit
+# elsewhere.
+
+[ -n "$CTDB_BASE" ] || \
+ CTDB_BASE=$(d=$(dirname "$0") ; cd -P "$d" ; dirname "$PWD")
+
+. "${CTDB_BASE}/functions"
+
+loadconfig
+
+############################################################
+
+# type is commonly supported and more portable than which(1)
+# shellcheck disable=SC2039
+select_tdb_checker ()
+{
+ # Find the best TDB consistency check available.
+ use_tdb_tool_check=false
+ type tdbtool >/dev/null 2>&1 && found_tdbtool=true
+ type tdbdump >/dev/null 2>&1 && found_tdbdump=true
+
+ if $found_tdbtool && echo "help" | tdbtool | grep -q check ; then
+ use_tdb_tool_check=true
+ elif $found_tdbtool && $found_tdbdump ; then
+ cat <<EOF
+WARNING: The installed 'tdbtool' does not offer the 'check' subcommand.
+ Using 'tdbdump' for database checks.
+ Consider updating 'tdbtool' for better checks!
+EOF
+ elif $found_tdbdump ; then
+ cat <<EOF
+WARNING: 'tdbtool' is not available.
+ Using 'tdbdump' to check the databases.
+ Consider installing a recent 'tdbtool' for better checks!
+EOF
+ else
+ cat <<EOF
+WARNING: Cannot check databases since neither
+ 'tdbdump' nor 'tdbtool check' is available.
+ Consider installing tdbtool or at least tdbdump!
+EOF
+ return 1
+ fi
+}
+
+check_tdb ()
+{
+ _db="$1"
+
+ if $use_tdb_tool_check ; then
+ # tdbtool always exits with 0 :-(
+ if timeout 10 tdbtool "$_db" check 2>/dev/null |
+ grep -q "Database integrity is OK" ; then
+ return 0
+ else
+ return 1
+ fi
+ else
+ timeout 10 tdbdump "$_db" >/dev/null 2>/dev/null
+ return $?
+ fi
+}
+
+check_persistent_databases ()
+{
+ _dir="${CTDB_DBDIR_PERSISTENT:-${CTDB_DBDIR:-${CTDB_VARDIR}}/persistent}"
+ [ -d "$_dir" ] || return 0
+
+ [ "${CTDB_MAX_PERSISTENT_CHECK_ERRORS:-0}" = "0" ] || return 0
+
+ for _db in "$_dir/"*.tdb.*[0-9] ; do
+ [ -r "$_db" ] || continue
+ check_tdb "$_db" || \
+ die "Persistent database $_db is corrupted! CTDB will not start."
+ done
+}
+
+check_non_persistent_databases ()
+{
+ _dir="${CTDB_DBDIR:-${CTDB_VARDIR}}"
+ [ -d "$_dir" ] || return 0
+
+ for _db in "${_dir}/"*.tdb.*[0-9] ; do
+ [ -r "$_db" ] || continue
+ check_tdb "$_db" || {
+ _backup="${_db}.$(date +'%Y%m%d.%H%M%S.%N').corrupt"
+ cat <<EOF
+WARNING: database ${_db} is corrupted.
+ Moving to backup ${_backup} for later analysis.
+EOF
+ mv "$_db" "$_backup"
+
+ # Now remove excess backups
+ _max="${CTDB_MAX_CORRUPT_DB_BACKUPS:-10}"
+ _bdb="${_db##*/}" # basename
+ find "$_dir" -name "${_bdb}.*.corrupt" |
+ sort -r |
+ tail -n +$((_max + 1)) |
+ xargs rm -f
+ }
+ done
+}
+
+set_ctdb_variables ()
+{
+ # set any tunables from the config file
+ set | sed -n '/^CTDB_SET_/s/=.*//p' |
+ while read v; do
+ varname="${v#CTDB_SET_}"
+ value=$(eval echo "\$$v")
+ if $CTDB setvar "$varname" "$value" ; then
+ echo "Set $varname to $value"
+ else
+ echo "Invalid configuration: CTDB_SET_${varname}=${value}"
+ return 1
+ fi
+ done
+}
+
+############################################################
+
+ctdb_check_args "$@"
+
+case "$1" in
+init)
+ # make sure we have a blank state directory for the scripts to work with
+ rm -rf "$CTDB_SCRIPT_VARDIR"
+ mkdir -p "$CTDB_SCRIPT_VARDIR" || \
+ die "mkdir -p ${CTDB_SCRIPT_VARDIR} - failed - $?" $?
+
+ if select_tdb_checker ; then
+ check_persistent_databases || exit $?
+ check_non_persistent_databases
+ fi
+ ;;
+
+setup)
+ # Set any tunables from the config file
+ set_ctdb_variables || \
+ die "Aborting setup due to invalid configuration - fix typos, remove unknown tunables"
+ ;;
+
+startup)
+ $CTDB attach ctdb.tdb persistent
+ ;;
+esac
+
+# all OK
+exit 0
--- /dev/null
+#!/bin/sh
+# script to check accessibility to the reclock file on a node
+
+[ -n "$CTDB_BASE" ] || \
+ CTDB_BASE=$(d=$(dirname "$0") ; cd -P "$d" ; dirname "$PWD")
+
+. "${CTDB_BASE}/functions"
+
+loadconfig
+
+# If CTDB_RECOVERY_LOCK specifies a helper then exit because this
+# script can't do anything useful.
+case "$CTDB_RECOVERY_LOCK" in
+!*) exit 0 ;;
+esac
+
+case "$1" in
+init)
+ ctdb_counter_init
+
+ if [ -n "$CTDB_RECOVERY_LOCK" ] ; then
+ d=$(dirname "$CTDB_RECOVERY_LOCK")
+ mkdir -vp "$d"
+ fi
+ ;;
+
+monitor)
+ # Early exit if not using a reclock file
+ [ -n "$CTDB_RECOVERY_LOCK" ] || exit 0
+
+ # Try to stat the reclock file as a background process so that
+ # we don't block in case the cluster filesystem is unavailable
+ (
+ if stat "$CTDB_RECOVERY_LOCK" ; then
+ # We could stat the file, reset the counter
+ ctdb_counter_init
+ fi
+ ) >/dev/null 2>&1 &
+
+ ctdb_counter_incr
+ num_fails=$(ctdb_counter_get)
+ if [ "$num_fails" -ge 200 ] ; then
+ echo "Reclock file \"$CTDB_RECOVERY_LOCK\" can not be accessed. Shutting down."
+ df
+ sleep 1
+ $CTDB shutdown
+ exit 1
+ elif [ "$num_fails" -ge 4 ] ; then
+ die "ERROR: ${num_fails} consecutive failures checking reclock"
+ fi
+ ;;
+esac
+
+exit 0
--- /dev/null
+#!/bin/sh
+# ctdb event script for checking local file system utilization
+
+[ -n "$CTDB_BASE" ] || \
+ CTDB_BASE=$(d=$(dirname "$0") ; cd -P "$d" ; dirname "$PWD")
+
+. "${CTDB_BASE}/functions"
+
+loadconfig
+
+service_state_dir=$(ctdb_setup_service_state_dir "system-monitoring") || exit $?
+
+validate_percentage ()
+{
+ case "$1" in
+ "") return 1 ;; # A failure that doesn't need a warning
+ [0-9]|[0-9][0-9]|100) return 0 ;;
+ *) echo "WARNING: ${1} is an invalid percentage${2:+ in \"}${2}${2:+\"} check"
+ return 1
+ esac
+}
+
+check_thresholds ()
+{
+ _thing="$1"
+ _thresholds="$2"
+ _usage="$3"
+ _unhealthy_callout="$4"
+
+ case "$_thresholds" in
+ *:*)
+ _warn_threshold="${_thresholds%:*}"
+ _unhealthy_threshold="${_thresholds#*:}"
+ ;;
+ *)
+ _warn_threshold="$_thresholds"
+ _unhealthy_threshold=""
+ esac
+
+ _t=$(echo "$_thing" | sed -e 's@/@SLASH_@g' -e 's@ @_@g')
+ _cache="${service_state_dir}/cache_${_t}"
+ if validate_percentage "$_unhealthy_threshold" "$_thing" ; then
+ if [ "$_usage" -ge "$_unhealthy_threshold" ] ; then
+ echo "ERROR: ${_thing} utilization ${_usage}% >= threshold ${_unhealthy_threshold}%"
+ eval "$_unhealthy_callout"
+ echo "$_usage" >"$_cache"
+ exit 1
+ fi
+ fi
+
+ if validate_percentage "$_warn_threshold" "$_thing" ; then
+ if [ "$_usage" -ge "$_warn_threshold" ] ; then
+ if [ -r "$_cache" ] ; then
+ read _prev <"$_cache"
+ else
+ _prev=""
+ fi
+ if [ "$_usage" != "$_prev" ] ; then
+ echo "WARNING: ${_thing} utilization ${_usage}% >= threshold ${_warn_threshold}%"
+ echo "$_usage" >"$_cache"
+ fi
+ else
+ if [ -r "$_cache" ] ; then
+ echo "NOTICE: ${_thing} utilization ${_usage}% < threshold ${_warn_threshold}%"
+ fi
+ rm -f "$_cache"
+ fi
+ fi
+}
+
+set_monitor_filsystem_usage_defaults ()
+{
+ _fs_defaults_cache="${service_state_dir}/cache_monitor_filsystem_usage_defaults"
+
+ if [ ! -r "$_fs_defaults_cache" ] ; then
+ # Determine filesystem for each database directory, generate
+ # an entry to warn at 90%, de-duplicate entries, put all items
+ # on 1 line (so the read below gets everything)
+ for _t in "${CTDB_DBDIR:-${CTDB_VARDIR}}" \
+ "${CTDB_DBDIR_PERSISTENT:-${CTDB_VARDIR}/persistent}" \
+ "${CTDB_DBDIR_STATE:-${CTDB_VARDIR}/state}" ; do
+ df -kP "$_t" | awk 'NR == 2 { printf "%s:90\n", $6 }'
+ done | sort -u | xargs >"$_fs_defaults_cache"
+ fi
+
+ read CTDB_MONITOR_FILESYSTEM_USAGE <"$_fs_defaults_cache"
+}
+
+monitor_filesystem_usage ()
+{
+ if [ -z "$CTDB_MONITOR_FILESYSTEM_USAGE" ] ; then
+ set_monitor_filsystem_usage_defaults
+ fi
+
+ # Check each specified filesystem, specified in format
+ # <fs_mount>:<fs_warn_threshold>[:fs_unhealthy_threshold]
+ for _fs in $CTDB_MONITOR_FILESYSTEM_USAGE ; do
+ _fs_mount="${_fs%%:*}"
+ _fs_thresholds="${_fs#*:}"
+
+ if [ ! -d "$_fs_mount" ]; then
+ echo "WARNING: Directory ${_fs_mount} does not exist"
+ continue
+ fi
+
+ # Get current utilization
+ _fs_usage=$(df -kP "$_fs_mount" | \
+ sed -n -e 's@.*[[:space:]]\([[:digit:]]*\)%.*@\1@p')
+ if [ -z "$_fs_usage" ] ; then
+ echo "WARNING: Unable to get FS utilization for ${_fs_mount}"
+ continue
+ fi
+
+ check_thresholds "Filesystem ${_fs_mount}" \
+ "$_fs_thresholds" \
+ "$_fs_usage"
+ done
+}
+
+dump_memory_info ()
+{
+ get_proc "meminfo"
+ ps auxfww
+ set_proc "sysrq-trigger" "m"
+}
+
+monitor_memory_usage ()
+{
+ # Defaults
+ if [ -z "$CTDB_MONITOR_MEMORY_USAGE" ] ; then
+ CTDB_MONITOR_MEMORY_USAGE=80
+ fi
+ if [ -z "$CTDB_MONITOR_SWAP_USAGE" ] ; then
+ CTDB_MONITOR_SWAP_USAGE=25
+ fi
+
+ _meminfo=$(get_proc "meminfo")
+ # Intentional word splitting here
+ # shellcheck disable=SC2046
+ set -- $(echo "$_meminfo" | awk '
+$1 == "MemAvailable:" { memavail += $2 }
+$1 == "MemFree:" { memfree += $2 }
+$1 == "Cached:" { memfree += $2 }
+$1 == "Buffers:" { memfree += $2 }
+$1 == "MemTotal:" { memtotal = $2 }
+$1 == "SwapFree:" { swapfree = $2 }
+$1 == "SwapTotal:" { swaptotal = $2 }
+END {
+ if (memavail != 0) { memfree = memavail ; }
+ if (memtotal != 0) { print int((memtotal - memfree) / memtotal * 100) ; } else { print 0 ; }
+ if (swaptotal != 0) { print int((swaptotal - swapfree) / swaptotal * 100) ; } else { print 0 ; }
+}')
+ _mem_usage="$1"
+ _swap_usage="$2"
+
+ check_thresholds "System memory" \
+ "$CTDB_MONITOR_MEMORY_USAGE" \
+ "$_mem_usage" \
+ dump_memory_info
+
+ check_thresholds "System swap" \
+ "$CTDB_MONITOR_SWAP_USAGE" \
+ "$_swap_usage" \
+ dump_memory_info
+}
+
+
+case "$1" in
+monitor)
+ monitor_filesystem_usage
+ monitor_memory_usage
+ ;;
+esac
+
+exit 0
--- /dev/null
+#!/bin/sh
+# script to manage nfs in a clustered environment
+
+[ -n "$CTDB_BASE" ] || \
+ CTDB_BASE=$(d=$(dirname "$0") ; cd -P "$d" ; dirname "$PWD")
+
+. "${CTDB_BASE}/functions"
+
+# service_name is used by various functions
+# shellcheck disable=SC2034
+service_name="nfs"
+
+loadconfig
+service_state_dir=$(ctdb_setup_service_state_dir) || exit $?
+
+######################################################################
+
+nfs_callout_pre ()
+{
+ _event="$1"
+ shift
+
+ nfs_callout "${_event}-pre" "$@"
+}
+
+######################################################################
+
+nfs_callout_init "$service_state_dir"
+
+is_ctdb_managed_service || exit 0
+
+case "$1" in
+takeip)
+ nfs_callout_pre "$@"
+ ;;
+
+releaseip)
+ nfs_callout_pre "$@"
+ ;;
+esac
--- /dev/null
+#!/bin/sh
+
+# Eventscript for CTDB to cope with externally managed public IP addresses
+
+# If DisableIPFailover is set:
+#
+# * 10.interface must be disabled.
+# * For connection tracking/killing to work this script must be enabled.
+
+[ -n "$CTDB_BASE" ] || \
+ CTDB_BASE=$(d=$(dirname "$0") ; cd -P "$d" ; dirname "$PWD")
+
+. "${CTDB_BASE}/functions"
+
+loadconfig
+
+if [ -z "$CTDB_PUBLIC_ADDRESSES" ] ; then
+ exit 0
+fi
+
+if [ ! -f "$CTDB_PUBLIC_ADDRESSES" ] ; then
+ if [ "$1" = "init" ]; then
+ echo "No public addresses file found. Nothing to do for 10.interfaces.external"
+ fi
+ exit 0
+fi
+
+takeover_assigned_ips ()
+{
+ _pnn=$(ctdb_get_pnn)
+
+ $CTDB -X ip |
+ awk -F'|' '{print $2}' |
+ while read ip ; do
+ _ip_details=$(ip_maskbits_iface "$ip")
+ if [ -n "$_ip_details" ] ; then
+ echo "Assigning $ip to this node (${_pnn})"
+ $CTDB moveip "$ip" "$_pnn"
+ fi
+ done
+}
+
+ctdb_check_args "$@"
+
+case "$1" in
+ startup)
+ takeover_assigned_ips
+ ;;
+esac
+
+exit 0
--- /dev/null
+#!/bin/sh
+
+#################################
+# interface event script for ctdb
+# this adds/removes IPs from your
+# public interface
+
+[ -n "$CTDB_BASE" ] || \
+ CTDB_BASE=$(d=$(dirname "$0") ; cd -P "$d" ; dirname "$PWD")
+
+. "${CTDB_BASE}/functions"
+
+loadconfig
+
+[ -z "$CTDB_PUBLIC_ADDRESSES" ] && {
+ CTDB_PUBLIC_ADDRESSES="${CTDB_BASE}/public_addresses"
+}
+
+[ ! -f "$CTDB_PUBLIC_ADDRESSES" ] && {
+ if [ "$1" = "init" ]; then
+ echo "No public addresses file found. Nothing to do for 10.interfaces"
+ fi
+ exit 0
+}
+
+# This sets $all_interfaces as a side-effect.
+get_all_interfaces ()
+{
+ # Get all the interfaces listed in the public_addresses file
+ all_interfaces=$(sed -e "s/^[^\t ]*[\t ]*//" \
+ -e "s/,/ /g" \
+ -e "s/[\t ]*$//" "$CTDB_PUBLIC_ADDRESSES")
+
+ # Add some special interfaces if they're defined
+ [ "$CTDB_PUBLIC_INTERFACE" ] && all_interfaces="$CTDB_PUBLIC_INTERFACE $all_interfaces"
+
+ # Get the interfaces for which CTDB has public IPs configured.
+ # That is, for all but the 1st line, get the 1st field.
+ ctdb_ifaces=$($CTDB -X ifaces | sed -e '1d' -e 's@^|@@' -e 's@|.*@@')
+
+ # Add $ctdb_interfaces and uniquify
+ # Use word splitting to squash whitespace
+ # shellcheck disable=SC2086
+ all_interfaces=$(echo $all_interfaces $ctdb_ifaces | tr ' ' '\n' | sort -u)
+}
+
+monitor_interfaces()
+{
+ get_all_interfaces
+
+ down_interfaces_found=false
+ up_interfaces_found=false
+
+ # Note that this loop must not exit early. It must process
+ # all interfaces so that the correct state for each interface
+ # is set in CTDB using setifacelink.
+ for _iface in $all_interfaces ; do
+ if interface_monitor "$_iface" ; then
+ up_interfaces_found=true
+ $CTDB setifacelink "$_iface" up >/dev/null 2>&1
+ else
+ down_interfaces_found=true
+ $CTDB setifacelink "$_iface" down >/dev/null 2>&1
+ fi
+ done
+
+ if ! $down_interfaces_found ; then
+ return 0
+ fi
+
+ if ! $up_interfaces_found ; then
+ return 1
+ fi
+
+ if [ "$CTDB_PARTIALLY_ONLINE_INTERFACES" != "yes" ]; then
+ return 1
+ fi
+
+ return 0
+}
+
+# Sets: iface, ip, maskbits
+get_iface_ip_maskbits ()
+{
+ _iface_in="$1"
+ ip="$2"
+ _maskbits_in="$3"
+
+ # Intentional word splitting here
+ # shellcheck disable=SC2046
+ set -- $(ip_maskbits_iface "$ip")
+ if [ -n "$1" ] ; then
+ maskbits="$1"
+ iface="$2"
+
+ if [ "$iface" != "$_iface_in" ] ; then
+ printf \
+ 'WARNING: Public IP %s hosted on interface %s but VNN says %s\n' \
+ "$ip" "$iface" "$_iface_in"
+ fi
+ if [ "$maskbits" != "$_maskbits_in" ] ; then
+ printf \
+ 'WARNING: Public IP %s has %s bit netmask but VNN says %s\n' \
+ "$ip" "$maskbits" "$_maskbits_in"
+ fi
+ else
+ die "ERROR: Unable to determine interface for IP ${ip}"
+ fi
+}
+
+ip_block ()
+{
+ _ip="$1"
+ _iface="$2"
+
+ case "$_ip" in
+ *:*) _family="inet6" ;;
+ *) _family="inet" ;;
+ esac
+
+ # Extra delete copes with previously killed script
+ iptables_wrapper "$_family" \
+ -D INPUT -i "$_iface" -d "$_ip" -j DROP 2>/dev/null
+ iptables_wrapper "$_family" \
+ -I INPUT -i "$_iface" -d "$_ip" -j DROP
+}
+
+ip_unblock ()
+{
+ _ip="$1"
+ _iface="$2"
+
+ case "$_ip" in
+ *:*) _family="inet6" ;;
+ *) _family="inet" ;;
+ esac
+
+ iptables_wrapper "$_family" \
+ -D INPUT -i "$_iface" -d "$_ip" -j DROP 2>/dev/null
+}
+
+ctdb_check_args "$@"
+
+case "$1" in
+init)
+ # make sure that we only respond to ARP messages from the NIC where
+ # a particular ip address is associated.
+ get_proc sys/net/ipv4/conf/all/arp_filter >/dev/null 2>&1 && {
+ set_proc sys/net/ipv4/conf/all/arp_filter 1
+ }
+
+ _promote="sys/net/ipv4/conf/all/promote_secondaries"
+ get_proc "$_promote" >/dev/null 2>&1 || \
+ die "Public IPs only supported if promote_secondaries is available"
+
+ # make sure we drop any ips that might still be held if
+ # previous instance of ctdb got killed with -9 or similar
+ drop_all_public_ips
+ ;;
+
+startup)
+ monitor_interfaces
+ ;;
+
+takeip)
+ iface=$2
+ ip=$3
+ maskbits=$4
+
+ add_ip_to_iface "$iface" "$ip" "$maskbits" || {
+ exit 1;
+ }
+
+ # In case a previous "releaseip" for this IP was killed...
+ ip_unblock "$ip" "$iface"
+
+ flush_route_cache
+ ;;
+
+releaseip)
+ # releasing an IP is a bit more complex than it seems. Once the IP
+ # is released, any open tcp connections to that IP on this host will end
+ # up being stuck. Some of them (such as NFS connections) will be unkillable
+ # so we need to use the killtcp ctdb function to kill them off. We also
+ # need to make sure that no new connections get established while we are
+ # doing this! So what we do is this:
+ # 1) firewall this IP, so no new external packets arrive for it
+ # 2) find existing connections, and kill them
+ # 3) remove the IP from the interface
+ # 4) remove the firewall rule
+ shift
+ get_iface_ip_maskbits "$@"
+
+ ip_block "$ip" "$iface"
+
+ kill_tcp_connections "$iface" "$ip"
+
+ delete_ip_from_iface "$iface" "$ip" "$maskbits" || {
+ ip_unblock "$ip" "$iface"
+ exit 1
+ }
+
+ ip_unblock "$ip" "$iface"
+
+ flush_route_cache
+ ;;
+
+updateip)
+ # moving an IP is a bit more complex than it seems.
+ # First we drop all traffic on the old interface.
+ # Then we try to add the ip to the new interface and before
+ # we finally remove it from the old interface.
+ #
+ # 1) firewall this IP, so no new external packets arrive for it
+ # 2) remove the IP from the old interface (and new interface, to be sure)
+ # 3) add the IP to the new interface
+ # 4) remove the firewall rule
+ # 5) use ctdb gratarp to propagate the new mac address
+ # 6) use netstat -tn to find existing connections, and tickle them
+ _oiface=$2
+ niface=$3
+ _ip=$4
+ _maskbits=$5
+
+ get_iface_ip_maskbits "$_oiface" "$_ip" "$_maskbits"
+ oiface="$iface"
+
+ # Could check maskbits too. However, that should never change
+ # so we want to notice if it does.
+ if [ "$oiface" = "$niface" ] ; then
+ echo "Redundant \"updateip\" - ${ip} already on ${niface}"
+ exit 0
+ fi
+
+ ip_block "$ip" "$oiface"
+
+ delete_ip_from_iface "$oiface" "$ip" "$maskbits" 2>/dev/null
+ delete_ip_from_iface "$niface" "$ip" "$maskbits" 2>/dev/null
+
+ add_ip_to_iface "$niface" "$ip" "$maskbits" || {
+ ip_unblock "$ip" "$oiface"
+ exit 1
+ }
+
+ ip_unblock "$ip" "$oiface"
+
+ flush_route_cache
+
+ # propagate the new mac address
+ $CTDB gratarp "$ip" "$niface"
+
+ # tickle all existing connections, so that dropped packets
+ # are retransmited and the tcp streams work
+ tickle_tcp_connections "$ip"
+ ;;
+
+monitor)
+ monitor_interfaces || exit 1
+ ;;
+esac
+
+exit 0
--- /dev/null
+#!/bin/sh
+# Script to set up one of the nodes as a NAT gateway for all other nodes.
+# This is used to ensure that all nodes in the cluster can still originate
+# traffic to the external network even if there are no public addresses
+# available.
+#
+
+[ -n "$CTDB_BASE" ] || \
+ CTDB_BASE=$(d=$(dirname "$0") ; cd -P "$d" ; dirname "$PWD")
+
+. "${CTDB_BASE}/functions"
+
+# service_name is used by various functions
+# shellcheck disable=SC2034
+service_name=natgw
+
+loadconfig
+
+[ -n "$CTDB_NATGW_NODES" ] || exit 0
+export CTDB_NATGW_NODES
+
+service_state_dir=$(ctdb_setup_service_state_dir) || exit $?
+
+natgw_cfg_new="${service_state_dir}/cfg_new"
+natgw_cfg_old="${service_state_dir}/cfg_old"
+natgw_master_old="${service_state_dir}/master_old"
+
+ctdb_natgw_slave_only ()
+{
+ _ip_address=$(ctdb_get_ip_address)
+
+ awk -v my_ip="$_ip_address" \
+ '$1 == my_ip { if ($2 ~ "slave-only") { exit 0 } else { exit 1 } }' \
+ "$CTDB_NATGW_NODES"
+}
+
+natgw_check_config ()
+{
+ [ -r "$CTDB_NATGW_NODES" ] || \
+ die "error: CTDB_NATGW_NODES=${CTDB_NATGW_NODES} unreadable"
+ if ! ctdb_natgw_slave_only ; then
+ [ -n "$CTDB_NATGW_PUBLIC_IP" ] || \
+ die "Invalid configuration: CTDB_NATGW_PUBLIC_IP not set"
+ [ -n "$CTDB_NATGW_PUBLIC_IFACE" ] || \
+ die "Invalid configuration: CTDB_NATGW_PUBLIC_IFACE not set"
+ fi
+ [ -n "$CTDB_NATGW_PRIVATE_NETWORK" ] || \
+ die "Invalid configuration: CTDB_NATGW_PRIVATE_NETWORK not set"
+
+ if [ "$CTDB_PARTIALLY_ONLINE_INTERFACES" = "yes" ] ; then
+ die "Invalid configuration: CTDB_PARTIALLY_ONLINE_INTERFACES=yes incompatible with NAT gateway"
+ fi
+
+ # The default is to create a single default route
+ [ -n "$CTDB_NATGW_STATIC_ROUTES" ] || CTDB_NATGW_STATIC_ROUTES="0.0.0.0/0"
+}
+
+natgw_write_config ()
+{
+ _f="$1"
+
+ cat >"$_f" <<EOF
+CTDB_NATGW_NODES="$CTDB_NATGW_NODES"
+CTDB_NATGW_PUBLIC_IP="$CTDB_NATGW_PUBLIC_IP"
+CTDB_NATGW_PUBLIC_IFACE="$CTDB_NATGW_PUBLIC_IFACE"
+CTDB_NATGW_DEFAULT_GATEWAY="$CTDB_NATGW_DEFAULT_GATEWAY"
+CTDB_NATGW_PRIVATE_NETWORK="$CTDB_NATGW_PRIVATE_NETWORK"
+CTDB_NATGW_STATIC_ROUTES="$CTDB_NATGW_STATIC_ROUTES"
+EOF
+}
+
+natgw_config_has_changed ()
+{
+ natgw_write_config "$natgw_cfg_new"
+
+ # Non-existent old returns true, no log message
+ if [ ! -f "$natgw_cfg_old" ] ; then
+ return 0
+ fi
+
+ # Handle no change
+ if cmp "$natgw_cfg_old" "$natgw_cfg_new" >/dev/null 2>&1 ; then
+ return 1
+ fi
+
+ echo "NAT gateway configuration has changed"
+ return 0
+}
+
+_natgw_clear ()
+{
+ _ip="${CTDB_NATGW_PUBLIC_IP%/*}"
+ _maskbits="${CTDB_NATGW_PUBLIC_IP#*/}"
+
+ delete_ip_from_iface \
+ "$CTDB_NATGW_PUBLIC_IFACE" "$_ip" "$_maskbits" >/dev/null 2>&1
+ for _net_gw in $CTDB_NATGW_STATIC_ROUTES ; do
+ _net="${_net_gw%@*}"
+ ip route del "$_net" metric 10 >/dev/null 2>/dev/null
+ done
+
+ # Delete the masquerading setup from a previous iteration where we
+ # were the NAT-GW
+ iptables -D POSTROUTING -t nat \
+ -s "$CTDB_NATGW_PRIVATE_NETWORK" ! -d "$CTDB_NATGW_PRIVATE_NETWORK" \
+ -j MASQUERADE >/dev/null 2>/dev/null
+
+ iptables -D INPUT -p tcp --syn -d "${_ip}/32" -j REJECT 2>/dev/null
+}
+
+natgw_clear ()
+{
+ if [ -r "$natgw_cfg_old" ] ; then
+ (. "$natgw_cfg_old" ; _natgw_clear)
+ else
+ _natgw_clear
+ fi
+}
+
+natgw_set_master ()
+{
+ set_proc sys/net/ipv4/ip_forward 1
+ iptables -A POSTROUTING -t nat \
+ -s "$CTDB_NATGW_PRIVATE_NETWORK" ! -d "$CTDB_NATGW_PRIVATE_NETWORK" \
+ -j MASQUERADE
+
+ # block all incoming connections to the NATGW IP address
+ ctdb_natgw_public_ip_host="${CTDB_NATGW_PUBLIC_IP%/*}/32"
+ iptables -D INPUT -p tcp --syn \
+ -d "$ctdb_natgw_public_ip_host" -j REJECT 2>/dev/null
+ iptables -I INPUT -p tcp --syn \
+ -d "$ctdb_natgw_public_ip_host" -j REJECT 2>/dev/null
+
+ ip addr add "$CTDB_NATGW_PUBLIC_IP" dev "$CTDB_NATGW_PUBLIC_IFACE"
+ for _net_gw in $CTDB_NATGW_STATIC_ROUTES ; do
+ _net="${_net_gw%@*}"
+ if [ "$_net" != "$_net_gw" ] ; then
+ _gw="${_net_gw#*@}"
+ else
+ _gw="$CTDB_NATGW_DEFAULT_GATEWAY"
+ fi
+
+ [ -n "$_gw" ] || continue
+ ip route add "$_net" metric 10 via "$_gw"
+ done
+}
+
+natgw_set_slave ()
+{
+ _natgwip="$1"
+
+ for _net_gw in $CTDB_NATGW_STATIC_ROUTES ; do
+ _net="${_net_gw%@*}"
+ ip route add "$_net" via "$_natgwip" metric 10
+ done
+}
+
+natgw_ensure_master ()
+{
+ # Intentional word splitting here
+ # shellcheck disable=SC2046
+ set -- $("${CTDB_HELPER_BINDIR}/ctdb_natgw" master)
+ natgwmaster="${1:--1}" # Default is -1, for failure above
+ natgwip="$2"
+
+ if [ "$natgwmaster" = "-1" ]; then
+ # Fail...
+ die "There is no NATGW master node"
+ fi
+}
+
+natgw_master_has_changed ()
+{
+ if [ -r "$natgw_master_old" ] ; then
+ read _old_natgwmaster <"$natgw_master_old"
+ else
+ _old_natgwmaster=""
+ fi
+ [ "$_old_natgwmaster" != "$natgwmaster" ]
+}
+
+natgw_save_state ()
+{
+ echo "$natgwmaster" >"$natgw_master_old"
+ # Created by natgw_config_has_changed()
+ mv "$natgw_cfg_new" "$natgw_cfg_old"
+}
+
+
+case "$1" in
+setup)
+ natgw_check_config
+ ;;
+
+startup)
+ natgw_check_config
+
+ # Error if CTDB_NATGW_PUBLIC_IP is listed in public addresses
+ ip_pat=$(echo "$CTDB_NATGW_PUBLIC_IP" | sed -e 's@\.@\\.@g')
+ if grep -q "^${ip_pat}[[:space:]]" \
+ "${CTDB_PUBLIC_ADDRESSES:-${CTDB_BASE}/public_addresses}" ; then
+ die "ERROR: CTDB_NATGW_PUBLIC_IP same as a public address"
+ fi
+
+ # do not send out arp requests from loopback addresses
+ set_proc sys/net/ipv4/conf/all/arp_announce 2
+ ;;
+
+updatenatgw|ipreallocated)
+ natgw_check_config
+
+ natgw_ensure_master
+
+ natgw_config_has_changed || natgw_master_has_changed || exit 0
+
+ natgw_clear
+
+ pnn=$(ctdb_get_pnn)
+ if [ "$pnn" = "$natgwmaster" ]; then
+ natgw_set_master
+ else
+ natgw_set_slave "$natgwip"
+ fi
+
+ # flush our route cache
+ set_proc sys/net/ipv4/route/flush 1
+
+ # Only update saved state when NATGW successfully updated
+ natgw_save_state
+ ;;
+
+shutdown|removenatgw)
+ natgw_check_config
+ natgw_clear
+ ;;
+
+monitor)
+ natgw_check_config
+
+ if [ -n "$CTDB_NATGW_PUBLIC_IFACE" ] ; then
+ interface_monitor "$CTDB_NATGW_PUBLIC_IFACE" || exit 1
+ fi
+ ;;
+esac
+
+exit 0
--- /dev/null
+#!/bin/sh
+
+# Attempt to add a set of static routes.
+#
+# Do this in "ipreallocated" rather than just "startup" because some
+# of the routes might be missing because the corresponding interface
+# has not previously had any IPs assigned or IPs were previously
+# released and corresponding routes were dropped.
+#
+# Addition of some routes might fail, errors go to /dev/null.
+#
+# Routes to add are defined in $CTDB_BASE/static-routes. Syntax is:
+#
+# IFACE NET/MASK GATEWAY
+#
+# Example:
+#
+# bond1 10.3.3.0/24 10.0.0.1
+
+[ -n "$CTDB_BASE" ] || \
+ CTDB_BASE=$(d=$(dirname "$0") ; cd -P "$d" ; dirname "$PWD")
+
+. "${CTDB_BASE}/functions"
+
+loadconfig
+
+[ -f "${CTDB_BASE}/static-routes" ] || {
+ exit 0
+}
+
+case "$1" in
+ipreallocated)
+ while read iface dest gw; do
+ ip route add "$dest" via "$gw" dev "$iface" >/dev/null 2>&1
+ done <"${CTDB_BASE}/static-routes"
+ ;;
+
+updateip)
+ oiface=$2
+ niface=$3
+ while read iface dest gw; do
+ if [ "$niface" = "$iface" -o "$oiface" = "$iface" ] ; then
+ ip route add "$dest" via "$gw" dev "$iface" >/dev/null 2>&1
+ fi
+ done <"${CTDB_BASE}/static-routes"
+ ;;
+esac
+
+exit 0
--- /dev/null
+#!/bin/sh
+
+[ -n "$CTDB_BASE" ] || \
+ CTDB_BASE=$(d=$(dirname "$0") ; cd -P "$d" ; dirname "$PWD")
+
+. "${CTDB_BASE}/functions"
+
+loadconfig
+
+# service_name is used by various functions
+# shellcheck disable=SC2034
+service_name=per_ip_routing
+
+# Do nothing if unconfigured
+[ -n "$CTDB_PER_IP_ROUTING_CONF" ] || exit 0
+
+table_id_prefix="ctdb."
+
+[ -n "$CTDB_PER_IP_ROUTING_RULE_PREF" ] || \
+ die "error: CTDB_PER_IP_ROUTING_RULE_PREF not configured"
+
+[ "$CTDB_PER_IP_ROUTING_TABLE_ID_LOW" -lt "$CTDB_PER_IP_ROUTING_TABLE_ID_HIGH" ] 2>/dev/null || \
+ die "error: CTDB_PER_IP_ROUTING_TABLE_ID_LOW[$CTDB_PER_IP_ROUTING_TABLE_ID_LOW] and/or CTDB_PER_IP_ROUTING_TABLE_ID_HIGH[$CTDB_PER_IP_ROUTING_TABLE_ID_HIGH] improperly configured"
+
+if [ "$CTDB_PER_IP_ROUTING_TABLE_ID_LOW" -le 253 -a \
+ 255 -le "$CTDB_PER_IP_ROUTING_TABLE_ID_HIGH" ] ; then
+ die "error: range CTDB_PER_IP_ROUTING_TABLE_ID_LOW[$CTDB_PER_IP_ROUTING_TABLE_ID_LOW]..CTDB_PER_IP_ROUTING_TABLE_ID_HIGH[$CTDB_PER_IP_ROUTING_TABLE_ID_HIGH] must not include 253-255"
+fi
+
+have_link_local_config ()
+{
+ [ "$CTDB_PER_IP_ROUTING_CONF" = "__auto_link_local__" ]
+}
+
+if ! have_link_local_config && [ ! -r "$CTDB_PER_IP_ROUTING_CONF" ] ; then
+ die "error: CTDB_PER_IP_ROUTING_CONF=$CTDB_PER_IP_ROUTING_CONF file not found"
+fi
+
+service_state_dir=$(ctdb_setup_service_state_dir) || exit $?
+
+######################################################################
+
+ipv4_is_valid_addr()
+{
+ _ip="$1"
+
+ _count=0
+ # Get the shell to break up the address into 1 word per octet
+ # Intentional word splitting here
+ # shellcheck disable=SC2086
+ for _o in $(export IFS="." ; echo $_ip) ; do
+ # The 2>/dev/null stops output from failures where an "octet"
+ # is not numeric. The test will still fail.
+ if ! [ 0 -le $_o -a $_o -le 255 ] 2>/dev/null ; then
+ return 1
+ fi
+ _count=$((_count + 1))
+ done
+
+ # A valid IPv4 address has 4 octets
+ [ $_count -eq 4 ]
+}
+
+ensure_ipv4_is_valid_addr ()
+{
+ _event="$1"
+ _ip="$2"
+
+ ipv4_is_valid_addr "$_ip" || {
+ echo "$0: $_event not an ipv4 address skipping IP:$_ip"
+ exit 0
+ }
+}
+
+ipv4_host_addr_to_net ()
+{
+ _host="$1"
+ _maskbits="$2"
+
+ # Convert the host address to an unsigned long by splitting out
+ # the octets and doing the math.
+ _host_ul=0
+ # Intentional word splitting here
+ # shellcheck disable=SC2086
+ for _o in $(export IFS="." ; echo $_host) ; do
+ _host_ul=$(( (_host_ul << 8) + _o)) # work around Emacs color bug
+ done
+
+ # Calculate the mask and apply it.
+ _mask_ul=$(( 0xffffffff << (32 - _maskbits) ))
+ _net_ul=$(( _host_ul & _mask_ul ))
+
+ # Now convert to a network address one byte at a time.
+ _net=""
+ for _o in $(seq 1 4) ; do
+ _net="$((_net_ul & 255))${_net:+.}${_net}"
+ _net_ul=$((_net_ul >> 8))
+ done
+
+ echo "${_net}/${_maskbits}"
+}
+
+######################################################################
+
+ensure_rt_tables ()
+{
+ rt_tables="$CTDB_SYS_ETCDIR/iproute2/rt_tables"
+ rt_tables_lock="${service_state_dir}/rt_tables_lock"
+
+ # This file should always exist. Even if this didn't exist on the
+ # system, adding a route will have created it. What if we startup
+ # and immediately shutdown? Let's be sure.
+ if [ ! -f "$rt_tables" ] ; then
+ mkdir -p "${rt_tables%/*}" # dirname
+ touch "$rt_tables"
+ fi
+}
+
+# Setup a table id to use for the given IP. We don't need to know it,
+# it just needs to exist in /etc/iproute2/rt_tables. Fail if no free
+# table id could be found in the configured range.
+ensure_table_id_for_ip ()
+{
+ _ip=$1
+
+ ensure_rt_tables
+
+ # Maintain a table id for each IP address we've ever seen in
+ # rt_tables. We use a "ctdb." prefix on the label.
+ _label="${table_id_prefix}${_ip}"
+
+ # This finds either the table id corresponding to the label or a
+ # new unused one (that is greater than all the used ones in the
+ # range).
+ (
+ # Note that die() just gets us out of the subshell...
+ flock --timeout 30 9 || \
+ die "ensure_table_id_for_ip: failed to lock file $rt_tables"
+
+ _new="$CTDB_PER_IP_ROUTING_TABLE_ID_LOW"
+ while read _t _l ; do
+ # Skip comments
+ case "$_t" in
+ \#*) continue ;;
+ esac
+ # Found existing: done
+ if [ "$_l" = "$_label" ] ; then
+ return 0
+ fi
+ # Potentially update the new table id to be used. The
+ # redirect stops error spam for a non-numeric value.
+ if [ "$_new" -le "$_t" -a \
+ "$_t" -le "$CTDB_PER_IP_ROUTING_TABLE_ID_HIGH" ] 2>/dev/null ; then
+ _new=$((_t + 1))
+ fi
+ done <"$rt_tables"
+
+ # If the new table id is legal then add it to the file and
+ # print it.
+ if [ "$_new" -le "$CTDB_PER_IP_ROUTING_TABLE_ID_HIGH" ] ; then
+ printf "%d\t%s\n" "$_new" "$_label" >>"$rt_tables"
+ return 0
+ else
+ return 1
+ fi
+ ) 9>"$rt_tables_lock"
+}
+
+# Clean up all the table ids that we might own.
+clean_up_table_ids ()
+{
+ ensure_rt_tables
+
+ (
+ # Note that die() just gets us out of the subshell...
+ flock --timeout 30 9 || \
+ die "clean_up_table_ids: failed to lock file $rt_tables"
+
+ # Delete any items from the file that have a table id in our
+ # range or a label matching our label. Preserve comments.
+ _tmp="${rt_tables}.$$.ctdb"
+ awk -v min="$CTDB_PER_IP_ROUTING_TABLE_ID_LOW" \
+ -v max="$CTDB_PER_IP_ROUTING_TABLE_ID_HIGH" \
+ -v pre="$table_id_prefix" \
+ '/^#/ ||
+ !(min <= $1 && $1 <= max) &&
+ !(index($2, pre) == 1) {
+ print $0 }' "$rt_tables" >"$_tmp"
+
+ mv "$_tmp" "$rt_tables"
+ ) 9>"$rt_tables_lock"
+}
+
+######################################################################
+
+# This prints the config for an IP, which is either relevant entries
+# from the config file or, if set to the magic link local value, some
+# link local routing config for the IP.
+get_config_for_ip ()
+{
+ _ip="$1"
+
+ if have_link_local_config ; then
+ # When parsing public_addresses also split on '/'. This means
+ # that we get the maskbits as item #2 without further parsing.
+ while IFS="/$IFS" read _i _maskbits _x ; do
+ if [ "$_ip" = "$_i" ] ; then
+ printf "%s" "$_ip "; ipv4_host_addr_to_net "$_ip" "$_maskbits"
+ fi
+ done <"${CTDB_PUBLIC_ADDRESSES:-/dev/null}"
+ else
+ while read _i _rest ; do
+ if [ "$_ip" = "$_i" ] ; then
+ printf "%s\t%s\n" "$_ip" "$_rest"
+ fi
+ done <"$CTDB_PER_IP_ROUTING_CONF"
+ fi
+}
+
+ip_has_configuration ()
+{
+ _ip="$1"
+
+ _conf=$(get_config_for_ip "$_ip")
+ [ -n "$_conf" ]
+}
+
+add_routing_for_ip ()
+{
+ _iface="$1"
+ _ip="$2"
+
+ # Do nothing if no config for this IP.
+ ip_has_configuration "$_ip" || return 0
+
+ ensure_table_id_for_ip "$_ip" || \
+ die "add_routing_for_ip: out of table ids in range $CTDB_PER_IP_ROUTING_TABLE_ID_LOW - $CTDB_PER_IP_ROUTING_TABLE_ID_HIGH"
+
+ _pref="$CTDB_PER_IP_ROUTING_RULE_PREF"
+ _table_id="${table_id_prefix}${_ip}"
+
+ del_routing_for_ip "$_ip" >/dev/null 2>&1
+
+ ip rule add from "$_ip" pref "$_pref" table "$_table_id" || \
+ die "add_routing_for_ip: failed to add rule for $_ip"
+
+ # Add routes to table for any lines matching the IP.
+ get_config_for_ip "$_ip" |
+ while read _i _dest _gw ; do
+ _r="$_dest ${_gw:+via} $_gw dev $_iface table $_table_id"
+ # Intentionally unquoted multi-word value here
+ # shellcheck disable=SC2086
+ ip route add $_r || \
+ die "add_routing_for_ip: failed to add route: $_r"
+ done
+}
+
+del_routing_for_ip ()
+{
+ _ip="$1"
+
+ _pref="$CTDB_PER_IP_ROUTING_RULE_PREF"
+ _table_id="${table_id_prefix}${_ip}"
+
+ # Do this unconditionally since we own any matching table ids.
+ # However, print a meaningful message if something goes wrong.
+ _cmd="ip rule del from $_ip pref $_pref table $_table_id"
+ _out=$($_cmd 2>&1) || \
+ cat <<EOF
+WARNING: Failed to delete policy routing rule
+ Command "$_cmd" failed:
+ $_out
+EOF
+ # This should never usually fail, so don't redirect output.
+ # However, it can fail when deleting a rogue IP, since there will
+ # be no routes for that IP. In this case it should only fail when
+ # the rule deletion above has already failed because the table id
+ # is invalid. Therefore, go to a little bit of trouble to indent
+ # the failure message so that it is associated with the above
+ # warning message and doesn't look too nasty.
+ ip route flush table "$_table_id" 2>&1 | sed -e 's@^.@ &@'
+}
+
+######################################################################
+
+flush_rules_and_routes ()
+{
+ ip rule show |
+ while read _p _x _i _x _t ; do
+ # Remove trailing colon after priority/preference.
+ _p="${_p%:}"
+ # Only remove rules that match our priority/preference.
+ [ "$CTDB_PER_IP_ROUTING_RULE_PREF" = "$_p" ] || continue
+
+ echo "Removing ip rule for public address $_i for routing table $_t"
+ ip rule del from "$_i" table "$_t" pref "$_p"
+ ip route flush table "$_t" 2>/dev/null
+ done
+}
+
+# Add any missing routes. Some might have gone missing if, for
+# example, all IPs on the network were removed (possibly if the
+# primary was removed). If $1 is "force" then (re-)add all the
+# routes.
+add_missing_routes ()
+{
+ $CTDB ip -v -X | {
+ read _x # skip header line
+
+ # Read the rest of the lines. We're only interested in the
+ # "IP" and "ActiveInterface" columns. The latter is only set
+ # for addresses local to this node, making it easy to skip
+ # non-local addresses. For each IP local address we check if
+ # the relevant routing table is populated and populate it if
+ # not.
+ while IFS="|" read _x _ip _x _iface _x ; do
+ [ -n "$_iface" ] || continue
+
+ _table_id="${table_id_prefix}${_ip}"
+ if [ -z "$(ip route show table "$_table_id" 2>/dev/null)" -o \
+ "$1" = "force" ] ; then
+ add_routing_for_ip "$_iface" "$_ip"
+ fi
+ done
+ } || exit $?
+}
+
+# Remove rules/routes for addresses that we're not hosting. If a
+# releaseip event failed in an earlier script then we might not have
+# had a chance to remove the corresponding rules/routes.
+remove_bogus_routes ()
+{
+ # Get a IPs current hosted by this node, each anchored with '@'.
+ _ips=$($CTDB ip -v -X | awk -F'|' 'NR > 1 && $4 != "" {printf "@%s@\n", $2}')
+
+ # x is intentionally ignored
+ # shellcheck disable=SC2034
+ ip rule show |
+ while read _p _x _i _x _t ; do
+ # Remove trailing colon after priority/preference.
+ _p="${_p%:}"
+ # Only remove rules that match our priority/preference.
+ [ "$CTDB_PER_IP_ROUTING_RULE_PREF" = "$_p" ] || continue
+ # Only remove rules for which we don't have an IP. This could
+ # be done with grep, but let's do it with shell prefix removal
+ # to avoid unnecessary processes. This falls through if
+ # "@${_i}@" isn't present in $_ips.
+ [ "$_ips" = "${_ips#*@${_i}@}" ] || continue
+
+ echo "Removing ip rule/routes for unhosted public address $_i"
+ del_routing_for_ip "$_i"
+ done
+}
+
+######################################################################
+
+service_reconfigure ()
+{
+ add_missing_routes "force"
+ remove_bogus_routes
+
+ # flush our route cache
+ set_proc sys/net/ipv4/route/flush 1
+}
+
+######################################################################
+
+ctdb_check_args "$@"
+
+case "$1" in
+startup)
+ flush_rules_and_routes
+
+ # make sure that we only respond to ARP messages from the NIC
+ # where a particular ip address is associated.
+ get_proc sys/net/ipv4/conf/all/arp_filter >/dev/null 2>&1 && {
+ set_proc sys/net/ipv4/conf/all/arp_filter 1
+ }
+ ;;
+
+shutdown)
+ flush_rules_and_routes
+ clean_up_table_ids
+ ;;
+
+takeip)
+ iface=$2
+ ip=$3
+ # maskbits included here so argument order is obvious
+ # shellcheck disable=SC2034
+ maskbits=$4
+
+ ensure_ipv4_is_valid_addr "$1" "$ip"
+ add_routing_for_ip "$iface" "$ip"
+
+ # flush our route cache
+ set_proc sys/net/ipv4/route/flush 1
+
+ $CTDB gratarp "$ip" "$iface"
+ ;;
+
+updateip)
+ # oiface, maskbits included here so argument order is obvious
+ # shellcheck disable=SC2034
+ oiface=$2
+ niface=$3
+ ip=$4
+ # shellcheck disable=SC2034
+ maskbits=$5
+
+ ensure_ipv4_is_valid_addr "$1" "$ip"
+ add_routing_for_ip "$niface" "$ip"
+
+ # flush our route cache
+ set_proc sys/net/ipv4/route/flush 1
+
+ $CTDB gratarp "$ip" "$niface"
+ tickle_tcp_connections "$ip"
+ ;;
+
+releaseip)
+ iface=$2
+ ip=$3
+ # maskbits included here so argument order is obvious
+ # shellcheck disable=SC2034
+ maskbits=$4
+
+ ensure_ipv4_is_valid_addr "$1" "$ip"
+ del_routing_for_ip "$ip"
+ ;;
+
+ipreallocated)
+ add_missing_routes
+ remove_bogus_routes
+ ;;
+
+reconfigure)
+ ctdb_service_reconfigure
+ ;;
+esac
+
+exit 0
--- /dev/null
+#!/bin/sh
+# ctdb event script for monitoring the multipath daemon
+#
+# Configure monitporing of multipath devices by listing the device serials
+# in /etc/ctdb/multipathd :
+# CTDB_MONITOR_MPDEVICES="device1 device2 ..."
+#
+
+[ -n "$CTDB_BASE" ] || \
+ CTDB_BASE=$(d=$(dirname "$0") ; cd -P "$d" ; dirname "$PWD")
+
+. "${CTDB_BASE}/functions"
+
+# service_name is used by various functions
+# shellcheck disable=SC2034
+service_name="multipathd"
+
+loadconfig
+
+[ -n "$CTDB_MONITOR_MPDEVICES" ] || exit 0
+
+service_state_dir=$(ctdb_setup_service_state_dir) || exit $?
+
+multipath_fail="${service_state_dir}/fail"
+
+multipathd_check_background()
+{
+ for _device in $CTDB_MONITOR_MPDEVICES; do
+ # Check multipath knows about the device
+ _out=$(multipath -ll "$_device")
+ if [ -z "$_out" ] ; then
+ echo "ERROR: device \"${_device}\" not known to multipathd" \
+ >"$multipath_fail"
+ exit 1
+ fi
+
+ # Check for at least 1 active path
+ if ! echo "$_out" | grep 'prio=.* status=active' >/dev/null 2>&1 ; then
+ echo "ERROR: multipath device \"${_device}\" has no active paths" \
+ >"$multipath_fail"
+ exit 1
+ fi
+ done
+ exit 0
+}
+
+multipathd_check()
+{
+ # Run the actual check in the background since the call to
+ # multipath may block
+ multipathd_check_background </dev/null >/dev/null 2>&1 &
+ _pid="$!"
+ _timeleft=10
+
+ while [ $_timeleft -gt 0 ]; do
+ _timeleft=$((_timeleft - 1))
+
+ # see if the process still exists
+ kill -0 $_pid >/dev/null 2>&1 || {
+ if wait $_pid ; then
+ return 0
+ else
+ cat "$multipath_fail"
+ rm -f "$multipath_fail"
+ return 1
+ fi
+ }
+ sleep 1
+ done
+
+ echo "ERROR: callout to multipath checks hung"
+ # If hung then this probably won't work, but worth trying...
+ kill -9 $_pid >/dev/null 2>&1
+ return 1
+}
+
+case "$1" in
+monitor)
+ multipathd_check || die "multipath monitoring failed"
+ ;;
+esac
+
+exit 0
--- /dev/null
+#!/bin/sh
+# event script to manage clamd in a cluster environment
+
+[ -n "$CTDB_BASE" ] || \
+ CTDB_BASE=$(d=$(dirname "$0") ; cd -P "$d" ; dirname "$PWD")
+
+. "${CTDB_BASE}/functions"
+
+detect_init_style
+
+case $CTDB_INIT_STYLE in
+redhat)
+ service_name="clamd"
+ # service_config is used by loadconfig()
+ # shellcheck disable=SC2034
+ service_config="clamd"
+ ;;
+*)
+ service_name="clamav"
+ # service_config is used by loadconfig()
+ # shellcheck disable=SC2034
+ service_config="clamav"
+ ;;
+esac
+
+loadconfig
+
+is_ctdb_managed_service || exit 0
+
+case "$1" in
+startup)
+ service "$service_name" stop > /dev/null 2>&1
+ service "$service_name" start || exit $?
+ ;;
+
+shutdown)
+ service "$service_name"_stop
+ ;;
+
+monitor)
+ ctdb_check_unix_socket "$CTDB_CLAMD_SOCKET" || exit $?
+ ;;
+esac
+
+exit 0
--- /dev/null
+#!/bin/sh
+# event strict to manage vsftpd in a cluster environment
+
+[ -n "$CTDB_BASE" ] || \
+ CTDB_BASE=$(d=$(dirname "$0") ; cd -P "$d" ; dirname "$PWD")
+
+. "${CTDB_BASE}/functions"
+
+service_name="vsftpd"
+
+service_reconfigure ()
+{
+ service $service_name restart
+}
+
+loadconfig
+
+is_ctdb_managed_service || exit 0
+
+case "$1" in
+startup)
+ service "$service_name" stop > /dev/null 2>&1
+ service "$service_name" start
+ ctdb_counter_init
+ ;;
+
+shutdown)
+ service "$service_name" stop
+ ;;
+
+takeip|releaseip)
+ ctdb_service_set_reconfigure
+ ;;
+
+ipreallocated)
+ if ctdb_service_needs_reconfigure ; then
+ ctdb_service_reconfigure
+ fi
+ ;;
+
+monitor)
+ if ctdb_check_tcp_ports 21 ; then
+ ctdb_counter_init
+ else
+ ctdb_counter_incr
+ num_fails=$(ctdb_counter_get)
+ if [ "$num_fails" -ge 2 ] ; then
+ die "ERROR: ${num_fails} consecutive failures for vsftpd, marking node unhealthy"
+ elif [ "$num_fails" -eq 1 ] ; then
+ echo "WARNING: vsftpd not listening but less than 2 consecutive failures, not unhealthy yet"
+ fi
+ fi
+ ;;
+esac
+
+exit 0
--- /dev/null
+#!/bin/sh
+# event script to manage httpd in a cluster environment
+
+[ -n "$CTDB_BASE" ] || \
+ CTDB_BASE=$(d=$(dirname "$0") ; cd -P "$d" ; dirname "$PWD")
+
+. "${CTDB_BASE}/functions"
+
+detect_init_style
+
+case $CTDB_INIT_STYLE in
+redhat)
+ service_name="httpd"
+ # service_config is used by loadconfig()
+ # shellcheck disable=SC2034
+ service_config="http"
+ ;;
+suse|debian|*)
+ service_name="apache2"
+ # service_config is used by loadconfig()
+ # shellcheck disable=SC2034
+ service_config="apache2"
+ ;;
+esac
+
+# RHEL5 sometimes use a SIGKILL to terminate httpd, which then leaks
+# semaphores. This is a hack to clean them up.
+cleanup_httpd_semaphore_leak() {
+ killall -q -0 "$service_name" ||
+ for i in $(ipcs -s | awk '$3 == "apache" { print $2 }') ; do
+ ipcrm -s "$i"
+ done
+}
+
+##########
+
+service_start ()
+{
+ cleanup_httpd_semaphore_leak
+ service $service_name start
+}
+service_stop ()
+{
+ service $service_name stop
+ killall -q -9 $service_name || true
+}
+
+loadconfig
+
+is_ctdb_managed_service || exit 0
+
+case "$1" in
+startup)
+ service_start
+ ctdb_counter_int
+ ;;
+
+shutdown)
+ service_stop
+ ;;
+
+monitor)
+ if ctdb_check_tcp_ports 80 >/dev/null 2>/dev/null ; then
+ ctdb_counter_init
+ else
+ ctdb_counter_incr
+ num_fails=$(ctdb_counter_get)
+ if [ "$num_fails" -eq 2 ] ; then
+ echo "HTTPD is not running. Trying to restart HTTPD."
+ service_stop
+ service_start
+ exit 0
+ elif [ "$num_fails" -ge 5 ] ; then
+ echo "HTTPD is not running. Trying to restart HTTPD."
+ service_stop
+ service_start
+ exit 1
+ fi
+ fi
+ ;;
+esac
+
+exit 0
+
--- /dev/null
+#!/bin/sh
+# ctdb event script for winbind
+
+[ -n "$CTDB_BASE" ] || \
+ CTDB_BASE=$(d=$(dirname "$0") ; cd -P "$d" ; dirname "$PWD")
+
+. "${CTDB_BASE}/functions"
+
+CTDB_SERVICE_WINBIND=${CTDB_SERVICE_WINBIND:-winbind}
+
+# service_name is used by various functions
+# shellcheck disable=SC2034
+service_name="winbind"
+
+loadconfig
+
+service_start ()
+{
+ service "$CTDB_SERVICE_WINBIND" stop >/dev/null 2>&1
+ killall -0 -q winbindd && {
+ sleep 1
+ # make absolutely sure winbindd is dead
+ killall -q -9 winbindd
+ }
+
+ service "$CTDB_SERVICE_WINBIND" start || \
+ die "Failed to start winbind"
+}
+
+service_stop ()
+{
+ service "$CTDB_SERVICE_WINBIND" stop
+}
+
+###########################
+
+is_ctdb_managed_service || exit 0
+
+###########################
+
+case "$1" in
+startup)
+ service_start
+ ;;
+
+shutdown)
+ service_stop
+ ;;
+
+monitor)
+ if ! out=$(wbinfo -p 2>&1) ; then
+ echo "ERROR: wbinfo -p returned error"
+ echo "$out"
+ exit 1
+ fi
+ ;;
+esac
+
+exit 0
--- /dev/null
+#!/bin/sh
+# ctdb event script for Samba
+
+[ -n "$CTDB_BASE" ] || \
+ CTDB_BASE=$(d=$(dirname "$0") ; cd -P "$d" ; dirname "$PWD")
+
+. "${CTDB_BASE}/functions"
+
+detect_init_style
+
+case $CTDB_INIT_STYLE in
+ suse)
+ CTDB_SERVICE_SMB=${CTDB_SERVICE_SMB:-smb}
+ CTDB_SERVICE_NMB=${CTDB_SERVICE_NMB:-nmb}
+ ;;
+ debian)
+ CTDB_SERVICE_SMB=${CTDB_SERVICE_SMB:-smbd}
+ CTDB_SERVICE_NMB=${CTDB_SERVICE_NMB:-nmbd}
+ ;;
+ *)
+ # Use redhat style as default:
+ CTDB_SERVICE_SMB=${CTDB_SERVICE_SMB:-smb}
+ CTDB_SERVICE_NMB=${CTDB_SERVICE_NMB:-""}
+ ;;
+esac
+
+# service_name is used by various functions
+# shellcheck disable=SC2034
+service_name="samba"
+
+loadconfig
+
+service_state_dir=$(ctdb_setup_service_state_dir) || exit $?
+
+service_start ()
+{
+ # make sure samba is not already started
+ service "$CTDB_SERVICE_SMB" stop > /dev/null 2>&1
+ if [ -n "$CTDB_SERVICE_NMB" ] ; then
+ service "$CTDB_SERVICE_NMB" stop > /dev/null 2>&1
+ fi
+ killall -0 -q smbd && {
+ sleep 1
+ # make absolutely sure samba is dead
+ killall -q -9 smbd
+ }
+ killall -0 -q nmbd && {
+ sleep 1
+ # make absolutely sure samba is dead
+ killall -q -9 nmbd
+ }
+
+ # start Samba service. Start it reniced, as under very heavy load
+ # the number of smbd processes will mean that it leaves few cycles
+ # for anything else
+ net serverid wipe
+
+ if [ -n "$CTDB_SERVICE_NMB" ] ; then
+ nice_service "$CTDB_SERVICE_NMB" start || die "Failed to start nmbd"
+ fi
+
+ nice_service "$CTDB_SERVICE_SMB" start || die "Failed to start samba"
+}
+
+service_stop ()
+{
+ service "$CTDB_SERVICE_SMB" stop
+ program_stack_traces "smbd" 5
+ if [ -n "$CTDB_SERVICE_NMB" ] ; then
+ service "$CTDB_SERVICE_NMB" stop
+ fi
+}
+
+######################################################################
+# Show the testparm output using a cached smb.conf to avoid delays due
+# to registry access.
+
+smbconf_cache="$service_state_dir/smb.conf.cache"
+
+testparm_foreground_update ()
+{
+ _timeout="$1"
+
+ # No need to remove these temporary files, since there are only 2
+ # of them.
+ _out="${smbconf_cache}.out"
+ _err="${smbconf_cache}.err"
+
+ timeout "$_timeout" testparm -v -s >"$_out" 2>"$_err"
+ case $? in
+ 0) : ;;
+ 124)
+ if [ -f "$smbconf_cache" ] ; then
+ echo "WARNING: smb.conf cache update timed out - using old cache file"
+ return 1
+ else
+ echo "ERROR: smb.conf cache create failed - testparm command timed out"
+ exit 1
+ fi
+ ;;
+ *)
+ if [ -f "$smbconf_cache" ] ; then
+ echo "WARNING: smb.conf cache update failed - using old cache file"
+ cat "$_err"
+ return 1
+ else
+ echo "ERROR: smb.conf cache create failed - testparm failed with:"
+ cat "$_err"
+ exit 1
+ fi
+ esac
+
+ # Only using $$ here to avoid a collision. This is written into
+ # CTDB's own state directory so there is no real need for a secure
+ # temporary file.
+ _tmpfile="${smbconf_cache}.$$"
+ # Patterns to exclude...
+ _pat='^[[:space:]]+(registry[[:space:]]+shares|include|copy|winbind[[:space:]]+separator)[[:space:]]+='
+ grep -Ev "$_pat" <"$_out" >"$_tmpfile"
+ mv "$_tmpfile" "$smbconf_cache" # atomic
+
+ return 0
+}
+
+testparm_background_update ()
+{
+ _timeout="$1"
+
+ testparm_foreground_update "$_timeout" >/dev/null 2>&1 </dev/null &
+}
+
+testparm_cat ()
+{
+ testparm -s "$smbconf_cache" "$@" 2>/dev/null
+}
+
+list_samba_shares ()
+{
+ testparm_cat |
+ sed -n -e 's@^[[:space:]]*path[[:space:]]*=[[:space:]]@@p' |
+ sed -e 's/"//g'
+}
+
+list_samba_ports ()
+{
+ testparm_cat --parameter-name="smb ports" |
+ sed -e 's@,@ @g'
+}
+
+###########################
+
+is_ctdb_managed_service || exit 0
+
+###########################
+
+case "$1" in
+startup)
+ service_start
+ ;;
+
+shutdown)
+ service_stop
+ ;;
+
+monitor)
+ testparm_foreground_update 10
+ ret=$?
+
+ smb_ports="$CTDB_SAMBA_CHECK_PORTS"
+ if [ -z "$smb_ports" ] ; then
+ smb_ports=$(list_samba_ports)
+ [ -n "$smb_ports" ] || die "Failed to set smb ports"
+ fi
+ # Intentionally unquoted multi-word value here
+ # shellcheck disable=SC2086
+ ctdb_check_tcp_ports $smb_ports || exit $?
+
+ if [ "$CTDB_SAMBA_SKIP_SHARE_CHECK" != "yes" ] ; then
+ list_samba_shares | ctdb_check_directories || exit $?
+ fi
+
+ if [ $ret -ne 0 ] ; then
+ testparm_background_update 10
+ fi
+ ;;
+esac
+
+exit 0
--- /dev/null
+#!/bin/sh
+# script to manage nfs in a clustered environment
+
+[ -n "$CTDB_BASE" ] || \
+ CTDB_BASE=$(d=$(dirname "$0") ; cd -P "$d" ; dirname "$PWD")
+
+. "${CTDB_BASE}/functions"
+
+# service_name is used by various functions
+# shellcheck disable=SC2034
+service_name="nfs"
+
+loadconfig
+service_state_dir=$(ctdb_setup_service_state_dir) || exit $?
+
+######################################################################
+
+service_reconfigure ()
+{
+ # Restart lock manager, notify clients
+ if [ -x "${CTDB_BASE}/statd-callout" ] ; then
+ "${CTDB_BASE}/statd-callout" notify &
+ fi >/dev/null 2>&1
+}
+
+######################################################################
+
+######################################################
+# Check the health of NFS services
+#
+# Use .check files in $CTDB_NFS_CHECKS_DIR.
+# Default is "${CTDB_BASE}/nfs-checks.d/"
+######################################################
+nfs_check_services ()
+{
+ _dir="${CTDB_NFS_CHECKS_DIR:-${CTDB_BASE}/nfs-checks.d}"
+
+ # Files must end with .check - avoids editor backups, RPM fu, ...
+ for _f in "$_dir"/[0-9][0-9].*.check ; do
+ [ -r "$_f" ] || continue
+
+ _t="${_f%.check}"
+ _progname="${_t##*/[0-9][0-9].}"
+
+ nfs_check_service "$_progname" <"$_f"
+ done
+}
+
+######################################################
+# Check the health of an NFS service
+#
+# $1 - progname, passed to rpcinfo (looked up in /etc/rpc)
+#
+# Reads variables from stdin
+#
+# Variables are:
+#
+# * family - "tcp" or "udp" or space separated list
+# default: tcp, not used with "service_check_cmd"
+# * version - optional, RPC service version number
+# default is to omit to check for any version,
+# not used with "service_check_cmd"
+# * unhealthy_after - number of check fails before unhealthy
+# default: 1
+# * restart_every - number of check fails before restart
+# default: 0, meaning no restart
+# * service_stop_cmd - command to stop service
+# default: no default, must be provided if
+# restart_every > 0
+# * service_start_cmd - command to start service
+# default: no default, must be provided if
+# restart_every > 0
+# * service_check_cmd - command to check health of service
+# default is to check RPC service using rpcinfo
+# * service_debug_cmd - command to debug a service after trying to stop it;
+# for example, it can be useful to print stack
+# traces of threads that have not exited, since
+# they may be stuck doing I/O;
+# no default, see also function program_stack_traces()
+#
+# Quoting in values is not preserved
+#
+######################################################
+nfs_check_service ()
+{
+ _progname="$1"
+
+ # This sub-shell is created to intentionally limit the scope of
+ # variable values read from the .check files.
+ # shellcheck disable=SC2030
+ (
+ # Subshell to restrict scope variables...
+
+ # Defaults
+ family="tcp"
+ version=""
+ unhealthy_after=1
+ restart_every=0
+ service_stop_cmd=""
+ service_start_cmd=""
+ service_check_cmd=""
+ service_debug_cmd=""
+
+ # Eval line-by-line. Expands variable references in values.
+ # Also allows variable name checking, which seems useful.
+ while read _line ; do
+ case "$_line" in
+ \#*|"") : ;; # Ignore comments, blank lines
+
+ family=*|version=*|\
+ unhealthy_after=*|restart_every=*|\
+ service_stop_cmd=*|service_start_cmd=*|\
+ service_check_cmd=*|service_debug_cmd=*)
+
+ eval "$_line"
+ ;;
+ *)
+ echo "ERROR: Unknown variable for ${_progname}: ${_line}"
+ exit 1
+ esac
+ done
+
+ _service_name="nfs_${_progname}"
+
+ _ok=false
+ if [ -n "$service_check_cmd" ] ; then
+ # Using eval means variables can contain semicolon separated commands
+ if eval "$service_check_cmd" ; then
+ _ok=true
+ else
+ _err="monitoring service \"${_progname}\" failed"
+ fi
+ else
+ if nfs_check_rpcinfo \
+ "$_progname" "$version" "$family" >/dev/null ; then
+ _ok=true
+ else
+ _err="$ctdb_check_rpc_out"
+ fi
+ fi
+
+ if $_ok ; then
+ if [ $unhealthy_after -ne 1 -o $restart_every -ne 0 ] ; then
+ ctdb_counter_init "$_service_name"
+ fi
+ exit 0
+ fi
+
+ ctdb_counter_incr "$_service_name"
+ _failcount=$(ctdb_counter_get "$_service_name")
+
+ _unhealthy=false
+ if [ "$unhealthy_after" -gt 0 ] ; then
+ if [ "$_failcount" -ge "$unhealthy_after" ] ; then
+ _unhealthy=true
+ echo "ERROR: $_err"
+ fi
+ fi
+
+ if [ "$restart_every" -gt 0 ] ; then
+ if [ $((_failcount % restart_every)) -eq 0 ] ; then
+ if ! $_unhealthy ; then
+ echo "WARNING: $_err"
+ fi
+ nfs_restart_service
+ fi
+ fi
+
+ if $_unhealthy ; then
+ exit 1
+ fi
+
+ return 0
+ ) || exit 1
+}
+
+# Uses: service_stop_cmd, service_start_cmd, service_debug_cmd
+# This function is called within the sub-shell that shellcheck thinks
+# loses the above variable values.
+# shellcheck disable=SC2031
+nfs_restart_service ()
+{
+ if [ -z "$service_stop_cmd" -o -z "$service_start_cmd" ] ; then
+ die "ERROR: Can not restart service \"${_progname}\" without corresponding service_start_cmd/service_stop_cmd settings"
+ fi
+
+ echo "Trying to restart service \"${_progname}\"..."
+ # Using eval means variables can contain semicolon separated commands
+ eval "$service_stop_cmd"
+ if [ -n "$service_debug_cmd" ] ; then
+ eval "$service_debug_cmd"
+ fi
+ background_with_logging eval "$service_start_cmd"
+}
+
+######################################################
+# Check an RPC service with rpcinfo
+######################################################
+ctdb_check_rpc ()
+{
+ _progname="$1" # passed to rpcinfo (looked up in /etc/rpc)
+ _version="$2" # optional, not passed if empty/unset
+ _family="${3:-tcp}" # optional, default is "tcp"
+
+ case "$_family" in
+ tcp6|udp6)
+ _localhost="${CTDB_RPCINFO_LOCALHOST6:-::1}"
+ ;;
+ *)
+ _localhost="${CTDB_RPCINFO_LOCALHOST:-127.0.0.1}"
+ esac
+
+ # $_version is not quoted because it is optional
+ # shellcheck disable=SC2086
+ if ! ctdb_check_rpc_out=$(rpcinfo -T "$_family" "$_localhost" \
+ "$_progname" $_version 2>&1) ; then
+ ctdb_check_rpc_out="$_progname failed RPC check:
+$ctdb_check_rpc_out"
+ echo "$ctdb_check_rpc_out"
+ return 1
+ fi
+}
+
+nfs_check_rpcinfo ()
+{
+ _progname="$1" # passed to rpcinfo (looked up in /etc/rpc)
+ _versions="$2" # optional, space separated, not passed if empty/unset
+ _families="${3:-tcp}" # optional, space separated, default is "tcp"
+
+ for _family in $_families ; do
+ if [ -n "$_versions" ] ; then
+ for _version in $_versions ; do
+ ctdb_check_rpc "$_progname" "$_version" "$_family" || return $?
+ done
+ else
+ ctdb_check_rpc "$_progname" "" "$_family" || return $?
+ fi
+ done
+}
+
+##################################################################
+# use statd-callout to update NFS lock info
+##################################################################
+nfs_update_lock_info ()
+{
+ if [ -x "$CTDB_BASE/statd-callout" ] ; then
+ "$CTDB_BASE/statd-callout" update
+ fi
+}
+
+######################################################################
+
+nfs_callout_init "$service_state_dir"
+
+is_ctdb_managed_service || exit 0
+
+case "$1" in
+startup)
+ nfs_callout "$@" || exit $?
+ ;;
+
+shutdown)
+ nfs_callout "$@" || exit $?
+ ;;
+
+takeip)
+ nfs_callout "$@" || exit $?
+ ctdb_service_set_reconfigure
+ ;;
+
+releaseip)
+ nfs_callout "$@" || exit $?
+ ctdb_service_set_reconfigure
+ ;;
+
+ipreallocated)
+ if ctdb_service_needs_reconfigure ; then
+ ctdb_service_reconfigure
+ fi
+ ;;
+
+monitor)
+ nfs_callout "monitor-pre" || exit $?
+
+ # Check that directories for shares actually exist
+ if [ "$CTDB_NFS_SKIP_SHARE_CHECK" != "yes" ] ; then
+ nfs_callout "monitor-list-shares" | ctdb_check_directories || \
+ exit $?
+ fi
+
+ update_tickles 2049
+ nfs_update_lock_info
+
+ nfs_check_services
+
+ nfs_callout "monitor-post" || exit $?
+ ;;
+esac
+
+exit 0
--- /dev/null
+#!/bin/sh
+
+# CTDB event script for TGTD based iSCSI
+
+[ -n "$CTDB_BASE" ] || \
+ CTDB_BASE=$(d=$(dirname "$0") ; cd -P "$d" ; dirname "$PWD")
+
+. "${CTDB_BASE}/functions"
+
+# service_name is used by various functions
+# shellcheck disable=SC2034
+service_name="iscsi"
+
+loadconfig
+
+is_ctdb_managed_service || exit 0
+
+[ -z "$CTDB_START_ISCSI_SCRIPTS" ] && {
+ echo "No iscsi start script directory found"
+ exit 0
+}
+
+case "$1" in
+ipreallocated)
+ all_ips=$($CTDB -X ip | tail -n +2)
+
+ # Block the iSCSI port. Only block for the address families
+ # we have configured. This copes with, for example, ip6tables
+ # being unavailable on an IPv4-only system.
+ have_ipv4=false
+ have_ipv6=false
+ # x is intentionally ignored
+ # shellcheck disable=SC2034
+ while IFS='|' read x ip pnn x ; do
+ case "$ip" in
+ *:*) have_ipv6=true ;;
+ *) have_ipv4=true ;;
+ esac
+ done <<EOF
+$all_ips
+EOF
+ if $have_ipv4 ; then
+ iptables -I INPUT 1 -p tcp --dport 3260 -j DROP
+ fi
+ if $have_ipv6 ; then
+ ip6tables -I INPUT 1 -p tcp --dport 3260 -j DROP
+ fi
+
+ # Stop iSCSI daemon
+ killall -9 tgtd >/dev/null 2>/dev/null
+
+ pnn=$(ctdb_get_pnn)
+ [ -n "$pnn" ] || die "Failed to get node pnn"
+
+ # Start iSCSI daemon
+ tgtd >/dev/null 2>&1
+
+ # Run a script for each currently hosted public IP address
+ ips=$(echo "$all_ips" | awk -F'|' -v pnn="$pnn" '$3 == pnn {print $2}')
+ for ip in $ips ; do
+ script="${CTDB_START_ISCSI_SCRIPTS}/${ip}.sh"
+ if [ -x "$script" ] ; then
+ echo "Starting iSCSI service for public address ${ip}"
+ "$script"
+ fi
+ done
+
+ # Unblock iSCSI port. These can be unconditional (compared to
+ # blocking above), since errors are redirected.
+ while iptables -D INPUT -p tcp --dport 3260 -j DROP >/dev/null 2>&1 ; do
+ :
+ done
+ while ip6tables -D INPUT -p tcp --dport 3260 -j DROP >/dev/null 2>&1 ; do
+ :
+ done
+
+ ;;
+
+shutdown)
+ # Shutdown iSCSI daemon when ctdb goes down
+ killall -9 tgtd >/dev/null 2>&1
+ ;;
+
+monitor)
+ ctdb_check_tcp_ports 3260 || exit $?
+ ;;
+esac
+
+exit 0
--- /dev/null
+#!/bin/sh
+# script to manage the lvs ip multiplexer for a single public address cluster
+
+[ -n "$CTDB_BASE" ] || \
+ CTDB_BASE=$(d=$(dirname "$0") ; cd -P "$d" ; dirname "$PWD")
+
+. "${CTDB_BASE}/functions"
+
+loadconfig ctdb
+
+[ -n "$CTDB_LVS_NODES" ] || exit 0
+export CTDB_LVS_NODES
+
+# type is commonly supported and more portable than which(1)
+# shellcheck disable=SC2039
+if ! type ipvsadm >/dev/null 2>&1 ; then
+ echo "LVS configured but ipvsadm not found"
+ exit 0
+fi
+
+
+lvs_slave_only ()
+{
+ _ip_address=$(ctdb_get_ip_address)
+ awk -v my_ip="$_ip_address" \
+ '$1 == my_ip { if ($2 ~ "slave-only") { exit 0 } else { exit 1 } }' \
+ "$CTDB_LVS_NODES"
+}
+
+lvs_check_config ()
+{
+ [ -r "$CTDB_LVS_NODES" ] || \
+ die "error: CTDB_LVS_NODES=${CTDB_LVS_NODES} unreadable"
+ [ -n "$CTDB_LVS_PUBLIC_IP" ] || \
+ die "Invalid configuration: CTDB_LVS_PUBLIC_IP not set"
+ if ! lvs_slave_only ; then
+ [ -n "$CTDB_LVS_PUBLIC_IFACE" ] || \
+ die "Invalid configuration: CTDB_LVS_PUBLIC_IFACE not set"
+ fi
+
+ if [ "$CTDB_PARTIALLY_ONLINE_INTERFACES" = "yes" ] ; then
+ die "Invalid configuration: CTDB_PARTIALLY_ONLINE_INTERFACES=yes incompatible with LVS"
+ fi
+}
+
+case "$1" in
+setup)
+ lvs_check_config
+ ;;
+startup)
+ lvs_check_config
+
+ ipvsadm -D -t "$CTDB_LVS_PUBLIC_IP" >/dev/null 2>&1
+ ipvsadm -D -u "$CTDB_LVS_PUBLIC_IP" >/dev/null 2>&1
+
+ ip addr add "${CTDB_LVS_PUBLIC_IP}/32" dev lo scope host
+
+ # do not respond to ARPs that are for ip addresses with scope 'host'
+ set_proc_maybe sys/net/ipv4/conf/all/arp_ignore 3
+ # do not send out arp requests from loopback addresses
+ set_proc_maybe sys/net/ipv4/conf/all/arp_announce 2
+ ;;
+
+shutdown)
+ lvs_check_config
+
+ ipvsadm -D -t "$CTDB_LVS_PUBLIC_IP"
+ ipvsadm -D -u "$CTDB_LVS_PUBLIC_IP"
+
+ ip addr del "${CTDB_LVS_PUBLIC_IP}/32" dev lo >/dev/null 2>&1
+
+ flush_route_cache
+ ;;
+
+ipreallocated)
+ lvs_check_config
+
+ # Kill connections
+ ipvsadm -D -t "$CTDB_LVS_PUBLIC_IP" >/dev/null 2>&1
+ ipvsadm -D -u "$CTDB_LVS_PUBLIC_IP" >/dev/null 2>&1
+ kill_tcp_connections_local_only \
+ "$CTDB_LVS_PUBLIC_IFACE" "$CTDB_LVS_PUBLIC_IP"
+
+ pnn=$(ctdb_get_pnn)
+ lvsmaster=$("${CTDB_HELPER_BINDIR}/ctdb_lvs" master)
+ if [ "$pnn" != "$lvsmaster" ] ; then
+ # This node is not the LVS master so change the IP address
+ # to have scope "host" so this node won't respond to ARPs
+ ip addr del "${CTDB_LVS_PUBLIC_IP}/32" dev lo >/dev/null 2>&1
+ ip addr add "${CTDB_LVS_PUBLIC_IP}/32" dev lo scope host
+ exit 0
+ fi
+
+ # Change the scope so this node starts responding to ARPs
+ ip addr del "${CTDB_LVS_PUBLIC_IP}/32" dev lo >/dev/null 2>&1
+ ip addr add "${CTDB_LVS_PUBLIC_IP}/32" dev lo >/dev/null 2>&1
+
+ ipvsadm -A -t "$CTDB_LVS_PUBLIC_IP" -p 1999999 -s lc
+ ipvsadm -A -u "$CTDB_LVS_PUBLIC_IP" -p 1999999 -s lc
+
+ # Add all nodes (except this node) as LVS servers
+ "${CTDB_HELPER_BINDIR}/ctdb_lvs" list |
+ awk -v pnn="$pnn" '$1 != pnn { print $2 }' |
+ while read ip ; do
+ ipvsadm -a -t "$CTDB_LVS_PUBLIC_IP" -r "$ip" -g
+ ipvsadm -a -u "$CTDB_LVS_PUBLIC_IP" -r "$ip" -g
+ done
+
+ # Add localhost too...
+ ipvsadm -a -t "$CTDB_LVS_PUBLIC_IP" -r 127.0.0.1
+ ipvsadm -a -u "$CTDB_LVS_PUBLIC_IP" -r 127.0.0.1
+
+ $CTDB gratarp \
+ "$CTDB_LVS_PUBLIC_IP" "$CTDB_LVS_PUBLIC_IFACE" >/dev/null 2>&1
+
+ flush_route_cache
+ ;;
+
+monitor)
+ lvs_check_config
+
+ if [ -n "$CTDB_LVS_PUBLIC_IFACE" ] ; then
+ interface_monitor "$CTDB_LVS_PUBLIC_IFACE" || exit 1
+ fi
+ ;;
+esac
+
+exit 0
--- /dev/null
+#!/bin/sh
+#
+# Event script to just sleep longer than the timeout
+# in the monitor action. The purpose is to trigger
+# the event timeout mechanism.
+
+[ -n "$CTDB_BASE" ] || \
+ CTDB_BASE=$(d=$(dirname "$0") ; cd -P "$d" ; dirname "$PWD")
+
+. "${CTDB_BASE}/functions"
+
+loadconfig ctdb
+
+[ "$CTDB_RUN_TIMEOUT_MONITOR" = "yes" ] || exit 0
+
+case "$1" in
+monitor)
+ TIMEOUT=$($CTDB getvar EventScriptTimeout | awk '{print $3}')
+ echo "sleeping for $((TIMEOUT * 2)) seconds..."
+ sleep $((TIMEOUT * 2))
+ ;;
+esac
+
+exit 0
+
--- /dev/null
+The events.d/ directory contains event scripts used by CTDB. Event
+scripts are triggered on certain events, such as startup, monitoring
+or public IP allocation. Scripts may be specific to services,
+networking or internal CTDB operations.
+
+All event scripts start with the prefix 'NN.' where N is a digit. The
+event scripts are run in sequence based on NN. Thus 10.interface will
+be run before 60.nfs. It is recommended to keep each NN unique.
+However, scripts with the same NN prefix will be executed in
+alphanumeric sort order.
+
+As a special case, any eventscript that ends with a '~' character will be
+ignored since this is a common postfix that some editors will append to
+older versions of a file. Similarly, any eventscript with multiple '.'s
+will be ignored as package managers can create copies with additional
+suffix starting with '.' (e.g. .rpmnew, .dpkg-dist).
+
+Only executable event scripts are run by CTDB. Any event script that
+does not have execute permission is ignored.
+
+The eventscripts are called with varying number of arguments. The
+first argument is the event name and the rest of the arguments depend
+on the event name.
+
+Event scripts must return 0 for success and non-zero for failure.
+
+Output of event scripts is logged. On failure the output of the
+failing event script is included in the output of "ctdb scriptstatus".
+
+The following events are supported (with arguments shown):
+
+init
+
+ This event is triggered once when CTDB is starting up. This
+ event is used to do some basic cleanup and initialisation.
+
+ During the "init" event CTDB is not listening on its Unix
+ domain socket, so the "ctdb" CLI will not work.
+
+ Failure of this event will cause CTDB to terminate.
+
+ Example: 00.ctdb creates $CTDB_SCRIPT_VARDIR
+
+setup
+
+ This event is triggered once, after the "init" event has
+ completed.
+
+ For this and any subsequent events the CTDB Unix domain socket
+ is available, so the "ctdb" CLI will work.
+
+ Failure of this event will cause CTDB to terminate.
+
+ Example: 00.ctdb processes tunables defined in the CTDB
+ configuration using CTDB_SET_<TunableName>=<TunableValue>.
+
+startup
+
+ This event is triggered after the "setup" event has completed
+ and CTDB has finished its initial database recovery.
+
+ This event starts all services that are managed by CTDB. Each
+ service that is managed by CTDB should implement this event
+ and use it to (re)start the service.
+
+ If the "startup" event fails then CTDB will retry it until it
+ succeeds. There is no limit on the number of retries.
+
+ Example: 50.samba uses this event to start the Samba daemon if
+ CTDB_MANAGES_SAMBA=yes.
+
+shutdown
+
+ This event is triggered when CTDB is shutting down.
+
+ This event shuts down all services that are managed by CTDB.
+ Each service that is managed by CTDB should implement this
+ event and use it to stop the service.
+
+ Example: 50.samba uses this event to shut down the Samba
+ daemon if CTDB_MANAGES_SAMBA=yes.
+
+monitor
+
+ This event is run periodically. The interval between
+ successive "monitor" events is configured using the
+ MonitorInterval tunable, which defaults to 15 seconds.
+
+ This event is triggered by CTDB to continuously monitor that
+ all managed services are healthy. If all event scripts
+ complete then the monitor event successfully then the node is
+ marked HEALTHY. If any event script fails then no subsequent
+ scripts will be run for that event and the node is marked
+ UNHEALTHY.
+
+ Each service that is managed by CTDB should implement this
+ event and use it to monitor the service.
+
+ Example: 10.interface checks that each configured interface
+ for public IP addresses has a physical link established.
+
+startrecovery
+
+ This event is triggered every time a database recovery process
+ is started.
+
+ This is rarely used.
+
+recovered
+
+ This event is triggered every time a database recovery process
+ is completed.
+
+ This is rarely used.
+
+takeip <interface> <ip-address> <netmask-bits>
+
+ This event is triggered for each public IP address taken by a
+ node during IP address (re)assignment. Multiple "takeip"
+ events can be run in parallel if multiple IP addresses are
+ being assigned.
+
+ Example: In 10.interface the "ip" command (from the Linux
+ iproute2 package) is used to add the specified public IP
+ address to the specified interface. The "ip" command can
+ safely be run concurrently. However, the "iptables" command
+ cannot be run concurrently so a wrapper is used to serialise
+ runs using exclusive locking.
+
+ If substantial work is required to reconfigure a service when
+ a public IP address is taken over it can be better to defer
+ service reconfiguration to the "ipreallocated" event, after
+ all IP addresses have been assigned.
+
+ Example: 60.nfs uses ctdb_service_set_reconfigure() to flag
+ that public IP addresses have changed so that service
+ reconfiguration will occur in the "ipreallocated" event.
+
+releaseip <interface> <ip-address> <netmask-bits>
+
+ This event is triggered for each public IP address released by
+ a node during IP address (re)assignment. Multiple "releaseip"
+ events can be run in parallel if multiple IP addresses are
+ being unassigned.
+
+ In all other regards, this event is analogous to the "takeip"
+ event above.
+
+updateip <old-interface> <new-interface> <ip-address> <netmask-bits>
+
+ This event is triggered for each public IP address moved
+ between interfaces on a node during IP address (re)assignment.
+ Multiple "updateip" events can be run in parallel if multiple
+ IP addresses are being moved.
+
+ This event is only used if multiple interfaces are capable of
+ hosting an IP address, as specified in the public addresses
+ configuration file.
+
+ This event is similar to the "takeip" event above.
+
+ipreallocated
+
+ This event is triggered after "releaseip", "takeip" and
+ "updateip" events during public IP address (re)assignment.
+
+ This event is used to reconfigure services.
+
+ This event runs even if public IP addresses on a node have not
+ been changed. This allows reconfiguration to depend on the
+ states of other nodes rather that just IP addresses.
+
+ Example: 11.natgw recalculates the NAT gateway master and
+ updates the relevant network configuration on each node if the
+ NAT gateway master has changed.
+
+Additional notes for "takeip", "releaseip", "updateip",
+ipreallocated":
+
+* Failure of any of these events causes IP allocation to be retried.
+
+* The "ipreallocated" event is run on all nodes. It is even run if no
+ "takeip", "releaseip" or "updateip" events were triggered.
+
+* An event script can use ctdb_service_set_reconfigure() in "takeip"
+ or "releaseip" events to flag that its service needs to be
+ reconfigured. The event script can then define a
+ service_reconfigure() function, which will be implicitly run before
+ the "ipreallocated" event. This is a useful way of performing
+ reconfiguration that is conditional upon public IP address changes.
+
+ This means an explicit "ipreallocated" event handler is usually not
+ necessary.
--- /dev/null
+# Hey Emacs, this is a -*- shell-script -*- !!!
+
+# utility functions for ctdb event scripts
+
+if [ -z "$CTDB_BASE" ] ; then
+ echo 'CTDB_BASE unset in CTDB functions file'
+ exit 1
+fi
+export CTDB_BASE
+
+# CTDB_VARDIR is used elsewhere
+# shellcheck disable=SC2034
+CTDB_VARDIR="/var/lib/ctdb"
+ctdb_rundir="/var/run/ctdb"
+
+CTDB="${CTDB:-/usr/bin/ctdb}"
+
+# Only (and always) override these variables in test code
+
+if [ -z "$CTDB_SCRIPT_VARDIR" ] ; then
+ CTDB_SCRIPT_VARDIR="/var/lib/ctdb/state"
+fi
+
+if [ -z "$CTDB_SYS_ETCDIR" ] ; then
+ CTDB_SYS_ETCDIR="/etc"
+fi
+
+if [ -z "$CTDB_HELPER_BINDIR" ] ; then
+ CTDB_HELPER_BINDIR="/usr/lib/x86_64-linux-gnu/ctdb"
+fi
+
+#######################################
+# pull in a system config file, if any
+
+rewrite_ctdb_options ()
+{
+ case "$CTDB_DBDIR" in
+ tmpfs|tmpfs:*)
+ _opts_defaults="mode=700"
+ # Get any extra options specified after colon
+ if [ "$CTDB_DBDIR" = "tmpfs" ] ; then
+ _opts=""
+ else
+ _opts="${CTDB_DBDIR#tmpfs:}"
+ fi
+ # It is OK to repeat mount options - last value wins.
+ # CTDB_DBDIR_TMPFS_OPTIONS is used by ctdbd_wrapper
+ # shellcheck disable=SC2034
+ CTDB_DBDIR_TMPFS_OPTIONS="${_opts_defaults}${_opts:+,}${_opts}"
+
+ CTDB_DBDIR="${ctdb_rundir}/CTDB_DBDIR"
+ ;;
+ *)
+ # shellcheck disable=SC2034
+ CTDB_DBDIR_TMPFS_OPTIONS=""
+ esac
+}
+
+_loadconfig() {
+
+ if [ -z "$1" ] ; then
+ foo="${service_config:-${service_name}}"
+ if [ -n "$foo" ] ; then
+ loadconfig "$foo"
+ return
+ fi
+ fi
+
+ if [ "$1" != "ctdb" ] ; then
+ loadconfig "ctdb"
+ fi
+
+ if [ -z "$1" ] ; then
+ return
+ fi
+
+ if [ -f "${CTDB_SYS_ETCDIR}/sysconfig/$1" ]; then
+ . "${CTDB_SYS_ETCDIR}/sysconfig/$1"
+ elif [ -f "${CTDB_SYS_ETCDIR}/default/$1" ]; then
+ . "${CTDB_SYS_ETCDIR}/default/$1"
+ elif [ -f "${CTDB_BASE}/sysconfig/$1" ]; then
+ . "${CTDB_BASE}/sysconfig/$1"
+ fi
+
+ if [ "$1" = "ctdb" ] ; then
+ _config="${CTDBD_CONF:-${CTDB_BASE}/ctdbd.conf}"
+ if [ -r "$_config" ] ; then
+ . "$_config"
+ fi
+ rewrite_ctdb_options
+ fi
+}
+
+loadconfig () {
+ _loadconfig "$@"
+}
+
+##############################################################
+
+die ()
+{
+ _msg="$1"
+ _rc="${2:-1}"
+
+ echo "$_msg" >&2
+ exit "$_rc"
+}
+
+# Log given message or stdin to either syslog or a CTDB log file
+# $1 is the tag passed to logger if syslog is in use.
+script_log ()
+{
+ _tag="$1" ; shift
+
+ case "$CTDB_LOGGING" in
+ file:*|"")
+ if [ -n "$CTDB_LOGGING" ] ; then
+ _file="${CTDB_LOGGING#file:}"
+ else
+ _file="/var/log/ctdb/log.ctdb"
+ fi
+ {
+ if [ -n "$*" ] ; then
+ echo "$*"
+ else
+ cat
+ fi
+ } >>"$_file"
+ ;;
+ *)
+ # Handle all syslog:* variants here too. There's no tool to do
+ # the lossy things, so just use logger.
+ logger -t "ctdbd: ${_tag}" "$@"
+ ;;
+ esac
+}
+
+# When things are run in the background in an eventscript then logging
+# output might get lost. This is the "solution". :-)
+background_with_logging ()
+{
+ (
+ "$@" 2>&1 </dev/null |
+ script_log "${script_name}&"
+ )&
+
+ return 0
+}
+
+##############################################################
+# check number of args for different events
+ctdb_check_args ()
+{
+ case "$1" in
+ takeip|releaseip)
+ if [ $# != 4 ]; then
+ echo "ERROR: must supply interface, IP and maskbits"
+ exit 1
+ fi
+ ;;
+ updateip)
+ if [ $# != 5 ]; then
+ echo "ERROR: must supply old interface, new interface, IP and maskbits"
+ exit 1
+ fi
+ ;;
+ esac
+}
+
+##############################################################
+# determine on what type of system (init style) we are running
+detect_init_style()
+{
+ # only do detection if not already set:
+ [ -z "$CTDB_INIT_STYLE" ] || return
+
+ if [ -x /sbin/startproc ]; then
+ CTDB_INIT_STYLE="suse"
+ elif [ -x /sbin/start-stop-daemon ]; then
+ CTDB_INIT_STYLE="debian"
+ else
+ CTDB_INIT_STYLE="redhat"
+ fi
+}
+
+######################################################
+# simulate /sbin/service on platforms that don't have it
+# _service() makes it easier to hook the service() function for
+# testing.
+_service ()
+{
+ _service_name="$1"
+ _op="$2"
+
+ # do nothing, when no service was specified
+ [ -z "$_service_name" ] && return
+
+ if [ -x /sbin/service ]; then
+ $_nice /sbin/service "$_service_name" "$_op"
+ elif [ -x /usr/sbin/service ]; then
+ $_nice /usr/sbin/service "$_service_name" "$_op"
+ elif [ -x /bin/systemctl ]; then
+ $_nice /bin/systemctl "$_op" "$_service_name"
+ elif [ -x "${CTDB_SYS_ETCDIR}/init.d/${_service_name}" ]; then
+ $_nice "${CTDB_SYS_ETCDIR}/init.d/${_service_name}" "$_op"
+ elif [ -x "${CTDB_SYS_ETCDIR}/rc.d/init.d/${_service_name}" ]; then
+ $_nice "${CTDB_SYS_ETCDIR}/rc.d/init.d/${_service_name}" "$_op"
+ fi
+}
+
+service()
+{
+ _nice=""
+ _service "$@"
+}
+
+######################################################
+# simulate /sbin/service (niced) on platforms that don't have it
+nice_service()
+{
+ _nice="nice"
+ _service "$@"
+}
+
+######################################################
+# Cached retrieval of PNN from local node. This never changes so why
+# open a client connection to the server each time this is needed?
+ctdb_get_pnn ()
+{
+ _pnn_file="${CTDB_SCRIPT_VARDIR}/my-pnn"
+ if [ ! -f "$_pnn_file" ] ; then
+ $CTDB pnn >"$_pnn_file"
+ fi
+
+ cat "$_pnn_file"
+}
+
+# Cached retrieval of private IP address from local node. This never
+# changes.
+ctdb_get_ip_address ()
+{
+ _ip_addr_file="${CTDB_SCRIPT_VARDIR}/my-ip-address"
+ if [ ! -f "$_ip_addr_file" ] ; then
+ $CTDB -X nodestatus |
+ awk -F '|' 'NR == 2 { print $3 }' >"$_ip_addr_file"
+ fi
+
+ # ip_address is used by caller
+ # shellcheck disable=SC2034
+ cat "$_ip_addr_file"
+}
+
+######################################################
+# wrapper around /proc/ settings to allow them to be hooked
+# for testing
+# 1st arg is relative path under /proc/, 2nd arg is value to set
+set_proc ()
+{
+ echo "$2" >"/proc/$1"
+}
+
+set_proc_maybe ()
+{
+ if [ -w "/proc/$1" ] ; then
+ set_proc "$1" "$2"
+ fi
+}
+
+######################################################
+# wrapper around getting file contents from /proc/ to allow
+# this to be hooked for testing
+# 1st arg is relative path under /proc/
+get_proc ()
+{
+ cat "/proc/$1"
+}
+
+######################################################
+# Print up to $_max kernel stack traces for processes named $_program
+program_stack_traces ()
+{
+ _prog="$1"
+ _max="${2:-1}"
+
+ _count=1
+ for _pid in $(pidof "$_prog") ; do
+ [ "$_count" -le "$_max" ] || break
+
+ # Do this first to avoid racing with process exit
+ _stack=$(get_proc "${_pid}/stack" 2>/dev/null)
+ if [ -n "$_stack" ] ; then
+ echo "Stack trace for ${_prog}[${_pid}]:"
+ echo "$_stack"
+ _count=$((_count + 1))
+ fi
+ done
+}
+
+######################################################
+# Ensure $service_name is set
+assert_service_name ()
+{
+ [ -n "$service_name" ] || die "INTERNAL ERROR: \$service_name not set"
+}
+
+######################################################
+# check a set of directories is available
+# return 1 on a missing directory
+# directories are read from stdin
+######################################################
+ctdb_check_directories_probe()
+{
+ while IFS="" read d ; do
+ case "$d" in
+ *%*)
+ continue
+ ;;
+ *)
+ [ -d "${d}/." ] || return 1
+ esac
+ done
+}
+
+######################################################
+# check a set of directories is available
+# directories are read from stdin
+######################################################
+ctdb_check_directories()
+{
+ ctdb_check_directories_probe || {
+ echo "ERROR: $service_name directory \"$d\" not available"
+ exit 1
+ }
+}
+
+######################################################
+# check a set of tcp ports
+# usage: ctdb_check_tcp_ports <ports...>
+######################################################
+
+# Check whether something is listening on all of the given TCP ports
+# using the "ctdb checktcpport" command.
+ctdb_check_tcp_ports()
+{
+ if [ -z "$1" ] ; then
+ echo "INTERNAL ERROR: ctdb_check_tcp_ports - no ports specified"
+ exit 1
+ fi
+
+ for _p ; do # process each function argument (port)
+ _cmd="$CTDB checktcpport $_p"
+ _out=$($_cmd 2>&1)
+ _ret=$?
+ case "$_ret" in
+ 0)
+ echo "$service_name not listening on TCP port $_p"
+ return 1
+ ;;
+ 98)
+ # Couldn't bind, something already listening, next port
+ continue
+ ;;
+ *)
+ echo "unexpected error (${_ret}) running \"${_cmd}\""
+ if [ -n "$_out" ] ; then
+ echo "$_out"
+ fi
+ return $_ret
+ ;;
+ esac
+ done
+
+ # All ports listening
+ return 0
+}
+
+######################################################
+# check a unix socket
+# usage: ctdb_check_unix_socket SERVICE_NAME <socket_path>
+######################################################
+ctdb_check_unix_socket() {
+ socket_path="$1"
+ [ -z "$socket_path" ] && return
+
+ if ! netstat --unix -a -n | grep -q "^unix.*LISTEN.*${socket_path}$"; then
+ echo "ERROR: $service_name socket $socket_path not found"
+ return 1
+ fi
+}
+
+################################################
+# kill off any TCP connections with the given IP
+################################################
+kill_tcp_connections ()
+{
+ _iface="$1"
+ _ip="$2"
+
+ _oneway=false
+ if [ "$3" = "oneway" ] ; then
+ _oneway=true
+ fi
+
+ get_tcp_connections_for_ip "$_ip" | {
+ _killcount=0
+ _connections=""
+ _nl="
+"
+ while read _dst _src; do
+ _destport="${_dst##*:}"
+ __oneway=$_oneway
+ case $_destport in
+ # we only do one-way killtcp for CIFS
+ 139|445) __oneway=true ;;
+ esac
+
+ _connections="${_connections}${_nl}${_src} ${_dst}"
+ if ! $__oneway ; then
+ _connections="${_connections}${_nl}${_dst} ${_src}"
+ fi
+
+ _killcount=$((_killcount + 1))
+ done
+
+ if [ $_killcount -eq 0 ] ; then
+ return
+ fi
+
+ echo "$_connections" | \
+ "${CTDB_HELPER_BINDIR}/ctdb_killtcp" "$_iface" || {
+ echo "Failed to kill TCP connections"
+ return
+ }
+
+ _connections=$(get_tcp_connections_for_ip "$_ip")
+ if [ -z "$_connections" ] ; then
+ _remaining=0
+ else
+ _remaining=$(echo "$_connections" | wc -l)
+ fi
+
+ _actually_killed=$((_killcount - _remaining))
+
+ _t="${_actually_killed}/${_killcount}"
+ echo "Killed ${_t} TCP connections to released IP $_ip"
+
+ if [ -n "$_connections" ] ; then
+ echo "Remaining connections:"
+ echo "$_connections" | sed -e 's|^| |'
+ fi
+ }
+}
+
+##################################################################
+# kill off the local end for any TCP connections with the given IP
+##################################################################
+kill_tcp_connections_local_only ()
+{
+ kill_tcp_connections "$@" "oneway"
+}
+
+##################################################################
+# tickle any TCP connections with the given IP
+##################################################################
+tickle_tcp_connections ()
+{
+ _ip="$1"
+
+ # Get connections, both directions
+ _conns=$(get_tcp_connections_for_ip "$_ip" | \
+ awk '{ print $1, $2 ; print $2, $1 }')
+
+ echo "$_conns" | awk '{ print "Tickle TCP connection", $1, $2 }'
+ echo "$_conns" | ctdb tickle
+}
+
+get_tcp_connections_for_ip ()
+{
+ _ip="$1"
+
+ ss -tn state established "src [$_ip]" | awk 'NR > 1 {print $3, $4}'
+}
+
+########################################################
+
+add_ip_to_iface ()
+{
+ _iface=$1
+ _ip=$2
+ _maskbits=$3
+
+ # Ensure interface is up
+ ip link set "$_iface" up || \
+ die "Failed to bringup interface $_iface"
+
+ # Only need to define broadcast for IPv4
+ case "$_ip" in
+ *:*) _bcast="" ;;
+ *) _bcast="brd +" ;;
+ esac
+
+ # Intentionally unquoted multi-word value here
+ # shellcheck disable=SC2086
+ ip addr add "$_ip/$_maskbits" $_bcast dev "$_iface" || {
+ echo "Failed to add $_ip/$_maskbits on dev $_iface"
+ return 1
+ }
+
+ # Wait 5 seconds for IPv6 addresses to stop being tentative...
+ if [ -z "$_bcast" ] ; then
+ for _x in $(seq 1 10) ; do
+ ip addr show to "${_ip}/128" | grep -q "tentative" || break
+ sleep 0.5
+ done
+
+ # If the address was a duplicate then it won't be on the
+ # interface so flag an error.
+ _t=$(ip addr show to "${_ip}/128")
+ case "$_t" in
+ "")
+ echo "Failed to add $_ip/$_maskbits on dev $_iface"
+ return 1
+ ;;
+ *tentative*|*dadfailed*)
+ echo "Failed to add $_ip/$_maskbits on dev $_iface"
+ ip addr del "$_ip/$_maskbits" dev "$_iface"
+ return 1
+ ;;
+ esac
+ fi
+}
+
+delete_ip_from_iface()
+{
+ _iface=$1
+ _ip=$2
+ _maskbits=$3
+
+ # This could be set globally for all interfaces but it is probably
+ # better to avoid surprises, so limit it the interfaces where CTDB
+ # has public IP addresses. There isn't anywhere else convenient
+ # to do this so just set it each time. This is much cheaper than
+ # remembering and re-adding secondaries.
+ set_proc "sys/net/ipv4/conf/${_iface}/promote_secondaries" 1
+
+ ip addr del "$_ip/$_maskbits" dev "$_iface" || {
+ echo "Failed to del $_ip on dev $_iface"
+ return 1
+ }
+}
+
+# If the given IP is hosted then print 2 items: maskbits and iface
+ip_maskbits_iface ()
+{
+ _addr="$1"
+
+ case "$_addr" in
+ *:*) _bits=128 ;;
+ *) _bits=32 ;;
+ esac
+ ip addr show to "${_addr}/${_bits}" 2>/dev/null | \
+ awk 'NR == 1 { iface = $2; sub(":$", "", iface) ;
+ sub("@.*", "", iface) }
+ $1 ~ /inet/ { mask = $2; sub(".*/", "", mask);
+ print mask, iface }'
+}
+
+drop_ip ()
+{
+ _addr="${1%/*}" # Remove optional maskbits
+
+ # Intentional word splitting here
+ # shellcheck disable=SC2046
+ set -- $(ip_maskbits_iface "$_addr")
+ if [ -n "$1" ] ; then
+ _maskbits="$1"
+ _iface="$2"
+ echo "Removing public address $_addr/$_maskbits from device $_iface"
+ delete_ip_from_iface "$_iface" "$_addr" "$_maskbits" >/dev/null 2>&1
+ fi
+}
+
+drop_all_public_ips ()
+{
+ # _x is intentionally ignored
+ # shellcheck disable=SC2034
+ while read _ip _x ; do
+ drop_ip "$_ip"
+ done <"${CTDB_PUBLIC_ADDRESSES:-/dev/null}"
+}
+
+flush_route_cache ()
+{
+ set_proc_maybe sys/net/ipv4/route/flush 1
+ set_proc_maybe sys/net/ipv6/route/flush 1
+}
+
+########################################################
+# Interface monitoring
+
+# If the interface is a virtual one (e.g. VLAN) then get the
+# underlying interface
+interface_get_real ()
+{
+ # Output of "ip link show <iface>"
+ _iface_info="$1"
+
+ # Extract the full interface description to see if it is a VLAN
+ _t=$(echo "$_iface_info" |
+ awk 'NR == 1 { iface = $2; sub(":$", "", iface) ;
+ print iface }')
+ case "$_t" in
+ *@*)
+ # VLAN: use the underlying interface, after the '@'
+ echo "${_t##*@}"
+ ;;
+ *)
+ # Not a regular VLAN. For backward compatibility, assume
+ # there is some other sort of VLAN that doesn't have the
+ # '@' in the output and only use what is before a '.'. If
+ # there is no '.' then this will be the whole interface
+ # name.
+ echo "${_t%%.*}"
+ esac
+}
+
+# Check whether an interface is operational
+interface_monitor ()
+{
+ _iface="$1"
+
+ _iface_info=$(ip link show "$_iface" 2>&1) || {
+ echo "ERROR: Monitored interface ${_iface} does not exist"
+ return 1
+ }
+
+
+ # If the interface is a virtual one (e.g. VLAN) then get the
+ # underlying interface.
+ _realiface=$(interface_get_real "$_iface_info")
+
+ if _bi=$(get_proc "net/bonding/${_realiface}" 2>/dev/null) ; then
+ # This is a bond: various monitoring strategies
+ echo "$_bi" | grep -q 'Currently Active Slave: None' && {
+ echo "ERROR: No active slaves for bond device ${_realiface}"
+ return 1
+ }
+ echo "$_bi" | grep -q '^MII Status: up' || {
+ echo "ERROR: public network interface ${_realiface} is down"
+ return 1
+ }
+ echo "$_bi" | grep -q '^Bonding Mode: IEEE 802.3ad Dynamic link aggregation' && {
+ # This works around a bug in the driver where the
+ # overall bond status can be up but none of the actual
+ # physical interfaces have a link.
+ echo "$_bi" | grep 'MII Status:' | tail -n +2 | grep -q '^MII Status: up' || {
+ echo "ERROR: No active slaves for 802.ad bond device ${_realiface}"
+ return 1
+ }
+ }
+
+ return 0
+ else
+ # Not a bond
+ case "$_iface" in
+ lo*)
+ # loopback is always working
+ return 0
+ ;;
+ ib*)
+ # we don't know how to test ib links
+ return 0
+ ;;
+ *)
+ ethtool "$_iface" | grep -q 'Link detected: yes' || {
+ # On some systems, this is not successful when a
+ # cable is plugged but the interface has not been
+ # brought up previously. Bring the interface up
+ # and try again...
+ ip link set "$_iface" up
+ ethtool "$_iface" | grep -q 'Link detected: yes' || {
+ echo "ERROR: No link on the public network interface ${_iface}"
+ return 1
+ }
+ }
+ return 0
+ ;;
+ esac
+ fi
+}
+
+########################################################
+# Simple counters
+_ctdb_counter_common () {
+ _service_name="${1:-${service_name:-${script_name}}}"
+ _counter_file="${CTDB_SCRIPT_VARDIR}/failcount/${_service_name}"
+ mkdir -p "${_counter_file%/*}" # dirname
+}
+# Some code passes an argument
+# shellcheck disable=SC2120
+ctdb_counter_init () {
+ _ctdb_counter_common "$1"
+
+ >"$_counter_file"
+}
+ctdb_counter_incr () {
+ _ctdb_counter_common "$1"
+
+ # unary counting using newlines!
+ echo >>"$_counter_file"
+}
+ctdb_counter_get () {
+ _ctdb_counter_common "$1"
+ # unary counting!
+ stat -c "%s" "$_counter_file" 2>/dev/null || echo 0
+}
+
+########################################################
+
+ctdb_setup_service_state_dir ()
+{
+ _s="${1:-${service_name}}"
+
+ _service_state_dir="${CTDB_SCRIPT_VARDIR}/service_state/${_s}"
+ mkdir -p "$_service_state_dir" ||
+ die "Error creating state dir \"${_service_state_dir}\""
+
+ echo "$_service_state_dir"
+}
+
+##################################################################
+# Reconfigure a service on demand
+
+_ctdb_service_reconfigure_common ()
+{
+ _d="${CTDB_SCRIPT_VARDIR}/service_status/${service_name}"
+ mkdir -p "$_d"
+ _ctdb_service_reconfigure_flag="$_d/reconfigure"
+}
+
+ctdb_service_needs_reconfigure ()
+{
+ _ctdb_service_reconfigure_common
+ [ -e "$_ctdb_service_reconfigure_flag" ]
+}
+
+ctdb_service_set_reconfigure ()
+{
+ _ctdb_service_reconfigure_common
+ >"$_ctdb_service_reconfigure_flag"
+}
+
+ctdb_service_unset_reconfigure ()
+{
+ _ctdb_service_reconfigure_common
+ rm -f "$_ctdb_service_reconfigure_flag"
+}
+
+ctdb_service_reconfigure ()
+{
+ echo "Reconfiguring service \"${service_name}\"..."
+ ctdb_service_unset_reconfigure
+ service_reconfigure || return $?
+ # Intentionally have this use $service_name as default
+ # shellcheck disable=SC2119
+ ctdb_counter_init
+}
+
+# Default service_reconfigure() function does nothing.
+service_reconfigure ()
+{
+ :
+}
+
+##################################################################
+# Does CTDB manage this service?
+
+ctdb_compat_managed_service ()
+{
+ if [ "$1" = "yes" -a "$2" = "$service_name" ] ; then
+ CTDB_MANAGED_SERVICES="$CTDB_MANAGED_SERVICES $2"
+ fi
+}
+
+is_ctdb_managed_service ()
+{
+ assert_service_name
+
+ # $t is used just for readability and to allow better accurate
+ # matching via leading/trailing spaces
+ t=" $CTDB_MANAGED_SERVICES "
+
+ # Return 0 if "<space>$service_name<space>" appears in $t
+ if [ "${t#* ${service_name} }" != "${t}" ] ; then
+ return 0
+ fi
+
+ # If above didn't match then update $CTDB_MANAGED_SERVICES for
+ # backward compatibility and try again.
+ ctdb_compat_managed_service "$CTDB_MANAGES_VSFTPD" "vsftpd"
+ ctdb_compat_managed_service "$CTDB_MANAGES_SAMBA" "samba"
+ ctdb_compat_managed_service "$CTDB_MANAGES_WINBIND" "winbind"
+ ctdb_compat_managed_service "$CTDB_MANAGES_HTTPD" "apache2"
+ ctdb_compat_managed_service "$CTDB_MANAGES_HTTPD" "httpd"
+ ctdb_compat_managed_service "$CTDB_MANAGES_ISCSI" "iscsi"
+ ctdb_compat_managed_service "$CTDB_MANAGES_CLAMD" "clamd"
+ ctdb_compat_managed_service "$CTDB_MANAGES_NFS" "nfs"
+
+ t=" $CTDB_MANAGED_SERVICES "
+
+ # Return 0 if "<space>$service_name<space>" appears in $t
+ [ "${t#* ${service_name} }" != "${t}" ]
+}
+
+# Default service_start() and service_stop() functions.
+
+# These may be overridden in an eventscript.
+service_start ()
+{
+ service "$service_name" start
+}
+
+service_stop ()
+{
+ service "$service_name" stop
+}
+
+##################################################################
+
+# This exists only for backward compatibility with 3rd party scripts
+# that call it
+ctdb_standard_event_handler ()
+{
+ :
+}
+
+iptables_wrapper ()
+{
+ _family="$1" ; shift
+ if [ "$_family" = "inet6" ] ; then
+ _iptables_cmd="ip6tables"
+ else
+ _iptables_cmd="iptables"
+ fi
+
+ # iptables doesn't like being re-entered, so flock-wrap it.
+ flock -w 30 "${CTDB_SCRIPT_VARDIR}/iptables.flock" "$_iptables_cmd" "$@"
+}
+
+# AIX (and perhaps others?) doesn't have mktemp
+# type is commonly supported and more portable than which(1)
+# shellcheck disable=SC2039
+if ! type mktemp >/dev/null 2>&1 ; then
+ mktemp ()
+ {
+ _dir=false
+ if [ "$1" = "-d" ] ; then
+ _dir=true
+ shift
+ fi
+ _d="${TMPDIR:-/tmp}"
+ _hex10=$(dd if=/dev/urandom count=20 2>/dev/null | \
+ md5sum | \
+ sed -e 's@\(..........\).*@\1@')
+ _t="${_d}/tmp.${_hex10}"
+ (
+ umask 077
+ if $_dir ; then
+ mkdir "$_t"
+ else
+ >"$_t"
+ fi
+ )
+ echo "$_t"
+ }
+fi
+
+######################################################################
+# NFS callout handling
+
+nfs_callout_init ()
+{
+ _state_dir="$1"
+
+ if [ -z "$CTDB_NFS_CALLOUT" ] ; then
+ CTDB_NFS_CALLOUT="${CTDB_BASE}/nfs-linux-kernel-callout"
+ fi
+ # Always export, for statd callout
+ export CTDB_NFS_CALLOUT
+
+ # If the callout wants to use this then it must create it
+ export CTDB_NFS_CALLOUT_STATE_DIR="${_state_dir}/callout-state"
+
+ # Export, if set, for use by clustered NFS callouts
+ if [ -n "$CTDB_NFS_STATE_FS_TYPE" ] ; then
+ export CTDB_NFS_STATE_FS_TYPE
+ fi
+ if [ -n "$CTDB_NFS_STATE_MNT" ] ; then
+ export CTDB_NFS_STATE_MNT
+ fi
+
+ nfs_callout_cache="${_state_dir}/nfs_callout_cache"
+ nfs_callout_cache_callout="${nfs_callout_cache}/CTDB_NFS_CALLOUT"
+ nfs_callout_cache_ops="${nfs_callout_cache}/ops"
+}
+
+nfs_callout_register ()
+{
+ mkdir -p "$nfs_callout_cache_ops"
+ rm -f "$nfs_callout_cache_ops"/*
+
+ echo "$CTDB_NFS_CALLOUT" >"$nfs_callout_cache_callout"
+
+ _t=$(eval "$CTDB_NFS_CALLOUT" "register")
+ if [ -n "$_t" ] ; then
+ echo "$_t" |
+ while IFS="" read _op ; do
+ touch "${nfs_callout_cache_ops}/${_op}"
+ done
+ else
+ touch "${nfs_callout_cache_ops}/ALL"
+ fi
+}
+
+nfs_callout ()
+{
+ # Re-run registration if $CTDB_NFS_CALLOUT has changed
+ _prev=""
+ if [ -r "$nfs_callout_cache_callout" ] ; then
+ read _prev <"$nfs_callout_cache_callout"
+ fi
+ if [ "$CTDB_NFS_CALLOUT" != "$_prev" ] ; then
+ nfs_callout_register
+ fi
+
+ # Run the operation if it is registered...
+ if [ -e "${nfs_callout_cache_ops}/${1}" ] || \
+ [ -e "${nfs_callout_cache_ops}/ALL" ]; then
+ eval "$CTDB_NFS_CALLOUT" "$@"
+ fi
+}
+
+########################################################
+# tickle handling
+########################################################
+
+update_tickles ()
+{
+ _port="$1"
+
+ tickledir="${CTDB_SCRIPT_VARDIR}/tickles"
+ mkdir -p "$tickledir"
+
+ # What public IPs do I hold?
+ _pnn=$(ctdb_get_pnn)
+ _ips=$($CTDB -X ip | awk -F'|' -v pnn="$_pnn" '$3 == pnn {print $2}')
+
+ # IPs and port as ss filters
+ _ip_filter=""
+ for _ip in $_ips ; do
+ _ip_filter="${_ip_filter}${_ip_filter:+ || }src [${_ip}]"
+ done
+ _port_filter="sport == :${_port}"
+
+ # Record connections to our public IPs in a temporary file.
+ # This temporary file is in CTDB's private state directory and
+ # $$ is used to avoid a very rare race involving CTDB's script
+ # debugging. No security issue, nothing to see here...
+ _my_connections="${tickledir}/${_port}.connections.$$"
+ # Parentheses are needed around the filters for precedence but
+ # the parentheses can't be empty!
+ ss -tn state established \
+ "${_ip_filter:+( ${_ip_filter} )}" \
+ "${_port_filter:+( ${_port_filter} )}" |
+ awk 'NR > 1 {print $4, $3}' |
+ sort >"$_my_connections"
+
+ # Record our current tickles in a temporary file
+ _my_tickles="${tickledir}/${_port}.tickles.$$"
+ for _i in $_ips ; do
+ $CTDB -X gettickles "$_i" "$_port" |
+ awk -F'|' 'NR > 1 { printf "%s:%s %s:%s\n", $2, $3, $4, $5 }'
+ done |
+ sort >"$_my_tickles"
+
+ # Add tickles for connections that we haven't already got tickles for
+ comm -23 "$_my_connections" "$_my_tickles" | \
+ $CTDB addtickle
+
+ # Remove tickles for connections that are no longer there
+ comm -13 "$_my_connections" "$_my_tickles" | \
+ $CTDB deltickle
+
+ rm -f "$_my_connections" "$_my_tickles"
+
+ # Remove stale files from killed scripts
+ # Files can't have spaces in name, more portable than -print0/-0
+ # shellcheck disable=SC2038
+ (cd "$tickledir" && find . -type f -mmin +10 | xargs -r rm)
+}
+
+########################################################
+# load a site local config file
+########################################################
+
+[ -n "$CTDB_RC_LOCAL" -a -x "$CTDB_RC_LOCAL" ] && {
+ . "$CTDB_RC_LOCAL"
+}
+
+[ -x "${CTDB_BASE}/rc.local" ] && {
+ . "${CTDB_BASE}/rc.local"
+}
+
+[ -d "${CTDB_BASE}/rc.local.d" ] && {
+ for i in "${CTDB_BASE}/rc.local.d"/* ; do
+ [ -x "$i" ] && . "$i"
+ done
+}
+
+script_name="${0##*/}" # basename
--- /dev/null
+#!/bin/sh
+
+gcore -o "/var/log/core" "$1" 2>&1 | logger -t "ctdb:gcore_trace"
--- /dev/null
+# portmapper
+unhealthy_after=1
--- /dev/null
+# status
+version="1"
+restart_every=2
+unhealthy_after=6
+service_stop_cmd="killall -q -9 rpc.statd"
+service_start_cmd="rpc.statd ${STATD_HA_CALLOUT:+-H} $STATD_HA_CALLOUT ${STATD_HOSTNAME:+-n} $STATD_HOSTNAME ${STATD_PORT:+-p} $STATD_PORT ${STATD_OUTGOING_PORT:+-o} $STATD_OUTGOING_PORT"
+service_debug_cmd="program_stack_traces rpc.statd 5"
--- /dev/null
+# nfs
+version="3"
+restart_every=10
+unhealthy_after=2
+service_stop_cmd="$CTDB_NFS_CALLOUT stop nfs"
+service_start_cmd="$CTDB_NFS_CALLOUT start nfs"
+service_debug_cmd="program_stack_traces nfsd 5"
--- /dev/null
+# nlockmgr
+version="4"
+restart_every=2
+unhealthy_after=6
+service_stop_cmd="$CTDB_NFS_CALLOUT stop nlockmgr"
+service_start_cmd="$CTDB_NFS_CALLOUT start nlockmgr"
--- /dev/null
+# mountd
+version="1"
+restart_every=2
+unhealthy_after=6
+service_stop_cmd="killall -q -9 rpc.mountd"
+service_start_cmd="rpc.mountd $RPCMOUNTDOPTS ${MOUNTD_PORT:+-p} $MOUNTD_PORT"
+service_debug_cmd="program_stack_traces rpc.mountd 5"
--- /dev/null
+# rquotad
+version="1"
+restart_every=2
+unhealthy_after=6
+service_stop_cmd="killall -q -9 rpc.rquotad"
+service_start_cmd="rpc.rquotad ${RQUOTAD_PORT:+-p} $RQUOTAD_PORT"
+service_debug_cmd="program_stack_traces rpc.rquotad 5"
--- /dev/null
+NFS check configuration files.
+
+Files are named NN.RPCSERVICE.check. Files without a .check suffix
+are ignored.
+
+Supported variables are:
+
+* family - "tcp" or "udp" or space separated list
+ default: tcp, not used with "service_check_cmd"
+* version - optional, RPC service version number
+ default is to omit to check for any version,
+ not used with "service_check_cmd"
+* unhealthy_after - number of check fails before unhealthy
+ default: 1
+* restart_every - number of check fails before restart
+ default: 0, meaning no restart
+* service_stop_cmd - command to stop service
+ default: no default, must be provided if
+ restart_every > 0
+* service_start_cmd - command to start service
+ default: no default, must be provided if
+ restart_every > 0
+* service_check_cmd - command to check health of service
+ default is to check RPC service using rpcinfo
+* service_debug_cmd - command to debug a service after trying to stop it;
+ for example, it can be useful to print stack
+ traces of threads that have not exited, since
+ they may be stuck doing I/O;
+ no default, see also function program_stack_traces()
+
+Quoting inside values is not preserved.
--- /dev/null
+#!/bin/sh
+
+# Exit on 1st error
+set -e
+
+# NFS exports file. Some code below keeps a cache of output derived
+# from exportfs(8). When this file is updated the cache is invalid
+# and needs to be regenerated.
+#
+# To change the file, edit the default value below. Do not set
+# CTDB_NFS_EXPORTS_FILE - it isn't a configuration variable, just a
+# hook for testing.
+nfs_exports_file="${CTDB_NFS_EXPORTS_FILE:-/var/lib/nfs/etab}"
+
+# Red Hat
+nfs_service="nfs"
+nfslock_service="nfslock"
+nfs_config="/etc/sysconfig/nfs"
+
+# SUSE
+#nfs_service="nfsserver"
+#nfslock_service=""
+#nfs_config="/etc/sysconfig/nfs"
+
+# Debian
+#nfs_service="nfs-kernel-server"
+#nfslock_service=""
+#nfs_config="/etc/default/nfs-kernel-server"
+
+# Override for unit testing
+if [ -z "$PROCFS_PATH" ] ; then
+ PROCFS_PATH="/proc"
+fi
+
+##################################################
+
+usage ()
+{
+ _c=$(basename "$0")
+ cat <<EOF
+usage: $_c { shutdown | startup }
+ $_c { stop | start } { nfs | nlockmgr }
+ $_c { monitor-list-shares | monitor-post }
+ $_c { register }
+EOF
+ exit 1
+}
+
+
+##################################################
+# Basic service stop and start
+
+basic_stop ()
+{
+ case "$1" in
+ nfs)
+ service "$nfs_service" stop
+ if [ -n "$nfslock_service" ] ; then
+ service "$nfslock_service" stop
+ fi
+ ;;
+ nfslock)
+ if [ -n "$nfslock_service" ] ; then
+ service "$nfslock_service" stop
+ else
+ service "$nfs_service" stop
+ fi
+ ;;
+ *)
+ usage
+ esac
+}
+
+basic_start ()
+{
+ case "$1" in
+ nfs)
+ if [ -n "$nfslock_service" ] ; then
+ service "$nfslock_service" start
+ fi
+ service "$nfs_service" start
+ ;;
+ nfslock)
+ if [ -n "$nfslock_service" ] ; then
+ service "$nfslock_service" start
+ else
+ service "$nfs_service" start
+ fi
+ ;;
+ *)
+ usage
+ esac
+}
+
+##################################################
+# service "stop" and "start" options for restarting
+
+service_stop ()
+{
+ case "$1" in
+ nfs)
+ echo 0 >"${PROCFS_PATH}/fs/nfsd/threads"
+ basic_stop "nfs" >/dev/null 2>&1 || true
+ pkill -9 nfsd
+ ;;
+ nlockmgr)
+ basic_stop "nfslock" >/dev/null 2>&1 || true
+ ;;
+ *)
+ usage
+ esac
+}
+
+service_start ()
+{
+ case "$1" in
+ nfs)
+ basic_start "nfs"
+ ;;
+ nlockmgr)
+ basic_start "nfslock"
+ ;;
+ *)
+ usage
+ esac
+}
+
+##################################################
+# service init startup and final shutdown
+
+nfs_shutdown ()
+{
+ basic_stop "nfs"
+}
+
+nfs_startup ()
+{
+ basic_stop "nfs" || true
+ basic_start "nfs"
+ _f="${PROCFS_PATH}/sys/net/ipv4/tcp_tw_recycle"
+ if [ "$_f" ] ; then
+ echo 1 >"$_f"
+ fi
+}
+
+##################################################
+# monitor-post support
+
+nfs_check_thread_count ()
+{
+ # Load NFS configuration to get desired number of threads.
+ if [ -r "$nfs_config" ] ; then
+ . "$nfs_config"
+ fi
+
+ # If $RPCNFSDCOUNT/$USE_KERNEL_NFSD_NUMBER isn't set then we could
+ # guess the default from the initscript. However, let's just
+ # assume that those using the default don't care about the number
+ # of threads and that they have switched on this feature in error.
+ _configured_threads="${RPCNFSDCOUNT:-${USE_KERNEL_NFSD_NUMBER}}"
+ [ -n "$_configured_threads" ] || return 0
+
+ _threads_file="${PROCFS_PATH}/fs/nfsd/threads"
+
+ # nfsd should be running the configured number of threads. If
+ # there are a different number of threads then tell nfsd the
+ # correct number.
+ read _running_threads <"$_threads_file" || {
+ echo "WARNING: Reading \"${_threads_file}\" unexpectedly failed"
+ exit 0
+ }
+
+ # Intentionally not arithmetic comparison - avoids extra errors
+ # when above read fails in an unexpected way...
+ if [ "$_running_threads" != "$_configured_threads" ] ; then
+ echo "Attempting to correct number of nfsd threads from ${_running_threads} to ${_configured_threads}"
+ echo "$_configured_threads" >"$_threads_file"
+ fi
+}
+
+##################################################
+# list share directories
+
+nfs_monitor_list_shares ()
+{
+ _cache_file="${CTDB_NFS_CALLOUT_STATE_DIR}/list_shares_cache"
+ # -nt operator is well supported in Linux: dash, bash, ksh, ...
+ # shellcheck disable=SC2039
+ if [ ! -r "$nfs_exports_file" ] || [ ! -r "$_cache_file" ] || \
+ [ "$nfs_exports_file" -nt "$_cache_file" ] ; then
+ mkdir -p "$CTDB_NFS_CALLOUT_STATE_DIR"
+ # We could just use the contents of $nfs_exports_file.
+ # However, let's regard that file as internal to NFS and use
+ # exportfs, which is the public API.
+ if ! _exports=$(exportfs -v) ; then
+ echo "WARNING: failed to run exportfs to list NFS shares" >&2
+ return
+ fi
+
+ echo "$_exports" |
+ grep '^/' |
+ sed -e 's@[[:space:]][[:space:]]*[^[:space:]()][^[:space:]()]*([^[:space:]()][^[:space:]()]*)$@@' |
+ sort -u >"$_cache_file"
+ fi
+
+ cat "$_cache_file"
+}
+
+##################################################
+
+nfs_register ()
+{
+ cat <<EOF
+shutdown
+startup
+stop
+start
+monitor-list-shares
+monitor-post
+EOF
+}
+
+##################################################
+
+case "$1" in
+ shutdown)
+ nfs_shutdown
+ ;;
+ startup)
+ nfs_startup
+ ;;
+ stop)
+ service_stop "$2"
+ ;;
+ start)
+ service_start "$2"
+ ;;
+ monitor-list-shares)
+ nfs_monitor_list_shares
+ ;;
+ monitor-post)
+ nfs_check_thread_count
+ ;;
+ register)
+ nfs_register
+ ;;
+ monitor-pre|releaseip|takeip|releaseip-pre|takeip-pre)
+ # Not required/implemented
+ :
+ ;;
+ *)
+ usage
+esac
--- /dev/null
+This directory should contain executable programs to handle CTDB event
+notifications. The first and only argument passed to each program is
+the event, which is one of:
+
+ init, setup, startup, unhealthy, healthy
+
+To use notifications with this directory then you need to set:
+
+ CTDB_NOTIFY_SCRIPT=/etc/ctdb/notify.sh
+
+in your CTDB configuration file.
+
+An example script that sends SNMP traps for unhealthy/healthy might
+look like this:
+
+ #!/bin/sh
+
+ case "$1" in
+ unhealthy)
+ # Send an SNMP trap saying that the node is unhealthy:
+ snmptrap -m ALL -v 1 -c public 10.1.1.105 ctdb \
+ $(hostname) 0 0 $(date +"%s") ctdb.nodeHealth.0 i 1
+ ;;
+ healthy)
+ # Send an SNMP trap saying that the node is healthy again:
+ snmptrap -m ALL -v 1 -c public 10.1.1.105 ctdb \
+ $(hostname) 0 0 $(date +"%s") ctdb.nodeHealth.0 i 0
+ ;;
+ esac
+
+Alternatively, email could be sent:
+
+ #!/bin/sh
+
+ case "$1" in
+ unhealthy)
+ mail -s "$(hostname) is UNHEALTHY" foo@example.com </dev/null >/dev/null 2>&1
+ ;;
+ healthy)
+ mail -s "$(hostname) is HEALTHY" foo@example.com </dev/null >/dev/null 2>&1
+ ;;
+ esac
+
+When adding programs please note the exclusion patterns in notify.sh.
--- /dev/null
+#!/bin/sh
+
+# This script is activated by setting CTDB_NOTIFY_SCRIPT=/etc/ctdb/notify.sh
+# in /etc/sysconfig/ctdb
+
+# This is script is invoked from ctdb when certain events happen. See
+# /etc/ctdb/notify.d/README for more details.
+
+d=$(dirname "$0")
+nd="${d}/notify.d"
+
+ok=true
+
+for i in "${nd}/"* ; do
+ # Don't run files matching basename
+ case "${i##*/}" in
+ *~|*,|*.rpm*|*.swp|README) continue ;;
+ esac
+
+ # Files must be executable
+ [ -x "$i" ] || continue
+
+ # Flag failures
+ "$i" "$1" || ok=false
+done
+
+$ok
--- /dev/null
+#!/bin/sh
+
+# This must run as root as CTDB tool commands need to access CTDB socket
+[ "$(id -u)" -eq 0 ] || exec sudo "$0" "$@"
+
+# this script needs to be installed so that statd points to it with the -H
+# command line argument. The easiest way to do that is to put something like this in
+# /etc/sysconfig/nfs:
+# STATD_HOSTNAME="myhostname -H /etc/ctdb/statd-callout"
+
+[ -n "$CTDB_BASE" ] || \
+ CTDB_BASE=$(d=$(dirname "$0") ; cd -P "$d" ; echo "$PWD")
+
+. "${CTDB_BASE}/functions"
+
+# Overwrite this so we get some logging
+die ()
+{
+ script_log "statd-callout" "$@"
+ exit 1
+}
+
+loadconfig ctdb
+loadconfig nfs
+
+[ -n "$NFS_HOSTNAME" ] || \
+ die "NFS_HOSTNAME is not configured. statd-callout failed"
+
+# A handy newline
+nl="
+"
+
+service_state_dir=$(ctdb_setup_service_state_dir "statd-callout") || exit $?
+
+cd "$service_state_dir" || \
+ die "Failed to change directory to \"${service_state_dir}\""
+
+pnn=$(ctdb_get_pnn)
+
+case "$1" in
+ # Keep a single file to keep track of the last "add-client" or
+ # "del-client'. These get pushed to ctdb.tdb during "update",
+ # which will generally be run once each "monitor" cycle. In this
+ # way we avoid scalability problems with flood of persistent
+ # transactions after a "notify" when all the clients re-take their
+ # locks.
+
+ add-client)
+ # statd does not tell us to which IP the client connected so
+ # we must add it to all the IPs that we serve
+ cip="$2"
+ date=$(date '+%s')
+ # x is intentionally ignored
+ # shellcheck disable=SC2034
+ $CTDB ip -X |
+ tail -n +2 |
+ while IFS="|" read x sip node x ; do
+ [ "$node" = "$pnn" ] || continue # not us
+ key="statd-state@${sip}@${cip}"
+ echo "\"${key}\" \"${date}\"" >"$key"
+ done
+ ;;
+
+ del-client)
+ # statd does not tell us from which IP the client disconnected
+ # so we must add it to all the IPs that we serve
+ cip="$2"
+ # x is intentionally ignored
+ # shellcheck disable=SC2034
+ $CTDB ip -X |
+ tail -n +2 |
+ while IFS="|" read x sip node x ; do
+ [ "$node" = "$pnn" ] || continue # not us
+ key="statd-state@${sip}@${cip}"
+ echo "\"${key}\" \"\"" >"$key"
+ done
+ ;;
+
+ update)
+ files=$(echo statd-state@*)
+ if [ "$files" = "statd-state@*" ] ; then
+ # No files!
+ exit 0
+ fi
+ # Filter out lines for any IP addresses that are not currently
+ # hosted public IP addresses.
+ ctdb_ips=$($CTDB ip | tail -n +2)
+ sed_expr=$(echo "$ctdb_ips" |
+ awk -v pnn="$pnn" 'pnn == $2 {
+ ip = $1; gsub(/\./, "\\.", ip);
+ printf "/statd-state@%s@/p\n", ip }')
+ # Intentional multi-word expansion for multiple files
+ # shellcheck disable=SC2086
+ if sed -n "$sed_expr" $files | $CTDB ptrans "ctdb.tdb" ; then
+ rm $files
+ fi
+ ;;
+
+ notify)
+ # we must restart the lockmanager (on all nodes) so that we get
+ # a clusterwide grace period (so other clients don't take out
+ # conflicting locks through other nodes before all locks have been
+ # reclaimed)
+
+ # we need these settings to make sure that no tcp connections survive
+ # across a very fast failover/failback
+ #echo 10 > /proc/sys/net/ipv4/tcp_fin_timeout
+ #echo 0 > /proc/sys/net/ipv4/tcp_max_tw_buckets
+ #echo 0 > /proc/sys/net/ipv4/tcp_max_orphans
+
+ # Delete the notification list for statd, we don't want it to
+ # ping any clients
+ rm -f /var/lib/nfs/statd/sm/*
+ rm -f /var/lib/nfs/statd/sm.bak/*
+
+ # we must keep a monotonically increasing state variable for the entire
+ # cluster so state always increases when ip addresses fail from one
+ # node to another
+ # We use epoch and hope the nodes are close enough in clock.
+ # Even numbers mean service is shut down, odd numbers mean
+ # service is started.
+ # Intentionally round to an even number
+ # shellcheck disable=SC2017
+ state_even=$(( $(date '+%s') / 2 * 2))
+
+ # We must also let some time pass between stopping and
+ # restarting the lock manager. Otherwise there is a window
+ # where the lock manager will respond "strangely" immediately
+ # after restarting it, which causes clients to fail to reclaim
+ # their locks.
+ nfs_callout_init
+ "$CTDB_NFS_CALLOUT" "stop" "nlockmgr" >/dev/null 2>&1
+ sleep 2
+ "$CTDB_NFS_CALLOUT" "start" "nlockmgr" >/dev/null 2>&1
+
+ # we now need to send out additional statd notifications to ensure
+ # that clients understand that the lockmanager has restarted.
+ # we have three cases:
+ # 1, clients that ignore the ip address the stat notification came from
+ # and ONLY care about the 'name' in the notify packet.
+ # these clients ONLY work with lock failover IFF that name
+ # can be resolved into an ipaddress that matches the one used
+ # to mount the share. (==linux clients)
+ # This is handled when starting lockmanager above, but those
+ # packets are sent from the "wrong" ip address, something linux
+ # clients are ok with, buth other clients will barf at.
+ # 2, Some clients only accept statd packets IFF they come from the
+ # 'correct' ip address.
+ # 2a,Send out the notification using the 'correct' ip address and also
+ # specify the 'correct' hostname in the statd packet.
+ # Some clients require both the correct source address and also the
+ # correct name. (these clients also ONLY work if the ip addresses
+ # used to map the share can be resolved into the name returned in
+ # the notify packet.)
+ # 2b,Other clients require that the source ip address of the notify
+ # packet matches the ip address used to take out the lock.
+ # I.e. that the correct source address is used.
+ # These clients also require that the statd notify packet contains
+ # the name as the ip address used when the lock was taken out.
+ #
+ # Both 2a and 2b are commonly used in lockmanagers since they maximize
+ # probability that the client will accept the statd notify packet and
+ # not just ignore it.
+ # For all IPs we serve, collect info and push to the config database
+
+ # Construct a sed expression to take catdb output and produce pairs of:
+ # server-IP client-IP
+ # but only for the server-IPs that are hosted on this node.
+ ctdb_all_ips=$($CTDB ip all | tail -n +2)
+ sed_expr=$(echo "$ctdb_all_ips" |
+ awk -v pnn="$pnn" 'pnn == $2 {
+ ip = $1; gsub(/\./, "\\.", ip);
+ printf "s/^key.*=.*statd-state@\\(%s\\)@\\([^\"]*\\).*/\\1 \\2/p\n", ip }')
+
+ statd_state=$($CTDB catdb ctdb.tdb | sed -n "$sed_expr" | sort)
+ [ -n "$statd_state" ] || exit 0
+
+ smnotify="${CTDB_HELPER_BINDIR}/smnotify"
+ prev=""
+ echo "$statd_state" | {
+ # This all needs to be in the same command group at the
+ # end of the pipe so it doesn't get lost when the loop
+ # completes.
+ items=""
+ while read sip cip ; do
+ # Collect item to delete from the DB
+ key="statd-state@${sip}@${cip}"
+ item="\"${key}\" \"\""
+ items="${items}${items:+${nl}}${item}"
+
+ # NOTE: Consider optimising smnotify to read all the
+ # data from stdin and then run it in the background.
+
+ # Reset stateval for each serverip
+ [ "$sip" = "$prev" ] || stateval="$state_even"
+ # Send notifies for server shutdown
+ "$smnotify" --client="$cip" --ip="$sip" \
+ --server="$sip" --stateval="$stateval"
+ "$smnotify" --client="$cip" --ip="$sip" \
+ --server="$NFS_HOSTNAME" --stateval="$stateval"
+ # Send notifies for server startup
+ stateval=$((stateval + 1))
+ "$smnotify" --client="$cip" --ip="$sip" \
+ --server="$sip" --stateval="$stateval"
+ "$smnotify" --client="$cip" --ip="$sip" \
+ --server="$NFS_HOSTNAME" --stateval="$stateval"
+ done
+
+ echo "$items" | $CTDB ptrans "ctdb.tdb"
+ }
+
+ # Remove any stale touch files (i.e. for IPs not currently
+ # hosted on this node and created since the last "update").
+ # There's nothing else we can do with them at this stage.
+ echo "$ctdb_all_ips" |
+ awk -v pnn="$pnn" 'pnn != $2 { print $1 }' |
+ while read sip ; do
+ rm -f "statd-state@${sip}@"*
+ done
+ ;;
+esac
--- /dev/null
+# Defaults for winbind initscript
+# sourced by /etc/init.d/winbind
+#
+
+#
+# This is a POSIX shell fragment
+#
+
+
+# Winbind configuration
+#WINBINDD_OPTS="-n"
libvirt-qemu:x:64055:libvirt-qemu
libvirt-dnsmasq:x:137:
mysql:x:138:
+winbindd_priv:x:139:
libvirt:x:136:frank
libvirt-qemu:x:64055:libvirt-qemu
libvirt-dnsmasq:x:137:
+mysql:x:138:
libvirt-qemu:!::libvirt-qemu
libvirt-dnsmasq:!::
mysql:!::
+winbindd_priv:!::
libvirt:!::frank
libvirt-qemu:!::libvirt-qemu
libvirt-dnsmasq:!::
+mysql:!::
--- /dev/null
+#!/bin/sh
+
+# Start and stop CTDB (Clustered TDB daemon)
+#
+# chkconfig: - 90 01
+#
+# description: Starts and stops CTDB
+# pidfile: /var/run/ctdb/ctdbd.pid
+# config: /etc/sysconfig/ctdb
+
+### BEGIN INIT INFO
+# Provides: ctdb
+# Required-Start: $local_fs $syslog $network $remote_fs
+# Required-Stop: $local_fs $syslog $network $remote_fs
+# Default-Start: 2 3 4 5
+# Default-Stop: 0 1 6
+# Short-Description: start and stop ctdb service
+# Description: Start and stop CTDB (Clustered TDB daemon)
+### END INIT INFO
+
+# Source function library.
+if [ -f /etc/init.d/functions ] ; then
+ # Red Hat
+ . /etc/init.d/functions
+elif [ -f /etc/rc.d/init.d/functions ] ; then
+ # Red Hat
+ . /etc/rc.d/init.d/functions
+elif [ -f /etc/rc.status ] ; then
+ # SUSE
+ . /etc/rc.status
+ rc_reset
+ LC_ALL=en_US.UTF-8
+elif [ -f /lib/lsb/init-functions ] ; then
+ # Debian
+ . /lib/lsb/init-functions
+fi
+
+# Avoid using root's TMPDIR
+unset TMPDIR
+
+[ -n "$CTDB_BASE" ] || export CTDB_BASE="/etc/ctdb"
+
+. "${CTDB_BASE}/functions"
+loadconfig "network"
+loadconfig "ctdb"
+
+# check networking is up (for redhat)
+if [ "$NETWORKING" = "no" ] ; then
+ exit 0
+fi
+
+detect_init_style
+export CTDB_INIT_STYLE
+
+ctdbd="${CTDBD:-/usr/sbin/ctdbd}"
+ctdbd_wrapper="${CTDBD_WRAPPER:-/usr/sbin/ctdbd_wrapper}"
+pidfile="${CTDB_PIDFILE:-/var/run/ctdb/ctdbd.pid}"
+
+############################################################
+
+start()
+{
+ printf "Starting ctdbd service: "
+
+ case "$CTDB_INIT_STYLE" in
+ suse)
+ startproc \
+ "$ctdbd_wrapper" "$pidfile" "start"
+ rc_status -v
+ ;;
+ redhat)
+ daemon --pidfile "$pidfile" \
+ "$ctdbd_wrapper" "$pidfile" "start"
+ RETVAL=$?
+ echo
+ [ $RETVAL -eq 0 ] && touch /var/lock/subsys/ctdb || RETVAL=1
+ return $RETVAL
+ ;;
+ debian)
+ eval start-stop-daemon --start --quiet --background --exec \
+ "$ctdbd_wrapper" "$pidfile" "start"
+ ;;
+ esac
+}
+
+stop()
+{
+ printf "Shutting down ctdbd service: "
+
+ case "$CTDB_INIT_STYLE" in
+ suse)
+ "$ctdbd_wrapper" "$pidfile" "stop"
+ rc_status -v
+ ;;
+ redhat)
+ "$ctdbd_wrapper" "$pidfile" "stop"
+ RETVAL=$?
+ # Common idiom in Red Hat init scripts - success() always
+ # succeeds so this does behave like if-then-else
+ # shellcheck disable=SC2015
+ [ $RETVAL -eq 0 ] && success || failure
+ echo ""
+ [ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/ctdb
+ return $RETVAL
+ ;;
+ debian)
+ "$ctdbd_wrapper" "$pidfile" "stop"
+ log_end_msg $?
+ ;;
+ esac
+}
+
+restart()
+{
+ stop
+ start
+}
+
+check_status ()
+{
+ # Backward compatibility. When we arrange to pass --pidfile to
+ # ctdbd we also create the directory that will contain it. If
+ # that directory is missing then we don't use the pidfile to check
+ # status. Note that this probably won't work if
+ # $CTDB_VALGRIND="yes" but this doesn't need full backward
+ # compatibility because it is a debug option.
+ _d=$(dirname "$pidfile")
+ if [ -d "$_d" ] ; then
+ _pf_opt="-p $pidfile"
+ else
+ _pf_opt=""
+ fi
+
+ case "$CTDB_INIT_STYLE" in
+ suse)
+ checkproc $_pf_opt "$ctdbd"
+ rc_status -v
+ ;;
+ redhat)
+ status $_pf_opt -l "ctdb" "$ctdbd"
+ ;;
+ debian)
+ status_of_proc $_pf_opt "$ctdbd" "ctdb"
+ ;;
+ esac
+}
+
+############################################################
+
+case "$1" in
+ start)
+ start
+ ;;
+ stop)
+ stop
+ ;;
+ restart|reload|force-reload)
+ restart
+ ;;
+ status)
+ check_status
+ ;;
+ condrestart|try-restart)
+ if check_status >/dev/null ; then
+ restart
+ fi
+ ;;
+ cron)
+ # used from cron to auto-restart ctdb
+ check_status >/dev/null 2>&1 || restart
+ ;;
+ *)
+ echo "Usage: $0 {start|stop|restart|reload|force-reload|status|cron|condrestart|try-restart}"
+ exit 1
+esac
--- /dev/null
+#!/bin/sh
+
+### BEGIN INIT INFO
+# Provides: nmbd
+# Required-Start: $network $local_fs $remote_fs
+# Required-Stop: $network $local_fs $remote_fs
+# X-Start-Before: smbd
+# Default-Start: 2 3 4 5
+# Default-Stop: 0 1 6
+# Short-Description: Samba NetBIOS nameserver (nmbd)
+# Description: NetBIOS name server to provide NetBIOS over IP naming services
+# to clients
+### END INIT INFO
+
+
+PIDDIR=/var/run/samba
+NMBDPID=$PIDDIR/nmbd.pid
+
+# clear conflicting settings from the environment
+unset TMPDIR
+
+# See if the daemons are there
+test -x /usr/sbin/nmbd || exit 0
+
+. /lib/lsb/init-functions
+
+case $1 in
+ start)
+ SERVER_ROLE=`samba-tool testparm --parameter-name="server role" 2>/dev/null | tail -1`
+ if [ "$SERVER_ROLE" = "active directory domain controller" ]; then
+ exit 0
+ fi
+
+ if [ -n `which testparm` ]
+ then
+ NMBD_DISABLED=`testparm -s --parameter-name='disable netbios' 2>/dev/null`
+ fi
+ if [ "$NMBD_DISABLED" != Yes ]; then
+ log_daemon_msg "Starting NetBIOS name server" nmbd
+ # Make sure we have our PIDDIR, even if it's on a tmpfs
+ install -o root -g root -m 755 -d $PIDDIR
+
+ if ! start-stop-daemon --start --quiet --oknodo --exec /usr/sbin/nmbd --pidfile $NMBDPID -- -D
+ then
+ log_end_msg 1
+ exit 1
+ fi
+ log_end_msg 0
+ fi
+
+ ;;
+ stop)
+
+ log_daemon_msg "Stopping NetBIOS name server" nmbd
+
+ start-stop-daemon --stop --quiet --pidfile $NMBDPID
+ # Wait a little and remove stale PID file
+ sleep 1
+ if [ -f $NMBDPID ] && ! ps h `cat $NMBDPID` > /dev/null
+ then
+ # Stale PID file (nmbd was succesfully stopped),
+ # remove it (should be removed by nmbd itself IMHO.)
+ rm -f $NMBDPID
+ fi
+
+ log_end_msg 0
+
+ ;;
+ restart|force-reload)
+ $0 stop
+ sleep 1
+ $0 start
+ ;;
+ status)
+ status_of_proc -p $NMBDPID /usr/sbin/nmbd nmbd
+ exit $?
+ ;;
+ *)
+ echo "Usage: /etc/init.d/nmbd {start|stop|restart|force-reload|status}"
+ exit 1
+ ;;
+esac
+
+exit 0
--- /dev/null
+#! /bin/sh
+
+### BEGIN INIT INFO
+# Provides: samba-ad-dc
+# Required-Start: $network $local_fs $remote_fs
+# Required-Stop: $network $local_fs $remote_fs
+# Default-Start: 2 3 4 5
+# Default-Stop: 0 1 6
+# Short-Description: Samba daemons for the AD DC
+# Description: Meta-service to provide AD and SMB/CIFS services to clients
+### END INIT INFO
+
+#
+# Start/stops the Samba daemon (samba).
+# Adapted from the Samba 3 packages.
+#
+
+PIDDIR=/var/run/samba
+SAMBAPID=$PIDDIR/samba.pid
+
+# clear conflicting settings from the environment
+unset TMPDIR
+
+# See if the daemon and the config file are there
+test -x /usr/sbin/samba -a -r /etc/samba/smb.conf || exit 0
+
+. /lib/lsb/init-functions
+
+case "$1" in
+ start)
+ SERVER_ROLE=`samba-tool testparm --parameter-name="server role" 2>/dev/null | tail -1`
+ if [ "$SERVER_ROLE" != "active directory domain controller" ]; then
+ exit 0
+ fi
+
+
+ # CVE-2013-4475
+ KEYFILE=/var/lib/samba/private/tls/key.pem
+ if [ -e $KEYFILE ]
+ then
+ KEYPERMS=`stat -c %a $KEYFILE`
+ if [ "$KEYPERMS" != "600" ]
+ then
+ echo "wrong permission on $KEYFILE, must be 600"
+ echo "samba will not start (CVE-2013-4475)"
+ echo "Removing all tls .pem files will cause an auto-regeneration with the correct permissions."
+ exit 1
+ fi
+ fi
+
+ log_daemon_msg "Starting Samba AD DC daemon" "samba"
+ # Make sure we have our PIDDIR, even if it's on a tmpfs
+ install -o root -g root -m 755 -d $PIDDIR
+
+ if ! start-stop-daemon --start --quiet --oknodo --exec /usr/sbin/samba --pidfile $SAMBAPID -- -D; then
+ log_end_msg 1
+ exit 1
+ fi
+
+ log_end_msg 0
+ ;;
+ stop)
+ log_daemon_msg "Stopping Samba AD DC daemon" "samba"
+
+ start-stop-daemon --stop --quiet --pidfile $SAMBAPID
+ # Wait a little and remove stale PID file
+ sleep 1
+ if [ -f $SAMBAPID ] && ! ps h `cat $SAMBAPID` > /dev/null
+ then
+ # Stale PID file (samba was succesfully stopped),
+ # remove it (should be removed by samba itself IMHO.)
+ rm -f $SAMBAPID
+ fi
+
+ log_end_msg 0
+
+ ;;
+ restart|force-reload)
+ $0 stop
+ sleep 1
+ $0 start
+ ;;
+ status)
+ status_of_proc -p $SAMBAPID /usr/sbin/samba samba
+ exit $?
+ ;;
+ *)
+ echo "Usage: /etc/init.d/samba-ad-dc {start|stop|restart|force-reload|status}"
+ exit 1
+ ;;
+esac
+
+exit 0
--- /dev/null
+#!/bin/sh
+
+### BEGIN INIT INFO
+# Provides: smbd
+# Required-Start: $network $local_fs $remote_fs
+# Required-Stop: $network $local_fs $remote_fs
+# Default-Start: 2 3 4 5
+# Default-Stop: 0 1 6
+# Should-Start: slapd cups
+# Should-Stop: slapd cups
+# Short-Description: Samba SMB/CIFS daemon (smbd)
+# Description: server to provide SMB/CIFS services to clients
+### END INIT INFO
+
+
+PIDDIR=/var/run/samba
+SMBDPID=$PIDDIR/smbd.pid
+
+# clear conflicting settings from the environment
+unset TMPDIR
+
+# See if the daemons are there
+test -x /usr/sbin/smbd || exit 0
+
+. /lib/lsb/init-functions
+
+case $1 in
+ start)
+ SERVER_ROLE=`samba-tool testparm --parameter-name="server role" 2>/dev/null | tail -1`
+ if [ "$SERVER_ROLE" = "active directory domain controller" ]; then
+ exit 0
+ fi
+
+ log_daemon_msg "Starting SMB/CIFS daemon" smbd
+ # Make sure we have our PIDDIR, even if it's on a tmpfs
+ install -o root -g root -m 755 -d $PIDDIR
+
+ if ! start-stop-daemon --start --quiet --oknodo --exec /usr/sbin/smbd --pidfile $SMBDPID -- -D; then
+ log_end_msg 1
+ exit 1
+ fi
+
+ log_end_msg 0
+ ;;
+ stop)
+
+ log_daemon_msg "Stopping SMB/CIFS daemon" smbd
+
+ start-stop-daemon --stop --quiet --pidfile $SMBDPID
+ # Wait a little and remove stale PID file
+ sleep 1
+ if [ -f $SMBDPID ] && ! ps h `cat $SMBDPID` > /dev/null
+ then
+ # Stale PID file, remove it (should be removed by
+ # smbd itself IMHO).
+ rm -f $SMBDPID
+ fi
+
+ log_end_msg 0
+
+ ;;
+ reload)
+ log_daemon_msg "Reloading /etc/samba/smb.conf" smbd
+
+ start-stop-daemon --stop --quiet --signal HUP --pidfile $SMBDPID
+
+ log_end_msg 0
+ ;;
+ restart|force-reload)
+ $0 stop
+ sleep 1
+ $0 start
+ ;;
+ status)
+ status_of_proc -p $SMBDPID /usr/sbin/smbd smbd
+ exit $?
+ ;;
+ *)
+ echo "Usage: /etc/init.d/smbd {start|stop|reload|restart|force-reload|status}"
+ exit 1
+ ;;
+esac
+
+exit 0
--- /dev/null
+#!/bin/sh
+
+### BEGIN INIT INFO
+# Provides: winbind
+# Required-Start: $network $remote_fs $syslog
+# Required-Stop: $network $remote_fs $syslog
+# Should-Start: samba
+# Default-Start: 2 3 4 5
+# Default-Stop: 0 1 6
+# Short-Description: Samba Winbind daemon
+# Description: Name Service Switch daemon for resolving names from NT servers
+### END INIT INFO
+
+
+PATH=/sbin:/bin:/usr/sbin:/usr/bin
+
+[ -r /etc/default/winbind ] && . /etc/default/winbind
+
+DAEMON=/usr/sbin/winbindd
+PIDDIR=/var/run/samba
+WINBINDPID=$PIDDIR/winbindd.pid
+
+# clear conflicting settings from the environment
+unset TMPDIR
+
+# See if the daemon is there
+test -x $DAEMON || exit 0
+
+SERVER_ROLE=`samba-tool testparm --parameter-name="server role" 2>/dev/null | tail -1`
+if [ "$SERVER_ROLE" = "active directory domain controller" ]; then
+ exit 0
+fi
+
+. /lib/lsb/init-functions
+
+case "$1" in
+ start)
+ log_daemon_msg "Starting the Winbind daemon" "winbind"
+
+ start-stop-daemon --start --quiet --oknodo --exec $DAEMON --pidfile $WINBINDPID -- $WINBINDD_OPTS
+
+ log_end_msg $?
+ ;;
+
+ stop)
+ log_daemon_msg "Stopping the Winbind daemon" "winbind"
+ start-stop-daemon --stop --quiet --oknodo --exec $DAEMON --pidfile $WINBINDPID
+ log_end_msg $?
+ ;;
+
+ restart|force-reload)
+ $0 stop && sleep 2 && $0 start
+ ;;
+
+ status)
+ status_of_proc -p $WINBINDPID $DAEMON winbind && exit 0 || exit $?
+ ;;
+ *)
+ echo "Usage: /etc/init.d/winbind {start|stop|restart|force-reload|status}"
+ exit 1
+ ;;
+esac
--- /dev/null
+/var/log/ctdb/log.ctdb {
+ weekly
+ missingok
+ rotate 7
+ copytruncate
+ compress
+ delaycompress
+ notifempty
+}
--- /dev/null
+/var/log/samba/log.smbd {
+ weekly
+ missingok
+ rotate 7
+ postrotate
+ [ ! -x /usr/bin/smbcontrol ] || /usr/bin/smbcontrol smbd reload-config
+ endscript
+ compress
+ delaycompress
+ notifempty
+}
+
+/var/log/samba/log.nmbd {
+ weekly
+ missingok
+ rotate 7
+ postrotate
+ [ ! -x /usr/bin/smbcontrol ] || /usr/bin/smbcontrol nmbd reload-config
+ endscript
+ compress
+ delaycompress
+ notifempty
+}
+
+/var/log/samba/log.samba {
+ weekly
+ missingok
+ rotate 7
+ postrotate
+ if [ -d /run/systemd/system ] && command systemctl >/dev/null 2>&1 && systemctl is-active --quiet samba-ad-dc; then
+ systemctl kill --kill-who all --signal=SIGHUP samba-ad-dc
+ elif [ -f /var/run/samba/samba.pid ]; then
+ # This only sends to main pid, See #803924
+ kill -HUP `cat /var/run/samba/samba.pid`
+ fi
+ endscript
+ compress
+ delaycompress
+ notifempty
+}
--- /dev/null
+/var/log/samba/log.winbindd {
+ weekly
+ missingok
+ rotate 7
+ postrotate
+ if [ -x /usr/bin/smbcontrol ]; then
+ /usr/bin/smbcontrol winbindd reload-config
+ elif [ -f /var/run/samba/winbindd.pid ]; then
+ kill -HUP `cat /var/run/samba/winbindd.pid`
+ fi
+ endscript
+ compress
+ delaycompress
+ notifempty
+}
--- /dev/null
+../init.d/ctdb
\ No newline at end of file
--- /dev/null
+../init.d/nmbd
\ No newline at end of file
--- /dev/null
+../init.d/samba-ad-dc
\ No newline at end of file
--- /dev/null
+../init.d/smbd
\ No newline at end of file
--- /dev/null
+../init.d/winbind
\ No newline at end of file
--- /dev/null
+../init.d/ctdb
\ No newline at end of file
--- /dev/null
+../init.d/nmbd
\ No newline at end of file
--- /dev/null
+../init.d/samba-ad-dc
\ No newline at end of file
--- /dev/null
+../init.d/smbd
\ No newline at end of file
--- /dev/null
+../init.d/winbind
\ No newline at end of file
--- /dev/null
+../init.d/ctdb
\ No newline at end of file
--- /dev/null
+../init.d/nmbd
\ No newline at end of file
--- /dev/null
+../init.d/samba-ad-dc
\ No newline at end of file
--- /dev/null
+../init.d/smbd
\ No newline at end of file
--- /dev/null
+../init.d/winbind
\ No newline at end of file
--- /dev/null
+../init.d/ctdb
\ No newline at end of file
--- /dev/null
+../init.d/nmbd
\ No newline at end of file
--- /dev/null
+../init.d/samba-ad-dc
\ No newline at end of file
--- /dev/null
+../init.d/smbd
\ No newline at end of file
--- /dev/null
+../init.d/winbind
\ No newline at end of file
--- /dev/null
+../init.d/ctdb
\ No newline at end of file
--- /dev/null
+../init.d/nmbd
\ No newline at end of file
--- /dev/null
+../init.d/samba-ad-dc
\ No newline at end of file
--- /dev/null
+../init.d/smbd
\ No newline at end of file
--- /dev/null
+../init.d/winbind
\ No newline at end of file
--- /dev/null
+../init.d/ctdb
\ No newline at end of file
--- /dev/null
+../init.d/nmbd
\ No newline at end of file
--- /dev/null
+../init.d/samba-ad-dc
\ No newline at end of file
--- /dev/null
+../init.d/smbd
\ No newline at end of file
--- /dev/null
+../init.d/winbind
\ No newline at end of file
--- /dev/null
+../init.d/ctdb
\ No newline at end of file
--- /dev/null
+../init.d/nmbd
\ No newline at end of file
--- /dev/null
+../init.d/samba-ad-dc
\ No newline at end of file
--- /dev/null
+../init.d/smbd
\ No newline at end of file
--- /dev/null
+../init.d/winbind
\ No newline at end of file
--- /dev/null
+Defaults!/etc/ctdb/statd-callout !requiretty
+
+rpcuser ALL=(ALL) NOPASSWD: /etc/ctdb/statd-callout
--- /dev/null
+/lib/systemd/system/ctdb.service
\ No newline at end of file
--- /dev/null
+/lib/systemd/system/nmbd.service
\ No newline at end of file
--- /dev/null
+/lib/systemd/system/smbd.service
\ No newline at end of file
--- /dev/null
+/lib/systemd/system/winbind.service
\ No newline at end of file
--- /dev/null
+/dev/null
\ No newline at end of file
--- /dev/null
+[Samba]
+title=LanManager-like file and printer server for Unix
+description=The Samba software suite is a collection of programs that implements the SMB/CIFS protocol for unix systems, allowing you to serve files and printers to Windows, NT, OS/2 and DOS clients. This protocol is sometimes also referred to as the LanManager or NetBIOS protocol.
+ports=137,138/udp|139,445/tcp