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

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