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