root/lib/pengine/native.c

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

DEFINITIONS

This source file includes following definitions.
  1. is_multiply_active
  2. native_priority_to_node
  3. native_add_running
  4. recursive_clear_unique
  5. native_unpack
  6. rsc_is_on_node
  7. native_find_rsc
  8. native_parameter
  9. native_active
  10. native_pending_state
  11. native_pending_task
  12. native_displayable_role
  13. native_displayable_state
  14. native_print_xml
  15. add_output_flag
  16. add_output_node
  17. pcmk__native_output_string
  18. pe__common_output_html
  19. pe__common_output_text
  20. common_print
  21. native_print
  22. PCMK__OUTPUT_ARGS
  23. PCMK__OUTPUT_ARGS
  24. PCMK__OUTPUT_ARGS
  25. native_free
  26. native_resource_state
  27. native_location
  28. get_rscs_brief
  29. destroy_node_table
  30. print_rscs_brief
  31. pe__rscs_brief_output
  32. pe__native_is_filtered

   1 /*
   2  * Copyright 2004-2021 the Pacemaker project contributors
   3  *
   4  * The version control history for this file may have further details.
   5  *
   6  * This source code is licensed under the GNU Lesser General Public License
   7  * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
   8  */
   9 
  10 #include <crm_internal.h>
  11 
  12 #include <crm/pengine/rules.h>
  13 #include <crm/pengine/status.h>
  14 #include <crm/pengine/complex.h>
  15 #include <crm/pengine/internal.h>
  16 #include <crm/msg_xml.h>
  17 #include <pe_status_private.h>
  18 
  19 #define VARIANT_NATIVE 1
  20 #include "./variant.h"
  21 
  22 #ifdef PCMK__COMPAT_2_0
  23 #define PROVIDER_SEP "::"
  24 #else
  25 #define PROVIDER_SEP ":"
  26 #endif
  27 
  28 /*!
  29  * \internal
  30  * \brief Check whether a resource is active on multiple nodes
  31  */
  32 static bool
  33 is_multiply_active(pe_resource_t *rsc)
     /* [previous][next][first][last][top][bottom][index][help] */
  34 {
  35     unsigned int count = 0;
  36 
  37     if (rsc->variant == pe_native) {
  38         pe__find_active_requires(rsc, &count);
  39     }
  40     return count > 1;
  41 }
  42 
  43 static void
  44 native_priority_to_node(pe_resource_t * rsc, pe_node_t * node, gboolean failed)
     /* [previous][next][first][last][top][bottom][index][help] */
  45 {
  46     int priority = 0;
  47 
  48     if ((rsc->priority == 0) || (failed == TRUE)) {
  49         return;
  50     }
  51 
  52     if (rsc->role == RSC_ROLE_PROMOTED) {
  53         // Promoted instance takes base priority + 1
  54         priority = rsc->priority + 1;
  55 
  56     } else {
  57         priority = rsc->priority;
  58     }
  59 
  60     node->details->priority += priority;
  61     pe_rsc_trace(rsc, "Node '%s' now has priority %d with %s'%s' (priority: %d%s)",
  62                  node->details->uname, node->details->priority,
  63                  (rsc->role == RSC_ROLE_PROMOTED)? "promoted " : "",
  64                  rsc->id, rsc->priority,
  65                  (rsc->role == RSC_ROLE_PROMOTED)? " + 1" : "");
  66 
  67     /* Priority of a resource running on a guest node is added to the cluster
  68      * node as well. */
  69     if (node->details->remote_rsc
  70         && node->details->remote_rsc->container) {
  71         GList *gIter = node->details->remote_rsc->container->running_on;
  72 
  73         for (; gIter != NULL; gIter = gIter->next) {
  74             pe_node_t *a_node = gIter->data;
  75 
  76             a_node->details->priority += priority;
  77             pe_rsc_trace(rsc, "Node '%s' now has priority %d with %s'%s' (priority: %d%s) "
  78                          "from guest node '%s'",
  79                          a_node->details->uname, a_node->details->priority,
  80                          (rsc->role == RSC_ROLE_PROMOTED)? "promoted " : "",
  81                          rsc->id, rsc->priority,
  82                          (rsc->role == RSC_ROLE_PROMOTED)? " + 1" : "",
  83                          node->details->uname);
  84         }
  85     }
  86 }
  87 
  88 void
  89 native_add_running(pe_resource_t * rsc, pe_node_t * node, pe_working_set_t * data_set, gboolean failed)
     /* [previous][next][first][last][top][bottom][index][help] */
  90 {
  91     GList *gIter = rsc->running_on;
  92 
  93     CRM_CHECK(node != NULL, return);
  94     for (; gIter != NULL; gIter = gIter->next) {
  95         pe_node_t *a_node = (pe_node_t *) gIter->data;
  96 
  97         CRM_CHECK(a_node != NULL, return);
  98         if (pcmk__str_eq(a_node->details->id, node->details->id, pcmk__str_casei)) {
  99             return;
 100         }
 101     }
 102 
 103     pe_rsc_trace(rsc, "Adding %s to %s %s", rsc->id, node->details->uname,
 104                  pcmk_is_set(rsc->flags, pe_rsc_managed)? "" : "(unmanaged)");
 105 
 106     rsc->running_on = g_list_append(rsc->running_on, node);
 107     if (rsc->variant == pe_native) {
 108         node->details->running_rsc = g_list_append(node->details->running_rsc, rsc);
 109 
 110         native_priority_to_node(rsc, node, failed);
 111     }
 112 
 113     if (rsc->variant == pe_native && node->details->maintenance) {
 114         pe__clear_resource_flags(rsc, pe_rsc_managed);
 115     }
 116 
 117     if (!pcmk_is_set(rsc->flags, pe_rsc_managed)) {
 118         pe_resource_t *p = rsc->parent;
 119 
 120         pe_rsc_info(rsc, "resource %s isn't managed", rsc->id);
 121         resource_location(rsc, node, INFINITY, "not_managed_default", data_set);
 122 
 123         while(p && node->details->online) {
 124             /* add without the additional location constraint */
 125             p->running_on = g_list_append(p->running_on, node);
 126             p = p->parent;
 127         }
 128         return;
 129     }
 130 
 131     if (is_multiply_active(rsc)) {
 132         switch (rsc->recovery_type) {
 133             case recovery_stop_only:
 134                 {
 135                     GHashTableIter gIter;
 136                     pe_node_t *local_node = NULL;
 137 
 138                     /* make sure it doesn't come up again */
 139                     if (rsc->allowed_nodes != NULL) {
 140                         g_hash_table_destroy(rsc->allowed_nodes);
 141                     }
 142                     rsc->allowed_nodes = pe__node_list2table(data_set->nodes);
 143                     g_hash_table_iter_init(&gIter, rsc->allowed_nodes);
 144                     while (g_hash_table_iter_next(&gIter, NULL, (void **)&local_node)) {
 145                         local_node->weight = -INFINITY;
 146                     }
 147                 }
 148                 break;
 149             case recovery_stop_start:
 150                 break;
 151             case recovery_block:
 152                 pe__clear_resource_flags(rsc, pe_rsc_managed);
 153                 pe__set_resource_flags(rsc, pe_rsc_block);
 154 
 155                 /* If the resource belongs to a group or bundle configured with
 156                  * multiple-active=block, block the entire entity.
 157                  */
 158                 if (rsc->parent
 159                     && (rsc->parent->variant == pe_group || rsc->parent->variant == pe_container)
 160                     && rsc->parent->recovery_type == recovery_block) {
 161                     GList *gIter = rsc->parent->children;
 162 
 163                     for (; gIter != NULL; gIter = gIter->next) {
 164                         pe_resource_t *child = (pe_resource_t *) gIter->data;
 165 
 166                         pe__clear_resource_flags(child, pe_rsc_managed);
 167                         pe__set_resource_flags(child, pe_rsc_block);
 168                     }
 169                 }
 170                 break;
 171         }
 172         crm_debug("%s is active on multiple nodes including %s: %s",
 173                   rsc->id, node->details->uname,
 174                   recovery2text(rsc->recovery_type));
 175 
 176     } else {
 177         pe_rsc_trace(rsc, "Resource %s is active on: %s", rsc->id, node->details->uname);
 178     }
 179 
 180     if (rsc->parent != NULL) {
 181         native_add_running(rsc->parent, node, data_set, FALSE);
 182     }
 183 }
 184 
 185 static void
 186 recursive_clear_unique(pe_resource_t *rsc)
     /* [previous][next][first][last][top][bottom][index][help] */
 187 {
 188     pe__clear_resource_flags(rsc, pe_rsc_unique);
 189     add_hash_param(rsc->meta, XML_RSC_ATTR_UNIQUE, XML_BOOLEAN_FALSE);
 190 
 191     for (GList *child = rsc->children; child != NULL; child = child->next) {
 192         recursive_clear_unique((pe_resource_t *) child->data);
 193     }
 194 }
 195 
 196 gboolean
 197 native_unpack(pe_resource_t * rsc, pe_working_set_t * data_set)
     /* [previous][next][first][last][top][bottom][index][help] */
 198 {
 199     pe_resource_t *parent = uber_parent(rsc);
 200     native_variant_data_t *native_data = NULL;
 201     const char *standard = crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS);
 202     uint32_t ra_caps = pcmk_get_ra_caps(standard);
 203 
 204     pe_rsc_trace(rsc, "Processing resource %s...", rsc->id);
 205 
 206     native_data = calloc(1, sizeof(native_variant_data_t));
 207     rsc->variant_opaque = native_data;
 208 
 209     // Only some agent standards support unique and promotable clones
 210     if (!pcmk_is_set(ra_caps, pcmk_ra_cap_unique)
 211         && pcmk_is_set(rsc->flags, pe_rsc_unique) && pe_rsc_is_clone(parent)) {
 212 
 213         /* @COMPAT We should probably reject this situation as an error (as we
 214          * do for promotable below) rather than warn and convert, but that would
 215          * be a backward-incompatible change that we should probably do with a
 216          * transform at a schema major version bump.
 217          */
 218         pe__force_anon(standard, parent, rsc->id, data_set);
 219 
 220         /* Clear globally-unique on the parent and all its descendents unpacked
 221          * so far (clearing the parent should make any future children unpacking
 222          * correct). We have to clear this resource explicitly because it isn't
 223          * hooked into the parent's children yet.
 224          */
 225         recursive_clear_unique(parent);
 226         recursive_clear_unique(rsc);
 227     }
 228     if (!pcmk_is_set(ra_caps, pcmk_ra_cap_promotable)
 229         && pcmk_is_set(parent->flags, pe_rsc_promotable)) {
 230 
 231         pe_err("Resource %s is of type %s and therefore "
 232                "cannot be used as a promotable clone resource",
 233                rsc->id, standard);
 234         return FALSE;
 235     }
 236     return TRUE;
 237 }
 238 
 239 static bool
 240 rsc_is_on_node(pe_resource_t *rsc, const pe_node_t *node, int flags)
     /* [previous][next][first][last][top][bottom][index][help] */
 241 {
 242     pe_rsc_trace(rsc, "Checking whether %s is on %s",
 243                  rsc->id, node->details->uname);
 244 
 245     if (pcmk_is_set(flags, pe_find_current) && rsc->running_on) {
 246 
 247         for (GList *iter = rsc->running_on; iter; iter = iter->next) {
 248             pe_node_t *loc = (pe_node_t *) iter->data;
 249 
 250             if (loc->details == node->details) {
 251                 return TRUE;
 252             }
 253         }
 254 
 255     } else if (pcmk_is_set(flags, pe_find_inactive)
 256                && (rsc->running_on == NULL)) {
 257         return TRUE;
 258 
 259     } else if (!pcmk_is_set(flags, pe_find_current) && rsc->allocated_to
 260                && (rsc->allocated_to->details == node->details)) {
 261         return TRUE;
 262     }
 263     return FALSE;
 264 }
 265 
 266 pe_resource_t *
 267 native_find_rsc(pe_resource_t * rsc, const char *id, const pe_node_t *on_node,
     /* [previous][next][first][last][top][bottom][index][help] */
 268                 int flags)
 269 {
 270     bool match = FALSE;
 271     pe_resource_t *result = NULL;
 272 
 273     CRM_CHECK(id && rsc && rsc->id, return NULL);
 274 
 275     if (flags & pe_find_clone) {
 276         const char *rid = ID(rsc->xml);
 277 
 278         if (!pe_rsc_is_clone(uber_parent(rsc))) {
 279             match = FALSE;
 280 
 281         } else if (!strcmp(id, rsc->id) || pcmk__str_eq(id, rid, pcmk__str_casei)) {
 282             match = TRUE;
 283         }
 284 
 285     } else if (!strcmp(id, rsc->id)) {
 286         match = TRUE;
 287 
 288     } else if (pcmk_is_set(flags, pe_find_renamed)
 289                && rsc->clone_name && strcmp(rsc->clone_name, id) == 0) {
 290         match = TRUE;
 291 
 292     } else if (pcmk_is_set(flags, pe_find_any)
 293                || (pcmk_is_set(flags, pe_find_anon)
 294                    && !pcmk_is_set(rsc->flags, pe_rsc_unique))) {
 295         match = pe_base_name_eq(rsc, id);
 296     }
 297 
 298     if (match && on_node) {
 299         bool match_node = rsc_is_on_node(rsc, on_node, flags);
 300 
 301         if (match_node == FALSE) {
 302             match = FALSE;
 303         }
 304     }
 305 
 306     if (match) {
 307         return rsc;
 308     }
 309 
 310     for (GList *gIter = rsc->children; gIter != NULL; gIter = gIter->next) {
 311         pe_resource_t *child = (pe_resource_t *) gIter->data;
 312 
 313         result = rsc->fns->find_rsc(child, id, on_node, flags);
 314         if (result) {
 315             return result;
 316         }
 317     }
 318     return NULL;
 319 }
 320 
 321 // create is ignored
 322 char *
 323 native_parameter(pe_resource_t * rsc, pe_node_t * node, gboolean create, const char *name,
     /* [previous][next][first][last][top][bottom][index][help] */
 324                  pe_working_set_t * data_set)
 325 {
 326     char *value_copy = NULL;
 327     const char *value = NULL;
 328     GHashTable *params = NULL;
 329 
 330     CRM_CHECK(rsc != NULL, return NULL);
 331     CRM_CHECK(name != NULL && strlen(name) != 0, return NULL);
 332 
 333     pe_rsc_trace(rsc, "Looking up %s in %s", name, rsc->id);
 334     params = pe_rsc_params(rsc, node, data_set);
 335     value = g_hash_table_lookup(params, name);
 336     if (value == NULL) {
 337         /* try meta attributes instead */
 338         value = g_hash_table_lookup(rsc->meta, name);
 339     }
 340     if (value != NULL) {
 341         value_copy = strdup(value);
 342     }
 343     return value_copy;
 344 }
 345 
 346 gboolean
 347 native_active(pe_resource_t * rsc, gboolean all)
     /* [previous][next][first][last][top][bottom][index][help] */
 348 {
 349     for (GList *gIter = rsc->running_on; gIter != NULL; gIter = gIter->next) {
 350         pe_node_t *a_node = (pe_node_t *) gIter->data;
 351 
 352         if (a_node->details->unclean) {
 353             pe_rsc_trace(rsc, "Resource %s: node %s is unclean",
 354                          rsc->id, a_node->details->uname);
 355             return TRUE;
 356         } else if (a_node->details->online == FALSE) {
 357             pe_rsc_trace(rsc, "Resource %s: node %s is offline",
 358                          rsc->id, a_node->details->uname);
 359         } else {
 360             pe_rsc_trace(rsc, "Resource %s active on %s",
 361                          rsc->id, a_node->details->uname);
 362             return TRUE;
 363         }
 364     }
 365     return FALSE;
 366 }
 367 
 368 struct print_data_s {
 369     long options;
 370     void *print_data;
 371 };
 372 
 373 static const char *
 374 native_pending_state(pe_resource_t * rsc)
     /* [previous][next][first][last][top][bottom][index][help] */
 375 {
 376     const char *pending_state = NULL;
 377 
 378     if (pcmk__str_eq(rsc->pending_task, CRMD_ACTION_START, pcmk__str_casei)) {
 379         pending_state = "Starting";
 380 
 381     } else if (pcmk__str_eq(rsc->pending_task, CRMD_ACTION_STOP, pcmk__str_casei)) {
 382         pending_state = "Stopping";
 383 
 384     } else if (pcmk__str_eq(rsc->pending_task, CRMD_ACTION_MIGRATE, pcmk__str_casei)) {
 385         pending_state = "Migrating";
 386 
 387     } else if (pcmk__str_eq(rsc->pending_task, CRMD_ACTION_MIGRATED, pcmk__str_casei)) {
 388        /* Work might be done in here. */
 389         pending_state = "Migrating";
 390 
 391     } else if (pcmk__str_eq(rsc->pending_task, CRMD_ACTION_PROMOTE, pcmk__str_casei)) {
 392         pending_state = "Promoting";
 393 
 394     } else if (pcmk__str_eq(rsc->pending_task, CRMD_ACTION_DEMOTE, pcmk__str_casei)) {
 395         pending_state = "Demoting";
 396     }
 397 
 398     return pending_state;
 399 }
 400 
 401 static const char *
 402 native_pending_task(pe_resource_t * rsc)
     /* [previous][next][first][last][top][bottom][index][help] */
 403 {
 404     const char *pending_task = NULL;
 405 
 406     if (pcmk__str_eq(rsc->pending_task, CRMD_ACTION_STATUS, pcmk__str_casei)) {
 407         pending_task = "Monitoring";
 408 
 409     /* Pending probes are not printed, even if pending
 410      * operations are requested. If someone ever requests that
 411      * behavior, uncomment this and the corresponding part of
 412      * unpack.c:unpack_rsc_op().
 413      */
 414     /*
 415     } else if (pcmk__str_eq(rsc->pending_task, "probe", pcmk__str_casei)) {
 416         pending_task = "Checking";
 417     */
 418     }
 419 
 420     return pending_task;
 421 }
 422 
 423 static enum rsc_role_e
 424 native_displayable_role(pe_resource_t *rsc)
     /* [previous][next][first][last][top][bottom][index][help] */
 425 {
 426     enum rsc_role_e role = rsc->role;
 427 
 428     if ((role == RSC_ROLE_STARTED)
 429         && pcmk_is_set(uber_parent(rsc)->flags, pe_rsc_promotable)) {
 430 
 431         role = RSC_ROLE_UNPROMOTED;
 432     }
 433     return role;
 434 }
 435 
 436 static const char *
 437 native_displayable_state(pe_resource_t *rsc, long options)
     /* [previous][next][first][last][top][bottom][index][help] */
 438 {
 439     const char *rsc_state = NULL;
 440 
 441     if (options & pe_print_pending) {
 442         rsc_state = native_pending_state(rsc);
 443     }
 444     if (rsc_state == NULL) {
 445         rsc_state = role2text(native_displayable_role(rsc));
 446     }
 447     return rsc_state;
 448 }
 449 
 450 static void
 451 native_print_xml(pe_resource_t * rsc, const char *pre_text, long options, void *print_data)
     /* [previous][next][first][last][top][bottom][index][help] */
 452 {
 453     const char *class = crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS);
 454     const char *prov = crm_element_value(rsc->xml, XML_AGENT_ATTR_PROVIDER);
 455     const char *rsc_state = native_displayable_state(rsc, options);
 456     const char *target_role = NULL;
 457 
 458     /* resource information. */
 459     status_print("%s<resource ", pre_text);
 460     status_print("id=\"%s\" ", rsc_printable_id(rsc));
 461     status_print("resource_agent=\"%s%s%s:%s\" ", class,
 462                  ((prov == NULL)? "" : PROVIDER_SEP),
 463                  ((prov == NULL)? "" : prov),
 464                  crm_element_value(rsc->xml, XML_ATTR_TYPE));
 465 
 466     status_print("role=\"%s\" ", rsc_state);
 467     if (rsc->meta) {
 468         target_role = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_TARGET_ROLE);
 469     }
 470     if (target_role) {
 471         status_print("target_role=\"%s\" ", target_role);
 472     }
 473     status_print("active=\"%s\" ", pcmk__btoa(rsc->fns->active(rsc, TRUE)));
 474     status_print("orphaned=\"%s\" ", pe__rsc_bool_str(rsc, pe_rsc_orphan));
 475     status_print("blocked=\"%s\" ", pe__rsc_bool_str(rsc, pe_rsc_block));
 476     status_print("managed=\"%s\" ", pe__rsc_bool_str(rsc, pe_rsc_managed));
 477     status_print("failed=\"%s\" ", pe__rsc_bool_str(rsc, pe_rsc_failed));
 478     status_print("failure_ignored=\"%s\" ",
 479                  pe__rsc_bool_str(rsc, pe_rsc_failure_ignored));
 480     status_print("nodes_running_on=\"%d\" ", g_list_length(rsc->running_on));
 481 
 482     if (options & pe_print_pending) {
 483         const char *pending_task = native_pending_task(rsc);
 484 
 485         if (pending_task) {
 486             status_print("pending=\"%s\" ", pending_task);
 487         }
 488     }
 489 
 490     /* print out the nodes this resource is running on */
 491     if (options & pe_print_rsconly) {
 492         status_print("/>\n");
 493         /* do nothing */
 494     } else if (rsc->running_on != NULL) {
 495         GList *gIter = rsc->running_on;
 496 
 497         status_print(">\n");
 498         for (; gIter != NULL; gIter = gIter->next) {
 499             pe_node_t *node = (pe_node_t *) gIter->data;
 500 
 501             status_print("%s    <node name=\"%s\" id=\"%s\" cached=\"%s\"/>\n", pre_text,
 502                          node->details->uname, node->details->id,
 503                          pcmk__btoa(node->details->online == FALSE));
 504         }
 505         status_print("%s</resource>\n", pre_text);
 506     } else {
 507         status_print("/>\n");
 508     }
 509 }
 510 
 511 // Append a flag to resource description string's flags list
 512 static bool
 513 add_output_flag(GString *s, const char *flag_desc, bool have_flags)
     /* [previous][next][first][last][top][bottom][index][help] */
 514 {
 515     g_string_append(s, (have_flags? ", " : " ("));
 516     g_string_append(s, flag_desc);
 517     return true;
 518 }
 519 
 520 // Append a node name to resource description string's node list
 521 static bool
 522 add_output_node(GString *s, const char *node, bool have_nodes)
     /* [previous][next][first][last][top][bottom][index][help] */
 523 {
 524     g_string_append(s, (have_nodes? " " : " [ "));
 525     g_string_append(s, node);
 526     return true;
 527 }
 528 
 529 /*!
 530  * \internal
 531  * \brief Create a string description of a resource
 532  *
 533  * \param[in] rsc          Resource to describe
 534  * \param[in] name         Desired identifier for the resource
 535  * \param[in] node         If not NULL, node that resource is "on"
 536  * \param[in] options      Bitmask of pe_print_*
 537  * \param[in] target_role  Resource's target role
 538  * \param[in] show_nodes   Whether to display nodes when multiply active
 539  *
 540  * \return Newly allocated string description of resource
 541  * \note Caller must free the result with g_free().
 542  */
 543 gchar *
 544 pcmk__native_output_string(pe_resource_t *rsc, const char *name, pe_node_t *node,
     /* [previous][next][first][last][top][bottom][index][help] */
 545                            long options, const char *target_role, bool show_nodes)
 546 {
 547     const char *class = crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS);
 548     const char *provider = NULL;
 549     const char *kind = crm_element_value(rsc->xml, XML_ATTR_TYPE);
 550     gchar *retval = NULL;
 551     GString *outstr = NULL;
 552     bool have_flags = false;
 553 
 554     if (rsc->variant != pe_native) {
 555         return NULL;
 556     }
 557 
 558     CRM_CHECK(name != NULL, name = "unknown");
 559     CRM_CHECK(kind != NULL, kind = "unknown");
 560     CRM_CHECK(class != NULL, class = "unknown");
 561 
 562     if (pcmk_is_set(pcmk_get_ra_caps(class), pcmk_ra_cap_provider)) {
 563         provider = crm_element_value(rsc->xml, XML_AGENT_ATTR_PROVIDER);
 564     }
 565 
 566     if ((node == NULL) && (rsc->lock_node != NULL)) {
 567         node = rsc->lock_node;
 568     }
 569     if (pcmk_is_set(options, pe_print_rsconly)
 570         || pcmk__list_of_multiple(rsc->running_on)) {
 571         node = NULL;
 572     }
 573 
 574     // We need a string of at least this size
 575     outstr = g_string_sized_new(strlen(name) + strlen(class) + strlen(kind)
 576                                 + (provider? (strlen(provider) + 2) : 0)
 577                                 + (node? strlen(node->details->uname) + 1 : 0)
 578                                 + 11);
 579 
 580     // Resource name and agent
 581     g_string_printf(outstr, "%s\t(%s%s%s:%s):\t", name, class,
 582                     ((provider == NULL)? "" : PROVIDER_SEP),
 583                     ((provider == NULL)? "" : provider), kind);
 584 
 585     // State on node
 586     if (pcmk_is_set(rsc->flags, pe_rsc_orphan)) {
 587         g_string_append(outstr, " ORPHANED");
 588     }
 589     if (pcmk_is_set(rsc->flags, pe_rsc_failed)) {
 590         enum rsc_role_e role = native_displayable_role(rsc);
 591 
 592         if (role > RSC_ROLE_UNPROMOTED) {
 593             g_string_append_printf(outstr, " FAILED %s", role2text(role));
 594         } else {
 595             g_string_append(outstr, " FAILED");
 596         }
 597     } else {
 598         g_string_append_printf(outstr, " %s", native_displayable_state(rsc, options));
 599     }
 600     if (node) {
 601         g_string_append_printf(outstr, " %s", node->details->uname);
 602     }
 603 
 604     // Flags, as: (<flag> [...])
 605     if (node && !(node->details->online) && node->details->unclean) {
 606         have_flags = add_output_flag(outstr, "UNCLEAN", have_flags);
 607     }
 608     if (node && (node == rsc->lock_node)) {
 609         have_flags = add_output_flag(outstr, "LOCKED", have_flags);
 610     }
 611     if (pcmk_is_set(options, pe_print_pending)) {
 612         const char *pending_task = native_pending_task(rsc);
 613 
 614         if (pending_task) {
 615             have_flags = add_output_flag(outstr, pending_task, have_flags);
 616         }
 617     }
 618     if (target_role) {
 619         enum rsc_role_e target_role_e = text2role(target_role);
 620 
 621         /* Only show target role if it limits our abilities (i.e. ignore
 622          * Started, as it is the default anyways, and doesn't prevent the
 623          * resource from becoming promoted).
 624          */
 625         if (target_role_e == RSC_ROLE_STOPPED) {
 626             have_flags = add_output_flag(outstr, "disabled", have_flags);
 627 
 628         } else if (pcmk_is_set(uber_parent(rsc)->flags, pe_rsc_promotable)
 629                    && target_role_e == RSC_ROLE_UNPROMOTED) {
 630             have_flags = add_output_flag(outstr, "target-role:", have_flags);
 631             g_string_append(outstr, target_role);
 632         }
 633     }
 634     if (pcmk_is_set(rsc->flags, pe_rsc_block)) {
 635         have_flags = add_output_flag(outstr, "blocked", have_flags);
 636     } else if (!pcmk_is_set(rsc->flags, pe_rsc_managed)) {
 637         have_flags = add_output_flag(outstr, "unmanaged", have_flags);
 638     }
 639     if (pcmk_is_set(rsc->flags, pe_rsc_failure_ignored)) {
 640         have_flags = add_output_flag(outstr, "failure ignored", have_flags);
 641     }
 642     if (have_flags) {
 643         g_string_append(outstr, ")");
 644     }
 645 
 646     // User-supplied description
 647     if (pcmk_is_set(options, pe_print_rsconly)
 648         || pcmk__list_of_multiple(rsc->running_on)) {
 649         const char *desc = crm_element_value(rsc->xml, XML_ATTR_DESC);
 650 
 651         if (desc) {
 652             g_string_append_printf(outstr, " %s", desc);
 653         }
 654     }
 655 
 656     if (show_nodes && !pcmk_is_set(options, pe_print_rsconly)
 657         && pcmk__list_of_multiple(rsc->running_on)) {
 658         bool have_nodes = false;
 659 
 660         for (GList *iter = rsc->running_on; iter != NULL; iter = iter->next) {
 661             pe_node_t *n = (pe_node_t *) iter->data;
 662 
 663             have_nodes = add_output_node(outstr, n->details->uname, have_nodes);
 664         }
 665         if (have_nodes) {
 666             g_string_append(outstr, " ]");
 667         }
 668     }
 669 
 670     retval = outstr->str;
 671     g_string_free(outstr, FALSE);
 672     return retval;
 673 }
 674 
 675 int
 676 pe__common_output_html(pcmk__output_t *out, pe_resource_t * rsc,
     /* [previous][next][first][last][top][bottom][index][help] */
 677                        const char *name, pe_node_t *node, long options)
 678 {
 679     const char *kind = crm_element_value(rsc->xml, XML_ATTR_TYPE);
 680     const char *target_role = NULL;
 681 
 682     xmlNodePtr list_node = NULL;
 683     const char *cl = NULL;
 684 
 685     CRM_ASSERT(rsc->variant == pe_native);
 686     CRM_ASSERT(kind != NULL);
 687 
 688     if (rsc->meta) {
 689         const char *is_internal = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_INTERNAL_RSC);
 690 
 691         if (crm_is_true(is_internal)
 692             && !pcmk_is_set(options, pe_print_implicit)) {
 693 
 694             crm_trace("skipping print of internal resource %s", rsc->id);
 695             return pcmk_rc_no_output;
 696         }
 697         target_role = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_TARGET_ROLE);
 698     }
 699 
 700     if (!pcmk_is_set(rsc->flags, pe_rsc_managed)) {
 701         cl = "rsc-managed";
 702 
 703     } else if (pcmk_is_set(rsc->flags, pe_rsc_failed)) {
 704         cl = "rsc-failed";
 705 
 706     } else if (rsc->variant == pe_native && (rsc->running_on == NULL)) {
 707         cl = "rsc-failed";
 708 
 709     } else if (pcmk__list_of_multiple(rsc->running_on)) {
 710         cl = "rsc-multiple";
 711 
 712     } else if (pcmk_is_set(rsc->flags, pe_rsc_failure_ignored)) {
 713         cl = "rsc-failure-ignored";
 714 
 715     } else {
 716         cl = "rsc-ok";
 717     }
 718 
 719     {
 720         gchar *s = pcmk__native_output_string(rsc, name, node, options,
 721                                               target_role, true);
 722 
 723         list_node = pcmk__output_create_html_node(out, "li", NULL, NULL, NULL);
 724         pcmk_create_html_node(list_node, "span", NULL, cl, s);
 725         g_free(s);
 726     }
 727 
 728     return pcmk_rc_ok;
 729 }
 730 
 731 int
 732 pe__common_output_text(pcmk__output_t *out, pe_resource_t * rsc,
     /* [previous][next][first][last][top][bottom][index][help] */
 733                        const char *name, pe_node_t *node, long options)
 734 {
 735     const char *target_role = NULL;
 736 
 737     CRM_ASSERT(rsc->variant == pe_native);
 738 
 739     if (rsc->meta) {
 740         const char *is_internal = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_INTERNAL_RSC);
 741 
 742         if (crm_is_true(is_internal)
 743             && !pcmk_is_set(options, pe_print_implicit)) {
 744 
 745             crm_trace("skipping print of internal resource %s", rsc->id);
 746             return pcmk_rc_no_output;
 747         }
 748         target_role = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_TARGET_ROLE);
 749     }
 750 
 751     {
 752         gchar *s = pcmk__native_output_string(rsc, name, node, options,
 753                                               target_role, true);
 754 
 755         out->list_item(out, NULL, "%s", s);
 756         g_free(s);
 757     }
 758 
 759     return pcmk_rc_ok;
 760 }
 761 
 762 void
 763 common_print(pe_resource_t * rsc, const char *pre_text, const char *name, pe_node_t *node, long options, void *print_data)
     /* [previous][next][first][last][top][bottom][index][help] */
 764 {
 765     const char *target_role = NULL;
 766 
 767     CRM_ASSERT(rsc->variant == pe_native);
 768 
 769     if (rsc->meta) {
 770         const char *is_internal = g_hash_table_lookup(rsc->meta,
 771                                                       XML_RSC_ATTR_INTERNAL_RSC);
 772 
 773         if (crm_is_true(is_internal)
 774             && !pcmk_is_set(options, pe_print_implicit)) {
 775 
 776             crm_trace("skipping print of internal resource %s", rsc->id);
 777             return;
 778         }
 779         target_role = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_TARGET_ROLE);
 780     }
 781 
 782     if (options & pe_print_xml) {
 783         native_print_xml(rsc, pre_text, options, print_data);
 784         return;
 785     }
 786 
 787     if ((pre_text == NULL) && (options & pe_print_printf)) {
 788         pre_text = " ";
 789     }
 790 
 791     if (options & pe_print_html) {
 792         if (!pcmk_is_set(rsc->flags, pe_rsc_managed)) {
 793             status_print("<font color=\"yellow\">");
 794 
 795         } else if (pcmk_is_set(rsc->flags, pe_rsc_failed)) {
 796             status_print("<font color=\"red\">");
 797 
 798         } else if (rsc->running_on == NULL) {
 799             status_print("<font color=\"red\">");
 800 
 801         } else if (pcmk__list_of_multiple(rsc->running_on)) {
 802             status_print("<font color=\"orange\">");
 803 
 804         } else if (pcmk_is_set(rsc->flags, pe_rsc_failure_ignored)) {
 805             status_print("<font color=\"yellow\">");
 806 
 807         } else {
 808             status_print("<font color=\"green\">");
 809         }
 810     }
 811 
 812     {
 813         gchar *resource_s = pcmk__native_output_string(rsc, name, node, options,
 814                                                        target_role, false);
 815         status_print("%s%s", (pre_text? pre_text : ""), resource_s);
 816         g_free(resource_s);
 817     }
 818 
 819     if (pcmk_is_set(options, pe_print_html)) {
 820         status_print(" </font> ");
 821     }
 822 
 823     if (!pcmk_is_set(options, pe_print_rsconly)
 824         && pcmk__list_of_multiple(rsc->running_on)) {
 825 
 826         GList *gIter = rsc->running_on;
 827         int counter = 0;
 828 
 829         if (options & pe_print_html) {
 830             status_print("<ul>\n");
 831         } else if ((options & pe_print_printf)
 832                    || (options & pe_print_ncurses)) {
 833             status_print("[");
 834         }
 835 
 836         for (; gIter != NULL; gIter = gIter->next) {
 837             pe_node_t *n = (pe_node_t *) gIter->data;
 838 
 839             counter++;
 840 
 841             if (options & pe_print_html) {
 842                 status_print("<li>\n%s", n->details->uname);
 843 
 844             } else if ((options & pe_print_printf)
 845                        || (options & pe_print_ncurses)) {
 846                 status_print(" %s", n->details->uname);
 847 
 848             } else if ((options & pe_print_log)) {
 849                 status_print("\t%d : %s", counter, n->details->uname);
 850 
 851             } else {
 852                 status_print("%s", n->details->uname);
 853             }
 854             if (options & pe_print_html) {
 855                 status_print("</li>\n");
 856 
 857             }
 858         }
 859 
 860         if (options & pe_print_html) {
 861             status_print("</ul>\n");
 862         } else if ((options & pe_print_printf)
 863                    || (options & pe_print_ncurses)) {
 864             status_print(" ]");
 865         }
 866     }
 867 
 868     if (options & pe_print_html) {
 869         status_print("<br/>\n");
 870     } else if (options & pe_print_suppres_nl) {
 871         /* nothing */
 872     } else if ((options & pe_print_printf) || (options & pe_print_ncurses)) {
 873         status_print("\n");
 874     }
 875 }
 876 
 877 void
 878 native_print(pe_resource_t * rsc, const char *pre_text, long options, void *print_data)
     /* [previous][next][first][last][top][bottom][index][help] */
 879 {
 880     pe_node_t *node = NULL;
 881 
 882     CRM_ASSERT(rsc->variant == pe_native);
 883     if (options & pe_print_xml) {
 884         native_print_xml(rsc, pre_text, options, print_data);
 885         return;
 886     }
 887 
 888     node = pe__current_node(rsc);
 889 
 890     if (node == NULL) {
 891         // This is set only if a non-probe action is pending on this node
 892         node = rsc->pending_node;
 893     }
 894 
 895     common_print(rsc, pre_text, rsc_printable_id(rsc), node, options, print_data);
 896 }
 897 
 898 PCMK__OUTPUT_ARGS("primitive", "unsigned int", "pe_resource_t *", "GList *", "GList *")
     /* [previous][next][first][last][top][bottom][index][help] */
 899 int
 900 pe__resource_xml(pcmk__output_t *out, va_list args)
 901 {
 902     unsigned int options = va_arg(args, unsigned int);
 903     pe_resource_t *rsc = va_arg(args, pe_resource_t *);
 904     GList *only_node G_GNUC_UNUSED = va_arg(args, GList *);
 905     GList *only_rsc = va_arg(args, GList *);
 906 
 907     const char *class = crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS);
 908     const char *prov = crm_element_value(rsc->xml, XML_AGENT_ATTR_PROVIDER);
 909     const char *rsc_state = native_displayable_state(rsc, options);
 910 
 911     long is_print_pending = options & pe_print_pending;
 912 
 913     char ra_name[LINE_MAX];
 914     char *nodes_running_on = NULL;
 915     char *priority = NULL;
 916     int rc = pcmk_rc_no_output;
 917     const char *target_role = NULL;
 918 
 919     if (rsc->meta != NULL) {
 920        target_role = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_TARGET_ROLE);
 921     }
 922 
 923     CRM_ASSERT(rsc->variant == pe_native);
 924 
 925     if (rsc->fns->is_filtered(rsc, only_rsc, TRUE)) {
 926         return pcmk_rc_no_output;
 927     }
 928 
 929     /* resource information. */
 930     snprintf(ra_name, LINE_MAX, "%s%s%s:%s", class,
 931             ((prov == NULL)? "" : PROVIDER_SEP), ((prov == NULL)? "" : prov),
 932             crm_element_value(rsc->xml, XML_ATTR_TYPE));
 933 
 934     nodes_running_on = pcmk__itoa(g_list_length(rsc->running_on));
 935     priority = pcmk__ftoa(rsc->priority);
 936 
 937     rc = pe__name_and_nvpairs_xml(out, true, "resource", 12,
 938              "id", rsc_printable_id(rsc),
 939              "resource_agent", ra_name,
 940              "role", rsc_state,
 941              "target_role", target_role,
 942              "active", pcmk__btoa(rsc->fns->active(rsc, TRUE)),
 943              "orphaned", pe__rsc_bool_str(rsc, pe_rsc_orphan),
 944              "blocked", pe__rsc_bool_str(rsc, pe_rsc_block),
 945              "managed", pe__rsc_bool_str(rsc, pe_rsc_managed),
 946              "failed", pe__rsc_bool_str(rsc, pe_rsc_failed),
 947              "failure_ignored", pe__rsc_bool_str(rsc, pe_rsc_failure_ignored),
 948              "nodes_running_on", nodes_running_on,
 949              "pending", (is_print_pending? native_pending_task(rsc) : NULL));
 950     free(priority);
 951     free(nodes_running_on);
 952 
 953     CRM_ASSERT(rc == pcmk_rc_ok);
 954 
 955     if (rsc->running_on != NULL) {
 956         GList *gIter = rsc->running_on;
 957 
 958         for (; gIter != NULL; gIter = gIter->next) {
 959             pe_node_t *node = (pe_node_t *) gIter->data;
 960 
 961             rc = pe__name_and_nvpairs_xml(out, false, "node", 3,
 962                      "name", node->details->uname,
 963                      "id", node->details->id,
 964                      "cached", pcmk__btoa(node->details->online));
 965             CRM_ASSERT(rc == pcmk_rc_ok);
 966         }
 967     }
 968 
 969     pcmk__output_xml_pop_parent(out);
 970     return rc;
 971 }
 972 
 973 PCMK__OUTPUT_ARGS("primitive", "unsigned int", "pe_resource_t *", "GList *", "GList *")
     /* [previous][next][first][last][top][bottom][index][help] */
 974 int
 975 pe__resource_html(pcmk__output_t *out, va_list args)
 976 {
 977     unsigned int options = va_arg(args, unsigned int);
 978     pe_resource_t *rsc = va_arg(args, pe_resource_t *);
 979     GList *only_node G_GNUC_UNUSED = va_arg(args, GList *);
 980     GList *only_rsc = va_arg(args, GList *);
 981 
 982     pe_node_t *node = pe__current_node(rsc);
 983 
 984     if (rsc->fns->is_filtered(rsc, only_rsc, TRUE)) {
 985         return pcmk_rc_no_output;
 986     }
 987 
 988     CRM_ASSERT(rsc->variant == pe_native);
 989 
 990     if (node == NULL) {
 991         // This is set only if a non-probe action is pending on this node
 992         node = rsc->pending_node;
 993     }
 994     return pe__common_output_html(out, rsc, rsc_printable_id(rsc), node, options);
 995 }
 996 
 997 PCMK__OUTPUT_ARGS("primitive", "unsigned int", "pe_resource_t *", "GList *", "GList *")
     /* [previous][next][first][last][top][bottom][index][help] */
 998 int
 999 pe__resource_text(pcmk__output_t *out, va_list args)
