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