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. PCMK__OUTPUT_ARGS
  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. add_digest_xml
  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__OUTPUT_ARGS
  47. PCMK__OUTPUT_ARGS
  48. PCMK__OUTPUT_ARGS
  49. PCMK__OUTPUT_ARGS
  50. PCMK__OUTPUT_ARGS
  51. PCMK__OUTPUT_ARGS
  52. PCMK__OUTPUT_ARGS
  53. PCMK__OUTPUT_ARGS
  54. PCMK__OUTPUT_ARGS
  55. PCMK__OUTPUT_ARGS
  56. PCMK__OUTPUT_ARGS
  57. PCMK__OUTPUT_ARGS
  58. PCMK__OUTPUT_ARGS
  59. PCMK__OUTPUT_ARGS
  60. PCMK__OUTPUT_ARGS
  61. PCMK__OUTPUT_ARGS
  62. PCMK__OUTPUT_ARGS
  63. pcmk__register_lib_messages

   1 /*
   2  * Copyright 2019-2022 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/output.h>
  12 #include <crm/common/results.h>
  13 #include <crm/msg_xml.h>
  14 #include <crm/stonith-ng.h>
  15 #include <crm/fencing/internal.h>
  16 #include <crm/pengine/internal.h>
  17 #include <libxml/tree.h>
  18 #include <pacemaker-internal.h>
  19 
  20 #include <stdint.h>
  21 
  22 static char *
  23 colocations_header(pe_resource_t *rsc, pcmk__colocation_t *cons,
     /* [previous][next][first][last][top][bottom][index][help] */
  24                    bool dependents) {
  25     char *retval = NULL;
  26 
  27     if (cons->primary_role > RSC_ROLE_STARTED) {
  28         retval = crm_strdup_printf("%s (score=%s, %s role=%s, id=%s)",
  29                                    rsc->id, pcmk_readable_score(cons->score),
  30                                    (dependents? "needs" : "with"),
  31                                    role2text(cons->primary_role), cons->id);
  32     } else {
  33         retval = crm_strdup_printf("%s (score=%s, id=%s)",
  34                                    rsc->id, pcmk_readable_score(cons->score),
  35                                    cons->id);
  36     }
  37     return retval;
  38 }
  39 
  40 static void
  41 colocations_xml_node(pcmk__output_t *out, pe_resource_t *rsc,
     /* [previous][next][first][last][top][bottom][index][help] */
  42                      pcmk__colocation_t *cons) {
  43     xmlNodePtr node = NULL;
  44 
  45     node = pcmk__output_create_xml_node(out, XML_CONS_TAG_RSC_DEPEND,
  46                                         "id", cons->id,
  47                                         "rsc", cons->dependent->id,
  48                                         "with-rsc", cons->primary->id,
  49                                         "score", pcmk_readable_score(cons->score),
  50                                         NULL);
  51 
  52     if (cons->node_attribute) {
  53         xmlSetProp(node, (pcmkXmlStr) "node-attribute", (pcmkXmlStr) cons->node_attribute);
  54     }
  55 
  56     if (cons->dependent_role != RSC_ROLE_UNKNOWN) {
  57         xmlSetProp(node, (pcmkXmlStr) "rsc-role",
  58                    (pcmkXmlStr) role2text(cons->dependent_role));
  59     }
  60 
  61     if (cons->primary_role != RSC_ROLE_UNKNOWN) {
  62         xmlSetProp(node, (pcmkXmlStr) "with-rsc-role",
  63                    (pcmkXmlStr) role2text(cons->primary_role));
  64     }
  65 }
  66 
  67 static int
  68 do_locations_list_xml(pcmk__output_t *out, pe_resource_t *rsc, bool add_header)
     /* [previous][next][first][last][top][bottom][index][help] */
  69 {
  70     GList *lpc = NULL;
  71     GList *list = rsc->rsc_location;
  72     int rc = pcmk_rc_no_output;
  73 
  74     for (lpc = list; lpc != NULL; lpc = lpc->next) {
  75         pe__location_t *cons = lpc->data;
  76 
  77         GList *lpc2 = NULL;
  78 
  79         for (lpc2 = cons->node_list_rh; lpc2 != NULL; lpc2 = lpc2->next) {
  80             pe_node_t *node = (pe_node_t *) lpc2->data;
  81 
  82             if (add_header) {
  83                 PCMK__OUTPUT_LIST_HEADER(out, false, rc, "locations");
  84             }
  85 
  86             pcmk__output_create_xml_node(out, XML_CONS_TAG_RSC_LOCATION,
  87                                          "node", node->details->uname,
  88                                          "rsc", rsc->id,
  89                                          "id", cons->id,
  90                                          "score", pcmk_readable_score(node->weight),
  91                                          NULL);
  92         }
  93     }
  94 
  95     if (add_header) {
  96         PCMK__OUTPUT_LIST_FOOTER(out, rc);
  97     }
  98 
  99     return rc;
 100 }
 101 
 102 PCMK__OUTPUT_ARGS("rsc-action-item", "const char *", "pe_resource_t *",
     /* [previous][next][first][last][top][bottom][index][help] */
 103                   "pe_node_t *", "pe_node_t *", "pe_action_t *",
 104                   "pe_action_t *")
 105 static int
 106 rsc_action_item(pcmk__output_t *out, va_list args)
 107 {
 108     const char *change = va_arg(args, const char *);
 109     pe_resource_t *rsc = va_arg(args, pe_resource_t *);
 110     pe_node_t *origin = va_arg(args, pe_node_t *);
 111     pe_node_t *destination = va_arg(args, pe_node_t *);
 112     pe_action_t *action = va_arg(args, pe_action_t *);
 113     pe_action_t *source = va_arg(args, pe_action_t *);
 114 
 115     int len = 0;
 116     char *reason = NULL;
 117     char *details = NULL;
 118     bool same_host = false;
 119     bool same_role = false;
 120     bool need_role = false;
 121 
 122     static int rsc_width = 5;
 123     static int detail_width = 5;
 124 
 125     CRM_ASSERT(action);
 126     CRM_ASSERT(destination != NULL || origin != NULL);
 127 
 128     if(source == NULL) {
 129         source = action;
 130     }
 131 
 132     len = strlen(rsc->id);
 133     if(len > rsc_width) {
 134         rsc_width = len + 2;
 135     }
 136 
 137     if ((rsc->role > RSC_ROLE_STARTED)
 138         || (rsc->next_role > RSC_ROLE_UNPROMOTED)) {
 139         need_role = true;
 140     }
 141 
 142     if(origin != NULL && destination != NULL && origin->details == destination->details) {
 143         same_host = true;
 144     }
 145 
 146     if(rsc->role == rsc->next_role) {
 147         same_role = true;
 148     }
 149 
 150     if (need_role && (origin == NULL)) {
 151         /* Starting and promoting a promotable clone instance */
 152         details = crm_strdup_printf("%s -> %s %s", role2text(rsc->role),
 153                                     role2text(rsc->next_role),
 154                                     pe__node_name(destination));
 155 
 156     } else if (origin == NULL) {
 157         /* Starting a resource */
 158         details = crm_strdup_printf("%s", pe__node_name(destination));
 159 
 160     } else if (need_role && (destination == NULL)) {
 161         /* Stopping a promotable clone instance */
 162         details = crm_strdup_printf("%s %s", role2text(rsc->role),
 163                                     pe__node_name(origin));
 164 
 165     } else if (destination == NULL) {
 166         /* Stopping a resource */
 167         details = crm_strdup_printf("%s", pe__node_name(origin));
 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),
 172                                     pe__node_name(origin));
 173 
 174     } else if (same_role && same_host) {
 175         /* Recovering or Restarting a normal resource */
 176         details = crm_strdup_printf("%s", pe__node_name(origin));
 177 
 178     } else if (need_role && same_role) {
 179         /* Moving a promotable clone instance */
 180         details = crm_strdup_printf("%s -> %s %s", pe__node_name(origin),
 181                                     pe__node_name(destination),
 182                                     role2text(rsc->role));
 183 
 184     } else if (same_role) {
 185         /* Moving a normal resource */
 186         details = crm_strdup_printf("%s -> %s", pe__node_name(origin),
 187                                     pe__node_name(destination));
 188 
 189     } else if (same_host) {
 190         /* Promoting or demoting a promotable clone instance */
 191         details = crm_strdup_printf("%s -> %s %s", role2text(rsc->role),
 192                                     role2text(rsc->next_role),
 193                                     pe__node_name(origin));
 194 
 195     } else {
 196         /* Moving and promoting/demoting */
 197         details = crm_strdup_printf("%s %s -> %s %s", role2text(rsc->role),
 198                                     pe__node_name(origin),
 199                                     role2text(rsc->next_role),
 200                                     pe__node_name(destination));
 201     }
 202 
 203     len = strlen(details);
 204     if(len > detail_width) {
 205         detail_width = len;
 206     }
 207 
 208     if(source->reason && !pcmk_is_set(action->flags, pe_action_runnable)) {
 209         reason = crm_strdup_printf("due to %s (blocked)", source->reason);
 210 
 211     } else if(source->reason) {
 212         reason = crm_strdup_printf("due to %s", source->reason);
 213 
 214     } else if (!pcmk_is_set(action->flags, pe_action_runnable)) {
 215         reason = strdup("blocked");
 216 
 217     }
 218 
 219     out->list_item(out, NULL, "%-8s   %-*s   ( %*s )%s%s", change, rsc_width,
 220                    rsc->id, detail_width, details, reason ? "  " : "", reason ? reason : "");
 221 
 222     free(details);
 223     free(reason);
 224     return pcmk_rc_ok;
 225 }
 226 
 227 PCMK__OUTPUT_ARGS("rsc-action-item", "const char *", "pe_resource_t *",
     /* [previous][next][first][last][top][bottom][index][help] */
 228                   "pe_node_t *", "pe_node_t *", "pe_action_t *",
 229                   "pe_action_t *")
 230 static int
 231 rsc_action_item_xml(pcmk__output_t *out, va_list args)
 232 {
 233     const char *change = va_arg(args, const char *);
 234     pe_resource_t *rsc = va_arg(args, pe_resource_t *);
 235     pe_node_t *origin = va_arg(args, pe_node_t *);
 236     pe_node_t *destination = va_arg(args, pe_node_t *);
 237     pe_action_t *action = va_arg(args, pe_action_t *);
 238     pe_action_t *source = va_arg(args, pe_action_t *);
 239 
 240     char *change_str = NULL;
 241 
 242     bool same_host = false;
 243     bool same_role = false;
 244     bool need_role = false;
 245     xmlNode *xml = NULL;
 246 
 247     CRM_ASSERT(action);
 248     CRM_ASSERT(destination != NULL || origin != NULL);
 249 
 250     if (source == NULL) {
 251         source = action;
 252     }
 253 
 254     if ((rsc->role > RSC_ROLE_STARTED)
 255         || (rsc->next_role > RSC_ROLE_UNPROMOTED)) {
 256         need_role = true;
 257     }
 258 
 259     if(origin != NULL && destination != NULL && origin->details == destination->details) {
 260         same_host = true;
 261     }
 262 
 263     if(rsc->role == rsc->next_role) {
 264         same_role = true;
 265     }
 266 
 267     change_str = g_ascii_strdown(change, -1);
 268     xml = pcmk__output_create_xml_node(out, "rsc_action",
 269                                        "action", change_str,
 270                                        "resource", rsc->id,
 271                                        NULL);
 272     g_free(change_str);
 273 
 274     if (need_role && (origin == NULL)) {
 275         /* Starting and promoting a promotable clone instance */
 276         pcmk__xe_set_props(xml,
 277                            "role", role2text(rsc->role),
 278                            "next-role", role2text(rsc->next_role),
 279                            "dest", destination->details->uname,
 280                            NULL);
 281 
 282     } else if (origin == NULL) {
 283         /* Starting a resource */
 284         crm_xml_add(xml, "node", destination->details->uname);
 285 
 286     } else if (need_role && (destination == NULL)) {
 287         /* Stopping a promotable clone instance */
 288         pcmk__xe_set_props(xml,
 289                            "role", role2text(rsc->role),
 290                            "node", origin->details->uname,
 291                            NULL);
 292 
 293     } else if (destination == NULL) {
 294         /* Stopping a resource */
 295         crm_xml_add(xml, "node", origin->details->uname);
 296 
 297     } else if (need_role && same_role && same_host) {
 298         /* Recovering, restarting or re-promoting a promotable clone instance */
 299         pcmk__xe_set_props(xml,
 300                            "role", role2text(rsc->role),
 301                            "source", origin->details->uname,
 302                            NULL);
 303 
 304     } else if (same_role && same_host) {
 305         /* Recovering or Restarting a normal resource */
 306         crm_xml_add(xml, "source", origin->details->uname);
 307 
 308     } else if (need_role && same_role) {
 309         /* Moving a promotable clone instance */
 310         pcmk__xe_set_props(xml,
 311                            "source", origin->details->uname,
 312                            "dest", destination->details->uname,
 313                            "role", role2text(rsc->role),
 314                            NULL);
 315 
 316     } else if (same_role) {
 317         /* Moving a normal resource */
 318         pcmk__xe_set_props(xml,
 319                            "source", origin->details->uname,
 320                            "dest", destination->details->uname,
 321                            NULL);
 322 
 323     } else if (same_host) {
 324         /* Promoting or demoting a promotable clone instance */
 325         pcmk__xe_set_props(xml,
 326                            "role", role2text(rsc->role),
 327                            "next-role", role2text(rsc->next_role),
 328                            "source", origin->details->uname,
 329                            NULL);
 330 
 331     } else {
 332         /* Moving and promoting/demoting */
 333         pcmk__xe_set_props(xml,
 334                            "role", role2text(rsc->role),
 335                            "source", origin->details->uname,
 336                            "next-role", role2text(rsc->next_role),
 337                            "dest", destination->details->uname,
 338                            NULL);
 339     }
 340 
 341     if (source->reason && !pcmk_is_set(action->flags, pe_action_runnable)) {
 342         pcmk__xe_set_props(xml,
 343                            "reason", source->reason,
 344                            "blocked", "true",
 345                            NULL);
 346 
 347     } else if(source->reason) {
 348         crm_xml_add(xml, "reason", source->reason);
 349 
 350     } else if (!pcmk_is_set(action->flags, pe_action_runnable)) {
 351         pcmk__xe_set_bool_attr(xml, "blocked", true);
 352 
 353     }
 354 
 355     return pcmk_rc_ok;
 356 }
 357 
 358 PCMK__OUTPUT_ARGS("rsc-is-colocated-with-list", "pe_resource_t *", "bool")
     /* [previous][next][first][last][top][bottom][index][help] */
 359 static int
 360 rsc_is_colocated_with_list(pcmk__output_t *out, va_list args) {
 361     pe_resource_t *rsc = va_arg(args, pe_resource_t *);
 362     bool recursive = va_arg(args, int);
 363 
 364     int rc = pcmk_rc_no_output;
 365 
 366     if (pcmk_is_set(rsc->flags, pe_rsc_allocating)) {
 367         return rc;
 368     }
 369 
 370     pe__set_resource_flags(rsc, pe_rsc_allocating);
 371     for (GList *lpc = rsc->rsc_cons; lpc != NULL; lpc = lpc->next) {
 372         pcmk__colocation_t *cons = (pcmk__colocation_t *) lpc->data;
 373         char *hdr = NULL;
 374 
 375         PCMK__OUTPUT_LIST_HEADER(out, false, rc, "Resources %s is colocated with", rsc->id);
 376 
 377         if (pcmk_is_set(cons->primary->flags, pe_rsc_allocating)) {
 378             out->list_item(out, NULL, "%s (id=%s - loop)",
 379                            cons->primary->id, cons->id);
 380             continue;
 381         }
 382 
 383         hdr = colocations_header(cons->primary, cons, false);
 384         out->list_item(out, NULL, "%s", hdr);
 385         free(hdr);
 386 
 387         /* Empty list header just for indentation of information about this resource. */
 388         out->begin_list(out, NULL, NULL, NULL);
 389 
 390         out->message(out, "locations-list", cons->primary);
 391         if (recursive) {
 392             out->message(out, "rsc-is-colocated-with-list",
 393                          cons->primary, recursive);
 394         }
 395 
 396         out->end_list(out);
 397     }
 398 
 399     PCMK__OUTPUT_LIST_FOOTER(out, rc);
 400     return rc;
 401 }
 402 
 403 PCMK__OUTPUT_ARGS("rsc-is-colocated-with-list", "pe_resource_t *", "bool")
     /* [previous][next][first][last][top][bottom][index][help] */
 404 static int
 405 rsc_is_colocated_with_list_xml(pcmk__output_t *out, va_list args) {
 406     pe_resource_t *rsc = va_arg(args, pe_resource_t *);
 407     bool recursive = va_arg(args, int);
 408 
 409     int rc = pcmk_rc_no_output;
 410 
 411     if (pcmk_is_set(rsc->flags, pe_rsc_allocating)) {
 412         return rc;
 413     }
 414 
 415     pe__set_resource_flags(rsc, pe_rsc_allocating);
 416     for (GList *lpc = rsc->rsc_cons; lpc != NULL; lpc = lpc->next) {
 417         pcmk__colocation_t *cons = (pcmk__colocation_t *) lpc->data;
 418 
 419         if (pcmk_is_set(cons->primary->flags, pe_rsc_allocating)) {
 420             colocations_xml_node(out, cons->primary, cons);
 421             continue;
 422         }
 423 
 424         colocations_xml_node(out, cons->primary, cons);
 425         do_locations_list_xml(out, cons->primary, false);
 426 
 427         if (recursive) {
 428             out->message(out, "rsc-is-colocated-with-list",
 429                          cons->primary, recursive);
 430         }
 431     }
 432 
 433     return rc;
 434 }
 435 
 436 PCMK__OUTPUT_ARGS("rscs-colocated-with-list", "pe_resource_t *", "bool")
     /* [previous][next][first][last][top][bottom][index][help] */
 437 static int
 438 rscs_colocated_with_list(pcmk__output_t *out, va_list args) {
 439     pe_resource_t *rsc = va_arg(args, pe_resource_t *);
 440     bool recursive = va_arg(args, int);
 441 
 442     int rc = pcmk_rc_no_output;
 443 
 444     if (pcmk_is_set(rsc->flags, pe_rsc_allocating)) {
 445         return rc;
 446     }
 447 
 448     pe__set_resource_flags(rsc, pe_rsc_allocating);
 449     for (GList *lpc = rsc->rsc_cons_lhs; lpc != NULL; lpc = lpc->next) {
 450         pcmk__colocation_t *cons = (pcmk__colocation_t *) lpc->data;
 451         char *hdr = NULL;
 452 
 453         PCMK__OUTPUT_LIST_HEADER(out, false, rc, "Resources colocated with %s", rsc->id);
 454 
 455         if (pcmk_is_set(cons->dependent->flags, pe_rsc_allocating)) {
 456             out->list_item(out, NULL, "%s (id=%s - loop)",
 457                            cons->dependent->id, cons->id);
 458             continue;
 459         }
 460 
 461         hdr = colocations_header(cons->dependent, cons, true);
 462         out->list_item(out, NULL, "%s", hdr);
 463         free(hdr);
 464 
 465         /* Empty list header just for indentation of information about this resource. */
 466         out->begin_list(out, NULL, NULL, NULL);
 467 
 468         out->message(out, "locations-list", cons->dependent);
 469         if (recursive) {
 470             out->message(out, "rscs-colocated-with-list",
 471                          cons->dependent, recursive);
 472         }
 473 
 474         out->end_list(out);
 475     }
 476 
 477     PCMK__OUTPUT_LIST_FOOTER(out, rc);
 478     return rc;
 479 }
 480 
 481 PCMK__OUTPUT_ARGS("rscs-colocated-with-list", "pe_resource_t *", "bool")
     /* [previous][next][first][last][top][bottom][index][help] */
 482 static int
 483 rscs_colocated_with_list_xml(pcmk__output_t *out, va_list args) {
 484     pe_resource_t *rsc = va_arg(args, pe_resource_t *);
 485     bool recursive = va_arg(args, int);
 486 
 487     int rc = pcmk_rc_no_output;
 488 
 489     if (pcmk_is_set(rsc->flags, pe_rsc_allocating)) {
 490         return rc;
 491     }
 492 
 493     pe__set_resource_flags(rsc, pe_rsc_allocating);
 494     for (GList *lpc = rsc->rsc_cons_lhs; lpc != NULL; lpc = lpc->next) {
 495         pcmk__colocation_t *cons = (pcmk__colocation_t *) lpc->data;
 496 
 497         if (pcmk_is_set(cons->dependent->flags, pe_rsc_allocating)) {
 498             colocations_xml_node(out, cons->dependent, cons);
 499             continue;
 500         }
 501 
 502         colocations_xml_node(out, cons->dependent, cons);
 503         do_locations_list_xml(out, cons->dependent, false);
 504 
 505         if (recursive) {
 506             out->message(out, "rscs-colocated-with-list",
 507                          cons->dependent, recursive);
 508         }
 509     }
 510 
 511     return rc;
 512 }
 513 
 514 PCMK__OUTPUT_ARGS("locations-list", "pe_resource_t *")
     /* [previous][next][first][last][top][bottom][index][help] */
 515 static int
 516 locations_list(pcmk__output_t *out, va_list args) {
 517     pe_resource_t *rsc = va_arg(args, pe_resource_t *);
 518 
 519     GList *lpc = NULL;
 520     GList *list = rsc->rsc_location;
 521     int rc = pcmk_rc_no_output;
 522 
 523     for (lpc = list; lpc != NULL; lpc = lpc->next) {
 524         pe__location_t *cons = lpc->data;
 525 
 526         GList *lpc2 = NULL;
 527 
 528         for (lpc2 = cons->node_list_rh; lpc2 != NULL; lpc2 = lpc2->next) {
 529             pe_node_t *node = (pe_node_t *) lpc2->data;
 530 
 531             PCMK__OUTPUT_LIST_HEADER(out, false, rc, "Locations");
 532             out->list_item(out, NULL, "Node %s (score=%s, id=%s, rsc=%s)",
 533                            pe__node_name(node),
 534                            pcmk_readable_score(node->weight), cons->id,
 535                            rsc->id);
 536         }
 537     }
 538 
 539     PCMK__OUTPUT_LIST_FOOTER(out, rc);
 540     return rc;
 541 }
 542 
 543 PCMK__OUTPUT_ARGS("locations-list", "pe_resource_t *")
     /* [previous][next][first][last][top][bottom][index][help] */
 544 static int
 545 locations_list_xml(pcmk__output_t *out, va_list args) {
 546     pe_resource_t *rsc = va_arg(args, pe_resource_t *);
 547     return do_locations_list_xml(out, rsc, true);
 548 }
 549 
 550 PCMK__OUTPUT_ARGS("locations-and-colocations", "pe_resource_t *",
     /* [previous][next][first][last][top][bottom][index][help] */
 551                   "pe_working_set_t *", "bool", "bool")
 552 static int
 553 locations_and_colocations(pcmk__output_t *out, va_list args)
 554 {
 555     pe_resource_t *rsc = va_arg(args, pe_resource_t *);
 556     pe_working_set_t *data_set = va_arg(args, pe_working_set_t *);
 557     bool recursive = va_arg(args, int);
 558     bool force = va_arg(args, int);
 559 
 560     pcmk__unpack_constraints(data_set);
 561 
 562     // Constraints apply to group/clone, not member/instance
 563     if (!force) {
 564         rsc = uber_parent(rsc);
 565     }
 566 
 567     out->message(out, "locations-list", rsc);
 568 
 569     pe__clear_resource_flags_on_all(data_set, pe_rsc_allocating);
 570     out->message(out, "rscs-colocated-with-list", rsc, recursive);
 571 
 572     pe__clear_resource_flags_on_all(data_set, pe_rsc_allocating);
 573     out->message(out, "rsc-is-colocated-with-list", rsc, recursive);
 574     return pcmk_rc_ok;
 575 }
 576 
 577 PCMK__OUTPUT_ARGS("locations-and-colocations", "pe_resource_t *",
     /* [previous][next][first][last][top][bottom][index][help] */
 578                   "pe_working_set_t *", "bool", "bool")
 579 static int
 580 locations_and_colocations_xml(pcmk__output_t *out, va_list args)
 581 {
 582     pe_resource_t *rsc = va_arg(args, pe_resource_t *);
 583     pe_working_set_t *data_set = va_arg(args, pe_working_set_t *);
 584     bool recursive = va_arg(args, int);
 585     bool force = va_arg(args, int);
 586 
 587     pcmk__unpack_constraints(data_set);
 588 
 589     // Constraints apply to group/clone, not member/instance
 590     if (!force) {
 591         rsc = uber_parent(rsc);
 592     }
 593 
 594     pcmk__output_xml_create_parent(out, "constraints", NULL);
 595     do_locations_list_xml(out, rsc, false);
 596 
 597     pe__clear_resource_flags_on_all(data_set, pe_rsc_allocating);
 598     out->message(out, "rscs-colocated-with-list", rsc, recursive);
 599 
 600     pe__clear_resource_flags_on_all(data_set, pe_rsc_allocating);
 601     out->message(out, "rsc-is-colocated-with-list", rsc, recursive);
 602 
 603     pcmk__output_xml_pop_parent(out);
 604     return pcmk_rc_ok;
 605 }
 606 
 607 PCMK__OUTPUT_ARGS("health", "const char *", "const char *", "const char *", "const char *")
     /* [previous][next][first][last][top][bottom][index][help] */
 608 static int
 609 health(pcmk__output_t *out, va_list args)
 610 {
 611     const char *sys_from G_GNUC_UNUSED = va_arg(args, const char *);
 612     const char *host_from = va_arg(args, const char *);
 613     const char *fsa_state = va_arg(args, const char *);
 614     const char *result = va_arg(args, const char *);
 615 
 616     return out->info(out, "Controller on %s in state %s: %s",
 617                      pcmk__s(host_from, "unknown node"),
 618                      pcmk__s(fsa_state, "unknown"),
 619                      pcmk__s(result, "unknown result"));
 620 }
 621 
 622 PCMK__OUTPUT_ARGS("health", "const char *", "const char *", "const char *", "const char *")
     /* [previous][next][first][last][top][bottom][index][help] */
 623 static int
 624 health_text(pcmk__output_t *out, va_list args)
 625 {
 626     if (!out->is_quiet(out)) {
 627         return health(out, args);
 628     } else {
 629         const char *sys_from G_GNUC_UNUSED = va_arg(args, const char *);
 630         const char *host_from G_GNUC_UNUSED = va_arg(args, const char *);
 631         const char *fsa_state = va_arg(args, const char *);
 632         const char *result G_GNUC_UNUSED = va_arg(args, const char *);
 633 
 634         if (fsa_state != NULL) {
 635             pcmk__formatted_printf(out, "%s\n", fsa_state);
 636             return pcmk_rc_ok;
 637         }
 638     }
 639 
 640     return pcmk_rc_no_output;
 641 }
 642 
 643 PCMK__OUTPUT_ARGS("health", "const char *", "const char *", "const char *", "const char *")
     /* [previous][next][first][last][top][bottom][index][help] */
 644 static int
 645 health_xml(pcmk__output_t *out, va_list args)
 646 {
 647     const char *sys_from = va_arg(args, const char *);
 648     const char *host_from = va_arg(args, const char *);
 649     const char *fsa_state = va_arg(args, const char *);
 650     const char *result = va_arg(args, const char *);
 651 
 652     pcmk__output_create_xml_node(out, pcmk__s(sys_from, ""),
 653                                  "node_name", pcmk__s(host_from, ""),
 654                                  "state", pcmk__s(fsa_state, ""),
 655                                  "result", pcmk__s(result, ""),
 656                                  NULL);
 657     return pcmk_rc_ok;
 658 }
 659 
 660 PCMK__OUTPUT_ARGS("pacemakerd-health", "const char *", "int", "const char *",
     /* [previous][next][first][last][top][bottom][index][help] */
 661                   "const char *")
 662 static int
 663 pacemakerd_health(pcmk__output_t *out, va_list args)
 664 {
 665     const char *sys_from = va_arg(args, const char *);
 666     enum pcmk_pacemakerd_state state =
 667         (enum pcmk_pacemakerd_state) va_arg(args, int);
 668     const char *state_s = va_arg(args, const char *);
 669     const char *last_updated = va_arg(args, const char *);
 670 
 671     if (state_s == NULL) {
 672         state_s = pcmk__pcmkd_state_enum2friendly(state);
 673     }
 674     return out->info(out, "Status of %s: '%s' (last updated %s)",
 675                      pcmk__s(sys_from, "unknown subsystem"), state_s,
 676                      pcmk__s(last_updated, "at unknown time"));
 677 }
 678 
 679 PCMK__OUTPUT_ARGS("pacemakerd-health", "const char *", "int", "const char *",
     /* [previous][next][first][last][top][bottom][index][help] */
 680                   "const char *")
 681 static int
 682 pacemakerd_health_html(pcmk__output_t *out, va_list args)
 683 {
 684     const char *sys_from = va_arg(args, const char *);
 685     enum pcmk_pacemakerd_state state =
 686         (enum pcmk_pacemakerd_state) va_arg(args, int);
 687     const char *state_s = va_arg(args, const char *);
 688     const char *last_updated = va_arg(args, const char *);
 689     char *msg = NULL;
 690 
 691     if (state_s == NULL) {
 692         state_s = pcmk__pcmkd_state_enum2friendly(state);
 693     }
 694 
 695     msg = crm_strdup_printf("Status of %s: '%s' (last updated %s)",
 696                             pcmk__s(sys_from, "unknown subsystem"), state_s,
 697                             pcmk__s(last_updated, "at unknown time"));
 698     pcmk__output_create_html_node(out, "li", NULL, NULL, msg);
 699 
 700     free(msg);
 701     return pcmk_rc_ok;
 702 }
 703 
 704 PCMK__OUTPUT_ARGS("pacemakerd-health", "const char *", "int", "const char *",
     /* [previous][next][first][last][top][bottom][index][help] */
 705                   "const char *")
 706 static int
 707 pacemakerd_health_text(pcmk__output_t *out, va_list args)
 708 {
 709     if (!out->is_quiet(out)) {
 710         return pacemakerd_health(out, args);
 711     } else {
 712         const char *sys_from G_GNUC_UNUSED = va_arg(args, const char *);
 713         enum pcmk_pacemakerd_state state =
 714             (enum pcmk_pacemakerd_state) va_arg(args, int);
 715         const char *state_s = va_arg(args, const char *);
 716         const char *last_updated G_GNUC_UNUSED = va_arg(args, const char *);
 717 
 718         if (state_s == NULL) {
 719             state_s = pcmk_pacemakerd_api_daemon_state_enum2text(state);
 720         }
 721         pcmk__formatted_printf(out, "%s\n", state_s);
 722         return pcmk_rc_ok;
 723     }
 724 }
 725 
 726 PCMK__OUTPUT_ARGS("pacemakerd-health", "const char *", "int", "const char *",
     /* [previous][next][first][last][top][bottom][index][help] */
 727                   "const char *")
 728 static int
 729 pacemakerd_health_xml(pcmk__output_t *out, va_list args)
 730 {
 731     const char *sys_from = va_arg(args, const char *);
 732     enum pcmk_pacemakerd_state state =
 733         (enum pcmk_pacemakerd_state) va_arg(args, int);
 734     const char *state_s = va_arg(args, const char *);
 735     const char *last_updated = va_arg(args, const char *);
 736 
 737     if (state_s == NULL) {
 738         state_s = pcmk_pacemakerd_api_daemon_state_enum2text(state);
 739     }
 740 
 741     pcmk__output_create_xml_node(out, "pacemakerd",
 742                                  "sys_from", sys_from,
 743                                  "state", state_s,
 744                                  "last_updated", last_updated,
 745                                  NULL);
 746     return pcmk_rc_ok;
 747 }
 748 
 749 PCMK__OUTPUT_ARGS("profile", "const char *", "clock_t", "clock_t")
     /* [previous][next][first][last][top][bottom][index][help] */
 750 static int
 751 profile_default(pcmk__output_t *out, va_list args) {
 752     const char *xml_file = va_arg(args, const char *);
 753     clock_t start = va_arg(args, clock_t);
 754     clock_t end = va_arg(args, clock_t);
 755 
 756     out->list_item(out, NULL, "Testing %s ... %.2f secs", xml_file,
 757                    (end - start) / (float) CLOCKS_PER_SEC);
 758 
 759     return pcmk_rc_ok;
 760 }
 761 
 762 PCMK__OUTPUT_ARGS("profile", "const char *", "clock_t", "clock_t")
     /* [previous][next][first][last][top][bottom][index][help] */
 763 static int
 764 profile_xml(pcmk__output_t *out, va_list args) {
 765     const char *xml_file = va_arg(args, const char *);
 766     clock_t start = va_arg(args, clock_t);
 767     clock_t end = va_arg(args, clock_t);
 768 
 769     char *duration = pcmk__ftoa((end - start) / (float) CLOCKS_PER_SEC);
 770 
 771     pcmk__output_create_xml_node(out, "timing",
 772                                  "file", xml_file,
 773                                  "duration", duration,
 774                                  NULL);
 775 
 776     free(duration);
 777     return pcmk_rc_ok;
 778 }
 779 
 780 PCMK__OUTPUT_ARGS("dc", "const char *")
     /* [previous][next][first][last][top][bottom][index][help] */
 781 static int
 782 dc(pcmk__output_t *out, va_list args)
 783 {
 784     const char *dc = va_arg(args, const char *);
 785 
 786     return out->info(out, "Designated Controller is: %s",
 787                      pcmk__s(dc, "not yet elected"));
 788 }
 789 
 790 PCMK__OUTPUT_ARGS("dc", "const char *")
     /* [previous][next][first][last][top][bottom][index][help] */
 791 static int
 792 dc_text(pcmk__output_t *out, va_list args)
 793 {
 794     if (!out->is_quiet(out)) {
 795         return dc(out, args);
 796     } else {
 797         const char *dc = va_arg(args, const char *);
 798 
 799         if (dc != NULL) {
 800             pcmk__formatted_printf(out, "%s\n", pcmk__s(dc, ""));
 801             return pcmk_rc_ok;
 802         }
 803     }
 804 
 805     return pcmk_rc_no_output;
 806 }
 807 
 808 PCMK__OUTPUT_ARGS("dc", "const char *")
     /* [previous][next][first][last][top][bottom][index][help] */
 809 static int
 810 dc_xml(pcmk__output_t *out, va_list args)
 811 {
 812     const char *dc = va_arg(args, const char *);
 813 
 814     pcmk__output_create_xml_node(out, "dc",
 815                                  "node_name", pcmk__s(dc, ""),
 816                                  NULL);
 817     return pcmk_rc_ok;
 818 }
 819 
 820 PCMK__OUTPUT_ARGS("crmadmin-node", "const char *", "const char *", "const char *", "bool")
     /* [previous][next][first][last][top][bottom][index][help] */
 821 static int
 822 crmadmin_node(pcmk__output_t *out, va_list args)
 823 {
 824     const char *type = va_arg(args, const char *);
 825     const char *name = va_arg(args, const char *);
 826     const char *id = va_arg(args, const char *);
 827     bool bash_export = va_arg(args, int);
 828 
 829     if (bash_export) {
 830         return out->info(out, "export %s=%s",
 831                          pcmk__s(name, "<null>"), pcmk__s(id, ""));
 832     } else {
 833         return out->info(out, "%s node: %s (%s)", type ? type : "cluster",
 834                          pcmk__s(name, "<null>"), pcmk__s(id, "<null>"));
 835     }
 836 }
 837 
 838 PCMK__OUTPUT_ARGS("crmadmin-node", "const char *", "const char *", "const char *", "bool")
     /* [previous][next][first][last][top][bottom][index][help] */
 839 static int
 840 crmadmin_node_text(pcmk__output_t *out, va_list args)
 841 {
 842     if (!out->is_quiet(out)) {
 843         return crmadmin_node(out, args);
 844     } else {
 845         const char *type G_GNUC_UNUSED = va_arg(args, const char *);
 846         const char *name = va_arg(args, const char *);
 847         const char *id G_GNUC_UNUSED = va_arg(args, const char *);
 848         bool bash_export G_GNUC_UNUSED = va_arg(args, int);
 849 
 850         pcmk__formatted_printf(out, "%s\n", pcmk__s(name, "<null>"));
 851         return pcmk_rc_ok;
 852     }
 853 }
 854 
 855 PCMK__OUTPUT_ARGS("crmadmin-node", "const char *", "const char *", "const char *", "bool")
     /* [previous][next][first][last][top][bottom][index][help] */
 856 static int
 857 crmadmin_node_xml(pcmk__output_t *out, va_list args)
 858 {
 859     const char *type = va_arg(args, const char *);
 860     const char *name = va_arg(args, const char *);
 861     const char *id = va_arg(args, const char *);
 862     bool bash_export G_GNUC_UNUSED = va_arg(args, int);
 863 
 864     pcmk__output_create_xml_node(out, "node",
 865                                  "type", type ? type : "cluster",
 866                                  "name", pcmk__s(name, ""),
 867                                  "id", pcmk__s(id, ""),
 868                                  NULL);
 869     return pcmk_rc_ok;
 870 }
 871 
 872 PCMK__OUTPUT_ARGS("digests", "pe_resource_t *", "pe_node_t *", "const char *",
     /* [previous][next][first][last][top][bottom][index][help] */
 873                   "guint", "op_digest_cache_t *")
 874 static int
 875 digests_text(pcmk__output_t *out, va_list args)
 876 {
 877     pe_resource_t *rsc = va_arg(args, pe_resource_t *);
 878     pe_node_t *node = va_arg(args, pe_node_t *);
 879     const char *task = va_arg(args, const char *);
 880     guint interval_ms = va_arg(args, guint);
 881     op_digest_cache_t *digests = va_arg(args, op_digest_cache_t *);
 882 
 883     char *action_desc = NULL;
 884     const char *rsc_desc = "unknown resource";
 885     const char *node_desc = "unknown node";
 886 
 887     if (interval_ms != 0) {
 888         action_desc = crm_strdup_printf("%ums-interval %s action", interval_ms,
 889                                         ((task == NULL)? "unknown" : task));
 890     } else if (pcmk__str_eq(task, "monitor", pcmk__str_none)) {
 891         action_desc = strdup("probe action");
 892     } else {
 893         action_desc = crm_strdup_printf("%s action",
 894                                         ((task == NULL)? "unknown" : task));
 895     }
 896     if ((rsc != NULL) && (rsc->id != NULL)) {
 897         rsc_desc = rsc->id;
 898     }
 899     if ((node != NULL) && (node->details->uname != NULL)) {
 900         node_desc = node->details->uname;
 901     }
 902     out->begin_list(out, NULL, NULL, "Digests for %s %s on %s",
 903                     rsc_desc, action_desc, node_desc);
 904     free(action_desc);
 905 
 906     if (digests == NULL) {
 907         out->list_item(out, NULL, "none");
 908         out->end_list(out);
 909         return pcmk_rc_ok;
 910     }
 911     if (digests->digest_all_calc != NULL) {
 912         out->list_item(out, NULL, "%s (all parameters)",
 913                        digests->digest_all_calc);
 914     }
 915     if (digests->digest_secure_calc != NULL) {
 916         out->list_item(out, NULL, "%s (non-private parameters)",
 917                        digests->digest_secure_calc);
 918     }
 919     if (digests->digest_restart_calc != NULL) {
 920         out->list_item(out, NULL, "%s (non-reloadable parameters)",
 921                        digests->digest_restart_calc);
 922     }
 923     out->end_list(out);
 924     return pcmk_rc_ok;
 925 }
 926 
 927 static void
 928 add_digest_xml(xmlNode *parent, const char *type, const char *digest,
     /* [previous][next][first][last][top][bottom][index][help] */
 929                xmlNode *digest_source)
 930 {
 931     if (digest != NULL) {
 932         xmlNodePtr digest_xml = create_xml_node(parent, "digest");
 933 
 934         crm_xml_add(digest_xml, "type", ((type == NULL)? "unspecified" : type));
 935         crm_xml_add(digest_xml, "hash", digest);
 936         if (digest_source != NULL) {
 937             add_node_copy(digest_xml, digest_source);
 938         }
 939     }
 940 }
 941 
 942 PCMK__OUTPUT_ARGS("digests", "pe_resource_t *", "pe_node_t *", "const char *",
     /* [previous][next][first][last][top][bottom][index][help] */
 943                   "guint", "op_digest_cache_t *")
 944 static int
 945 digests_xml(pcmk__output_t *out, va_list args)
 946 {
 947     pe_resource_t *rsc = va_arg(args, pe_resource_t *);
 948     pe_node_t *node = va_arg(args, pe_node_t *);
 949     const char *task = va_arg(args, const char *);
 950     guint interval_ms = va_arg(args, guint);
 951     op_digest_cache_t *digests = va_arg(args, op_digest_cache_t *);
 952 
 953     char *interval_s = crm_strdup_printf("%ums", interval_ms);
 954     xmlNode *xml = NULL;
 955 
 956     xml = pcmk__output_create_xml_node(out, "digests",
 957                                        "resource", pcmk__s(rsc->id, ""),
 958                                        "node", pcmk__s(node->details->uname, ""),
 959                                        "task", pcmk__s(task, ""),
 960                                        "interval", interval_s,
 961                                        NULL);
 962     free(interval_s);
 963     if (digests != NULL) {
 964         add_digest_xml(xml, "all", digests->digest_all_calc,
 965                        digests->params_all);
 966         add_digest_xml(xml, "nonprivate", digests->digest_secure_calc,
 967                        digests->params_secure);
 968         add_digest_xml(xml, "nonreloadable", digests->digest_restart_calc,
 969                        digests->params_restart);
 970     }
 971     return pcmk_rc_ok;
 972 }
 973 
 974 #define STOP_SANITY_ASSERT(lineno) do {                                 \
 975         if(current && current->details->unclean) {                      \
 976             /* It will be a pseudo op */                                \
 977         } else if(stop == NULL) {                                       \
 978             crm_err("%s:%d: No stop action exists for %s",              \
 979                     __func__, lineno, rsc->id);                         \
 980             CRM_ASSERT(stop != NULL);                                   \
 981         } else if (pcmk_is_set(stop->flags, pe_action_optional)) {      \
 982             crm_err("%s:%d: Action %s is still optional",               \
 983                     __func__, lineno, stop->uuid);                      \
 984             CRM_ASSERT(!pcmk_is_set(stop->flags, pe_action_optional));  \
 985         }                                                               \
 986     } while(0)
 987 
 988 PCMK__OUTPUT_ARGS("rsc-action", "pe_resource_t *", "pe_node_t *", "pe_node_t *")
     /* [previous][next][first][last][top][bottom][index][help] */
 989 static int
 990 rsc_action_default(pcmk__output_t *out, va_list args)
 991 {
 992     pe_resource_t *rsc = va_arg(args, pe_resource_t *);
 993     pe_node_t *current = va_arg(args, pe_node_t *);
 994     pe_node_t *next = va_arg(args, pe_node_t *);
 995 
 996     GList *possible_matches = NULL;
 997     char *key = NULL;
 998     int rc = pcmk_rc_no_output;
 999     bool moving = false;
1000 
1001     pe_node_t *start_node = NULL;
1002     pe_action_t *start = NULL;
1003     pe_action_t *stop = NULL;
1004     pe_action_t *promote = NULL;
1005     pe_action_t *demote = NULL;
1006 
1007     if (!pcmk_is_set(rsc->flags, pe_rsc_managed)
1008         || (current == NULL && next == NULL)) {
1009         pe_rsc_info(rsc, "Leave   %s\t(%s%s)",
1010                     rsc->id, role2text(rsc->role),
1011                     !pcmk_is_set(rsc->flags, pe_rsc_managed)? " unmanaged" : "");
1012         return rc;
1013     }
1014 
1015     moving = (current != NULL) && (next != NULL)
1016              && (current->details != next->details);
1017 
1018     possible_matches = pe__resource_actions(rsc, next, RSC_START, false);
1019     if (possible_matches) {
1020         start = possible_matches->data;
1021         g_list_free(possible_matches);
1022     }
1023 
1024     if ((start == NULL) || !pcmk_is_set(start->flags, pe_action_runnable)) {
1025         start_node = NULL;
1026     } else {
1027         start_node = current;
1028     }
1029     possible_matches = pe__resource_actions(rsc, start_node, RSC_STOP, false);
1030     if (possible_matches) {
1031         stop = possible_matches->data;
1032         g_list_free(possible_matches);
1033     } else if (pcmk_is_set(rsc->flags, pe_rsc_stop_unexpected)) {
1034         /* The resource is multiply active with multiple-active set to
1035          * stop_unexpected, and not stopping on its current node, but it should
1036          * be stopping elsewhere.
1037          */
1038         possible_matches = pe__resource_actions(rsc, NULL, RSC_STOP, false);
1039         if (possible_matches != NULL) {
1040             stop = possible_matches->data;
1041             g_list_free(possible_matches);
1042         }
1043     }
1044 
1045     possible_matches = pe__resource_actions(rsc, next, RSC_PROMOTE, false);
1046     if (possible_matches) {
1047         promote = possible_matches->data;
1048         g_list_free(possible_matches);
1049     }
1050 
1051     possible_matches = pe__resource_actions(rsc, next, RSC_DEMOTE, false);
1052     if (possible_matches) {
1053         demote = possible_matches->data;
1054         g_list_free(possible_matches);
1055     }
1056 
1057     if (rsc->role == rsc->next_role) {
1058         pe_action_t *migrate_op = NULL;
1059 
1060         CRM_CHECK(next != NULL, return rc);
1061 
1062         possible_matches = pe__resource_actions(rsc, next, RSC_MIGRATED, false);
1063         if (possible_matches) {
1064             migrate_op = possible_matches->data;
1065         }
1066 
1067         if ((migrate_op != NULL) && (current != NULL)
1068                    && pcmk_is_set(migrate_op->flags, pe_action_runnable)) {
1069             rc = out->message(out, "rsc-action-item", "Migrate", rsc, current,
1070                               next, start, NULL);
1071 
1072         } else if (pcmk_is_set(rsc->flags, pe_rsc_reload)) {
1073             rc = out->message(out, "rsc-action-item", "Reload", rsc, current,
1074                               next, start, NULL);
1075 
1076         } else if (start == NULL || pcmk_is_set(start->flags, pe_action_optional)) {
1077             if ((demote != NULL) && (promote != NULL)
1078                 && !pcmk_is_set(demote->flags, pe_action_optional)
1079                 && !pcmk_is_set(promote->flags, pe_action_optional)) {
1080                 rc = out->message(out, "rsc-action-item", "Re-promote", rsc,
1081                                   current, next, promote, demote);
1082             } else {
1083                 pe_rsc_info(rsc, "Leave   %s\t(%s %s)", rsc->id,
1084                             role2text(rsc->role), pe__node_name(next));
1085             }
1086 
1087         } else if (!pcmk_is_set(start->flags, pe_action_runnable)) {
1088             rc = out->message(out, "rsc-action-item", "Stop", rsc, current,
1089                               NULL, stop, (stop && stop->reason)? stop : start);
1090             STOP_SANITY_ASSERT(__LINE__);
1091 
1092         } else if (moving && current) {
1093             rc = out->message(out, "rsc-action-item", pcmk_is_set(rsc->flags, pe_rsc_failed)? "Recover" : "Move",
1094                               rsc, current, next, stop, NULL);
1095 
1096         } else if (pcmk_is_set(rsc->flags, pe_rsc_failed)) {
1097             rc = out->message(out, "rsc-action-item", "Recover", rsc, current,
1098                               NULL, stop, NULL);
1099             STOP_SANITY_ASSERT(__LINE__);
1100 
1101         } else {
1102             rc = out->message(out, "rsc-action-item", "Restart", rsc, current,
1103                               next, start, NULL);
1104             /* STOP_SANITY_ASSERT(__LINE__); False positive for migrate-fail-7 */
1105         }
1106 
1107         g_list_free(possible_matches);
1108         return rc;
1109     }
1110 
1111     if(stop
1112        && (rsc->next_role == RSC_ROLE_STOPPED
1113            || (start && !pcmk_is_set(start->flags, pe_action_runnable)))) {
1114 
1115         GList *gIter = NULL;
1116 
1117         key = stop_key(rsc);
1118         for (gIter = rsc->running_on; gIter != NULL; gIter = gIter->next) {
1119             pe_node_t *node = (pe_node_t *) gIter->data;
1120             pe_action_t *stop_op = NULL;
1121 
1122             possible_matches = find_actions(rsc->actions, key, node);
1123             if (possible_matches) {
1124                 stop_op = possible_matches->data;
1125                 g_list_free(possible_matches);
1126             }
1127 
1128             if (stop_op && (stop_op->flags & pe_action_runnable)) {
1129                 STOP_SANITY_ASSERT(__LINE__);
1130             }
1131 
1132             if (out->message(out, "rsc-action-item", "Stop", rsc, node, NULL,
1133                              stop_op, (stop_op && stop_op->reason)? stop_op : start) == pcmk_rc_ok) {
1134                 rc = pcmk_rc_ok;
1135             }
1136         }
1137 
1138         free(key);
1139 
1140     } else if ((stop != NULL)
1141                && pcmk_all_flags_set(rsc->flags, pe_rsc_failed|pe_rsc_stop)) {
1142         /* 'stop' may be NULL if the failure was ignored */
1143         rc = out->message(out, "rsc-action-item", "Recover", rsc, current,
1144                           next, stop, start);
1145         STOP_SANITY_ASSERT(__LINE__);
1146 
1147     } else if (moving) {
1148         rc = out->message(out, "rsc-action-item", "Move", rsc, current, next,
1149                           stop, NULL);
1150         STOP_SANITY_ASSERT(__LINE__);
1151 
1152     } else if (pcmk_is_set(rsc->flags, pe_rsc_reload)) {
1153         rc = out->message(out, "rsc-action-item", "Reload", rsc, current, next,
1154                           start, NULL);
1155 
1156     } else if (stop != NULL && !pcmk_is_set(stop->flags, pe_action_optional)) {
1157         rc = out->message(out, "rsc-action-item", "Restart", rsc, current,
1158                           next, start, NULL);
1159         STOP_SANITY_ASSERT(__LINE__);
1160 
1161     } else if (rsc->role == RSC_ROLE_PROMOTED) {
1162         CRM_LOG_ASSERT(current != NULL);
1163         rc = out->message(out, "rsc-action-item", "Demote", rsc, current,
1164                           next, demote, NULL);
1165 
1166     } else if (rsc->next_role == RSC_ROLE_PROMOTED) {
1167         CRM_LOG_ASSERT(next);
1168         rc = out->message(out, "rsc-action-item", "Promote", rsc, current,
1169                           next, promote, NULL);
1170 
1171     } else if (rsc->role == RSC_ROLE_STOPPED && rsc->next_role > RSC_ROLE_STOPPED) {
1172         rc = out->message(out, "rsc-action-item", "Start", rsc, current, next,
1173                           start, NULL);
1174     }
1175 
1176     return rc;
1177 }
1178 
1179 PCMK__OUTPUT_ARGS("node-action", "char *", "char *", "char *")
     /* [previous][next][first][last][top][bottom][index][help] */
