root/daemons/fenced/cts-fence-helper.c

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

DEFINITIONS

This source file includes following definitions.
  1. mode_cb
  2. mainloop_test_done
  3. dispatch_helper
  4. st_callback
  5. st_global_callback
  6. run_fence_failure_test
  7. run_fence_failure_rollover_test
  8. run_standard_test
  9. sanity_tests
  10. standard_dev_test
  11. mainloop_callback
  12. register_callback_helper
  13. test_async_fence_pass
  14. test_async_fence_custom_timeout
  15. test_async_fence_timeout
  16. test_async_monitor
  17. test_register_async_devices
  18. try_mainloop_connect
  19. iterate_mainloop_tests
  20. trigger_iterate_mainloop_tests
  21. test_shutdown
  22. mainloop_tests
  23. build_arg_context
  24. main

   1 /*
   2  * Copyright 2009-2025 the Pacemaker project contributors
   3  *
   4  * This source code is licensed under the GNU General Public License version 2
   5  * or later (GPLv2+) WITHOUT ANY WARRANTY.
   6  */
   7 
   8 #include <crm_internal.h>
   9 
  10 #include <sys/param.h>
  11 #include <stdio.h>
  12 #include <sys/time.h>
  13 #include <sys/types.h>
  14 #include <sys/stat.h>
  15 #include <unistd.h>
  16 #include <sys/utsname.h>
  17 
  18 #include <stdlib.h>
  19 #include <errno.h>
  20 #include <fcntl.h>
  21 
  22 #include <crm/crm.h>
  23 #include <crm/common/ipc.h>
  24 #include <crm/cluster/internal.h>
  25 
  26 #include <crm/stonith-ng.h>
  27 #include <crm/fencing/internal.h>
  28 #include <crm/common/agents.h>
  29 #include <crm/common/cmdline_internal.h>
  30 #include <crm/common/xml.h>
  31 
  32 #include <crm/common/mainloop.h>
  33 
  34 #define SUMMARY "cts-fence-helper - inject commands into the Pacemaker fencer and watch for events"
  35 
  36 static GMainLoop *mainloop = NULL;
  37 static crm_trigger_t *trig = NULL;
  38 static int mainloop_iter = 0;
  39 static pcmk__action_result_t result = PCMK__UNKNOWN_RESULT;
  40 
  41 typedef void (*mainloop_test_iteration_cb) (int check_event);
  42 
  43 #define MAINLOOP_DEFAULT_TIMEOUT 2
  44 
  45 enum test_modes {
  46     test_standard = 0,  // test using a specific developer environment
  47     test_api_sanity,    // sanity-test stonith client API using fence_dummy
  48     test_api_mainloop,  // sanity-test mainloop code with async responses
  49 };
  50 
  51 struct {
  52     enum test_modes mode;
  53 } options = {
  54     .mode = test_standard
  55 };
  56 
  57 static gboolean
  58 mode_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error) {
     /* [previous][next][first][last][top][bottom][index][help] */
  59     if (pcmk__str_any_of(option_name, "--mainloop_api_test", "-m", NULL)) {
  60         options.mode = test_api_mainloop;
  61     } else if (pcmk__str_any_of(option_name, "--api_test", "-t", NULL)) {
  62         options.mode = test_api_sanity;
  63     }
  64 
  65     return TRUE;
  66 }
  67 
  68 static GOptionEntry entries[] = {
  69     { "mainloop_api_test", 'm', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, mode_cb,
  70       NULL, NULL,
  71     },
  72 
  73     { "api_test", 't', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, mode_cb,
  74       NULL, NULL,
  75     },
  76 
  77     { NULL }
  78 };
  79 
  80 static stonith_t *st = NULL;
  81 static struct pollfd pollfd;
  82 static const int st_opts = st_opt_sync_call;
  83 static int expected_notifications = 0;
  84 static int verbose = 0;
  85 
  86 static void
  87 mainloop_test_done(const char *origin, bool pass)
     /* [previous][next][first][last][top][bottom][index][help] */
  88 {
  89     if (pass) {
  90         crm_info("SUCCESS - %s", origin);
  91         mainloop_iter++;
  92         mainloop_set_trigger(trig);
  93         result.execution_status = PCMK_EXEC_DONE;
  94         result.exit_status = CRM_EX_OK;
  95     } else {
  96         crm_err("FAILURE - %s (%d: %s)", origin, result.exit_status,
  97                 pcmk_exec_status_str(result.execution_status));
  98         crm_exit(CRM_EX_ERROR);
  99     }
 100 }
 101 
 102 
 103 static void
 104 dispatch_helper(int timeout)
     /* [previous][next][first][last][top][bottom][index][help] */
 105 {
 106     int rc;
 107 
 108     crm_debug("Looking for notification");
 109     pollfd.events = POLLIN;
 110     while (true) {
 111         rc = poll(&pollfd, 1, timeout); /* wait 10 minutes, -1 forever */
 112         if (rc > 0) {
 113             if (stonith__api_dispatch(st) != pcmk_rc_ok) {
 114                 break;
 115             }
 116         } else {
 117             break;
 118         }
 119     }
 120 }
 121 
 122 static void
 123 st_callback(stonith_t * st, stonith_event_t * e)
     /* [previous][next][first][last][top][bottom][index][help] */
 124 {
 125     char *desc = NULL;
 126 
 127     if (st->state == stonith_disconnected) {
 128         crm_exit(CRM_EX_DISCONNECT);
 129     }
 130 
 131     desc = stonith__event_description(e);
 132     crm_notice("%s", desc);
 133     free(desc);
 134 
 135     if (expected_notifications) {
 136         expected_notifications--;
 137     }
 138 }
 139 
 140 static void
 141 st_global_callback(stonith_t * stonith, stonith_callback_data_t * data)
     /* [previous][next][first][last][top][bottom][index][help] */
 142 {
 143     crm_notice("Call %d exited %d: %s (%s)",
 144                data->call_id, stonith__exit_status(data),
 145                stonith__execution_status(data),
 146                pcmk__s(stonith__exit_reason(data), "unspecified reason"));
 147 }
 148 
 149 #define single_test(cmd, str, num_notifications, expected_rc) \
 150 { \
 151     int rc = 0; \
 152     rc = cmd; \
 153     expected_notifications = 0;  \
 154     if (num_notifications) { \
 155         expected_notifications = num_notifications; \
 156         dispatch_helper(500);  \
 157     } \
 158     if (rc != expected_rc) { \
 159         crm_err("FAILURE - expected rc %d != %d(%s) for cmd - %s", expected_rc, rc, pcmk_strerror(rc), str); \
 160         crm_exit(CRM_EX_ERROR); \
 161     } else if (expected_notifications) { \
 162         crm_err("FAILURE - expected %d notifications, got only %d for cmd - %s", \
 163             num_notifications, num_notifications - expected_notifications, str); \
 164         crm_exit(CRM_EX_ERROR); \
 165     } else { \
 166         if (verbose) {                   \
 167             crm_info("SUCCESS - %s: %d", str, rc);    \
 168         } else {   \
 169             crm_debug("SUCCESS - %s: %d", str, rc);    \
 170         }                          \
 171     } \
 172 }\
 173 
 174 static void
 175 run_fence_failure_test(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 176 {
 177     stonith_key_value_t *params = NULL;
 178 
 179     params = stonith__key_value_add(params, PCMK_STONITH_HOST_MAP,
 180                                     "false_1_node1=1,2 false_1_node2=3,4");
 181     params = stonith__key_value_add(params, "mode", "fail");
 182 
 183     single_test(st->
 184                 cmds->register_device(st, st_opts, "test-id1", "stonith-ng", "fence_dummy", params),
 185                 "Register device1 for failure test", 1, 0);
 186 
 187     single_test(st->cmds->fence(st, st_opts, "false_1_node2", PCMK_ACTION_OFF,
 188                                 3, 0),
 189                 "Fence failure results off", 1, -ENODATA);
 190 
 191     single_test(st->cmds->fence(st, st_opts, "false_1_node2",
 192                                 PCMK_ACTION_REBOOT, 3, 0),
 193                 "Fence failure results reboot", 1, -ENODATA);
 194 
 195     single_test(st->cmds->remove_device(st, st_opts, "test-id1"),
 196                 "Remove device1 for failure test", 1, 0);
 197 
 198     stonith__key_value_freeall(params, true, true);
 199 }
 200 
 201 static void
 202 run_fence_failure_rollover_test(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 203 {
 204     stonith_key_value_t *params = NULL;
 205 
 206     params = stonith__key_value_add(params, PCMK_STONITH_HOST_MAP,
 207                                     "false_1_node1=1,2 false_1_node2=3,4");
 208     params = stonith__key_value_add(params, "mode", "fail");
 209 
 210     single_test(st->
 211                 cmds->register_device(st, st_opts, "test-id1", "stonith-ng", "fence_dummy", params),
 212                 "Register device1 for rollover test", 1, 0);
 213     stonith__key_value_freeall(params, true, true);
 214     params = NULL;
 215     params = stonith__key_value_add(params, PCMK_STONITH_HOST_MAP,
 216                                     "false_1_node1=1,2 false_1_node2=3,4");
 217     params = stonith__key_value_add(params, "mode", "pass");
 218 
 219     single_test(st->
 220                 cmds->register_device(st, st_opts, "test-id2", "stonith-ng", "fence_dummy", params),
 221                 "Register device2 for rollover test", 1, 0);
 222 
 223     single_test(st->cmds->fence(st, st_opts, "false_1_node2", PCMK_ACTION_OFF,
 224                                 3, 0),
 225                 "Fence rollover results off", 1, 0);
 226 
 227     /* Expect -ENODEV because fence_dummy requires 'on' to be executed on target */
 228     single_test(st->cmds->fence(st, st_opts, "false_1_node2", PCMK_ACTION_ON, 3,
 229                                 0),
 230                 "Fence rollover results on", 1, -ENODEV);
 231 
 232     single_test(st->cmds->remove_device(st, st_opts, "test-id1"),
 233                 "Remove device1 for rollover tests", 1, 0);
 234 
 235     single_test(st->cmds->remove_device(st, st_opts, "test-id2"),
 236                 "Remove device2 for rollover tests", 1, 0);
 237 
 238     stonith__key_value_freeall(params, true, true);
 239 }
 240 
 241 static void
 242 run_standard_test(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 243 {
 244     stonith_key_value_t *params = NULL;
 245 
 246     params = stonith__key_value_add(params, PCMK_STONITH_HOST_MAP,
 247                                     "false_1_node1=1,2 false_1_node2=3,4");
 248     params = stonith__key_value_add(params, "mode", "pass");
 249     params = stonith__key_value_add(params, "mock_dynamic_hosts",
 250                                     "false_1_node1 false_1_node2");
 251 
 252     single_test(st->
 253                 cmds->register_device(st, st_opts, "test-id", "stonith-ng", "fence_dummy", params),
 254                 "Register", 1, 0);
 255     stonith__key_value_freeall(params, true, true);
 256     params = NULL;
 257 
 258     single_test(st->cmds->list(st, st_opts, "test-id", NULL, 1),
 259                 PCMK_ACTION_LIST, 0, 0);
 260 
 261     single_test(st->cmds->monitor(st, st_opts, "test-id", 1), "Monitor", 0, 0);
 262 
 263     single_test(st->cmds->status(st, st_opts, "test-id", "false_1_node2", 1),
 264                 "Status false_1_node2", 0, 0);
 265 
 266     single_test(st->cmds->status(st, st_opts, "test-id", "false_1_node1", 1),
 267                 "Status false_1_node1", 0, 0);
 268 
 269     single_test(st->cmds->fence(st, st_opts, "unknown-host", PCMK_ACTION_OFF,
 270                                 1, 0),
 271                 "Fence unknown-host (expected failure)", 0, -ENODEV);
 272 
 273     single_test(st->cmds->fence(st, st_opts, "false_1_node1", PCMK_ACTION_OFF,
 274                                 1, 0),
 275                 "Fence false_1_node1", 1, 0);
 276 
 277     /* Expect -ENODEV because fence_dummy requires 'on' to be executed on target */
 278     single_test(st->cmds->fence(st, st_opts, "false_1_node1", PCMK_ACTION_ON, 1,
 279                                 0),
 280                 "Unfence false_1_node1", 1, -ENODEV);
 281 
 282     /* Confirm that an invalid level index is rejected */
 283     single_test(st->cmds->register_level(st, st_opts, "node1", 999, params),
 284                 "Attempt to register an invalid level index", 0, -EINVAL);
 285 
 286     single_test(st->cmds->remove_device(st, st_opts, "test-id"), "Remove test-id", 1, 0);
 287 
 288     stonith__key_value_freeall(params, true, true);
 289 }
 290 
 291 static void
 292 sanity_tests(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 293 {
 294     int rc = 0;
 295 
 296     rc = st->cmds->connect(st, crm_system_name, &pollfd.fd);
 297     if (rc != pcmk_ok) {
 298         stonith__api_free(st);
 299         crm_exit(CRM_EX_DISCONNECT);
 300     }
 301     st->cmds->register_notification(st, PCMK__VALUE_ST_NOTIFY_DISCONNECT,
 302                                     st_callback);
 303     st->cmds->register_notification(st, PCMK__VALUE_ST_NOTIFY_FENCE,
 304                                     st_callback);
 305     st->cmds->register_notification(st, STONITH_OP_DEVICE_ADD, st_callback);
 306     st->cmds->register_notification(st, STONITH_OP_DEVICE_DEL, st_callback);
 307     st->cmds->register_callback(st, 0, 120, st_opt_timeout_updates, NULL, "st_global_callback",
 308                                 st_global_callback);
 309 
 310     crm_info("Starting API Sanity Tests");
 311     run_standard_test();
 312     run_fence_failure_test();
 313     run_fence_failure_rollover_test();
 314     crm_info("Sanity Tests Passed");
 315 }
 316 
 317 static void
 318 standard_dev_test(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 319 {
 320     int rc = 0;
 321     char *tmp = NULL;
 322     stonith_key_value_t *params = NULL;
 323 
 324     rc = st->cmds->connect(st, crm_system_name, &pollfd.fd);
 325     if (rc != pcmk_ok) {
 326         stonith__api_free(st);
 327         crm_exit(CRM_EX_DISCONNECT);
 328     }
 329 
 330     params = stonith__key_value_add(params, PCMK_STONITH_HOST_MAP,
 331                                     "some-host=pcmk-7 true_1_node1=3,4");
 332 
 333     rc = st->cmds->register_device(st, st_opts, "test-id", "stonith-ng", "fence_xvm", params);
 334     crm_debug("Register: %d", rc);
 335 
 336     rc = st->cmds->list(st, st_opts, "test-id", &tmp, 10);
 337     crm_debug("List: %d output: %s", rc, tmp ? tmp : "<none>");
 338 
 339     rc = st->cmds->monitor(st, st_opts, "test-id", 10);
 340     crm_debug("Monitor: %d", rc);
 341 
 342     rc = st->cmds->status(st, st_opts, "test-id", "false_1_node2", 10);
 343     crm_debug("Status false_1_node2: %d", rc);
 344 
 345     rc = st->cmds->status(st, st_opts, "test-id", "false_1_node1", 10);
 346     crm_debug("Status false_1_node1: %d", rc);
 347 
 348     rc = st->cmds->fence(st, st_opts, "unknown-host", PCMK_ACTION_OFF, 60, 0);
 349     crm_debug("Fence unknown-host: %d", rc);
 350 
 351     rc = st->cmds->status(st, st_opts, "test-id", "false_1_node1", 10);
 352     crm_debug("Status false_1_node1: %d", rc);
 353 
 354     rc = st->cmds->fence(st, st_opts, "false_1_node1", PCMK_ACTION_OFF, 60, 0);
 355     crm_debug("Fence false_1_node1: %d", rc);
 356 
 357     rc = st->cmds->status(st, st_opts, "test-id", "false_1_node1", 10);
 358     crm_debug("Status false_1_node1: %d", rc);
 359 
 360     rc = st->cmds->fence(st, st_opts, "false_1_node1", PCMK_ACTION_ON, 10, 0);
 361     crm_debug("Unfence false_1_node1: %d", rc);
 362 
 363     rc = st->cmds->status(st, st_opts, "test-id", "false_1_node1", 10);
 364     crm_debug("Status false_1_node1: %d", rc);
 365 
 366     rc = st->cmds->fence(st, st_opts, "some-host", PCMK_ACTION_OFF, 10, 0);
 367     crm_debug("Fence alias: %d", rc);
 368 
 369     rc = st->cmds->status(st, st_opts, "test-id", "some-host", 10);
 370     crm_debug("Status alias: %d", rc);
 371 
 372     rc = st->cmds->fence(st, st_opts, "false_1_node1", PCMK_ACTION_ON, 10, 0);
 373     crm_debug("Unfence false_1_node1: %d", rc);
 374 
 375     rc = st->cmds->remove_device(st, st_opts, "test-id");
 376     crm_debug("Remove test-id: %d", rc);
 377 
 378     stonith__key_value_freeall(params, true, true);
 379 }
 380 
 381 static void
 382  iterate_mainloop_tests(gboolean event_ready);
 383 
 384 static void
 385 mainloop_callback(stonith_t * stonith, stonith_callback_data_t * data)
     /* [previous][next][first][last][top][bottom][index][help] */
 386 {
 387     pcmk__set_result(&result, stonith__exit_status(data),
 388                      stonith__execution_status(data),
 389                      stonith__exit_reason(data));
 390     iterate_mainloop_tests(TRUE);
 391 }
 392 
 393 static int
 394 register_callback_helper(int callid)
     /* [previous][next][first][last][top][bottom][index][help] */
 395 {
 396     return st->cmds->register_callback(st,
 397                                        callid,
 398                                        MAINLOOP_DEFAULT_TIMEOUT,
 399                                        st_opt_timeout_updates, NULL, "callback", mainloop_callback);
 400 }
 401 
 402 static void
 403 test_async_fence_pass(int check_event)
     /* [previous][next][first][last][top][bottom][index][help] */
 404 {
 405     int rc = 0;
 406 
 407     if (check_event) {
 408         mainloop_test_done(__func__, (result.exit_status == CRM_EX_OK));
 409         return;
 410     }
 411 
 412     rc = st->cmds->fence(st, 0, "true_1_node1", PCMK_ACTION_OFF,
 413                          MAINLOOP_DEFAULT_TIMEOUT, 0);
 414     if (rc < 0) {
 415         crm_err("fence failed with rc %d", rc);
 416         mainloop_test_done(__func__, false);
 417     }
 418     register_callback_helper(rc);
 419     /* wait for event */
 420 }
 421 
 422 #define CUSTOM_TIMEOUT_ADDITION 10
 423 static void
 424 test_async_fence_custom_timeout(int check_event)
     /* [previous][next][first][last][top][bottom][index][help] */
 425 {
 426     int rc = 0;
 427     static time_t begin = 0;
 428 
 429     if (check_event) {
 430         uint32_t diff = (time(NULL) - begin);
 431 
 432         if (result.execution_status != PCMK_EXEC_TIMEOUT) {
 433             mainloop_test_done(__func__, false);
 434         } else if (diff < CUSTOM_TIMEOUT_ADDITION + MAINLOOP_DEFAULT_TIMEOUT) {
 435             crm_err
 436                 ("Custom timeout test failed, callback expiration should be updated to %d, actual timeout was %d",
 437                  CUSTOM_TIMEOUT_ADDITION + MAINLOOP_DEFAULT_TIMEOUT, diff);
 438             mainloop_test_done(__func__, false);
 439         } else {
 440             mainloop_test_done(__func__, true);
 441         }
 442         return;
 443     }
 444     begin = time(NULL);
 445 
 446     rc = st->cmds->fence(st, 0, "custom_timeout_node1", PCMK_ACTION_OFF,
 447                          MAINLOOP_DEFAULT_TIMEOUT, 0);
 448     if (rc < 0) {
 449         crm_err("fence failed with rc %d", rc);
 450         mainloop_test_done(__func__, false);
 451     }
 452     register_callback_helper(rc);
 453     /* wait for event */
 454 }
 455 
 456 static void
 457 test_async_fence_timeout(int check_event)
     /* [previous][next][first][last][top][bottom][index][help] */
 458 {
 459     int rc = 0;
 460 
 461     if (check_event) {
 462         mainloop_test_done(__func__,
 463                            (result.execution_status == PCMK_EXEC_NO_FENCE_DEVICE));
 464         return;
 465     }
 466 
 467     rc = st->cmds->fence(st, 0, "false_1_node2", PCMK_ACTION_OFF,
 468                          MAINLOOP_DEFAULT_TIMEOUT, 0);
 469     if (rc < 0) {
 470         crm_err("fence failed with rc %d", rc);
 471         mainloop_test_done(__func__, false);
 472     }
 473     register_callback_helper(rc);
 474     /* wait for event */
 475 }
 476 
 477 static void
 478 test_async_monitor(int check_event)
     /* [previous][next][first][last][top][bottom][index][help] */
 479 {
 480     int rc = 0;
 481 
 482     if (check_event) {
 483         mainloop_test_done(__func__, (result.exit_status == CRM_EX_OK));
 484         return;
 485     }
 486 
 487     rc = st->cmds->monitor(st, 0, "false_1", MAINLOOP_DEFAULT_TIMEOUT);
 488     if (rc < 0) {
 489         crm_err("monitor failed with rc %d", rc);
 490         mainloop_test_done(__func__, false);
 491     }
 492 
 493     register_callback_helper(rc);
 494     /* wait for event */
 495 }
 496 
 497 static void
 498 test_register_async_devices(int check_event)
     /* [previous][next][first][last][top][bottom][index][help] */
 499 {
 500     char buf[16] = { 0, };
 501     stonith_key_value_t *params = NULL;
 502 
 503     params = stonith__key_value_add(params, PCMK_STONITH_HOST_MAP,
 504                                     "false_1_node1=1,2");
 505     params = stonith__key_value_add(params, "mode", "fail");
 506     st->cmds->register_device(st, st_opts, "false_1", "stonith-ng", "fence_dummy", params);
 507     stonith__key_value_freeall(params, true, true);
 508 
 509     params = NULL;
 510     params = stonith__key_value_add(params, PCMK_STONITH_HOST_MAP,
 511                                     "true_1_node1=1,2");
 512     params = stonith__key_value_add(params, "mode", "pass");
 513     st->cmds->register_device(st, st_opts, "true_1", "stonith-ng", "fence_dummy", params);
 514     stonith__key_value_freeall(params, true, true);
 515 
 516     params = NULL;
 517     params = stonith__key_value_add(params, PCMK_STONITH_HOST_MAP,
 518                                     "custom_timeout_node1=1,2");
 519     params = stonith__key_value_add(params, "mode", "fail");
 520     params = stonith__key_value_add(params, "delay", "1000");
 521     snprintf(buf, sizeof(buf) - 1, "%d", MAINLOOP_DEFAULT_TIMEOUT + CUSTOM_TIMEOUT_ADDITION);
 522     params = stonith__key_value_add(params, "pcmk_off_timeout", buf);
 523     st->cmds->register_device(st, st_opts, "false_custom_timeout", "stonith-ng", "fence_dummy",
 524                               params);
 525     stonith__key_value_freeall(params, true, true);
 526 
 527     mainloop_test_done(__func__, true);
 528 }
 529 
 530 static void
 531 try_mainloop_connect(int check_event)
     /* [previous][next][first][last][top][bottom][index][help] */
 532 {
 533     int rc = stonith__api_connect_retry(st, crm_system_name, 10);
 534 
 535     if (rc == pcmk_rc_ok) {
 536         mainloop_test_done(__func__, true);
 537         return;
 538     }
 539     crm_err("API CONNECTION FAILURE");
 540     mainloop_test_done(__func__, false);
 541 }
 542 
 543 static void
 544 iterate_mainloop_tests(gboolean event_ready)
     /* [previous][next][first][last][top][bottom][index][help] */
 545 {
 546     static mainloop_test_iteration_cb callbacks[] = {
 547         try_mainloop_connect,
 548         test_register_async_devices,
 549         test_async_monitor,
 550         test_async_fence_pass,
 551         test_async_fence_timeout,
 552         test_async_fence_custom_timeout,
 553     };
 554 
 555     if (mainloop_iter == (sizeof(callbacks) / sizeof(mainloop_test_iteration_cb))) {
 556         /* all tests ran, everything passed */
 557         crm_info("ALL MAINLOOP TESTS PASSED!");
 558         crm_exit(CRM_EX_OK);
 559     }
 560 
 561     callbacks[mainloop_iter] (event_ready);
 562 }
 563 
 564 static gboolean
 565 trigger_iterate_mainloop_tests(gpointer user_data)
     /* [previous][next][first][last][top][bottom][index][help] */
 566 {
 567     iterate_mainloop_tests(FALSE);
 568     return TRUE;
 569 }
 570 
 571 static void
 572 test_shutdown(int nsig)
     /* [previous][next][first][last][top][bottom][index][help] */
 573 {
 574     int rc = 0;
 575 
 576     if (st) {
 577         rc = st->cmds->disconnect(st);
 578         crm_info("Disconnect: %d", rc);
 579 
 580         crm_debug("Destroy");
 581         stonith__api_free(st);
 582     }
 583 
 584     if (rc) {
 585         crm_exit(CRM_EX_ERROR);
 586     }
 587 }
 588 
 589 static void
 590 mainloop_tests(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 591 {
 592     trig = mainloop_add_trigger(G_PRIORITY_HIGH, trigger_iterate_mainloop_tests, NULL);
 593     mainloop_set_trigger(trig);
 594     mainloop_add_signal(SIGTERM, test_shutdown);
 595 
 596     crm_info("Starting");
 597     mainloop = g_main_loop_new(NULL, FALSE);
 598     g_main_loop_run(mainloop);
 599 }
 600 
 601 static GOptionContext *
 602 build_arg_context(pcmk__common_args_t *args, GOptionGroup **group) {
     /* [previous][next][first][last][top][bottom][index][help] */
 603     GOptionContext *context = NULL;
 604 
 605     context = pcmk__build_arg_context(args, NULL, group, NULL);
 606     pcmk__add_main_args(context, entries);
 607     return context;
 608 }
 609 
 610 int
 611 main(int argc, char **argv)
     /* [previous][next][first][last][top][bottom][index][help] */
 612 {
 613     GError *error = NULL;
 614     crm_exit_t exit_code = CRM_EX_OK;
 615 
 616     pcmk__common_args_t *args = pcmk__new_common_args(SUMMARY);
 617     gchar **processed_args = pcmk__cmdline_preproc(argv, NULL);
 618     GOptionContext *context = build_arg_context(args, NULL);
 619 
 620     if (!g_option_context_parse_strv(context, &processed_args, &error)) {
 621         exit_code = CRM_EX_USAGE;
 622         goto done;
 623     }
 624 
 625     /* We have to use crm_log_init here to set up the logging because there's
 626      * different handling for daemons vs. command line programs, and
 627      * pcmk__cli_init_logging is set up to only handle the latter.
 628      */
 629     crm_log_init(NULL, LOG_INFO, TRUE, (verbose? TRUE : FALSE), argc, argv,
 630                  FALSE);
 631 
 632     for (int i = 0; i < args->verbosity; i++) {
 633         crm_bump_log_level(argc, argv);
 634     }
 635 
 636     st = stonith__api_new();
 637     if (st == NULL) {
 638         exit_code = CRM_EX_DISCONNECT;
 639         g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
 640                     "Could not connect to fencer: API memory allocation failed");
 641         goto done;
 642     }
 643 
 644     switch (options.mode) {
 645         case test_standard:
 646             standard_dev_test();
 647             break;
 648         case test_api_sanity:
 649             sanity_tests();
 650             break;
 651         case test_api_mainloop:
 652             mainloop_tests();
 653             break;
 654     }
 655 
 656     test_shutdown(0);
 657 
 658 done:
 659     g_strfreev(processed_args);
 660     pcmk__free_arg_context(context);
 661 
 662     pcmk__output_and_clear_error(&error, NULL);
 663     crm_exit(exit_code);
 664 }

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