root/lib/pacemaker/pcmk_output.c

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

DEFINITIONS

This source file includes following definitions.
  1. colocations_header
  2. colocations_xml_node
  3. do_locations_list_xml
  4. PCMK__OUTPUT_ARGS
  5. PCMK__OUTPUT_ARGS
  6. PCMK__OUTPUT_ARGS
  7. PCMK__OUTPUT_ARGS
  8. PCMK__OUTPUT_ARGS
  9. PCMK__OUTPUT_ARGS
  10. PCMK__OUTPUT_ARGS
  11. PCMK__OUTPUT_ARGS
  12. PCMK__OUTPUT_ARGS
  13. PCMK__OUTPUT_ARGS
  14. PCMK__OUTPUT_ARGS
  15. PCMK__OUTPUT_ARGS
  16. PCMK__OUTPUT_ARGS
  17. PCMK__OUTPUT_ARGS
  18. PCMK__OUTPUT_ARGS
  19. PCMK__OUTPUT_ARGS
  20. PCMK__OUTPUT_ARGS
  21. PCMK__OUTPUT_ARGS
  22. PCMK__OUTPUT_ARGS
  23. add_digest_xml
  24. PCMK__OUTPUT_ARGS
  25. PCMK__OUTPUT_ARGS
  26. PCMK__OUTPUT_ARGS
  27. PCMK__OUTPUT_ARGS
  28. PCMK__OUTPUT_ARGS
  29. PCMK__OUTPUT_ARGS
  30. PCMK__OUTPUT_ARGS
  31. PCMK__OUTPUT_ARGS
  32. PCMK__OUTPUT_ARGS
  33. PCMK__OUTPUT_ARGS
  34. PCMK__OUTPUT_ARGS
  35. PCMK__OUTPUT_ARGS
  36. PCMK__OUTPUT_ARGS
  37. PCMK__OUTPUT_ARGS
  38. PCMK__OUTPUT_ARGS
  39. PCMK__OUTPUT_ARGS
  40. PCMK__OUTPUT_ARGS
  41. PCMK__OUTPUT_ARGS
  42. PCMK__OUTPUT_ARGS
  43. PCMK__OUTPUT_ARGS
  44. PCMK__OUTPUT_ARGS
  45. PCMK__OUTPUT_ARGS
  46. pcmk__register_lib_messages

   1 /*
   2  * Copyright 2019-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/results.h>
  12 #include <crm/msg_xml.h>
  13 #include <crm/stonith-ng.h>
  14 #include <crm/fencing/internal.h>
  15 #include <crm/pengine/internal.h>
  16 #include <libxml/tree.h>
  17 #include <pacemaker-internal.h>
  18 
  19 static char *
  20 colocations_header(pe_resource_t *rsc, pcmk__colocation_t *cons,
     /* [previous][next][first][last][top][bottom][index][help] */
  21                    gboolean dependents) {
  22     char *score = NULL;
  23     char *retval = NULL;
  24 
  25     score = score2char(cons->score);
  26     if (cons->role_rh > RSC_ROLE_STARTED) {
  27             retval = crm_strdup_printf("%s (score=%s, %s role=%s, id=%s)",
  28                                        rsc->id, score, dependents ? "needs" : "with",
  29                                        role2text(cons->role_rh), cons->id);
  30     } else {
  31         retval = crm_strdup_printf("%s (score=%s, id=%s)",
  32                                    rsc->id, score, cons->id);
  33     }
  34 
  35     free(score);
  36     return retval;
  37 }
  38 
  39 static void
  40 colocations_xml_node(pcmk__output_t *out, pe_resource_t *rsc,
     /* [previous][next][first][last][top][bottom][index][help] */
  41                      pcmk__colocation_t *cons) {
  42     char *score = NULL;
  43     xmlNodePtr node = NULL;
  44 
  45     score = score2char(cons->score);
  46     node = pcmk__output_create_xml_node(out, XML_CONS_TAG_RSC_DEPEND,
  47                                         "id", cons->id,
  48                                         "rsc", cons->rsc_lh->id,
  49                                         "with-rsc", cons->rsc_rh->id,
  50                                         "score", score,
  51                                         NULL);
  52 
  53     if (cons->node_attribute) {
  54         xmlSetProp(node, (pcmkXmlStr) "node-attribute", (pcmkXmlStr) cons->node_attribute);
  55     }
  56 
  57     if (cons->role_lh != RSC_ROLE_UNKNOWN) {
  58         xmlSetProp(node, (pcmkXmlStr) "rsc-role", (pcmkXmlStr) role2text(cons->role_lh));
  59     }
  60 
  61     if (cons->role_rh != RSC_ROLE_UNKNOWN) {
  62         xmlSetProp(node, (pcmkXmlStr) "with-rsc-role", (pcmkXmlStr) role2text(cons->role_rh));
  63     }
  64 
  65     free(score);
  66 }
  67 
  68 static int
  69 do_locations_list_xml(pcmk__output_t *out, pe_resource_t *rsc, bool add_header)
     /* [previous][next][first][last][top][bottom][index][help] */
  70 {
  71     GList *lpc = NULL;
  72     GList *list = rsc->rsc_location;
  73     int rc = pcmk_rc_no_output;
  74 
  75     for (lpc = list; lpc != NULL; lpc = lpc->next) {
  76         pe__location_t *cons = lpc->data;
  77 
  78         GList *lpc2 = NULL;
  79 
  80         for (lpc2 = cons->node_list_rh; lpc2 != NULL; lpc2 = lpc2->next) {
  81             pe_node_t *node = (pe_node_t *) lpc2->data;
  82             char *score = score2char(node->weight);
  83 
  84             if (add_header) {
  85                 PCMK__OUTPUT_LIST_HEADER(out, FALSE, rc, "locations");
  86             }
  87 
  88             pcmk__output_create_xml_node(out, XML_CONS_TAG_RSC_LOCATION,
  89                                          "node", node->details->uname,
  90                                          "rsc", rsc->id,
  91                                          "id", cons->id,
  92                                          "score", score,
  93                                          NULL);
  94             free(score);
  95         }
  96     }
  97 
  98     if (add_header) {
  99         PCMK__OUTPUT_LIST_FOOTER(out, rc);
 100     }
 101 
 102     return rc;
 103 }
 104 
 105 PCMK__OUTPUT_ARGS("rsc-action-item", "const char *", "pe_resource_t *",
     /* [previous][next][first][last][top][bottom][index][help] */
 106                   "pe_node_t *", "pe_node_t *", "pe_action_t *",
 107                   "pe_action_t *")
 108 static int
 109 rsc_action_item(pcmk__output_t *out, va_list args)
 110 {
 111     const char *change = va_arg(args, const char *);
 112     pe_resource_t *rsc = va_arg(args, pe_resource_t *);
 113     pe_node_t *origin = va_arg(args, pe_node_t *);
 114     pe_node_t *destination = va_arg(args, pe_node_t *);
 115     pe_action_t *action = va_arg(args, pe_action_t *);
 116     pe_action_t *source = va_arg(args, pe_action_t *);
 117 
 118     int len = 0;
 119     char *reason = NULL;
 120     char *details = NULL;
 121     bool same_host = FALSE;
 122     bool same_role = FALSE;
 123     bool need_role = FALSE;
 124 
 125     static int rsc_width = 5;
 126     static int detail_width = 5;
 127 
 128     CRM_ASSERT(action);
 129     CRM_ASSERT(destination != NULL || origin != NULL);
 130 
 131     if(source == NULL) {
 132         source = action;
 133     }
 134 
 135     len = strlen(rsc->id);
 136     if(len > rsc_width) {
 137         rsc_width = len + 2;
 138     }
 139 
 140     if ((rsc->role > RSC_ROLE_STARTED)
 141         || (rsc->next_role > RSC_ROLE_UNPROMOTED)) {
 142         need_role = TRUE;
 143     }
 144 
 145     if(origin != NULL && destination != NULL && origin->details == destination->details) {
 146         same_host = TRUE;
 147     }
 148 
 149     if(rsc->role == rsc->next_role) {
 150         same_role = TRUE;
 151     }
 152 
 153     if (need_role && (origin == NULL)) {
 154         /* Starting and promoting a promotable clone instance */
 155         details = crm_strdup_printf("%s -> %s %s", role2text(rsc->role), role2text(rsc->next_role), destination->details->uname);
 156 
 157     } else if (origin == NULL) {
 158         /* Starting a resource */
 159         details = crm_strdup_printf("%s", destination->details->uname);
 160 
 161     } else if (need_role && (destination == NULL)) {
 162         /* Stopping a promotable clone instance */
 163         details = crm_strdup_printf("%s %s", role2text(rsc->role), origin->details->uname);
 164 
 165     } else if (destination == NULL) {
 166         /* Stopping a resource */
 167         details = crm_strdup_printf("%s", origin->details->uname);
 168 
 169     } else if (need_role && same_role && same_host) {
 170         /* Recovering, restarting or re-promoting a promotable clone instance */
 171         details = crm_strdup_printf("%s %s", role2text(rsc->role), origin->details->uname);
 172 
 173     } else if (same_role && same_host) {
 174         /* Recovering or Restarting a normal resource */
 175         details = crm_strdup_printf("%s", origin->details->uname);
 176 
 177     } else if (need_role && same_role) {
 178         /* Moving a promotable clone instance */
 179         details = crm_strdup_printf("%s -> %s %s", origin->details->uname, destination->details->uname, role2text(rsc->role));
 180 
 181     } else if (same_role) {
 182         /* Moving a normal resource */
 183         details = crm_strdup_printf("%s -> %s", origin->details->uname, destination->details->uname);
 184 
 185     } else if (same_host) {
 186         /* Promoting or demoting a promotable clone instance */
 187         details = crm_strdup_printf("%s -> %s %s", role2text(rsc->role), role2text(rsc->next_role), origin->details->uname);
 188 
 189     } else {
 190         /* Moving and promoting/demoting */
 191         details = crm_strdup_printf("%s %s -> %s %s", role2text(rsc->role), origin->details->uname, role2text(rsc->next_role), destination->details->uname);
 192     }
 193 
 194     len = strlen(details);
 195     if(len > detail_width) {
 196         detail_width = len;
 197     }
 198 
 199     if(source->reason && !pcmk_is_set(action->flags, pe_action_runnable)) {
 200         reason = crm_strdup_printf("due to %s (blocked)", source->reason);
 201 
 202     } else if(source->reason) {
 203         reason = crm_strdup_printf("due to %s", source->reason);
 204 
 205     } else if (!pcmk_is_set(action->flags, pe_action_runnable)) {
 206         reason = strdup("blocked");
 207 
 208     }
 209 
 210     out->list_item(out, NULL, "%-8s   %-*s   ( %*s )%s%s", change, rsc_width,
 211                    rsc->id, detail_width, details, reason ? "  " : "", reason ? reason : "");
 212 
 213     free(details);
 214     free(reason);
 215     return pcmk_rc_ok;
 216 }
 217 
 218 PCMK__OUTPUT_ARGS("rsc-action-item", "const char *", "pe_resource_t *",
     /* [previous][next][first][last][top][bottom][index][help] */
 219                   "pe_node_t *", "pe_node_t *", "pe_action_t *",
 220                   "pe_action_t *")
 221 static int
 222 rsc_action_item_xml(pcmk__output_t *out, va_list args)
 223 {
 224     const char *change = va_arg(args, const char *);
 225     pe_resource_t *rsc = va_arg(args, pe_resource_t *);
 226     pe_node_t *origin = va_arg(args, pe_node_t *);
 227     pe_node_t *destination = va_arg(args, pe_node_t *);
 228     pe_action_t *action = va_arg(args, pe_action_t *);
 229     pe_action_t *source = va_arg(args, pe_action_t *);
 230 
 231     char *change_str = NULL;
 232 
 233     bool same_host = FALSE;
 234     bool same_role = FALSE;
 235     bool need_role = FALSE;
 236     xmlNode *xml = NULL;
 237 
 238     CRM_ASSERT(action);
 239     CRM_ASSERT(destination != NULL || origin != NULL);
 240 
 241     if (source == NULL) {
 242         source = action;
 243     }
 244 
 245     if ((rsc->role > RSC_ROLE_STARTED)
 246         || (rsc->next_role > RSC_ROLE_UNPROMOTED)) {
 247         need_role = TRUE;
 248     }
 249 
 250     if(origin != NULL && destination != NULL && origin->details == destination->details) {
 251         same_host = TRUE;
 252     }
 253 
 254     if(rsc->role == rsc->next_role) {
 255         same_role = TRUE;
 256     }
 257 
 258     change_str = g_ascii_strdown(change, -1);
 259     xml = pcmk__output_create_xml_node(out, "rsc_action",
 260                                        "action", change_str,
 261                                        "resource", rsc->id,
 262                                        NULL);
 263     g_free(change_str);
 264 
 265     if (need_role && (origin == NULL)) {
 266         /* Starting and promoting a promotable clone instance */
 267         pcmk__xe_set_props(xml,
 268                            "role", role2text(rsc->role),
 269                            "next-role", role2text(rsc->next_role),
 270                            "dest", destination->details->uname,
 271                            NULL);
 272 
 273     } else if (origin == NULL) {
 274         /* Starting a resource */
 275         crm_xml_add(xml, "node", destination->details->uname);
 276 
 277     } else if (need_role && (destination == NULL)) {
 278         /* Stopping a promotable clone instance */
 279         pcmk__xe_set_props(xml,
 280                            "role", role2text(rsc->role),
 281                            "node", origin->details->uname,
 282                            NULL);
 283 
 284     } else if (destination == NULL) {
 285         /* Stopping a resource */
 286         crm_xml_add(xml, "node", origin->details->uname);
 287 
 288     } else if (need_role && same_role && same_host) {
 289         /* Recovering, restarting or re-promoting a promotable clone instance */
 290         pcmk__xe_set_props(xml,
 291                            "role", role2text(rsc->role),
 292                            "source", origin->details->uname,
 293                            NULL);
 294 
 295     } else if (same_role && same_host) {
 296         /* Recovering or Restarting a normal resource */
 297         crm_xml_add(xml, "source", origin->details->uname);
 298 
 299     } else if (need_role && same_role) {
 300         /* Moving a promotable clone instance */
 301         pcmk__xe_set_props(xml,
 302                            "source", origin->details->uname,
 303                            "dest", destination->details->uname,
 304                            "role", role2text(rsc->role),
 305                            NULL);
 306 
 307     } else if (same_role) {
 308         /* Moving a normal resource */
 309         pcmk__xe_set_props(xml,
 310                            "source", origin->details->uname,
 311                            "dest", destination->details->uname,
 312                            NULL);
 313 
 314     } else if (same_host) {
 315         /* Promoting or demoting a promotable clone instance */
 316         pcmk__xe_set_props(xml,
 317                            "role", role2text(rsc->role),
 318                            "next-role", role2text(rsc->next_role),
 319                            "source", origin->details->uname,
 320                            NULL);
 321 
 322     } else {
 323         /* Moving and promoting/demoting */
 324         pcmk__xe_set_props(xml,
 325                            "role", role2text(rsc->role),
 326                            "source", origin->details->uname,
 327                            "next-role", role2text(rsc->next_role),
 328                            "dest", destination->details->uname,
 329                            NULL);
 330     }
 331 
 332     if (source->reason && !pcmk_is_set(action->flags, pe_action_runnable)) {
 333         pcmk__xe_set_props(xml,
 334                            "reason", source->reason,
 335                            "blocked", "true",
 336                            NULL);
 337 
 338     } else if(source->reason) {
 339         crm_xml_add(xml, "reason", source->reason);
 340 
 341     } else if (!pcmk_is_set(action->flags, pe_action_runnable)) {
 342         crm_xml_add(xml, "blocked", "true");
 343 
 344     }
 345 
 346     return pcmk_rc_ok;
 347 }
 348 
 349 PCMK__OUTPUT_ARGS("rsc-is-colocated-with-list", "pe_resource_t *", "gboolean")
     /* [previous][next][first][last][top][bottom][index][help] */
 350 static int
 351 rsc_is_colocated_with_list(pcmk__output_t *out, va_list args) {
 352     pe_resource_t *rsc = va_arg(args, pe_resource_t *);
 353     gboolean recursive = va_arg(args, gboolean);
 354 
 355     int rc = pcmk_rc_no_output;
 356 
 357     if (pcmk_is_set(rsc->flags, pe_rsc_allocating)) {
 358         return rc;
 359     }
 360 
 361     pe__set_resource_flags(rsc, pe_rsc_allocating);
 362     for (GList *lpc = rsc->rsc_cons; lpc != NULL; lpc = lpc->next) {
 363         pcmk__colocation_t *cons = (pcmk__colocation_t *) lpc->data;
 364         char *hdr = NULL;
 365 
 366         PCMK__OUTPUT_LIST_HEADER(out, FALSE, rc, "Resources %s is colocated with", rsc->id);
 367 
 368         if (pcmk_is_set(cons->rsc_rh->flags, pe_rsc_allocating)) {
 369             out->list_item(out, NULL, "%s (id=%s - loop)", cons->rsc_rh->id, cons->id);
 370             continue;
 371         }
 372 
 373         hdr = colocations_header(cons->rsc_rh, cons, FALSE);
 374         out->list_item(out, NULL, "%s", hdr);
 375         free(hdr);
 376 
 377         /* Empty list header just for indentation of information about this resource. */
 378         out->begin_list(out, NULL, NULL, NULL);
 379 
 380         out->message(out, "locations-list", cons->rsc_rh);
 381         if (recursive) {
 382             out->message(out, "rsc-is-colocated-with-list", cons->rsc_rh, recursive);
 383         }
 384 
 385         out->end_list(out);
 386     }
 387 
 388     PCMK__OUTPUT_LIST_FOOTER(out, rc);
 389     return rc;
 390 }
 391 
 392 PCMK__OUTPUT_ARGS("rsc-is-colocated-with-list", "pe_resource_t *", "gboolean")
     /* [previous][next][first][last][top][bottom][index][help] */
 393 static int
 394 rsc_is_colocated_with_list_xml(pcmk__output_t *out, va_list args) {
 395     pe_resource_t *rsc = va_arg(args, pe_resource_t *);
 396     gboolean recursive = va_arg(args, gboolean);
 397 
 398     int rc = pcmk_rc_no_output;
 399 
 400     if (pcmk_is_set(rsc->flags, pe_rsc_allocating)) {
 401         return rc;
 402     }
 403 
 404     pe__set_resource_flags(rsc, pe_rsc_allocating);
 405     for (GList *lpc = rsc->rsc_cons; lpc != NULL; lpc = lpc->next) {
 406         pcmk__colocation_t *cons = (pcmk__colocation_t *) lpc->data;
 407 
 408         if (pcmk_is_set(cons->rsc_rh->flags, pe_rsc_allocating)) {
 409             colocations_xml_node(out, cons->rsc_rh, cons);
 410             continue;
 411         }
 412 
 413         colocations_xml_node(out, cons->rsc_rh, cons);
 414         do_locations_list_xml(out, cons->rsc_rh, false);
 415 
 416         if (recursive) {
 417             out->message(out, "rsc-is-colocated-with-list", cons->rsc_rh, recursive);
 418         }
 419     }
 420 
 421     return rc;
 422 }
 423 
 424 PCMK__OUTPUT_ARGS("rscs-colocated-with-list", "pe_resource_t *", "gboolean")
     /* [previous][next][first][last][top][bottom][index][help] */
 425 static int
 426 rscs_colocated_with_list(pcmk__output_t *out, va_list args) {
 427     pe_resource_t *rsc = va_arg(args, pe_resource_t *);
 428     gboolean recursive = va_arg(args, gboolean);
 429 
 430     int rc = pcmk_rc_no_output;
 431 
 432     if (pcmk_is_set(rsc->flags, pe_rsc_allocating)) {
 433         return rc;
 434     }
 435 
 436     pe__set_resource_flags(rsc, pe_rsc_allocating);
 437     for (GList *lpc = rsc->rsc_cons_lhs; lpc != NULL; lpc = lpc->next) {
 438         pcmk__colocation_t *cons = (pcmk__colocation_t *) lpc->data;
 439         char *hdr = NULL;
 440 
 441         PCMK__OUTPUT_LIST_HEADER(out, FALSE, rc, "Resources colocated with %s", rsc->id);
 442 
 443         if (pcmk_is_set(cons->rsc_lh->flags, pe_rsc_allocating)) {
 444             out->list_item(out, NULL, "%s (id=%s - loop)", cons->rsc_lh->id, cons->id);
 445             continue;
 446         }
 447 
 448         hdr = colocations_header(cons->rsc_lh, cons, TRUE);
 449         out->list_item(out, NULL, "%s", hdr);
 450         free(hdr);
 451 
 452         /* Empty list header just for indentation of information about this resource. */
 453         out->begin_list(out, NULL, NULL, NULL);
 454 
 455         out->message(out, "locations-list", cons->rsc_lh);
 456         if (recursive) {
 457             out->message(out, "rscs-colocated-with-list", cons->rsc_lh, recursive);
 458         }
 459 
 460         out->end_list(out);
 461     }
 462 
 463     PCMK__OUTPUT_LIST_FOOTER(out, rc);
 464     return rc;
 465 }
 466 
 467 PCMK__OUTPUT_ARGS("rscs-colocated-with-list", "pe_resource_t *", "gboolean")
     /* [previous][next][first][last][top][bottom][index][help] */
 468 static int
 469 rscs_colocated_with_list_xml(pcmk__output_t *out, va_list args) {
 470     pe_resource_t *rsc = va_arg(args, pe_resource_t *);
 471     gboolean recursive = va_arg(args, gboolean);
 472 
 473     int rc = pcmk_rc_no_output;
 474 
 475     if (pcmk_is_set(rsc->flags, pe_rsc_allocating)) {
 476         return rc;
 477     }
 478 
 479     pe__set_resource_flags(rsc, pe_rsc_allocating);
 480     for (GList *lpc = rsc->rsc_cons_lhs; lpc != NULL; lpc = lpc->next) {
 481         pcmk__colocation_t *cons = (pcmk__colocation_t *) lpc->data;
 482 
 483         if (pcmk_is_set(cons->rsc_lh->flags, pe_rsc_allocating)) {
 484             colocations_xml_node(out, cons->rsc_lh, cons);
 485             continue;
 486         }
 487 
 488         colocations_xml_node(out, cons->rsc_lh, cons);
 489         do_locations_list_xml(out, cons->rsc_lh, false);
 490 
 491         if (recursive) {
 492             out->message(out, "rscs-colocated-with-list", cons->rsc_lh, recursive);
 493         }
 494     }
 495 
 496     return rc;
 497 }
 498 
 499 PCMK__OUTPUT_ARGS("locations-list", "pe_resource_t *")
     /* [previous][next][first][last][top][bottom][index][help] */
 500 static int
 501 locations_list(pcmk__output_t *out, va_list args) {
 502     pe_resource_t *rsc = va_arg(args, pe_resource_t *);
 503 
 504     GList *lpc = NULL;
 505     GList *list = rsc->rsc_location;
 506     int rc = pcmk_rc_no_output;
 507 
 508     for (lpc = list; lpc != NULL; lpc = lpc->next) {
 509         pe__location_t *cons = lpc->data;
 510 
 511         GList *lpc2 = NULL;
 512 
 513         for (lpc2 = cons->node_list_rh; lpc2 != NULL; lpc2 = lpc2->next) {
 514             pe_node_t *node = (pe_node_t *) lpc2->data;
 515             char *score = score2char(node->weight);
 516 
 517             PCMK__OUTPUT_LIST_HEADER(out, FALSE, rc, "Locations");
 518             out->list_item(out, NULL, "Node %s (score=%s, id=%s, rsc=%s)",
 519                            node->details->uname, score, cons->id, rsc->id);
 520             free(score);
 521         }
 522     }
 523 
 524     PCMK__OUTPUT_LIST_FOOTER(out, rc);
 525     return rc;
 526 }
 527 
 528 PCMK__OUTPUT_ARGS("locations-list", "pe_resource_t *")
     /* [previous][next][first][last][top][bottom][index][help] */
 529 static int
 530 locations_list_xml(pcmk__output_t *out, va_list args) {
 531     pe_resource_t *rsc = va_arg(args, pe_resource_t *);
 532     return do_locations_list_xml(out, rsc, true);
 533 }
 534 
 535 PCMK__OUTPUT_ARGS("stacks-constraints", "pe_resource_t *", "pe_working_set_t *", "gboolean")
     /* [previous][next][first][last][top][bottom][index][help] */
 536 static int
 537 stacks_and_constraints(pcmk__output_t *out, va_list args) {
 538     pe_resource_t *rsc = va_arg(args, pe_resource_t *);
 539     pe_working_set_t *data_set = va_arg(args, pe_working_set_t *);
 540     gboolean recursive = va_arg(args, gboolean);
 541 
 542     xmlNodePtr cib_constraints = get_object_root(XML_CIB_TAG_CONSTRAINTS,
 543                                                  data_set->input);
 544 
 545     unpack_constraints(cib_constraints, data_set);
 546 
 547     // Constraints apply to group/clone, not member/instance
 548     rsc = uber_parent(rsc);
 549 
 550     out->message(out, "locations-list", rsc);
 551 
 552     pe__clear_resource_flags_on_all(data_set, pe_rsc_allocating);
 553     out->message(out, "rscs-colocated-with-list", rsc, recursive);
 554 
 555     pe__clear_resource_flags_on_all(data_set, pe_rsc_allocating);
 556     out->message(out, "rsc-is-colocated-with-list", rsc, recursive);
 557     return pcmk_rc_ok;
 558 }
 559 
 560 PCMK__OUTPUT_ARGS("stacks-constraints", "pe_resource_t *", "pe_working_set_t *", "gboolean")
     /* [previous][next][first][last][top][bottom][index][help] */
 561 static int
 562 stacks_and_constraints_xml(pcmk__output_t *out, va_list args) {
 563     pe_resource_t *rsc = va_arg(args, pe_resource_t *);
 564     pe_working_set_t *data_set = va_arg(args, pe_working_set_t *);
 565     gboolean recursive = va_arg(args, gboolean);
 566 
 567     xmlNodePtr cib_constraints = get_object_root(XML_CIB_TAG_CONSTRAINTS,
 568                                                  data_set->input);
 569 
 570     unpack_constraints(cib_constraints, data_set);
 571 
 572     // Constraints apply to group/clone, not member/instance
 573     rsc = uber_parent(rsc);
 574 
 575     pcmk__output_xml_create_parent(out, "constraints", NULL);
 576     do_locations_list_xml(out, rsc, false);
 577 
 578     pe__clear_resource_flags_on_all(data_set, pe_rsc_allocating);
 579     out->message(out, "rscs-colocated-with-list", rsc, recursive);
 580 
 581     pe__clear_resource_flags_on_all(data_set, pe_rsc_allocating);
 582     out->message(out, "rsc-is-colocated-with-list", rsc, recursive);
 583 
 584     pcmk__output_xml_pop_parent(out);
 585     return pcmk_rc_ok;
 586 }
 587 
 588 PCMK__OUTPUT_ARGS("health", "const char *", "const char *", "const char *", "const char *")
     /* [previous][next][first][last][top][bottom][index][help] */
 589 static int
 590 health_text(pcmk__output_t *out, va_list args)
 591 {
 592     const char *sys_from G_GNUC_UNUSED = va_arg(args, const char *);
 593     const char *host_from = va_arg(args, const char *);
 594     const char *fsa_state = va_arg(args, const char *);
 595     const char *result = va_arg(args, const char *);
 596 
 597     if (!out->is_quiet(out)) {
 598         return out->info(out, "Controller on %s in state %s: %s", crm_str(host_from),
 599                          crm_str(fsa_state), crm_str(result));
 600     } else if (fsa_state != NULL) {
 601         pcmk__formatted_printf(out, "%s\n", fsa_state);
 602         return pcmk_rc_ok;
 603     }
 604 
 605     return pcmk_rc_no_output;
 606 }
 607 
 608 PCMK__OUTPUT_ARGS("health", "const char *", "const char *", "const char *", "const char *")
     /* [previous][next][first][last][top][bottom][index][help] */
 609 static int
 610 health_xml(pcmk__output_t *out, va_list args)
 611 {
 612     const char *sys_from = va_arg(args, const char *);
 613     const char *host_from = va_arg(args, const char *);
 614     const char *fsa_state = va_arg(args, const char *);
 615     const char *result = va_arg(args, const char *);
 616 
 617     pcmk__output_create_xml_node(out, crm_str(sys_from),
 618                                  "node_name", crm_str(host_from),
 619                                  "state", crm_str(fsa_state),
 620                                  "result", crm_str(result),
 621                                  NULL);
 622     return pcmk_rc_ok;
 623 }
 624 
 625 PCMK__OUTPUT_ARGS("pacemakerd-health", "const char *", "const char *", "const char *")
     /* [previous][next][first][last][top][bottom][index][help] */
 626 static int
 627 pacemakerd_health_text(pcmk__output_t *out, va_list args)
 628 {
 629     const char *sys_from = va_arg(args, const char *);
 630     const char *state = va_arg(args, const char *);
 631     const char *last_updated = va_arg(args, const char *);
 632 
 633     if (!out->is_quiet(out)) {
 634         return out->info(out, "Status of %s: '%s' %s %s", crm_str(sys_from),
 635                          crm_str(state), (!pcmk__str_empty(last_updated))?
 636                          "last updated":"", crm_str(last_updated));
 637     } else {
 638         pcmk__formatted_printf(out, "%s\n", crm_str(state));
 639         return pcmk_rc_ok;
 640     }
 641 
 642     return pcmk_rc_no_output;
 643 }
 644 
 645 PCMK__OUTPUT_ARGS("pacemakerd-health", "const char *", "const char *", "const char *")
     /* [previous][next][first][last][top][bottom][index][help] */
 646 static int
 647 pacemakerd_health_xml(pcmk__output_t *out, va_list args)
 648 {
 649     const char *sys_from = va_arg(args, const char *);
 650     const char *state = va_arg(args, const char *);
 651     const char *last_updated = va_arg(args, const char *);
 652 
 653     pcmk__output_create_xml_node(out, crm_str(sys_from),
 654                                  "state", crm_str(state),
 655                                  "last_updated", crm_str(last_updated),
 656                                  NULL);
 657     return pcmk_rc_ok;
 658 }
 659 
 660 PCMK__OUTPUT_ARGS("dc", "const char *")
     /* [previous][next][first][last][top][bottom][index][help] */
 661 static int
 662 dc_text(pcmk__output_t *out, va_list args)
 663 {
 664     const char *dc = va_arg(args, const char *);
 665 
 666     if (!out->is_quiet(out)) {
 667         return out->info(out, "Designated Controller is: %s", crm_str(dc));
 668     } else if (dc != NULL) {
 669         pcmk__formatted_printf(out, "%s\n", dc);
 670         return pcmk_rc_ok;
 671     }
 672 
 673     return pcmk_rc_no_output;
 674 }
 675 
 676 PCMK__OUTPUT_ARGS("dc", "const char *")
     /* [previous][next][first][last][top][bottom][index][help] */
 677 static int
 678 dc_xml(pcmk__output_t *out, va_list args)
 679 {
 680     const char *dc = va_arg(args, const char *);
 681 
 682     pcmk__output_create_xml_node(out, "dc",
 683                                  "node_name", crm_str(dc),
 684                                  NULL);
 685     return pcmk_rc_ok;
 686 }
 687 
 688 PCMK__OUTPUT_ARGS("crmadmin-node", "const char *", "const char *", "const char *", "gboolean")
     /* [previous][next][first][last][top][bottom][index][help] */
 689 static int
 690 crmadmin_node_text(pcmk__output_t *out, va_list args)
 691 {
 692     const char *type = va_arg(args, const char *);
 693     const char *name = va_arg(args, const char *);
 694     const char *id = va_arg(args, const char *);
 695     gboolean BASH_EXPORT = va_arg(args, gboolean);
 696 
 697     if (out->is_quiet(out)) {
 698         pcmk__formatted_printf(out, "%s\n", crm_str(name));
 699         return pcmk_rc_ok;
 700     } else if (BASH_EXPORT) {
 701         return out->info(out, "export %s=%s", crm_str(name), crm_str(id));
 702     } else {
 703         return out->info(out, "%s node: %s (%s)", type ? type : "cluster",
 704                          crm_str(name), crm_str(id));
 705     }
 706 }
 707 
 708 PCMK__OUTPUT_ARGS("crmadmin-node", "const char *", "const char *", "const char *", "gboolean")
     /* [previous][next][first][last][top][bottom][index][help] */
 709 static int
 710 crmadmin_node_xml(pcmk__output_t *out, va_list args)
 711 {
 712     const char *type = va_arg(args, const char *);
 713     const char *name = va_arg(args, const char *);
 714     const char *id = va_arg(args, const char *);
 715 
 716     pcmk__output_create_xml_node(out, "node",
 717                                  "type", type ? type : "cluster",
 718                                  "name", crm_str(name),
 719                                  "id", crm_str(id),
 720                                  NULL);
 721     return pcmk_rc_ok;
 722 }
 723 
 724 PCMK__OUTPUT_ARGS("digests", "pe_resource_t *", "pe_node_t *", "const char *",
     /* [previous][next][first][last][top][bottom][index][help] */
 725                   "guint", "op_digest_cache_t *")
 726 static int
 727 digests_text(pcmk__output_t *out, va_list args)
 728 {
 729     pe_resource_t *rsc = va_arg(args, pe_resource_t *);
 730     pe_node_t *node = va_arg(args, pe_node_t *);
 731     const char *task = va_arg(args, const char *);
 732     guint interval_ms = va_arg(args, guint);
 733     op_digest_cache_t *digests = va_arg(args, op_digest_cache_t *);
 734 
 735     char *action_desc = NULL;
 736     const char *rsc_desc = "unknown resource";
 737     const char *node_desc = "unknown node";
 738 
 739     if (interval_ms != 0) {
 740         action_desc = crm_strdup_printf("%ums-interval %s action", interval_ms,
 741                                         ((task == NULL)? "unknown" : task));
 742     } else if (pcmk__str_eq(task, "monitor", pcmk__str_none)) {
 743         action_desc = strdup("probe action");
 744     } else {
 745         action_desc = crm_strdup_printf("%s action",
 746                                         ((task == NULL)? "unknown" : task));
 747     }
 748     if ((rsc != NULL) && (rsc->id != NULL)) {
 749         rsc_desc = rsc->id;
 750     }
 751     if ((node != NULL) && (node->details->uname != NULL)) {
 752         node_desc = node->details->uname;
 753     }
 754     out->begin_list(out, NULL, NULL, "Digests for %s %s on %s",
 755                     rsc_desc, action_desc, node_desc);
 756     free(action_desc);
 757 
 758     if (digests == NULL) {
 759         out->list_item(out, NULL, "none");
 760         out->end_list(out);
 761         return pcmk_rc_ok;
 762     }
 763     if (digests->digest_all_calc != NULL) {
 764         out->list_item(out, NULL, "%s (all parameters)",
 765                        digests->digest_all_calc);
 766     }
 767     if (digests->digest_secure_calc != NULL) {
 768         out->list_item(out, NULL, "%s (non-private parameters)",
 769                        digests->digest_secure_calc);
 770     }
 771     if (digests->digest_restart_calc != NULL) {
 772         out->list_item(out, NULL, "%s (non-reloadable parameters)",
 773                        digests->digest_restart_calc);
 774     }
 775     out->end_list(out);
 776     return pcmk_rc_ok;
 777 }
 778 
 779 static void
 780 add_digest_xml(xmlNode *parent, const char *type, const char *digest,
     /* [previous][next][first][last][top][bottom][index][help] */
 781                xmlNode *digest_source)
 782 {
 783     if (digest != NULL) {
 784         xmlNodePtr digest_xml = create_xml_node(parent, "digest");
 785 
 786         crm_xml_add(digest_xml, "type", ((type == NULL)? "unspecified" : type));
 787         crm_xml_add(digest_xml, "hash", digest);
 788         if (digest_source != NULL) {
 789             add_node_copy(digest_xml, digest_source);
 790         }
 791     }
 792 }
 793 
 794 PCMK__OUTPUT_ARGS("digests", "pe_resource_t *", "pe_node_t *", "const char *",
     /* [previous][next][first][last][top][bottom][index][help] */
 795                   "guint", "op_digest_cache_t *")
 796 static int
 797 digests_xml(pcmk__output_t *out, va_list args)
 798 {
 799     pe_resource_t *rsc = va_arg(args, pe_resource_t *);
 800     pe_node_t *node = va_arg(args, pe_node_t *);
 801     const char *task = va_arg(args, const char *);
 802     guint interval_ms = va_arg(args, guint);
 803     op_digest_cache_t *digests = va_arg(args, op_digest_cache_t *);
 804 
 805     char *interval_s = crm_strdup_printf("%ums", interval_ms);
 806     xmlNode *xml = NULL;
 807 
 808     xml = pcmk__output_create_xml_node(out, "digests",
 809                                        "resource", crm_str(rsc->id),
 810                                        "node", crm_str(node->details->uname),
 811                                        "task", crm_str(task),
 812                                        "interval", interval_s,
 813                                        NULL);
 814     free(interval_s);
 815     if (digests != NULL) {
 816         add_digest_xml(xml, "all", digests->digest_all_calc,
 817                        digests->params_all);
 818         add_digest_xml(xml, "nonprivate", digests->digest_secure_calc,
 819                        digests->params_secure);
 820         add_digest_xml(xml, "nonreloadable", digests->digest_restart_calc,
 821                        digests->params_restart);
 822     }
 823     return pcmk_rc_ok;
 824 }
 825 
 826 #define STOP_SANITY_ASSERT(lineno) do {                                 \
 827         if(current && current->details->unclean) {                      \
 828             /* It will be a pseudo op */                                \
 829         } else if(stop == NULL) {                                       \
 830             crm_err("%s:%d: No stop action exists for %s",              \
 831                     __func__, lineno, rsc->id);                         \
 832             CRM_ASSERT(stop != NULL);                                   \
 833         } else if (pcmk_is_set(stop->flags, pe_action_optional)) {      \
 834             crm_err("%s:%d: Action %s is still optional",               \
 835                     __func__, lineno, stop->uuid);                      \
 836             CRM_ASSERT(!pcmk_is_set(stop->flags, pe_action_optional));  \
 837         }                                                               \
 838     } while(0)
 839 
 840 PCMK__OUTPUT_ARGS("rsc-action", "pe_resource_t *", "pe_node_t *", "pe_node_t *",
     /* [previous][next][first][last][top][bottom][index][help] */
 841                   "gboolean")
 842 static int
 843 rsc_action_default(pcmk__output_t *out, va_list args)
 844 {
 845     pe_resource_t *rsc = va_arg(args, pe_resource_t *);
 846     pe_node_t *current = va_arg(args, pe_node_t *);
 847     pe_node_t *next = va_arg(args, pe_node_t *);
 848     gboolean moving = va_arg(args, gboolean);
 849 
 850     GList *possible_matches = NULL;
 851     char *key = NULL;
 852     int rc = pcmk_rc_no_output;
 853 
 854     pe_node_t *start_node = NULL;
 855     pe_action_t *start = NULL;
 856     pe_action_t *stop = NULL;
 857     pe_action_t *promote = NULL;
 858     pe_action_t *demote = NULL;
 859 
 860     if (!pcmk_is_set(rsc->flags, pe_rsc_managed)
 861         || (current == NULL && next == NULL)) {
 862         pe_rsc_info(rsc, "Leave   %s\t(%s%s)",
 863                     rsc->id, role2text(rsc->role),
 864                     !pcmk_is_set(rsc->flags, pe_rsc_managed)? " unmanaged" : "");
 865         return rc;
 866     }
 867 
 868     if (current != NULL && next != NULL && !pcmk__str_eq(current->details->id, next->details->id, pcmk__str_casei)) {
 869         moving = TRUE;
 870     }
 871 
 872     possible_matches = pe__resource_actions(rsc, next, RSC_START, FALSE);
 873     if (possible_matches) {
 874         start = possible_matches->data;
 875         g_list_free(possible_matches);
 876     }
 877 
 878     if ((start == NULL) || !pcmk_is_set(start->flags, pe_action_runnable)) {
 879         start_node = NULL;
 880     } else {
 881         start_node = current;
 882     }
 883     possible_matches = pe__resource_actions(rsc, start_node, RSC_STOP, FALSE);
 884     if (possible_matches) {
 885         stop = possible_matches->data;
 886         g_list_free(possible_matches);
 887     }
 888 
 889     possible_matches = pe__resource_actions(rsc, next, RSC_PROMOTE, FALSE);
 890     if (possible_matches) {
 891         promote = possible_matches->data;
 892         g_list_free(possible_matches);
 893     }
 894 
 895     possible_matches = pe__resource_actions(rsc, next, RSC_DEMOTE, FALSE);
 896     if (possible_matches) {
 897         demote = possible_matches->data;
 898         g_list_free(possible_matches);
 899     }
 900 
 901     if (rsc->role == rsc->next_role) {
 902         pe_action_t *migrate_op = NULL;
 903 
 904         possible_matches = pe__resource_actions(rsc, next, RSC_MIGRATED, FALSE);
 905         if (possible_matches) {
 906             migrate_op = possible_matches->data;
 907         }
 908 
 909         CRM_CHECK(next != NULL,);
 910         if (next == NULL) {
 911         } else if ((migrate_op != NULL) && (current != NULL)
 912                    && pcmk_is_set(migrate_op->flags, pe_action_runnable)) {
 913             rc = out->message(out, "rsc-action-item", "Migrate", rsc, current,
 914                               next, start, NULL);
 915 
 916         } else if (pcmk_is_set(rsc->flags, pe_rsc_reload)) {
 917             rc = out->message(out, "rsc-action-item", "Reload", rsc, current,
 918                               next, start, NULL);
 919 
 920         } else if (start == NULL || pcmk_is_set(start->flags, pe_action_optional)) {
 921             if ((demote != NULL) && (promote != NULL)
 922                 && !pcmk_is_set(demote->flags, pe_action_optional)
 923                 && !pcmk_is_set(promote->flags, pe_action_optional)) {
 924                 rc = out->message(out, "rsc-action-item", "Re-promote", rsc,
 925                                   current, next, promote, demote);
 926             } else {
 927                 pe_rsc_info(rsc, "Leave   %s\t(%s %s)", rsc->id,
 928                             role2text(rsc->role), next->details->uname);
 929             }
 930 
 931         } else if (!pcmk_is_set(start->flags, pe_action_runnable)) {
 932             rc = out->message(out, "rsc-action-item", "Stop", rsc, current,
 933                               NULL, stop, (stop && stop->reason)? stop : start);
 934             STOP_SANITY_ASSERT(__LINE__);
 935 
 936         } else if (moving && current) {
 937             rc = out->message(out, "rsc-action-item", pcmk_is_set(rsc->flags, pe_rsc_failed)? "Recover" : "Move",
 938                               rsc, current, next, stop, NULL);
 939 
 940         } else if (pcmk_is_set(rsc->flags, pe_rsc_failed)) {
 941             rc = out->message(out, "rsc-action-item", "Recover", rsc, current,
 942                               NULL, stop, NULL);
 943             STOP_SANITY_ASSERT(__LINE__);
 944 
 945         } else {
 946             rc = out->message(out, "rsc-action-item", "Restart", rsc, current,
 947                               next, start, NULL);
 948             /* STOP_SANITY_ASSERT(__LINE__); False positive for migrate-fail-7 */
 949         }
 950 
 951         g_list_free(possible_matches);
 952         return rc;
 953     }
 954 
 955     if(stop
 956        && (rsc->next_role == RSC_ROLE_STOPPED
 957            || (start && !pcmk_is_set(start->flags, pe_action_runnable)))) {
 958 
 959         GList *gIter = NULL;
 960 
 961         key = stop_key(rsc);
 962         for (gIter = rsc->running_on; gIter != NULL; gIter = gIter->next) {
 963             pe_node_t *node = (pe_node_t *) gIter->data;
 964             pe_action_t *stop_op = NULL;
 965 
 966             possible_matches = find_actions(rsc->actions, key, node);
 967             if (possible_matches) {
 968                 stop_op = possible_matches->data;
 969                 g_list_free(possible_matches);
 970             }
 971 
 972             if (stop_op && (stop_op->flags & pe_action_runnable)) {
 973                 STOP_SANITY_ASSERT(__LINE__);
 974             }
 975 
 976             if (out->message(out, "rsc-action-item", "Stop", rsc, node, NULL,
 977                              stop_op, (stop_op && stop_op->reason)? stop_op : start) == pcmk_rc_ok) {
 978                 rc = pcmk_rc_ok;
 979             }
 980         }
 981 
 982         free(key);
 983 
 984     } else if ((stop != NULL)
 985                && pcmk_all_flags_set(rsc->flags, pe_rsc_failed|pe_rsc_stop)) {
 986         /* 'stop' may be NULL if the failure was ignored */
 987         rc = out->message(out, "rsc-action-item", "Recover", rsc, current,
 988                           next, stop, start);
 989         STOP_SANITY_ASSERT(__LINE__);
 990 
 991     } else if (moving) {
 992         rc = out->message(out, "rsc-action-item", "Move", rsc, current, next,
 993                           stop, NULL);
 994         STOP_SANITY_ASSERT(__LINE__);
 995 
 996     } else if (pcmk_is_set(rsc->flags, pe_rsc_reload)) {
 997         rc = out->message(out, "rsc-action-item", "Reload", rsc, current, next,
 998                           start, NULL);
 999 
1000     } else if (stop != NULL && !pcmk_is_set(stop->flags, pe_action_optional)) {
1001         rc = out->message(out, "rsc-action-item", "Restart", rsc, current,
1002                           next, start, NULL);
1003         STOP_SANITY_ASSERT(__LINE__);
1004 
1005     } else if (rsc->role == RSC_ROLE_PROMOTED) {
1006         CRM_LOG_ASSERT(current != NULL);
1007         rc = out->message(out, "rsc-action-item", "Demote", rsc, current,
1008                           next, demote, NULL);
1009 
1010     } else if (rsc->next_role == RSC_ROLE_PROMOTED) {
1011         CRM_LOG_ASSERT(next);
1012         rc = out->message(out, "rsc-action-item", "Promote", rsc, current,
1013                           next, promote, NULL);
1014 
1015     } else if (rsc->role == RSC_ROLE_STOPPED && rsc->next_role > RSC_ROLE_STOPPED) {
1016         rc = out->message(out, "rsc-action-item", "Start", rsc, current, next,
1017                           start, NULL);
1018     }
1019 
1020     return rc;
1021 }
1022 
1023 PCMK__OUTPUT_ARGS("node-action", "char *", "char *", "char *")
     /* [previous][next][first][last][top][bottom][index][help] */
