C H A P T E R  7

Managing Changes in the Cluster State

This chapter describes how to receive and react to notifications about changes in the cluster state, with examples on how to respond to these notifications by modifying the state of the cluster. For more information, see the following topics:


Setting a Timeout Value for Calls to the nhcmmd Daemon

The timeout parameter is used globally by the CMM API to signify the maximum amount of time a call can block. A different timeout can be set for each client.

Using the cmm_connect function, you can:



Note - The cmm_connect function is called implicitly by the first call to the CMM API. You do not need to call the cmm_connect function to create a connection between an application and the nhcmmd daemon on a node. If you do not set the timeout, it remains at the default value of five seconds.



The new value of the timeout is not used by the call with which you set it.

The cmm_connect function can be called from any node, even a node that has been excluded from the cluster for administrative reasons. The cmm_connect function does not use information provided by the CMM API. For further information, see the cmm_connect(3CMM) man page.

The cmm_disconnect function closes the connection between the current calling process and the nhcmmd daemon. For more information about this, see the nhcmmd(1M) man page, or for the Linux OS, refer to the nhcmmd(8) man page and nhfs.conf(4) man pages. This frees the resources allocated to the client connection. If notifications were registered, they are no longer sent. For information about notifications, see Chapter 6.

The cmm_connect and cmm_disconnect functions cannot be called within a callback function.

The following example demonstrates how to use the cmm_connect function to set a timeout:


EXAMPLE 7-1   connect.c
#include <stdio.h>
#include <cmm/cmm.h>
 
#include "common.h"
 
 
int main(void)
{
    cmm_error_t  result;
    struct timespec time_out = { 1 /*seconds*/,
                                 500000000 /* nanoseconds */};
 
    result
    if (result != CMM_OK) {
        printf("Couldn’t set the timeout: %s\n",
            cmm_strerror(result));
        return 1;
    }
 
    /*
    /* Your code here
     */
    return 0;
}


Reloading the Cluster Node Table

The cmm_config_reload function can be called from the master node to make the nhcmmd daemon reload the cluster node table. Use this function when a node is added to or removed from the cluster node table.

The only permitted operations here are addition and removal of a node. For more information about adding and removing a node, see the Netra High Availability Suite 3.0 1/08 Foundation Services Cluster Administration Guide.

You cannot use the cluster node table to edit a node's attributes. Use the CMM API to do this. For example, use the cmm_member_setqualif(3CMM) function.

For more information, see the cmm_config_reload(3CMM), cluster_nodes_table(4), and nhcmmd(1M), or for the Linux OS, the nhcmmd(8), man pages.



caution icon

Caution - If you want to add a node make sure it is powered on before you reload the cluster node table. If you want to remove a node make sure it is powered off before you reload the cluster node table. This ensures that you cannot remove the master node from the table.




Receiving and Handling Change Notifications



Note - NMA is not available for use on the Linux platform, and is supported for use only with the Solaris OS.



You can use the CMM API to register and unregister for notifications that indicate a change in the cluster. You can also configure your applications to filter, receive, and dispatch these notifications.

This information applies to the CMM API only and is separate from the process of registering for notifications sent by the Node Management Agent (NMA).

For more information, see “Registering to Receive Notifications” in the Netra High Availability Suite 3.0 1/08 Foundation Services NMA Programming Guide.

You can manage the handling of notifications in general by using the following functions:

This sections that follow contain these topics:

Registering to Receive Notifications

To receive notifications, the applications or services can use the cmm_cmc_register function to register a callback with the nhcmmd daemon. When a membership change occurs in the cluster, the nhcmmd daemon notifies the application or service through the callback function by sending a notification. Applications or services receive notifications by polling, using a function such as the poll function. For more information, see the poll(2) man page.

To change a registration, an application or service must first cancel the existing registration by using the cmm_cmc_unregister function, and then register a new notification by using the cmm_cmc_register function.

For an example of how to use these functions, see EXAMPLE 7-2. For further information, see the cmm_cmc_register(3CMM) and cmm_cmc_unregister(3CMM) man pages.

Filtering Notifications

By default, when an application registers to receive notifications, the application receives a notification for every change in the cluster state. These notifications can be filtered by using the cmm_cmc_filter function.

For each notification present in the filter, as selected by using the cmm_cmc_filter function, the registered callback is invoked. The defined filter is applied for further calls to the cmm_notify_dispatch function.

For an example of how to use these functions, see EXAMPLE 7-2. For further information about how to use the cmm_cmc_filter function, see the cmm_cmc_filter(3CMM) man page.