1180 static int
1181 node_action(pcmk__output_t *out, va_list args)
1182 {
1183     char *task = va_arg(args, char *);
1184     char *node_name = va_arg(args, char *);
1185     char *reason = va_arg(args, char *);
1186 
1187     if (task == NULL) {
1188         return pcmk_rc_no_output;
1189     } else if (reason) {
1190         out->list_item(out, NULL, "%s %s '%s'", task, node_name, reason);
1191     } else {
1192         crm_notice(" * %s %s", task, node_name);
1193     }
1194 
1195     return pcmk_rc_ok;
1196 }
1197 
1198 PCMK__OUTPUT_ARGS("node-action", "char *", "char *", "char *")
     /* [previous][next][first][last][top][bottom][index][help] */
1199 static int
1200 node_action_xml(pcmk__output_t *out, va_list args)
1201 {
1202     char *task = va_arg(args, char *);
1203     char *node_name = va_arg(args, char *);
1204     char *reason = va_arg(args, char *);
1205 
1206     if (task == NULL) {
1207         return pcmk_rc_no_output;
1208     } else if (reason) {
1209         pcmk__output_create_xml_node(out, "node_action",
1210                                      "task", task,
1211                                      "node", node_name,
1212                                      "reason", reason,
1213                                      NULL);
1214     } else {
1215         crm_notice(" * %s %s", task, node_name);
1216     }
1217 
1218     return pcmk_rc_ok;
1219 }
1220 
1221 PCMK__OUTPUT_ARGS("inject-cluster-action", "const char *", "const char *", "xmlNodePtr")
     /* [previous][next][first][last][top][bottom][index][help] */
