Explorar o código

Add IP address takeover as an AMF component

git-svn-id: http://svn.fedorahosted.org/svn/corosync/trunk@1388 fd59a12c-fef9-0310-b244-a6a79926bd2f
Steven Dake %!s(int64=18) %!d(string=hai) anos
pai
achega
7b65087d28

+ 16 - 0
test/comp_amf/takeover/Makefile

@@ -0,0 +1,16 @@
+OPTIONS = -Wall -I../../include
+
+all: test_amf
+
+serv_main.o: serv_main.c serv_main.h
+	gcc $(OPTIONS) -c serv_main.c
+
+serv_amf.o: serv_amf.c serv_amf.h
+	gcc $(OPTIONS) -c serv_amf.c
+
+test_amf: serv_main.o serv_amf.o
+	gcc $(OPTIONS) -o test_amf serv_main.o serv_amf.o ../../lib/libSaAmf.a ../../lib/libSaCkpt.a -lpthread
+
+clean:
+	rm -f test_amf
+	rm -f *.o

+ 4 - 0
test/comp_amf/takeover/README.TXT

@@ -0,0 +1,4 @@
+Pollux -> 10.0.0.2
+Castor -> 10.0.0.1
+
+Device eth0 <- eth0:0 with 10.0.0.100

+ 111 - 0
test/comp_amf/takeover/amf.conf

@@ -0,0 +1,111 @@
+# AMF Test configuration file
+# - Times in milliseconds
+# - clccli_path can be set on any level from application and down and will be
+# added to the CLI commands if they are not already specified with an absolute
+# path (begins with /).
+# WL - WorkLoad
+
+safAmfCluster = TEST_AMF {
+	saAmfClusterStartupTimeout=3000
+	safAmfNode = NODE1 {
+		saAmfNodeSuFailOverProb=1000
+		saAmfNodeSuFailoverMax=1
+		saAmfNodeClmNode=pollux
+	}
+	safAmfNode = NODE2 {
+		saAmfNodeSuFailOverProb=1000
+		saAmfNodeSuFailoverMax=1
+		saAmfNodeClmNode=castor
+	}
+	safApp = APP-1 {
+		safSg = RAID {
+			saAmfSGRedundancyModel=nplusm	
+			saAmfSGNumPrefActiveSUs=1
+			saAmfSGMaxActiveSIsperSUs=2
+			saAmfSGNumPrefStandbySUs=1
+			saAmfSGMaxStandbySIsperSUs=2
+			saAmfSGCompRestartProb=100000
+			saAmfSGCompRestartMax=1
+			saAmfSGSuRestartProb=20000	
+			saAmfSGSuRestartMax=1
+			saAmfSGAutoAdjustProb=5000
+			safSu = SERVICE_X_1 {
+				saAmfSUHostedByNode=NODE1
+				saAmfSUNumComponents=1
+				safComp = A {
+					saAmfCompCategory=sa_aware
+					saAmfCompCapability=x_active_or_y_standby
+					saAmfCompNumMaxActiveCsi=1
+					saAmfCompNumMaxStandbyCsi=1
+					saAmfCompDefaultClcCliTimeout = 500
+					saAmfCompDefaultCallbackTimeOut = 500
+					saAmfCompInstantiateCmd = /root/openais/trunk/test/clc_cli_script
+					saAmfCompInstantiateCmdArgv= instantiate /root/openais/trunk/test/test_amf
+					saAmfCompTerminateCmd = /root/openais/trunk/test/clc_cli_script
+					saAmfCompTerminateCmdArgv = terminate
+					saAmfCompCleanupCmd = /root/openais/trunk/test/clc_cli_script
+					saAmfCompCleanupCmdArgv = cleanup
+					saAmfCompCsTypes {
+						A
+					}
+					saAmfCompCmdEnv {
+						COMP_BINARY_PATH=/root/openais/trunk/test/
+						COMP_BINARY_NAME=test_amf
+					}
+					saAmfCompRecoveryOnError=component_restart
+					safHealthcheckKey = takeoverInvoked {
+						saAmfHealthcheckPeriod = 1000
+						saAmfHealthcheckMaxDuration = 350
+					}
+				}
+			}
+			safSu = SERVICE_X_2 {
+				clccli_path=/root/openais/trunk/test/
+				saAmfSUHostedByNode=NODE2
+				saAmfSUNumComponents=1
+				safComp = A {
+					saAmfCompCategory=sa_aware
+					saAmfCompCapability=x_active_or_y_standby
+					saAmfCompNumMaxActiveCsi=1
+					saAmfCompNumMaxStandbyCsi=1
+					saAmfCompDefaultClcCliTimeout = 500
+					saAmfCompDefaultCallbackTimeOut = 500
+					saAmfCompInstantiateCmd = clc_cli_script
+					saAmfCompInstantiateCmdArgv= instantiate
+					saAmfCompTerminateCmd = clc_cli_script
+					saAmfCompTerminateCmdArgv = terminate
+					saAmfCompCleanupCmd = clc_cli_script
+					saAmfCompCleanupCmdArgv = cleanup
+					saAmfCompCsTypes {
+						A
+					}
+					saAmfCompCmdEnv {
+						COMP_BINARY_PATH=/root/openais/trunk/test/
+						COMP_BINARY_NAME=test_amf
+					}
+					saAmfCompRecoveryOnError=component_restart
+					safHealthcheckKey = takeoverInvoked {
+						saAmfHealthcheckPeriod = 1000
+						saAmfHealthcheckMaxDuration = 350
+					}
+				}
+			}
+		}
+		safSi = WL1 {
+			saAmfSINumCSIs=2
+			safCsi = WL1-1 {
+				saAmfCSTypeName = A
+				safCSIAttr = interface {
+                                        eth0:0
+                                }
+				safCSIAttr = ip_addr {
+                                        10.0.0.100
+                                }
+			}
+		}
+		safCSType = A {
+                        safAmfCSAttrName = interface
+                        safAmfCSAttrName = ip_addr
+                }
+	}
+}