Receiving and Dispatching Notifications

Applications or services that are registered to receive notifications can use the cmm_notify_getfd function. This function returns the file descriptor through which the notifications are delivered.

An application uses a polling function, such as poll, to monitor the file descriptors returned by cmm_notify_getfd. When the polling function indicates activity on this file descriptor, cmm_notify_dispatch must be called. For each pending notification, before invoking the callback, the CMM API checks that this notification is present in the filter (as selected with cmm_cmc_filter).

The callback is invoked with the notification and the client_data argument passed to the cmm_cmc_register function.

For an example of how to use these functions, see EXAMPLE 7-2. For further information see the cmm_cmc_register(3CMM), cmm_notify_getfd(3CMM), cmm_notify_dispatch(3CMM), and poll(2) man pages.

Retrieving Change Notifications

The following example demonstrates how to use the functions that enable you to filter, receive and dispatch notifications:


EXAMPLE 7-2   notif.c  
#include <stdio.h>
#include <poll.h>
#include <cmm/cmm.h>
 
#include "common.h"
 
static void notif_callback(const cmm_cmc_notification_t *notif,
                           void *data)
{
    cmm_member_t member ;
 
        switch (notif->cmchange) {
        case CMM_VICEMASTER_ELECTED:
            printf("Node %u elected vicemaster\n", notif->nodeid);
            if (cmm_vicemaster_getinfo(&member) == CMM_OK)
                print_member(&member) ;
            break ;
        case CMM_VICEMASTER_DEMOTED:
            printf("vicemaster %u demoted\n", notif->nodeid);
            break ;
        default::
            printf("Unexpected notification received\n",
            break ;
        }
}
 
int main(void)
{
    cmm_error_t     result;
    cmm_cmchanges_t wanted_notifs[2] = { CMM_VICEMASTER_ELECTED, 
                                            CMM_VICEMASTER_DEMOTED } ;
    struct pollfd   notif_poll;
    int             poll_res; 
 
    result = cmm_cmc_filter(CMM_CM_NOTIFY_SET, wanted_notifs, 2);
    if (result != CMM_OK) {
        printf("Couldn’t set notification filter: %s\n",
                cmm_strerror(result)) ;
        return 1;
    }
 
    result = cmm_notify_getfd(&notif_poll.fd);
    if (result != CMM_OK) {
        printf("Couldn’t get notification fd: %s\n",
                cmm_strerror(result));
        return 1;
    }
 
    notif_poll.events = POLLIN;
    notif_poll.revents = 0;
 
    fprintf ("Waiting for notifications\n");
 
    while (notif_poll.revents & POLLHUP) == 0) {
 
        poll_res = poll(&notif_poll, 1, -1);
        if (poll_res == 1 && (notif_poll.revents & POLLHUP) == 0) {
            result = cmm_notify_dispatch();
            if (result != CMM_OK) {
                printf("Failed dipatch: %s\n",
                       cmm_strerror(result));
                /* Force leaving the loop */
                notif_poll.revents = POLLHUP
            }
        }
    }
    (void) cmm_cmc_unregister();
    }
    return 0;
}


Responding to Cluster Notifications by Modifying the Cluster

You can use the CMM API to respond to notifications received from the nhcmmd daemon that indicate a change in the cluster. In response to these notifications, it might be necessary to remove or disqualify a node or to trigger a switchover or a failover.

This sections that follow contain these topics:

Removing or Excluding a Node

A node can be removed from the cluster by using the cmm_membership_remove function. The cmm_membership_remove function temporarily takes the current node out of the cluster by giving it the CMM_OUT_OF_CLUSTER role and all other peer nodes learn that it is not an active peer node.

A node with this role is not actually excluded from the cluster. It is still configured to be in the cluster. For an explanation of this role, see Membership Roles.

If you want to exclude a node completely from the cluster, first use the cmm_membership_remove function to remove the node from the cluster. Then remove the entry for this node from the cluster node table. It is better to remove the node completely from the cluster node table instead of attributing the node with an excluded value (X) in the cluster_nodes_table file. For more information, see the cluster_nodes_table(4) man page.

The nhcmmd issues notifications of the node's exclusion. For more information, see Triggering a Failover by Using the cmm_membership_remove Function.

Removing the Master Node

