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