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

   1 /*
   2  * Copyright 2009-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 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 (!out->is_quiet(out)) {
 181         if (cleanup) {
 182             out->info(out, "cleaning up fencing-history%s%s",
 183                       target ? " for node " : "", target ? target : "");
 184         }
 185         if (broadcast) {
 186             out->info(out, "gather fencing-history from all nodes");
 187         }
 188     }
 189 
 190     stonith__set_call_options(opts, target, st_opts);
 191     if (cleanup) {
 192         stonith__set_call_options(opts, target, st_opt_cleanup);
 193     }
 194     if (broadcast) {
 195         stonith__set_call_options(opts, target, st_opt_broadcast);
 196     }
 197     rc = st->cmds->history(st, opts,
 198                            pcmk__str_eq(target, "*", pcmk__str_none)? NULL : target,
 199                            &history, timeout/1000);
 200 
 201     if (cleanup) {
 202         // Cleanup doesn't return a history list
 203         stonith_history_free(history);
 204         return pcmk_legacy2rc(rc);
 205     }
 206 
 207     out->begin_list(out, "event", "events", "Fencing history");
 208 
 209     history = stonith__sort_history(history);
 210     for (hp = history; hp; hp = hp->next) {
 211         if (hp->state == st_done) {
 212             latest = hp;
 213         }
 214 
 215         if (out->is_quiet(out) || !verbose) {
 216             continue;
 217         }
 218 
 219         out->message(out, "stonith-event", hp, 1, stonith__later_succeeded(hp, history));
 220         out->increment_list(out);
 221     }
 222 
 223     if (latest) {
 224         if (out->is_quiet(out)) {
 225             out->info(out, "%lld", (long long) latest->completed);
 226         } else if (!verbose) { // already printed if verbose
 227             out->message(out, "stonith-event", latest, 0, FALSE);
 228             out->increment_list(out);
 229         }
 230     }
 231 
 232     out->end_list(out);
 233 
 234     stonith_history_free(history);
 235     return pcmk_legacy2rc(rc);
 236 }
 237 
 238 #ifdef BUILD_PUBLIC_LIBPACEMAKER
 239 int
 240 pcmk_fence_history(xmlNodePtr *xml, stonith_t *st, char *target, unsigned int timeout,
     /* [previous][next][first][last][top][bottom][index][help] */
 241                    bool quiet, int verbose, bool broadcast, bool cleanup) {
 242     pcmk__output_t *out = NULL;
 243     int rc = pcmk_rc_ok;
 244 
 245     rc = pcmk__out_prologue(&out, xml);
 246     if (rc != pcmk_rc_ok) {
 247         return rc;
 248     }
 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     rc = pcmk__fence_installed(out, st, timeout);
 291     pcmk__out_epilogue(out, xml, rc);
 292     return rc;
 293 }
 294 #endif
 295 
 296 int
 297 pcmk__fence_last(pcmk__output_t *out, const char *target, bool as_nodeid) {
     /* [previous][next][first][last][top][bottom][index][help] */
 298     time_t when = 0;
 299 
 300     if (target == NULL) {
 301         return pcmk_rc_ok;
 302     }
 303 
 304     if (as_nodeid) {
 305         when = stonith_api_time(atol(target), NULL, FALSE);
 306     } else {
 307         when = stonith_api_time(0, target, FALSE);
 308     }
 309 
 310     return out->message(out, "last-fenced", target, when);
 311 }
 312 
 313 #ifdef BUILD_PUBLIC_LIBPACEMAKER
 314 int
 315 pcmk_fence_last(xmlNodePtr *xml, const char *target, bool as_nodeid) {
     /* [previous][next][first][last][top][bottom][index][help] */
 316     pcmk__output_t *out = NULL;
 317     int rc = pcmk_rc_ok;
 318 
 319     rc = pcmk__out_prologue(&out, xml);
 320     if (rc != pcmk_rc_ok) {
 321         return rc;
 322     }
 323 
 324     rc = pcmk__fence_last(out, target, as_nodeid);
 325     pcmk__out_epilogue(out, xml, rc);
 326     return rc;
 327 }
 328 #endif
 329 
 330 int
 331 pcmk__fence_list_targets(pcmk__output_t *out, stonith_t *st,
     /* [previous][next][first][last][top][bottom][index][help] */
 332                          const char *device_id, unsigned int timeout) {
 333     GList *targets = NULL;
 334     char *lists = NULL;
 335     int rc = pcmk_rc_ok;
 336 
 337     rc = st->cmds->list(st, st_opts, device_id, &lists, timeout/1000);
 338     if (rc != pcmk_rc_ok) {
 339         return pcmk_legacy2rc(rc);
 340     }
 341 
 342     targets = stonith__parse_targets(lists);
 343 
 344     out->begin_list(out, "fence target", "fence targets", "Fence Targets");
 345     while (targets != NULL) {
 346         out->list_item(out, NULL, "%s", (const char *) targets->data);
 347         targets = targets->next;
 348     }
 349     out->end_list(out);
 350 
 351     free(lists);
 352     return rc;
 353 }
 354 
 355 #ifdef BUILD_PUBLIC_LIBPACEMAKER
 356 int
 357 pcmk_fence_list_targets(xmlNodePtr *xml, stonith_t *st, const char *device_id,
     /* [previous][next][first][last][top][bottom][index][help] */
 358                         unsigned int timeout) {
 359     pcmk__output_t *out = NULL;
 360     int rc = pcmk_rc_ok;
 361 
 362     rc = pcmk__out_prologue(&out, xml);
 363     if (rc != pcmk_rc_ok) {
 364         return rc;
 365     }
 366 
 367     rc = pcmk__fence_list_targets(out, st, device_id, timeout);
 368     pcmk__out_epilogue(out, xml, rc);
 369     return rc;
 370 }
 371 #endif
 372 
 373 int
 374 pcmk__fence_metadata(pcmk__output_t *out, stonith_t *st, char *agent,
     /* [previous][next][first][last][top][bottom][index][help] */
 375                      unsigned int timeout) {
 376     char *buffer = NULL;
 377     int rc = st->cmds->metadata(st, st_opt_sync_call, agent, NULL, &buffer,
 378                                 timeout/1000);
 379 
 380     if (rc != pcmk_rc_ok) {
 381         return pcmk_legacy2rc(rc);
 382     }
 383 
 384     out->output_xml(out, "metadata", buffer);
 385     free(buffer);
 386     return rc;
 387 }
 388 
 389 #ifdef BUILD_PUBLIC_LIBPACEMAKER
 390 int
 391 pcmk_fence_metadata(xmlNodePtr *xml, stonith_t *st, char *agent,
     /* [previous][next][first][last][top][bottom][index][help] */
 392                     unsigned int timeout) {
 393     pcmk__output_t *out = NULL;
 394     int rc = pcmk_rc_ok;
 395 
 396     rc = pcmk__out_prologue(&out, xml);
 397     if (rc != pcmk_rc_ok) {
 398         return rc;
 399     }
 400 
 401     rc = pcmk__fence_metadata(out, st, agent, timeout);
 402     pcmk__out_epilogue(out, xml, rc);
 403     return rc;
 404 }
 405 #endif
 406 
 407 int
 408 pcmk__fence_registered(pcmk__output_t *out, stonith_t *st, char *target,
     /* [previous][next][first][last][top][bottom][index][help] */
 409                        unsigned int timeout) {
 410     stonith_key_value_t *devices = NULL;
 411     int rc = pcmk_rc_ok;
 412 
 413     rc = st->cmds->query(st, st_opts, target, &devices, timeout/1000);
 414     /* query returns a negative error code or a positive number of results. */
 415     if (rc < 0) {
 416         return pcmk_legacy2rc(rc);
 417     }
 418 
 419     out->begin_list(out, "fence device", "fence devices", "Registered fence devices");
 420     for (stonith_key_value_t *dIter = devices; dIter; dIter = dIter->next) {
 421         out->list_item(out, "device", "%s", dIter->value);
 422     }
 423     out->end_list(out);
 424 
 425     stonith_key_value_freeall(devices, 1, 1);
 426 
 427     /* Return pcmk_rc_ok here, not the number of results.  Callers probably
 428      * don't care.
 429      */
 430     return pcmk_rc_ok;
 431 }
 432 
 433 #ifdef BUILD_PUBLIC_LIBPACEMAKER
 434 int
 435 pcmk_fence_registered(xmlNodePtr *xml, stonith_t *st, char *target,
     /* [previous][next][first][last][top][bottom][index][help] */
 436                       unsigned int timeout) {
 437     pcmk__output_t *out = NULL;
 438     int rc = pcmk_rc_ok;
 439 
 440     rc = pcmk__out_prologue(&out, xml);
 441     if (rc != pcmk_rc_ok) {
 442         return rc;
 443     }
 444 
 445     rc = pcmk__fence_registered(out, st, target, timeout);
 446     pcmk__out_epilogue(out, xml, rc);
 447     return rc;
 448 }
 449 #endif
 450 
 451 int
 452 pcmk__fence_register_level(stonith_t *st, char *target, int fence_level,
     /* [previous][next][first][last][top][bottom][index][help] */
 453                            stonith_key_value_t *devices) {
 454     return handle_level(st, target, fence_level, devices, true);
 455 }
 456 
 457 #ifdef BUILD_PUBLIC_LIBPACEMAKER
 458 int
 459 pcmk_fence_register_level(stonith_t *st, char *target, int fence_level,
     /* [previous][next][first][last][top][bottom][index][help] */
 460                             stonith_key_value_t *devices) {
 461     return pcmk__fence_register_level(st, target, fence_level, devices);
 462 }
 463 #endif
 464 
 465 int
 466 pcmk__fence_unregister_level(stonith_t *st, char *target, int fence_level) {
     /* [previous][next][first][last][top][bottom][index][help] */
 467     return handle_level(st, target, fence_level, NULL, false);
 468 }
 469 
 470 #ifdef BUILD_PUBLIC_LIBPACEMAKER
 471 int
 472 pcmk_fence_unregister_level(stonith_t *st, char *target, int fence_level) {
     /* [previous][next][first][last][top][bottom][index][help] */
 473     return pcmk__fence_unregister_level(st, target, fence_level);
 474 }
 475 #endif
 476 
 477 int
 478 pcmk__fence_validate(pcmk__output_t *out, stonith_t *st, const char *agent,
     /* [previous][next][first][last][top][bottom][index][help] */
 479                      const char *id, stonith_key_value_t *params,
 480                      unsigned int timeout) {
 481     char *output = NULL;
 482     char *error_output = NULL;
 483     int rc;
 484 
 485     rc  = st->cmds->validate(st, st_opt_sync_call, id, NULL, agent, params,
 486                              timeout/1000, &output, &error_output);
 487     out->message(out, "validate", agent, id, output, error_output, rc);
 488     return pcmk_legacy2rc(rc);
 489 }
 490 
 491 #ifdef BUILD_PUBLIC_LIBPACEMAKER
 492 int
 493 pcmk_fence_validate(xmlNodePtr *xml, stonith_t *st, const char *agent,
     /* [previous][next][first][last][top][bottom][index][help] */
 494                     const char *id, stonith_key_value_t *params,
 495                     unsigned int timeout) {
 496     pcmk__output_t *out = NULL;
 497     int rc = pcmk_rc_ok;
 498 
 499     rc = pcmk__out_prologue(&out, xml);
 500     if (rc != pcmk_rc_ok) {
 501         return rc;
 502     }
 503 
 504     rc = pcmk__fence_validate(out, st, agent, id, params, timeout);
 505     pcmk__out_epilogue(out, xml, rc);
 506     return rc;
 507 }
 508 #endif

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