Removing the master node must be done in two stages so as to avoid triggering a failover. First, the node that is master should be released from the role of master by using the cmm_mastership_release function. This triggers a switchover. Only then should the node be removed from the cluster. The node is removed from the cluster by calling the cmm_membership_remove function from the node. This gives the node the CMM_OUT_OF_CLUSTER role, effectively taking the node out of the cluster. For more information about how to trigger a switchover, see Triggering a Switchover. For an explanation of the notifications sent when you trigger a switchover, see Switchover Notifications.

If the cmm_membership_remove function is called directly from the master node, without first triggering a switchover to a qualified vice-master node, then a failover is triggered.



caution icon

Caution - Triggering a failover should be done for test purposes only.



For more information about how to trigger a failover, see Triggering a Failover.

For an explanation of the notifications sent when you remove the master role with the cmm_membership_remove function, see TABLE 6-15. For an explanation of the notifications sent when you trigger a failover, see Failover Notifications.

Removing the Vice-Master Node

When the cmm_membership_remove function is called by a system service on the vice-master node, the function removes the vice-master node from the cluster. If the vice-master is removed from the cluster, the cluster no longer has 2N redundancy.

You can remove the vice-master node for maintenance purposes. If you want to perform maintenance on both master-eligible nodes, remove the vice-master and carry out the maintenance. Then trigger a switchover, remove the new vice-master and perform the maintenance tasks on this node. For more information, see the Netra High Availability Suite 3.0 1/08 Foundation Services Cluster Administration Guide.

For an explanation of the notifications sent when you remove the vice-master node with the cmm_membership_remove function, see TABLE 6-9.

Removing Diskless and Dataless Nodes

If the cmm_membership_remove function is called by a system service on a diskless node, the function removes the diskless node from the cluster. This action has no effect on the role of other nodes in the cluster.

Setting the Qualification of a Node

The cmm_member_setqualif function sets the qualification of a node. Qualification level is only relevant for master-eligible nodes. This function can only be called from the master node. The nodeid and the qualification level must be provided as input parameters to this function. The nodeid of the current node can be retrieved by using the cmm_node_getid function.

The following example demonstrates how to use the cmm_member_setqualif function to disqualify a node with the nodeid 12.


EXAMPLE 7-3   Disqualifying a Node
new_qualif = (qualify ? CMM_QUALIFIED_MEMBER : 
              CMM_DISQUALIFIED_MEMBER);
if (cmm_member_setqualif (12, CMM_DISQUALIFIED_MEMBER) != CMM_OK) 
    /* handle the error  */;

Triggering a Switchover

A switchover is usually triggered by the system administrator for maintenance of a node. There are two ways to trigger a switchover:

For information about the nhcmmstat tool, see the nhcmmstat(1M) man page.

Triggering a Switchover Using cmm_mastership_release

The cmm_mastership_release function enables a calling process to trigger a switchover. This function must be called from the master node. If the vice-master node is qualified to be master when the cmm_mastership_release function is called, it becomes the master node. If there is no node qualified to become master when the cmm_mastership_release function is called, the function does not release the mastership from the current master and the function fails.

After the cmm_mastership_release function is called, the calling node remains master until the vice-master node has taken the master role. When this happens, the nhcmmd daemon issues a notification of the switchover. For information about notifications during a switchover, see Switchover Notifications. For more information about the nhcmmd daemon and notifications, see Introduction to Change Notifications.

The cmm_mastership_release call is synchronous, that is, it only returns when the switchover has been completed or has failed, or when a timeout occurs.

EXAMPLE 7-4 demonstrates how to use the cmm_mastership_release function to trigger a switchover:


EXAMPLE 7-4   switchover.c  
#include <stdio.h>
#include <cmm/cmm.h>
 