1222 static int
1223 inject_cluster_action(pcmk__output_t *out, va_list args)
1224 {
1225     const char *node = va_arg(args, const char *);
1226     const char *task = va_arg(args, const char *);
1227     xmlNodePtr rsc = va_arg(args, xmlNodePtr);
1228 
1229     if (out->is_quiet(out)) {
1230         return pcmk_rc_no_output;
1231     }
1232 
1233     if(rsc) {
1234         out->list_item(out, NULL, "Cluster action:  %s for %s on %s", task, ID(rsc), node);
1235     } else {
1236         out->list_item(out, NULL, "Cluster action:  %s on %s", task, node);
1237     }
1238 
1239     return pcmk_rc_ok;
1240 }
1241 
1242 PCMK__OUTPUT_ARGS("inject-cluster-action", "const char *", "const char *", "xmlNodePtr")
     /* [previous][next][first][last][top][bottom][index][help] */
1243 static int
1244 inject_cluster_action_xml(pcmk__output_t *out, va_list args)
1245 {
1246     const char *node = va_arg(args, const char *);
1247     const char *task = va_arg(args, const char *);
1248     xmlNodePtr rsc = va_arg(args, xmlNodePtr);
1249 
1250     xmlNodePtr xml_node = NULL;
1251 
1252     if (out->is_quiet(out)) {
1253         return pcmk_rc_no_output;
1254     }
1255 
1256     xml_node = pcmk__output_create_xml_node(out, "cluster_action",
1257                                             "task", task,
1258                                             "node", node,
1259                                             NULL);
1260 
1261     if (rsc) {
1262         crm_xml_add(xml_node, "id", ID(rsc));
1263     }
1264 
1265     return pcmk_rc_ok;
1266 }
1267 
1268 PCMK__OUTPUT_ARGS("inject-fencing-action", "char *", "const char *")
     /* [previous][next][first][last][top][bottom][index][help] */
