pacemaker  2.0.5-ba59be712
Scalable High-Availability cluster resource manager
pcmk_trans_utils.c
Go to the documentation of this file.
1 /*
2  * Copyright 2004-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 Lesser General Public License
7  * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
8  */
9 
10 #include <crm_internal.h>
11 
12 #include <crm/crm.h>
13 #include <crm/msg_xml.h>
14 #include <crm/common/xml.h>
15 #include <pacemaker-internal.h>
16 
18 
19 static gboolean
20 pseudo_action_dummy(crm_graph_t * graph, crm_action_t * action)
21 {
22  static int fail = -1;
23 
24  if (fail < 0) {
25  char *fail_s = getenv("PE_fail");
26 
27  if (fail_s) {
28  fail = (int) crm_parse_ll(fail_s, NULL);
29  } else {
30  fail = 0;
31  }
32  }
33 
34  crm_trace("Dummy event handler: action %d executed", action->id);
35  if (action->id == fail) {
36  crm_err("Dummy event handler: pretending action %d failed", action->id);
37  action->failed = TRUE;
38  graph->abort_priority = INFINITY;
39  }
40  action->confirmed = TRUE;
41  update_graph(graph, action);
42  return TRUE;
43 }
44 
46  pseudo_action_dummy,
47  pseudo_action_dummy,
48  pseudo_action_dummy,
49  pseudo_action_dummy
50 };
51 
52 void
54 {
56 }
57 
58 void
60 {
61  crm_info("Setting custom graph functions");
62  graph_fns = fns;
63 
64  CRM_ASSERT(graph_fns != NULL);
65  CRM_ASSERT(graph_fns->rsc != NULL);
66  CRM_ASSERT(graph_fns->crmd != NULL);
67  CRM_ASSERT(graph_fns->pseudo != NULL);
68  CRM_ASSERT(graph_fns->stonith != NULL);
69 }
70 
71 const char *
73 {
74  switch (state) {
75  case transition_active:
76  return "active";
77  case transition_pending:
78  return "pending";
80  return "complete";
81  case transition_stopped:
82  return "stopped";
84  return "terminated";
86  return "failed (action)";
87  case transition_failed:
88  return "failed";
89  }
90  return "unknown";
91 }
92 
93 const char *
95 {
96  switch (type) {
97  case action_type_pseudo:
98  return "pseudo";
99  case action_type_rsc:
100  return "resource";
101  case action_type_crm:
102  return "cluster";
103  }
104  return "invalid";
105 }
106 
107 static crm_action_t *
108 find_action(crm_graph_t * graph, int id)
109 {
110  GListPtr sIter = NULL;
111 
112  if (graph == NULL) {
113  return NULL;
114  }
115 
116  for (sIter = graph->synapses; sIter != NULL; sIter = sIter->next) {
117  GListPtr aIter = NULL;
118  synapse_t *synapse = (synapse_t *) sIter->data;
119 
120  for (aIter = synapse->actions; aIter != NULL; aIter = aIter->next) {
121  crm_action_t *action = (crm_action_t *) aIter->data;
122 
123  if (action->id == id) {
124  return action;
125  }
126  }
127  }
128  return NULL;
129 }
130 
131 static const char *
132 synapse_state_str(synapse_t *synapse)
133 {
134  if (synapse->failed) {
135  return "Failed";
136 
137  } else if (synapse->confirmed) {
138  return "Completed";
139 
140  } else if (synapse->executed) {
141  return "In-flight";
142 
143  } else if (synapse->ready) {
144  return "Ready";
145  }
146  return "Pending";
147 }
148 
149 // List action IDs of inputs in graph that haven't completed successfully
150 static char *
151 synapse_pending_inputs(crm_graph_t *graph, synapse_t *synapse)
152 {
153  char *pending = NULL;
154  size_t pending_len = 0;
155 
156  for (GList *lpc = synapse->inputs; lpc != NULL; lpc = lpc->next) {
157  crm_action_t *input = (crm_action_t *) lpc->data;
158 
159  if (input->failed) {
160  pcmk__add_word(&pending, &pending_len, ID(input->xml));
161 
162  } else if (input->confirmed) {
163  // Confirmed successful inputs are not pending
164 
165  } else if (find_action(graph, input->id) != NULL) {
166  // In-flight or pending
167  pcmk__add_word(&pending, &pending_len, ID(input->xml));
168  }
169  }
170  if (pending == NULL) {
171  pending = strdup("none");
172  }
173  return pending;
174 }
175 
176 // Log synapse inputs that aren't in graph
177 static void
178 log_unresolved_inputs(unsigned int log_level, crm_graph_t *graph,
179  synapse_t *synapse)
180 {
181  for (GList *lpc = synapse->inputs; lpc != NULL; lpc = lpc->next) {
182  crm_action_t *input = (crm_action_t *) lpc->data;
183  const char *key = crm_element_value(input->xml, XML_LRM_ATTR_TASK_KEY);
184  const char *host = crm_element_value(input->xml, XML_LRM_ATTR_TARGET);
185 
186  if (find_action(graph, input->id) == NULL) {
187  do_crm_log(log_level,
188  " * [Input %2d]: Unresolved dependency %s op %s%s%s",
189  input->id, actiontype2text(input->type), key,
190  (host? " on " : ""), (host? host : ""));
191  }
192  }
193 }
194 
195 static void
196 log_synapse_action(unsigned int log_level, synapse_t *synapse,
197  crm_action_t *action, const char *pending_inputs)
198 {
199  const char *key = crm_element_value(action->xml, XML_LRM_ATTR_TASK_KEY);
200  const char *host = crm_element_value(action->xml, XML_LRM_ATTR_TARGET);
201  char *desc = crm_strdup_printf("%s %s op %s",
202  synapse_state_str(synapse),
203  actiontype2text(action->type), key);
204 
205  do_crm_log(log_level,
206  "[Action %4d]: %-50s%s%s (priority: %d, waiting: %s)",
207  action->id, desc, (host? " on " : ""), (host? host : ""),
208  synapse->priority, pending_inputs);
209  free(desc);
210 }
211 
212 static void
213 print_synapse(unsigned int log_level, crm_graph_t * graph, synapse_t * synapse)
214 {
215  char *pending = NULL;
216 
217  if (!synapse->executed) {
218  pending = synapse_pending_inputs(graph, synapse);
219  }
220  for (GList *lpc = synapse->actions; lpc != NULL; lpc = lpc->next) {
221  log_synapse_action(log_level, synapse, (crm_action_t *) lpc->data,
222  pending);
223  }
224  free(pending);
225  if (!synapse->executed) {
226  log_unresolved_inputs(log_level, graph, synapse);
227  }
228 }
229 
230 void
231 print_action(int log_level, const char *prefix, crm_action_t * action)
232 {
233  print_synapse(log_level, NULL, action->synapse);
234 }
235 
236 void
237 print_graph(unsigned int log_level, crm_graph_t * graph)
238 {
239  GListPtr lpc = NULL;
240 
241  if (graph == NULL || graph->num_actions == 0) {
242  if (log_level == LOG_TRACE) {
243  crm_debug("Empty transition graph");
244  }
245  return;
246  }
247 
248  do_crm_log(log_level, "Graph %d with %d actions:"
249  " batch-limit=%d jobs, network-delay=%ums",
250  graph->id, graph->num_actions,
251  graph->batch_limit, graph->network_delay);
252 
253  for (lpc = graph->synapses; lpc != NULL; lpc = lpc->next) {
254  synapse_t *synapse = (synapse_t *) lpc->data;
255 
256  print_synapse(log_level, graph, synapse);
257  }
258 }
259 
260 static const char *
261 abort2text(enum transition_action abort_action)
262 {
263  switch (abort_action) {
264  case tg_done:
265  return "done";
266  case tg_stop:
267  return "stop";
268  case tg_restart:
269  return "restart";
270  case tg_shutdown:
271  return "shutdown";
272  }
273  return "unknown";
274 }
275 
276 bool
277 update_abort_priority(crm_graph_t * graph, int priority,
278  enum transition_action action, const char *abort_reason)
279 {
280  bool change = FALSE;
281 
282  if (graph == NULL) {
283  return change;
284  }
285 
286  if (graph->abort_priority < priority) {
287  crm_debug("Abort priority upgraded from %d to %d", graph->abort_priority, priority);
288  graph->abort_priority = priority;
289  if (graph->abort_reason != NULL) {
290  crm_debug("'%s' abort superseded by %s", graph->abort_reason, abort_reason);
291  }
292  graph->abort_reason = abort_reason;
293  change = TRUE;
294  }
295 
296  if (graph->completion_action < action) {
297  crm_debug("Abort action %s superseded by %s: %s",
298  abort2text(graph->completion_action), abort2text(action), abort_reason);
299  graph->completion_action = action;
300  change = TRUE;
301  }
302 
303  return change;
304 }
#define LOG_TRACE
Definition: logging.h:36
GListPtr actions
gboolean confirmed
A dumping ground.
action_type_e type
#define INFINITY
Definition: crm.h:95
enum transition_action completion_action
crm_graph_functions_t * graph_fns
transition_status
gboolean(* stonith)(crm_graph_t *graph, crm_action_t *action)
AIS_Host host
Definition: internal.h:84
void set_default_graph_functions(void)
gboolean ready
const char * action
Definition: pcmk_fence.c:30
void print_graph(unsigned int log_level, crm_graph_t *graph)
#define XML_LRM_ATTR_TASK_KEY
Definition: msg_xml.h:268
gboolean(* crmd)(crm_graph_t *graph, crm_action_t *action)
void print_action(int log_level, const char *prefix, crm_action_t *action)
const char * actiontype2text(action_type_e type)
#define crm_debug(fmt, args...)
Definition: logging.h:352
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
Definition: nvpair.c:523
#define crm_trace(fmt, args...)
Definition: logging.h:353
#define do_crm_log(level, fmt, args...)
Log a message.
Definition: logging.h:156
Wrappers for and extensions to libxml2.
gboolean update_graph(crm_graph_t *graph, crm_action_t *action)
GListPtr synapses
gboolean(* rsc)(crm_graph_t *graph, crm_action_t *action)
void set_graph_functions(crm_graph_functions_t *fns)
bool update_abort_priority(crm_graph_t *graph, int priority, enum transition_action action, const char *abort_reason)
GListPtr inputs
gboolean failed
long long crm_parse_ll(const char *text, const char *default_text)
Parse a long long integer value from a string.
Definition: strings.c:107
gboolean(* pseudo)(crm_graph_t *graph, crm_action_t *action)
#define crm_err(fmt, args...)
Definition: logging.h:347
#define CRM_ASSERT(expr)
Definition: results.h:42
crm_graph_functions_t default_fns
transition_action
gboolean confirmed
action_type_e
#define XML_LRM_ATTR_TARGET
Definition: msg_xml.h:269
#define ID(x)
Definition: msg_xml.h:425
const char * transition_status(enum transition_status state)
char * crm_strdup_printf(char const *format,...) __attribute__((__format__(__printf__
gboolean executed
GList * GListPtr
Definition: crm.h:214
#define crm_info(fmt, args...)
Definition: logging.h:350
const char * abort_reason
enum crm_ais_msg_types type
Definition: internal.h:83