1024 static int
1025 node_action(pcmk__output_t *out, va_list args)
1026 {
1027     char *task = va_arg(args, char *);
1028     char *node_name = va_arg(args, char *);
1029     char *reason = va_arg(args, char *);
1030 
1031     if (task == NULL) {
1032         return pcmk_rc_no_output;
1033     } else if (reason) {
1034         out->list_item(out, NULL, "%s %s '%s'", task, node_name, reason);
1035     } else {
1036         crm_notice(" * %s %s\n", task, node_name);
1037     }
1038 
1039     return pcmk_rc_ok;
1040 }
1041 
1042 PCMK__OUTPUT_ARGS("node-action", "char *", "char *", "char *")
     /* [previous][next][first][last][top][bottom][index][help] */
1043 static int
1044 node_action_xml(pcmk__output_t *out, va_list args)
1045 {
1046     char *task = va_arg(args, char *);
1047     char *node_name = va_arg(args, char *);
1048     char *reason = va_arg(args, char *);
1049 
1050     if (task == NULL) {
1051         return pcmk_rc_no_output;
1052     } else if (reason) {
1053         pcmk__output_create_xml_node(out, "node_action",
1054                                      "task", task,
1055                                      "node", node_name,
1056                                      "reason", reason,
1057                                      NULL);
1058     } else {
1059         crm_notice(" * %s %s\n", task, node_name);
1060     }
1061 
1062     return pcmk_rc_ok;
1063 }
1064 
1065 PCMK__OUTPUT_ARGS("inject-cluster-action", "const char *", "const char *", "xmlNodePtr")
     /* [previous][next][first][last][top][bottom][index][help] */
