pacemaker  2.0.5-ba59be712
Scalable High-Availability cluster resource manager
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 (pcmk__str_eq(a_node->details->id, node->details->id, pcmk__str_casei)) {
93  return;
94  }
95  }
96 
97  pe_rsc_trace(rsc, "Adding %s to %s %s", rsc->id, node->details->uname,
98  pcmk_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 (!pcmk_is_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:
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 
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 (!pcmk_is_set(ra_caps, pcmk_ra_cap_unique)
205  && pcmk_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 (!pcmk_is_set(ra_caps, pcmk_ra_cap_promotable)
223  && pcmk_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 
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 (pcmk_is_set(flags, pe_find_inactive)
250  && (rsc->running_on == NULL)) {
251  return TRUE;
252 
253  } else if (!pcmk_is_set(flags, pe_find_current) && rsc->allocated_to
254  && (rsc->allocated_to->details == node->details)) {
255  return TRUE;
256  }
257  return FALSE;
258 }
259 
261 native_find_rsc(pe_resource_t * rsc, const char *id, const pe_node_t *on_node,
262  int flags)
263 {
264  bool match = FALSE;
265  pe_resource_t *result = NULL;
266 
267  CRM_CHECK(id && rsc && rsc->id, return NULL);
268 
269  if (flags & pe_find_clone) {
270  const char *rid = ID(rsc->xml);
271 
272  if (!pe_rsc_is_clone(uber_parent(rsc))) {
273  match = FALSE;
274 
275  } else if (!strcmp(id, rsc->id) || pcmk__str_eq(id, rid, pcmk__str_casei)) {
276  match = TRUE;
277  }
278 
279  } else if (!strcmp(id, rsc->id)) {
280  match = TRUE;
281 
282  } else if (pcmk_is_set(flags, pe_find_renamed)
283  && rsc->clone_name && strcmp(rsc->clone_name, id) == 0) {
284  match = TRUE;
285 
286  } else if (pcmk_is_set(flags, pe_find_any)
288  && !pcmk_is_set(rsc->flags, pe_rsc_unique))) {
289  match = pe_base_name_eq(rsc, id);
290  }
291 
292  if (match && on_node) {
293  bool match_node = rsc_is_on_node(rsc, on_node, flags);
294 
295  if (match_node == FALSE) {
296  match = FALSE;
297  }
298  }
299 
300  if (match) {
301  return rsc;
302  }
303 
304  for (GListPtr gIter = rsc->children; gIter != NULL; gIter = gIter->next) {
305  pe_resource_t *child = (pe_resource_t *) gIter->data;
306 
307  result = rsc->fns->find_rsc(child, id, on_node, flags);
308  if (result) {
309  return result;
310  }
311  }
312  return NULL;
313 }
314 
315 char *
316 native_parameter(pe_resource_t * rsc, pe_node_t * node, gboolean create, const char *name,
317  pe_working_set_t * data_set)
318 {
319  char *value_copy = NULL;
320  const char *value = NULL;
321  GHashTable *hash = NULL;
322  GHashTable *local_hash = NULL;
323 
324  CRM_CHECK(rsc != NULL, return NULL);
325  CRM_CHECK(name != NULL && strlen(name) != 0, return NULL);
326 
327  pe_rsc_trace(rsc, "Looking up %s in %s", name, rsc->id);
328 
329  if (create || g_hash_table_size(rsc->parameters) == 0) {
330  if (node != NULL) {
331  pe_rsc_trace(rsc, "Creating hash with node %s", node->details->uname);
332  } else {
333  pe_rsc_trace(rsc, "Creating default hash");
334  }
335 
336  local_hash = crm_str_table_new();
337 
338  get_rsc_attributes(local_hash, rsc, node, data_set);
339 
340  hash = local_hash;
341  } else {
342  hash = rsc->parameters;
343  }
344 
345  value = g_hash_table_lookup(hash, name);
346  if (value == NULL) {
347  /* try meta attributes instead */
348  value = g_hash_table_lookup(rsc->meta, name);
349  }
350 
351  if (value != NULL) {
352  value_copy = strdup(value);
353  }
354  if (local_hash != NULL) {
355  g_hash_table_destroy(local_hash);
356  }
357  return value_copy;
358 }
359 
360 gboolean
361 native_active(pe_resource_t * rsc, gboolean all)
362 {
363  for (GList *gIter = rsc->running_on; gIter != NULL; gIter = gIter->next) {
364  pe_node_t *a_node = (pe_node_t *) gIter->data;
365 
366  if (a_node->details->unclean) {
367  pe_rsc_trace(rsc, "Resource %s: node %s is unclean",
368  rsc->id, a_node->details->uname);
369  return TRUE;
370  } else if (a_node->details->online == FALSE) {
371  pe_rsc_trace(rsc, "Resource %s: node %s is offline",
372  rsc->id, a_node->details->uname);
373  } else {
374  pe_rsc_trace(rsc, "Resource %s active on %s",
375  rsc->id, a_node->details->uname);
376  return TRUE;
377  }
378  }
379  return FALSE;
380 }
381 
382 struct print_data_s {
383  long options;
384  void *print_data;
385 };
386 
387 static void
388 native_print_attr(gpointer key, gpointer value, gpointer user_data)
389 {
390  long options = ((struct print_data_s *)user_data)->options;
391  void *print_data = ((struct print_data_s *)user_data)->print_data;
392 
393  status_print("Option: %s = %s\n", (char *)key, (char *)value);
394 }
395 
396 static const char *
397 native_pending_state(pe_resource_t * rsc)
398 {
399  const char *pending_state = NULL;
400 
401  if (pcmk__str_eq(rsc->pending_task, CRMD_ACTION_START, pcmk__str_casei)) {
402  pending_state = "Starting";
403 
404  } else if (pcmk__str_eq(rsc->pending_task, CRMD_ACTION_STOP, pcmk__str_casei)) {
405  pending_state = "Stopping";
406 
407  } else if (pcmk__str_eq(rsc->pending_task, CRMD_ACTION_MIGRATE, pcmk__str_casei)) {
408  pending_state = "Migrating";
409 
410  } else if (pcmk__str_eq(rsc->pending_task, CRMD_ACTION_MIGRATED, pcmk__str_casei)) {
411  /* Work might be done in here. */
412  pending_state = "Migrating";
413 
414  } else if (pcmk__str_eq(rsc->pending_task, CRMD_ACTION_PROMOTE, pcmk__str_casei)) {
415  pending_state = "Promoting";
416 
417  } else if (pcmk__str_eq(rsc->pending_task, CRMD_ACTION_DEMOTE, pcmk__str_casei)) {
418  pending_state = "Demoting";
419  }
420 
421  return pending_state;
422 }
423 
424 static const char *
425 native_pending_task(pe_resource_t * rsc)
426 {
427  const char *pending_task = NULL;
428 
429  if (pcmk__str_eq(rsc->pending_task, CRMD_ACTION_STATUS, pcmk__str_casei)) {
430  pending_task = "Monitoring";
431 
432  /* Pending probes are not printed, even if pending
433  * operations are requested. If someone ever requests that
434  * behavior, uncomment this and the corresponding part of
435  * unpack.c:unpack_rsc_op().
436  */
437  /*
438  } else if (pcmk__str_eq(rsc->pending_task, "probe", pcmk__str_casei)) {
439  pending_task = "Checking";
440  */
441  }
442 
443  return pending_task;
444 }
445 
446 static enum rsc_role_e
447 native_displayable_role(pe_resource_t *rsc)
448 {
449  enum rsc_role_e role = rsc->role;
450 
451  if ((role == RSC_ROLE_STARTED)
453 
454  role = RSC_ROLE_SLAVE;
455  }
456  return role;
457 }
458 
459 static const char *
460 native_displayable_state(pe_resource_t *rsc, long options)
461 {
462  const char *rsc_state = NULL;
463 
464  if (options & pe_print_pending) {
465  rsc_state = native_pending_state(rsc);
466  }
467  if (rsc_state == NULL) {
468  rsc_state = role2text(native_displayable_role(rsc));
469  }
470  return rsc_state;
471 }
472 
473 static void
474 native_print_xml(pe_resource_t * rsc, const char *pre_text, long options, void *print_data)
475 {
476  const char *class = crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS);
477  const char *prov = crm_element_value(rsc->xml, XML_AGENT_ATTR_PROVIDER);
478  const char *rsc_state = native_displayable_state(rsc, options);
479  const char *target_role = NULL;
480 
481  /* resource information. */
482  status_print("%s<resource ", pre_text);
483  status_print("id=\"%s\" ", rsc_printable_id(rsc));
484  status_print("resource_agent=\"%s%s%s:%s\" ",
485  class,
486  prov ? "::" : "", prov ? prov : "", crm_element_value(rsc->xml, XML_ATTR_TYPE));
487 
488  status_print("role=\"%s\" ", rsc_state);
489  if (rsc->meta) {
490  target_role = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_TARGET_ROLE);
491  }
492  if (target_role) {
493  status_print("target_role=\"%s\" ", target_role);
494  }
495  status_print("active=\"%s\" ", pcmk__btoa(rsc->fns->active(rsc, TRUE)));
496  status_print("orphaned=\"%s\" ", pe__rsc_bool_str(rsc, pe_rsc_orphan));
497  status_print("blocked=\"%s\" ", pe__rsc_bool_str(rsc, pe_rsc_block));
498  status_print("managed=\"%s\" ", pe__rsc_bool_str(rsc, pe_rsc_managed));
499  status_print("failed=\"%s\" ", pe__rsc_bool_str(rsc, pe_rsc_failed));
500  status_print("failure_ignored=\"%s\" ",
501  pe__rsc_bool_str(rsc, pe_rsc_failure_ignored));
502  status_print("nodes_running_on=\"%d\" ", g_list_length(rsc->running_on));
503 
504  if (options & pe_print_pending) {
505  const char *pending_task = native_pending_task(rsc);
506 
507  if (pending_task) {
508  status_print("pending=\"%s\" ", pending_task);
509  }
510  }
511 
512  if (options & pe_print_dev) {
513  status_print("provisional=\"%s\" ",
514  pe__rsc_bool_str(rsc, pe_rsc_provisional));
515  status_print("runnable=\"%s\" ", pe__rsc_bool_str(rsc, pe_rsc_runnable));
516  status_print("priority=\"%f\" ", (double)rsc->priority);
517  status_print("variant=\"%s\" ", crm_element_name(rsc->xml));
518  }
519 
520  /* print out the nodes this resource is running on */
521  if (options & pe_print_rsconly) {
522  status_print("/>\n");
523  /* do nothing */
524  } else if (rsc->running_on != NULL) {
525  GListPtr gIter = rsc->running_on;
526 
527  status_print(">\n");
528  for (; gIter != NULL; gIter = gIter->next) {
529  pe_node_t *node = (pe_node_t *) gIter->data;
530 
531  status_print("%s <node name=\"%s\" id=\"%s\" cached=\"%s\"/>\n", pre_text,
532  node->details->uname, node->details->id,
533  pcmk__btoa(node->details->online == FALSE));
534  }
535  status_print("%s</resource>\n", pre_text);
536  } else {
537  status_print("/>\n");
538  }
539 }
540 
541 // Append a flag to resource description string's flags list
542 static bool
543 add_output_flag(GString *s, const char *flag_desc, bool have_flags)
544 {
545  g_string_append(s, (have_flags? ", " : " ("));
546  g_string_append(s, flag_desc);
547  return true;
548 }
549 
550 // Append a node name to resource description string's node list
551 static bool
552 add_output_node(GString *s, const char *node, bool have_nodes)
553 {
554  g_string_append(s, (have_nodes? " " : " [ "));
555  g_string_append(s, node);
556  return true;
557 }
558 
573 static gchar *
574 native_output_string(pe_resource_t *rsc, const char *name, pe_node_t *node,
575  long options, const char *target_role, bool show_nodes)
576 {
577  const char *class = crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS);
578  const char *provider = NULL;
579  const char *kind = crm_element_value(rsc->xml, XML_ATTR_TYPE);
580  char *retval = NULL;
581  GString *outstr = NULL;
582  bool have_flags = false;
583 
584  CRM_CHECK(name != NULL, name = "unknown");
585  CRM_CHECK(kind != NULL, kind = "unknown");
586  CRM_CHECK(class != NULL, class = "unknown");
587 
590  }
591 
592  if ((node == NULL) && (rsc->lock_node != NULL)) {
593  node = rsc->lock_node;
594  }
595  if (pcmk_is_set(options, pe_print_rsconly)
596  || pcmk__list_of_multiple(rsc->running_on)) {
597  node = NULL;
598  }
599 
600  // We need a string of at least this size
601  outstr = g_string_sized_new(strlen(name) + strlen(class) + strlen(kind)
602  + (provider? (strlen(provider) + 2) : 0)
603  + (node? strlen(node->details->uname) + 1 : 0)
604  + 11);
605 
606  // Resource name and agent
607  g_string_printf(outstr, "%s\t(%s%s%s:%s):\t", name, class,
608  /* @COMPAT This should be a single ':' (see CLBZ#5395) but
609  * to avoid breaking anything relying on it, we're keeping
610  * it like this until the next minor version bump.
611  */
612  (provider? "::" : ""), (provider? provider : ""), kind);
613 
614  // State on node
615  if (pcmk_is_set(rsc->flags, pe_rsc_orphan)) {
616  g_string_append(outstr, " ORPHANED");
617  }
618  if (pcmk_is_set(rsc->flags, pe_rsc_failed)) {
619  enum rsc_role_e role = native_displayable_role(rsc);
620 
621  if (role > RSC_ROLE_SLAVE) {
622  g_string_append_printf(outstr, " FAILED %s", role2text(role));
623  } else {
624  g_string_append(outstr, " FAILED");
625  }
626  } else {
627  g_string_append_printf(outstr, " %s", native_displayable_state(rsc, options));
628  }
629  if (node) {
630  g_string_append_printf(outstr, " %s", node->details->uname);
631  }
632 
633  // Flags, as: (<flag> [...])
634  if (node && !(node->details->online) && node->details->unclean) {
635  have_flags = add_output_flag(outstr, "UNCLEAN", have_flags);
636  }
637  if (node && (node == rsc->lock_node)) {
638  have_flags = add_output_flag(outstr, "LOCKED", have_flags);
639  }
640  if (pcmk_is_set(options, pe_print_pending)) {
641  const char *pending_task = native_pending_task(rsc);
642 
643  if (pending_task) {
644  have_flags = add_output_flag(outstr, pending_task, have_flags);
645  }
646  }
647  if (target_role) {
648  enum rsc_role_e target_role_e = text2role(target_role);
649 
650  /* Only show target role if it limits our abilities (i.e. ignore
651  * Started, as it is the default anyways, and doesn't prevent the
652  * resource from becoming Master).
653  */
654  if (target_role_e == RSC_ROLE_STOPPED) {
655  have_flags = add_output_flag(outstr, "disabled", have_flags);
656 
658  && target_role_e == RSC_ROLE_SLAVE) {
659  have_flags = add_output_flag(outstr, "target-role:", have_flags);
660  g_string_append(outstr, target_role);
661  }
662  }
663  if (pcmk_is_set(rsc->flags, pe_rsc_block)) {
664  have_flags = add_output_flag(outstr, "blocked", have_flags);
665  } else if (!pcmk_is_set(rsc->flags, pe_rsc_managed)) {
666  have_flags = add_output_flag(outstr, "unmanaged", have_flags);
667  }
669  have_flags = add_output_flag(outstr, "failure ignored", have_flags);
670  }
671  if (pcmk_is_set(options, pe_print_dev)) {
672  if (pcmk_is_set(options, pe_rsc_provisional)) {
673  have_flags = add_output_flag(outstr, "provisional", have_flags);
674  }
675  if (!pcmk_is_set(options, pe_rsc_runnable)) {
676  have_flags = add_output_flag(outstr, "non-startable", have_flags);
677  }
678  have_flags = add_output_flag(outstr, "variant:", have_flags);
679  g_string_append_printf(outstr, "%s priority:%f",
680  crm_element_name(rsc->xml),
681  (double) (rsc->priority));
682  }
683  if (have_flags) {
684  g_string_append(outstr, ")");
685  }
686 
687  // User-supplied description
688  if (pcmk_is_set(options, pe_print_rsconly)
689  || pcmk__list_of_multiple(rsc->running_on)) {
690  const char *desc = crm_element_value(rsc->xml, XML_ATTR_DESC);
691 
692  if (desc) {
693  g_string_append_printf(outstr, " %s", desc);
694  }
695  }
696 
697  if (show_nodes && !pcmk_is_set(options, pe_print_rsconly)
698  && pcmk__list_of_multiple(rsc->running_on)) {
699  bool have_nodes = false;
700 
701  for (GList *iter = rsc->running_on; iter != NULL; iter = iter->next) {
702  pe_node_t *n = (pe_node_t *) iter->data;
703 
704  have_nodes = add_output_node(outstr, n->details->uname, have_nodes);
705  }
706  if (have_nodes) {
707  g_string_append(outstr, " ]");
708  }
709  }
710 
711  retval = outstr->str;
712  g_string_free(outstr, FALSE);
713  return retval;
714 }
715 
716 int
718  const char *name, pe_node_t *node, long options)
719 {
720  const char *kind = crm_element_value(rsc->xml, XML_ATTR_TYPE);
721  const char *target_role = NULL;
722 
723  xmlNodePtr list_node = NULL;
724  const char *cl = NULL;
725 
726  CRM_ASSERT(rsc->variant == pe_native);
727  CRM_ASSERT(kind != NULL);
728 
729  if (rsc->meta) {
730  const char *is_internal = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_INTERNAL_RSC);
731 
732  if (crm_is_true(is_internal)
733  && !pcmk_is_set(options, pe_print_implicit)) {
734 
735  crm_trace("skipping print of internal resource %s", rsc->id);
736  return pcmk_rc_no_output;
737  }
738  target_role = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_TARGET_ROLE);
739  }
740 
741  if (!pcmk_is_set(rsc->flags, pe_rsc_managed)) {
742  cl = "rsc-managed";
743 
744  } else if (pcmk_is_set(rsc->flags, pe_rsc_failed)) {
745  cl = "rsc-failed";
746 
747  } else if (rsc->variant == pe_native && (rsc->running_on == NULL)) {
748  cl = "rsc-failed";
749 
750  } else if (pcmk__list_of_multiple(rsc->running_on)) {
751  cl = "rsc-multiple";
752 
753  } else if (pcmk_is_set(rsc->flags, pe_rsc_failure_ignored)) {
754  cl = "rsc-failure-ignored";
755 
756  } else {
757  cl = "rsc-ok";
758  }
759 
760  {
761  gchar *s = native_output_string(rsc, name, node, options, target_role,
762  true);
763 
764  list_node = pcmk__output_create_html_node(out, "li", NULL, NULL, NULL);
765  pcmk_create_html_node(list_node, "span", NULL, cl, s);
766  g_free(s);
767  }
768 
769  if (pcmk_is_set(options, pe_print_details)) {
770  GHashTableIter iter;
771  gpointer key, value;
772 
773  out->begin_list(out, NULL, NULL, "Options");
774  g_hash_table_iter_init(&iter, rsc->parameters);
775  while (g_hash_table_iter_next(&iter, &key, &value)) {
776  out->list_item(out, NULL, "Option: %s = %s", (char *) key, (char *) value);
777  }
778  out->end_list(out);
779  }
780 
781  if (pcmk_is_set(options, pe_print_dev)) {
782  GHashTableIter iter;
783  pe_node_t *n = NULL;
784 
785  out->begin_list(out, NULL, NULL, "Allowed Nodes");
786  g_hash_table_iter_init(&iter, rsc->allowed_nodes);
787  while (g_hash_table_iter_next(&iter, NULL, (void **)&n)) {
788  out->list_item(out, NULL, "%s %d", n->details->uname, n->weight);
789  }
790  out->end_list(out);
791  }
792 
793  if (pcmk_is_set(options, pe_print_max_details)) {
794  GHashTableIter iter;
795  pe_node_t *n = NULL;
796 
797  out->begin_list(out, NULL, NULL, "=== Allowed Nodes");
798  g_hash_table_iter_init(&iter, rsc->allowed_nodes);
799  while (g_hash_table_iter_next(&iter, NULL, (void **)&n)) {
800  pe__output_node(n, FALSE, out);
801  }
802  out->end_list(out);
803  }
804 
805  return pcmk_rc_ok;
806 }
807 
808 int
810  const char *name, pe_node_t *node, long options)
811 {
812  const char *target_role = NULL;
813 
814  CRM_ASSERT(rsc->variant == pe_native);
815 
816  if (rsc->meta) {
817  const char *is_internal = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_INTERNAL_RSC);
818 
819  if (crm_is_true(is_internal)
820  && !pcmk_is_set(options, pe_print_implicit)) {
821 
822  crm_trace("skipping print of internal resource %s", rsc->id);
823  return pcmk_rc_no_output;
824  }
825  target_role = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_TARGET_ROLE);
826  }
827 
828  {
829  gchar *s = native_output_string(rsc, name, node, options, target_role,
830  true);
831 
832  out->list_item(out, NULL, "%s", s);
833  g_free(s);
834  }
835 
836  if (pcmk_is_set(options, pe_print_details)) {
837  GHashTableIter iter;
838  gpointer key, value;
839 
840  out->begin_list(out, NULL, NULL, "Options");
841  g_hash_table_iter_init(&iter, rsc->parameters);
842  while (g_hash_table_iter_next(&iter, &key, &value)) {
843  out->list_item(out, NULL, "Option: %s = %s", (char *) key, (char *) value);
844  }
845  out->end_list(out);
846  }
847 
848  if (pcmk_is_set(options, pe_print_dev)) {
849  GHashTableIter iter;
850  pe_node_t *n = NULL;
851 
852  out->begin_list(out, NULL, NULL, "Allowed Nodes");
853  g_hash_table_iter_init(&iter, rsc->allowed_nodes);
854  while (g_hash_table_iter_next(&iter, NULL, (void **)&n)) {
855  out->list_item(out, NULL, "%s %d", n->details->uname, n->weight);
856  }
857  out->end_list(out);
858  }
859 
860  if (pcmk_is_set(options, pe_print_max_details)) {
861  GHashTableIter iter;
862  pe_node_t *n = NULL;
863 
864  out->begin_list(out, NULL, NULL, "=== Allowed Nodes");
865  g_hash_table_iter_init(&iter, rsc->allowed_nodes);
866  while (g_hash_table_iter_next(&iter, NULL, (void **)&n)) {
867  pe__output_node(n, FALSE, out);
868  }
869  out->end_list(out);
870  }
871 
872  return pcmk_rc_ok;
873 }
874 
875 void
876 common_print(pe_resource_t * rsc, const char *pre_text, const char *name, pe_node_t *node, long options, void *print_data)
877 {
878  const char *target_role = NULL;
879 
880  CRM_ASSERT(rsc->variant == pe_native);
881 
882  if (rsc->meta) {
883  const char *is_internal = g_hash_table_lookup(rsc->meta,
885 
886  if (crm_is_true(is_internal)
887  && !pcmk_is_set(options, pe_print_implicit)) {
888 
889  crm_trace("skipping print of internal resource %s", rsc->id);
890  return;
891  }
892  target_role = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_TARGET_ROLE);
893  }
894 
895  if (options & pe_print_xml) {
896  native_print_xml(rsc, pre_text, options, print_data);
897  return;
898  }
899 
900  if ((pre_text == NULL) && (options & pe_print_printf)) {
901  pre_text = " ";
902  }
903 
904  if (options & pe_print_html) {
905  if (!pcmk_is_set(rsc->flags, pe_rsc_managed)) {
906  status_print("<font color=\"yellow\">");
907 
908  } else if (pcmk_is_set(rsc->flags, pe_rsc_failed)) {
909  status_print("<font color=\"red\">");
910 
911  } else if (rsc->running_on == NULL) {
912  status_print("<font color=\"red\">");
913 
914  } else if (pcmk__list_of_multiple(rsc->running_on)) {
915  status_print("<font color=\"orange\">");
916 
917  } else if (pcmk_is_set(rsc->flags, pe_rsc_failure_ignored)) {
918  status_print("<font color=\"yellow\">");
919 
920  } else {
921  status_print("<font color=\"green\">");
922  }
923  }
924 
925  {
926  gchar *resource_s = native_output_string(rsc, name, node, options,
927  target_role, false);
928  status_print("%s%s", (pre_text? pre_text : ""), resource_s);
929  g_free(resource_s);
930  }
931 
932 #if CURSES_ENABLED
933  if (pcmk_is_set(options, pe_print_ncurses)
934  && !pcmk_is_set(options, pe_print_rsconly)
935  && !pcmk__list_of_multiple(rsc->running_on)) {
936  /* coverity[negative_returns] False positive */
937  move(-1, 0);
938  }
939 #endif
940 
941  if (pcmk_is_set(options, pe_print_html)) {
942  status_print(" </font> ");
943  }
944 
945  if (!pcmk_is_set(options, pe_print_rsconly)
946  && pcmk__list_of_multiple(rsc->running_on)) {
947 
948  GListPtr gIter = rsc->running_on;
949  int counter = 0;
950 
951  if (options & pe_print_html) {
952  status_print("<ul>\n");
953  } else if ((options & pe_print_printf)
954  || (options & pe_print_ncurses)) {
955  status_print("[");
956  }
957 
958  for (; gIter != NULL; gIter = gIter->next) {
959  pe_node_t *n = (pe_node_t *) gIter->data;
960 
961  counter++;
962 
963  if (options & pe_print_html) {
964  status_print("<li>\n%s", n->details->uname);
965 
966  } else if ((options & pe_print_printf)
967  || (options & pe_print_ncurses)) {
968  status_print(" %s", n->details->uname);
969 
970  } else if ((options & pe_print_log)) {
971  status_print("\t%d : %s", counter, n->details->uname);
972 
973  } else {
974  status_print("%s", n->details->uname);
975  }
976  if (options & pe_print_html) {
977  status_print("</li>\n");
978 
979  }
980  }
981 
982  if (options & pe_print_html) {
983  status_print("</ul>\n");
984  } else if ((options & pe_print_printf)
985  || (options & pe_print_ncurses)) {
986  status_print(" ]");
987  }
988  }
989 
990  if (options & pe_print_html) {
991  status_print("<br/>\n");
992  } else if (options & pe_print_suppres_nl) {
993  /* nothing */
994  } else if ((options & pe_print_printf) || (options & pe_print_ncurses)) {
995  status_print("\n");
996  }
997 
998  if (options & pe_print_details) {
999  struct print_data_s pdata;
1000 
1001  pdata.options = options;
1002  pdata.print_data = print_data;
1003  g_hash_table_foreach(rsc->parameters, native_print_attr, &pdata);
1004  }
1005 
1006  if (options & pe_print_dev) {
1007  GHashTableIter iter;
1008  pe_node_t *n = NULL;
1009 
1010  status_print("%s\tAllowed Nodes", pre_text);
1011  g_hash_table_iter_init(&iter, rsc->allowed_nodes);
1012  while (g_hash_table_iter_next(&iter, NULL, (void **)&n)) {
1013  status_print("%s\t * %s %d", pre_text, n->details->uname, n->weight);
1014  }
1015  }
1016 
1017  if (options & pe_print_max_details) {
1018  GHashTableIter iter;
1019  pe_node_t *n = NULL;
1020 
1021  status_print("%s\t=== Allowed Nodes\n", pre_text);
1022  g_hash_table_iter_init(&iter, rsc->allowed_nodes);
1023  while (g_hash_table_iter_next(&iter, NULL, (void **)&n)) {
1024  print_node("\t", n, FALSE);
1025  }
1026  }
1027 }
1028 
1029 void
1030 native_print(pe_resource_t * rsc, const char *pre_text, long options, void *print_data)
1031 {
1032  pe_node_t *node = NULL;
1033 
1034  CRM_ASSERT(rsc->variant == pe_native);
1035  if (options & pe_print_xml) {
1036  native_print_xml(rsc, pre_text, options, print_data);
1037  return;
1038  }
1039 
1040  node = pe__current_node(rsc);
1041 
1042  if (node == NULL) {
1043  // This is set only if a non-probe action is pending on this node
1044  node = rsc->pending_node;
1045  }
1046 
1047  common_print(rsc, pre_text, rsc_printable_id(rsc), node, options, print_data);
1048 }
1049 
1050 PCMK__OUTPUT_ARGS("primitive", "unsigned int", "pe_resource_t *", "GListPtr", "GListPtr")
1051 int
1053 {
1054  unsigned int options = va_arg(args, unsigned int);
1055  pe_resource_t *rsc = va_arg(args, pe_resource_t *);
1056  GListPtr only_node G_GNUC_UNUSED = va_arg(args, GListPtr);
1057  GListPtr only_rsc = va_arg(args, GListPtr);
1058 
1059  const char *class = crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS);
1060  const char *prov = crm_element_value(rsc->xml, XML_AGENT_ATTR_PROVIDER);
1061  const char *rsc_state = native_displayable_state(rsc, options);
1062 
1063  long is_print_pending = options & pe_print_pending;
1064  long is_print_dev = options & pe_print_dev;
1065 
1066  char ra_name[LINE_MAX];
1067  char *nodes_running_on = NULL;
1068  char *priority = NULL;
1069  int rc = pcmk_rc_no_output;
1070  const char *target_role = NULL;
1071 
1072  if (rsc->meta != NULL) {
1073  target_role = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_TARGET_ROLE);
1074  }
1075 
1076  CRM_ASSERT(rsc->variant == pe_native);
1077 
1078  if (rsc->fns->is_filtered(rsc, only_rsc, TRUE)) {
1079  return pcmk_rc_no_output;
1080  }
1081 
1082  /* resource information. */
1083  sprintf(ra_name, "%s%s%s:%s", class, prov ? "::" : "", prov ? prov : ""
1084  , crm_element_value(rsc->xml, XML_ATTR_TYPE));
1085 
1086  nodes_running_on = crm_itoa(g_list_length(rsc->running_on));
1087  priority = crm_ftoa(rsc->priority);
1088 
1089  rc = pe__name_and_nvpairs_xml(out, true, "resource", 16,
1090  "id", rsc_printable_id(rsc),
1091  "resource_agent", ra_name,
1092  "role", rsc_state,
1093  "target_role", target_role,
1094  "active", pcmk__btoa(rsc->fns->active(rsc, TRUE)),
1095  "orphaned", pe__rsc_bool_str(rsc, pe_rsc_orphan),
1096  "blocked", pe__rsc_bool_str(rsc, pe_rsc_block),
1097  "managed", pe__rsc_bool_str(rsc, pe_rsc_managed),
1098  "failed", pe__rsc_bool_str(rsc, pe_rsc_failed),
1099  "failure_ignored", pe__rsc_bool_str(rsc, pe_rsc_failure_ignored),
1100  "nodes_running_on", nodes_running_on,
1101  "pending", (is_print_pending? native_pending_task(rsc) : NULL),
1102  "provisional", (is_print_dev? pe__rsc_bool_str(rsc, pe_rsc_provisional) : NULL),
1103  "runnable", (is_print_dev? pe__rsc_bool_str(rsc, pe_rsc_runnable) : NULL),
1104  "priority", (is_print_dev? priority : NULL),
1105  "variant", (is_print_dev? crm_element_name(rsc->xml) : NULL));
1106  free(priority);
1107  free(nodes_running_on);
1108 
1109  CRM_ASSERT(rc == pcmk_rc_ok);
1110 
1111  if (rsc->running_on != NULL) {
1112  GListPtr gIter = rsc->running_on;
1113 
1114  for (; gIter != NULL; gIter = gIter->next) {
1115  pe_node_t *node = (pe_node_t *) gIter->data;
1116 
1117  rc = pe__name_and_nvpairs_xml(out, false, "node", 3,
1118  "name", node->details->uname,
1119  "id", node->details->id,
1120  "cached", pcmk__btoa(node->details->online));
1121  CRM_ASSERT(rc == pcmk_rc_ok);
1122  }
1123  }
1124 
1126  return rc;
1127 }
1128 
1129 PCMK__OUTPUT_ARGS("primitive", "unsigned int", "pe_resource_t *", "GListPtr", "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_node G_GNUC_UNUSED = va_arg(args, GListPtr);
1136  GListPtr only_rsc = va_arg(args, GListPtr);
1137 
1138  pe_node_t *node = pe__current_node(rsc);
1139 
1140  if (rsc->fns->is_filtered(rsc, only_rsc, TRUE)) {
1141  return pcmk_rc_no_output;
1142  }
1143 
1144  CRM_ASSERT(rsc->variant == pe_native);
1145 
1146  if (node == NULL) {
1147  // This is set only if a non-probe action is pending on this node
1148  node = rsc->pending_node;
1149  }
1150  return pe__common_output_html(out, rsc, rsc_printable_id(rsc), node, options);
1151 }
1152 
1153 PCMK__OUTPUT_ARGS("primitive", "unsigned int", "pe_resource_t *", "GListPtr", "GListPtr")
1154 int
1156 {
1157  unsigned int options = va_arg(args, unsigned int);
1158  pe_resource_t *rsc = va_arg(args, pe_resource_t *);
1159  GListPtr only_node G_GNUC_UNUSED = va_arg(args, GListPtr);
1160  GListPtr only_rsc = va_arg(args, GListPtr);
1161 
1162  pe_node_t *node = pe__current_node(rsc);
1163 
1164  CRM_ASSERT(rsc->variant == pe_native);
1165 
1166  if (rsc->fns->is_filtered(rsc, only_rsc, TRUE)) {
1167  return pcmk_rc_no_output;
1168  }
1169 
1170  if (node == NULL) {
1171  // This is set only if a non-probe action is pending on this node
1172  node = rsc->pending_node;
1173  }
1174  return pe__common_output_text(out, rsc, rsc_printable_id(rsc), node, options);
1175 }
1176 
1177 void
1179 {
1180  pe_rsc_trace(rsc, "Freeing resource action list (not the data)");
1181  common_free(rsc);
1182 }
1183 
1184 enum rsc_role_e
1185 native_resource_state(const pe_resource_t * rsc, gboolean current)
1186 {
1187  enum rsc_role_e role = rsc->next_role;
1188 
1189  if (current) {
1190  role = rsc->role;
1191  }
1192  pe_rsc_trace(rsc, "%s state: %s", rsc->id, role2text(role));
1193  return role;
1194 }
1195 
1206 pe_node_t *
1207 native_location(const pe_resource_t *rsc, GList **list, int current)
1208 {
1209  pe_node_t *one = NULL;
1210  GListPtr result = NULL;
1211 
1212  if (rsc->children) {
1213  GListPtr gIter = rsc->children;
1214 
1215  for (; gIter != NULL; gIter = gIter->next) {
1216  pe_resource_t *child = (pe_resource_t *) gIter->data;
1217 
1218  child->fns->location(child, &result, current);
1219  }
1220 
1221  } else if (current) {
1222 
1223  if (rsc->running_on) {
1224  result = g_list_copy(rsc->running_on);
1225  }
1226  if ((current == 2) && rsc->pending_node
1227  && !pe_find_node_id(result, rsc->pending_node->details->id)) {
1228  result = g_list_append(result, rsc->pending_node);
1229  }
1230 
1231  } else if (current == FALSE && rsc->allocated_to) {
1232  result = g_list_append(NULL, rsc->allocated_to);
1233  }
1234 
1235  if (result && (result->next == NULL)) {
1236  one = result->data;
1237  }
1238 
1239  if (list) {
1240  GListPtr gIter = result;
1241 
1242  for (; gIter != NULL; gIter = gIter->next) {
1243  pe_node_t *node = (pe_node_t *) gIter->data;
1244 
1245  if (*list == NULL || pe_find_node_id(*list, node->details->id) == NULL) {
1246  *list = g_list_append(*list, node);
1247  }
1248  }
1249  }
1250 
1251  g_list_free(result);
1252  return one;
1253 }
1254 
1255 static void
1256 get_rscs_brief(GListPtr rsc_list, GHashTable * rsc_table, GHashTable * active_table)
1257 {
1258  GListPtr gIter = rsc_list;
1259 
1260  for (; gIter != NULL; gIter = gIter->next) {
1261  pe_resource_t *rsc = (pe_resource_t *) gIter->data;
1262 
1263  const char *class = crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS);
1264  const char *kind = crm_element_value(rsc->xml, XML_ATTR_TYPE);
1265 
1266  int offset = 0;
1267  char buffer[LINE_MAX];
1268 
1269  int *rsc_counter = NULL;
1270  int *active_counter = NULL;
1271 
1272  if (rsc->variant != pe_native) {
1273  continue;
1274  }
1275 
1276  offset += snprintf(buffer + offset, LINE_MAX - offset, "%s", class);
1278  const char *prov = crm_element_value(rsc->xml, XML_AGENT_ATTR_PROVIDER);
1279  offset += snprintf(buffer + offset, LINE_MAX - offset, "::%s", prov);
1280  }
1281  offset += snprintf(buffer + offset, LINE_MAX - offset, ":%s", kind);
1282  CRM_LOG_ASSERT(offset > 0);
1283 
1284  if (rsc_table) {
1285  rsc_counter = g_hash_table_lookup(rsc_table, buffer);
1286  if (rsc_counter == NULL) {
1287  rsc_counter = calloc(1, sizeof(int));
1288  *rsc_counter = 0;
1289  g_hash_table_insert(rsc_table, strdup(buffer), rsc_counter);
1290  }
1291  (*rsc_counter)++;
1292  }
1293 
1294  if (active_table) {
1295  GListPtr gIter2 = rsc->running_on;
1296 
1297  for (; gIter2 != NULL; gIter2 = gIter2->next) {
1298  pe_node_t *node = (pe_node_t *) gIter2->data;
1299  GHashTable *node_table = NULL;
1300 
1301  if (node->details->unclean == FALSE && node->details->online == FALSE) {
1302  continue;
1303  }
1304 
1305  node_table = g_hash_table_lookup(active_table, node->details->uname);
1306  if (node_table == NULL) {
1307  node_table = crm_str_table_new();
1308  g_hash_table_insert(active_table, strdup(node->details->uname), node_table);
1309  }
1310 
1311  active_counter = g_hash_table_lookup(node_table, buffer);
1312  if (active_counter == NULL) {
1313  active_counter = calloc(1, sizeof(int));
1314  *active_counter = 0;
1315  g_hash_table_insert(node_table, strdup(buffer), active_counter);
1316  }
1317  (*active_counter)++;
1318  }
1319  }
1320  }
1321 }
1322 
1323 static void
1324 destroy_node_table(gpointer data)
1325 {
1326  GHashTable *node_table = data;
1327 
1328  if (node_table) {
1329  g_hash_table_destroy(node_table);
1330  }
1331 }
1332 
1333 void
1334 print_rscs_brief(GListPtr rsc_list, const char *pre_text, long options,
1335  void *print_data, gboolean print_all)
1336 {
1337  GHashTable *rsc_table = crm_str_table_new();
1338  GHashTable *active_table = g_hash_table_new_full(crm_str_hash, g_str_equal,
1339  free, destroy_node_table);
1340  GHashTableIter hash_iter;
1341  char *type = NULL;
1342  int *rsc_counter = NULL;
1343 
1344  get_rscs_brief(rsc_list, rsc_table, active_table);
1345 
1346  g_hash_table_iter_init(&hash_iter, rsc_table);
1347  while (g_hash_table_iter_next(&hash_iter, (gpointer *)&type, (gpointer *)&rsc_counter)) {
1348  GHashTableIter hash_iter2;
1349  char *node_name = NULL;
1350  GHashTable *node_table = NULL;
1351  int active_counter_all = 0;
1352 
1353  g_hash_table_iter_init(&hash_iter2, active_table);
1354  while (g_hash_table_iter_next(&hash_iter2, (gpointer *)&node_name, (gpointer *)&node_table)) {
1355  int *active_counter = g_hash_table_lookup(node_table, type);
1356 
1357  if (active_counter == NULL || *active_counter == 0) {
1358  continue;
1359 
1360  } else {
1361  active_counter_all += *active_counter;
1362  }
1363 
1364  if (options & pe_print_rsconly) {
1365  node_name = NULL;
1366  }
1367 
1368  if (options & pe_print_html) {
1369  status_print("<li>\n");
1370  }
1371 
1372  if (print_all) {
1373  status_print("%s%d/%d\t(%s):\tActive %s\n", pre_text ? pre_text : "",
1374  active_counter ? *active_counter : 0,
1375  rsc_counter ? *rsc_counter : 0, type,
1376  active_counter && (*active_counter > 0) && node_name ? node_name : "");
1377  } else {
1378  status_print("%s%d\t(%s):\tActive %s\n", pre_text ? pre_text : "",
1379  active_counter ? *active_counter : 0, type,
1380  active_counter && (*active_counter > 0) && node_name ? node_name : "");
1381  }
1382 
1383  if (options & pe_print_html) {
1384  status_print("</li>\n");
1385  }
1386  }
1387 
1388  if (print_all && active_counter_all == 0) {
1389  if (options & pe_print_html) {
1390  status_print("<li>\n");
1391  }
1392 
1393  status_print("%s%d/%d\t(%s):\tActive\n", pre_text ? pre_text : "",
1394  active_counter_all,
1395  rsc_counter ? *rsc_counter : 0, type);
1396 
1397  if (options & pe_print_html) {
1398  status_print("</li>\n");
1399  }
1400  }
1401  }
1402 
1403  if (rsc_table) {
1404  g_hash_table_destroy(rsc_table);
1405  rsc_table = NULL;
1406  }
1407  if (active_table) {
1408  g_hash_table_destroy(active_table);
1409  active_table = NULL;
1410  }
1411 }
1412 
1413 int
1414 pe__rscs_brief_output(pcmk__output_t *out, GListPtr rsc_list, long options, gboolean print_all)
1415 {
1416  GHashTable *rsc_table = crm_str_table_new();
1417  GHashTable *active_table = g_hash_table_new_full(crm_str_hash, g_str_equal,
1418  free, destroy_node_table);
1419  GListPtr sorted_rscs;
1420  int rc = pcmk_rc_no_output;
1421 
1422  get_rscs_brief(rsc_list, rsc_table, active_table);
1423 
1424  /* Make a list of the rsc_table keys so that it can be sorted. This is to make sure
1425  * output order stays consistent between systems.
1426  */
1427  sorted_rscs = g_hash_table_get_keys(rsc_table);
1428  sorted_rscs = g_list_sort(sorted_rscs, (GCompareFunc) strcmp);
1429 
1430  for (GListPtr gIter = sorted_rscs; gIter; gIter = gIter->next) {
1431  char *type = (char *) gIter->data;
1432  int *rsc_counter = g_hash_table_lookup(rsc_table, type);
1433 
1434  GHashTableIter hash_iter2;
1435  char *node_name = NULL;
1436  GHashTable *node_table = NULL;
1437  int active_counter_all = 0;
1438 
1439  g_hash_table_iter_init(&hash_iter2, active_table);
1440  while (g_hash_table_iter_next(&hash_iter2, (gpointer *)&node_name, (gpointer *)&node_table)) {
1441  int *active_counter = g_hash_table_lookup(node_table, type);
1442 
1443  if (active_counter == NULL || *active_counter == 0) {
1444  continue;
1445 
1446  } else {
1447  active_counter_all += *active_counter;
1448  }
1449 
1450  if (options & pe_print_rsconly) {
1451  node_name = NULL;
1452  }
1453 
1454  if (print_all) {
1455  out->list_item(out, NULL, " %d/%d\t(%s):\tActive %s",
1456  *active_counter,
1457  rsc_counter ? *rsc_counter : 0, type,
1458  (*active_counter > 0) && node_name ? node_name : "");
1459  } else {
1460  out->list_item(out, NULL, " %d\t(%s):\tActive %s",
1461  *active_counter, type,
1462  (*active_counter > 0) && node_name ? node_name : "");
1463  }
1464 
1465  rc = pcmk_rc_ok;
1466  }
1467 
1468  if (print_all && active_counter_all == 0) {
1469  out->list_item(out, NULL, " %d/%d\t(%s):\tActive",
1470  active_counter_all,
1471  rsc_counter ? *rsc_counter : 0, type);
1472  rc = pcmk_rc_ok;
1473  }
1474  }
1475 
1476  if (rsc_table) {
1477  g_hash_table_destroy(rsc_table);
1478  rsc_table = NULL;
1479  }
1480  if (active_table) {
1481  g_hash_table_destroy(active_table);
1482  active_table = NULL;
1483  }
1484  if (sorted_rscs) {
1485  g_list_free(sorted_rscs);
1486  }
1487 
1488  return rc;
1489 }
1490 
1491 gboolean
1492 pe__native_is_filtered(pe_resource_t *rsc, GListPtr only_rsc, gboolean check_parent)
1493 {
1494  if (pcmk__str_in_list(only_rsc, rsc_printable_id(rsc)) ||
1495  pcmk__str_in_list(only_rsc, rsc->id)) {
1496  return FALSE;
1497  } else if (check_parent) {
1498  pe_resource_t *up = uber_parent(rsc);
1499 
1500  if (pe_rsc_is_bundled(rsc)) {
1501  return up->parent->fns->is_filtered(up->parent, only_rsc, FALSE);
1502  } else {
1503  return up->fns->is_filtered(up, only_rsc, FALSE);
1504  }
1505  }
1506 
1507  return TRUE;
1508 }
void(* end_list)(pcmk__output_t *out)
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:215
GListPtr nodes
Definition: pe_types.h:148
GHashTable * pe__node_list2table(GList *list)
Definition: utils.c:201
#define CRMD_ACTION_MIGRATED
Definition: crm.h:169
gboolean native_active(pe_resource_t *rsc, gboolean all)
Definition: native.c:361
#define INFINITY
Definition: crm.h:95
pe_resource_t * container
Definition: pe_types.h:367
#define XML_ATTR_TYPE
Definition: msg_xml.h:99
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:809
#define pe_rsc_runnable
Definition: pe_types.h:256
enum rsc_role_e role
Definition: pe_types.h:357
#define XML_BOOLEAN_FALSE
Definition: msg_xml.h:108
gboolean native_unpack(pe_resource_t *rsc, pe_working_set_t *data_set)
Definition: native.c:191
enum rsc_role_e native_resource_state(const pe_resource_t *rsc, gboolean current)
Definition: native.c:1185
xmlNode * xml
Definition: pe_types.h:310
gboolean pcmk__str_in_list(GList *lst, const gchar *s)
Definition: strings.c:794
enum rsc_role_e next_role
Definition: pe_types.h:358
xmlNode * pcmk_create_html_node(xmlNode *parent, const char *element_name, const char *id, const char *class_name, const char *text)
Definition: xml.c:700
pe_resource_t * remote_rsc
Definition: pe_types.h:219
void pe__force_anon(const char *standard, pe_resource_t *rsc, const char *rid, pe_working_set_t *data_set)
Definition: clone.c:23
GHashTable * meta
Definition: pe_types.h:360
match resource not running anywhere
Definition: pe_types.h:87
#define pe_rsc_unique
Definition: pe_types.h:243
resource_object_functions_t * fns
Definition: pe_types.h:319
GHashTable * parameters
Definition: pe_types.h:361
#define CRMD_ACTION_PROMOTE
Definition: crm.h:177
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:717
void print_node(const char *pre_text, pe_node_t *node, gboolean details)
Definition: utils.c:1372
gboolean(* is_filtered)(pe_resource_t *, GListPtr, gboolean)
Definition: pe_types.h:56
#define CRM_LOG_ASSERT(expr)
Definition: logging.h:199
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:1669
int pe__resource_xml(pcmk__output_t *out, va_list args)
Definition: native.c:1052
int pe__resource_text(pcmk__output_t *out, va_list args)
Definition: native.c:1155
#define resource_s
pe_node_t * allocated_to
Definition: pe_types.h:350
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:407
char * pending_task
Definition: pe_types.h:333
void native_add_running(pe_resource_t *rsc, pe_node_t *node, pe_working_set_t *data_set)
Definition: native.c:83
pe_node_t * pe_find_node_id(GListPtr node_list, const char *id)
Definition: status.c:419
#define pe__set_resource_flags(resource, flags_to_set)
Definition: internal.h:47
pe_node_t * lock_node
Definition: pe_types.h:371
#define CRMD_ACTION_START
Definition: crm.h:171
#define pe_rsc_provisional
Definition: pe_types.h:247
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:316
const char * role2text(enum rsc_role_e role)
Definition: common.c:463
pe_node_t *(* location)(const pe_resource_t *, GList **, int)
Definition: pe_types.h:53
#define CRMD_ACTION_STOP
Definition: crm.h:174
#define CRMD_ACTION_DEMOTE
Definition: crm.h:179
int rc
Definition: pcmk_fence.c:35
#define pe_rsc_failed
Definition: pe_types.h:255
#define crm_debug(fmt, args...)
Definition: logging.h:352
pe_resource_t * uber_parent(pe_resource_t *rsc)
Definition: complex.c:799
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
Definition: nvpair.c:523
#define PCMK__OUTPUT_ARGS(ARGS...)
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:398
match only clone instances
Definition: pe_types.h:85
#define crm_trace(fmt, args...)
Definition: logging.h:353
void native_print(pe_resource_t *rsc, const char *pre_text, long options, void *print_data)
Definition: native.c:1030
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
Definition: util.h:196
void native_free(pe_resource_t *rsc)
Definition: native.c:1178
struct pe_node_shared_s * details
Definition: pe_types.h:233
GListPtr running_on
Definition: pe_types.h:353
enum rsc_recovery_type recovery_type
Definition: pe_types.h:322
#define XML_AGENT_ATTR_PROVIDER
Definition: msg_xml.h:237
void common_free(pe_resource_t *rsc)
Definition: complex.c:813
unsigned long long flags
Definition: pe_types.h:335
const char * uname
Definition: pe_types.h:198
#define pe_rsc_promotable
Definition: pe_types.h:245
char * clone_name
Definition: pe_types.h:309
#define XML_ATTR_DESC
Definition: msg_xml.h:95
uint32_t pcmk_get_ra_caps(const char *standard)
Get capabilities of a resource agent standard.
Definition: agents.c:31
pe_node_t * native_location(const pe_resource_t *rsc, GList **list, int current)
Definition: native.c:1207
#define XML_RSC_ATTR_TARGET_ROLE
Definition: msg_xml.h:203
match base name of any clone instance
Definition: pe_types.h:88
enum rsc_role_e text2role(const char *role)
Definition: common.c:484
enum pe_obj_types variant
Definition: pe_types.h:317
void pcmk__output_xml_pop_parent(pcmk__output_t *out)
Definition: output_xml.c:458
const char * id
Definition: pe_types.h:197
void print_rscs_brief(GListPtr rsc_list, const char *pre_text, long options, void *print_data, gboolean print_all)
Definition: native.c:1334
#define XML_RSC_ATTR_UNIQUE
Definition: msg_xml.h:204
match resource ID or LRM history ID
Definition: pe_types.h:83
GListPtr running_rsc
Definition: pe_types.h:220
void get_rsc_attributes(GHashTable *meta_hash, pe_resource_t *rsc, pe_node_t *node, pe_working_set_t *data_set)
Definition: complex.c:147
Cluster status and scheduling.
pe_node_t * pending_node
Definition: pe_types.h:370
pe_resource_t * native_find_rsc(pe_resource_t *rsc, const char *id, const pe_node_t *on_node, int flags)
Definition: native.c:261
GListPtr children
Definition: pe_types.h:364
void add_hash_param(GHashTable *hash, const char *name, const char *value)
Definition: common.c:573
void * variant_opaque
Definition: pe_types.h:318
#define CRM_ASSERT(expr)
Definition: results.h:42
void(*) void(* list_item)(pcmk__output_t *out, const char *name, const char *format,...) G_GNUC_PRINTF(3
const char * rsc_printable_id(pe_resource_t *rsc)
Definition: utils.c:2329
#define status_print(fmt, args...)
This structure contains everything that makes up a single output formatter.
#define CRMD_ACTION_MIGRATE
Definition: crm.h:168
#define crm_str_hash
Definition: util.h:62
void(* begin_list)(pcmk__output_t *out, const char *singular_noun, const char *plural_noun, const char *format,...) G_GNUC_PRINTF(4
#define XML_RSC_ATTR_INTERNAL_RSC
Definition: msg_xml.h:213
char data[0]
Definition: internal.h:90
#define pe__clear_resource_flags(resource, flags_to_clear)
Definition: internal.h:53
rsc_role_e
Definition: common.h:91
#define pe_rsc_block
Definition: pe_types.h:239
gboolean maintenance
Definition: pe_types.h:211
#define pe_rsc_failure_ignored
Definition: pe_types.h:263
gboolean crm_is_true(const char *s)
Definition: strings.c:392
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:876
#define pe_rsc_trace(rsc, fmt, args...)
Definition: internal.h:20
int pe__resource_html(pcmk__output_t *out, va_list args)
Definition: native.c:1131
pe_node_t * pe__find_active_requires(const pe_resource_t *rsc, unsigned int *count)
Definition: complex.c:975
#define ID(x)
Definition: msg_xml.h:425
#define pe_err(fmt...)
Definition: internal.h:22
void pe__output_node(pe_node_t *node, gboolean details, pcmk__output_t *out)
Definition: pe_output.c:1896
char * name
Definition: pcmk_fence.c:31
int pe__rscs_brief_output(pcmk__output_t *out, GListPtr rsc_list, long options, gboolean print_all)
Definition: native.c:1414
pe_resource_t *(* find_rsc)(pe_resource_t *parent, const char *search, const pe_node_t *node, int flags)
Definition: pe_types.h:45
gboolean unclean
Definition: pe_types.h:206
GList * GListPtr
Definition: crm.h:214
#define pe_rsc_managed
Definition: pe_types.h:238
#define pe_rsc_orphan
Definition: pe_types.h:237
gboolean online
Definition: pe_types.h:202
uint64_t flags
Definition: remote.c:149
match resource active on specified node
Definition: pe_types.h:86
gboolean pe__native_is_filtered(pe_resource_t *rsc, GListPtr only_rsc, gboolean check_parent)
Definition: native.c:1492
pe_resource_t * parent
Definition: pe_types.h:315
enum crm_ais_msg_types type
Definition: internal.h:83
gboolean(* active)(pe_resource_t *, gboolean)
Definition: pe_types.h:51
#define pe_rsc_info(rsc, fmt, args...)
Definition: internal.h:18
#define XML_AGENT_ATTR_CLASS
Definition: msg_xml.h:236
char * id
Definition: pe_types.h:308
GHashTable * allowed_nodes
Definition: pe_types.h:355
match base name of anonymous clone instances
Definition: pe_types.h:84
#define CRMD_ACTION_STATUS
Definition: crm.h:185