1000 {
1001     unsigned int options = va_arg(args, unsigned int);
1002     pe_resource_t *rsc = va_arg(args, pe_resource_t *);
1003     GList *only_node G_GNUC_UNUSED = va_arg(args, GList *);
1004     GList *only_rsc = va_arg(args, GList *);
1005 
1006     pe_node_t *node = pe__current_node(rsc);
1007 
1008     CRM_ASSERT(rsc->variant == pe_native);
1009 
1010     if (rsc->fns->is_filtered(rsc, only_rsc, TRUE)) {
1011         return pcmk_rc_no_output;
1012     }
1013 
1014     if (node == NULL) {
1015         // This is set only if a non-probe action is pending on this node
1016         node = rsc->pending_node;
1017     }
1018     return pe__common_output_text(out, rsc, rsc_printable_id(rsc), node, options);
1019 }
1020 
1021 void
1022 native_free(pe_resource_t * rsc)
     /* [previous][next][first][last][top][bottom][index][help] */
1023 {
1024     pe_rsc_trace(rsc, "Freeing resource action list (not the data)");
1025     common_free(rsc);
1026 }
1027 
1028 enum rsc_role_e
1029 native_resource_state(const pe_resource_t * rsc, gboolean current)
     /* [previous][next][first][last][top][bottom][index][help] */
