pacemaker  1.1.18-1a4ef7d180
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 if (strcmp(rsc->id, id) == 0) {
184  match = TRUE;
185 
186  } else if (is_set(flags, pe_find_renamed)
187  && rsc->clone_name && strcmp(rsc->clone_name, id) == 0) {
188  match = TRUE;
189 
190  } else if (is_set(flags, pe_find_anon) && is_not_set(rsc->flags, pe_rsc_unique)) {
191  char *tmp = clone_strip(rsc->id);
192  if(strcmp(tmp, id) == 0) {
193  match = TRUE;
194  }
195  free(tmp);
196  }
197 
198  if (match && on_node) {
199  pe_rsc_trace(rsc, "Now checking %s is on %s", rsc->id, on_node->details->uname);
200  if (is_set(flags, pe_find_current) && rsc->running_on) {
201 
202  GListPtr gIter = rsc->running_on;
203 
204  for (; gIter != NULL; gIter = gIter->next) {
205  node_t *loc = (node_t *) gIter->data;
206 
207  if (loc->details == on_node->details) {
208  return rsc;
209  }
210  }
211 
212  } else if (is_set(flags, pe_find_inactive) && rsc->running_on == NULL) {
213  return rsc;
214 
215  } else if (is_not_set(flags, pe_find_current) && rsc->allocated_to
216  && rsc->allocated_to->details == on_node->details) {
217  return rsc;
218  }
219 
220  } else if (match) {
221  return rsc;
222  }
223 
224  for (; gIter != NULL; gIter = gIter->next) {
225  resource_t *child = (resource_t *) gIter->data;
226 
227  result = rsc->fns->find_rsc(child, id, on_node, flags);
228  if (result) {
229  return result;
230  }
231  }
232  return NULL;
233 }
234 
235 char *
236 native_parameter(resource_t * rsc, node_t * node, gboolean create, const char *name,
237  pe_working_set_t * data_set)
238 {
239  char *value_copy = NULL;
240  const char *value = NULL;
241  GHashTable *hash = rsc->parameters;
242  GHashTable *local_hash = NULL;
243 
244  CRM_CHECK(rsc != NULL, return NULL);
245  CRM_CHECK(name != NULL && strlen(name) != 0, return NULL);
246 
247  pe_rsc_trace(rsc, "Looking up %s in %s", name, rsc->id);
248 
249  if (create || g_hash_table_size(rsc->parameters) == 0) {
250  if (node != NULL) {
251  pe_rsc_trace(rsc, "Creating hash with node %s", node->details->uname);
252  } else {
253  pe_rsc_trace(rsc, "Creating default hash");
254  }
255 
256  local_hash = crm_str_table_new();
257 
258  get_rsc_attributes(local_hash, rsc, node, data_set);
259 
260  hash = local_hash;
261  }
262 
263  value = g_hash_table_lookup(hash, name);
264  if (value == NULL) {
265  /* try meta attributes instead */
266  value = g_hash_table_lookup(rsc->meta, name);
267  }
268 
269  if (value != NULL) {
270  value_copy = strdup(value);
271  }
272  if (local_hash != NULL) {
273  g_hash_table_destroy(local_hash);
274  }
275  return value_copy;
276 }
277 
278 gboolean
279 native_active(resource_t * rsc, gboolean all)
280 {
281  GListPtr gIter = rsc->running_on;
282 
283  for (; gIter != NULL; gIter = gIter->next) {
284  node_t *a_node = (node_t *) gIter->data;
285 
286  if (a_node->details->unclean) {
287  crm_debug("Resource %s: node %s is unclean", rsc->id, a_node->details->uname);
288  return TRUE;
289  } else if (a_node->details->online == FALSE) {
290  crm_debug("Resource %s: node %s is offline", rsc->id, a_node->details->uname);
291  } else {
292  crm_debug("Resource %s active on %s", rsc->id, a_node->details->uname);
293  return TRUE;
294  }
295  }
296 
297  return FALSE;
298 }
299 
300 struct print_data_s {
301  long options;
302  void *print_data;
303 };
304 
305 static void
306 native_print_attr(gpointer key, gpointer value, gpointer user_data)
307 {
308  long options = ((struct print_data_s *)user_data)->options;
309  void *print_data = ((struct print_data_s *)user_data)->print_data;
310 
311  status_print("Option: %s = %s\n", (char *)key, (char *)value);
312 }
313 
314 static const char *
315 native_pending_state(resource_t * rsc)
316 {
317  const char *pending_state = NULL;
318 
320  pending_state = "Starting";
321 
322  } else if (safe_str_eq(rsc->pending_task, CRMD_ACTION_STOP)) {
323  pending_state = "Stopping";
324 
325  } else if (safe_str_eq(rsc->pending_task, CRMD_ACTION_MIGRATE)) {
326  pending_state = "Migrating";
327 
328  } else if (safe_str_eq(rsc->pending_task, CRMD_ACTION_MIGRATED)) {
329  /* Work might be done in here. */
330  pending_state = "Migrating";
331 
332  } else if (safe_str_eq(rsc->pending_task, CRMD_ACTION_PROMOTE)) {
333  pending_state = "Promoting";
334 
335  } else if (safe_str_eq(rsc->pending_task, CRMD_ACTION_DEMOTE)) {
336  pending_state = "Demoting";
337  }
338 
339  return pending_state;
340 }
341 
342 static const char *
343 native_pending_task(resource_t * rsc)
344 {
345  const char *pending_task = NULL;
346 
348  /* "Notifying" is not very useful to be shown. */
349  pending_task = NULL;
350 
351  } else if (safe_str_eq(rsc->pending_task, CRMD_ACTION_STATUS)) {
352  pending_task = "Monitoring";
353 
354  /* Pending probes are not printed, even if pending
355  * operations are requested. If someone ever requests that
356  * behavior, uncomment this and the corresponding part of
357  * unpack.c:unpack_rsc_op().
358  */
359  /*
360  } else if (safe_str_eq(rsc->pending_task, "probe")) {
361  pending_task = "Checking";
362  */
363  }
364 
365  return pending_task;
366 }
367 
368 static enum rsc_role_e
369 native_displayable_role(resource_t *rsc)
370 {
371  enum rsc_role_e role = rsc->role;
372 
373  if ((role == RSC_ROLE_STARTED)
374  && (uber_parent(rsc)->variant == pe_master)) {
375 
376  role = RSC_ROLE_SLAVE;
377  }
378  return role;
379 }
380 
381 static const char *
382 native_displayable_state(resource_t *rsc, long options)
383 {
384  const char *rsc_state = NULL;
385 
386  if (options & pe_print_pending) {
387  rsc_state = native_pending_state(rsc);
388  }
389  if (rsc_state == NULL) {
390  rsc_state = role2text(native_displayable_role(rsc));
391  }
392  return rsc_state;
393 }
394 
395 static void
396 native_print_xml(resource_t * rsc, const char *pre_text, long options, void *print_data)
397 {
398  const char *class = crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS);
399  const char *prov = crm_element_value(rsc->xml, XML_AGENT_ATTR_PROVIDER);
400  const char *rsc_state = native_displayable_state(rsc, options);
401  const char *target_role = NULL;
402 
403  /* resource information. */
404  status_print("%s<resource ", pre_text);
405  status_print("id=\"%s\" ", rsc_printable_id(rsc));
406  status_print("resource_agent=\"%s%s%s:%s\" ",
407  class,
408  prov ? "::" : "", prov ? prov : "", crm_element_value(rsc->xml, XML_ATTR_TYPE));
409 
410  status_print("role=\"%s\" ", rsc_state);
411  if (rsc->meta) {
412  target_role = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_TARGET_ROLE);
413  }
414  if (target_role) {
415  status_print("target_role=\"%s\" ", target_role);
416  }
417  status_print("active=\"%s\" ", rsc->fns->active(rsc, TRUE) ? "true" : "false");
418  status_print("orphaned=\"%s\" ", is_set(rsc->flags, pe_rsc_orphan) ? "true" : "false");
419  status_print("blocked=\"%s\" ", is_set(rsc->flags, pe_rsc_block) ? "true" : "false");
420  status_print("managed=\"%s\" ", is_set(rsc->flags, pe_rsc_managed) ? "true" : "false");
421  status_print("failed=\"%s\" ", is_set(rsc->flags, pe_rsc_failed) ? "true" : "false");
422  status_print("failure_ignored=\"%s\" ",
423  is_set(rsc->flags, pe_rsc_failure_ignored) ? "true" : "false");
424  status_print("nodes_running_on=\"%d\" ", g_list_length(rsc->running_on));
425 
426  if (options & pe_print_pending) {
427  const char *pending_task = native_pending_task(rsc);
428 
429  if (pending_task) {
430  status_print("pending=\"%s\" ", pending_task);
431  }
432  }
433 
434  if (options & pe_print_dev) {
435  status_print("provisional=\"%s\" ",
436  is_set(rsc->flags, pe_rsc_provisional) ? "true" : "false");
437  status_print("runnable=\"%s\" ", is_set(rsc->flags, pe_rsc_runnable) ? "true" : "false");
438  status_print("priority=\"%f\" ", (double)rsc->priority);
439  status_print("variant=\"%s\" ", crm_element_name(rsc->xml));
440  }
441 
442  /* print out the nodes this resource is running on */
443  if (options & pe_print_rsconly) {
444  status_print("/>\n");
445  /* do nothing */
446  } else if (g_list_length(rsc->running_on) > 0) {
447  GListPtr gIter = rsc->running_on;
448 
449  status_print(">\n");
450  for (; gIter != NULL; gIter = gIter->next) {
451  node_t *node = (node_t *) gIter->data;
452 
453  status_print("%s <node name=\"%s\" id=\"%s\" cached=\"%s\"/>\n", pre_text,
454  node->details->uname, node->details->id,
455  node->details->online ? "false" : "true");
456  }
457  status_print("%s</resource>\n", pre_text);
458  } else {
459  status_print("/>\n");
460  }
461 }
462 
463 /* making this inline rather than a macro prevents a coverity "unreachable"
464  * warning on the first usage
465  */
466 static inline const char *
467 comma_if(int i)
468 {
469  return i? ", " : "";
470 }
471 
472 void
473 common_print(resource_t * rsc, const char *pre_text, const char *name, node_t *node, long options, void *print_data)
474 {
475  const char *desc = NULL;
476  const char *class = crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS);
477  const char *kind = crm_element_value(rsc->xml, XML_ATTR_TYPE);
478  const char *target_role = NULL;
479  enum rsc_role_e role = native_displayable_role(rsc);
480 
481  int offset = 0;
482  int flagOffset = 0;
483  char buffer[LINE_MAX];
484  char flagBuffer[LINE_MAX];
485 
486  CRM_ASSERT(rsc->variant == pe_native);
487  CRM_ASSERT(kind != NULL);
488 
489  if (rsc->meta) {
490  const char *is_internal = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_INTERNAL_RSC);
491  if (crm_is_true(is_internal) && is_not_set(options, pe_print_clone_details)) {
492  crm_trace("skipping print of internal resource %s", rsc->id);
493  return;
494  }
495  target_role = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_TARGET_ROLE);
496  }
497 
498  if (pre_text == NULL && (options & pe_print_printf)) {
499  pre_text = " ";
500  }
501 
502  if (options & pe_print_xml) {
503  native_print_xml(rsc, pre_text, options, print_data);
504  return;
505  }
506 
507  if ((options & pe_print_rsconly) || g_list_length(rsc->running_on) > 1) {
508  node = NULL;
509  }
510 
511  if (options & pe_print_html) {
512  if (is_not_set(rsc->flags, pe_rsc_managed)) {
513  status_print("<font color=\"yellow\">");
514 
515  } else if (is_set(rsc->flags, pe_rsc_failed)) {
516  status_print("<font color=\"red\">");
517 
518  } else if (rsc->variant == pe_native && g_list_length(rsc->running_on) == 0) {
519  status_print("<font color=\"red\">");
520 
521  } else if (g_list_length(rsc->running_on) > 1) {
522  status_print("<font color=\"orange\">");
523 
524  } else if (is_set(rsc->flags, pe_rsc_failure_ignored)) {
525  status_print("<font color=\"yellow\">");
526 
527  } else {
528  status_print("<font color=\"green\">");
529  }
530  }
531 
532  if(pre_text) {
533  offset += snprintf(buffer + offset, LINE_MAX - offset, "%s", pre_text);
534  }
535  offset += snprintf(buffer + offset, LINE_MAX - offset, "%s", name);
536  offset += snprintf(buffer + offset, LINE_MAX - offset, "\t(%s", class);
537  if (crm_provider_required(class)) {
538  const char *prov = crm_element_value(rsc->xml, XML_AGENT_ATTR_PROVIDER);
539  offset += snprintf(buffer + offset, LINE_MAX - offset, "::%s", prov);
540  }
541  offset += snprintf(buffer + offset, LINE_MAX - offset, ":%s):\t", kind);
542  if(is_set(rsc->flags, pe_rsc_orphan)) {
543  offset += snprintf(buffer + offset, LINE_MAX - offset, " ORPHANED ");
544  }
545  if(role > RSC_ROLE_SLAVE && is_set(rsc->flags, pe_rsc_failed)) {
546  offset += snprintf(buffer + offset, LINE_MAX - offset, "FAILED %s", role2text(role));
547  } else if(is_set(rsc->flags, pe_rsc_failed)) {
548  offset += snprintf(buffer + offset, LINE_MAX - offset, "FAILED");
549  } else {
550  const char *rsc_state = native_displayable_state(rsc, options);
551 
552  offset += snprintf(buffer + offset, LINE_MAX - offset, "%s", rsc_state);
553  }
554 
555  if(node) {
556  offset += snprintf(buffer + offset, LINE_MAX - offset, " %s", node->details->uname);
557 
558  if (node->details->online == FALSE && node->details->unclean) {
559  flagOffset += snprintf(flagBuffer + flagOffset, LINE_MAX - flagOffset,
560  "%sUNCLEAN", comma_if(flagOffset));
561  }
562  }
563 
564  if (options & pe_print_pending) {
565  const char *pending_task = native_pending_task(rsc);
566 
567  if (pending_task) {
568  flagOffset += snprintf(flagBuffer + flagOffset, LINE_MAX - flagOffset,
569  "%s%s", comma_if(flagOffset), pending_task);
570  }
571  }
572 
573  if (target_role) {
574  enum rsc_role_e target_role_e = text2role(target_role);
575 
576  /* Ignore target role Started, as it is the default anyways
577  * (and would also allow a Master to be Master).
578  * Show if target role limits our abilities. */
579  if (target_role_e == RSC_ROLE_STOPPED) {
580  flagOffset += snprintf(flagBuffer + flagOffset, LINE_MAX - flagOffset,
581  "%sdisabled", comma_if(flagOffset));
582  rsc->cluster->disabled_resources++;
583 
584  } else if (uber_parent(rsc)->variant == pe_master
585  && target_role_e == RSC_ROLE_SLAVE) {
586  flagOffset += snprintf(flagBuffer + flagOffset, LINE_MAX - flagOffset,
587  "%starget-role:%s", comma_if(flagOffset), target_role);
588  rsc->cluster->disabled_resources++;
589  }
590  }
591 
592  if (is_set(rsc->flags, pe_rsc_block)) {
593  flagOffset += snprintf(flagBuffer + flagOffset, LINE_MAX - flagOffset,
594  "%sblocked", comma_if(flagOffset));
595  rsc->cluster->blocked_resources++;
596 
597  } else if (is_not_set(rsc->flags, pe_rsc_managed)) {
598  flagOffset += snprintf(flagBuffer + flagOffset, LINE_MAX - flagOffset,
599  "%sunmanaged", comma_if(flagOffset));
600  }
601 
602  if(is_set(rsc->flags, pe_rsc_failure_ignored)) {
603  flagOffset += snprintf(flagBuffer + flagOffset, LINE_MAX - flagOffset,
604  "%sfailure ignored", comma_if(flagOffset));
605  }
606 
607  if ((options & pe_print_rsconly) || g_list_length(rsc->running_on) > 1) {
608  desc = crm_element_value(rsc->xml, XML_ATTR_DESC);
609  }
610 
611  CRM_LOG_ASSERT(offset > 0);
612  if(flagOffset > 0) {
613  status_print("%s (%s)%s%s", buffer, flagBuffer, desc?" ":"", desc?desc:"");
614  } else {
615  status_print("%s%s%s", buffer, desc?" ":"", desc?desc:"");
616  }
617 
618 #if CURSES_ENABLED
619  if ((options & pe_print_rsconly) || g_list_length(rsc->running_on) > 1) {
620  /* Done */
621 
622  } else if (options & pe_print_ncurses) {
623  /* coverity[negative_returns] False positive */
624  move(-1, 0);
625  }
626 #endif
627 
628  if (options & pe_print_html) {
629  status_print(" </font> ");
630  }
631 
632  if ((options & pe_print_rsconly)) {
633 
634  } else if (g_list_length(rsc->running_on) > 1) {
635  GListPtr gIter = rsc->running_on;
636  int counter = 0;
637 
638  if (options & pe_print_html) {
639  status_print("<ul>\n");
640  } else if ((options & pe_print_printf)
641  || (options & pe_print_ncurses)) {
642  status_print("[");
643  }
644 
645  for (; gIter != NULL; gIter = gIter->next) {
646  node_t *node = (node_t *) gIter->data;
647 
648  counter++;
649 
650  if (options & pe_print_html) {
651  status_print("<li>\n%s", node->details->uname);
652 
653  } else if ((options & pe_print_printf)
654  || (options & pe_print_ncurses)) {
655  status_print(" %s", node->details->uname);
656 
657  } else if ((options & pe_print_log)) {
658  status_print("\t%d : %s", counter, node->details->uname);
659 
660  } else {
661  status_print("%s", node->details->uname);
662  }
663  if (options & pe_print_html) {
664  status_print("</li>\n");
665 
666  }
667  }
668 
669  if (options & pe_print_html) {
670  status_print("</ul>\n");
671  } else if ((options & pe_print_printf)
672  || (options & pe_print_ncurses)) {
673  status_print(" ]");
674  }
675  }
676 
677  if (options & pe_print_html) {
678  status_print("<br/>\n");
679  } else if (options & pe_print_suppres_nl) {
680  /* nothing */
681  } else if ((options & pe_print_printf) || (options & pe_print_ncurses)) {
682  status_print("\n");
683  }
684 
685  if (options & pe_print_details) {
686  struct print_data_s pdata;
687 
688  pdata.options = options;
689  pdata.print_data = print_data;
690  g_hash_table_foreach(rsc->parameters, native_print_attr, &pdata);
691  }
692 
693  if (options & pe_print_dev) {
694  GHashTableIter iter;
695  node_t *node = NULL;
696 
697  status_print("%s\t(%s%svariant=%s, priority=%f)", pre_text,
698  is_set(rsc->flags, pe_rsc_provisional) ? "provisional, " : "",
699  is_set(rsc->flags, pe_rsc_runnable) ? "" : "non-startable, ",
700  crm_element_name(rsc->xml), (double)rsc->priority);
701  status_print("%s\tAllowed Nodes", pre_text);
702  g_hash_table_iter_init(&iter, rsc->allowed_nodes);
703  while (g_hash_table_iter_next(&iter, NULL, (void **)&node)) {
704  status_print("%s\t * %s %d", pre_text, node->details->uname, node->weight);
705  }
706  }
707 
708  if (options & pe_print_max_details) {
709  GHashTableIter iter;
710  node_t *node = NULL;
711 
712  status_print("%s\t=== Allowed Nodes\n", pre_text);
713  g_hash_table_iter_init(&iter, rsc->allowed_nodes);
714  while (g_hash_table_iter_next(&iter, NULL, (void **)&node)) {
715  print_node("\t", node, FALSE);
716  }
717  }
718 }
719 
720 void
721 native_print(resource_t * rsc, const char *pre_text, long options, void *print_data)
722 {
723  node_t *node = NULL;
724 
725  CRM_ASSERT(rsc->variant == pe_native);
726  if (options & pe_print_xml) {
727  native_print_xml(rsc, pre_text, options, print_data);
728  return;
729  }
730 
731  if (rsc->running_on != NULL) {
732  node = rsc->running_on->data;
733  }
734  common_print(rsc, pre_text, rsc_printable_id(rsc), node, options, print_data);
735 }
736 
737 void
739 {
740  pe_rsc_trace(rsc, "Freeing resource action list (not the data)");
741  common_free(rsc);
742 }
743 
744 enum rsc_role_e
745 native_resource_state(const resource_t * rsc, gboolean current)
746 {
747  enum rsc_role_e role = rsc->next_role;
748 
749  if (current) {
750  role = rsc->role;
751  }
752  pe_rsc_trace(rsc, "%s state: %s", rsc->id, role2text(role));
753  return role;
754 }
755 
756 node_t *
757 native_location(resource_t * rsc, GListPtr * list, gboolean current)
758 {
759  node_t *one = NULL;
760  GListPtr result = NULL;
761 
762  if (rsc->children) {
763  GListPtr gIter = rsc->children;
764 
765  for (; gIter != NULL; gIter = gIter->next) {
766  resource_t *child = (resource_t *) gIter->data;
767 
768  child->fns->location(child, &result, current);
769  }
770 
771  } else if (current && rsc->running_on) {
772  result = g_list_copy(rsc->running_on);
773 
774  } else if (current == FALSE && rsc->allocated_to) {
775  result = g_list_append(NULL, rsc->allocated_to);
776  }
777 
778  if (result && g_list_length(result) == 1) {
779  one = g_list_nth_data(result, 0);
780  }
781 
782  if (list) {
783  GListPtr gIter = result;
784 
785  for (; gIter != NULL; gIter = gIter->next) {
786  node_t *node = (node_t *) gIter->data;
787 
788  if (*list == NULL || pe_find_node_id(*list, node->details->id) == NULL) {
789  *list = g_list_append(*list, node);
790  }
791  }
792  }
793 
794  g_list_free(result);
795  return one;
796 }
797 
798 static void
799 get_rscs_brief(GListPtr rsc_list, GHashTable * rsc_table, GHashTable * active_table)
800 {
801  GListPtr gIter = rsc_list;
802 
803  for (; gIter != NULL; gIter = gIter->next) {
804  resource_t *rsc = (resource_t *) gIter->data;
805 
806  const char *class = crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS);
807  const char *kind = crm_element_value(rsc->xml, XML_ATTR_TYPE);
808 
809  int offset = 0;
810  char buffer[LINE_MAX];
811 
812  int *rsc_counter = NULL;
813  int *active_counter = NULL;
814 
815  if (rsc->variant != pe_native) {
816  continue;
817  }
818 
819  offset += snprintf(buffer + offset, LINE_MAX - offset, "%s", class);
820  if (crm_provider_required(class)) {
821  const char *prov = crm_element_value(rsc->xml, XML_AGENT_ATTR_PROVIDER);
822  offset += snprintf(buffer + offset, LINE_MAX - offset, "::%s", prov);
823  }
824  offset += snprintf(buffer + offset, LINE_MAX - offset, ":%s", kind);
825  CRM_LOG_ASSERT(offset > 0);
826 
827  if (rsc_table) {
828  rsc_counter = g_hash_table_lookup(rsc_table, buffer);
829  if (rsc_counter == NULL) {
830  rsc_counter = calloc(1, sizeof(int));
831  *rsc_counter = 0;
832  g_hash_table_insert(rsc_table, strdup(buffer), rsc_counter);
833  }
834  (*rsc_counter)++;
835  }
836 
837  if (active_table) {
838  GListPtr gIter2 = rsc->running_on;
839 
840  for (; gIter2 != NULL; gIter2 = gIter2->next) {
841  node_t *node = (node_t *) gIter2->data;
842  GHashTable *node_table = NULL;
843 
844  if (node->details->unclean == FALSE && node->details->online == FALSE) {
845  continue;
846  }
847 
848  node_table = g_hash_table_lookup(active_table, node->details->uname);
849  if (node_table == NULL) {
850  node_table = crm_str_table_new();
851  g_hash_table_insert(active_table, strdup(node->details->uname), node_table);
852  }
853 
854  active_counter = g_hash_table_lookup(node_table, buffer);
855  if (active_counter == NULL) {
856  active_counter = calloc(1, sizeof(int));
857  *active_counter = 0;
858  g_hash_table_insert(node_table, strdup(buffer), active_counter);
859  }
860  (*active_counter)++;
861  }
862  }
863  }
864 }
865 
866 static void
867 destroy_node_table(gpointer data)
868 {
869  GHashTable *node_table = data;
870 
871  if (node_table) {
872  g_hash_table_destroy(node_table);
873  }
874 }
875 
876 void
877 print_rscs_brief(GListPtr rsc_list, const char *pre_text, long options,
878  void *print_data, gboolean print_all)
879 {
880  GHashTable *rsc_table = crm_str_table_new();
881  GHashTable *active_table = g_hash_table_new_full(crm_str_hash, g_str_equal,
882  free, destroy_node_table);
883  GHashTableIter hash_iter;
884  char *type = NULL;
885  int *rsc_counter = NULL;
886 
887  get_rscs_brief(rsc_list, rsc_table, active_table);
888 
889  g_hash_table_iter_init(&hash_iter, rsc_table);
890  while (g_hash_table_iter_next(&hash_iter, (gpointer *)&type, (gpointer *)&rsc_counter)) {
891  GHashTableIter hash_iter2;
892  char *node_name = NULL;
893  GHashTable *node_table = NULL;
894  int active_counter_all = 0;
895 
896  g_hash_table_iter_init(&hash_iter2, active_table);
897  while (g_hash_table_iter_next(&hash_iter2, (gpointer *)&node_name, (gpointer *)&node_table)) {
898  int *active_counter = g_hash_table_lookup(node_table, type);
899 
900  if (active_counter == NULL || *active_counter == 0) {
901  continue;
902 
903  } else {
904  active_counter_all += *active_counter;
905  }
906 
907  if (options & pe_print_rsconly) {
908  node_name = NULL;
909  }
910 
911  if (options & pe_print_html) {
912  status_print("<li>\n");
913  }
914 
915  if (print_all) {
916  status_print("%s%d/%d\t(%s):\tActive %s\n", pre_text ? pre_text : "",
917  active_counter ? *active_counter : 0,
918  rsc_counter ? *rsc_counter : 0, type,
919  active_counter && (*active_counter > 0) && node_name ? node_name : "");
920  } else {
921  status_print("%s%d\t(%s):\tActive %s\n", pre_text ? pre_text : "",
922  active_counter ? *active_counter : 0, type,
923  active_counter && (*active_counter > 0) && node_name ? node_name : "");
924  }
925 
926  if (options & pe_print_html) {
927  status_print("</li>\n");
928  }
929  }
930 
931  if (print_all && active_counter_all == 0) {
932  if (options & pe_print_html) {
933  status_print("<li>\n");
934  }
935 
936  status_print("%s%d/%d\t(%s):\tActive\n", pre_text ? pre_text : "",
937  active_counter_all,
938  rsc_counter ? *rsc_counter : 0, type);
939 
940  if (options & pe_print_html) {
941  status_print("</li>\n");
942  }
943  }
944  }
945 
946  if (rsc_table) {
947  g_hash_table_destroy(rsc_table);
948  rsc_table = NULL;
949  }
950  if (active_table) {
951  g_hash_table_destroy(active_table);
952  active_table = NULL;
953  }
954 }
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:164
GListPtr nodes
Definition: status.h:106
const char * uname
Definition: status.h:138
#define CRMD_ACTION_MIGRATED
Definition: crm.h:173
xmlNode * xml
Definition: status.h:258
#define INFINITY
Definition: crm.h:83
void native_print(resource_t *rsc, const char *pre_text, long options, void *print_data)
Definition: native.c:721
char * native_parameter(resource_t *rsc, node_t *node, gboolean create, const char *name, pe_working_set_t *data_set)
Definition: native.c:236
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:137
#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:473
#define pe_rsc_orphan
Definition: status.h:183
enum rsc_role_e native_resource_state(const resource_t *rsc, gboolean current)
Definition: native.c:745
#define CRMD_ACTION_NOTIFY
Definition: crm.h:186
#define pe_rsc_provisional
Definition: status.h:192
GListPtr running_rsc
Definition: status.h:152
enum pe_obj_types variant
Definition: status.h:264
void common_free(resource_t *rsc)
Definition: complex.c:911
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:181
void get_rsc_attributes(GHashTable *meta_hash, resource_t *rsc, node_t *node, pe_working_set_t *data_set)
Definition: complex.c:174
void print_node(const char *pre_text, node_t *node, gboolean details)
Definition: utils.c:1240
#define CRM_LOG_ASSERT(expr)
Definition: logging.h:150
char * clone_name
Definition: status.h:257
resource_t * uber_parent(resource_t *rsc)
Definition: complex.c:897
#define clear_bit(word, bit)
Definition: crm_internal.h:191
enum rsc_role_e role
Definition: status.h:293
GListPtr children
Definition: status.h:300
char * id
Definition: status.h:256
GHashTable * parameters
Definition: status.h:297
#define CRMD_ACTION_START
Definition: crm.h:175
#define pe_rsc_block
Definition: status.h:185
gboolean native_active(resource_t *rsc, gboolean all)
Definition: native.c:279
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:48
#define CRMD_ACTION_STOP
Definition: crm.h:178
struct node_shared_s * details
Definition: status.h:177
#define CRMD_ACTION_DEMOTE
Definition: crm.h:183
#define set_bit(word, bit)
Definition: crm_internal.h:190
#define PCMK_RESOURCE_CLASS_OCF
Definition: services.h:57
gboolean unclean
Definition: status.h:145
#define crm_debug(fmt, args...)
Definition: logging.h:253
char * pending_task
Definition: status.h:309
enum rsc_recovery_type recovery_type
Definition: status.h:268
#define XML_BOOLEAN_TRUE
Definition: msg_xml.h:117
#define pe_rsc_failed
Definition: status.h:201
char * clone_strip(const char *last_rsc_id)
Definition: unpack.c:1561
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:265
GHashTable * allowed_nodes
Definition: status.h:291
#define crm_trace(fmt, args...)
Definition: logging.h:254
#define XML_AGENT_ATTR_PROVIDER
Definition: msg_xml.h:254
#define pe_rsc_runnable
Definition: status.h:203
const char * crm_element_value(xmlNode *data, const char *name)
Definition: xml.c:5165
#define XML_ATTR_DESC
Definition: msg_xml.h:101
unsigned long long flags
Definition: status.h:280
resource_t * parent
Definition: status.h:262
#define XML_RSC_ATTR_TARGET_ROLE
Definition: msg_xml.h:219
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:877
node_t * native_location(resource_t *rsc, GListPtr *list, gboolean current)
Definition: native.c:757
gboolean maintenance
Definition: status.h:165
#define pe_rsc_unique
Definition: status.h:189
GHashTable * node_hash_from_list(GListPtr list)
Definition: utils.c:183
GHashTable * meta
Definition: status.h:296
#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:1516
enum rsc_role_e next_role
Definition: status.h:294
gboolean online
Definition: status.h:141
#define pe_rsc_failure_ignored
Definition: status.h:211
#define pe_rsc_managed
Definition: status.h:184
#define CRMD_ACTION_MIGRATE
Definition: crm.h:172
#define crm_str_hash
Definition: util.h:73
#define XML_RSC_ATTR_INTERNAL_RSC
Definition: msg_xml.h:230
#define CRM_ASSERT(expr)
Definition: error.h:35
char data[0]
Definition: internal.h:58
node_t * allocated_to
Definition: status.h:288
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:173
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:25
#define ID(x)
Definition: msg_xml.h:446
#define pe_err(fmt...)
Definition: internal.h:27
#define safe_str_eq(a, b)
Definition: util.h:72
GList * GListPtr
Definition: crm.h:218
void native_free(resource_t *rsc)
Definition: native.c:738
const char * rsc_printable_id(resource_t *rsc)
Definition: utils.c:2082
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:253
#define CRMD_ACTION_STATUS
Definition: crm.h:189
GListPtr running_on
Definition: status.h:289