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