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. notify_callback
  3. fence_callback
  4. async_fence_helper
  5. pcmk__fence_action
  6. pcmk_fence_action
  7. pcmk__fence_history
  8. pcmk_fence_history
  9. pcmk__fence_installed
  10. pcmk_fence_installed
  11. pcmk__fence_last
  12. pcmk_fence_last
  13. pcmk__fence_list_targets
  14. pcmk_fence_list_targets
  15. pcmk__fence_metadata
  16. pcmk_fence_metadata
  17. pcmk__fence_registered
  18. pcmk_fence_registered
  19. pcmk__fence_register_level
  20. pcmk_fence_register_level
  21. pcmk__fence_unregister_level
  22. pcmk_fence_unregister_level
  23. pcmk__fence_validate
  24. pcmk_fence_validate
  25. pcmk__reduce_fence_history

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

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