1269 static int
1270 inject_fencing_action(pcmk__output_t *out, va_list args)
1271 {
1272     char *target = va_arg(args, char *);
1273     const char *op = va_arg(args, const char *);
1274 
1275     if (out->is_quiet(out)) {
1276         return pcmk_rc_no_output;
1277     }
1278 
1279     out->list_item(out, NULL, "Fencing %s (%s)", target, op);
1280     return pcmk_rc_ok;
1281 }
1282 
1283 PCMK__OUTPUT_ARGS("inject-fencing-action", "char *", "const char *")
     /* [previous][next][first][last][top][bottom][index][help] */
1284 static int
1285 inject_fencing_action_xml(pcmk__output_t *out, va_list args)
1286 {
1287     char *target = va_arg(args, char *);
1288     const char *op = va_arg(args, const char *);
1289 
1290     if (out->is_quiet(out)) {
1291         return pcmk_rc_no_output;
1292     }
1293 
1294     pcmk__output_create_xml_node(out, "fencing_action",
1295                                  "target", target,
1296                                  "op", op,
1297                                  NULL);
1298     return pcmk_rc_ok;
1299 }
1300 
1301 PCMK__OUTPUT_ARGS("inject-attr", "const char *", "const char *", "xmlNodePtr")
     /* [previous][next][first][last][top][bottom][index][help] */
