diff options
Diffstat (limited to 'ctdb/doc/examples/config_migrate.sh')
-rwxr-xr-x | ctdb/doc/examples/config_migrate.sh | 741 |
1 files changed, 741 insertions, 0 deletions
diff --git a/ctdb/doc/examples/config_migrate.sh b/ctdb/doc/examples/config_migrate.sh new file mode 100755 index 0000000..874e96c --- /dev/null +++ b/ctdb/doc/examples/config_migrate.sh @@ -0,0 +1,741 @@ +#!/bin/sh + +# config_migrate.sh - migrate old ctdbd.conf file to new configuration files +# +# Input files are old-style CTDB configuration files, including: +# +# /etc/ctdb/ctdbd.conf +# /usr/local/etc/ctdb/ctdbd.conf +# /etc/sysconfig/ctdb +# /etc/defaults/ctdb +# +# These files are sourced by this script. They used to be sourced by +# ctdbd_wrapper, so this should not be too surprising. +# +# By default, the output directory is the given configuration +# directory. An alternate output directory can be specified if this +# isn't desired. +# +# The output directory will contain the following if non-empty: +# +# * ctdb.conf (may be empty) +# * script.options +# * ctdb.tunables +# * ctdb.sysconfig - consider installing as /etc/sysconfig/ctdb, +# /etc/default/ctdb, or similar +# * commands.sh - consider running commands in this files +# * README.warn - warnings about removed/invalid configuration options + +usage () +{ + cat <<EOF +usage: config_migrate.sh [-f] [-d <ctdb-config-dir>] [-o <out-dir>] <file> ... +EOF + exit 1 +} + +config_dir="" +out_dir="" +force=false + +while getopts "d:fho:?" opt ; do + case "$opt" in + d) config_dir="$OPTARG" ;; + f) force=true ;; + o) out_dir="$OPTARG" ;; + \?|h) usage ;; + esac +done +shift $((OPTIND - 1)) + +if [ $# -lt 1 ] ; then + usage +fi + +if [ -z "$config_dir" ] ; then + echo "Assuming \"/etc/ctdb\" as ctdb configuration directory" + echo "If that's not correct, please specify config dir with -d" + echo + config_dir="/etc/ctdb" +else + echo "Using \"$config_dir\" as ctdb configuration directory" + echo +fi + +if [ -z "$out_dir" ] ; then + echo "No output directory specified, using \"$config_dir\"" + echo + out_dir="$config_dir" +fi + +############################################################ + +# +# Output file handling +# + +out_file_check_and_create () +{ + _out_file="$1" + + if [ -f "$_out_file" ] ; then + if ! $force ; then + echo "Not overwriting existing file: ${_out_file}" >&2 + return 1 + fi + mv -v "$_out_file" "${_out_file}.convertsave" + fi + + touch "$_out_file" + + return 0 +} + +out_file_remove_if_empty () +{ + _out_file="$1" + + if [ ! -s "$_out_file" ] ; then + rm "$_out_file" + fi +} + +############################################################ + +# +# Option/tunable/service conversion and validity checking +# +# This is basically the data that drives most of the rest of the +# script +# + +# Convert a ctdbd.conf opt+val into a ctdb.conf section+opt+val +# +# If opt is matched and val is empty then output is printed, allowing +# this function to be reused to check if opt is valid. +# +# Note that for boolean options, the expected value and the new value +# form part of the data. +get_ctdb_conf_option () +{ + _opt="$1" + _val="$2" + + awk -v opt="${_opt}" -v val="${_val}" \ + '$3 == opt { + if (!$4 || !val || val == $4) { + if ($5) { + print $1, $2, $5 + } else { + print $1, $2, val + } + } + }' <<EOF +cluster node-address CTDB_NODE_ADDRESS +cluster cluster-lock CTDB_RECOVERY_LOCK +cluster transport CTDB_TRANSPORT +cluster leader-capability CTDB_CAPABILITY_RECMASTER no false +database lock-debug-script CTDB_DEBUG_LOCKS +database persistent-database-directory CTDB_DBDIR_PERSISTENT +database state-database-directory CTDB_DBDIR_STATE +database volatile-database-directory CTDB_DBDIR +event debug-script CTDB_DEBUG_HUNG_SCRIPT +legacy lmaster-capability CTDB_CAPABILITY_LMASTER no false +legacy realtime-scheduling CTDB_NOSETSCHED yes false +legacy script-log-level CTDB_SCRIPT_LOG_LEVEL +legacy start-as-disabled CTDB_START_AS_DISABLED yes true +legacy start-as-stopped CTDB_START_AS_STOPPED yes true +logging location CTDB_LOGGING +logging log-level CTDB_DEBUGLEVEL +EOF + +} + +# Check if an option will convert to a ctdb.conf option +check_ctdb_conf_option () +{ + _opt="$1" + + _out=$(get_ctdb_conf_option "$_opt" "") + [ -n "$_out" ] +} + +# Convert a ctdbd.conf tunable option into a ctdb.conf section+opt +# +# The difference between this and get_ctdb_conf_option() is that only +# the tunable part of the option is passed as opt and it is matched +# case-insensitively. +get_ctdb_conf_tunable_option () +{ + _opt="$1" + _val="$2" + + awk -v opt="${_opt}" -v val="${_val}" \ + 'tolower($3) == tolower(opt) { + if (!$4 || !val || (val == 0 ? 0 : 1) == $4) { + if ($5) { + print $1, $2, $5 + } else { + print $1, $2, val + } + } + }' <<EOF +database tdb-mutexes TDBMutexEnabled 0 false +failover disabled DisableIPFailover 1 true +EOF + +} + +# Check if a tunable will convert to a ctdb.conf option +check_ctdb_conf_tunable_option () +{ + _opt="$1" + + _out=$(get_ctdb_conf_tunable_option "$_opt" "") + [ -n "$_out" ] +} + +# Check if an option has been removed +check_removed_option () +{ + _option="$1" + + grep -Fqx "$_option" <<EOF +CTDB_BASE +CTDB_PIDFILE +CTDB_SOCKET +CTDB_EVENT_SCRIPT_DIR +CTDB_NOTIFY_SCRIPT +CTDB_PUBLIC_INTERFACE +CTDB_MAX_PERSISTENT_CHECK_ERRORS +CTDB_SHUTDOWN_TIMEOUT +CTDB_MONITOR_SWAP_USAGE +EOF +} + +# Check if an option is a valid script option +check_valid_script_option () +{ + _option="$1" + + grep -Fqx "$_option" <<EOF +# 10.interface +CTDB_PARTIALLY_ONLINE_INTERFACES +# 11.natgw +CTDB_NATGW_DEFAULT_GATEWAY +CTDB_NATGW_NODES +CTDB_NATGW_PRIVATE_NETWORK +CTDB_NATGW_PUBLIC_IFACE +CTDB_NATGW_PUBLIC_IP +CTDB_NATGW_STATIC_ROUTES +# 13.per_ip_routing +CTDB_PER_IP_ROUTING_CONF +CTDB_PER_IP_ROUTING_RULE_PREF +CTDB_PER_IP_ROUTING_TABLE_ID_LOW +CTDB_PER_IP_ROUTING_TABLE_ID_HIGH +# 90.lvs +CTDB_LVS_NODES +CTDB_LVS_PUBLIC_IFACE +CTDB_LVS_PUBLIC_IP +# 20.multipathd +CTDB_MONITOR_MPDEVICES +# 31.clamd +CTDB_CLAMD_SOCKET +# 48.netbios +CTDB_SERVICE_NMB +# 49.winbind +CTDB_SERVICE_WINBIND +# 50.samba +CTDB_SAMBA_CHECK_PORTS +CTDB_SAMBA_SKIP_SHARE_CHECK +CTDB_SERVICE_SMB +# 60.nfs +CTDB_NFS_CALLOUT +CTDB_NFS_CHECKS_DIR +CTDB_NFS_SKIP_SHARE_CHECK +CTDB_RPCINFO_LOCALHOST +CTDB_RPCINFO_LOCALHOST6 +CTDB_NFS_STATE_FS_TYPE +CTDB_NFS_STATE_MNT +# 70.iscsi +CTDB_START_ISCSI_SCRIPTS +# 00.ctdb +CTDB_MAX_CORRUPT_DB_BACKUPS +# 05.system +CTDB_MONITOR_FILESYSTEM_USAGE +CTDB_MONITOR_MEMORY_USAGE +# debug_hung_scripts.sh +CTDB_DEBUG_HUNG_SCRIPT_STACKPAT +EOF +} + +# Check if a tunable is valid +check_valid_tunable () +{ + _tunable="$1" + + grep -Fiqx "$_tunable" <<EOF +AllowClientDBAttach +AllowMixedVersions +AllowUnhealthyDBRead +ControlTimeout +DBRecordCountWarn +DBRecordSizeWarn +DBSizeWarn +DatabaseHashSize +DatabaseMaxDead +DeferredAttachTO +DisableIPFailover +ElectionTimeout +EnableBans +EventScriptTimeout +FetchCollapse +HopcountMakeSticky +IPAllocAlgorithm +KeepaliveInterval +KeepaliveLimit +LockProcessesPerDB +LogLatencyMs +MaxQueueDropMsg +MonitorInterval +MonitorTimeoutCount +NoIPFailback +NoIPTakeover +PullDBPreallocation +QueueBufferSize +RecBufferSizeLimit +RecLockLatencyMs +RecdFailCount +RecdPingTimeout +RecoverInterval +RecoverTimeout +RecoveryBanPeriod +RecoveryDropAllIPs +RecoveryGracePeriod +RepackLimit +RerecoveryTimeout +SeqnumInterval +StatHistoryInterval +StickyDuration +StickyPindown +TDBMutexEnabled +TakeoverTimeout +TickleUpdateInterval +TraverseTimeout +VacuumFastPathCount +VacuumInterval +VacuumMaxRunTime +VerboseMemoryNames +EOF +} + +# Check if a tunable has been removed +check_removed_tunable () +{ + _tunable="$1" + + grep -Fiqx "$_tunable" <<EOF +NoIPHostOnAllDisabled +VacuumLimit +EOF +} + +# Print a command to enable an event script for the given service +print_event_script_enable_command () +{ + _service="$1" + + _component="" + _script="" + case "$_service" in + samba) _component="legacy" ; _script="50.samba" ;; + winbind) _component="legacy" ; _script="49.winbind" ;; + apache2|httpd) _component="legacy" ; _script="41.httpd" ;; + clamd) _component="legacy" ; _script="31.clamd" ;; + iscsi) _component="legacy" ; _script="70.iscsi" ;; + nfs) _component="legacy" ; _script="60.nfs" ;; + vsftpd) _component="legacy" ; _script="40.vsftpd" ;; + esac + + if [ -z "$_script" ] ; then + return 1 + fi + + cat <<EOF +# Enable the ${_service} service +ctdb event script enable ${_component} ${_script} + +EOF +} + +# Check if the given service is valid +check_valid_service () +{ + _service="$1" + + print_event_script_enable_command "$_service" >/dev/null +} + +############################################################ + +# +# Utilities +# + +# List all options starting with "CTDB_" set in given configuration files +list_options () +{ + set | + sed -n 's|^\(CTDB_[^=]*\)=\(.*\)|\1 \2|p' | + while read -r _var _val ; do + # Strip quotes from value + _val=$(echo "$_val" | sed -e "s|^'||" -e "s|'\$||") + + echo "${_var} ${_val}" + done +} + +# List all tunables set in the given configuration files +list_tunables () +{ + list_options | + while read -r _opt _val ; do + case "$_opt" in + CTDB_SET_*) echo "${_opt#CTDB_SET_} ${_val}" ;; + esac + done +} + +# List all managed services according to the given configuration files +list_managed_services () +{ + # + # CTDB_MANAGES_<service>="yes" + # + list_options | + while read -r _opt _val ; do + case "$_opt" in + CTDB_MANAGES_*) : ;; + *) continue ;; + esac + + if [ "$_val" != "yes" ] ; then + continue + fi + + # Trim and downcase + echo "${_opt#CTDB_MANAGES_}" | tr '[:upper:]' '[:lower:]' + done + + # + # CTDB_MANAGED_SERVICES + # + for _service in $CTDB_MANAGED_SERVICES ; do + echo "$_service" + done +} + +############################################################ + +# +# Print warnings for removed and unknown options +# + + +# Print a warning as a bullet list item +# +# Arguments after the 1st are printed as a subsequent paragraph. +warn () +{ + bullet="$1" ; shift + + printf '* %s\n\n' "$bullet" + + if [ $# -gt 0 ] ; then + printf ' %s\n\n' "$*" + fi +} + +warn_about_CTDB_DBDIR_tmpfs_yes () +{ + if $ctdb_dbdir_tmpfs_magic ; then + warn "Option \"CTDB_DBDIR=tmpfs\" is no longer available:" \ + "Permanently mount a tmpfs filesystem on the volatile" \ + "database directory" + fi +} + +warn_about_unknown_managed_services () +{ + list_managed_services | + while read -r _s ; do + if check_valid_service "$_s" ; then + continue + fi + warn "Unknown service \"${_s}\" marked as managed" \ + "If this is a 3rd party service, please enable it manually" + done +} + +warn_about_removed_and_unknown_options () +{ + list_options | + while read -r _opt _val ; do + if check_ctdb_conf_option "$_opt" ; then + continue + fi + + if check_valid_script_option "$_opt" ; then + continue + fi + + case "$_opt" in + CTDB_MANAGED_SERVICES|\ + CTDB_MANAGES_*|\ + CTDB_SET_*|\ + CTDB_NODES|\ + CTDB_PUBLIC_ADDRESSES|\ + CTDB_MAX_OPEN_FILES|\ + CTDB_SUPPRESS_COREFILE) + # Handled elsewhere + continue + ;; + esac + + if check_removed_option "$_opt" ; then + warn "Option \"${_opt}\" is no longer available" \ + "Please see the WHATSNEW.txt" + continue + fi + + warn "Option \"${_opt}\" is unknown" + done +} + +warn_about_removed_and_unknown_tunables () +{ + list_tunables | + while read -r _var _val ; do + if check_valid_tunable "$_var" ; then + continue + fi + + if check_removed_tunable "$_var" ; then + warn "Tunable \"${_var}\" is no longer available" \ + "Please see the WHATSNEW.txt" + continue + fi + + warn "Tunable \"${_var}\" is unknown" + done +} + +############################################################ + +# +# Top-level file builders +# + +build_ctdb_conf () +{ + _out_file="$1" + + out_file_check_and_create "$_out_file" || return + + list_options | + while read -r _opt _val ; do + case "$_opt" in + CTDB_SET_*) + _opt="${_opt#CTDB_SET_}" + _out=$(get_ctdb_conf_tunable_option "$_opt" "$_val") + ;; + *) + _out=$(get_ctdb_conf_option "$_opt" "$_val") + esac + if [ -z "$_out" ] ; then + continue + fi + + # $_out is section and key, replace dashes with spaces + # Intentional word splitting + # shellcheck disable=SC2086 + set -- $_out + _section=$(echo "$1" | sed -e 's|-| |g') + _key=$(echo "$2" | sed -e 's|-| |g') + _newval="$3" + + if ! grep -Fqx "[${_section}]" "$_out_file" ; then + # Add blank line if file is not empty + if [ -s "$_out_file" ] ; then + echo >>"$_out_file" + fi + # Create section at end of file + echo "[${_section}]" >>"$_out_file" + fi + + # Must escape leading TAB or sed eats it + sed -i -e "/\\[${_section}\\]/a\ +\\ ${_key} = ${_newval} +" "$_out_file" + + done + +} + +build_script_options () +{ + _out_file="$1" + + out_file_check_and_create "$_out_file" || return + + list_options | + while read -r _var _val ; do + if check_valid_script_option "$_var" ; then + echo "${_var}=${_val}" + fi + done >>"$_out_file" + + out_file_remove_if_empty "$_out_file" +} + +build_ctdb_tunables () +{ + _out_file="$1" + + out_file_check_and_create "$_out_file" || return + + list_tunables | + while read -r _var _val ; do + if check_ctdb_conf_tunable_option "$_var" ; then + continue + fi + if ! check_valid_tunable "$_var" ; then + continue + fi + echo "${_var}=${_val}" + done >>"$_out_file" + + out_file_remove_if_empty "$_out_file" +} + +build_ctdb_sysconfig () +{ + _out_file="$1" + + out_file_check_and_create "$_out_file" || return + + if [ -n "$CTDB_SUPPRESS_COREFILE" ] ; then + if [ "$CTDB_SUPPRESS_COREFILE" = "yes" ] ; then + echo "ulimit -c 0" + else + echo "ulimit -c unlimited" + fi >>"$_out_file" + fi + + if [ -n "$CTDB_MAX_OPEN_FILES" ] ; then + echo "ulimit -n ${CTDB_MAX_OPEN_FILES}" >>"$_out_file" + fi + + out_file_remove_if_empty "$_out_file" +} + +build_commands_sh () +{ + _out_file="$1" + + out_file_check_and_create "$_out_file" || return + + # + # Enable script for managed services + # + list_managed_services | + while read -r _service ; do + print_event_script_enable_command "$_service" + done >>"$_out_file" + + # + # CTDB_NODES no longer available + # + if [ -n "$CTDB_NODES" ] ; then + if [ "$CTDB_NODES" = "${config_dir}/nodes" ] ; then + cat <<EOF +# CTDB_NODES=${CTDB_NODES} +# Looks like the standard location. Nothing to do. + +EOF + else + cat <<EOF +# CTDB_NODES=${CTDB_NODES} +# Looks like a non-standard location. Use the default location +# in the configuration directory or create a symlink. +ln -s "$CTDB_NODES" "${config_dir}/nodes" + +EOF + fi >>"$_out_file" + fi + + # + # CTDB_PUBLIC_ADDRESSES no longer available + # + if [ -n "$CTDB_PUBLIC_ADDRESSES" ] ; then + _pa="public_addresses" + if [ "$CTDB_PUBLIC_ADDRESSES" = "${config_dir}/${_pa}" ] ; then + cat <<EOF +# CTDB_PUBLIC_ADDRESSES=${CTDB_PUBLIC_ADDRESSES} +# Looks like the standard location. Nothing to do. + +EOF + else + cat <<EOF +# CTDB_PUBLIC_ADDRESSES=${CTDB_PUBLIC_ADDRESSES} +# Looks like a non-standard location. Use the default location +# in the configuration directory or create a symlink. +ln -s "$CTDB_PUBLIC_ADDRESSES" "${config_dir}/${_pa}" + +EOF + fi >>"$_out_file" + fi + + out_file_remove_if_empty "$_out_file" +} + +build_README_warn () +{ + _out_file="$1" + + out_file_check_and_create "$_out_file" || return + + { + warn_about_CTDB_DBDIR_tmpfs_yes + warn_about_unknown_managed_services + warn_about_removed_and_unknown_options + warn_about_removed_and_unknown_tunables + } >>"$_out_file" + + out_file_remove_if_empty "$_out_file" +} + +############################################################ + +mkdir -p "$out_dir" || exit 1 + +# Source the input files +for i ; do + # Unknown non-constant source + # shellcheck disable=SC1090 + . "$i" +done + +# Special case +ctdb_dbdir_tmpfs_magic=false +if [ "$CTDB_DBDIR" = "tmpfs" ] ; then + ctdb_dbdir_tmpfs_magic=true + unset CTDB_DBDIR +fi + +build_ctdb_conf "${out_dir}/ctdb.conf" +build_script_options "${out_dir}/script.options" +build_ctdb_tunables "${out_dir}/ctdb.tunables" +build_ctdb_sysconfig "${out_dir}/ctdb.sysconfig" +build_commands_sh "${out_dir}/commands.sh" +build_README_warn "${out_dir}/README.warn" |