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