pacemaker  2.0.4-2deceaa3ae
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 
155  for (GList *lpc = synapse->inputs; lpc != NULL; lpc = lpc->next) {
156  crm_action_t *input = (crm_action_t *) lpc->data;
157 
158  if (input->failed) {
159  pending = pcmk__add_word(pending, ID(input->xml));
160 
161  } else if (input->confirmed) {
162  // Confirmed successful inputs are not pending
163 
164  } else if (find_action(graph, input->id) != NULL) {
165  // In-flight or pending
166  pending = pcmk__add_word(pending, ID(input->xml));
167  }
168  }
169  if (pending == NULL) {
170  pending = strdup("none");
171  }
172  return pending;
173 }
174 
175 // Log synapse inputs that aren't in graph
176 static void
177 log_unresolved_inputs(unsigned int log_level, crm_graph_t *graph,
178  synapse_t *synapse)
179 {
180  for (GList *lpc = synapse->inputs; lpc != NULL; lpc = lpc->next) {
181  crm_action_t *input = (crm_action_t *) lpc->data;
182  const char *key = crm_element_value(input->xml, XML_LRM_ATTR_TASK_KEY);
183  const char *host = crm_element_value(input->xml, XML_LRM_ATTR_TARGET);
184 
185  if (find_action(graph, input->id) == NULL) {
186  do_crm_log(log_level,
187  " * [Input %2d]: Unresolved dependency %s op %s%s%s",
188  input->id, actiontype2text(input->type), key,
189  (host? " on " : ""), (host? host : ""));
190  }
191  }
192 }
193 
194 static void
195 log_synapse_action(unsigned int log_level, synapse_t *synapse,
196  crm_action_t *action, const char *pending_inputs)
197 {
198  const char *key = crm_element_value(action->xml, XML_LRM_ATTR_TASK_KEY);
199  const char *host = crm_element_value(action->xml, XML_LRM_ATTR_TARGET);
200  char *desc = crm_strdup_printf("%s %s op %s",
201  synapse_state_str(synapse),
202  actiontype2text(action->type), key);
203 
204  do_crm_log(log_level,
205  "[Action %4d]: %-50s%s%s (priority: %d, waiting: %s)",
206  action->id, desc, (host? " on " : ""), (host? host : ""),
207  synapse->priority, pending_inputs);
208  free(desc);
209 }
210 
211 static void
212 print_synapse(unsigned int log_level, crm_graph_t * graph, synapse_t * synapse)
213 {
214  char *pending = NULL;
215 
216  if (!synapse->executed) {
217  pending = synapse_pending_inputs(graph, synapse);
218  }
219  for (GList *lpc = synapse->actions; lpc != NULL; lpc = lpc->next) {
220  log_synapse_action(log_level, synapse, (crm_action_t *) lpc->data,
221  pending);
222  }
223  free(pending);
224  if (!synapse->executed) {
225  log_unresolved_inputs(log_level, graph, synapse);
226  }
227 }
228 
229 void
230 print_action(int log_level, const char *prefix, crm_action_t * action)
231 {
232  print_synapse(log_level, NULL, action->synapse);
233 }
234 
235 void
236 print_graph(unsigned int log_level, crm_graph_t * graph)
237 {
238  GListPtr lpc = NULL;
239 
240  if (graph == NULL || graph->num_actions == 0) {
241  if (log_level == LOG_TRACE) {
242  crm_debug("Empty transition graph");
243  }
244  return;
245  }
246 
247  do_crm_log(log_level, "Graph %d with %d actions:"
248  " batch-limit=%d jobs, network-delay=%ums",
249  graph->id, graph->num_actions,
250  graph->batch_limit, graph->network_delay);
251 
252  for (lpc = graph->synapses; lpc != NULL; lpc = lpc->next) {
253  synapse_t *synapse = (synapse_t *) lpc->data;
254 
255  print_synapse(log_level, graph, synapse);
256  }
257 }
258 
259 static const char *
260 abort2text(enum transition_action abort_action)
261 {
262  switch (abort_action) {
263  case tg_done:
264  return "done";
265  case tg_stop:
266  return "stop";
267  case tg_restart:
268  return "restart";
269  case tg_shutdown:
270  return "shutdown";
271  }
272  return "unknown";
273 }
274 
275 bool
276 update_abort_priority(crm_graph_t * graph, int priority,
277  enum transition_action action, const char *abort_reason)
278 {
279  bool change = FALSE;
280 
281  if (graph == NULL) {
282  return change;
283  }
284 
285  if (graph->abort_priority < priority) {
286  crm_debug("Abort priority upgraded from %d to %d", graph->abort_priority, priority);
287  graph->abort_priority = priority;
288  if (graph->abort_reason != NULL) {
289  crm_debug("'%s' abort superseded by %s", graph->abort_reason, abort_reason);
290  }
291  graph->abort_reason = abort_reason;
292  change = TRUE;
293  }
294 
295  if (graph->completion_action < action) {
296  crm_debug("Abort action %s superseded by %s: %s",
297  abort2text(graph->completion_action), abort2text(action), abort_reason);
298  graph->completion_action = action;
299  change = TRUE;
300  }
301 
302  return change;
303 }
GListPtr
GList * GListPtr
Definition: crm.h:215
INFINITY
#define INFINITY
Definition: crm.h:96
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:261
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
pcmk__add_word
char * pcmk__add_word(char *list, const char *word)
Definition: strings.c:517
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:363
print_action
void print_action(int log_level, const char *prefix, crm_action_t *action)
Definition: pcmk_trans_utils.c:230
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:369
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:29
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:100
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:418
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:236
crm_info
#define crm_info(fmt, args...)
Definition: logging.h:366
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:276
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:368
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:150
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:522
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:262
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