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