1030 {
1031     enum rsc_role_e role = rsc->next_role;
1032 
1033     if (current) {
1034         role = rsc->role;
1035     }
1036     pe_rsc_trace(rsc, "%s state: %s", rsc->id, role2text(role));
1037     return role;
1038 }
1039 
1040 /*!
1041  * \internal
1042  * \brief List nodes where a resource (or any of its children) is
1043  *
1044  * \param[in]  rsc      Resource to check
1045  * \param[out] list     List to add result to
1046  * \param[in]  current  0 = where allocated, 1 = where running,
1047  *                      2 = where running or pending
1048  *
1049  * \return If list contains only one node, that node, or NULL otherwise
1050  */
1051 pe_node_t *
1052 native_location(const pe_resource_t *rsc, GList **list, int current)
     /* [previous][next][first][last][top][bottom][index][help] */
1053 {
1054     pe_node_t *one = NULL;
1055     GList *result = NULL;
1056 
1057     if (rsc->children) {
1058         GList *gIter = rsc->children;
1059 
1060         for (; gIter != NULL; gIter = gIter->next) {
1061             pe_resource_t *child = (pe_resource_t *) gIter->data;
1062 
1063             child->fns->location(child, &result, current);
1064         }
1065 
1066     } else if (current) {
1067 
1068         if (rsc->running_on) {
1069             result = g_list_copy(rsc->running_on);
1070         }
1071         if ((current == 2) && rsc->pending_node
1072             && !pe_find_node_id(result, rsc->pending_node->details->id)) {
1073                 result = g_list_append(result, rsc->pending_node);
1074         }
1075 
1076     } else if (current == FALSE && rsc->allocated_to) {
1077         result = g_list_append(NULL, rsc->allocated_to);
1078     }
1079 
1080     if (result && (result->next == NULL)) {
1081         one = result->data;
1082     }
1083 
1084     if (list) {
1085         GList *gIter = result;
1086 
1087         for (; gIter != NULL; gIter = gIter->next) {
1088             pe_node_t *node = (pe_node_t *) gIter->data;
1089 
1090             if (*list == NULL || pe_find_node_id(*list, node->details->id) == NULL) {
1091                 *list = g_list_append(*list, node);
1092             }
1093         }
1094     }
1095 
1096     g_list_free(result);
1097     return one;
1098 }
1099 
1100 static void
1101 get_rscs_brief(GList *rsc_list, GHashTable * rsc_table, GHashTable * active_table)
     /* [previous][next][first][last][top][bottom][index][help] */
