pacemaker  1.1.16-94ff4df
Scalable High-Availability cluster resource manager
utils.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 #include <crm_internal.h>
19 #include <crm/crm.h>
20 #include <crm/msg_xml.h>
21 #include <crm/common/xml.h>
22 #include <crm/common/util.h>
23 
24 #include <glib.h>
25 
26 #include <crm/pengine/rules.h>
27 #include <crm/pengine/internal.h>
28 
30 
31 extern xmlNode *get_object_root(const char *object_type, xmlNode * the_root);
32 void print_str_str(gpointer key, gpointer value, gpointer user_data);
33 gboolean ghash_free_str_str(gpointer key, gpointer value, gpointer user_data);
34 void unpack_operation(action_t * action, xmlNode * xml_obj, resource_t * container,
35  pe_working_set_t * data_set);
36 static xmlNode *find_rsc_op_entry_helper(resource_t * rsc, const char *key,
37  gboolean include_disabled);
38 
39 bool pe_can_fence(pe_working_set_t * data_set, node_t *node)
40 {
41  if(is_not_set(data_set->flags, pe_flag_stonith_enabled)) {
42  return FALSE; /* Turned off */
43 
44  } else if (is_not_set(data_set->flags, pe_flag_have_stonith_resource)) {
45  return FALSE; /* No devices */
46 
47  } else if (is_set(data_set->flags, pe_flag_have_quorum)) {
48  return TRUE;
49 
50  } else if (data_set->no_quorum_policy == no_quorum_ignore) {
51  return TRUE;
52 
53  } else if(node == NULL) {
54  return FALSE;
55 
56  } else if(node->details->online) {
57  crm_notice("We can fence %s without quorum because they're in our membership", node->details->uname);
58  return TRUE;
59  }
60 
61  crm_trace("Cannot fence %s", node->details->uname);
62  return FALSE;
63 }
64 
65 node_t *
66 node_copy(const node_t *this_node)
67 {
68  node_t *new_node = NULL;
69 
70  CRM_CHECK(this_node != NULL, return NULL);
71 
72  new_node = calloc(1, sizeof(node_t));
73  CRM_ASSERT(new_node != NULL);
74 
75  crm_trace("Copying %p (%s) to %p", this_node, this_node->details->uname, new_node);
76 
77  new_node->rsc_discover_mode = this_node->rsc_discover_mode;
78  new_node->weight = this_node->weight;
79  new_node->fixed = this_node->fixed;
80  new_node->details = this_node->details;
81 
82  return new_node;
83 }
84 
85 /* any node in list1 or list2 and not in the other gets a score of -INFINITY */
86 void
87 node_list_exclude(GHashTable * hash, GListPtr list, gboolean merge_scores)
88 {
89  GHashTable *result = hash;
90  node_t *other_node = NULL;
91  GListPtr gIter = list;
92 
93  GHashTableIter iter;
94  node_t *node = NULL;
95 
96  g_hash_table_iter_init(&iter, hash);
97  while (g_hash_table_iter_next(&iter, NULL, (void **)&node)) {
98 
99  other_node = pe_find_node_id(list, node->details->id);
100  if (other_node == NULL) {
101  node->weight = -INFINITY;
102  } else if (merge_scores) {
103  node->weight = merge_weights(node->weight, other_node->weight);
104  }
105  }
106 
107  for (; gIter != NULL; gIter = gIter->next) {
108  node_t *node = (node_t *) gIter->data;
109 
110  other_node = pe_hash_table_lookup(result, node->details->id);
111 
112  if (other_node == NULL) {
113  node_t *new_node = node_copy(node);
114 
115  new_node->weight = -INFINITY;
116  g_hash_table_insert(result, (gpointer) new_node->details->id, new_node);
117  }
118  }
119 }
120 
121 GHashTable *
123 {
124  GListPtr gIter = list;
125  GHashTable *result = g_hash_table_new_full(crm_str_hash, g_str_equal, NULL, g_hash_destroy_str);
126 
127  for (; gIter != NULL; gIter = gIter->next) {
128  node_t *node = (node_t *) gIter->data;
129  node_t *n = node_copy(node);
130 
131  g_hash_table_insert(result, (gpointer) n->details->id, n);
132  }
133 
134  return result;
135 }
136 
137 GListPtr
138 node_list_dup(GListPtr list1, gboolean reset, gboolean filter)
139 {
140  GListPtr result = NULL;
141  GListPtr gIter = list1;
142 
143  for (; gIter != NULL; gIter = gIter->next) {
144  node_t *new_node = NULL;
145  node_t *this_node = (node_t *) gIter->data;
146 
147  if (filter && this_node->weight < 0) {
148  continue;
149  }
150 
151  new_node = node_copy(this_node);
152  if (reset) {
153  new_node->weight = 0;
154  }
155  if (new_node != NULL) {
156  result = g_list_prepend(result, new_node);
157  }
158  }
159 
160  return result;
161 }
162 
163 gint
164 sort_node_uname(gconstpointer a, gconstpointer b)
165 {
166  const node_t *node_a = a;
167  const node_t *node_b = b;
168 
169  return strcmp(node_a->details->uname, node_b->details->uname);
170 }
171 
172 void
173 dump_node_scores_worker(int level, const char *file, const char *function, int line,
174  resource_t * rsc, const char *comment, GHashTable * nodes)
175 {
176  GHashTable *hash = nodes;
177  GHashTableIter iter;
178  node_t *node = NULL;
179 
180  if (rsc) {
181  hash = rsc->allowed_nodes;
182  }
183 
184  if (rsc && is_set(rsc->flags, pe_rsc_orphan)) {
185  /* Don't show the allocation scores for orphans */
186  return;
187  }
188 
189  if (level == 0) {
190  char score[128];
191  int len = sizeof(score);
192  /* For now we want this in sorted order to keep the regression tests happy */
193  GListPtr gIter = NULL;
194  GListPtr list = g_hash_table_get_values(hash);
195 
196  list = g_list_sort(list, sort_node_uname);
197 
198  gIter = list;
199  for (; gIter != NULL; gIter = gIter->next) {
200  node_t *node = (node_t *) gIter->data;
201  /* This function is called a whole lot, use stack allocated score */
202  score2char_stack(node->weight, score, len);
203 
204  if (rsc) {
205  printf("%s: %s allocation score on %s: %s\n",
206  comment, rsc->id, node->details->uname, score);
207  } else {
208  printf("%s: %s = %s\n", comment, node->details->uname, score);
209  }
210  }
211 
212  g_list_free(list);
213 
214  } else if (hash) {
215  char score[128];
216  int len = sizeof(score);
217  g_hash_table_iter_init(&iter, hash);
218  while (g_hash_table_iter_next(&iter, NULL, (void **)&node)) {
219  /* This function is called a whole lot, use stack allocated score */
220  score2char_stack(node->weight, score, len);
221 
222  if (rsc) {
223  do_crm_log_alias(LOG_TRACE, file, function, line,
224  "%s: %s allocation score on %s: %s", comment, rsc->id,
225  node->details->uname, score);
226  } else {
227  do_crm_log_alias(LOG_TRACE, file, function, line + 1, "%s: %s = %s", comment,
228  node->details->uname, score);
229  }
230  }
231  }
232 
233  if (rsc && rsc->children) {
234  GListPtr gIter = NULL;
235 
236  gIter = rsc->children;
237  for (; gIter != NULL; gIter = gIter->next) {
238  resource_t *child = (resource_t *) gIter->data;
239 
240  dump_node_scores_worker(level, file, function, line, child, comment, nodes);
241  }
242  }
243 }
244 
245 static void
246 append_dump_text(gpointer key, gpointer value, gpointer user_data)
247 {
248  char **dump_text = user_data;
249  int len = 0;
250  char *new_text = NULL;
251 
252  len = strlen(*dump_text) + strlen(" ") + strlen(key) + strlen("=") + strlen(value) + 1;
253  new_text = calloc(1, len);
254  sprintf(new_text, "%s %s=%s", *dump_text, (char *)key, (char *)value);
255 
256  free(*dump_text);
257  *dump_text = new_text;
258 }
259 
260 void
261 dump_node_capacity(int level, const char *comment, node_t * node)
262 {
263  int len = 0;
264  char *dump_text = NULL;
265 
266  len = strlen(comment) + strlen(": ") + strlen(node->details->uname) + strlen(" capacity:") + 1;
267  dump_text = calloc(1, len);
268  sprintf(dump_text, "%s: %s capacity:", comment, node->details->uname);
269 
270  g_hash_table_foreach(node->details->utilization, append_dump_text, &dump_text);
271 
272  if (level == 0) {
273  fprintf(stdout, "%s\n", dump_text);
274  } else {
275  crm_trace("%s", dump_text);
276  }
277 
278  free(dump_text);
279 }
280 
281 void
282 dump_rsc_utilization(int level, const char *comment, resource_t * rsc, node_t * node)
283 {
284  int len = 0;
285  char *dump_text = NULL;
286 
287  len = strlen(comment) + strlen(": ") + strlen(rsc->id) + strlen(" utilization on ")
288  + strlen(node->details->uname) + strlen(":") + 1;
289  dump_text = calloc(1, len);
290  sprintf(dump_text, "%s: %s utilization on %s:", comment, rsc->id, node->details->uname);
291 
292  g_hash_table_foreach(rsc->utilization, append_dump_text, &dump_text);
293 
294  if (level == 0) {
295  fprintf(stdout, "%s\n", dump_text);
296  } else {
297  crm_trace("%s", dump_text);
298  }
299 
300  free(dump_text);
301 }
302 
303 gint
304 sort_rsc_index(gconstpointer a, gconstpointer b)
305 {
306  const resource_t *resource1 = (const resource_t *)a;
307  const resource_t *resource2 = (const resource_t *)b;
308 
309  if (a == NULL && b == NULL) {
310  return 0;
311  }
312  if (a == NULL) {
313  return 1;
314  }
315  if (b == NULL) {
316  return -1;
317  }
318 
319  if (resource1->sort_index > resource2->sort_index) {
320  return -1;
321  }
322 
323  if (resource1->sort_index < resource2->sort_index) {
324  return 1;
325  }
326 
327  return 0;
328 }
329 
330 gint
331 sort_rsc_priority(gconstpointer a, gconstpointer b)
332 {
333  const resource_t *resource1 = (const resource_t *)a;
334  const resource_t *resource2 = (const resource_t *)b;
335 
336  if (a == NULL && b == NULL) {
337  return 0;
338  }
339  if (a == NULL) {
340  return 1;
341  }
342  if (b == NULL) {
343  return -1;
344  }
345 
346  if (resource1->priority > resource2->priority) {
347  return -1;
348  }
349 
350  if (resource1->priority < resource2->priority) {
351  return 1;
352  }
353 
354  return 0;
355 }
356 
357 action_t *
358 custom_action(resource_t * rsc, char *key, const char *task,
359  node_t * on_node, gboolean optional, gboolean save_action,
360  pe_working_set_t * data_set)
361 {
362  action_t *action = NULL;
363  GListPtr possible_matches = NULL;
364 
365  CRM_CHECK(key != NULL, return NULL);
366  CRM_CHECK(task != NULL, free(key); return NULL);
367 
368  if (save_action && rsc != NULL) {
369  possible_matches = find_actions(rsc->actions, key, on_node);
370  } else if(save_action) {
371 #if 0
372  action = g_hash_table_lookup(data_set->singletons, key);
373 #else
374  /* More expensive but takes 'node' into account */
375  possible_matches = find_actions(data_set->actions, key, on_node);
376 #endif
377  }
378 
379  if(data_set->singletons == NULL) {
380  data_set->singletons = g_hash_table_new_full(crm_str_hash, g_str_equal, NULL, NULL);
381  }
382 
383  if (possible_matches != NULL) {
384  if (g_list_length(possible_matches) > 1) {
385  pe_warn("Action %s for %s on %s exists %d times",
386  task, rsc ? rsc->id : "<NULL>",
387  on_node ? on_node->details->uname : "<NULL>", g_list_length(possible_matches));
388  }
389 
390  action = g_list_nth_data(possible_matches, 0);
391  pe_rsc_trace(rsc, "Found existing action (%d) %s for %s on %s",
392  action->id, task, rsc ? rsc->id : "<NULL>",
393  on_node ? on_node->details->uname : "<NULL>");
394  g_list_free(possible_matches);
395  }
396 
397  if (action == NULL) {
398  if (save_action) {
399  pe_rsc_trace(rsc, "Creating%s action %d: %s for %s on %s %d",
400  optional ? "" : " mandatory", data_set->action_id, key,
401  rsc ? rsc->id : "<NULL>", on_node ? on_node->details->uname : "<NULL>", optional);
402  }
403 
404  action = calloc(1, sizeof(action_t));
405  if (save_action) {
406  action->id = data_set->action_id++;
407  } else {
408  action->id = 0;
409  }
410  action->rsc = rsc;
411  CRM_ASSERT(task != NULL);
412  action->task = strdup(task);
413  if (on_node) {
414  action->node = node_copy(on_node);
415  }
416  action->uuid = strdup(key);
417 
419  if (optional) {
420  pe_rsc_trace(rsc, "Set optional on %s", action->uuid);
422  } else {
424  pe_rsc_trace(rsc, "Unset optional on %s", action->uuid);
425  }
426 
427 /*
428  Implied by calloc()...
429  action->actions_before = NULL;
430  action->actions_after = NULL;
431 
432  action->pseudo = FALSE;
433  action->dumped = FALSE;
434  action->processed = FALSE;
435  action->seen_count = 0;
436 */
437 
438  action->extra = g_hash_table_new_full(crm_str_hash, g_str_equal, free, free);
439 
440  action->meta = g_hash_table_new_full(crm_str_hash, g_str_equal, free, free);
441 
442  if (save_action) {
443  data_set->actions = g_list_prepend(data_set->actions, action);
444  if(rsc == NULL) {
445  g_hash_table_insert(data_set->singletons, action->uuid, action);
446  }
447  }
448 
449  if (rsc != NULL) {
450  action->op_entry = find_rsc_op_entry_helper(rsc, key, TRUE);
451 
452  unpack_operation(action, action->op_entry, rsc->container, data_set);
453 
454  if (save_action) {
455  rsc->actions = g_list_prepend(rsc->actions, action);
456  }
457  }
458 
459  if (save_action) {
460  pe_rsc_trace(rsc, "Action %d created", action->id);
461  }
462  }
463 
464  if (optional == FALSE) {
465  pe_rsc_trace(rsc, "Unset optional on %s", action->uuid);
467  }
468 
469  if (rsc != NULL) {
470  enum action_tasks a_task = text2task(action->task);
471  int warn_level = LOG_TRACE;
472 
473  if (save_action) {
474  warn_level = LOG_WARNING;
475  }
476 
477  if (is_set(action->flags, pe_action_have_node_attrs) == FALSE
478  && action->node != NULL && action->op_entry != NULL) {
481  action->node->details->attrs,
482  action->extra, NULL, FALSE, data_set->now);
483  }
484 
485  if (is_set(action->flags, pe_action_pseudo)) {
486  /* leave untouched */
487 
488  } else if (action->node == NULL) {
489  pe_rsc_trace(rsc, "Unset runnable on %s", action->uuid);
491 
492  } else if (is_not_set(rsc->flags, pe_rsc_managed)
493  && g_hash_table_lookup(action->meta, XML_LRM_ATTR_INTERVAL) == NULL) {
494  crm_debug("Action %s (unmanaged)", action->uuid);
495  pe_rsc_trace(rsc, "Set optional on %s", action->uuid);
497 /* action->runnable = FALSE; */
498 
499  } else if (action->node->details->online == FALSE) {
501  do_crm_log(warn_level, "Action %s on %s is unrunnable (offline)",
502  action->uuid, action->node->details->uname);
503  if (is_set(action->rsc->flags, pe_rsc_managed)
504  && save_action && a_task == stop_rsc) {
505  pe_fence_node(data_set, action->node, "because node is unclean");
506  }
507 
508  } else if (action->node->details->pending) {
510  do_crm_log(warn_level, "Action %s on %s is unrunnable (pending)",
511  action->uuid, action->node->details->uname);
512 
513  } else if (action->needs == rsc_req_nothing) {
514  pe_rsc_trace(rsc, "Action %s does not require anything", action->uuid);
516 #if 0
517  /*
518  * No point checking this
519  * - if we dont have quorum we can't stonith anyway
520  */
521  } else if (action->needs == rsc_req_stonith) {
522  crm_trace("Action %s requires only stonith", action->uuid);
523  action->runnable = TRUE;
524 #endif
525  } else if (is_set(data_set->flags, pe_flag_have_quorum) == FALSE
526  && data_set->no_quorum_policy == no_quorum_stop) {
528  crm_debug("%s\t%s (cancelled : quorum)", action->node->details->uname, action->uuid);
529 
530  } else if (is_set(data_set->flags, pe_flag_have_quorum) == FALSE
531  && data_set->no_quorum_policy == no_quorum_freeze) {
532  pe_rsc_trace(rsc, "Check resource is already active: %s %s %s %s", rsc->id, action->uuid, role2text(rsc->next_role), role2text(rsc->role));
533  if (rsc->fns->active(rsc, TRUE) == FALSE || rsc->next_role > rsc->role) {
535  pe_rsc_debug(rsc, "%s\t%s (cancelled : quorum freeze)",
536  action->node->details->uname, action->uuid);
537  }
538 
539  } else {
540  pe_rsc_trace(rsc, "Action %s is runnable", action->uuid);
542  }
543 
544  if (save_action) {
545  switch (a_task) {
546  case stop_rsc:
548  break;
549  case start_rsc:
551  if (is_set(action->flags, pe_action_runnable)) {
553  }
554  break;
555  default:
556  break;
557  }
558  }
559  }
560 
561  free(key);
562  return action;
563 }
564 
565 static const char *
566 unpack_operation_on_fail(action_t * action)
567 {
568 
569  const char *value = g_hash_table_lookup(action->meta, XML_OP_ATTR_ON_FAIL);
570 
571  if (safe_str_eq(action->task, CRMD_ACTION_STOP) && safe_str_eq(value, "standby")) {
572  crm_config_err("on-fail=standby is not allowed for stop actions: %s", action->rsc->id);
573  return NULL;
574  } else if (safe_str_eq(action->task, CRMD_ACTION_DEMOTE) && !value) {
575  /* demote on_fail defaults to master monitor value if present */
576  xmlNode *operation = NULL;
577  const char *name = NULL;
578  const char *role = NULL;
579  const char *on_fail = NULL;
580  const char *interval = NULL;
581  const char *enabled = NULL;
582 
583  CRM_CHECK(action->rsc != NULL, return NULL);
584 
585  for (operation = __xml_first_child(action->rsc->ops_xml);
586  operation && !value; operation = __xml_next_element(operation)) {
587 
588  if (!crm_str_eq((const char *)operation->name, "op", TRUE)) {
589  continue;
590  }
591  name = crm_element_value(operation, "name");
592  role = crm_element_value(operation, "role");
593  on_fail = crm_element_value(operation, XML_OP_ATTR_ON_FAIL);
594  enabled = crm_element_value(operation, "enabled");
595  interval = crm_element_value(operation, XML_LRM_ATTR_INTERVAL);
596  if (!on_fail) {
597  continue;
598  } else if (enabled && !crm_is_true(enabled)) {
599  continue;
600  } else if (safe_str_neq(name, "monitor") || safe_str_neq(role, "Master")) {
601  continue;
602  } else if (crm_get_interval(interval) <= 0) {
603  continue;
604  }
605 
606  value = on_fail;
607  }
608  }
609 
610  return value;
611 }
612 
613 static xmlNode *
614 find_min_interval_mon(resource_t * rsc, gboolean include_disabled)
615 {
616  int number = 0;
617  int min_interval = -1;
618  const char *name = NULL;
619  const char *value = NULL;
620  const char *interval = NULL;
621  xmlNode *op = NULL;
622  xmlNode *operation = NULL;
623 
624  for (operation = __xml_first_child(rsc->ops_xml); operation != NULL;
625  operation = __xml_next_element(operation)) {
626 
627  if (crm_str_eq((const char *)operation->name, "op", TRUE)) {
628  name = crm_element_value(operation, "name");
629  interval = crm_element_value(operation, XML_LRM_ATTR_INTERVAL);
630  value = crm_element_value(operation, "enabled");
631  if (!include_disabled && value && crm_is_true(value) == FALSE) {
632  continue;
633  }
634 
635  if (safe_str_neq(name, RSC_STATUS)) {
636  continue;
637  }
638 
639  number = crm_get_interval(interval);
640  if (number < 0) {
641  continue;
642  }
643 
644  if (min_interval < 0 || number < min_interval) {
645  min_interval = number;
646  op = operation;
647  }
648  }
649  }
650 
651  return op;
652 }
653 
654 void
655 unpack_operation(action_t * action, xmlNode * xml_obj, resource_t * container,
656  pe_working_set_t * data_set)
657 {
658  int value_i = 0;
659  unsigned long long interval = 0;
660  unsigned long long start_delay = 0;
661  char *value_ms = NULL;
662  const char *value = NULL;
663  const char *field = NULL;
664 
665  CRM_CHECK(action->rsc != NULL, return);
666 
668  action->meta, NULL, FALSE, data_set->now);
669 
670  if (xml_obj) {
671  xmlAttrPtr xIter = NULL;
672 
673  for (xIter = xml_obj->properties; xIter; xIter = xIter->next) {
674  const char *prop_name = (const char *)xIter->name;
675  const char *prop_value = crm_element_value(xml_obj, prop_name);
676 
677  g_hash_table_replace(action->meta, strdup(prop_name), strdup(prop_value));
678  }
679  }
680 
682  NULL, action->meta, NULL, FALSE, data_set->now);
683 
685  NULL, action->meta, NULL, FALSE, data_set->now);
686  g_hash_table_remove(action->meta, "id");
687 
688  field = XML_LRM_ATTR_INTERVAL;
689  value = g_hash_table_lookup(action->meta, field);
690  if (value != NULL) {
691  interval = crm_get_interval(value);
692  if (interval > 0) {
693  value_ms = crm_itoa(interval);
694  g_hash_table_replace(action->meta, strdup(field), value_ms);
695 
696  } else {
697  g_hash_table_remove(action->meta, field);
698  }
699  }
700 
701  /* Begin compatibility code ("requires" set on start action not resource) */
702  value = g_hash_table_lookup(action->meta, "requires");
703 
704  if (safe_str_neq(action->task, RSC_START)
705  && safe_str_neq(action->task, RSC_PROMOTE)) {
706  action->needs = rsc_req_nothing;
707  value = "nothing (not start/promote)";
708 
709  } else if (safe_str_eq(value, "nothing")) {
710  action->needs = rsc_req_nothing;
711 
712  } else if (safe_str_eq(value, "quorum")) {
713  action->needs = rsc_req_quorum;
714 
715  } else if (safe_str_eq(value, "unfencing")) {
716  action->needs = rsc_req_stonith;
718  if (is_not_set(data_set->flags, pe_flag_stonith_enabled)) {
719  crm_notice("%s requires unfencing but fencing is disabled", action->rsc->id);
720  }
721 
722  } else if (is_set(data_set->flags, pe_flag_stonith_enabled)
723  && safe_str_eq(value, "fencing")) {
724  action->needs = rsc_req_stonith;
725  if (is_not_set(data_set->flags, pe_flag_stonith_enabled)) {
726  crm_notice("%s requires fencing but fencing is disabled", action->rsc->id);
727  }
728  /* End compatibility code */
729 
730  } else if (is_set(action->rsc->flags, pe_rsc_needs_fencing)) {
731  action->needs = rsc_req_stonith;
732  value = "fencing (resource)";
733 
734  } else if (is_set(action->rsc->flags, pe_rsc_needs_quorum)) {
735  action->needs = rsc_req_quorum;
736  value = "quorum (resource)";
737 
738  } else {
739  action->needs = rsc_req_nothing;
740  value = "nothing (resource)";
741  }
742 
743  pe_rsc_trace(action->rsc, "\tAction %s requires: %s", action->task, value);
744 
745  value = unpack_operation_on_fail(action);
746 
747  if (value == NULL) {
748 
749  } else if (safe_str_eq(value, "block")) {
750  action->on_fail = action_fail_block;
751  g_hash_table_insert(action->meta, strdup(XML_OP_ATTR_ON_FAIL), strdup("block"));
752 
753  } else if (safe_str_eq(value, "fence")) {
754  action->on_fail = action_fail_fence;
755  value = "node fencing";
756 
757  if (is_set(data_set->flags, pe_flag_stonith_enabled) == FALSE) {
758  crm_config_err("Specifying on_fail=fence and" " stonith-enabled=false makes no sense");
759  action->on_fail = action_fail_stop;
760  action->fail_role = RSC_ROLE_STOPPED;
761  value = "stop resource";
762  }
763 
764  } else if (safe_str_eq(value, "standby")) {
765  action->on_fail = action_fail_standby;
766  value = "node standby";
767 
768  } else if (safe_str_eq(value, "ignore")
769  || safe_str_eq(value, "nothing")) {
770  action->on_fail = action_fail_ignore;
771  value = "ignore";
772 
773  } else if (safe_str_eq(value, "migrate")) {
774  action->on_fail = action_fail_migrate;
775  value = "force migration";
776 
777  } else if (safe_str_eq(value, "stop")) {
778  action->on_fail = action_fail_stop;
779  action->fail_role = RSC_ROLE_STOPPED;
780  value = "stop resource";
781 
782  } else if (safe_str_eq(value, "restart")) {
783  action->on_fail = action_fail_recover;
784  value = "restart (and possibly migrate)";
785 
786  } else if (safe_str_eq(value, "restart-container")) {
787  if (container) {
789  value = "restart container (and possibly migrate)";
790 
791  } else {
792  value = NULL;
793  }
794 
795  } else {
796  pe_err("Resource %s: Unknown failure type (%s)", action->rsc->id, value);
797  value = NULL;
798  }
799 
800  /* defaults */
801  if (value == NULL && container) {
803  value = "restart container (and possibly migrate) (default)";
804 
805  /* for baremetal remote nodes, ensure that any failure that results in
806  * dropping an active connection to a remote node results in fencing of
807  * the remote node.
808  *
809  * There are only two action failures that don't result in fencing.
810  * 1. probes - probe failures are expected.
811  * 2. start - a start failure indicates that an active connection does not already
812  * exist. The user can set op on-fail=fence if they really want to fence start
813  * failures. */
814  } else if (value == NULL &&
815  is_rsc_baremetal_remote_node(action->rsc, data_set) &&
816  !(safe_str_eq(action->task, CRMD_ACTION_STATUS) && interval == 0) &&
817  (safe_str_neq(action->task, CRMD_ACTION_START))) {
818 
819  if (is_set(data_set->flags, pe_flag_stonith_enabled)) {
820  value = "fence baremetal remote node (default)";
821  } else {
822  value = "recover baremetal remote node connection (default)";
823  }
824  if (action->rsc->remote_reconnect_interval) {
825  action->fail_role = RSC_ROLE_STOPPED;
826  }
828 
829  } else if (value == NULL && safe_str_eq(action->task, CRMD_ACTION_STOP)) {
830  if (is_set(data_set->flags, pe_flag_stonith_enabled)) {
831  action->on_fail = action_fail_fence;
832  value = "resource fence (default)";
833 
834  } else {
835  action->on_fail = action_fail_block;
836  value = "resource block (default)";
837  }
838 
839  } else if (value == NULL) {
840  action->on_fail = action_fail_recover;
841  value = "restart (and possibly migrate) (default)";
842  }
843 
844  pe_rsc_trace(action->rsc, "\t%s failure handling: %s", action->task, value);
845 
846  value = NULL;
847  if (xml_obj != NULL) {
848  value = g_hash_table_lookup(action->meta, "role_after_failure");
849  }
850  if (value != NULL && action->fail_role == RSC_ROLE_UNKNOWN) {
851  action->fail_role = text2role(value);
852  }
853  /* defaults */
854  if (action->fail_role == RSC_ROLE_UNKNOWN) {
855  if (safe_str_eq(action->task, CRMD_ACTION_PROMOTE)) {
856  action->fail_role = RSC_ROLE_SLAVE;
857  } else {
858  action->fail_role = RSC_ROLE_STARTED;
859  }
860  }
861  pe_rsc_trace(action->rsc, "\t%s failure results in: %s", action->task,
862  role2text(action->fail_role));
863 
864  field = XML_OP_ATTR_START_DELAY;
865  value = g_hash_table_lookup(action->meta, field);
866  if (value != NULL) {
867  value_i = crm_get_msec(value);
868  if (value_i < 0) {
869  value_i = 0;
870  }
871  start_delay = value_i;
872  value_ms = crm_itoa(value_i);
873  g_hash_table_replace(action->meta, strdup(field), value_ms);
874 
875  } else if (interval > 0 && g_hash_table_lookup(action->meta, XML_OP_ATTR_ORIGIN)) {
876  crm_time_t *origin = NULL;
877 
878  value = g_hash_table_lookup(action->meta, XML_OP_ATTR_ORIGIN);
879  origin = crm_time_new(value);
880 
881  if (origin == NULL) {
882  crm_config_err("Operation %s contained an invalid " XML_OP_ATTR_ORIGIN ": %s",
883  ID(xml_obj), value);
884 
885  } else {
886  crm_time_t *delay = NULL;
887  int rc = crm_time_compare(origin, data_set->now);
888  long long delay_s = 0;
889  int interval_s = (interval / 1000);
890 
891  crm_trace("Origin: %s, interval: %d", value, interval_s);
892 
893  /* If 'origin' is in the future, find the most recent "multiple" that occurred in the past */
894  while(rc > 0) {
895  crm_time_add_seconds(origin, -interval_s);
896  rc = crm_time_compare(origin, data_set->now);
897  }
898 
899  /* Now find the first "multiple" that occurs after 'now' */
900  while (rc < 0) {
901  crm_time_add_seconds(origin, interval_s);
902  rc = crm_time_compare(origin, data_set->now);
903  }
904 
905  delay = crm_time_calculate_duration(origin, data_set->now);
906 
907  crm_time_log(LOG_TRACE, "origin", origin,
910  crm_time_log(LOG_TRACE, "now", data_set->now,
913  crm_time_log(LOG_TRACE, "delay", delay, crm_time_log_duration);
914 
915  delay_s = crm_time_get_seconds(delay);
916 
917  CRM_CHECK(delay_s >= 0, delay_s = 0);
918  start_delay = delay_s * 1000;
919 
920  crm_info("Calculated a start delay of %llds for %s", delay_s, ID(xml_obj));
921  g_hash_table_replace(action->meta, strdup(XML_OP_ATTR_START_DELAY),
922  crm_itoa(start_delay));
923  crm_time_free(origin);
924  crm_time_free(delay);
925  }
926  }
927 
928  field = XML_ATTR_TIMEOUT;
929  value = g_hash_table_lookup(action->meta, field);
930  if (value == NULL && xml_obj == NULL && safe_str_eq(action->task, RSC_STATUS) && interval == 0) {
931  xmlNode *min_interval_mon = find_min_interval_mon(action->rsc, FALSE);
932 
933  if (min_interval_mon) {
934  value = crm_element_value(min_interval_mon, XML_ATTR_TIMEOUT);
935  pe_rsc_trace(action->rsc,
936  "\t%s uses the timeout value '%s' from the minimum interval monitor",
937  action->uuid, value);
938  }
939  }
940  if (value == NULL) {
941  value = pe_pref(data_set->config_hash, "default-action-timeout");
942  }
943  value_i = crm_get_msec(value);
944  if (value_i < 0) {
945  value_i = 0;
946  }
947  value_ms = crm_itoa(value_i);
948  g_hash_table_replace(action->meta, strdup(field), value_ms);
949 }
950 
951 static xmlNode *
952 find_rsc_op_entry_helper(resource_t * rsc, const char *key, gboolean include_disabled)
953 {
954  unsigned long long number = 0;
955  gboolean do_retry = TRUE;
956  char *local_key = NULL;
957  const char *name = NULL;
958  const char *value = NULL;
959  const char *interval = NULL;
960  char *match_key = NULL;
961  xmlNode *op = NULL;
962  xmlNode *operation = NULL;
963 
964  retry:
965  for (operation = __xml_first_child(rsc->ops_xml); operation != NULL;
966  operation = __xml_next_element(operation)) {
967  if (crm_str_eq((const char *)operation->name, "op", TRUE)) {
968  name = crm_element_value(operation, "name");
969  interval = crm_element_value(operation, XML_LRM_ATTR_INTERVAL);
970  value = crm_element_value(operation, "enabled");
971  if (!include_disabled && value && crm_is_true(value) == FALSE) {
972  continue;
973  }
974 
975  number = crm_get_interval(interval);
976  match_key = generate_op_key(rsc->id, name, number);
977  if (safe_str_eq(key, match_key)) {
978  op = operation;
979  }
980  free(match_key);
981 
982  if (rsc->clone_name) {
983  match_key = generate_op_key(rsc->clone_name, name, number);
984  if (safe_str_eq(key, match_key)) {
985  op = operation;
986  }
987  free(match_key);
988  }
989 
990  if (op != NULL) {
991  free(local_key);
992  return op;
993  }
994  }
995  }
996 
997  free(local_key);
998  if (do_retry == FALSE) {
999  return NULL;
1000  }
1001 
1002  do_retry = FALSE;
1003  if (strstr(key, CRMD_ACTION_MIGRATE) || strstr(key, CRMD_ACTION_MIGRATED)) {
1004  local_key = generate_op_key(rsc->id, "migrate", 0);
1005  key = local_key;
1006  goto retry;
1007 
1008  } else if (strstr(key, "_notify_")) {
1009  local_key = generate_op_key(rsc->id, "notify", 0);
1010  key = local_key;
1011  goto retry;
1012  }
1013 
1014  return NULL;
1015 }
1016 
1017 xmlNode *
1018 find_rsc_op_entry(resource_t * rsc, const char *key)
1019 {
1020  return find_rsc_op_entry_helper(rsc, key, FALSE);
1021 }
1022 
1023 void
1024 print_node(const char *pre_text, node_t * node, gboolean details)
1025 {
1026  if (node == NULL) {
1027  crm_trace("%s%s: <NULL>", pre_text == NULL ? "" : pre_text, pre_text == NULL ? "" : ": ");
1028  return;
1029  }
1030 
1031  CRM_ASSERT(node->details);
1032  crm_trace("%s%s%sNode %s: (weight=%d, fixed=%s)",
1033  pre_text == NULL ? "" : pre_text,
1034  pre_text == NULL ? "" : ": ",
1035  node->details->online ? "" : "Unavailable/Unclean ",
1036  node->details->uname, node->weight, node->fixed ? "True" : "False");
1037 
1038  if (details) {
1039  char *pe_mutable = strdup("\t\t");
1040  GListPtr gIter = node->details->running_rsc;
1041 
1042  crm_trace("\t\t===Node Attributes");
1043  g_hash_table_foreach(node->details->attrs, print_str_str, pe_mutable);
1044  free(pe_mutable);
1045 
1046  crm_trace("\t\t=== Resources");
1047 
1048  for (; gIter != NULL; gIter = gIter->next) {
1049  resource_t *rsc = (resource_t *) gIter->data;
1050 
1051  print_resource(LOG_DEBUG_4, "\t\t", rsc, FALSE);
1052  }
1053  }
1054 }
1055 
1056 /*
1057  * Used by the HashTable for-loop
1058  */
1059 void
1060 print_str_str(gpointer key, gpointer value, gpointer user_data)
1061 {
1062  crm_trace("%s%s %s ==> %s",
1063  user_data == NULL ? "" : (char *)user_data,
1064  user_data == NULL ? "" : ": ", (char *)key, (char *)value);
1065 }
1066 
1067 void
1068 print_resource(int log_level, const char *pre_text, resource_t * rsc, gboolean details)
1069 {
1070  long options = pe_print_log | pe_print_pending;
1071 
1072  if (rsc == NULL) {
1073  do_crm_log(log_level - 1, "%s%s: <NULL>",
1074  pre_text == NULL ? "" : pre_text, pre_text == NULL ? "" : ": ");
1075  return;
1076  }
1077  if (details) {
1078  options |= pe_print_details;
1079  }
1080  rsc->fns->print(rsc, pre_text, options, &log_level);
1081 }
1082 
1083 void
1085 {
1086  if (action == NULL) {
1087  return;
1088  }
1089  g_list_free_full(action->actions_before, free); /* action_warpper_t* */
1090  g_list_free_full(action->actions_after, free); /* action_warpper_t* */
1091  if (action->extra) {
1092  g_hash_table_destroy(action->extra);
1093  }
1094  if (action->meta) {
1095  g_hash_table_destroy(action->meta);
1096  }
1097  free(action->cancel_task);
1098  free(action->task);
1099  free(action->uuid);
1100  free(action->node);
1101  free(action);
1102 }
1103 
1104 GListPtr
1106 {
1107  const char *value = NULL;
1108  GListPtr result = NULL;
1109  GListPtr gIter = input;
1110 
1111  CRM_CHECK(input != NULL, return NULL);
1112 
1113  for (; gIter != NULL; gIter = gIter->next) {
1114  action_t *action = (action_t *) gIter->data;
1115 
1116  value = g_hash_table_lookup(action->meta, XML_LRM_ATTR_INTERVAL);
1117  if (value == NULL) {
1118  /* skip */
1119  } else if (safe_str_eq(value, "0")) {
1120  /* skip */
1121  } else if (safe_str_eq(CRMD_ACTION_CANCEL, action->task)) {
1122  /* skip */
1123  } else if (not_on_node == NULL) {
1124  crm_trace("(null) Found: %s", action->uuid);
1125  result = g_list_prepend(result, action);
1126 
1127  } else if (action->node == NULL) {
1128  /* skip */
1129  } else if (action->node->details != not_on_node->details) {
1130  crm_trace("Found: %s", action->uuid);
1131  result = g_list_prepend(result, action);
1132  }
1133  }
1134 
1135  return result;
1136 }
1137 
1138 enum action_tasks
1139 get_complex_task(resource_t * rsc, const char *name, gboolean allow_non_atomic)
1140 {
1141  enum action_tasks task = text2task(name);
1142 
1143  if (rsc == NULL) {
1144  return task;
1145 
1146  } else if (allow_non_atomic == FALSE || rsc->variant == pe_native) {
1147  switch (task) {
1148  case stopped_rsc:
1149  case started_rsc:
1150  case action_demoted:
1151  case action_promoted:
1152  crm_trace("Folding %s back into its atomic counterpart for %s", name, rsc->id);
1153  return task - 1;
1154  break;
1155  default:
1156  break;
1157  }
1158  }
1159  return task;
1160 }
1161 
1162 action_t *
1163 find_first_action(GListPtr input, const char *uuid, const char *task, node_t * on_node)
1164 {
1165  GListPtr gIter = NULL;
1166 
1167  CRM_CHECK(uuid || task, return NULL);
1168 
1169  for (gIter = input; gIter != NULL; gIter = gIter->next) {
1170  action_t *action = (action_t *) gIter->data;
1171 
1172  if (uuid != NULL && safe_str_neq(uuid, action->uuid)) {
1173  continue;
1174 
1175  } else if (task != NULL && safe_str_neq(task, action->task)) {
1176  continue;
1177 
1178  } else if (on_node == NULL) {
1179  return action;
1180 
1181  } else if (action->node == NULL) {
1182  continue;
1183 
1184  } else if (on_node->details == action->node->details) {
1185  return action;
1186  }
1187  }
1188 
1189  return NULL;
1190 }
1191 
1192 GListPtr
1193 find_actions(GListPtr input, const char *key, const node_t *on_node)
1194 {
1195  GListPtr gIter = input;
1196  GListPtr result = NULL;
1197 
1198  CRM_CHECK(key != NULL, return NULL);
1199 
1200  for (; gIter != NULL; gIter = gIter->next) {
1201  action_t *action = (action_t *) gIter->data;
1202 
1203  if (safe_str_neq(key, action->uuid)) {
1204  crm_trace("%s does not match action %s", key, action->uuid);
1205  continue;
1206 
1207  } else if (on_node == NULL) {
1208  crm_trace("Action %s matches (ignoring node)", key);
1209  result = g_list_prepend(result, action);
1210 
1211  } else if (action->node == NULL) {
1212  crm_trace("Action %s matches (unallocated, assigning to %s)",
1213  key, on_node->details->uname);
1214 
1215  action->node = node_copy(on_node);
1216  result = g_list_prepend(result, action);
1217 
1218  } else if (on_node->details == action->node->details) {
1219  crm_trace("Action %s on %s matches", key, on_node->details->uname);
1220  result = g_list_prepend(result, action);
1221 
1222  } else {
1223  crm_trace("Action %s on node %s does not match requested node %s",
1224  key, action->node->details->uname,
1225  on_node->details->uname);
1226  }
1227  }
1228 
1229  return result;
1230 }
1231 
1232 GListPtr
1233 find_actions_exact(GListPtr input, const char *key, node_t * on_node)
1234 {
1235  GListPtr gIter = input;
1236  GListPtr result = NULL;
1237 
1238  CRM_CHECK(key != NULL, return NULL);
1239 
1240  for (; gIter != NULL; gIter = gIter->next) {
1241  action_t *action = (action_t *) gIter->data;
1242 
1243  crm_trace("Matching %s against %s", key, action->uuid);
1244  if (safe_str_neq(key, action->uuid)) {
1245  crm_trace("Key mismatch: %s vs. %s", key, action->uuid);
1246  continue;
1247 
1248  } else if (on_node == NULL || action->node == NULL) {
1249  crm_trace("on_node=%p, action->node=%p", on_node, action->node);
1250  continue;
1251 
1252  } else if (safe_str_eq(on_node->details->id, action->node->details->id)) {
1253  result = g_list_prepend(result, action);
1254  }
1255  crm_trace("Node mismatch: %s vs. %s", on_node->details->id, action->node->details->id);
1256  }
1257 
1258  return result;
1259 }
1260 
1261 static void
1262 resource_node_score(resource_t * rsc, node_t * node, int score, const char *tag)
1263 {
1264  node_t *match = NULL;
1265 
1266  if (rsc->children) {
1267  GListPtr gIter = rsc->children;
1268 
1269  for (; gIter != NULL; gIter = gIter->next) {
1270  resource_t *child_rsc = (resource_t *) gIter->data;
1271 
1272  resource_node_score(child_rsc, node, score, tag);
1273  }
1274  }
1275 
1276  pe_rsc_trace(rsc, "Setting %s for %s on %s: %d", tag, rsc->id, node->details->uname, score);
1277  match = pe_hash_table_lookup(rsc->allowed_nodes, node->details->id);
1278  if (match == NULL) {
1279  match = node_copy(node);
1280  match->weight = merge_weights(score, node->weight);
1281  g_hash_table_insert(rsc->allowed_nodes, (gpointer) match->details->id, match);
1282  }
1283  match->weight = merge_weights(match->weight, score);
1284 }
1285 
1286 void
1287 resource_location(resource_t * rsc, node_t * node, int score, const char *tag,
1288  pe_working_set_t * data_set)
1289 {
1290  if (node != NULL) {
1291  resource_node_score(rsc, node, score, tag);
1292 
1293  } else if (data_set != NULL) {
1294  GListPtr gIter = data_set->nodes;
1295 
1296  for (; gIter != NULL; gIter = gIter->next) {
1297  node_t *node_iter = (node_t *) gIter->data;
1298 
1299  resource_node_score(rsc, node_iter, score, tag);
1300  }
1301 
1302  } else {
1303  GHashTableIter iter;
1304  node_t *node_iter = NULL;
1305 
1306  g_hash_table_iter_init(&iter, rsc->allowed_nodes);
1307  while (g_hash_table_iter_next(&iter, NULL, (void **)&node_iter)) {
1308  resource_node_score(rsc, node_iter, score, tag);
1309  }
1310  }
1311 
1312  if (node == NULL && score == -INFINITY) {
1313  if (rsc->allocated_to) {
1314  crm_info("Deallocating %s from %s", rsc->id, rsc->allocated_to->details->uname);
1315  free(rsc->allocated_to);
1316  rsc->allocated_to = NULL;
1317  }
1318  }
1319 }
1320 
1321 #define sort_return(an_int, why) do { \
1322  free(a_uuid); \
1323  free(b_uuid); \
1324  crm_trace("%s (%d) %c %s (%d) : %s", \
1325  a_xml_id, a_call_id, an_int>0?'>':an_int<0?'<':'=', \
1326  b_xml_id, b_call_id, why); \
1327  return an_int; \
1328  } while(0)
1329 
1330 gint
1331 sort_op_by_callid(gconstpointer a, gconstpointer b)
1332 {
1333  int a_call_id = -1;
1334  int b_call_id = -1;
1335 
1336  char *a_uuid = NULL;
1337  char *b_uuid = NULL;
1338 
1339  const xmlNode *xml_a = a;
1340  const xmlNode *xml_b = b;
1341 
1342  const char *a_xml_id = crm_element_value_const(xml_a, XML_ATTR_ID);
1343  const char *b_xml_id = crm_element_value_const(xml_b, XML_ATTR_ID);
1344 
1345  if (safe_str_eq(a_xml_id, b_xml_id)) {
1346  /* We have duplicate lrm_rsc_op entries in the status
1347  * section which is unliklely to be a good thing
1348  * - we can handle it easily enough, but we need to get
1349  * to the bottom of why its happening.
1350  */
1351  pe_err("Duplicate lrm_rsc_op entries named %s", a_xml_id);
1352  sort_return(0, "duplicate");
1353  }
1354 
1357 
1358  if (a_call_id == -1 && b_call_id == -1) {
1359  /* both are pending ops so it doesn't matter since
1360  * stops are never pending
1361  */
1362  sort_return(0, "pending");
1363 
1364  } else if (a_call_id >= 0 && a_call_id < b_call_id) {
1365  sort_return(-1, "call id");
1366 
1367  } else if (b_call_id >= 0 && a_call_id > b_call_id) {
1368  sort_return(1, "call id");
1369 
1370  } else if (b_call_id >= 0 && a_call_id == b_call_id) {
1371  /*
1372  * The op and last_failed_op are the same
1373  * Order on last-rc-change
1374  */
1375  int last_a = -1;
1376  int last_b = -1;
1377 
1380 
1381  crm_trace("rc-change: %d vs %d", last_a, last_b);
1382  if (last_a >= 0 && last_a < last_b) {
1383  sort_return(-1, "rc-change");
1384 
1385  } else if (last_b >= 0 && last_a > last_b) {
1386  sort_return(1, "rc-change");
1387  }
1388  sort_return(0, "rc-change");
1389 
1390  } else {
1391  /* One of the inputs is a pending operation
1392  * Attempt to use XML_ATTR_TRANSITION_MAGIC to determine its age relative to the other
1393  */
1394 
1395  int a_id = -1;
1396  int b_id = -1;
1397  int dummy = -1;
1398 
1399  const char *a_magic = crm_element_value_const(xml_a, XML_ATTR_TRANSITION_MAGIC);
1400  const char *b_magic = crm_element_value_const(xml_b, XML_ATTR_TRANSITION_MAGIC);
1401 
1402  CRM_CHECK(a_magic != NULL && b_magic != NULL, sort_return(0, "No magic"));
1403  if(!decode_transition_magic(a_magic, &a_uuid, &a_id, &dummy, &dummy, &dummy, &dummy)) {
1404  sort_return(0, "bad magic a");
1405  }
1406  if(!decode_transition_magic(b_magic, &b_uuid, &b_id, &dummy, &dummy, &dummy, &dummy)) {
1407  sort_return(0, "bad magic b");
1408  }
1409  /* try to determine the relative age of the operation...
1410  * some pending operations (ie. a start) may have been superseded
1411  * by a subsequent stop
1412  *
1413  * [a|b]_id == -1 means its a shutdown operation and _always_ comes last
1414  */
1415  if (safe_str_neq(a_uuid, b_uuid) || a_id == b_id) {
1416  /*
1417  * some of the logic in here may be redundant...
1418  *
1419  * if the UUID from the TE doesn't match then one better
1420  * be a pending operation.
1421  * pending operations dont survive between elections and joins
1422  * because we query the LRM directly
1423  */
1424 
1425  if (b_call_id == -1) {
1426  sort_return(-1, "transition + call");
1427 
1428  } else if (a_call_id == -1) {
1429  sort_return(1, "transition + call");
1430  }
1431 
1432  } else if ((a_id >= 0 && a_id < b_id) || b_id == -1) {
1433  sort_return(-1, "transition");
1434 
1435  } else if ((b_id >= 0 && a_id > b_id) || a_id == -1) {
1436  sort_return(1, "transition");
1437  }
1438  }
1439 
1440  /* we should never end up here */
1441  CRM_CHECK(FALSE, sort_return(0, "default"));
1442 
1443 }
1444 
1445 time_t
1447 {
1448  if(data_set) {
1449  if (data_set->now == NULL) {
1450  crm_trace("Recording a new 'now'");
1451  data_set->now = crm_time_new(NULL);
1452  }
1453  return crm_time_get_seconds_since_epoch(data_set->now);
1454  }
1455 
1456  crm_trace("Defaulting to 'now'");
1457  return time(NULL);
1458 }
1459 
1460 struct fail_search {
1461  resource_t *rsc;
1462  pe_working_set_t * data_set;
1463 
1464  int count;
1465  long long last;
1466  char *key;
1467 };
1468 
1469 static void
1470 get_failcount_by_prefix(gpointer key_p, gpointer value, gpointer user_data)
1471 {
1472  struct fail_search *search = user_data;
1473  const char *attr_id = key_p;
1474  const char *match = strstr(attr_id, search->key);
1475  resource_t *parent = NULL;
1476 
1477  if (match == NULL) {
1478  return;
1479  }
1480 
1481  /* we are only incrementing the failcounts here if the rsc
1482  * that matches our prefix has the same uber parent as the rsc we're
1483  * calculating the failcounts for. This prevents false positive matches
1484  * where unrelated resources may have similar prefixes in their names.
1485  *
1486  * search->rsc is already set to be the uber parent. */
1487  parent = uber_parent(pe_find_resource(search->data_set->resources, match));
1488  if (parent == NULL || parent != search->rsc) {
1489  return;
1490  }
1491  if (strstr(attr_id, "last-failure-") == attr_id) {
1492  search->last = crm_int_helper(value, NULL);
1493 
1494  } else if (strstr(attr_id, "fail-count-") == attr_id) {
1495  search->count += char2score(value);
1496  }
1497 }
1498 
1499 int
1500 get_failcount(node_t * node, resource_t * rsc, time_t *last_failure, pe_working_set_t * data_set)
1501 {
1502  return get_failcount_full(node, rsc, last_failure, TRUE, NULL, data_set);
1503 }
1504 
1505 static gboolean
1506 is_matched_failure(const char * rsc_id, xmlNode * conf_op_xml, xmlNode * lrm_op_xml)
1507 {
1508  gboolean matched = FALSE;
1509  const char *conf_op_name = NULL;
1510  int conf_op_interval = 0;
1511  const char *lrm_op_task = NULL;
1512  int lrm_op_interval = 0;
1513  const char *lrm_op_id = NULL;
1514  char *last_failure_key = NULL;
1515 
1516  if (rsc_id == NULL || conf_op_xml == NULL || lrm_op_xml == NULL) {
1517  return FALSE;
1518  }
1519 
1520  conf_op_name = crm_element_value(conf_op_xml, "name");
1521  conf_op_interval = crm_get_msec(crm_element_value(conf_op_xml, "interval"));
1522  lrm_op_task = crm_element_value(lrm_op_xml, XML_LRM_ATTR_TASK);
1523  crm_element_value_int(lrm_op_xml, XML_LRM_ATTR_INTERVAL, &lrm_op_interval);
1524 
1525  if (safe_str_eq(conf_op_name, lrm_op_task) == FALSE
1526  || conf_op_interval != lrm_op_interval) {
1527  return FALSE;
1528  }
1529 
1530  lrm_op_id = ID(lrm_op_xml);
1531  last_failure_key = generate_op_key(rsc_id, "last_failure", 0);
1532 
1533  if (safe_str_eq(last_failure_key, lrm_op_id)) {
1534  matched = TRUE;
1535 
1536  } else {
1537  char *expected_op_key = generate_op_key(rsc_id, conf_op_name, conf_op_interval);
1538 
1539  if (safe_str_eq(expected_op_key, lrm_op_id)) {
1540  int rc = 0;
1541  int target_rc = get_target_rc(lrm_op_xml);
1542 
1543  crm_element_value_int(lrm_op_xml, XML_LRM_ATTR_RC, &rc);
1544  if (rc != target_rc) {
1545  matched = TRUE;
1546  }
1547  }
1548  free(expected_op_key);
1549  }
1550 
1551  free(last_failure_key);
1552  return matched;
1553 }
1554 
1555 static gboolean
1556 block_failure(node_t * node, resource_t * rsc, xmlNode * xml_op, pe_working_set_t * data_set)
1557 {
1558  char *xml_name = clone_strip(rsc->id);
1559  char *xpath = crm_strdup_printf("//primitive[@id='%s']//op[@on-fail='block']", xml_name);
1560  xmlXPathObject *xpathObj = xpath_search(rsc->xml, xpath);
1561  gboolean should_block = FALSE;
1562 
1563  free(xpath);
1564 
1565  if (xpathObj) {
1566  int max = numXpathResults(xpathObj);
1567  int lpc = 0;
1568 
1569  for (lpc = 0; lpc < max; lpc++) {
1570  xmlNode *pref = getXpathResult(xpathObj, lpc);
1571 
1572  if (xml_op) {
1573  should_block = is_matched_failure(xml_name, pref, xml_op);
1574  if (should_block) {
1575  break;
1576  }
1577 
1578  } else {
1579  const char *conf_op_name = NULL;
1580  int conf_op_interval = 0;
1581  char *lrm_op_xpath = NULL;
1582  xmlXPathObject *lrm_op_xpathObj = NULL;
1583 
1584  conf_op_name = crm_element_value(pref, "name");
1585  conf_op_interval = crm_get_msec(crm_element_value(pref, "interval"));
1586 
1587  lrm_op_xpath = crm_strdup_printf("//node_state[@uname='%s']"
1588  "//lrm_resource[@id='%s']"
1589  "/lrm_rsc_op[@operation='%s'][@interval='%d']",
1590  node->details->uname, xml_name,
1591  conf_op_name, conf_op_interval);
1592  lrm_op_xpathObj = xpath_search(data_set->input, lrm_op_xpath);
1593 
1594  free(lrm_op_xpath);
1595 
1596  if (lrm_op_xpathObj) {
1597  int max2 = numXpathResults(lrm_op_xpathObj);
1598  int lpc2 = 0;
1599 
1600  for (lpc2 = 0; lpc2 < max2; lpc2++) {
1601  xmlNode *lrm_op_xml = getXpathResult(lrm_op_xpathObj, lpc2);
1602 
1603  should_block = is_matched_failure(xml_name, pref, lrm_op_xml);
1604  if (should_block) {
1605  break;
1606  }
1607  }
1608  }
1609  freeXpathObject(lrm_op_xpathObj);
1610 
1611  if (should_block) {
1612  break;
1613  }
1614  }
1615  }
1616  }
1617 
1618  free(xml_name);
1619  freeXpathObject(xpathObj);
1620 
1621  return should_block;
1622 }
1623 
1624 int
1625 get_failcount_full(node_t * node, resource_t * rsc, time_t *last_failure,
1626  bool effective, xmlNode * xml_op, pe_working_set_t * data_set)
1627 {
1628  char *key = NULL;
1629  const char *value = NULL;
1630  struct fail_search search = { rsc, data_set, 0, 0, NULL };
1631 
1632  /* Optimize the "normal" case */
1633  key = crm_concat("fail-count", rsc->clone_name ? rsc->clone_name : rsc->id, '-');
1634  value = g_hash_table_lookup(node->details->attrs, key);
1635  search.count = char2score(value);
1636  crm_trace("%s = %s", key, value);
1637  free(key);
1638 
1639  if (value) {
1640  key = crm_concat("last-failure", rsc->clone_name ? rsc->clone_name : rsc->id, '-');
1641  value = g_hash_table_lookup(node->details->attrs, key);
1642  search.last = crm_int_helper(value, NULL);
1643  free(key);
1644 
1645  /* This block is still relevant once we omit anonymous instance numbers
1646  * because stopped clones won't have clone_name set
1647  */
1648  } else if (is_not_set(rsc->flags, pe_rsc_unique)) {
1649  search.rsc = uber_parent(rsc);
1650  search.key = clone_strip(rsc->id);
1651 
1652  g_hash_table_foreach(node->details->attrs, get_failcount_by_prefix, &search);
1653  free(search.key);
1654  search.key = NULL;
1655  }
1656 
1657  if (search.count != 0 && search.last != 0 && last_failure) {
1658  *last_failure = search.last;
1659  }
1660 
1661  if(search.count && rsc->failure_timeout) {
1662  /* Never time-out if blocking failures are configured */
1663  if (block_failure(node, rsc, xml_op, data_set)) {
1664  pe_warn("Setting %s.failure-timeout=%d conflicts with on-fail=block: ignoring timeout", rsc->id, rsc->failure_timeout);
1665  rsc->failure_timeout = 0;
1666 #if 0
1667  /* A good idea? */
1668  } else if (rsc->container == NULL && is_not_set(data_set->flags, pe_flag_stonith_enabled)) {
1669  /* In this case, stop.on-fail defaults to block in unpack_operation() */
1670  rsc->failure_timeout = 0;
1671 #endif
1672  }
1673  }
1674 
1675  if (effective && search.count != 0 && search.last != 0 && rsc->failure_timeout) {
1676  if (search.last > 0) {
1677  time_t now = get_effective_time(data_set);
1678 
1679  if (now > (search.last + rsc->failure_timeout)) {
1680  crm_debug("Failcount for %s on %s has expired (limit was %ds)",
1681  search.rsc->id, node->details->uname, rsc->failure_timeout);
1682  search.count = 0;
1683  }
1684  }
1685  }
1686 
1687  if (search.count != 0) {
1688  char *score = score2char(search.count);
1689 
1690  crm_info("%s has failed %s times on %s", search.rsc->id, score, node->details->uname);
1691  free(score);
1692  }
1693 
1694  return search.count;
1695 }
1696 
1697 /* If it's a resource container, get its failcount plus all the failcounts of the resources within it */
1698 int
1699 get_failcount_all(node_t * node, resource_t * rsc, time_t *last_failure, pe_working_set_t * data_set)
1700 {
1701  int failcount_all = 0;
1702 
1703  failcount_all = get_failcount(node, rsc, last_failure, data_set);
1704 
1705  if (rsc->fillers) {
1706  GListPtr gIter = NULL;
1707 
1708  for (gIter = rsc->fillers; gIter != NULL; gIter = gIter->next) {
1709  resource_t *filler = (resource_t *) gIter->data;
1710  time_t filler_last_failure = 0;
1711 
1712  failcount_all += get_failcount(node, filler, &filler_last_failure, data_set);
1713 
1714  if (last_failure && filler_last_failure > *last_failure) {
1715  *last_failure = filler_last_failure;
1716  }
1717  }
1718 
1719  if (failcount_all != 0) {
1720  char *score = score2char(failcount_all);
1721 
1722  crm_info("Container %s and the resources within it have failed %s times on %s",
1723  rsc->id, score, node->details->uname);
1724  free(score);
1725  }
1726  }
1727 
1728  return failcount_all;
1729 }
1730 
1731 gboolean
1733 {
1734  enum rsc_role_e local_role = RSC_ROLE_UNKNOWN;
1735  const char *value = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_TARGET_ROLE);
1736 
1737  CRM_CHECK(role != NULL, return FALSE);
1738 
1739  if (value == NULL || safe_str_eq("started", value)
1740  || safe_str_eq("default", value)) {
1741  return FALSE;
1742  }
1743 
1744  local_role = text2role(value);
1745  if (local_role == RSC_ROLE_UNKNOWN) {
1746  crm_config_err("%s: Unknown value for %s: %s", rsc->id, XML_RSC_ATTR_TARGET_ROLE, value);
1747  return FALSE;
1748 
1749  } else if (local_role > RSC_ROLE_STARTED) {
1750  if (uber_parent(rsc)->variant == pe_master) {
1751  if (local_role > RSC_ROLE_SLAVE) {
1752  /* This is what we'd do anyway, just leave the default to avoid messing up the placement algorithm */
1753  return FALSE;
1754  }
1755 
1756  } else {
1757  crm_config_err("%s is not part of a master/slave resource, a %s of '%s' makes no sense",
1758  rsc->id, XML_RSC_ATTR_TARGET_ROLE, value);
1759  return FALSE;
1760  }
1761  }
1762 
1763  *role = local_role;
1764  return TRUE;
1765 }
1766 
1767 gboolean
1768 order_actions(action_t * lh_action, action_t * rh_action, enum pe_ordering order)
1769 {
1770  GListPtr gIter = NULL;
1771  action_wrapper_t *wrapper = NULL;
1772  GListPtr list = NULL;
1773 
1774  if (order == pe_order_none) {
1775  return FALSE;
1776  }
1777 
1778  if (lh_action == NULL || rh_action == NULL) {
1779  return FALSE;
1780  }
1781 
1782  crm_trace("Ordering Action %s before %s", lh_action->uuid, rh_action->uuid);
1783 
1784  /* Ensure we never create a dependency on ourselves... its happened */
1785  CRM_ASSERT(lh_action != rh_action);
1786 
1787  /* Filter dups, otherwise update_action_states() has too much work to do */
1788  gIter = lh_action->actions_after;
1789  for (; gIter != NULL; gIter = gIter->next) {
1790  action_wrapper_t *after = (action_wrapper_t *) gIter->data;
1791 
1792  if (after->action == rh_action && (after->type & order)) {
1793  return FALSE;
1794  }
1795  }
1796 
1797  wrapper = calloc(1, sizeof(action_wrapper_t));
1798  wrapper->action = rh_action;
1799  wrapper->type = order;
1800 
1801  list = lh_action->actions_after;
1802  list = g_list_prepend(list, wrapper);
1803  lh_action->actions_after = list;
1804 
1805  wrapper = NULL;
1806 
1807 /* order |= pe_order_implies_then; */
1808 /* order ^= pe_order_implies_then; */
1809 
1810  wrapper = calloc(1, sizeof(action_wrapper_t));
1811  wrapper->action = lh_action;
1812  wrapper->type = order;
1813  list = rh_action->actions_before;
1814  list = g_list_prepend(list, wrapper);
1815  rh_action->actions_before = list;
1816  return TRUE;
1817 }
1818 
1819 action_t *
1820 get_pseudo_op(const char *name, pe_working_set_t * data_set)
1821 {
1822  action_t *op = NULL;
1823 
1824  if(data_set->singletons) {
1825  op = g_hash_table_lookup(data_set->singletons, name);
1826  }
1827  if (op == NULL) {
1828  op = custom_action(NULL, strdup(name), name, NULL, TRUE, TRUE, data_set);
1831  }
1832 
1833  return op;
1834 }
1835 
1836 void
1838 {
1839  ticket_t *ticket = data;
1840 
1841  if (ticket->state) {
1842  g_hash_table_destroy(ticket->state);
1843  }
1844  free(ticket->id);
1845  free(ticket);
1846 }
1847 
1848 ticket_t *
1849 ticket_new(const char *ticket_id, pe_working_set_t * data_set)
1850 {
1851  ticket_t *ticket = NULL;
1852 
1853  if (ticket_id == NULL || strlen(ticket_id) == 0) {
1854  return NULL;
1855  }
1856 
1857  if (data_set->tickets == NULL) {
1858  data_set->tickets =
1859  g_hash_table_new_full(crm_str_hash, g_str_equal, g_hash_destroy_str, destroy_ticket);
1860  }
1861 
1862  ticket = g_hash_table_lookup(data_set->tickets, ticket_id);
1863  if (ticket == NULL) {
1864 
1865  ticket = calloc(1, sizeof(ticket_t));
1866  if (ticket == NULL) {
1867  crm_err("Cannot allocate ticket '%s'", ticket_id);
1868  return NULL;
1869  }
1870 
1871  crm_trace("Creaing ticket entry for %s", ticket_id);
1872 
1873  ticket->id = strdup(ticket_id);
1874  ticket->granted = FALSE;
1875  ticket->last_granted = -1;
1876  ticket->standby = FALSE;
1877  ticket->state = g_hash_table_new_full(crm_str_hash, g_str_equal,
1879 
1880  g_hash_table_insert(data_set->tickets, strdup(ticket->id), ticket);
1881  }
1882 
1883  return ticket;
1884 }
1885 
1886 static void
1887 filter_parameters(xmlNode * param_set, const char *param_string, bool need_present)
1888 {
1889  int len = 0;
1890  char *name = NULL;
1891  char *match = NULL;
1892 
1893  if (param_set == NULL) {
1894  return;
1895  }
1896 
1897  if (param_set) {
1898  xmlAttrPtr xIter = param_set->properties;
1899 
1900  while (xIter) {
1901  const char *prop_name = (const char *)xIter->name;
1902 
1903  xIter = xIter->next;
1904  name = NULL;
1905  len = strlen(prop_name) + 3;
1906 
1907  name = malloc(len);
1908  if(name) {
1909  sprintf(name, " %s ", prop_name);
1910  name[len - 1] = 0;
1911  match = strstr(param_string, name);
1912  }
1913 
1914  if (need_present && match == NULL) {
1915  crm_trace("%s not found in %s", prop_name, param_string);
1916  xml_remove_prop(param_set, prop_name);
1917 
1918  } else if (need_present == FALSE && match) {
1919  crm_trace("%s found in %s", prop_name, param_string);
1920  xml_remove_prop(param_set, prop_name);
1921  }
1922  free(name);
1923  }
1924  }
1925 }
1926 
1928 rsc_action_digest_cmp(resource_t * rsc, xmlNode * xml_op, node_t * node,
1929  pe_working_set_t * data_set)
1930 {
1931  op_digest_cache_t *data = NULL;
1932 
1933  GHashTable *local_rsc_params = NULL;
1934 
1935  action_t *action = NULL;
1936  char *key = NULL;
1937 
1938  int interval = 0;
1939  const char *op_id = ID(xml_op);
1940  const char *interval_s = crm_element_value(xml_op, XML_LRM_ATTR_INTERVAL);
1941  const char *task = crm_element_value(xml_op, XML_LRM_ATTR_TASK);
1942  const char *digest_all;
1943  const char *digest_restart;
1944  const char *secure_list;
1945  const char *restart_list;
1946  const char *op_version;
1947 
1948  data = g_hash_table_lookup(node->details->digest_cache, op_id);
1949  if (data) {
1950  return data;
1951  }
1952 
1953  data = calloc(1, sizeof(op_digest_cache_t));
1954 
1955  digest_all = crm_element_value(xml_op, XML_LRM_ATTR_OP_DIGEST);
1956  digest_restart = crm_element_value(xml_op, XML_LRM_ATTR_RESTART_DIGEST);
1957 
1958  secure_list = crm_element_value(xml_op, XML_LRM_ATTR_OP_SECURE);
1959  restart_list = crm_element_value(xml_op, XML_LRM_ATTR_OP_RESTART);
1960 
1961  op_version = crm_element_value(xml_op, XML_ATTR_CRM_VERSION);
1962 
1963  /* key is freed in custom_action */
1964  interval = crm_parse_int(interval_s, "0");
1965  key = generate_op_key(rsc->id, task, interval);
1966  action = custom_action(rsc, key, task, node, TRUE, FALSE, data_set);
1967  key = NULL;
1968 
1969  local_rsc_params = g_hash_table_new_full(crm_str_hash, g_str_equal,
1971  get_rsc_attributes(local_rsc_params, rsc, node, data_set);
1972  data->params_all = create_xml_node(NULL, XML_TAG_PARAMS);
1973  g_hash_table_foreach(local_rsc_params, hash2field, data->params_all);
1974  g_hash_table_foreach(action->extra, hash2field, data->params_all);
1975  g_hash_table_foreach(rsc->parameters, hash2field, data->params_all);
1976  g_hash_table_foreach(action->meta, hash2metafield, data->params_all);
1977  filter_action_parameters(data->params_all, op_version);
1978 
1979  data->digest_all_calc = calculate_operation_digest(data->params_all, op_version);
1980 
1981  if (secure_list && is_set(data_set->flags, pe_flag_sanitized)) {
1982  data->params_secure = copy_xml(data->params_all);
1983 
1984  if (secure_list) {
1985  filter_parameters(data->params_secure, secure_list, FALSE);
1986  }
1987  data->digest_secure_calc = calculate_operation_digest(data->params_secure, op_version);
1988  }
1989 
1990  if (digest_restart) {
1991  data->params_restart = copy_xml(data->params_all);
1992 
1993  if (restart_list) {
1994  filter_parameters(data->params_restart, restart_list, TRUE);
1995  }
1997  }
1998 
1999  data->rc = RSC_DIGEST_MATCH;
2000  if (digest_restart && strcmp(data->digest_restart_calc, digest_restart) != 0) {
2001  data->rc = RSC_DIGEST_RESTART;
2002 
2003  } else if (digest_all == NULL) {
2004  /* it is unknown what the previous op digest was */
2005  data->rc = RSC_DIGEST_UNKNOWN;
2006 
2007  } else if (strcmp(digest_all, data->digest_all_calc) != 0) {
2008  data->rc = RSC_DIGEST_ALL;
2009  }
2010 
2011  g_hash_table_insert(node->details->digest_cache, strdup(op_id), data);
2012  g_hash_table_destroy(local_rsc_params);
2013  pe_free_action(action);
2014 
2015  return data;
2016 }
2017 
2018 const char *rsc_printable_id(resource_t *rsc)
2019 {
2020  if (is_not_set(rsc->flags, pe_rsc_unique)) {
2021  return ID(rsc->xml);
2022  }
2023  return rsc->id;
2024 }
2025 
2026 void
2027 clear_bit_recursive(resource_t * rsc, unsigned long long flag)
2028 {
2029  GListPtr gIter = rsc->children;
2030 
2031  clear_bit(rsc->flags, flag);
2032  for (; gIter != NULL; gIter = gIter->next) {
2033  resource_t *child_rsc = (resource_t *) gIter->data;
2034 
2035  clear_bit_recursive(child_rsc, flag);
2036  }
2037 }
2038 
2039 void
2040 set_bit_recursive(resource_t * rsc, unsigned long long flag)
2041 {
2042  GListPtr gIter = rsc->children;
2043 
2044  set_bit(rsc->flags, flag);
2045  for (; gIter != NULL; gIter = gIter->next) {
2046  resource_t *child_rsc = (resource_t *) gIter->data;
2047 
2048  set_bit_recursive(child_rsc, flag);
2049  }
2050 }
2051 
2052 action_t *
2053 pe_fence_op(node_t * node, const char *op, bool optional, pe_working_set_t * data_set)
2054 {
2055  char *key = NULL;
2056  action_t *stonith_op = NULL;
2057 
2058  if(op == NULL) {
2059  op = data_set->stonith_action;
2060  }
2061 
2062  key = crm_strdup_printf("%s-%s-%s", CRM_OP_FENCE, node->details->uname, op);
2063 
2064  if(data_set->singletons) {
2065  stonith_op = g_hash_table_lookup(data_set->singletons, key);
2066  }
2067 
2068  if(stonith_op == NULL) {
2069  stonith_op = custom_action(NULL, key, CRM_OP_FENCE, node, optional, TRUE, data_set);
2070 
2071  add_hash_param(stonith_op->meta, XML_LRM_ATTR_TARGET, node->details->uname);
2072  add_hash_param(stonith_op->meta, XML_LRM_ATTR_TARGET_UUID, node->details->id);
2073  add_hash_param(stonith_op->meta, "stonith_action", op);
2074  } else {
2075  free(key);
2076  }
2077 
2078  if(optional == FALSE) {
2079  crm_trace("%s is no longer optional", stonith_op->uuid);
2081  }
2082 
2083  return stonith_op;
2084 }
2085 
2086 void
2088  resource_t * rsc, node_t *node, const char *reason, action_t *dependency, pe_working_set_t * data_set)
2089 {
2090  if(is_not_set(data_set->flags, pe_flag_enable_unfencing)) {
2091  /* No resources require it */
2092  return;
2093 
2094  } else if (rsc != NULL && is_not_set(rsc->flags, pe_rsc_fence_device)) {
2095  /* Wasnt a stonith device */
2096  return;
2097 
2098  } else if(node
2099  && node->details->online
2100  && node->details->unclean == FALSE
2101  && node->details->shutdown == FALSE) {
2102  action_t *unfence = pe_fence_op(node, "on", FALSE, data_set);
2103 
2104  crm_notice("Unfencing %s: %s", node->details->uname, reason);
2105  if(dependency) {
2106  order_actions(unfence, dependency, pe_order_optional);
2107  }
2108 
2109  } else if(rsc) {
2110  GHashTableIter iter;
2111 
2112  g_hash_table_iter_init(&iter, rsc->allowed_nodes);
2113  while (g_hash_table_iter_next(&iter, NULL, (void **)&node)) {
2114  if(node->details->online && node->details->unclean == FALSE && node->details->shutdown == FALSE) {
2115  trigger_unfencing(rsc, node, reason, dependency, data_set);
2116  }
2117  }
2118  }
2119 }
2120 
2121 gboolean
2122 add_tag_ref(GHashTable * tags, const char * tag_name, const char * obj_ref)
2123 {
2124  tag_t *tag = NULL;
2125  GListPtr gIter = NULL;
2126  gboolean is_existing = FALSE;
2127 
2128  CRM_CHECK(tags && tag_name && obj_ref, return FALSE);
2129 
2130  tag = g_hash_table_lookup(tags, tag_name);
2131  if (tag == NULL) {
2132  tag = calloc(1, sizeof(tag_t));
2133  if (tag == NULL) {
2134  return FALSE;
2135  }
2136  tag->id = strdup(tag_name);
2137  tag->refs = NULL;
2138  g_hash_table_insert(tags, strdup(tag_name), tag);
2139  }
2140 
2141  for (gIter = tag->refs; gIter != NULL; gIter = gIter->next) {
2142  const char *existing_ref = (const char *) gIter->data;
2143 
2144  if (crm_str_eq(existing_ref, obj_ref, TRUE)){
2145  is_existing = TRUE;
2146  break;
2147  }
2148  }
2149 
2150  if (is_existing == FALSE) {
2151  tag->refs = g_list_append(tag->refs, strdup(obj_ref));
2152  crm_trace("Added: tag=%s ref=%s", tag->id, obj_ref);
2153  }
2154 
2155  return TRUE;
2156 }
#define XML_OP_ATTR_ORIGIN
Definition: msg_xml.h:227
#define LOG_TRACE
Definition: logging.h:29
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:164
GListPtr nodes
Definition: status.h:101
#define XML_RSC_OP_LAST_CHANGE
Definition: msg_xml.h:283
const char * uname
Definition: status.h:133
enum rsc_start_requirement needs
Definition: status.h:319
enum pe_ordering type
Definition: status.h:417
A dumping ground.
long long crm_get_msec(const char *input)
Definition: utils.c:578
#define LOG_DEBUG_4
Definition: logging.h:33
action_t * custom_action(resource_t *rsc, char *key, const char *task, node_t *on_node, gboolean optional, gboolean save_action, pe_working_set_t *data_set)
Definition: utils.c:358
void destroy_ticket(gpointer data)
Definition: utils.c:1837
#define crm_notice(fmt, args...)
Definition: logging.h:250
#define CRMD_ACTION_MIGRATED
Definition: crm.h:156
xmlNode * xml
Definition: status.h:246
enum action_tasks get_complex_task(resource_t *rsc, const char *name, gboolean allow_non_atomic)
Definition: utils.c:1139
#define pe_rsc_debug(rsc, fmt, args...)
Definition: internal.h:24
#define pe_flag_have_stonith_resource
Definition: status.h:63
void crm_time_add_seconds(crm_time_t *dt, int value)
Definition: iso8601.c:1174
gboolean safe_str_neq(const char *a, const char *b)
Definition: strings.c:150
#define INFINITY
Definition: crm.h:83
#define pe_rsc_needs_unfencing
Definition: status.h:208
GHashTable * utilization
Definition: status.h:286
#define CRM_OP_FENCE
Definition: crm.h:120
time_t get_effective_time(pe_working_set_t *data_set)
Definition: utils.c:1446
#define XML_ATTR_TRANSITION_MAGIC
Definition: msg_xml.h:361
GHashTable * node_hash_from_list(GListPtr list)
Definition: utils.c:122
int crm_element_value_const_int(const xmlNode *data, const char *name, int *dest)
Definition: xml.c:3758
#define crm_time_log_timeofday
Definition: iso8601.h:71
#define pe_flag_enable_unfencing
Definition: status.h:64
const char * id
Definition: status.h:132
pe_working_set_t * pe_dataset
Definition: utils.c:29
void node_list_exclude(GHashTable *hash, GListPtr list, gboolean merge_scores)
Definition: utils.c:87
int weight
Definition: status.h:166
int sort_index
Definition: status.h:261
struct crm_time_s crm_time_t
Definition: iso8601.h:37
time_t last_granted
Definition: status.h:360
bool pe_can_fence(pe_working_set_t *data_set, node_t *node)
Definition: utils.c:39
#define crm_config_err(fmt...)
Definition: crm_internal.h:256
#define pe_rsc_stopping
Definition: status.h:198
xmlNode * op_defaults
Definition: status.h:110
#define pe_rsc_needs_quorum
Definition: status.h:206
enum action_fail_response on_fail
Definition: status.h:320
#define pe_rsc_orphan
Definition: status.h:175
long long crm_int_helper(const char *text, char **end_text)
Definition: strings.c:80
gint sort_op_by_callid(gconstpointer a, gconstpointer b)
Definition: utils.c:1331
xmlNode * find_rsc_op_entry(resource_t *rsc, const char *key)
Definition: utils.c:1018
char * cancel_task
Definition: status.h:316
GListPtr running_rsc
Definition: status.h:146
enum pe_obj_types variant
Definition: status.h:252
#define XML_LRM_ATTR_INTERVAL
Definition: msg_xml.h:262
#define XML_LRM_ATTR_OP_DIGEST
Definition: msg_xml.h:276
gboolean pending
Definition: status.h:138
#define XML_ATTR_TIMEOUT
Definition: msg_xml.h:94
#define CRMD_ACTION_PROMOTE
Definition: crm.h:164
#define XML_LRM_ATTR_OP_RESTART
Definition: msg_xml.h:277
int crm_parse_int(const char *text, const char *default_text)
Definition: strings.c:125
void get_rsc_attributes(GHashTable *meta_hash, resource_t *rsc, node_t *node, pe_working_set_t *data_set)
Definition: complex.c:153
gboolean fixed
Definition: status.h:167
int get_failcount(node_t *node, resource_t *rsc, time_t *last_failure, pe_working_set_t *data_set)
Definition: utils.c:1500
enum action_tasks text2task(const char *task)
Definition: common.c:230
no_quorum_policy_t no_quorum_policy
Definition: status.h:95
GListPtr find_actions_exact(GListPtr input, const char *key, node_t *on_node)
Definition: utils.c:1233
const char * pe_pref(GHashTable *options, const char *name)
Definition: common.c:187
void dump_node_capacity(int level, const char *comment, node_t *node)
Definition: utils.c:261
char * clone_name
Definition: status.h:245
action_t * find_first_action(GListPtr input, const char *uuid, const char *task, node_t *on_node)
Definition: utils.c:1163
xmlNode * params_restart
Definition: internal.h:261
xmlNode * op_entry
Definition: status.h:312
#define do_crm_log_alias(level, file, function, line, fmt, args...)
Log a message as if it came from a different code location.
Definition: logging.h:196
resource_t * uber_parent(resource_t *rsc)
Definition: complex.c:781
int id
Definition: status.h:307
#define clear_bit(word, bit)
Definition: crm_internal.h:192
void resource_location(resource_t *rsc, node_t *node, int score, const char *tag, pe_working_set_t *data_set)
Definition: utils.c:1287
#define RSC_START
Definition: crm.h:181
int get_target_rc(xmlNode *xml_op)
Definition: unpack.c:2937
GHashTable * tickets
Definition: status.h:98
enum rsc_role_e role
Definition: status.h:281
#define XML_OP_ATTR_ON_FAIL
Definition: msg_xml.h:223
node_t * node_copy(const node_t *this_node)
Definition: utils.c:66
GListPtr children
Definition: status.h:288
gboolean get_target_role(resource_t *rsc, enum rsc_role_e *role)
Definition: utils.c:1732
void print_resource(int log_level, const char *pre_text, resource_t *rsc, gboolean details)
Definition: utils.c:1068
GListPtr actions_before
Definition: status.h:353
#define crm_time_log_duration
Definition: iso8601.h:73
gboolean order_actions(action_t *lh_action, action_t *rh_action, enum pe_ordering order)
Definition: utils.c:1768
#define XML_LRM_ATTR_OP_SECURE
Definition: msg_xml.h:278
gboolean is_rsc_baremetal_remote_node(resource_t *rsc, pe_working_set_t *data_set)
Definition: remote.c:25
GHashTable * extra
Definition: status.h:331
char * id
Definition: status.h:244
GHashTable * parameters
Definition: status.h:285
#define CRMD_ACTION_START
Definition: crm.h:158
xmlNode * copy_xml(xmlNode *src_node)
Definition: xml.c:2633
int get_failcount_all(node_t *node, resource_t *rsc, time_t *last_failure, pe_working_set_t *data_set)
Definition: utils.c:1699
gboolean ghash_free_str_str(gpointer key, gpointer value, gpointer user_data)
#define XML_TAG_ATTR_SETS
Definition: msg_xml.h:176
GHashTable * utilization
Definition: status.h:154
#define XML_LRM_ATTR_TASK
Definition: msg_xml.h:263
const char * role2text(enum rsc_role_e role)
Definition: common.c:343
void hash2field(gpointer key, gpointer value, gpointer user_data)
Definition: xml.c:4742
gboolean add_tag_ref(GHashTable *tags, const char *tag_name, const char *obj_ref)
Definition: utils.c:2122
#define CRMD_ACTION_STOP
Definition: crm.h:161
#define pe_rsc_starting
Definition: status.h:197
#define pe_warn(fmt...)
Definition: internal.h:28
struct node_shared_s * details
Definition: status.h:169
char * calculate_operation_digest(xmlNode *local_cib, const char *version)
Calculate and return digest of XML operation.
Definition: digest.c:175
#define CRMD_ACTION_DEMOTE
Definition: crm.h:166
#define set_bit(word, bit)
Definition: crm_internal.h:191
gboolean unclean
Definition: status.h:139
#define crm_debug(fmt, args...)
Definition: logging.h:253
Utility functions.
#define XML_ATTR_ID
Definition: msg_xml.h:100
GListPtr find_recurring_actions(GListPtr input, node_t *not_on_node)
Definition: utils.c:1105
char * digest_all_calc
Definition: internal.h:262
char * clone_strip(const char *last_rsc_id)
Definition: unpack.c:1523
crm_time_t * crm_time_calculate_duration(crm_time_t *dt, crm_time_t *value)
Definition: iso8601.c:1070
ticket_t * ticket_new(const char *ticket_id, pe_working_set_t *data_set)
Definition: utils.c:1849
char * score2char(int score)
Definition: utils.c:277
resource_object_functions_t * fns
Definition: status.h:253
char * task
Definition: status.h:314
#define sort_return(an_int, why)
Definition: utils.c:1321
void pe_free_action(action_t *action)
Definition: utils.c:1084
resource_t * container
Definition: status.h:294
GHashTable * allowed_nodes
Definition: status.h:279
unsigned long long crm_get_interval(const char *input)
Definition: utils.c:553
GHashTable * digest_cache
Definition: status.h:157
#define crm_trace(fmt, args...)
Definition: logging.h:254
#define do_crm_log(level, fmt, args...)
Log a message.
Definition: logging.h:129
enum rsc_digest_cmp_val rc
Definition: internal.h:258
void set_bit_recursive(resource_t *rsc, unsigned long long flag)
Definition: utils.c:2040
char * digest_secure_calc
Definition: internal.h:263
void dump_rsc_utilization(int level, const char *comment, resource_t *rsc, node_t *node)
Definition: utils.c:282
GHashTable * meta
Definition: status.h:330
gint sort_node_uname(gconstpointer a, gconstpointer b)
Definition: utils.c:164
GListPtr refs
Definition: status.h:367
const char * stonith_action
Definition: status.h:88
const char * crm_element_value_const(const xmlNode *data, const char *name)
Definition: xml.c:3764
int get_failcount_full(node_t *node, resource_t *rsc, time_t *last_failure, bool effective, xmlNode *xml_op, pe_working_set_t *data_set)
Definition: utils.c:1625
void pe_fence_node(pe_working_set_t *data_set, node_t *node, const char *reason)
Definition: unpack.c:66
#define XML_TAG_META_SETS
Definition: msg_xml.h:177
GListPtr actions
Definition: status.h:108
Wrappers for and extensions to libxml2.
GHashTable * config_hash
Definition: status.h:97
xmlNode * create_xml_node(xmlNode *parent, const char *name)
Definition: xml.c:2532
long long int crm_time_get_seconds_since_epoch(crm_time_t *dt)
Definition: iso8601.c:305
int crm_element_value_int(xmlNode *data, const char *name, int *dest)
Definition: xml.c:3745
const char * crm_element_value(xmlNode *data, const char *name)
Definition: xml.c:4987
unsigned long long flags
Definition: status.h:268
#define crm_time_log(level, prefix, dt, flags)
Definition: iso8601.h:66
xmlNode * get_object_root(const char *object_type, xmlNode *the_root)
Definition: cib_utils.c:230
#define XML_RSC_ATTR_TARGET_ROLE
Definition: msg_xml.h:206
char * uuid
Definition: status.h:315
#define XML_LRM_ATTR_RESTART_DIGEST
Definition: msg_xml.h:279
void unpack_operation(action_t *action, xmlNode *xml_obj, resource_t *container, pe_working_set_t *data_set)
Definition: utils.c:655
#define crm_time_log_with_timezone
Definition: iso8601.h:72
enum rsc_role_e text2role(const char *role)
Definition: common.c:363
xmlNode * input
Definition: status.h:82
gboolean crm_str_eq(const char *a, const char *b, gboolean use_case)
Definition: strings.c:213
GListPtr fillers
Definition: status.h:295
void filter_action_parameters(xmlNode *param_set, const char *version)
Definition: utils.c:887
int failure_timeout
Definition: status.h:262
xmlNode * params_all
Definition: internal.h:259
int remote_reconnect_interval
Definition: status.h:301
gboolean decode_transition_magic(const char *magic, char **uuid, int *transition_id, int *action_id, int *op_status, int *op_rc, int *target_rc)
Definition: utils.c:778
#define XML_LRM_ATTR_TARGET_UUID
Definition: msg_xml.h:266
node_t * node
Definition: status.h:311
long long int crm_time_get_seconds(crm_time_t *dt)
Definition: iso8601.c:269
gboolean(* active)(resource_t *, gboolean)
Definition: complex.h:47
void hash2metafield(gpointer key, gpointer value, gpointer user_data)
Definition: xml.c:4758
action_t * action
Definition: status.h:419
GListPtr actions
Definition: status.h:273
void dump_node_scores_worker(int level, const char *file, const char *function, int line, resource_t *rsc, const char *comment, GHashTable *nodes)
Definition: utils.c:173
pe_ordering
Definition: status.h:377
void(* print)(resource_t *, const char *, long, void *)
Definition: complex.h:46
#define pe_rsc_unique
Definition: status.h:181
gint sort_rsc_index(gconstpointer a, gconstpointer b)
Definition: utils.c:304
GHashTable * meta
Definition: status.h:284
void trigger_unfencing(resource_t *rsc, node_t *node, const char *reason, action_t *dependency, pe_working_set_t *data_set)
Definition: utils.c:2087
const char * rsc_printable_id(resource_t *rsc)
Definition: utils.c:2018
void add_hash_param(GHashTable *hash, const char *name, const char *value)
Definition: common.c:419
#define pe_set_action_bit(action, bit)
Definition: internal.h:31
GListPtr find_actions(GListPtr input, const char *key, const node_t *on_node)
Definition: utils.c:1193
int char2score(const char *score)
Definition: utils.c:225
#define crm_err(fmt, args...)
Definition: logging.h:248
xmlXPathObjectPtr xpath_search(xmlNode *xml_top, const char *path)
Definition: xpath.c:145
#define RSC_STATUS
Definition: crm.h:195
#define RSC_PROMOTE
Definition: crm.h:187
crm_time_t * crm_time_new(const char *string)
Definition: iso8601.c:98
GHashTable * attrs
Definition: status.h:151
#define pe_clear_action_bit(action, bit)
Definition: internal.h:32
op_digest_cache_t * rsc_action_digest_cmp(resource_t *rsc, xmlNode *xml_op, node_t *node, pe_working_set_t *data_set)
Definition: utils.c:1928
enum rsc_role_e next_role
Definition: status.h:282
gboolean online
Definition: status.h:135
void xml_remove_prop(xmlNode *obj, const char *name)
Definition: xml.c:3782
xmlNode * getXpathResult(xmlXPathObjectPtr xpathObj, int index)
Definition: xpath.c:64
gboolean shutdown
Definition: status.h:141
void print_str_str(gpointer key, gpointer value, gpointer user_data)
Definition: utils.c:1060
GListPtr actions_after
Definition: status.h:354
xmlNode * params_secure
Definition: internal.h:260
int merge_weights(int w1, int w2)
Definition: common.c:382
#define XML_LRM_ATTR_CALLID
Definition: msg_xml.h:275
#define pe_rsc_managed
Definition: status.h:176
#define CRMD_ACTION_MIGRATE
Definition: crm.h:155
enum rsc_role_e fail_role
Definition: status.h:321
char * id
Definition: status.h:366
#define CRM_ASSERT(expr)
Definition: error.h:35
char data[0]
Definition: internal.h:58
#define XML_ATTR_CRM_VERSION
Definition: msg_xml.h:83
int crm_time_compare(crm_time_t *dt, crm_time_t *rhs)
Definition: iso8601.c:1147
node_t * allocated_to
Definition: status.h:276
rsc_role_e
Definition: common.h:81
char * generate_op_key(const char *rsc_id, const char *op_type, int interval)
Definition: utils.c:633
node_t * pe_find_node_id(GListPtr node_list, const char *id)
Definition: status.c:282
enum pe_action_flags flags
Definition: status.h:318
#define XML_LRM_ATTR_RC
Definition: msg_xml.h:274
gboolean standby
Definition: status.h:361
Definition: status.h:365
#define XML_OP_ATTR_START_DELAY
Definition: msg_xml.h:224
#define pe_flag_have_quorum
Definition: status.h:57
int rsc_discover_mode
Definition: status.h:170
void unpack_instance_attributes(xmlNode *top, xmlNode *xml_obj, const char *set_name, GHashTable *node_hash, GHashTable *hash, const char *always_first, gboolean overwrite, crm_time_t *now)
Definition: rules.c:724
action_t * get_pseudo_op(const char *name, pe_working_set_t *data_set)
Definition: utils.c:1820
gboolean granted
Definition: status.h:359
Definition: status.h:165
gboolean crm_is_true(const char *s)
Definition: strings.c:165
action_t * pe_fence_op(node_t *node, const char *op, bool optional, pe_working_set_t *data_set)
Definition: utils.c:2053
resource_t * rsc
Definition: status.h:310
#define XML_LRM_ATTR_TARGET
Definition: msg_xml.h:265
#define pe_rsc_trace(rsc, fmt, args...)
Definition: internal.h:25
char * crm_concat(const char *prefix, const char *suffix, char join)
Definition: strings.c:32
GHashTable * singletons
Definition: status.h:99
#define ID(x)
Definition: msg_xml.h:423
unsigned long long flags
Definition: status.h:91
#define pe_err(fmt...)
Definition: internal.h:27
xmlNode * ops_xml
Definition: status.h:248
char * crm_itoa(int an_int)
Definition: strings.c:60
resource_t * pe_find_resource(GListPtr rsc_list, const char *id_rh)
Definition: status.c:252
#define pe_rsc_needs_fencing
Definition: status.h:207
#define safe_str_eq(a, b)
Definition: util.h:63
char * id
Definition: status.h:358
char * crm_strdup_printf(char const *format,...) __attribute__((__format__(__printf__
#define crm_str_hash
Definition: crm.h:204
gint sort_rsc_priority(gconstpointer a, gconstpointer b)
Definition: utils.c:331
void freeXpathObject(xmlXPathObjectPtr xpathObj)
Definition: xpath.c:45
void print_node(const char *pre_text, node_t *node, gboolean details)
Definition: utils.c:1024
#define pe_flag_sanitized
Definition: status.h:79
#define pe_rsc_fence_device
Definition: status.h:182
GList * GListPtr
Definition: crm.h:198
#define CRMD_ACTION_CANCEL
Definition: crm.h:152
crm_time_t * now
Definition: status.h:83
#define XML_TAG_PARAMS
Definition: msg_xml.h:179
#define crm_info(fmt, args...)
Definition: logging.h:251
char * digest_restart_calc
Definition: internal.h:264
void g_hash_destroy_str(gpointer data)
Definition: strings.c:74
GListPtr node_list_dup(GListPtr list1, gboolean reset, gboolean filter)
Definition: utils.c:138
char * score2char_stack(int score, char *buf, size_t len)
Definition: utils.c:263
#define crm_time_log_date
Definition: iso8601.h:70
GHashTable * state
Definition: status.h:362
#define pe_flag_stonith_enabled
Definition: status.h:62
action_tasks
Definition: common.h:52
void clear_bit_recursive(resource_t *rsc, unsigned long long flag)
Definition: utils.c:2027
int priority
Definition: status.h:259
#define CRMD_ACTION_STATUS
Definition: crm.h:172
void crm_time_free(crm_time_t *dt)
Definition: iso8601.c:115