+ 31 - 0
test/comp_amf/takeover/openais.conf

@@ -0,0 +1,31 @@
+# Please read the openais.conf.5 manual page
+
+totem {
+	version: 2
+	secauth: off
+	threads: 0
+	interface {
+		ringnumber: 0
+		bindnetaddr: 10.0.0.1
+		mcastaddr: 226.94.1.1
+		mcastport: 5405
+	}
+}
+
+logging {
+	fileline: off
+	to_stderr: no
+	to_file: yes
+	logfile: /tmp/openais.log
+	debug: off
+	timestamp: on
+	logger {
+		ident: AMF
+		debug: off
+		tags: enter|leave|trace1|trace2|trace3|trace4|trace6
+	}
+}
+
+amf {
+	mode: enabled
+}

+ 364 - 0
test/comp_amf/takeover/serv_amf.c

@@ -0,0 +1,364 @@
+/*
+ * 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 );
+    }
+}

+ 24 - 0
test/comp_amf/takeover/serv_amf.h

@@ -0,0 +1,24 @@
+#ifndef SERV_AMF_H
+#define SERV_AMF_H
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <signal.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/stat.h>
+#include <stdarg.h>
+#include <pthread.h>
+
+#include "saAis.h"
+#include "saAmf.h"
+
+SaAmfHAStateT *VG_ha_state;
+
+void amf_comp_init( SaAmfHAStateT* );
+
+#endif	/* SERV_AMF_H */

+ 94 - 0
test/comp_amf/takeover/serv_main.c

@@ -0,0 +1,94 @@
+/*
+ * 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<stdio.h>
+#include<stdlib.h>
+#include<unistd.h>
+#include<string.h>
+#include<signal.h>
+#include<sys/types.h>
+#include<sys/socket.h>
+#include<netinet/in.h>
+#include<arpa/inet.h>
+
+#include "serv_main.h"
+#include "serv_amf.h"
+
+// Cluster management
+SaAmfHAStateT VG_AMF_ha_state;		// State of the cluster
+
+/*
+ * =================================================================================
+ *   MAIN
+ * =================================================================================
+ */
+
+int
+main(
+	int p_argc,
+	char *p_argv[]
+) {
+  // This function initializes AMF for the invoking process
+  // and registers the various callback functions
+  amf_comp_init( &VG_AMF_ha_state );
+
+  // 
+  for (;;sleep(1)) {
+
+    switch( VG_AMF_ha_state ) {
+
+      case SA_AMF_HA_ACTIVE:
+        printf( "Active\n" );
+        break;
+
+      case SA_AMF_HA_STANDBY:
+        printf( "Standby\n" );
+        break;
+
+      case SA_AMF_HA_QUIESCED:
+        printf( "Quiesced\n" );
+        break;
+
+      case SA_AMF_HA_QUIESCING:
+        printf( "Quiescing\n" );
+        break;
+
+      default:
+        printf( "Unkwown\n" );
+        break;
+    }
+  }
+
+  exit( EXIT_SUCCESS );
+}

+ 4 - 0
test/comp_amf/takeover/serv_main.h

@@ -0,0 +1,4 @@
+#ifndef _SERV_MAIN_H
+#define _SERV_MAIN_H
+
+#endif	/* _SERV_MAIN_H */

+ 21 - 0
test/comp_amf/takeover/takeover.sh

@@ -0,0 +1,21 @@
+#!/bin/sh
+INTERFACE=$1
+ADRESSE=$2
+ACTION=$3
+
+case "$ACTION" in
+  start)
+    /sbin/ifconfig $INTERFACE $ADRESSE
+    DEVICE=`echo $INTERFACE | /usr/bin/cut -d ":" -f 1`
+    LISTE=`/sbin/arp -i $DEVICE | /usr/bin/grep -v Address | /usr/bin/awk '{print $1}'`
+    for elt in $LISTE; do
+      /sbin/arping -q -c 1 -w 0 $elt &
+    done
+    ;;
+  stop)
+    (/sbin/ifconfig -a | grep $INTERFACE 1>/dev/null) && /sbin/ifconfig $INTERFACE down
+    ;;
+  *)
+    echo "$0 ethx:y X.Y.Z.W [start|stop]"
+    ;;
+esac