summaryrefslogtreecommitdiffstats
path: root/heartbeat/symlink
diff options
context:
space:
mode:
Diffstat (limited to '')
-rwxr-xr-xheartbeat/symlink245
1 files changed, 245 insertions, 0 deletions
diff --git a/heartbeat/symlink b/heartbeat/symlink
new file mode 100755
index 0000000..decd9f7
--- /dev/null
+++ b/heartbeat/symlink
@@ -0,0 +1,245 @@
+#!/bin/sh
+#
+#
+# An OCF RA that manages a symlink
+#
+# Copyright (c) 2011 Dominik Klein
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of version 2 of the GNU General Public License as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it would be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+#
+# Further, this software is distributed without any warranty that it is
+# free of the rightful claim of any third person regarding infringement
+# or the like. Any license provided herein, whether implied or
+# otherwise, applies only to this software file. Patent licenses, if
+# any, provided herein do not apply to combinations of this program with
+# other software, or any other product whatsoever.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+#
+
+#######################################################################
+# Initialization:
+
+: ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat}
+. ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs
+
+#######################################################################
+
+meta_data() {
+ cat <<END
+<?xml version="1.0"?>
+<!DOCTYPE resource-agent SYSTEM "ra-api-1.dtd">
+<resource-agent name="symlink" version="1.1">
+<version>1.0</version>
+
+<longdesc lang="en">
+This resource agent that manages a symbolic link (symlink).
+
+It is primarily intended to manage configuration files which should be
+enabled or disabled based on where the resource is running, such as
+cron job definitions and the like.
+</longdesc>
+<shortdesc lang="en">Manages a symbolic link</shortdesc>
+<parameters>
+<parameter name="link" required="1">
+<longdesc lang="en">
+Full path of the symbolic link to be managed. This must obviously be
+in a filesystem that supports symbolic links.
+</longdesc>
+<shortdesc lang="en">Full path of the symlink</shortdesc>
+<content type="string"/>
+</parameter>
+<parameter name="target" required="1">
+<longdesc lang="en">
+Full path to the link target (the file or directory which the symlink points to).
+</longdesc>
+<shortdesc lang="en">Full path to the link target</shortdesc>
+<content type="string" />
+</parameter>
+<parameter name="backup_suffix">
+<longdesc lang="en">
+A suffix to append to any files that the resource agent moves out of
+the way because they clash with "link".
+
+If this is unset (the default), then the resource agent will simply
+refuse to create a symlink if it clashes with an existing file.
+</longdesc>
+<shortdesc lang="en">Suffix to append to backup files</shortdesc>
+<content type="string" />
+</parameter>
+</parameters>
+<actions>
+<action name="start" timeout="15s" />
+<action name="stop" timeout="15s" />
+<action name="monitor" depth="0" timeout="15s" interval="60s"/>
+<action name="meta-data" timeout="5s" />
+<action name="validate-all" timeout="10s" />
+</actions>
+</resource-agent>
+END
+}
+
+symlink_monitor() {
+ # This applies the following logic:
+ #
+ # * If $OCF_RESKEY_link does not exist, then the resource is
+ # definitely stopped.
+ #
+ # * If $OCF_RESKEY_link exists and is a symlink that points to
+ # ${OCF_RESKEY_target}, then the resource is definitely started.
+ #
+ # * If $OCF_RESKEY_link exists, but is anything other than a
+ # symlink to ${OCF_RESKEY_target}, then the status depends on whether
+ # ${OCF_RESKEY_backup_suffix} is set:
+ #
+ # - if ${OCF_RESKEY_backup_suffix} is set, then the resource is
+ # simply not running. The existing file will be moved out of
+ # the way, to ${OCF_RESKEY_link}${OCF_RESKEY_backup_suffix},
+ # when the resource starts.
+ #
+ # - if ${OCF_RESKEY_backup_suffix} is not set, then an existing
+ # file ${OCF_RESKEY_link} is an error condition, and the
+ # resource can't start here.
+ rc=$OCF_ERR_GENERIC
+
+ # Using ls here instead of "test -e", as "test -e" returns false
+ # if the file does exist, but it a symlink to a file that doesn't
+ if ! ls "$OCF_RESKEY_link" >/dev/null 2>&1; then
+ ocf_log debug "$OCF_RESKEY_link does not exist"
+ rc=$OCF_NOT_RUNNING
+ elif [ ! -L "$OCF_RESKEY_link" ]; then
+ if [ -z "$OCF_RESKEY_backup_suffix" ]; then
+ ocf_exit_reason "$OCF_RESKEY_link exists but is not a symbolic link!"
+ exit $OCF_ERR_INSTALLED
+ else
+ ocf_log debug "$OCF_RESKEY_link exists but is not a symbolic link, will be moved to ${OCF_RESKEY_link}${OCF_RESKEY_backup_suffix} on start"
+ rc=$OCF_NOT_RUNNING
+ fi
+ elif readlink -m "$OCF_RESKEY_link" | egrep -q "^$(readlink -m ${OCF_RESKEY_target})$"; then
+ ocf_log debug "$OCF_RESKEY_link exists and is a symbolic link to ${OCF_RESKEY_target}."
+ rc=$OCF_SUCCESS
+ else
+ if [ -z "$OCF_RESKEY_backup_suffix" ]; then
+ ocf_exit_reason "$OCF_RESKEY_link does not point to ${OCF_RESKEY_target}!"
+ exit $OCF_ERR_INSTALLED
+ else
+ ocf_log debug "$OCF_RESKEY_link does not point to ${OCF_RESKEY_target}, will be moved to ${OCF_RESKEY_link}${OCF_RESKEY_backup_suffix} on start"
+ rc=$OCF_NOT_RUNNING
+ fi
+ fi
+ return $rc
+}
+
+symlink_start() {
+ if ! symlink_monitor; then
+ if [ -e "$OCF_RESKEY_link" ]; then
+ if [ -z "$OCF_RESKEY_backup_suffix" ]; then
+ # Shouldn't happen, because symlink_monitor should
+ # have errored out. But there is a chance that
+ # something else put that file there after
+ # symlink_monitor ran.
+ ocf_exit_reason "$OCF_RESKEY_link exists and no backup_suffix is set, won't overwrite."
+ exit $OCF_ERR_GENERIC
+ else
+ ocf_log debug "Found $OCF_RESKEY_link, moving to ${OCF_RESKEY_link}${OCF_RESKEY_backup_suffix}"
+ ocf_run mv -v "$OCF_RESKEY_link" "${OCF_RESKEY_link}${OCF_RESKEY_backup_suffix}" \
+ || exit $OCF_ERR_GENERIC
+ fi
+ fi
+ ocf_run ln -sv "$OCF_RESKEY_target" "$OCF_RESKEY_link"
+ symlink_monitor
+ return $?
+ else
+ return $OCF_SUCCESS
+ fi
+}
+
+symlink_stop() {
+ if symlink_monitor; then
+ ocf_run rm -vf "$OCF_RESKEY_link" || exit $OCF_ERR_GENERIC
+ if ! symlink_monitor; then
+ if [ -e "${OCF_RESKEY_link}${OCF_RESKEY_backup_suffix}" ]; then
+ ocf_log debug "Found backup ${OCF_RESKEY_link}${OCF_RESKEY_backup_suffix}, moving to $OCF_RESKEY_link"
+ # if restoring the backup fails then still return with
+ # $OCF_SUCCESS, but log a warning
+ ocf_run -warn mv "${OCF_RESKEY_link}${OCF_RESKEY_backup_suffix}" "$OCF_RESKEY_link"
+ fi
+ return $OCF_SUCCESS
+ else
+ ocf_exit_reason "Removing $OCF_RESKEY_link failed."
+ return $OCF_ERR_GENERIC
+ fi
+ else
+ return $OCF_SUCCESS
+ fi
+}
+
+symlink_validate_all() {
+ if [ "x${OCF_RESKEY_link}" = "x" ]; then
+ ocf_exit_reason "Mandatory parameter link is unset"
+ exit $OCF_ERR_CONFIGURED
+ fi
+ if [ "x${OCF_RESKEY_target}" = "x" ]; then
+ ocf_exit_reason "Mandatory parameter target is unset"
+ exit $OCF_ERR_CONFIGURED
+ fi
+
+ # Having a non-existant target is technically not an error, as
+ # symlinks are allowed to point to non-existant paths. But it
+ # still doesn't hurt to warn people if the target does not exist
+ # (but only during non-probes).
+ if [ ! -e "${OCF_RESKEY_target}" ]; then
+ ocf_log warn "${OCF_RESKEY_target} does not exist!"
+ fi
+}
+
+symlink_usage() {
+ cat <<EOF
+usage: $0 {start|stop|monitor|validate-all|meta-data}
+Expects to have a fully populated OCF RA-compliant environment set.
+EOF
+}
+
+if [ $# -ne 1 ]; then
+ symlink_usage
+ exit $OCF_ERR_ARGS
+fi
+
+case $__OCF_ACTION in
+meta-data)
+ meta_data
+ exit $OCF_SUCCESS
+ ;;
+usage)
+ symlink_usage
+ exit $OCF_SUCCESS
+esac
+
+# Everything except usage and meta-data must pass the validate test
+symlink_validate_all || exit
+
+case $__OCF_ACTION in
+start)
+ symlink_start
+ ;;
+stop)
+ symlink_stop
+ ;;
+status|monitor)
+ symlink_monitor
+ ;;
+validate-all)
+ ;;
+*)
+ symlink_usage
+ exit $OCF_ERR_UNIMPLEMENTED
+esac
+# exit code is the exit code (return code) of the last command (shell function)