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

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