1102 {
1103     GList *gIter = rsc_list;
1104 
1105     for (; gIter != NULL; gIter = gIter->next) {
1106         pe_resource_t *rsc = (pe_resource_t *) gIter->data;
1107 
1108         const char *class = crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS);
1109         const char *kind = crm_element_value(rsc->xml, XML_ATTR_TYPE);
1110 
1111         int offset = 0;
1112         char buffer[LINE_MAX];
1113 
1114         int *rsc_counter = NULL;
1115         int *active_counter = NULL;
1116 
1117         if (rsc->variant != pe_native) {
1118             continue;
1119         }
1120 
1121         offset += snprintf(buffer + offset, LINE_MAX - offset, "%s", class);
1122         if (pcmk_is_set(pcmk_get_ra_caps(class), pcmk_ra_cap_provider)) {
1123             const char *prov = crm_element_value(rsc->xml, XML_AGENT_ATTR_PROVIDER);
1124 
1125             if (prov != NULL) {
1126                 offset += snprintf(buffer + offset, LINE_MAX - offset,
1127                                    PROVIDER_SEP "%s", prov);
1128             }
1129         }
1130         offset += snprintf(buffer + offset, LINE_MAX - offset, ":%s", kind);
1131         CRM_LOG_ASSERT(offset > 0);
1132 
1133         if (rsc_table) {
1134             rsc_counter = g_hash_table_lookup(rsc_table, buffer);
1135             if (rsc_counter == NULL) {
1136                 rsc_counter = calloc(1, sizeof(int));
1137                 *rsc_counter = 0;
1138                 g_hash_table_insert(rsc_table, strdup(buffer), rsc_counter);
1139             }
1140             (*rsc_counter)++;
1141         }
1142 
1143         if (active_table) {
1144             GList *gIter2 = rsc->running_on;
1145 
1146             for (; gIter2 != NULL; gIter2 = gIter2->next) {
1147                 pe_node_t *node = (pe_node_t *) gIter2->data;
1148                 GHashTable *node_table = NULL;
1149 
1150                 if (node->details->unclean == FALSE && node->details->online == FALSE) {
1151                     continue;
1152                 }
1153 
1154                 node_table = g_hash_table_lookup(active_table, node->details->uname);
1155                 if (node_table == NULL) {
1156                     node_table = pcmk__strkey_table(free, free);
1157                     g_hash_table_insert(active_table, strdup(node->details->uname), node_table);
1158                 }
1159 
1160                 active_counter = g_hash_table_lookup(node_table, buffer);
1161                 if (active_counter == NULL) {
1162                     active_counter = calloc(1, sizeof(int));
1163                     *active_counter = 0;
1164                     g_hash_table_insert(node_table, strdup(buffer), active_counter);
1165                 }
1166                 (*active_counter)++;
1167             }
1168         }
1169     }
1170 }
1171 
1172 static void
1173 destroy_node_table(gpointer data)
     /* [previous][next][first][last][top][bottom][index][help] */
