1 /* 2 * Copyright 2004-2021 the Pacemaker project contributors 3 * 4 * The version control history for this file may have further details. 5 * 6 * This source code is licensed under the GNU Lesser General Public License 7 * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY. 8 */ 9 10 #ifndef STONITH_NG__H 11 # define STONITH_NG__H 12 13 #ifdef __cplusplus 14 extern "C" { 15 #endif 16 17 /** 18 * \file 19 * \brief Fencing aka. STONITH 20 * \ingroup fencing 21 */ 22 23 /* IMPORTANT: DLM source code includes this file directly, without having access 24 * to other Pacemaker headers on its include path, so this file should *not* 25 * include any other Pacemaker headers. (DLM might be updated to avoid the 26 * issue, but we should still follow this guideline for a long time after.) 27 */ 28 29 # include <dlfcn.h> 30 # include <errno.h> 31 # include <stdbool.h> // bool 32 # include <stdint.h> // uint32_t 33 # include <time.h> // time_t 34 35 # define T_STONITH_NOTIFY_DISCONNECT "st_notify_disconnect" 36 # define T_STONITH_NOTIFY_FENCE "st_notify_fence" 37 # define T_STONITH_NOTIFY_HISTORY "st_notify_history" 38 # define T_STONITH_NOTIFY_HISTORY_SYNCED "st_notify_history_synced" 39 40 /* *INDENT-OFF* */ 41 enum stonith_state { 42 stonith_connected_command, 43 stonith_connected_query, 44 stonith_disconnected, 45 }; 46 47 enum stonith_call_options { 48 st_opt_none = 0x00000000, 49 st_opt_verbose = 0x00000001, 50 st_opt_allow_suicide = 0x00000002, 51 52 st_opt_manual_ack = 0x00000008, 53 st_opt_discard_reply = 0x00000010, 54 /* st_opt_all_replies = 0x00000020, */ 55 st_opt_topology = 0x00000040, 56 st_opt_scope_local = 0x00000100, 57 st_opt_cs_nodeid = 0x00000200, 58 st_opt_sync_call = 0x00001000, 59 /*! Allow the timeout period for a callback to be adjusted 60 * based on the time the server reports the operation will take. */ 61 st_opt_timeout_updates = 0x00002000, 62 /*! Only report back if operation is a success in callback */ 63 st_opt_report_only_success = 0x00004000, 64 /* used where ever apropriate - e.g. cleanup of history */ 65 st_opt_cleanup = 0x000080000, 66 /* used where ever apropriate - e.g. send out a history query to all nodes */ 67 st_opt_broadcast = 0x000100000, 68 }; 69 70 /*! Order matters here, do not change values */ 71 enum op_state 72 { 73 st_query, 74 st_exec, 75 st_done, 76 st_duplicate, 77 st_failed, 78 }; 79 80 // Supported fence agent interface standards 81 enum stonith_namespace { 82 st_namespace_invalid, 83 st_namespace_any, 84 st_namespace_internal, // Implemented internally by Pacemaker 85 86 /* Neither of these projects are active any longer, but the fence agent 87 * interfaces they created are still in use and supported by Pacemaker. 88 */ 89 st_namespace_rhcs, // Red Hat Cluster Suite compatible 90 st_namespace_lha, // Linux-HA compatible 91 }; 92 93 enum stonith_namespace stonith_text2namespace(const char *namespace_s); 94 const char *stonith_namespace2text(enum stonith_namespace st_namespace); 95 enum stonith_namespace stonith_get_namespace(const char *agent, 96 const char *namespace_s); 97 98 typedef struct stonith_key_value_s { 99 char *key; 100 char *value; 101 struct stonith_key_value_s *next; 102 } stonith_key_value_t; 103 104 typedef struct stonith_history_s { 105 char *target; 106 char *action; 107 char *origin; 108 char *delegate; 109 char *client; 110 int state; 111 time_t completed; 112 struct stonith_history_s *next; 113 } stonith_history_t; 114 115 typedef struct stonith_s stonith_t; 116 117 typedef struct stonith_event_s 118 { 119 char *id; 120 char *type; 121 char *message; 122 char *operation; 123 124 int result; 125 char *origin; 126 char *target; 127 char *action; 128 char *executioner; 129 130 char *device; 131 132 /*! The name of the client that initiated the action. */ 133 char *client_origin; 134 135 } stonith_event_t; 136 137 typedef struct stonith_callback_data_s 138 { 139 int rc; 140 int call_id; 141 void *userdata; 142 } stonith_callback_data_t; 143 144 typedef struct stonith_api_operations_s 145 { 146 /*! 147 * \brief Destroy the stonith api structure. 148 */ 149 int (*free) (stonith_t *st); 150 151 /*! 152 * \brief Connect to the local stonith daemon. 153 * 154 * \retval 0, success 155 * \retval negative error code on failure 156 */ 157 int (*connect) (stonith_t *st, const char *name, int *stonith_fd); 158 159 /*! 160 * \brief Disconnect from the local stonith daemon. 161 * 162 * \retval 0, success 163 * \retval negative error code on failure 164 */ 165 int (*disconnect)(stonith_t *st); 166 167 /*! 168 * \brief Remove a registered stonith device with the local stonith daemon. 169 * 170 * \note Synchronous, guaranteed to occur in daemon before function returns. 171 * 172 * \retval 0, success 173 * \retval negative error code on failure 174 */ 175 int (*remove_device)( 176 stonith_t *st, int options, const char *name); 177 178 /*! 179 * \brief Register a stonith device with the local stonith daemon. 180 * 181 * \note Synchronous, guaranteed to occur in daemon before function returns. 182 * 183 * \retval 0, success 184 * \retval negative error code on failure 185 */ 186 int (*register_device)( 187 stonith_t *st, int options, const char *id, 188 const char *provider, const char *agent, stonith_key_value_t *params); 189 190 /*! 191 * \brief Remove a fencing level for a specific node. 192 * 193 * \retval 0, success 194 * \retval negative error code on failure 195 */ 196 int (*remove_level)( 197 stonith_t *st, int options, const char *node, int level); 198 199 /*! 200 * \brief Register a fencing level containing the fencing devices to be used 201 * at that level for a specific node. 202 * 203 * \retval 0, success 204 * \retval negative error code on failure 205 */ 206 int (*register_level)( 207 stonith_t *st, int options, const char *node, int level, stonith_key_value_t *device_list); 208 209 /*! 210 * \brief Get the metadata documentation for a resource. 211 * 212 * \note Value is returned in output. Output must be freed when set. 213 * 214 * \retval 0 success 215 * \retval negative error code on failure 216 */ 217 int (*metadata)(stonith_t *st, int options, 218 const char *device, const char *provider, char **output, int timeout); 219 220 /*! 221 * \brief Retrieve a list of installed stonith agents 222 * 223 * \note if provider is not provided, all known agents will be returned 224 * \note list must be freed using stonith_key_value_freeall() 225 * \note call_options parameter is not used, it is reserved for future use. 226 * 227 * \retval num items in list on success 228 * \retval negative error code on failure 229 */ 230 int (*list_agents)(stonith_t *stonith, int call_options, const char *provider, 231 stonith_key_value_t **devices, int timeout); 232 233 /*! 234 * \brief Retrieve string listing hosts and port assignments from a local stonith device. 235 * 236 * \retval 0 on success 237 * \retval negative error code on failure 238 */ 239 int (*list)(stonith_t *st, int options, const char *id, char **list_output, int timeout); 240 241 /*! 242 * \brief Check to see if a local stonith device is reachable 243 * 244 * \retval 0 on success 245 * \retval negative error code on failure 246 */ 247 int (*monitor)(stonith_t *st, int options, const char *id, int timeout); 248 249 /*! 250 * \brief Check to see if a local stonith device's port is reachable 251 * 252 * \retval 0 on success 253 * \retval negative error code on failure 254 */ 255 int (*status)(stonith_t *st, int options, const char *id, const char *port, int timeout); 256 257 /*! 258 * \brief Retrieve a list of registered stonith devices. 259 * 260 * \note If node is provided, only devices that can fence the node id 261 * will be returned. 262 * 263 * \retval num items in list on success 264 * \retval negative error code on failure 265 */ 266 int (*query)(stonith_t *st, int options, const char *node, 267 stonith_key_value_t **devices, int timeout); 268 269 /*! 270 * \brief Issue a fencing action against a node. 271 * 272 * \note Possible actions are, 'on', 'off', and 'reboot'. 273 * 274 * \param st, stonith connection 275 * \param options, call options 276 * \param node, The target node to fence 277 * \param action, The fencing action to take 278 * \param timeout, The default per device timeout to use with each device 279 * capable of fencing the target. 280 * 281 * \retval 0 success 282 * \retval negative error code on failure. 283 */ 284 int (*fence)(stonith_t *st, int options, const char *node, const char *action, 285 int timeout, int tolerance); 286 287 /*! 288 * \brief Manually confirm that a node is down. 289 * 290 * \retval 0 success 291 * \retval negative error code on failure. 292 */ 293 int (*confirm)(stonith_t *st, int options, const char *node); 294 295 /*! 296 * \brief Retrieve a list of fencing operations that have occurred for a specific node. 297 * 298 * \retval 0 success 299 * \retval negative error code on failure. 300 */ 301 int (*history)(stonith_t *st, int options, const char *node, stonith_history_t **output, int timeout); 302 303 int (*register_notification)( 304 stonith_t *st, const char *event, 305 void (*notify)(stonith_t *st, stonith_event_t *e)); 306 int (*remove_notification)(stonith_t *st, const char *event); 307 308 /*! 309 * \brief Register a callback to receive the result of an asynchronous call 310 * 311 * \param[in] call_id The call ID to register callback for 312 * \param[in] timeout Default time to wait until callback expires 313 * \param[in] options Bitmask of \c stonith_call_options (respects 314 * \c st_opt_timeout_updates and 315 * \c st_opt_report_only_success) 316 * \param[in] userdata Pointer that will be given to callback 317 * \param[in] callback_name Unique name to identify callback 318 * \param[in] callback The callback function to register 319 * 320 * \return \c TRUE on success, \c FALSE if call_id is negative, -errno otherwise 321 * 322 * \todo This function should return \c pcmk_ok on success, and \c call_id 323 * when negative, but that would break backward compatibility. 324 */ 325 int (*register_callback)(stonith_t *st, 326 int call_id, 327 int timeout, 328 int options, 329 void *userdata, 330 const char *callback_name, 331 void (*callback)(stonith_t *st, stonith_callback_data_t *data)); 332 333 /*! 334 * \brief Remove a registered callback for a given call id. 335 */ 336 int (*remove_callback)(stonith_t *st, int call_id, bool all_callbacks); 337 338 /*! 339 * \brief Remove fencing level for specific node, node regex or attribute 340 * 341 * \param[in] st Fencer connection to use 342 * \param[in] options Bitmask of stonith_call_options to pass to the fencer 343 * \param[in] node If not NULL, target level by this node name 344 * \param[in] pattern If not NULL, target by node name using this regex 345 * \param[in] attr If not NULL, target by this node attribute 346 * \param[in] value If not NULL, target by this node attribute value 347 * \param[in] level Index number of level to remove 348 * 349 * \return 0 on success, negative error code otherwise 350 * 351 * \note The caller should set only one of node, pattern or attr/value. 352 */ 353 int (*remove_level_full)(stonith_t *st, int options, 354 const char *node, const char *pattern, 355 const char *attr, const char *value, int level); 356 357 /*! 358 * \brief Register fencing level for specific node, node regex or attribute 359 * 360 * \param[in] st Fencer connection to use 361 * \param[in] options Bitmask of stonith_call_options to pass to fencer 362 * \param[in] node If not NULL, target level by this node name 363 * \param[in] pattern If not NULL, target by node name using this regex 364 * \param[in] attr If not NULL, target by this node attribute 365 * \param[in] value If not NULL, target by this node attribute value 366 * \param[in] level Index number of level to add 367 * \param[in] device_list Devices to use in level 368 * 369 * \return 0 on success, negative error code otherwise 370 * 371 * \note The caller should set only one of node, pattern or attr/value. 372 */ 373 int (*register_level_full)(stonith_t *st, int options, 374 const char *node, const char *pattern, 375 const char *attr, const char *value, 376 int level, stonith_key_value_t *device_list); 377 378 /*! 379 * \brief Validate an arbitrary stonith device configuration 380 * 381 * \param[in] st Stonithd connection to use 382 * \param[in] call_options Bitmask of stonith_call_options to use with fencer 383 * \param[in] rsc_id ID used to replace CIB secrets in params 384 * \param[in] namespace_s Namespace of fence agent to validate (optional) 385 * \param[in] agent Fence agent to validate 386 * \param[in] params Configuration parameters to pass to fence agent 387 * \param[in] timeout Fail if no response within this many seconds 388 * \param[out] output If non-NULL, where to store any agent output 389 * \param[out] error_output If non-NULL, where to store agent error output 390 * 391 * \return pcmk_ok if validation succeeds, -errno otherwise 392 * 393 * \note If pcmk_ok is returned, the caller is responsible for freeing 394 * the output (if requested). 395 */ 396 int (*validate)(stonith_t *st, int call_options, const char *rsc_id, 397 const char *namespace_s, const char *agent, 398 stonith_key_value_t *params, int timeout, char **output, 399 char **error_output); 400 401 /*! 402 * \brief Issue a fencing action against a node with requested fencing delay. 403 * 404 * \note Possible actions are, 'on', 'off', and 'reboot'. 405 * 406 * \param st, stonith connection 407 * \param options, call options 408 * \param node, The target node to fence 409 * \param action, The fencing action to take 410 * \param timeout, The default per device timeout to use with each device 411 * capable of fencing the target. 412 * \param delay, Apply a fencing delay. Value -1 means disable also any 413 * static/random fencing delays from pcmk_delay_base/max 414 * 415 * \retval 0 success 416 * \retval negative error code on failure. 417 */ 418 int (*fence_with_delay)(stonith_t *st, int options, const char *node, const char *action, 419 int timeout, int tolerance, int delay); 420 421 } stonith_api_operations_t; 422 423 struct stonith_s 424 { 425 enum stonith_state state; 426 427 int call_id; 428 int call_timeout; 429 void *st_private; 430 431 stonith_api_operations_t *cmds; 432 }; 433 /* *INDENT-ON* */ 434 435 /* Core functions */ 436 stonith_t *stonith_api_new(void); 437 void stonith_api_delete(stonith_t * st); 438 439 void stonith_dump_pending_callbacks(stonith_t * st); 440 441 bool stonith_dispatch(stonith_t * st); 442 443 stonith_key_value_t *stonith_key_value_add(stonith_key_value_t * kvp, const char *key, 444 const char *value); 445 void stonith_key_value_freeall(stonith_key_value_t * kvp, int keys, int values); 446 447 void stonith_history_free(stonith_history_t *history); 448 449 // Convenience functions 450 int stonith_api_connect_retry(stonith_t *st, const char *name, 451 int max_attempts); 452 const char *stonith_op_state_str(enum op_state state); 453 454 /* Basic helpers that allows nodes to be fenced and the history to be 455 * queried without mainloop or the caller understanding the full API 456 * 457 * At least one of nodeid and uname are required 458 */ 459 int stonith_api_kick(uint32_t nodeid, const char *uname, int timeout, bool off); 460 time_t stonith_api_time(uint32_t nodeid, const char *uname, bool in_progress); 461 462 /* 463 * Helpers for using the above functions without install-time dependencies 464 * 465 * Usage: 466 * #include <crm/stonith-ng.h> 467 * 468 * To turn a node off by corosync nodeid: 469 * stonith_api_kick_helper(nodeid, 120, 1); 470 * 471 * To check the last fence date/time (also by nodeid): 472 * last = stonith_api_time_helper(nodeid, 0); 473 * 474 * To check if fencing is in progress: 475 * if(stonith_api_time_helper(nodeid, 1) > 0) { ... } 476 * 477 * eg. 478 479 #include <stdio.h> 480 #include <time.h> 481 #include <crm/stonith-ng.h> 482 int 483 main(int argc, char ** argv) 484 { 485 int rc = 0; 486 int nodeid = 102; 487 488 rc = stonith_api_time_helper(nodeid, 0); 489 printf("%d last fenced at %s\n", nodeid, ctime(rc)); 490 491 rc = stonith_api_kick_helper(nodeid, 120, 1); 492 printf("%d fence result: %d\n", nodeid, rc); 493 494 rc = stonith_api_time_helper(nodeid, 0); 495 printf("%d last fenced at %s\n", nodeid, ctime(rc)); 496 497 return 0; 498 } 499 500 */ 501 502 # define STONITH_LIBRARY "libstonithd.so.26" 503 504 typedef int (*st_api_kick_fn) (int nodeid, const char *uname, int timeout, bool off); 505 typedef time_t (*st_api_time_fn) (int nodeid, const char *uname, bool in_progress); 506 507 static inline int 508 stonith_api_kick_helper(uint32_t nodeid, int timeout, bool off) /* */ 509 { 510 static void *st_library = NULL; 511 static st_api_kick_fn st_kick_fn; 512 513 if (st_library == NULL) { 514 st_library = dlopen(STONITH_LIBRARY, RTLD_LAZY); 515 } 516 if (st_library && st_kick_fn == NULL) { 517 st_kick_fn = (st_api_kick_fn) dlsym(st_library, "stonith_api_kick"); 518 } 519 if (st_kick_fn == NULL) { 520 #ifdef ELIBACC 521 return -ELIBACC; 522 #else 523 return -ENOSYS; 524 #endif 525 } 526 527 return (*st_kick_fn) (nodeid, NULL, timeout, off); 528 } 529 530 static inline time_t 531 stonith_api_time_helper(uint32_t nodeid, bool in_progress) /* */ 532 { 533 static void *st_library = NULL; 534 static st_api_time_fn st_time_fn; 535 536 if (st_library == NULL) { 537 st_library = dlopen(STONITH_LIBRARY, RTLD_LAZY); 538 } 539 if (st_library && st_time_fn == NULL) { 540 st_time_fn = (st_api_time_fn) dlsym(st_library, "stonith_api_time"); 541 } 542 if (st_time_fn == NULL) { 543 return 0; 544 } 545 546 return (*st_time_fn) (nodeid, NULL, in_progress); 547 } 548 549 /** 550 * Does the given agent describe a stonith resource that can exist? 551 * 552 * \param[in] agent What is the name of the agent? 553 * \param[in] timeout Timeout to use when querying. If 0 is given, 554 * use a default of 120. 555 * 556 * \return A boolean 557 */ 558 bool stonith_agent_exists(const char *agent, int timeout); 559 560 /*! 561 * \brief Turn stonith action into a more readable string. 562 * 563 * \param action Stonith action 564 */ 565 const char *stonith_action_str(const char *action); 566 567 #if !defined(PCMK_ALLOW_DEPRECATED) || (PCMK_ALLOW_DEPRECATED == 1) 568 /* Normally we'd put this section in a separate file (crm/fencing/compat.h), but 569 * we can't do that for the reason noted at the top of this file. That does mean 570 * we have to duplicate these declarations where they're implemented. 571 */ 572 573 //! \deprecated Use stonith_get_namespace() instead 574 const char *get_stonith_provider(const char *agent, const char *provider); 575 576 #endif 577 578 #ifdef __cplusplus 579 } 580 #endif 581 582 #endif