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