1174 {
1175     GHashTable *node_table = data;
1176 
1177     if (node_table) {
1178         g_hash_table_destroy(node_table);
1179     }
1180 }
1181 
1182 void
1183 print_rscs_brief(GList *rsc_list, const char *pre_text, long options,
     /* [previous][next][first][last][top][bottom][index][help] */
1184                  void *print_data, gboolean print_all)
1185 {
1186     GHashTable *rsc_table = pcmk__strkey_table(free, free);
1187     GHashTable *active_table = pcmk__strkey_table(free, destroy_node_table);
1188     GHashTableIter hash_iter;
1189     char *type = NULL;
1190     int *rsc_counter = NULL;
1191 
1192     get_rscs_brief(rsc_list, rsc_table, active_table);
1193 
1194     g_hash_table_iter_init(&hash_iter, rsc_table);
1195     while (g_hash_table_iter_next(&hash_iter, (gpointer *)&type, (gpointer *)&rsc_counter)) {
1196         GHashTableIter hash_iter2;
1197         char *node_name = NULL;
1198         GHashTable *node_table = NULL;
1199         int active_counter_all = 0;
1200 
1201         g_hash_table_iter_init(&hash_iter2, active_table);
1202         while (g_hash_table_iter_next(&hash_iter2, (gpointer *)&node_name, (gpointer *)&node_table)) {
1203             int *active_counter = g_hash_table_lookup(node_table, type);
1204 
1205             if (active_counter == NULL || *active_counter == 0) {
1206                 continue;
1207 
1208             } else {
1209                 active_counter_all += *active_counter;
1210             }
1211 
1212             if (options & pe_print_rsconly) {
1213                 node_name = NULL;
1214             }
1215 
1216             if (options & pe_print_html) {
1217                 status_print("<li>\n");
1218             }
1219 
1220             if (print_all) {
1221                 status_print("%s%d/%d\t(%s):\tActive %s\n", pre_text ? pre_text : "",
1222                              active_counter ? *active_counter : 0,
1223                              rsc_counter ? *rsc_counter : 0, type,
1224                              active_counter && (*active_counter > 0) && node_name ? node_name : "");
1225             } else {
1226                 status_print("%s%d\t(%s):\tActive %s\n", pre_text ? pre_text : "",
1227                              active_counter ? *active_counter : 0, type,
1228                              active_counter && (*active_counter > 0) && node_name ? node_name : "");
1229             }
1230 
1231             if (options & pe_print_html) {
1232                 status_print("</li>\n");
1233             }
1234         }
1235 
1236         if (print_all && active_counter_all == 0) {
1237             if (options & pe_print_html) {
1238                 status_print("<li>\n");
1239             }
1240 
1241             status_print("%s%d/%d\t(%s):\tActive\n", pre_text ? pre_text : "",
1242                          active_counter_all,
1243                          rsc_counter ? *rsc_counter : 0, type);
1244 
1245             if (options & pe_print_html) {
1246                 status_print("</li>\n");
1247             }
1248         }
1249     }
1250 
1251     if (rsc_table) {
1252         g_hash_table_destroy(rsc_table);
1253         rsc_table = NULL;
1254     }
1255     if (active_table) {
1256         g_hash_table_destroy(active_table);
1257         active_table = NULL;
1258     }
1259 }
1260 
1261 int
1262 pe__rscs_brief_output(pcmk__output_t *out, GList *rsc_list, long options, gboolean print_all)
     /* [previous][next][first][last][top][bottom][index][help] */
