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