pacemaker  1.1.24-3850484742
Scalable High-Availability cluster resource manager
native.c
Go to the documentation of this file.
1 /*
2  * Copyright 2004-2018 Andrew Beekhof <andrew@beekhof.net>
3  *
4  * This source code is licensed under the GNU Lesser General Public License
5  * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
6  */
7 
8 #include <crm_internal.h>
9 
10 #include <crm/pengine/rules.h>
11 #include <crm/pengine/status.h>
12 #include <crm/pengine/complex.h>
13 #include <crm/pengine/internal.h>
14 #include <unpack.h>
15 #include <crm/msg_xml.h>
16 #include <pe_status_private.h>
17 
18 #define VARIANT_NATIVE 1
19 #include "./variant.h"
20 
25 static bool
26 is_multiply_active(pe_resource_t *rsc)
27 {
28  unsigned int count = 0;
29 
30  if (rsc->variant == pe_native) {
31  pe__find_active_requires(rsc, &count);
32  }
33  return count > 1;
34 }
35 
36 static void
37 native_priority_to_node(pe_resource_t * rsc, pe_node_t * node)
38 {
39  int priority = 0;
40 
41  if (rsc->priority == 0) {
42  return;
43  }
44 
45  if (rsc->role == RSC_ROLE_MASTER) {
46  // Promoted instance takes base priority + 1
47  priority = rsc->priority + 1;
48 
49  } else {
50  priority = rsc->priority;
51  }
52 
53  node->details->priority += priority;
54  pe_rsc_trace(rsc, "Node '%s' now has priority %d with %s'%s' (priority: %d%s)",
55  node->details->uname, node->details->priority,
56  rsc->role == RSC_ROLE_MASTER ? "promoted " : "",
57  rsc->id, rsc->priority,
58  rsc->role == RSC_ROLE_MASTER ? " + 1" : "");
59 
60  /* Priority of a resource running on a guest node is added to the cluster
61  * node as well. */
62  if (node->details->remote_rsc
63  && node->details->remote_rsc->container) {
65 
66  for (; gIter != NULL; gIter = gIter->next) {
67  pe_node_t *a_node = gIter->data;
68 
69  a_node->details->priority += priority;
70  pe_rsc_trace(rsc, "Node '%s' now has priority %d with %s'%s' (priority: %d%s) "
71  "from guest node '%s'",
72  a_node->details->uname, a_node->details->priority,
73  rsc->role == RSC_ROLE_MASTER ? "promoted " : "",
74  rsc->id, rsc->priority,
75  rsc->role == RSC_ROLE_MASTER ? " + 1" : "",
76  node->details->uname);
77  }
78  }
79 }
80 
81 void
83 {
84  GListPtr gIter = rsc->running_on;
85 
86  CRM_CHECK(node != NULL, return);
87  for (; gIter != NULL; gIter = gIter->next) {
88  node_t *a_node = (node_t *) gIter->data;
89 
90  CRM_CHECK(a_node != NULL, return);
91  if (safe_str_eq(a_node->details->id, node->details->id)) {
92  return;
93  }
94  }
95 
96  pe_rsc_trace(rsc, "Adding %s to %s %s", rsc->id, node->details->uname,
97  is_set(rsc->flags, pe_rsc_managed)?"":"(unmanaged)");
98 
99  rsc->running_on = g_list_append(rsc->running_on, node);
100  if (rsc->variant == pe_native) {
101  node->details->running_rsc = g_list_append(node->details->running_rsc, rsc);
102 
103  native_priority_to_node(rsc, node);
104  }
105 
106  if (rsc->variant == pe_native && node->details->maintenance) {
108  }
109 
110  if (is_not_set(rsc->flags, pe_rsc_managed)) {
111  resource_t *p = rsc->parent;
112 
113  pe_rsc_info(rsc, "resource %s isn't managed", rsc->id);
114  resource_location(rsc, node, INFINITY, "not_managed_default", data_set);
115 
116  while(p && node->details->online) {
117  /* add without the additional location constraint */
118  p->running_on = g_list_append(p->running_on, node);
119  p = p->parent;
120  }
121  return;
122  }
123 
124  if (is_multiply_active(rsc)) {
125  switch (rsc->recovery_type) {
126  case recovery_stop_only:
127  {
128  GHashTableIter gIter;
129  node_t *local_node = NULL;
130 
131  /* make sure it doesn't come up again */
132  if (rsc->allowed_nodes != NULL) {
133  g_hash_table_destroy(rsc->allowed_nodes);
134  }
135  rsc->allowed_nodes = node_hash_from_list(data_set->nodes);
136  g_hash_table_iter_init(&gIter, rsc->allowed_nodes);
137  while (g_hash_table_iter_next(&gIter, NULL, (void **)&local_node)) {
138  local_node->weight = -INFINITY;
139  }
140  }
141  break;
142  case recovery_stop_start:
143  break;
144  case recovery_block:
146  set_bit(rsc->flags, pe_rsc_block);
147 
148  /* If the resource belongs to a group or bundle configured with
149  * multiple-active=block, block the entire entity.
150  */
151  if (rsc->parent
152  && (rsc->parent->variant == pe_group || rsc->parent->variant == pe_container)
153  && rsc->parent->recovery_type == recovery_block) {
154  GListPtr gIter = rsc->parent->children;
155 
156  for (; gIter != NULL; gIter = gIter->next) {
157  resource_t *child = (resource_t *) gIter->data;
158 
159  clear_bit(child->flags, pe_rsc_managed);
160  set_bit(child->flags, pe_rsc_block);
161  }
162  }
163  break;
164  }
165  crm_debug("%s is active on multiple nodes including %s: %s",
166  rsc->id, node->details->uname,
167  recovery2text(rsc->recovery_type));
168 
169  } else {
170  pe_rsc_trace(rsc, "Resource %s is active on: %s", rsc->id, node->details->uname);
171  }
172 
173  if (rsc->parent != NULL) {
174  native_add_running(rsc->parent, node, data_set);
175  }
176 }
177 
178 static void
179 recursive_clear_unique(pe_resource_t *rsc)
180 {
183 
184  for (GList *child = rsc->children; child != NULL; child = child->next) {
185  recursive_clear_unique((pe_resource_t *) child->data);
186  }
187 }
188 
189 gboolean
191 {
192  resource_t *parent = uber_parent(rsc);
193  native_variant_data_t *native_data = NULL;
194  const char *standard = crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS);
195  uint32_t ra_caps = pcmk_get_ra_caps(standard);
196 
197  pe_rsc_trace(rsc, "Processing resource %s...", rsc->id);
198 
199  native_data = calloc(1, sizeof(native_variant_data_t));
200  rsc->variant_opaque = native_data;
201 
202  // Only some agent standards support unique and promotable clones
203  if (is_not_set(ra_caps, pcmk_ra_cap_unique)
204  && is_set(rsc->flags, pe_rsc_unique) && pe_rsc_is_clone(parent)) {
205 
206  /* @COMPAT We should probably reject this situation as an error (as we
207  * do for promotable below) rather than warn and convert, but that would
208  * be a backward-incompatible change that we should probably do with a
209  * transform at a schema major version bump.
210  */
211  pe__force_anon(standard, parent, rsc->id, data_set);
212 
213  /* Clear globally-unique on the parent and all its descendents unpacked
214  * so far (clearing the parent should make any future children unpacking
215  * correct). We have to clear this resource explicitly because it isn't
216  * hooked into the parent's children yet.
217  */
218  recursive_clear_unique(parent);
219  recursive_clear_unique(rsc);
220  }
221  if (is_not_set(ra_caps, pcmk_ra_cap_promotable)) {
222  const char *stateful = g_hash_table_lookup(parent->meta, "stateful");
223 
224  if (safe_str_eq(stateful, XML_BOOLEAN_TRUE)) {
225  pe_err
226  ("Resource %s is of type %s and therefore cannot be used as a master/slave resource",
227  rsc->id, standard);
228  return FALSE;
229  }
230  }
231  return TRUE;
232 }
233 
234 static bool
235 rsc_is_on_node(resource_t *rsc, node_t *node, int flags)
236 {
237  pe_rsc_trace(rsc, "Checking whether %s is on %s",
238  rsc->id, node->details->uname);
239 
240  if (is_set(flags, pe_find_current) && rsc->running_on) {
241 
242  for (GListPtr iter = rsc->running_on; iter; iter = iter->next) {
243  node_t *loc = (node_t *) iter->data;
244 
245  if (loc->details == node->details) {
246  return TRUE;
247  }
248  }
249 
250  } else if (is_set(flags, pe_find_inactive) && (rsc->running_on == NULL)) {
251  return TRUE;
252 
253  } else if (is_not_set(flags, pe_find_current) && rsc->allocated_to
254  && (rsc->allocated_to->details == node->details)) {
255  return TRUE;
256  }
257  return FALSE;
258 }
259 
260 resource_t *
261 native_find_rsc(resource_t * rsc, const char *id, node_t * on_node, int flags)
262 {
263  bool match = FALSE;
264  resource_t *result = NULL;
265 
266  CRM_CHECK(id && rsc && rsc->id, return NULL);
267 
268  if (flags & pe_find_clone) {
269  const char *rid = ID(rsc->xml);
270 
271  if (!pe_rsc_is_clone(uber_parent(rsc))) {
272  match = FALSE;
273 
274  } else if (!strcmp(id, rsc->id) || safe_str_eq(id, rid)) {
275  match = TRUE;
276  }
277 
278  } else if (!strcmp(id, rsc->id)) {
279  match = TRUE;
280 
281  } else if (is_set(flags, pe_find_renamed)
282  && rsc->clone_name && strcmp(rsc->clone_name, id) == 0) {
283  match = TRUE;
284 
285  } else if (is_set(flags, pe_find_any)
286  || (is_set(flags, pe_find_anon)
287  && is_not_set(rsc->flags, pe_rsc_unique))) {
288  match = pe_base_name_eq(rsc, id);
289  }
290 
291  if (match && on_node) {
292  bool match_node = rsc_is_on_node(rsc, on_node, flags);
293 
294  if (match_node == FALSE) {
295  match = FALSE;
296  }
297  }
298 
299  if (match) {
300  return rsc;
301  }
302 
303  for (GListPtr gIter = rsc->children; gIter != NULL; gIter = gIter->next) {
304  resource_t *child = (resource_t *) gIter->data;
305 
306  result = rsc->fns->find_rsc(child, id, on_node, flags);
307  if (result) {
308  return result;
309  }
310  }
311  return NULL;
312 }
313 
314 char *
315 native_parameter(resource_t * rsc, node_t * node, gboolean create, const char *name,
316  pe_working_set_t * data_set)
317 {
318  char *value_copy = NULL;
319  const char *value = NULL;
320  GHashTable *hash = NULL;
321  GHashTable *local_hash = NULL;
322 
323  CRM_CHECK(rsc != NULL, return NULL);
324  CRM_CHECK(name != NULL && strlen(name) != 0, return NULL);
325 
326  pe_rsc_trace(rsc, "Looking up %s in %s", name, rsc->id);
327 
328  if (create || g_hash_table_size(rsc->parameters) == 0) {
329  if (node != NULL) {
330  pe_rsc_trace(rsc, "Creating hash with node %s", node->details->uname);
331  } else {
332  pe_rsc_trace(rsc, "Creating default hash");
333  }
334 
335  local_hash = crm_str_table_new();
336 
337  get_rsc_attributes(local_hash, rsc, node, data_set);
338 
339  hash = local_hash;
340  } else {
341  hash = rsc->parameters;
342  }
343 
344  value = g_hash_table_lookup(hash, name);
345  if (value == NULL) {
346  /* try meta attributes instead */
347  value = g_hash_table_lookup(rsc->meta, name);
348  }
349 
350  if (value != NULL) {
351  value_copy = strdup(value);
352  }
353  if (local_hash != NULL) {
354  g_hash_table_destroy(local_hash);
355  }
356  return value_copy;
357 }
358 
359 gboolean
360 native_active(resource_t * rsc, gboolean all)
361 {
362  GListPtr gIter = rsc->running_on;
363 
364  for (; gIter != NULL; gIter = gIter->next) {
365  node_t *a_node = (node_t *) gIter->data;
366 
367  if (a_node->details->unclean) {
368  crm_debug("Resource %s: node %s is unclean", rsc->id, a_node->details->uname);
369  return TRUE;
370  } else if (a_node->details->online == FALSE) {
371  crm_debug("Resource %s: node %s is offline", rsc->id, a_node->details->uname);
372  } else {
373  crm_debug("Resource %s active on %s", rsc->id, a_node->details->uname);
374  return TRUE;
375  }
376  }
377 
378  return FALSE;
379 }
380 
381 struct print_data_s {
382  long options;
383  void *print_data;
384 };
385 
386 static void
387 native_print_attr(gpointer key, gpointer value, gpointer user_data)
388 {
389  long options = ((struct print_data_s *)user_data)->options;
390  void *print_data = ((struct print_data_s *)user_data)->print_data;
391 
392  status_print("Option: %s = %s\n", (char *)key, (char *)value);
393 }
394 
395 static const char *
396 native_pending_state(resource_t * rsc)
397 {
398  const char *pending_state = NULL;
399 
401  pending_state = "Starting";
402 
403  } else if (safe_str_eq(rsc->pending_task, CRMD_ACTION_STOP)) {
404  pending_state = "Stopping";
405 
406  } else if (safe_str_eq(rsc->pending_task, CRMD_ACTION_MIGRATE)) {
407  pending_state = "Migrating";
408 
409  } else if (safe_str_eq(rsc->pending_task, CRMD_ACTION_MIGRATED)) {
410  /* Work might be done in here. */
411  pending_state = "Migrating";
412 
413  } else if (safe_str_eq(rsc->pending_task, CRMD_ACTION_PROMOTE)) {
414  pending_state = "Promoting";
415 
416  } else if (safe_str_eq(rsc->pending_task, CRMD_ACTION_DEMOTE)) {
417  pending_state = "Demoting";
418  }
419 
420  return pending_state;
421 }
422 
423 static const char *
424 native_pending_task(resource_t * rsc)
425 {
426  const char *pending_task = NULL;
427 
429  /* "Notifying" is not very useful to be shown. */
430  pending_task = NULL;
431 
432  } else if (safe_str_eq(rsc->pending_task, CRMD_ACTION_STATUS)) {
433  pending_task = "Monitoring";
434 
435  /* Pending probes are not printed, even if pending
436  * operations are requested. If someone ever requests that
437  * behavior, uncomment this and the corresponding part of
438  * unpack.c:unpack_rsc_op().
439  */
440  /*
441  } else if (safe_str_eq(rsc->pending_task, "probe")) {
442  pending_task = "Checking";
443  */
444  }
445 
446  return pending_task;
447 }
448 
449 static enum rsc_role_e
450 native_displayable_role(resource_t *rsc)
451 {
452  enum rsc_role_e role = rsc->role;
453 
454  if ((role == RSC_ROLE_STARTED)
455  && (uber_parent(rsc)->variant == pe_master)) {
456 
457  role = RSC_ROLE_SLAVE;
458  }
459  return role;
460 }
461 
462 static const char *
463 native_displayable_state(resource_t *rsc, long options)
464 {
465  const char *rsc_state = NULL;
466 
467  if (options & pe_print_pending) {
468  rsc_state = native_pending_state(rsc);
469  }
470  if (rsc_state == NULL) {
471  rsc_state = role2text(native_displayable_role(rsc));
472  }
473  return rsc_state;
474 }
475 
476 static void
477 native_print_xml(resource_t * rsc, const char *pre_text, long options, void *print_data)
478 {
479  const char *class = crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS);
480  const char *prov = crm_element_value(rsc->xml, XML_AGENT_ATTR_PROVIDER);
481  const char *rsc_state = native_displayable_state(rsc, options);
482  const char *target_role = NULL;
483 
484  /* resource information. */
485  status_print("%s<resource ", pre_text);
486  status_print("id=\"%s\" ", rsc_printable_id(rsc));
487  status_print("resource_agent=\"%s%s%s:%s\" ",
488  class,
489  prov ? "::" : "", prov ? prov : "", crm_element_value(rsc->xml, XML_ATTR_TYPE));
490 
491  status_print("role=\"%s\" ", rsc_state);
492  if (rsc->meta) {
493  target_role = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_TARGET_ROLE);
494  }
495  if (target_role) {
496  status_print("target_role=\"%s\" ", target_role);
497  }
498  status_print("active=\"%s\" ", rsc->fns->active(rsc, TRUE) ? "true" : "false");
499  status_print("orphaned=\"%s\" ", is_set(rsc->flags, pe_rsc_orphan) ? "true" : "false");
500  status_print("blocked=\"%s\" ", is_set(rsc->flags, pe_rsc_block) ? "true" : "false");
501  status_print("managed=\"%s\" ", is_set(rsc->flags, pe_rsc_managed) ? "true" : "false");
502  status_print("failed=\"%s\" ", is_set(rsc->flags, pe_rsc_failed) ? "true" : "false");
503  status_print("failure_ignored=\"%s\" ",
504  is_set(rsc->flags, pe_rsc_failure_ignored) ? "true" : "false");
505  status_print("nodes_running_on=\"%d\" ", g_list_length(rsc->running_on));
506 
507  if (options & pe_print_pending) {
508  const char *pending_task = native_pending_task(rsc);
509 
510  if (pending_task) {
511  status_print("pending=\"%s\" ", pending_task);
512  }
513  }
514 
515  if (options & pe_print_dev) {
516  status_print("provisional=\"%s\" ",
517  is_set(rsc->flags, pe_rsc_provisional) ? "true" : "false");
518  status_print("runnable=\"%s\" ", is_set(rsc->flags, pe_rsc_runnable) ? "true" : "false");
519  status_print("priority=\"%f\" ", (double)rsc->priority);
520  status_print("variant=\"%s\" ", crm_element_name(rsc->xml));
521  }
522 
523  /* print out the nodes this resource is running on */
524  if (options & pe_print_rsconly) {
525  status_print("/>\n");
526  /* do nothing */
527  } else if (rsc->running_on != NULL) {
528  GListPtr gIter = rsc->running_on;
529 
530  status_print(">\n");
531  for (; gIter != NULL; gIter = gIter->next) {
532  node_t *node = (node_t *) gIter->data;
533 
534  status_print("%s <node name=\"%s\" id=\"%s\" cached=\"%s\"/>\n", pre_text,
535  node->details->uname, node->details->id,
536  node->details->online ? "false" : "true");
537  }
538  status_print("%s</resource>\n", pre_text);
539  } else {
540  status_print("/>\n");
541  }
542 }
543 
544 /* making this inline rather than a macro prevents a coverity "unreachable"
545  * warning on the first usage
546  */
547 static inline const char *
548 comma_if(int i)
549 {
550  return i? ", " : "";
551 }
552 
553 void
554 common_print(resource_t * rsc, const char *pre_text, const char *name, node_t *node, long options, void *print_data)
555 {
556  const char *desc = NULL;
557  const char *class = crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS);
558  const char *kind = crm_element_value(rsc->xml, XML_ATTR_TYPE);
559  const char *target_role = NULL;
560  enum rsc_role_e role = native_displayable_role(rsc);
561 
562  int offset = 0;
563  int flagOffset = 0;
564  char buffer[LINE_MAX];
565  char flagBuffer[LINE_MAX];
566 
567  CRM_ASSERT(rsc->variant == pe_native);
568  CRM_ASSERT(kind != NULL);
569 
570  if (rsc->meta) {
571  const char *is_internal = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_INTERNAL_RSC);
572  if (crm_is_true(is_internal) && is_not_set(options, pe_print_implicit)) {
573  crm_trace("skipping print of internal resource %s", rsc->id);
574  return;
575  }
576  target_role = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_TARGET_ROLE);
577  }
578 
579  if (pre_text == NULL && (options & pe_print_printf)) {
580  pre_text = " ";
581  }
582 
583  if (options & pe_print_xml) {
584  native_print_xml(rsc, pre_text, options, print_data);
585  return;
586  }
587 
588  if ((options & pe_print_rsconly) || g_list_length(rsc->running_on) > 1) {
589  node = NULL;
590  }
591 
592  if (options & pe_print_html) {
593  if (is_not_set(rsc->flags, pe_rsc_managed)) {
594  status_print("<font color=\"yellow\">");
595 
596  } else if (is_set(rsc->flags, pe_rsc_failed)) {
597  status_print("<font color=\"red\">");
598 
599  } else if (rsc->variant == pe_native && (rsc->running_on == NULL)) {
600  status_print("<font color=\"red\">");
601 
602  } else if (g_list_length(rsc->running_on) > 1) {
603  status_print("<font color=\"orange\">");
604 
605  } else if (is_set(rsc->flags, pe_rsc_failure_ignored)) {
606  status_print("<font color=\"yellow\">");
607 
608  } else {
609  status_print("<font color=\"green\">");
610  }
611  }
612 
613  if(pre_text) {
614  offset += snprintf(buffer + offset, LINE_MAX - offset, "%s", pre_text);
615  }
616  offset += snprintf(buffer + offset, LINE_MAX - offset, "%s", name);
617  offset += snprintf(buffer + offset, LINE_MAX - offset, "\t(%s", class);
618  if (is_set(pcmk_get_ra_caps(class), pcmk_ra_cap_provider)) {
619  const char *prov = crm_element_value(rsc->xml, XML_AGENT_ATTR_PROVIDER);
620  offset += snprintf(buffer + offset, LINE_MAX - offset, "::%s", prov);
621  }
622  offset += snprintf(buffer + offset, LINE_MAX - offset, ":%s):\t", kind);
623  if(is_set(rsc->flags, pe_rsc_orphan)) {
624  offset += snprintf(buffer + offset, LINE_MAX - offset, " ORPHANED ");
625  }
626  if(role > RSC_ROLE_SLAVE && is_set(rsc->flags, pe_rsc_failed)) {
627  offset += snprintf(buffer + offset, LINE_MAX - offset, "FAILED %s", role2text(role));
628  } else if(is_set(rsc->flags, pe_rsc_failed)) {
629  offset += snprintf(buffer + offset, LINE_MAX - offset, "FAILED");
630  } else {
631  const char *rsc_state = native_displayable_state(rsc, options);
632 
633  offset += snprintf(buffer + offset, LINE_MAX - offset, "%s", rsc_state);
634  }
635 
636  if(node) {
637  offset += snprintf(buffer + offset, LINE_MAX - offset, " %s", node->details->uname);
638 
639  if (node->details->online == FALSE && node->details->unclean) {
640  flagOffset += snprintf(flagBuffer + flagOffset, LINE_MAX - flagOffset,
641  "%sUNCLEAN", comma_if(flagOffset));
642  }
643  }
644 
645  if (options & pe_print_pending) {
646  const char *pending_task = native_pending_task(rsc);
647 
648  if (pending_task) {
649  flagOffset += snprintf(flagBuffer + flagOffset, LINE_MAX - flagOffset,
650  "%s%s", comma_if(flagOffset), pending_task);
651  }
652  }
653 
654  if (target_role) {
655  enum rsc_role_e target_role_e = text2role(target_role);
656 
657  /* Ignore target role Started, as it is the default anyways
658  * (and would also allow a Master to be Master).
659  * Show if target role limits our abilities. */
660  if (target_role_e == RSC_ROLE_STOPPED) {
661  flagOffset += snprintf(flagBuffer + flagOffset, LINE_MAX - flagOffset,
662  "%sdisabled", comma_if(flagOffset));
663 
664  } else if (uber_parent(rsc)->variant == pe_master
665  && target_role_e == RSC_ROLE_SLAVE) {
666  flagOffset += snprintf(flagBuffer + flagOffset, LINE_MAX - flagOffset,
667  "%starget-role:%s", comma_if(flagOffset), target_role);
668  }
669  }
670 
671  if (is_set(rsc->flags, pe_rsc_block)) {
672  flagOffset += snprintf(flagBuffer + flagOffset, LINE_MAX - flagOffset,
673  "%sblocked", comma_if(flagOffset));
674 
675  } else if (is_not_set(rsc->flags, pe_rsc_managed)) {
676  flagOffset += snprintf(flagBuffer + flagOffset, LINE_MAX - flagOffset,
677  "%sunmanaged", comma_if(flagOffset));
678  }
679 
680  if(is_set(rsc->flags, pe_rsc_failure_ignored)) {
681  flagOffset += snprintf(flagBuffer + flagOffset, LINE_MAX - flagOffset,
682  "%sfailure ignored", comma_if(flagOffset));
683  }
684 
685  if ((options & pe_print_rsconly) || g_list_length(rsc->running_on) > 1) {
686  desc = crm_element_value(rsc->xml, XML_ATTR_DESC);
687  }
688 
689  CRM_LOG_ASSERT(offset > 0);
690  if(flagOffset > 0) {
691  status_print("%s (%s)%s%s", buffer, flagBuffer, desc?" ":"", desc?desc:"");
692  } else {
693  status_print("%s%s%s", buffer, desc?" ":"", desc?desc:"");
694  }
695 
696 #if CURSES_ENABLED
697  if ((options & pe_print_rsconly) || g_list_length(rsc->running_on) > 1) {
698  /* Done */
699 
700  } else if (options & pe_print_ncurses) {
701  /* coverity[negative_returns] False positive */
702  move(-1, 0);
703  }
704 #endif
705 
706  if (options & pe_print_html) {
707  status_print(" </font> ");
708  }
709 
710  if ((options & pe_print_rsconly)) {
711 
712  } else if (g_list_length(rsc->running_on) > 1) {
713  GListPtr gIter = rsc->running_on;
714  int counter = 0;
715 
716  if (options & pe_print_html) {
717  status_print("<ul>\n");
718  } else if ((options & pe_print_printf)
719  || (options & pe_print_ncurses)) {
720  status_print("[");
721  }
722 
723  for (; gIter != NULL; gIter = gIter->next) {
724  node_t *n = (node_t *) gIter->data;
725 
726  counter++;
727 
728  if (options & pe_print_html) {
729  status_print("<li>\n%s", n->details->uname);
730 
731  } else if ((options & pe_print_printf)
732  || (options & pe_print_ncurses)) {
733  status_print(" %s", n->details->uname);
734 
735  } else if ((options & pe_print_log)) {
736  status_print("\t%d : %s", counter, n->details->uname);
737 
738  } else {
739  status_print("%s", n->details->uname);
740  }
741  if (options & pe_print_html) {
742  status_print("</li>\n");
743 
744  }
745  }
746 
747  if (options & pe_print_html) {
748  status_print("</ul>\n");
749  } else if ((options & pe_print_printf)
750  || (options & pe_print_ncurses)) {
751  status_print(" ]");
752  }
753  }
754 
755  if (options & pe_print_html) {
756  status_print("<br/>\n");
757  } else if (options & pe_print_suppres_nl) {
758  /* nothing */
759  } else if ((options & pe_print_printf) || (options & pe_print_ncurses)) {
760  status_print("\n");
761  }
762 
763  if (options & pe_print_details) {
764  struct print_data_s pdata;
765 
766  pdata.options = options;
767  pdata.print_data = print_data;
768  g_hash_table_foreach(rsc->parameters, native_print_attr, &pdata);
769  }
770 
771  if (options & pe_print_dev) {
772  GHashTableIter iter;
773  node_t *n = NULL;
774 
775  status_print("%s\t(%s%svariant=%s, priority=%f)", pre_text,
776  is_set(rsc->flags, pe_rsc_provisional) ? "provisional, " : "",
777  is_set(rsc->flags, pe_rsc_runnable) ? "" : "non-startable, ",
778  crm_element_name(rsc->xml), (double)rsc->priority);
779  status_print("%s\tAllowed Nodes", pre_text);
780  g_hash_table_iter_init(&iter, rsc->allowed_nodes);
781  while (g_hash_table_iter_next(&iter, NULL, (void **)&n)) {
782  status_print("%s\t * %s %d", pre_text, n->details->uname, n->weight);
783  }
784  }
785 
786  if (options & pe_print_max_details) {
787  GHashTableIter iter;
788  node_t *n = NULL;
789 
790  status_print("%s\t=== Allowed Nodes\n", pre_text);
791  g_hash_table_iter_init(&iter, rsc->allowed_nodes);
792  while (g_hash_table_iter_next(&iter, NULL, (void **)&n)) {
793  print_node("\t", n, FALSE);
794  }
795  }
796 }
797 
798 void
799 native_print(resource_t * rsc, const char *pre_text, long options, void *print_data)
800 {
801  node_t *node = NULL;
802 
803  CRM_ASSERT(rsc->variant == pe_native);
804  if (options & pe_print_xml) {
805  native_print_xml(rsc, pre_text, options, print_data);
806  return;
807  }
808 
809  node = pe__current_node(rsc);
810 
811  if (node == NULL) {
812  // This is set only if a non-probe action is pending on this node
813  node = rsc->pending_node;
814  }
815 
816  common_print(rsc, pre_text, rsc_printable_id(rsc), node, options, print_data);
817 }
818 
819 void
821 {
822  pe_rsc_trace(rsc, "Freeing resource action list (not the data)");
823  common_free(rsc);
824 }
825 
826 enum rsc_role_e
827 native_resource_state(const resource_t * rsc, gboolean current)
828 {
829  enum rsc_role_e role = rsc->next_role;
830 
831  if (current) {
832  role = rsc->role;
833  }
834  pe_rsc_trace(rsc, "%s state: %s", rsc->id, role2text(role));
835  return role;
836 }
837 
848 pe_node_t *
849 native_location(const pe_resource_t *rsc, GList **list, int current)
850 {
851  node_t *one = NULL;
852  GListPtr result = NULL;
853 
854  if (rsc->children) {
855  GListPtr gIter = rsc->children;
856 
857  for (; gIter != NULL; gIter = gIter->next) {
858  resource_t *child = (resource_t *) gIter->data;
859 
860  child->fns->location(child, &result, current);
861  }
862 
863  } else if (current) {
864 
865  if (rsc->running_on) {
866  result = g_list_copy(rsc->running_on);
867  }
868  if ((current == 2) && rsc->pending_node
869  && !pe_find_node_id(result, rsc->pending_node->details->id)) {
870  result = g_list_append(result, rsc->pending_node);
871  }
872 
873  } else if (current == FALSE && rsc->allocated_to) {
874  result = g_list_append(NULL, rsc->allocated_to);
875  }
876 
877  if (result && (result->next == NULL)) {
878  one = result->data;
879  }
880 
881  if (list) {
882  GListPtr gIter = result;
883 
884  for (; gIter != NULL; gIter = gIter->next) {
885  node_t *node = (node_t *) gIter->data;
886 
887  if (*list == NULL || pe_find_node_id(*list, node->details->id) == NULL) {
888  *list = g_list_append(*list, node);
889  }
890  }
891  }
892 
893  g_list_free(result);
894  return one;
895 }
896 
897 static void
898 get_rscs_brief(GListPtr rsc_list, GHashTable * rsc_table, GHashTable * active_table)
899 {
900  GListPtr gIter = rsc_list;
901 
902  for (; gIter != NULL; gIter = gIter->next) {
903  resource_t *rsc = (resource_t *) gIter->data;
904 
905  const char *class = crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS);
906  const char *kind = crm_element_value(rsc->xml, XML_ATTR_TYPE);
907 
908  int offset = 0;
909  char buffer[LINE_MAX];
910 
911  int *rsc_counter = NULL;
912  int *active_counter = NULL;
913 
914  if (rsc->variant != pe_native) {
915  continue;
916  }
917 
918  offset += snprintf(buffer + offset, LINE_MAX - offset, "%s", class);
919  if (is_set(pcmk_get_ra_caps(class), pcmk_ra_cap_provider)) {
920  const char *prov = crm_element_value(rsc->xml, XML_AGENT_ATTR_PROVIDER);
921  offset += snprintf(buffer + offset, LINE_MAX - offset, "::%s", prov);
922  }
923  offset += snprintf(buffer + offset, LINE_MAX - offset, ":%s", kind);
924  CRM_LOG_ASSERT(offset > 0);
925 
926  if (rsc_table) {
927  rsc_counter = g_hash_table_lookup(rsc_table, buffer);
928  if (rsc_counter == NULL) {
929  rsc_counter = calloc(1, sizeof(int));
930  *rsc_counter = 0;
931  g_hash_table_insert(rsc_table, strdup(buffer), rsc_counter);
932  }
933  (*rsc_counter)++;
934  }
935 
936  if (active_table) {
937  GListPtr gIter2 = rsc->running_on;
938 
939  for (; gIter2 != NULL; gIter2 = gIter2->next) {
940  node_t *node = (node_t *) gIter2->data;
941  GHashTable *node_table = NULL;
942 
943  if (node->details->unclean == FALSE && node->details->online == FALSE) {
944  continue;
945  }
946 
947  node_table = g_hash_table_lookup(active_table, node->details->uname);
948  if (node_table == NULL) {
949  node_table = crm_str_table_new();
950  g_hash_table_insert(active_table, strdup(node->details->uname), node_table);
951  }
952 
953  active_counter = g_hash_table_lookup(node_table, buffer);
954  if (active_counter == NULL) {
955  active_counter = calloc(1, sizeof(int));
956  *active_counter = 0;
957  g_hash_table_insert(node_table, strdup(buffer), active_counter);
958  }
959  (*active_counter)++;
960  }
961  }
962  }
963 }
964 
965 static void
966 destroy_node_table(gpointer data)
967 {
968  GHashTable *node_table = data;
969 
970  if (node_table) {
971  g_hash_table_destroy(node_table);
972  }
973 }
974 
975 void
976 print_rscs_brief(GListPtr rsc_list, const char *pre_text, long options,
977  void *print_data, gboolean print_all)
978 {
979  GHashTable *rsc_table = crm_str_table_new();
980  GHashTable *active_table = g_hash_table_new_full(crm_str_hash, g_str_equal,
981  free, destroy_node_table);
982  GHashTableIter hash_iter;
983  char *type = NULL;
984  int *rsc_counter = NULL;
985 
986  get_rscs_brief(rsc_list, rsc_table, active_table);
987 
988  g_hash_table_iter_init(&hash_iter, rsc_table);
989  while (g_hash_table_iter_next(&hash_iter, (gpointer *)&type, (gpointer *)&rsc_counter)) {
990  GHashTableIter hash_iter2;
991  char *node_name = NULL;
992  GHashTable *node_table = NULL;
993  int active_counter_all = 0;
994 
995  g_hash_table_iter_init(&hash_iter2, active_table);
996  while (g_hash_table_iter_next(&hash_iter2, (gpointer *)&node_name, (gpointer *)&node_table)) {
997  int *active_counter = g_hash_table_lookup(node_table, type);
998 
999  if (active_counter == NULL || *active_counter == 0) {
1000  continue;
1001 
1002  } else {
1003  active_counter_all += *active_counter;
1004  }
1005 
1006  if (options & pe_print_rsconly) {
1007  node_name = NULL;
1008  }
1009 
1010  if (options & pe_print_html) {
1011  status_print("<li>\n");
1012  }
1013 
1014  if (print_all) {
1015  status_print("%s%d/%d\t(%s):\tActive %s\n", pre_text ? pre_text : "",
1016  active_counter ? *active_counter : 0,
1017  rsc_counter ? *rsc_counter : 0, type,
1018  active_counter && (*active_counter > 0) && node_name ? node_name : "");
1019  } else {
1020  status_print("%s%d\t(%s):\tActive %s\n", pre_text ? pre_text : "",
1021  active_counter ? *active_counter : 0, type,
1022  active_counter && (*active_counter > 0) && node_name ? node_name : "");
1023  }
1024 
1025  if (options & pe_print_html) {
1026  status_print("</li>\n");
1027  }
1028  }
1029 
1030  if (print_all && active_counter_all == 0) {
1031  if (options & pe_print_html) {
1032  status_print("<li>\n");
1033  }
1034 
1035  status_print("%s%d/%d\t(%s):\tActive\n", pre_text ? pre_text : "",
1036  active_counter_all,
1037  rsc_counter ? *rsc_counter : 0, type);
1038 
1039  if (options & pe_print_html) {
1040  status_print("</li>\n");
1041  }
1042  }
1043  }
1044 
1045  if (rsc_table) {
1046  g_hash_table_destroy(rsc_table);
1047  rsc_table = NULL;
1048  }
1049  if (active_table) {
1050  g_hash_table_destroy(active_table);
1051  active_table = NULL;
1052  }
1053 }
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:190
GListPtr nodes
Definition: status.h:125
const char * uname
Definition: status.h:173
#define CRMD_ACTION_MIGRATED
Definition: crm.h:165
xmlNode * xml
Definition: status.h:294
#define INFINITY
Definition: crm.h:73
void native_print(resource_t *rsc, const char *pre_text, long options, void *print_data)
Definition: native.c:799
char * native_parameter(resource_t *rsc, node_t *node, gboolean create, const char *name, pe_working_set_t *data_set)
Definition: native.c:315
int priority
Definition: status.h:206
resource_t * native_find_rsc(resource_t *rsc, const char *id, node_t *on_node, int flags)
Definition: native.c:261
const char * id
Definition: status.h:172
#define XML_ATTR_TYPE
Definition: msg_xml.h:105
void common_print(resource_t *rsc, const char *pre_text, const char *name, node_t *node, long options, void *print_data)
Definition: native.c:554
#define XML_BOOLEAN_FALSE
Definition: msg_xml.h:118
#define pe_rsc_orphan
Definition: status.h:219
enum rsc_role_e native_resource_state(const resource_t *rsc, gboolean current)
Definition: native.c:827
#define CRMD_ACTION_NOTIFY
Definition: crm.h:178
void pe__force_anon(const char *standard, pe_resource_t *rsc, const char *rid, pe_working_set_t *data_set)
Definition: clone.c:21
#define pe_rsc_provisional
Definition: status.h:228
GListPtr running_rsc
Definition: status.h:187
enum pe_obj_types variant
Definition: status.h:300
void common_free(resource_t *rsc)
Definition: complex.c:918
gboolean native_unpack(resource_t *rsc, pe_working_set_t *data_set)
Definition: native.c:190
#define status_print(fmt, args...)
Definition: unpack.h:79
#define CRMD_ACTION_PROMOTE
Definition: crm.h:173
void get_rsc_attributes(GHashTable *meta_hash, resource_t *rsc, node_t *node, pe_working_set_t *data_set)
Definition: complex.c:168
void print_node(const char *pre_text, node_t *node, gboolean details)
Definition: utils.c:1357
#define CRM_LOG_ASSERT(expr)
Definition: logging.h:176
char * clone_name
Definition: status.h:293
resource_t * uber_parent(resource_t *rsc)
Definition: complex.c:904
resource_t * remote_rsc
Definition: status.h:190
#define clear_bit(word, bit)
Definition: crm_internal.h:211
enum rsc_role_e role
Definition: status.h:330
GListPtr children
Definition: status.h:337
char * id
Definition: status.h:292
GHashTable * parameters
Definition: status.h:334
#define CRMD_ACTION_START
Definition: crm.h:167
#define pe_rsc_block
Definition: status.h:221
gboolean native_active(resource_t *rsc, gboolean all)
Definition: native.c:360
const char * role2text(enum rsc_role_e role)
Definition: common.c:365
pe_node_t *(* location)(const pe_resource_t *, GList **, int)
Definition: complex.h:40
#define CRMD_ACTION_STOP
Definition: crm.h:170
struct node_shared_s * details
Definition: status.h:213
#define CRMD_ACTION_DEMOTE
Definition: crm.h:175
#define set_bit(word, bit)
Definition: crm_internal.h:210
gboolean unclean
Definition: status.h:180
#define crm_debug(fmt, args...)
Definition: logging.h:279
char * pending_task
Definition: status.h:346
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
Definition: nvpair.c:393
enum rsc_recovery_type recovery_type
Definition: status.h:304
#define XML_BOOLEAN_TRUE
Definition: msg_xml.h:117
#define pe_rsc_failed
Definition: status.h:237
void native_add_running(resource_t *rsc, node_t *node, pe_working_set_t *data_set)
Definition: native.c:82
pe_node_t * pending_node
Definition: status.h:354
resource_object_functions_t * fns
Definition: status.h:301
resource_t * container
Definition: status.h:343
GHashTable * allowed_nodes
Definition: status.h:328
void * variant_opaque
Definition: status.h:299
#define crm_trace(fmt, args...)
Definition: logging.h:280
pe_node_t * pe__find_active_requires(const resource_t *rsc, unsigned int *count)
Definition: complex.c:1080
#define XML_AGENT_ATTR_PROVIDER
Definition: msg_xml.h:258
#define pe_rsc_runnable
Definition: status.h:239
#define XML_ATTR_DESC
Definition: msg_xml.h:101
unsigned long long flags
Definition: status.h:316
uint32_t pcmk_get_ra_caps(const char *standard)
Get capabilities of a resource agent standard.
Definition: agents.c:29
pe_node_t * native_location(const pe_resource_t *rsc, GList **list, int current)
Definition: native.c:849
resource_t * parent
Definition: status.h:298
#define XML_RSC_ATTR_TARGET_ROLE
Definition: msg_xml.h:220
enum rsc_role_e text2role(const char *role)
Definition: common.c:386
uint32_t counter
Definition: internal.h:78
void print_rscs_brief(GListPtr rsc_list, const char *pre_text, long options, void *print_data, gboolean print_all)
Definition: native.c:976
#define XML_RSC_ATTR_UNIQUE
Definition: msg_xml.h:221
gboolean maintenance
Definition: status.h:200
#define pe_rsc_unique
Definition: status.h:225
GHashTable * node_hash_from_list(GListPtr list)
Definition: utils.c:197
GHashTable * meta
Definition: status.h:333
Cluster status and scheduling.
void add_hash_param(GHashTable *hash, const char *name, const char *value)
Definition: common.c:442
resource_t *(* find_rsc)(resource_t *parent, const char *search, node_t *node, int flags)
Definition: complex.h:34
void resource_location(resource_t *rsc, node_t *node, int score, const char *tag, pe_working_set_t *data_set)
Definition: utils.c:1628
enum rsc_role_e next_role
Definition: status.h:331
gboolean online
Definition: status.h:176
#define pe_rsc_failure_ignored
Definition: status.h:247
#define pe_rsc_managed
Definition: status.h:220
#define CRMD_ACTION_MIGRATE
Definition: crm.h:164
#define crm_str_hash
Definition: util.h:75
#define uint32_t
Definition: stdint.in.h:158
#define XML_RSC_ATTR_INTERNAL_RSC
Definition: msg_xml.h:231
#define CRM_ASSERT(expr)
Definition: error.h:20
char data[0]
Definition: internal.h:86
node_t * allocated_to
Definition: status.h:325
rsc_role_e
Definition: common.h:81
node_t * pe_find_node_id(GListPtr node_list, const char *id)
Definition: status.c:428
Definition: status.h:209
gboolean crm_is_true(const char *s)
Definition: strings.c:197
#define pe_rsc_trace(rsc, fmt, args...)
Definition: internal.h:16
#define ID(x)
Definition: msg_xml.h:452
#define pe_err(fmt...)
Definition: internal.h:18
#define safe_str_eq(a, b)
Definition: util.h:74
GList * GListPtr
Definition: crm.h:210
void native_free(resource_t *rsc)
Definition: native.c:820
const char * rsc_printable_id(resource_t *rsc)
Definition: utils.c:2291
uint64_t flags
Definition: remote.c:156
enum crm_ais_msg_types type
Definition: internal.h:79
#define pe_rsc_info(rsc, fmt, args...)
Definition: internal.h:14
int priority
Definition: status.h:307
#define XML_AGENT_ATTR_CLASS
Definition: msg_xml.h:257
#define CRMD_ACTION_STATUS
Definition: crm.h:181
GListPtr running_on
Definition: status.h:326