pacemaker  2.0.4-2deceaa
Scalable High-Availability cluster resource manager
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
lrmd_client.c
Go to the documentation of this file.
1 /*
2  * Copyright 2012-2020 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 <stdarg.h>
16 #include <string.h>
17 #include <ctype.h>
18 
19 #include <sys/types.h>
20 #include <sys/wait.h>
21 
22 #include <glib.h>
23 #include <dirent.h>
24 
25 #include <crm/crm.h>
26 #include <crm/lrmd.h>
27 #include <crm/lrmd_internal.h>
28 #include <crm/services.h>
29 #include <crm/common/mainloop.h>
32 #include <crm/msg_xml.h>
33 
34 #include <crm/stonith-ng.h>
35 
36 #ifdef HAVE_GNUTLS_GNUTLS_H
37 # undef KEYFILE
38 # include <gnutls/gnutls.h>
39 #endif
40 
41 #include <sys/socket.h>
42 #include <netinet/in.h>
43 #include <netinet/ip.h>
44 #include <arpa/inet.h>
45 #include <netdb.h>
46 
47 #define MAX_TLS_RECV_WAIT 10000
48 
50 
51 static int lrmd_api_disconnect(lrmd_t * lrmd);
52 static int lrmd_api_is_connected(lrmd_t * lrmd);
53 
54 /* IPC proxy functions */
55 int lrmd_internal_proxy_send(lrmd_t * lrmd, xmlNode *msg);
56 static void lrmd_internal_proxy_dispatch(lrmd_t *lrmd, xmlNode *msg);
57 void lrmd_internal_set_proxy_callback(lrmd_t * lrmd, void *userdata, void (*callback)(lrmd_t *lrmd, void *userdata, xmlNode *msg));
58 
59 #ifdef HAVE_GNUTLS_GNUTLS_H
60 # define LRMD_CLIENT_HANDSHAKE_TIMEOUT 5000 /* 5 seconds */
61 gnutls_psk_client_credentials_t psk_cred_s;
62 int lrmd_tls_set_key(gnutls_datum_t * key);
63 static void lrmd_tls_disconnect(lrmd_t * lrmd);
64 static int global_remote_msg_id = 0;
65 static void lrmd_tls_connection_destroy(gpointer userdata);
66 #endif
67 
68 typedef struct lrmd_private_s {
70  char *token;
71  mainloop_io_t *source;
72 
73  /* IPC parameters */
74  crm_ipc_t *ipc;
75 
76  pcmk__remote_t *remote;
77 
78  /* Extra TLS parameters */
79  char *remote_nodename;
80 #ifdef HAVE_GNUTLS_GNUTLS_H
81  char *server;
82  int port;
83  gnutls_psk_client_credentials_t psk_cred_c;
84 
85  /* while the async connection is occurring, this is the id
86  * of the connection timeout timer. */
87  int async_timer;
88  int sock;
89  /* since tls requires a round trip across the network for a
90  * request/reply, there are times where we just want to be able
91  * to send a request from the client and not wait around (or even care
92  * about) what the reply is. */
93  int expected_late_replies;
94  GList *pending_notify;
95  crm_trigger_t *process_notify;
96 #endif
97 
98  lrmd_event_callback callback;
99 
100  /* Internal IPC proxy msg passing for remote guests */
101  void (*proxy_callback)(lrmd_t *lrmd, void *userdata, xmlNode *msg);
102  void *proxy_callback_userdata;
103  char *peer_version;
105 
106 static lrmd_list_t *
107 lrmd_list_add(lrmd_list_t * head, const char *value)
108 {
109  lrmd_list_t *p, *end;
110 
111  p = calloc(1, sizeof(lrmd_list_t));
112  p->val = strdup(value);
113 
114  end = head;
115  while (end && end->next) {
116  end = end->next;
117  }
118 
119  if (end) {
120  end->next = p;
121  } else {
122  head = p;
123  }
124 
125  return head;
126 }
127 
128 void
130 {
131  lrmd_list_t *p;
132 
133  while (head) {
134  char *val = (char *)head->val;
135 
136  p = head->next;
137  free(val);
138  free(head);
139  head = p;
140  }
141 }
142 
144 lrmd_key_value_add(lrmd_key_value_t * head, const char *key, const char *value)
145 {
146  lrmd_key_value_t *p, *end;
147 
148  p = calloc(1, sizeof(lrmd_key_value_t));
149  p->key = strdup(key);
150  p->value = strdup(value);
151 
152  end = head;
153  while (end && end->next) {
154  end = end->next;
155  }
156 
157  if (end) {
158  end->next = p;
159  } else {
160  head = p;
161  }
162 
163  return head;
164 }
165 
166 void
168 {
169  lrmd_key_value_t *p;
170 
171  while (head) {
172  p = head->next;
173  free(head->key);
174  free(head->value);
175  free(head);
176  head = p;
177  }
178 }
179 
193 lrmd_new_event(const char *rsc_id, const char *task, guint interval_ms)
194 {
195  lrmd_event_data_t *event = calloc(1, sizeof(lrmd_event_data_t));
196 
197  CRM_ASSERT(event != NULL);
198  if (rsc_id != NULL) {
199  event->rsc_id = strdup(rsc_id);
200  CRM_ASSERT(event->rsc_id != NULL);
201  }
202  if (task != NULL) {
203  event->op_type = strdup(task);
204  CRM_ASSERT(event->op_type != NULL);
205  }
206  event->interval_ms = interval_ms;
207  return event;
208 }
209 
212 {
213  lrmd_event_data_t *copy = NULL;
214 
215  copy = calloc(1, sizeof(lrmd_event_data_t));
216 
217  /* This will get all the int values.
218  * we just have to be careful not to leave any
219  * dangling pointers to strings. */
220  memcpy(copy, event, sizeof(lrmd_event_data_t));
221 
222  copy->rsc_id = event->rsc_id ? strdup(event->rsc_id) : NULL;
223  copy->op_type = event->op_type ? strdup(event->op_type) : NULL;
224  copy->user_data = event->user_data ? strdup(event->user_data) : NULL;
225  copy->output = event->output ? strdup(event->output) : NULL;
226  copy->exit_reason = event->exit_reason ? strdup(event->exit_reason) : NULL;
227  copy->remote_nodename = event->remote_nodename ? strdup(event->remote_nodename) : NULL;
228  copy->params = crm_str_table_dup(event->params);
229 
230  return copy;
231 }
232 
233 void
235 {
236  if (!event) {
237  return;
238  }
239 
240  /* free gives me grief if i try to cast */
241  free((char *)event->rsc_id);
242  free((char *)event->op_type);
243  free((char *)event->user_data);
244  free((char *)event->output);
245  free((char *)event->exit_reason);
246  free((char *)event->remote_nodename);
247  if (event->params) {
248  g_hash_table_destroy(event->params);
249  }
250  free(event);
251 }
252 
253 static int
254 lrmd_dispatch_internal(lrmd_t * lrmd, xmlNode * msg)
255 {
256  const char *type;
257  const char *proxy_session = crm_element_value(msg, F_LRMD_IPC_SESSION);
258  lrmd_private_t *native = lrmd->lrmd_private;
259  lrmd_event_data_t event = { 0, };
260 
261  if (proxy_session != NULL) {
262  /* this is proxy business */
263  lrmd_internal_proxy_dispatch(lrmd, msg);
264  return 1;
265  } else if (!native->callback) {
266  /* no callback set */
267  crm_trace("notify event received but client has not set callback");
268  return 1;
269  }
270 
271  event.remote_nodename = native->remote_nodename;
272  type = crm_element_value(msg, F_LRMD_OPERATION);
273  crm_element_value_int(msg, F_LRMD_CALLID, &event.call_id);
274  event.rsc_id = crm_element_value(msg, F_LRMD_RSC_ID);
275 
276  if (crm_str_eq(type, LRMD_OP_RSC_REG, TRUE)) {
277  event.type = lrmd_event_register;
278  } else if (crm_str_eq(type, LRMD_OP_RSC_UNREG, TRUE)) {
279  event.type = lrmd_event_unregister;
280  } else if (crm_str_eq(type, LRMD_OP_RSC_EXEC, TRUE)) {
281  time_t epoch = 0;
282 
283  crm_element_value_int(msg, F_LRMD_TIMEOUT, &event.timeout);
284  crm_element_value_ms(msg, F_LRMD_RSC_INTERVAL, &event.interval_ms);
285  crm_element_value_int(msg, F_LRMD_RSC_START_DELAY, &event.start_delay);
286  crm_element_value_int(msg, F_LRMD_EXEC_RC, (int *)&event.rc);
287  crm_element_value_int(msg, F_LRMD_OP_STATUS, &event.op_status);
288  crm_element_value_int(msg, F_LRMD_RSC_DELETED, &event.rsc_deleted);
289 
291  event.t_run = (unsigned int) epoch;
292 
294  event.t_rcchange = (unsigned int) epoch;
295 
296  crm_element_value_int(msg, F_LRMD_RSC_EXEC_TIME, (int *)&event.exec_time);
297  crm_element_value_int(msg, F_LRMD_RSC_QUEUE_TIME, (int *)&event.queue_time);
298 
299  event.op_type = crm_element_value(msg, F_LRMD_RSC_ACTION);
300  event.user_data = crm_element_value(msg, F_LRMD_RSC_USERDATA_STR);
301  event.output = crm_element_value(msg, F_LRMD_RSC_OUTPUT);
302  event.exit_reason = crm_element_value(msg, F_LRMD_RSC_EXIT_REASON);
303  event.type = lrmd_event_exec_complete;
304 
305  event.params = xml2list(msg);
306  } else if (crm_str_eq(type, LRMD_OP_NEW_CLIENT, TRUE)) {
307  event.type = lrmd_event_new_client;
308  } else if (crm_str_eq(type, LRMD_OP_POKE, TRUE)) {
309  event.type = lrmd_event_poke;
310  } else {
311  return 1;
312  }
313 
314  crm_trace("op %s notify event received", type);
315  native->callback(&event);
316 
317  if (event.params) {
318  g_hash_table_destroy(event.params);
319  }
320  return 1;
321 }
322 
323 static int
324 lrmd_ipc_dispatch(const char *buffer, ssize_t length, gpointer userdata)
325 {
326  lrmd_t *lrmd = userdata;
327  lrmd_private_t *native = lrmd->lrmd_private;
328  xmlNode *msg;
329  int rc;
330 
331  if (!native->callback) {
332  /* no callback set */
333  return 1;
334  }
335 
336  msg = string2xml(buffer);
337  rc = lrmd_dispatch_internal(lrmd, msg);
338  free_xml(msg);
339  return rc;
340 }
341 
342 #ifdef HAVE_GNUTLS_GNUTLS_H
343 static void
344 lrmd_free_xml(gpointer userdata)
345 {
346  free_xml((xmlNode *) userdata);
347 }
348 
349 static int
350 lrmd_tls_connected(lrmd_t * lrmd)
351 {
352  lrmd_private_t *native = lrmd->lrmd_private;
353 
354  if (native->remote->tls_session) {
355  return TRUE;
356  }
357 
358  return FALSE;
359 }
360 
361 static int
362 lrmd_tls_dispatch(gpointer userdata)
363 {
364  lrmd_t *lrmd = userdata;
365  lrmd_private_t *native = lrmd->lrmd_private;
366  xmlNode *xml = NULL;
367  int rc = pcmk_rc_ok;
368 
369  if (lrmd_tls_connected(lrmd) == FALSE) {
370  crm_trace("TLS dispatch triggered after disconnect");
371  return 0;
372  }
373 
374  crm_trace("TLS dispatch triggered");
375 
376  /* First check if there are any pending notifies to process that came
377  * while we were waiting for replies earlier. */
378  if (native->pending_notify) {
379  GList *iter = NULL;
380 
381  crm_trace("Processing pending notifies");
382  for (iter = native->pending_notify; iter; iter = iter->next) {
383  lrmd_dispatch_internal(lrmd, iter->data);
384  }
385  g_list_free_full(native->pending_notify, lrmd_free_xml);
386  native->pending_notify = NULL;
387  }
388 
389  /* Next read the current buffer and see if there are any messages to handle. */
390  switch (pcmk__remote_ready(native->remote, 0)) {
391  case pcmk_rc_ok:
392  rc = pcmk__read_remote_message(native->remote, -1);
393  xml = pcmk__remote_message_xml(native->remote);
394  break;
395  case ETIME:
396  // Nothing to read, check if a full message is already in buffer
397  xml = pcmk__remote_message_xml(native->remote);
398  break;
399  default:
400  rc = ENOTCONN;
401  break;
402  }
403  while (xml) {
404  const char *msg_type = crm_element_value(xml, F_LRMD_REMOTE_MSG_TYPE);
405  if (safe_str_eq(msg_type, "notify")) {
406  lrmd_dispatch_internal(lrmd, xml);
407  } else if (safe_str_eq(msg_type, "reply")) {
408  if (native->expected_late_replies > 0) {
409  native->expected_late_replies--;
410  } else {
411  int reply_id = 0;
412  crm_element_value_int(xml, F_LRMD_CALLID, &reply_id);
413  /* if this happens, we want to know about it */
414  crm_err("Got outdated Pacemaker Remote reply %d", reply_id);
415  }
416  }
417  free_xml(xml);
418  xml = pcmk__remote_message_xml(native->remote);
419  }
420 
421  if (rc == ENOTCONN) {
422  crm_info("Lost %s executor connection while reading data",
423  (native->remote_nodename? native->remote_nodename : "local"));
424  lrmd_tls_disconnect(lrmd);
425  return 0;
426  }
427  return 1;
428 }
429 #endif
430 
431 /* Not used with mainloop */
432 int
434 {
435  lrmd_private_t *native = lrmd->lrmd_private;
436 
437  switch (native->type) {
438  case PCMK__CLIENT_IPC:
439  return crm_ipc_ready(native->ipc);
440 
441 #ifdef HAVE_GNUTLS_GNUTLS_H
442  case PCMK__CLIENT_TLS:
443  if (native->pending_notify) {
444  return 1;
445  } else {
446  int rc = pcmk__remote_ready(native->remote, 0);
447 
448  switch (rc) {
449  case pcmk_rc_ok:
450  return 1;
451  case ETIME:
452  return 0;
453  default:
454  return pcmk_rc2legacy(rc);
455  }
456  }
457 #endif
458  default:
459  crm_err("Unsupported connection type: %d", native->type);
460  }
461 
462  return 0;
463 }
464 
465 /* Not used with mainloop */
466 bool
468 {
469  lrmd_private_t *private = NULL;
470 
471  CRM_ASSERT(lrmd != NULL);
472 
473  private = lrmd->lrmd_private;
474  switch (private->type) {
475  case PCMK__CLIENT_IPC:
476  while (crm_ipc_ready(private->ipc)) {
477  if (crm_ipc_read(private->ipc) > 0) {
478  const char *msg = crm_ipc_buffer(private->ipc);
479 
480  lrmd_ipc_dispatch(msg, strlen(msg), lrmd);
481  }
482  }
483  break;
484 #ifdef HAVE_GNUTLS_GNUTLS_H
485  case PCMK__CLIENT_TLS:
486  lrmd_tls_dispatch(lrmd);
487  break;
488 #endif
489  default:
490  crm_err("Unsupported connection type: %d", private->type);
491  }
492 
493  if (lrmd_api_is_connected(lrmd) == FALSE) {
494  crm_err("Connection closed");
495  return FALSE;
496  }
497 
498  return TRUE;
499 }
500 
501 static xmlNode *
502 lrmd_create_op(const char *token, const char *op, xmlNode *data, int timeout,
503  enum lrmd_call_options options)
504 {
505  xmlNode *op_msg = create_xml_node(NULL, "lrmd_command");
506 
507  CRM_CHECK(op_msg != NULL, return NULL);
508  CRM_CHECK(token != NULL, return NULL);
509 
510  crm_xml_add(op_msg, F_XML_TAGNAME, "lrmd_command");
511  crm_xml_add(op_msg, F_TYPE, T_LRMD);
512  crm_xml_add(op_msg, F_LRMD_CALLBACK_TOKEN, token);
513  crm_xml_add(op_msg, F_LRMD_OPERATION, op);
514  crm_xml_add_int(op_msg, F_LRMD_TIMEOUT, timeout);
515  crm_xml_add_int(op_msg, F_LRMD_CALLOPTS, options);
516 
517  if (data != NULL) {
518  add_message_xml(op_msg, F_LRMD_CALLDATA, data);
519  }
520 
521  crm_trace("Created executor %s command with call options %.8lx (%d)",
522  op, (long)options, options);
523  return op_msg;
524 }
525 
526 static void
527 lrmd_ipc_connection_destroy(gpointer userdata)
528 {
529  lrmd_t *lrmd = userdata;
530  lrmd_private_t *native = lrmd->lrmd_private;
531 
532  crm_info("IPC connection destroyed");
533 
534  /* Prevent these from being cleaned up in lrmd_api_disconnect() */
535  native->ipc = NULL;
536  native->source = NULL;
537 
538  if (native->callback) {
539  lrmd_event_data_t event = { 0, };
540  event.type = lrmd_event_disconnect;
541  event.remote_nodename = native->remote_nodename;
542  native->callback(&event);
543  }
544 }
545 
546 #ifdef HAVE_GNUTLS_GNUTLS_H
547 static void
548 lrmd_tls_connection_destroy(gpointer userdata)
549 {
550  lrmd_t *lrmd = userdata;
551  lrmd_private_t *native = lrmd->lrmd_private;
552 
553  crm_info("TLS connection destroyed");
554 
555  if (native->remote->tls_session) {
556  gnutls_bye(*native->remote->tls_session, GNUTLS_SHUT_RDWR);
557  gnutls_deinit(*native->remote->tls_session);
558  gnutls_free(native->remote->tls_session);
559  }
560  if (native->psk_cred_c) {
561  gnutls_psk_free_client_credentials(native->psk_cred_c);
562  }
563  if (native->sock) {
564  close(native->sock);
565  }
566  if (native->process_notify) {
567  mainloop_destroy_trigger(native->process_notify);
568  native->process_notify = NULL;
569  }
570  if (native->pending_notify) {
571  g_list_free_full(native->pending_notify, lrmd_free_xml);
572  native->pending_notify = NULL;
573  }
574 
575  free(native->remote->buffer);
576  native->remote->buffer = NULL;
577  native->source = 0;
578  native->sock = 0;
579  native->psk_cred_c = NULL;
580  native->remote->tls_session = NULL;
581  native->sock = 0;
582 
583  if (native->callback) {
584  lrmd_event_data_t event = { 0, };
585  event.remote_nodename = native->remote_nodename;
586  event.type = lrmd_event_disconnect;
587  native->callback(&event);
588  }
589  return;
590 }
591 
592 // \return Standard Pacemaker return code
593 int
594 lrmd_tls_send_msg(pcmk__remote_t *session, xmlNode *msg, uint32_t id,
595  const char *msg_type)
596 {
598  crm_xml_add(msg, F_LRMD_REMOTE_MSG_TYPE, msg_type);
599  return pcmk__remote_send_xml(session, msg);
600 }
601 
602 static xmlNode *
603 lrmd_tls_recv_reply(lrmd_t * lrmd, int total_timeout, int expected_reply_id, int *disconnected)
604 {
605  lrmd_private_t *native = lrmd->lrmd_private;
606  xmlNode *xml = NULL;
607  time_t start = time(NULL);
608  const char *msg_type = NULL;
609  int reply_id = 0;
610  int remaining_timeout = 0;
611 
612  /* A timeout of 0 here makes no sense. We have to wait a period of time
613  * for the response to come back. If -1 or 0, default to 10 seconds. */
614  if (total_timeout <= 0 || total_timeout > MAX_TLS_RECV_WAIT) {
615  total_timeout = MAX_TLS_RECV_WAIT;
616  }
617 
618  while (!xml) {
619 
620  xml = pcmk__remote_message_xml(native->remote);
621  if (!xml) {
622  /* read some more off the tls buffer if we still have time left. */
623  if (remaining_timeout) {
624  remaining_timeout = total_timeout - ((time(NULL) - start) * 1000);
625  } else {
626  remaining_timeout = total_timeout;
627  }
628  if (remaining_timeout <= 0) {
629  crm_err("Never received the expected reply during the timeout period, disconnecting.");
630  *disconnected = TRUE;
631  return NULL;
632  }
633 
634  if (pcmk__read_remote_message(native->remote,
635  remaining_timeout) == ENOTCONN) {
636  *disconnected = TRUE;
637  } else {
638  *disconnected = FALSE;
639  }
640  xml = pcmk__remote_message_xml(native->remote);
641  if (!xml) {
642  crm_err("Unable to receive expected reply, disconnecting.");
643  *disconnected = TRUE;
644  return NULL;
645  } else if (*disconnected) {
646  return NULL;
647  }
648  }
649 
650  CRM_ASSERT(xml != NULL);
651 
653  msg_type = crm_element_value(xml, F_LRMD_REMOTE_MSG_TYPE);
654 
655  if (!msg_type) {
656  crm_err("Empty msg type received while waiting for reply");
657  free_xml(xml);
658  xml = NULL;
659  } else if (safe_str_eq(msg_type, "notify")) {
660  /* got a notify while waiting for reply, trigger the notify to be processed later */
661  crm_info("queueing notify");
662  native->pending_notify = g_list_append(native->pending_notify, xml);
663  if (native->process_notify) {
664  crm_info("notify trigger set.");
665  mainloop_set_trigger(native->process_notify);
666  }
667  xml = NULL;
668  } else if (safe_str_neq(msg_type, "reply")) {
669  /* msg isn't a reply, make some noise */
670  crm_err("Expected a reply, got %s", msg_type);
671  free_xml(xml);
672  xml = NULL;
673  } else if (reply_id != expected_reply_id) {
674  if (native->expected_late_replies > 0) {
675  native->expected_late_replies--;
676  } else {
677  crm_err("Got outdated reply, expected id %d got id %d", expected_reply_id, reply_id);
678  }
679  free_xml(xml);
680  xml = NULL;
681  }
682  }
683 
684  if (native->remote->buffer && native->process_notify) {
685  mainloop_set_trigger(native->process_notify);
686  }
687 
688  return xml;
689 }
690 
691 static int
692 lrmd_tls_send(lrmd_t * lrmd, xmlNode * msg)
693 {
694  int rc = 0;
695  lrmd_private_t *native = lrmd->lrmd_private;
696 
697  global_remote_msg_id++;
698  if (global_remote_msg_id <= 0) {
699  global_remote_msg_id = 1;
700  }
701 
702  rc = lrmd_tls_send_msg(native->remote, msg, global_remote_msg_id, "request");
703  if (rc != pcmk_rc_ok) {
704  crm_err("Disconnecting because TLS message could not be sent to "
705  "Pacemaker Remote: %s", pcmk_rc_str(rc));
706  lrmd_tls_disconnect(lrmd);
707  return -ENOTCONN;
708  }
709  return pcmk_ok;
710 }
711 
712 static int
713 lrmd_tls_send_recv(lrmd_t * lrmd, xmlNode * msg, int timeout, xmlNode ** reply)
714 {
715  int rc = 0;
716  int disconnected = 0;
717  xmlNode *xml = NULL;
718 
719  if (lrmd_tls_connected(lrmd) == FALSE) {
720  return -1;
721  }
722 
723  rc = lrmd_tls_send(lrmd, msg);
724  if (rc < 0) {
725  return rc;
726  }
727 
728  xml = lrmd_tls_recv_reply(lrmd, timeout, global_remote_msg_id, &disconnected);
729 
730  if (disconnected) {
731  crm_err("Pacemaker Remote disconnected while waiting for reply to request id %d",
732  global_remote_msg_id);
733  lrmd_tls_disconnect(lrmd);
734  rc = -ENOTCONN;
735  } else if (!xml) {
736  crm_err("Did not receive reply from Pacemaker Remote for request id %d (timeout %dms)",
737  global_remote_msg_id, timeout);
738  rc = -ECOMM;
739  }
740 
741  if (reply) {
742  *reply = xml;
743  } else {
744  free_xml(xml);
745  }
746 
747  return rc;
748 }
749 #endif
750 
751 static int
752 lrmd_send_xml(lrmd_t * lrmd, xmlNode * msg, int timeout, xmlNode ** reply)
753 {
754  int rc = -1;
755  lrmd_private_t *native = lrmd->lrmd_private;
756 
757  switch (native->type) {
758  case PCMK__CLIENT_IPC:
759  rc = crm_ipc_send(native->ipc, msg, crm_ipc_client_response, timeout, reply);
760  break;
761 #ifdef HAVE_GNUTLS_GNUTLS_H
762  case PCMK__CLIENT_TLS:
763  rc = lrmd_tls_send_recv(lrmd, msg, timeout, reply);
764  break;
765 #endif
766  default:
767  crm_err("Unsupported connection type: %d", native->type);
768  }
769 
770  return rc;
771 }
772 
773 static int
774 lrmd_send_xml_no_reply(lrmd_t * lrmd, xmlNode * msg)
775 {
776  int rc = -1;
777  lrmd_private_t *native = lrmd->lrmd_private;
778 
779  switch (native->type) {
780  case PCMK__CLIENT_IPC:
781  rc = crm_ipc_send(native->ipc, msg, crm_ipc_flags_none, 0, NULL);
782  break;
783 #ifdef HAVE_GNUTLS_GNUTLS_H
784  case PCMK__CLIENT_TLS:
785  rc = lrmd_tls_send(lrmd, msg);
786  if (rc == pcmk_ok) {
787  /* we don't want to wait around for the reply, but
788  * since the request/reply protocol needs to behave the same
789  * as libqb, a reply will eventually come later anyway. */
790  native->expected_late_replies++;
791  }
792  break;
793 #endif
794  default:
795  crm_err("Unsupported connection type: %d", native->type);
796  }
797 
798  return rc;
799 }
800 
801 static int
802 lrmd_api_is_connected(lrmd_t * lrmd)
803 {
804  lrmd_private_t *native = lrmd->lrmd_private;
805 
806  switch (native->type) {
807  case PCMK__CLIENT_IPC:
808  return crm_ipc_connected(native->ipc);
809  break;
810 #ifdef HAVE_GNUTLS_GNUTLS_H
811  case PCMK__CLIENT_TLS:
812  return lrmd_tls_connected(lrmd);
813  break;
814 #endif
815  default:
816  crm_err("Unsupported connection type: %d", native->type);
817  }
818 
819  return 0;
820 }
821 
840 static int
841 lrmd_send_command(lrmd_t *lrmd, const char *op, xmlNode *data,
842  xmlNode **output_data, int timeout,
843  enum lrmd_call_options options, gboolean expect_reply)
844 {
845  int rc = pcmk_ok;
846  lrmd_private_t *native = lrmd->lrmd_private;
847  xmlNode *op_msg = NULL;
848  xmlNode *op_reply = NULL;
849 
850  if (!lrmd_api_is_connected(lrmd)) {
851  return -ENOTCONN;
852  }
853 
854  if (op == NULL) {
855  crm_err("No operation specified");
856  return -EINVAL;
857  }
858 
859  CRM_CHECK(native->token != NULL,;
860  );
861  crm_trace("Sending %s op to executor", op);
862 
863  op_msg = lrmd_create_op(native->token, op, data, timeout, options);
864 
865  if (op_msg == NULL) {
866  return -EINVAL;
867  }
868 
869  if (expect_reply) {
870  rc = lrmd_send_xml(lrmd, op_msg, timeout, &op_reply);
871  } else {
872  rc = lrmd_send_xml_no_reply(lrmd, op_msg);
873  goto done;
874  }
875 
876  if (rc < 0) {
877  crm_perror(LOG_ERR, "Couldn't perform %s operation (timeout=%d): %d", op, timeout, rc);
878  rc = -ECOMM;
879  goto done;
880 
881  } else if(op_reply == NULL) {
882  rc = -ENOMSG;
883  goto done;
884  }
885 
886  rc = pcmk_ok;
887  crm_trace("%s op reply received", op);
888  if (crm_element_value_int(op_reply, F_LRMD_RC, &rc) != 0) {
889  rc = -ENOMSG;
890  goto done;
891  }
892 
893  crm_log_xml_trace(op_reply, "Reply");
894 
895  if (output_data) {
896  *output_data = op_reply;
897  op_reply = NULL; /* Prevent subsequent free */
898  }
899 
900  done:
901  if (lrmd_api_is_connected(lrmd) == FALSE) {
902  crm_err("Executor disconnected");
903  }
904 
905  free_xml(op_msg);
906  free_xml(op_reply);
907  return rc;
908 }
909 
910 static int
911 lrmd_api_poke_connection(lrmd_t * lrmd)
912 {
913  int rc;
914  lrmd_private_t *native = lrmd->lrmd_private;
915  xmlNode *data = create_xml_node(NULL, F_LRMD_RSC);
916 
917  crm_xml_add(data, F_LRMD_ORIGIN, __FUNCTION__);
918  rc = lrmd_send_command(lrmd, LRMD_OP_POKE, data, NULL, 0, 0,
919  (native->type == PCMK__CLIENT_IPC));
920  free_xml(data);
921 
922  return rc < 0 ? rc : pcmk_ok;
923 }
924 
925 int
926 remote_proxy_check(lrmd_t * lrmd, GHashTable *hash)
927 {
928  int rc;
929  const char *value;
930  lrmd_private_t *native = lrmd->lrmd_private;
931  xmlNode *data = create_xml_node(NULL, F_LRMD_OPERATION);
932 
933  crm_xml_add(data, F_LRMD_ORIGIN, __FUNCTION__);
934 
935  value = g_hash_table_lookup(hash, "stonith-watchdog-timeout");
936  crm_xml_add(data, F_LRMD_WATCHDOG, value);
937 
938  rc = lrmd_send_command(lrmd, LRMD_OP_CHECK, 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 static int
946 lrmd_handshake(lrmd_t * lrmd, const char *name)
947 {
948  int rc = pcmk_ok;
949  lrmd_private_t *native = lrmd->lrmd_private;
950  xmlNode *reply = NULL;
951  xmlNode *hello = create_xml_node(NULL, "lrmd_command");
952 
953  crm_xml_add(hello, F_TYPE, T_LRMD);
955  crm_xml_add(hello, F_LRMD_CLIENTNAME, name);
957 
958  /* advertise that we are a proxy provider */
959  if (native->proxy_callback) {
960  crm_xml_add(hello, F_LRMD_IS_IPC_PROVIDER, "true");
961  }
962 
963  rc = lrmd_send_xml(lrmd, hello, -1, &reply);
964 
965  if (rc < 0) {
966  crm_perror(LOG_DEBUG, "Couldn't complete registration with the executor API: %d", rc);
967  rc = -ECOMM;
968  } else if (reply == NULL) {
969  crm_err("Did not receive registration reply");
970  rc = -EPROTO;
971  } else {
972  const char *version = crm_element_value(reply, F_LRMD_PROTOCOL_VERSION);
973  const char *msg_type = crm_element_value(reply, F_LRMD_OPERATION);
974  const char *tmp_ticket = crm_element_value(reply, F_LRMD_CLIENTID);
975 
976  crm_element_value_int(reply, F_LRMD_RC, &rc);
977 
978  if (rc == -EPROTO) {
979  crm_err("Executor protocol version mismatch between client (%s) and server (%s)",
980  LRMD_PROTOCOL_VERSION, version);
981  crm_log_xml_err(reply, "Protocol Error");
982 
983  } else if (safe_str_neq(msg_type, CRM_OP_REGISTER)) {
984  crm_err("Invalid registration message: %s", msg_type);
985  crm_log_xml_err(reply, "Bad reply");
986  rc = -EPROTO;
987  } else if (tmp_ticket == NULL) {
988  crm_err("No registration token provided");
989  crm_log_xml_err(reply, "Bad reply");
990  rc = -EPROTO;
991  } else {
992  crm_trace("Obtained registration token: %s", tmp_ticket);
993  native->token = strdup(tmp_ticket);
994  native->peer_version = strdup(version?version:"1.0"); /* Included since 1.1 */
995  rc = pcmk_ok;
996  }
997  }
998 
999  free_xml(reply);
1000  free_xml(hello);
1001 
1002  if (rc != pcmk_ok) {
1003  lrmd_api_disconnect(lrmd);
1004  }
1005  return rc;
1006 }
1007 
1008 static int
1009 lrmd_ipc_connect(lrmd_t * lrmd, int *fd)
1010 {
1011  int rc = pcmk_ok;
1012  lrmd_private_t *native = lrmd->lrmd_private;
1013 
1014  struct ipc_client_callbacks lrmd_callbacks = {
1015  .dispatch = lrmd_ipc_dispatch,
1016  .destroy = lrmd_ipc_connection_destroy
1017  };
1018 
1019  crm_info("Connecting to executor");
1020 
1021  if (fd) {
1022  /* No mainloop */
1023  native->ipc = crm_ipc_new(CRM_SYSTEM_LRMD, 0);
1024  if (native->ipc && crm_ipc_connect(native->ipc)) {
1025  *fd = crm_ipc_get_fd(native->ipc);
1026  } else if (native->ipc) {
1027  crm_perror(LOG_ERR, "Connection to executor failed");
1028  rc = -ENOTCONN;
1029  }
1030  } else {
1031  native->source = mainloop_add_ipc_client(CRM_SYSTEM_LRMD, G_PRIORITY_HIGH, 0, lrmd, &lrmd_callbacks);
1032  native->ipc = mainloop_get_ipc_client(native->source);
1033  }
1034 
1035  if (native->ipc == NULL) {
1036  crm_debug("Could not connect to the executor API");
1037  rc = -ENOTCONN;
1038  }
1039 
1040  return rc;
1041 }
1042 
1043 #ifdef HAVE_GNUTLS_GNUTLS_H
1044 static void
1045 copy_gnutls_datum(gnutls_datum_t *dest, gnutls_datum_t *source)
1046 {
1047  dest->data = gnutls_malloc(source->size);
1048  CRM_ASSERT(dest->data);
1049  memcpy(dest->data, source->data, source->size);
1050  dest->size = source->size;
1051 }
1052 
1053 static void
1054 clear_gnutls_datum(gnutls_datum_t *datum)
1055 {
1056  gnutls_free(datum->data);
1057  datum->data = NULL;
1058  datum->size = 0;
1059 }
1060 
1061 #define KEY_READ_LEN 256
1062 
1063 static int
1064 set_key(gnutls_datum_t * key, const char *location)
1065 {
1066  FILE *stream;
1067  size_t buf_len = KEY_READ_LEN;
1068  static gnutls_datum_t key_cache = { 0, };
1069  static time_t key_cache_updated = 0;
1070 
1071  if (location == NULL) {
1072  return -1;
1073  }
1074 
1075  if (key_cache.data != NULL) {
1076  if ((time(NULL) - key_cache_updated) < 60) {
1077  copy_gnutls_datum(key, &key_cache);
1078  crm_debug("Using cached Pacemaker Remote key");
1079  return 0;
1080  } else {
1081  clear_gnutls_datum(&key_cache);
1082  key_cache_updated = 0;
1083  crm_debug("Cleared Pacemaker Remote key cache");
1084  }
1085  }
1086 
1087  stream = fopen(location, "r");
1088  if (!stream) {
1089  return -1;
1090  }
1091 
1092  key->data = gnutls_malloc(buf_len);
1093  key->size = 0;
1094  while (!feof(stream)) {
1095  int next = fgetc(stream);
1096 
1097  if (next == EOF) {
1098  if (!feof(stream)) {
1099  crm_err("Error reading Pacemaker Remote key; copy in memory may be corrupted");
1100  }
1101  break;
1102  }
1103  if (key->size == buf_len) {
1104  buf_len = key->size + KEY_READ_LEN;
1105  key->data = gnutls_realloc(key->data, buf_len);
1106  CRM_ASSERT(key->data);
1107  }
1108  key->data[key->size++] = (unsigned char) next;
1109  }
1110  fclose(stream);
1111 
1112  if (key->size == 0) {
1113  clear_gnutls_datum(key);
1114  return -1;
1115  }
1116 
1117  if (key_cache.data == NULL) {
1118  copy_gnutls_datum(&key_cache, key);
1119  key_cache_updated = time(NULL);
1120  crm_debug("Cached Pacemaker Remote key");
1121  }
1122 
1123  return 0;
1124 }
1125 
1126 int
1127 lrmd_tls_set_key(gnutls_datum_t * key)
1128 {
1129  const char *specific_location = getenv("PCMK_authkey_location");
1130 
1131  if (set_key(key, specific_location) == 0) {
1132  crm_debug("Using custom authkey location %s", specific_location);
1133  return pcmk_ok;
1134 
1135  } else if (specific_location) {
1136  crm_err("No valid Pacemaker Remote key found at %s, trying default location", specific_location);
1137  }
1138 
1139  if ((set_key(key, DEFAULT_REMOTE_KEY_LOCATION) != 0)
1140  && (set_key(key, ALT_REMOTE_KEY_LOCATION) != 0)) {
1141  crm_err("No valid Pacemaker Remote key found at %s", DEFAULT_REMOTE_KEY_LOCATION);
1142  return -ENOKEY;
1143  }
1144 
1145  return pcmk_ok;
1146 }
1147 
1148 static void
1149 lrmd_gnutls_global_init(void)
1150 {
1151  static int gnutls_init = 0;
1152 
1153  if (!gnutls_init) {
1154  crm_gnutls_global_init();
1155  }
1156  gnutls_init = 1;
1157 }
1158 #endif
1159 
1160 static void
1161 report_async_connection_result(lrmd_t * lrmd, int rc)
1162 {
1163  lrmd_private_t *native = lrmd->lrmd_private;
1164 
1165  if (native->callback) {
1166  lrmd_event_data_t event = { 0, };
1167  event.type = lrmd_event_connect;
1168  event.remote_nodename = native->remote_nodename;
1169  event.connection_rc = rc;
1170  native->callback(&event);
1171  }
1172 }
1173 
1174 #ifdef HAVE_GNUTLS_GNUTLS_H
1175 static inline int
1176 lrmd__tls_client_handshake(pcmk__remote_t *remote)
1177 {
1178  return pcmk__tls_client_handshake(remote, LRMD_CLIENT_HANDSHAKE_TIMEOUT);
1179 }
1180 
1181 static void
1182 lrmd_tcp_connect_cb(void *userdata, int rc, int sock)
1183 {
1184  lrmd_t *lrmd = userdata;
1185  lrmd_private_t *native = lrmd->lrmd_private;
1186  char *name;
1187  static struct mainloop_fd_callbacks lrmd_tls_callbacks = {
1188  .dispatch = lrmd_tls_dispatch,
1189  .destroy = lrmd_tls_connection_destroy,
1190  };
1191  gnutls_datum_t psk_key = { NULL, 0 };
1192 
1193  native->async_timer = 0;
1194 
1195  if (rc != pcmk_rc_ok) {
1196  lrmd_tls_connection_destroy(lrmd);
1197  crm_info("Could not connect to Pacemaker Remote at %s:%d: %s "
1198  CRM_XS " rc=%d",
1199  native->server, native->port, pcmk_rc_str(rc), rc);
1200  report_async_connection_result(lrmd, pcmk_rc2legacy(rc));
1201  return;
1202  }
1203 
1204  /* The TCP connection was successful, so establish the TLS connection.
1205  * @TODO make this async to avoid blocking code in client
1206  */
1207 
1208  native->sock = sock;
1209 
1210  rc = lrmd_tls_set_key(&psk_key);
1211  if (rc != 0) {
1212  crm_warn("Could not set key for Pacemaker Remote at %s:%d " CRM_XS " rc=%d",
1213  native->server, native->port, rc);
1214  lrmd_tls_connection_destroy(lrmd);
1215  report_async_connection_result(lrmd, rc);
1216  return;
1217  }
1218 
1219  gnutls_psk_allocate_client_credentials(&native->psk_cred_c);
1220  gnutls_psk_set_client_credentials(native->psk_cred_c, DEFAULT_REMOTE_USERNAME, &psk_key, GNUTLS_PSK_KEY_RAW);
1221  gnutls_free(psk_key.data);
1222 
1223  native->remote->tls_session = pcmk__new_tls_session(sock, GNUTLS_CLIENT,
1224  GNUTLS_CRD_PSK,
1225  native->psk_cred_c);
1226  if (native->remote->tls_session == NULL) {
1227  lrmd_tls_connection_destroy(lrmd);
1228  report_async_connection_result(lrmd, -EPROTO);
1229  return;
1230  }
1231 
1232  if (lrmd__tls_client_handshake(native->remote) != pcmk_rc_ok) {
1233  crm_warn("Disconnecting after TLS handshake with Pacemaker Remote server %s:%d failed",
1234  native->server, native->port);
1235  gnutls_deinit(*native->remote->tls_session);
1236  gnutls_free(native->remote->tls_session);
1237  native->remote->tls_session = NULL;
1238  lrmd_tls_connection_destroy(lrmd);
1239  report_async_connection_result(lrmd, -EKEYREJECTED);
1240  return;
1241  }
1242 
1243  crm_info("TLS connection to Pacemaker Remote server %s:%d succeeded",
1244  native->server, native->port);
1245 
1246  name = crm_strdup_printf("pacemaker-remote-%s:%d",
1247  native->server, native->port);
1248 
1249  native->process_notify = mainloop_add_trigger(G_PRIORITY_HIGH, lrmd_tls_dispatch, lrmd);
1250  native->source =
1251  mainloop_add_fd(name, G_PRIORITY_HIGH, native->sock, lrmd, &lrmd_tls_callbacks);
1252 
1253  rc = lrmd_handshake(lrmd, name);
1254  free(name);
1255 
1256  report_async_connection_result(lrmd, rc);
1257  return;
1258 }
1259 
1260 static int
1261 lrmd_tls_connect_async(lrmd_t * lrmd, int timeout /*ms */ )
1262 {
1263  int rc;
1264  int timer_id = 0;
1265  lrmd_private_t *native = lrmd->lrmd_private;
1266 
1267  lrmd_gnutls_global_init();
1268  native->sock = -1;
1269  rc = pcmk__connect_remote(native->server, native->port, timeout, &timer_id,
1270  &(native->sock), lrmd, lrmd_tcp_connect_cb);
1271  if (rc != pcmk_rc_ok) {
1272  crm_warn("Pacemaker Remote connection to %s:%s failed: %s "
1273  CRM_XS " rc=%d",
1274  native->server, native->port, pcmk_rc_str(rc), rc);
1275  return -1;
1276  }
1277  native->async_timer = timer_id;
1278  return pcmk_ok;
1279 }
1280 
1281 static int
1282 lrmd_tls_connect(lrmd_t * lrmd, int *fd)
1283 {
1284  static struct mainloop_fd_callbacks lrmd_tls_callbacks = {
1285  .dispatch = lrmd_tls_dispatch,
1286  .destroy = lrmd_tls_connection_destroy,
1287  };
1288  int rc;
1289 
1290  lrmd_private_t *native = lrmd->lrmd_private;
1291  gnutls_datum_t psk_key = { NULL, 0 };
1292 
1293  lrmd_gnutls_global_init();
1294 
1295  native->sock = -1;
1296  rc = pcmk__connect_remote(native->server, native->port, 0, NULL,
1297  &(native->sock), NULL, NULL);
1298  if (rc != pcmk_rc_ok) {
1299  crm_warn("Pacemaker Remote connection to %s:%s failed: %s "
1300  CRM_XS " rc=%d",
1301  native->server, native->port, pcmk_rc_str(rc), rc);
1302  lrmd_tls_connection_destroy(lrmd);
1303  return -ENOTCONN;
1304  }
1305 
1306  rc = lrmd_tls_set_key(&psk_key);
1307  if (rc < 0) {
1308  lrmd_tls_connection_destroy(lrmd);
1309  return rc;
1310  }
1311 
1312  gnutls_psk_allocate_client_credentials(&native->psk_cred_c);
1313  gnutls_psk_set_client_credentials(native->psk_cred_c, DEFAULT_REMOTE_USERNAME, &psk_key, GNUTLS_PSK_KEY_RAW);
1314  gnutls_free(psk_key.data);
1315 
1316  native->remote->tls_session = pcmk__new_tls_session(native->sock, GNUTLS_CLIENT,
1317  GNUTLS_CRD_PSK,
1318  native->psk_cred_c);
1319  if (native->remote->tls_session == NULL) {
1320  lrmd_tls_connection_destroy(lrmd);
1321  return -EPROTO;
1322  }
1323 
1324  if (lrmd__tls_client_handshake(native->remote) != pcmk_rc_ok) {
1325  crm_err("Session creation for %s:%d failed", native->server, native->port);
1326  gnutls_deinit(*native->remote->tls_session);
1327  gnutls_free(native->remote->tls_session);
1328  native->remote->tls_session = NULL;
1329  lrmd_tls_connection_destroy(lrmd);
1330  return -EKEYREJECTED;
1331  }
1332 
1333  crm_info("Client TLS connection established with Pacemaker Remote server %s:%d", native->server,
1334  native->port);
1335 
1336  if (fd) {
1337  *fd = native->sock;
1338  } else {
1339  char *name = crm_strdup_printf("pacemaker-remote-%s:%d",
1340  native->server, native->port);
1341 
1342  native->process_notify = mainloop_add_trigger(G_PRIORITY_HIGH, lrmd_tls_dispatch, lrmd);
1343  native->source =
1344  mainloop_add_fd(name, G_PRIORITY_HIGH, native->sock, lrmd, &lrmd_tls_callbacks);
1345  free(name);
1346  }
1347  return pcmk_ok;
1348 }
1349 #endif
1350 
1351 static int
1352 lrmd_api_connect(lrmd_t * lrmd, const char *name, int *fd)
1353 {
1354  int rc = -ENOTCONN;
1355  lrmd_private_t *native = lrmd->lrmd_private;
1356 
1357  switch (native->type) {
1358  case PCMK__CLIENT_IPC:
1359  rc = lrmd_ipc_connect(lrmd, fd);
1360  break;
1361 #ifdef HAVE_GNUTLS_GNUTLS_H
1362  case PCMK__CLIENT_TLS:
1363  rc = lrmd_tls_connect(lrmd, fd);
1364  break;
1365 #endif
1366  default:
1367  crm_err("Unsupported connection type: %d", native->type);
1368  }
1369 
1370  if (rc == pcmk_ok) {
1371  rc = lrmd_handshake(lrmd, name);
1372  }
1373 
1374  return rc;
1375 }
1376 
1377 static int
1378 lrmd_api_connect_async(lrmd_t * lrmd, const char *name, int timeout)
1379 {
1380  int rc = 0;
1381  lrmd_private_t *native = lrmd->lrmd_private;
1382 
1383  CRM_CHECK(native && native->callback, return -1);
1384 
1385  switch (native->type) {
1386  case PCMK__CLIENT_IPC:
1387  /* fake async connection with ipc. it should be fast
1388  * enough that we gain very little from async */
1389  rc = lrmd_api_connect(lrmd, name, NULL);
1390  if (!rc) {
1391  report_async_connection_result(lrmd, rc);
1392  }
1393  break;
1394 #ifdef HAVE_GNUTLS_GNUTLS_H
1395  case PCMK__CLIENT_TLS:
1396  rc = lrmd_tls_connect_async(lrmd, timeout);
1397  if (rc) {
1398  /* connection failed, report rc now */
1399  report_async_connection_result(lrmd, rc);
1400  }
1401  break;
1402 #endif
1403  default:
1404  crm_err("Unsupported connection type: %d", native->type);
1405  }
1406 
1407  return rc;
1408 }
1409 
1410 static void
1411 lrmd_ipc_disconnect(lrmd_t * lrmd)
1412 {
1413  lrmd_private_t *native = lrmd->lrmd_private;
1414 
1415  if (native->source != NULL) {
1416  /* Attached to mainloop */
1417  mainloop_del_ipc_client(native->source);
1418  native->source = NULL;
1419  native->ipc = NULL;
1420 
1421  } else if (native->ipc) {
1422  /* Not attached to mainloop */
1423  crm_ipc_t *ipc = native->ipc;
1424 
1425  native->ipc = NULL;
1426  crm_ipc_close(ipc);
1427  crm_ipc_destroy(ipc);
1428  }
1429 }
1430 
1431 #ifdef HAVE_GNUTLS_GNUTLS_H
1432 static void
1433 lrmd_tls_disconnect(lrmd_t * lrmd)
1434 {
1435  lrmd_private_t *native = lrmd->lrmd_private;
1436 
1437  if (native->remote->tls_session) {
1438  gnutls_bye(*native->remote->tls_session, GNUTLS_SHUT_RDWR);
1439  gnutls_deinit(*native->remote->tls_session);
1440  gnutls_free(native->remote->tls_session);
1441  native->remote->tls_session = 0;
1442  }
1443 
1444  if (native->async_timer) {
1445  g_source_remove(native->async_timer);
1446  native->async_timer = 0;
1447  }
1448 
1449  if (native->source != NULL) {
1450  /* Attached to mainloop */
1451  mainloop_del_ipc_client(native->source);
1452  native->source = NULL;
1453 
1454  } else if (native->sock) {
1455  close(native->sock);
1456  native->sock = 0;
1457  }
1458 
1459  if (native->pending_notify) {
1460  g_list_free_full(native->pending_notify, lrmd_free_xml);
1461  native->pending_notify = NULL;
1462  }
1463 }
1464 #endif
1465 
1466 static int
1467 lrmd_api_disconnect(lrmd_t * lrmd)
1468 {
1469  lrmd_private_t *native = lrmd->lrmd_private;
1470 
1471  crm_info("Disconnecting %s %s executor connection",
1472  pcmk__client_type_str(native->type),
1473  (native->remote_nodename? native->remote_nodename : "local"));
1474  switch (native->type) {
1475  case PCMK__CLIENT_IPC:
1476  lrmd_ipc_disconnect(lrmd);
1477  break;
1478 #ifdef HAVE_GNUTLS_GNUTLS_H
1479  case PCMK__CLIENT_TLS:
1480  lrmd_tls_disconnect(lrmd);
1481  break;
1482 #endif
1483  default:
1484  crm_err("Unsupported connection type: %d", native->type);
1485  }
1486 
1487  free(native->token);
1488  native->token = NULL;
1489 
1490  free(native->peer_version);
1491  native->peer_version = NULL;
1492  return 0;
1493 }
1494 
1495 static int
1496 lrmd_api_register_rsc(lrmd_t * lrmd,
1497  const char *rsc_id,
1498  const char *class,
1499  const char *provider, const char *type, enum lrmd_call_options options)
1500 {
1501  int rc = pcmk_ok;
1502  xmlNode *data = NULL;
1503 
1504  if (!class || !type || !rsc_id) {
1505  return -EINVAL;
1506  }
1507  if (is_set(pcmk_get_ra_caps(class), pcmk_ra_cap_provider) && !provider) {
1508  return -EINVAL;
1509  }
1510 
1511  data = create_xml_node(NULL, F_LRMD_RSC);
1512 
1513  crm_xml_add(data, F_LRMD_ORIGIN, __FUNCTION__);
1514  crm_xml_add(data, F_LRMD_RSC_ID, rsc_id);
1515  crm_xml_add(data, F_LRMD_CLASS, class);
1516  crm_xml_add(data, F_LRMD_PROVIDER, provider);
1517  crm_xml_add(data, F_LRMD_TYPE, type);
1518  rc = lrmd_send_command(lrmd, LRMD_OP_RSC_REG, data, NULL, 0, options, TRUE);
1519  free_xml(data);
1520 
1521  return rc;
1522 }
1523 
1524 static int
1525 lrmd_api_unregister_rsc(lrmd_t * lrmd, const char *rsc_id, enum lrmd_call_options options)
1526 {
1527  int rc = pcmk_ok;
1528  xmlNode *data = create_xml_node(NULL, F_LRMD_RSC);
1529 
1530  crm_xml_add(data, F_LRMD_ORIGIN, __FUNCTION__);
1531  crm_xml_add(data, F_LRMD_RSC_ID, rsc_id);
1532  rc = lrmd_send_command(lrmd, LRMD_OP_RSC_UNREG, data, NULL, 0, options, TRUE);
1533  free_xml(data);
1534 
1535  return rc;
1536 }
1537 
1539 lrmd_new_rsc_info(const char *rsc_id, const char *standard,
1540  const char *provider, const char *type)
1541 {
1542  lrmd_rsc_info_t *rsc_info = calloc(1, sizeof(lrmd_rsc_info_t));
1543 
1544  CRM_ASSERT(rsc_info);
1545  if (rsc_id) {
1546  rsc_info->id = strdup(rsc_id);
1547  CRM_ASSERT(rsc_info->id);
1548  }
1549  if (standard) {
1550  rsc_info->standard = strdup(standard);
1551  CRM_ASSERT(rsc_info->standard);
1552  }
1553  if (provider) {
1554  rsc_info->provider = strdup(provider);
1555  CRM_ASSERT(rsc_info->provider);
1556  }
1557  if (type) {
1558  rsc_info->type = strdup(type);
1559  CRM_ASSERT(rsc_info->type);
1560  }
1561  return rsc_info;
1562 }
1563 
1566 {
1567  return lrmd_new_rsc_info(rsc_info->id, rsc_info->standard,
1568  rsc_info->provider, rsc_info->type);
1569 }
1570 
1571 void
1573 {
1574  if (!rsc_info) {
1575  return;
1576  }
1577  free(rsc_info->id);
1578  free(rsc_info->type);
1579  free(rsc_info->standard);
1580  free(rsc_info->provider);
1581  free(rsc_info);
1582 }
1583 
1584 static lrmd_rsc_info_t *
1585 lrmd_api_get_rsc_info(lrmd_t * lrmd, const char *rsc_id, enum lrmd_call_options options)
1586 {
1587  lrmd_rsc_info_t *rsc_info = NULL;
1588  xmlNode *data = create_xml_node(NULL, F_LRMD_RSC);
1589  xmlNode *output = NULL;
1590  const char *class = NULL;
1591  const char *provider = NULL;
1592  const char *type = NULL;
1593 
1594  crm_xml_add(data, F_LRMD_ORIGIN, __FUNCTION__);
1595  crm_xml_add(data, F_LRMD_RSC_ID, rsc_id);
1596  lrmd_send_command(lrmd, LRMD_OP_RSC_INFO, data, &output, 0, options, TRUE);
1597  free_xml(data);
1598 
1599  if (!output) {
1600  return NULL;
1601  }
1602 
1603  class = crm_element_value(output, F_LRMD_CLASS);
1604  provider = crm_element_value(output, F_LRMD_PROVIDER);
1605  type = crm_element_value(output, F_LRMD_TYPE);
1606 
1607  if (!class || !type) {
1608  free_xml(output);
1609  return NULL;
1610  } else if (is_set(pcmk_get_ra_caps(class), pcmk_ra_cap_provider)
1611  && !provider) {
1612  free_xml(output);
1613  return NULL;
1614  }
1615 
1616  rsc_info = lrmd_new_rsc_info(rsc_id, class, provider, type);
1617  free_xml(output);
1618  return rsc_info;
1619 }
1620 
1621 void
1623 {
1624  if (op_info) {
1625  free(op_info->rsc_id);
1626  free(op_info->action);
1627  free(op_info->interval_ms_s);
1628  free(op_info->timeout_ms_s);
1629  free(op_info);
1630  }
1631 }
1632 
1633 static int
1634 lrmd_api_get_recurring_ops(lrmd_t *lrmd, const char *rsc_id, int timeout_ms,
1635  enum lrmd_call_options options, GList **output)
1636 {
1637  xmlNode *data = NULL;
1638  xmlNode *output_xml = NULL;
1639  int rc = pcmk_ok;
1640 
1641  if (output == NULL) {
1642  return -EINVAL;
1643  }
1644  *output = NULL;
1645 
1646  // Send request
1647  if (rsc_id) {
1648  data = create_xml_node(NULL, F_LRMD_RSC);
1649  crm_xml_add(data, F_LRMD_ORIGIN, __FUNCTION__);
1650  crm_xml_add(data, F_LRMD_RSC_ID, rsc_id);
1651  }
1652  rc = lrmd_send_command(lrmd, LRMD_OP_GET_RECURRING, data, &output_xml,
1653  timeout_ms, options, TRUE);
1654  if (data) {
1655  free_xml(data);
1656  }
1657 
1658  // Process reply
1659  if ((rc != pcmk_ok) || (output_xml == NULL)) {
1660  return rc;
1661  }
1662  for (xmlNode *rsc_xml = first_named_child(output_xml, F_LRMD_RSC);
1663  rsc_xml != NULL; rsc_xml = crm_next_same_xml(rsc_xml)) {
1664 
1665  rsc_id = crm_element_value(rsc_xml, F_LRMD_RSC_ID);
1666  if (rsc_id == NULL) {
1667  crm_err("Could not parse recurring operation information from executor");
1668  continue;
1669  }
1670  for (xmlNode *op_xml = first_named_child(rsc_xml, T_LRMD_RSC_OP);
1671  op_xml != NULL; op_xml = crm_next_same_xml(op_xml)) {
1672 
1673  lrmd_op_info_t *op_info = calloc(1, sizeof(lrmd_op_info_t));
1674 
1675  CRM_CHECK(op_info != NULL, break);
1676  op_info->rsc_id = strdup(rsc_id);
1677  op_info->action = crm_element_value_copy(op_xml, F_LRMD_RSC_ACTION);
1678  op_info->interval_ms_s = crm_element_value_copy(op_xml,
1680  op_info->timeout_ms_s = crm_element_value_copy(op_xml,
1681  F_LRMD_TIMEOUT);
1682  *output = g_list_prepend(*output, op_info);
1683  }
1684  }
1685  free_xml(output_xml);
1686  return rc;
1687 }
1688 
1689 
1690 static void
1691 lrmd_api_set_callback(lrmd_t * lrmd, lrmd_event_callback callback)
1692 {
1693  lrmd_private_t *native = lrmd->lrmd_private;
1694 
1695  native->callback = callback;
1696 }
1697 
1698 void
1699 lrmd_internal_set_proxy_callback(lrmd_t * lrmd, void *userdata, void (*callback)(lrmd_t *lrmd, void *userdata, xmlNode *msg))
1700 {
1701  lrmd_private_t *native = lrmd->lrmd_private;
1702 
1703  native->proxy_callback = callback;
1704  native->proxy_callback_userdata = userdata;
1705 }
1706 
1707 void
1708 lrmd_internal_proxy_dispatch(lrmd_t *lrmd, xmlNode *msg)
1709 {
1710  lrmd_private_t *native = lrmd->lrmd_private;
1711 
1712  if (native->proxy_callback) {
1713  crm_log_xml_trace(msg, "PROXY_INBOUND");
1714  native->proxy_callback(lrmd, native->proxy_callback_userdata, msg);
1715  }
1716 }
1717 
1718 int
1719 lrmd_internal_proxy_send(lrmd_t * lrmd, xmlNode *msg)
1720 {
1721  if (lrmd == NULL) {
1722  return -ENOTCONN;
1723  }
1725 
1726  crm_log_xml_trace(msg, "PROXY_OUTBOUND");
1727  return lrmd_send_xml_no_reply(lrmd, msg);
1728 }
1729 
1730 static int
1731 stonith_get_metadata(const char *provider, const char *type, char **output)
1732 {
1733  int rc = pcmk_ok;
1734  stonith_t *stonith_api = stonith_api_new();
1735 
1736  if (stonith_api == NULL) {
1737  crm_err("Could not get fence agent meta-data: API memory allocation failed");
1738  return -ENOMEM;
1739  }
1740 
1741  rc = stonith_api->cmds->metadata(stonith_api, st_opt_sync_call, type,
1742  provider, output, 0);
1743  if ((rc == pcmk_ok) && (*output == NULL)) {
1744  rc = -EIO;
1745  }
1746  stonith_api->cmds->free(stonith_api);
1747  return rc;
1748 }
1749 
1750 static int
1751 lrmd_api_get_metadata(lrmd_t *lrmd, const char *standard, const char *provider,
1752  const char *type, char **output,
1753  enum lrmd_call_options options)
1754 {
1755  return lrmd->cmds->get_metadata_params(lrmd, standard, provider, type,
1756  output, options, NULL);
1757 }
1758 
1759 static int
1760 lrmd_api_get_metadata_params(lrmd_t *lrmd, const char *standard,
1761  const char *provider, const char *type,
1762  char **output, enum lrmd_call_options options,
1763  lrmd_key_value_t *params)
1764 {
1765  svc_action_t *action = NULL;
1766  GHashTable *params_table = NULL;
1767 
1768  if (!standard || !type) {
1769  lrmd_key_value_freeall(params);
1770  return -EINVAL;
1771  }
1772 
1773  if (safe_str_eq(standard, PCMK_RESOURCE_CLASS_STONITH)) {
1774  lrmd_key_value_freeall(params);
1775  return stonith_get_metadata(provider, type, output);
1776  }
1777 
1778  params_table = crm_str_table_new();
1779  for (const lrmd_key_value_t *param = params; param; param = param->next) {
1780  g_hash_table_insert(params_table, strdup(param->key), strdup(param->value));
1781  }
1782  action = resources_action_create(type, standard, provider, type,
1784  CRMD_METADATA_CALL_TIMEOUT, params_table,
1785  0);
1786  lrmd_key_value_freeall(params);
1787 
1788  if (action == NULL) {
1789  crm_err("Unable to retrieve meta-data for %s:%s:%s",
1790  standard, provider, type);
1791  return -EINVAL;
1792  }
1793 
1794  if (!services_action_sync(action)) {
1795  crm_err("Failed to retrieve meta-data for %s:%s:%s",
1796  standard, provider, type);
1797  services_action_free(action);
1798  return -EIO;
1799  }
1800 
1801  if (!action->stdout_data) {
1802  crm_err("Failed to receive meta-data for %s:%s:%s",
1803  standard, provider, type);
1804  services_action_free(action);
1805  return -EIO;
1806  }
1807 
1808  *output = strdup(action->stdout_data);
1809  services_action_free(action);
1810 
1811  return pcmk_ok;
1812 }
1813 
1814 static int
1815 lrmd_api_exec(lrmd_t *lrmd, const char *rsc_id, const char *action,
1816  const char *userdata, guint interval_ms,
1817  int timeout, /* ms */
1818  int start_delay, /* ms */
1819  enum lrmd_call_options options, lrmd_key_value_t * params)
1820 {
1821  int rc = pcmk_ok;
1822  xmlNode *data = create_xml_node(NULL, F_LRMD_RSC);
1823  xmlNode *args = create_xml_node(data, XML_TAG_ATTRS);
1824  lrmd_key_value_t *tmp = NULL;
1825 
1826  crm_xml_add(data, F_LRMD_ORIGIN, __FUNCTION__);
1827  crm_xml_add(data, F_LRMD_RSC_ID, rsc_id);
1828  crm_xml_add(data, F_LRMD_RSC_ACTION, action);
1829  crm_xml_add(data, F_LRMD_RSC_USERDATA_STR, userdata);
1830  crm_xml_add_ms(data, F_LRMD_RSC_INTERVAL, interval_ms);
1831  crm_xml_add_int(data, F_LRMD_TIMEOUT, timeout);
1832  crm_xml_add_int(data, F_LRMD_RSC_START_DELAY, start_delay);
1833 
1834  for (tmp = params; tmp; tmp = tmp->next) {
1835  hash2smartfield((gpointer) tmp->key, (gpointer) tmp->value, args);
1836  }
1837 
1838  rc = lrmd_send_command(lrmd, LRMD_OP_RSC_EXEC, data, NULL, timeout, options, TRUE);
1839  free_xml(data);
1840 
1841  lrmd_key_value_freeall(params);
1842  return rc;
1843 }
1844 
1845 /* timeout is in ms */
1846 static int
1847 lrmd_api_exec_alert(lrmd_t *lrmd, const char *alert_id, const char *alert_path,
1848  int timeout, lrmd_key_value_t *params)
1849 {
1850  int rc = pcmk_ok;
1851  xmlNode *data = create_xml_node(NULL, F_LRMD_ALERT);
1852  xmlNode *args = create_xml_node(data, XML_TAG_ATTRS);
1853  lrmd_key_value_t *tmp = NULL;
1854 
1855  crm_xml_add(data, F_LRMD_ORIGIN, __FUNCTION__);
1856  crm_xml_add(data, F_LRMD_ALERT_ID, alert_id);
1857  crm_xml_add(data, F_LRMD_ALERT_PATH, alert_path);
1858  crm_xml_add_int(data, F_LRMD_TIMEOUT, timeout);
1859 
1860  for (tmp = params; tmp; tmp = tmp->next) {
1861  hash2smartfield((gpointer) tmp->key, (gpointer) tmp->value, args);
1862  }
1863 
1864  rc = lrmd_send_command(lrmd, LRMD_OP_ALERT_EXEC, data, NULL, timeout,
1866  free_xml(data);
1867 
1868  lrmd_key_value_freeall(params);
1869  return rc;
1870 }
1871 
1872 static int
1873 lrmd_api_cancel(lrmd_t *lrmd, const char *rsc_id, const char *action,
1874  guint interval_ms)
1875 {
1876  int rc = pcmk_ok;
1877  xmlNode *data = create_xml_node(NULL, F_LRMD_RSC);
1878 
1879  crm_xml_add(data, F_LRMD_ORIGIN, __FUNCTION__);
1880  crm_xml_add(data, F_LRMD_RSC_ACTION, action);
1881  crm_xml_add(data, F_LRMD_RSC_ID, rsc_id);
1882  crm_xml_add_ms(data, F_LRMD_RSC_INTERVAL, interval_ms);
1883  rc = lrmd_send_command(lrmd, LRMD_OP_RSC_CANCEL, data, NULL, 0, 0, TRUE);
1884  free_xml(data);
1885  return rc;
1886 }
1887 
1888 static int
1889 list_stonith_agents(lrmd_list_t ** resources)
1890 {
1891  int rc = 0;
1892  stonith_t *stonith_api = stonith_api_new();
1893  stonith_key_value_t *stonith_resources = NULL;
1894  stonith_key_value_t *dIter = NULL;
1895 
1896  if (stonith_api == NULL) {
1897  crm_err("Could not list fence agents: API memory allocation failed");
1898  return -ENOMEM;
1899  }
1900  stonith_api->cmds->list_agents(stonith_api, st_opt_sync_call, NULL,
1901  &stonith_resources, 0);
1902  stonith_api->cmds->free(stonith_api);
1903 
1904  for (dIter = stonith_resources; dIter; dIter = dIter->next) {
1905  rc++;
1906  if (resources) {
1907  *resources = lrmd_list_add(*resources, dIter->value);
1908  }
1909  }
1910 
1911  stonith_key_value_freeall(stonith_resources, 1, 0);
1912  return rc;
1913 }
1914 
1915 static int
1916 lrmd_api_list_agents(lrmd_t * lrmd, lrmd_list_t ** resources, const char *class,
1917  const char *provider)
1918 {
1919  int rc = 0;
1920  int stonith_count = 0; // Initially, whether to include stonith devices
1921 
1923  stonith_count = 1;
1924 
1925  } else {
1926  GListPtr gIter = NULL;
1927  GList *agents = resources_list_agents(class, provider);
1928 
1929  for (gIter = agents; gIter != NULL; gIter = gIter->next) {
1930  *resources = lrmd_list_add(*resources, (const char *)gIter->data);
1931  rc++;
1932  }
1933  g_list_free_full(agents, free);
1934 
1935  if (!class) {
1936  stonith_count = 1;
1937  }
1938  }
1939 
1940  if (stonith_count) {
1941  // Now, if stonith devices are included, how many there are
1942  stonith_count = list_stonith_agents(resources);
1943  if (stonith_count > 0) {
1944  rc += stonith_count;
1945  }
1946  }
1947  if (rc == 0) {
1948  crm_notice("No agents found for class %s", class);
1949  rc = -EPROTONOSUPPORT;
1950  }
1951  return rc;
1952 }
1953 
1954 static int
1955 does_provider_have_agent(const char *agent, const char *provider, const char *class)
1956 {
1957  int found = 0;
1958  GList *agents = NULL;
1959  GListPtr gIter2 = NULL;
1960 
1961  agents = resources_list_agents(class, provider);
1962  for (gIter2 = agents; gIter2 != NULL; gIter2 = gIter2->next) {
1963  if (safe_str_eq(agent, gIter2->data)) {
1964  found = 1;
1965  }
1966  }
1967  g_list_free_full(agents, free);
1968 
1969  return found;
1970 }
1971 
1972 static int
1973 lrmd_api_list_ocf_providers(lrmd_t * lrmd, const char *agent, lrmd_list_t ** providers)
1974 {
1975  int rc = pcmk_ok;
1976  char *provider = NULL;
1977  GList *ocf_providers = NULL;
1978  GListPtr gIter = NULL;
1979 
1981 
1982  for (gIter = ocf_providers; gIter != NULL; gIter = gIter->next) {
1983  provider = gIter->data;
1984  if (!agent || does_provider_have_agent(agent, provider,
1986  *providers = lrmd_list_add(*providers, (const char *)gIter->data);
1987  rc++;
1988  }
1989  }
1990 
1991  g_list_free_full(ocf_providers, free);
1992  return rc;
1993 }
1994 
1995 static int
1996 lrmd_api_list_standards(lrmd_t * lrmd, lrmd_list_t ** supported)
1997 {
1998  int rc = 0;
1999  GList *standards = NULL;
2000  GListPtr gIter = NULL;
2001 
2002  standards = resources_list_standards();
2003 
2004  for (gIter = standards; gIter != NULL; gIter = gIter->next) {
2005  *supported = lrmd_list_add(*supported, (const char *)gIter->data);
2006  rc++;
2007  }
2008 
2009  if (list_stonith_agents(NULL) > 0) {
2010  *supported = lrmd_list_add(*supported, PCMK_RESOURCE_CLASS_STONITH);
2011  rc++;
2012  }
2013 
2014  g_list_free_full(standards, free);
2015  return rc;
2016 }
2017 
2018 lrmd_t *
2020 {
2021  lrmd_t *new_lrmd = NULL;
2022  lrmd_private_t *pvt = NULL;
2023 
2024  new_lrmd = calloc(1, sizeof(lrmd_t));
2025  pvt = calloc(1, sizeof(lrmd_private_t));
2026  pvt->remote = calloc(1, sizeof(pcmk__remote_t));
2027  new_lrmd->cmds = calloc(1, sizeof(lrmd_api_operations_t));
2028 
2029  pvt->type = PCMK__CLIENT_IPC;
2030  new_lrmd->lrmd_private = pvt;
2031 
2032  new_lrmd->cmds->connect = lrmd_api_connect;
2033  new_lrmd->cmds->connect_async = lrmd_api_connect_async;
2034  new_lrmd->cmds->is_connected = lrmd_api_is_connected;
2035  new_lrmd->cmds->poke_connection = lrmd_api_poke_connection;
2036  new_lrmd->cmds->disconnect = lrmd_api_disconnect;
2037  new_lrmd->cmds->register_rsc = lrmd_api_register_rsc;
2038  new_lrmd->cmds->unregister_rsc = lrmd_api_unregister_rsc;
2039  new_lrmd->cmds->get_rsc_info = lrmd_api_get_rsc_info;
2040  new_lrmd->cmds->get_recurring_ops = lrmd_api_get_recurring_ops;
2041  new_lrmd->cmds->set_callback = lrmd_api_set_callback;
2042  new_lrmd->cmds->get_metadata = lrmd_api_get_metadata;
2043  new_lrmd->cmds->exec = lrmd_api_exec;
2044  new_lrmd->cmds->cancel = lrmd_api_cancel;
2045  new_lrmd->cmds->list_agents = lrmd_api_list_agents;
2046  new_lrmd->cmds->list_ocf_providers = lrmd_api_list_ocf_providers;
2047  new_lrmd->cmds->list_standards = lrmd_api_list_standards;
2048  new_lrmd->cmds->exec_alert = lrmd_api_exec_alert;
2049  new_lrmd->cmds->get_metadata_params = lrmd_api_get_metadata_params;
2050 
2051  return new_lrmd;
2052 }
2053 
2054 lrmd_t *
2055 lrmd_remote_api_new(const char *nodename, const char *server, int port)
2056 {
2057 #ifdef HAVE_GNUTLS_GNUTLS_H
2058  lrmd_t *new_lrmd = lrmd_api_new();
2059  lrmd_private_t *native = new_lrmd->lrmd_private;
2060 
2061  if (!nodename && !server) {
2062  lrmd_api_delete(new_lrmd);
2063  return NULL;
2064  }
2065 
2066  native->type = PCMK__CLIENT_TLS;
2067  native->remote_nodename = nodename ? strdup(nodename) : strdup(server);
2068  native->server = server ? strdup(server) : strdup(nodename);
2069  native->port = port;
2070  if (native->port == 0) {
2071  native->port = crm_default_remote_port();
2072  }
2073 
2074  return new_lrmd;
2075 #else
2076  crm_err("Cannot communicate with Pacemaker Remote because GnuTLS is not enabled for this build");
2077  return NULL;
2078 #endif
2079 }
2080 
2081 void
2083 {
2084  if (!lrmd) {
2085  return;
2086  }
2087  lrmd->cmds->disconnect(lrmd); /* no-op if already disconnected */
2088  free(lrmd->cmds);
2089  if (lrmd->lrmd_private) {
2090  lrmd_private_t *native = lrmd->lrmd_private;
2091 
2092 #ifdef HAVE_GNUTLS_GNUTLS_H
2093  free(native->server);
2094 #endif
2095  free(native->remote_nodename);
2096  free(native->remote);
2097  free(native->token);
2098  free(native->peer_version);
2099  }
2100 
2101  free(lrmd->lrmd_private);
2102  free(lrmd);
2103 }
Services API.
#define F_LRMD_RSC
Definition: lrmd.h:87
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:233
char * rsc_id
Definition: lrmd.h:264
#define LRMD_OP_ALERT_EXEC
Definition: lrmd.h:102
int pcmk__remote_send_xml(pcmk__remote_t *remote, xmlNode *msg)
Definition: remote.c:501
#define CRMD_METADATA_CALL_TIMEOUT
Definition: crm.h:187
bool crm_ipc_connect(crm_ipc_t *client)
Establish an IPC connection to a Pacemaker component.
Definition: ipc.c:1158
A dumping ground.
#define F_TYPE
Definition: msg_xml.h:30
#define crm_notice(fmt, args...)
Definition: logging.h:365
int(* get_recurring_ops)(lrmd_t *lrmd, const char *rsc_id, int timeout_ms, enum lrmd_call_options options, GList **output)
Retrieve registered recurring operations.
Definition: lrmd.h:356
#define ETIME
Definition: portability.h:162
int lrmd_tls_send_msg(pcmk__remote_t *session, xmlNode *msg, uint32_t id, const char *msg_type)
int remote_proxy_check(lrmd_t *lrmd, GHashTable *hash)
Definition: lrmd_client.c:926
gboolean safe_str_neq(const char *a, const char *b)
Definition: strings.c:263
void services_action_free(svc_action_t *op)
Definition: services.c:469
lrmd_call_options
Definition: lrmd.h:172
const char * user_data
Definition: lrmd.h:207
mainloop_io_t * mainloop_add_fd(const char *name, int priority, int fd, void *userdata, struct mainloop_fd_callbacks *callbacks)
Definition: mainloop.c:881
#define F_LRMD_IS_IPC_PROVIDER
Definition: lrmd.h:55
const char * rsc_id
Definition: lrmd.h:203
int pcmk_rc2legacy(int rc)
Definition: results.c:430
int(* cancel)(lrmd_t *lrmd, const char *rsc_id, const char *action, guint interval_ms)
Cancel a recurring command.
Definition: lrmd.h:424
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:446
#define F_LRMD_IPC_SESSION
Definition: lrmd.h:116
#define F_LRMD_RSC_EXEC_TIME
Definition: lrmd.h:76
const char * pcmk__client_type_str(enum pcmk__client_type client_type)
Definition: ipc.c:281
#define F_LRMD_RSC_ACTION
Definition: lrmd.h:80
#define LRMD_OP_RSC_CANCEL
Definition: lrmd.h:95
int crm_ipc_get_fd(crm_ipc_t *client)
Definition: ipc.c:1263
#define LRMD_OP_CHECK
Definition: lrmd.h:101
#define F_LRMD_ORIGIN
Definition: lrmd.h:72
#define F_LRMD_RSC_OUTPUT
Definition: lrmd.h:82
int(* poke_connection)(lrmd_t *lrmd)
Poke executor connection to verify it is still capable of serving requests.
Definition: lrmd.h:319
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)
Get resource metadata for a resource agent, passing parameters.
Definition: lrmd.h:525
xmlNode * first_named_child(const xmlNode *parent, const char *name)
Definition: xml.c:4399
void(* set_callback)(lrmd_t *lrmd, lrmd_event_callback callback)
Set a callback for executor events.
Definition: lrmd.h:378
int(* is_connected)(lrmd_t *lrmd)
Is connected to lrmd daemon?
Definition: lrmd.h:310
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:424
#define EKEYREJECTED
Definition: portability.h:174
struct stonith_key_value_s * next
Definition: stonith-ng.h:95
void lrmd_free_op_info(lrmd_op_info_t *op_info)
Definition: lrmd_client.c:1622
char * id
Definition: lrmd.h:257
void lrmd_list_freeall(lrmd_list_t *head)
Definition: lrmd_client.c:129
#define XML_TAG_ATTRS
Definition: msg_xml.h:165
struct mainloop_io_s mainloop_io_t
Definition: mainloop.h:32
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:316
int pcmk__remote_ready(pcmk__remote_t *remote, int timeout_ms)
Definition: remote.c:646
void lrmd_free_event(lrmd_event_data_t *event)
Definition: lrmd_client.c:234
void mainloop_set_trigger(crm_trigger_t *source)
Definition: mainloop.c:171
#define DEFAULT_REMOTE_USERNAME
Definition: lrmd.h:51
svc_action_t * resources_action_create(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:165
#define LRMD_OP_GET_RECURRING
Definition: lrmd.h:103
Resource agent executor.
#define MAX_TLS_RECV_WAIT
Definition: lrmd_client.c:47
int(* free)(stonith_t *st)
Destroy the stonith api structure.
Definition: stonith-ng.h:143
void(* lrmd_event_callback)(lrmd_event_data_t *event)
Definition: lrmd.h:276
int(* dispatch)(gpointer userdata)
Definition: mainloop.h:115
#define F_LRMD_EXEC_RC
Definition: lrmd.h:65
const char * output
Definition: lrmd.h:225
int lrmd_internal_proxy_send(lrmd_t *lrmd, xmlNode *msg)
Definition: lrmd_client.c:1719
#define F_LRMD_WATCHDOG
Definition: lrmd.h:68
#define LRMD_OP_POKE
Definition: lrmd.h:99
#define F_LRMD_ALERT_PATH
Definition: lrmd.h:90
long crm_ipc_read(crm_ipc_t *client)
Definition: ipc.c:1373
gboolean mainloop_destroy_trigger(crm_trigger_t *source)
Definition: mainloop.c:179
const char * pcmk_rc_str(int rc)
Get a user-friendly description of a return code.
Definition: results.c:413
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:2055
int crm_element_value_int(const xmlNode *data, const char *name, int *dest)
Retrieve the integer value of an XML attribute.
Definition: nvpair.c:558
void hash2smartfield(gpointer key, gpointer value, gpointer user_data)
Add hash table entry to XML as (possibly legacy) name/value.
Definition: nvpair.c:750
#define F_LRMD_RSC_ID
Definition: lrmd.h:79
Wrappers for and extensions to glib mainloop.
#define F_LRMD_PROTOCOL_VERSION
Definition: lrmd.h:57
#define F_LRMD_RC
Definition: lrmd.h:64
stonith_t * stonith_api_new(void)
Definition: st_client.c:2111
#define CRM_OP_REGISTER
Definition: crm.h:142
const char * action
Definition: pcmk_fence.c:29
xmlNode * string2xml(const char *input)
Definition: xml.c:2180
int(* exec_alert)(lrmd_t *lrmd, const char *alert_id, const char *alert_path, int timeout, lrmd_key_value_t *params)
Execute an alert agent.
Definition: lrmd.h:504
int(* disconnect)(lrmd_t *lrmd)
Disconnect from the executor.
Definition: lrmd.h:327
const char * crm_ipc_buffer(crm_ipc_t *client)
Definition: ipc.c:1420
const char * val
Definition: lrmd.h:279
#define LRMD_OP_RSC_UNREG
Definition: lrmd.h:96
#define F_LRMD_CLIENTID
Definition: lrmd.h:56
#define CRM_TRACE_INIT_DATA(name)
Definition: logging.h:134
#define DEFAULT_REMOTE_KEY_LOCATION
Definition: lrmd.h:48
struct trigger_s crm_trigger_t
Definition: mainloop.h:31
int(* list_ocf_providers)(lrmd_t *lrmd, const char *agent, lrmd_list_t **providers)
Retrieve a list of resource agent providers.
Definition: lrmd.h:477
struct lrmd_private_s lrmd_private_t
char * interval_ms_s
Definition: lrmd.h:266
void * params
Definition: lrmd.h:240
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:1539
lrmd_rsc_info_t * lrmd_copy_rsc_info(lrmd_rsc_info_t *rsc_info)
Definition: lrmd_client.c:1565
#define crm_warn(fmt, args...)
Definition: logging.h:364
const char * exit_reason
Definition: lrmd.h:248
#define PCMK_RESOURCE_CLASS_OCF
Definition: services.h:43
int rc
Definition: pcmk_fence.c:34
int crm_element_value_ms(const xmlNode *data, const char *name, guint *dest)
Retrieve the millisecond value of an XML attribute.
Definition: nvpair.c:614
#define crm_debug(fmt, args...)
Definition: logging.h:368
struct crm_ipc_s crm_ipc_t
Definition: ipc.h:58
#define F_LRMD_RSC_EXIT_REASON
Definition: lrmd.h:83
char * crm_element_value_copy(const xmlNode *data, const char *name)
Retrieve a copy of the value of an XML attribute.
Definition: nvpair.c:725
#define ALT_REMOTE_KEY_LOCATION
Definition: lrmd.h:49
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
Definition: nvpair.c:522
char * key
Definition: lrmd.h:29
struct lrmd_list_s * next
Definition: lrmd.h:280
gboolean services_action_sync(svc_action_t *op)
Definition: services.c:874
char * stdout_data
Definition: services.h:177
#define F_LRMD_ALERT_ID
Definition: lrmd.h:89
#define LRMD_PROTOCOL_VERSION
Definition: lrmd.h:37
#define F_LRMD_TIMEOUT
Definition: lrmd.h:67
#define F_LRMD_CALLDATA
Definition: lrmd.h:63
#define crm_trace(fmt, args...)
Definition: logging.h:369
#define F_LRMD_TYPE
Definition: lrmd.h:71
#define F_LRMD_CLASS
Definition: lrmd.h:69
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:1076
int(* metadata)(stonith_t *st, int options, const char *device, const char *provider, char **output, int timeout)
Get the metadata documentation for a resource.
Definition: stonith-ng.h:211
crm_trigger_t * mainloop_add_trigger(int priority, int(*dispatch)(gpointer user_data), gpointer userdata)
Definition: mainloop.c:159
lrmd_t * lrmd_api_new(void)
Create a new connection to the local executor.
Definition: lrmd_client.c:2019
#define LRMD_OP_NEW_CLIENT
Definition: lrmd.h:100
xmlNode * create_xml_node(xmlNode *parent, const char *name)
Definition: xml.c:1976
int(* list_agents)(stonith_t *stonith, int call_options, const char *provider, stonith_key_value_t **devices, int timeout)
Retrieve a list of installed stonith agents.
Definition: stonith-ng.h:224
bool lrmd_dispatch(lrmd_t *lrmd)
Use after lrmd_poll returns 1 to read and dispatch a message.
Definition: lrmd_client.c:467
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:649
void stonith_key_value_freeall(stonith_key_value_t *kvp, int keys, int values)
Definition: st_client.c:2238
uint32_t pcmk_get_ra_caps(const char *standard)
Get capabilities of a resource agent standard.
Definition: agents.c:31
lrmd_key_value_t * lrmd_key_value_add(lrmd_key_value_t *kvp, const char *key, const char *value)
Definition: lrmd_client.c:144
#define ECOMM
Definition: portability.h:138
void mainloop_del_ipc_client(mainloop_io_t *client)
Definition: mainloop.c:866
void crm_ipc_destroy(crm_ipc_t *client)
Definition: ipc.c:1240
GList * resources_list_providers(const char *standard)
Get a list of providers.
Definition: services.c:955
struct lrmd_key_value_s * next
Definition: lrmd.h:31
#define F_LRMD_RSC_USERDATA_STR
Definition: lrmd.h:81
gboolean add_message_xml(xmlNode *msg, const char *field, xmlNode *xml)
Definition: xml.c:2627
void free_xml(xmlNode *child)
Definition: xml.c:2136
#define F_LRMD_RSC_INTERVAL
Definition: lrmd.h:85
#define LRMD_OP_RSC_EXEC
Definition: lrmd.h:94
gboolean crm_str_eq(const char *a, const char *b, gboolean use_case)
Definition: strings.c:326
#define F_LRMD_ALERT
Definition: lrmd.h:91
#define F_LRMD_OP_STATUS
Definition: lrmd.h:66
int(* get_metadata)(lrmd_t *lrmd, const char *standard, const char *provider, const char *agent, char **output, enum lrmd_call_options options)
Get resource metadata for a specified resource agent.
Definition: lrmd.h:450
int(* connect_async)(lrmd_t *lrmd, const char *client_name, int timeout)
Initiate an executor connection without blocking.
Definition: lrmd.h:302
#define F_LRMD_RSC_START_DELAY
Definition: lrmd.h:84
const char * op_type
Definition: lrmd.h:205
#define LRMD_OP_RSC_REG
Definition: lrmd.h:93
char * action
Definition: lrmd.h:265
#define ENOKEY
Definition: portability.h:154
bool crm_ipc_connected(crm_ipc_t *client)
Definition: ipc.c:1277
void lrmd_key_value_freeall(lrmd_key_value_t *head)
Definition: lrmd_client.c:167
#define PCMK_RESOURCE_CLASS_STONITH
Definition: services.h:49
#define CRM_XS
Definition: logging.h:54
int crm_ipc_ready(crm_ipc_t *client)
Check whether an IPC connection is ready to be read.
Definition: ipc.c:1309
void * lrmd_private
Definition: lrmd.h:534
#define F_LRMD_RSC_RCCHANGE_TIME
Definition: lrmd.h:75
lrmd_event_data_t * lrmd_new_event(const char *rsc_id, const char *task, guint interval_ms)
Definition: lrmd_client.c:193
char * type
Definition: lrmd.h:258
#define crm_log_xml_err(xml, text)
Definition: logging.h:372
#define F_LRMD_PROVIDER
Definition: lrmd.h:70
#define F_LRMD_REMOTE_MSG_ID
Definition: lrmd.h:59
#define crm_perror(level, fmt, args...)
Send a system error message to both the log and stderr.
Definition: logging.h:314
int(* connect)(lrmd_t *lrmd, const char *client_name, int *fd)
Connect to an executor.
Definition: lrmd.h:293
const char * remote_nodename
Definition: lrmd.h:245
lrmd_api_operations_t * cmds
Definition: lrmd.h:533
crm_ipc_t * mainloop_get_ipc_client(mainloop_io_t *client)
Definition: mainloop.c:872
GList * resources_list_standards(void)
Definition: services.c:915
int(* register_rsc)(lrmd_t *lrmd, const char *rsc_id, const char *standard, const char *provider, const char *agent, enum lrmd_call_options options)
Register a resource with the executor.
Definition: lrmd.h:337
#define crm_err(fmt, args...)
Definition: logging.h:363
#define CRM_ASSERT(expr)
Definition: results.h:42
#define T_LRMD
Definition: lrmd.h:123
enum lrmd_callback_event type
Definition: lrmd.h:200
stonith_api_operations_t * cmds
Definition: stonith-ng.h:425
int crm_ipc_send(crm_ipc_t *client, xmlNode *message, enum crm_ipc_flags flags, int32_t ms_timeout, xmlNode **reply)
Send an IPC XML message.
Definition: ipc.c:1515
GHashTable * crm_str_table_dup(GHashTable *old_table)
Definition: strings.c:495
Fencing aka. STONITH.
#define F_LRMD_CALLID
Definition: lrmd.h:61
#define CRMD_ACTION_METADATA
Definition: crm.h:186
crm_ipc_t * crm_ipc_new(const char *name, size_t max_size)
Definition: ipc.c:1128
#define F_LRMD_CALLOPTS
Definition: lrmd.h:62
int(* unregister_rsc)(lrmd_t *lrmd, const char *rsc_id, enum lrmd_call_options options)
Unregister a resource from the executor.
Definition: lrmd.h:373
GList * resources_list_agents(const char *standard, const char *provider)
Get a list of resource agents.
Definition: services.c:965
#define CRM_SYSTEM_LRMD
Definition: crm.h:103
char * standard
Definition: lrmd.h:259
#define T_LRMD_RSC_OP
Definition: lrmd.h:127
char data[0]
Definition: internal.h:90
GHashTable * xml2list(xmlNode *parent)
Retrieve XML attributes as a hash table.
Definition: nvpair.c:910
lrmd_event_data_t * lrmd_copy_event(lrmd_event_data_t *event)
Definition: lrmd_client.c:211
#define F_LRMD_RSC_RUN_TIME
Definition: lrmd.h:74
char * provider
Definition: lrmd.h:260
int(* exec)(lrmd_t *lrmd, const char *rsc_id, const char *action, const char *userdata, guint interval_ms, int timeout, int start_delay, enum lrmd_call_options options, lrmd_key_value_t *params)
Issue a command on a resource.
Definition: lrmd.h:395
Definition: lrmd.h:532
int lrmd_poll(lrmd_t *lrmd, int timeout)
Poll for a specified timeout period to determine if a message is ready for dispatch.
Definition: lrmd_client.c:433
#define pcmk_ok
Definition: results.h:67
void lrmd_internal_set_proxy_callback(lrmd_t *lrmd, void *userdata, void(*callback)(lrmd_t *lrmd, void *userdata, xmlNode *msg))
Definition: lrmd_client.c:1699
#define crm_log_xml_trace(xml, text)
Definition: logging.h:377
void lrmd_free_rsc_info(lrmd_rsc_info_t *rsc_info)
Definition: lrmd_client.c:1572
#define F_LRMD_CLIENTNAME
Definition: lrmd.h:54
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:838
#define F_LRMD_RSC_QUEUE_TIME
Definition: lrmd.h:77
int pcmk__read_remote_message(pcmk__remote_t *remote, int timeout_ms)
Definition: remote.c:804
#define F_LRMD_RSC_DELETED
Definition: lrmd.h:86
#define F_LRMD_OPERATION
Definition: lrmd.h:53
lrmd_rsc_info_t *(* get_rsc_info)(lrmd_t *lrmd, const char *rsc_id, enum lrmd_call_options options)
Retrieve registration info for a rsc.
Definition: lrmd.h:348
#define CRM_OP_IPC_FWD
Definition: crm.h:143
#define safe_str_eq(a, b)
Definition: util.h:65
#define F_LRMD_CALLBACK_TOKEN
Definition: lrmd.h:60
void lrmd_api_delete(lrmd_t *lrmd)
Destroy executor connection object.
Definition: lrmd_client.c:2082
#define F_XML_TAGNAME
Definition: msg_xml.h:38
char * name
Definition: pcmk_fence.c:30
char * timeout_ms_s
Definition: lrmd.h:267
#define F_LRMD_REMOTE_MSG_TYPE
Definition: lrmd.h:58
void crm_ipc_close(crm_ipc_t *client)
Definition: ipc.c:1225
char * crm_strdup_printf(char const *format,...) __attribute__((__format__(__printf__
unsigned int timeout
Definition: pcmk_fence.c:31
int(* list_agents)(lrmd_t *lrmd, lrmd_list_t **agents, const char *standard, const char *provider)
Retrieve a list of installed resource agents.
Definition: lrmd.h:464
GList * GListPtr
Definition: crm.h:214
char * value
Definition: lrmd.h:30
#define crm_info(fmt, args...)
Definition: logging.h:366
uint32_t version
Definition: remote.c:147
pcmk__client_type
Definition: ipcs_internal.h:29
int(* dispatch)(const char *buffer, ssize_t length, gpointer userdata)
Definition: mainloop.h:74
int(* list_standards)(lrmd_t *lrmd, lrmd_list_t **standards)
Retrieve a list of standards supported by this machine/installation.
Definition: lrmd.h:487
xmlNode * pcmk__remote_message_xml(pcmk__remote_t *remote)
Definition: remote.c:553
int crm_default_remote_port(void)
Get the default remote connection TCP port on this host.
Definition: remote.c:1262
#define LRMD_OP_RSC_INFO
Definition: lrmd.h:97
enum crm_ais_msg_types type
Definition: internal.h:83
xmlNode * crm_next_same_xml(const xmlNode *sibling)
Get next instance of same XML tag.
Definition: xml.c:4425