1302 static int
1303 inject_attr(pcmk__output_t *out, va_list args)
1304 {
1305     const char *name = va_arg(args, const char *);
1306     const char *value = va_arg(args, const char *);
1307     xmlNodePtr cib_node = va_arg(args, xmlNodePtr);
1308 
1309     xmlChar *node_path = NULL;
1310 
1311     if (out->is_quiet(out)) {
1312         return pcmk_rc_no_output;
1313     }
1314 
1315     node_path = xmlGetNodePath(cib_node);
1316 
1317     out->list_item(out, NULL, "Injecting attribute %s=%s into %s '%s'",
1318                    name, value, node_path, ID(cib_node));
1319 
1320     free(node_path);
1321     return pcmk_rc_ok;
1322 }
1323 
1324 PCMK__OUTPUT_ARGS("inject-attr", "const char *", "const char *", "xmlNodePtr")
     /* [previous][next][first][last][top][bottom][index][help] */
1325 static int
1326 inject_attr_xml(pcmk__output_t *out, va_list args)
1327 {
1328     const char *name = va_arg(args, const char *);
1329     const char *value = va_arg(args, const char *);
1330     xmlNodePtr cib_node = va_arg(args, xmlNodePtr);
1331 
1332     xmlChar *node_path = NULL;
1333 
1334     if (out->is_quiet(out)) {
1335         return pcmk_rc_no_output;
1336     }
1337 
1338     node_path = xmlGetNodePath(cib_node);
1339 
1340     pcmk__output_create_xml_node(out, "inject_attr",
1341                                  "name", name,
1342                                  "value", value,
1343                                  "node_path", node_path,
1344                                  "cib_node", ID(cib_node),
1345                                  NULL);
1346     free(node_path);
1347     return pcmk_rc_ok;
1348 }
1349 
1350 PCMK__OUTPUT_ARGS("inject-spec", "const char *")
     /* [previous][next][first][last][top][bottom][index][help] */
1351 static int
1352 inject_spec(pcmk__output_t *out, va_list args)
1353 {
1354     const char *spec = va_arg(args, const char *);
1355 
1356     if (out->is_quiet(out)) {
1357         return pcmk_rc_no_output;
1358     }
1359 
1360     out->list_item(out, NULL, "Injecting %s into the configuration", spec);
1361     return pcmk_rc_ok;
1362 }
1363 
1364 PCMK__OUTPUT_ARGS("inject-spec", "const char *")
     /* [previous][next][first][last][top][bottom][index][help] */
1365 static int
1366 inject_spec_xml(pcmk__output_t *out, va_list args)
1367 {
1368     const char *spec = va_arg(args, const char *);
1369 
1370     if (out->is_quiet(out)) {
1371         return pcmk_rc_no_output;
1372     }
1373 
1374     pcmk__output_create_xml_node(out, "inject_spec",
1375                                  "spec", spec,
1376                                  NULL);
1377     return pcmk_rc_ok;
1378 }
1379 
1380 PCMK__OUTPUT_ARGS("inject-modify-config", "char *", "char *")
     /* [previous][next][first][last][top][bottom][index][help] */
