This source file includes following definitions.
- init_working_set
- handle_pecalc_op
- process_pe_message
- pe_ipc_accept
- pe_ipc_dispatch
- pe_ipc_closed
- pe_ipc_destroy
- main
- pengine_shutdown
1
2
3
4
5
6
7
8
9
10 #include <crm_internal.h>
11
12 #include <crm/crm.h>
13 #include <stdio.h>
14 #include <stdbool.h>
15 #include <sys/stat.h>
16 #include <sys/types.h>
17 #include <unistd.h>
18
19 #include <stdlib.h>
20 #include <errno.h>
21 #include <fcntl.h>
22
23 #include <libxml/parser.h>
24
25 #include <crm/common/ipc_internal.h>
26 #include <crm/common/mainloop.h>
27 #include <crm/pengine/internal.h>
28 #include <pacemaker-internal.h>
29 #include <crm/msg_xml.h>
30
31 #define OPTARGS "hVc"
32
33 static GMainLoop *mainloop = NULL;
34 static qb_ipcs_service_t *ipcs = NULL;
35 static pe_working_set_t *sched_data_set = NULL;
36 static pcmk__output_t *out = NULL;
37
38 pcmk__supported_format_t formats[] = {
39 PCMK__SUPPORTED_FORMAT_LOG,
40 PCMK__SUPPORTED_FORMAT_NONE,
41 PCMK__SUPPORTED_FORMAT_TEXT,
42 { NULL, NULL, NULL }
43 };
44
45 void pengine_shutdown(int nsig);
46
47 static void
48 init_working_set(void)
49 {
50 crm_config_error = FALSE;
51 crm_config_warning = FALSE;
52
53 was_processing_error = FALSE;
54 was_processing_warning = FALSE;
55
56 if (sched_data_set == NULL) {
57 sched_data_set = pe_new_working_set();
58 CRM_ASSERT(sched_data_set != NULL);
59 pe__set_working_set_flags(sched_data_set,
60 pe_flag_no_counts|pe_flag_no_compat);
61 pe__set_working_set_flags(sched_data_set,
62 pe_flag_show_utilization);
63 sched_data_set->priv = out;
64 } else {
65 pe_reset_working_set(sched_data_set);
66 }
67 }
68
69 static void
70 handle_pecalc_op(xmlNode *msg, xmlNode *xml_data, pcmk__client_t *sender)
71 {
72 static struct series_s {
73 const char *name;
74 const char *param;
75
76
77
78
79 int wrap;
80 } series[] = {
81 { "pe-error", "pe-error-series-max", -1 },
82 { "pe-warn", "pe-warn-series-max", 5000 },
83 { "pe-input", "pe-input-series-max", 4000 },
84 };
85 static char *last_digest = NULL;
86 static char *filename = NULL;
87
88 unsigned int seq;
89 int series_id = 0;
90 int series_wrap = 0;
91 char *digest = NULL;
92 const char *value = NULL;
93 time_t execution_date = time(NULL);
94 xmlNode *converted = NULL;
95 xmlNode *reply = NULL;
96 bool is_repoke = false;
97 bool process = true;
98
99 init_working_set();
100
101 digest = calculate_xml_versioned_digest(xml_data, FALSE, FALSE,
102 CRM_FEATURE_SET);
103 converted = copy_xml(xml_data);
104 if (!cli_config_update(&converted, NULL, TRUE)) {
105 sched_data_set->graph = create_xml_node(NULL, XML_TAG_GRAPH);
106 crm_xml_add_int(sched_data_set->graph, "transition_id", 0);
107 crm_xml_add_int(sched_data_set->graph, "cluster-delay", 0);
108 process = false;
109 free(digest);
110
111 } else if (pcmk__str_eq(digest, last_digest, pcmk__str_casei)) {
112 is_repoke = true;
113 free(digest);
114
115 } else {
116 free(last_digest);
117 last_digest = digest;
118 }
119
120 if (process) {
121 pcmk__schedule_actions(sched_data_set, converted, NULL);
122 }
123
124
125 if (was_processing_error) {
126 series_id = 0;
127 } else if (was_processing_warning) {
128 series_id = 1;
129 } else {
130 series_id = 2;
131 }
132
133 value = pe_pref(sched_data_set->config_hash, series[series_id].param);
134 if ((value == NULL)
135 || (pcmk__scan_min_int(value, &series_wrap, -1) != pcmk_rc_ok)) {
136 series_wrap = series[series_id].wrap;
137 }
138
139 if (pcmk__read_series_sequence(PE_STATE_DIR, series[series_id].name,
140 &seq) != pcmk_rc_ok) {
141
142 seq = 0;
143 }
144 crm_trace("Series %s: wrap=%d, seq=%u, pref=%s",
145 series[series_id].name, series_wrap, seq, value);
146
147 sched_data_set->input = NULL;
148 reply = create_reply(msg, sched_data_set->graph);
149 CRM_ASSERT(reply != NULL);
150
151 if (series_wrap == 0) {
152 free(filename);
153 filename = NULL;
154
155 } else if (!is_repoke) {
156 free(filename);
157 filename = pcmk__series_filename(PE_STATE_DIR,
158 series[series_id].name, seq, true);
159 }
160
161 crm_xml_add(reply, F_CRM_TGRAPH_INPUT, filename);
162 crm_xml_add_int(reply, "graph-errors", was_processing_error);
163 crm_xml_add_int(reply, "graph-warnings", was_processing_warning);
164 crm_xml_add_int(reply, "config-errors", crm_config_error);
165 crm_xml_add_int(reply, "config-warnings", crm_config_warning);
166
167 if (pcmk__ipc_send_xml(sender, 0, reply,
168 crm_ipc_server_event) != pcmk_rc_ok) {
169 int graph_file_fd = 0;
170 char *graph_file = NULL;
171 umask(S_IWGRP | S_IWOTH | S_IROTH);
172
173 graph_file = crm_strdup_printf("%s/pengine.graph.XXXXXX",
174 PE_STATE_DIR);
175 graph_file_fd = mkstemp(graph_file);
176
177 crm_err("Couldn't send transition graph to peer, writing to %s instead",
178 graph_file);
179
180 crm_xml_add(reply, F_CRM_TGRAPH, graph_file);
181 write_xml_fd(sched_data_set->graph, graph_file, graph_file_fd, FALSE);
182
183 free(graph_file);
184 free_xml(first_named_child(reply, F_CRM_DATA));
185 CRM_ASSERT(pcmk__ipc_send_xml(sender, 0, reply,
186 crm_ipc_server_event) == pcmk_rc_ok);
187 }
188
189 free_xml(reply);
190 pcmk__log_transition_summary(filename);
191
192 if (series_wrap == 0) {
193 crm_debug("Not saving input to disk (disabled by configuration)");
194
195 } else if (is_repoke) {
196 crm_info("Input has not changed since last time, not saving to disk");
197
198 } else {
199 unlink(filename);
200 crm_xml_add_ll(xml_data, "execution-date", (long long) execution_date);
201 write_xml_file(xml_data, filename, TRUE);
202 pcmk__write_series_sequence(PE_STATE_DIR, series[series_id].name,
203 ++seq, series_wrap);
204 }
205
206 free_xml(converted);
207 }
208
209 static gboolean
210 process_pe_message(xmlNode *msg, xmlNode *xml_data, pcmk__client_t *sender)
211 {
212 const char *sys_to = crm_element_value(msg, F_CRM_SYS_TO);
213 const char *op = crm_element_value(msg, F_CRM_TASK);
214 const char *ref = crm_element_value(msg, F_CRM_REFERENCE);
215
216 crm_trace("Processing %s op (ref=%s)...", op, ref);
217
218 if (op == NULL) {
219
220
221 } else if (strcasecmp(op, CRM_OP_HELLO) == 0) {
222
223
224 } else if (pcmk__str_eq(crm_element_value(msg, F_CRM_MSG_TYPE), XML_ATTR_RESPONSE, pcmk__str_casei)) {
225
226
227 } else if (sys_to == NULL || strcasecmp(sys_to, CRM_SYSTEM_PENGINE) != 0) {
228 crm_trace("Bad sys-to %s", crm_str(sys_to));
229 return FALSE;
230
231 } else if (strcasecmp(op, CRM_OP_PECALC) == 0) {
232 handle_pecalc_op(msg, xml_data, sender);
233 }
234
235 return TRUE;
236 }
237
238 static int32_t
239 pe_ipc_accept(qb_ipcs_connection_t * c, uid_t uid, gid_t gid)
240 {
241 crm_trace("Connection %p", c);
242 if (pcmk__new_client(c, uid, gid) == NULL) {
243 return -EIO;
244 }
245 return 0;
246 }
247
248 gboolean process_pe_message(xmlNode *msg, xmlNode *xml_data,
249 pcmk__client_t *sender);
250
251 static int32_t
252 pe_ipc_dispatch(qb_ipcs_connection_t * qbc, void *data, size_t size)
253 {
254 uint32_t id = 0;
255 uint32_t flags = 0;
256 pcmk__client_t *c = pcmk__find_client(qbc);
257 xmlNode *msg = pcmk__client_data2xml(c, data, &id, &flags);
258
259 pcmk__ipc_send_ack(c, id, flags, "ack", CRM_EX_INDETERMINATE);
260 if (msg != NULL) {
261 xmlNode *data_xml = get_message_xml(msg, F_CRM_DATA);
262
263 process_pe_message(msg, data_xml, c);
264 free_xml(msg);
265 }
266 return 0;
267 }
268
269
270 static int32_t
271 pe_ipc_closed(qb_ipcs_connection_t * c)
272 {
273 pcmk__client_t *client = pcmk__find_client(c);
274
275 if (client == NULL) {
276 return 0;
277 }
278 crm_trace("Connection %p", c);
279 pcmk__free_client(client);
280 return 0;
281 }
282
283 static void
284 pe_ipc_destroy(qb_ipcs_connection_t * c)
285 {
286 crm_trace("Connection %p", c);
287 pe_ipc_closed(c);
288 }
289
290 struct qb_ipcs_service_handlers ipc_callbacks = {
291 .connection_accept = pe_ipc_accept,
292 .connection_created = NULL,
293 .msg_process = pe_ipc_dispatch,
294 .connection_closed = pe_ipc_closed,
295 .connection_destroyed = pe_ipc_destroy
296 };
297
298 static pcmk__cli_option_t long_options[] = {
299
300 {
301 "help", no_argument, NULL, '?',
302 "\tThis text", pcmk__option_default
303 },
304 {
305 "verbose", no_argument, NULL, 'V',
306 "\tIncrease debug output", pcmk__option_default
307 },
308 { 0, 0, 0, 0 }
309 };
310
311 int
312 main(int argc, char **argv)
313 {
314 int flag;
315 int index = 0;
316 int argerr = 0;
317 int rc = pcmk_rc_ok;
318
319 crm_log_preinit(NULL, argc, argv);
320 pcmk__set_cli_options(NULL, "[options]", long_options,
321 "daemon for calculating a Pacemaker cluster's "
322 "response to events");
323
324 mainloop_add_signal(SIGTERM, pengine_shutdown);
325
326 while (1) {
327 flag = pcmk__next_cli_option(argc, argv, &index, NULL);
328 if (flag == -1)
329 break;
330
331 switch (flag) {
332 case 'V':
333 crm_bump_log_level(argc, argv);
334 break;
335 case 'h':
336 pcmk__cli_help('?', CRM_EX_OK);
337 break;
338 default:
339 ++argerr;
340 break;
341 }
342 }
343
344 if (argc - optind == 1 && pcmk__str_eq("metadata", argv[optind], pcmk__str_casei)) {
345 pe_metadata();
346 return CRM_EX_OK;
347 }
348
349 if (optind > argc) {
350 ++argerr;
351 }
352
353 if (argerr) {
354 pcmk__cli_help('?', CRM_EX_USAGE);
355 }
356
357 crm_log_init(NULL, LOG_INFO, TRUE, FALSE, argc, argv, FALSE);
358 crm_notice("Starting Pacemaker scheduler");
359
360 if (pcmk__daemon_can_write(PE_STATE_DIR, NULL) == FALSE) {
361 crm_err("Terminating due to bad permissions on " PE_STATE_DIR);
362 fprintf(stderr,
363 "ERROR: Bad permissions on " PE_STATE_DIR " (see logs for details)\n");
364 fflush(stderr);
365 return CRM_EX_FATAL;
366 }
367
368 ipcs = mainloop_add_ipc_server(CRM_SYSTEM_PENGINE, QB_IPC_SHM, &ipc_callbacks);
369 if (ipcs == NULL) {
370 crm_err("Failed to create IPC server: shutting down and inhibiting respawn");
371 crm_exit(CRM_EX_FATAL);
372 }
373
374 pcmk__register_formats(NULL, formats);
375 rc = pcmk__output_new(&out, "log", NULL, argv);
376 if ((rc != pcmk_rc_ok) || (out == NULL)) {
377 crm_err("Can't log resource details due to internal error: %s\n",
378 pcmk_rc_str(rc));
379 crm_exit(CRM_EX_FATAL);
380 }
381
382 pe__register_messages(out);
383 pcmk__register_lib_messages(out);
384
385 pcmk__output_set_log_level(out, LOG_TRACE);
386
387
388 mainloop = g_main_loop_new(NULL, FALSE);
389 crm_notice("Pacemaker scheduler successfully started and accepting connections");
390 g_main_loop_run(mainloop);
391 pengine_shutdown(0);
392 }
393
394 void
395 pengine_shutdown(int nsig)
396 {
397 mainloop_del_ipc_server(ipcs);
398 ipcs = NULL;
399
400 pe_free_working_set(sched_data_set);
401 sched_data_set = NULL;
402
403 pcmk__unregister_formats();
404 if (out != NULL) {
405 out->finish(out, CRM_EX_OK, true, NULL);
406 pcmk__output_free(out);
407 out = NULL;
408 }
409
410 crm_exit(CRM_EX_OK);
411 }