serv_amf.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364
  1. /*
  2. * Copyright (c) 2007 Diginext/C-S
  3. *
  4. * All rights reserved.
  5. *
  6. * Author: Lionel Tricon (lionel.tricon@diginext.fr)
  7. *
  8. * This software licensed under BSD license, the text of which follows:
  9. *
  10. * Redistribution and use in source and binary forms, with or without
  11. * modification, are permitted provided that the following conditions are met:
  12. *
  13. * - Redistributions of source code must retain the above copyright notice,
  14. * this list of conditions and the following disclaimer.
  15. * - Redistributions in binary form must reproduce the above copyright notice,
  16. * this list of conditions and the following disclaimer in the documentation
  17. * and/or other materials provided with the distribution.
  18. * - Neither the name of the MontaVista Software, Inc. nor the names of its
  19. * contributors may be used to endorse or promote products derived from this
  20. * software without specific prior written permission.
  21. *
  22. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  23. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  24. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  25. * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  26. * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  27. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  28. * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  29. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  30. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  31. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
  32. * THE POSSIBILITY OF SUCH DAMAGE.
  33. */
  34. #include "serv_amf.h"
  35. // Global variables
  36. SaVersionT VG_amf_version = { 'B', 1, 1 }; // AMF version supported
  37. SaAmfHandleT VG_amf_handle; // AMF handle
  38. SaNameT VG_compNameGlobal; // name of the component
  39. // Ip takeover
  40. char *VG_interface=NULL; // ip takeover interface
  41. char *VG_ip_addr=NULL; // floating ip address
  42. SaAmfHAStateT VG_AMF_old_haState; // We store the old state to ease transition detection
  43. SaAmfHAStateT VG_AMF_haState; // Current ha state
  44. SaAmfHAStateT *VG_AMF_remote_haState; // Remote ha state (from the amf_comp_init function)
  45. // Types for State Management
  46. char *TG_ha_state[128] = {
  47. "null",
  48. "SA_AMF_HA_ACTIVE",
  49. "SA_AMF_HA_STANDBY",
  50. "SA_AMF_HA_QUIESCED",
  51. "SA_AMF_HA_QUIESCING"
  52. };
  53. // The key of the healthcheck to be executed
  54. SaAmfHealthcheckKeyT VG_keyAmfInvoked = {
  55. .key = "takeoverInvoked",
  56. .keyLen = 15
  57. };
  58. // Local function Prototypes
  59. static void amf_send_response( SaAmfHandleT, SaInvocationT, SaAisErrorT );
  60. static void amf_healthcheckCallback( SaInvocationT, const SaNameT*, SaAmfHealthcheckKeyT* );
  61. static void amf_ip_takeover( SaAmfCSIDescriptorT*, SaAmfHAStateT );
  62. static void amf_csi_setCallback( SaInvocationT, const SaNameT*, SaAmfHAStateT, SaAmfCSIDescriptorT* );
  63. static void* amf_comp_callbacks( void* );
  64. // Define the various callback functions that AMF may invoke on a component
  65. SaAmfCallbacksT VG_amfCallbacks = {
  66. .saAmfHealthcheckCallback = amf_healthcheckCallback,
  67. .saAmfCSISetCallback = amf_csi_setCallback
  68. };
  69. //
  70. // Response to Framework Requests to acknowledge the reception of a
  71. // message or a callback
  72. //
  73. static void
  74. amf_send_response(
  75. SaAmfHandleT p_handle, // AMF handle
  76. SaInvocationT p_invocation, // associate an invocation of this response function
  77. SaAisErrorT p_retval // return SA_AIS_OK in case of success, else returns an appropriate error
  78. ){
  79. SaAisErrorT v_error;
  80. for (;;usleep(10000)) {
  81. v_error = saAmfResponse( p_handle, p_invocation, p_retval );
  82. if (v_error != SA_AIS_ERR_TRY_AGAIN) break;
  83. }
  84. if (v_error != SA_AIS_OK) {
  85. fprintf( stderr, "saAmfResponse failed %d\n", v_error );
  86. exit( EXIT_FAILURE );
  87. }
  88. }
  89. //
  90. // AMF requests the component p_compName to perform a healthcheck
  91. // specified by p_healthcheckKey
  92. //
  93. void
  94. amf_healthcheckCallback(
  95. SaInvocationT p_invocation,
  96. const SaNameT *p_compName,
  97. SaAmfHealthcheckKeyT *p_healthcheckKey
  98. ){
  99. amf_send_response( VG_amf_handle, p_invocation, SA_AIS_OK );
  100. }
  101. //
  102. // IP takeover management
  103. //
  104. void
  105. amf_ip_takeover(
  106. SaAmfCSIDescriptorT *p_csiDescriptor, // information about the CSI targeted
  107. SaAmfHAStateT p_action // SA_AMF_HA_ACTIVE=="start", sinon "stop"
  108. ){
  109. char v_action[64], v_exec[256];
  110. char *v_path = getenv( "COMP_BINARY_PATH" );
  111. int i;
  112. // CSI attributs
  113. if (p_csiDescriptor!=NULL && (VG_interface==NULL || VG_ip_addr==NULL)) {
  114. for(i=0; i<p_csiDescriptor->csiAttr.number; i++) {
  115. // Interface
  116. if (VG_interface==NULL && !strcmp((char*)p_csiDescriptor->csiAttr.attr[i].attrName,"interface")) {
  117. VG_interface = (char*)malloc(strlen((char*)p_csiDescriptor->csiAttr.attr[i].attrName)+1);
  118. strcpy( VG_interface, (char*)p_csiDescriptor->csiAttr.attr[i].attrValue );
  119. }
  120. // Floating ip address
  121. if (VG_ip_addr==NULL && !strcmp((char*)p_csiDescriptor->csiAttr.attr[i].attrName,"ip_addr")) {
  122. VG_ip_addr = (char*)malloc(strlen((char*)p_csiDescriptor->csiAttr.attr[i].attrName)+1);
  123. strcpy( VG_ip_addr, (char*)p_csiDescriptor->csiAttr.attr[i].attrValue );
  124. }
  125. }
  126. }
  127. // Test d'integrite
  128. if (v_path==NULL || VG_interface==NULL || VG_ip_addr==NULL) return;
  129. // Ip takeover action
  130. strcpy( v_action, "stop" );
  131. if (p_action == SA_AMF_HA_ACTIVE) strcpy( v_action, "start" );
  132. // We execute the takeover script
  133. sprintf( v_exec, "%s/takeover.sh %s %s %s", v_path, VG_interface, VG_ip_addr, v_action );
  134. system( v_exec );
  135. }
  136. //
  137. // AMF invokes this callback to request the component to assume a
  138. // particular HA state
  139. //
  140. static void
  141. amf_csi_setCallback(
  142. SaInvocationT p_invocation, // to acknowledge the new state
  143. const SaNameT *p_compName, // name of the component
  144. SaAmfHAStateT p_haState, // new HA state to be assumed by the component for the CSI
  145. SaAmfCSIDescriptorT *p_csiDescriptor // information about the CSI targeted
  146. ){
  147. SaAmfHAStateT v_state;
  148. SaAisErrorT v_error;
  149. // new state
  150. switch( p_haState ) {
  151. case SA_AMF_HA_ACTIVE:
  152. case SA_AMF_HA_STANDBY:
  153. case SA_AMF_HA_QUIESCED:
  154. case SA_AMF_HA_QUIESCING:
  155. // Send response to AMF
  156. amf_send_response( VG_amf_handle, p_invocation, SA_AIS_OK );
  157. // Takeover of the ip address
  158. amf_ip_takeover( p_csiDescriptor, p_haState );
  159. // We change the local state
  160. VG_AMF_haState = p_haState;
  161. fprintf( stderr, "PID %d: Component '%s' requested to enter hastate %s for \n\tCSI '%s'\n",
  162. (int)getpid(), p_compName->value, TG_ha_state[p_haState], p_csiDescriptor->csiName.value );
  163. // We check if the state is changed
  164. v_error = saAmfHAStateGet( VG_amf_handle, p_compName, &p_csiDescriptor->csiName, &v_state );
  165. if (v_error!=SA_AIS_OK || p_haState!=v_state) {
  166. fprintf( stderr, "saAmfHAStateGet failed: %d\n", v_error );
  167. exit (-1);
  168. }
  169. break;
  170. default:
  171. break;
  172. }
  173. //
  174. // Transition detection
  175. //
  176. if (VG_AMF_haState != VG_AMF_old_haState) {
  177. VG_AMF_old_haState = VG_AMF_haState;
  178. *VG_AMF_remote_haState = VG_AMF_haState;
  179. }
  180. }
  181. //
  182. // Invoke pending callbacks for the handle amfHandle
  183. //
  184. void*
  185. amf_comp_callbacks(
  186. void* p_select_fd // file descriptor
  187. ) {
  188. int v_select_fd = (int)p_select_fd;
  189. struct timeval v_timeval;
  190. SaAisErrorT v_error;
  191. fd_set v_read_fds;
  192. int retval;
  193. // initialization
  194. pthread_detach( pthread_self() );
  195. FD_ZERO( &v_read_fds );
  196. // saAmfDispatch
  197. for (;;) {
  198. // related to value in amf.conf!
  199. v_timeval.tv_sec = 0;
  200. v_timeval.tv_usec = 1000;
  201. FD_SET( v_select_fd, &v_read_fds );
  202. // we check if there are data waiting
  203. retval = select( v_select_fd+1, &v_read_fds, 0, 0, &v_timeval );
  204. if (retval == -1) {
  205. if (errno == EINTR) continue;
  206. fprintf( stderr, "select failed - %s",strerror(errno) );
  207. exit( EXIT_FAILURE );
  208. }
  209. // We detect the availability of some date on the file descriptor
  210. // This avoid us to launch saAmfDispatch() too often
  211. if (retval > 0) {
  212. // invoke pending callbacks for the handle amfHandle
  213. for (;;usleep(10000)) {
  214. v_error = saAmfDispatch( VG_amf_handle, // AMF handle
  215. SA_DISPATCH_ALL ); // callback execution behavior
  216. if (v_error != SA_AIS_ERR_TRY_AGAIN) break;
  217. }
  218. if (v_error != SA_AIS_OK) {
  219. fprintf( stderr, "saAmfDispatch failed %d", v_error );
  220. exit( EXIT_FAILURE );
  221. }
  222. }
  223. }
  224. pthread_exit( NULL );
  225. return NULL;
  226. }
  227. //
  228. // Initialize AMF for the invoking process
  229. //
  230. void
  231. amf_comp_init(
  232. SaAmfHAStateT *p_amf_state // current HA state of the component
  233. ){
  234. char *v_name; // to get the environment variables
  235. SaAisErrorT v_error; // result of the AMF functions
  236. SaSelectionObjectT v_select_fd; // file descriptor to check if there is pending callbacks
  237. pthread_t v_thread; // to create a thread to manage the healthcheck
  238. int retval;
  239. // We get the environment variable SA_AMF_COMPONENT_NAME
  240. v_name = getenv( "SA_AMF_COMPONENT_NAME" );
  241. if (v_name == NULL) {
  242. fprintf( stderr, "SA_AMF_COMPONENT_NAME missing\n" );
  243. exit( EXIT_FAILURE );
  244. }
  245. fprintf( stderr, "** %d: Hello world from [%s]\n", (int)getpid(), v_name );
  246. // the real application need to know about ha state
  247. VG_AMF_remote_haState = p_amf_state;
  248. // Initialization
  249. VG_AMF_haState = SA_AMF_HA_STANDBY;
  250. VG_AMF_old_haState = SA_AMF_HA_STANDBY;
  251. *VG_AMF_remote_haState = SA_AMF_HA_STANDBY;
  252. // Initialize AMF for the invoking process and registers the various callback functions
  253. for (;;usleep(10000)) {
  254. v_error = saAmfInitialize( &VG_amf_handle, // handle of the Availability Management Framework
  255. &VG_amfCallbacks, // callback functions that AMF may invoke
  256. &VG_amf_version ); // version that should support AMF
  257. if (v_error != SA_AIS_ERR_TRY_AGAIN) break;
  258. }
  259. if (v_error != SA_AIS_OK) {
  260. fprintf( stderr, "saAmfInitialize result is %d\n", v_error );
  261. exit( EXIT_FAILURE );
  262. }
  263. // Handle to detect pending callbacks,
  264. // instead of repeatedly invoking saAmfDispatch()
  265. for (;;usleep(10000)) {
  266. v_error = saAmfSelectionObjectGet( VG_amf_handle, // AMF handle
  267. &v_select_fd ); // descriptor to detect pending callbacks
  268. if (v_error != SA_AIS_ERR_TRY_AGAIN) break;
  269. }
  270. if (v_error != SA_AIS_OK) {
  271. fprintf( stderr, "saAmfSelectionObjectGet failed %d\n", v_error );
  272. exit( EXIT_FAILURE );
  273. }
  274. // Get the name of the component the calling process belongs to
  275. for (;;usleep(10000)) {
  276. v_error = saAmfComponentNameGet( VG_amf_handle, // AMF handle
  277. &VG_compNameGlobal ); // name of the component
  278. if (v_error != SA_AIS_ERR_TRY_AGAIN) break;
  279. }
  280. if (v_error != SA_AIS_OK) {
  281. fprintf( stderr, "saAmfComponentNameGet failed %d\n", v_error );
  282. exit( EXIT_FAILURE );
  283. }
  284. // The healthchecks are invoked by the Availability Management Framework
  285. for (;;usleep(10000)) {
  286. v_error = saAmfHealthcheckStart( VG_amf_handle, // AMF handle
  287. &VG_compNameGlobal, // name of the component to be healthchecked
  288. &VG_keyAmfInvoked, // the key of the healthcheck to be executed
  289. SA_AMF_HEALTHCHECK_AMF_INVOKED, // component Healthcheck Monitoring
  290. SA_AMF_NO_RECOMMENDATION ); // What to do if the component fails a healthcheck
  291. if (v_error != SA_AIS_ERR_TRY_AGAIN) break;
  292. }
  293. if (v_error != SA_AIS_OK) {
  294. fprintf( stderr, "saAmfHealthcheckStart failed %d\n", v_error );
  295. exit( EXIT_FAILURE );
  296. }
  297. // Registration of the componant
  298. for (;;usleep(10000)) {
  299. v_error = saAmfComponentRegister( VG_amf_handle, // AMF handle
  300. &VG_compNameGlobal, // name of the component to be registered
  301. NULL ); // unused (proxy component)
  302. if (v_error != SA_AIS_ERR_TRY_AGAIN) break;
  303. }
  304. if (v_error != SA_AIS_OK) {
  305. fprintf( stderr, "saAmfComponentRegister failed %d\n", v_error );
  306. exit( EXIT_FAILURE );
  307. }
  308. // We start the healthcheck processing
  309. retval = pthread_create( &v_thread, NULL, (void*(*)(void*))amf_comp_callbacks, (void*)(int)v_select_fd );
  310. if (retval != 0) {
  311. fprintf( stderr, "saAmfComponentRegister failed %d\n", retval );
  312. exit( EXIT_FAILURE );
  313. }
  314. }