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