1066 static int
1067 inject_cluster_action(pcmk__output_t *out, va_list args)
1068 {
1069     const char *node = va_arg(args, const char *);
1070     const char *task = va_arg(args, const char *);
1071     xmlNodePtr rsc = va_arg(args, xmlNodePtr);
1072 
1073     if (out->is_quiet(out)) {
1074         return pcmk_rc_no_output;
1075     }
1076 
1077     if(rsc) {
1078         out->list_item(out, NULL, "Cluster action:  %s for %s on %s", task, ID(rsc), node);
1079     } else {
1080         out->list_item(out, NULL, "Cluster action:  %s on %s", task, node);
1081     }
1082 
1083     return pcmk_rc_ok;
1084 }
1085 
1086 PCMK__OUTPUT_ARGS("inject-cluster-action", "const char *", "const char *", "xmlNodePtr")
     /* [previous][next][first][last][top][bottom][index][help] */
1087 static int
1088 inject_cluster_action_xml(pcmk__output_t *out, va_list args)
1089 {
1090     const char *node = va_arg(args, const char *);
1091     const char *task = va_arg(args, const char *);
1092     xmlNodePtr rsc = va_arg(args, xmlNodePtr);
1093 
1094     xmlNodePtr xml_node = NULL;
1095 
1096     if (out->is_quiet(out)) {
1097         return pcmk_rc_no_output;
1098     }
1099 
1100     xml_node = pcmk__output_create_xml_node(out, "cluster_action",
1101                                             "task", task,
1102                                             "node", node,
1103                                             NULL);
1104 
1105     if (rsc) {
1106         crm_xml_add(xml_node, "id", ID(rsc));
1107     }
1108 
1109     return pcmk_rc_ok;
1110 }
1111 
1112 PCMK__OUTPUT_ARGS("inject-fencing-action", "char *", "const char *")
     /* [previous][next][first][last][top][bottom][index][help] */
