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