pacemaker  2.0.5-ba59be7122
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 }
GListPtr
GList * GListPtr
Definition: crm.h:214
INFINITY
#define INFINITY
Definition: crm.h:95
crm_graph_functions_s::pseudo
gboolean(* pseudo)(crm_graph_t *graph, crm_action_t *action)
Definition: pcmki_transition.h:107
XML_LRM_ATTR_TASK_KEY
#define XML_LRM_ATTR_TASK_KEY
Definition: msg_xml.h:268
synapse_s::confirmed
gboolean confirmed
Definition: pcmki_transition.h:38
transition_action_failed
@ transition_action_failed
Definition: pcmki_transition.h:120
crm_action_s::failed
gboolean failed
Definition: pcmki_transition.h:58
pacemaker-internal.h
msg_xml.h
crm_graph_s::batch_limit
int batch_limit
Definition: pcmki_transition.h:91
crm_action_s
Definition: pcmki_transition.h:44
transition_pending
@ transition_pending
Definition: pcmki_transition.h:116
LOG_TRACE
#define LOG_TRACE
Definition: logging.h:36
set_default_graph_functions
void set_default_graph_functions(void)
Definition: pcmk_trans_utils.c:53
crm_action_s::id
int id
Definition: pcmki_transition.h:45
update_graph
gboolean update_graph(crm_graph_t *graph, crm_action_t *action)
Definition: pcmk_trans_graph.c:91
crm_graph_s::id
int id
Definition: pcmki_transition.h:80
transition_complete
@ transition_complete
Definition: pcmki_transition.h:117
action_type_e
action_type_e
Definition: pcmki_transition.h:22
synapse_s
Definition: pcmki_transition.h:31
crm_graph_functions_s::crmd
gboolean(* crmd)(crm_graph_t *graph, crm_action_t *action)
Definition: pcmki_transition.h:109
type
enum crm_ais_msg_types type
Definition: internal.h:3
crm_err
#define crm_err(fmt, args...)
Definition: logging.h:347
print_action
void print_action(int log_level, const char *prefix, crm_action_t *action)
Definition: pcmk_trans_utils.c:231
graph_fns
crm_graph_functions_t * graph_fns
Definition: pcmk_trans_graph.c:17
tg_shutdown
@ tg_shutdown
Definition: pcmki_transition.h:76
crm_trace
#define crm_trace(fmt, args...)
Definition: logging.h:353
crm_graph_functions_s::stonith
gboolean(* stonith)(crm_graph_t *graph, crm_action_t *action)
Definition: pcmki_transition.h:110
crm_graph_s::synapses
GListPtr synapses
Definition: pcmki_transition.h:101
action
const char * action
Definition: pcmk_fence.c:30
crm_graph_s::abort_reason
const char * abort_reason
Definition: pcmki_transition.h:85
tg_done
@ tg_done
Definition: pcmki_transition.h:73
xml.h
Wrappers for and extensions to libxml2.
action_type_pseudo
@ action_type_pseudo
Definition: pcmki_transition.h:23
crm_parse_ll
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
crm_action_s::xml
xmlNode * xml
Definition: pcmki_transition.h:61
crm_graph_s::num_actions
int num_actions
Definition: pcmki_transition.h:88
crm_action_s::type
action_type_e type
Definition: pcmki_transition.h:49
ID
#define ID(x)
Definition: msg_xml.h:425
tg_stop
@ tg_stop
Definition: pcmki_transition.h:74
synapse_s::priority
int priority
Definition: pcmki_transition.h:33
print_graph
void print_graph(unsigned int log_level, crm_graph_t *graph)
Definition: pcmk_trans_utils.c:237
crm_info
#define crm_info(fmt, args...)
Definition: logging.h:350
crm_graph_s::network_delay
guint network_delay
Definition: pcmki_transition.h:92
crm_graph_functions_s::rsc
gboolean(* rsc)(crm_graph_t *graph, crm_action_t *action)
Definition: pcmki_transition.h:108
crm_graph_s::completion_action
enum transition_action completion_action
Definition: pcmki_transition.h:86
update_abort_priority
bool update_abort_priority(crm_graph_t *graph, int priority, enum transition_action action, const char *abort_reason)
Definition: pcmk_trans_utils.c:277
synapse_s::ready
gboolean ready
Definition: pcmki_transition.h:35
actiontype2text
const char * actiontype2text(action_type_e type)
Definition: pcmk_trans_utils.c:94
crm_strdup_printf
char * crm_strdup_printf(char const *format,...) __attribute__((__format__(__printf__
synapse_s::failed
gboolean failed
Definition: pcmki_transition.h:36
crm_debug
#define crm_debug(fmt, args...)
Definition: logging.h:352
tg_restart
@ tg_restart
Definition: pcmki_transition.h:75
crm_graph_s::abort_priority
int abort_priority
Definition: pcmki_transition.h:82
do_crm_log
#define do_crm_log(level, fmt, args...)
Log a message.
Definition: logging.h:156
transition_failed
@ transition_failed
Definition: pcmki_transition.h:121
crm_element_value
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
Definition: nvpair.c:523
transition_status
transition_status
Definition: pcmki_transition.h:114
transition_action
transition_action
Definition: pcmki_transition.h:72
transition_stopped
@ transition_stopped
Definition: pcmki_transition.h:118
host
AIS_Host host
Definition: internal.h:4
crm_graph_functions_s
Definition: pcmki_transition.h:106
transition_status
const char * transition_status(enum transition_status state)
Definition: pcmk_trans_utils.c:72
set_graph_functions
void set_graph_functions(crm_graph_functions_t *fns)
Definition: pcmk_trans_utils.c:59
XML_LRM_ATTR_TARGET
#define XML_LRM_ATTR_TARGET
Definition: msg_xml.h:269
CRM_ASSERT
#define CRM_ASSERT(expr)
Definition: results.h:42
synapse_s::inputs
GListPtr inputs
Definition: pcmki_transition.h:41
crm_action_s::confirmed
gboolean confirmed
Definition: pcmki_transition.h:56
default_fns
crm_graph_functions_t default_fns
Definition: pcmk_trans_utils.c:45
transition_terminated
@ transition_terminated
Definition: pcmki_transition.h:119
action_type_rsc
@ action_type_rsc
Definition: pcmki_transition.h:24
transition_active
@ transition_active
Definition: pcmki_transition.h:115
crm_internal.h
crm.h
A dumping ground.
synapse_s::actions
GListPtr actions
Definition: pcmki_transition.h:40
action_type_crm
@ action_type_crm
Definition: pcmki_transition.h:25
synapse_s::executed
gboolean executed
Definition: pcmki_transition.h:37
crm_graph_s
Definition: pcmki_transition.h:79