1381 static int
1382 inject_modify_config(pcmk__output_t *out, va_list args)
1383 {
1384     char *quorum = va_arg(args, char *);
1385     char *watchdog = va_arg(args, char *);
1386 
1387     if (out->is_quiet(out)) {
1388         return pcmk_rc_no_output;
1389     }
1390 
1391     out->begin_list(out, NULL, NULL, "Performing Requested Modifications");
1392 
1393     if (quorum) {
1394         out->list_item(out, NULL, "Setting quorum: %s", quorum);
1395     }
1396 
1397     if (watchdog) {
1398         out->list_item(out, NULL, "Setting watchdog: %s", watchdog);
1399     }
1400 
1401     return pcmk_rc_ok;
1402 }
1403 
1404 PCMK__OUTPUT_ARGS("inject-modify-config", "char *", "char *")
     /* [previous][next][first][last][top][bottom][index][help] */
1405 static int
1406 inject_modify_config_xml(pcmk__output_t *out, va_list args)
1407 {
1408     char *quorum = va_arg(args, char *);
1409     char *watchdog = va_arg(args, char *);
1410 
1411     xmlNodePtr node = NULL;
1412 
1413     if (out->is_quiet(out)) {
1414         return pcmk_rc_no_output;
1415     }
1416 
1417     node = pcmk__output_xml_create_parent(out, "modifications", NULL);
1418 
1419     if (quorum) {
1420         crm_xml_add(node, "quorum", quorum);
1421     }
1422 
1423     if (watchdog) {
1424         crm_xml_add(node, "watchdog", watchdog);
1425     }
1426 
1427     return pcmk_rc_ok;
1428 }
1429 
1430 PCMK__OUTPUT_ARGS("inject-modify-node", "const char *", "char *")
     /* [previous][next][first][last][top][bottom][index][help] */
1431 static int
1432 inject_modify_node(pcmk__output_t *out, va_list args)
1433 {
1434     const char *action = va_arg(args, const char *);
1435     char *node = va_arg(args, char *);
1436 
1437     if (out->is_quiet(out)) {
1438         return pcmk_rc_no_output;
1439     }
1440 
1441     if (pcmk__str_eq(action, "Online", pcmk__str_none)) {
1442         out->list_item(out, NULL, "Bringing node %s online", node);
1443         return pcmk_rc_ok;
1444     } else if (pcmk__str_eq(action, "Offline", pcmk__str_none)) {
1445         out->list_item(out, NULL, "Taking node %s offline", node);
1446         return pcmk_rc_ok;
1447     } else if (pcmk__str_eq(action, "Failing", pcmk__str_none)) {
1448         out->list_item(out, NULL, "Failing node %s", node);
1449         return pcmk_rc_ok;
1450     }
1451 
1452     return pcmk_rc_no_output;
1453 }
1454 
1455 PCMK__OUTPUT_ARGS("inject-modify-node", "const char *", "char *")
     /* [previous][next][first][last][top][bottom][index][help] */
1456 static int
1457 inject_modify_node_xml(pcmk__output_t *out, va_list args)
1458 {
1459     const char *action = va_arg(args, const char *);
1460     char *node = va_arg(args, char *);
1461 
1462     if (out->is_quiet(out)) {
1463         return pcmk_rc_no_output;
1464     }
1465 
1466     pcmk__output_create_xml_node(out, "modify_node",
1467                                  "action", action,
1468                                  "node", node,
1469                                  NULL);
1470     return pcmk_rc_ok;
1471 }
1472 
1473 PCMK__OUTPUT_ARGS("inject-modify-ticket", "const char *", "char *")
     /* [previous][next][first][last][top][bottom][index][help] */
1474 static int
1475 inject_modify_ticket(pcmk__output_t *out, va_list args)
1476 {
1477     const char *action = va_arg(args, const char *);
1478     char *ticket = va_arg(args, char *);
1479 
1480     if (out->is_quiet(out)) {
1481         return pcmk_rc_no_output;
1482     }
1483 
1484     if (pcmk__str_eq(action, "Standby", pcmk__str_none)) {
1485         out->list_item(out, NULL, "Making ticket %s standby", ticket);
1486     } else {
1487         out->list_item(out, NULL, "%s ticket %s", action, ticket);
1488     }
1489 
1490     return pcmk_rc_ok;
1491 }
1492 
1493 PCMK__OUTPUT_ARGS("inject-modify-ticket", "const char *", "char *")
     /* [previous][next][first][last][top][bottom][index][help] */
1494 static int
1495 inject_modify_ticket_xml(pcmk__output_t *out, va_list args)
1496 {
1497     const char *action = va_arg(args, const char *);
1498     char *ticket = va_arg(args, char *);
1499 
1500     if (out->is_quiet(out)) {
1501         return pcmk_rc_no_output;
1502     }
1503 
1504     pcmk__output_create_xml_node(out, "modify_ticket",
1505                                  "action", action,
1506                                  "ticket", ticket,
1507                                  NULL);
1508     return pcmk_rc_ok;
1509 }
1510 
1511 PCMK__OUTPUT_ARGS("inject-pseudo-action", "const char *", "const char *")
     /* [previous][next][first][last][top][bottom][index][help] */
1512 static int
1513 inject_pseudo_action(pcmk__output_t *out, va_list args)
1514 {
1515     const char *node = va_arg(args, const char *);
1516     const char *task = va_arg(args, const char *);
1517 
1518     if (out->is_quiet(out)) {
1519         return pcmk_rc_no_output;
1520     }
1521 
1522     out->list_item(out, NULL, "Pseudo action:   %s%s%s", task, node ? " on " : "",
1523                    node ? node : "");
1524     return pcmk_rc_ok;
1525 }
1526 
1527 PCMK__OUTPUT_ARGS("inject-pseudo-action", "const char *", "const char *")
     /* [previous][next][first][last][top][bottom][index][help] */
1528 static int
1529 inject_pseudo_action_xml(pcmk__output_t *out, va_list args)
1530 {
1531     const char *node = va_arg(args, const char *);
1532     const char *task = va_arg(args, const char *);
1533 
1534     xmlNodePtr xml_node = NULL;
1535 
1536     if (out->is_quiet(out)) {
1537         return pcmk_rc_no_output;
1538     }
1539 
1540     xml_node = pcmk__output_create_xml_node(out, "pseudo_action",
1541                                             "task", task,
1542                                             NULL);
1543     if (node) {
1544         crm_xml_add(xml_node, "node", node);
1545     }
1546 
1547     return pcmk_rc_ok;
1548 }
1549 
1550 PCMK__OUTPUT_ARGS("inject-rsc-action", "const char *", "const char *", "char *", "guint")
     /* [previous][next][first][last][top][bottom][index][help] */
1551 static int
1552 inject_rsc_action(pcmk__output_t *out, va_list args)
1553 {
1554     const char *rsc = va_arg(args, const char *);
1555     const char *operation = va_arg(args, const char *);
1556     char *node = va_arg(args, char *);
1557     guint interval_ms = va_arg(args, guint);
1558 
1559     if (out->is_quiet(out)) {
1560         return pcmk_rc_no_output;
1561     }
1562 
1563     if (interval_ms) {
1564         out->list_item(out, NULL, "Resource action: %-15s %s=%u on %s",
1565                        rsc, operation, interval_ms, node);
1566     } else {
1567         out->list_item(out, NULL, "Resource action: %-15s %s on %s",
1568                        rsc, operation, node);
1569     }
1570 
1571     return pcmk_rc_ok;
1572 }
1573 
1574 PCMK__OUTPUT_ARGS("inject-rsc-action", "const char *", "const char *", "char *", "guint")
     /* [previous][next][first][last][top][bottom][index][help] */