int main(void)
{
    cmm_error_t  result;
 
    result = cmm_mastership_release();
    switch (result) {
    case CMM_OK:
        printf("Switch-over requested\n");
        break;
    case CMM_EPERM:
        printf("Not running on the master node\n";
        break;
    case CMM_ECANCELED:
        printf("No vicemaster in the cluster\n";
        break;
    default:
        printf("Failed to release the mastership: %s\n",
                cmm_strerror(result));
        break;
    }
 
    return (result == CMM_OK ? 0 : 1);
}

Triggering a Failover

A failover can be triggered by removing the master node by using the cmm_membership_release function, or by disqualifying the master node by using the cmm_member_setqualif function.

The sections that follow contain these topics:



caution icon

Caution - Trigger a failover only for test purposes.



Triggering a Failover by Using the cmm_membership_remove Function

The cmm_membership_remove function removes from the cluster the node from which the cmm_membership_remove function is called. If you call this function from the master when the vice-master is synchronized, you trigger a failover. When the cmm_membership_remove function is called from the master node, the master node stops sending heartbeat information to other nodes in the cluster, which triggers a failover. The notifications sent for this scenario are shown in Failover Due to the Removal or Failure of the Master Node.

If there is no vice-master, or the master-eligible nodes are desynchronized, the CMM_ECANCELLED error is returned. If a node is not configured to be in any cluster, any subsequent call to the CMM API returns the CMM_ENOCLUSTER error. For further information about these and other return values, see Return Values of the CMM API.

The only way for a removed node to rejoin the cluster is to restart the nhprobed daemon and the CMM service.

For further information, see the cmm_membership_remove(3CMM) man page and the nhprobed(1M), or for the Linux OS, refer to the nhprobed(8), man page.

An example that demonstrates how to trigger a failover by using the cmm_membership_remove function is shown in EXAMPLE 7-5.


EXAMPLE 7-5   failover.c  
#include <stdio.h>
#include <cmm/cmm.h>
 
 
int main(void)
{
    cmm_error_t  result;
    cmm_nodeid_t curr_node;
    cmm_member_t master_info;
 
    result = cmm_node_getid(&curr_node);
    if (result != CMM_OK) {
        printf("Couldn’t get node id: %s\n", cmm_strerror(result));
        return 1;
    }
 
    result = cmm_master_getinfo(&master_info);
    if (result != CMM_OK) {
        printf("Couldn't get node id: %s\n", cmm_strerror(res));
        return 1;
    }
 
    if (master_info.nodeid != curr_node) {
        printf("Not running on the master node\n");
        return 1;
    }
 
    result = cmm_membership_remove(); 
    switch (result) {
    case CMM_OK:
        printf("Failover triggered and node removed from the
                cluster\n”);
        break;
    case CMM_OK:
        printf("Failover triggered and node removed from the
                cluster\n”);
        break;
    default:
        printf("Failed to release the membership: %s\n”),
                cmm_strerror(result));
        break;
    }
 
    return (result == CMM_OK ? 0 : 1);
}

Triggering a Failover by Using the cmm_member_setqualif Function

A failover can be triggered by calling the cmm_member_setqualif function on the master node. The notifications sent for this scenario are shown in TABLE 6-16.

When the master node fails, if the vice-master node cannot take over the master role, another master-eligible node must be qualified to become master.

The vice-master node cannot take over the master role if, for example, the vice-master node is not synchronized with the master node. If this is the case, and if no other node in the cluster is qualified to become the master, a master-eligible node must be qualified using the cmm_member_seizequalif function. For more information about the cmm_member_seizequalif function, see the cmm_member_seizequalif(3CMM) man page.

The cmm_member_seizequalif function is used by the cmm_member_setqualif command and the squalif command of the nhcmmstat tool.

Rejoining the Cluster

When a node has the CMM_OUT_OF_CLUSTER role, two of the possible reasons are:

If the node has the CMM_OUT_OF_CLUSTER role for one of these two reasons, then you can rejoin it to the cluster using a call to the function cmm_membership_include. If the node is already in the cluster, the function will succeed.

A successful return of this function does not mean that the node has joined the cluster. It means that the request is being taken into consideration and an attempt will be made to rejoin the node to the cluster. The node could fail to join the cluster if some of the required conditions are not met, such as if the node is excluded or disqualified.


EXAMPLE 7-6   join.c
#include <stdio.h>
#include <cmm/cmm.h>
 
 
int main(void)
{
     cmm_member_t member_info;
     cmm_error_t  result;
     cmm_nodeid_t current;
 
     result = cmm_node_getid(&current);
     if (result != CMM_OK) {
          printf("Failed to retrieve the current node’s id\n: %s",
               cmm_strerror(result));
          return 1;
     }
 
     result = cmm_potential_getinfo(current, &member_info);
     switch (result) {
     case CMM_OK:
          break;
     case CMM_ESRCH:
          printf("Current node is NOT configured in the cluster\n");
          break;
     default:
          printf("Couldn’t get member node information: %s\n",
               cmm_strerror(result));
          break;
     }
 
     if (!cmm_member_isoutofcluster(&member_info)) {
          printf("Node is already in the cluster\n");
     } else {
          result = cmm_membership_include();
          switch (result) {
          case CMM_OK:
               printf("Trying to join the cluster\n");
                    cmm_strerror(result));
               break;
          }
     }
 
     return (result == CMM_OK ? 0 : 1);
}