Appendix B. Using the Script Library

The purpose of the script library (scriptlib) is to simplify the FailSafe application interface so that users can use scripts and need not be aware of input and output file format.

The /var/cluster/ha/common_scripts/scriptlib file contains the library of environment variables (beginning with uppercase HA_) and functions (beginning with lowercase ha_) available for use in your action scripts.


Note: Do not change the contents of the scriptlib file.

This chapter describes functions that perform the following tasks, using samples from the scriptlib file:

File Formats

There are three file formats:

  • Input file, which contains the list of resources that must be acted on by the executable; each resource must be specified on a separate line in the file.

  • (Optional) Output file, in which the executable writes the return the status of each resource on a separate line, using the following format:

    resource_name  resource_status

    There are corresponding lines for each line in the input file. The resource_name and resource_status fields are separated by whitespace. The resource status may be one of the following:

    • HA_SUCCESS

    • HA_RUNNING

    • HA_NOT_RUNNING

    • HA_INVAL_ARGS

    • HA_CMD_FAILED

    • HA_NOTSUPPORTED

    • HA_NOCFGINFO (no configuration information)

    If information about a resource is not present in the output file, SRMD assumes that the action on the resource has timed out. A nonzero value for the resource_status field is considered an error.

    If the executable requires more information to perform the action on the resource, the information must be stored in the cluster database (CDB) in the local machine. The executables can use cluster database commands to extract information about the resource.

  • Input parameter file, which contains the cluster name in the following format:

    ClusterName clustername

Set Global Definitions

The ha_set_global_defs() function sets the global definitions for the environment variables shown in the following subsections.

The HA_INFILE and HA_OUTFILE variables set the input and output files for a script. These variables do not have global definitions, and are not set by the ha_set_global_defs() function.

Global Variable

HA_HOSTNAME

The output of the uname command with the -n option, which is the host name or node name. The node name is the name by which the system is known to communications networks.

Default: `uname -n`

Command Location Variables

HA_CMDSPATH

Path to user commands.

Default: /usr/cluster/bin

HA_PRIVCMDSPATH

Path to privileged commands (those that can only be run by root).

Default: /usr/sysadm/privbin

HA_LOGCMD

Command used to log information.

Default: ha_cilog

HA_RESOURCEQUERYCMD

Resource query command. This is an internal command that is not meant for direct use in scripts; use the ha_get_info() function of scriptlib instead.

Default: resourceQuery

HA_SCRIPTTMPDIR

Location of the script temporary directory.

Default: /tmp

Database Location Variables

HA_CDB

Location of the cluster database.

Default: /var/cluster/cdb/cdb.db

Script Log Level Variables

HA_NORMLVL

Normal level of script logs.

Default: 0

HA_DBGLVL

Debug level of script logs.

Default: 10

Script Log Variables

HA_SCRIPTGROUP

Log for the script group.

Default: script

HA_SCRIPTSUBSYS

Log for the script subsystem.

Default: script

Script Logging Command Variables

HA_LOGQUERY_OUTPUT

Determine the current logging level for scripts.

Default:

`${HA_PRIVCMDSPATH}/loggroupQuery _NUM_LOG_GROUPS=1 \ _LOG_GROUP_0=ha_script`

HA_DBGLOG

Command used to log debug messages from the scripts.

Default: ha_dbglog

HA_CURRENT_LOGLEVEL

Display the current log level. The default will be 0 (no script logging) if the loggroupQuery command fails or does not find configuration information.

Default: `echo ${HA_LOGQUERY_OUTPUT} | /usr/bin/awk '{print $2}'`

HA_LOG

Command used to log the scripts.

Default: ha_log

Script Error Value Variables

HA_SUCCESS

Successful execution of the script. This variable is used by the start, stop, restart, and monitor scripts.

Default: 0

HA_NOT_RUNNING

The script is not running. This variable is used by exclusive scripts.

Default: 0

HA_INVAL_ARGS

An invalid argument was entered. This is used by all scripts.

Default: 1

HA_CMD_FAILED

A command called by the script has failed. This variable is used by the start, stop, restart , and monitor, scripts.

Default: 2

HA_RUNNING

The script is running. This variable is used by exclusive scripts.

Default: 2

HA_NOTSUPPORTED

The specific action is not supported for this resource type. This is used by all scripts.

Default: 3

HA_NOCFGINFO

No configuration information was found. This is used by all scripts.

Default: 4

Check Arguments

An action script can have an input file ($1 HA_INFILE), an output file ($2HA_OUTFILE), and a parameter file ($3 HA_PARAMFILE). The parameter file is optional.

The ha_check_args() function checks the arguments specified for a script and sets the $HA_INFILE and $HA_OUTFILE variables accordingly.

If a parameter file exists, the ha_check_args() function reads the list of parameters from the file and sets the $HA_CLUSTERNAME variable.

In the following, long lines use the continuation character ( \) for readability.

