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