1113 static int
1114 inject_fencing_action(pcmk__output_t *out, va_list args)
1115 {
1116     char *target = va_arg(args, char *);
1117     const char *op = va_arg(args, const char *);
1118 
1119     if (out->is_quiet(out)) {
1120         return pcmk_rc_no_output;
1121     }
1122 
1123     out->list_item(out, NULL, "Fencing %s (%s)", target, op);
1124     return pcmk_rc_ok;
1125 }
1126 
1127 PCMK__OUTPUT_ARGS("inject-fencing-action", "char *", "const char *")
     /* [previous][next][first][last][top][bottom][index][help] */
1128 static int
1129 inject_fencing_action_xml(pcmk__output_t *out, va_list args)
1130 {
1131     char *target = va_arg(args, char *);
1132     const char *op = va_arg(args, const char *);
1133 
1134     if (out->is_quiet(out)) {
1135         return pcmk_rc_no_output;
1136     }
1137 
1138     pcmk__output_create_xml_node(out, "fencing_action",
1139                                  "target", target,
1140                                  "op", op,
1141                                  NULL);
1142     return pcmk_rc_ok;
1143 }
1144 
1145 PCMK__OUTPUT_ARGS("inject-attr", "const char *", "const char *", "xmlNodePtr")
     /* [previous][next][first][last][top][bottom][index][help] */
