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