pacemaker  3.0.0-d8340737c4
Scalable High-Availability cluster resource manager
status.c
Go to the documentation of this file.
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 <sys/param.h>
13 
14 #include <crm/crm.h>
15 #include <crm/common/xml.h>
17 
18 #include <glib.h>
19 
20 #include <crm/pengine/internal.h>
21 #include <pe_status_private.h>
22 
35 {
36  pcmk_scheduler_t *scheduler = calloc(1, sizeof(pcmk_scheduler_t));
37 
38  if (scheduler == NULL) {
39  return NULL;
40  }
41  scheduler->priv = calloc(1, sizeof(pcmk__scheduler_private_t));
42  if (scheduler->priv == NULL) {
43  free(scheduler);
44  return NULL;
45  }
47  return scheduler;
48 }
49 
55 void
57 {
58  if (scheduler != NULL) {
61  free(scheduler->priv);
62  free(scheduler);
63  }
64 }
65 
66 #define XPATH_DEPRECATED_RULES \
67  "//" PCMK_XE_OP_DEFAULTS "//" PCMK_XE_EXPRESSION \
68  "|//" PCMK_XE_OP "//" PCMK_XE_EXPRESSION
69 
76 static void
77 check_for_deprecated_rules(pcmk_scheduler_t *scheduler)
78 {
79  // @COMPAT Drop this function when support for the syntax is dropped
80  xmlNode *deprecated = get_xpath_object(XPATH_DEPRECATED_RULES,
82 
83  if (deprecated != NULL) {
85  "Support for rules with node attribute expressions in "
86  PCMK_XE_OP " or " PCMK_XE_OP_DEFAULTS " is deprecated "
87  "and will be dropped in a future release");
88  }
89 }
90 
91 /*
92  * Unpack everything
93  * At the end you'll have:
94  * - A list of nodes
95  * - A list of resources (each with any dependencies on other resources)
96  * - A list of constraints between resources and nodes
97  * - A list of constraints between start/stop actions
98  * - A list of nodes that need to be stonith'd
99  * - A list of nodes that need to be shutdown
100  * - A list of the possible stop/start actions (without dependencies)
101  */
102 gboolean
104 {
105  const char *new_version = NULL;
106  xmlNode *section = NULL;
107 
108  if ((scheduler == NULL) || (scheduler->input == NULL)) {
109  return FALSE;
110  }
111 
113 
114  if (pcmk__check_feature_set(new_version) != pcmk_rc_ok) {
115  pcmk__config_err("Can't process CIB with feature set '%s' greater than our own '%s'",
116  new_version, CRM_FEATURE_SET);
117  return FALSE;
118  }
119 
120  crm_trace("Beginning unpack");
121 
122  if (scheduler->priv->failed != NULL) {
124  }
125  scheduler->priv->failed = pcmk__xe_create(NULL, "failed-ops");
126 
127  if (scheduler->priv->now == NULL) {
128  scheduler->priv->now = crm_time_new(NULL);
129  }
130 
133  } else {
135  }
136 
138  scheduler->input,
139  LOG_NEVER);
140  check_for_deprecated_rules(scheduler);
141 
143  scheduler->input,
144  LOG_NEVER);
145 
147  LOG_TRACE);
148  unpack_config(section, scheduler);
149 
150  if (!pcmk_any_flags_set(scheduler->flags,
154  "Fencing and resource management disabled "
155  "due to lack of quorum");
156  }
157 
159  unpack_nodes(section, scheduler);
160 
162  LOG_TRACE);
164  unpack_remote_nodes(section, scheduler);
165  }
166  unpack_resources(section, scheduler);
167 
169  LOG_TRACE);
171 
173  unpack_tags(section, scheduler);
174 
177  LOG_TRACE);
178  unpack_status(section, scheduler);
179  }
180 
182  for (GList *item = scheduler->priv->resources;
183  item != NULL; item = item->next) {
184 
185  pcmk_resource_t *rsc = item->data;
186 
187  rsc->priv->fns->count(item->data);
188  }
189  crm_trace("Cluster resource count: %d (%d disabled, %d blocked)",
193  }
194 
195  if ((scheduler->priv->local_node_name != NULL)
197  scheduler->priv->local_node_name) == NULL)) {
198  crm_info("Creating a fake local node for %s",
202  }
203 
205  return TRUE;
206 }
207 
219 static void
220 pe_free_resources(GList *resources)
221 {
222  pcmk_resource_t *rsc = NULL;
223  GList *iterator = resources;
224 
225  while (iterator != NULL) {
226  rsc = (pcmk_resource_t *) iterator->data;
227  iterator = iterator->next;
228  rsc->priv->fns->free(rsc);
229  }
230  if (resources != NULL) {
231  g_list_free(resources);
232  }
233 }
234 
235 static void
236 pe_free_actions(GList *actions)
237 {
238  GList *iterator = actions;
239 
240  while (iterator != NULL) {
241  pe_free_action(iterator->data);
242  iterator = iterator->next;
243  }
244  if (actions != NULL) {
245  g_list_free(actions);
246  }
247 }
248 
249 static void
250 pe_free_nodes(GList *nodes)
251 {
252  for (GList *iterator = nodes; iterator != NULL; iterator = iterator->next) {
253  pcmk_node_t *node = (pcmk_node_t *) iterator->data;
254 
255  // Shouldn't be possible, but to be safe ...
256  if (node == NULL) {
257  continue;
258  }
259  if (node->details == NULL) {
260  free(node);
261  continue;
262  }
263 
264  /* This is called after pe_free_resources(), which means that we can't
265  * use node->private->name for Pacemaker Remote nodes.
266  */
267  crm_trace("Freeing node %s", (pcmk__is_pacemaker_remote_node(node)?
268  "(guest or remote)" : pcmk__node_name(node)));
269 
270  if (node->priv->attrs != NULL) {
271  g_hash_table_destroy(node->priv->attrs);
272  }
273  if (node->priv->utilization != NULL) {
274  g_hash_table_destroy(node->priv->utilization);
275  }
276  if (node->priv->digest_cache != NULL) {
277  g_hash_table_destroy(node->priv->digest_cache);
278  }
279  g_list_free(node->details->running_rsc);
280  g_list_free(node->priv->assigned_resources);
281  free(node->priv);
282  free(node->details);
283  free(node->assign);
284  free(node);
285  }
286  if (nodes != NULL) {
287  g_list_free(nodes);
288  }
289 }
290 
291 static void
292 pe__free_ordering(GList *constraints)
293 {
294  GList *iterator = constraints;
295 
296  while (iterator != NULL) {
297  pcmk__action_relation_t *order = iterator->data;
298 
299  iterator = iterator->next;
300 
301  free(order->task1);
302  free(order->task2);
303  free(order);
304  }
305  if (constraints != NULL) {
306  g_list_free(constraints);
307  }
308 }
309 
310 static void
311 pe__free_location(GList *constraints)
312 {
313  GList *iterator = constraints;
314 
315  while (iterator != NULL) {
316  pcmk__location_t *cons = iterator->data;
317 
318  iterator = iterator->next;
319 
320  g_list_free_full(cons->nodes, pcmk__free_node_copy);
321  free(cons->id);
322  free(cons);
323  }
324  if (constraints != NULL) {
325  g_list_free(constraints);
326  }
327 }
328 
337 void
339 {
340  if (scheduler == NULL) {
341  return;
342  }
343 
345  if (scheduler->priv->options != NULL) {
346  g_hash_table_destroy(scheduler->priv->options);
347  }
348 
349  if (scheduler->priv->singletons != NULL) {
350  g_hash_table_destroy(scheduler->priv->singletons);
351  }
352 
353  if (scheduler->priv->ticket_constraints != NULL) {
354  g_hash_table_destroy(scheduler->priv->ticket_constraints);
355  }
356 
357  if (scheduler->priv->templates != NULL) {
358  g_hash_table_destroy(scheduler->priv->templates);
359  }
360 
361  if (scheduler->priv->tags != NULL) {
362  g_hash_table_destroy(scheduler->priv->tags);
363  }
364 
365  crm_trace("deleting resources");
366  pe_free_resources(scheduler->priv->resources);
367 
368  crm_trace("deleting actions");
369  pe_free_actions(scheduler->priv->actions);
370 
371  crm_trace("deleting nodes");
372  pe_free_nodes(scheduler->nodes);
373 
375  g_list_free(scheduler->priv->stop_needed);
380 
382 
384  && (scheduler->priv->ordering_constraints == NULL));
385 }
386 
392 void
394 {
395  if (scheduler == NULL) {
396  return;
397  }
398 
399  crm_trace("Deleting %d ordering constraints",
400  g_list_length(scheduler->priv->ordering_constraints));
401  pe__free_ordering(scheduler->priv->ordering_constraints);
403 
404  crm_trace("Deleting %d location constraints",
405  g_list_length(scheduler->priv->location_constraints));
406  pe__free_location(scheduler->priv->location_constraints);
408 
409  crm_trace("Deleting %d colocation constraints",
410  g_list_length(scheduler->priv->colocation_constraints));
411  g_list_free_full(scheduler->priv->colocation_constraints, free);
413 
415 }
416 
417 void
419 {
420  // These members must be preserved
422  pcmk__output_t *out = priv->out;
423  char *local_node_name = scheduler->priv->local_node_name;
424 
425  // Wipe the main structs (any other members must have previously been freed)
426  memset(scheduler, 0, sizeof(pcmk_scheduler_t));
427  memset(priv, 0, sizeof(pcmk__scheduler_private_t));
428 
429  // Restore the members to preserve
430  scheduler->priv = priv;
431  scheduler->priv->out = out;
432  scheduler->priv->local_node_name = local_node_name;
433 
434  // Set defaults for everything else
438 #if PCMK__CONCURRENT_FENCING_DEFAULT_TRUE
444 #else
449 #endif
450 }
451 
453 pe_find_resource(GList *rsc_list, const char *id)
454 {
456 }
457 
459 pe_find_resource_with_flags(GList *rsc_list, const char *id, enum pe_find flags)
460 {
461  GList *rIter = NULL;
462 
463  for (rIter = rsc_list; id && rIter; rIter = rIter->next) {
464  pcmk_resource_t *parent = rIter->data;
465  pcmk_resource_t *match = parent->priv->fns->find_rsc(parent, id, NULL,
466  flags);
467 
468  if (match != NULL) {
469  return match;
470  }
471  }
472  crm_trace("No match for %s", id);
473  return NULL;
474 }
475 
487 pcmk_node_t *
488 pe_find_node_any(const GList *nodes, const char *id, const char *uname)
489 {
490  pcmk_node_t *match = NULL;
491 
492  if (id != NULL) {
493  match = pe_find_node_id(nodes, id);
494  }
495  if ((match == NULL) && (uname != NULL)) {
496  match = pcmk__find_node_in_list(nodes, uname);
497  }
498  return match;
499 }
500 
509 pcmk_node_t *
510 pe_find_node_id(const GList *nodes, const char *id)
511 {
512  for (const GList *iter = nodes; iter != NULL; iter = iter->next) {
513  pcmk_node_t *node = (pcmk_node_t *) iter->data;
514 
515  /* @TODO Whether node IDs should be considered case-sensitive should
516  * probably depend on the node type, so functionizing the comparison
517  * would be worthwhile
518  */
519  if (pcmk__str_eq(node->priv->id, id, pcmk__str_casei)) {
520  return node;
521  }
522  }
523  return NULL;
524 }
525 
526 // Deprecated functions kept only for backward API compatibility
527 // LCOV_EXCL_START
528 
530 
539 pcmk_node_t *
540 pe_find_node(const GList *nodes, const char *node_name)
541 {
542  return pcmk__find_node_in_list(nodes, node_name);
543 }
544 
545 // LCOV_EXCL_STOP
546 // End deprecated API
#define LOG_TRACE
Definition: logging.h:38
pcmk_node_t * pcmk_find_node(const pcmk_scheduler_t *scheduler, const char *node_name)
Find a node by name in scheduler data.
Definition: scheduler.c:100
#define PCMK_XE_FENCING_TOPOLOGY
Definition: xml_names.h:118
A dumping ground.
#define PCMK_XE_OP_DEFAULTS
Definition: xml_names.h:147
void pe_free_working_set(pcmk_scheduler_t *scheduler)
Free scheduler data.
Definition: status.c:56
#define PCMK_XE_STATUS
Definition: xml_names.h:204
pe_find
Search options for resources (exact resource ID always matches)
Definition: resources.h:32
#define PCMK_XE_RSC_DEFAULTS
Definition: xml_names.h:186
pcmk_resource_t * pe_find_resource_with_flags(GList *rsc_list, const char *id, enum pe_find flags)
Definition: status.c:459
#define CRM_FEATURE_SET
Definition: crm.h:66
#define pcmk__config_err(fmt...)
#define PCMK_XA_HAVE_QUORUM
Definition: xml_names.h:295
pcmk_scheduler_t * pe_new_working_set(void)
Create a new object to hold scheduler data.
Definition: status.c:34
pcmk__scheduler_private_t * priv
Definition: scheduler.h:99
pcmk_node_t * pe_create_node(const char *id, const char *uname, const char *type, int score, pcmk_scheduler_t *scheduler)
Definition: unpack.c:444
uint64_t flags
Definition: scheduler.h:89
Stop all resources in partition.
Definition: scheduler.h:40
#define CRM_LOG_ASSERT(expr)
Definition: logging.h:196
G_GNUC_INTERNAL gboolean unpack_remote_nodes(xmlNode *xml_resources, pcmk_scheduler_t *scheduler)
Definition: unpack.c:683
const pcmk__rsc_methods_t * fns
bool pcmk__xe_attr_is_true(const xmlNode *node, const char *name)
Definition: xml_element.c:1538
G_GNUC_INTERNAL void pcmk__validate_fencing_topology(const xmlNode *xml)
Definition: unpack.c:890
void pcmk__free_node_copy(void *data)
Definition: nodes.c:22
#define LOG_NEVER
Definition: logging.h:48
xmlNode * get_xpath_object(const char *xpath, xmlNode *xml_obj, int error_level)
Definition: xpath.c:189
G_GNUC_INTERNAL gboolean unpack_resources(const xmlNode *xml_resources, pcmk_scheduler_t *scheduler)
Definition: unpack.c:815
xmlNode * pcmk__xe_create(xmlNode *parent, const char *name)
Definition: xml_element.c:407
enum pe_quorum_policy no_quorum_policy
Definition: scheduler.h:93
pcmk_node_t * pe_find_node_id(const GList *nodes, const char *id)
Find a node by ID in a list of nodes.
Definition: status.c:510
void pcmk__xml_free(xmlNode *xml)
Definition: xml.c:789
Also match clone instance ID from resource history.
Definition: resources.h:34
G_GNUC_INTERNAL gboolean unpack_status(xmlNode *status, pcmk_scheduler_t *scheduler)
Definition: unpack.c:1388
pcmk__node_private_t * priv
Definition: nodes.h:85
void(* count)(pcmk_resource_t *rsc)
pcmk_node_t * pcmk__find_node_in_list(const GList *nodes, const char *node_name)
Definition: nodes.c:170
gboolean cluster_status(pcmk_scheduler_t *scheduler)
Definition: status.c:103
void pe__free_param_checks(pcmk_scheduler_t *scheduler)
Definition: remote.c:236
void set_working_set_defaults(pcmk_scheduler_t *scheduler)
Definition: status.c:418
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
Definition: xml_element.c:1168
#define crm_trace(fmt, args...)
Definition: logging.h:372
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
Definition: util.h:80
#define pcmk__clear_scheduler_flags(scheduler, flags_to_clear)
pcmk__resource_private_t * priv
Definition: resources.h:61
Wrappers for and extensions to libxml2.
Act as if partition still holds quorum.
Definition: scheduler.h:41
GHashTable * digest_cache
G_GNUC_INTERNAL gboolean unpack_nodes(xmlNode *xml_nodes, pcmk_scheduler_t *scheduler)
Definition: unpack.c:601
void cleanup_calculations(pcmk_scheduler_t *scheduler)
Reset scheduler data to defaults without freeing it or constraints.
Definition: status.c:338
#define pcmk__warn_once(wo_flag, fmt...)
#define PCMK_XE_TAGS
Definition: xml_names.h:209
GList * running_rsc
Definition: nodes.h:70
#define PCMK_XA_CRM_FEATURE_SET
Definition: xml_names.h:254
#define pcmk__sched_warn(scheduler, fmt...)
#define PCMK_XE_OP
Definition: xml_names.h:146
GList * nodes
Definition: scheduler.h:97
pcmk_scheduler_t * scheduler
Deprecated Pacemaker scheduler utilities.
crm_time_t * crm_time_new(const char *string)
Definition: iso8601.c:112
xmlNode * input
Definition: scheduler.h:81
This structure contains everything that makes up a single output formatter.
void pe_free_action(pcmk_action_t *action)
Definition: pe_actions.c:1361
char uname[MAX_NAME]
Definition: cpg.c:53
GHashTable * attrs
pcmk_node_t * pe_find_node_any(const GList *nodes, const char *id, const char *uname)
Find a node by name or ID in a list of nodes.
Definition: status.c:488
#define PCMK_XE_NODES
Definition: xml_names.h:142
G_GNUC_INTERNAL gboolean unpack_config(xmlNode *config, pcmk_scheduler_t *scheduler)
Definition: unpack.c:217
Location constraint object.
const char * parent
Definition: cib.c:27
void(* free)(pcmk_resource_t *rsc)
struct pcmk__node_details * details
Definition: nodes.h:82
pcmk_resource_t * pe_find_resource(GList *rsc_list, const char *id)
Definition: status.c:453
void pe_reset_working_set(pcmk_scheduler_t *scheduler)
Reset scheduler data to default state without freeing it.
Definition: status.c:393
#define crm_info(fmt, args...)
Definition: logging.h:367
#define PCMK_XE_RESOURCES
Definition: xml_names.h:179
#define pcmk__set_scheduler_flags(scheduler, flags_to_set)
uint64_t flags
Definition: remote.c:211
G_GNUC_INTERNAL gboolean unpack_tags(xmlNode *xml_tags, pcmk_scheduler_t *scheduler)
Definition: unpack.c:925
#define XPATH_DEPRECATED_RULES
Definition: status.c:66
#define PCMK_XE_CRM_CONFIG
Definition: xml_names.h:91
int pcmk__check_feature_set(const char *cib_version)
Definition: cib.c:184
GHashTable * utilization
void crm_time_free(crm_time_t *dt)
Definition: iso8601.c:150
struct pcmk__node_assignment * assign
Definition: nodes.h:79
pcmk_node_t * pe_find_node(const GList *nodes, const char *node_name)
Find a node by name in a list of nodes.
Definition: status.c:540