LCOV - code coverage report
Current view: top level - pengine - native.c (source / functions) Hit Total Coverage
Test: Pacemaker code coverage Lines: 41 697 5.9 %
Date: 2024-05-07 11:09:47 Functions: 2 33 6.1 %

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

Generated by: LCOV version 1.14