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