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