pacemaker 2.1.5-a3f44794f94
Scalable High-Availability cluster resource manager
lrmd_client.c
Go to the documentation of this file.
1/*
2 * Copyright 2012-2022 the Pacemaker project contributors
3 *
4 * The version control history for this file may have further details.
5 *
6 * This source code is licensed under the GNU Lesser General Public License
7 * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
8 */
9
10#include <crm_internal.h>
11
12#include <unistd.h>
13#include <stdlib.h>
14#include <stdio.h>
15#include <stdint.h> // uint32_t, uint64_t
16#include <stdarg.h>
17#include <string.h>
18#include <ctype.h>
19#include <errno.h>
20
21#include <sys/types.h>
22#include <sys/wait.h>
23
24#include <glib.h>
25#include <dirent.h>
26
27#include <crm/crm.h>
28#include <crm/lrmd.h>
29#include <crm/lrmd_internal.h>
30#include <crm/services.h>
32#include <crm/common/mainloop.h>
35#include <crm/msg_xml.h>
36
37#include <crm/stonith-ng.h>
39
40#ifdef HAVE_GNUTLS_GNUTLS_H
41# include <gnutls/gnutls.h>
42#endif
43
44#include <sys/socket.h>
45#include <netinet/in.h>
46#include <netinet/ip.h>
47#include <arpa/inet.h>
48#include <netdb.h>
49
50#define MAX_TLS_RECV_WAIT 10000
51
53
54static int lrmd_api_disconnect(lrmd_t * lrmd);
55static int lrmd_api_is_connected(lrmd_t * lrmd);
56
57/* IPC proxy functions */
58int lrmd_internal_proxy_send(lrmd_t * lrmd, xmlNode *msg);
59static void lrmd_internal_proxy_dispatch(lrmd_t *lrmd, xmlNode *msg);
60void lrmd_internal_set_proxy_callback(lrmd_t * lrmd, void *userdata, void (*callback)(lrmd_t *lrmd, void *userdata, xmlNode *msg));
61
62#ifdef HAVE_GNUTLS_GNUTLS_H
63# define LRMD_CLIENT_HANDSHAKE_TIMEOUT 5000 /* 5 seconds */
64gnutls_psk_client_credentials_t psk_cred_s;
65static void lrmd_tls_disconnect(lrmd_t * lrmd);
66static int global_remote_msg_id = 0;
67static void lrmd_tls_connection_destroy(gpointer userdata);
68#endif
69
70typedef struct lrmd_private_s {
71 uint64_t type;
72 char *token;
73 mainloop_io_t *source;
74
75 /* IPC parameters */
76 crm_ipc_t *ipc;
77
78 pcmk__remote_t *remote;
79
80 /* Extra TLS parameters */
81 char *remote_nodename;
82#ifdef HAVE_GNUTLS_GNUTLS_H
83 char *server;
84 int port;
85 gnutls_psk_client_credentials_t psk_cred_c;
86
87 /* while the async connection is occurring, this is the id
88 * of the connection timeout timer. */
89 int async_timer;
90 int sock;
91 /* since tls requires a round trip across the network for a
92 * request/reply, there are times where we just want to be able
93 * to send a request from the client and not wait around (or even care
94 * about) what the reply is. */
95 int expected_late_replies;
96 GList *pending_notify;
97 crm_trigger_t *process_notify;
98#endif
99
100 lrmd_event_callback callback;
101
102 /* Internal IPC proxy msg passing for remote guests */
103 void (*proxy_callback)(lrmd_t *lrmd, void *userdata, xmlNode *msg);
104 void *proxy_callback_userdata;
105 char *peer_version;
107
108static lrmd_list_t *
109lrmd_list_add(lrmd_list_t * head, const char *value)
110{
111 lrmd_list_t *p, *end;
112
113 p = calloc(1, sizeof(lrmd_list_t));
114 p->val = strdup(value);
115
116 end = head;
117 while (end && end->next) {
118 end = end->next;
119 }
120
121 if (end) {
122 end->next = p;
123 } else {
124 head = p;
125 }
126
127 return head;
128}
129
130void
132{
133 lrmd_list_t *p;
134
135 while (head) {
136 char *val = (char *)head->val;
137
138 p = head->next;
139 free(val);
140 free(head);
141 head = p;
142 }
143}
144
146lrmd_key_value_add(lrmd_key_value_t * head, const char *key, const char *value)
147{
148 lrmd_key_value_t *p, *end;
149
150 p = calloc(1, sizeof(lrmd_key_value_t));
151 p->key = strdup(key);
152 p->value = strdup(value);
153
154 end = head;
155 while (end && end->next) {
156 end = end->next;
157 }
158
159 if (end) {
160 end->next = p;
161 } else {
162 head = p;
163 }
164
165 return head;
166}
167
168void
170{
172
173 while (head) {
174 p = head->next;
175 free(head->key);
176 free(head->value);
177 free(head);
178 head = p;
179 }
180}
181
195lrmd_new_event(const char *rsc_id, const char *task, guint interval_ms)
196{
197 lrmd_event_data_t *event = calloc(1, sizeof(lrmd_event_data_t));
198
199 CRM_ASSERT(event != NULL);
200 pcmk__str_update((char **) &event->rsc_id, rsc_id);
201 pcmk__str_update((char **) &event->op_type, task);
202 event->interval_ms = interval_ms;
203 return event;
204}
205
208{
209 lrmd_event_data_t *copy = NULL;
210
211 copy = calloc(1, sizeof(lrmd_event_data_t));
212
213 copy->type = event->type;
214 pcmk__str_update((char **) &copy->rsc_id, event->rsc_id);
215 pcmk__str_update((char **) &copy->op_type, event->op_type);
216 pcmk__str_update((char **) &copy->user_data, event->user_data);
217 copy->call_id = event->call_id;
218 copy->timeout = event->timeout;
219 copy->interval_ms = event->interval_ms;
220 copy->start_delay = event->start_delay;
221 copy->rsc_deleted = event->rsc_deleted;
222 copy->rc = event->rc;
223 copy->op_status = event->op_status;
224 pcmk__str_update((char **) &copy->output, event->output);
225 copy->t_run = event->t_run;
226 copy->t_rcchange = event->t_rcchange;
227 copy->exec_time = event->exec_time;
228 copy->queue_time = event->queue_time;
229 copy->connection_rc = event->connection_rc;
230 copy->params = pcmk__str_table_dup(event->params);
231 pcmk__str_update((char **) &copy->remote_nodename, event->remote_nodename);
232 pcmk__str_update((char **) &copy->exit_reason, event->exit_reason);
233
234 return copy;
235}
236
242void
244{
245 if (event == NULL) {
246 return;
247 }
248 // @TODO Why are these const char *?
249 free((void *) event->rsc_id);
250 free((void *) event->op_type);
251 free((void *) event->user_data);
252 free((void *) event->remote_nodename);
253 lrmd__reset_result(event);
254 if (event->params != NULL) {
255 g_hash_table_destroy(event->params);
256 }
257 free(event);
258}
259
260static void
261lrmd_dispatch_internal(lrmd_t * lrmd, xmlNode * msg)
262{
263 const char *type;
264 const char *proxy_session = crm_element_value(msg, F_LRMD_IPC_SESSION);
265 lrmd_private_t *native = lrmd->lrmd_private;
266 lrmd_event_data_t event = { 0, };
267
268 if (proxy_session != NULL) {
269 /* this is proxy business */
270 lrmd_internal_proxy_dispatch(lrmd, msg);
271 return;
272 } else if (!native->callback) {
273 /* no callback set */
274 crm_trace("notify event received but client has not set callback");
275 return;
276 }
277
278 event.remote_nodename = native->remote_nodename;
280 crm_element_value_int(msg, F_LRMD_CALLID, &event.call_id);
281 event.rsc_id = crm_element_value(msg, F_LRMD_RSC_ID);
282
283 if (pcmk__str_eq(type, LRMD_OP_RSC_REG, pcmk__str_none)) {
284 event.type = lrmd_event_register;
285 } else if (pcmk__str_eq(type, LRMD_OP_RSC_UNREG, pcmk__str_none)) {
286 event.type = lrmd_event_unregister;
287 } else if (pcmk__str_eq(type, LRMD_OP_RSC_EXEC, pcmk__str_none)) {
288 time_t epoch = 0;
289
290 crm_element_value_int(msg, F_LRMD_TIMEOUT, &event.timeout);
291 crm_element_value_ms(msg, F_LRMD_RSC_INTERVAL, &event.interval_ms);
292 crm_element_value_int(msg, F_LRMD_RSC_START_DELAY, &event.start_delay);
293 crm_element_value_int(msg, F_LRMD_EXEC_RC, (int *)&event.rc);
294 crm_element_value_int(msg, F_LRMD_OP_STATUS, &event.op_status);
295 crm_element_value_int(msg, F_LRMD_RSC_DELETED, &event.rsc_deleted);
296
298 event.t_run = (unsigned int) epoch;
299
301 event.t_rcchange = (unsigned int) epoch;
302
303 crm_element_value_int(msg, F_LRMD_RSC_EXEC_TIME, (int *)&event.exec_time);
304 crm_element_value_int(msg, F_LRMD_RSC_QUEUE_TIME, (int *)&event.queue_time);
305
306 event.op_type = crm_element_value(msg, F_LRMD_RSC_ACTION);
307 event.user_data = crm_element_value(msg, F_LRMD_RSC_USERDATA_STR);
308 event.type = lrmd_event_exec_complete;
309
310 /* output and exit_reason may be freed by a callback */
311 event.output = crm_element_value_copy(msg, F_LRMD_RSC_OUTPUT);
312 lrmd__set_result(&event, event.rc, event.op_status,
314
315 event.params = xml2list(msg);
316 } else if (pcmk__str_eq(type, LRMD_OP_NEW_CLIENT, pcmk__str_none)) {
317 event.type = lrmd_event_new_client;
318 } else if (pcmk__str_eq(type, LRMD_OP_POKE, pcmk__str_none)) {
319 event.type = lrmd_event_poke;
320 } else {
321 return;
322 }
323
324 crm_trace("op %s notify event received", type);
325 native->callback(&event);
326
327 if (event.params) {
328 g_hash_table_destroy(event.params);
329 }
330 lrmd__reset_result(&event);
331}
332
333// \return Always 0, to indicate that IPC mainloop source should be kept
334static int
335lrmd_ipc_dispatch(const char *buffer, ssize_t length, gpointer userdata)
336{
337 lrmd_t *lrmd = userdata;
338 lrmd_private_t *native = lrmd->lrmd_private;
339
340 if (native->callback != NULL) {
341 xmlNode *msg = string2xml(buffer);
342
343 lrmd_dispatch_internal(lrmd, msg);
344 free_xml(msg);
345 }
346 return 0;
347}
348
349#ifdef HAVE_GNUTLS_GNUTLS_H
350static void
351lrmd_free_xml(gpointer userdata)
352{
353 free_xml((xmlNode *) userdata);
354}
355
356static bool
357remote_executor_connected(lrmd_t * lrmd)
358{
359 lrmd_private_t *native = lrmd->lrmd_private;
360
361 return (native->remote->tls_session != NULL);
362}
363
375static int
376lrmd_tls_dispatch(gpointer userdata)
377{
378 lrmd_t *lrmd = userdata;
379 lrmd_private_t *native = lrmd->lrmd_private;
380 xmlNode *xml = NULL;
381 int rc = pcmk_rc_ok;
382
383 if (!remote_executor_connected(lrmd)) {
384 crm_trace("TLS dispatch triggered after disconnect");
385 return 0;
386 }
387
388 crm_trace("TLS dispatch triggered");
389
390 /* First check if there are any pending notifies to process that came
391 * while we were waiting for replies earlier. */
392 if (native->pending_notify) {
393 GList *iter = NULL;
394
395 crm_trace("Processing pending notifies");
396 for (iter = native->pending_notify; iter; iter = iter->next) {
397 lrmd_dispatch_internal(lrmd, iter->data);
398 }
399 g_list_free_full(native->pending_notify, lrmd_free_xml);
400 native->pending_notify = NULL;
401 }
402
403 /* Next read the current buffer and see if there are any messages to handle. */
404 switch (pcmk__remote_ready(native->remote, 0)) {
405 case pcmk_rc_ok:
406 rc = pcmk__read_remote_message(native->remote, -1);
407 xml = pcmk__remote_message_xml(native->remote);
408 break;
409 case ETIME:
410 // Nothing to read, check if a full message is already in buffer
411 xml = pcmk__remote_message_xml(native->remote);
412 break;
413 default:
414 rc = ENOTCONN;
415 break;
416 }
417 while (xml) {
418 const char *msg_type = crm_element_value(xml, F_LRMD_REMOTE_MSG_TYPE);
419 if (pcmk__str_eq(msg_type, "notify", pcmk__str_casei)) {
420 lrmd_dispatch_internal(lrmd, xml);
421 } else if (pcmk__str_eq(msg_type, "reply", pcmk__str_casei)) {
422 if (native->expected_late_replies > 0) {
423 native->expected_late_replies--;
424 } else {
425 int reply_id = 0;
426 crm_element_value_int(xml, F_LRMD_CALLID, &reply_id);
427 /* if this happens, we want to know about it */
428 crm_err("Got outdated Pacemaker Remote reply %d", reply_id);
429 }
430 }
431 free_xml(xml);
432 xml = pcmk__remote_message_xml(native->remote);
433 }
434
435 if (rc == ENOTCONN) {
436 crm_info("Lost %s executor connection while reading data",
437 (native->remote_nodename? native->remote_nodename : "local"));
438 lrmd_tls_disconnect(lrmd);
439 return 0;
440 }
441 return 1;
442}
443#endif
444
445/* Not used with mainloop */
446int
448{
449 lrmd_private_t *native = lrmd->lrmd_private;
450
451 switch (native->type) {
452 case pcmk__client_ipc:
453 return crm_ipc_ready(native->ipc);
454
455#ifdef HAVE_GNUTLS_GNUTLS_H
456 case pcmk__client_tls:
457 if (native->pending_notify) {
458 return 1;
459 } else {
460 int rc = pcmk__remote_ready(native->remote, 0);
461
462 switch (rc) {
463 case pcmk_rc_ok:
464 return 1;
465 case ETIME:
466 return 0;
467 default:
468 return pcmk_rc2legacy(rc);
469 }
470 }
471#endif
472 default:
473 crm_err("Unsupported executor connection type (bug?): %d",
474 native->type);
475 return -EPROTONOSUPPORT;
476 }
477}
478
479/* Not used with mainloop */
480bool
482{
483 lrmd_private_t *private = NULL;
484
485 CRM_ASSERT(lrmd != NULL);
486
487 private = lrmd->lrmd_private;
488 switch (private->type) {
489 case pcmk__client_ipc:
490 while (crm_ipc_ready(private->ipc)) {
491 if (crm_ipc_read(private->ipc) > 0) {
492 const char *msg = crm_ipc_buffer(private->ipc);
493
494 lrmd_ipc_dispatch(msg, strlen(msg), lrmd);
495 }
496 }
497 break;
498#ifdef HAVE_GNUTLS_GNUTLS_H
499 case pcmk__client_tls:
500 lrmd_tls_dispatch(lrmd);
501 break;
502#endif
503 default:
504 crm_err("Unsupported executor connection type (bug?): %d",
505 private->type);
506 }
507
508 if (lrmd_api_is_connected(lrmd) == FALSE) {
509 crm_err("Connection closed");
510 return FALSE;
511 }
512
513 return TRUE;
514}
515
516static xmlNode *
517lrmd_create_op(const char *token, const char *op, xmlNode *data, int timeout,
518 enum lrmd_call_options options)
519{
520 xmlNode *op_msg = create_xml_node(NULL, "lrmd_command");
521
522 CRM_CHECK(op_msg != NULL, return NULL);
523 CRM_CHECK(token != NULL, return NULL);
524
525 crm_xml_add(op_msg, F_XML_TAGNAME, "lrmd_command");
526 crm_xml_add(op_msg, F_TYPE, T_LRMD);
527 crm_xml_add(op_msg, F_LRMD_CALLBACK_TOKEN, token);
528 crm_xml_add(op_msg, F_LRMD_OPERATION, op);
530 crm_xml_add_int(op_msg, F_LRMD_CALLOPTS, options);
531
532 if (data != NULL) {
534 }
535
536 crm_trace("Created executor %s command with call options %.8lx (%d)",
537 op, (long)options, options);
538 return op_msg;
539}
540
541static void
542lrmd_ipc_connection_destroy(gpointer userdata)
543{
544 lrmd_t *lrmd = userdata;
545 lrmd_private_t *native = lrmd->lrmd_private;
546
547 crm_info("IPC connection destroyed");
548
549 /* Prevent these from being cleaned up in lrmd_api_disconnect() */
550 native->ipc = NULL;
551 native->source = NULL;
552
553 if (native->callback) {
554 lrmd_event_data_t event = { 0, };
556 event.remote_nodename = native->remote_nodename;
557 native->callback(&event);
558 }
559}
560
561#ifdef HAVE_GNUTLS_GNUTLS_H
562static void
563lrmd_tls_connection_destroy(gpointer userdata)
564{
565 lrmd_t *lrmd = userdata;
566 lrmd_private_t *native = lrmd->lrmd_private;
567
568 crm_info("TLS connection destroyed");
569
570 if (native->remote->tls_session) {
571 gnutls_bye(*native->remote->tls_session, GNUTLS_SHUT_RDWR);
572 gnutls_deinit(*native->remote->tls_session);
573 gnutls_free(native->remote->tls_session);
574 }
575 if (native->psk_cred_c) {
576 gnutls_psk_free_client_credentials(native->psk_cred_c);
577 }
578 if (native->sock) {
579 close(native->sock);
580 }
581 if (native->process_notify) {
582 mainloop_destroy_trigger(native->process_notify);
583 native->process_notify = NULL;
584 }
585 if (native->pending_notify) {
586 g_list_free_full(native->pending_notify, lrmd_free_xml);
587 native->pending_notify = NULL;
588 }
589
590 free(native->remote->buffer);
591 native->remote->buffer = NULL;
592 native->source = 0;
593 native->sock = 0;
594 native->psk_cred_c = NULL;
595 native->remote->tls_session = NULL;
596 native->sock = 0;
597
598 if (native->callback) {
599 lrmd_event_data_t event = { 0, };
600 event.remote_nodename = native->remote_nodename;
601 event.type = lrmd_event_disconnect;
602 native->callback(&event);
603 }
604 return;
605}
606
607// \return Standard Pacemaker return code
608int
609lrmd__remote_send_xml(pcmk__remote_t *session, xmlNode *msg, uint32_t id,
610 const char *msg_type)
611{
613 crm_xml_add(msg, F_LRMD_REMOTE_MSG_TYPE, msg_type);
614 return pcmk__remote_send_xml(session, msg);
615}
616
617// \return Standard Pacemaker return code
618static int
619read_remote_reply(lrmd_t *lrmd, int total_timeout, int expected_reply_id,
620 xmlNode **reply)
621{
622 lrmd_private_t *native = lrmd->lrmd_private;
623 time_t start = time(NULL);
624 const char *msg_type = NULL;
625 int reply_id = 0;
626 int remaining_timeout = 0;
627 int rc = pcmk_rc_ok;
628
629 /* A timeout of 0 here makes no sense. We have to wait a period of time
630 * for the response to come back. If -1 or 0, default to 10 seconds. */
631 if (total_timeout <= 0 || total_timeout > MAX_TLS_RECV_WAIT) {
632 total_timeout = MAX_TLS_RECV_WAIT;
633 }
634
635 for (*reply = NULL; *reply == NULL; ) {
636
637 *reply = pcmk__remote_message_xml(native->remote);
638 if (*reply == NULL) {
639 /* read some more off the tls buffer if we still have time left. */
640 if (remaining_timeout) {
641 remaining_timeout = total_timeout - ((time(NULL) - start) * 1000);
642 } else {
643 remaining_timeout = total_timeout;
644 }
645 if (remaining_timeout <= 0) {
646 return ETIME;
647 }
648
649 rc = pcmk__read_remote_message(native->remote, remaining_timeout);
650 if (rc != pcmk_rc_ok) {
651 return rc;
652 }
653
654 *reply = pcmk__remote_message_xml(native->remote);
655 if (*reply == NULL) {
656 return ENOMSG;
657 }
658 }
659
661 msg_type = crm_element_value(*reply, F_LRMD_REMOTE_MSG_TYPE);
662
663 if (!msg_type) {
664 crm_err("Empty msg type received while waiting for reply");
665 free_xml(*reply);
666 *reply = NULL;
667 } else if (pcmk__str_eq(msg_type, "notify", pcmk__str_casei)) {
668 /* got a notify while waiting for reply, trigger the notify to be processed later */
669 crm_info("queueing notify");
670 native->pending_notify = g_list_append(native->pending_notify, *reply);
671 if (native->process_notify) {
672 crm_info("notify trigger set.");
673 mainloop_set_trigger(native->process_notify);
674 }
675 *reply = NULL;
676 } else if (!pcmk__str_eq(msg_type, "reply", pcmk__str_casei)) {
677 /* msg isn't a reply, make some noise */
678 crm_err("Expected a reply, got %s", msg_type);
679 free_xml(*reply);
680 *reply = NULL;
681 } else if (reply_id != expected_reply_id) {
682 if (native->expected_late_replies > 0) {
683 native->expected_late_replies--;
684 } else {
685 crm_err("Got outdated reply, expected id %d got id %d", expected_reply_id, reply_id);
686 }
687 free_xml(*reply);
688 *reply = NULL;
689 }
690 }
691
692 if (native->remote->buffer && native->process_notify) {
693 mainloop_set_trigger(native->process_notify);
694 }
695
696 return rc;
697}
698
699// \return Standard Pacemaker return code
700static int
701send_remote_message(lrmd_t *lrmd, xmlNode *msg)
702{
703 int rc = pcmk_rc_ok;
704 lrmd_private_t *native = lrmd->lrmd_private;
705
706 global_remote_msg_id++;
707 if (global_remote_msg_id <= 0) {
708 global_remote_msg_id = 1;
709 }
710
711 rc = lrmd__remote_send_xml(native->remote, msg, global_remote_msg_id,
712 "request");
713 if (rc != pcmk_rc_ok) {
714 crm_err("Disconnecting because TLS message could not be sent to "
715 "Pacemaker Remote: %s", pcmk_rc_str(rc));
716 lrmd_tls_disconnect(lrmd);
717 }
718 return rc;
719}
720
721static int
722lrmd_tls_send_recv(lrmd_t * lrmd, xmlNode * msg, int timeout, xmlNode ** reply)
723{
724 int rc = 0;
725 xmlNode *xml = NULL;
726
727 if (!remote_executor_connected(lrmd)) {
728 return -ENOTCONN;
729 }
730
731 rc = send_remote_message(lrmd, msg);
732 if (rc != pcmk_rc_ok) {
733 return pcmk_rc2legacy(rc);
734 }
735
736 rc = read_remote_reply(lrmd, timeout, global_remote_msg_id, &xml);
737 if (rc != pcmk_rc_ok) {
738 crm_err("Disconnecting remote after request %d reply not received: %s "
739 CRM_XS " rc=%d timeout=%dms",
740 global_remote_msg_id, pcmk_rc_str(rc), rc, timeout);
741 lrmd_tls_disconnect(lrmd);
742 }
743
744 if (reply) {
745 *reply = xml;
746 } else {
747 free_xml(xml);
748 }
749
750 return pcmk_rc2legacy(rc);
751}
752#endif
753
754static int
755lrmd_send_xml(lrmd_t * lrmd, xmlNode * msg, int timeout, xmlNode ** reply)
756{
757 int rc = pcmk_ok;
758 lrmd_private_t *native = lrmd->lrmd_private;
759
760 switch (native->type) {
761 case pcmk__client_ipc:
762 rc = crm_ipc_send(native->ipc, msg, crm_ipc_client_response, timeout, reply);
763 break;
764#ifdef HAVE_GNUTLS_GNUTLS_H
765 case pcmk__client_tls:
766 rc = lrmd_tls_send_recv(lrmd, msg, timeout, reply);
767 break;
768#endif
769 default:
770 crm_err("Unsupported executor connection type (bug?): %d",
771 native->type);
772 rc = -EPROTONOSUPPORT;
773 }
774
775 return rc;
776}
777
778static int
779lrmd_send_xml_no_reply(lrmd_t * lrmd, xmlNode * msg)
780{
781 int rc = pcmk_ok;
782 lrmd_private_t *native = lrmd->lrmd_private;
783
784 switch (native->type) {
785 case pcmk__client_ipc:
786 rc = crm_ipc_send(native->ipc, msg, crm_ipc_flags_none, 0, NULL);
787 break;
788#ifdef HAVE_GNUTLS_GNUTLS_H
789 case pcmk__client_tls:
790 rc = send_remote_message(lrmd, msg);
791 if (rc == pcmk_rc_ok) {
792 /* we don't want to wait around for the reply, but
793 * since the request/reply protocol needs to behave the same
794 * as libqb, a reply will eventually come later anyway. */
795 native->expected_late_replies++;
796 }
797 rc = pcmk_rc2legacy(rc);
798 break;
799#endif
800 default:
801 crm_err("Unsupported executor connection type (bug?): %d",
802 native->type);
803 rc = -EPROTONOSUPPORT;
804 }
805
806 return rc;
807}
808
809static int
810lrmd_api_is_connected(lrmd_t * lrmd)
811{
812 lrmd_private_t *native = lrmd->lrmd_private;
813
814 switch (native->type) {
815 case pcmk__client_ipc:
816 return crm_ipc_connected(native->ipc);
817#ifdef HAVE_GNUTLS_GNUTLS_H
818 case pcmk__client_tls:
819 return remote_executor_connected(lrmd);
820#endif
821 default:
822 crm_err("Unsupported executor connection type (bug?): %d",
823 native->type);
824 return 0;
825 }
826}
827
846static int
847lrmd_send_command(lrmd_t *lrmd, const char *op, xmlNode *data,
848 xmlNode **output_data, int timeout,
849 enum lrmd_call_options options, gboolean expect_reply)
850{
851 int rc = pcmk_ok;
852 lrmd_private_t *native = lrmd->lrmd_private;
853 xmlNode *op_msg = NULL;
854 xmlNode *op_reply = NULL;
855
856 if (!lrmd_api_is_connected(lrmd)) {
857 return -ENOTCONN;
858 }
859
860 if (op == NULL) {
861 crm_err("No operation specified");
862 return -EINVAL;
863 }
864
865 CRM_CHECK(native->token != NULL,;
866 );
867 crm_trace("Sending %s op to executor", op);
868
869 op_msg = lrmd_create_op(native->token, op, data, timeout, options);
870
871 if (op_msg == NULL) {
872 return -EINVAL;
873 }
874
875 if (expect_reply) {
876 rc = lrmd_send_xml(lrmd, op_msg, timeout, &op_reply);
877 } else {
878 rc = lrmd_send_xml_no_reply(lrmd, op_msg);
879 goto done;
880 }
881
882 if (rc < 0) {
883 crm_perror(LOG_ERR, "Couldn't perform %s operation (timeout=%d): %d", op, timeout, rc);
884 goto done;
885
886 } else if(op_reply == NULL) {
887 rc = -ENOMSG;
888 goto done;
889 }
890
891 rc = pcmk_ok;
892 crm_trace("%s op reply received", op);
893 if (crm_element_value_int(op_reply, F_LRMD_RC, &rc) != 0) {
894 rc = -ENOMSG;
895 goto done;
896 }
897
898 crm_log_xml_trace(op_reply, "Reply");
899
900 if (output_data) {
901 *output_data = op_reply;
902 op_reply = NULL; /* Prevent subsequent free */
903 }
904
905 done:
906 if (lrmd_api_is_connected(lrmd) == FALSE) {
907 crm_err("Executor disconnected");
908 }
909
910 free_xml(op_msg);
911 free_xml(op_reply);
912 return rc;
913}
914
915static int
916lrmd_api_poke_connection(lrmd_t * lrmd)
917{
918 int rc;
919 lrmd_private_t *native = lrmd->lrmd_private;
920 xmlNode *data = create_xml_node(NULL, F_LRMD_RSC);
921
922 crm_xml_add(data, F_LRMD_ORIGIN, __func__);
923 rc = lrmd_send_command(lrmd, LRMD_OP_POKE, data, NULL, 0, 0,
924 (native->type == pcmk__client_ipc));
925 free_xml(data);
926
927 return rc < 0 ? rc : pcmk_ok;
928}
929
930// \return Standard Pacemaker return code
931int
933{
934 int rc = pcmk_rc_ok;
935 const char *value;
936 lrmd_private_t *native = lrmd->lrmd_private;
937 xmlNode *data = create_xml_node(NULL, F_LRMD_OPERATION);
938
939 crm_xml_add(data, F_LRMD_ORIGIN, __func__);
940
941 value = g_hash_table_lookup(hash, "stonith-watchdog-timeout");
942 if ((value) &&
943 (stonith__watchdog_fencing_enabled_for_node(native->remote_nodename))) {
945 }
946
947 rc = lrmd_send_command(lrmd, LRMD_OP_CHECK, data, NULL, 0, 0,
948 (native->type == pcmk__client_ipc));
949 free_xml(data);
950 return (rc < 0)? pcmk_legacy2rc(rc) : pcmk_rc_ok;
951}
952
953static int
954lrmd_handshake(lrmd_t * lrmd, const char *name)
955{
956 int rc = pcmk_ok;
957 lrmd_private_t *native = lrmd->lrmd_private;
958 xmlNode *reply = NULL;
959 xmlNode *hello = create_xml_node(NULL, "lrmd_command");
960
961 crm_xml_add(hello, F_TYPE, T_LRMD);
965
966 /* advertise that we are a proxy provider */
967 if (native->proxy_callback) {
969 }
970
971 rc = lrmd_send_xml(lrmd, hello, -1, &reply);
972
973 if (rc < 0) {
974 crm_perror(LOG_DEBUG, "Couldn't complete registration with the executor API: %d", rc);
975 rc = -ECOMM;
976 } else if (reply == NULL) {
977 crm_err("Did not receive registration reply");
978 rc = -EPROTO;
979 } else {
981 const char *msg_type = crm_element_value(reply, F_LRMD_OPERATION);
982 const char *tmp_ticket = crm_element_value(reply, F_LRMD_CLIENTID);
983
984 crm_element_value_int(reply, F_LRMD_RC, &rc);
985
986 if (rc == -EPROTO) {
987 crm_err("Executor protocol version mismatch between client (%s) and server (%s)",
989 crm_log_xml_err(reply, "Protocol Error");
990
991 } else if (!pcmk__str_eq(msg_type, CRM_OP_REGISTER, pcmk__str_casei)) {
992 crm_err("Invalid registration message: %s", msg_type);
993 crm_log_xml_err(reply, "Bad reply");
994 rc = -EPROTO;
995 } else if (tmp_ticket == NULL) {
996 crm_err("No registration token provided");
997 crm_log_xml_err(reply, "Bad reply");
998 rc = -EPROTO;
999 } else {
1000 crm_trace("Obtained registration token: %s", tmp_ticket);
1001 native->token = strdup(tmp_ticket);
1002 native->peer_version = strdup(version?version:"1.0"); /* Included since 1.1 */
1003 rc = pcmk_ok;
1004 }
1005 }
1006
1007 free_xml(reply);
1008 free_xml(hello);
1009
1010 if (rc != pcmk_ok) {
1011 lrmd_api_disconnect(lrmd);
1012 }
1013 return rc;
1014}
1015
1016static int
1017lrmd_ipc_connect(lrmd_t * lrmd, int *fd)
1018{
1019 int rc = pcmk_ok;
1020 lrmd_private_t *native = lrmd->lrmd_private;
1021
1022 struct ipc_client_callbacks lrmd_callbacks = {
1023 .dispatch = lrmd_ipc_dispatch,
1024 .destroy = lrmd_ipc_connection_destroy
1025 };
1026
1027 crm_info("Connecting to executor");
1028
1029 if (fd) {
1030 /* No mainloop */
1031 native->ipc = crm_ipc_new(CRM_SYSTEM_LRMD, 0);
1032 if (native->ipc && crm_ipc_connect(native->ipc)) {
1033 *fd = crm_ipc_get_fd(native->ipc);
1034 } else if (native->ipc) {
1035 crm_perror(LOG_ERR, "Connection to executor failed");
1036 rc = -ENOTCONN;
1037 }
1038 } else {
1039 native->source = mainloop_add_ipc_client(CRM_SYSTEM_LRMD, G_PRIORITY_HIGH, 0, lrmd, &lrmd_callbacks);
1040 native->ipc = mainloop_get_ipc_client(native->source);
1041 }
1042
1043 if (native->ipc == NULL) {
1044 crm_debug("Could not connect to the executor API");
1045 rc = -ENOTCONN;
1046 }
1047
1048 return rc;
1049}
1050
1051#ifdef HAVE_GNUTLS_GNUTLS_H
1052static void
1053copy_gnutls_datum(gnutls_datum_t *dest, gnutls_datum_t *source)
1054{
1055 CRM_ASSERT((dest != NULL) && (source != NULL) && (source->data != NULL));
1056
1057 dest->data = gnutls_malloc(source->size);
1058 CRM_ASSERT(dest->data);
1059
1060 memcpy(dest->data, source->data, source->size);
1061 dest->size = source->size;
1062}
1063
1064static void
1065clear_gnutls_datum(gnutls_datum_t *datum)
1066{
1067 gnutls_free(datum->data);
1068 datum->data = NULL;
1069 datum->size = 0;
1070}
1071
1072#define KEY_READ_LEN 256 // Chunk size for reading key from file
1073
1074// \return Standard Pacemaker return code
1075static int
1076read_gnutls_key(const char *location, gnutls_datum_t *key)
1077{
1078 FILE *stream = NULL;
1079 size_t buf_len = KEY_READ_LEN;
1080
1081 if ((location == NULL) || (key == NULL)) {
1082 return EINVAL;
1083 }
1084
1085 stream = fopen(location, "r");
1086 if (stream == NULL) {
1087 return errno;
1088 }
1089
1090 key->data = gnutls_malloc(buf_len);
1091 key->size = 0;
1092 while (!feof(stream)) {
1093 int next = fgetc(stream);
1094
1095 if (next == EOF) {
1096 if (!feof(stream)) {
1097 crm_warn("Pacemaker Remote key read was partially successful "
1098 "(copy in memory may be corrupted)");
1099 }
1100 break;
1101 }
1102 if (key->size == buf_len) {
1103 buf_len = key->size + KEY_READ_LEN;
1104 key->data = gnutls_realloc(key->data, buf_len);
1105 CRM_ASSERT(key->data);
1106 }
1107 key->data[key->size++] = (unsigned char) next;
1108 }
1109 fclose(stream);
1110
1111 if (key->size == 0) {
1112 clear_gnutls_datum(key);
1113 return ENOKEY;
1114 }
1115 return pcmk_rc_ok;
1116}
1117
1118// Cache the most recently used Pacemaker Remote authentication key
1119
1120struct key_cache_s {
1121 time_t updated; // When cached key was read (valid for 1 minute)
1122 const char *location; // Where cached key was read from
1123 gnutls_datum_t key; // Cached key
1124};
1125
1126static bool
1127key_is_cached(struct key_cache_s *key_cache)
1128{
1129 return key_cache->updated != 0;
1130}
1131
1132static bool
1133key_cache_expired(struct key_cache_s *key_cache)
1134{
1135 return (time(NULL) - key_cache->updated) >= 60;
1136}
1137
1138static void
1139clear_key_cache(struct key_cache_s *key_cache)
1140{
1141 clear_gnutls_datum(&(key_cache->key));
1142 if ((key_cache->updated != 0) || (key_cache->location != NULL)) {
1143 key_cache->updated = 0;
1144 key_cache->location = NULL;
1145 crm_debug("Cleared Pacemaker Remote key cache");
1146 }
1147}
1148
1149static void
1150get_cached_key(struct key_cache_s *key_cache, gnutls_datum_t *key)
1151{
1152 copy_gnutls_datum(key, &(key_cache->key));
1153 crm_debug("Using cached Pacemaker Remote key from %s",
1154 pcmk__s(key_cache->location, "unknown location"));
1155}
1156
1157static void
1158cache_key(struct key_cache_s *key_cache, gnutls_datum_t *key,
1159 const char *location)
1160{
1161 key_cache->updated = time(NULL);
1162 key_cache->location = location;
1163 copy_gnutls_datum(&(key_cache->key), key);
1164 crm_debug("Using (and cacheing) Pacemaker Remote key from %s",
1165 pcmk__s(location, "unknown location"));
1166}
1167
1178static int
1179get_remote_key(const char *location, gnutls_datum_t *key)
1180{
1181 static struct key_cache_s key_cache = { 0, };
1182 int rc = pcmk_rc_ok;
1183
1184 if ((location == NULL) || (key == NULL)) {
1185 return EINVAL;
1186 }
1187
1188 if (key_is_cached(&key_cache)) {
1189 if (key_cache_expired(&key_cache)) {
1190 clear_key_cache(&key_cache);
1191 } else {
1192 get_cached_key(&key_cache, key);
1193 return pcmk_rc_ok;
1194 }
1195 }
1196
1197 rc = read_gnutls_key(location, key);
1198 if (rc != pcmk_rc_ok) {
1199 return rc;
1200 }
1201 cache_key(&key_cache, key, location);
1202 return pcmk_rc_ok;
1203}
1204
1218int
1219lrmd__init_remote_key(gnutls_datum_t *key)
1220{
1221 static const char *env_location = NULL;
1222 static bool need_env = true;
1223
1224 int env_rc = pcmk_rc_ok;
1225 int default_rc = pcmk_rc_ok;
1226 int alt_rc = pcmk_rc_ok;
1227
1228 bool env_is_default = false;
1229 bool env_is_fallback = false;
1230
1231 if (need_env) {
1232 env_location = getenv("PCMK_authkey_location");
1233 need_env = false;
1234 }
1235
1236 // Try location in environment variable, if set
1237 if (env_location != NULL) {
1238 env_rc = get_remote_key(env_location, key);
1239 if (env_rc == pcmk_rc_ok) {
1240 return pcmk_rc_ok;
1241 }
1242
1243 env_is_default = !strcmp(env_location, DEFAULT_REMOTE_KEY_LOCATION);
1244 env_is_fallback = !strcmp(env_location, ALT_REMOTE_KEY_LOCATION);
1245
1246 /* @TODO It would be more secure to fail, rather than fall back to the
1247 * default, if an explicitly set key location is not readable, and it
1248 * would be better to never use the Corosync location as a fallback.
1249 * However, that would break any deployments currently working with the
1250 * fallbacks.
1251 */
1252 }
1253
1254 // Try default location, if environment wasn't explicitly set to it
1255 if (env_is_default) {
1256 default_rc = env_rc;
1257 } else {
1258 default_rc = get_remote_key(DEFAULT_REMOTE_KEY_LOCATION, key);
1259 }
1260
1261 // Try fallback location, if environment wasn't set to it and default failed
1262 if (env_is_fallback) {
1263 alt_rc = env_rc;
1264 } else if (default_rc != pcmk_rc_ok) {
1265 alt_rc = get_remote_key(ALT_REMOTE_KEY_LOCATION, key);
1266 }
1267
1268 // We have all results, so log and return
1269
1270 if ((env_rc != pcmk_rc_ok) && (default_rc != pcmk_rc_ok)
1271 && (alt_rc != pcmk_rc_ok)) { // Environment set, everything failed
1272
1273 crm_warn("Could not read Pacemaker Remote key from %s (%s%s%s%s%s): %s",
1274 env_location,
1275 env_is_default? "" : "or default location ",
1276 env_is_default? "" : DEFAULT_REMOTE_KEY_LOCATION,
1277 !env_is_default && !env_is_fallback? " " : "",
1278 env_is_fallback? "" : "or fallback location ",
1279 env_is_fallback? "" : ALT_REMOTE_KEY_LOCATION,
1280 pcmk_rc_str(env_rc));
1281 return ENOKEY;
1282 }
1283
1284 if (env_rc != pcmk_rc_ok) { // Environment set but failed, using a default
1285 crm_warn("Could not read Pacemaker Remote key from %s "
1286 "(using %s location %s instead): %s",
1287 env_location,
1288 (default_rc == pcmk_rc_ok)? "default" : "fallback",
1290 pcmk_rc_str(env_rc));
1291 return pcmk_rc_ok;
1292 }
1293
1294 if ((default_rc != pcmk_rc_ok) && (alt_rc != pcmk_rc_ok)) {
1295 // Environment unset, defaults failed
1296 crm_warn("Could not read Pacemaker Remote key from default location %s"
1297 " (or fallback location %s): %s",
1299 pcmk_rc_str(default_rc));
1300 return ENOKEY;
1301 }
1302
1303 return pcmk_rc_ok; // Environment variable unset, a default worked
1304}
1305
1306static void
1307lrmd_gnutls_global_init(void)
1308{
1309 static int gnutls_init = 0;
1310
1311 if (!gnutls_init) {
1312 crm_gnutls_global_init();
1313 }
1314 gnutls_init = 1;
1315}
1316#endif
1317
1318static void
1319report_async_connection_result(lrmd_t * lrmd, int rc)
1320{
1321 lrmd_private_t *native = lrmd->lrmd_private;
1322
1323 if (native->callback) {
1324 lrmd_event_data_t event = { 0, };
1325 event.type = lrmd_event_connect;
1326 event.remote_nodename = native->remote_nodename;
1327 event.connection_rc = rc;
1328 native->callback(&event);
1329 }
1330}
1331
1332#ifdef HAVE_GNUTLS_GNUTLS_H
1333static inline int
1334lrmd__tls_client_handshake(pcmk__remote_t *remote)
1335{
1336 return pcmk__tls_client_handshake(remote, LRMD_CLIENT_HANDSHAKE_TIMEOUT);
1337}
1338
1348static int
1349add_tls_to_mainloop(lrmd_t *lrmd, bool do_handshake)
1350{
1351 lrmd_private_t *native = lrmd->lrmd_private;
1352 int rc = pcmk_rc_ok;
1353
1354 char *name = crm_strdup_printf("pacemaker-remote-%s:%d",
1355 native->server, native->port);
1356
1357 struct mainloop_fd_callbacks tls_fd_callbacks = {
1358 .dispatch = lrmd_tls_dispatch,
1359 .destroy = lrmd_tls_connection_destroy,
1360 };
1361
1362 native->process_notify = mainloop_add_trigger(G_PRIORITY_HIGH,
1363 lrmd_tls_dispatch, lrmd);
1364 native->source = mainloop_add_fd(name, G_PRIORITY_HIGH, native->sock, lrmd,
1365 &tls_fd_callbacks);
1366
1367 /* Async connections lose the client name provided by the API caller, so we
1368 * have to use our generated name here to perform the executor handshake.
1369 *
1370 * @TODO Keep track of the caller-provided name. Perhaps we should be using
1371 * that name in this function instead of generating one anyway.
1372 */
1373 if (do_handshake) {
1374 rc = lrmd_handshake(lrmd, name);
1375 rc = pcmk_legacy2rc(rc);
1376 }
1377 free(name);
1378 return rc;
1379}
1380
1381static void
1382lrmd_tcp_connect_cb(void *userdata, int rc, int sock)
1383{
1384 lrmd_t *lrmd = userdata;
1385 lrmd_private_t *native = lrmd->lrmd_private;
1386 gnutls_datum_t psk_key = { NULL, 0 };
1387
1388 native->async_timer = 0;
1389
1390 if (rc != pcmk_rc_ok) {
1391 lrmd_tls_connection_destroy(lrmd);
1392 crm_info("Could not connect to Pacemaker Remote at %s:%d: %s "
1393 CRM_XS " rc=%d",
1394 native->server, native->port, pcmk_rc_str(rc), rc);
1395 report_async_connection_result(lrmd, pcmk_rc2legacy(rc));
1396 return;
1397 }
1398
1399 /* The TCP connection was successful, so establish the TLS connection.
1400 * @TODO make this async to avoid blocking code in client
1401 */
1402
1403 native->sock = sock;
1404
1405 rc = lrmd__init_remote_key(&psk_key);
1406 if (rc != pcmk_rc_ok) {
1407 crm_info("Could not connect to Pacemaker Remote at %s:%d: %s "
1408 CRM_XS " rc=%d",
1409 native->server, native->port, pcmk_rc_str(rc), rc);
1410 lrmd_tls_connection_destroy(lrmd);
1411 report_async_connection_result(lrmd, pcmk_rc2legacy(rc));
1412 return;
1413 }
1414
1415 gnutls_psk_allocate_client_credentials(&native->psk_cred_c);
1416 gnutls_psk_set_client_credentials(native->psk_cred_c, DEFAULT_REMOTE_USERNAME, &psk_key, GNUTLS_PSK_KEY_RAW);
1417 gnutls_free(psk_key.data);
1418
1419 native->remote->tls_session = pcmk__new_tls_session(sock, GNUTLS_CLIENT,
1420 GNUTLS_CRD_PSK,
1421 native->psk_cred_c);
1422 if (native->remote->tls_session == NULL) {
1423 lrmd_tls_connection_destroy(lrmd);
1424 report_async_connection_result(lrmd, -EPROTO);
1425 return;
1426 }
1427
1428 if (lrmd__tls_client_handshake(native->remote) != pcmk_rc_ok) {
1429 crm_warn("Disconnecting after TLS handshake with Pacemaker Remote server %s:%d failed",
1430 native->server, native->port);
1431 gnutls_deinit(*native->remote->tls_session);
1432 gnutls_free(native->remote->tls_session);
1433 native->remote->tls_session = NULL;
1434 lrmd_tls_connection_destroy(lrmd);
1435 report_async_connection_result(lrmd, -EKEYREJECTED);
1436 return;
1437 }
1438
1439 crm_info("TLS connection to Pacemaker Remote server %s:%d succeeded",
1440 native->server, native->port);
1441 rc = add_tls_to_mainloop(lrmd, true);
1442 report_async_connection_result(lrmd, pcmk_rc2legacy(rc));
1443}
1444
1445static int
1446lrmd_tls_connect_async(lrmd_t * lrmd, int timeout /*ms */ )
1447{
1448 int rc;
1449 int timer_id = 0;
1450 lrmd_private_t *native = lrmd->lrmd_private;
1451
1452 lrmd_gnutls_global_init();
1453 native->sock = -1;
1454 rc = pcmk__connect_remote(native->server, native->port, timeout, &timer_id,
1455 &(native->sock), lrmd, lrmd_tcp_connect_cb);
1456 if (rc != pcmk_rc_ok) {
1457 crm_warn("Pacemaker Remote connection to %s:%d failed: %s "
1458 CRM_XS " rc=%d",
1459 native->server, native->port, pcmk_rc_str(rc), rc);
1460 return pcmk_rc2legacy(rc);
1461 }
1462 native->async_timer = timer_id;
1463 return pcmk_ok;
1464}
1465
1466static int
1467lrmd_tls_connect(lrmd_t * lrmd, int *fd)
1468{
1469 int rc;
1470
1471 lrmd_private_t *native = lrmd->lrmd_private;
1472 gnutls_datum_t psk_key = { NULL, 0 };
1473
1474 lrmd_gnutls_global_init();
1475
1476 native->sock = -1;
1477 rc = pcmk__connect_remote(native->server, native->port, 0, NULL,
1478 &(native->sock), NULL, NULL);
1479 if (rc != pcmk_rc_ok) {
1480 crm_warn("Pacemaker Remote connection to %s:%d failed: %s "
1481 CRM_XS " rc=%d",
1482 native->server, native->port, pcmk_rc_str(rc), rc);
1483 lrmd_tls_connection_destroy(lrmd);
1484 return -ENOTCONN;
1485 }
1486
1487 rc = lrmd__init_remote_key(&psk_key);
1488 if (rc != pcmk_rc_ok) {
1489 lrmd_tls_connection_destroy(lrmd);
1490 return pcmk_rc2legacy(rc);
1491 }
1492
1493 gnutls_psk_allocate_client_credentials(&native->psk_cred_c);
1494 gnutls_psk_set_client_credentials(native->psk_cred_c, DEFAULT_REMOTE_USERNAME, &psk_key, GNUTLS_PSK_KEY_RAW);
1495 gnutls_free(psk_key.data);
1496
1497 native->remote->tls_session = pcmk__new_tls_session(native->sock, GNUTLS_CLIENT,
1498 GNUTLS_CRD_PSK,
1499 native->psk_cred_c);
1500 if (native->remote->tls_session == NULL) {
1501 lrmd_tls_connection_destroy(lrmd);
1502 return -EPROTO;
1503 }
1504
1505 if (lrmd__tls_client_handshake(native->remote) != pcmk_rc_ok) {
1506 crm_err("Session creation for %s:%d failed", native->server, native->port);
1507 gnutls_deinit(*native->remote->tls_session);
1508 gnutls_free(native->remote->tls_session);
1509 native->remote->tls_session = NULL;
1510 lrmd_tls_connection_destroy(lrmd);
1511 return -EKEYREJECTED;
1512 }
1513
1514 crm_info("Client TLS connection established with Pacemaker Remote server %s:%d", native->server,
1515 native->port);
1516
1517 if (fd) {
1518 *fd = native->sock;
1519 } else {
1520 add_tls_to_mainloop(lrmd, false);
1521 }
1522 return pcmk_ok;
1523}
1524#endif
1525
1526static int
1527lrmd_api_connect(lrmd_t * lrmd, const char *name, int *fd)
1528{
1529 int rc = -ENOTCONN;
1530 lrmd_private_t *native = lrmd->lrmd_private;
1531
1532 switch (native->type) {
1533 case pcmk__client_ipc:
1534 rc = lrmd_ipc_connect(lrmd, fd);
1535 break;
1536#ifdef HAVE_GNUTLS_GNUTLS_H
1537 case pcmk__client_tls:
1538 rc = lrmd_tls_connect(lrmd, fd);
1539 break;
1540#endif
1541 default:
1542 crm_err("Unsupported executor connection type (bug?): %d",
1543 native->type);
1544 rc = -EPROTONOSUPPORT;
1545 }
1546
1547 if (rc == pcmk_ok) {
1548 rc = lrmd_handshake(lrmd, name);
1549 }
1550
1551 return rc;
1552}
1553
1554static int
1555lrmd_api_connect_async(lrmd_t * lrmd, const char *name, int timeout)
1556{
1557 int rc = pcmk_ok;
1558 lrmd_private_t *native = lrmd->lrmd_private;
1559
1560 CRM_CHECK(native && native->callback, return -EINVAL);
1561
1562 switch (native->type) {
1563 case pcmk__client_ipc:
1564 /* fake async connection with ipc. it should be fast
1565 * enough that we gain very little from async */
1566 rc = lrmd_api_connect(lrmd, name, NULL);
1567 if (!rc) {
1568 report_async_connection_result(lrmd, rc);
1569 }
1570 break;
1571#ifdef HAVE_GNUTLS_GNUTLS_H
1572 case pcmk__client_tls:
1573 rc = lrmd_tls_connect_async(lrmd, timeout);
1574 if (rc) {
1575 /* connection failed, report rc now */
1576 report_async_connection_result(lrmd, rc);
1577 }
1578 break;
1579#endif
1580 default:
1581 crm_err("Unsupported executor connection type (bug?): %d",
1582 native->type);
1583 rc = -EPROTONOSUPPORT;
1584 }
1585
1586 return rc;
1587}
1588
1589static void
1590lrmd_ipc_disconnect(lrmd_t * lrmd)
1591{
1592 lrmd_private_t *native = lrmd->lrmd_private;
1593
1594 if (native->source != NULL) {
1595 /* Attached to mainloop */
1596 mainloop_del_ipc_client(native->source);
1597 native->source = NULL;
1598 native->ipc = NULL;
1599
1600 } else if (native->ipc) {
1601 /* Not attached to mainloop */
1602 crm_ipc_t *ipc = native->ipc;
1603
1604 native->ipc = NULL;
1605 crm_ipc_close(ipc);
1606 crm_ipc_destroy(ipc);
1607 }
1608}
1609
1610#ifdef HAVE_GNUTLS_GNUTLS_H
1611static void
1612lrmd_tls_disconnect(lrmd_t * lrmd)
1613{
1614 lrmd_private_t *native = lrmd->lrmd_private;
1615
1616 if (native->remote->tls_session) {
1617 gnutls_bye(*native->remote->tls_session, GNUTLS_SHUT_RDWR);
1618 gnutls_deinit(*native->remote->tls_session);
1619 gnutls_free(native->remote->tls_session);
1620 native->remote->tls_session = 0;
1621 }
1622
1623 if (native->async_timer) {
1624 g_source_remove(native->async_timer);
1625 native->async_timer = 0;
1626 }
1627
1628 if (native->source != NULL) {
1629 /* Attached to mainloop */
1630 mainloop_del_ipc_client(native->source);
1631 native->source = NULL;
1632
1633 } else if (native->sock) {
1634 close(native->sock);
1635 native->sock = 0;
1636 }
1637
1638 if (native->pending_notify) {
1639 g_list_free_full(native->pending_notify, lrmd_free_xml);
1640 native->pending_notify = NULL;
1641 }
1642}
1643#endif
1644
1645static int
1646lrmd_api_disconnect(lrmd_t * lrmd)
1647{
1648 lrmd_private_t *native = lrmd->lrmd_private;
1649 int rc = pcmk_ok;
1650
1651 crm_info("Disconnecting %s %s executor connection",
1652 pcmk__client_type_str(native->type),
1653 (native->remote_nodename? native->remote_nodename : "local"));
1654 switch (native->type) {
1655 case pcmk__client_ipc:
1656 lrmd_ipc_disconnect(lrmd);
1657 break;
1658#ifdef HAVE_GNUTLS_GNUTLS_H
1659 case pcmk__client_tls:
1660 lrmd_tls_disconnect(lrmd);
1661 break;
1662#endif
1663 default:
1664 crm_err("Unsupported executor connection type (bug?): %d",
1665 native->type);
1666 rc = -EPROTONOSUPPORT;
1667 }
1668
1669 free(native->token);
1670 native->token = NULL;
1671
1672 free(native->peer_version);
1673 native->peer_version = NULL;
1674 return rc;
1675}
1676
1677static int
1678lrmd_api_register_rsc(lrmd_t * lrmd,
1679 const char *rsc_id,
1680 const char *class,
1681 const char *provider, const char *type, enum lrmd_call_options options)
1682{
1683 int rc = pcmk_ok;
1684 xmlNode *data = NULL;
1685
1686 if (!class || !type || !rsc_id) {
1687 return -EINVAL;
1688 }
1690 && (provider == NULL)) {
1691 return -EINVAL;
1692 }
1693
1695
1696 crm_xml_add(data, F_LRMD_ORIGIN, __func__);
1697 crm_xml_add(data, F_LRMD_RSC_ID, rsc_id);
1698 crm_xml_add(data, F_LRMD_CLASS, class);
1699 crm_xml_add(data, F_LRMD_PROVIDER, provider);
1701 rc = lrmd_send_command(lrmd, LRMD_OP_RSC_REG, data, NULL, 0, options, TRUE);
1702 free_xml(data);
1703
1704 return rc;
1705}
1706
1707static int
1708lrmd_api_unregister_rsc(lrmd_t * lrmd, const char *rsc_id, enum lrmd_call_options options)
1709{
1710 int rc = pcmk_ok;
1711 xmlNode *data = create_xml_node(NULL, F_LRMD_RSC);
1712
1713 crm_xml_add(data, F_LRMD_ORIGIN, __func__);
1714 crm_xml_add(data, F_LRMD_RSC_ID, rsc_id);
1715 rc = lrmd_send_command(lrmd, LRMD_OP_RSC_UNREG, data, NULL, 0, options, TRUE);
1716 free_xml(data);
1717
1718 return rc;
1719}
1720
1722lrmd_new_rsc_info(const char *rsc_id, const char *standard,
1723 const char *provider, const char *type)
1724{
1725 lrmd_rsc_info_t *rsc_info = calloc(1, sizeof(lrmd_rsc_info_t));
1726
1727 CRM_ASSERT(rsc_info);
1728 pcmk__str_update(&rsc_info->id, rsc_id);
1729 pcmk__str_update(&rsc_info->standard, standard);
1730 pcmk__str_update(&rsc_info->provider, provider);
1731 pcmk__str_update(&rsc_info->type, type);
1732 return rsc_info;
1733}
1734
1737{
1738 return lrmd_new_rsc_info(rsc_info->id, rsc_info->standard,
1739 rsc_info->provider, rsc_info->type);
1740}
1741
1742void
1744{
1745 if (!rsc_info) {
1746 return;
1747 }
1748 free(rsc_info->id);
1749 free(rsc_info->type);
1750 free(rsc_info->standard);
1751 free(rsc_info->provider);
1752 free(rsc_info);
1753}
1754
1755static lrmd_rsc_info_t *
1756lrmd_api_get_rsc_info(lrmd_t * lrmd, const char *rsc_id, enum lrmd_call_options options)
1757{
1758 lrmd_rsc_info_t *rsc_info = NULL;
1759 xmlNode *data = create_xml_node(NULL, F_LRMD_RSC);
1760 xmlNode *output = NULL;
1761 const char *class = NULL;
1762 const char *provider = NULL;
1763 const char *type = NULL;
1764
1765 crm_xml_add(data, F_LRMD_ORIGIN, __func__);
1766 crm_xml_add(data, F_LRMD_RSC_ID, rsc_id);
1767 lrmd_send_command(lrmd, LRMD_OP_RSC_INFO, data, &output, 0, options, TRUE);
1768 free_xml(data);
1769
1770 if (!output) {
1771 return NULL;
1772 }
1773
1774 class = crm_element_value(output, F_LRMD_CLASS);
1775 provider = crm_element_value(output, F_LRMD_PROVIDER);
1777
1778 if (!class || !type) {
1779 free_xml(output);
1780 return NULL;
1782 && !provider) {
1783 free_xml(output);
1784 return NULL;
1785 }
1786
1787 rsc_info = lrmd_new_rsc_info(rsc_id, class, provider, type);
1788 free_xml(output);
1789 return rsc_info;
1790}
1791
1792void
1794{
1795 if (op_info) {
1796 free(op_info->rsc_id);
1797 free(op_info->action);
1798 free(op_info->interval_ms_s);
1799 free(op_info->timeout_ms_s);
1800 free(op_info);
1801 }
1802}
1803
1804static int
1805lrmd_api_get_recurring_ops(lrmd_t *lrmd, const char *rsc_id, int timeout_ms,
1806 enum lrmd_call_options options, GList **output)
1807{
1808 xmlNode *data = NULL;
1809 xmlNode *output_xml = NULL;
1810 int rc = pcmk_ok;
1811
1812 if (output == NULL) {
1813 return -EINVAL;
1814 }
1815 *output = NULL;
1816
1817 // Send request
1818 if (rsc_id) {
1820 crm_xml_add(data, F_LRMD_ORIGIN, __func__);
1821 crm_xml_add(data, F_LRMD_RSC_ID, rsc_id);
1822 }
1823 rc = lrmd_send_command(lrmd, LRMD_OP_GET_RECURRING, data, &output_xml,
1824 timeout_ms, options, TRUE);
1825 if (data) {
1826 free_xml(data);
1827 }
1828
1829 // Process reply
1830 if ((rc != pcmk_ok) || (output_xml == NULL)) {
1831 return rc;
1832 }
1833 for (xmlNode *rsc_xml = first_named_child(output_xml, F_LRMD_RSC);
1834 (rsc_xml != NULL) && (rc == pcmk_ok);
1835 rsc_xml = crm_next_same_xml(rsc_xml)) {
1836
1837 rsc_id = crm_element_value(rsc_xml, F_LRMD_RSC_ID);
1838 if (rsc_id == NULL) {
1839 crm_err("Could not parse recurring operation information from executor");
1840 continue;
1841 }
1842 for (xmlNode *op_xml = first_named_child(rsc_xml, T_LRMD_RSC_OP);
1843 op_xml != NULL; op_xml = crm_next_same_xml(op_xml)) {
1844
1845 lrmd_op_info_t *op_info = calloc(1, sizeof(lrmd_op_info_t));
1846
1847 if (op_info == NULL) {
1848 rc = -ENOMEM;
1849 break;
1850 }
1851 op_info->rsc_id = strdup(rsc_id);
1853 op_info->interval_ms_s = crm_element_value_copy(op_xml,
1855 op_info->timeout_ms_s = crm_element_value_copy(op_xml,
1857 *output = g_list_prepend(*output, op_info);
1858 }
1859 }
1860 free_xml(output_xml);
1861 return rc;
1862}
1863
1864
1865static void
1866lrmd_api_set_callback(lrmd_t * lrmd, lrmd_event_callback callback)
1867{
1868 lrmd_private_t *native = lrmd->lrmd_private;
1869
1870 native->callback = callback;
1871}
1872
1873void
1874lrmd_internal_set_proxy_callback(lrmd_t * lrmd, void *userdata, void (*callback)(lrmd_t *lrmd, void *userdata, xmlNode *msg))
1875{
1876 lrmd_private_t *native = lrmd->lrmd_private;
1877
1878 native->proxy_callback = callback;
1879 native->proxy_callback_userdata = userdata;
1880}
1881
1882void
1883lrmd_internal_proxy_dispatch(lrmd_t *lrmd, xmlNode *msg)
1884{
1885 lrmd_private_t *native = lrmd->lrmd_private;
1886
1887 if (native->proxy_callback) {
1888 crm_log_xml_trace(msg, "PROXY_INBOUND");
1889 native->proxy_callback(lrmd, native->proxy_callback_userdata, msg);
1890 }
1891}
1892
1893int
1895{
1896 if (lrmd == NULL) {
1897 return -ENOTCONN;
1898 }
1900
1901 crm_log_xml_trace(msg, "PROXY_OUTBOUND");
1902 return lrmd_send_xml_no_reply(lrmd, msg);
1903}
1904
1905static int
1906stonith_get_metadata(const char *provider, const char *type, char **output)
1907{
1908 int rc = pcmk_ok;
1909 stonith_t *stonith_api = stonith_api_new();
1910
1911 if (stonith_api == NULL) {
1912 crm_err("Could not get fence agent meta-data: API memory allocation failed");
1913 return -ENOMEM;
1914 }
1915
1916 rc = stonith_api->cmds->metadata(stonith_api, st_opt_sync_call, type,
1917 provider, output, 0);
1918 if ((rc == pcmk_ok) && (*output == NULL)) {
1919 rc = -EIO;
1920 }
1921 stonith_api->cmds->free(stonith_api);
1922 return rc;
1923}
1924
1925static int
1926lrmd_api_get_metadata(lrmd_t *lrmd, const char *standard, const char *provider,
1927 const char *type, char **output,
1928 enum lrmd_call_options options)
1929{
1930 return lrmd->cmds->get_metadata_params(lrmd, standard, provider, type,
1931 output, options, NULL);
1932}
1933
1934static int
1935lrmd_api_get_metadata_params(lrmd_t *lrmd, const char *standard,
1936 const char *provider, const char *type,
1937 char **output, enum lrmd_call_options options,
1938 lrmd_key_value_t *params)
1939{
1940 svc_action_t *action = NULL;
1941 GHashTable *params_table = NULL;
1942
1943 if (!standard || !type) {
1944 lrmd_key_value_freeall(params);
1945 return -EINVAL;
1946 }
1947
1948 if (pcmk__str_eq(standard, PCMK_RESOURCE_CLASS_STONITH, pcmk__str_casei)) {
1949 lrmd_key_value_freeall(params);
1950 return stonith_get_metadata(provider, type, output);
1951 }
1952
1953 params_table = pcmk__strkey_table(free, free);
1954 for (const lrmd_key_value_t *param = params; param; param = param->next) {
1955 g_hash_table_insert(params_table, strdup(param->key), strdup(param->value));
1956 }
1957 action = services__create_resource_action(type, standard, provider, type,
1960 params_table, 0);
1961 lrmd_key_value_freeall(params);
1962
1963 if (action == NULL) {
1964 return -ENOMEM;
1965 }
1966 if (action->rc != PCMK_OCF_UNKNOWN) {
1968 return -EINVAL;
1969 }
1970
1972 crm_err("Failed to retrieve meta-data for %s:%s:%s",
1973 standard, provider, type);
1975 return -EIO;
1976 }
1977
1978 if (!action->stdout_data) {
1979 crm_err("Failed to receive meta-data for %s:%s:%s",
1980 standard, provider, type);
1982 return -EIO;
1983 }
1984
1985 *output = strdup(action->stdout_data);
1987
1988 return pcmk_ok;
1989}
1990
1991static int
1992lrmd_api_exec(lrmd_t *lrmd, const char *rsc_id, const char *action,
1993 const char *userdata, guint interval_ms,
1994 int timeout, /* ms */
1995 int start_delay, /* ms */
1996 enum lrmd_call_options options, lrmd_key_value_t * params)
1997{
1998 int rc = pcmk_ok;
1999 xmlNode *data = create_xml_node(NULL, F_LRMD_RSC);
2000 xmlNode *args = create_xml_node(data, XML_TAG_ATTRS);
2001 lrmd_key_value_t *tmp = NULL;
2002
2003 crm_xml_add(data, F_LRMD_ORIGIN, __func__);
2004 crm_xml_add(data, F_LRMD_RSC_ID, rsc_id);
2010
2011 for (tmp = params; tmp; tmp = tmp->next) {
2012 hash2smartfield((gpointer) tmp->key, (gpointer) tmp->value, args);
2013 }
2014
2015 rc = lrmd_send_command(lrmd, LRMD_OP_RSC_EXEC, data, NULL, timeout, options, TRUE);
2016 free_xml(data);
2017
2018 lrmd_key_value_freeall(params);
2019 return rc;
2020}
2021
2022/* timeout is in ms */
2023static int
2024lrmd_api_exec_alert(lrmd_t *lrmd, const char *alert_id, const char *alert_path,
2025 int timeout, lrmd_key_value_t *params)
2026{
2027 int rc = pcmk_ok;
2028 xmlNode *data = create_xml_node(NULL, F_LRMD_ALERT);
2029 xmlNode *args = create_xml_node(data, XML_TAG_ATTRS);
2030 lrmd_key_value_t *tmp = NULL;
2031
2032 crm_xml_add(data, F_LRMD_ORIGIN, __func__);
2033 crm_xml_add(data, F_LRMD_ALERT_ID, alert_id);
2034 crm_xml_add(data, F_LRMD_ALERT_PATH, alert_path);
2036
2037 for (tmp = params; tmp; tmp = tmp->next) {
2038 hash2smartfield((gpointer) tmp->key, (gpointer) tmp->value, args);
2039 }
2040
2041 rc = lrmd_send_command(lrmd, LRMD_OP_ALERT_EXEC, data, NULL, timeout,
2043 free_xml(data);
2044
2045 lrmd_key_value_freeall(params);
2046 return rc;
2047}
2048
2049static int
2050lrmd_api_cancel(lrmd_t *lrmd, const char *rsc_id, const char *action,
2051 guint interval_ms)
2052{
2053 int rc = pcmk_ok;
2054 xmlNode *data = create_xml_node(NULL, F_LRMD_RSC);
2055
2056 crm_xml_add(data, F_LRMD_ORIGIN, __func__);
2058 crm_xml_add(data, F_LRMD_RSC_ID, rsc_id);
2060 rc = lrmd_send_command(lrmd, LRMD_OP_RSC_CANCEL, data, NULL, 0, 0, TRUE);
2061 free_xml(data);
2062 return rc;
2063}
2064
2065static int
2066list_stonith_agents(lrmd_list_t ** resources)
2067{
2068 int rc = 0;
2069 stonith_t *stonith_api = stonith_api_new();
2070 stonith_key_value_t *stonith_resources = NULL;
2071 stonith_key_value_t *dIter = NULL;
2072
2073 if (stonith_api == NULL) {
2074 crm_err("Could not list fence agents: API memory allocation failed");
2075 return -ENOMEM;
2076 }
2077 stonith_api->cmds->list_agents(stonith_api, st_opt_sync_call, NULL,
2078 &stonith_resources, 0);
2079 stonith_api->cmds->free(stonith_api);
2080
2081 for (dIter = stonith_resources; dIter; dIter = dIter->next) {
2082 rc++;
2083 if (resources) {
2084 *resources = lrmd_list_add(*resources, dIter->value);
2085 }
2086 }
2087
2088 stonith_key_value_freeall(stonith_resources, 1, 0);
2089 return rc;
2090}
2091
2092static int
2093lrmd_api_list_agents(lrmd_t * lrmd, lrmd_list_t ** resources, const char *class,
2094 const char *provider)
2095{
2096 int rc = 0;
2097 int stonith_count = 0; // Initially, whether to include stonith devices
2098
2099 if (pcmk__str_eq(class, PCMK_RESOURCE_CLASS_STONITH, pcmk__str_casei)) {
2100 stonith_count = 1;
2101
2102 } else {
2103 GList *gIter = NULL;
2104 GList *agents = resources_list_agents(class, provider);
2105
2106 for (gIter = agents; gIter != NULL; gIter = gIter->next) {
2107 *resources = lrmd_list_add(*resources, (const char *)gIter->data);
2108 rc++;
2109 }
2110 g_list_free_full(agents, free);
2111
2112 if (!class) {
2113 stonith_count = 1;
2114 }
2115 }
2116
2117 if (stonith_count) {
2118 // Now, if stonith devices are included, how many there are
2119 stonith_count = list_stonith_agents(resources);
2120 if (stonith_count > 0) {
2121 rc += stonith_count;
2122 }
2123 }
2124 if (rc == 0) {
2125 crm_notice("No agents found for class %s", class);
2126 rc = -EPROTONOSUPPORT;
2127 }
2128 return rc;
2129}
2130
2131static bool
2132does_provider_have_agent(const char *agent, const char *provider, const char *class)
2133{
2134 bool found = false;
2135 GList *agents = NULL;
2136 GList *gIter2 = NULL;
2137
2138 agents = resources_list_agents(class, provider);
2139 for (gIter2 = agents; gIter2 != NULL; gIter2 = gIter2->next) {
2140 if (pcmk__str_eq(agent, gIter2->data, pcmk__str_casei)) {
2141 found = true;
2142 }
2143 }
2144 g_list_free_full(agents, free);
2145 return found;
2146}
2147
2148static int
2149lrmd_api_list_ocf_providers(lrmd_t * lrmd, const char *agent, lrmd_list_t ** providers)
2150{
2151 int rc = pcmk_ok;
2152 char *provider = NULL;
2153 GList *ocf_providers = NULL;
2154 GList *gIter = NULL;
2155
2157
2158 for (gIter = ocf_providers; gIter != NULL; gIter = gIter->next) {
2159 provider = gIter->data;
2160 if (!agent || does_provider_have_agent(agent, provider,
2162 *providers = lrmd_list_add(*providers, (const char *)gIter->data);
2163 rc++;
2164 }
2165 }
2166
2167 g_list_free_full(ocf_providers, free);
2168 return rc;
2169}
2170
2171static int
2172lrmd_api_list_standards(lrmd_t * lrmd, lrmd_list_t ** supported)
2173{
2174 int rc = 0;
2175 GList *standards = NULL;
2176 GList *gIter = NULL;
2177
2178 standards = resources_list_standards();
2179
2180 for (gIter = standards; gIter != NULL; gIter = gIter->next) {
2181 *supported = lrmd_list_add(*supported, (const char *)gIter->data);
2182 rc++;
2183 }
2184
2185 if (list_stonith_agents(NULL) > 0) {
2186 *supported = lrmd_list_add(*supported, PCMK_RESOURCE_CLASS_STONITH);
2187 rc++;
2188 }
2189
2190 g_list_free_full(standards, free);
2191 return rc;
2192}
2193
2213int
2214lrmd__new(lrmd_t **api, const char *nodename, const char *server, int port)
2215{
2216 lrmd_private_t *pvt = NULL;
2217
2218 if (api == NULL) {
2219 return EINVAL;
2220 }
2221 *api = NULL;
2222
2223 // Allocate all memory needed
2224
2225 *api = calloc(1, sizeof(lrmd_t));
2226 if (*api == NULL) {
2227 return ENOMEM;
2228 }
2229
2230 pvt = calloc(1, sizeof(lrmd_private_t));
2231 if (pvt == NULL) {
2232 lrmd_api_delete(*api);
2233 *api = NULL;
2234 return ENOMEM;
2235 }
2236 (*api)->lrmd_private = pvt;
2237
2238 // @TODO Do we need to do this for local connections?
2239 pvt->remote = calloc(1, sizeof(pcmk__remote_t));
2240
2241 (*api)->cmds = calloc(1, sizeof(lrmd_api_operations_t));
2242
2243 if ((pvt->remote == NULL) || ((*api)->cmds == NULL)) {
2244 lrmd_api_delete(*api);
2245 *api = NULL;
2246 return ENOMEM;
2247 }
2248
2249 // Set methods
2250 (*api)->cmds->connect = lrmd_api_connect;
2251 (*api)->cmds->connect_async = lrmd_api_connect_async;
2252 (*api)->cmds->is_connected = lrmd_api_is_connected;
2253 (*api)->cmds->poke_connection = lrmd_api_poke_connection;
2254 (*api)->cmds->disconnect = lrmd_api_disconnect;
2255 (*api)->cmds->register_rsc = lrmd_api_register_rsc;
2256 (*api)->cmds->unregister_rsc = lrmd_api_unregister_rsc;
2257 (*api)->cmds->get_rsc_info = lrmd_api_get_rsc_info;
2258 (*api)->cmds->get_recurring_ops = lrmd_api_get_recurring_ops;
2259 (*api)->cmds->set_callback = lrmd_api_set_callback;
2260 (*api)->cmds->get_metadata = lrmd_api_get_metadata;
2261 (*api)->cmds->exec = lrmd_api_exec;
2262 (*api)->cmds->cancel = lrmd_api_cancel;
2263 (*api)->cmds->list_agents = lrmd_api_list_agents;
2264 (*api)->cmds->list_ocf_providers = lrmd_api_list_ocf_providers;
2265 (*api)->cmds->list_standards = lrmd_api_list_standards;
2266 (*api)->cmds->exec_alert = lrmd_api_exec_alert;
2267 (*api)->cmds->get_metadata_params = lrmd_api_get_metadata_params;
2268
2269 if ((nodename == NULL) && (server == NULL)) {
2270 pvt->type = pcmk__client_ipc;
2271 } else {
2272#ifdef HAVE_GNUTLS_GNUTLS_H
2273 if (nodename == NULL) {
2274 nodename = server;
2275 } else if (server == NULL) {
2276 server = nodename;
2277 }
2278 pvt->type = pcmk__client_tls;
2279 pvt->remote_nodename = strdup(nodename);
2280 pvt->server = strdup(server);
2281 if ((pvt->remote_nodename == NULL) || (pvt->server == NULL)) {
2282 lrmd_api_delete(*api);
2283 *api = NULL;
2284 return ENOMEM;
2285 }
2286 pvt->port = port;
2287 if (pvt->port == 0) {
2288 pvt->port = crm_default_remote_port();
2289 }
2290#else
2291 crm_err("Cannot communicate with Pacemaker Remote "
2292 "because GnuTLS is not enabled for this build");
2293 lrmd_api_delete(*api);
2294 *api = NULL;
2295 return EOPNOTSUPP;
2296#endif
2297 }
2298 return pcmk_rc_ok;
2299}
2300
2301lrmd_t *
2303{
2304 lrmd_t *api = NULL;
2305
2306 CRM_ASSERT(lrmd__new(&api, NULL, NULL, 0) == pcmk_rc_ok);
2307 return api;
2308}
2309
2310lrmd_t *
2311lrmd_remote_api_new(const char *nodename, const char *server, int port)
2312{
2313 lrmd_t *api = NULL;
2314
2315 CRM_ASSERT(lrmd__new(&api, nodename, server, port) == pcmk_rc_ok);
2316 return api;
2317}
2318
2319void
2321{
2322 if (lrmd == NULL) {
2323 return;
2324 }
2325 if (lrmd->cmds != NULL) { // Never NULL, but make static analysis happy
2326 if (lrmd->cmds->disconnect != NULL) { // Also never really NULL
2327 lrmd->cmds->disconnect(lrmd); // No-op if already disconnected
2328 }
2329 free(lrmd->cmds);
2330 }
2331 if (lrmd->lrmd_private != NULL) {
2332 lrmd_private_t *native = lrmd->lrmd_private;
2333
2334#ifdef HAVE_GNUTLS_GNUTLS_H
2335 free(native->server);
2336#endif
2337 free(native->remote_nodename);
2338 free(native->remote);
2339 free(native->token);
2340 free(native->peer_version);
2341 free(lrmd->lrmd_private);
2342 }
2343 free(lrmd);
2344}
2345
2346struct metadata_cb {
2347 void (*callback)(int pid, const pcmk__action_result_t *result,
2348 void *user_data);
2349 void *user_data;
2350};
2351
2358static void
2359metadata_complete(svc_action_t *action)
2360{
2361 struct metadata_cb *metadata_cb = (struct metadata_cb *) action->cb_data;
2363
2364 pcmk__set_result(&result, action->rc, action->status,
2366 pcmk__set_result_output(&result, action->stdout_data, action->stderr_data);
2367
2368 metadata_cb->callback(0, &result, metadata_cb->user_data);
2369 result.action_stdout = NULL; // Prevent free, because action owns it
2370 result.action_stderr = NULL; // Prevent free, because action owns it
2372 free(metadata_cb);
2373}
2374
2391int
2393 void (*callback)(int pid,
2395 void *user_data),
2396 void *user_data)
2397{
2398 svc_action_t *action = NULL;
2399 struct metadata_cb *metadata_cb = NULL;
2401
2402 CRM_CHECK(callback != NULL, return EINVAL);
2403
2404 if ((rsc == NULL) || (rsc->standard == NULL) || (rsc->type == NULL)) {
2407 "Invalid resource specification");
2408 callback(0, &result, user_data);
2410 return EINVAL;
2411 }
2412
2413 if (strcmp(rsc->standard, PCMK_RESOURCE_CLASS_STONITH) == 0) {
2414 return stonith__metadata_async(rsc->type,
2416 callback, user_data);
2417 }
2418
2419 action = services__create_resource_action(pcmk__s(rsc->id, rsc->type),
2420 rsc->standard, rsc->provider,
2423 NULL, 0);
2424 if (action == NULL) {
2426 "Out of memory");
2427 callback(0, &result, user_data);
2429 return ENOMEM;
2430 }
2431 if (action->rc != PCMK_OCF_UNKNOWN) {
2432 pcmk__set_result(&result, action->rc, action->status,
2434 callback(0, &result, user_data);
2437 return EINVAL;
2438 }
2439
2440 action->cb_data = calloc(1, sizeof(struct metadata_cb));
2441 if (action->cb_data == NULL) {
2444 "Out of memory");
2445 callback(0, &result, user_data);
2447 return ENOMEM;
2448 }
2449
2450 metadata_cb = (struct metadata_cb *) action->cb_data;
2451 metadata_cb->callback = callback;
2452 metadata_cb->user_data = user_data;
2453 if (!services_action_async(action, metadata_complete)) {
2455 return pcmk_rc_error; // @TODO Derive from action->rc and ->status
2456 }
2457
2458 // The services library has taken responsibility for action
2459 return pcmk_rc_ok;
2460}
2461
2471void
2473 const char *exit_reason)
2474{
2475 if (event == NULL) {
2476 return;
2477 }
2478
2479 event->rc = rc;
2480 event->op_status = op_status;
2481 pcmk__str_update((char **) &event->exit_reason, exit_reason);
2482}
2483
2490void
2492{
2493 if (event == NULL) {
2494 return;
2495 }
2496
2497 free((void *) event->exit_reason);
2498 event->exit_reason = NULL;
2499
2500 free((void *) event->output);
2501 event->output = NULL;
2502}
uint32_t pcmk_get_ra_caps(const char *standard)
Get capabilities of a resource agent standard.
Definition: agents.c:31
#define PCMK_RESOURCE_CLASS_STONITH
Definition: agents.h:33
#define PCMK_RESOURCE_CLASS_OCF
Definition: agents.h:27
@ pcmk_ra_cap_provider
Definition: agents.h:57
const char * name
Definition: cib.c:24
void pcmk__xe_set_bool_attr(xmlNodePtr node, const char *name, bool value)
Definition: nvpair.c:942
uint32_t version
Definition: remote.c:1
int pcmk__remote_ready(const pcmk__remote_t *remote, int timeout_ms)
Definition: remote.c:633
int pcmk__remote_send_xml(pcmk__remote_t *remote, xmlNode *msg)
Definition: remote.c:488
int pcmk__connect_remote(const char *host, int port, int timeout_ms, int *timer_id, int *sock_fd, void *userdata, void(*callback)(void *userdata, int rc, int sock))
Definition: remote.c:1063
xmlNode * pcmk__remote_message_xml(pcmk__remote_t *remote)
Definition: remote.c:540
int pcmk__read_remote_message(pcmk__remote_t *remote, int timeout_ms)
Definition: remote.c:791
int crm_default_remote_port(void)
Get the default remote connection TCP port on this host.
Definition: remote.c:1250
char * crm_strdup_printf(char const *format,...) G_GNUC_PRINTF(1
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
Definition: util.h:121
enum crm_ais_msg_types type
Definition: cpg.c:3
char data[0]
Definition: cpg.c:10
uint32_t pid
Definition: cpg.c:1
A dumping ground.
#define CRMD_ACTION_METADATA
Definition: crm.h:189
#define CRM_OP_IPC_FWD
Definition: crm.h:146
#define CRM_OP_REGISTER
Definition: crm.h:145
#define CRM_SYSTEM_LRMD
Definition: crm.h:106
#define CRMD_METADATA_CALL_TIMEOUT
Definition: crm.h:190
int stonith__metadata_async(const char *agent, int timeout_sec, void(*callback)(int pid, const pcmk__action_result_t *result, void *user_data), void *user_data)
Definition: st_client.c:2446
gboolean stonith__watchdog_fencing_enabled_for_node(const char *node)
Definition: st_client.c:231
void crm_ipc_destroy(crm_ipc_t *client)
Definition: ipc_client.c:930
int crm_ipc_send(crm_ipc_t *client, xmlNode *message, enum crm_ipc_flags flags, int32_t ms_timeout, xmlNode **reply)
Send an IPC XML message.
Definition: ipc_client.c:1209
long crm_ipc_read(crm_ipc_t *client)
Definition: ipc_client.c:1066
int crm_ipc_get_fd(crm_ipc_t *client)
Definition: ipc_client.c:956
@ crm_ipc_flags_none
Definition: ipc.h:146
@ crm_ipc_client_response
Definition: ipc.h:151
int crm_ipc_ready(crm_ipc_t *client)
Check whether an IPC connection is ready to be read.
Definition: ipc_client.c:1002
bool crm_ipc_connected(crm_ipc_t *client)
Definition: ipc_client.c:970
bool crm_ipc_connect(crm_ipc_t *client)
Establish an IPC connection to a Pacemaker component.
Definition: ipc_client.c:847
void crm_ipc_close(crm_ipc_t *client)
Definition: ipc_client.c:917
const char * crm_ipc_buffer(crm_ipc_t *client)
Definition: ipc_client.c:1115
struct crm_ipc_s crm_ipc_t
Definition: ipc.h:165
crm_ipc_t * crm_ipc_new(const char *name, size_t max_size)
Create a new (legacy) object for using Pacemaker daemon IPC.
Definition: ipc_client.c:800
const char * pcmk__client_type_str(uint64_t client_type)
Definition: ipc_common.c:96
@ pcmk__client_ipc
Client uses plain IPC.
Definition: ipc_internal.h:129
#define crm_info(fmt, args...)
Definition: logging.h:362
#define crm_warn(fmt, args...)
Definition: logging.h:360
#define CRM_XS
Definition: logging.h:55
#define crm_log_xml_err(xml, text)
Definition: logging.h:368
#define crm_notice(fmt, args...)
Definition: logging.h:361
#define crm_perror(level, fmt, args...)
Send a system error message to both the log and stderr.
Definition: logging.h:310
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:227
#define crm_debug(fmt, args...)
Definition: logging.h:364
#define crm_err(fmt, args...)
Definition: logging.h:359
#define crm_log_xml_trace(xml, text)
Definition: logging.h:373
#define crm_trace(fmt, args...)
Definition: logging.h:365
Resource agent executor.
#define F_LRMD_ALERT
Definition: lrmd.h:92
#define LRMD_OP_NEW_CLIENT
Definition: lrmd.h:101
#define DEFAULT_REMOTE_USERNAME
Definition: lrmd.h:52
#define T_LRMD_RSC_OP
Definition: lrmd.h:128
#define F_LRMD_CLASS
Definition: lrmd.h:70
#define LRMD_OP_RSC_REG
Definition: lrmd.h:94
#define F_LRMD_OP_STATUS
Definition: lrmd.h:67
#define F_LRMD_ALERT_PATH
Definition: lrmd.h:91
#define F_LRMD_TYPE
Definition: lrmd.h:72
#define LRMD_OP_RSC_EXEC
Definition: lrmd.h:95
#define LRMD_OP_GET_RECURRING
Definition: lrmd.h:104
#define DEFAULT_REMOTE_KEY_LOCATION
Definition: lrmd.h:49
lrmd_call_options
Definition: lrmd.h:182
@ lrmd_opt_notify_orig_only
Notify only the client that made the request (rather than all clients)
Definition: lrmd.h:186
#define F_LRMD_RSC_ACTION
Definition: lrmd.h:81
#define F_LRMD_REMOTE_MSG_TYPE
Definition: lrmd.h:59
#define F_LRMD_RSC_RCCHANGE_TIME
Definition: lrmd.h:76
#define T_LRMD
Definition: lrmd.h:124
#define F_LRMD_EXEC_RC
Definition: lrmd.h:66
#define F_LRMD_TIMEOUT
Definition: lrmd.h:68
#define F_LRMD_IS_IPC_PROVIDER
Definition: lrmd.h:56
#define F_LRMD_CALLDATA
Definition: lrmd.h:64
#define F_LRMD_OPERATION
Definition: lrmd.h:54
#define F_LRMD_CALLBACK_TOKEN
Definition: lrmd.h:61
@ lrmd_event_new_client
Definition: lrmd.h:213
@ lrmd_event_connect
Definition: lrmd.h:211
@ lrmd_event_unregister
Definition: lrmd.h:208
@ lrmd_event_exec_complete
Definition: lrmd.h:209
@ lrmd_event_register
Definition: lrmd.h:207
@ lrmd_event_poke
Definition: lrmd.h:212
@ lrmd_event_disconnect
Definition: lrmd.h:210
#define F_LRMD_RSC_ID
Definition: lrmd.h:80
#define F_LRMD_CALLID
Definition: lrmd.h:62
#define LRMD_OP_POKE
Definition: lrmd.h:100
#define F_LRMD_RSC_INTERVAL
Definition: lrmd.h:86
#define ALT_REMOTE_KEY_LOCATION
Definition: lrmd.h:50
#define F_LRMD_CLIENTNAME
Definition: lrmd.h:55
#define F_LRMD_RSC_USERDATA_STR
Definition: lrmd.h:82
#define F_LRMD_RSC_OUTPUT
Definition: lrmd.h:83
#define LRMD_OP_RSC_INFO
Definition: lrmd.h:98
#define F_LRMD_RSC
Definition: lrmd.h:88
#define F_LRMD_RSC_EXEC_TIME
Definition: lrmd.h:77
#define F_LRMD_RSC_DELETED
Definition: lrmd.h:87
#define LRMD_OP_RSC_UNREG
Definition: lrmd.h:97
#define F_LRMD_PROVIDER
Definition: lrmd.h:71
#define LRMD_OP_CHECK
Definition: lrmd.h:102
#define F_LRMD_RSC_RUN_TIME
Definition: lrmd.h:75
#define F_LRMD_CLIENTID
Definition: lrmd.h:57
#define F_LRMD_PROTOCOL_VERSION
Definition: lrmd.h:58
#define F_LRMD_RSC_START_DELAY
Definition: lrmd.h:85
#define F_LRMD_WATCHDOG
Definition: lrmd.h:69
#define F_LRMD_RSC_EXIT_REASON
Definition: lrmd.h:84
#define F_LRMD_IPC_SESSION
Definition: lrmd.h:117
#define F_LRMD_ORIGIN
Definition: lrmd.h:73
#define F_LRMD_RSC_QUEUE_TIME
Definition: lrmd.h:78
#define F_LRMD_ALERT_ID
Definition: lrmd.h:90
#define LRMD_PROTOCOL_VERSION
Definition: lrmd.h:38
#define F_LRMD_RC
Definition: lrmd.h:65
#define F_LRMD_REMOTE_MSG_ID
Definition: lrmd.h:60
#define F_LRMD_CALLOPTS
Definition: lrmd.h:63
void(* lrmd_event_callback)(lrmd_event_data_t *event)
Definition: lrmd.h:294
#define LRMD_OP_RSC_CANCEL
Definition: lrmd.h:96
#define LRMD_OP_ALERT_EXEC
Definition: lrmd.h:103
int lrmd_internal_proxy_send(lrmd_t *lrmd, xmlNode *msg)
Definition: lrmd_client.c:1894
lrmd_rsc_info_t * lrmd_copy_rsc_info(lrmd_rsc_info_t *rsc_info)
Definition: lrmd_client.c:1736
struct lrmd_private_s lrmd_private_t
#define MAX_TLS_RECV_WAIT
Definition: lrmd_client.c:50
void lrmd__reset_result(lrmd_event_data_t *event)
Definition: lrmd_client.c:2491
void lrmd_key_value_freeall(lrmd_key_value_t *head)
Definition: lrmd_client.c:169
bool lrmd_dispatch(lrmd_t *lrmd)
Use after lrmd_poll returns 1 to read and dispatch a message.
Definition: lrmd_client.c:481
void lrmd_free_op_info(lrmd_op_info_t *op_info)
Definition: lrmd_client.c:1793
void lrmd__set_result(lrmd_event_data_t *event, enum ocf_exitcode rc, int op_status, const char *exit_reason)
Definition: lrmd_client.c:2472
void lrmd_api_delete(lrmd_t *lrmd)
Destroy executor connection object.
Definition: lrmd_client.c:2320
void lrmd_list_freeall(lrmd_list_t *head)
Definition: lrmd_client.c:131
lrmd_t * lrmd_remote_api_new(const char *nodename, const char *server, int port)
Create a new TLS connection to a remote executor.
Definition: lrmd_client.c:2311
lrmd_rsc_info_t * lrmd_new_rsc_info(const char *rsc_id, const char *standard, const char *provider, const char *type)
Definition: lrmd_client.c:1722
int lrmd__metadata_async(lrmd_rsc_info_t *rsc, void(*callback)(int pid, const pcmk__action_result_t *result, void *user_data), void *user_data)
Definition: lrmd_client.c:2392
void lrmd_internal_set_proxy_callback(lrmd_t *lrmd, void *userdata, void(*callback)(lrmd_t *lrmd, void *userdata, xmlNode *msg))
Definition: lrmd_client.c:1874
CRM_TRACE_INIT_DATA(lrmd)
void lrmd_free_event(lrmd_event_data_t *event)
Free an executor event.
Definition: lrmd_client.c:243
void lrmd_free_rsc_info(lrmd_rsc_info_t *rsc_info)
Definition: lrmd_client.c:1743
lrmd_t * lrmd_api_new(void)
Create a new connection to the local executor.
Definition: lrmd_client.c:2302
lrmd_key_value_t * lrmd_key_value_add(lrmd_key_value_t *head, const char *key, const char *value)
Definition: lrmd_client.c:146
lrmd_event_data_t * lrmd_new_event(const char *rsc_id, const char *task, guint interval_ms)
Definition: lrmd_client.c:195
int lrmd__validate_remote_settings(lrmd_t *lrmd, GHashTable *hash)
Definition: lrmd_client.c:932
int lrmd__new(lrmd_t **api, const char *nodename, const char *server, int port)
Definition: lrmd_client.c:2214
int lrmd_poll(lrmd_t *lrmd, int timeout)
Check whether a message is available on an executor connection.
Definition: lrmd_client.c:447
lrmd_event_data_t * lrmd_copy_event(lrmd_event_data_t *event)
Definition: lrmd_client.c:207
int lrmd__remote_send_xml(pcmk__remote_t *session, xmlNode *msg, uint32_t id, const char *msg_type)
Wrappers for and extensions to glib mainloop.
void mainloop_set_trigger(crm_trigger_t *source)
Definition: mainloop.c:200
gboolean mainloop_destroy_trigger(crm_trigger_t *source)
Definition: mainloop.c:208
crm_ipc_t * mainloop_get_ipc_client(mainloop_io_t *client)
Definition: mainloop.c:947
mainloop_io_t * mainloop_add_ipc_client(const char *name, int priority, size_t max_size, void *userdata, struct ipc_client_callbacks *callbacks)
Definition: mainloop.c:916
struct mainloop_io_s mainloop_io_t
Definition: mainloop.h:33
crm_trigger_t * mainloop_add_trigger(int priority, int(*dispatch)(gpointer user_data), gpointer userdata)
Create a trigger to be used as a mainloop source.
Definition: mainloop.c:187
struct trigger_s crm_trigger_t
Definition: mainloop.h:32
void mainloop_del_ipc_client(mainloop_io_t *client)
Definition: mainloop.c:941
mainloop_io_t * mainloop_add_fd(const char *name, int priority, int fd, void *userdata, struct mainloop_fd_callbacks *callbacks)
Definition: mainloop.c:956
#define F_XML_TAGNAME
Definition: msg_xml.h:77
#define XML_TAG_ATTRS
Definition: msg_xml.h:211
#define F_TYPE
Definition: msg_xml.h:69
GHashTable * xml2list(const xmlNode *parent)
Retrieve XML attributes as a hash table.
Definition: nvpair.c:896
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
Definition: nvpair.c:517
int crm_element_value_int(const xmlNode *data, const char *name, int *dest)
Retrieve the integer value of an XML attribute.
Definition: nvpair.c:553
const char * crm_xml_add_int(xmlNode *node, const char *name, int value)
Create an XML attribute with specified name and integer value.
Definition: nvpair.c:419
int crm_element_value_ms(const xmlNode *data, const char *name, guint *dest)
Retrieve the millisecond value of an XML attribute.
Definition: nvpair.c:610
char * crm_element_value_copy(const xmlNode *data, const char *name)
Retrieve a copy of the value of an XML attribute.
Definition: nvpair.c:714
void hash2smartfield(gpointer key, gpointer value, gpointer user_data)
Add hash table entry to XML as (possibly legacy) name/value.
Definition: nvpair.c:736
int crm_element_value_epoch(const xmlNode *xml, const char *name, time_t *dest)
Retrieve the seconds-since-epoch value of an XML attribute.
Definition: nvpair.c:638
const char * crm_xml_add(xmlNode *node, const char *name, const char *value)
Create an XML attribute with specified name and value.
Definition: nvpair.c:323
const char * crm_xml_add_ms(xmlNode *node, const char *name, guint ms)
Create an XML attribute with specified name and unsigned value.
Definition: nvpair.c:441
unsigned int timeout
Definition: pcmk_fence.c:32
const char * action
Definition: pcmk_fence.c:30
pcmk__action_result_t result
Definition: pcmk_fence.c:35
#define ENOKEY
Definition: portability.h:140
#define ETIME
Definition: portability.h:150
#define ECOMM
Definition: portability.h:125
#define EKEYREJECTED
Definition: portability.h:155
#define CRM_ASSERT(expr)
Definition: results.h:42
const char * pcmk_rc_str(int rc)
Get a user-friendly description of a return code.
Definition: results.c:476
ocf_exitcode
Exit status codes for resource agents.
Definition: results.h:163
@ PCMK_OCF_NOT_CONFIGURED
Parameter invalid (inherently)
Definition: results.h:170
@ PCMK_OCF_UNKNOWN_ERROR
Unspecified error.
Definition: results.h:165
@ PCMK_OCF_UNKNOWN
Action is pending.
Definition: results.h:183
@ pcmk_rc_ok
Definition: results.h:148
@ pcmk_rc_error
Definition: results.h:144
#define pcmk_ok
Definition: results.h:68
int pcmk_rc2legacy(int rc)
Definition: results.c:521
@ PCMK_EXEC_ERROR_FATAL
Execution failed, do not retry anywhere.
Definition: results.h:318
@ PCMK_EXEC_ERROR
Execution failed, may be retried.
Definition: results.h:316
int pcmk_legacy2rc(int legacy_rc)
Definition: results.c:534
void pcmk__set_result(pcmk__action_result_t *result, int exit_status, enum pcmk_exec_status exec_status, const char *exit_reason)
Definition: results.c:895
#define PCMK__UNKNOWN_RESULT
void void pcmk__set_result_output(pcmk__action_result_t *result, char *out, char *err)
Definition: results.c:964
void pcmk__reset_result(pcmk__action_result_t *result)
Definition: results.c:984
Services API.
GList * resources_list_agents(const char *standard, const char *provider)
Get a list of resource agents.
Definition: services.c:1119
gboolean services_action_async(svc_action_t *op, void(*action_callback)(svc_action_t *))
Request asynchronous execution of an action.
Definition: services.c:901
gboolean services_action_sync(svc_action_t *op)
Definition: services.c:1020
GList * resources_list_standards(void)
Definition: services.c:1061
void services_action_free(svc_action_t *op)
Definition: services.c:585
GList * resources_list_providers(const char *standard)
Get a list of providers.
Definition: services.c:1109
op_status
svc_action_t * services__create_resource_action(const char *name, const char *standard, const char *provider, const char *agent, const char *action, guint interval_ms, int timeout, GHashTable *params, enum svc_action_flags flags)
Create a new resource action.
Definition: services.c:254
const char * services__exit_reason(svc_action_t *action)
Definition: services.c:1376
Fencing aka. STONITH.
@ st_opt_sync_call
Definition: stonith-ng.h:58
void stonith_key_value_freeall(stonith_key_value_t *kvp, int keys, int values)
Definition: st_client.c:1938
stonith_t * stonith_api_new(void)
Definition: st_client.c:1816
GHashTable * pcmk__str_table_dup(GHashTable *old_table)
Definition: strings.c:675
GHashTable * pcmk__strkey_table(GDestroyNotify key_destroy_func, GDestroyNotify value_destroy_func)
Definition: strings.c:611
void pcmk__str_update(char **str, const char *value)
Definition: strings.c:1190
@ pcmk__str_none
@ pcmk__str_casei
int(* dispatch)(const char *buffer, ssize_t length, gpointer userdata)
Dispatch function for an IPC connection used as mainloop source.
Definition: mainloop.h:84
int(* get_metadata_params)(lrmd_t *lrmd, const char *standard, const char *provider, const char *agent, char **output, enum lrmd_call_options options, lrmd_key_value_t *params)
Retrieve resource agent metadata synchronously with parameters.
Definition: lrmd.h:590
int(* disconnect)(lrmd_t *lrmd)
Disconnect from the executor.
Definition: lrmd.h:360
int(* connect)(lrmd_t *lrmd, const char *client_name, int *fd)
Connect to an executor.
Definition: lrmd.h:315
const char * op_type
Definition: lrmd.h:223
unsigned int t_run
Definition: lrmd.h:245
unsigned int t_rcchange
Definition: lrmd.h:247
const char * remote_nodename
Definition: lrmd.h:263
const char * exit_reason
Definition: lrmd.h:266
const char * user_data
Definition: lrmd.h:225
const char * output
Definition: lrmd.h:243
unsigned int exec_time
Definition: lrmd.h:249
enum lrmd_callback_event type
Definition: lrmd.h:218
int start_delay
Definition: lrmd.h:234
enum ocf_exitcode rc
Definition: lrmd.h:239
unsigned int queue_time
Definition: lrmd.h:251
void * params
Definition: lrmd.h:258
guint interval_ms
Definition: lrmd.h:232
int rsc_deleted
Definition: lrmd.h:236
int connection_rc
Definition: lrmd.h:254
const char * rsc_id
Definition: lrmd.h:221
char * key
Definition: lrmd.h:30
struct lrmd_key_value_s * next
Definition: lrmd.h:32
char * value
Definition: lrmd.h:31
const char * val
Definition: lrmd.h:297
struct lrmd_list_s * next
Definition: lrmd.h:298
char * timeout_ms_s
Definition: lrmd.h:285
char * rsc_id
Definition: lrmd.h:282
char * interval_ms_s
Definition: lrmd.h:284
char * action
Definition: lrmd.h:283
char * id
Definition: lrmd.h:275
char * standard
Definition: lrmd.h:277
char * type
Definition: lrmd.h:276
char * provider
Definition: lrmd.h:278
Definition: lrmd.h:597
void * lrmd_private
Definition: lrmd.h:599
lrmd_api_operations_t * cmds
Definition: lrmd.h:598
int(* dispatch)(gpointer userdata)
Dispatch function for mainloop file descriptor with data ready.
Definition: mainloop.h:138
int(* free)(stonith_t *st)
Destroy a fencer connection.
Definition: stonith-ng.h:157
int(* metadata)(stonith_t *stonith, int call_options, const char *agent, const char *namespace, char **output, int timeout_sec)
Retrieve a fence agent's metadata.
Definition: stonith-ng.h:258
int(* list_agents)(stonith_t *stonith, int call_options, const char *namespace, stonith_key_value_t **devices, int timeout)
Retrieve a list of installed fence agents.
Definition: stonith-ng.h:279
struct stonith_key_value_s * next
Definition: stonith-ng.h:101
stonith_api_operations_t * cmds
Definition: stonith-ng.h:556
Object for executing external actions.
Definition: services.h:112
xmlNode * first_named_child(const xmlNode *parent, const char *name)
Definition: xml.c:2930
xmlNode * crm_next_same_xml(const xmlNode *sibling)
Get next instance of same XML tag.
Definition: xml.c:2956
gboolean add_message_xml(xmlNode *msg, const char *field, xmlNode *xml)
Definition: messages.c:160
xmlNode * string2xml(const char *input)
Definition: xml.c:930
void free_xml(xmlNode *child)
Definition: xml.c:885
xmlNode * create_xml_node(xmlNode *parent, const char *name)
Definition: xml.c:749