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