1146 static int
1147 inject_attr(pcmk__output_t *out, va_list args)
1148 {
1149     const char *name = va_arg(args, const char *);
1150     const char *value = va_arg(args, const char *);
1151     xmlNodePtr cib_node = va_arg(args, xmlNodePtr);
1152 
1153     xmlChar *node_path = NULL;
1154 
1155     if (out->is_quiet(out)) {
1156         return pcmk_rc_no_output;
1157     }
1158 
1159     node_path = xmlGetNodePath(cib_node);
1160 
1161     out->list_item(out, NULL, "Injecting attribute %s=%s into %s '%s'",
1162                    name, value, node_path, ID(cib_node));
1163 
1164     free(node_path);
1165     return pcmk_rc_ok;
1166 }
1167 
1168 PCMK__OUTPUT_ARGS("inject-attr", "const char *", "const char *", "xmlNodePtr")
     /* [previous][next][first][last][top][bottom][index][help] */
1169 static int
1170 inject_attr_xml(pcmk__output_t *out, va_list args)
1171 {
1172     const char *name = va_arg(args, const char *);
1173     const char *value = va_arg(args, const char *);
1174     xmlNodePtr cib_node = va_arg(args, xmlNodePtr);
1175 
1176     xmlChar *node_path = NULL;
1177 
1178     if (out->is_quiet(out)) {
1179         return pcmk_rc_no_output;
1180     }
1181 
1182     node_path = xmlGetNodePath(cib_node);
1183 
1184     pcmk__output_create_xml_node(out, "inject_attr",
1185                                  "name", name,
1186                                  "value", value,
1187                                  "node_path", node_path,
1188                                  "cib_node", ID(cib_node),
1189                                  NULL);
1190     free(node_path);
1191     return pcmk_rc_ok;
1192 }
1193 
1194 PCMK__OUTPUT_ARGS("inject-spec", "char *")
     /* [previous][next][first][last][top][bottom][index][help] */