1575 static int
1576 inject_rsc_action_xml(pcmk__output_t *out, va_list args)
1577 {
1578     const char *rsc = va_arg(args, const char *);
1579     const char *operation = va_arg(args, const char *);
1580     char *node = va_arg(args, char *);
1581     guint interval_ms = va_arg(args, guint);
1582 
1583     xmlNodePtr xml_node = NULL;
1584 
1585     if (out->is_quiet(out)) {
1586         return pcmk_rc_no_output;
1587     }
1588 
1589     xml_node = pcmk__output_create_xml_node(out, "rsc_action",
1590                                             "resource", rsc,
1591                                             "op", operation,
1592                                             "node", node,
1593                                             NULL);
1594 
1595     if (interval_ms) {
1596         char *interval_s = pcmk__itoa(interval_ms);
1597 
1598         crm_xml_add(xml_node, "interval", interval_s);
1599         free(interval_s);
1600     }
1601 
1602     return pcmk_rc_ok;
1603 }
1604 
1605 #define CHECK_RC(retcode, retval)   \
1606     if (retval == pcmk_rc_ok) {     \
1607         retcode = pcmk_rc_ok;       \
1608     }
1609 
1610 PCMK__OUTPUT_ARGS("cluster-status", "pe_working_set_t *", "crm_exit_t", "stonith_history_t *",
     /* [previous][next][first][last][top][bottom][index][help] */
1611                   "enum pcmk__fence_history", "uint32_t", "uint32_t", "const char *", "GList *",
1612                   "GList *")
1613 int
1614 pcmk__cluster_status_text(pcmk__output_t *out, va_list args)
1615 {
1616     pe_working_set_t *data_set = va_arg(args, pe_working_set_t *);
1617     crm_exit_t history_rc = va_arg(args, crm_exit_t);
1618     stonith_history_t *stonith_history = va_arg(args, stonith_history_t *);
1619     enum pcmk__fence_history fence_history = va_arg(args, int);
1620     uint32_t section_opts = va_arg(args, uint32_t);
1621     uint32_t show_opts = va_arg(args, uint32_t);
1622     const char *prefix = va_arg(args, const char *);
1623     GList *unames = va_arg(args, GList *);
1624     GList *resources = va_arg(args, GList *);
1625 
1626     int rc = pcmk_rc_no_output;
1627     bool already_printed_failure = false;
1628 
1629     CHECK_RC(rc, out->message(out, "cluster-summary", data_set,
1630                               section_opts, show_opts));
1631 
1632     if (pcmk_is_set(section_opts, pcmk_section_nodes) && unames) {
1633         CHECK_RC(rc, out->message(out, "node-list", data_set->nodes, unames,
1634                                   resources, show_opts, rc == pcmk_rc_ok));
1635     }
1636 
1637     /* Print resources section, if needed */
1638     if (pcmk_is_set(section_opts, pcmk_section_resources)) {
1639         CHECK_RC(rc, out->message(out, "resource-list", data_set, show_opts,
1640                                   true, unames, resources, rc == pcmk_rc_ok));
1641     }
1642 
1643     /* print Node Attributes section if requested */
1644     if (pcmk_is_set(section_opts, pcmk_section_attributes)) {
1645         CHECK_RC(rc, out->message(out, "node-attribute-list", data_set,
1646                                   show_opts, rc == pcmk_rc_ok, unames, resources));
1647     }
1648 
1649     /* If requested, print resource operations (which includes failcounts)
1650      * or just failcounts
1651      */
1652     if (pcmk_any_flags_set(section_opts, pcmk_section_operations | pcmk_section_failcounts)) {
1653         CHECK_RC(rc, out->message(out, "node-summary", data_set, unames,
1654                                   resources, section_opts, show_opts, rc == pcmk_rc_ok));
1655     }
1656 
1657     /* If there were any failed actions, print them */
1658     if (pcmk_is_set(section_opts, pcmk_section_failures)
1659         && xml_has_children(data_set->failed)) {
1660 
1661         CHECK_RC(rc, out->message(out, "failed-action-list", data_set, unames,
1662                                   resources, show_opts, rc == pcmk_rc_ok));
1663     }
1664 
1665     /* Print failed stonith actions */
1666     if (pcmk_is_set(section_opts, pcmk_section_fence_failed) &&
1667         fence_history != pcmk__fence_history_none) {
1668         if (history_rc == 0) {
1669             stonith_history_t *hp = stonith__first_matching_event(stonith_history, stonith__event_state_eq,
1670                                                                   GINT_TO_POINTER(st_failed));
1671 
1672             if (hp) {
1673                 CHECK_RC(rc, out->message(out, "failed-fencing-list",
1674                                           stonith_history, unames, section_opts,
1675                                           show_opts, rc == pcmk_rc_ok));
1676             }
1677         } else {
1678             PCMK__OUTPUT_SPACER_IF(out, rc == pcmk_rc_ok);
1679             out->begin_list(out, NULL, NULL, "Failed Fencing Actions");
1680             out->list_item(out, NULL, "Failed to get fencing history: %s",
1681                            crm_exit_str(history_rc));
1682             out->end_list(out);
1683 
1684             already_printed_failure = true;
1685         }
1686     }
1687 
1688     /* Print tickets if requested */
1689     if (pcmk_is_set(section_opts, pcmk_section_tickets)) {
1690         CHECK_RC(rc, out->message(out, "ticket-list", data_set, rc == pcmk_rc_ok));
1691     }
1692 
1693     /* Print negative location constraints if requested */
1694     if (pcmk_is_set(section_opts, pcmk_section_bans)) {
1695         CHECK_RC(rc, out->message(out, "ban-list", data_set, prefix, resources,
1696                                   show_opts, rc == pcmk_rc_ok));
1697     }
1698 
1699     /* Print stonith history */
1700     if (pcmk_any_flags_set(section_opts, pcmk_section_fencing_all) &&
1701         fence_history != pcmk__fence_history_none) {
1702         if (history_rc != 0) {
1703             if (!already_printed_failure) {
1704                 PCMK__OUTPUT_SPACER_IF(out, rc == pcmk_rc_ok);
1705                 out->begin_list(out, NULL, NULL, "Failed Fencing Actions");
1706                 out->list_item(out, NULL, "Failed to get fencing history: %s",
1707                                crm_exit_str(history_rc));
1708                 out->end_list(out);
1709             }
1710         } else if (pcmk_is_set(section_opts, pcmk_section_fence_worked)) {
1711             stonith_history_t *hp = stonith__first_matching_event(stonith_history, stonith__event_state_neq,
1712                                                                   GINT_TO_POINTER(st_failed));
1713 
1714             if (hp) {
1715                 CHECK_RC(rc, out->message(out, "fencing-list", hp, unames,
1716                                           section_opts, show_opts,
1717                                           rc == pcmk_rc_ok));
1718             }
1719         } else if (pcmk_is_set(section_opts, pcmk_section_fence_pending)) {
1720             stonith_history_t *hp = stonith__first_matching_event(stonith_history, stonith__event_state_pending, NULL);
1721 
1722             if (hp) {
1723                 CHECK_RC(rc, out->message(out, "pending-fencing-list", hp,
1724                                           unames, section_opts, show_opts,
1725                                           rc == pcmk_rc_ok));
1726             }
1727         }
1728     }
1729 
1730     return rc;
1731 }
1732 
1733 PCMK__OUTPUT_ARGS("cluster-status", "pe_working_set_t *", "crm_exit_t", "stonith_history_t *",
     /* [previous][next][first][last][top][bottom][index][help] */
1734                   "enum pcmk__fence_history", "uint32_t", "uint32_t", "const char *", "GList *",
1735                   "GList *")
1736 static int
1737 cluster_status_xml(pcmk__output_t *out, va_list args)
1738 {
1739     pe_working_set_t *data_set = va_arg(args, pe_working_set_t *);
1740     crm_exit_t history_rc = va_arg(args, crm_exit_t);
1741     stonith_history_t *stonith_history = va_arg(args, stonith_history_t *);
1742     enum pcmk__fence_history fence_history = va_arg(args, int);
1743     uint32_t section_opts = va_arg(args, uint32_t);
1744     uint32_t show_opts = va_arg(args, uint32_t);
1745     const char *prefix = va_arg(args, const char *);
1746     GList *unames = va_arg(args, GList *);
1747     GList *resources = va_arg(args, GList *);
1748 
1749     out->message(out, "cluster-summary", data_set, section_opts, show_opts);
1750 
1751     /*** NODES ***/
1752     if (pcmk_is_set(section_opts, pcmk_section_nodes)) {
1753         out->message(out, "node-list", data_set->nodes, unames, resources,
1754                      show_opts, false);
1755     }
1756 
1757     /* Print resources section, if needed */
1758     if (pcmk_is_set(section_opts, pcmk_section_resources)) {
1759         /* XML output always displays full details. */
1760         uint32_t full_show_opts = show_opts & ~pcmk_show_brief;
1761 
1762         out->message(out, "resource-list", data_set, full_show_opts,
1763                      false, unames, resources, false);
1764     }
1765 
1766     /* print Node Attributes section if requested */
1767     if (pcmk_is_set(section_opts, pcmk_section_attributes)) {
1768         out->message(out, "node-attribute-list", data_set, show_opts, false,
1769                      unames, resources);
1770     }
1771 
1772     /* If requested, print resource operations (which includes failcounts)
1773      * or just failcounts
1774      */
1775     if (pcmk_any_flags_set(section_opts, pcmk_section_operations | pcmk_section_failcounts)) {
1776         out->message(out, "node-summary", data_set, unames,
1777                      resources, section_opts, show_opts, false);
1778     }
1779 
1780     /* If there were any failed actions, print them */
1781     if (pcmk_is_set(section_opts, pcmk_section_failures)
1782         && xml_has_children(data_set->failed)) {
1783 
1784         out->message(out, "failed-action-list", data_set, unames, resources,
1785                      show_opts, false);
1786     }
1787 
1788     /* Print stonith history */
1789     if (pcmk_is_set(section_opts, pcmk_section_fencing_all) &&
1790         fence_history != pcmk__fence_history_none) {
1791         out->message(out, "full-fencing-list", history_rc, stonith_history,
1792                      unames, section_opts, show_opts, false);
1793     }
1794 
1795     /* Print tickets if requested */
1796     if (pcmk_is_set(section_opts, pcmk_section_tickets)) {
1797         out->message(out, "ticket-list", data_set, false);
1798     }
1799 
1800     /* Print negative location constraints if requested */
1801     if (pcmk_is_set(section_opts, pcmk_section_bans)) {
1802         out->message(out, "ban-list", data_set, prefix, resources, show_opts,
1803                      false);
1804     }
1805 
1806     return pcmk_rc_ok;
1807 }
1808 
1809 PCMK__OUTPUT_ARGS("cluster-status", "pe_working_set_t *", "crm_exit_t", "stonith_history_t *",
     /* [previous][next][first][last][top][bottom][index][help] */
1810                   "enum pcmk__fence_history", "uint32_t", "uint32_t", "const char *", "GList *",
1811                   "GList *")
1812 static int
1813 cluster_status_html(pcmk__output_t *out, va_list args)
1814 {
1815     pe_working_set_t *data_set = va_arg(args, pe_working_set_t *);
1816     crm_exit_t history_rc = va_arg(args, crm_exit_t);
1817     stonith_history_t *stonith_history = va_arg(args, stonith_history_t *);
1818     enum pcmk__fence_history fence_history = va_arg(args, int);
1819     uint32_t section_opts = va_arg(args, uint32_t);
1820     uint32_t show_opts = va_arg(args, uint32_t);
1821     const char *prefix = va_arg(args, const char *);
1822     GList *unames = va_arg(args, GList *);
1823     GList *resources = va_arg(args, GList *);
1824     bool already_printed_failure = false;
1825 
1826     out->message(out, "cluster-summary", data_set, section_opts, show_opts);
1827 
1828     /*** NODE LIST ***/
1829     if (pcmk_is_set(section_opts, pcmk_section_nodes) && unames) {
1830         out->message(out, "node-list", data_set->nodes, unames, resources,
1831                      show_opts, false);
1832     }
1833 
1834     /* Print resources section, if needed */
1835     if (pcmk_is_set(section_opts, pcmk_section_resources)) {
1836         out->message(out, "resource-list", data_set, show_opts, true, unames,
1837                      resources, false);
1838     }
1839 
1840     /* print Node Attributes section if requested */
1841     if (pcmk_is_set(section_opts, pcmk_section_attributes)) {
1842         out->message(out, "node-attribute-list", data_set, show_opts, false,
1843                      unames, resources);
1844     }
1845 
1846     /* If requested, print resource operations (which includes failcounts)
1847      * or just failcounts
1848      */
1849     if (pcmk_any_flags_set(section_opts, pcmk_section_operations | pcmk_section_failcounts)) {
1850         out->message(out, "node-summary", data_set, unames,
1851                      resources, section_opts, show_opts, false);
1852     }
1853 
1854     /* If there were any failed actions, print them */
1855     if (pcmk_is_set(section_opts, pcmk_section_failures)
1856         && xml_has_children(data_set->failed)) {
1857 
1858         out->message(out, "failed-action-list", data_set, unames, resources,
1859                      show_opts, false);
1860     }
1861 
1862     /* Print failed stonith actions */
1863     if (pcmk_is_set(section_opts, pcmk_section_fence_failed) &&
1864         fence_history != pcmk__fence_history_none) {
1865         if (history_rc == 0) {
1866             stonith_history_t *hp = stonith__first_matching_event(stonith_history, stonith__event_state_eq,
1867                                                                   GINT_TO_POINTER(st_failed));
1868 
1869             if (hp) {
1870                 out->message(out, "failed-fencing-list", stonith_history, unames,
1871                              section_opts, show_opts, false);
1872             }
1873         } else {
1874             out->begin_list(out, NULL, NULL, "Failed Fencing Actions");
1875             out->list_item(out, NULL, "Failed to get fencing history: %s",
1876                            crm_exit_str(history_rc));
1877             out->end_list(out);
1878         }
1879     }
1880 
1881     /* Print stonith history */
1882     if (pcmk_any_flags_set(section_opts, pcmk_section_fencing_all) &&
1883         fence_history != pcmk__fence_history_none) {
1884         if (history_rc != 0) {
1885             if (!already_printed_failure) {
1886                 out->begin_list(out, NULL, NULL, "Failed Fencing Actions");
1887                 out->list_item(out, NULL, "Failed to get fencing history: %s",
1888                                crm_exit_str(history_rc));
1889                 out->end_list(out);
1890             }
1891         } else if (pcmk_is_set(section_opts, pcmk_section_fence_worked)) {
1892             stonith_history_t *hp = stonith__first_matching_event(stonith_history, stonith__event_state_neq,
1893                                                                   GINT_TO_POINTER(st_failed));
1894 
1895             if (hp) {
1896                 out->message(out, "fencing-list", hp, unames, section_opts,
1897                              show_opts, false);
1898             }
1899         } else if (pcmk_is_set(section_opts, pcmk_section_fence_pending)) {
1900             stonith_history_t *hp = stonith__first_matching_event(stonith_history, stonith__event_state_pending, NULL);
1901 
1902             if (hp) {
1903                 out->message(out, "pending-fencing-list", hp, unames,
1904                              section_opts, show_opts, false);
1905             }
1906         }
1907     }
1908 
1909     /* Print tickets if requested */
1910     if (pcmk_is_set(section_opts, pcmk_section_tickets)) {
1911         out->message(out, "ticket-list", data_set, false);
1912     }
1913 
1914     /* Print negative location constraints if requested */
1915     if (pcmk_is_set(section_opts, pcmk_section_bans)) {
1916         out->message(out, "ban-list", data_set, prefix, resources, show_opts,
1917                      false);
1918     }
1919 
1920     return pcmk_rc_ok;
1921 }
1922 
1923 PCMK__OUTPUT_ARGS("attribute", "const char *", "const char *", "const char *",
     /* [previous][next][first][last][top][bottom][index][help] */
1924                   "const char *", "const char *")
1925 static int
1926 attribute_default(pcmk__output_t *out, va_list args)
1927 {
1928     const char *scope = va_arg(args, const char *);
1929     const char *instance = va_arg(args, const char *);
1930     const char *name = va_arg(args, const char *);
1931     const char *value = va_arg(args, const char *);
1932     const char *host = va_arg(args, const char *);
1933 
1934     GString *s = g_string_sized_new(50);
1935 
1936     if (!pcmk__str_empty(scope)) {
1937         pcmk__g_strcat(s, "scope=\"", scope, "\" ", NULL);
1938     }
1939 
1940     if (!pcmk__str_empty(instance)) {
1941         pcmk__g_strcat(s, "id=\"", instance, "\" ", NULL);
1942     }
1943 
1944     pcmk__g_strcat(s, "name=\"", pcmk__s(name, ""), "\" ", NULL);
1945 
1946     if (!pcmk__str_empty(host)) {
1947         pcmk__g_strcat(s, "host=\"", host, "\" ", NULL);
1948     }
1949 
1950     pcmk__g_strcat(s, "value=\"", pcmk__s(value, ""), "\"", NULL);
1951 
1952     out->info(out, "%s", s->str);
1953     g_string_free(s, TRUE);
1954 
1955     return pcmk_rc_ok;
1956 }
1957 
1958 PCMK__OUTPUT_ARGS("attribute", "const char *", "const char *", "const char *",
     /* [previous][next][first][last][top][bottom][index][help] */
1959                   "const char *", "const char *")
1960 static int
1961 attribute_xml(pcmk__output_t *out, va_list args)
1962 {
1963     const char *scope = va_arg(args, const char *);
1964     const char *instance = va_arg(args, const char *);
1965     const char *name = va_arg(args, const char *);
1966     const char *value = va_arg(args, const char *);
1967     const char *host = va_arg(args, const char *);
1968 
1969     xmlNodePtr node = NULL;
1970 
1971     node = pcmk__output_create_xml_node(out, "attribute",
1972                                         "name", name,
1973                                         "value", value ? value : "",
1974                                         NULL);
1975 
1976     if (!pcmk__str_empty(scope)) {
1977         crm_xml_add(node, "scope", scope);
1978     }
1979 
1980     if (!pcmk__str_empty(instance)) {
1981         crm_xml_add(node, "id", instance);
1982     }
1983 
1984     if (!pcmk__str_empty(host)) {
1985         crm_xml_add(node, "host", host);
1986     }
1987 
1988     return pcmk_rc_ok;
1989 }
1990 
1991 PCMK__OUTPUT_ARGS("rule-check", "const char *", "int", "const char *")
     /* [previous][next][first][last][top][bottom][index][help] */
