root/lib/pengine/status.c

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

DEFINITIONS

This source file includes following definitions.
  1. pe_new_working_set
  2. pe_free_working_set
  3. cluster_status
  4. pe_free_resources
  5. pe_free_actions
  6. pe_free_nodes
  7. pe__free_ordering
  8. pe__free_location
  9. cleanup_calculations
  10. pe_reset_working_set
  11. set_working_set_defaults
  12. pe_find_resource
  13. pe_find_resource_with_flags
  14. pe_find_node_any
  15. pe_find_node_id
  16. pe_find_node

   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 <sys/param.h>
  13 
  14 #include <crm/crm.h>
  15 #include <crm/msg_xml.h>
  16 #include <crm/common/xml.h>
  17 
  18 #include <glib.h>
  19 
  20 #include <crm/pengine/internal.h>
  21 #include <pe_status_private.h>
  22 
  23 /*!
  24  * \brief Create a new working set
  25  *
  26  * \return New, initialized working set on success, else NULL (and set errno)
  27  * \note Only pe_working_set_t objects created with this function (as opposed
  28  *       to statically declared or directly allocated) should be used with the
  29  *       functions in this library, to allow for future extensions to the
  30  *       data type. The caller is responsible for freeing the memory with
  31  *       pe_free_working_set() when the instance is no longer needed.
  32  */
  33 pe_working_set_t *
  34 pe_new_working_set()
     /* [previous][next][first][last][top][bottom][index][help] */
  35 {
  36     pe_working_set_t *data_set = calloc(1, sizeof(pe_working_set_t));
  37 
  38     if (data_set != NULL) {
  39         set_working_set_defaults(data_set);
  40     }
  41     return data_set;
  42 }
  43 
  44 /*!
  45  * \brief Free a working set
  46  *
  47  * \param[in] data_set  Working set to free
  48  */
  49 void
  50 pe_free_working_set(pe_working_set_t *data_set)
     /* [previous][next][first][last][top][bottom][index][help] */
  51 {
  52     if (data_set != NULL) {
  53         pe_reset_working_set(data_set);
  54         data_set->priv = NULL;
  55         free(data_set);
  56     }
  57 }
  58 
  59 /*
  60  * Unpack everything
  61  * At the end you'll have:
  62  *  - A list of nodes
  63  *  - A list of resources (each with any dependencies on other resources)
  64  *  - A list of constraints between resources and nodes
  65  *  - A list of constraints between start/stop actions
  66  *  - A list of nodes that need to be stonith'd
  67  *  - A list of nodes that need to be shutdown
  68  *  - A list of the possible stop/start actions (without dependencies)
  69  */
  70 gboolean
  71 cluster_status(pe_working_set_t * data_set)
     /* [previous][next][first][last][top][bottom][index][help] */
  72 {
  73     xmlNode *config = get_xpath_object("//"XML_CIB_TAG_CRMCONFIG, data_set->input, LOG_TRACE);
  74     xmlNode *cib_nodes = get_xpath_object("//"XML_CIB_TAG_NODES, data_set->input, LOG_TRACE);
  75     xmlNode *cib_resources = get_xpath_object("//"XML_CIB_TAG_RESOURCES, data_set->input, LOG_TRACE);
  76     xmlNode *cib_status = get_xpath_object("//"XML_CIB_TAG_STATUS, data_set->input, LOG_TRACE);
  77     xmlNode *cib_tags = get_xpath_object("//" XML_CIB_TAG_TAGS, data_set->input,
  78                                          LOG_NEVER);
  79     const char *value = crm_element_value(data_set->input, XML_ATTR_HAVE_QUORUM);
  80 
  81     crm_trace("Beginning unpack");
  82 
  83     /* reset remaining global variables */
  84     data_set->failed = create_xml_node(NULL, "failed-ops");
  85 
  86     if (data_set->input == NULL) {
  87         return FALSE;
  88     }
  89 
  90     if (data_set->now == NULL) {
  91         data_set->now = crm_time_new(NULL);
  92     }
  93 
  94     if (data_set->dc_uuid == NULL) {
  95         data_set->dc_uuid = crm_element_value_copy(data_set->input,
  96                                                    XML_ATTR_DC_UUID);
  97     }
  98 
  99     if (crm_is_true(value)) {
 100         pe__set_working_set_flags(data_set, pe_flag_have_quorum);
 101     } else {
 102         pe__clear_working_set_flags(data_set, pe_flag_have_quorum);
 103     }
 104 
 105     data_set->op_defaults = get_xpath_object("//" XML_CIB_TAG_OPCONFIG,
 106                                              data_set->input, LOG_NEVER);
 107     data_set->rsc_defaults = get_xpath_object("//" XML_CIB_TAG_RSCCONFIG,
 108                                               data_set->input, LOG_NEVER);
 109 
 110     unpack_config(config, data_set);
 111 
 112    if (!pcmk_any_flags_set(data_set->flags,
 113                            pe_flag_quick_location|pe_flag_have_quorum)
 114        && (data_set->no_quorum_policy != no_quorum_ignore)) {
 115         crm_warn("Fencing and resource management disabled due to lack of quorum");
 116     }
 117 
 118     unpack_nodes(cib_nodes, data_set);
 119 
 120     if (!pcmk_is_set(data_set->flags, pe_flag_quick_location)) {
 121         unpack_remote_nodes(cib_resources, data_set);
 122     }
 123 
 124     unpack_resources(cib_resources, data_set);
 125     unpack_tags(cib_tags, data_set);
 126 
 127     if (!pcmk_is_set(data_set->flags, pe_flag_quick_location)) {
 128         unpack_status(cib_status, data_set);
 129     }
 130 
 131     if (!pcmk_is_set(data_set->flags, pe_flag_no_counts)) {
 132         for (GList *item = data_set->resources; item != NULL;
 133              item = item->next) {
 134             ((pe_resource_t *) (item->data))->fns->count(item->data);
 135         }
 136     }
 137 
 138     pe__set_working_set_flags(data_set, pe_flag_have_status);
 139     return TRUE;
 140 }
 141 
 142 /*!
 143  * \internal
 144  * \brief Free a list of pe_resource_t
 145  *
 146  * \param[in] resources  List to free
 147  *
 148  * \note When a working set's resource list is freed, that includes the original
 149  *       storage for the uname and id of any Pacemaker Remote nodes in the
 150  *       working set's node list, so take care not to use those afterward.
 151  * \todo Refactor pe_node_t to strdup() the node name.
 152  */
 153 static void
 154 pe_free_resources(GList *resources)
     /* [previous][next][first][last][top][bottom][index][help] */
 155 {
 156     pe_resource_t *rsc = NULL;
 157     GList *iterator = resources;
 158 
 159     while (iterator != NULL) {
 160         rsc = (pe_resource_t *) iterator->data;
 161         iterator = iterator->next;
 162         rsc->fns->free(rsc);
 163     }
 164     if (resources != NULL) {
 165         g_list_free(resources);
 166     }
 167 }
 168 
 169 static void
 170 pe_free_actions(GList *actions)
     /* [previous][next][first][last][top][bottom][index][help] */
 171 {
 172     GList *iterator = actions;
 173 
 174     while (iterator != NULL) {
 175         pe_free_action(iterator->data);
 176         iterator = iterator->next;
 177     }
 178     if (actions != NULL) {
 179         g_list_free(actions);
 180     }
 181 }
 182 
 183 static void
 184 pe_free_nodes(GList *nodes)
     /* [previous][next][first][last][top][bottom][index][help] */
 185 {
 186     for (GList *iterator = nodes; iterator != NULL; iterator = iterator->next) {
 187         pe_node_t *node = (pe_node_t *) iterator->data;
 188 
 189         // Shouldn't be possible, but to be safe ...
 190         if (node == NULL) {
 191             continue;
 192         }
 193         if (node->details == NULL) {
 194             free(node);
 195             continue;
 196         }
 197 
 198         /* This is called after pe_free_resources(), which means that we can't
 199          * use node->details->uname for Pacemaker Remote nodes.
 200          */
 201         crm_trace("Freeing node %s", (pe__is_guest_or_remote_node(node)?
 202                   "(guest or remote)" : node->details->uname));
 203 
 204         if (node->details->attrs != NULL) {
 205             g_hash_table_destroy(node->details->attrs);
 206         }
 207         if (node->details->utilization != NULL) {
 208             g_hash_table_destroy(node->details->utilization);
 209         }
 210         if (node->details->digest_cache != NULL) {
 211             g_hash_table_destroy(node->details->digest_cache);
 212         }
 213         g_list_free(node->details->running_rsc);
 214         g_list_free(node->details->allocated_rsc);
 215         free(node->details);
 216         free(node);
 217     }
 218     if (nodes != NULL) {
 219         g_list_free(nodes);
 220     }
 221 }
 222 
 223 static void
 224 pe__free_ordering(GList *constraints)
     /* [previous][next][first][last][top][bottom][index][help] */
 225 {
 226     GList *iterator = constraints;
 227 
 228     while (iterator != NULL) {
 229         pe__ordering_t *order = iterator->data;
 230 
 231         iterator = iterator->next;
 232 
 233         free(order->lh_action_task);
 234         free(order->rh_action_task);
 235         free(order);
 236     }
 237     if (constraints != NULL) {
 238         g_list_free(constraints);
 239     }
 240 }
 241 
 242 static void
 243 pe__free_location(GList *constraints)
     /* [previous][next][first][last][top][bottom][index][help] */
 244 {
 245     GList *iterator = constraints;
 246 
 247     while (iterator != NULL) {
 248         pe__location_t *cons = iterator->data;
 249 
 250         iterator = iterator->next;
 251 
 252         g_list_free_full(cons->node_list_rh, free);
 253         free(cons->id);
 254         free(cons);
 255     }
 256     if (constraints != NULL) {
 257         g_list_free(constraints);
 258     }
 259 }
 260 
 261 /*!
 262  * \brief Reset working set to default state without freeing it or constraints
 263  *
 264  * \param[in,out] data_set  Working set to reset
 265  *
 266  * \deprecated This function is deprecated as part of the API;
 267  *             pe_reset_working_set() should be used instead.
 268  */
 269 void
 270 cleanup_calculations(pe_working_set_t * data_set)
     /* [previous][next][first][last][top][bottom][index][help] */
 271 {
 272     if (data_set == NULL) {
 273         return;
 274     }
 275 
 276     pe__clear_working_set_flags(data_set, pe_flag_have_status);
 277     if (data_set->config_hash != NULL) {
 278         g_hash_table_destroy(data_set->config_hash);
 279     }
 280 
 281     if (data_set->singletons != NULL) {
 282         g_hash_table_destroy(data_set->singletons);
 283     }
 284 
 285     if (data_set->tickets) {
 286         g_hash_table_destroy(data_set->tickets);
 287     }
 288 
 289     if (data_set->template_rsc_sets) {
 290         g_hash_table_destroy(data_set->template_rsc_sets);
 291     }
 292 
 293     if (data_set->tags) {
 294         g_hash_table_destroy(data_set->tags);
 295     }
 296 
 297     free(data_set->dc_uuid);
 298 
 299     crm_trace("deleting resources");
 300     pe_free_resources(data_set->resources);
 301 
 302     crm_trace("deleting actions");
 303     pe_free_actions(data_set->actions);
 304 
 305     crm_trace("deleting nodes");
 306     pe_free_nodes(data_set->nodes);
 307 
 308     pe__free_param_checks(data_set);
 309     g_list_free(data_set->stop_needed);
 310     free_xml(data_set->graph);
 311     crm_time_free(data_set->now);
 312     free_xml(data_set->input);
 313     free_xml(data_set->failed);
 314 
 315     set_working_set_defaults(data_set);
 316 
 317     CRM_CHECK(data_set->ordering_constraints == NULL,;
 318         );
 319     CRM_CHECK(data_set->placement_constraints == NULL,;
 320         );
 321 }
 322 
 323 /*!
 324  * \brief Reset a working set to default state without freeing it
 325  *
 326  * \param[in,out] data_set  Working set to reset
 327  */
 328 void
 329 pe_reset_working_set(pe_working_set_t *data_set)
     /* [previous][next][first][last][top][bottom][index][help] */
 330 {
 331     if (data_set == NULL) {
 332         return;
 333     }
 334 
 335     crm_trace("Deleting %d ordering constraints",
 336               g_list_length(data_set->ordering_constraints));
 337     pe__free_ordering(data_set->ordering_constraints);
 338     data_set->ordering_constraints = NULL;
 339 
 340     crm_trace("Deleting %d location constraints",
 341               g_list_length(data_set->placement_constraints));
 342     pe__free_location(data_set->placement_constraints);
 343     data_set->placement_constraints = NULL;
 344 
 345     crm_trace("Deleting %d colocation constraints",
 346               g_list_length(data_set->colocation_constraints));
 347     g_list_free_full(data_set->colocation_constraints, free);
 348     data_set->colocation_constraints = NULL;
 349 
 350     crm_trace("Deleting %d ticket constraints",
 351               g_list_length(data_set->ticket_constraints));
 352     g_list_free_full(data_set->ticket_constraints, free);
 353     data_set->ticket_constraints = NULL;
 354 
 355     cleanup_calculations(data_set);
 356 }
 357 
 358 void
 359 set_working_set_defaults(pe_working_set_t * data_set)
     /* [previous][next][first][last][top][bottom][index][help] */
 360 {
 361     void *priv = data_set->priv;
 362 
 363     memset(data_set, 0, sizeof(pe_working_set_t));
 364 
 365     data_set->priv = priv;
 366     data_set->order_id = 1;
 367     data_set->action_id = 1;
 368     data_set->no_quorum_policy = no_quorum_stop;
 369 
 370     data_set->flags = 0x0ULL;
 371 
 372     pe__set_working_set_flags(data_set,
 373                               pe_flag_stop_rsc_orphans
 374                               |pe_flag_symmetric_cluster
 375                               |pe_flag_stop_action_orphans);
 376     if (!strcmp(PCMK__CONCURRENT_FENCING_DEFAULT, "true")) {
 377         pe__set_working_set_flags(data_set, pe_flag_concurrent_fencing);
 378     }
 379 }
 380 
 381 pe_resource_t *
 382 pe_find_resource(GList *rsc_list, const char *id)
     /* [previous][next][first][last][top][bottom][index][help] */
 383 {
 384     return pe_find_resource_with_flags(rsc_list, id, pe_find_renamed);
 385 }
 386 
 387 pe_resource_t *
 388 pe_find_resource_with_flags(GList *rsc_list, const char *id, enum pe_find flags)
     /* [previous][next][first][last][top][bottom][index][help] */
 389 {
 390     GList *rIter = NULL;
 391 
 392     for (rIter = rsc_list; id && rIter; rIter = rIter->next) {
 393         pe_resource_t *parent = rIter->data;
 394 
 395         pe_resource_t *match =
 396             parent->fns->find_rsc(parent, id, NULL, flags);
 397         if (match != NULL) {
 398             return match;
 399         }
 400     }
 401     crm_trace("No match for %s", id);
 402     return NULL;
 403 }
 404 
 405 pe_node_t *
 406 pe_find_node_any(GList *nodes, const char *id, const char *uname)
     /* [previous][next][first][last][top][bottom][index][help] */
 407 {
 408     pe_node_t *match = pe_find_node_id(nodes, id);
 409 
 410     if (match) {
 411         return match;
 412     }
 413     crm_trace("Looking up %s via its uname instead", uname);
 414     return pe_find_node(nodes, uname);
 415 }
 416 
 417 pe_node_t *
 418 pe_find_node_id(GList *nodes, const char *id)
     /* [previous][next][first][last][top][bottom][index][help] */
 419 {
 420     GList *gIter = nodes;
 421 
 422     for (; gIter != NULL; gIter = gIter->next) {
 423         pe_node_t *node = (pe_node_t *) gIter->data;
 424 
 425         if (node && pcmk__str_eq(node->details->id, id, pcmk__str_casei)) {
 426             return node;
 427         }
 428     }
 429     /* error */
 430     return NULL;
 431 }
 432 
 433 pe_node_t *
 434 pe_find_node(GList *nodes, const char *uname)
     /* [previous][next][first][last][top][bottom][index][help] */
 435 {
 436     GList *gIter = nodes;
 437 
 438     for (; gIter != NULL; gIter = gIter->next) {
 439         pe_node_t *node = (pe_node_t *) gIter->data;
 440 
 441         if (node && pcmk__str_eq(node->details->uname, uname, pcmk__str_casei)) {
 442             return node;
 443         }
 444     }
 445     /* error */
 446     return NULL;
 447 }

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