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