pacemaker 2.1.8-2.1.8~rc1
Scalable High-Availability cluster resource manager
Loading...
Searching...
No Matches
lrmd_client.c
Go to the documentation of this file.
1/*
2 * Copyright 2012-2024 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/common/xml.h>
36
37#include <crm/stonith-ng.h>
38#include <crm/fencing/internal.h> // stonith__*
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 = pcmk__assert_alloc(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 = pcmk__assert_alloc(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{
198
199 // lrmd_event_data_t has (const char *) members that lrmd_free_event() frees
200 event->rsc_id = pcmk__str_copy(rsc_id);
201 event->op_type = pcmk__str_copy(task);
202 event->interval_ms = interval_ms;
203 return event;
204}
205
208{
209 lrmd_event_data_t *copy = NULL;
210
211 copy = pcmk__assert_alloc(1, sizeof(lrmd_event_data_t));
212
213 copy->type = event->type;
214
215 // lrmd_event_data_t has (const char *) members that lrmd_free_event() frees
216 copy->rsc_id = pcmk__str_copy(event->rsc_id);
217 copy->op_type = pcmk__str_copy(event->op_type);
218 copy->user_data = pcmk__str_copy(event->user_data);
219 copy->output = pcmk__str_copy(event->output);
221 copy->exit_reason = pcmk__str_copy(event->exit_reason);
222
223 copy->call_id = event->call_id;
224 copy->timeout = event->timeout;
225 copy->interval_ms = event->interval_ms;
226 copy->start_delay = event->start_delay;
227 copy->rsc_deleted = event->rsc_deleted;
228 copy->rc = event->rc;
229 copy->op_status = event->op_status;
230 copy->t_run = event->t_run;
231 copy->t_rcchange = event->t_rcchange;
232 copy->exec_time = event->exec_time;
233 copy->queue_time = event->queue_time;
234 copy->connection_rc = event->connection_rc;
235 copy->params = pcmk__str_table_dup(event->params);
236
237 return copy;
238}
239
245void
247{
248 if (event == NULL) {
249 return;
250 }
251 // @TODO Why are these const char *?
252 free((void *) event->rsc_id);
253 free((void *) event->op_type);
254 free((void *) event->user_data);
255 free((void *) event->remote_nodename);
256 lrmd__reset_result(event);
257 if (event->params != NULL) {
258 g_hash_table_destroy(event->params);
259 }
260 free(event);
261}
262
263static void
264lrmd_dispatch_internal(lrmd_t * lrmd, xmlNode * msg)
265{
266 const char *type;
267 const char *proxy_session = crm_element_value(msg,
269 lrmd_private_t *native = lrmd->lrmd_private;
270 lrmd_event_data_t event = { 0, };
271
272 if (proxy_session != NULL) {
273 /* this is proxy business */
274 lrmd_internal_proxy_dispatch(lrmd, msg);
275 return;
276 } else if (!native->callback) {
277 /* no callback set */
278 crm_trace("notify event received but client has not set callback");
279 return;
280 }
281
282 event.remote_nodename = native->remote_nodename;
284 crm_element_value_int(msg, PCMK__XA_LRMD_CALLID, &event.call_id);
285 event.rsc_id = crm_element_value(msg, PCMK__XA_LRMD_RSC_ID);
286
287 if (pcmk__str_eq(type, LRMD_OP_RSC_REG, pcmk__str_none)) {
288 event.type = lrmd_event_register;
289 } else if (pcmk__str_eq(type, LRMD_OP_RSC_UNREG, pcmk__str_none)) {
290 event.type = lrmd_event_unregister;
291 } else if (pcmk__str_eq(type, LRMD_OP_RSC_EXEC, pcmk__str_none)) {
292 int rc = 0;
293 int exec_time = 0;
294 int queue_time = 0;
295 time_t epoch = 0;
296
297 crm_element_value_int(msg, PCMK__XA_LRMD_TIMEOUT, &event.timeout);
299 &event.interval_ms);
301 &event.start_delay);
302
304 event.rc = (enum ocf_exitcode) rc;
305
307 &event.op_status);
309 &event.rsc_deleted);
310
312 event.t_run = (unsigned int) epoch;
313
315 event.t_rcchange = (unsigned int) epoch;
316
318 CRM_LOG_ASSERT(exec_time >= 0);
319 event.exec_time = QB_MAX(0, exec_time);
320
322 CRM_LOG_ASSERT(queue_time >= 0);
323 event.queue_time = QB_MAX(0, queue_time);
324
325 event.op_type = crm_element_value(msg, PCMK__XA_LRMD_RSC_ACTION);
326 event.user_data = crm_element_value(msg,
328 event.type = lrmd_event_exec_complete;
329
330 /* output and exit_reason may be freed by a callback */
332 lrmd__set_result(&event, event.rc, event.op_status,
334
335 event.params = xml2list(msg);
336 } else if (pcmk__str_eq(type, LRMD_OP_NEW_CLIENT, pcmk__str_none)) {
337 event.type = lrmd_event_new_client;
338 } else if (pcmk__str_eq(type, LRMD_OP_POKE, pcmk__str_none)) {
339 event.type = lrmd_event_poke;
340 } else {
341 return;
342 }
343
344 crm_trace("op %s notify event received", type);
345 native->callback(&event);
346
347 if (event.params) {
348 g_hash_table_destroy(event.params);
349 }
350 lrmd__reset_result(&event);
351}
352
353// \return Always 0, to indicate that IPC mainloop source should be kept
354static int
355lrmd_ipc_dispatch(const char *buffer, ssize_t length, gpointer userdata)
356{
357 lrmd_t *lrmd = userdata;
358 lrmd_private_t *native = lrmd->lrmd_private;
359
360 if (native->callback != NULL) {
361 xmlNode *msg = pcmk__xml_parse(buffer);
362
363 lrmd_dispatch_internal(lrmd, msg);
364 free_xml(msg);
365 }
366 return 0;
367}
368
369#ifdef HAVE_GNUTLS_GNUTLS_H
370static void
371lrmd_free_xml(gpointer userdata)
372{
373 free_xml((xmlNode *) userdata);
374}
375
376static bool
377remote_executor_connected(lrmd_t * lrmd)
378{
379 lrmd_private_t *native = lrmd->lrmd_private;
380
381 return (native->remote->tls_session != NULL);
382}
383
395static int
396lrmd_tls_dispatch(gpointer userdata)
397{
398 lrmd_t *lrmd = userdata;
399 lrmd_private_t *native = lrmd->lrmd_private;
400 xmlNode *xml = NULL;
401 int rc = pcmk_rc_ok;
402
403 if (!remote_executor_connected(lrmd)) {
404 crm_trace("TLS dispatch triggered after disconnect");
405 return 0;
406 }
407
408 crm_trace("TLS dispatch triggered");
409
410 /* First check if there are any pending notifies to process that came
411 * while we were waiting for replies earlier. */
412 if (native->pending_notify) {
413 GList *iter = NULL;
414
415 crm_trace("Processing pending notifies");
416 for (iter = native->pending_notify; iter; iter = iter->next) {
417 lrmd_dispatch_internal(lrmd, iter->data);
418 }
419 g_list_free_full(native->pending_notify, lrmd_free_xml);
420 native->pending_notify = NULL;
421 }
422
423 /* Next read the current buffer and see if there are any messages to handle. */
424 switch (pcmk__remote_ready(native->remote, 0)) {
425 case pcmk_rc_ok:
426 rc = pcmk__read_remote_message(native->remote, -1);
427 xml = pcmk__remote_message_xml(native->remote);
428 break;
429 case ETIME:
430 // Nothing to read, check if a full message is already in buffer
431 xml = pcmk__remote_message_xml(native->remote);
432 break;
433 default:
434 rc = ENOTCONN;
435 break;
436 }
437 while (xml) {
438 const char *msg_type = crm_element_value(xml,
440 if (pcmk__str_eq(msg_type, "notify", pcmk__str_casei)) {
441 lrmd_dispatch_internal(lrmd, xml);
442 } else if (pcmk__str_eq(msg_type, "reply", pcmk__str_casei)) {
443 if (native->expected_late_replies > 0) {
444 native->expected_late_replies--;
445 } else {
446 int reply_id = 0;
448 /* if this happens, we want to know about it */
449 crm_err("Got outdated Pacemaker Remote reply %d", reply_id);
450 }
451 }
452 free_xml(xml);
453 xml = pcmk__remote_message_xml(native->remote);
454 }
455
456 if (rc == ENOTCONN) {
457 crm_info("Lost %s executor connection while reading data",
458 (native->remote_nodename? native->remote_nodename : "local"));
459 lrmd_tls_disconnect(lrmd);
460 return 0;
461 }
462 return 1;
463}
464#endif
465
466/* Not used with mainloop */
467int
469{
470 lrmd_private_t *native = lrmd->lrmd_private;
471
472 switch (native->type) {
473 case pcmk__client_ipc:
474 return crm_ipc_ready(native->ipc);
475
476#ifdef HAVE_GNUTLS_GNUTLS_H
477 case pcmk__client_tls:
478 if (native->pending_notify) {
479 return 1;
480 } else {
481 int rc = pcmk__remote_ready(native->remote, 0);
482
483 switch (rc) {
484 case pcmk_rc_ok:
485 return 1;
486 case ETIME:
487 return 0;
488 default:
489 return pcmk_rc2legacy(rc);
490 }
491 }
492#endif
493 default:
494 crm_err("Unsupported executor connection type (bug?): %d",
495 native->type);
496 return -EPROTONOSUPPORT;
497 }
498}
499
500/* Not used with mainloop */
501bool
503{
504 lrmd_private_t *private = NULL;
505
506 CRM_ASSERT(lrmd != NULL);
507
508 private = lrmd->lrmd_private;
509 switch (private->type) {
510 case pcmk__client_ipc:
511 while (crm_ipc_ready(private->ipc)) {
512 if (crm_ipc_read(private->ipc) > 0) {
513 const char *msg = crm_ipc_buffer(private->ipc);
514
515 lrmd_ipc_dispatch(msg, strlen(msg), lrmd);
516 }
517 }
518 break;
519#ifdef HAVE_GNUTLS_GNUTLS_H
520 case pcmk__client_tls:
521 lrmd_tls_dispatch(lrmd);
522 break;
523#endif
524 default:
525 crm_err("Unsupported executor connection type (bug?): %d",
526 private->type);
527 }
528
529 if (lrmd_api_is_connected(lrmd) == FALSE) {
530 crm_err("Connection closed");
531 return FALSE;
532 }
533
534 return TRUE;
535}
536
537static xmlNode *
538lrmd_create_op(const char *token, const char *op, xmlNode *data, int timeout,
539 enum lrmd_call_options options)
540{
541 xmlNode *op_msg = NULL;
542
543 CRM_CHECK(token != NULL, return NULL);
544
547 crm_xml_add(op_msg, PCMK__XA_LRMD_OP, op);
549 crm_xml_add_int(op_msg, PCMK__XA_LRMD_CALLOPT, options);
550
551 if (data != NULL) {
552 xmlNode *wrapper = pcmk__xe_create(op_msg, PCMK__XE_LRMD_CALLDATA);
553
554 pcmk__xml_copy(wrapper, data);
555 }
556
557 crm_trace("Created executor %s command with call options %.8lx (%d)",
558 op, (long)options, options);
559 return op_msg;
560}
561
562static void
563lrmd_ipc_connection_destroy(gpointer userdata)
564{
565 lrmd_t *lrmd = userdata;
566 lrmd_private_t *native = lrmd->lrmd_private;
567
568 switch (native->type) {
569 case pcmk__client_ipc:
570 crm_info("Disconnected from local executor");
571 break;
572#ifdef HAVE_GNUTLS_GNUTLS_H
573 case pcmk__client_tls:
574 crm_info("Disconnected from remote executor on %s",
575 native->remote_nodename);
576 break;
577#endif
578 default:
579 crm_err("Unsupported executor connection type %d (bug?)",
580 native->type);
581 }
582
583 /* Prevent these from being cleaned up in lrmd_api_disconnect() */
584 native->ipc = NULL;
585 native->source = NULL;
586
587 if (native->callback) {
588 lrmd_event_data_t event = { 0, };
590 event.remote_nodename = native->remote_nodename;
591 native->callback(&event);
592 }
593}
594
595#ifdef HAVE_GNUTLS_GNUTLS_H
596static void
597lrmd_tls_connection_destroy(gpointer userdata)
598{
599 lrmd_t *lrmd = userdata;
600 lrmd_private_t *native = lrmd->lrmd_private;
601
602 crm_info("TLS connection destroyed");
603
604 if (native->remote->tls_session) {
605 gnutls_bye(*native->remote->tls_session, GNUTLS_SHUT_RDWR);
606 gnutls_deinit(*native->remote->tls_session);
607 gnutls_free(native->remote->tls_session);
608 native->remote->tls_session = NULL;
609 }
610 if (native->psk_cred_c) {
611 gnutls_psk_free_client_credentials(native->psk_cred_c);
612 }
613 if (native->sock) {
614 close(native->sock);
615 }
616 if (native->process_notify) {
617 mainloop_destroy_trigger(native->process_notify);
618 native->process_notify = NULL;
619 }
620 if (native->pending_notify) {
621 g_list_free_full(native->pending_notify, lrmd_free_xml);
622 native->pending_notify = NULL;
623 }
624
625 free(native->remote->buffer);
626 free(native->remote->start_state);
627 native->remote->buffer = NULL;
628 native->remote->start_state = NULL;
629 native->source = 0;
630 native->sock = 0;
631 native->psk_cred_c = NULL;
632 native->sock = 0;
633
634 if (native->callback) {
635 lrmd_event_data_t event = { 0, };
636 event.remote_nodename = native->remote_nodename;
637 event.type = lrmd_event_disconnect;
638 native->callback(&event);
639 }
640 return;
641}
642
643// \return Standard Pacemaker return code
644int
645lrmd__remote_send_xml(pcmk__remote_t *session, xmlNode *msg, uint32_t id,
646 const char *msg_type)
647{
650 return pcmk__remote_send_xml(session, msg);
651}
652
653// \return Standard Pacemaker return code
654static int
655read_remote_reply(lrmd_t *lrmd, int total_timeout, int expected_reply_id,
656 xmlNode **reply)
657{
658 lrmd_private_t *native = lrmd->lrmd_private;
659 time_t start = time(NULL);
660 const char *msg_type = NULL;
661 int reply_id = 0;
662 int remaining_timeout = 0;
663 int rc = pcmk_rc_ok;
664
665 /* A timeout of 0 here makes no sense. We have to wait a period of time
666 * for the response to come back. If -1 or 0, default to 10 seconds. */
667 if (total_timeout <= 0 || total_timeout > MAX_TLS_RECV_WAIT) {
668 total_timeout = MAX_TLS_RECV_WAIT;
669 }
670
671 for (*reply = NULL; *reply == NULL; ) {
672
673 *reply = pcmk__remote_message_xml(native->remote);
674 if (*reply == NULL) {
675 /* read some more off the tls buffer if we still have time left. */
676 if (remaining_timeout) {
677 remaining_timeout = total_timeout - ((time(NULL) - start) * 1000);
678 } else {
679 remaining_timeout = total_timeout;
680 }
681 if (remaining_timeout <= 0) {
682 return ETIME;
683 }
684
685 rc = pcmk__read_remote_message(native->remote, remaining_timeout);
686 if (rc != pcmk_rc_ok) {
687 return rc;
688 }
689
690 *reply = pcmk__remote_message_xml(native->remote);
691 if (*reply == NULL) {
692 return ENOMSG;
693 }
694 }
695
698
699 if (!msg_type) {
700 crm_err("Empty msg type received while waiting for reply");
701 free_xml(*reply);
702 *reply = NULL;
703 } else if (pcmk__str_eq(msg_type, "notify", pcmk__str_casei)) {
704 /* got a notify while waiting for reply, trigger the notify to be processed later */
705 crm_info("queueing notify");
706 native->pending_notify = g_list_append(native->pending_notify, *reply);
707 if (native->process_notify) {
708 crm_info("notify trigger set.");
709 mainloop_set_trigger(native->process_notify);
710 }
711 *reply = NULL;
712 } else if (!pcmk__str_eq(msg_type, "reply", pcmk__str_casei)) {
713 /* msg isn't a reply, make some noise */
714 crm_err("Expected a reply, got %s", msg_type);
715 free_xml(*reply);
716 *reply = NULL;
717 } else if (reply_id != expected_reply_id) {
718 if (native->expected_late_replies > 0) {
719 native->expected_late_replies--;
720 } else {
721 crm_err("Got outdated reply, expected id %d got id %d", expected_reply_id, reply_id);
722 }
723 free_xml(*reply);
724 *reply = NULL;
725 }
726 }
727
728 if (native->remote->buffer && native->process_notify) {
729 mainloop_set_trigger(native->process_notify);
730 }
731
732 return rc;
733}
734
735// \return Standard Pacemaker return code
736static int
737send_remote_message(lrmd_t *lrmd, xmlNode *msg)
738{
739 int rc = pcmk_rc_ok;
740 lrmd_private_t *native = lrmd->lrmd_private;
741
742 global_remote_msg_id++;
743 if (global_remote_msg_id <= 0) {
744 global_remote_msg_id = 1;
745 }
746
747 rc = lrmd__remote_send_xml(native->remote, msg, global_remote_msg_id,
748 "request");
749 if (rc != pcmk_rc_ok) {
750 crm_err("Disconnecting because TLS message could not be sent to "
751 "Pacemaker Remote: %s", pcmk_rc_str(rc));
752 lrmd_tls_disconnect(lrmd);
753 }
754 return rc;
755}
756
757static int
758lrmd_tls_send_recv(lrmd_t * lrmd, xmlNode * msg, int timeout, xmlNode ** reply)
759{
760 int rc = 0;
761 xmlNode *xml = NULL;
762
763 if (!remote_executor_connected(lrmd)) {
764 return -ENOTCONN;
765 }
766
767 rc = send_remote_message(lrmd, msg);
768 if (rc != pcmk_rc_ok) {
769 return pcmk_rc2legacy(rc);
770 }
771
772 rc = read_remote_reply(lrmd, timeout, global_remote_msg_id, &xml);
773 if (rc != pcmk_rc_ok) {
774 crm_err("Disconnecting remote after request %d reply not received: %s "
775 CRM_XS " rc=%d timeout=%dms",
776 global_remote_msg_id, pcmk_rc_str(rc), rc, timeout);
777 lrmd_tls_disconnect(lrmd);
778 }
779
780 if (reply) {
781 *reply = xml;
782 } else {
783 free_xml(xml);
784 }
785
786 return pcmk_rc2legacy(rc);
787}
788#endif
789
790static int
791lrmd_send_xml(lrmd_t * lrmd, xmlNode * msg, int timeout, xmlNode ** reply)
792{
793 int rc = pcmk_ok;
794 lrmd_private_t *native = lrmd->lrmd_private;
795
796 switch (native->type) {
797 case pcmk__client_ipc:
798 rc = crm_ipc_send(native->ipc, msg, crm_ipc_client_response, timeout, reply);
799 break;
800#ifdef HAVE_GNUTLS_GNUTLS_H
801 case pcmk__client_tls:
802 rc = lrmd_tls_send_recv(lrmd, msg, timeout, reply);
803 break;
804#endif
805 default:
806 crm_err("Unsupported executor connection type (bug?): %d",
807 native->type);
808 rc = -EPROTONOSUPPORT;
809 }
810
811 return rc;
812}
813
814static int
815lrmd_send_xml_no_reply(lrmd_t * lrmd, xmlNode * msg)
816{
817 int rc = pcmk_ok;
818 lrmd_private_t *native = lrmd->lrmd_private;
819
820 switch (native->type) {
821 case pcmk__client_ipc:
822 rc = crm_ipc_send(native->ipc, msg, crm_ipc_flags_none, 0, NULL);
823 break;
824#ifdef HAVE_GNUTLS_GNUTLS_H
825 case pcmk__client_tls:
826 rc = send_remote_message(lrmd, msg);
827 if (rc == pcmk_rc_ok) {
828 /* we don't want to wait around for the reply, but
829 * since the request/reply protocol needs to behave the same
830 * as libqb, a reply will eventually come later anyway. */
831 native->expected_late_replies++;
832 }
833 rc = pcmk_rc2legacy(rc);
834 break;
835#endif
836 default:
837 crm_err("Unsupported executor connection type (bug?): %d",
838 native->type);
839 rc = -EPROTONOSUPPORT;
840 }
841
842 return rc;
843}
844
845static int
846lrmd_api_is_connected(lrmd_t * lrmd)
847{
848 lrmd_private_t *native = lrmd->lrmd_private;
849
850 switch (native->type) {
851 case pcmk__client_ipc:
852 return crm_ipc_connected(native->ipc);
853#ifdef HAVE_GNUTLS_GNUTLS_H
854 case pcmk__client_tls:
855 return remote_executor_connected(lrmd);
856#endif
857 default:
858 crm_err("Unsupported executor connection type (bug?): %d",
859 native->type);
860 return 0;
861 }
862}
863
882static int
883lrmd_send_command(lrmd_t *lrmd, const char *op, xmlNode *data,
884 xmlNode **output_data, int timeout,
885 enum lrmd_call_options options, gboolean expect_reply)
886{
887 int rc = pcmk_ok;
888 lrmd_private_t *native = lrmd->lrmd_private;
889 xmlNode *op_msg = NULL;
890 xmlNode *op_reply = NULL;
891
892 if (!lrmd_api_is_connected(lrmd)) {
893 return -ENOTCONN;
894 }
895
896 if (op == NULL) {
897 crm_err("No operation specified");
898 return -EINVAL;
899 }
900
901 CRM_CHECK(native->token != NULL,;
902 );
903 crm_trace("Sending %s op to executor", op);
904
905 op_msg = lrmd_create_op(native->token, op, data, timeout, options);
906
907 if (op_msg == NULL) {
908 return -EINVAL;
909 }
910
911 if (expect_reply) {
912 rc = lrmd_send_xml(lrmd, op_msg, timeout, &op_reply);
913 } else {
914 rc = lrmd_send_xml_no_reply(lrmd, op_msg);
915 goto done;
916 }
917
918 if (rc < 0) {
919 crm_perror(LOG_ERR, "Couldn't perform %s operation (timeout=%d): %d", op, timeout, rc);
920 goto done;
921
922 } else if(op_reply == NULL) {
923 rc = -ENOMSG;
924 goto done;
925 }
926
927 rc = pcmk_ok;
928 crm_trace("%s op reply received", op);
929 if (crm_element_value_int(op_reply, PCMK__XA_LRMD_RC, &rc) != 0) {
930 rc = -ENOMSG;
931 goto done;
932 }
933
934 crm_log_xml_trace(op_reply, "Reply");
935
936 if (output_data) {
937 *output_data = op_reply;
938 op_reply = NULL; /* Prevent subsequent free */
939 }
940
941 done:
942 if (lrmd_api_is_connected(lrmd) == FALSE) {
943 crm_err("Executor disconnected");
944 }
945
946 free_xml(op_msg);
947 free_xml(op_reply);
948 return rc;
949}
950
951static int
952lrmd_api_poke_connection(lrmd_t * lrmd)
953{
954 int rc;
955 lrmd_private_t *native = lrmd->lrmd_private;
956 xmlNode *data = pcmk__xe_create(NULL, PCMK__XE_LRMD_RSC);
957
959 rc = lrmd_send_command(lrmd, LRMD_OP_POKE, data, NULL, 0, 0,
960 (native->type == pcmk__client_ipc));
961 free_xml(data);
962
963 return rc < 0 ? rc : pcmk_ok;
964}
965
966// \return Standard Pacemaker return code
967int
969{
970 int rc = pcmk_rc_ok;
971 const char *value;
972 lrmd_private_t *native = lrmd->lrmd_private;
973 xmlNode *data = pcmk__xe_create(NULL, PCMK__XA_LRMD_OP);
974
976
977 value = g_hash_table_lookup(hash, PCMK_OPT_STONITH_WATCHDOG_TIMEOUT);
978 if ((value) &&
979 (stonith__watchdog_fencing_enabled_for_node(native->remote_nodename))) {
981 }
982
983 rc = lrmd_send_command(lrmd, LRMD_OP_CHECK, data, NULL, 0, 0,
984 (native->type == pcmk__client_ipc));
985 free_xml(data);
986 return (rc < 0)? pcmk_legacy2rc(rc) : pcmk_rc_ok;
987}
988
989static int
990lrmd_handshake(lrmd_t * lrmd, const char *name)
991{
992 int rc = pcmk_ok;
993 lrmd_private_t *native = lrmd->lrmd_private;
994 xmlNode *reply = NULL;
995 xmlNode *hello = pcmk__xe_create(NULL, PCMK__XE_LRMD_COMMAND);
996
1001
1002 /* advertise that we are a proxy provider */
1003 if (native->proxy_callback) {
1005 }
1006
1007 rc = lrmd_send_xml(lrmd, hello, -1, &reply);
1008
1009 if (rc < 0) {
1010 crm_perror(LOG_DEBUG, "Couldn't complete registration with the executor API: %d", rc);
1011 rc = -ECOMM;
1012 } else if (reply == NULL) {
1013 crm_err("Did not receive registration reply");
1014 rc = -EPROTO;
1015 } else {
1016 const char *version = crm_element_value(reply,
1018 const char *msg_type = crm_element_value(reply, PCMK__XA_LRMD_OP);
1019 const char *tmp_ticket = crm_element_value(reply,
1021 const char *start_state = crm_element_value(reply, PCMK__XA_NODE_START_STATE);
1022 long long uptime = -1;
1023
1025
1026 /* The remote executor may add its uptime to the XML reply, which is
1027 * useful in handling transient attributes when the connection to the
1028 * remote node unexpectedly drops. If no parameter is given, just
1029 * default to -1.
1030 */
1031 crm_element_value_ll(reply, PCMK__XA_UPTIME, &uptime);
1032 native->remote->uptime = uptime;
1033
1034 if (start_state) {
1035 native->remote->start_state = strdup(start_state);
1036 }
1037
1038 if (rc == -EPROTO) {
1039 crm_err("Executor protocol version mismatch between client (%s) and server (%s)",
1041 crm_log_xml_err(reply, "Protocol Error");
1042
1043 } else if (!pcmk__str_eq(msg_type, CRM_OP_REGISTER, pcmk__str_casei)) {
1044 crm_err("Invalid registration message: %s", msg_type);
1045 crm_log_xml_err(reply, "Bad reply");
1046 rc = -EPROTO;
1047 } else if (tmp_ticket == NULL) {
1048 crm_err("No registration token provided");
1049 crm_log_xml_err(reply, "Bad reply");
1050 rc = -EPROTO;
1051 } else {
1052 crm_trace("Obtained registration token: %s", tmp_ticket);
1053 native->token = strdup(tmp_ticket);
1054 native->peer_version = strdup(version?version:"1.0"); /* Included since 1.1 */
1055 rc = pcmk_ok;
1056 }
1057 }
1058
1059 free_xml(reply);
1060 free_xml(hello);
1061
1062 if (rc != pcmk_ok) {
1063 lrmd_api_disconnect(lrmd);
1064 }
1065 return rc;
1066}
1067
1068static int
1069lrmd_ipc_connect(lrmd_t * lrmd, int *fd)
1070{
1071 int rc = pcmk_ok;
1072 lrmd_private_t *native = lrmd->lrmd_private;
1073
1074 struct ipc_client_callbacks lrmd_callbacks = {
1075 .dispatch = lrmd_ipc_dispatch,
1076 .destroy = lrmd_ipc_connection_destroy
1077 };
1078
1079 crm_info("Connecting to executor");
1080
1081 if (fd) {
1082 /* No mainloop */
1083 native->ipc = crm_ipc_new(CRM_SYSTEM_LRMD, 0);
1084 if (native->ipc != NULL) {
1085 rc = pcmk__connect_generic_ipc(native->ipc);
1086 if (rc == pcmk_rc_ok) {
1087 rc = pcmk__ipc_fd(native->ipc, fd);
1088 }
1089 if (rc != pcmk_rc_ok) {
1090 crm_err("Connection to executor failed: %s", pcmk_rc_str(rc));
1091 rc = -ENOTCONN;
1092 }
1093 }
1094 } else {
1095 native->source = mainloop_add_ipc_client(CRM_SYSTEM_LRMD, G_PRIORITY_HIGH, 0, lrmd, &lrmd_callbacks);
1096 native->ipc = mainloop_get_ipc_client(native->source);
1097 }
1098
1099 if (native->ipc == NULL) {
1100 crm_debug("Could not connect to the executor API");
1101 rc = -ENOTCONN;
1102 }
1103
1104 return rc;
1105}
1106
1107#ifdef HAVE_GNUTLS_GNUTLS_H
1108static void
1109copy_gnutls_datum(gnutls_datum_t *dest, gnutls_datum_t *source)
1110{
1111 CRM_ASSERT((dest != NULL) && (source != NULL) && (source->data != NULL));
1112
1113 dest->data = gnutls_malloc(source->size);
1114 pcmk__mem_assert(dest->data);
1115
1116 memcpy(dest->data, source->data, source->size);
1117 dest->size = source->size;
1118}
1119
1120static void
1121clear_gnutls_datum(gnutls_datum_t *datum)
1122{
1123 gnutls_free(datum->data);
1124 datum->data = NULL;
1125 datum->size = 0;
1126}
1127
1128#define KEY_READ_LEN 256 // Chunk size for reading key from file
1129
1130// \return Standard Pacemaker return code
1131static int
1132read_gnutls_key(const char *location, gnutls_datum_t *key)
1133{
1134 FILE *stream = NULL;
1135 size_t buf_len = KEY_READ_LEN;
1136
1137 if ((location == NULL) || (key == NULL)) {
1138 return EINVAL;
1139 }
1140
1141 stream = fopen(location, "r");
1142 if (stream == NULL) {
1143 return errno;
1144 }
1145
1146 key->data = gnutls_malloc(buf_len);
1147 key->size = 0;
1148 while (!feof(stream)) {
1149 int next = fgetc(stream);
1150
1151 if (next == EOF) {
1152 if (!feof(stream)) {
1153 crm_warn("Pacemaker Remote key read was partially successful "
1154 "(copy in memory may be corrupted)");
1155 }
1156 break;
1157 }
1158 if (key->size == buf_len) {
1159 buf_len = key->size + KEY_READ_LEN;
1160 key->data = gnutls_realloc(key->data, buf_len);
1161 CRM_ASSERT(key->data);
1162 }
1163 key->data[key->size++] = (unsigned char) next;
1164 }
1165 fclose(stream);
1166
1167 if (key->size == 0) {
1168 clear_gnutls_datum(key);
1169 return ENOKEY;
1170 }
1171 return pcmk_rc_ok;
1172}
1173
1174// Cache the most recently used Pacemaker Remote authentication key
1175
1176struct key_cache_s {
1177 time_t updated; // When cached key was read (valid for 1 minute)
1178 const char *location; // Where cached key was read from
1179 gnutls_datum_t key; // Cached key
1180};
1181
1182static bool
1183key_is_cached(struct key_cache_s *key_cache)
1184{
1185 return key_cache->updated != 0;
1186}
1187
1188static bool
1189key_cache_expired(struct key_cache_s *key_cache)
1190{
1191 return (time(NULL) - key_cache->updated) >= 60;
1192}
1193
1194static void
1195clear_key_cache(struct key_cache_s *key_cache)
1196{
1197 clear_gnutls_datum(&(key_cache->key));
1198 if ((key_cache->updated != 0) || (key_cache->location != NULL)) {
1199 key_cache->updated = 0;
1200 key_cache->location = NULL;
1201 crm_debug("Cleared Pacemaker Remote key cache");
1202 }
1203}
1204
1205static void
1206get_cached_key(struct key_cache_s *key_cache, gnutls_datum_t *key)
1207{
1208 copy_gnutls_datum(key, &(key_cache->key));
1209 crm_debug("Using cached Pacemaker Remote key from %s",
1210 pcmk__s(key_cache->location, "unknown location"));
1211}
1212
1213static void
1214cache_key(struct key_cache_s *key_cache, gnutls_datum_t *key,
1215 const char *location)
1216{
1217 key_cache->updated = time(NULL);
1218 key_cache->location = location;
1219 copy_gnutls_datum(&(key_cache->key), key);
1220 crm_debug("Using (and cacheing) Pacemaker Remote key from %s",
1221 pcmk__s(location, "unknown location"));
1222}
1223
1234static int
1235get_remote_key(const char *location, gnutls_datum_t *key)
1236{
1237 static struct key_cache_s key_cache = { 0, };
1238 int rc = pcmk_rc_ok;
1239
1240 if ((location == NULL) || (key == NULL)) {
1241 return EINVAL;
1242 }
1243
1244 if (key_is_cached(&key_cache)) {
1245 if (key_cache_expired(&key_cache)) {
1246 clear_key_cache(&key_cache);
1247 } else {
1248 get_cached_key(&key_cache, key);
1249 return pcmk_rc_ok;
1250 }
1251 }
1252
1253 rc = read_gnutls_key(location, key);
1254 if (rc != pcmk_rc_ok) {
1255 return rc;
1256 }
1257 cache_key(&key_cache, key, location);
1258 return pcmk_rc_ok;
1259}
1260
1274int
1275lrmd__init_remote_key(gnutls_datum_t *key)
1276{
1277 static const char *env_location = NULL;
1278 static bool need_env = true;
1279
1280 int env_rc = pcmk_rc_ok;
1281 int default_rc = pcmk_rc_ok;
1282 int alt_rc = pcmk_rc_ok;
1283
1284 bool env_is_default = false;
1285 bool env_is_fallback = false;
1286
1287 if (need_env) {
1289 need_env = false;
1290 }
1291
1292 // Try location in environment variable, if set
1293 if (env_location != NULL) {
1294 env_rc = get_remote_key(env_location, key);
1295 if (env_rc == pcmk_rc_ok) {
1296 return pcmk_rc_ok;
1297 }
1298
1299 env_is_default = !strcmp(env_location, DEFAULT_REMOTE_KEY_LOCATION);
1300 env_is_fallback = !strcmp(env_location, ALT_REMOTE_KEY_LOCATION);
1301
1302 /* @TODO It would be more secure to fail, rather than fall back to the
1303 * default, if an explicitly set key location is not readable, and it
1304 * would be better to never use the Corosync location as a fallback.
1305 * However, that would break any deployments currently working with the
1306 * fallbacks.
1307 *
1308 * @COMPAT Change at 3.0.0
1309 */
1310 }
1311
1312 // Try default location, if environment wasn't explicitly set to it
1313 if (env_is_default) {
1314 default_rc = env_rc;
1315 } else {
1316 default_rc = get_remote_key(DEFAULT_REMOTE_KEY_LOCATION, key);
1317 }
1318
1319 // Try fallback location, if environment wasn't set to it and default failed
1320 // @COMPAT Drop at 3.0.0
1321 if (env_is_fallback) {
1322 alt_rc = env_rc;
1323 } else if (default_rc != pcmk_rc_ok) {
1324 alt_rc = get_remote_key(ALT_REMOTE_KEY_LOCATION, key);
1325 }
1326
1327 // We have all results, so log and return
1328
1329 if ((env_rc != pcmk_rc_ok) && (default_rc != pcmk_rc_ok)
1330 && (alt_rc != pcmk_rc_ok)) { // Environment set, everything failed
1331
1332 crm_warn("Could not read Pacemaker Remote key from %s (%s%s%s%s%s): %s",
1333 env_location,
1334 env_is_default? "" : "or default location ",
1335 env_is_default? "" : DEFAULT_REMOTE_KEY_LOCATION,
1336 !env_is_default && !env_is_fallback? " " : "",
1337 env_is_fallback? "" : "or fallback location ",
1338 env_is_fallback? "" : ALT_REMOTE_KEY_LOCATION,
1339 pcmk_rc_str(env_rc));
1340 return ENOKEY;
1341 }
1342
1343 if (env_rc != pcmk_rc_ok) { // Environment set but failed, using a default
1344 crm_warn("Could not read Pacemaker Remote key from %s "
1345 "(using %s location %s instead): %s",
1346 env_location,
1347 (default_rc == pcmk_rc_ok)? "default" : "fallback",
1349 pcmk_rc_str(env_rc));
1350 crm_warn("This undocumented behavior is deprecated and unsafe and will "
1351 "be removed in a future release");
1352 return pcmk_rc_ok;
1353 }
1354
1355 if (default_rc != pcmk_rc_ok) {
1356 if (alt_rc == pcmk_rc_ok) {
1357 // Environment variable unset, used alternate location
1358 // This gets caught by the default return below, but we additionally
1359 // warn on this behavior here.
1360 crm_warn("Read Pacemaker Remote key from alternate location %s",
1362 crm_warn("This undocumented behavior is deprecated and unsafe and will "
1363 "be removed in a future release");
1364 } else {
1365 // Environment unset, defaults failed
1366 crm_warn("Could not read Pacemaker Remote key from default location %s"
1367 " (or fallback location %s): %s",
1369 pcmk_rc_str(default_rc));
1370 return ENOKEY;
1371 }
1372 }
1373
1374 return pcmk_rc_ok; // Environment variable unset, a default worked
1375}
1376
1377static void
1378lrmd_gnutls_global_init(void)
1379{
1380 static int gnutls_init = 0;
1381
1382 if (!gnutls_init) {
1383 crm_gnutls_global_init();
1384 }
1385 gnutls_init = 1;
1386}
1387#endif
1388
1389static void
1390report_async_connection_result(lrmd_t * lrmd, int rc)
1391{
1392 lrmd_private_t *native = lrmd->lrmd_private;
1393
1394 if (native->callback) {
1395 lrmd_event_data_t event = { 0, };
1396 event.type = lrmd_event_connect;
1397 event.remote_nodename = native->remote_nodename;
1398 event.connection_rc = rc;
1399 native->callback(&event);
1400 }
1401}
1402
1403#ifdef HAVE_GNUTLS_GNUTLS_H
1404static inline int
1405lrmd__tls_client_handshake(pcmk__remote_t *remote)
1406{
1407 return pcmk__tls_client_handshake(remote, LRMD_CLIENT_HANDSHAKE_TIMEOUT);
1408}
1409
1419static int
1420add_tls_to_mainloop(lrmd_t *lrmd, bool do_handshake)
1421{
1422 lrmd_private_t *native = lrmd->lrmd_private;
1423 int rc = pcmk_rc_ok;
1424
1425 char *name = crm_strdup_printf("pacemaker-remote-%s:%d",
1426 native->server, native->port);
1427
1428 struct mainloop_fd_callbacks tls_fd_callbacks = {
1429 .dispatch = lrmd_tls_dispatch,
1430 .destroy = lrmd_tls_connection_destroy,
1431 };
1432
1433 native->process_notify = mainloop_add_trigger(G_PRIORITY_HIGH,
1434 lrmd_tls_dispatch, lrmd);
1435 native->source = mainloop_add_fd(name, G_PRIORITY_HIGH, native->sock, lrmd,
1436 &tls_fd_callbacks);
1437
1438 /* Async connections lose the client name provided by the API caller, so we
1439 * have to use our generated name here to perform the executor handshake.
1440 *
1441 * @TODO Keep track of the caller-provided name. Perhaps we should be using
1442 * that name in this function instead of generating one anyway.
1443 */
1444 if (do_handshake) {
1445 rc = lrmd_handshake(lrmd, name);
1446 rc = pcmk_legacy2rc(rc);
1447 }
1448 free(name);
1449 return rc;
1450}
1451
1452static void
1453lrmd_tcp_connect_cb(void *userdata, int rc, int sock)
1454{
1455 lrmd_t *lrmd = userdata;
1456 lrmd_private_t *native = lrmd->lrmd_private;
1457 gnutls_datum_t psk_key = { NULL, 0 };
1458
1459 native->async_timer = 0;
1460
1461 if (rc != pcmk_rc_ok) {
1462 lrmd_tls_connection_destroy(lrmd);
1463 crm_info("Could not connect to Pacemaker Remote at %s:%d: %s "
1464 CRM_XS " rc=%d",
1465 native->server, native->port, pcmk_rc_str(rc), rc);
1466 report_async_connection_result(lrmd, pcmk_rc2legacy(rc));
1467 return;
1468 }
1469
1470 /* The TCP connection was successful, so establish the TLS connection.
1471 * @TODO make this async to avoid blocking code in client
1472 */
1473
1474 native->sock = sock;
1475
1476 rc = lrmd__init_remote_key(&psk_key);
1477 if (rc != pcmk_rc_ok) {
1478 crm_info("Could not connect to Pacemaker Remote at %s:%d: %s "
1479 CRM_XS " rc=%d",
1480 native->server, native->port, pcmk_rc_str(rc), rc);
1481 lrmd_tls_connection_destroy(lrmd);
1482 report_async_connection_result(lrmd, pcmk_rc2legacy(rc));
1483 return;
1484 }
1485
1486 gnutls_psk_allocate_client_credentials(&native->psk_cred_c);
1487 gnutls_psk_set_client_credentials(native->psk_cred_c, DEFAULT_REMOTE_USERNAME, &psk_key, GNUTLS_PSK_KEY_RAW);
1488 gnutls_free(psk_key.data);
1489
1490 native->remote->tls_session = pcmk__new_tls_session(sock, GNUTLS_CLIENT,
1491 GNUTLS_CRD_PSK,
1492 native->psk_cred_c);
1493 if (native->remote->tls_session == NULL) {
1494 lrmd_tls_connection_destroy(lrmd);
1495 report_async_connection_result(lrmd, -EPROTO);
1496 return;
1497 }
1498
1499 if (lrmd__tls_client_handshake(native->remote) != pcmk_rc_ok) {
1500 crm_warn("Disconnecting after TLS handshake with Pacemaker Remote server %s:%d failed",
1501 native->server, native->port);
1502 gnutls_deinit(*native->remote->tls_session);
1503 gnutls_free(native->remote->tls_session);
1504 native->remote->tls_session = NULL;
1505 lrmd_tls_connection_destroy(lrmd);
1506 report_async_connection_result(lrmd, -EKEYREJECTED);
1507 return;
1508 }
1509
1510 crm_info("TLS connection to Pacemaker Remote server %s:%d succeeded",
1511 native->server, native->port);
1512 rc = add_tls_to_mainloop(lrmd, true);
1513 report_async_connection_result(lrmd, pcmk_rc2legacy(rc));
1514}
1515
1516static int
1517lrmd_tls_connect_async(lrmd_t * lrmd, int timeout /*ms */ )
1518{
1519 int rc;
1520 int timer_id = 0;
1521 lrmd_private_t *native = lrmd->lrmd_private;
1522
1523 lrmd_gnutls_global_init();
1524 native->sock = -1;
1525 rc = pcmk__connect_remote(native->server, native->port, timeout, &timer_id,
1526 &(native->sock), lrmd, lrmd_tcp_connect_cb);
1527 if (rc != pcmk_rc_ok) {
1528 crm_warn("Pacemaker Remote connection to %s:%d failed: %s "
1529 CRM_XS " rc=%d",
1530 native->server, native->port, pcmk_rc_str(rc), rc);
1531 return pcmk_rc2legacy(rc);
1532 }
1533 native->async_timer = timer_id;
1534 return pcmk_ok;
1535}
1536
1537static int
1538lrmd_tls_connect(lrmd_t * lrmd, int *fd)
1539{
1540 int rc;
1541
1542 lrmd_private_t *native = lrmd->lrmd_private;
1543 gnutls_datum_t psk_key = { NULL, 0 };
1544
1545 lrmd_gnutls_global_init();
1546
1547 native->sock = -1;
1548 rc = pcmk__connect_remote(native->server, native->port, 0, NULL,
1549 &(native->sock), NULL, NULL);
1550 if (rc != pcmk_rc_ok) {
1551 crm_warn("Pacemaker Remote connection to %s:%d failed: %s "
1552 CRM_XS " rc=%d",
1553 native->server, native->port, pcmk_rc_str(rc), rc);
1554 lrmd_tls_connection_destroy(lrmd);
1555 return -ENOTCONN;
1556 }
1557
1558 rc = lrmd__init_remote_key(&psk_key);
1559 if (rc != pcmk_rc_ok) {
1560 lrmd_tls_connection_destroy(lrmd);
1561 return pcmk_rc2legacy(rc);
1562 }
1563
1564 gnutls_psk_allocate_client_credentials(&native->psk_cred_c);
1565 gnutls_psk_set_client_credentials(native->psk_cred_c, DEFAULT_REMOTE_USERNAME, &psk_key, GNUTLS_PSK_KEY_RAW);
1566 gnutls_free(psk_key.data);
1567
1568 native->remote->tls_session = pcmk__new_tls_session(native->sock, GNUTLS_CLIENT,
1569 GNUTLS_CRD_PSK,
1570 native->psk_cred_c);
1571 if (native->remote->tls_session == NULL) {
1572 lrmd_tls_connection_destroy(lrmd);
1573 return -EPROTO;
1574 }
1575
1576 if (lrmd__tls_client_handshake(native->remote) != pcmk_rc_ok) {
1577 crm_err("Session creation for %s:%d failed", native->server, native->port);
1578 gnutls_deinit(*native->remote->tls_session);
1579 gnutls_free(native->remote->tls_session);
1580 native->remote->tls_session = NULL;
1581 lrmd_tls_connection_destroy(lrmd);
1582 return -EKEYREJECTED;
1583 }
1584
1585 crm_info("Client TLS connection established with Pacemaker Remote server %s:%d", native->server,
1586 native->port);
1587
1588 if (fd) {
1589 *fd = native->sock;
1590 } else {
1591 add_tls_to_mainloop(lrmd, false);
1592 }
1593 return pcmk_ok;
1594}
1595#endif
1596
1597static int
1598lrmd_api_connect(lrmd_t * lrmd, const char *name, int *fd)
1599{
1600 int rc = -ENOTCONN;
1601 lrmd_private_t *native = lrmd->lrmd_private;
1602
1603 switch (native->type) {
1604 case pcmk__client_ipc:
1605 rc = lrmd_ipc_connect(lrmd, fd);
1606 break;
1607#ifdef HAVE_GNUTLS_GNUTLS_H
1608 case pcmk__client_tls:
1609 rc = lrmd_tls_connect(lrmd, fd);
1610 break;
1611#endif
1612 default:
1613 crm_err("Unsupported executor connection type (bug?): %d",
1614 native->type);
1615 rc = -EPROTONOSUPPORT;
1616 }
1617
1618 if (rc == pcmk_ok) {
1619 rc = lrmd_handshake(lrmd, name);
1620 }
1621
1622 return rc;
1623}
1624
1625static int
1626lrmd_api_connect_async(lrmd_t * lrmd, const char *name, int timeout)
1627{
1628 int rc = pcmk_ok;
1629 lrmd_private_t *native = lrmd->lrmd_private;
1630
1631 CRM_CHECK(native && native->callback, return -EINVAL);
1632
1633 switch (native->type) {
1634 case pcmk__client_ipc:
1635 /* fake async connection with ipc. it should be fast
1636 * enough that we gain very little from async */
1637 rc = lrmd_api_connect(lrmd, name, NULL);
1638 if (!rc) {
1639 report_async_connection_result(lrmd, rc);
1640 }
1641 break;
1642#ifdef HAVE_GNUTLS_GNUTLS_H
1643 case pcmk__client_tls:
1644 rc = lrmd_tls_connect_async(lrmd, timeout);
1645 if (rc) {
1646 /* connection failed, report rc now */
1647 report_async_connection_result(lrmd, rc);
1648 }
1649 break;
1650#endif
1651 default:
1652 crm_err("Unsupported executor connection type (bug?): %d",
1653 native->type);
1654 rc = -EPROTONOSUPPORT;
1655 }
1656
1657 return rc;
1658}
1659
1660static void
1661lrmd_ipc_disconnect(lrmd_t * lrmd)
1662{
1663 lrmd_private_t *native = lrmd->lrmd_private;
1664
1665 if (native->source != NULL) {
1666 /* Attached to mainloop */
1667 mainloop_del_ipc_client(native->source);
1668 native->source = NULL;
1669 native->ipc = NULL;
1670
1671 } else if (native->ipc) {
1672 /* Not attached to mainloop */
1673 crm_ipc_t *ipc = native->ipc;
1674
1675 native->ipc = NULL;
1676 crm_ipc_close(ipc);
1677 crm_ipc_destroy(ipc);
1678 }
1679}
1680
1681#ifdef HAVE_GNUTLS_GNUTLS_H
1682static void
1683lrmd_tls_disconnect(lrmd_t * lrmd)
1684{
1685 lrmd_private_t *native = lrmd->lrmd_private;
1686
1687 if (native->remote->tls_session) {
1688 gnutls_bye(*native->remote->tls_session, GNUTLS_SHUT_RDWR);
1689 gnutls_deinit(*native->remote->tls_session);
1690 gnutls_free(native->remote->tls_session);
1691 native->remote->tls_session = NULL;
1692 }
1693
1694 if (native->async_timer) {
1695 g_source_remove(native->async_timer);
1696 native->async_timer = 0;
1697 }
1698
1699 if (native->source != NULL) {
1700 /* Attached to mainloop */
1701 mainloop_del_ipc_client(native->source);
1702 native->source = NULL;
1703
1704 } else if (native->sock) {
1705 close(native->sock);
1706 native->sock = 0;
1707 }
1708
1709 if (native->pending_notify) {
1710 g_list_free_full(native->pending_notify, lrmd_free_xml);
1711 native->pending_notify = NULL;
1712 }
1713}
1714#endif
1715
1716static int
1717lrmd_api_disconnect(lrmd_t * lrmd)
1718{
1719 lrmd_private_t *native = lrmd->lrmd_private;
1720 int rc = pcmk_ok;
1721
1722 switch (native->type) {
1723 case pcmk__client_ipc:
1724 crm_debug("Disconnecting from local executor");
1725 lrmd_ipc_disconnect(lrmd);
1726 break;
1727#ifdef HAVE_GNUTLS_GNUTLS_H
1728 case pcmk__client_tls:
1729 crm_debug("Disconnecting from remote executor on %s",
1730 native->remote_nodename);
1731 lrmd_tls_disconnect(lrmd);
1732 break;
1733#endif
1734 default:
1735 crm_err("Unsupported executor connection type (bug?): %d",
1736 native->type);
1737 rc = -EPROTONOSUPPORT;
1738 }
1739
1740 free(native->token);
1741 native->token = NULL;
1742
1743 free(native->peer_version);
1744 native->peer_version = NULL;
1745 return rc;
1746}
1747
1748static int
1749lrmd_api_register_rsc(lrmd_t * lrmd,
1750 const char *rsc_id,
1751 const char *class,
1752 const char *provider, const char *type, enum lrmd_call_options options)
1753{
1754 int rc = pcmk_ok;
1755 xmlNode *data = NULL;
1756
1757 if (!class || !type || !rsc_id) {
1758 return -EINVAL;
1759 }
1761 && (provider == NULL)) {
1762 return -EINVAL;
1763 }
1764
1766
1772 rc = lrmd_send_command(lrmd, LRMD_OP_RSC_REG, data, NULL, 0, options, TRUE);
1773 free_xml(data);
1774
1775 return rc;
1776}
1777
1778static int
1779lrmd_api_unregister_rsc(lrmd_t * lrmd, const char *rsc_id, enum lrmd_call_options options)
1780{
1781 int rc = pcmk_ok;
1782 xmlNode *data = pcmk__xe_create(NULL, PCMK__XE_LRMD_RSC);
1783
1786 rc = lrmd_send_command(lrmd, LRMD_OP_RSC_UNREG, data, NULL, 0, options, TRUE);
1787 free_xml(data);
1788
1789 return rc;
1790}
1791
1793lrmd_new_rsc_info(const char *rsc_id, const char *standard,
1794 const char *provider, const char *type)
1795{
1796 lrmd_rsc_info_t *rsc_info = pcmk__assert_alloc(1, sizeof(lrmd_rsc_info_t));
1797
1798 rsc_info->id = pcmk__str_copy(rsc_id);
1799 rsc_info->standard = pcmk__str_copy(standard);
1800 rsc_info->provider = pcmk__str_copy(provider);
1801 rsc_info->type = pcmk__str_copy(type);
1802 return rsc_info;
1803}
1804
1807{
1808 return lrmd_new_rsc_info(rsc_info->id, rsc_info->standard,
1809 rsc_info->provider, rsc_info->type);
1810}
1811
1812void
1814{
1815 if (!rsc_info) {
1816 return;
1817 }
1818 free(rsc_info->id);
1819 free(rsc_info->type);
1820 free(rsc_info->standard);
1821 free(rsc_info->provider);
1822 free(rsc_info);
1823}
1824
1825static lrmd_rsc_info_t *
1826lrmd_api_get_rsc_info(lrmd_t * lrmd, const char *rsc_id, enum lrmd_call_options options)
1827{
1828 lrmd_rsc_info_t *rsc_info = NULL;
1829 xmlNode *data = pcmk__xe_create(NULL, PCMK__XE_LRMD_RSC);
1830 xmlNode *output = NULL;
1831 const char *class = NULL;
1832 const char *provider = NULL;
1833 const char *type = NULL;
1834
1837 lrmd_send_command(lrmd, LRMD_OP_RSC_INFO, data, &output, 0, options, TRUE);
1838 free_xml(data);
1839
1840 if (!output) {
1841 return NULL;
1842 }
1843
1844 class = crm_element_value(output, PCMK__XA_LRMD_CLASS);
1845 provider = crm_element_value(output, PCMK__XA_LRMD_PROVIDER);
1847
1848 if (!class || !type) {
1849 free_xml(output);
1850 return NULL;
1852 && !provider) {
1853 free_xml(output);
1854 return NULL;
1855 }
1856
1857 rsc_info = lrmd_new_rsc_info(rsc_id, class, provider, type);
1858 free_xml(output);
1859 return rsc_info;
1860}
1861
1862void
1864{
1865 if (op_info) {
1866 free(op_info->rsc_id);
1867 free(op_info->action);
1868 free(op_info->interval_ms_s);
1869 free(op_info->timeout_ms_s);
1870 free(op_info);
1871 }
1872}
1873
1874static int
1875lrmd_api_get_recurring_ops(lrmd_t *lrmd, const char *rsc_id, int timeout_ms,
1876 enum lrmd_call_options options, GList **output)
1877{
1878 xmlNode *data = NULL;
1879 xmlNode *output_xml = NULL;
1880 int rc = pcmk_ok;
1881
1882 if (output == NULL) {
1883 return -EINVAL;
1884 }
1885 *output = NULL;
1886
1887 // Send request
1888 if (rsc_id) {
1892 }
1893 rc = lrmd_send_command(lrmd, LRMD_OP_GET_RECURRING, data, &output_xml,
1894 timeout_ms, options, TRUE);
1895 if (data) {
1896 free_xml(data);
1897 }
1898
1899 // Process reply
1900 if ((rc != pcmk_ok) || (output_xml == NULL)) {
1901 return rc;
1902 }
1903 for (const xmlNode *rsc_xml = pcmk__xe_first_child(output_xml,
1904 PCMK__XE_LRMD_RSC, NULL,
1905 NULL);
1906 (rsc_xml != NULL) && (rc == pcmk_ok);
1907 rsc_xml = pcmk__xe_next_same(rsc_xml)) {
1908
1909 rsc_id = crm_element_value(rsc_xml, PCMK__XA_LRMD_RSC_ID);
1910 if (rsc_id == NULL) {
1911 crm_err("Could not parse recurring operation information from executor");
1912 continue;
1913 }
1914 for (const xmlNode *op_xml = pcmk__xe_first_child(rsc_xml,
1916 NULL, NULL);
1917 op_xml != NULL; op_xml = pcmk__xe_next_same(op_xml)) {
1918
1919 lrmd_op_info_t *op_info = calloc(1, sizeof(lrmd_op_info_t));
1920
1921 if (op_info == NULL) {
1922 rc = -ENOMEM;
1923 break;
1924 }
1925 op_info->rsc_id = strdup(rsc_id);
1926 op_info->action = crm_element_value_copy(op_xml,
1928 op_info->interval_ms_s =
1930 op_info->timeout_ms_s =
1932 *output = g_list_prepend(*output, op_info);
1933 }
1934 }
1935 free_xml(output_xml);
1936 return rc;
1937}
1938
1939
1940static void
1941lrmd_api_set_callback(lrmd_t * lrmd, lrmd_event_callback callback)
1942{
1943 lrmd_private_t *native = lrmd->lrmd_private;
1944
1945 native->callback = callback;
1946}
1947
1948void
1949lrmd_internal_set_proxy_callback(lrmd_t * lrmd, void *userdata, void (*callback)(lrmd_t *lrmd, void *userdata, xmlNode *msg))
1950{
1951 lrmd_private_t *native = lrmd->lrmd_private;
1952
1953 native->proxy_callback = callback;
1954 native->proxy_callback_userdata = userdata;
1955}
1956
1957void
1958lrmd_internal_proxy_dispatch(lrmd_t *lrmd, xmlNode *msg)
1959{
1960 lrmd_private_t *native = lrmd->lrmd_private;
1961
1962 if (native->proxy_callback) {
1963 crm_log_xml_trace(msg, "PROXY_INBOUND");
1964 native->proxy_callback(lrmd, native->proxy_callback_userdata, msg);
1965 }
1966}
1967
1968int
1970{
1971 if (lrmd == NULL) {
1972 return -ENOTCONN;
1973 }
1975
1976 crm_log_xml_trace(msg, "PROXY_OUTBOUND");
1977 return lrmd_send_xml_no_reply(lrmd, msg);
1978}
1979
1980static int
1981stonith_get_metadata(const char *provider, const char *type, char **output)
1982{
1983 int rc = pcmk_ok;
1984 stonith_t *stonith_api = stonith_api_new();
1985
1986 if (stonith_api == NULL) {
1987 crm_err("Could not get fence agent meta-data: API memory allocation failed");
1988 return -ENOMEM;
1989 }
1990
1991 rc = stonith_api->cmds->metadata(stonith_api, st_opt_sync_call, type,
1992 provider, output, 0);
1993 if ((rc == pcmk_ok) && (*output == NULL)) {
1994 rc = -EIO;
1995 }
1996 stonith_api->cmds->free(stonith_api);
1997 return rc;
1998}
1999
2000static int
2001lrmd_api_get_metadata(lrmd_t *lrmd, const char *standard, const char *provider,
2002 const char *type, char **output,
2003 enum lrmd_call_options options)
2004{
2005 return lrmd->cmds->get_metadata_params(lrmd, standard, provider, type,
2006 output, options, NULL);
2007}
2008
2009static int
2010lrmd_api_get_metadata_params(lrmd_t *lrmd, const char *standard,
2011 const char *provider, const char *type,
2012 char **output, enum lrmd_call_options options,
2013 lrmd_key_value_t *params)
2014{
2015 svc_action_t *action = NULL;
2016 GHashTable *params_table = NULL;
2017
2018 if (!standard || !type) {
2019 lrmd_key_value_freeall(params);
2020 return -EINVAL;
2021 }
2022
2023 if (pcmk__str_eq(standard, PCMK_RESOURCE_CLASS_STONITH, pcmk__str_casei)) {
2024 lrmd_key_value_freeall(params);
2025 return stonith_get_metadata(provider, type, output);
2026 }
2027
2028 params_table = pcmk__strkey_table(free, free);
2029 for (const lrmd_key_value_t *param = params; param; param = param->next) {
2030 pcmk__insert_dup(params_table, param->key, param->value);
2031 }
2032 action = services__create_resource_action(type, standard, provider, type,
2035 params_table, 0);
2036 lrmd_key_value_freeall(params);
2037
2038 if (action == NULL) {
2039 return -ENOMEM;
2040 }
2041 if (action->rc != PCMK_OCF_UNKNOWN) {
2043 return -EINVAL;
2044 }
2045
2047 crm_err("Failed to retrieve meta-data for %s:%s:%s",
2048 standard, provider, type);
2050 return -EIO;
2051 }
2052
2053 if (!action->stdout_data) {
2054 crm_err("Failed to receive meta-data for %s:%s:%s",
2055 standard, provider, type);
2057 return -EIO;
2058 }
2059
2060 *output = strdup(action->stdout_data);
2062
2063 return pcmk_ok;
2064}
2065
2066static int
2067lrmd_api_exec(lrmd_t *lrmd, const char *rsc_id, const char *action,
2068 const char *userdata, guint interval_ms,
2069 int timeout, /* ms */
2070 int start_delay, /* ms */
2071 enum lrmd_call_options options, lrmd_key_value_t * params)
2072{
2073 int rc = pcmk_ok;
2074 xmlNode *data = pcmk__xe_create(NULL, PCMK__XE_LRMD_RSC);
2075 xmlNode *args = pcmk__xe_create(data, PCMK__XE_ATTRIBUTES);
2076 lrmd_key_value_t *tmp = NULL;
2077
2085
2086 for (tmp = params; tmp; tmp = tmp->next) {
2087 hash2smartfield((gpointer) tmp->key, (gpointer) tmp->value, args);
2088 }
2089
2090 rc = lrmd_send_command(lrmd, LRMD_OP_RSC_EXEC, data, NULL, timeout, options, TRUE);
2091 free_xml(data);
2092
2093 lrmd_key_value_freeall(params);
2094 return rc;
2095}
2096
2097/* timeout is in ms */
2098static int
2099lrmd_api_exec_alert(lrmd_t *lrmd, const char *alert_id, const char *alert_path,
2100 int timeout, lrmd_key_value_t *params)
2101{
2102 int rc = pcmk_ok;
2103 xmlNode *data = pcmk__xe_create(NULL, PCMK__XE_LRMD_ALERT);
2104 xmlNode *args = pcmk__xe_create(data, PCMK__XE_ATTRIBUTES);
2105 lrmd_key_value_t *tmp = NULL;
2106
2111
2112 for (tmp = params; tmp; tmp = tmp->next) {
2113 hash2smartfield((gpointer) tmp->key, (gpointer) tmp->value, args);
2114 }
2115
2116 rc = lrmd_send_command(lrmd, LRMD_OP_ALERT_EXEC, data, NULL, timeout,
2118 free_xml(data);
2119
2120 lrmd_key_value_freeall(params);
2121 return rc;
2122}
2123
2124static int
2125lrmd_api_cancel(lrmd_t *lrmd, const char *rsc_id, const char *action,
2126 guint interval_ms)
2127{
2128 int rc = pcmk_ok;
2129 xmlNode *data = pcmk__xe_create(NULL, PCMK__XE_LRMD_RSC);
2130
2135 rc = lrmd_send_command(lrmd, LRMD_OP_RSC_CANCEL, data, NULL, 0, 0, TRUE);
2136 free_xml(data);
2137 return rc;
2138}
2139
2140static int
2141list_stonith_agents(lrmd_list_t ** resources)
2142{
2143 int rc = 0;
2144 stonith_t *stonith_api = stonith_api_new();
2145 stonith_key_value_t *stonith_resources = NULL;
2146 stonith_key_value_t *dIter = NULL;
2147
2148 if (stonith_api == NULL) {
2149 crm_err("Could not list fence agents: API memory allocation failed");
2150 return -ENOMEM;
2151 }
2152 stonith_api->cmds->list_agents(stonith_api, st_opt_sync_call, NULL,
2153 &stonith_resources, 0);
2154 stonith_api->cmds->free(stonith_api);
2155
2156 for (dIter = stonith_resources; dIter; dIter = dIter->next) {
2157 rc++;
2158 if (resources) {
2159 *resources = lrmd_list_add(*resources, dIter->value);
2160 }
2161 }
2162
2163 stonith_key_value_freeall(stonith_resources, 1, 0);
2164 return rc;
2165}
2166
2167static int
2168lrmd_api_list_agents(lrmd_t * lrmd, lrmd_list_t ** resources, const char *class,
2169 const char *provider)
2170{
2171 int rc = 0;
2172 int stonith_count = 0; // Initially, whether to include stonith devices
2173
2174 if (pcmk__str_eq(class, PCMK_RESOURCE_CLASS_STONITH, pcmk__str_casei)) {
2175 stonith_count = 1;
2176
2177 } else {
2178 GList *gIter = NULL;
2179 GList *agents = resources_list_agents(class, provider);
2180
2181 for (gIter = agents; gIter != NULL; gIter = gIter->next) {
2182 *resources = lrmd_list_add(*resources, (const char *)gIter->data);
2183 rc++;
2184 }
2185 g_list_free_full(agents, free);
2186
2187 if (!class) {
2188 stonith_count = 1;
2189 }
2190 }
2191
2192 if (stonith_count) {
2193 // Now, if stonith devices are included, how many there are
2194 stonith_count = list_stonith_agents(resources);
2195 if (stonith_count > 0) {
2196 rc += stonith_count;
2197 }
2198 }
2199 if (rc == 0) {
2200 crm_notice("No agents found for class %s", class);
2201 rc = -EPROTONOSUPPORT;
2202 }
2203 return rc;
2204}
2205
2206static bool
2207does_provider_have_agent(const char *agent, const char *provider, const char *class)
2208{
2209 bool found = false;
2210 GList *agents = NULL;
2211 GList *gIter2 = NULL;
2212
2213 agents = resources_list_agents(class, provider);
2214 for (gIter2 = agents; gIter2 != NULL; gIter2 = gIter2->next) {
2215 if (pcmk__str_eq(agent, gIter2->data, pcmk__str_casei)) {
2216 found = true;
2217 }
2218 }
2219 g_list_free_full(agents, free);
2220 return found;
2221}
2222
2223static int
2224lrmd_api_list_ocf_providers(lrmd_t * lrmd, const char *agent, lrmd_list_t ** providers)
2225{
2226 int rc = pcmk_ok;
2227 char *provider = NULL;
2228 GList *ocf_providers = NULL;
2229 GList *gIter = NULL;
2230
2232
2233 for (gIter = ocf_providers; gIter != NULL; gIter = gIter->next) {
2234 provider = gIter->data;
2235 if (!agent || does_provider_have_agent(agent, provider,
2237 *providers = lrmd_list_add(*providers, (const char *)gIter->data);
2238 rc++;
2239 }
2240 }
2241
2242 g_list_free_full(ocf_providers, free);
2243 return rc;
2244}
2245
2246static int
2247lrmd_api_list_standards(lrmd_t * lrmd, lrmd_list_t ** supported)
2248{
2249 int rc = 0;
2250 GList *standards = NULL;
2251 GList *gIter = NULL;
2252
2253 standards = resources_list_standards();
2254
2255 for (gIter = standards; gIter != NULL; gIter = gIter->next) {
2256 *supported = lrmd_list_add(*supported, (const char *)gIter->data);
2257 rc++;
2258 }
2259
2260 if (list_stonith_agents(NULL) > 0) {
2261 *supported = lrmd_list_add(*supported, PCMK_RESOURCE_CLASS_STONITH);
2262 rc++;
2263 }
2264
2265 g_list_free_full(standards, free);
2266 return rc;
2267}
2268
2288int
2289lrmd__new(lrmd_t **api, const char *nodename, const char *server, int port)
2290{
2291 lrmd_private_t *pvt = NULL;
2292
2293 if (api == NULL) {
2294 return EINVAL;
2295 }
2296 *api = NULL;
2297
2298 // Allocate all memory needed
2299
2300 *api = calloc(1, sizeof(lrmd_t));
2301 if (*api == NULL) {
2302 return ENOMEM;
2303 }
2304
2305 pvt = calloc(1, sizeof(lrmd_private_t));
2306 if (pvt == NULL) {
2307 lrmd_api_delete(*api);
2308 *api = NULL;
2309 return ENOMEM;
2310 }
2311 (*api)->lrmd_private = pvt;
2312
2313 // @TODO Do we need to do this for local connections?
2314 pvt->remote = calloc(1, sizeof(pcmk__remote_t));
2315
2316 (*api)->cmds = calloc(1, sizeof(lrmd_api_operations_t));
2317
2318 if ((pvt->remote == NULL) || ((*api)->cmds == NULL)) {
2319 lrmd_api_delete(*api);
2320 *api = NULL;
2321 return ENOMEM;
2322 }
2323
2324 // Set methods
2325 (*api)->cmds->connect = lrmd_api_connect;
2326 (*api)->cmds->connect_async = lrmd_api_connect_async;
2327 (*api)->cmds->is_connected = lrmd_api_is_connected;
2328 (*api)->cmds->poke_connection = lrmd_api_poke_connection;
2329 (*api)->cmds->disconnect = lrmd_api_disconnect;
2330 (*api)->cmds->register_rsc = lrmd_api_register_rsc;
2331 (*api)->cmds->unregister_rsc = lrmd_api_unregister_rsc;
2332 (*api)->cmds->get_rsc_info = lrmd_api_get_rsc_info;
2333 (*api)->cmds->get_recurring_ops = lrmd_api_get_recurring_ops;
2334 (*api)->cmds->set_callback = lrmd_api_set_callback;
2335 (*api)->cmds->get_metadata = lrmd_api_get_metadata;
2336 (*api)->cmds->exec = lrmd_api_exec;
2337 (*api)->cmds->cancel = lrmd_api_cancel;
2338 (*api)->cmds->list_agents = lrmd_api_list_agents;
2339 (*api)->cmds->list_ocf_providers = lrmd_api_list_ocf_providers;
2340 (*api)->cmds->list_standards = lrmd_api_list_standards;
2341 (*api)->cmds->exec_alert = lrmd_api_exec_alert;
2342 (*api)->cmds->get_metadata_params = lrmd_api_get_metadata_params;
2343
2344 if ((nodename == NULL) && (server == NULL)) {
2345 pvt->type = pcmk__client_ipc;
2346 } else {
2347#ifdef HAVE_GNUTLS_GNUTLS_H
2348 if (nodename == NULL) {
2349 nodename = server;
2350 } else if (server == NULL) {
2351 server = nodename;
2352 }
2353 pvt->type = pcmk__client_tls;
2354 pvt->remote_nodename = strdup(nodename);
2355 pvt->server = strdup(server);
2356 if ((pvt->remote_nodename == NULL) || (pvt->server == NULL)) {
2357 lrmd_api_delete(*api);
2358 *api = NULL;
2359 return ENOMEM;
2360 }
2361 pvt->port = port;
2362 if (pvt->port == 0) {
2363 pvt->port = crm_default_remote_port();
2364 }
2365#else
2366 crm_err("Cannot communicate with Pacemaker Remote "
2367 "because GnuTLS is not enabled for this build");
2368 lrmd_api_delete(*api);
2369 *api = NULL;
2370 return EOPNOTSUPP;
2371#endif
2372 }
2373 return pcmk_rc_ok;
2374}
2375
2376lrmd_t *
2378{
2379 lrmd_t *api = NULL;
2380
2381 CRM_ASSERT(lrmd__new(&api, NULL, NULL, 0) == pcmk_rc_ok);
2382 return api;
2383}
2384
2385lrmd_t *
2386lrmd_remote_api_new(const char *nodename, const char *server, int port)
2387{
2388 lrmd_t *api = NULL;
2389
2390 CRM_ASSERT(lrmd__new(&api, nodename, server, port) == pcmk_rc_ok);
2391 return api;
2392}
2393
2394void
2396{
2397 if (lrmd == NULL) {
2398 return;
2399 }
2400 if (lrmd->cmds != NULL) { // Never NULL, but make static analysis happy
2401 if (lrmd->cmds->disconnect != NULL) { // Also never really NULL
2402 lrmd->cmds->disconnect(lrmd); // No-op if already disconnected
2403 }
2404 free(lrmd->cmds);
2405 }
2406 if (lrmd->lrmd_private != NULL) {
2407 lrmd_private_t *native = lrmd->lrmd_private;
2408
2409#ifdef HAVE_GNUTLS_GNUTLS_H
2410 free(native->server);
2411#endif
2412 free(native->remote_nodename);
2413 free(native->remote);
2414 free(native->token);
2415 free(native->peer_version);
2416 free(lrmd->lrmd_private);
2417 }
2418 free(lrmd);
2419}
2420
2421struct metadata_cb {
2422 void (*callback)(int pid, const pcmk__action_result_t *result,
2423 void *user_data);
2424 void *user_data;
2425};
2426
2433static void
2434metadata_complete(svc_action_t *action)
2435{
2436 struct metadata_cb *metadata_cb = (struct metadata_cb *) action->cb_data;
2438
2439 pcmk__set_result(&result, action->rc, action->status,
2441 pcmk__set_result_output(&result, action->stdout_data, action->stderr_data);
2442
2443 metadata_cb->callback(0, &result, metadata_cb->user_data);
2444 result.action_stdout = NULL; // Prevent free, because action owns it
2445 result.action_stderr = NULL; // Prevent free, because action owns it
2447 free(metadata_cb);
2448}
2449
2466int
2468 void (*callback)(int pid,
2470 void *user_data),
2471 void *user_data)
2472{
2473 svc_action_t *action = NULL;
2474 struct metadata_cb *metadata_cb = NULL;
2476
2477 CRM_CHECK(callback != NULL, return EINVAL);
2478
2479 if ((rsc == NULL) || (rsc->standard == NULL) || (rsc->type == NULL)) {
2482 "Invalid resource specification");
2483 callback(0, &result, user_data);
2485 return EINVAL;
2486 }
2487
2488 if (strcmp(rsc->standard, PCMK_RESOURCE_CLASS_STONITH) == 0) {
2489 return stonith__metadata_async(rsc->type,
2491 callback, user_data);
2492 }
2493
2494 action = services__create_resource_action(pcmk__s(rsc->id, rsc->type),
2495 rsc->standard, rsc->provider,
2496 rsc->type,
2499 NULL, 0);
2500 if (action == NULL) {
2502 "Out of memory");
2503 callback(0, &result, user_data);
2505 return ENOMEM;
2506 }
2507 if (action->rc != PCMK_OCF_UNKNOWN) {
2508 pcmk__set_result(&result, action->rc, action->status,
2510 callback(0, &result, user_data);
2513 return EINVAL;
2514 }
2515
2516 action->cb_data = calloc(1, sizeof(struct metadata_cb));
2517 if (action->cb_data == NULL) {
2520 "Out of memory");
2521 callback(0, &result, user_data);
2523 return ENOMEM;
2524 }
2525
2526 metadata_cb = (struct metadata_cb *) action->cb_data;
2527 metadata_cb->callback = callback;
2528 metadata_cb->user_data = user_data;
2529 if (!services_action_async(action, metadata_complete)) {
2531 return pcmk_rc_error; // @TODO Derive from action->rc and ->status
2532 }
2533
2534 // The services library has taken responsibility for action
2535 return pcmk_rc_ok;
2536}
2537
2547void
2549 const char *exit_reason)
2550{
2551 if (event == NULL) {
2552 return;
2553 }
2554
2555 event->rc = rc;
2556 event->op_status = op_status;
2557
2558 // lrmd_event_data_t has (const char *) members that lrmd_free_event() frees
2559 pcmk__str_update((char **) &event->exit_reason, exit_reason);
2560}
2561
2568void
2570{
2571 if (event == NULL) {
2572 return;
2573 }
2574
2575 free((void *) event->exit_reason);
2576 event->exit_reason = NULL;
2577
2578 free((void *) event->output);
2579 event->output = NULL;
2580}
2581
2592time_t
2594{
2595 lrmd_private_t *native = lrmd->lrmd_private;
2596
2597 if (native->remote == NULL) {
2598 return -1;
2599 } else {
2600 return native->remote->uptime;
2601 }
2602}
2603
2604const char *
2606{
2607 lrmd_private_t *native = lrmd->lrmd_private;
2608
2609 if (native->remote == NULL) {
2610 return NULL;
2611 } else {
2612 return native->remote->start_state;
2613 }
2614}
#define PCMK_ACTION_META_DATA
Definition actions.h:56
#define PCMK_DEFAULT_METADATA_TIMEOUT_MS
Definition actions.h:42
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:31
#define PCMK_RESOURCE_CLASS_OCF
Definition agents.h:27
@ pcmk_ra_cap_provider
Definition agents.h:59
const char * name
Definition cib.c:26
void pcmk__xe_set_bool_attr(xmlNodePtr node, const char *name, bool value)
Definition nvpair.c:903
#define pcmk__assert_alloc(nmemb, size)
Definition internal.h:297
uint32_t version
Definition remote.c:1
int pcmk__remote_ready(const pcmk__remote_t *remote, int timeout_ms)
Definition remote.c:640
int pcmk__remote_send_xml(pcmk__remote_t *remote, const xmlNode *msg)
Definition remote.c:492
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:1070
xmlNode * pcmk__remote_message_xml(pcmk__remote_t *remote)
Definition remote.c:545
int pcmk__read_remote_message(pcmk__remote_t *remote, int timeout_ms)
Definition remote.c:798
int crm_default_remote_port(void)
Get the default remote connection TCP port on this host.
Definition remote.c:1265
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:100
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 CRM_OP_IPC_FWD
Definition crm.h:130
#define CRM_OP_REGISTER
Definition crm.h:129
#define CRM_SYSTEM_LRMD
Definition crm.h:91
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:2463
gboolean stonith__watchdog_fencing_enabled_for_node(const char *node)
Definition st_client.c:231
void crm_ipc_destroy(crm_ipc_t *client)
int crm_ipc_send(crm_ipc_t *client, const xmlNode *message, enum crm_ipc_flags flags, int32_t ms_timeout, xmlNode **reply)
Send an IPC XML message.
long crm_ipc_read(crm_ipc_t *client)
@ crm_ipc_flags_none
Definition ipc.h:165
@ crm_ipc_client_response
Definition ipc.h:170
int crm_ipc_ready(crm_ipc_t *client)
Check whether an IPC connection is ready to be read.
bool crm_ipc_connected(crm_ipc_t *client)
void crm_ipc_close(crm_ipc_t *client)
Definition ipc_client.c:993
const char * crm_ipc_buffer(crm_ipc_t *client)
struct crm_ipc_s crm_ipc_t
Definition ipc.h:184
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:850
int pcmk__connect_generic_ipc(crm_ipc_t *ipc)
Definition ipc_client.c:896
int pcmk__ipc_fd(crm_ipc_t *ipc, int *fd)
@ pcmk__client_ipc
Client uses plain IPC.
#define CRM_TRACE_INIT_DATA(name)
Definition logging.h:143
#define crm_info(fmt, args...)
Definition logging.h:397
#define crm_warn(fmt, args...)
Definition logging.h:392
#define CRM_XS
Definition logging.h:56
#define CRM_LOG_ASSERT(expr)
Definition logging.h:228
#define crm_log_xml_err(xml, text)
Definition logging.h:405
#define crm_notice(fmt, args...)
Definition logging.h:395
#define crm_perror(level, fmt, args...)
Send a system error message to both the log and stderr.
Definition logging.h:331
#define CRM_CHECK(expr, failure_action)
Definition logging.h:245
#define crm_debug(fmt, args...)
Definition logging.h:400
#define crm_err(fmt, args...)
Definition logging.h:389
#define crm_log_xml_trace(xml, text)
Definition logging.h:410
#define crm_trace(fmt, args...)
Definition logging.h:402
Resource agent executor.
#define LRMD_OP_NEW_CLIENT
Definition lrmd.h:77
#define DEFAULT_REMOTE_USERNAME
Definition lrmd.h:68
#define LRMD_OP_RSC_REG
Definition lrmd.h:70
#define LRMD_OP_RSC_EXEC
Definition lrmd.h:71
#define LRMD_OP_GET_RECURRING
Definition lrmd.h:80
#define DEFAULT_REMOTE_KEY_LOCATION
Definition lrmd.h:65
lrmd_call_options
Definition lrmd.h:143
@ lrmd_opt_notify_orig_only
Notify only the client that made the request (rather than all clients)
Definition lrmd.h:147
#define LRMD_OP_POKE
Definition lrmd.h:76
#define ALT_REMOTE_KEY_LOCATION
Definition lrmd.h:66
#define LRMD_OP_RSC_INFO
Definition lrmd.h:74
#define LRMD_OP_RSC_UNREG
Definition lrmd.h:73
#define LRMD_OP_CHECK
Definition lrmd.h:78
#define LRMD_PROTOCOL_VERSION
Definition lrmd.h:44
void(* lrmd_event_callback)(lrmd_event_data_t *event)
Definition lrmd.h:187
#define LRMD_OP_RSC_CANCEL
Definition lrmd.h:72
#define LRMD_OP_ALERT_EXEC
Definition lrmd.h:79
int lrmd__metadata_async(const lrmd_rsc_info_t *rsc, void(*callback)(int pid, const pcmk__action_result_t *result, void *user_data), void *user_data)
int lrmd_internal_proxy_send(lrmd_t *lrmd, xmlNode *msg)
lrmd_rsc_info_t * lrmd_copy_rsc_info(lrmd_rsc_info_t *rsc_info)
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)
void lrmd_key_value_freeall(lrmd_key_value_t *head)
bool lrmd_dispatch(lrmd_t *lrmd)
Use after lrmd_poll returns 1 to read and dispatch a message.
void lrmd_free_op_info(lrmd_op_info_t *op_info)
void lrmd__set_result(lrmd_event_data_t *event, enum ocf_exitcode rc, int op_status, const char *exit_reason)
void lrmd_api_delete(lrmd_t *lrmd)
Destroy executor connection object.
time_t lrmd__uptime(lrmd_t *lrmd)
void lrmd_list_freeall(lrmd_list_t *head)
lrmd_t * lrmd_remote_api_new(const char *nodename, const char *server, int port)
Create a new TLS connection to a remote executor.
lrmd_rsc_info_t * lrmd_new_rsc_info(const char *rsc_id, const char *standard, const char *provider, const char *type)
const char * lrmd__node_start_state(lrmd_t *lrmd)
void lrmd_internal_set_proxy_callback(lrmd_t *lrmd, void *userdata, void(*callback)(lrmd_t *lrmd, void *userdata, xmlNode *msg))
void lrmd_free_event(lrmd_event_data_t *event)
Free an executor event.
void lrmd_free_rsc_info(lrmd_rsc_info_t *rsc_info)
lrmd_t * lrmd_api_new(void)
Create a new connection to the local executor.
lrmd_key_value_t * lrmd_key_value_add(lrmd_key_value_t *head, const char *key, const char *value)
lrmd_event_data_t * lrmd_new_event(const char *rsc_id, const char *task, guint interval_ms)
Create a new lrmd_event_data_t object.
int lrmd__validate_remote_settings(lrmd_t *lrmd, GHashTable *hash)
int lrmd__new(lrmd_t **api, const char *nodename, const char *server, int port)
int lrmd_poll(lrmd_t *lrmd, int timeout)
Check whether a message is available on an executor connection.
lrmd_event_data_t * lrmd_copy_event(lrmd_event_data_t *event)
@ lrmd_event_new_client
Definition lrmd_events.h:33
@ lrmd_event_connect
Definition lrmd_events.h:31
@ lrmd_event_unregister
Definition lrmd_events.h:28
@ lrmd_event_exec_complete
Definition lrmd_events.h:29
@ lrmd_event_register
Definition lrmd_events.h:27
@ lrmd_event_poke
Definition lrmd_events.h:32
@ lrmd_event_disconnect
Definition lrmd_events.h:30
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:199
gboolean mainloop_destroy_trigger(crm_trigger_t *source)
Definition mainloop.c:207
crm_ipc_t * mainloop_get_ipc_client(mainloop_io_t *client)
Definition mainloop.c:949
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:918
struct mainloop_io_s mainloop_io_t
Definition mainloop.h:35
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:33
void mainloop_del_ipc_client(mainloop_io_t *client)
Definition mainloop.c:943
mainloop_io_t * mainloop_add_fd(const char *name, int priority, int fd, void *userdata, struct mainloop_fd_callbacks *callbacks)
Definition mainloop.c:958
GHashTable * xml2list(const xmlNode *parent)
Retrieve XML attributes as a hash table.
Definition nvpair.c:859
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
Definition nvpair.c:446
int crm_element_value_int(const xmlNode *data, const char *name, int *dest)
Retrieve the integer value of an XML attribute.
Definition nvpair.c:482
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:348
int crm_element_value_ms(const xmlNode *data, const char *name, guint *dest)
Retrieve the millisecond value of an XML attribute.
Definition nvpair.c:539
char * crm_element_value_copy(const xmlNode *data, const char *name)
Retrieve a copy of the value of an XML attribute.
Definition nvpair.c:674
void hash2smartfield(gpointer key, gpointer value, gpointer user_data)
Safely add hash table entry to XML as attribute or name-value pair.
Definition nvpair.c:694
int crm_element_value_ll(const xmlNode *data, const char *name, long long *dest)
Retrieve the long long integer value of an XML attribute.
Definition nvpair.c:514
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:567
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:301
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:370
#define PCMK_OPT_STONITH_WATCHDOG_TIMEOUT
Definition options.h:68
#define PCMK__VALUE_LRMD
#define PCMK__ENV_AUTHKEY_LOCATION
const char * pcmk__env_option(const char *option)
Definition options.c:1088
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
#define ETIME
#define ECOMM
Definition portability.h:86
#define EKEYREJECTED
#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:501
ocf_exitcode
Exit status codes for resource agents.
Definition results.h:177
@ PCMK_OCF_NOT_CONFIGURED
Parameter invalid (inherently)
Definition results.h:187
@ PCMK_OCF_UNKNOWN_ERROR
Unspecified error.
Definition results.h:181
@ PCMK_OCF_UNKNOWN
Action is pending.
Definition results.h:203
@ pcmk_rc_ok
Definition results.h:162
@ pcmk_rc_error
Definition results.h:157
#define pcmk_ok
Definition results.h:69
int pcmk_rc2legacy(int rc)
Definition results.c:546
@ PCMK_EXEC_ERROR_FATAL
Execution failed, do not retry anywhere.
Definition results.h:339
@ PCMK_EXEC_ERROR
Execution failed, may be retried.
Definition results.h:337
int pcmk_legacy2rc(int legacy_rc)
Definition results.c:559
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:976
#define PCMK__UNKNOWN_RESULT
void void pcmk__set_result_output(pcmk__action_result_t *result, char *out, char *err)
Definition results.c:1045
#define pcmk__mem_assert(ptr)
void pcmk__reset_result(pcmk__action_result_t *result)
Definition results.c:1065
Services API.
GList * resources_list_agents(const char *standard, const char *provider)
Get a list of resource agents.
Definition services.c:1117
gboolean services_action_async(svc_action_t *op, void(*action_callback)(svc_action_t *))
Request asynchronous execution of an action.
Definition services.c:899
gboolean services_action_sync(svc_action_t *op)
Definition services.c:1018
GList * resources_list_standards(void)
Definition services.c:1059
void services_action_free(svc_action_t *op)
Definition services.c:583
GList * resources_list_providers(const char *standard)
Get a list of providers.
Definition services.c:1107
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(const svc_action_t *action)
Definition services.c:1374
Fencing aka. STONITH.
@ st_opt_sync_call
Definition stonith-ng.h:53
void stonith_key_value_freeall(stonith_key_value_t *kvp, int keys, int values)
Definition st_client.c:1953
stonith_t * stonith_api_new(void)
Definition st_client.c:1831
GHashTable * pcmk__str_table_dup(GHashTable *old_table)
Definition strings.c:766
void pcmk__insert_dup(GHashTable *table, const char *name, const char *value)
Definition strings.c:701
GHashTable * pcmk__strkey_table(GDestroyNotify key_destroy_func, GDestroyNotify value_destroy_func)
Definition strings.c:683
void pcmk__str_update(char **str, const char *value)
Definition strings.c:1277
@ pcmk__str_none
@ pcmk__str_casei
#define pcmk__str_copy(str)
int(* dispatch)(const char *buffer, ssize_t length, gpointer userdata)
Dispatch function for an IPC connection used as mainloop source.
Definition mainloop.h:94
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:483
int(* disconnect)(lrmd_t *lrmd)
Disconnect from the executor.
Definition lrmd.h:253
int(* connect)(lrmd_t *lrmd, const char *client_name, int *fd)
Connect to an executor.
Definition lrmd.h:208
const char * op_type
Definition lrmd_events.h:43
unsigned int t_run
Definition lrmd_events.h:72
unsigned int t_rcchange
Definition lrmd_events.h:75
const char * remote_nodename
Definition lrmd_events.h:93
const char * exit_reason
Definition lrmd_events.h:96
const char * user_data
Definition lrmd_events.h:45
const char * output
Definition lrmd_events.h:69
unsigned int exec_time
Definition lrmd_events.h:78
enum lrmd_callback_event type
Definition lrmd_events.h:38
enum ocf_exitcode rc
Definition lrmd_events.h:63
unsigned int queue_time
Definition lrmd_events.h:81
const char * rsc_id
Definition lrmd_events.h:41
char * key
Definition lrmd.h:31
struct lrmd_key_value_s * next
Definition lrmd.h:33
char * value
Definition lrmd.h:32
const char * val
Definition lrmd.h:190
struct lrmd_list_s * next
Definition lrmd.h:191
char * timeout_ms_s
Definition lrmd.h:178
char * rsc_id
Definition lrmd.h:175
char * interval_ms_s
Definition lrmd.h:177
char * action
Definition lrmd.h:176
char * id
Definition lrmd.h:168
char * standard
Definition lrmd.h:170
char * type
Definition lrmd.h:169
char * provider
Definition lrmd.h:171
Definition lrmd.h:490
void * lrmd_private
Definition lrmd.h:492
lrmd_api_operations_t * cmds
Definition lrmd.h:491
int(* dispatch)(gpointer userdata)
Dispatch function for mainloop file descriptor with data ready.
Definition mainloop.h:148
int(* free)(stonith_t *st)
Destroy a fencer connection.
Definition stonith-ng.h:152
int(* list_agents)(stonith_t *stonith, int call_options, const char *namespace_s, stonith_key_value_t **devices, int timeout)
Retrieve a list of installed fence agents.
Definition stonith-ng.h:274
int(* metadata)(stonith_t *stonith, int call_options, const char *agent, const char *namespace_s, char **output, int timeout_sec)
Retrieve a fence agent's metadata.
Definition stonith-ng.h:253
struct stonith_key_value_s * next
Definition stonith-ng.h:96
stonith_api_operations_t * cmds
Definition stonith-ng.h:551
Object for executing external actions.
Definition services.h:122
Wrappers for and extensions to libxml2.
void free_xml(xmlNode *child)
Definition xml.c:867
xmlNode * pcmk__xml_copy(xmlNode *parent, xmlNode *src)
Definition xml.c:883
xmlNode * pcmk__xe_first_child(const xmlNode *parent, const char *node_name, const char *attr_n, const char *attr_v)
Definition xml.c:440
xmlNode * pcmk__xe_next_same(const xmlNode *node)
Definition xml.c:2108
xmlNode * pcmk__xe_create(xmlNode *parent, const char *name)
Definition xml.c:720
xmlNode * pcmk__xml_parse(const char *input)
Definition xml_io.c:244
#define PCMK__XA_LRMD_RSC_USERDATA_STR
#define PCMK__XA_LRMD_OP
#define PCMK__XA_LRMD_RSC_START_DELAY
#define PCMK__XA_LRMD_RSC_DELETED
#define PCMK__XA_LRMD_RSC_INTERVAL
#define PCMK__XA_LRMD_TYPE
#define PCMK__XA_LRMD_RSC_ACTION
#define PCMK__XA_LRMD_EXEC_TIME
#define PCMK__XA_LRMD_PROTOCOL_VERSION
#define PCMK__XA_LRMD_REMOTE_MSG_ID
#define PCMK__XA_LRMD_CLIENTNAME
#define PCMK__XA_LRMD_IPC_SESSION
#define PCMK__XA_LRMD_EXEC_OP_STATUS
#define PCMK__XA_LRMD_CALLID
#define PCMK__XA_LRMD_REMOTE_MSG_TYPE
#define PCMK__XA_LRMD_WATCHDOG
#define PCMK__XA_LRMD_CLASS
#define PCMK__XE_LRMD_ALERT
#define PCMK__XA_T
#define PCMK__XA_LRMD_ALERT_PATH
#define PCMK__XE_LRMD_CALLDATA
#define PCMK__XA_LRMD_TIMEOUT
#define PCMK__XA_LRMD_RUN_TIME
#define PCMK__XA_NODE_START_STATE
#define PCMK__XA_LRMD_RSC_ID
#define PCMK__XA_LRMD_RCCHANGE_TIME
#define PCMK__XA_LRMD_QUEUE_TIME
#define PCMK__XA_LRMD_IS_IPC_PROVIDER
#define PCMK__XA_LRMD_RSC_EXIT_REASON
#define PCMK__XA_LRMD_CALLOPT
#define PCMK__XA_LRMD_RSC_OUTPUT
#define PCMK__XA_LRMD_RC
#define PCMK__XE_LRMD_COMMAND
#define PCMK__XA_LRMD_PROVIDER
#define PCMK__XA_LRMD_EXEC_RC
#define PCMK__XA_LRMD_ALERT_ID
#define PCMK__XA_LRMD_ORIGIN
#define PCMK__XA_UPTIME
#define PCMK__XE_ATTRIBUTES
#define PCMK__XE_LRMD_RSC_OP
#define PCMK__XA_LRMD_CLIENTID
#define PCMK__XE_LRMD_RSC