1195 static int
1196 inject_spec(pcmk__output_t *out, va_list args)
1197 {
1198     char *spec = va_arg(args, char *);
1199 
1200     if (out->is_quiet(out)) {
1201         return pcmk_rc_no_output;
1202     }
1203 
1204     out->list_item(out, NULL, "Injecting %s into the configuration", spec);
1205     return pcmk_rc_ok;
1206 }
1207 
1208 PCMK__OUTPUT_ARGS("inject-spec", "char *")
     /* [previous][next][first][last][top][bottom][index][help] */
1209 static int
1210 inject_spec_xml(pcmk__output_t *out, va_list args)
1211 {
1212     char *spec = va_arg(args, char *);
1213 
1214     if (out->is_quiet(out)) {
1215         return pcmk_rc_no_output;
1216     }
1217 
1218     pcmk__output_create_xml_node(out, "inject_spec",
1219                                  "spec", spec,
1220                                  NULL);
1221     return pcmk_rc_ok;
1222 }
1223 
1224 PCMK__OUTPUT_ARGS("inject-modify-config", "const char *", "const char *")
     /* [previous][next][first][last][top][bottom][index][help] */
1225 static int
1226 inject_modify_config(pcmk__output_t *out, va_list args)
1227 {
1228     const char *quorum = va_arg(args, const char *);
1229     const char *watchdog = va_arg(args, const char *);
1230 
1231     if (out->is_quiet(out)) {
1232         return pcmk_rc_no_output;
1233     }
1234 
1235     out->begin_list(out, NULL, NULL, "Performing Requested Modifications");
1236 
1237     if (quorum) {
1238         out->list_item(out, NULL, "Setting quorum: %s", quorum);
1239     }
1240 
1241     if (watchdog) {
1242         out->list_item(out, NULL, "Setting watchdog: %s", watchdog);
1243     }
1244 
1245     return pcmk_rc_ok;
1246 }
1247 
1248 PCMK__OUTPUT_ARGS("inject-modify-config", "const char *", "const char *")
     /* [previous][next][first][last][top][bottom][index][help] */
