| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364 |
- /*
- * Copyright (c) 2007 Diginext/C-S
- *
- * All rights reserved.
- *
- * Author: Lionel Tricon (lionel.tricon@diginext.fr)
- *
- * This software licensed under BSD license, the text of which follows:
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * - Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * - Neither the name of the MontaVista Software, Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from this
- * software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
- * THE POSSIBILITY OF SUCH DAMAGE.
- */
- #include "serv_amf.h"
- // Global variables
- SaVersionT VG_amf_version = { 'B', 1, 1 }; // AMF version supported
- SaAmfHandleT VG_amf_handle; // AMF handle
- SaNameT VG_compNameGlobal; // name of the component
- // Ip takeover
- char *VG_interface=NULL; // ip takeover interface
- char *VG_ip_addr=NULL; // floating ip address
- SaAmfHAStateT VG_AMF_old_haState; // We store the old state to ease transition detection
- SaAmfHAStateT VG_AMF_haState; // Current ha state
- SaAmfHAStateT *VG_AMF_remote_haState; // Remote ha state (from the amf_comp_init function)
- // Types for State Management
- char *TG_ha_state[128] = {
- "null",
- "SA_AMF_HA_ACTIVE",
- "SA_AMF_HA_STANDBY",
- "SA_AMF_HA_QUIESCED",
- "SA_AMF_HA_QUIESCING"
- };
- // The key of the healthcheck to be executed
- SaAmfHealthcheckKeyT VG_keyAmfInvoked = {
- .key = "takeoverInvoked",
- .keyLen = 15
- };
- // Local function Prototypes
- static void amf_send_response( SaAmfHandleT, SaInvocationT, SaAisErrorT );
- static void amf_healthcheckCallback( SaInvocationT, const SaNameT*, SaAmfHealthcheckKeyT* );
- static void amf_ip_takeover( SaAmfCSIDescriptorT*, SaAmfHAStateT );
- static void amf_csi_setCallback( SaInvocationT, const SaNameT*, SaAmfHAStateT, SaAmfCSIDescriptorT* );
- static void* amf_comp_callbacks( void* );
- // Define the various callback functions that AMF may invoke on a component
- SaAmfCallbacksT VG_amfCallbacks = {
- .saAmfHealthcheckCallback = amf_healthcheckCallback,
- .saAmfCSISetCallback = amf_csi_setCallback
- };
- //
- // Response to Framework Requests to acknowledge the reception of a
- // message or a callback
- //
- static void
- amf_send_response(
- SaAmfHandleT p_handle, // AMF handle
- SaInvocationT p_invocation, // associate an invocation of this response function
- SaAisErrorT p_retval // return SA_AIS_OK in case of success, else returns an appropriate error
- ){
- SaAisErrorT v_error;
- for (;;usleep(10000)) {
- v_error = saAmfResponse( p_handle, p_invocation, p_retval );
- if (v_error != SA_AIS_ERR_TRY_AGAIN) break;
- }
- if (v_error != SA_AIS_OK) {
- fprintf( stderr, "saAmfResponse failed %d\n", v_error );
- exit( EXIT_FAILURE );
- }
- }
- //
- // AMF requests the component p_compName to perform a healthcheck
- // specified by p_healthcheckKey
- //
- void
- amf_healthcheckCallback(
- SaInvocationT p_invocation,
- const SaNameT *p_compName,
- SaAmfHealthcheckKeyT *p_healthcheckKey
- ){
- amf_send_response( VG_amf_handle, p_invocation, SA_AIS_OK );
- }
- //
- // IP takeover management
- //
- void
- amf_ip_takeover(
- SaAmfCSIDescriptorT *p_csiDescriptor, // information about the CSI targeted
- SaAmfHAStateT p_action // SA_AMF_HA_ACTIVE=="start", sinon "stop"
- ){
- char v_action[64], v_exec[256];
- char *v_path = getenv( "COMP_BINARY_PATH" );
- int i;
- // CSI attributs
- if (p_csiDescriptor!=NULL && (VG_interface==NULL || VG_ip_addr==NULL)) {
- for(i=0; i<p_csiDescriptor->csiAttr.number; i++) {
- // Interface
- if (VG_interface==NULL && !strcmp((char*)p_csiDescriptor->csiAttr.attr[i].attrName,"interface")) {
- VG_interface = (char*)malloc(strlen((char*)p_csiDescriptor->csiAttr.attr[i].attrName)+1);
- strcpy( VG_interface, (char*)p_csiDescriptor->csiAttr.attr[i].attrValue );
- }
- // Floating ip address
- if (VG_ip_addr==NULL && !strcmp((char*)p_csiDescriptor->csiAttr.attr[i].attrName,"ip_addr")) {
- VG_ip_addr = (char*)malloc(strlen((char*)p_csiDescriptor->csiAttr.attr[i].attrName)+1);
- strcpy( VG_ip_addr, (char*)p_csiDescriptor->csiAttr.attr[i].attrValue );
- }
- }
- }
- // Test d'integrite
- if (v_path==NULL || VG_interface==NULL || VG_ip_addr==NULL) return;
- // Ip takeover action
- strcpy( v_action, "stop" );
- if (p_action == SA_AMF_HA_ACTIVE) strcpy( v_action, "start" );
- // We execute the takeover script
- sprintf( v_exec, "%s/takeover.sh %s %s %s", v_path, VG_interface, VG_ip_addr, v_action );
- system( v_exec );
- }
- //
- // AMF invokes this callback to request the component to assume a
- // particular HA state
- //
- static void
- amf_csi_setCallback(
- SaInvocationT p_invocation, // to acknowledge the new state
- const SaNameT *p_compName, // name of the component
- SaAmfHAStateT p_haState, // new HA state to be assumed by the component for the CSI
- SaAmfCSIDescriptorT *p_csiDescriptor // information about the CSI targeted
- ){
- SaAmfHAStateT v_state;
- SaAisErrorT v_error;
- // new state
- switch( p_haState ) {
- case SA_AMF_HA_ACTIVE:
- case SA_AMF_HA_STANDBY:
- case SA_AMF_HA_QUIESCED:
- case SA_AMF_HA_QUIESCING:
- // Send response to AMF
- amf_send_response( VG_amf_handle, p_invocation, SA_AIS_OK );
- // Takeover of the ip address
- amf_ip_takeover( p_csiDescriptor, p_haState );
- // We change the local state
- VG_AMF_haState = p_haState;
- fprintf( stderr, "PID %d: Component '%s' requested to enter hastate %s for \n\tCSI '%s'\n",
- (int)getpid(), p_compName->value, TG_ha_state[p_haState], p_csiDescriptor->csiName.value );
- // We check if the state is changed
- v_error = saAmfHAStateGet( VG_amf_handle, p_compName, &p_csiDescriptor->csiName, &v_state );
- if (v_error!=SA_AIS_OK || p_haState!=v_state) {
- fprintf( stderr, "saAmfHAStateGet failed: %d\n", v_error );
- exit (-1);
- }
- break;
- default:
- break;
- }
- //
- // Transition detection
- //
- if (VG_AMF_haState != VG_AMF_old_haState) {
- VG_AMF_old_haState = VG_AMF_haState;
- *VG_AMF_remote_haState = VG_AMF_haState;
- }
- }
- //
- // Invoke pending callbacks for the handle amfHandle
- //
- void*
- amf_comp_callbacks(
- void* p_select_fd // file descriptor
- ) {
- int v_select_fd = (int)p_select_fd;
- struct timeval v_timeval;
- SaAisErrorT v_error;
- fd_set v_read_fds;
- int retval;
- // initialization
- pthread_detach( pthread_self() );
- FD_ZERO( &v_read_fds );
- // saAmfDispatch
- for (;;) {
- // related to value in amf.conf!
- v_timeval.tv_sec = 0;
- v_timeval.tv_usec = 1000;
- FD_SET( v_select_fd, &v_read_fds );
- // we check if there are data waiting
- retval = select( v_select_fd+1, &v_read_fds, 0, 0, &v_timeval );
- if (retval == -1) {
- if (errno == EINTR) continue;
- fprintf( stderr, "select failed - %s",strerror(errno) );
- exit( EXIT_FAILURE );
- }
- // We detect the availability of some date on the file descriptor
- // This avoid us to launch saAmfDispatch() too often
- if (retval > 0) {
- // invoke pending callbacks for the handle amfHandle
- for (;;usleep(10000)) {
- v_error = saAmfDispatch( VG_amf_handle, // AMF handle
- SA_DISPATCH_ALL ); // callback execution behavior
- if (v_error != SA_AIS_ERR_TRY_AGAIN) break;
- }
- if (v_error != SA_AIS_OK) {
- fprintf( stderr, "saAmfDispatch failed %d", v_error );
- exit( EXIT_FAILURE );
- }
- }
- }
- pthread_exit( NULL );
- return NULL;
- }
- //
- // Initialize AMF for the invoking process
- //
- void
- amf_comp_init(
- SaAmfHAStateT *p_amf_state // current HA state of the component
- ){
- char *v_name; // to get the environment variables
- SaAisErrorT v_error; // result of the AMF functions
- SaSelectionObjectT v_select_fd; // file descriptor to check if there is pending callbacks
- pthread_t v_thread; // to create a thread to manage the healthcheck
- int retval;
- // We get the environment variable SA_AMF_COMPONENT_NAME
- v_name = getenv( "SA_AMF_COMPONENT_NAME" );
- if (v_name == NULL) {
- fprintf( stderr, "SA_AMF_COMPONENT_NAME missing\n" );
- exit( EXIT_FAILURE );
- }
- fprintf( stderr, "** %d: Hello world from [%s]\n", (int)getpid(), v_name );
- // the real application need to know about ha state
- VG_AMF_remote_haState = p_amf_state;
- // Initialization
- VG_AMF_haState = SA_AMF_HA_STANDBY;
- VG_AMF_old_haState = SA_AMF_HA_STANDBY;
- *VG_AMF_remote_haState = SA_AMF_HA_STANDBY;
- // Initialize AMF for the invoking process and registers the various callback functions
- for (;;usleep(10000)) {
- v_error = saAmfInitialize( &VG_amf_handle, // handle of the Availability Management Framework
- &VG_amfCallbacks, // callback functions that AMF may invoke
- &VG_amf_version ); // version that should support AMF
- if (v_error != SA_AIS_ERR_TRY_AGAIN) break;
- }
- if (v_error != SA_AIS_OK) {
- fprintf( stderr, "saAmfInitialize result is %d\n", v_error );
- exit( EXIT_FAILURE );
- }
- // Handle to detect pending callbacks,
- // instead of repeatedly invoking saAmfDispatch()
- for (;;usleep(10000)) {
- v_error = saAmfSelectionObjectGet( VG_amf_handle, // AMF handle
- &v_select_fd ); // descriptor to detect pending callbacks
- if (v_error != SA_AIS_ERR_TRY_AGAIN) break;
- }
- if (v_error != SA_AIS_OK) {
- fprintf( stderr, "saAmfSelectionObjectGet failed %d\n", v_error );
- exit( EXIT_FAILURE );
- }
- // Get the name of the component the calling process belongs to
- for (;;usleep(10000)) {
- v_error = saAmfComponentNameGet( VG_amf_handle, // AMF handle
- &VG_compNameGlobal ); // name of the component
- if (v_error != SA_AIS_ERR_TRY_AGAIN) break;
- }
- if (v_error != SA_AIS_OK) {
- fprintf( stderr, "saAmfComponentNameGet failed %d\n", v_error );
- exit( EXIT_FAILURE );
- }
- // The healthchecks are invoked by the Availability Management Framework
- for (;;usleep(10000)) {
- v_error = saAmfHealthcheckStart( VG_amf_handle, // AMF handle
- &VG_compNameGlobal, // name of the component to be healthchecked
- &VG_keyAmfInvoked, // the key of the healthcheck to be executed
- SA_AMF_HEALTHCHECK_AMF_INVOKED, // component Healthcheck Monitoring
- SA_AMF_NO_RECOMMENDATION ); // What to do if the component fails a healthcheck
- if (v_error != SA_AIS_ERR_TRY_AGAIN) break;
- }
- if (v_error != SA_AIS_OK) {
- fprintf( stderr, "saAmfHealthcheckStart failed %d\n", v_error );
- exit( EXIT_FAILURE );
- }
- // Registration of the componant
- for (;;usleep(10000)) {
- v_error = saAmfComponentRegister( VG_amf_handle, // AMF handle
- &VG_compNameGlobal, // name of the component to be registered
- NULL ); // unused (proxy component)
- if (v_error != SA_AIS_ERR_TRY_AGAIN) break;
- }
- if (v_error != SA_AIS_OK) {
- fprintf( stderr, "saAmfComponentRegister failed %d\n", v_error );
- exit( EXIT_FAILURE );
- }
- // We start the healthcheck processing
- retval = pthread_create( &v_thread, NULL, (void*(*)(void*))amf_comp_callbacks, (void*)(int)v_select_fd );
- if (retval != 0) {
- fprintf( stderr, "saAmfComponentRegister failed %d\n", retval );
- exit( EXIT_FAILURE );
- }
- }
|