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