1249 static int
1250 inject_modify_config_xml(pcmk__output_t *out, va_list args)
1251 {
1252     const char *quorum = va_arg(args, const char *);
1253     const char *watchdog = va_arg(args, const char *);
1254 
1255     xmlNodePtr node = NULL;
1256 
1257     if (out->is_quiet(out)) {
1258         return pcmk_rc_no_output;
1259     }
1260 
1261     node = pcmk__output_xml_create_parent(out, "modifications", NULL);
1262 
1263     if (quorum) {
1264         crm_xml_add(node, "quorum", quorum);
1265     }
1266 
1267     if (watchdog) {
1268         crm_xml_add(node, "watchdog", watchdog);
1269     }
1270 
1271     return pcmk_rc_ok;
1272 }
1273 
1274 PCMK__OUTPUT_ARGS("inject-modify-node", "const char *", "char *")
     /* [previous][next][first][last][top][bottom][index][help] */
1275 static int
1276 inject_modify_node(pcmk__output_t *out, va_list args)
1277 {
1278     const char *action = va_arg(args, const char *);
1279     char *node = va_arg(args, char *);
1280 
1281     if (out->is_quiet(out)) {
1282         return pcmk_rc_no_output;
1283     }
1284 
1285     if (pcmk__str_eq(action, "Online", pcmk__str_none)) {
1286         out->list_item(out, NULL, "Bringing node %s online", node);
1287         return pcmk_rc_ok;
1288     } else if (pcmk__str_eq(action, "Offline", pcmk__str_none)) {
1289         out->list_item(out, NULL, "Taking node %s offline", node);
1290         return pcmk_rc_ok;
1291     } else if (pcmk__str_eq(action, "Failing", pcmk__str_none)) {
1292         out->list_item(out, NULL, "Failing node %s", node);
1293         return pcmk_rc_ok;
1294     }
1295 
1296     return pcmk_rc_no_output;
1297 }
1298 
1299 PCMK__OUTPUT_ARGS("inject-modify-node", "const char *", "char *")
     /* [previous][next][first][last][top][bottom][index][help] */