1263 {
1264     GHashTable *rsc_table = pcmk__strkey_table(free, free);
1265     GHashTable *active_table = pcmk__strkey_table(free, destroy_node_table);
1266     GList *sorted_rscs;
1267     int rc = pcmk_rc_no_output;
1268 
1269     get_rscs_brief(rsc_list, rsc_table, active_table);
1270 
1271     /* Make a list of the rsc_table keys so that it can be sorted.  This is to make sure
1272      * output order stays consistent between systems.
1273      */
1274     sorted_rscs = g_hash_table_get_keys(rsc_table);
1275     sorted_rscs = g_list_sort(sorted_rscs, (GCompareFunc) strcmp);
1276 
1277     for (GList *gIter = sorted_rscs; gIter; gIter = gIter->next) {
1278         char *type = (char *) gIter->data;
1279         int *rsc_counter = g_hash_table_lookup(rsc_table, type);
1280 
1281         GHashTableIter hash_iter2;
1282         char *node_name = NULL;
1283         GHashTable *node_table = NULL;
1284         int active_counter_all = 0;
1285 
1286         g_hash_table_iter_init(&hash_iter2, active_table);
1287         while (g_hash_table_iter_next(&hash_iter2, (gpointer *)&node_name, (gpointer *)&node_table)) {
1288             int *active_counter = g_hash_table_lookup(node_table, type);
1289 
1290             if (active_counter == NULL || *active_counter == 0) {
1291                 continue;
1292 
1293             } else {
1294                 active_counter_all += *active_counter;
1295             }
1296 
1297             if (options & pe_print_rsconly) {
1298                 node_name = NULL;
1299             }
1300 
1301             if (print_all) {
1302                 out->list_item(out, NULL, "%d/%d\t(%s):\tActive %s",
1303                                *active_counter,
1304                                rsc_counter ? *rsc_counter : 0, type,
1305                                (*active_counter > 0) && node_name ? node_name : "");
1306             } else {
1307                 out->list_item(out, NULL, "%d\t(%s):\tActive %s",
1308                                *active_counter, type,
1309                                (*active_counter > 0) && node_name ? node_name : "");
1310             }
1311 
1312             rc = pcmk_rc_ok;
1313         }
1314 
1315         if (print_all && active_counter_all == 0) {
1316             out->list_item(out, NULL, "%d/%d\t(%s):\tActive",
1317                            active_counter_all,
1318                            rsc_counter ? *rsc_counter : 0, type);
1319             rc = pcmk_rc_ok;
1320         }
1321     }
1322 
1323     if (rsc_table) {
1324         g_hash_table_destroy(rsc_table);
1325         rsc_table = NULL;
1326     }
1327     if (active_table) {
1328         g_hash_table_destroy(active_table);
1329         active_table = NULL;
1330     }
1331     if (sorted_rscs) {
1332         g_list_free(sorted_rscs);
1333     }
1334 
1335     return rc;
1336 }
1337 
1338 gboolean
1339 pe__native_is_filtered(pe_resource_t *rsc, GList *only_rsc, gboolean check_parent)
     /* [previous][next][first][last][top][bottom][index][help] */
1340 {
1341     if (pcmk__str_in_list(only_rsc, rsc_printable_id(rsc)) ||
1342         pcmk__str_in_list(only_rsc, rsc->id)) {
1343         return FALSE;
1344     } else if (check_parent) {
1345         pe_resource_t *up = uber_parent(rsc);
1346 
1347         if (pe_rsc_is_bundled(rsc)) {
1348             return up->parent->fns->is_filtered(up->parent, only_rsc, FALSE);
1349         } else {
1350             return up->fns->is_filtered(up, only_rsc, FALSE);
1351         }
1352     }
1353 
1354     return TRUE;
1355 }

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