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. passive_test
  7. run_fence_failure_test
  8. run_fence_failure_rollover_test
  9. run_standard_test
  10. sanity_tests
  11. standard_dev_test
  12. mainloop_callback
  13. register_callback_helper
  14. test_async_fence_pass
  15. test_async_fence_custom_timeout
  16. test_async_fence_timeout
  17. test_async_monitor
  18. test_register_async_devices
  19. try_mainloop_connect
  20. iterate_mainloop_tests
  21. trigger_iterate_mainloop_tests
  22. test_shutdown
  23. mainloop_tests
  24. build_arg_context
  25. main

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

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