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