pacemaker  2.0.3-4b1f869f0f
Scalable High-Availability cluster resource manager
pcmk_sched_transition.c
Go to the documentation of this file.
1 /*
2  * Copyright 2009-2019 the Pacemaker project contributors
3  *
4  * The version control history for this file may have further details.
5  *
6  * This source code is licensed under the GNU General Public License version 2
7  * or later (GPLv2+) WITHOUT ANY WARRANTY.
8  */
9 
10 #include <crm_internal.h>
11 
12 #include <stdio.h>
13 #include <unistd.h>
14 #include <stdlib.h>
15 
16 #include <sys/stat.h>
17 #include <sys/param.h>
18 #include <sys/types.h>
19 #include <dirent.h>
20 
21 #include <crm/crm.h>
22 #include <crm/lrmd.h> // lrmd_event_data_t, lrmd_free_event()
23 #include <crm/cib.h>
24 #include <crm/common/util.h>
25 #include <crm/common/iso8601.h>
26 #include <crm/pengine/status.h>
27 #include <pacemaker-internal.h>
28 
29 static bool fake_quiet = FALSE;
30 static cib_t *fake_cib = NULL;
31 static GListPtr fake_resource_list = NULL;
32 static GListPtr fake_op_fail_list = NULL;
33 gboolean bringing_nodes_online = FALSE;
34 
35 #define STATUS_PATH_MAX 512
36 
37 #define quiet_log(fmt, args...) do { \
38  if(fake_quiet) { \
39  crm_trace(fmt, ##args); \
40  } else { \
41  printf(fmt , ##args); \
42  } \
43  } while(0)
44 
45 #define NEW_NODE_TEMPLATE "//"XML_CIB_TAG_NODE"[@uname='%s']"
46 #define NODE_TEMPLATE "//"XML_CIB_TAG_STATE"[@uname='%s']"
47 #define RSC_TEMPLATE "//"XML_CIB_TAG_STATE"[@uname='%s']//"XML_LRM_TAG_RESOURCE"[@id='%s']"
48 
49 
50 static void
51 inject_transient_attr(xmlNode * cib_node, const char *name, const char *value)
52 {
53  xmlNode *attrs = NULL;
54  xmlNode *instance_attrs = NULL;
55  xmlChar *node_path;
56  const char *node_uuid = ID(cib_node);
57 
58  node_path = xmlGetNodePath(cib_node);
59  quiet_log(" + Injecting attribute %s=%s into %s '%s'\n",
60  name, value, node_path, ID(cib_node));
61  free(node_path);
62 
64  if (attrs == NULL) {
66  crm_xml_add(attrs, XML_ATTR_ID, node_uuid);
67  }
68 
69  instance_attrs = first_named_child(attrs, XML_TAG_ATTR_SETS);
70  if (instance_attrs == NULL) {
71  instance_attrs = create_xml_node(attrs, XML_TAG_ATTR_SETS);
72  crm_xml_add(instance_attrs, XML_ATTR_ID, node_uuid);
73  }
74 
75  crm_create_nvpair_xml(instance_attrs, NULL, name, value);
76 }
77 
78 static void
79 update_failcounts(xmlNode * cib_node, const char *resource, const char *task,
80  guint interval_ms, int rc)
81 {
82  if (rc == 0) {
83  return;
84 
85  } else if ((rc == 7) && (interval_ms == 0)) {
86  return;
87 
88  } else {
89  char *name = NULL;
90  char *now = crm_ttoa(time(NULL));
91 
92  name = crm_failcount_name(resource, task, interval_ms);
93  inject_transient_attr(cib_node, name, "value++");
94  free(name);
95 
96  name = crm_lastfailure_name(resource, task, interval_ms);
97  inject_transient_attr(cib_node, name, now);
98  free(name);
99  free(now);
100  }
101 }
102 
103 static void
104 create_node_entry(cib_t * cib_conn, const char *node)
105 {
106  int rc = pcmk_ok;
107  char *xpath = crm_strdup_printf(NEW_NODE_TEMPLATE, node);
108 
109  rc = cib_conn->cmds->query(cib_conn, xpath, NULL, cib_xpath | cib_sync_call | cib_scope_local);
110 
111  if (rc == -ENXIO) {
112  xmlNode *cib_object = create_xml_node(NULL, XML_CIB_TAG_NODE);
113 
114  crm_xml_add(cib_object, XML_ATTR_ID, node); // Use node name as ID
115  crm_xml_add(cib_object, XML_ATTR_UNAME, node);
116  cib_conn->cmds->create(cib_conn, XML_CIB_TAG_NODES, cib_object,
118  /* Not bothering with subsequent query to see if it exists,
119  we'll bomb out later in the call to query_node_uuid()... */
120 
121  free_xml(cib_object);
122  }
123 
124  free(xpath);
125 }
126 
127 static lrmd_event_data_t *
128 create_op(xmlNode *cib_resource, const char *task, guint interval_ms,
129  int outcome)
130 {
131  lrmd_event_data_t *op = NULL;
132  xmlNode *xop = NULL;
133 
134  op = calloc(1, sizeof(lrmd_event_data_t));
135 
136  op->rsc_id = strdup(ID(cib_resource));
137  op->interval_ms = interval_ms;
138  op->op_type = strdup(task);
139 
140  op->rc = outcome;
141  op->op_status = 0;
142  op->params = NULL; /* TODO: Fill me in */
143  op->t_run = (unsigned int) time(NULL);
144  op->t_rcchange = op->t_run;
145 
146  op->call_id = 0;
147  for (xop = __xml_first_child_element(cib_resource); xop != NULL;
148  xop = __xml_next_element(xop)) {
149 
150  int tmp = 0;
151 
153  if (tmp > op->call_id) {
154  op->call_id = tmp;
155  }
156  }
157  op->call_id++;
158 
159  return op;
160 }
161 
162 static xmlNode *
163 inject_op(xmlNode * cib_resource, lrmd_event_data_t * op, int target_rc)
164 {
165  return pcmk__create_history_xml(cib_resource, op, CRM_FEATURE_SET,
166  target_rc, NULL, crm_system_name,
167  LOG_TRACE);
168 }
169 
170 static xmlNode *
171 inject_node_state(cib_t * cib_conn, const char *node, const char *uuid)
172 {
173  int rc = pcmk_ok;
174  xmlNode *cib_object = NULL;
175  char *xpath = crm_strdup_printf(NODE_TEMPLATE, node);
176 
177  if (bringing_nodes_online) {
178  create_node_entry(cib_conn, node);
179  }
180 
181  rc = cib_conn->cmds->query(cib_conn, xpath, &cib_object,
183 
184  if (cib_object && ID(cib_object) == NULL) {
185  crm_err("Detected multiple node_state entries for xpath=%s, bailing", xpath);
186  crm_log_xml_warn(cib_object, "Duplicates");
187  free(xpath);
189  return NULL; // not reached, but makes static analysis happy
190  }
191 
192  if (rc == -ENXIO) {
193  char *found_uuid = NULL;
194 
195  if (uuid == NULL) {
196  query_node_uuid(cib_conn, node, &found_uuid, NULL);
197  } else {
198  found_uuid = strdup(uuid);
199  }
200 
201  cib_object = create_xml_node(NULL, XML_CIB_TAG_STATE);
202  crm_xml_add(cib_object, XML_ATTR_UUID, found_uuid);
203  crm_xml_add(cib_object, XML_ATTR_UNAME, node);
204  cib_conn->cmds->create(cib_conn, XML_CIB_TAG_STATUS, cib_object,
206  free_xml(cib_object);
207  free(found_uuid);
208 
209  rc = cib_conn->cmds->query(cib_conn, xpath, &cib_object,
211  crm_trace("injecting node state for %s. rc is %d", node, rc);
212  }
213 
214  free(xpath);
215  CRM_ASSERT(rc == pcmk_ok);
216  return cib_object;
217 }
218 
219 static xmlNode *
220 modify_node(cib_t * cib_conn, char *node, gboolean up)
221 {
222  xmlNode *cib_node = inject_node_state(cib_conn, node, NULL);
223 
224  if (up) {
229 
230  } else {
235  }
236 
238  return cib_node;
239 }
240 
241 static xmlNode *
242 find_resource_xml(xmlNode * cib_node, const char *resource)
243 {
244  xmlNode *match = NULL;
245  const char *node = crm_element_value(cib_node, XML_ATTR_UNAME);
246  char *xpath = crm_strdup_printf(RSC_TEMPLATE, node, resource);
247 
248  match = get_xpath_object(xpath, cib_node, LOG_TRACE);
249  free(xpath);
250  return match;
251 }
252 
253 
254 static xmlNode *
255 inject_resource(xmlNode * cib_node, const char *resource, const char *lrm_name,
256  const char *rclass, const char *rtype, const char *rprovider)
257 {
258  xmlNode *lrm = NULL;
259  xmlNode *container = NULL;
260  xmlNode *cib_resource = NULL;
261  char *xpath = NULL;
262 
263  cib_resource = find_resource_xml(cib_node, resource);
264  if (cib_resource != NULL) {
265  /* If an existing LRM history entry uses the resource name,
266  * continue using it, even if lrm_name is different.
267  */
268  return cib_resource;
269  }
270 
271  // Check for history entry under preferred name
272  if (strcmp(resource, lrm_name)) {
273  cib_resource = find_resource_xml(cib_node, lrm_name);
274  if (cib_resource != NULL) {
275  return cib_resource;
276  }
277  }
278 
279  /* One day, add query for class, provider, type */
280 
281  if (rclass == NULL || rtype == NULL) {
282  fprintf(stderr, "Resource %s not found in the status section of %s."
283  " Please supply the class and type to continue\n", resource, ID(cib_node));
284  return NULL;
285 
286  } else if (safe_str_neq(rclass, PCMK_RESOURCE_CLASS_OCF)
292  fprintf(stderr, "Invalid class for %s: %s\n", resource, rclass);
293  return NULL;
294 
295  } else if (is_set(pcmk_get_ra_caps(rclass), pcmk_ra_cap_provider)
296  && (rprovider == NULL)) {
297  fprintf(stderr, "Please specify the provider for resource %s\n", resource);
298  return NULL;
299  }
300 
301  xpath = (char *)xmlGetNodePath(cib_node);
302  crm_info("Injecting new resource %s into %s '%s'", lrm_name, xpath, ID(cib_node));
303  free(xpath);
304 
305  lrm = first_named_child(cib_node, XML_CIB_TAG_LRM);
306  if (lrm == NULL) {
307  const char *node_uuid = ID(cib_node);
308 
309  lrm = create_xml_node(cib_node, XML_CIB_TAG_LRM);
310  crm_xml_add(lrm, XML_ATTR_ID, node_uuid);
311  }
312 
313  container = first_named_child(lrm, XML_LRM_TAG_RESOURCES);
314  if (container == NULL) {
315  container = create_xml_node(lrm, XML_LRM_TAG_RESOURCES);
316  }
317 
318  cib_resource = create_xml_node(container, XML_LRM_TAG_RESOURCE);
319 
320  // If we're creating a new entry, use the preferred name
321  crm_xml_add(cib_resource, XML_ATTR_ID, lrm_name);
322 
323  crm_xml_add(cib_resource, XML_AGENT_ATTR_CLASS, rclass);
324  crm_xml_add(cib_resource, XML_AGENT_ATTR_PROVIDER, rprovider);
325  crm_xml_add(cib_resource, XML_ATTR_TYPE, rtype);
326 
327  return cib_resource;
328 }
329 
330 #define XPATH_MAX 1024
331 
332 static int
333 find_ticket_state(cib_t * the_cib, const char *ticket_id, xmlNode ** ticket_state_xml)
334 {
335  int offset = 0;
336  int rc = pcmk_ok;
337  xmlNode *xml_search = NULL;
338 
339  char *xpath_string = NULL;
340 
341  CRM_ASSERT(ticket_state_xml != NULL);
342  *ticket_state_xml = NULL;
343 
344  xpath_string = calloc(1, XPATH_MAX);
345  offset += snprintf(xpath_string + offset, XPATH_MAX - offset, "%s", "/cib/status/tickets");
346 
347  if (ticket_id) {
348  offset += snprintf(xpath_string + offset, XPATH_MAX - offset, "/%s[@id=\"%s\"]",
349  XML_CIB_TAG_TICKET_STATE, ticket_id);
350  }
351  CRM_LOG_ASSERT(offset > 0);
352  rc = the_cib->cmds->query(the_cib, xpath_string, &xml_search,
354 
355  if (rc != pcmk_ok) {
356  goto bail;
357  }
358 
359  crm_log_xml_debug(xml_search, "Match");
360  if (xml_has_children(xml_search)) {
361  if (ticket_id) {
362  fprintf(stdout, "Multiple ticket_states match ticket_id=%s\n", ticket_id);
363  }
364  *ticket_state_xml = xml_search;
365  } else {
366  *ticket_state_xml = xml_search;
367  }
368 
369  bail:
370  free(xpath_string);
371  return rc;
372 }
373 
374 static int
375 set_ticket_state_attr(const char *ticket_id, const char *attr_name,
376  const char *attr_value, cib_t * cib, int cib_options)
377 {
378  int rc = pcmk_ok;
379  xmlNode *xml_top = NULL;
380  xmlNode *ticket_state_xml = NULL;
381 
382  rc = find_ticket_state(cib, ticket_id, &ticket_state_xml);
383  if (rc == pcmk_ok) {
384  crm_debug("Found a match state for ticket: id=%s", ticket_id);
385  xml_top = ticket_state_xml;
386 
387  } else if (rc != -ENXIO) {
388  return rc;
389 
390  } else {
391  xmlNode *xml_obj = NULL;
392 
393  xml_top = create_xml_node(NULL, XML_CIB_TAG_STATUS);
394  xml_obj = create_xml_node(xml_top, XML_CIB_TAG_TICKETS);
395  ticket_state_xml = create_xml_node(xml_obj, XML_CIB_TAG_TICKET_STATE);
396  crm_xml_add(ticket_state_xml, XML_ATTR_ID, ticket_id);
397  }
398 
399  crm_xml_add(ticket_state_xml, attr_name, attr_value);
400 
401  crm_log_xml_debug(xml_top, "Update");
402 
403  rc = cib->cmds->modify(cib, XML_CIB_TAG_STATUS, xml_top, cib_options);
404 
405  free_xml(xml_top);
406 
407  return rc;
408 }
409 
410 void
412  const char *quorum, const char *watchdog, GListPtr node_up, GListPtr node_down, GListPtr node_fail,
413  GListPtr op_inject, GListPtr ticket_grant, GListPtr ticket_revoke,
414  GListPtr ticket_standby, GListPtr ticket_activate)
415 {
416  int rc = pcmk_ok;
417  GListPtr gIter = NULL;
418 
419  xmlNode *cib_op = NULL;
420  xmlNode *cib_node = NULL;
421  xmlNode *cib_resource = NULL;
422 
423  lrmd_event_data_t *op = NULL;
424 
425  if (quorum) {
426  xmlNode *top = create_xml_node(NULL, XML_TAG_CIB);
427 
428  quiet_log(" + Setting quorum: %s\n", quorum);
429  /* crm_xml_add(top, XML_ATTR_DC_UUID, dc_uuid); */
430  crm_xml_add(top, XML_ATTR_HAVE_QUORUM, quorum);
431 
432  rc = cib->cmds->modify(cib, NULL, top, cib_sync_call | cib_scope_local);
433  CRM_ASSERT(rc == pcmk_ok);
434  }
435 
436  if (watchdog) {
437  quiet_log(" + Setting watchdog: %s\n", watchdog);
438 
440  XML_CIB_TAG_CRMCONFIG, NULL, NULL, NULL, NULL,
441  XML_ATTR_HAVE_WATCHDOG, watchdog, FALSE, NULL, NULL);
442 
443  CRM_ASSERT(rc == pcmk_ok);
444  }
445 
446  for (gIter = node_up; gIter != NULL; gIter = gIter->next) {
447  char *node = (char *)gIter->data;
448 
449  quiet_log(" + Bringing node %s online\n", node);
450  cib_node = modify_node(cib, node, TRUE);
451  CRM_ASSERT(cib_node != NULL);
452 
453  rc = cib->cmds->modify(cib, XML_CIB_TAG_STATUS, cib_node,
455  CRM_ASSERT(rc == pcmk_ok);
456  free_xml(cib_node);
457  }
458 
459  for (gIter = node_down; gIter != NULL; gIter = gIter->next) {
460  char xpath[STATUS_PATH_MAX];
461  char *node = (char *)gIter->data;
462 
463  quiet_log(" + Taking node %s offline\n", node);
464  cib_node = modify_node(cib, node, FALSE);
465  CRM_ASSERT(cib_node != NULL);
466 
467  rc = cib->cmds->modify(cib, XML_CIB_TAG_STATUS, cib_node,
469  CRM_ASSERT(rc == pcmk_ok);
470  free_xml(cib_node);
471 
472  snprintf(xpath, STATUS_PATH_MAX, "//node_state[@uname='%s']/%s", node, XML_CIB_TAG_LRM);
473  cib->cmds->remove(cib, xpath, NULL,
475 
476  snprintf(xpath, STATUS_PATH_MAX, "//node_state[@uname='%s']/%s", node,
478  cib->cmds->remove(cib, xpath, NULL,
480 
481  }
482 
483  for (gIter = node_fail; gIter != NULL; gIter = gIter->next) {
484  char *node = (char *)gIter->data;
485 
486  quiet_log(" + Failing node %s\n", node);
487  cib_node = modify_node(cib, node, TRUE);
489  CRM_ASSERT(cib_node != NULL);
490 
491  rc = cib->cmds->modify(cib, XML_CIB_TAG_STATUS, cib_node,
493  CRM_ASSERT(rc == pcmk_ok);
494  free_xml(cib_node);
495  }
496 
497  for (gIter = ticket_grant; gIter != NULL; gIter = gIter->next) {
498  char *ticket_id = (char *)gIter->data;
499 
500  quiet_log(" + Granting ticket %s\n", ticket_id);
501  rc = set_ticket_state_attr(ticket_id, "granted", "true",
503 
504  CRM_ASSERT(rc == pcmk_ok);
505  }
506 
507  for (gIter = ticket_revoke; gIter != NULL; gIter = gIter->next) {
508  char *ticket_id = (char *)gIter->data;
509 
510  quiet_log(" + Revoking ticket %s\n", ticket_id);
511  rc = set_ticket_state_attr(ticket_id, "granted", "false",
513 
514  CRM_ASSERT(rc == pcmk_ok);
515  }
516 
517  for (gIter = ticket_standby; gIter != NULL; gIter = gIter->next) {
518  char *ticket_id = (char *)gIter->data;
519 
520  quiet_log(" + Making ticket %s standby\n", ticket_id);
521  rc = set_ticket_state_attr(ticket_id, "standby", "true",
523 
524  CRM_ASSERT(rc == pcmk_ok);
525  }
526 
527  for (gIter = ticket_activate; gIter != NULL; gIter = gIter->next) {
528  char *ticket_id = (char *)gIter->data;
529 
530  quiet_log(" + Activating ticket %s\n", ticket_id);
531  rc = set_ticket_state_attr(ticket_id, "standby", "false",
533 
534  CRM_ASSERT(rc == pcmk_ok);
535  }
536 
537  for (gIter = op_inject; gIter != NULL; gIter = gIter->next) {
538  char *spec = (char *)gIter->data;
539 
540  int rc = 0;
541  int outcome = 0;
542  guint interval_ms = 0;
543 
544  char *key = NULL;
545  char *node = NULL;
546  char *task = NULL;
547  char *resource = NULL;
548 
549  const char *rtype = NULL;
550  const char *rclass = NULL;
551  const char *rprovider = NULL;
552 
553  resource_t *rsc = NULL;
554 
555  quiet_log(" + Injecting %s into the configuration\n", spec);
556 
557  key = calloc(1, strlen(spec) + 1);
558  node = calloc(1, strlen(spec) + 1);
559  rc = sscanf(spec, "%[^@]@%[^=]=%d", key, node, &outcome);
560  if (rc != 3) {
561  fprintf(stderr, "Invalid operation spec: %s. Only found %d fields\n", spec, rc);
562  free(key);
563  free(node);
564  continue;
565  }
566 
567  parse_op_key(key, &resource, &task, &interval_ms);
568 
569  rsc = pe_find_resource(data_set->resources, resource);
570  if (rsc == NULL) {
571  fprintf(stderr, " - Invalid resource name: %s\n", resource);
572  } else {
573  rclass = crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS);
574  rtype = crm_element_value(rsc->xml, XML_ATTR_TYPE);
575  rprovider = crm_element_value(rsc->xml, XML_AGENT_ATTR_PROVIDER);
576 
577  cib_node = inject_node_state(cib, node, NULL);
578  CRM_ASSERT(cib_node != NULL);
579 
580  update_failcounts(cib_node, resource, task, interval_ms, outcome);
581 
582  cib_resource = inject_resource(cib_node, resource, resource,
583  rclass, rtype, rprovider);
584  CRM_ASSERT(cib_resource != NULL);
585 
586  op = create_op(cib_resource, task, interval_ms, outcome);
587  CRM_ASSERT(op != NULL);
588 
589  cib_op = inject_op(cib_resource, op, 0);
590  CRM_ASSERT(cib_op != NULL);
591  lrmd_free_event(op);
592 
593  rc = cib->cmds->modify(cib, XML_CIB_TAG_STATUS, cib_node,
595  CRM_ASSERT(rc == pcmk_ok);
596  }
597  free(task);
598  free(node);
599  free(key);
600  }
601 }
602 
603 static gboolean
604 exec_pseudo_action(crm_graph_t * graph, crm_action_t * action)
605 {
606  const char *node = crm_element_value(action->xml, XML_LRM_ATTR_TARGET);
607  const char *task = crm_element_value(action->xml, XML_LRM_ATTR_TASK_KEY);
608 
609  action->confirmed = TRUE;
610 
611  quiet_log(" * Pseudo action: %s%s%s\n", task, node ? " on " : "", node ? node : "");
612  update_graph(graph, action);
613  return TRUE;
614 }
615 
616 static gboolean
617 exec_rsc_action(crm_graph_t * graph, crm_action_t * action)
618 {
619  int rc = 0;
620  GListPtr gIter = NULL;
621  lrmd_event_data_t *op = NULL;
622  int target_outcome = 0;
623 
624  const char *rtype = NULL;
625  const char *rclass = NULL;
626  const char *resource = NULL;
627  const char *rprovider = NULL;
628  const char *lrm_name = NULL;
629  const char *operation = crm_element_value(action->xml, "operation");
630  const char *target_rc_s = crm_meta_value(action->params, XML_ATTR_TE_TARGET_RC);
631 
632  xmlNode *cib_node = NULL;
633  xmlNode *cib_resource = NULL;
634  xmlNode *action_rsc = first_named_child(action->xml, XML_CIB_TAG_RESOURCE);
635 
636  char *node = crm_element_value_copy(action->xml, XML_LRM_ATTR_TARGET);
637  char *uuid = crm_element_value_copy(action->xml, XML_LRM_ATTR_TARGET_UUID);
638  const char *router_node = crm_element_value(action->xml, XML_LRM_ATTR_ROUTER_NODE);
639 
640  if (safe_str_eq(operation, CRM_OP_PROBED)
641  || safe_str_eq(operation, CRM_OP_REPROBE)) {
642  crm_info("Skipping %s op for %s", operation, node);
643  goto done;
644  }
645 
646  if (action_rsc == NULL) {
647  crm_log_xml_err(action->xml, "Bad");
648  free(node); free(uuid);
649  return FALSE;
650  }
651 
652  /* Look for the preferred name
653  * If not found, try the expected 'local' name
654  * If not found use the preferred name anyway
655  */
656  resource = crm_element_value(action_rsc, XML_ATTR_ID);
657  CRM_ASSERT(resource != NULL); // makes static analysis happy
658  lrm_name = resource; // Preferred name when writing history
659  if (pe_find_resource(fake_resource_list, resource) == NULL) {
660  const char *longname = crm_element_value(action_rsc, XML_ATTR_ID_LONG);
661 
662  if (longname && pe_find_resource(fake_resource_list, longname)) {
663  resource = longname;
664  }
665  }
666 
667  if (safe_str_eq(operation, "delete") || safe_str_eq(operation, RSC_METADATA)) {
668  quiet_log(" * Resource action: %-15s %s on %s\n", resource, operation, node);
669  goto done;
670  }
671 
672  rclass = crm_element_value(action_rsc, XML_AGENT_ATTR_CLASS);
673  rtype = crm_element_value(action_rsc, XML_ATTR_TYPE);
674  rprovider = crm_element_value(action_rsc, XML_AGENT_ATTR_PROVIDER);
675 
676  if (target_rc_s != NULL) {
677  target_outcome = crm_parse_int(target_rc_s, "0");
678  }
679 
680  CRM_ASSERT(fake_cib->cmds->query(fake_cib, NULL, NULL, cib_sync_call | cib_scope_local) ==
681  pcmk_ok);
682 
683  cib_node = inject_node_state(fake_cib, node, (router_node? node : uuid));
684  CRM_ASSERT(cib_node != NULL);
685 
686  cib_resource = inject_resource(cib_node, resource, lrm_name,
687  rclass, rtype, rprovider);
688  if (cib_resource == NULL) {
689  crm_err("invalid resource in transition");
690  free(node); free(uuid);
691  free_xml(cib_node);
692  return FALSE;
693  }
694 
695  op = convert_graph_action(cib_resource, action, 0, target_outcome);
696  if (op->interval_ms) {
697  quiet_log(" * Resource action: %-15s %s=%u on %s\n",
698  resource, op->op_type, op->interval_ms, node);
699  } else {
700  quiet_log(" * Resource action: %-15s %s on %s\n", resource, op->op_type, node);
701  }
702 
703  for (gIter = fake_op_fail_list; gIter != NULL; gIter = gIter->next) {
704  char *spec = (char *)gIter->data;
705  char *key = NULL;
706  const char *match_name = NULL;
707 
708  // Allow user to specify anonymous clone with or without instance number
709  key = crm_strdup_printf(CRM_OP_FMT "@%s=", resource, op->op_type,
710  op->interval_ms, node);
711  if (strncasecmp(key, spec, strlen(key)) == 0) {
712  match_name = resource;
713  }
714  free(key);
715 
716  if ((match_name == NULL) && strcmp(resource, lrm_name)) {
717  key = crm_strdup_printf(CRM_OP_FMT "@%s=", lrm_name, op->op_type,
718  op->interval_ms, node);
719  if (strncasecmp(key, spec, strlen(key)) == 0) {
720  match_name = lrm_name;
721  }
722  free(key);
723  }
724 
725  if (match_name != NULL) {
726 
727  rc = sscanf(spec, "%*[^=]=%d", (int *) &op->rc);
728  // ${match_name}_${task}_${interval_in_ms}@${node}=${rc}
729 
730  if (rc != 1) {
731  fprintf(stderr,
732  "Invalid failed operation spec: %s. Result code must be integer\n",
733  spec);
734  continue;
735  }
736  action->failed = TRUE;
737  graph->abort_priority = INFINITY;
738  printf("\tPretending action %d failed with rc=%d\n", action->id, op->rc);
739  update_failcounts(cib_node, match_name, op->op_type,
740  op->interval_ms, op->rc);
741  break;
742  }
743  }
744 
745  inject_op(cib_resource, op, target_outcome);
746  lrmd_free_event(op);
747 
748  rc = fake_cib->cmds->modify(fake_cib, XML_CIB_TAG_STATUS, cib_node,
750  CRM_ASSERT(rc == pcmk_ok);
751 
752  done:
753  free(node); free(uuid);
754  free_xml(cib_node);
755  action->confirmed = TRUE;
756  update_graph(graph, action);
757  return TRUE;
758 }
759 
760 static gboolean
761 exec_crmd_action(crm_graph_t * graph, crm_action_t * action)
762 {
763  const char *node = crm_element_value(action->xml, XML_LRM_ATTR_TARGET);
764  const char *task = crm_element_value(action->xml, XML_LRM_ATTR_TASK);
765  xmlNode *rsc = first_named_child(action->xml, XML_CIB_TAG_RESOURCE);
766 
767  action->confirmed = TRUE;
768 
769  if(rsc) {
770  quiet_log(" * Cluster action: %s for %s on %s\n", task, ID(rsc), node);
771  } else {
772  quiet_log(" * Cluster action: %s on %s\n", task, node);
773  }
774  update_graph(graph, action);
775  return TRUE;
776 }
777 
778 static gboolean
779 exec_stonith_action(crm_graph_t * graph, crm_action_t * action)
780 {
781  const char *op = crm_meta_value(action->params, "stonith_action");
782  char *target = crm_element_value_copy(action->xml, XML_LRM_ATTR_TARGET);
783 
784  quiet_log(" * Fencing %s (%s)\n", target, op);
785  if(safe_str_neq(op, "on")) {
786  int rc = 0;
787  char xpath[STATUS_PATH_MAX];
788  xmlNode *cib_node = modify_node(fake_cib, target, FALSE);
789 
790  crm_xml_add(cib_node, XML_ATTR_ORIGIN, __FUNCTION__);
791  CRM_ASSERT(cib_node != NULL);
792 
793  rc = fake_cib->cmds->replace(fake_cib, XML_CIB_TAG_STATUS, cib_node,
795  CRM_ASSERT(rc == pcmk_ok);
796 
797  snprintf(xpath, STATUS_PATH_MAX, "//node_state[@uname='%s']/%s", target, XML_CIB_TAG_LRM);
798  fake_cib->cmds->remove(fake_cib, xpath, NULL,
800 
801  snprintf(xpath, STATUS_PATH_MAX, "//node_state[@uname='%s']/%s", target,
803  fake_cib->cmds->remove(fake_cib, xpath, NULL,
805 
806  free_xml(cib_node);
807  }
808 
809  action->confirmed = TRUE;
810  update_graph(graph, action);
811  free(target);
812  return TRUE;
813 }
814 
815 int
816 run_simulation(pe_working_set_t * data_set, cib_t *cib, GListPtr op_fail_list, bool quiet)
817 {
818  crm_graph_t *transition = NULL;
819  enum transition_status graph_rc = -1;
820 
821  crm_graph_functions_t exec_fns = {
822  exec_pseudo_action,
823  exec_rsc_action,
824  exec_crmd_action,
825  exec_stonith_action,
826  };
827 
828  fake_cib = cib;
829  fake_quiet = quiet;
830  fake_op_fail_list = op_fail_list;
831 
832  quiet_log("\nExecuting cluster transition:\n");
833 
834  set_graph_functions(&exec_fns);
835  transition = unpack_graph(data_set->graph, crm_system_name);
836  print_graph(LOG_DEBUG, transition);
837 
838  fake_resource_list = data_set->resources;
839  do {
840  graph_rc = run_graph(transition);
841 
842  } while (graph_rc == transition_active);
843  fake_resource_list = NULL;
844 
845  if (graph_rc != transition_complete) {
846  fprintf(stdout, "Transition failed: %s\n", transition_status(graph_rc));
847  print_graph(LOG_ERR, transition);
848  }
849  destroy_graph(transition);
850  if (graph_rc != transition_complete) {
851  fprintf(stdout, "An invalid transition was produced\n");
852  }
853 
854  if (quiet == FALSE) {
855  xmlNode *cib_object = NULL;
856  int rc = fake_cib->cmds->query(fake_cib, NULL, &cib_object, cib_sync_call | cib_scope_local);
857 
858  CRM_ASSERT(rc == pcmk_ok);
859  pe_reset_working_set(data_set);
860  data_set->input = cib_object;
861  }
862 
863  if (graph_rc != transition_complete) {
864  return graph_rc;
865  }
866  return 0;
867 }
quiet_log
#define quiet_log(fmt, args...)
Definition: pcmk_sched_transition.c:37
STATUS_PATH_MAX
#define STATUS_PATH_MAX
Definition: pcmk_sched_transition.c:35
GListPtr
GList * GListPtr
Definition: crm.h:214
pe_working_set_s::input
xmlNode * input
Definition: pe_types.h:118
INFINITY
#define INFINITY
Definition: crm.h:95
pe_reset_working_set
void pe_reset_working_set(pe_working_set_t *data_set)
Reset a working set to default state without freeing it.
Definition: status.c:322
CRMD_JOINSTATE_DOWN
#define CRMD_JOINSTATE_DOWN
Definition: crm.h:159
cib_xpath
@ cib_xpath
Definition: cib_types.h:52
XML_LRM_ATTR_TASK_KEY
#define XML_LRM_ATTR_TASK_KEY
Definition: msg_xml.h:261
XML_LRM_TAG_RESOURCE
#define XML_LRM_TAG_RESOURCE
Definition: msg_xml.h:227
pe_find_resource
pe_resource_t * pe_find_resource(GListPtr rsc_list, const char *id_rh)
Definition: status.c:370
PCMK_RESOURCE_CLASS_SYSTEMD
#define PCMK_RESOURCE_CLASS_SYSTEMD
Definition: services.h:46
pe_working_set_s::resources
GListPtr resources
Definition: pe_types.h:139
crm_action_s::failed
gboolean failed
Definition: pcmki_transition.h:58
pacemaker-internal.h
cib_s::cmds
cib_api_operations_t * cmds
Definition: cib_types.h:147
run_simulation
int run_simulation(pe_working_set_t *data_set, cib_t *cib, GListPtr op_fail_list, bool quiet)
Definition: pcmk_sched_transition.c:816
XML_NODE_JOIN_STATE
#define XML_NODE_JOIN_STATE
Definition: msg_xml.h:238
crm_action_s
Definition: pcmki_transition.h:44
XML_CIB_TAG_TICKETS
#define XML_CIB_TAG_TICKETS
Definition: msg_xml.h:385
XML_LRM_ATTR_TARGET_UUID
#define XML_LRM_ATTR_TARGET_UUID
Definition: msg_xml.h:263
cib_api_operations_s::remove
int(* remove)(cib_t *cib, const char *section, xmlNode *data, int call_options)
Definition: cib_types.h:113
LOG_TRACE
#define LOG_TRACE
Definition: logging.h:26
print_graph
void print_graph(unsigned int log_level, crm_graph_t *graph)
Definition: pcmk_trans_utils.c:236
crm_element_value_int
int crm_element_value_int(const xmlNode *data, const char *name, int *dest)
Retrieve the integer value of an XML attribute.
Definition: nvpair.c:555
PCMK_RESOURCE_CLASS_STONITH
#define PCMK_RESOURCE_CLASS_STONITH
Definition: services.h:49
create_xml_node
xmlNode * create_xml_node(xmlNode *parent, const char *name)
Definition: xml.c:1970
crm_action_s::id
int id
Definition: pcmki_transition.h:45
lrmd_event_data_s::rc
enum ocf_exitcode rc
Definition: lrmd.h:221
update_graph
gboolean update_graph(crm_graph_t *graph, crm_action_t *action)
Definition: pcmk_trans_graph.c:91
XML_NODE_IN_CLUSTER
#define XML_NODE_IN_CLUSTER
Definition: msg_xml.h:240
PCMK_RESOURCE_CLASS_OCF
#define PCMK_RESOURCE_CLASS_OCF
Definition: services.h:43
cib_api_operations_s::modify
int(* modify)(cib_t *cib, const char *section, xmlNode *data, int call_options)
Definition: cib_types.h:107
get_xpath_object
xmlNode * get_xpath_object(const char *xpath, xmlNode *xml_obj, int error_level)
Definition: xpath.c:220
XML_CIB_TAG_STATE
#define XML_CIB_TAG_STATE
Definition: msg_xml.h:158
set_graph_functions
void set_graph_functions(crm_graph_functions_t *fns)
Definition: pcmk_trans_utils.c:59
transition_complete
@ transition_complete
Definition: pcmki_transition.h:117
pcmk_ra_cap_provider
@ pcmk_ra_cap_provider
Definition: util.h:145
CRMD_JOINSTATE_MEMBER
#define CRMD_JOINSTATE_MEMBER
Definition: crm.h:161
XML_CIB_TAG_LRM
#define XML_CIB_TAG_LRM
Definition: msg_xml.h:225
OFFLINESTATUS
#define OFFLINESTATUS
Definition: util.h:37
XML_CIB_TAG_TICKET_STATE
#define XML_CIB_TAG_TICKET_STATE
Definition: msg_xml.h:386
crm_err
#define crm_err(fmt, args...)
Definition: logging.h:241
crm_trace
#define crm_trace(fmt, args...)
Definition: logging.h:247
unpack_graph
crm_graph_t * unpack_graph(xmlNode *xml_graph, const char *reference)
Definition: pcmk_trans_unpack.c:163
CRM_OP_PROBED
#define CRM_OP_PROBED
Definition: crm.h:149
safe_str_eq
#define safe_str_eq(a, b)
Definition: util.h:61
XML_TAG_ATTR_SETS
#define XML_TAG_ATTR_SETS
Definition: msg_xml.h:163
ONLINESTATUS
#define ONLINESTATUS
Definition: util.h:36
cib_sync_call
@ cib_sync_call
Definition: cib_types.h:61
XML_ATTR_UNAME
#define XML_ATTR_UNAME
Definition: msg_xml.h:118
convert_graph_action
lrmd_event_data_t * convert_graph_action(xmlNode *resource, crm_action_t *action, int status, int rc)
Definition: pcmk_trans_unpack.c:287
modify_configuration
void modify_configuration(pe_working_set_t *data_set, cib_t *cib, const char *quorum, const char *watchdog, GListPtr node_up, GListPtr node_down, GListPtr node_fail, GListPtr op_inject, GListPtr ticket_grant, GListPtr ticket_revoke, GListPtr ticket_standby, GListPtr ticket_activate)
Definition: pcmk_sched_transition.c:411
free_xml
void free_xml(xmlNode *child)
Definition: xml.c:2130
XML_TAG_TRANSIENT_NODEATTRS
#define XML_TAG_TRANSIENT_NODEATTRS
Definition: msg_xml.h:362
bringing_nodes_online
gboolean bringing_nodes_online
Definition: pcmk_sched_transition.c:33
lrmd_event_data_s::call_id
int call_id
Definition: lrmd.h:210
PCMK_RESOURCE_CLASS_SERVICE
#define PCMK_RESOURCE_CLASS_SERVICE
Definition: services.h:44
XML_NODE_EXPECTED
#define XML_NODE_EXPECTED
Definition: msg_xml.h:239
xml_has_children
gboolean xml_has_children(const xmlNode *root)
Definition: xml.c:3316
XML_CIB_TAG_STATUS
#define XML_CIB_TAG_STATUS
Definition: msg_xml.h:139
lrmd_event_data_s::t_run
unsigned int t_run
Definition: lrmd.h:227
crm_action_s::xml
xmlNode * xml
Definition: pcmki_transition.h:61
XML_ATTR_ID
#define XML_ATTR_ID
Definition: msg_xml.h:96
CRM_OP_REPROBE
#define CRM_OP_REPROBE
Definition: crm.h:150
ID
#define ID(x)
Definition: msg_xml.h:415
XML_CIB_TAG_RESOURCE
#define XML_CIB_TAG_RESOURCE
Definition: msg_xml.h:174
parse_op_key
gboolean parse_op_key(const char *key, char **rsc_id, char **op_type, guint *interval_ms)
Definition: operations.c:47
first_named_child
xmlNode * first_named_child(const xmlNode *parent, const char *name)
Definition: xml.c:4384
XML_CIB_TAG_NODES
#define XML_CIB_TAG_NODES
Definition: msg_xml.h:141
crm_info
#define crm_info(fmt, args...)
Definition: logging.h:244
XML_LRM_ATTR_ROUTER_NODE
#define XML_LRM_ATTR_ROUTER_NODE
Definition: msg_xml.h:268
CRM_LOG_ASSERT
#define CRM_LOG_ASSERT(expr)
Definition: logging.h:143
crm_create_nvpair_xml
xmlNode * crm_create_nvpair_xml(xmlNode *parent, const char *id, const char *name, const char *value)
Create an XML name/value pair.
Definition: nvpair.c:831
lrmd_event_data_s::rsc_id
const char * rsc_id
Definition: lrmd.h:203
XML_AGENT_ATTR_CLASS
#define XML_AGENT_ATTR_CLASS
Definition: msg_xml.h:229
CRM_FEATURE_SET
#define CRM_FEATURE_SET
Definition: crm.h:54
PCMK_RESOURCE_CLASS_UPSTART
#define PCMK_RESOURCE_CLASS_UPSTART
Definition: services.h:47
XML_ATTR_TE_TARGET_RC
#define XML_ATTR_TE_TARGET_RC
Definition: msg_xml.h:361
CRM_OP_FMT
#define CRM_OP_FMT
Definition: crm_internal.h:133
lrmd_event_data_s::t_rcchange
unsigned int t_rcchange
Definition: lrmd.h:229
XML_LRM_ATTR_TASK
#define XML_LRM_ATTR_TASK
Definition: msg_xml.h:260
CRM_EX_SOFTWARE
@ CRM_EX_SOFTWARE
Definition: results.h:129
lrmd_event_data_s
Definition: lrmd.h:198
XML_BOOLEAN_YES
#define XML_BOOLEAN_YES
Definition: msg_xml.h:109
cib_api_operations_s::create
int(* create)(cib_t *cib, const char *section, xmlNode *data, int call_options)
Definition: cib_types.h:105
pcmk__create_history_xml
xmlNode * pcmk__create_history_xml(xmlNode *parent, lrmd_event_data_t *event, const char *caller_version, int target_rc, const char *node, const char *origin, int level)
Definition: pcmk_sched_utils.c:530
crm_strdup_printf
char * crm_strdup_printf(char const *format,...) __attribute__((__format__(__printf__
lrmd_event_data_s::op_type
const char * op_type
Definition: lrmd.h:205
crm_debug
#define crm_debug(fmt, args...)
Definition: logging.h:246
XML_TAG_CIB
#define XML_TAG_CIB
Definition: msg_xml.h:76
crm_graph_s::abort_priority
int abort_priority
Definition: pcmki_transition.h:82
crm_system_name
char * crm_system_name
Definition: utils.c:61
lrmd_event_data_s::op_status
int op_status
Definition: lrmd.h:223
RSC_METADATA
#define RSC_METADATA
Definition: crm.h:211
XPATH_MAX
#define XPATH_MAX
Definition: pcmk_sched_transition.c:330
iso8601.h
ISO_8601 Date handling.
crm_xml_add
const char * crm_xml_add(xmlNode *node, const char *name, const char *value)
Create an XML attribute with specified name and value.
Definition: nvpair.c:313
XML_LRM_TAG_RESOURCES
#define XML_LRM_TAG_RESOURCES
Definition: msg_xml.h:226
pe_working_set_s
Definition: pe_types.h:117
lrmd.h
Resource agent executor.
crm_element_value
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
Definition: nvpair.c:519
transition_status
transition_status
Definition: pcmki_transition.h:114
crm_log_xml_warn
#define crm_log_xml_warn(xml, text)
Definition: logging.h:251
lrmd_free_event
void lrmd_free_event(lrmd_event_data_t *event)
Definition: lrmd_client.c:202
cib_api_operations_s::query
int(* query)(cib_t *cib, const char *section, xmlNode **output_data, int call_options)
Definition: cib_types.h:92
crm_log_xml_debug
#define crm_log_xml_debug(xml, text)
Definition: logging.h:254
NEW_NODE_TEMPLATE
#define NEW_NODE_TEMPLATE
Definition: pcmk_sched_transition.c:45
lrmd_event_data_s::params
void * params
Definition: lrmd.h:240
crm_meta_value
const char * crm_meta_value(GHashTable *hash, const char *field)
Definition: utils.c:761
XML_ATTR_ORIGIN
#define XML_ATTR_ORIGIN
Definition: msg_xml.h:91
crm_action_s::params
GHashTable * params
Definition: pcmki_transition.h:48
XML_CIB_TAG_CRMCONFIG
#define XML_CIB_TAG_CRMCONFIG
Definition: msg_xml.h:144
query_node_uuid
int query_node_uuid(cib_t *the_cib, const char *uname, char **uuid, int *is_remote_node)
Definition: cib_attrs.c:489
cib_scope_local
@ cib_scope_local
Definition: cib_types.h:59
crm_parse_int
int crm_parse_int(const char *text, const char *default_text)
Parse an integer value from a string.
Definition: strings.c:114
cib.h
Cluster Configuration.
safe_str_neq
gboolean safe_str_neq(const char *a, const char *b)
Definition: strings.c:161
NODE_TEMPLATE
#define NODE_TEMPLATE
Definition: pcmk_sched_transition.c:46
crm_log_xml_err
#define crm_log_xml_err(xml, text)
Definition: logging.h:250
crm_graph_functions_s
Definition: pcmki_transition.h:106
XML_AGENT_ATTR_PROVIDER
#define XML_AGENT_ATTR_PROVIDER
Definition: msg_xml.h:230
crm_element_value_copy
char * crm_element_value_copy(const xmlNode *data, const char *name)
Retrieve a copy of the value of an XML attribute.
Definition: nvpair.c:709
pe_working_set_s::graph
xmlNode * graph
Definition: pe_types.h:157
cib_s
Definition: cib_types.h:134
XML_NODE_IS_PEER
#define XML_NODE_IS_PEER
Definition: msg_xml.h:241
XML_LRM_ATTR_TARGET
#define XML_LRM_ATTR_TARGET
Definition: msg_xml.h:262
CRM_ASSERT
#define CRM_ASSERT(expr)
Definition: results.h:42
lrmd_event_data_s::interval_ms
guint interval_ms
Definition: lrmd.h:214
XML_ATTR_UUID
#define XML_ATTR_UUID
Definition: msg_xml.h:119
run_graph
int run_graph(crm_graph_t *graph)
Definition: pcmk_trans_graph.c:236
crm_action_s::confirmed
gboolean confirmed
Definition: pcmki_transition.h:56
update_attr_delegate
int update_attr_delegate(cib_t *the_cib, int call_options, const char *section, const char *node_uuid, const char *set_type, const char *set_name, const char *attr_id, const char *attr_name, const char *attr_value, gboolean to_console, const char *user_name, const char *node_type)
Definition: cib_attrs.c:176
XML_ATTR_TYPE
#define XML_ATTR_TYPE
Definition: msg_xml.h:99
transition_active
@ transition_active
Definition: pcmki_transition.h:115
pe_resource_s
Definition: pe_types.h:291
XML_ATTR_HAVE_WATCHDOG
#define XML_ATTR_HAVE_WATCHDOG
Definition: msg_xml.h:86
RSC_TEMPLATE
#define RSC_TEMPLATE
Definition: pcmk_sched_transition.c:47
XML_LRM_ATTR_CALLID
#define XML_LRM_ATTR_CALLID
Definition: msg_xml.h:272
XML_ATTR_ID_LONG
#define XML_ATTR_ID_LONG
Definition: msg_xml.h:98
pcmk_get_ra_caps
uint32_t pcmk_get_ra_caps(const char *standard)
Get capabilities of a resource agent standard.
Definition: agents.c:29
XML_CIB_TAG_NODE
#define XML_CIB_TAG_NODE
Definition: msg_xml.h:159
crm_exit
_Noreturn crm_exit_t crm_exit(crm_exit_t rc)
Definition: results.c:478
PCMK_RESOURCE_CLASS_LSB
#define PCMK_RESOURCE_CLASS_LSB
Definition: services.h:45
XML_BOOLEAN_NO
#define XML_BOOLEAN_NO
Definition: msg_xml.h:110
crm_internal.h
util.h
Utility functions.
cib_api_operations_s::replace
int(* replace)(cib_t *cib, const char *section, xmlNode *data, int call_options)
Definition: cib_types.h:111
destroy_graph
void destroy_graph(crm_graph_t *graph)
Definition: pcmk_trans_unpack.c:270
status.h
Cluster status and scheduling.
crm.h
A dumping ground.
pcmk_ok
#define pcmk_ok
Definition: results.h:57
crm_graph_s
Definition: pcmki_transition.h:79
XML_ATTR_HAVE_QUORUM
#define XML_ATTR_HAVE_QUORUM
Definition: msg_xml.h:85