ha_check_args() 
{
    ${HA_DBGLOG} "$HA_SCRIPTNAME called with $1, $2 and $3"

    if  ! [ $# -eq 2 -o $# -eq 3 ]; then
        ${HA_LOG} "Incorrect number of arguments"
        return 1;
    fi

    if [ ! -r $1 ]; then
        ${HA_LOG} "file $1 is not readable or does not exist"
        return 1;
    fi

    if [ ! -s $1 ]; then
        ${HA_LOG} "file $1 is empty"
        return 1;
    fi
    if [ $# -eq 3 ]; then
        HA_PARAMFILE=$3

        if [ ! -r $3 ]; then
            ${HA_LOG} "file $3 is not readable or does not exist"
            return 1;
        fi

        HA_CLUSTERNAME=`/usr/bin/awk '{ if ( $1 == "ClusterName" ) \ 
        print $2 }' ${HA_PARAMFILE}`
    fi

    HA_INFILE=$1
    HA_OUTFILE=$2

    return 0;
}

Read an Input File

The ha_read_infile() function reads the $HA_INFILE input file into the $HA_RES_NAMES variable, which specifies the list of resource names.

ha_read_infile()
{
    HA_RES_NAMES="";
 
    for HA_RESOURCE in `cat ${HA_INFILE}`
    do
        HA_TMP="${HA_RES_NAMES} ${HA_RESOURCE}";
        HA_RES_NAMES=${HA_TMP};
    done
}

Execute a Command

The ha_execute_cmd() function executes the command specified by $HA_CMD, which is set in the action script. $1 is the string to be logged. The function returns 1 on error and 0 on success. On errors, the standard output and standard error of the command is redirected to the log file.

ha_execute_cmd()
{
    OUTFILE=${HA_SCRIPTTMPDIR}/script.$$
 
    ${HA_DBGLOG} $1
 
    eval ${HA_CMD} > ${OUTFILE} 2>&1;
 
    ha_exit_code=$?;
 
    if [ $ha_exit_code -ne 0 ]; then
        ${HA_DBGLOG} `cat ${HA_SCRIPTTMPDIR}/script.$$`
    fi
 
    ${HA_DBGLOG} "${HA_CMD} exited with status $ha_exit_code";
 
    /sbin/rm ${OUTFILE}
 
    return $ha_exit_code;
}

The ha_execute_cmd_ret() function is similar to ha_execute_cmd, except that it places the command output in the location specified by $HA_CMD_OUTPUT.

ha_execute_cmd_ret()
{
    ${HA_DBGLOG} $1
 
    # REVISIT: Is it possible to redirect the output to a log
    HA_CMD_OUTPUT=`${HA_CMD}`;
 
    ha_exit_code=$?;
 
${HA_DBGLOG} "${HA_CMD} exited with status $ha_exit_code";
 
    return $ha_exit_code;
}

Write Status for a Resource

The ha_write_status_for_resource() function writes the status for a resource to the $HA_OUTFILE output file. $1 is the resource name, and $2 is the resource status.

ha_write_status_for_resource()
{
    echo $1 $2 >> $HA_OUTFILE;
}

Similarly, the ha_write_status_for_all_resources() function writes the status for all resources. $HA_RES_NAMES is the list of resource names.

ha_write_status_for_all_resources()
{
    for HA_RES in $HA_RES_NAMES
    do
        echo $HA_RES $1 >> $HA_OUTFILE;
    done
}

Get the Value for a Field

The ha_get_field() function obtains the field value from a string, where $1 is the string and $2 is the field name. The string format is as follows:

ha_get_field()
{
    HA_STR=$1
    HA_FIELD_NAME=$2
    ha_found=0;
    ha_field=1;

    for ha_i in $HA_STR
    do
        if [ $ha_field -eq 1 ]; then
            ha_field=0;
            if [ $ha_i = $HA_FIELD_NAME ]; then
                ha_found=1;
            fi
        else
            ha_field=1;
            if [ $ha_found -eq 1 ]; then
                HA_FIELD_VALUE=$ha_i
                return 0;
            fi
        fi
    done

    return 1;
}

Get the Value for Multiple Fields

The ha_get_multi_fields() function obtains the field values from a string, where $1 is the string and $2 is the field name. The string format is a series of name-value field pairs, where a name field is followed by the value of the name, separated by whitespace.

This function is typically used to extract dependency information. There may be multiple fields with the same name, so the string returned in HA_FIELD_VALUE may contain multiple values separated by white space. This appears as follows:

ha_get_multi_fields()
{
    HA_STR=$1
    HA_FIELD_NAME=$2
    ha_found=0;
    ha_field=1;

    for ha_i in $HA_STR
    do
        if [ $ha_field -eq 1 ]; then
            ha_field=0;
            if [ $ha_i = $HA_FIELD_NAME ]; then
                ha_found=1;
            fi
        else
            ha_field=1;
            if [ $ha_found -eq 1 ]; then
                if [ -z "$HA_FIELD_VALUE" ]; then
                    HA_FIELD_VALUE=$ha_i;
                else
                    HA_FIELD_VALUE="$HA_FIELD_VALUE $ha_i";
                fi;
                ha_found=0;
            fi
        fi
    done

    if [ -z "$HA_FIELD_VALUE" ]; then
        return 1;
    else
        return 0;
    fi
}

Get Resource Information

The ha_get_info() and ha_get_info_debug()functions read resource information. $1 is the resource type, $2 is the resource name, and $3 is an optional parameter of any value that specifies a request for resource dependency information. Resource information is stored in the HA_STRING variable. If the resourceQuery command fails, the HA_STRING is set to an invalid string, and future calls to ha_get_info() or ha_get_info_debug() return errors.

You can use ha_get_info_debug() while developing scripts.

ha_get_info()
{
    if [ -f /var/cluster/ha/resourceQuery.debug ]; then
        ha_get_info_debug $1 $2 $3
        return;
    fi

    if [ -n "$3" ]; then
        ha_doall="_ALL=true"
    else
        ha_doall=""
    fi

    # Retry resourceQuery command $HA_RETRY_CMD_MAX times if $HA_RETRY_CMD_ERR
    # is returned.
    ha_retry_count=1

    while [ $ha_retry_count -le $HA_RETRY_CMD_MAX ];
    do
        if [ -n "${HA_CLUSTERNAME}" ]; then
            HA_STRING=`${HA_PRIVCMDSPATH}/${HA_RESOURCEQUERYCMD} \
                        _CDB_DB=$HA_CDB _RESOURCE=$2 _RESOURCE_TYPE=$1  \
                        $ha_doall _NO_LOGGING=true _CLUSTER=${HA_CLUSTERNAME}`
        else
            HA_STRING=`${HA_PRIVCMDSPATH}/${HA_RESOURCEQUERYCMD} \
                        _CDB_DB=$HA_CDB _RESOURCE=$2 _RESOURCE_TYPE=$1  \
                        $ha_doall _NO_LOGGING=true`
        fi

        ha_exit_code=$?

        if [ $ha_exit_code -ne 0 ]; then
            ${HA_LOG} "${HA_RESOURCEQUERYCMD}: resource name $2 resource type $1"
            ${HA_LOG} "Failed with error: ${HA_STRING}";
        fi

        if [ $ha_exit_code -ne $HA_RETRY_CMD_ERR ]; then
            break;
        fi

        ha_retry_count=`expr $ha_retry_count + 1`

    done

    if [ -n "$ha_doall" ]; then
        echo $HA_STRING  \
                | grep "No resource dependencies" > /dev/null 2>&1
        if [ $? -eq 0 ]; then
            HA_STRING=
        else
            HA_STRING=`echo $HA_STRING  | /bin/sed -e "s/^.*Resource dependencies //"`
        fi
    fi

    return ${ha_exit_code};
}

The ha_get_info is a faster version of ha_get_info_debug().

ha_get_info_debug()
{
    if [ -n "$3" ]; then
        ha_doall="_ALL=true"
    else
        ha_doall=""
    fi

    if [ -n "${HA_CLUSTERNAME}" ]; then
        HA_STRING=`${HA_PRIVCMDSPATH}/${HA_RESOURCEQUERYCMD} \
                    _CDB_DB=$HA_CDB _RESOURCE=$2 _RESOURCE_TYPE=$1      \
                    $ha_doall _CLUSTER=${HA_CLUSTERNAME}`
    else
        HA_STRING=`${HA_PRIVCMDSPATH}/${HA_RESOURCEQUERYCMD} \
                    _CDB_DB=$HA_CDB _RESOURCE=$2 _RESOURCE_TYPE=$1 $ha_doall`
    fi
    ha_exit_code=$?

    if [ $? -ne 0 ]; then
        ${HA_LOG} "${HA_RESOURCEQUERYCMD}: resource name $2 resource type $1"
        ${HA_LOG} "Failed with error: ${HA_STRING}";
    fi

    if [ -n "$ha_doall" ]; then
        echo $HA_STRING  \
                | grep "No resource dependencies" > /dev/null 2>&1
        if [ $? -eq 0 ]; then
            HA_STRING=
        else
            HA_STRING=`echo $HA_STRING  | /bin/sed -e "s/^.*Resource dependencies //"`
        fi
    fi

    return ${ha_exit_code};
}

Print Exclusivity Check Messages

The ha_print_exclusive_status() function prints exclusivity check messages to the log file. $1 is the resource name and $2 is the exit status.

ha_print_exclusive_status()
{
    if [ $? -eq $HA_NOT_RUNNING ]; then
        ${HA_LOG} "resource $1 exclusive status: NOT RUNNING"
    else
        ${HA_LOG} "resource $1 exclusive status: RUNNING"
    fi
}

The ha_print_exclusive_status_all_resources() function is similar, but it prints exclusivity check messages for all resources. $HA_RES_NAMES is the list of resource names.

ha_print_exclusive_status_all_resources()
{
    for HA_RES in $HA_RES_NAMES
    do
        ha_print_exclusive_status ${HA_RES} $1
    done
}