pacemaker  2.0.4-2deceaa
Scalable High-Availability cluster resource manager
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
native.c
Go to the documentation of this file.
1 /*
2  * Copyright 2004-2020 the Pacemaker project contributors
3  *
4  * The version control history for this file may have further details.
5  *
6  * This source code is licensed under the GNU Lesser General Public License
7  * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
8  */
9 
10 #include <crm_internal.h>
11 
12 #include <crm/pengine/rules.h>
13 #include <crm/pengine/status.h>
14 #include <crm/pengine/complex.h>
15 #include <crm/pengine/internal.h>
16 #include <crm/msg_xml.h>
17 #include <pe_status_private.h>
18 
19 #define VARIANT_NATIVE 1
20 #include "./variant.h"
21 
26 static bool
27 is_multiply_active(pe_resource_t *rsc)
28 {
29  unsigned int count = 0;
30 
31  if (rsc->variant == pe_native) {
32  pe__find_active_requires(rsc, &count);
33  }
34  return count > 1;
35 }
36 
37 static void
38 native_priority_to_node(pe_resource_t * rsc, pe_node_t * node)
39 {
40  int priority = 0;
41 
42  if (rsc->priority == 0) {
43  return;
44  }
45 
46  if (rsc->role == RSC_ROLE_MASTER) {
47  // Promoted instance takes base priority + 1
48  priority = rsc->priority + 1;
49 
50  } else {
51  priority = rsc->priority;
52  }
53 
54  node->details->priority += priority;
55  pe_rsc_trace(rsc, "Node '%s' now has priority %d with %s'%s' (priority: %d%s)",
56  node->details->uname, node->details->priority,
57  rsc->role == RSC_ROLE_MASTER ? "promoted " : "",
58  rsc->id, rsc->priority,
59  rsc->role == RSC_ROLE_MASTER ? " + 1" : "");
60 
61  /* Priority of a resource running on a guest node is added to the cluster
62  * node as well. */
63  if (node->details->remote_rsc
64  && node->details->remote_rsc->container) {
66 
67  for (; gIter != NULL; gIter = gIter->next) {
68  pe_node_t *a_node = gIter->data;
69 
70  a_node->details->priority += priority;
71  pe_rsc_trace(rsc, "Node '%s' now has priority %d with %s'%s' (priority: %d%s) "
72  "from guest node '%s'",
73  a_node->details->uname, a_node->details->priority,
74  rsc->role == RSC_ROLE_MASTER ? "promoted " : "",
75  rsc->id, rsc->priority,
76  rsc->role == RSC_ROLE_MASTER ? " + 1" : "",
77  node->details->uname);
78  }
79  }
80 }
81 
82 void
84 {
85  GListPtr gIter = rsc->running_on;
86 
87  CRM_CHECK(node != NULL, return);
88  for (; gIter != NULL; gIter = gIter->next) {
89  pe_node_t *a_node = (pe_node_t *) gIter->data;
90 
91  CRM_CHECK(a_node != NULL, return);
92  if (safe_str_eq(a_node->details->id, node->details->id)) {
93  return;
94  }
95  }
96 
97  pe_rsc_trace(rsc, "Adding %s to %s %s", rsc->id, node->details->uname,
98  is_set(rsc->flags, pe_rsc_managed)?"":"(unmanaged)");
99 
100  rsc->running_on = g_list_append(rsc->running_on, node);
101  if (rsc->variant == pe_native) {
102  node->details->running_rsc = g_list_append(node->details->running_rsc, rsc);
103 
104  native_priority_to_node(rsc, node);
105  }
106 
107  if (rsc->variant == pe_native && node->details->maintenance) {
109  }
110 
111  if (is_not_set(rsc->flags, pe_rsc_managed)) {
112  pe_resource_t *p = rsc->parent;
113 
114  pe_rsc_info(rsc, "resource %s isn't managed", rsc->id);
115  resource_location(rsc, node, INFINITY, "not_managed_default", data_set);
116 
117  while(p && node->details->online) {
118  /* add without the additional location constraint */
119  p->running_on = g_list_append(p->running_on, node);
120  p = p->parent;
121  }
122  return;
123  }
124 
125  if (is_multiply_active(rsc)) {
126  switch (rsc->recovery_type) {
127  case recovery_stop_only:
128  {
129  GHashTableIter gIter;
130  pe_node_t *local_node = NULL;
131 
132  /* make sure it doesn't come up again */
133  if (rsc->allowed_nodes != NULL) {
134  g_hash_table_destroy(rsc->allowed_nodes);
135  }
136  rsc->allowed_nodes = pe__node_list2table(data_set->nodes);
137  g_hash_table_iter_init(&gIter, rsc->allowed_nodes);
138  while (g_hash_table_iter_next(&gIter, NULL, (void **)&local_node)) {
139  local_node->weight = -INFINITY;
140  }
141  }
142  break;
143  case recovery_stop_start:
144  break;
145  case recovery_block:
147  set_bit(rsc->flags, pe_rsc_block);
148 
149  /* If the resource belongs to a group or bundle configured with
150  * multiple-active=block, block the entire entity.
151  */
152  if (rsc->parent
153  && (rsc->parent->variant == pe_group || rsc->parent->variant == pe_container)
154  && rsc->parent->recovery_type == recovery_block) {
155  GListPtr gIter = rsc->parent->children;
156 
157  for (; gIter != NULL; gIter = gIter->next) {
158  pe_resource_t *child = (pe_resource_t *) gIter->data;
159 
160  clear_bit(child->flags, pe_rsc_managed);
161  set_bit(child->flags, pe_rsc_block);
162  }
163  }
164  break;
165  }
166  crm_debug("%s is active on multiple nodes including %s: %s",
167  rsc->id, node->details->uname,
168  recovery2text(rsc->recovery_type));
169 
170  } else {
171  pe_rsc_trace(rsc, "Resource %s is active on: %s", rsc->id, node->details->uname);
172  }
173 
174  if (rsc->parent != NULL) {
175  native_add_running(rsc->parent, node, data_set);
176  }
177 }
178 
179 static void
180 recursive_clear_unique(pe_resource_t *rsc)
181 {
184 
185  for (GList *child = rsc->children; child != NULL; child = child->next) {
186  recursive_clear_unique((pe_resource_t *) child->data);
187  }
188 }
189 
190 gboolean
192 {
193  pe_resource_t *parent = uber_parent(rsc);
194  native_variant_data_t *native_data = NULL;
195  const char *standard = crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS);
196  uint32_t ra_caps = pcmk_get_ra_caps(standard);
197 
198  pe_rsc_trace(rsc, "Processing resource %s...", rsc->id);
199 
200  native_data = calloc(1, sizeof(native_variant_data_t));
201  rsc->variant_opaque = native_data;
202 
203  // Only some agent standards support unique and promotable clones
204  if (is_not_set(ra_caps, pcmk_ra_cap_unique)
205  && is_set(rsc->flags, pe_rsc_unique) && pe_rsc_is_clone(parent)) {
206 
207  /* @COMPAT We should probably reject this situation as an error (as we
208  * do for promotable below) rather than warn and convert, but that would
209  * be a backward-incompatible change that we should probably do with a
210  * transform at a schema major version bump.
211  */
212  pe__force_anon(standard, parent, rsc->id, data_set);
213 
214  /* Clear globally-unique on the parent and all its descendents unpacked
215  * so far (clearing the parent should make any future children unpacking
216  * correct). We have to clear this resource explicitly because it isn't
217  * hooked into the parent's children yet.
218  */
219  recursive_clear_unique(parent);
220  recursive_clear_unique(rsc);
221  }
222  if (is_not_set(ra_caps, pcmk_ra_cap_promotable)
223  && is_set(parent->flags, pe_rsc_promotable)) {
224 
225  pe_err("Resource %s is of type %s and therefore "
226  "cannot be used as a promotable clone resource",
227  rsc->id, standard);
228  return FALSE;
229  }
230  return TRUE;
231 }
232 
233 static bool
234 rsc_is_on_node(pe_resource_t *rsc, const pe_node_t *node, int flags)
235 {
236  pe_rsc_trace(rsc, "Checking whether %s is on %s",
237  rsc->id, node->details->uname);
238 
239  if (is_set(flags, pe_find_current) && rsc->running_on) {
240 
241  for (GListPtr iter = rsc->running_on; iter; iter = iter->next) {
242  pe_node_t *loc = (pe_node_t *) iter->data;
243 
244  if (loc->details == node->details) {
245  return TRUE;
246  }
247  }
248 
249  } else if (is_set(flags, pe_find_inactive) && (rsc->running_on == NULL)) {
250  return TRUE;
251 
252  } else if (is_not_set(flags, pe_find_current) && rsc->allocated_to
253  && (rsc->allocated_to->details == node->details)) {
254  return TRUE;
255  }
256  return FALSE;
257 }
258 
260 native_find_rsc(pe_resource_t * rsc, const char *id, const pe_node_t *on_node,
261  int flags)
262 {
263  bool match = FALSE;
264  pe_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  pe_resource_t *child = (pe_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(pe_resource_t * rsc, pe_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(pe_resource_t * rsc, gboolean all)
361 {
362  GListPtr gIter = rsc->running_on;
363 
364  for (; gIter != NULL; gIter = gIter->next) {
365  pe_node_t *a_node = (pe_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(pe_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(pe_resource_t * rsc)
425 {
426  const char *pending_task = NULL;
427 
429  pending_task = "Monitoring";
430 
431  /* Pending probes are not printed, even if pending
432  * operations are requested. If someone ever requests that
433  * behavior, uncomment this and the corresponding part of
434  * unpack.c:unpack_rsc_op().
435  */
436  /*
437  } else if (safe_str_eq(rsc->pending_task, "probe")) {
438  pending_task = "Checking";
439  */
440  }
441 
442  return pending_task;
443 }
444 
445 static enum rsc_role_e
446 native_displayable_role(pe_resource_t *rsc)
447 {
448  enum rsc_role_e role = rsc->role;
449 
450  if ((role == RSC_ROLE_STARTED)
451  && is_set(uber_parent(rsc)->flags, pe_rsc_promotable)) {
452 
453  role = RSC_ROLE_SLAVE;
454  }
455  return role;
456 }
457 
458 static const char *
459 native_displayable_state(pe_resource_t *rsc, long options)
460 {
461  const char *rsc_state = NULL;
462 
463  if (options & pe_print_pending) {
464  rsc_state = native_pending_state(rsc);
465  }
466  if (rsc_state == NULL) {
467  rsc_state = role2text(native_displayable_role(rsc));
468  }
469  return rsc_state;
470 }
471 
472 static void
473 native_print_xml(pe_resource_t * rsc, const char *pre_text, long options, void *print_data)
474 {
475  const char *class = crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS);
476  const char *prov = crm_element_value(rsc->xml, XML_AGENT_ATTR_PROVIDER);
477  const char *rsc_state = native_displayable_state(rsc, options);
478  const char *target_role = NULL;
479 
480  /* resource information. */
481  status_print("%s<resource ", pre_text);
482  status_print("id=\"%s\" ", rsc_printable_id(rsc));
483  status_print("resource_agent=\"%s%s%s:%s\" ",
484  class,
485  prov ? "::" : "", prov ? prov : "", crm_element_value(rsc->xml, XML_ATTR_TYPE));
486 
487  status_print("role=\"%s\" ", rsc_state);
488  if (rsc->meta) {
489  target_role = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_TARGET_ROLE);
490  }
491  if (target_role) {
492  status_print("target_role=\"%s\" ", target_role);
493  }
494  status_print("active=\"%s\" ", rsc->fns->active(rsc, TRUE) ? "true" : "false");
495  status_print("orphaned=\"%s\" ", is_set(rsc->flags, pe_rsc_orphan) ? "true" : "false");
496  status_print("blocked=\"%s\" ", is_set(rsc->flags, pe_rsc_block) ? "true" : "false");
497  status_print("managed=\"%s\" ", is_set(rsc->flags, pe_rsc_managed) ? "true" : "false");
498  status_print("failed=\"%s\" ", is_set(rsc->flags, pe_rsc_failed) ? "true" : "false");
499  status_print("failure_ignored=\"%s\" ",
500  is_set(rsc->flags, pe_rsc_failure_ignored) ? "true" : "false");
501  status_print("nodes_running_on=\"%d\" ", g_list_length(rsc->running_on));
502 
503  if (options & pe_print_pending) {
504  const char *pending_task = native_pending_task(rsc);
505 
506  if (pending_task) {
507  status_print("pending=\"%s\" ", pending_task);
508  }
509  }
510 
511  if (options & pe_print_dev) {
512  status_print("provisional=\"%s\" ",
513  is_set(rsc->flags, pe_rsc_provisional) ? "true" : "false");
514  status_print("runnable=\"%s\" ", is_set(rsc->flags, pe_rsc_runnable) ? "true" : "false");
515  status_print("priority=\"%f\" ", (double)rsc->priority);
516  status_print("variant=\"%s\" ", crm_element_name(rsc->xml));
517  }
518 
519  /* print out the nodes this resource is running on */
520  if (options & pe_print_rsconly) {
521  status_print("/>\n");
522  /* do nothing */
523  } else if (rsc->running_on != NULL) {
524  GListPtr gIter = rsc->running_on;
525 
526  status_print(">\n");
527  for (; gIter != NULL; gIter = gIter->next) {
528  pe_node_t *node = (pe_node_t *) gIter->data;
529 
530  status_print("%s <node name=\"%s\" id=\"%s\" cached=\"%s\"/>\n", pre_text,
531  node->details->uname, node->details->id,
532  node->details->online ? "false" : "true");
533  }
534  status_print("%s</resource>\n", pre_text);
535  } else {
536  status_print("/>\n");
537  }
538 }
539 
540 // Append a flag to resource description string's flags list
541 static bool
542 add_output_flag(GString *s, const char *flag_desc, bool have_flags)
543 {
544  g_string_append(s, (have_flags? ", " : " ("));
545  g_string_append(s, flag_desc);
546  return true;
547 }
548 
549 // Append a node name to resource description string's node list
550 static bool
551 add_output_node(GString *s, const char *node, bool have_nodes)
552 {
553  g_string_append(s, (have_nodes? " " : " [ "));
554  g_string_append(s, node);
555  return true;
556 }
557 
572 static gchar *
573 native_output_string(pe_resource_t *rsc, const char *name, pe_node_t *node,
574  long options, const char *target_role, bool show_nodes)
575 {
576  const char *class = crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS);
577  const char *provider = NULL;
578  const char *kind = crm_element_value(rsc->xml, XML_ATTR_TYPE);
579  char *retval = NULL;
580  GString *outstr = NULL;
581  bool have_flags = false;
582 
583  CRM_CHECK(name != NULL, name = "unknown");
584  CRM_CHECK(kind != NULL, kind = "unknown");
585  CRM_CHECK(class != NULL, class = "unknown");
586 
587  if (is_set(pcmk_get_ra_caps(class), pcmk_ra_cap_provider)) {
589  }
590 
591  if ((node == NULL) && (rsc->lock_node != NULL)) {
592  node = rsc->lock_node;
593  }
594  if (is_set(options, pe_print_rsconly)
595  || pcmk__list_of_multiple(rsc->running_on)) {
596  node = NULL;
597  }
598 
599  // We need a string of at least this size
600  outstr = g_string_sized_new(strlen(name) + strlen(class) + strlen(kind)
601  + (provider? (strlen(provider) + 2) : 0)
602  + (node? strlen(node->details->uname) + 1 : 0)
603  + 11);
604 
605  // Resource name and agent
606  g_string_printf(outstr, "%s\t(%s%s%s:%s):\t", name, class,
607  /* @COMPAT This should be a single ':' (see CLBZ#5395) but
608  * to avoid breaking anything relying on it, we're keeping
609  * it like this until the next minor version bump.
610  */
611  (provider? "::" : ""), (provider? provider : ""), kind);
612 
613  // State on node
614  if (is_set(rsc->flags, pe_rsc_orphan)) {
615  g_string_append(outstr, " ORPHANED");
616  }
617  if (is_set(rsc->flags, pe_rsc_failed)) {
618  enum rsc_role_e role = native_displayable_role(rsc);
619 
620  if (role > RSC_ROLE_SLAVE) {
621  g_string_append_printf(outstr, " FAILED %s", role2text(role));
622  } else {
623  g_string_append(outstr, " FAILED");
624  }
625  } else {
626  g_string_append_printf(outstr, " %s", native_displayable_state(rsc, options));
627  }
628  if (node) {
629  g_string_append_printf(outstr, " %s", node->details->uname);
630  }
631 
632  // Flags, as: (<flag> [...])
633  if (node && !(node->details->online) && node->details->unclean) {
634  have_flags = add_output_flag(outstr, "UNCLEAN", have_flags);
635  }
636  if (node && (node == rsc->lock_node)) {
637  have_flags = add_output_flag(outstr, "LOCKED", have_flags);
638  }
639  if (is_set(options, pe_print_pending)) {
640  const char *pending_task = native_pending_task(rsc);
641 
642  if (pending_task) {
643  have_flags = add_output_flag(outstr, pending_task, have_flags);
644  }
645  }
646  if (target_role) {
647  enum rsc_role_e target_role_e = text2role(target_role);
648 
649  /* Only show target role if it limits our abilities (i.e. ignore
650  * Started, as it is the default anyways, and doesn't prevent the
651  * resource from becoming Master).
652  */
653  if (target_role_e == RSC_ROLE_STOPPED) {
654  have_flags = add_output_flag(outstr, "disabled", have_flags);
655 
656  } else if (is_set(uber_parent(rsc)->flags, pe_rsc_promotable)
657  && target_role_e == RSC_ROLE_SLAVE) {
658  have_flags = add_output_flag(outstr, "target-role:", have_flags);
659  g_string_append(outstr, target_role);
660  }
661  }
662  if (is_set(rsc->flags, pe_rsc_block)) {
663  have_flags = add_output_flag(outstr, "blocked", have_flags);
664  } else if (is_not_set(rsc->flags, pe_rsc_managed)) {
665  have_flags = add_output_flag(outstr, "unmanaged", have_flags);
666  }
667  if (is_set(rsc->flags, pe_rsc_failure_ignored)) {
668  have_flags = add_output_flag(outstr, "failure ignored", have_flags);
669  }
670  if (is_set(options, pe_print_dev)) {
671  if (is_set(options, pe_rsc_provisional)) {
672  have_flags = add_output_flag(outstr, "provisional", have_flags);
673  }
674  if (is_not_set(options, pe_rsc_runnable)) {
675  have_flags = add_output_flag(outstr, "non-startable", have_flags);
676  }
677  have_flags = add_output_flag(outstr, "variant:", have_flags);
678  g_string_append_printf(outstr, "%s priority:%f",
679  crm_element_name(rsc->xml),
680  (double) (rsc->priority));
681  }
682  if (have_flags) {
683  g_string_append(outstr, ")");
684  }
685 
686  // User-supplied description
687  if (is_set(options, pe_print_rsconly)
688  || pcmk__list_of_multiple(rsc->running_on)) {
689  const char *desc = crm_element_value(rsc->xml, XML_ATTR_DESC);
690 
691  if (desc) {
692  g_string_append_printf(outstr, " %s", desc);
693  }
694  }
695 
696  if (show_nodes && is_not_set(options, pe_print_rsconly)
697  && pcmk__list_of_multiple(rsc->running_on)) {
698  bool have_nodes = false;
699 
700  for (GList *iter = rsc->running_on; iter != NULL; iter = iter->next) {
701  pe_node_t *n = (pe_node_t *) iter->data;
702 
703  have_nodes = add_output_node(outstr, n->details->uname, have_nodes);
704  }
705  if (have_nodes) {
706  g_string_append(outstr, " ]");
707  }
708  }
709 
710  retval = outstr->str;
711  g_string_free(outstr, FALSE);
712  return retval;
713 }
714 
715 int
717  const char *name, pe_node_t *node, long options)
718 {
719  const char *kind = crm_element_value(rsc->xml, XML_ATTR_TYPE);
720  const char *target_role = NULL;
721 
722  xmlNodePtr list_node = NULL;
723  const char *cl = NULL;
724 
725  CRM_ASSERT(rsc->variant == pe_native);
726  CRM_ASSERT(kind != NULL);
727 
728  if (rsc->meta) {
729  const char *is_internal = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_INTERNAL_RSC);
730  if (crm_is_true(is_internal) && is_not_set(options, pe_print_implicit)) {
731  crm_trace("skipping print of internal resource %s", rsc->id);
732  return pcmk_rc_no_output;
733  }
734  target_role = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_TARGET_ROLE);
735  }
736 
737  if (is_not_set(rsc->flags, pe_rsc_managed)) {
738  cl = "rsc-managed";
739 
740  } else if (is_set(rsc->flags, pe_rsc_failed)) {
741  cl = "rsc-failed";
742 
743  } else if (rsc->variant == pe_native && (rsc->running_on == NULL)) {
744  cl = "rsc-failed";
745 
746  } else if (pcmk__list_of_multiple(rsc->running_on)) {
747  cl = "rsc-multiple";
748 
749  } else if (is_set(rsc->flags, pe_rsc_failure_ignored)) {
750  cl = "rsc-failure-ignored";
751 
752  } else {
753  cl = "rsc-ok";
754  }
755 
756  {
757  gchar *s = native_output_string(rsc, name, node, options, target_role,
758  true);
759 
760  list_node = pcmk__output_create_html_node(out, "li", NULL, NULL, NULL);
761  pcmk_create_html_node(list_node, "span", NULL, cl, s);
762  g_free(s);
763  }
764 
765  if (is_set(options, pe_print_details)) {
766  GHashTableIter iter;
767  gpointer key, value;
768 
769  out->begin_list(out, NULL, NULL, "Options");
770  g_hash_table_iter_init(&iter, rsc->parameters);
771  while (g_hash_table_iter_next(&iter, &key, &value)) {
772  out->list_item(out, NULL, "Option: %s = %s", (char *) key, (char *) value);
773  }
774  out->end_list(out);
775  }
776 
777  if (is_set(options, pe_print_dev)) {
778  GHashTableIter iter;
779  pe_node_t *n = NULL;
780 
781  out->begin_list(out, NULL, NULL, "Allowed Nodes");
782  g_hash_table_iter_init(&iter, rsc->allowed_nodes);
783  while (g_hash_table_iter_next(&iter, NULL, (void **)&n)) {
784  out->list_item(out, NULL, "%s %d", n->details->uname, n->weight);
785  }
786  out->end_list(out);
787  }
788 
789  if (is_set(options, pe_print_max_details)) {
790  GHashTableIter iter;
791  pe_node_t *n = NULL;
792 
793  out->begin_list(out, NULL, NULL, "=== Allowed Nodes");
794  g_hash_table_iter_init(&iter, rsc->allowed_nodes);
795  while (g_hash_table_iter_next(&iter, NULL, (void **)&n)) {
796  pe__output_node(n, FALSE, out);
797  }
798  out->end_list(out);
799  }
800 
801  return pcmk_rc_ok;
802 }
803 
804 int
806  const char *name, pe_node_t *node, long options)
807 {
808  const char *target_role = NULL;
809 
810  CRM_ASSERT(rsc->variant == pe_native);
811 
812  if (rsc->meta) {
813  const char *is_internal = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_INTERNAL_RSC);
814  if (crm_is_true(is_internal) && is_not_set(options, pe_print_implicit)) {
815  crm_trace("skipping print of internal resource %s", rsc->id);
816  return pcmk_rc_no_output;
817  }
818  target_role = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_TARGET_ROLE);
819  }
820 
821  {
822  gchar *s = native_output_string(rsc, name, node, options, target_role,
823  true);
824 
825  out->list_item(out, NULL, "%s", s);
826  g_free(s);
827  }
828 
829  if (is_set(options, pe_print_details)) {
830  GHashTableIter iter;
831  gpointer key, value;
832 
833  out->begin_list(out, NULL, NULL, "Options");
834  g_hash_table_iter_init(&iter, rsc->parameters);
835  while (g_hash_table_iter_next(&iter, &key, &value)) {
836  out->list_item(out, NULL, "Option: %s = %s", (char *) key, (char *) value);
837  }
838  out->end_list(out);
839  }
840 
841  if (is_set(options, pe_print_dev)) {
842  GHashTableIter iter;
843  pe_node_t *n = NULL;
844 
845  out->begin_list(out, NULL, NULL, "Allowed Nodes");
846  g_hash_table_iter_init(&iter, rsc->allowed_nodes);
847  while (g_hash_table_iter_next(&iter, NULL, (void **)&n)) {
848  out->list_item(out, NULL, "%s %d", n->details->uname, n->weight);
849  }
850  out->end_list(out);
851  }
852 
853  if (is_set(options, pe_print_max_details)) {
854  GHashTableIter iter;
855  pe_node_t *n = NULL;
856 
857  out->begin_list(out, NULL, NULL, "=== Allowed Nodes");
858  g_hash_table_iter_init(&iter, rsc->allowed_nodes);
859  while (g_hash_table_iter_next(&iter, NULL, (void **)&n)) {
860  pe__output_node(n, FALSE, out);
861  }
862  out->end_list(out);
863  }
864 
865  return pcmk_rc_ok;
866 }
867 
868 void
869 common_print(pe_resource_t * rsc, const char *pre_text, const char *name, pe_node_t *node, long options, void *print_data)
870 {
871  const char *target_role = NULL;
872 
873  CRM_ASSERT(rsc->variant == pe_native);
874 
875  if (rsc->meta) {
876  const char *is_internal = g_hash_table_lookup(rsc->meta,
878 
879  if (crm_is_true(is_internal) && is_not_set(options, pe_print_implicit)) {
880  crm_trace("skipping print of internal resource %s", rsc->id);
881  return;
882  }
883  target_role = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_TARGET_ROLE);
884  }
885 
886  if (options & pe_print_xml) {
887  native_print_xml(rsc, pre_text, options, print_data);
888  return;
889  }
890 
891  if ((pre_text == NULL) && (options & pe_print_printf)) {
892  pre_text = " ";
893  }
894 
895  if (options & pe_print_html) {
896  if (is_not_set(rsc->flags, pe_rsc_managed)) {
897  status_print("<font color=\"yellow\">");
898 
899  } else if (is_set(rsc->flags, pe_rsc_failed)) {
900  status_print("<font color=\"red\">");
901 
902  } else if (rsc->running_on == NULL) {
903  status_print("<font color=\"red\">");
904 
905  } else if (pcmk__list_of_multiple(rsc->running_on)) {
906  status_print("<font color=\"orange\">");
907 
908  } else if (is_set(rsc->flags, pe_rsc_failure_ignored)) {
909  status_print("<font color=\"yellow\">");
910 
911  } else {
912  status_print("<font color=\"green\">");
913  }
914  }
915 
916  {
917  gchar *resource_s = native_output_string(rsc, name, node, options,
918  target_role, false);
919  status_print("%s%s", (pre_text? pre_text : ""), resource_s);
920  g_free(resource_s);
921  }
922 
923 #if CURSES_ENABLED
924  if (is_set(options, pe_print_ncurses)
925  && is_not_set(options, pe_print_rsconly)
926  && !pcmk__list_of_multiple(rsc->running_on)) {
927  /* coverity[negative_returns] False positive */
928  move(-1, 0);
929  }
930 #endif
931 
932  if (is_set(options, pe_print_html)) {
933  status_print(" </font> ");
934  }
935 
936  if (is_not_set(options, pe_print_rsconly)
937  && pcmk__list_of_multiple(rsc->running_on)) {
938 
939  GListPtr gIter = rsc->running_on;
940  int counter = 0;
941 
942  if (options & pe_print_html) {
943  status_print("<ul>\n");
944  } else if ((options & pe_print_printf)
945  || (options & pe_print_ncurses)) {
946  status_print("[");
947  }
948 
949  for (; gIter != NULL; gIter = gIter->next) {
950  pe_node_t *n = (pe_node_t *) gIter->data;
951 
952  counter++;
953 
954  if (options & pe_print_html) {
955  status_print("<li>\n%s", n->details->uname);
956 
957  } else if ((options & pe_print_printf)
958  || (options & pe_print_ncurses)) {
959  status_print(" %s", n->details->uname);
960 
961  } else if ((options & pe_print_log)) {
962  status_print("\t%d : %s", counter, n->details->uname);
963 
964  } else {
965  status_print("%s", n->details->uname);
966  }
967  if (options & pe_print_html) {
968  status_print("</li>\n");
969 
970  }
971  }
972 
973  if (options & pe_print_html) {
974  status_print("</ul>\n");
975  } else if ((options & pe_print_printf)
976  || (options & pe_print_ncurses)) {
977  status_print(" ]");
978  }
979  }
980 
981  if (options & pe_print_html) {
982  status_print("<br/>\n");
983  } else if (options & pe_print_suppres_nl) {
984  /* nothing */
985  } else if ((options & pe_print_printf) || (options & pe_print_ncurses)) {
986  status_print("\n");
987  }
988 
989  if (options & pe_print_details) {
990  struct print_data_s pdata;
991 
992  pdata.options = options;
993  pdata.print_data = print_data;
994  g_hash_table_foreach(rsc->parameters, native_print_attr, &pdata);
995  }
996 
997  if (options & pe_print_dev) {
998  GHashTableIter iter;
999  pe_node_t *n = NULL;
1000 
1001  status_print("%s\tAllowed Nodes", pre_text);
1002  g_hash_table_iter_init(&iter, rsc->allowed_nodes);
1003  while (g_hash_table_iter_next(&iter, NULL, (void **)&n)) {
1004  status_print("%s\t * %s %d", pre_text, n->details->uname, n->weight);
1005  }
1006  }
1007 
1008  if (options & pe_print_max_details) {
1009  GHashTableIter iter;
1010  pe_node_t *n = NULL;
1011 
1012  status_print("%s\t=== Allowed Nodes\n", pre_text);
1013  g_hash_table_iter_init(&iter, rsc->allowed_nodes);
1014  while (g_hash_table_iter_next(&iter, NULL, (void **)&n)) {
1015  print_node("\t", n, FALSE);
1016  }
1017  }
1018 }
1019 
1020 void
1021 native_print(pe_resource_t * rsc, const char *pre_text, long options, void *print_data)
1022 {
1023  pe_node_t *node = NULL;
1024 
1025  CRM_ASSERT(rsc->variant == pe_native);
1026  if (options & pe_print_xml) {
1027  native_print_xml(rsc, pre_text, options, print_data);
1028  return;
1029  }
1030 
1031  node = pe__current_node(rsc);
1032 
1033  if (node == NULL) {
1034  // This is set only if a non-probe action is pending on this node
1035  node = rsc->pending_node;
1036  }
1037 
1038  common_print(rsc, pre_text, rsc_printable_id(rsc), node, options, print_data);
1039 }
1040 
1041 PCMK__OUTPUT_ARGS("primitive", "unsigned int", "struct pe_resource_t *", "GListPtr")
1042 int
1044 {
1045  unsigned int options = va_arg(args, unsigned int);
1046  pe_resource_t *rsc = va_arg(args, pe_resource_t *);
1047  GListPtr only_show G_GNUC_UNUSED = va_arg(args, GListPtr);
1048 
1049  const char *class = crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS);
1050  const char *prov = crm_element_value(rsc->xml, XML_AGENT_ATTR_PROVIDER);
1051  const char *rsc_state = native_displayable_state(rsc, options);
1052 
1053  long is_print_pending = options & pe_print_pending;
1054  long is_print_dev = options & pe_print_dev;
1055 
1056  char ra_name[LINE_MAX];
1057  char *nodes_running_on = NULL;
1058  char *priority = NULL;
1059  int rc = pcmk_rc_no_output;
1060 
1061  CRM_ASSERT(rsc->variant == pe_native);
1062 
1063  /* resource information. */
1064  sprintf(ra_name, "%s%s%s:%s", class, prov ? "::" : "", prov ? prov : ""
1065  , crm_element_value(rsc->xml, XML_ATTR_TYPE));
1066 
1067  nodes_running_on = crm_itoa(g_list_length(rsc->running_on));
1068  priority = crm_ftoa(rsc->priority);
1069 
1070  rc = pe__name_and_nvpairs_xml(out, true, "resource", 16
1071  , "id", rsc_printable_id(rsc)
1072  , "resource_agent", ra_name
1073  , "role", rsc_state
1074  , "target_role", (rsc->meta ? g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_TARGET_ROLE) : NULL)
1075  , "active", BOOL2STR(rsc->fns->active(rsc, TRUE))
1076  , "orphaned", BOOL2STR(is_set(rsc->flags, pe_rsc_orphan))
1077  , "blocked", BOOL2STR(is_set(rsc->flags, pe_rsc_block))
1078  , "managed", BOOL2STR(is_set(rsc->flags, pe_rsc_managed))
1079  , "failed", BOOL2STR(is_set(rsc->flags, pe_rsc_failed))
1080  , "failure_ignored", BOOL2STR(is_set(rsc->flags, pe_rsc_failure_ignored))
1081  , "nodes_running_on", nodes_running_on
1082  , "pending", (is_print_pending ? native_pending_task(rsc) : NULL)
1083  , "provisional", (is_print_dev ? BOOL2STR(is_set(rsc->flags, pe_rsc_provisional)) : NULL)
1084  , "runnable", (is_print_dev ? BOOL2STR(is_set(rsc->flags, pe_rsc_runnable)) : NULL)
1085  , "priority", (is_print_dev ? priority : NULL)
1086  , "variant", (is_print_dev ? crm_element_name(rsc->xml) : NULL));
1087  free(priority);
1088  free(nodes_running_on);
1089 
1090  CRM_ASSERT(rc == pcmk_rc_ok);
1091 
1092  if (rsc->running_on != NULL) {
1093  GListPtr gIter = rsc->running_on;
1094 
1095  for (; gIter != NULL; gIter = gIter->next) {
1096  pe_node_t *node = (pe_node_t *) gIter->data;
1097 
1098  rc = pe__name_and_nvpairs_xml(out, false, "node", 3
1099  , "name", node->details->uname
1100  , "id", node->details->id
1101  , "cached", BOOL2STR(node->details->online));
1102  CRM_ASSERT(rc == pcmk_rc_ok);
1103  }
1104  }
1105 
1107  return rc;
1108 }
1109 
1110 PCMK__OUTPUT_ARGS("primitive", "unsigned int", "struct pe_resource_t *", "GListPtr")
1111 int
1113 {
1114  unsigned int options = va_arg(args, unsigned int);
1115  pe_resource_t *rsc = va_arg(args, pe_resource_t *);
1116  GListPtr only_show G_GNUC_UNUSED = va_arg(args, GListPtr);
1117 
1118  pe_node_t *node = pe__current_node(rsc);
1119 
1120  CRM_ASSERT(rsc->variant == pe_native);
1121 
1122  if (node == NULL) {
1123  // This is set only if a non-probe action is pending on this node
1124  node = rsc->pending_node;
1125  }
1126  return pe__common_output_html(out, rsc, rsc_printable_id(rsc), node, options);
1127 }
1128 
1129 PCMK__OUTPUT_ARGS("primitive", "unsigned int", "struct pe_resource_t *", "GListPtr")
1130 int
1132 {
1133  unsigned int options = va_arg(args, unsigned int);
1134  pe_resource_t *rsc = va_arg(args, pe_resource_t *);
1135  GListPtr only_show G_GNUC_UNUSED = va_arg(args, GListPtr);
1136 
1137  pe_node_t *node = pe__current_node(rsc);
1138 
1139  CRM_ASSERT(rsc->variant == pe_native);
1140 
1141  if (node == NULL) {
1142  // This is set only if a non-probe action is pending on this node
1143  node = rsc->pending_node;
1144  }
1145  return pe__common_output_text(out, rsc, rsc_printable_id(rsc), node, options);
1146 }
1147 
1148 void
1150 {
1151  pe_rsc_trace(rsc, "Freeing resource action list (not the data)");
1152  common_free(rsc);
1153 }
1154 
1155 enum rsc_role_e
1156 native_resource_state(const pe_resource_t * rsc, gboolean current)
1157 {
1158  enum rsc_role_e role = rsc->next_role;
1159 
1160  if (current) {
1161  role = rsc->role;
1162  }
1163  pe_rsc_trace(rsc, "%s state: %s", rsc->id, role2text(role));
1164  return role;
1165 }
1166 
1177 pe_node_t *
1178 native_location(const pe_resource_t *rsc, GList **list, int current)
1179 {
1180  pe_node_t *one = NULL;
1181  GListPtr result = NULL;
1182 
1183  if (rsc->children) {
1184  GListPtr gIter = rsc->children;
1185 
1186  for (; gIter != NULL; gIter = gIter->next) {
1187  pe_resource_t *child = (pe_resource_t *) gIter->data;
1188 
1189  child->fns->location(child, &result, current);
1190  }
1191 
1192  } else if (current) {
1193 
1194  if (rsc->running_on) {
1195  result = g_list_copy(rsc->running_on);
1196  }
1197  if ((current == 2) && rsc->pending_node
1198  && !pe_find_node_id(result, rsc->pending_node->details->id)) {
1199  result = g_list_append(result, rsc->pending_node);
1200  }
1201 
1202  } else if (current == FALSE && rsc->allocated_to) {
1203  result = g_list_append(NULL, rsc->allocated_to);
1204  }
1205 
1206  if (result && (result->next == NULL)) {
1207  one = result->data;
1208  }
1209 
1210  if (list) {
1211  GListPtr gIter = result;
1212 
1213  for (; gIter != NULL; gIter = gIter->next) {
1214  pe_node_t *node = (pe_node_t *) gIter->data;
1215 
1216  if (*list == NULL || pe_find_node_id(*list, node->details->id) == NULL) {
1217  *list = g_list_append(*list, node);
1218  }
1219  }
1220  }
1221 
1222  g_list_free(result);
1223  return one;
1224 }
1225 
1226 static void
1227 get_rscs_brief(GListPtr rsc_list, GHashTable * rsc_table, GHashTable * active_table)
1228 {
1229  GListPtr gIter = rsc_list;
1230 
1231  for (; gIter != NULL; gIter = gIter->next) {
1232  pe_resource_t *rsc = (pe_resource_t *) gIter->data;
1233 
1234  const char *class = crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS);
1235  const char *kind = crm_element_value(rsc->xml, XML_ATTR_TYPE);
1236 
1237  int offset = 0;
1238  char buffer[LINE_MAX];
1239 
1240  int *rsc_counter = NULL;
1241  int *active_counter = NULL;
1242 
1243  if (rsc->variant != pe_native) {
1244  continue;
1245  }
1246 
1247  offset += snprintf(buffer + offset, LINE_MAX - offset, "%s", class);
1248  if (is_set(pcmk_get_ra_caps(class), pcmk_ra_cap_provider)) {
1249  const char *prov = crm_element_value(rsc->xml, XML_AGENT_ATTR_PROVIDER);
1250  offset += snprintf(buffer + offset, LINE_MAX - offset, "::%s", prov);
1251  }
1252  offset += snprintf(buffer + offset, LINE_MAX - offset, ":%s", kind);
1253  CRM_LOG_ASSERT(offset > 0);
1254 
1255  if (rsc_table) {
1256  rsc_counter = g_hash_table_lookup(rsc_table, buffer);
1257  if (rsc_counter == NULL) {
1258  rsc_counter = calloc(1, sizeof(int));
1259  *rsc_counter = 0;
1260  g_hash_table_insert(rsc_table, strdup(buffer), rsc_counter);
1261  }
1262  (*rsc_counter)++;
1263  }
1264 
1265  if (active_table) {
1266  GListPtr gIter2 = rsc->running_on;
1267 
1268  for (; gIter2 != NULL; gIter2 = gIter2->next) {
1269  pe_node_t *node = (pe_node_t *) gIter2->data;
1270  GHashTable *node_table = NULL;
1271 
1272  if (node->details->unclean == FALSE && node->details->online == FALSE) {
1273  continue;
1274  }
1275 
1276  node_table = g_hash_table_lookup(active_table, node->details->uname);
1277  if (node_table == NULL) {
1278  node_table = crm_str_table_new();
1279  g_hash_table_insert(active_table, strdup(node->details->uname), node_table);
1280  }
1281 
1282  active_counter = g_hash_table_lookup(node_table, buffer);
1283  if (active_counter == NULL) {
1284  active_counter = calloc(1, sizeof(int));
1285  *active_counter = 0;
1286  g_hash_table_insert(node_table, strdup(buffer), active_counter);
1287  }
1288  (*active_counter)++;
1289  }
1290  }
1291  }
1292 }
1293 
1294 static void
1295 destroy_node_table(gpointer data)
1296 {
1297  GHashTable *node_table = data;
1298 
1299  if (node_table) {
1300  g_hash_table_destroy(node_table);
1301  }
1302 }
1303 
1304 void
1305 print_rscs_brief(GListPtr rsc_list, const char *pre_text, long options,
1306  void *print_data, gboolean print_all)
1307 {
1308  GHashTable *rsc_table = crm_str_table_new();
1309  GHashTable *active_table = g_hash_table_new_full(crm_str_hash, g_str_equal,
1310  free, destroy_node_table);
1311  GHashTableIter hash_iter;
1312  char *type = NULL;
1313  int *rsc_counter = NULL;
1314 
1315  get_rscs_brief(rsc_list, rsc_table, active_table);
1316 
1317  g_hash_table_iter_init(&hash_iter, rsc_table);
1318  while (g_hash_table_iter_next(&hash_iter, (gpointer *)&type, (gpointer *)&rsc_counter)) {
1319  GHashTableIter hash_iter2;
1320  char *node_name = NULL;
1321  GHashTable *node_table = NULL;
1322  int active_counter_all = 0;
1323 
1324  g_hash_table_iter_init(&hash_iter2, active_table);
1325  while (g_hash_table_iter_next(&hash_iter2, (gpointer *)&node_name, (gpointer *)&node_table)) {
1326  int *active_counter = g_hash_table_lookup(node_table, type);
1327 
1328  if (active_counter == NULL || *active_counter == 0) {
1329  continue;
1330 
1331  } else {
1332  active_counter_all += *active_counter;
1333  }
1334 
1335  if (options & pe_print_rsconly) {
1336  node_name = NULL;
1337  }
1338 
1339  if (options & pe_print_html) {
1340  status_print("<li>\n");
1341  }
1342 
1343  if (print_all) {
1344  status_print("%s%d/%d\t(%s):\tActive %s\n", pre_text ? pre_text : "",
1345  active_counter ? *active_counter : 0,
1346  rsc_counter ? *rsc_counter : 0, type,
1347  active_counter && (*active_counter > 0) && node_name ? node_name : "");
1348  } else {
1349  status_print("%s%d\t(%s):\tActive %s\n", pre_text ? pre_text : "",
1350  active_counter ? *active_counter : 0, type,
1351  active_counter && (*active_counter > 0) && node_name ? node_name : "");
1352  }
1353 
1354  if (options & pe_print_html) {
1355  status_print("</li>\n");
1356  }
1357  }
1358 
1359  if (print_all && active_counter_all == 0) {
1360  if (options & pe_print_html) {
1361  status_print("<li>\n");
1362  }
1363 
1364  status_print("%s%d/%d\t(%s):\tActive\n", pre_text ? pre_text : "",
1365  active_counter_all,
1366  rsc_counter ? *rsc_counter : 0, type);
1367 
1368  if (options & pe_print_html) {
1369  status_print("</li>\n");
1370  }
1371  }
1372  }
1373 
1374  if (rsc_table) {
1375  g_hash_table_destroy(rsc_table);
1376  rsc_table = NULL;
1377  }
1378  if (active_table) {
1379  g_hash_table_destroy(active_table);
1380  active_table = NULL;
1381  }
1382 }
1383 
1384 int
1385 pe__rscs_brief_output(pcmk__output_t *out, GListPtr rsc_list, long options, gboolean print_all)
1386 {
1387  GHashTable *rsc_table = crm_str_table_new();
1388  GHashTable *active_table = g_hash_table_new_full(crm_str_hash, g_str_equal,
1389  free, destroy_node_table);
1390  GHashTableIter hash_iter;
1391  char *type = NULL;
1392  int *rsc_counter = NULL;
1393  int rc = pcmk_rc_no_output;
1394 
1395  get_rscs_brief(rsc_list, rsc_table, active_table);
1396 
1397  g_hash_table_iter_init(&hash_iter, rsc_table);
1398  while (g_hash_table_iter_next(&hash_iter, (gpointer *)&type, (gpointer *)&rsc_counter)) {
1399  GHashTableIter hash_iter2;
1400  char *node_name = NULL;
1401  GHashTable *node_table = NULL;
1402  int active_counter_all = 0;
1403 
1404  g_hash_table_iter_init(&hash_iter2, active_table);
1405  while (g_hash_table_iter_next(&hash_iter2, (gpointer *)&node_name, (gpointer *)&node_table)) {
1406  int *active_counter = g_hash_table_lookup(node_table, type);
1407 
1408  if (active_counter == NULL || *active_counter == 0) {
1409  continue;
1410 
1411  } else {
1412  active_counter_all += *active_counter;
1413  }
1414 
1415  if (options & pe_print_rsconly) {
1416  node_name = NULL;
1417  }
1418 
1419  if (print_all) {
1420  out->list_item(out, NULL, " %d/%d\t(%s):\tActive %s",
1421  *active_counter,
1422  rsc_counter ? *rsc_counter : 0, type,
1423  (*active_counter > 0) && node_name ? node_name : "");
1424  } else {
1425  out->list_item(out, NULL, " %d\t(%s):\tActive %s",
1426  *active_counter, type,
1427  (*active_counter > 0) && node_name ? node_name : "");
1428  }
1429 
1430  rc = pcmk_rc_ok;
1431  }
1432 
1433  if (print_all && active_counter_all == 0) {
1434  out->list_item(out, NULL, " %d/%d\t(%s):\tActive",
1435  active_counter_all,
1436  rsc_counter ? *rsc_counter : 0, type);
1437  rc = pcmk_rc_ok;
1438  }
1439  }
1440 
1441  if (rsc_table) {
1442  g_hash_table_destroy(rsc_table);
1443  rsc_table = NULL;
1444  }
1445  if (active_table) {
1446  g_hash_table_destroy(active_table);
1447  active_table = NULL;
1448  }
1449 
1450  return rc;
1451 }
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:233
GListPtr nodes
Definition: pe_types.h:146
GHashTable * pe__node_list2table(GList *list)
Definition: utils.c:201
int pe__common_output_html(pcmk__output_t *out, pe_resource_t *rsc, const char *name, pe_node_t *node, long options)
Definition: native.c:716
#define CRMD_ACTION_MIGRATED
Definition: crm.h:169
#define INFINITY
Definition: crm.h:95
pe_resource_t * container
Definition: pe_types.h:364
void pcmk__output_xml_pop_parent(pcmk__output_t *out)
Definition: output_xml.c:397
#define XML_ATTR_TYPE
Definition: msg_xml.h:99
#define pe_rsc_runnable
Definition: pe_types.h:253
enum rsc_role_e role
Definition: pe_types.h:354
#define XML_BOOLEAN_FALSE
Definition: msg_xml.h:108
xmlNode * xml
Definition: pe_types.h:307
enum rsc_role_e next_role
Definition: pe_types.h:355
xmlNode * pcmk_create_html_node(xmlNode *parent, const char *element_name, const char *id, const char *class_name, const char *text)
Definition: xml.c:2013
pe_resource_t * remote_rsc
Definition: pe_types.h:217
pe_node_t * native_location(const pe_resource_t *rsc, GList **list, int current)
Definition: native.c:1178
void pe__force_anon(const char *standard, pe_resource_t *rsc, const char *rid, pe_working_set_t *data_set)
Definition: clone.c:22
GHashTable * meta
Definition: pe_types.h:357
match resource not running anywhere
Definition: pe_types.h:85
#define pe_rsc_unique
Definition: pe_types.h:241
resource_object_functions_t * fns
Definition: pe_types.h:316
GHashTable * parameters
Definition: pe_types.h:358
#define CRMD_ACTION_PROMOTE
Definition: crm.h:177
void print_node(const char *pre_text, pe_node_t *node, gboolean details)
Definition: utils.c:1310
#define CRM_LOG_ASSERT(expr)
Definition: logging.h:219
void resource_location(pe_resource_t *rsc, pe_node_t *node, int score, const char *tag, pe_working_set_t *data_set)
Definition: utils.c:1609
#define clear_bit(word, bit)
Definition: crm_internal.h:69
#define resource_s
pe_node_t * allocated_to
Definition: pe_types.h:347
int pe__resource_text(pcmk__output_t *out, va_list args)
Definition: native.c:1131
void print_rscs_brief(GListPtr rsc_list, const char *pre_text, long options, void *print_data, gboolean print_all)
Definition: native.c:1305
xmlNodePtr pcmk__output_create_html_node(pcmk__output_t *out, const char *element_name, const char *id, const char *class_name, const char *text)
Definition: output_html.c:389
char * pending_task
Definition: pe_types.h:330
pe_node_t * pe_find_node_id(GListPtr node_list, const char *id)
Definition: status.c:411
void native_free(pe_resource_t *rsc)
Definition: native.c:1149
pe_node_t * lock_node
Definition: pe_types.h:368
#define CRMD_ACTION_START
Definition: crm.h:171
#define pe_rsc_provisional
Definition: pe_types.h:245
const char * role2text(enum rsc_role_e role)
Definition: common.c:463
#define CRMD_ACTION_STOP
Definition: crm.h:174
int weight
Definition: pe_types.h:228
void(* end_list)(pcmk__output_t *out)
Definition: output.h:432
#define CRMD_ACTION_DEMOTE
Definition: crm.h:179
#define set_bit(word, bit)
Definition: crm_internal.h:68
int rc
Definition: pcmk_fence.c:34
#define pe_rsc_failed
Definition: pe_types.h:252
#define crm_debug(fmt, args...)
Definition: logging.h:368
pe_resource_t * uber_parent(pe_resource_t *rsc)
Definition: complex.c:762
void(* begin_list)(pcmk__output_t *out, const char *singular_noun, const char *plural_noun, const char *format,...) G_GNUC_PRINTF(4
Definition: output.h:392
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
Definition: nvpair.c:522
int pe__name_and_nvpairs_xml(pcmk__output_t *out, bool is_list, const char *tag_name, size_t pairs_count,...)
Definition: pe_output.c:413
pe_resource_t *(* find_rsc)(pe_resource_t *parent, const char *search, const pe_node_t *node, int flags)
Definition: pe_types.h:45
match only clone instances
Definition: pe_types.h:83
char * native_parameter(pe_resource_t *rsc, pe_node_t *node, gboolean create, const char *name, pe_working_set_t *data_set)
Definition: native.c:315
#define crm_trace(fmt, args...)
Definition: logging.h:369
struct pe_node_shared_s * details
Definition: pe_types.h:231
GListPtr running_on
Definition: pe_types.h:350
enum rsc_recovery_type recovery_type
Definition: pe_types.h:319
#define XML_AGENT_ATTR_PROVIDER
Definition: msg_xml.h:230
void common_free(pe_resource_t *rsc)
Definition: complex.c:776
unsigned long long flags
Definition: pe_types.h:332
const char * uname
Definition: pe_types.h:196
#define pe_rsc_promotable
Definition: pe_types.h:243
char * clone_name
Definition: pe_types.h:306
PCMK__OUTPUT_ARGS("cluster-summary","struct pe_working_set_t *","gboolean","gboolean","gboolean","gboolean","gboolean","gboolean")
Definition: pe_output.c:214
#define XML_ATTR_DESC
Definition: msg_xml.h:95
enum rsc_role_e native_resource_state(const pe_resource_t *rsc, gboolean current)
Definition: native.c:1156
uint32_t pcmk_get_ra_caps(const char *standard)
Get capabilities of a resource agent standard.
Definition: agents.c:31
void native_print(pe_resource_t *rsc, const char *pre_text, long options, void *print_data)
Definition: native.c:1021
#define XML_RSC_ATTR_TARGET_ROLE
Definition: msg_xml.h:196
match base name of any clone instance
Definition: pe_types.h:86
enum rsc_role_e text2role(const char *role)
Definition: common.c:484
enum pe_obj_types variant
Definition: pe_types.h:314
void common_print(pe_resource_t *rsc, const char *pre_text, const char *name, pe_node_t *node, long options, void *print_data)
Definition: native.c:869
const char * id
Definition: pe_types.h:195
gboolean native_active(pe_resource_t *rsc, gboolean all)
Definition: native.c:360
int pe__resource_xml(pcmk__output_t *out, va_list args)
Definition: native.c:1043
#define XML_RSC_ATTR_UNIQUE
Definition: msg_xml.h:197
void native_add_running(pe_resource_t *rsc, pe_node_t *node, pe_working_set_t *data_set)
Definition: native.c:83
match resource ID or LRM history ID
Definition: pe_types.h:81
GListPtr running_rsc
Definition: pe_types.h:218
void get_rsc_attributes(GHashTable *meta_hash, pe_resource_t *rsc, pe_node_t *node, pe_working_set_t *data_set)
Definition: complex.c:129
Cluster status and scheduling.
pe_resource_t * native_find_rsc(pe_resource_t *rsc, const char *id, const pe_node_t *node, int flags)
Definition: native.c:260
pe_node_t * pending_node
Definition: pe_types.h:367
GListPtr children
Definition: pe_types.h:361
void add_hash_param(GHashTable *hash, const char *name, const char *value)
Definition: common.c:573
void * variant_opaque
Definition: pe_types.h:315
#define CRM_ASSERT(expr)
Definition: results.h:42
const char * rsc_printable_id(pe_resource_t *rsc)
Definition: utils.c:2276
#define status_print(fmt, args...)
This structure contains everything that makes up a single output formatter.
Definition: output.h:153
#define CRMD_ACTION_MIGRATE
Definition: crm.h:168
#define crm_str_hash
Definition: util.h:66
#define XML_RSC_ATTR_INTERNAL_RSC
Definition: msg_xml.h:206
char data[0]
Definition: internal.h:90
int pe__resource_html(pcmk__output_t *out, va_list args)
Definition: native.c:1112
rsc_role_e
Definition: common.h:76
#define pe_rsc_block
Definition: pe_types.h:237
#define BOOL2STR(x)
Definition: internal.h:455
gboolean maintenance
Definition: pe_types.h:209
#define pe_rsc_failure_ignored
Definition: pe_types.h:260
pe_node_t *(* location)(const pe_resource_t *, GList **, int)
Definition: pe_types.h:53
gboolean crm_is_true(const char *s)
Definition: strings.c:278
#define pe_rsc_trace(rsc, fmt, args...)
Definition: internal.h:19
gboolean(* active)(pe_resource_t *, gboolean)
Definition: pe_types.h:51
pe_node_t * pe__find_active_requires(const pe_resource_t *rsc, unsigned int *count)
Definition: complex.c:938
#define ID(x)
Definition: msg_xml.h:418
#define pe_err(fmt...)
Definition: internal.h:21
#define safe_str_eq(a, b)
Definition: util.h:65
void pe__output_node(pe_node_t *node, gboolean details, pcmk__output_t *out)
Definition: pe_output.c:1761
char * name
Definition: pcmk_fence.c:30
int pe__rscs_brief_output(pcmk__output_t *out, GListPtr rsc_list, long options, gboolean print_all)
Definition: native.c:1385
gboolean native_unpack(pe_resource_t *rsc, pe_working_set_t *data_set)
Definition: native.c:191
int pe__common_output_text(pcmk__output_t *out, pe_resource_t *rsc, const char *name, pe_node_t *node, long options)
Definition: native.c:805
gboolean unclean
Definition: pe_types.h:204
GList * GListPtr
Definition: crm.h:214
#define pe_rsc_managed
Definition: pe_types.h:236
#define pe_rsc_orphan
Definition: pe_types.h:235
gboolean online
Definition: pe_types.h:200
uint64_t flags
Definition: remote.c:149
match resource active on specified node
Definition: pe_types.h:84
pe_resource_t * parent
Definition: pe_types.h:312
void(*) void(* list_item)(pcmk__output_t *out, const char *name, const char *format,...) G_GNUC_PRINTF(3
Definition: output.h:405
enum crm_ais_msg_types type
Definition: internal.h:83
#define pe_rsc_info(rsc, fmt, args...)
Definition: internal.h:17
#define XML_AGENT_ATTR_CLASS
Definition: msg_xml.h:229
char * id
Definition: pe_types.h:305
GHashTable * allowed_nodes
Definition: pe_types.h:352
match base name of anonymous clone instances
Definition: pe_types.h:82
#define CRMD_ACTION_STATUS
Definition: crm.h:185