1 /* 2 * Copyright 2004-2022 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 PCMK__CRM_STONITH_NG__H 11 # define PCMK__CRM_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 long completed_nsec; 114 char *exit_reason; 115 } stonith_history_t; 116 117 typedef struct stonith_s stonith_t; 118 119 typedef struct stonith_event_s 120 { 121 char *id; 122 char *type; 123 char *message; 124 char *operation; 125 126 int result; 127 char *origin; 128 char *target; 129 char *action; 130 char *executioner; 131 132 char *device; 133 134 /*! The name of the client that initiated the action. */ 135 char *client_origin; 136 137 //! \internal This field should be treated as internal to Pacemaker 138 void *opaque; 139 } stonith_event_t; 140 141 typedef struct stonith_callback_data_s { 142 int rc; 143 int call_id; 144 void *userdata; 145 146 //! \internal This field should be treated as internal to Pacemaker 147 void *opaque; 148 } stonith_callback_data_t; 149 150 typedef struct stonith_api_operations_s 151 { 152 /*! 153 * \brief Destroy the stonith api structure. 154 */ 155 int (*free) (stonith_t *st); 156 157 /*! 158 * \brief Connect to the local stonith daemon. 159 * 160 * \return Legacy Pacemaker return code 161 */ 162 int (*connect) (stonith_t *st, const char *name, int *stonith_fd); 163 164 /*! 165 * \brief Disconnect from the local stonith daemon. 166 * 167 * \return Legacy Pacemaker return code 168 */ 169 int (*disconnect)(stonith_t *st); 170 171 /*! 172 * \brief Unregister a fence device with the local fencer 173 * 174 * \return pcmk_ok (if synchronous) or positive call ID (if asynchronous) 175 * on success, otherwise a negative legacy Pacemaker return code 176 */ 177 int (*remove_device)( 178 stonith_t *st, int options, const char *name); 179 180 /*! 181 * \brief Register a fence device with the local fencer 182 * 183 * \return pcmk_ok (if synchronous) or positive call ID (if asynchronous) 184 * on success, otherwise a negative legacy Pacemaker return code 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 Unregister a fencing level for specified node with local fencer 192 * 193 * \return pcmk_ok (if synchronous) or positive call ID (if asynchronous) 194 * on success, otherwise a negative legacy Pacemaker return code 195 */ 196 int (*remove_level)( 197 stonith_t *st, int options, const char *node, int level); 198 199 /*! 200 * \brief Register a fencing level for specified node with local fencer 201 * 202 * \return pcmk_ok (if synchronous) or positive call ID (if asynchronous) 203 * on success, otherwise a negative legacy Pacemaker return code 204 */ 205 int (*register_level)( 206 stonith_t *st, int options, const char *node, int level, stonith_key_value_t *device_list); 207 208 /*! 209 * \brief Get the metadata documentation for a resource. 210 * 211 * \note Value is returned in output. Output must be freed when set. 212 * 213 * \return Legacy Pacemaker return code 214 */ 215 int (*metadata)(stonith_t *st, int options, 216 const char *device, const char *provider, char **output, int timeout); 217 218 /*! 219 * \brief Retrieve a list of installed stonith agents 220 * 221 * \note if provider is not provided, all known agents will be returned 222 * \note list must be freed using stonith_key_value_freeall() 223 * \note call_options parameter is not used, it is reserved for future use. 224 * 225 * \return Number of items in list on success, or negative errno otherwise 226 */ 227 int (*list_agents)(stonith_t *stonith, int call_options, const char *provider, 228 stonith_key_value_t **devices, int timeout); 229 230 /*! 231 * \brief Retrieve string listing hosts and port assignments from a local stonith device. 232 * 233 * \return pcmk_ok (if synchronous) or positive call ID (if asynchronous) 234 * on success, otherwise a negative legacy Pacemaker return code 235 */ 236 int (*list)(stonith_t *st, int options, const char *id, char **list_output, int timeout); 237 238 /*! 239 * \brief Check to see if a local stonith device is reachable 240 * 241 * \return pcmk_ok (if synchronous) or positive call ID (if asynchronous) 242 * on success, otherwise a negative legacy Pacemaker return code 243 */ 244 int (*monitor)(stonith_t *st, int options, const char *id, int timeout); 245 246 /*! 247 * \brief Check to see if a local stonith device's port is reachable 248 * 249 * \return pcmk_ok (if synchronous) or positive call ID (if asynchronous) 250 * on success, otherwise a negative legacy Pacemaker return code 251 */ 252 int (*status)(stonith_t *st, int options, const char *id, const char *port, int timeout); 253 254 /*! 255 * \brief Retrieve a list of registered stonith devices. 256 * 257 * \note If node is provided, only devices that can fence the node id 258 * will be returned. 259 * 260 * \return Number of items in list on success, or negative errno otherwise 261 */ 262 int (*query)(stonith_t *st, int options, const char *node, 263 stonith_key_value_t **devices, int timeout); 264 265 /*! 266 * \brief Issue a fencing action against a node. 267 * 268 * \note Possible actions are, 'on', 'off', and 'reboot'. 269 * 270 * \param st, stonith connection 271 * \param options, call options 272 * \param node, The target node to fence 273 * \param action, The fencing action to take 274 * \param timeout, The default per device timeout to use with each device 275 * capable of fencing the target. 276 * 277 * \return pcmk_ok (if synchronous) or positive call ID (if asynchronous) 278 * on success, otherwise a negative legacy Pacemaker return code 279 */ 280 int (*fence)(stonith_t *st, int options, const char *node, const char *action, 281 int timeout, int tolerance); 282 283 /*! 284 * \brief Manually confirm that a node is down. 285 * 286 * \return pcmk_ok (if synchronous) or positive call ID (if asynchronous) 287 * on success, otherwise a negative legacy Pacemaker return code 288 */ 289 int (*confirm)(stonith_t *st, int options, const char *node); 290 291 /*! 292 * \brief Retrieve a list of fencing operations that have occurred for a specific node. 293 * 294 * \return Legacy Pacemaker return code 295 */ 296 int (*history)(stonith_t *st, int options, const char *node, stonith_history_t **output, int timeout); 297 298 int (*register_notification)( 299 stonith_t *st, const char *event, 300 void (*notify)(stonith_t *st, stonith_event_t *e)); 301 302 /*! 303 * \brief Remove a previously registered notification for \c event, or all 304 * notifications if NULL. 305 * 306 * \param[in] st Fencer connection to use 307 * \param[in] event The event to remove notifications for (may be NULL). 308 * 309 * \return Legacy Pacemaker return code 310 */ 311 int (*remove_notification)(stonith_t *st, const char *event); 312 313 /*! 314 * \brief Register a callback to receive the result of an asynchronous call 315 * 316 * \param[in] call_id The call ID to register callback for 317 * \param[in] timeout Default time to wait until callback expires 318 * \param[in] options Bitmask of \c stonith_call_options (respects 319 * \c st_opt_timeout_updates and 320 * \c st_opt_report_only_success) 321 * \param[in] userdata Pointer that will be given to callback 322 * \param[in] callback_name Unique name to identify callback 323 * \param[in] callback The callback function to register 324 * 325 * \return \c TRUE on success, \c FALSE if call_id is negative, -errno otherwise 326 */ 327 int (*register_callback)(stonith_t *st, 328 int call_id, 329 int timeout, 330 int options, 331 void *userdata, 332 const char *callback_name, 333 void (*callback)(stonith_t *st, stonith_callback_data_t *data)); 334 335 /*! 336 * \brief Remove a registered callback for a given call id 337 * 338 * \return pcmk_ok 339 */ 340 int (*remove_callback)(stonith_t *st, int call_id, bool all_callbacks); 341 342 /*! 343 * \brief Unregister fencing level for specified node, pattern or attribute 344 * 345 * \param[in] st Fencer connection to use 346 * \param[in] options Bitmask of stonith_call_options to pass to the fencer 347 * \param[in] node If not NULL, target level by this node name 348 * \param[in] pattern If not NULL, target by node name using this regex 349 * \param[in] attr If not NULL, target by this node attribute 350 * \param[in] value If not NULL, target by this node attribute value 351 * \param[in] level Index number of level to remove 352 * 353 * \return pcmk_ok (if synchronous) or positive call ID (if asynchronous) 354 * on success, otherwise a negative legacy Pacemaker return code 355 * 356 * \note The caller should set only one of node, pattern or attr/value. 357 */ 358 int (*remove_level_full)(stonith_t *st, int options, 359 const char *node, const char *pattern, 360 const char *attr, const char *value, int level); 361 362 /*! 363 * \brief Register fencing level for specified node, pattern or attribute 364 * 365 * \param[in] st Fencer connection to use 366 * \param[in] options Bitmask of stonith_call_options to pass to fencer 367 * \param[in] node If not NULL, target level by this node name 368 * \param[in] pattern If not NULL, target by node name using this regex 369 * \param[in] attr If not NULL, target by this node attribute 370 * \param[in] value If not NULL, target by this node attribute value 371 * \param[in] level Index number of level to add 372 * \param[in] device_list Devices to use in level 373 * 374 * \return pcmk_ok (if synchronous) or positive call ID (if asynchronous) 375 * on success, otherwise a negative legacy Pacemaker return code 376 * 377 * \note The caller should set only one of node, pattern or attr/value. 378 */ 379 int (*register_level_full)(stonith_t *st, int options, 380 const char *node, const char *pattern, 381 const char *attr, const char *value, 382 int level, stonith_key_value_t *device_list); 383 384 /*! 385 * \brief Validate an arbitrary stonith device configuration 386 * 387 * \param[in] st Stonithd connection to use 388 * \param[in] call_options Bitmask of stonith_call_options to use with fencer 389 * \param[in] rsc_id ID used to replace CIB secrets in params 390 * \param[in] namespace_s Namespace of fence agent to validate (optional) 391 * \param[in] agent Fence agent to validate 392 * \param[in] params Configuration parameters to pass to fence agent 393 * \param[in] timeout Fail if no response within this many seconds 394 * \param[out] output If non-NULL, where to store any agent output 395 * \param[out] error_output If non-NULL, where to store agent error output 396 * 397 * \return pcmk_ok if validation succeeds, -errno otherwise 398 * 399 * \note If pcmk_ok is returned, the caller is responsible for freeing 400 * the output (if requested). 401 */ 402 int (*validate)(stonith_t *st, int call_options, const char *rsc_id, 403 const char *namespace_s, const char *agent, 404 stonith_key_value_t *params, int timeout, char **output, 405 char **error_output); 406 407 /*! 408 * \brief Issue a fencing action against a node with requested fencing delay. 409 * 410 * \note Possible actions are, 'on', 'off', and 'reboot'. 411 * 412 * \param st, stonith connection 413 * \param options, call options 414 * \param node, The target node to fence 415 * \param action, The fencing action to take 416 * \param timeout, The default per device timeout to use with each device 417 * capable of fencing the target. 418 * \param delay, Apply a fencing delay. Value -1 means disable also any 419 * static/random fencing delays from pcmk_delay_base/max 420 * 421 * \return pcmk_ok (if synchronous) or positive call ID (if asynchronous) 422 * on success, otherwise a negative legacy Pacemaker return code 423 */ 424 int (*fence_with_delay)(stonith_t *st, int options, const char *node, const char *action, 425 int timeout, int tolerance, int delay); 426 427 } stonith_api_operations_t; 428 429 struct stonith_s 430 { 431 enum stonith_state state; 432 433 int call_id; 434 int call_timeout; //!< \deprecated Unused 435 void *st_private; 436 437 stonith_api_operations_t *cmds; 438 }; 439 /* *INDENT-ON* */ 440 441 /* Core functions */ 442 stonith_t *stonith_api_new(void); 443 void stonith_api_delete(stonith_t * st); 444 445 void stonith_dump_pending_callbacks(stonith_t * st); 446 447 bool stonith_dispatch(stonith_t * st); 448 449 stonith_key_value_t *stonith_key_value_add(stonith_key_value_t * kvp, const char *key, 450 const char *value); 451 void stonith_key_value_freeall(stonith_key_value_t * kvp, int keys, int values); 452 453 void stonith_history_free(stonith_history_t *history); 454 455 // Convenience functions 456 int stonith_api_connect_retry(stonith_t *st, const char *name, 457 int max_attempts); 458 const char *stonith_op_state_str(enum op_state state); 459 460 /* Basic helpers that allows nodes to be fenced and the history to be 461 * queried without mainloop or the caller understanding the full API 462 * 463 * At least one of nodeid and uname are required 464 */ 465 int stonith_api_kick(uint32_t nodeid, const char *uname, int timeout, bool off); 466 time_t stonith_api_time(uint32_t nodeid, const char *uname, bool in_progress); 467 468 /* 469 * Helpers for using the above functions without install-time dependencies 470 * 471 * Usage: 472 * #include <crm/stonith-ng.h> 473 * 474 * To turn a node off by corosync nodeid: 475 * stonith_api_kick_helper(nodeid, 120, 1); 476 * 477 * To check the last fence date/time (also by nodeid): 478 * last = stonith_api_time_helper(nodeid, 0); 479 * 480 * To check if fencing is in progress: 481 * if(stonith_api_time_helper(nodeid, 1) > 0) { ... } 482 * 483 * eg. 484 485 #include <stdio.h> 486 #include <time.h> 487 #include <crm/stonith-ng.h> 488 int 489 main(int argc, char ** argv) 490 { 491 int rc = 0; 492 int nodeid = 102; 493 494 rc = stonith_api_time_helper(nodeid, 0); 495 printf("%d last fenced at %s\n", nodeid, ctime(rc)); 496 497 rc = stonith_api_kick_helper(nodeid, 120, 1); 498 printf("%d fence result: %d\n", nodeid, rc); 499 500 rc = stonith_api_time_helper(nodeid, 0); 501 printf("%d last fenced at %s\n", nodeid, ctime(rc)); 502 503 return 0; 504 } 505 506 */ 507 508 # define STONITH_LIBRARY "libstonithd.so.26" 509 510 typedef int (*st_api_kick_fn) (int nodeid, const char *uname, int timeout, bool off); 511 typedef time_t (*st_api_time_fn) (int nodeid, const char *uname, bool in_progress); 512 513 static inline int 514 stonith_api_kick_helper(uint32_t nodeid, int timeout, bool off) /* */ 515 { 516 static void *st_library = NULL; 517 static st_api_kick_fn st_kick_fn; 518 519 if (st_library == NULL) { 520 st_library = dlopen(STONITH_LIBRARY, RTLD_LAZY); 521 } 522 if (st_library && st_kick_fn == NULL) { 523 st_kick_fn = (st_api_kick_fn) dlsym(st_library, "stonith_api_kick"); 524 } 525 if (st_kick_fn == NULL) { 526 #ifdef ELIBACC 527 return -ELIBACC; 528 #else 529 return -ENOSYS; 530 #endif 531 } 532 533 return (*st_kick_fn) (nodeid, NULL, timeout, off); 534 } 535 536 static inline time_t 537 stonith_api_time_helper(uint32_t nodeid, bool in_progress) /* */ 538 { 539 static void *st_library = NULL; 540 static st_api_time_fn st_time_fn; 541 542 if (st_library == NULL) { 543 st_library = dlopen(STONITH_LIBRARY, RTLD_LAZY); 544 } 545 if (st_library && st_time_fn == NULL) { 546 st_time_fn = (st_api_time_fn) dlsym(st_library, "stonith_api_time"); 547 } 548 if (st_time_fn == NULL) { 549 return 0; 550 } 551 552 return (*st_time_fn) (nodeid, NULL, in_progress); 553 } 554 555 /** 556 * Does the given agent describe a stonith resource that can exist? 557 * 558 * \param[in] agent What is the name of the agent? 559 * \param[in] timeout Timeout to use when querying. If 0 is given, 560 * use a default of 120. 561 * 562 * \return A boolean 563 */ 564 bool stonith_agent_exists(const char *agent, int timeout); 565 566 /*! 567 * \brief Turn stonith action into a more readable string. 568 * 569 * \param action Stonith action 570 */ 571 const char *stonith_action_str(const char *action); 572 573 #if !defined(PCMK_ALLOW_DEPRECATED) || (PCMK_ALLOW_DEPRECATED == 1) 574 /* Normally we'd put this section in a separate file (crm/fencing/compat.h), but 575 * we can't do that for the reason noted at the top of this file. That does mean 576 * we have to duplicate these declarations where they're implemented. 577 */ 578 579 //! \deprecated Use stonith_get_namespace() instead 580 const char *get_stonith_provider(const char *agent, const char *provider); 581 582 #endif 583 584 #ifdef __cplusplus 585 } 586 #endif 587 588 #endif