diff --git a/extra/resources/Makefile.am b/extra/resources/Makefile.am index a090a16fcb..a54d91906b 100644 --- a/extra/resources/Makefile.am +++ b/extra/resources/Makefile.am @@ -1,56 +1,57 @@ # Makefile.am for OCF RAs # # Author: Andrew Beekhof # Copyright (C) 2008 Andrew Beekhof # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # include $(top_srcdir)/Makefile.common EXTRA_DIST = $(ocf_SCRIPTS) isolationtechdir = @OCF_RA_DIR@/.isolation ocfdir = @OCF_RA_DIR@/pacemaker ocf_SCRIPTS = ClusterMon \ controld \ Dummy \ HealthCPU \ HealthSMART \ o2cb \ ping \ pingd \ Stateful \ SysInfo \ SystemHealth \ + attribute \ remote isolationtech_SCRIPTS = docker-wrapper if BUILD_XML_HELP man7_MANS = $(ocf_SCRIPTS:%=ocf_pacemaker_%.7) DBOOK_OPTS = --stringparam command.prefix ocf_pacemaker_ --stringparam variable.prefix OCF_RESKEY_ --param man.vol 7 ocf_pacemaker_%.xml: % $(AM_V_GEN)OCF_FUNCTIONS=/dev/null OCF_ROOT=$(OCF_ROOT_DIR) sh $(abs_builddir)/$< meta-data > $@ endif clean-generic: rm -f $(man7_MANS) $(ocf_SCRIPTS:%=%.xml) *~ diff --git a/extra/resources/attribute b/extra/resources/attribute new file mode 100644 index 0000000000..7444ec607e --- /dev/null +++ b/extra/resources/attribute @@ -0,0 +1,233 @@ +#!/bin/sh +# +# ocf:pacemaker:attribute resource agent +# +# Copyright (C) 2016 Andrew Beekhof +# +# This source code is licensed under GNU General Public License version 2 or +# later (GPLv2+) WITHOUT ANY WARRANTY. +# + +USAGE="Usage: $0 {start|stop|monitor|migrate_to|migrate_from|validate-all|meta-data} + +Expects to have a fully populated OCF RA-compliant environment set." + +# Load OCF helper functions +: ${OCF_FUNCTIONS=${OCF_ROOT}/resource.d/heartbeat/.ocf-shellfuncs} +. ${OCF_FUNCTIONS} +: ${__OCF_ACTION=$1} + +# Ensure certain variables are set and not empty +: ${HA_VARRUN:="/var/run"} +: ${OCF_RESKEY_CRM_meta_globally_unique:="false"} +: ${OCF_RESOURCE_INSTANCE:="undef"} + +DEFAULT_STATE_FILE="${HA_VARRUN%%/}/opa-${OCF_RESOURCE_INSTANCE}.state" +if [ ${OCF_RESKEY_CRM_meta_globally_unique} = "false" ]; then + # Strip off any trailing clone marker (note + is not portable in sed) + DEFAULT_STATE_FILE=$(echo "$DEFAULT_STATE_FILE" | sed s/:[0-9][0-9]*\.state/.state/) +fi + +DEFAULT_ATTR_NAME="opa-${OCF_RESOURCE_INSTANCE}" +DEFAULT_ACTIVE_VALUE="1" +DEFAULT_INACTIVE_VALUE="0" + +: ${OCF_RESKEY_state:="$DEFAULT_STATE_FILE"} +: ${OCF_RESKEY_name:="$DEFAULT_ATTR_NAME"} + +# Values may be empty string +if [ -z ${OCF_RESKEY_active_value+x} ]; then + OCF_RESKEY_active_value="$DEFAULT_ACTIVE_VALUE" +fi +if [ -z ${OCF_RESKEY_inactive_value+x} ]; then + OCF_RESKEY_inactive_value="$DEFAULT_INACTIVE_VALUE" +fi + +usage() { + USAGE_RC=$1 + cat < + + + 1.0 + Manages a node attribute + +This resource agent controls a node attribute for the node it's running on. +It sets the attribute one way when started, and another way when stopped, +according to the configuration parameters. + + + + + +Full path of a temporary file to store the resource state in + + State file + + + + + +Name of node attribute to manage + + Attribute name + + + + + +Value to use for node attribute when resource becomes active (empty string is +discouraged, because monitor cannot distinguish it from a query error) + + Attribute value when active + + + + + +Value to use for node attribute when resource becomes inactive + + Attribute value when inactive + + + + + + + + + + + + + + + +END + return $OCF_SUCCESS +} + +validate() { + if [ "$OCF_RESKEY_active_value" = "$OCF_RESKEY_inactive_value" ]; then + ocf_exit_reason "active value '%s' must be different from inactive value '%s'" \ + "$OCF_RESKEY_active_value" "$OCF_RESKEY_inactive_value" + return $OCF_ERR_CONFIGURED + fi + + VALIDATE_DIR=$(dirname "${OCF_RESKEY_state}") + if [ ! -d "$VALIDATE_DIR" ]; then + ocf_exit_reason "state file '$OCF_RESKEY_state' does not have a valid directory" + return $OCF_ERR_PERM + fi + if [ ! -w "$VALIDATE_DIR" -o ! -x "$VALIDATE_DIR" ]; then + ocf_exit_reason "insufficient privileges on directory of state file '$OCF_RESKEY_state'" + return $OCF_ERR_PERM + fi + + return $OCF_SUCCESS +} + +get_attribute() { + GET_LINE=$(attrd_updater -n "$OCF_RESKEY_name" -Q 2>/dev/null) + if [ $? -ne 0 ]; then + echo "" + else + echo "$GET_LINE" | sed -e "s/.* value=\"\(.*\)\"$/\1/" + fi +} + +set_attribute() { + attrd_updater -n "$OCF_RESKEY_name" -U "$1" 2>/dev/null + # TODO if above call is async, loop until get_attribute returns expected value +} + +check_attribute() { + CHECK_VALUE=$(get_attribute) + CHECK_REASON="" + if [ ! -f "$OCF_RESKEY_state" ]; then + if [ "$CHECK_VALUE" != "" -a "$CHECK_VALUE" != "$OCF_RESKEY_inactive_value" ]; then + CHECK_REASON="Node attribute $OCF_RESKEY_name='$CHECK_VALUE' differs from expected value '$OCF_RESKEY_inactive_value'" + return $OCF_ERR_GENERIC + fi + return $OCF_NOT_RUNNING + fi + if [ "$CHECK_VALUE" != "$OCF_RESKEY_active_value" ]; then + CHECK_REASON="Node attribute $OCF_RESKEY_name='$CHECK_VALUE' differs from expected value '$OCF_RESKEY_active_value'" + return $OCF_ERR_GENERIC + fi + return $OCF_SUCCESS +} + +monitor() { + check_attribute + MONITOR_RC=$? + if [ $MONITOR_RC -eq $OCF_ERR_GENERIC ]; then + ocf_exit_reason "$CHECK_REASON" + fi + return $MONITOR_RC +} + +start() { + check_attribute + if [ $? -eq $OCF_SUCCESS ]; then + return $OCF_SUCCESS + fi + + touch "${OCF_RESKEY_state}" 2>/dev/null + if [ $? -ne 0 ]; then + ocf_exit_reason "Unable to manage state file $OCF_RESKEY_state" + return $OCF_ERR_GENERIC + fi + + set_attribute "${OCF_RESKEY_active_value}" + if [ $? -ne 0 ]; then + rm -f "${OCF_RESKEY_state}" + ocf_exit_reason "Unable to set node attribute $OCF_RESKEY_name='$OCF_RESKEY_active_value'" + return $OCF_ERR_GENERIC + fi + + return $OCF_SUCCESS +} + +stop() { + check_attribute + if [ $? -eq $OCF_NOT_RUNNING ]; then + return $OCF_SUCCESS + fi + + rm -f ${OCF_RESKEY_state} + + set_attribute "${OCF_RESKEY_inactive_value}" + if [ $? -ne 0 ]; then + ocf_exit_reason "Unable to set node attribute $OCF_RESKEY_name='$OCF_RESKEY_inactive_value'" + return $OCF_ERR_GENERIC + fi + + return $OCF_SUCCESS +} + +case $__OCF_ACTION in +meta-data) meta_data ;; +start) start ;; +stop) stop ;; +monitor) monitor ;; +# We don't do anything special for live migration, but we support it so that +# other resources that live migrate can depend on this one. +migrate_to) stop ;; +migrate_from) start ;; +reload) start ;; +validate-all) validate ;; +usage|help) usage $OCF_SUCCESS ;; +*) usage $OCF_ERR_UNIMPLEMENTED ;; +esac + +exit $? + +# vim: expandtab:tabstop=4:softtabstop=4:shiftwidth=4:textwidth=80