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