root/lib/pacemaker/pcmk_fence.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. handle_level
  2. reduce_fence_history
  3. notify_callback
  4. fence_callback
  5. async_fence_helper
  6. pcmk__request_fencing
  7. pcmk_request_fencing
  8. pcmk__fence_history
  9. pcmk_fence_history
  10. pcmk__fence_installed
  11. pcmk_fence_installed
  12. pcmk__fence_last
  13. pcmk_fence_last
  14. pcmk__fence_list_targets
  15. pcmk_fence_list_targets
  16. pcmk__fence_metadata
  17. pcmk_fence_metadata
  18. pcmk__fence_registered
  19. pcmk_fence_registered
  20. pcmk__fence_register_level
  21. pcmk_fence_register_level
  22. pcmk__fence_unregister_level
  23. pcmk_fence_unregister_level
  24. pcmk__fence_validate
  25. pcmk_fence_validate
  26. pcmk__get_fencing_history

   1 /*
   2  * Copyright 2009-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 General Public License version 2
   7  * or later (GPLv2+) WITHOUT ANY WARRANTY.
   8  */
   9 
  10 #include <crm_internal.h>
  11 #include <crm/common/mainloop.h>
  12 #include <crm/common/results.h>
  13 #include <crm/common/output_internal.h>
  14 #include <crm/stonith-ng.h>
  15 #include <crm/fencing/internal.h>
  16 
  17 #include <glib.h>
  18 #include <libxml/tree.h>
  19 #include <pacemaker.h>
  20 #include <pacemaker-internal.h>
  21 
  22 static const int st_opts = st_opt_sync_call | st_opt_allow_suicide;
  23 
  24 static GMainLoop *mainloop = NULL;
  25 
  26 static struct {
  27     stonith_t *st;
  28     const char *target;
  29     const char *action;
  30     char *name;
  31     unsigned int timeout;
  32     unsigned int tolerance;
  33     int delay;
  34     pcmk__action_result_t result;
  35 } async_fence_data = { NULL, };
  36 
  37 static int
  38 handle_level(stonith_t *st, char *target, int fence_level,
     /* [previous][next][first][last][top][bottom][index][help] */
  39              stonith_key_value_t *devices, bool added) {
  40     char *node = NULL;
  41     char *pattern = NULL;
  42     char *name = NULL;
  43     char *value = NULL;
  44     int rc = pcmk_rc_ok;
  45 
  46     if (target == NULL) {
  47         // Not really possible, but makes static analysis happy
  48         return EINVAL;
  49     }
  50 
  51     /* Determine if targeting by attribute, node name pattern or node name */
  52     value = strchr(target, '=');
  53     if (value != NULL)  {
  54         name = target;
  55         *value++ = '\0';
  56     } else if (*target == '@') {
  57         pattern = target + 1;
  58     } else {
  59         node = target;
  60     }
  61 
  62     /* Register or unregister level as appropriate */
  63     if (added) {
  64         rc = st->cmds->register_level_full(st, st_opts, node, pattern,
  65                                            name, value, fence_level,
  66                                            devices);
  67     } else {
  68         rc = st->cmds->remove_level_full(st, st_opts, node, pattern,
  69                                          name, value, fence_level);
  70     }
  71 
  72     return pcmk_legacy2rc(rc);
  73 }
  74 
  75 static stonith_history_t *
  76 reduce_fence_history(stonith_history_t *history)
     /* [previous][next][first][last][top][bottom][index][help] */
  77 {
  78     stonith_history_t *new, *hp, *np;
  79 
  80     if (!history) {
  81         return history;
  82     }
  83 
  84     new = history;
  85     hp = new->next;
  86     new->next = NULL;
  87 
  88     while (hp) {
  89         stonith_history_t *hp_next = hp->next;
  90 
  91         hp->next = NULL;
  92 
  93         for (np = new; ; np = np->next) {
  94             if ((hp->state == st_done) || (hp->state == st_failed)) {
  95                 /* action not in progress */
  96                 if (pcmk__str_eq(hp->target, np->target, pcmk__str_casei) &&
  97                     pcmk__str_eq(hp->action, np->action, pcmk__str_none) &&
  98                     (hp->state == np->state) &&
  99                     ((hp->state == st_done) ||
 100                      pcmk__str_eq(hp->delegate, np->delegate, pcmk__str_casei))) {
 101                         /* purge older hp */
 102                         stonith_history_free(hp);
 103                         break;
 104                 }
 105             }
 106 
 107             if (!np->next) {
 108                 np->next = hp;
 109                 break;
 110             }
 111         }
 112         hp = hp_next;
 113     }
 114 
 115     return new;
 116 }
 117 
 118 static void
 119 notify_callback(stonith_t * st, stonith_event_t * e)
     /* [previous][next][first][last][top][bottom][index][help] */
 120 {
 121     if (pcmk__str_eq(async_fence_data.target, e->target, pcmk__str_casei)
 122         && pcmk__str_eq(async_fence_data.action, e->action, pcmk__str_none)) {
 123 
 124         pcmk__set_result(&async_fence_data.result,
 125                          stonith__event_exit_status(e),
 126                          stonith__event_execution_status(e),
 127                          stonith__event_exit_reason(e));
 128         g_main_loop_quit(mainloop);
 129     }
 130 }
 131 
 132 static void
 133 fence_callback(stonith_t * stonith, stonith_callback_data_t * data)
     /* [previous][next][first][last][top][bottom][index][help] */
 134 {
 135     pcmk__set_result(&async_fence_data.result, stonith__exit_status(data),
 136                      stonith__execution_status(data),
 137                      stonith__exit_reason(data));
 138     g_main_loop_quit(mainloop);
 139 }
 140 
 141 static gboolean
 142 async_fence_helper(gpointer user_data)
     /* [previous][next][first][last][top][bottom][index][help] */
 143 {
 144     stonith_t *st = async_fence_data.st;
 145     int call_id = 0;
 146     int rc = stonith_api_connect_retry(st, async_fence_data.name, 10);
 147 
 148     if (rc != pcmk_ok) {
 149         g_main_loop_quit(mainloop);
 150         pcmk__set_result(&async_fence_data.result, CRM_EX_ERROR,
 151                          PCMK_EXEC_NOT_CONNECTED, pcmk_strerror(rc));
 152         return TRUE;
 153     }
 154 
 155     st->cmds->register_notification(st, T_STONITH_NOTIFY_FENCE, notify_callback);
 156 
 157     call_id = st->cmds->fence_with_delay(st,
 158                                          st_opt_allow_suicide,
 159                                          async_fence_data.target,
 160                                          async_fence_data.action,
 161                                          async_fence_data.timeout/1000,
 162                                          async_fence_data.tolerance/1000,
 163                                          async_fence_data.delay);
 164 
 165     if (call_id < 0) {
 166         g_main_loop_quit(mainloop);
 167         pcmk__set_result(&async_fence_data.result, CRM_EX_ERROR,
 168                          PCMK_EXEC_ERROR, pcmk_strerror(call_id));
 169         return TRUE;
 170     }
 171 
 172     st->cmds->register_callback(st,
 173                                 call_id,
 174                                 async_fence_data.timeout/1000,
 175                                 st_opt_timeout_updates, NULL, "callback", fence_callback);
 176 
 177     return TRUE;
 178 }
 179 
 180 int
 181 pcmk__request_fencing(stonith_t *st, const char *target, const char *action,
     /* [previous][next][first][last][top][bottom][index][help] */
 182                       const char *name, unsigned int timeout,
 183                       unsigned int tolerance, int delay, char **reason)
 184 {
 185     crm_trigger_t *trig;
 186     int rc = pcmk_rc_ok;
 187 
 188     async_fence_data.st = st;
 189     async_fence_data.name = strdup(name);
 190     async_fence_data.target = target;
 191     async_fence_data.action = action;
 192     async_fence_data.timeout = timeout;
 193     async_fence_data.tolerance = tolerance;
 194     async_fence_data.delay = delay;
 195     pcmk__set_result(&async_fence_data.result, CRM_EX_ERROR, PCMK_EXEC_UNKNOWN,
 196                      NULL);
 197 
 198     trig = mainloop_add_trigger(G_PRIORITY_HIGH, async_fence_helper, NULL);
 199     mainloop_set_trigger(trig);
 200 
 201     mainloop = g_main_loop_new(NULL, FALSE);
 202     g_main_loop_run(mainloop);
 203 
 204     free(async_fence_data.name);
 205 
 206     if (reason != NULL) {
 207         // Give the caller ownership of the exit reason
 208         *reason = async_fence_data.result.exit_reason;
 209         async_fence_data.result.exit_reason = NULL;
 210     }
 211     rc = stonith__result2rc(&async_fence_data.result);
 212     pcmk__reset_result(&async_fence_data.result);
 213     return rc;
 214 }
 215 
 216 #ifdef BUILD_PUBLIC_LIBPACEMAKER
 217 int
 218 pcmk_request_fencing(stonith_t *st, const char *target, const char *action,
     /* [previous][next][first][last][top][bottom][index][help] */
 219                      const char *name, unsigned int timeout,
 220                      unsigned int tolerance, int delay, char **reason)
 221 {
 222     return pcmk__request_fencing(st, target, action, name, timeout, tolerance,
 223                                  delay, reason);
 224 }
 225 #endif
 226 
 227 int
 228 pcmk__fence_history(pcmk__output_t *out, stonith_t *st, char *target,
     /* [previous][next][first][last][top][bottom][index][help] */
 229                     unsigned int timeout, int verbose, bool broadcast,
 230                     bool cleanup) {
 231     stonith_history_t *history = NULL, *hp, *latest = NULL;
 232     int rc = pcmk_rc_ok;
 233     int opts = 0;
 234 
 235     if (cleanup) {
 236         out->info(out, "cleaning up fencing-history%s%s",
 237                   target ? " for node " : "", target ? target : "");
 238     }
 239     if (broadcast) {
 240         out->info(out, "gather fencing-history from all nodes");
 241     }
 242 
 243     stonith__set_call_options(opts, target, st_opts);
 244     if (cleanup) {
 245         stonith__set_call_options(opts, target, st_opt_cleanup);
 246     }
 247     if (broadcast) {
 248         stonith__set_call_options(opts, target, st_opt_broadcast);
 249     }
 250     rc = st->cmds->history(st, opts,
 251                            pcmk__str_eq(target, "*", pcmk__str_none)? NULL : target,
 252                            &history, timeout/1000);
 253 
 254     if (cleanup) {
 255         // Cleanup doesn't return a history list
 256         stonith_history_free(history);
 257         return pcmk_legacy2rc(rc);
 258     }
 259 
 260     out->begin_list(out, "event", "events", "Fencing history");
 261 
 262     history = stonith__sort_history(history);
 263     for (hp = history; hp; hp = hp->next) {
 264         if (hp->state == st_done) {
 265             latest = hp;
 266         }
 267 
 268         if (out->is_quiet(out) || !verbose) {
 269             continue;
 270         }
 271 
 272         out->message(out, "stonith-event", hp, 1, stonith__later_succeeded(hp, history));
 273         out->increment_list(out);
 274     }
 275 
 276     if (latest) {
 277         if (out->is_quiet(out)) {
 278             pcmk__formatted_printf(out, "%lld\n", (long long) latest->completed);
 279         } else if (!verbose) { // already printed if verbose
 280             out->message(out, "stonith-event", latest, 0, FALSE);
 281             out->increment_list(out);
 282         }
 283     }
 284 
 285     out->end_list(out);
 286 
 287     stonith_history_free(history);
 288     return pcmk_legacy2rc(rc);
 289 }
 290 
 291 #ifdef BUILD_PUBLIC_LIBPACEMAKER
 292 int
 293 pcmk_fence_history(xmlNodePtr *xml, stonith_t *st, char *target, unsigned int timeout,
     /* [previous][next][first][last][top][bottom][index][help] */
 294                    bool quiet, int verbose, bool broadcast, bool cleanup) {
 295     pcmk__output_t *out = NULL;
 296     int rc = pcmk_rc_ok;
 297 
 298     rc = pcmk__out_prologue(&out, xml);
 299     if (rc != pcmk_rc_ok) {
 300         return rc;
 301     }
 302 
 303     stonith__register_messages(out);
 304 
 305     out->quiet = quiet;
 306 
 307     rc = pcmk__fence_history(out, st, target, timeout, verbose, broadcast, cleanup);
 308     pcmk__out_epilogue(out, xml, rc);
 309     return rc;
 310 }
 311 #endif
 312 
 313 int
 314 pcmk__fence_installed(pcmk__output_t *out, stonith_t *st, unsigned int timeout) {
     /* [previous][next][first][last][top][bottom][index][help] */
 315     stonith_key_value_t *devices = NULL;
 316     int rc = pcmk_rc_ok;
 317 
 318     rc = st->cmds->list_agents(st, st_opt_sync_call, NULL, &devices, timeout/1000);
 319     /* list_agents returns a negative error code or a positive number of agents. */
 320     if (rc < 0) {
 321         return pcmk_legacy2rc(rc);
 322     }
 323 
 324     out->begin_list(out, "fence device", "fence devices", "Installed fence devices");
 325     for (stonith_key_value_t *dIter = devices; dIter; dIter = dIter->next) {
 326         out->list_item(out, "device", "%s", dIter->value);
 327     }
 328     out->end_list(out);
 329 
 330     stonith_key_value_freeall(devices, 1, 1);
 331     return pcmk_rc_ok;
 332 }
 333 
 334 #ifdef BUILD_PUBLIC_LIBPACEMAKER
 335 int
 336 pcmk_fence_installed(xmlNodePtr *xml, stonith_t *st, unsigned int timeout) {
     /* [previous][next][first][last][top][bottom][index][help] */
 337     pcmk__output_t *out = NULL;
 338     int rc = pcmk_rc_ok;
 339 
 340     rc = pcmk__out_prologue(&out, xml);
 341     if (rc != pcmk_rc_ok) {
 342         return rc;
 343     }
 344 
 345     stonith__register_messages(out);
 346 
 347     rc = pcmk__fence_installed(out, st, timeout);
 348     pcmk__out_epilogue(out, xml, rc);
 349     return rc;
 350 }
 351 #endif
 352 
 353 int
 354 pcmk__fence_last(pcmk__output_t *out, const char *target, bool as_nodeid) {
     /* [previous][next][first][last][top][bottom][index][help] */
 355     time_t when = 0;
 356 
 357     if (target == NULL) {
 358         return pcmk_rc_ok;
 359     }
 360 
 361     if (as_nodeid) {
 362         when = stonith_api_time(atol(target), NULL, FALSE);
 363     } else {
 364         when = stonith_api_time(0, target, FALSE);
 365     }
 366 
 367     return out->message(out, "last-fenced", target, when);
 368 }
 369 
 370 #ifdef BUILD_PUBLIC_LIBPACEMAKER
 371 int
 372 pcmk_fence_last(xmlNodePtr *xml, const char *target, bool as_nodeid) {
     /* [previous][next][first][last][top][bottom][index][help] */
 373     pcmk__output_t *out = NULL;
 374     int rc = pcmk_rc_ok;
 375 
 376     rc = pcmk__out_prologue(&out, xml);
 377     if (rc != pcmk_rc_ok) {
 378         return rc;
 379     }
 380 
 381     stonith__register_messages(out);
 382 
 383     rc = pcmk__fence_last(out, target, as_nodeid);
 384     pcmk__out_epilogue(out, xml, rc);
 385     return rc;
 386 }
 387 #endif
 388 
 389 int
 390 pcmk__fence_list_targets(pcmk__output_t *out, stonith_t *st,
     /* [previous][next][first][last][top][bottom][index][help] */
 391                          const char *device_id, unsigned int timeout) {
 392     GList *targets = NULL;
 393     char *lists = NULL;
 394     int rc = pcmk_rc_ok;
 395 
 396     rc = st->cmds->list(st, st_opts, device_id, &lists, timeout/1000);
 397     if (rc != pcmk_rc_ok) {
 398         return pcmk_legacy2rc(rc);
 399     }
 400 
 401     targets = stonith__parse_targets(lists);
 402 
 403     out->begin_list(out, "fence target", "fence targets", "Fence Targets");
 404     while (targets != NULL) {
 405         out->list_item(out, NULL, "%s", (const char *) targets->data);
 406         targets = targets->next;
 407     }
 408     out->end_list(out);
 409 
 410     free(lists);
 411     return rc;
 412 }
 413 
 414 #ifdef BUILD_PUBLIC_LIBPACEMAKER
 415 int
 416 pcmk_fence_list_targets(xmlNodePtr *xml, stonith_t *st, const char *device_id,
     /* [previous][next][first][last][top][bottom][index][help] */
 417                         unsigned int timeout) {
 418     pcmk__output_t *out = NULL;
 419     int rc = pcmk_rc_ok;
 420 
 421     rc = pcmk__out_prologue(&out, xml);
 422     if (rc != pcmk_rc_ok) {
 423         return rc;
 424     }
 425 
 426     stonith__register_messages(out);
 427 
 428     rc = pcmk__fence_list_targets(out, st, device_id, timeout);
 429     pcmk__out_epilogue(out, xml, rc);
 430     return rc;
 431 }
 432 #endif
 433 
 434 int
 435 pcmk__fence_metadata(pcmk__output_t *out, stonith_t *st, char *agent,
     /* [previous][next][first][last][top][bottom][index][help] */
 436                      unsigned int timeout) {
 437     char *buffer = NULL;
 438     int rc = st->cmds->metadata(st, st_opt_sync_call, agent, NULL, &buffer,
 439                                 timeout/1000);
 440 
 441     if (rc != pcmk_rc_ok) {
 442         return pcmk_legacy2rc(rc);
 443     }
 444 
 445     out->output_xml(out, "metadata", buffer);
 446     free(buffer);
 447     return rc;
 448 }
 449 
 450 #ifdef BUILD_PUBLIC_LIBPACEMAKER
 451 int
 452 pcmk_fence_metadata(xmlNodePtr *xml, stonith_t *st, char *agent,
     /* [previous][next][first][last][top][bottom][index][help] */
 453                     unsigned int timeout) {
 454     pcmk__output_t *out = NULL;
 455     int rc = pcmk_rc_ok;
 456 
 457     rc = pcmk__out_prologue(&out, xml);
 458     if (rc != pcmk_rc_ok) {
 459         return rc;
 460     }
 461 
 462     stonith__register_messages(out);
 463 
 464     rc = pcmk__fence_metadata(out, st, agent, timeout);
 465     pcmk__out_epilogue(out, xml, rc);
 466     return rc;
 467 }
 468 #endif
 469 
 470 int
 471 pcmk__fence_registered(pcmk__output_t *out, stonith_t *st, char *target,
     /* [previous][next][first][last][top][bottom][index][help] */
 472                        unsigned int timeout) {
 473     stonith_key_value_t *devices = NULL;
 474     int rc = pcmk_rc_ok;
 475 
 476     rc = st->cmds->query(st, st_opts, target, &devices, timeout/1000);
 477     /* query returns a negative error code or a positive number of results. */
 478     if (rc < 0) {
 479         return pcmk_legacy2rc(rc);
 480     }
 481 
 482     out->begin_list(out, "fence device", "fence devices", "Registered fence devices");
 483     for (stonith_key_value_t *dIter = devices; dIter; dIter = dIter->next) {
 484         out->list_item(out, "device", "%s", dIter->value);
 485     }
 486     out->end_list(out);
 487 
 488     stonith_key_value_freeall(devices, 1, 1);
 489 
 490     /* Return pcmk_rc_ok here, not the number of results.  Callers probably
 491      * don't care.
 492      */
 493     return pcmk_rc_ok;
 494 }
 495 
 496 #ifdef BUILD_PUBLIC_LIBPACEMAKER
 497 int
 498 pcmk_fence_registered(xmlNodePtr *xml, stonith_t *st, char *target,
     /* [previous][next][first][last][top][bottom][index][help] */
 499                       unsigned int timeout) {
 500     pcmk__output_t *out = NULL;
 501     int rc = pcmk_rc_ok;
 502 
 503     rc = pcmk__out_prologue(&out, xml);
 504     if (rc != pcmk_rc_ok) {
 505         return rc;
 506     }
 507 
 508     stonith__register_messages(out);
 509 
 510     rc = pcmk__fence_registered(out, st, target, timeout);
 511     pcmk__out_epilogue(out, xml, rc);
 512     return rc;
 513 }
 514 #endif
 515 
 516 int
 517 pcmk__fence_register_level(stonith_t *st, char *target, int fence_level,
     /* [previous][next][first][last][top][bottom][index][help] */
 518                            stonith_key_value_t *devices) {
 519     return handle_level(st, target, fence_level, devices, true);
 520 }
 521 
 522 #ifdef BUILD_PUBLIC_LIBPACEMAKER
 523 int
 524 pcmk_fence_register_level(stonith_t *st, char *target, int fence_level,
     /* [previous][next][first][last][top][bottom][index][help] */
 525                             stonith_key_value_t *devices) {
 526     return pcmk__fence_register_level(st, target, fence_level, devices);
 527 }
 528 #endif
 529 
 530 int
 531 pcmk__fence_unregister_level(stonith_t *st, char *target, int fence_level) {
     /* [previous][next][first][last][top][bottom][index][help] */
 532     return handle_level(st, target, fence_level, NULL, false);
 533 }
 534 
 535 #ifdef BUILD_PUBLIC_LIBPACEMAKER
 536 int
 537 pcmk_fence_unregister_level(stonith_t *st, char *target, int fence_level) {
     /* [previous][next][first][last][top][bottom][index][help] */
 538     return pcmk__fence_unregister_level(st, target, fence_level);
 539 }
 540 #endif
 541 
 542 int
 543 pcmk__fence_validate(pcmk__output_t *out, stonith_t *st, const char *agent,
     /* [previous][next][first][last][top][bottom][index][help] */
 544                      const char *id, stonith_key_value_t *params,
 545                      unsigned int timeout) {
 546     char *output = NULL;
 547     char *error_output = NULL;
 548     int rc;
 549 
 550     rc  = st->cmds->validate(st, st_opt_sync_call, id, NULL, agent, params,
 551                              timeout/1000, &output, &error_output);
 552     out->message(out, "validate", agent, id, output, error_output, rc);
 553     return pcmk_legacy2rc(rc);
 554 }
 555 
 556 #ifdef BUILD_PUBLIC_LIBPACEMAKER
 557 int
 558 pcmk_fence_validate(xmlNodePtr *xml, stonith_t *st, const char *agent,
     /* [previous][next][first][last][top][bottom][index][help] */
 559                     const char *id, stonith_key_value_t *params,
 560                     unsigned int timeout) {
 561     pcmk__output_t *out = NULL;
 562     int rc = pcmk_rc_ok;
 563 
 564     rc = pcmk__out_prologue(&out, xml);
 565     if (rc != pcmk_rc_ok) {
 566         return rc;
 567     }
 568 
 569     stonith__register_messages(out);
 570 
 571     rc = pcmk__fence_validate(out, st, agent, id, params, timeout);
 572     pcmk__out_epilogue(out, xml, rc);
 573     return rc;
 574 }
 575 #endif
 576 
 577 int
 578 pcmk__get_fencing_history(stonith_t *st, stonith_history_t **stonith_history,
     /* [previous][next][first][last][top][bottom][index][help] */
 579                           enum pcmk__fence_history fence_history)
 580 {
 581     int rc = pcmk_rc_ok;
 582 
 583     if (st == NULL) {
 584         rc = ENOTCONN;
 585     } else if (fence_history != pcmk__fence_history_none) {
 586         rc = st->cmds->history(st, st_opt_sync_call, NULL, stonith_history, 120);
 587 
 588         rc = pcmk_legacy2rc(rc);
 589         if (rc != pcmk_rc_ok) {
 590             return rc;
 591         }
 592 
 593         *stonith_history = stonith__sort_history(*stonith_history);
 594         if (fence_history == pcmk__fence_history_reduced) {
 595             *stonith_history = reduce_fence_history(*stonith_history);
 596         }
 597     }
 598 
 599     return rc;
 600 }

/* [previous][next][first][last][top][bottom][index][help] */