This source file includes following definitions.
- stonith_connection_destroy_cb
- get_stonith_connection
- lrmd_ipc_accept
- lrmd_ipc_created
- lrmd_ipc_dispatch
- lrmd_client_destroy
- lrmd_ipc_closed
- lrmd_ipc_destroy
- lrmd_server_send_reply
- lrmd_server_send_notify
- lrmd_exit
- lrmd_shutdown
- handle_shutdown_ack
- handle_shutdown_nack
- build_arg_context
- main
1
2
3
4
5
6
7
8
9
10 #include <crm_internal.h>
11
12 #include <glib.h>
13 #include <signal.h>
14 #include <sys/types.h>
15
16 #include <crm/crm.h>
17 #include <crm/msg_xml.h>
18 #include <crm/services.h>
19 #include <crm/common/cmdline_internal.h>
20 #include <crm/common/ipc.h>
21 #include <crm/common/ipc_internal.h>
22 #include <crm/common/mainloop.h>
23 #include <crm/common/output_internal.h>
24 #include <crm/common/remote_internal.h>
25 #include <crm/lrmd_internal.h>
26
27 #include "pacemaker-execd.h"
28
29 #ifdef PCMK__COMPILE_REMOTE
30 # define EXECD_TYPE "remote"
31 # define EXECD_NAME "pacemaker-remoted"
32 # define SUMMARY "resource agent executor daemon for Pacemaker Remote nodes"
33 #else
34 # define EXECD_TYPE "local"
35 # define EXECD_NAME "pacemaker-execd"
36 # define SUMMARY "resource agent executor daemon for Pacemaker cluster nodes"
37 #endif
38
39 static GMainLoop *mainloop = NULL;
40 static qb_ipcs_service_t *ipcs = NULL;
41 static stonith_t *stonith_api = NULL;
42 int lrmd_call_id = 0;
43 time_t start_time;
44
45 static struct {
46 gchar **log_files;
47 #ifdef PCMK__COMPILE_REMOTE
48 gchar *port;
49 #endif
50 } options;
51
52 #ifdef PCMK__COMPILE_REMOTE
53
54 static gboolean shutting_down = FALSE;
55
56
57 static guint shutdown_ack_timer = 0;
58
59 static gboolean lrmd_exit(gpointer data);
60 #endif
61
62 static void
63 stonith_connection_destroy_cb(stonith_t * st, stonith_event_t * e)
64 {
65 stonith_api->state = stonith_disconnected;
66 stonith_connection_failed();
67 }
68
69 stonith_t *
70 get_stonith_connection(void)
71 {
72 if (stonith_api && stonith_api->state == stonith_disconnected) {
73 stonith_api_delete(stonith_api);
74 stonith_api = NULL;
75 }
76
77 if (stonith_api == NULL) {
78 int rc = pcmk_ok;
79
80 stonith_api = stonith_api_new();
81 if (stonith_api == NULL) {
82 crm_err("Could not connect to fencer: API memory allocation failed");
83 return NULL;
84 }
85 rc = stonith_api_connect_retry(stonith_api, crm_system_name, 10);
86 if (rc != pcmk_ok) {
87 crm_err("Could not connect to fencer in 10 attempts: %s "
88 CRM_XS " rc=%d", pcmk_strerror(rc), rc);
89 stonith_api_delete(stonith_api);
90 stonith_api = NULL;
91 } else {
92 stonith_api->cmds->register_notification(stonith_api,
93 T_STONITH_NOTIFY_DISCONNECT,
94 stonith_connection_destroy_cb);
95 }
96 }
97 return stonith_api;
98 }
99
100 static int32_t
101 lrmd_ipc_accept(qb_ipcs_connection_t * c, uid_t uid, gid_t gid)
102 {
103 crm_trace("Connection %p", c);
104 if (pcmk__new_client(c, uid, gid) == NULL) {
105 return -EIO;
106 }
107 return 0;
108 }
109
110 static void
111 lrmd_ipc_created(qb_ipcs_connection_t * c)
112 {
113 pcmk__client_t *new_client = pcmk__find_client(c);
114
115 crm_trace("Connection %p", c);
116 CRM_ASSERT(new_client != NULL);
117
118
119
120 notify_of_new_client(new_client);
121 }
122
123 static int32_t
124 lrmd_ipc_dispatch(qb_ipcs_connection_t * c, void *data, size_t size)
125 {
126 uint32_t id = 0;
127 uint32_t flags = 0;
128 pcmk__client_t *client = pcmk__find_client(c);
129 xmlNode *request = pcmk__client_data2xml(client, data, &id, &flags);
130
131 CRM_CHECK(client != NULL, crm_err("Invalid client");
132 return FALSE);
133 CRM_CHECK(client->id != NULL, crm_err("Invalid client: %p", client);
134 return FALSE);
135
136 CRM_CHECK(flags & crm_ipc_client_response, crm_err("Invalid client request: %p", client);
137 return FALSE);
138
139 if (!request) {
140 return 0;
141 }
142
143 if (!client->name) {
144 const char *value = crm_element_value(request, F_LRMD_CLIENTNAME);
145
146 if (value == NULL) {
147 client->name = pcmk__itoa(pcmk__client_pid(c));
148 } else {
149 client->name = strdup(value);
150 }
151 }
152
153 lrmd_call_id++;
154 if (lrmd_call_id < 1) {
155 lrmd_call_id = 1;
156 }
157
158 crm_xml_add(request, F_LRMD_CLIENTID, client->id);
159 crm_xml_add(request, F_LRMD_CLIENTNAME, client->name);
160 crm_xml_add_int(request, F_LRMD_CALLID, lrmd_call_id);
161
162 process_lrmd_message(client, id, request);
163
164 free_xml(request);
165 return 0;
166 }
167
168
169
170
171
172
173
174 void
175 lrmd_client_destroy(pcmk__client_t *client)
176 {
177 pcmk__free_client(client);
178
179 #ifdef PCMK__COMPILE_REMOTE
180
181
182
183 if (shutting_down && (ipc_proxy_get_provider() == NULL)) {
184 lrmd_exit(NULL);
185 }
186 #endif
187 }
188
189 static int32_t
190 lrmd_ipc_closed(qb_ipcs_connection_t * c)
191 {
192 pcmk__client_t *client = pcmk__find_client(c);
193
194 if (client == NULL) {
195 return 0;
196 }
197
198 crm_trace("Connection %p", c);
199 client_disconnect_cleanup(client->id);
200 #ifdef PCMK__COMPILE_REMOTE
201 ipc_proxy_remove_provider(client);
202 #endif
203 lrmd_client_destroy(client);
204 return 0;
205 }
206
207 static void
208 lrmd_ipc_destroy(qb_ipcs_connection_t * c)
209 {
210 lrmd_ipc_closed(c);
211 crm_trace("Connection %p", c);
212 }
213
214 static struct qb_ipcs_service_handlers lrmd_ipc_callbacks = {
215 .connection_accept = lrmd_ipc_accept,
216 .connection_created = lrmd_ipc_created,
217 .msg_process = lrmd_ipc_dispatch,
218 .connection_closed = lrmd_ipc_closed,
219 .connection_destroyed = lrmd_ipc_destroy
220 };
221
222
223 int
224 lrmd_server_send_reply(pcmk__client_t *client, uint32_t id, xmlNode *reply)
225 {
226 crm_trace("Sending reply (%d) to client (%s)", id, client->id);
227 switch (PCMK__CLIENT_TYPE(client)) {
228 case pcmk__client_ipc:
229 return pcmk__ipc_send_xml(client, id, reply, FALSE);
230 #ifdef PCMK__COMPILE_REMOTE
231 case pcmk__client_tls:
232 return lrmd__remote_send_xml(client->remote, reply, id, "reply");
233 #endif
234 default:
235 crm_err("Could not send reply: unknown type for client %s "
236 CRM_XS " flags=%#llx",
237 pcmk__client_name(client), client->flags);
238 }
239 return ENOTCONN;
240 }
241
242
243 int
244 lrmd_server_send_notify(pcmk__client_t *client, xmlNode *msg)
245 {
246 crm_trace("Sending notification to client (%s)", client->id);
247 switch (PCMK__CLIENT_TYPE(client)) {
248 case pcmk__client_ipc:
249 if (client->ipcs == NULL) {
250 crm_trace("Could not notify local client: disconnected");
251 return ENOTCONN;
252 }
253 return pcmk__ipc_send_xml(client, 0, msg, crm_ipc_server_event);
254 #ifdef PCMK__COMPILE_REMOTE
255 case pcmk__client_tls:
256 if (client->remote == NULL) {
257 crm_trace("Could not notify remote client: disconnected");
258 return ENOTCONN;
259 } else {
260 return lrmd__remote_send_xml(client->remote, msg, 0, "notify");
261 }
262 #endif
263 default:
264 crm_err("Could not notify client %s with unknown transport "
265 CRM_XS " flags=%#llx",
266 pcmk__client_name(client), client->flags);
267 }
268 return ENOTCONN;
269 }
270
271
272
273
274
275
276
277
278
279
280 static gboolean
281 lrmd_exit(gpointer data)
282 {
283 crm_info("Terminating with %d clients", pcmk__ipc_client_count());
284 if (stonith_api) {
285 stonith_api->cmds->remove_notification(stonith_api, T_STONITH_NOTIFY_DISCONNECT);
286 stonith_api->cmds->disconnect(stonith_api);
287 stonith_api_delete(stonith_api);
288 }
289 if (ipcs) {
290 mainloop_del_ipc_server(ipcs);
291 }
292
293 #ifdef PCMK__COMPILE_REMOTE
294 execd_stop_tls_server();
295 ipc_proxy_cleanup();
296 #endif
297
298 pcmk__client_cleanup();
299 g_hash_table_destroy(rsc_list);
300
301 if (mainloop) {
302 lrmd_drain_alerts(mainloop);
303 }
304
305 crm_exit(CRM_EX_OK);
306 return FALSE;
307 }
308
309
310
311
312
313
314
315 static void
316 lrmd_shutdown(int nsig)
317 {
318 #ifdef PCMK__COMPILE_REMOTE
319 pcmk__client_t *ipc_proxy = ipc_proxy_get_provider();
320
321
322
323
324 if (ipc_proxy) {
325 if (shutting_down) {
326 crm_notice("Waiting for cluster to stop resources before exiting");
327 return;
328 }
329
330 crm_info("Sending shutdown request to cluster");
331 if (ipc_proxy_shutdown_req(ipc_proxy) < 0) {
332 crm_crit("Shutdown request failed, exiting immediately");
333
334 } else {
335
336
337
338
339
340 shutting_down = TRUE;
341
342
343 execd_stop_tls_server();
344
345
346
347
348
349 shutdown_ack_timer = g_timeout_add_seconds(20, lrmd_exit, NULL);
350
351
352
353
354
355
356 return;
357 }
358 }
359 #endif
360 lrmd_exit(NULL);
361 }
362
363
364
365
366
367 void
368 handle_shutdown_ack(void)
369 {
370 #ifdef PCMK__COMPILE_REMOTE
371 if (shutting_down) {
372 crm_info("Received shutdown ack");
373 if (shutdown_ack_timer > 0) {
374 g_source_remove(shutdown_ack_timer);
375 shutdown_ack_timer = 0;
376 }
377 return;
378 }
379 #endif
380 crm_debug("Ignoring unexpected shutdown ack");
381 }
382
383
384
385
386
387 void
388 handle_shutdown_nack(void)
389 {
390 #ifdef PCMK__COMPILE_REMOTE
391 if (shutting_down) {
392 crm_info("Received shutdown nack");
393 if (shutdown_ack_timer > 0) {
394 g_source_remove(shutdown_ack_timer);
395 shutdown_ack_timer = g_timeout_add(0, lrmd_exit, NULL);
396 }
397 return;
398 }
399 #endif
400 crm_debug("Ignoring unexpected shutdown nack");
401 }
402
403 static GOptionEntry entries[] = {
404 { "logfile", 'l', G_OPTION_FLAG_NONE, G_OPTION_ARG_FILENAME_ARRAY,
405 &options.log_files, "Send logs to the additional named logfile", NULL },
406
407 #ifdef PCMK__COMPILE_REMOTE
408
409 { "port", 'p', G_OPTION_FLAG_NONE, G_OPTION_ARG_STRING, &options.port,
410 "Port to listen on (defaults to " G_STRINGIFY(DEFAULT_REMOTE_PORT) ")", NULL },
411 #endif
412
413 { NULL }
414 };
415
416 static pcmk__supported_format_t formats[] = {
417 PCMK__SUPPORTED_FORMAT_NONE,
418 PCMK__SUPPORTED_FORMAT_TEXT,
419 PCMK__SUPPORTED_FORMAT_XML,
420 { NULL, NULL, NULL }
421 };
422
423 static GOptionContext *
424 build_arg_context(pcmk__common_args_t *args, GOptionGroup **group)
425 {
426 GOptionContext *context = NULL;
427
428 context = pcmk__build_arg_context(args, "text (default), xml", group, NULL);
429 pcmk__add_main_args(context, entries);
430 return context;
431 }
432
433 int
434 main(int argc, char **argv, char **envp)
435 {
436 int rc = pcmk_rc_ok;
437 crm_exit_t exit_code = CRM_EX_OK;
438
439 const char *option = NULL;
440
441 pcmk__output_t *out = NULL;
442
443 GError *error = NULL;
444
445 GOptionGroup *output_group = NULL;
446 pcmk__common_args_t *args = pcmk__new_common_args(SUMMARY);
447 #ifdef PCMK__COMPILE_REMOTE
448 gchar **processed_args = pcmk__cmdline_preproc(argv, "lp");
449 #else
450 gchar **processed_args = pcmk__cmdline_preproc(argv, "l");
451 #endif
452 GOptionContext *context = build_arg_context(args, &output_group);
453
454 #ifdef PCMK__COMPILE_REMOTE
455
456 remoted_spawn_pidone(argc, argv, envp);
457 #endif
458
459 crm_log_preinit(EXECD_NAME, argc, argv);
460
461 pcmk__register_formats(output_group, formats);
462 if (!g_option_context_parse_strv(context, &processed_args, &error)) {
463 exit_code = CRM_EX_USAGE;
464 goto done;
465 }
466
467 rc = pcmk__output_new(&out, args->output_ty, args->output_dest, argv);
468 if (rc != pcmk_rc_ok) {
469 exit_code = CRM_EX_ERROR;
470 g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
471 "Error creating output format %s: %s",
472 args->output_ty, pcmk_rc_str(rc));
473 goto done;
474 }
475
476 if (args->version) {
477 out->version(out, false);
478 goto done;
479 }
480
481
482 if (options.log_files != NULL) {
483 for (gchar **fname = options.log_files; *fname != NULL; fname++) {
484 rc = pcmk__add_logfile(*fname);
485
486 if (rc != pcmk_rc_ok) {
487 out->err(out, "Logging to %s is disabled: %s",
488 *fname, pcmk_rc_str(rc));
489 }
490 }
491 }
492
493 pcmk__cli_init_logging(EXECD_NAME, args->verbosity);
494 crm_log_init(NULL, LOG_INFO, TRUE, FALSE, argc, argv, FALSE);
495
496 option = pcmk__env_option(PCMK__ENV_LOGFACILITY);
497 if (!pcmk__str_eq(option, PCMK__VALUE_NONE,
498 pcmk__str_casei|pcmk__str_null_matches)
499 && !pcmk__str_eq(option, "/dev/null", pcmk__str_none)) {
500 setenv("HA_LOGFACILITY", option, 1);
501 }
502
503 option = pcmk__env_option(PCMK__ENV_LOGFILE);
504 if (!pcmk__str_eq(option, PCMK__VALUE_NONE,
505 pcmk__str_casei|pcmk__str_null_matches)) {
506 setenv("HA_LOGFILE", option, 1);
507
508 if (pcmk__env_option_enabled(crm_system_name, PCMK__ENV_DEBUG)) {
509 setenv("HA_DEBUGLOG", option, 1);
510 }
511 }
512
513 #ifdef PCMK__COMPILE_REMOTE
514 if (options.port != NULL) {
515 setenv("PCMK_remote_port", options.port, 1);
516 }
517 #endif
518
519 start_time = time(NULL);
520
521 crm_notice("Starting Pacemaker " EXECD_TYPE " executor");
522
523
524
525
526
527 unsetenv("NOTIFY_SOCKET");
528
529 {
530
531 int rc = pcmk__build_path(CRM_RSCTMP_DIR, 0755);
532
533 if (rc != pcmk_rc_ok) {
534 crm_warn("Could not create resource agent temporary directory "
535 CRM_RSCTMP_DIR ": %s", pcmk_rc_str(rc));
536 }
537 }
538
539 rsc_list = pcmk__strkey_table(NULL, free_rsc);
540 ipcs = mainloop_add_ipc_server(CRM_SYSTEM_LRMD, QB_IPC_SHM, &lrmd_ipc_callbacks);
541 if (ipcs == NULL) {
542 crm_err("Failed to create IPC server: shutting down and inhibiting respawn");
543 exit_code = CRM_EX_FATAL;
544 goto done;
545 }
546
547 #ifdef PCMK__COMPILE_REMOTE
548 if (lrmd_init_remote_tls_server() < 0) {
549 crm_err("Failed to create TLS listener: shutting down and staying down");
550 exit_code = CRM_EX_FATAL;
551 goto done;
552 }
553 ipc_proxy_init();
554 #endif
555
556 mainloop_add_signal(SIGTERM, lrmd_shutdown);
557 mainloop = g_main_loop_new(NULL, FALSE);
558 crm_notice("Pacemaker " EXECD_TYPE " executor successfully started and accepting connections");
559 crm_notice("OCF resource agent search path is %s", OCF_RA_PATH);
560 g_main_loop_run(mainloop);
561
562
563 lrmd_exit(NULL);
564
565 done:
566 g_strfreev(options.log_files);
567 #ifdef PCMK__COMPILE_REMOTE
568 g_free(options.port);
569 #endif
570
571 g_strfreev(processed_args);
572 pcmk__free_arg_context(context);
573
574 pcmk__output_and_clear_error(&error, out);
575
576 if (out != NULL) {
577 out->finish(out, exit_code, true, NULL);
578 pcmk__output_free(out);
579 }
580 pcmk__unregister_formats();
581 crm_exit(exit_code);
582 }