1992 static int
1993 rule_check_default(pcmk__output_t *out, va_list args)
1994 {
1995     const char *rule_id = va_arg(args, const char *);
1996     int result = va_arg(args, int);
1997     const char *error = va_arg(args, const char *);
1998 
1999     switch (result) {
2000         case pcmk_rc_within_range:
2001             return out->info(out, "Rule %s is still in effect", rule_id);
2002         case pcmk_rc_ok:
2003             return out->info(out, "Rule %s satisfies conditions", rule_id);
2004         case pcmk_rc_after_range:
2005             return out->info(out, "Rule %s is expired", rule_id);
2006         case pcmk_rc_before_range:
2007             return out->info(out, "Rule %s has not yet taken effect", rule_id);
2008         case pcmk_rc_op_unsatisfied:
2009             return out->info(out, "Rule %s does not satisfy conditions",
2010                              rule_id);
2011         default:
2012             out->err(out,
2013                      "Could not determine whether rule %s is in effect: %s",
2014                      rule_id, ((error != NULL)? error : "unexpected error"));
2015             return pcmk_rc_ok;
2016     }
2017 }
2018 
2019 PCMK__OUTPUT_ARGS("rule-check", "const char *", "int", "const char *")
     /* [previous][next][first][last][top][bottom][index][help] */
2020 static int
2021 rule_check_xml(pcmk__output_t *out, va_list args)
2022 {
2023     const char *rule_id = va_arg(args, const char *);
2024     int result = va_arg(args, int);
2025     const char *error = va_arg(args, const char *);
2026 
2027     char *rc_str = pcmk__itoa(pcmk_rc2exitc(result));
2028 
2029     pcmk__output_create_xml_node(out, "rule-check",
2030                                  "rule-id", rule_id,
2031                                  "rc", rc_str,
2032                                  NULL);
2033     free(rc_str);
2034 
2035     switch (result) {
2036         case pcmk_rc_within_range:
2037         case pcmk_rc_ok:
2038         case pcmk_rc_after_range:
2039         case pcmk_rc_before_range:
2040         case pcmk_rc_op_unsatisfied:
2041             return pcmk_rc_ok;
2042         default:
2043             out->err(out,
2044                     "Could not determine whether rule %s is in effect: %s",
2045                     rule_id, ((error != NULL)? error : "unexpected error"));
2046             return pcmk_rc_ok;
2047     }
2048 }
2049 
2050 PCMK__OUTPUT_ARGS("result-code", "int", "const char *", "const char *")
     /* [previous][next][first][last][top][bottom][index][help] */
2051 static int
2052 result_code_none(pcmk__output_t *out, va_list args)
2053 {
2054     return pcmk_rc_no_output;
2055 }
2056 
2057 PCMK__OUTPUT_ARGS("result-code", "int", "const char *", "const char *")
     /* [previous][next][first][last][top][bottom][index][help] */
2058 static int
2059 result_code_text(pcmk__output_t *out, va_list args)
2060 {
2061     int code = va_arg(args, int);
2062     const char *name = va_arg(args, const char *);
2063     const char *desc = va_arg(args, const char *);
2064 
2065     static int code_width = 0;
2066 
2067     if (out->is_quiet(out)) {
2068         /* If out->is_quiet(), don't print the code. Print name and/or desc in a
2069          * compact format for text output, or print nothing at all for none-type
2070          * output.
2071          */
2072         if ((name != NULL) && (desc != NULL)) {
2073             pcmk__formatted_printf(out, "%s - %s\n", name, desc);
2074 
2075         } else if ((name != NULL) || (desc != NULL)) {
2076             pcmk__formatted_printf(out, "%s\n", ((name != NULL)? name : desc));
2077         }
2078         return pcmk_rc_ok;
2079     }
2080 
2081     /* Get length of longest (most negative) standard Pacemaker return code
2082      * This should be longer than all the values of any other type of return
2083      * code.
2084      */
2085     if (code_width == 0) {
2086         long long most_negative = pcmk_rc_error - (long long) pcmk__n_rc + 1;
2087         code_width = (int) snprintf(NULL, 0, "%lld", most_negative);
2088     }
2089 
2090     if ((name != NULL) && (desc != NULL)) {
2091         static int name_width = 0;
2092 
2093         if (name_width == 0) {
2094             // Get length of longest standard Pacemaker return code name
2095             for (int lpc = 0; lpc < pcmk__n_rc; lpc++) {
2096                 int len = (int) strlen(pcmk_rc_name(pcmk_rc_error - lpc));
2097                 name_width = QB_MAX(name_width, len);
2098             }
2099         }
2100         return out->info(out, "% *d: %-*s  %s", code_width, code, name_width,
2101                          name, desc);
2102     }
2103 
2104     if ((name != NULL) || (desc != NULL)) {
2105         return out->info(out, "% *d: %s", code_width, code,
2106                          ((name != NULL)? name : desc));
2107     }
2108 
2109     return out->info(out, "% *d", code_width, code);
2110 }
2111 
2112 PCMK__OUTPUT_ARGS("result-code", "int", "const char *", "const char *")
     /* [previous][next][first][last][top][bottom][index][help] */
2113 static int
2114 result_code_xml(pcmk__output_t *out, va_list args)
2115 {
2116     int code = va_arg(args, int);
2117     const char *name = va_arg(args, const char *);
2118     const char *desc = va_arg(args, const char *);
2119 
2120     char *code_str = pcmk__itoa(code);
2121 
2122     pcmk__output_create_xml_node(out, "result-code",
2123                                  "code", code_str,
2124                                  XML_ATTR_NAME, name,
2125                                  XML_ATTR_DESC, desc,
2126                                  NULL);
2127     free(code_str);
2128     return pcmk_rc_ok;
2129 }
2130 
2131 static pcmk__message_entry_t fmt_functions[] = {
2132     { "attribute", "default", attribute_default },
2133     { "attribute", "xml", attribute_xml },
2134     { "cluster-status", "default", pcmk__cluster_status_text },
2135     { "cluster-status", "html", cluster_status_html },
2136     { "cluster-status", "xml", cluster_status_xml },
2137     { "crmadmin-node", "default", crmadmin_node },
2138     { "crmadmin-node", "text", crmadmin_node_text },
2139     { "crmadmin-node", "xml", crmadmin_node_xml },
2140     { "dc", "default", dc },
2141     { "dc", "text", dc_text },
2142     { "dc", "xml", dc_xml },
2143     { "digests", "default", digests_text },
2144     { "digests", "xml", digests_xml },
2145     { "health", "default", health },
2146     { "health", "text", health_text },
2147     { "health", "xml", health_xml },
2148     { "inject-attr", "default", inject_attr },
2149     { "inject-attr", "xml", inject_attr_xml },
2150     { "inject-cluster-action", "default", inject_cluster_action },
2151     { "inject-cluster-action", "xml", inject_cluster_action_xml },
2152     { "inject-fencing-action", "default", inject_fencing_action },
2153     { "inject-fencing-action", "xml", inject_fencing_action_xml },
2154     { "inject-modify-config", "default", inject_modify_config },
2155     { "inject-modify-config", "xml", inject_modify_config_xml },
2156     { "inject-modify-node", "default", inject_modify_node },
2157     { "inject-modify-node", "xml", inject_modify_node_xml },
2158     { "inject-modify-ticket", "default", inject_modify_ticket },
2159     { "inject-modify-ticket", "xml", inject_modify_ticket_xml },
2160     { "inject-pseudo-action", "default", inject_pseudo_action },
2161     { "inject-pseudo-action", "xml", inject_pseudo_action_xml },
2162     { "inject-rsc-action", "default", inject_rsc_action },
2163     { "inject-rsc-action", "xml", inject_rsc_action_xml },
2164     { "inject-spec", "default", inject_spec },
2165     { "inject-spec", "xml", inject_spec_xml },
2166     { "locations-list", "default", locations_list },
2167     { "locations-list", "xml", locations_list_xml },
2168     { "node-action", "default", node_action },
2169     { "node-action", "xml", node_action_xml },
2170     { "pacemakerd-health", "default", pacemakerd_health },
2171     { "pacemakerd-health", "html", pacemakerd_health_html },
2172     { "pacemakerd-health", "text", pacemakerd_health_text },
2173     { "pacemakerd-health", "xml", pacemakerd_health_xml },
2174     { "profile", "default", profile_default, },
2175     { "profile", "xml", profile_xml },
2176     { "result-code", "none", result_code_none },
2177     { "result-code", "text", result_code_text },
2178     { "result-code", "xml", result_code_xml },
2179     { "rsc-action", "default", rsc_action_default },
2180     { "rsc-action-item", "default", rsc_action_item },
2181     { "rsc-action-item", "xml", rsc_action_item_xml },
2182     { "rsc-is-colocated-with-list", "default", rsc_is_colocated_with_list },
2183     { "rsc-is-colocated-with-list", "xml", rsc_is_colocated_with_list_xml },
2184     { "rscs-colocated-with-list", "default", rscs_colocated_with_list },
2185     { "rscs-colocated-with-list", "xml", rscs_colocated_with_list_xml },
2186     { "rule-check", "default", rule_check_default },
2187     { "rule-check", "xml", rule_check_xml },
2188     { "locations-and-colocations", "default", locations_and_colocations },
2189     { "locations-and-colocations", "xml", locations_and_colocations_xml },
2190 
2191     { NULL, NULL, NULL }
2192 };
2193 
2194 void
2195 pcmk__register_lib_messages(pcmk__output_t *out) {
     /* [previous][next][first][last][top][bottom][index][help] */
2196     pcmk__register_messages(out, fmt_functions);
2197 }

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