1300 static int
1301 inject_modify_node_xml(pcmk__output_t *out, va_list args)
1302 {
1303     const char *action = va_arg(args, const char *);
1304     char *node = va_arg(args, char *);
1305 
1306     if (out->is_quiet(out)) {
1307         return pcmk_rc_no_output;
1308     }
1309 
1310     pcmk__output_create_xml_node(out, "modify_node",
1311                                  "action", action,
1312                                  "node", node,
1313                                  NULL);
1314     return pcmk_rc_ok;
1315 }
1316 
1317 PCMK__OUTPUT_ARGS("inject-modify-ticket", "const char *", "char *")
     /* [previous][next][first][last][top][bottom][index][help] */
1318 static int
1319 inject_modify_ticket(pcmk__output_t *out, va_list args)
1320 {
1321     const char *action = va_arg(args, const char *);
1322     char *ticket = va_arg(args, char *);
1323 
1324     if (out->is_quiet(out)) {
1325         return pcmk_rc_no_output;
1326     }
1327 
1328     if (pcmk__str_eq(action, "Standby", pcmk__str_none)) {
1329         out->list_item(out, NULL, "Making ticket %s standby", ticket);
1330     } else {
1331         out->list_item(out, NULL, "%s ticket %s", action, ticket);
1332     }
1333 
1334     return pcmk_rc_ok;
1335 }
1336 
1337 PCMK__OUTPUT_ARGS("inject-modify-ticket", "const char *", "char *")
     /* [previous][next][first][last][top][bottom][index][help] */
1338 static int
1339 inject_modify_ticket_xml(pcmk__output_t *out, va_list args)
1340 {
1341     const char *action = va_arg(args, const char *);
1342     char *ticket = va_arg(args, char *);
1343 
1344     if (out->is_quiet(out)) {
1345         return pcmk_rc_no_output;
1346     }
1347 
1348     pcmk__output_create_xml_node(out, "modify_ticket",
1349                                  "action", action,
1350                                  "ticket", ticket,
1351                                  NULL);
1352     return pcmk_rc_ok;
1353 }
1354 
1355 PCMK__OUTPUT_ARGS("inject-pseudo-action", "const char *", "const char *")
     /* [previous][next][first][last][top][bottom][index][help] */
1356 static int
1357 inject_pseudo_action(pcmk__output_t *out, va_list args)
1358 {
1359     const char *node = va_arg(args, const char *);
1360     const char *task = va_arg(args, const char *);
1361 
1362     if (out->is_quiet(out)) {
1363         return pcmk_rc_no_output;
1364     }
1365 
1366     out->list_item(out, NULL, "Pseudo action:   %s%s%s", task, node ? " on " : "",
1367                    node ? node : "");
1368     return pcmk_rc_ok;
1369 }
1370 
1371 PCMK__OUTPUT_ARGS("inject-pseudo-action", "const char *", "const char *")
     /* [previous][next][first][last][top][bottom][index][help] */
1372 static int
1373 inject_pseudo_action_xml(pcmk__output_t *out, va_list args)
1374 {
1375     const char *node = va_arg(args, const char *);
1376     const char *task = va_arg(args, const char *);
1377 
1378     xmlNodePtr xml_node = NULL;
1379 
1380     if (out->is_quiet(out)) {
1381         return pcmk_rc_no_output;
1382     }
1383 
1384     xml_node = pcmk__output_create_xml_node(out, "pseudo_action",
1385                                             "task", task,
1386                                             NULL);
1387     if (node) {
1388         crm_xml_add(xml_node, "node", node);
1389     }
1390 
1391     return pcmk_rc_ok;
1392 }
1393 
1394 PCMK__OUTPUT_ARGS("inject-rsc-action", "const char *", "const char *", "char *", "guint")
     /* [previous][next][first][last][top][bottom][index][help] */
1395 static int
1396 inject_rsc_action(pcmk__output_t *out, va_list args)
1397 {
1398     const char *rsc = va_arg(args, const char *);
1399     const char *operation = va_arg(args, const char *);
1400     char *node = va_arg(args, char *);
1401     guint interval_ms = va_arg(args, guint);
1402 
1403     if (out->is_quiet(out)) {
1404         return pcmk_rc_no_output;
1405     }
1406 
1407     if (interval_ms) {
1408         out->list_item(out, NULL, "Resource action: %-15s %s=%u on %s",
1409                        rsc, operation, interval_ms, node);
1410     } else {
1411         out->list_item(out, NULL, "Resource action: %-15s %s on %s",
1412                        rsc, operation, node);
1413     }
1414 
1415     return pcmk_rc_ok;
1416 }
1417 
1418 PCMK__OUTPUT_ARGS("inject-rsc-action", "const char *", "const char *", "char *", "guint")
     /* [previous][next][first][last][top][bottom][index][help] */
1419 static int
1420 inject_rsc_action_xml(pcmk__output_t *out, va_list args)
1421 {
1422     const char *rsc = va_arg(args, const char *);
1423     const char *operation = va_arg(args, const char *);
1424     char *node = va_arg(args, char *);
1425     guint interval_ms = va_arg(args, guint);
1426 
1427     xmlNodePtr xml_node = NULL;
1428 
1429     if (out->is_quiet(out)) {
1430         return pcmk_rc_no_output;
1431     }
1432 
1433     xml_node = pcmk__output_create_xml_node(out, "rsc_action",
1434                                             "resource", rsc,
1435                                             "op", operation,
1436                                             "node", node,
1437                                             NULL);
1438 
1439     if (interval_ms) {
1440         char *interval_s = pcmk__itoa(interval_ms);
1441 
1442         crm_xml_add(xml_node, "interval", interval_s);
1443         free(interval_s);
1444     }
1445 
1446     return pcmk_rc_ok;
1447 }
1448 
1449 static pcmk__message_entry_t fmt_functions[] = {
1450     { "crmadmin-node", "default", crmadmin_node_text },
1451     { "crmadmin-node", "xml", crmadmin_node_xml },
1452     { "dc", "default", dc_text },
1453     { "dc", "xml", dc_xml },
1454     { "digests", "default", digests_text },
1455     { "digests", "xml", digests_xml },
1456     { "health", "default", health_text },
1457     { "health", "xml", health_xml },
1458     { "inject-attr", "default", inject_attr },
1459     { "inject-attr", "xml", inject_attr_xml },
1460     { "inject-cluster-action", "default", inject_cluster_action },
1461     { "inject-cluster-action", "xml", inject_cluster_action_xml },
1462     { "inject-fencing-action", "default", inject_fencing_action },
1463     { "inject-fencing-action", "xml", inject_fencing_action_xml },
1464     { "inject-modify-config", "default", inject_modify_config },
1465     { "inject-modify-config", "xml", inject_modify_config_xml },
1466     { "inject-modify-node", "default", inject_modify_node },
1467     { "inject-modify-node", "xml", inject_modify_node_xml },
1468     { "inject-modify-ticket", "default", inject_modify_ticket },
1469     { "inject-modify-ticket", "xml", inject_modify_ticket_xml },
1470     { "inject-pseudo-action", "default", inject_pseudo_action },
1471     { "inject-pseudo-action", "xml", inject_pseudo_action_xml },
1472     { "inject-rsc-action", "default", inject_rsc_action },
1473     { "inject-rsc-action", "xml", inject_rsc_action_xml },
1474     { "inject-spec", "default", inject_spec },
1475     { "inject-spec", "xml", inject_spec_xml },
1476     { "locations-list", "default", locations_list },
1477     { "locations-list", "xml", locations_list_xml },
1478     { "node-action", "default", node_action },
1479     { "node-action", "xml", node_action_xml },
1480     { "pacemakerd-health", "default", pacemakerd_health_text },
1481     { "pacemakerd-health", "xml", pacemakerd_health_xml },
1482     { "rsc-action", "default", rsc_action_default },
1483     { "rsc-action-item", "default", rsc_action_item },
1484     { "rsc-action-item", "xml", rsc_action_item_xml },
1485     { "rsc-is-colocated-with-list", "default", rsc_is_colocated_with_list },
1486     { "rsc-is-colocated-with-list", "xml", rsc_is_colocated_with_list_xml },
1487     { "rscs-colocated-with-list", "default", rscs_colocated_with_list },
1488     { "rscs-colocated-with-list", "xml", rscs_colocated_with_list_xml },
1489     { "stacks-constraints", "default", stacks_and_constraints },
1490     { "stacks-constraints", "xml", stacks_and_constraints_xml },
1491 
1492     { NULL, NULL, NULL }
1493 };
1494 
1495 void
1496 pcmk__register_lib_messages(pcmk__output_t *out) {
     /* [previous][next][first][last][top][bottom][index][help] */
1497     pcmk__register_messages(out, fmt_functions);
1498 }

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