This source file includes following definitions.
- stop_te_timer
- te_graph_trigger
- controld_init_transition_trigger
- controld_destroy_transition_trigger
- controld_trigger_graph_as
- abort_timer_popped
- abort_after_delay
- abort2text
- update_abort_priority
- abort_transition_graph
1
2
3
4
5
6
7
8
9
10 #include <crm_internal.h>
11 #include <crm/crm.h>
12 #include <crm/msg_xml.h>
13 #include <crm/common/xml.h>
14
15 #include <pacemaker-controld.h>
16
17
18 static crm_trigger_t *transition_trigger = NULL;
19
20 gboolean
21 stop_te_timer(pcmk__graph_action_t *action)
22 {
23 if (action == NULL) {
24 return FALSE;
25 }
26 if (action->timer != 0) {
27 crm_trace("Stopping action timer");
28 g_source_remove(action->timer);
29 action->timer = 0;
30 } else {
31 crm_trace("Action timer was already stopped");
32 return FALSE;
33 }
34 return TRUE;
35 }
36
37 static gboolean
38 te_graph_trigger(gpointer user_data)
39 {
40 if (controld_globals.transition_graph == NULL) {
41 crm_debug("Nothing to do");
42 return TRUE;
43 }
44
45 crm_trace("Invoking graph %d in state %s",
46 controld_globals.transition_graph->id,
47 fsa_state2string(controld_globals.fsa_state));
48
49 switch (controld_globals.fsa_state) {
50 case S_STARTING:
51 case S_PENDING:
52 case S_NOT_DC:
53 case S_HALT:
54 case S_ILLEGAL:
55 case S_STOPPING:
56 case S_TERMINATE:
57 return TRUE;
58 default:
59 break;
60 }
61
62 if (!controld_globals.transition_graph->complete) {
63 enum pcmk__graph_status graph_rc;
64 int orig_limit = controld_globals.transition_graph->batch_limit;
65 int throttled_limit = throttle_get_total_job_limit(orig_limit);
66
67 controld_globals.transition_graph->batch_limit = throttled_limit;
68 graph_rc = pcmk__execute_graph(controld_globals.transition_graph);
69 controld_globals.transition_graph->batch_limit = orig_limit;
70
71 if (graph_rc == pcmk__graph_active) {
72 crm_trace("Transition not yet complete");
73 return TRUE;
74
75 } else if (graph_rc == pcmk__graph_pending) {
76 crm_trace("Transition not yet complete - no actions fired");
77 return TRUE;
78 }
79
80 if (graph_rc != pcmk__graph_complete) {
81 crm_warn("Transition failed: %s",
82 pcmk__graph_status2text(graph_rc));
83 pcmk__log_graph(LOG_NOTICE, controld_globals.transition_graph);
84 }
85 }
86
87 crm_debug("Transition %d is now complete",
88 controld_globals.transition_graph->id);
89 controld_globals.transition_graph->complete = true;
90 notify_crmd(controld_globals.transition_graph);
91
92 return TRUE;
93 }
94
95
96
97
98
99 void
100 controld_init_transition_trigger(void)
101 {
102 transition_trigger = mainloop_add_trigger(G_PRIORITY_LOW, te_graph_trigger,
103 NULL);
104 }
105
106
107
108
109
110 void
111 controld_destroy_transition_trigger(void)
112 {
113 mainloop_destroy_trigger(transition_trigger);
114 transition_trigger = NULL;
115 }
116
117 void
118 controld_trigger_graph_as(const char *fn, int line)
119 {
120 crm_trace("%s:%d - Triggered graph processing", fn, line);
121 mainloop_set_trigger(transition_trigger);
122 }
123
124 static struct abort_timer_s {
125 bool aborted;
126 guint id;
127 int priority;
128 enum pcmk__graph_next action;
129 const char *text;
130 } abort_timer = { 0, };
131
132 static gboolean
133 abort_timer_popped(gpointer data)
134 {
135 if (AM_I_DC && (abort_timer.aborted == FALSE)) {
136 abort_transition(abort_timer.priority, abort_timer.action,
137 abort_timer.text, NULL);
138 }
139 abort_timer.id = 0;
140 return FALSE;
141 }
142
143
144
145
146
147
148
149 void
150 abort_after_delay(int abort_priority, enum pcmk__graph_next abort_action,
151 const char *abort_text, guint delay_ms)
152 {
153 if (abort_timer.id) {
154
155 g_source_remove(abort_timer.id);
156 }
157 abort_timer.aborted = FALSE;
158 abort_timer.priority = abort_priority;
159 abort_timer.action = abort_action;
160 abort_timer.text = abort_text;
161 abort_timer.id = g_timeout_add(delay_ms, abort_timer_popped, NULL);
162 }
163
164 static const char *
165 abort2text(enum pcmk__graph_next abort_action)
166 {
167 switch (abort_action) {
168 case pcmk__graph_done: return "done";
169 case pcmk__graph_wait: return "stop";
170 case pcmk__graph_restart: return "restart";
171 case pcmk__graph_shutdown: return "shutdown";
172 }
173 return "unknown";
174 }
175
176 static bool
177 update_abort_priority(pcmk__graph_t *graph, int priority,
178 enum pcmk__graph_next action, const char *abort_reason)
179 {
180 bool change = FALSE;
181
182 if (graph == NULL) {
183 return change;
184 }
185
186 if (graph->abort_priority < priority) {
187 crm_debug("Abort priority upgraded from %d to %d", graph->abort_priority, priority);
188 graph->abort_priority = priority;
189 if (graph->abort_reason != NULL) {
190 crm_debug("'%s' abort superseded by %s", graph->abort_reason, abort_reason);
191 }
192 graph->abort_reason = abort_reason;
193 change = TRUE;
194 }
195
196 if (graph->completion_action < action) {
197 crm_debug("Abort action %s superseded by %s: %s",
198 abort2text(graph->completion_action), abort2text(action), abort_reason);
199 graph->completion_action = action;
200 change = TRUE;
201 }
202
203 return change;
204 }
205
206 void
207 abort_transition_graph(int abort_priority, enum pcmk__graph_next abort_action,
208 const char *abort_text, const xmlNode *reason,
209 const char *fn, int line)
210 {
211 int add[] = { 0, 0, 0 };
212 int del[] = { 0, 0, 0 };
213 int level = LOG_INFO;
214 const xmlNode *diff = NULL;
215 const xmlNode *change = NULL;
216
217 CRM_CHECK(controld_globals.transition_graph != NULL, return);
218
219 switch (controld_globals.fsa_state) {
220 case S_STARTING:
221 case S_PENDING:
222 case S_NOT_DC:
223 case S_HALT:
224 case S_ILLEGAL:
225 case S_STOPPING:
226 case S_TERMINATE:
227 crm_info("Abort %s suppressed: state=%s (%scomplete)",
228 abort_text, fsa_state2string(controld_globals.fsa_state),
229 (controld_globals.transition_graph->complete? "" : "in"));
230 return;
231 default:
232 break;
233 }
234
235 abort_timer.aborted = TRUE;
236 controld_expect_sched_reply(NULL);
237
238 if (!controld_globals.transition_graph->complete
239 && update_abort_priority(controld_globals.transition_graph,
240 abort_priority, abort_action,
241 abort_text)) {
242 level = LOG_NOTICE;
243 }
244
245 if (reason != NULL) {
246 const xmlNode *search = NULL;
247
248 for(search = reason; search; search = search->parent) {
249 if (pcmk__str_eq(XML_TAG_DIFF, TYPE(search), pcmk__str_casei)) {
250 diff = search;
251 break;
252 }
253 }
254
255 if(diff) {
256 xml_patch_versions(diff, add, del);
257 for(search = reason; search; search = search->parent) {
258 if (pcmk__str_eq(XML_DIFF_CHANGE, TYPE(search), pcmk__str_casei)) {
259 change = search;
260 break;
261 }
262 }
263 }
264 }
265
266 if (reason == NULL) {
267 do_crm_log(level,
268 "Transition %d aborted: %s " CRM_XS " source=%s:%d "
269 "complete=%s", controld_globals.transition_graph->id,
270 abort_text, fn, line,
271 pcmk__btoa(controld_globals.transition_graph->complete));
272
273 } else if(change == NULL) {
274 GString *local_path = pcmk__element_xpath(reason);
275 CRM_ASSERT(local_path != NULL);
276
277 do_crm_log(level, "Transition %d aborted by %s.%s: %s "
278 CRM_XS " cib=%d.%d.%d source=%s:%d path=%s complete=%s",
279 controld_globals.transition_graph->id, TYPE(reason),
280 ID(reason), abort_text, add[0], add[1], add[2], fn, line,
281 (const char *) local_path->str,
282 pcmk__btoa(controld_globals.transition_graph->complete));
283 g_string_free(local_path, TRUE);
284
285 } else {
286 const char *kind = NULL;
287 const char *op = crm_element_value(change, XML_DIFF_OP);
288 const char *path = crm_element_value(change, XML_DIFF_PATH);
289
290 if(change == reason) {
291 if(strcmp(op, "create") == 0) {
292 reason = reason->children;
293
294 } else if(strcmp(op, "modify") == 0) {
295 reason = first_named_child(reason, XML_DIFF_RESULT);
296 if(reason) {
297 reason = reason->children;
298 }
299 }
300 }
301
302 kind = TYPE(reason);
303 if(strcmp(op, "delete") == 0) {
304 const char *shortpath = strrchr(path, '/');
305
306 do_crm_log(level, "Transition %d aborted by deletion of %s: %s "
307 CRM_XS " cib=%d.%d.%d source=%s:%d path=%s complete=%s",
308 controld_globals.transition_graph->id,
309 (shortpath? (shortpath + 1) : path), abort_text,
310 add[0], add[1], add[2], fn, line, path,
311 pcmk__btoa(controld_globals.transition_graph->complete));
312
313 } else if (pcmk__str_eq(XML_CIB_TAG_NVPAIR, kind, pcmk__str_none)) {
314 do_crm_log(level, "Transition %d aborted by %s doing %s %s=%s: %s "
315 CRM_XS " cib=%d.%d.%d source=%s:%d path=%s complete=%s",
316 controld_globals.transition_graph->id,
317 crm_element_value(reason, XML_ATTR_ID), op,
318 crm_element_value(reason, XML_NVPAIR_ATTR_NAME),
319 crm_element_value(reason, XML_NVPAIR_ATTR_VALUE),
320 abort_text, add[0], add[1], add[2], fn, line, path,
321 pcmk__btoa(controld_globals.transition_graph->complete));
322
323 } else if (pcmk__str_eq(XML_LRM_TAG_RSC_OP, kind, pcmk__str_none)) {
324 const char *magic = crm_element_value(reason, XML_ATTR_TRANSITION_MAGIC);
325
326 do_crm_log(level, "Transition %d aborted by operation %s '%s' on %s: %s "
327 CRM_XS " magic=%s cib=%d.%d.%d source=%s:%d complete=%s",
328 controld_globals.transition_graph->id,
329 crm_element_value(reason, XML_LRM_ATTR_TASK_KEY), op,
330 crm_element_value(reason, XML_LRM_ATTR_TARGET), abort_text,
331 magic, add[0], add[1], add[2], fn, line,
332 pcmk__btoa(controld_globals.transition_graph->complete));
333
334 } else if (pcmk__str_any_of(kind, XML_CIB_TAG_STATE, XML_CIB_TAG_NODE, NULL)) {
335 const char *uname = crm_peer_uname(ID(reason));
336
337 do_crm_log(level, "Transition %d aborted by %s '%s' on %s: %s "
338 CRM_XS " cib=%d.%d.%d source=%s:%d complete=%s",
339 controld_globals.transition_graph->id,
340 kind, op, (uname? uname : ID(reason)), abort_text,
341 add[0], add[1], add[2], fn, line,
342 pcmk__btoa(controld_globals.transition_graph->complete));
343
344 } else {
345 const char *id = ID(reason);
346
347 do_crm_log(level, "Transition %d aborted by %s.%s '%s': %s "
348 CRM_XS " cib=%d.%d.%d source=%s:%d path=%s complete=%s",
349 controld_globals.transition_graph->id,
350 TYPE(reason), (id? id : ""), (op? op : "change"),
351 abort_text, add[0], add[1], add[2], fn, line, path,
352 pcmk__btoa(controld_globals.transition_graph->complete));
353 }
354 }
355
356 if (controld_globals.transition_graph->complete) {
357 if (controld_get_period_transition_timer() > 0) {
358 controld_stop_transition_timer();
359 controld_start_transition_timer();
360 } else {
361 register_fsa_input(C_FSA_INTERNAL, I_PE_CALC, NULL);
362 }
363 return;
364 }
365
366 trigger_graph();
367 }