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