PreviousNextIndex

Chapter 4: Sample Clinfo Client Program


This chapter lists a sample clinfo.rc script and the source code of a C program called from that script. This program reports the status of each service network interface on a given cluster node, and of the node itself.

Overview

The sample Clinfo client application program, cl_status, is shown here within the context of a typical customized clinfo.rc script. clinfo.rc is the HACMP for AIX 5L script run by Clinfo following cluster topology changes. The clinfo.rc script is listed first, followed by the cl_status program. The script and the program are commented to explain their usage.

Sample Customized clinfo.rc Script

#!/bin/ksh 
############################################################################## 
# Filename: /usr/sbin/cluster/etc/clinfo.rc 
# 
# Description: clinfo.rc is run by clinfo on clients following cluster 
#			topology changes. This particular example demonstrates 
#			user process management for a highly available database in a 
#			two-node primary/standby configuration. Most database 
#			client programs are state-dependent, and require  
			#restart following a node failure. This example provides  
#			user notification and application shutdown during  
#			appropriate topology changes. 
# 
############################################################################# 
############################################################################## 
# Grab Parameters Passed 
############################################################################## 
EVENT=$1				# action, one of {join, fail, swap} 
INTERFACE=$2				# target address label 
CLUSTERNAME="cluster1"				# cluster name 
NODENAME="victor"				# primary node name 
WATCHIF="svc_en0"				# interface to monitor 
############################################################################## 
#   Name:  _arp_flush 
#   This function flushes the entire arp cache. 
#   Arguments:  none 
#   Return Value:  none 
############################################################################## 
_arp_flush() 
{ 
	for IPADDR in $(/etc/arp -a |/bin/sed -e 's/^.*(.*).*$//' -e /incomplete/d) 
    do 
        /etc/arp -d $IPADDR 
    done 
} 
############################################################################## 
# 
#   Name:  _kill_user_procs 
# 
#   This function kills user processes associated with the specified  
#   interface. 
# 
#   Arguments:  interface 
#   Return Value:  none 
############################################################################## 
_kill_user_procs() 
{ 
    print _kill_user_procs 
	# place commands appropriate to the database in use here 
} 
# The main if statement disregards status changes for all interfaces except 
# WATCHIF, which in this example is svc_en0. 
if [[ "$INTERFACE" = "WATCHIF" ]]   
then 
  case "$EVENT" in 
    "join") # interface label $INTERFACE has joined the cluster 
            # perform necessary activity here, such as user notification, restoration 
of user access,  
		# and arp cache flushing. 
            	exit 0 
            	;; 
          
    "fail")# Use api calls in cl_status to determine if interface  
		# failure is a result of node failure.  
            
	CLSTAT_MSG=$(cl_status $CLUSTERNAME $NODENAME) 
            CLSTAT_RETURN=$?  # return code from cl_status 
                         
	case "$CLSTAT_RETURN" in 
              0) 			# Node UP 
	   		# Notify users of application availability 
			wall "Primary database is now available."                 
                 			# flush arp cache 
			_arp_flush 
                 		;;  
              1) 			# Node DOWN 
			# Notify users of topology change and restart requirement 
			touch /etc/nologin    # prevent new logins 
		 	wall "Primary database node failure. Please login again  
				 2 minutes" 
	         	sleep 10 
			# Kill all processes attached to WATCHIF interface 
			_kill_user_procs $WATCHIF 
			# flush arp cache 
                 		_	arp_flush 
                 			rm -f /etc/nologin     # enable logins 
                 			;; 
                                 
              *) 	# Indeterminate node state 
                 	# flush arp cache 
			_arp_flush 
                 		exit 1 
                 		;; 
                             
            esac  # case $CLSTAT_RETURN 
            ;; 
    "swap")# interface has been swapped 
	 	# flush arp cache. 
	   	_arp_flush 
		;; 
  esac  		# case $EVENT 
else 
    # event handling for other interfaces here, if desired 
    /bin/true 
fi 

cl_status.c

/*   
 * Program:  cl_status.c 
 * 
 * Purpose:  For systems running the clinfo daemon as a client, cl_status 
 *           will determine if the node for the network interface passed  
 *           to it is active in the cluster. 
 * 
 * Usage:    [path/]cl_status clustername nodename  
 * 
 * Returns:  0 = Node up 
 *           1 = Node down 
 *           2 = ERROR - Status Unavailable 
 * 
 */ 
#include <stdio.h> 
#include <sys/types.h> 
#include <sys/socket.h> 
#include <netinet/in.h> 
#include <cluster/clinfo.h> 
#include <strings.h> 
void usage() 
{ 
  printf("usage: cl_status clustername nodename"); 
  printf("Returns status of node in HACMP cluster."); 
} 
int main(int argc, char *argv[]) 
{ 
  int clusterid, node_status; 
  char *clustername, *nodename; 
   
  if(argc < 3) 
  { 
    /* incorrect syntax to cl_status call */ 
    usage(); 
    exit(2);   
  }  
  clustername = strdup(argv[1]); 
  if (strlen(clustername) > CL_MAXNAMELEN) 
  { 
    printf("error: clustername exceeds maximum length of %i characters",  
	   CL_MAXNAMELEN); 
    exit(2); 
  }  
  nodename = strdup(argv[2]); 
  if (strlen(nodename) > CL_MAXNAMELEN) 
  { 
    printf("error: nodename exceeds maximum length of %i characters",  
	   CL_MAXNAMELEN); 
    exit(2); 
  } 
  /* convert clustername (string) to clusterid (non-negative integer) */ 
  clusterid = cl_getclusterid(clustername); 
  switch(clusterid) 
  { 
    case CLE_SYSERR: perror("system error");  
			exit(5); 
			break; 
     
    case CLE_NOCLINFO: cl_perror(clusterid, "error"); 
          	 		exit(5); 
           	 		break;  
     
    case CLE_BADARGS: 
    case CLE_IVCLUSTERNAME: /* typically a usage error */ 
            	 		cl_perror(clusterid, "error"); 
             			usage(); 
                 			exit(2); 
         
    default: 		/* valid clusterid returned */ 
               ; 
  } 
  node_status = cl_isnodeavail(clusterid, nodename); 
  switch (node_status) 
  { 
    case CLE_OK: /* Node up */ 
                 		printf(“node %s up”, nodename); 
                 		exit(0);   
                 		break; 
    case CLE_IVNODENAME:  /* “Illegal node name” */ 
		 	cl_perror(node_status, "node unavailable"); 
		 	exit(2); 
		 	break; 
		  
    default:  
		 	cl_perror(node_status, "node unavailable"); 
		 	exit(1); 
  } 
} 


PreviousNextIndex