pacemaker  1.1.17-b36b869ca8
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 occuring, 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 
189 static void
190 dup_attr(gpointer key, gpointer value, gpointer user_data)
191 {
192  g_hash_table_replace(user_data, strdup(key), strdup(value));
193 }
194 
197 {
198  lrmd_event_data_t *copy = NULL;
199 
200  copy = calloc(1, sizeof(lrmd_event_data_t));
201 
202  /* This will get all the int values.
203  * we just have to be careful not to leave any
204  * dangling pointers to strings. */
205  memcpy(copy, event, sizeof(lrmd_event_data_t));
206 
207  copy->rsc_id = event->rsc_id ? strdup(event->rsc_id) : NULL;
208  copy->op_type = event->op_type ? strdup(event->op_type) : NULL;
209  copy->user_data = event->user_data ? strdup(event->user_data) : NULL;
210  copy->output = event->output ? strdup(event->output) : NULL;
211  copy->exit_reason = event->exit_reason ? strdup(event->exit_reason) : NULL;
212  copy->remote_nodename = event->remote_nodename ? strdup(event->remote_nodename) : NULL;
213 
214  if (event->params) {
215  copy->params = g_hash_table_new_full(crm_str_hash,
216  g_str_equal, g_hash_destroy_str, g_hash_destroy_str);
217 
218  if (copy->params != NULL) {
219  g_hash_table_foreach(event->params, dup_attr, copy->params);
220  }
221  }
222 
223 #ifdef ENABLE_VERSIONED_ATTRS
224  if (event->versioned_params) {
225  copy->versioned_params = copy_xml(event->versioned_params);
226  }
227 #endif
228 
229  return copy;
230 }
231 
232 void
234 {
235  if (!event) {
236  return;
237  }
238 
239  /* free gives me grief if i try to cast */
240  free((char *)event->rsc_id);
241  free((char *)event->op_type);
242  free((char *)event->user_data);
243  free((char *)event->output);
244  free((char *)event->exit_reason);
245  free((char *)event->remote_nodename);
246  if (event->params) {
247  g_hash_table_destroy(event->params);
248  }
249 #ifdef ENABLE_VERSIONED_ATTRS
250  if (event->versioned_params) {
251  free_xml(event->versioned_params);
252  }
253 #endif
254  free(event);
255 }
256 
257 static int
258 lrmd_dispatch_internal(lrmd_t * lrmd, xmlNode * msg)
259 {
260  const char *type;
261  const char *proxy_session = crm_element_value(msg, F_LRMD_IPC_SESSION);
262  lrmd_private_t *native = lrmd->private;
263  lrmd_event_data_t event = { 0, };
264 
265  if (proxy_session != NULL) {
266  /* this is proxy business */
267  lrmd_internal_proxy_dispatch(lrmd, msg);
268  return 1;
269  } else if (!native->callback) {
270  /* no callback set */
271  crm_trace("notify event received but client has not set callback");
272  return 1;
273  }
274 
275  event.remote_nodename = native->remote_nodename;
276  type = crm_element_value(msg, F_LRMD_OPERATION);
277  crm_element_value_int(msg, F_LRMD_CALLID, &event.call_id);
278  event.rsc_id = crm_element_value(msg, F_LRMD_RSC_ID);
279 
280  if (crm_str_eq(type, LRMD_OP_RSC_REG, TRUE)) {
281  event.type = lrmd_event_register;
282  } else if (crm_str_eq(type, LRMD_OP_RSC_UNREG, TRUE)) {
283  event.type = lrmd_event_unregister;
284  } else if (crm_str_eq(type, LRMD_OP_RSC_EXEC, TRUE)) {
285  crm_element_value_int(msg, F_LRMD_TIMEOUT, &event.timeout);
286  crm_element_value_int(msg, F_LRMD_RSC_INTERVAL, &event.interval);
287  crm_element_value_int(msg, F_LRMD_RSC_START_DELAY, &event.start_delay);
288  crm_element_value_int(msg, F_LRMD_EXEC_RC, (int *)&event.rc);
289  crm_element_value_int(msg, F_LRMD_OP_STATUS, &event.op_status);
290  crm_element_value_int(msg, F_LRMD_RSC_DELETED, &event.rsc_deleted);
291 
292  crm_element_value_int(msg, F_LRMD_RSC_RUN_TIME, (int *)&event.t_run);
293  crm_element_value_int(msg, F_LRMD_RSC_RCCHANGE_TIME, (int *)&event.t_rcchange);
294  crm_element_value_int(msg, F_LRMD_RSC_EXEC_TIME, (int *)&event.exec_time);
295  crm_element_value_int(msg, F_LRMD_RSC_QUEUE_TIME, (int *)&event.queue_time);
296 
297  event.op_type = crm_element_value(msg, F_LRMD_RSC_ACTION);
298  event.user_data = crm_element_value(msg, F_LRMD_RSC_USERDATA_STR);
299  event.output = crm_element_value(msg, F_LRMD_RSC_OUTPUT);
300  event.exit_reason = crm_element_value(msg, F_LRMD_RSC_EXIT_REASON);
301  event.type = lrmd_event_exec_complete;
302 
303  event.params = xml2list(msg);
304 #ifdef ENABLE_VERSIONED_ATTRS
305  event.versioned_params = first_named_child(msg, XML_TAG_VER_ATTRS);
306 #endif
307  } else if (crm_str_eq(type, LRMD_OP_NEW_CLIENT, TRUE)) {
308  event.type = lrmd_event_new_client;
309  } else if (crm_str_eq(type, LRMD_OP_POKE, TRUE)) {
310  event.type = lrmd_event_poke;
311  } else {
312  return 1;
313  }
314 
315  crm_trace("op %s notify event received", type);
316  native->callback(&event);
317 
318  if (event.params) {
319  g_hash_table_destroy(event.params);
320  }
321  return 1;
322 }
323 
324 static int
325 lrmd_ipc_dispatch(const char *buffer, ssize_t length, gpointer userdata)
326 {
327  lrmd_t *lrmd = userdata;
328  lrmd_private_t *native = lrmd->private;
329  xmlNode *msg;
330  int rc;
331 
332  if (!native->callback) {
333  /* no callback set */
334  return 1;
335  }
336 
337  msg = string2xml(buffer);
338  rc = lrmd_dispatch_internal(lrmd, msg);
339  free_xml(msg);
340  return rc;
341 }
342 
343 #ifdef HAVE_GNUTLS_GNUTLS_H
344 static void
345 lrmd_free_xml(gpointer userdata)
346 {
347  free_xml((xmlNode *) userdata);
348 }
349 
350 static int
351 lrmd_tls_connected(lrmd_t * lrmd)
352 {
353  lrmd_private_t *native = lrmd->private;
354 
355  if (native->remote->tls_session) {
356  return TRUE;
357  }
358 
359  return FALSE;
360 }
361 
362 static int
363 lrmd_tls_dispatch(gpointer userdata)
364 {
365  lrmd_t *lrmd = userdata;
366  lrmd_private_t *native = lrmd->private;
367  xmlNode *xml = NULL;
368  int rc = 0;
369  int disconnected = 0;
370 
371  if (lrmd_tls_connected(lrmd) == FALSE) {
372  crm_trace("tls dispatch triggered after disconnect");
373  return 0;
374  }
375 
376  crm_trace("tls_dispatch triggered");
377 
378  /* First check if there are any pending notifies to process that came
379  * while we were waiting for replies earlier. */
380  if (native->pending_notify) {
381  GList *iter = NULL;
382 
383  crm_trace("Processing pending notifies");
384  for (iter = native->pending_notify; iter; iter = iter->next) {
385  lrmd_dispatch_internal(lrmd, iter->data);
386  }
387  g_list_free_full(native->pending_notify, lrmd_free_xml);
388  native->pending_notify = NULL;
389  }
390 
391  /* Next read the current buffer and see if there are any messages to handle. */
392  rc = crm_remote_ready(native->remote, 0);
393  if (rc == 0) {
394  /* nothing to read, see if any full messages are already in buffer. */
395  xml = crm_remote_parse_buffer(native->remote);
396  } else if (rc < 0) {
397  disconnected = 1;
398  } else {
399  crm_remote_recv(native->remote, -1, &disconnected);
400  xml = crm_remote_parse_buffer(native->remote);
401  }
402  while (xml) {
403  const char *msg_type = crm_element_value(xml, F_LRMD_REMOTE_MSG_TYPE);
404  if (safe_str_eq(msg_type, "notify")) {
405  lrmd_dispatch_internal(lrmd, xml);
406  } else if (safe_str_eq(msg_type, "reply")) {
407  if (native->expected_late_replies > 0) {
408  native->expected_late_replies--;
409  } else {
410  int reply_id = 0;
411  crm_element_value_int(xml, F_LRMD_CALLID, &reply_id);
412  /* if this happens, we want to know about it */
413  crm_err("Got outdated reply %d", reply_id);
414  }
415  }
416  free_xml(xml);
417  xml = crm_remote_parse_buffer(native->remote);
418  }
419 
420  if (disconnected) {
421  crm_info("Server disconnected while reading remote server msg.");
422  lrmd_tls_disconnect(lrmd);
423  return 0;
424  }
425  return 1;
426 }
427 #endif
428 
429 /* Not used with mainloop */
430 int
431 lrmd_poll(lrmd_t * lrmd, int timeout)
432 {
433  lrmd_private_t *native = lrmd->private;
434 
435  switch (native->type) {
436  case CRM_CLIENT_IPC:
437  return crm_ipc_ready(native->ipc);
438 
439 #ifdef HAVE_GNUTLS_GNUTLS_H
440  case CRM_CLIENT_TLS:
441  if (native->pending_notify) {
442  return 1;
443  }
444 
445  return crm_remote_ready(native->remote, 0);
446 #endif
447  default:
448  crm_err("Unsupported connection type: %d", native->type);
449  }
450 
451  return 0;
452 }
453 
454 /* Not used with mainloop */
455 bool
457 {
458  lrmd_private_t *private = NULL;
459 
460  CRM_ASSERT(lrmd != NULL);
461 
462  private = lrmd->private;
463  switch (private->type) {
464  case CRM_CLIENT_IPC:
465  while (crm_ipc_ready(private->ipc)) {
466  if (crm_ipc_read(private->ipc) > 0) {
467  const char *msg = crm_ipc_buffer(private->ipc);
468 
469  lrmd_ipc_dispatch(msg, strlen(msg), lrmd);
470  }
471  }
472  break;
473 #ifdef HAVE_GNUTLS_GNUTLS_H
474  case CRM_CLIENT_TLS:
475  lrmd_tls_dispatch(lrmd);
476  break;
477 #endif
478  default:
479  crm_err("Unsupported connection type: %d", private->type);
480  }
481 
482  if (lrmd_api_is_connected(lrmd) == FALSE) {
483  crm_err("Connection closed");
484  return FALSE;
485  }
486 
487  return TRUE;
488 }
489 
490 static xmlNode *
491 lrmd_create_op(const char *token, const char *op, xmlNode * data, enum lrmd_call_options options)
492 {
493  xmlNode *op_msg = create_xml_node(NULL, "lrmd_command");
494 
495  CRM_CHECK(op_msg != NULL, return NULL);
496  CRM_CHECK(token != NULL, return NULL);
497 
498  crm_xml_add(op_msg, F_XML_TAGNAME, "lrmd_command");
499 
500  crm_xml_add(op_msg, F_TYPE, T_LRMD);
501  crm_xml_add(op_msg, F_LRMD_CALLBACK_TOKEN, token);
502  crm_xml_add(op_msg, F_LRMD_OPERATION, op);
503  crm_trace("Sending call options: %.8lx, %d", (long)options, options);
504  crm_xml_add_int(op_msg, F_LRMD_CALLOPTS, options);
505 
506  if (data != NULL) {
507  add_message_xml(op_msg, F_LRMD_CALLDATA, data);
508  }
509 
510  return op_msg;
511 }
512 
513 static void
514 lrmd_ipc_connection_destroy(gpointer userdata)
515 {
516  lrmd_t *lrmd = userdata;
517  lrmd_private_t *native = lrmd->private;
518 
519  crm_info("IPC connection destroyed");
520 
521  /* Prevent these from being cleaned up in lrmd_api_disconnect() */
522  native->ipc = NULL;
523  native->source = NULL;
524 
525  if (native->callback) {
526  lrmd_event_data_t event = { 0, };
527  event.type = lrmd_event_disconnect;
528  event.remote_nodename = native->remote_nodename;
529  native->callback(&event);
530  }
531 }
532 
533 #ifdef HAVE_GNUTLS_GNUTLS_H
534 static void
535 lrmd_tls_connection_destroy(gpointer userdata)
536 {
537  lrmd_t *lrmd = userdata;
538  lrmd_private_t *native = lrmd->private;
539 
540  crm_info("TLS connection destroyed");
541 
542  if (native->remote->tls_session) {
543  gnutls_bye(*native->remote->tls_session, GNUTLS_SHUT_RDWR);
544  gnutls_deinit(*native->remote->tls_session);
545  gnutls_free(native->remote->tls_session);
546  }
547  if (native->psk_cred_c) {
548  gnutls_psk_free_client_credentials(native->psk_cred_c);
549  }
550  if (native->sock) {
551  close(native->sock);
552  }
553  if (native->process_notify) {
554  mainloop_destroy_trigger(native->process_notify);
555  native->process_notify = NULL;
556  }
557  if (native->pending_notify) {
558  g_list_free_full(native->pending_notify, lrmd_free_xml);
559  native->pending_notify = NULL;
560  }
561 
562  free(native->remote->buffer);
563  native->remote->buffer = NULL;
564  native->source = 0;
565  native->sock = 0;
566  native->psk_cred_c = NULL;
567  native->remote->tls_session = NULL;
568  native->sock = 0;
569 
570  if (native->callback) {
571  lrmd_event_data_t event = { 0, };
572  event.remote_nodename = native->remote_nodename;
573  event.type = lrmd_event_disconnect;
574  native->callback(&event);
575  }
576  return;
577 }
578 
579 int
580 lrmd_tls_send_msg(crm_remote_t * session, xmlNode * msg, uint32_t id, const char *msg_type)
581 {
582  int rc = -1;
583 
585  crm_xml_add(msg, F_LRMD_REMOTE_MSG_TYPE, msg_type);
586 
587  rc = crm_remote_send(session, msg);
588 
589  if (rc < 0) {
590  crm_err("Failed to send remote lrmd tls msg, rc = %d", rc);
591  return rc;
592  }
593 
594  return rc;
595 }
596 
597 static xmlNode *
598 lrmd_tls_recv_reply(lrmd_t * lrmd, int total_timeout, int expected_reply_id, int *disconnected)
599 {
600  lrmd_private_t *native = lrmd->private;
601  xmlNode *xml = NULL;
602  time_t start = time(NULL);
603  const char *msg_type = NULL;
604  int reply_id = 0;
605  int remaining_timeout = 0;
606 
607  /* A timeout of 0 here makes no sense. We have to wait a period of time
608  * for the response to come back. If -1 or 0, default to 10 seconds. */
609  if (total_timeout <= 0 || total_timeout > MAX_TLS_RECV_WAIT) {
610  total_timeout = MAX_TLS_RECV_WAIT;
611  }
612 
613  while (!xml) {
614 
615  xml = crm_remote_parse_buffer(native->remote);
616  if (!xml) {
617  /* read some more off the tls buffer if we still have time left. */
618  if (remaining_timeout) {
619  remaining_timeout = total_timeout - ((time(NULL) - start) * 1000);
620  } else {
621  remaining_timeout = total_timeout;
622  }
623  if (remaining_timeout <= 0) {
624  crm_err("Never received the expected reply during the timeout period, disconnecting.");
625  *disconnected = TRUE;
626  return NULL;
627  }
628 
629  crm_remote_recv(native->remote, remaining_timeout, disconnected);
630  xml = crm_remote_parse_buffer(native->remote);
631  if (!xml) {
632  crm_err("Unable to receive expected reply, disconnecting.");
633  *disconnected = TRUE;
634  return NULL;
635  } else if (*disconnected) {
636  return NULL;
637  }
638  }
639 
640  CRM_ASSERT(xml != NULL);
641 
643  msg_type = crm_element_value(xml, F_LRMD_REMOTE_MSG_TYPE);
644 
645  if (!msg_type) {
646  crm_err("Empty msg type received while waiting for reply");
647  free_xml(xml);
648  xml = NULL;
649  } else if (safe_str_eq(msg_type, "notify")) {
650  /* got a notify while waiting for reply, trigger the notify to be processed later */
651  crm_info("queueing notify");
652  native->pending_notify = g_list_append(native->pending_notify, xml);
653  if (native->process_notify) {
654  crm_info("notify trigger set.");
655  mainloop_set_trigger(native->process_notify);
656  }
657  xml = NULL;
658  } else if (safe_str_neq(msg_type, "reply")) {
659  /* msg isn't a reply, make some noise */
660  crm_err("Expected a reply, got %s", msg_type);
661  free_xml(xml);
662  xml = NULL;
663  } else if (reply_id != expected_reply_id) {
664  if (native->expected_late_replies > 0) {
665  native->expected_late_replies--;
666  } else {
667  crm_err("Got outdated reply, expected id %d got id %d", expected_reply_id, reply_id);
668  }
669  free_xml(xml);
670  xml = NULL;
671  }
672  }
673 
674  if (native->remote->buffer && native->process_notify) {
675  mainloop_set_trigger(native->process_notify);
676  }
677 
678  return xml;
679 }
680 
681 static int
682 lrmd_tls_send(lrmd_t * lrmd, xmlNode * msg)
683 {
684  int rc = 0;
685  lrmd_private_t *native = lrmd->private;
686 
687  global_remote_msg_id++;
688  if (global_remote_msg_id <= 0) {
689  global_remote_msg_id = 1;
690  }
691 
692  rc = lrmd_tls_send_msg(native->remote, msg, global_remote_msg_id, "request");
693  if (rc <= 0) {
694  crm_err("Remote lrmd send failed, disconnecting");
695  lrmd_tls_disconnect(lrmd);
696  return -ENOTCONN;
697  }
698  return pcmk_ok;
699 }
700 
701 static int
702 lrmd_tls_send_recv(lrmd_t * lrmd, xmlNode * msg, int timeout, xmlNode ** reply)
703 {
704  int rc = 0;
705  int disconnected = 0;
706  xmlNode *xml = NULL;
707 
708  if (lrmd_tls_connected(lrmd) == FALSE) {
709  return -1;
710  }
711 
712  rc = lrmd_tls_send(lrmd, msg);
713  if (rc < 0) {
714  return rc;
715  }
716 
717  xml = lrmd_tls_recv_reply(lrmd, timeout, global_remote_msg_id, &disconnected);
718 
719  if (disconnected) {
720  crm_err("Remote lrmd server disconnected while waiting for reply with id %d. ",
721  global_remote_msg_id);
722  lrmd_tls_disconnect(lrmd);
723  rc = -ENOTCONN;
724  } else if (!xml) {
725  crm_err("Remote lrmd never received reply for request id %d. timeout: %dms ",
726  global_remote_msg_id, timeout);
727  rc = -ECOMM;
728  }
729 
730  if (reply) {
731  *reply = xml;
732  } else {
733  free_xml(xml);
734  }
735 
736  return rc;
737 }
738 #endif
739 
740 static int
741 lrmd_send_xml(lrmd_t * lrmd, xmlNode * msg, int timeout, xmlNode ** reply)
742 {
743  int rc = -1;
744  lrmd_private_t *native = lrmd->private;
745 
746  switch (native->type) {
747  case CRM_CLIENT_IPC:
748  rc = crm_ipc_send(native->ipc, msg, crm_ipc_client_response, timeout, reply);
749  break;
750 #ifdef HAVE_GNUTLS_GNUTLS_H
751  case CRM_CLIENT_TLS:
752  rc = lrmd_tls_send_recv(lrmd, msg, timeout, reply);
753  break;
754 #endif
755  default:
756  crm_err("Unsupported connection type: %d", native->type);
757  }
758 
759  return rc;
760 }
761 
762 static int
763 lrmd_send_xml_no_reply(lrmd_t * lrmd, xmlNode * msg)
764 {
765  int rc = -1;
766  lrmd_private_t *native = lrmd->private;
767 
768  switch (native->type) {
769  case CRM_CLIENT_IPC:
770  rc = crm_ipc_send(native->ipc, msg, crm_ipc_flags_none, 0, NULL);
771  break;
772 #ifdef HAVE_GNUTLS_GNUTLS_H
773  case CRM_CLIENT_TLS:
774  rc = lrmd_tls_send(lrmd, msg);
775  if (rc == pcmk_ok) {
776  /* we don't want to wait around for the reply, but
777  * since the request/reply protocol needs to behave the same
778  * as libqb, a reply will eventually come later anyway. */
779  native->expected_late_replies++;
780  }
781  break;
782 #endif
783  default:
784  crm_err("Unsupported connection type: %d", native->type);
785  }
786 
787  return rc;
788 }
789 
790 static int
791 lrmd_api_is_connected(lrmd_t * lrmd)
792 {
793  lrmd_private_t *native = lrmd->private;
794 
795  switch (native->type) {
796  case CRM_CLIENT_IPC:
797  return crm_ipc_connected(native->ipc);
798  break;
799 #ifdef HAVE_GNUTLS_GNUTLS_H
800  case CRM_CLIENT_TLS:
801  return lrmd_tls_connected(lrmd);
802  break;
803 #endif
804  default:
805  crm_err("Unsupported connection type: %d", native->type);
806  }
807 
808  return 0;
809 }
810 
811 static int
812 lrmd_send_command(lrmd_t * lrmd, const char *op, xmlNode * data, xmlNode ** output_data, int timeout, /* ms. defaults to 1000 if set to 0 */
813  enum lrmd_call_options options, gboolean expect_reply)
814 { /* TODO we need to reduce usage of this boolean */
815  int rc = pcmk_ok;
816  int reply_id = -1;
817  lrmd_private_t *native = lrmd->private;
818  xmlNode *op_msg = NULL;
819  xmlNode *op_reply = NULL;
820 
821  if (!lrmd_api_is_connected(lrmd)) {
822  return -ENOTCONN;
823  }
824 
825  if (op == NULL) {
826  crm_err("No operation specified");
827  return -EINVAL;
828  }
829 
830  CRM_CHECK(native->token != NULL,;
831  );
832  crm_trace("sending %s op to lrmd", op);
833 
834  op_msg = lrmd_create_op(native->token, op, data, options);
835 
836  if (op_msg == NULL) {
837  return -EINVAL;
838  }
839 
840  crm_xml_add_int(op_msg, F_LRMD_TIMEOUT, timeout);
841 
842  if (expect_reply) {
843  rc = lrmd_send_xml(lrmd, op_msg, timeout, &op_reply);
844  } else {
845  rc = lrmd_send_xml_no_reply(lrmd, op_msg);
846  goto done;
847  }
848 
849  if (rc < 0) {
850  crm_perror(LOG_ERR, "Couldn't perform %s operation (timeout=%d): %d", op, timeout, rc);
851  rc = -ECOMM;
852  goto done;
853 
854  } else if(op_reply == NULL) {
855  rc = -ENOMSG;
856  goto done;
857  }
858 
859  rc = pcmk_ok;
860  crm_element_value_int(op_reply, F_LRMD_CALLID, &reply_id);
861  crm_trace("%s op reply received", op);
862  if (crm_element_value_int(op_reply, F_LRMD_RC, &rc) != 0) {
863  rc = -ENOMSG;
864  goto done;
865  }
866 
867  crm_log_xml_trace(op_reply, "Reply");
868 
869  if (output_data) {
870  *output_data = op_reply;
871  op_reply = NULL; /* Prevent subsequent free */
872  }
873 
874  done:
875  if (lrmd_api_is_connected(lrmd) == FALSE) {
876  crm_err("LRMD disconnected");
877  }
878 
879  free_xml(op_msg);
880  free_xml(op_reply);
881  return rc;
882 }
883 
884 static int
885 lrmd_api_poke_connection(lrmd_t * lrmd)
886 {
887  int rc;
888  lrmd_private_t *native = lrmd->private;
889  xmlNode *data = create_xml_node(NULL, F_LRMD_RSC);
890 
891  crm_xml_add(data, F_LRMD_ORIGIN, __FUNCTION__);
892  rc = lrmd_send_command(lrmd, LRMD_OP_POKE, data, NULL, 0, 0, native->type == CRM_CLIENT_IPC ? TRUE : FALSE);
893  free_xml(data);
894 
895  return rc < 0 ? rc : pcmk_ok;
896 }
897 
898 int
899 remote_proxy_check(lrmd_t * lrmd, GHashTable *hash)
900 {
901  int rc;
902  const char *value;
903  lrmd_private_t *native = lrmd->private;
904  xmlNode *data = create_xml_node(NULL, F_LRMD_OPERATION);
905 
906  crm_xml_add(data, F_LRMD_ORIGIN, __FUNCTION__);
907 
908  value = g_hash_table_lookup(hash, "stonith-watchdog-timeout");
909  crm_xml_add(data, F_LRMD_WATCHDOG, value);
910 
911  rc = lrmd_send_command(lrmd, LRMD_OP_CHECK, data, NULL, 0, 0, native->type == CRM_CLIENT_IPC ? TRUE : FALSE);
912  free_xml(data);
913 
914  return rc < 0 ? rc : pcmk_ok;
915 }
916 
917 static int
918 lrmd_handshake(lrmd_t * lrmd, const char *name)
919 {
920  int rc = pcmk_ok;
921  lrmd_private_t *native = lrmd->private;
922  xmlNode *reply = NULL;
923  xmlNode *hello = create_xml_node(NULL, "lrmd_command");
924 
925  crm_xml_add(hello, F_TYPE, T_LRMD);
927  crm_xml_add(hello, F_LRMD_CLIENTNAME, name);
929 
930  /* advertise that we are a proxy provider */
931  if (native->proxy_callback) {
932  crm_xml_add(hello, F_LRMD_IS_IPC_PROVIDER, "true");
933  }
934 
935  rc = lrmd_send_xml(lrmd, hello, -1, &reply);
936 
937  if (rc < 0) {
938  crm_perror(LOG_DEBUG, "Couldn't complete registration with the lrmd API: %d", rc);
939  rc = -ECOMM;
940  } else if (reply == NULL) {
941  crm_err("Did not receive registration reply");
942  rc = -EPROTO;
943  } else {
944  const char *version = crm_element_value(reply, F_LRMD_PROTOCOL_VERSION);
945  const char *msg_type = crm_element_value(reply, F_LRMD_OPERATION);
946  const char *tmp_ticket = crm_element_value(reply, F_LRMD_CLIENTID);
947 
948  crm_element_value_int(reply, F_LRMD_RC, &rc);
949 
950  if (rc == -EPROTO) {
951  crm_err("LRMD protocol mismatch client version %s, server version %s",
952  LRMD_PROTOCOL_VERSION, version);
953  crm_log_xml_err(reply, "Protocol Error");
954 
955  } else if (safe_str_neq(msg_type, CRM_OP_REGISTER)) {
956  crm_err("Invalid registration message: %s", msg_type);
957  crm_log_xml_err(reply, "Bad reply");
958  rc = -EPROTO;
959  } else if (tmp_ticket == NULL) {
960  crm_err("No registration token provided");
961  crm_log_xml_err(reply, "Bad reply");
962  rc = -EPROTO;
963  } else {
964  crm_trace("Obtained registration token: %s", tmp_ticket);
965  native->token = strdup(tmp_ticket);
966  native->peer_version = strdup(version?version:"1.0"); /* Included since 1.1 */
967  rc = pcmk_ok;
968  }
969  }
970 
971  free_xml(reply);
972  free_xml(hello);
973 
974  if (rc != pcmk_ok) {
975  lrmd_api_disconnect(lrmd);
976  }
977  return rc;
978 }
979 
980 static int
981 lrmd_ipc_connect(lrmd_t * lrmd, int *fd)
982 {
983  int rc = pcmk_ok;
984  lrmd_private_t *native = lrmd->private;
985 
986  static struct ipc_client_callbacks lrmd_callbacks = {
987  .dispatch = lrmd_ipc_dispatch,
988  .destroy = lrmd_ipc_connection_destroy
989  };
990 
991  crm_info("Connecting to lrmd");
992 
993  if (fd) {
994  /* No mainloop */
995  native->ipc = crm_ipc_new(CRM_SYSTEM_LRMD, 0);
996  if (native->ipc && crm_ipc_connect(native->ipc)) {
997  *fd = crm_ipc_get_fd(native->ipc);
998  } else if (native->ipc) {
999  crm_perror(LOG_ERR, "Connection to local resource manager failed");
1000  rc = -ENOTCONN;
1001  }
1002  } else {
1003  native->source = mainloop_add_ipc_client(CRM_SYSTEM_LRMD, G_PRIORITY_HIGH, 0, lrmd, &lrmd_callbacks);
1004  native->ipc = mainloop_get_ipc_client(native->source);
1005  }
1006 
1007  if (native->ipc == NULL) {
1008  crm_debug("Could not connect to the LRMD API");
1009  rc = -ENOTCONN;
1010  }
1011 
1012  return rc;
1013 }
1014 
1015 #ifdef HAVE_GNUTLS_GNUTLS_H
1016 static int
1017 set_key(gnutls_datum_t * key, const char *location)
1018 {
1019  FILE *stream;
1020  int read_len = 256;
1021  int cur_len = 0;
1022  int buf_len = read_len;
1023  static char *key_cache = NULL;
1024  static size_t key_cache_len = 0;
1025  static time_t key_cache_updated;
1026 
1027  if (location == NULL) {
1028  return -1;
1029  }
1030 
1031  if (key_cache) {
1032  time_t now = time(NULL);
1033 
1034  if ((now - key_cache_updated) < 60) {
1035  key->data = gnutls_malloc(key_cache_len + 1);
1036  key->size = key_cache_len;
1037  memcpy(key->data, key_cache, key_cache_len);
1038 
1039  crm_debug("using cached LRMD key");
1040  return 0;
1041  } else {
1042  key_cache_len = 0;
1043  key_cache_updated = 0;
1044  free(key_cache);
1045  key_cache = NULL;
1046  crm_debug("clearing lrmd key cache");
1047  }
1048  }
1049 
1050  stream = fopen(location, "r");
1051  if (!stream) {
1052  return -1;
1053  }
1054 
1055  key->data = gnutls_malloc(read_len);
1056  while (!feof(stream)) {
1057  int next;
1058 
1059  if (cur_len == buf_len) {
1060  buf_len = cur_len + read_len;
1061  key->data = gnutls_realloc(key->data, buf_len);
1062  }
1063  next = fgetc(stream);
1064  if (next == EOF && feof(stream)) {
1065  break;
1066  }
1067 
1068  key->data[cur_len] = next;
1069  cur_len++;
1070  }
1071  fclose(stream);
1072 
1073  key->size = cur_len;
1074  if (!cur_len) {
1075  gnutls_free(key->data);
1076  key->data = 0;
1077  return -1;
1078  }
1079 
1080  if (!key_cache) {
1081  key_cache = calloc(1, key->size + 1);
1082  memcpy(key_cache, key->data, key->size);
1083 
1084  key_cache_len = key->size;
1085  key_cache_updated = time(NULL);
1086  }
1087 
1088  return 0;
1089 }
1090 
1091 int
1092 lrmd_tls_set_key(gnutls_datum_t * key)
1093 {
1094  int rc = 0;
1095  const char *specific_location = getenv("PCMK_authkey_location");
1096 
1097  if (set_key(key, specific_location) == 0) {
1098  crm_debug("Using custom authkey location %s", specific_location);
1099  return 0;
1100 
1101  } else if (specific_location) {
1102  crm_err("No valid lrmd remote key found at %s, trying default location", specific_location);
1103  }
1104 
1105  if (set_key(key, DEFAULT_REMOTE_KEY_LOCATION) != 0) {
1106  rc = set_key(key, ALT_REMOTE_KEY_LOCATION);
1107  }
1108 
1109  if (rc) {
1110  crm_err("No valid lrmd remote key found at %s", DEFAULT_REMOTE_KEY_LOCATION);
1111  return -1;
1112  }
1113 
1114  return rc;
1115 }
1116 
1117 static void
1118 lrmd_gnutls_global_init(void)
1119 {
1120  static int gnutls_init = 0;
1121 
1122  if (!gnutls_init) {
1123  crm_gnutls_global_init();
1124  }
1125  gnutls_init = 1;
1126 }
1127 #endif
1128 
1129 static void
1130 report_async_connection_result(lrmd_t * lrmd, int rc)
1131 {
1132  lrmd_private_t *native = lrmd->private;
1133 
1134  if (native->callback) {
1135  lrmd_event_data_t event = { 0, };
1136  event.type = lrmd_event_connect;
1137  event.remote_nodename = native->remote_nodename;
1138  event.connection_rc = rc;
1139  native->callback(&event);
1140  }
1141 }
1142 
1143 #ifdef HAVE_GNUTLS_GNUTLS_H
1144 static void
1145 lrmd_tcp_connect_cb(void *userdata, int sock)
1146 {
1147  lrmd_t *lrmd = userdata;
1148  lrmd_private_t *native = lrmd->private;
1149  char name[256] = { 0, };
1150  static struct mainloop_fd_callbacks lrmd_tls_callbacks = {
1151  .dispatch = lrmd_tls_dispatch,
1152  .destroy = lrmd_tls_connection_destroy,
1153  };
1154  int rc = sock;
1155  gnutls_datum_t psk_key = { NULL, 0 };
1156 
1157  native->async_timer = 0;
1158 
1159  if (rc < 0) {
1160  lrmd_tls_connection_destroy(lrmd);
1161  crm_info("remote lrmd connect to %s at port %d failed", native->server, native->port);
1162  report_async_connection_result(lrmd, rc);
1163  return;
1164  }
1165 
1166  /* TODO continue with tls stuff now that tcp connect passed. make this async as well soon
1167  * to avoid all blocking code in the client. */
1168  native->sock = sock;
1169 
1170  if (lrmd_tls_set_key(&psk_key) != 0) {
1171  lrmd_tls_connection_destroy(lrmd);
1172  return;
1173  }
1174 
1175  gnutls_psk_allocate_client_credentials(&native->psk_cred_c);
1176  gnutls_psk_set_client_credentials(native->psk_cred_c, DEFAULT_REMOTE_USERNAME, &psk_key, GNUTLS_PSK_KEY_RAW);
1177  gnutls_free(psk_key.data);
1178 
1179  native->remote->tls_session = create_psk_tls_session(sock, GNUTLS_CLIENT, native->psk_cred_c);
1180 
1181  if (crm_initiate_client_tls_handshake(native->remote, LRMD_CLIENT_HANDSHAKE_TIMEOUT) != 0) {
1182  crm_warn("Client tls handshake failed for server %s:%d. Disconnecting", native->server,
1183  native->port);
1184  gnutls_deinit(*native->remote->tls_session);
1185  gnutls_free(native->remote->tls_session);
1186  native->remote->tls_session = NULL;
1187  lrmd_tls_connection_destroy(lrmd);
1188  report_async_connection_result(lrmd, -1);
1189  return;
1190  }
1191 
1192  crm_info("Remote lrmd client TLS connection established with server %s:%d", native->server,
1193  native->port);
1194 
1195  snprintf(name, 128, "remote-lrmd-%s:%d", native->server, native->port);
1196 
1197  native->process_notify = mainloop_add_trigger(G_PRIORITY_HIGH, lrmd_tls_dispatch, lrmd);
1198  native->source =
1199  mainloop_add_fd(name, G_PRIORITY_HIGH, native->sock, lrmd, &lrmd_tls_callbacks);
1200 
1201  rc = lrmd_handshake(lrmd, name);
1202  report_async_connection_result(lrmd, rc);
1203 
1204  return;
1205 }
1206 
1207 static int
1208 lrmd_tls_connect_async(lrmd_t * lrmd, int timeout /*ms */ )
1209 {
1210  int rc = -1;
1211  int sock = 0;
1212  int timer_id = 0;
1213 
1214  lrmd_private_t *native = lrmd->private;
1215 
1216  lrmd_gnutls_global_init();
1217 
1218  sock = crm_remote_tcp_connect_async(native->server, native->port, timeout, &timer_id, lrmd,
1219  lrmd_tcp_connect_cb);
1220 
1221  if (sock != -1) {
1222  native->sock = sock;
1223  rc = 0;
1224  native->async_timer = timer_id;
1225  }
1226 
1227  return rc;
1228 }
1229 
1230 static int
1231 lrmd_tls_connect(lrmd_t * lrmd, int *fd)
1232 {
1233  static struct mainloop_fd_callbacks lrmd_tls_callbacks = {
1234  .dispatch = lrmd_tls_dispatch,
1235  .destroy = lrmd_tls_connection_destroy,
1236  };
1237 
1238  lrmd_private_t *native = lrmd->private;
1239  int sock;
1240  gnutls_datum_t psk_key = { NULL, 0 };
1241 
1242  lrmd_gnutls_global_init();
1243 
1244  sock = crm_remote_tcp_connect(native->server, native->port);
1245  if (sock < 0) {
1246  crm_warn("Could not establish remote lrmd connection to %s", native->server);
1247  lrmd_tls_connection_destroy(lrmd);
1248  return -ENOTCONN;
1249  }
1250 
1251  native->sock = sock;
1252 
1253  if (lrmd_tls_set_key(&psk_key) != 0) {
1254  lrmd_tls_connection_destroy(lrmd);
1255  return -1;
1256  }
1257 
1258  gnutls_psk_allocate_client_credentials(&native->psk_cred_c);
1259  gnutls_psk_set_client_credentials(native->psk_cred_c, DEFAULT_REMOTE_USERNAME, &psk_key, GNUTLS_PSK_KEY_RAW);
1260  gnutls_free(psk_key.data);
1261 
1262  native->remote->tls_session = create_psk_tls_session(sock, GNUTLS_CLIENT, native->psk_cred_c);
1263 
1264  if (crm_initiate_client_tls_handshake(native->remote, LRMD_CLIENT_HANDSHAKE_TIMEOUT) != 0) {
1265  crm_err("Session creation for %s:%d failed", native->server, native->port);
1266  gnutls_deinit(*native->remote->tls_session);
1267  gnutls_free(native->remote->tls_session);
1268  native->remote->tls_session = NULL;
1269  lrmd_tls_connection_destroy(lrmd);
1270  return -1;
1271  }
1272 
1273  crm_info("Remote lrmd client TLS connection established with server %s:%d", native->server,
1274  native->port);
1275 
1276  if (fd) {
1277  *fd = sock;
1278  } else {
1279  char name[256] = { 0, };
1280  snprintf(name, 128, "remote-lrmd-%s:%d", native->server, native->port);
1281 
1282  native->process_notify = mainloop_add_trigger(G_PRIORITY_HIGH, lrmd_tls_dispatch, lrmd);
1283  native->source =
1284  mainloop_add_fd(name, G_PRIORITY_HIGH, native->sock, lrmd, &lrmd_tls_callbacks);
1285  }
1286  return pcmk_ok;
1287 }
1288 #endif
1289 
1290 static int
1291 lrmd_api_connect(lrmd_t * lrmd, const char *name, int *fd)
1292 {
1293  int rc = -ENOTCONN;
1294  lrmd_private_t *native = lrmd->private;
1295 
1296  switch (native->type) {
1297  case CRM_CLIENT_IPC:
1298  rc = lrmd_ipc_connect(lrmd, fd);
1299  break;
1300 #ifdef HAVE_GNUTLS_GNUTLS_H
1301  case CRM_CLIENT_TLS:
1302  rc = lrmd_tls_connect(lrmd, fd);
1303  break;
1304 #endif
1305  default:
1306  crm_err("Unsupported connection type: %d", native->type);
1307  }
1308 
1309  if (rc == pcmk_ok) {
1310  rc = lrmd_handshake(lrmd, name);
1311  }
1312 
1313  return rc;
1314 }
1315 
1316 static int
1317 lrmd_api_connect_async(lrmd_t * lrmd, const char *name, int timeout)
1318 {
1319  int rc = 0;
1320  lrmd_private_t *native = lrmd->private;
1321 
1322  if (!native->callback) {
1323  crm_err("Async connect not possible, no lrmd client callback set.");
1324  return -1;
1325  }
1326 
1327  switch (native->type) {
1328  case CRM_CLIENT_IPC:
1329  /* fake async connection with ipc. it should be fast
1330  * enough that we gain very little from async */
1331  rc = lrmd_api_connect(lrmd, name, NULL);
1332  if (!rc) {
1333  report_async_connection_result(lrmd, rc);
1334  }
1335  break;
1336 #ifdef HAVE_GNUTLS_GNUTLS_H
1337  case CRM_CLIENT_TLS:
1338  rc = lrmd_tls_connect_async(lrmd, timeout);
1339  if (rc) {
1340  /* connection failed, report rc now */
1341  report_async_connection_result(lrmd, rc);
1342  }
1343  break;
1344 #endif
1345  default:
1346  crm_err("Unsupported connection type: %d", native->type);
1347  }
1348 
1349  return rc;
1350 }
1351 
1352 static void
1353 lrmd_ipc_disconnect(lrmd_t * lrmd)
1354 {
1355  lrmd_private_t *native = lrmd->private;
1356 
1357  if (native->source != NULL) {
1358  /* Attached to mainloop */
1359  mainloop_del_ipc_client(native->source);
1360  native->source = NULL;
1361  native->ipc = NULL;
1362 
1363  } else if (native->ipc) {
1364  /* Not attached to mainloop */
1365  crm_ipc_t *ipc = native->ipc;
1366 
1367  native->ipc = NULL;
1368  crm_ipc_close(ipc);
1369  crm_ipc_destroy(ipc);
1370  }
1371 }
1372 
1373 #ifdef HAVE_GNUTLS_GNUTLS_H
1374 static void
1375 lrmd_tls_disconnect(lrmd_t * lrmd)
1376 {
1377  lrmd_private_t *native = lrmd->private;
1378 
1379  if (native->remote->tls_session) {
1380  gnutls_bye(*native->remote->tls_session, GNUTLS_SHUT_RDWR);
1381  gnutls_deinit(*native->remote->tls_session);
1382  gnutls_free(native->remote->tls_session);
1383  native->remote->tls_session = 0;
1384  }
1385 
1386  if (native->async_timer) {
1387  g_source_remove(native->async_timer);
1388  native->async_timer = 0;
1389  }
1390 
1391  if (native->source != NULL) {
1392  /* Attached to mainloop */
1393  mainloop_del_ipc_client(native->source);
1394  native->source = NULL;
1395 
1396  } else if (native->sock) {
1397  close(native->sock);
1398  native->sock = 0;
1399  }
1400 
1401  if (native->pending_notify) {
1402  g_list_free_full(native->pending_notify, lrmd_free_xml);
1403  native->pending_notify = NULL;
1404  }
1405 }
1406 #endif
1407 
1408 static int
1409 lrmd_api_disconnect(lrmd_t * lrmd)
1410 {
1411  lrmd_private_t *native = lrmd->private;
1412 
1413  crm_info("Disconnecting from %d lrmd service", native->type);
1414  switch (native->type) {
1415  case CRM_CLIENT_IPC:
1416  lrmd_ipc_disconnect(lrmd);
1417  break;
1418 #ifdef HAVE_GNUTLS_GNUTLS_H
1419  case CRM_CLIENT_TLS:
1420  lrmd_tls_disconnect(lrmd);
1421  break;
1422 #endif
1423  default:
1424  crm_err("Unsupported connection type: %d", native->type);
1425  }
1426 
1427  free(native->token);
1428  native->token = NULL;
1429 
1430  free(native->peer_version);
1431  native->peer_version = NULL;
1432  return 0;
1433 }
1434 
1435 static int
1436 lrmd_api_register_rsc(lrmd_t * lrmd,
1437  const char *rsc_id,
1438  const char *class,
1439  const char *provider, const char *type, enum lrmd_call_options options)
1440 {
1441  int rc = pcmk_ok;
1442  xmlNode *data = NULL;
1443 
1444  if (!class || !type || !rsc_id) {
1445  return -EINVAL;
1446  }
1447  if (safe_str_eq(class, PCMK_RESOURCE_CLASS_OCF) && !provider) {
1448  return -EINVAL;
1449  }
1450 
1451  data = create_xml_node(NULL, F_LRMD_RSC);
1452 
1453  crm_xml_add(data, F_LRMD_ORIGIN, __FUNCTION__);
1454  crm_xml_add(data, F_LRMD_RSC_ID, rsc_id);
1455  crm_xml_add(data, F_LRMD_CLASS, class);
1456  crm_xml_add(data, F_LRMD_PROVIDER, provider);
1457  crm_xml_add(data, F_LRMD_TYPE, type);
1458  rc = lrmd_send_command(lrmd, LRMD_OP_RSC_REG, data, NULL, 0, options, TRUE);
1459  free_xml(data);
1460 
1461  return rc;
1462 }
1463 
1464 static int
1465 lrmd_api_unregister_rsc(lrmd_t * lrmd, const char *rsc_id, enum lrmd_call_options options)
1466 {
1467  int rc = pcmk_ok;
1468  xmlNode *data = create_xml_node(NULL, F_LRMD_RSC);
1469 
1470  crm_xml_add(data, F_LRMD_ORIGIN, __FUNCTION__);
1471  crm_xml_add(data, F_LRMD_RSC_ID, rsc_id);
1472  rc = lrmd_send_command(lrmd, LRMD_OP_RSC_UNREG, data, NULL, 0, options, TRUE);
1473  free_xml(data);
1474 
1475  return rc;
1476 }
1477 
1480 {
1481  lrmd_rsc_info_t *copy = NULL;
1482 
1483  copy = calloc(1, sizeof(lrmd_rsc_info_t));
1484 
1485  copy->id = strdup(rsc_info->id);
1486  copy->type = strdup(rsc_info->type);
1487  copy->class = strdup(rsc_info->class);
1488  if (rsc_info->provider) {
1489  copy->provider = strdup(rsc_info->provider);
1490  }
1491 
1492  return copy;
1493 }
1494 
1495 void
1497 {
1498  if (!rsc_info) {
1499  return;
1500  }
1501  free(rsc_info->id);
1502  free(rsc_info->type);
1503  free(rsc_info->class);
1504  free(rsc_info->provider);
1505  free(rsc_info);
1506 }
1507 
1508 static lrmd_rsc_info_t *
1509 lrmd_api_get_rsc_info(lrmd_t * lrmd, const char *rsc_id, enum lrmd_call_options options)
1510 {
1511  lrmd_rsc_info_t *rsc_info = NULL;
1512  xmlNode *data = create_xml_node(NULL, F_LRMD_RSC);
1513  xmlNode *output = NULL;
1514  const char *class = NULL;
1515  const char *provider = NULL;
1516  const char *type = NULL;
1517 
1518  crm_xml_add(data, F_LRMD_ORIGIN, __FUNCTION__);
1519  crm_xml_add(data, F_LRMD_RSC_ID, rsc_id);
1520  lrmd_send_command(lrmd, LRMD_OP_RSC_INFO, data, &output, 0, options, TRUE);
1521  free_xml(data);
1522 
1523  if (!output) {
1524  return NULL;
1525  }
1526 
1527  class = crm_element_value(output, F_LRMD_CLASS);
1528  provider = crm_element_value(output, F_LRMD_PROVIDER);
1529  type = crm_element_value(output, F_LRMD_TYPE);
1530 
1531  if (!class || !type) {
1532  free_xml(output);
1533  return NULL;
1534  } else if (safe_str_eq(class, PCMK_RESOURCE_CLASS_OCF) && !provider) {
1535  free_xml(output);
1536  return NULL;
1537  }
1538 
1539  rsc_info = calloc(1, sizeof(lrmd_rsc_info_t));
1540  rsc_info->id = strdup(rsc_id);
1541  rsc_info->class = strdup(class);
1542  if (provider) {
1543  rsc_info->provider = strdup(provider);
1544  }
1545  rsc_info->type = strdup(type);
1546 
1547  free_xml(output);
1548  return rsc_info;
1549 }
1550 
1551 static void
1552 lrmd_api_set_callback(lrmd_t * lrmd, lrmd_event_callback callback)
1553 {
1554  lrmd_private_t *native = lrmd->private;
1555 
1556  native->callback = callback;
1557 }
1558 
1559 void
1560 lrmd_internal_set_proxy_callback(lrmd_t * lrmd, void *userdata, void (*callback)(lrmd_t *lrmd, void *userdata, xmlNode *msg))
1561 {
1562  lrmd_private_t *native = lrmd->private;
1563 
1564  native->proxy_callback = callback;
1565  native->proxy_callback_userdata = userdata;
1566 }
1567 
1568 void
1569 lrmd_internal_proxy_dispatch(lrmd_t *lrmd, xmlNode *msg)
1570 {
1571  lrmd_private_t *native = lrmd->private;
1572 
1573  if (native->proxy_callback) {
1574  crm_log_xml_trace(msg, "PROXY_INBOUND");
1575  native->proxy_callback(lrmd, native->proxy_callback_userdata, msg);
1576  }
1577 }
1578 
1579 int
1580 lrmd_internal_proxy_send(lrmd_t * lrmd, xmlNode *msg)
1581 {
1582  if (lrmd == NULL) {
1583  return -ENOTCONN;
1584  }
1586 
1587  crm_log_xml_trace(msg, "PROXY_OUTBOUND");
1588  return lrmd_send_xml_no_reply(lrmd, msg);
1589 }
1590 
1591 static int
1592 stonith_get_metadata(const char *provider, const char *type, char **output)
1593 {
1594  int rc = pcmk_ok;
1595  stonith_t *stonith_api = stonith_api_new();
1596 
1597  if(stonith_api) {
1598  stonith_api->cmds->metadata(stonith_api, st_opt_sync_call, type, provider, output, 0);
1599  stonith_api->cmds->free(stonith_api);
1600  }
1601  if (*output == NULL) {
1602  rc = -EIO;
1603  }
1604  return rc;
1605 }
1606 
1607 #define lsb_metadata_template \
1608  "<?xml version='1.0'?>\n" \
1609  "<!DOCTYPE resource-agent SYSTEM 'ra-api-1.dtd'>\n" \
1610  "<resource-agent name='%s' version='0.1'>\n" \
1611  " <version>1.0</version>\n" \
1612  " <longdesc lang='en'>\n" \
1613  " %s\n" \
1614  " </longdesc>\n" \
1615  " <shortdesc lang='en'>%s</shortdesc>\n" \
1616  " <parameters>\n" \
1617  " </parameters>\n" \
1618  " <actions>\n" \
1619  " <action name='meta-data' timeout='5' />\n" \
1620  " <action name='start' timeout='15' />\n" \
1621  " <action name='stop' timeout='15' />\n" \
1622  " <action name='status' timeout='15' />\n" \
1623  " <action name='restart' timeout='15' />\n" \
1624  " <action name='force-reload' timeout='15' />\n" \
1625  " <action name='monitor' timeout='15' interval='15' />\n" \
1626  " </actions>\n" \
1627  " <special tag='LSB'>\n" \
1628  " <Provides>%s</Provides>\n" \
1629  " <Required-Start>%s</Required-Start>\n" \
1630  " <Required-Stop>%s</Required-Stop>\n" \
1631  " <Should-Start>%s</Should-Start>\n" \
1632  " <Should-Stop>%s</Should-Stop>\n" \
1633  " <Default-Start>%s</Default-Start>\n" \
1634  " <Default-Stop>%s</Default-Stop>\n" \
1635  " </special>\n" \
1636  "</resource-agent>\n"
1637 
1638 #define LSB_INITSCRIPT_INFOBEGIN_TAG "### BEGIN INIT INFO"
1639 #define LSB_INITSCRIPT_INFOEND_TAG "### END INIT INFO"
1640 #define PROVIDES "# Provides:"
1641 #define REQ_START "# Required-Start:"
1642 #define REQ_STOP "# Required-Stop:"
1643 #define SHLD_START "# Should-Start:"
1644 #define SHLD_STOP "# Should-Stop:"
1645 #define DFLT_START "# Default-Start:"
1646 #define DFLT_STOP "# Default-Stop:"
1647 #define SHORT_DSCR "# Short-Description:"
1648 #define DESCRIPTION "# Description:"
1649 
1650 #define lsb_meta_helper_free_value(m) \
1651  do { \
1652  if ((m) != NULL) { \
1653  xmlFree(m); \
1654  (m) = NULL; \
1655  } \
1656  } while(0)
1657 
1668 static inline gboolean
1669 lsb_meta_helper_get_value(const char *line, char **value, const char *prefix)
1670 {
1671  if (!*value && !strncasecmp(line, prefix, strlen(prefix))) {
1672  *value = (char *)xmlEncodeEntitiesReentrant(NULL, BAD_CAST line+strlen(prefix));
1673  return TRUE;
1674  }
1675  return FALSE;
1676 }
1677 
1678 static int
1679 lsb_get_metadata(const char *type, char **output)
1680 {
1681  char ra_pathname[PATH_MAX] = { 0, };
1682  FILE *fp;
1683  char buffer[1024];
1684  char *provides = NULL;
1685  char *req_start = NULL;
1686  char *req_stop = NULL;
1687  char *shld_start = NULL;
1688  char *shld_stop = NULL;
1689  char *dflt_start = NULL;
1690  char *dflt_stop = NULL;
1691  char *s_dscrpt = NULL;
1692  char *xml_l_dscrpt = NULL;
1693  int offset = 0;
1694  int max = 2048;
1695  char description[max];
1696 
1697  if(type[0] == '/') {
1698  snprintf(ra_pathname, sizeof(ra_pathname), "%s", type);
1699  } else {
1700  snprintf(ra_pathname, sizeof(ra_pathname), "%s/%s", LSB_ROOT_DIR, type);
1701  }
1702 
1703  crm_trace("Looking into %s", ra_pathname);
1704  if (!(fp = fopen(ra_pathname, "r"))) {
1705  return -errno;
1706  }
1707 
1708  /* Enter into the lsb-compliant comment block */
1709  while (fgets(buffer, sizeof(buffer), fp)) {
1710 
1711  /* Now suppose each of the following eight arguments contain only one line */
1712  if (lsb_meta_helper_get_value(buffer, &provides, PROVIDES)) {
1713  continue;
1714  }
1715  if (lsb_meta_helper_get_value(buffer, &req_start, REQ_START)) {
1716  continue;
1717  }
1718  if (lsb_meta_helper_get_value(buffer, &req_stop, REQ_STOP)) {
1719  continue;
1720  }
1721  if (lsb_meta_helper_get_value(buffer, &shld_start, SHLD_START)) {
1722  continue;
1723  }
1724  if (lsb_meta_helper_get_value(buffer, &shld_stop, SHLD_STOP)) {
1725  continue;
1726  }
1727  if (lsb_meta_helper_get_value(buffer, &dflt_start, DFLT_START)) {
1728  continue;
1729  }
1730  if (lsb_meta_helper_get_value(buffer, &dflt_stop, DFLT_STOP)) {
1731  continue;
1732  }
1733  if (lsb_meta_helper_get_value(buffer, &s_dscrpt, SHORT_DSCR)) {
1734  continue;
1735  }
1736 
1737  /* Long description may cross multiple lines */
1738  if (offset == 0 && (0 == strncasecmp(buffer, DESCRIPTION, strlen(DESCRIPTION)))) {
1739  /* Between # and keyword, more than one space, or a tab
1740  * character, indicates the continuation line.
1741  *
1742  * Extracted from LSB init script standard
1743  */
1744  while (fgets(buffer, sizeof(buffer), fp)) {
1745  if (!strncmp(buffer, "# ", 3) || !strncmp(buffer, "#\t", 2)) {
1746  buffer[0] = ' ';
1747  offset += snprintf(description+offset, max-offset, "%s", buffer);
1748 
1749  } else {
1750  fputs(buffer, fp);
1751  break; /* Long description ends */
1752  }
1753  }
1754  continue;
1755  }
1756 
1757  if (xml_l_dscrpt == NULL && offset > 0) {
1758  xml_l_dscrpt = (char *)xmlEncodeEntitiesReentrant(NULL, BAD_CAST(description));
1759  }
1760 
1761  if (!strncasecmp(buffer, LSB_INITSCRIPT_INFOEND_TAG, strlen(LSB_INITSCRIPT_INFOEND_TAG))) {
1762  /* Get to the out border of LSB comment block */
1763  break;
1764  }
1765  if (buffer[0] != '#') {
1766  break; /* Out of comment block in the beginning */
1767  }
1768  }
1769  fclose(fp);
1770 
1771  *output = crm_strdup_printf(lsb_metadata_template, type,
1772  (xml_l_dscrpt == NULL) ? type : xml_l_dscrpt,
1773  (s_dscrpt == NULL) ? type : s_dscrpt, (provides == NULL) ? "" : provides,
1774  (req_start == NULL) ? "" : req_start, (req_stop == NULL) ? "" : req_stop,
1775  (shld_start == NULL) ? "" : shld_start, (shld_stop == NULL) ? "" : shld_stop,
1776  (dflt_start == NULL) ? "" : dflt_start, (dflt_stop == NULL) ? "" : dflt_stop);
1777 
1778  lsb_meta_helper_free_value(xml_l_dscrpt);
1779  lsb_meta_helper_free_value(s_dscrpt);
1780  lsb_meta_helper_free_value(provides);
1781  lsb_meta_helper_free_value(req_start);
1782  lsb_meta_helper_free_value(req_stop);
1783  lsb_meta_helper_free_value(shld_start);
1784  lsb_meta_helper_free_value(shld_stop);
1785  lsb_meta_helper_free_value(dflt_start);
1786  lsb_meta_helper_free_value(dflt_stop);
1787 
1788  crm_trace("Created fake metadata: %llu",
1789  (unsigned long long) strlen(*output));
1790  return pcmk_ok;
1791 }
1792 
1793 #if SUPPORT_NAGIOS
1794 static int
1795 nagios_get_metadata(const char *type, char **output)
1796 {
1797  int rc = pcmk_ok;
1798  FILE *file_strm = NULL;
1799  int start = 0, length = 0, read_len = 0;
1800  char *metadata_file = NULL;
1801  int len = 36;
1802 
1803  len += strlen(NAGIOS_METADATA_DIR);
1804  len += strlen(type);
1805  metadata_file = calloc(1, len);
1806  CRM_CHECK(metadata_file != NULL, return -ENOMEM);
1807 
1808  sprintf(metadata_file, "%s/%s.xml", NAGIOS_METADATA_DIR, type);
1809  file_strm = fopen(metadata_file, "r");
1810  if (file_strm == NULL) {
1811  crm_err("Metadata file %s does not exist", metadata_file);
1812  free(metadata_file);
1813  return -EIO;
1814  }
1815 
1816  /* see how big the file is */
1817  start = ftell(file_strm);
1818  fseek(file_strm, 0L, SEEK_END);
1819  length = ftell(file_strm);
1820  fseek(file_strm, 0L, start);
1821 
1822  CRM_ASSERT(length >= 0);
1823  CRM_ASSERT(start == ftell(file_strm));
1824 
1825  if (length <= 0) {
1826  crm_info("%s was not valid", metadata_file);
1827  free(*output);
1828  *output = NULL;
1829  rc = -EIO;
1830 
1831  } else {
1832  crm_trace("Reading %d bytes from file", length);
1833  *output = calloc(1, (length + 1));
1834  read_len = fread(*output, 1, length, file_strm);
1835  if (read_len != length) {
1836  crm_err("Calculated and read bytes differ: %d vs. %d", length, read_len);
1837  free(*output);
1838  *output = NULL;
1839  rc = -EIO;
1840  }
1841  }
1842 
1843  fclose(file_strm);
1844  free(metadata_file);
1845  return rc;
1846 }
1847 #endif
1848 
1849 #if SUPPORT_HEARTBEAT
1850 /* strictly speaking, support for class=heartbeat style scripts
1851  * does not require "heartbeat support" to be enabled.
1852  * But since those scripts are part of the "heartbeat" package usually,
1853  * and are very unlikely to be present in any other deployment,
1854  * I leave it inside this ifdef.
1855  *
1856  * Yes, I know, these are legacy and should die,
1857  * or at least be rewritten to be a proper OCF style agent.
1858  * But they exist, and custom scripts following these rules do, too.
1859  *
1860  * Taken from the old "glue" lrmd, see
1861  * http://hg.linux-ha.org/glue/file/0a7add1d9996/lib/plugins/lrm/raexechb.c#l49
1862  * http://hg.linux-ha.org/glue/file/0a7add1d9996/lib/plugins/lrm/raexechb.c#l393
1863  */
1864 
1865 static const char hb_metadata_template[] =
1866 "<?xml version='1.0'?>\n"
1867 "<!DOCTYPE resource-agent SYSTEM 'ra-api-1.dtd'>\n"
1868 "<resource-agent name='%s' version='0.1'>\n"
1869 "<version>1.0</version>\n"
1870 "<longdesc lang='en'>\n"
1871 "%s"
1872 "</longdesc>\n"
1873 "<shortdesc lang='en'>%s</shortdesc>\n"
1874 "<parameters>\n"
1875 "<parameter name='1' unique='1' required='0'>\n"
1876 "<longdesc lang='en'>\n"
1877 "This argument will be passed as the first argument to the "
1878 "heartbeat resource agent (assuming it supports one)\n"
1879 "</longdesc>\n"
1880 "<shortdesc lang='en'>argv[1]</shortdesc>\n"
1881 "<content type='string' default=' ' />\n"
1882 "</parameter>\n"
1883 "<parameter name='2' unique='1' required='0'>\n"
1884 "<longdesc lang='en'>\n"
1885 "This argument will be passed as the second argument to the "
1886 "heartbeat resource agent (assuming it supports one)\n"
1887 "</longdesc>\n"
1888 "<shortdesc lang='en'>argv[2]</shortdesc>\n"
1889 "<content type='string' default=' ' />\n"
1890 "</parameter>\n"
1891 "<parameter name='3' unique='1' required='0'>\n"
1892 "<longdesc lang='en'>\n"
1893 "This argument will be passed as the third argument to the "
1894 "heartbeat resource agent (assuming it supports one)\n"
1895 "</longdesc>\n"
1896 "<shortdesc lang='en'>argv[3]</shortdesc>\n"
1897 "<content type='string' default=' ' />\n"
1898 "</parameter>\n"
1899 "<parameter name='4' unique='1' required='0'>\n"
1900 "<longdesc lang='en'>\n"
1901 "This argument will be passed as the fourth argument to the "
1902 "heartbeat resource agent (assuming it supports one)\n"
1903 "</longdesc>\n"
1904 "<shortdesc lang='en'>argv[4]</shortdesc>\n"
1905 "<content type='string' default=' ' />\n"
1906 "</parameter>\n"
1907 "<parameter name='5' unique='1' required='0'>\n"
1908 "<longdesc lang='en'>\n"
1909 "This argument will be passed as the fifth argument to the "
1910 "heartbeat resource agent (assuming it supports one)\n"
1911 "</longdesc>\n"
1912 "<shortdesc lang='en'>argv[5]</shortdesc>\n"
1913 "<content type='string' default=' ' />\n"
1914 "</parameter>\n"
1915 "</parameters>\n"
1916 "<actions>\n"
1917 "<action name='start' timeout='15' />\n"
1918 "<action name='stop' timeout='15' />\n"
1919 "<action name='status' timeout='15' />\n"
1920 "<action name='monitor' timeout='15' interval='15' start-delay='15' />\n"
1921 "<action name='meta-data' timeout='5' />\n"
1922 "</actions>\n"
1923 "<special tag='heartbeat'>\n"
1924 "</special>\n"
1925 "</resource-agent>\n";
1926 
1927 static int
1928 heartbeat_get_metadata(const char *type, char **output)
1929 {
1930  *output = crm_strdup_printf(hb_metadata_template, type, type, type);
1931  crm_trace("Created fake metadata: %llu",
1932  (unsigned long long) strlen(*output));
1933  return pcmk_ok;
1934 }
1935 #endif
1936 
1937 static int
1938 generic_get_metadata(const char *standard, const char *provider, const char *type, char **output)
1939 {
1940  svc_action_t *action;
1941 
1942  action = resources_action_create(type, standard, provider, type,
1943  "meta-data", 0, 30000, NULL, 0);
1944  if (action == NULL) {
1945  crm_err("Unable to retrieve meta-data for %s:%s:%s", standard, provider, type);
1946  services_action_free(action);
1947  return -EINVAL;
1948  }
1949 
1950  if (!(services_action_sync(action))) {
1951  crm_err("Failed to retrieve meta-data for %s:%s:%s", standard, provider, type);
1952  services_action_free(action);
1953  return -EIO;
1954  }
1955 
1956  if (!action->stdout_data) {
1957  crm_err("Failed to receive meta-data for %s:%s:%s", standard, provider, type);
1958  services_action_free(action);
1959  return -EIO;
1960  }
1961 
1962  *output = strdup(action->stdout_data);
1963  services_action_free(action);
1964 
1965  return pcmk_ok;
1966 }
1967 
1968 static int
1969 lrmd_api_get_metadata(lrmd_t * lrmd,
1970  const char *class,
1971  const char *provider,
1972  const char *type, char **output, enum lrmd_call_options options)
1973 {
1974  if (!class || !type) {
1975  return -EINVAL;
1976  }
1977 
1979  class = resources_find_service_class(type);
1980  }
1981 
1983  return stonith_get_metadata(provider, type, output);
1984  } else if (safe_str_eq(class, PCMK_RESOURCE_CLASS_LSB)) {
1985  return lsb_get_metadata(type, output);
1986 #if SUPPORT_NAGIOS
1987  } else if (safe_str_eq(class, PCMK_RESOURCE_CLASS_NAGIOS)) {
1988  return nagios_get_metadata(type, output);
1989 #endif
1990 #if SUPPORT_HEARTBEAT
1991  } else if (safe_str_eq(class, PCMK_RESOURCE_CLASS_HB)) {
1992  return heartbeat_get_metadata(type, output);
1993 #endif
1994  }
1995  return generic_get_metadata(class, provider, type, output);
1996 }
1997 
1998 static int
1999 lrmd_api_exec(lrmd_t * lrmd, const char *rsc_id, const char *action, const char *userdata, int interval, /* ms */
2000  int timeout, /* ms */
2001  int start_delay, /* ms */
2002  enum lrmd_call_options options, lrmd_key_value_t * params)
2003 {
2004  int rc = pcmk_ok;
2005  xmlNode *data = create_xml_node(NULL, F_LRMD_RSC);
2006  xmlNode *args = create_xml_node(data, XML_TAG_ATTRS);
2007  lrmd_key_value_t *tmp = NULL;
2008 #ifdef ENABLE_VERSIONED_ATTRS
2009  const char *versioned_args_key = "#" XML_TAG_VER_ATTRS;
2010 #endif
2011 
2012  crm_xml_add(data, F_LRMD_ORIGIN, __FUNCTION__);
2013  crm_xml_add(data, F_LRMD_RSC_ID, rsc_id);
2014  crm_xml_add(data, F_LRMD_RSC_ACTION, action);
2015  crm_xml_add(data, F_LRMD_RSC_USERDATA_STR, userdata);
2016  crm_xml_add_int(data, F_LRMD_RSC_INTERVAL, interval);
2017  crm_xml_add_int(data, F_LRMD_TIMEOUT, timeout);
2018  crm_xml_add_int(data, F_LRMD_RSC_START_DELAY, start_delay);
2019 
2020  for (tmp = params; tmp; tmp = tmp->next) {
2021 #ifdef ENABLE_VERSIONED_ATTRS
2022  if (safe_str_eq(tmp->key, versioned_args_key)) {
2023  xmlNode *versioned_args = string2xml(tmp->value);
2024 
2025  if (versioned_args) {
2026  add_node_nocopy(data, NULL, versioned_args);
2027  }
2028  } else {
2029 #endif
2030  hash2smartfield((gpointer) tmp->key, (gpointer) tmp->value, args);
2031 #ifdef ENABLE_VERSIONED_ATTRS
2032  }
2033 #endif
2034  }
2035 
2036  rc = lrmd_send_command(lrmd, LRMD_OP_RSC_EXEC, data, NULL, timeout, options, TRUE);
2037  free_xml(data);
2038 
2039  lrmd_key_value_freeall(params);
2040  return rc;
2041 }
2042 
2043 static int
2044 lrmd_api_cancel(lrmd_t * lrmd, const char *rsc_id, const char *action, int interval)
2045 {
2046  int rc = pcmk_ok;
2047  xmlNode *data = create_xml_node(NULL, F_LRMD_RSC);
2048 
2049  crm_xml_add(data, F_LRMD_ORIGIN, __FUNCTION__);
2050  crm_xml_add(data, F_LRMD_RSC_ACTION, action);
2051  crm_xml_add(data, F_LRMD_RSC_ID, rsc_id);
2052  crm_xml_add_int(data, F_LRMD_RSC_INTERVAL, interval);
2053  rc = lrmd_send_command(lrmd, LRMD_OP_RSC_CANCEL, data, NULL, 0, 0, TRUE);
2054  free_xml(data);
2055  return rc;
2056 }
2057 
2058 static int
2059 list_stonith_agents(lrmd_list_t ** resources)
2060 {
2061  int rc = 0;
2062  stonith_t *stonith_api = stonith_api_new();
2063  stonith_key_value_t *stonith_resources = NULL;
2064  stonith_key_value_t *dIter = NULL;
2065 
2066  if(stonith_api) {
2067  stonith_api->cmds->list_agents(stonith_api, st_opt_sync_call, NULL, &stonith_resources, 0);
2068  stonith_api->cmds->free(stonith_api);
2069  }
2070 
2071  for (dIter = stonith_resources; dIter; dIter = dIter->next) {
2072  rc++;
2073  if (resources) {
2074  *resources = lrmd_list_add(*resources, dIter->value);
2075  }
2076  }
2077 
2078  stonith_key_value_freeall(stonith_resources, 1, 0);
2079  return rc;
2080 }
2081 
2082 static int
2083 lrmd_api_list_agents(lrmd_t * lrmd, lrmd_list_t ** resources, const char *class,
2084  const char *provider)
2085 {
2086  int rc = 0;
2087 
2089  rc += list_stonith_agents(resources);
2090 
2091  } else {
2092  GListPtr gIter = NULL;
2093  GList *agents = resources_list_agents(class, provider);
2094 
2095  for (gIter = agents; gIter != NULL; gIter = gIter->next) {
2096  *resources = lrmd_list_add(*resources, (const char *)gIter->data);
2097  rc++;
2098  }
2099  g_list_free_full(agents, free);
2100 
2101  if (!class) {
2102  rc += list_stonith_agents(resources);
2103  }
2104  }
2105 
2106  if (rc == 0) {
2107  crm_notice("No agents found for class %s", class);
2108  rc = -EPROTONOSUPPORT;
2109  }
2110  return rc;
2111 }
2112 
2113 static int
2114 does_provider_have_agent(const char *agent, const char *provider, const char *class)
2115 {
2116  int found = 0;
2117  GList *agents = NULL;
2118  GListPtr gIter2 = NULL;
2119 
2120  agents = resources_list_agents(class, provider);
2121  for (gIter2 = agents; gIter2 != NULL; gIter2 = gIter2->next) {
2122  if (safe_str_eq(agent, gIter2->data)) {
2123  found = 1;
2124  }
2125  }
2126  g_list_free_full(agents, free);
2127 
2128  return found;
2129 }
2130 
2131 static int
2132 lrmd_api_list_ocf_providers(lrmd_t * lrmd, const char *agent, lrmd_list_t ** providers)
2133 {
2134  int rc = pcmk_ok;
2135  char *provider = NULL;
2136  GList *ocf_providers = NULL;
2137  GListPtr gIter = NULL;
2138 
2140 
2141  for (gIter = ocf_providers; gIter != NULL; gIter = gIter->next) {
2142  provider = gIter->data;
2143  if (!agent || does_provider_have_agent(agent, provider,
2145  *providers = lrmd_list_add(*providers, (const char *)gIter->data);
2146  rc++;
2147  }
2148  }
2149 
2150  g_list_free_full(ocf_providers, free);
2151  return rc;
2152 }
2153 
2154 static int
2155 lrmd_api_list_standards(lrmd_t * lrmd, lrmd_list_t ** supported)
2156 {
2157  int rc = 0;
2158  GList *standards = NULL;
2159  GListPtr gIter = NULL;
2160 
2161  standards = resources_list_standards();
2162 
2163  for (gIter = standards; gIter != NULL; gIter = gIter->next) {
2164  *supported = lrmd_list_add(*supported, (const char *)gIter->data);
2165  rc++;
2166  }
2167 
2168  if (list_stonith_agents(NULL) > 0) {
2169  *supported = lrmd_list_add(*supported, PCMK_RESOURCE_CLASS_STONITH);
2170  rc++;
2171  }
2172 
2173  g_list_free_full(standards, free);
2174  return rc;
2175 }
2176 
2177 lrmd_t *
2179 {
2180  lrmd_t *new_lrmd = NULL;
2181  lrmd_private_t *pvt = NULL;
2182 
2183  new_lrmd = calloc(1, sizeof(lrmd_t));
2184  pvt = calloc(1, sizeof(lrmd_private_t));
2185  pvt->remote = calloc(1, sizeof(crm_remote_t));
2186  new_lrmd->cmds = calloc(1, sizeof(lrmd_api_operations_t));
2187 
2188  pvt->type = CRM_CLIENT_IPC;
2189  new_lrmd->private = pvt;
2190 
2191  new_lrmd->cmds->connect = lrmd_api_connect;
2192  new_lrmd->cmds->connect_async = lrmd_api_connect_async;
2193  new_lrmd->cmds->is_connected = lrmd_api_is_connected;
2194  new_lrmd->cmds->poke_connection = lrmd_api_poke_connection;
2195  new_lrmd->cmds->disconnect = lrmd_api_disconnect;
2196  new_lrmd->cmds->register_rsc = lrmd_api_register_rsc;
2197  new_lrmd->cmds->unregister_rsc = lrmd_api_unregister_rsc;
2198  new_lrmd->cmds->get_rsc_info = lrmd_api_get_rsc_info;
2199  new_lrmd->cmds->set_callback = lrmd_api_set_callback;
2200  new_lrmd->cmds->get_metadata = lrmd_api_get_metadata;
2201  new_lrmd->cmds->exec = lrmd_api_exec;
2202  new_lrmd->cmds->cancel = lrmd_api_cancel;
2203  new_lrmd->cmds->list_agents = lrmd_api_list_agents;
2204  new_lrmd->cmds->list_ocf_providers = lrmd_api_list_ocf_providers;
2205  new_lrmd->cmds->list_standards = lrmd_api_list_standards;
2206 
2207  return new_lrmd;
2208 }
2209 
2210 lrmd_t *
2211 lrmd_remote_api_new(const char *nodename, const char *server, int port)
2212 {
2213 #ifdef HAVE_GNUTLS_GNUTLS_H
2214  lrmd_t *new_lrmd = lrmd_api_new();
2215  lrmd_private_t *native = new_lrmd->private;
2216 
2217  if (!nodename && !server) {
2218  lrmd_api_delete(new_lrmd);
2219  return NULL;
2220  }
2221 
2222  native->type = CRM_CLIENT_TLS;
2223  native->remote_nodename = nodename ? strdup(nodename) : strdup(server);
2224  native->server = server ? strdup(server) : strdup(nodename);
2225  native->port = port;
2226  if (native->port == 0) {
2227  const char *remote_port_str = getenv("PCMK_remote_port");
2228  native->port = remote_port_str ? atoi(remote_port_str) : DEFAULT_REMOTE_PORT;
2229  }
2230 
2231  return new_lrmd;
2232 #else
2233  crm_err("GNUTLS is not enabled for this build, remote LRMD client can not be created");
2234  return NULL;
2235 #endif
2236 
2237 }
2238 
2239 void
2241 {
2242  if (!lrmd) {
2243  return;
2244  }
2245  lrmd->cmds->disconnect(lrmd); /* no-op if already disconnected */
2246  free(lrmd->cmds);
2247  if (lrmd->private) {
2248  lrmd_private_t *native = lrmd->private;
2249 
2250 #ifdef HAVE_GNUTLS_GNUTLS_H
2251  free(native->server);
2252 #endif
2253  free(native->remote_nodename);
2254  free(native->remote);
2255  free(native->token);
2256  free(native->peer_version);
2257  }
2258 
2259  free(lrmd->private);
2260  free(lrmd);
2261 }
Services API.
#define F_LRMD_RSC
Definition: lrmd.h:82
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:164
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:4923
lrmd_event_data_t * lrmd_copy_event(lrmd_event_data_t *event)
Definition: lrmd_client.c:196
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:443
lrmd_call_options
Definition: lrmd.h:162
int crm_remote_ready(crm_remote_t *remote, int total_timeout)
Definition: remote.c:451
gboolean crm_remote_recv(crm_remote_t *remote, int total_timeout, int *disconnected)
Definition: remote.c:613
const char * user_data
Definition: lrmd.h:201
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:48
const char * rsc_id
Definition: lrmd.h:197
char * class
Definition: lrmd.h:258
#define F_LRMD_IPC_SESSION
Definition: lrmd.h:106
#define F_LRMD_RSC_EXEC_TIME
Definition: lrmd.h:70
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:211
#define F_LRMD_RSC_ACTION
Definition: lrmd.h:74
#define LRMD_OP_RSC_CANCEL
Definition: lrmd.h:87
int crm_ipc_get_fd(crm_ipc_t *client)
Definition: ipc.c:942
#define LRMD_OP_CHECK
Definition: lrmd.h:93
#define F_LRMD_ORIGIN
Definition: lrmd.h:66
#define F_LRMD_RSC_OUTPUT
Definition: lrmd.h:76
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:294
#define SHLD_START
Definition: lrmd_client.c:1643
void(* lrmd_event_callback)(lrmd_event_data_t *event)
Definition: lrmd.h:265
#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:154
struct stonith_key_value_s * next
Definition: stonith-ng.h:77
void lrmd_key_value_freeall(lrmd_key_value_t *head)
Definition: lrmd_client.c:176
char * id
Definition: lrmd.h:256
#define XML_TAG_ATTRS
Definition: msg_xml.h:179
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:44
Local Resource Manager.
#define MAX_TLS_RECV_WAIT
Definition: lrmd_client.c:55
#define F_LRMD_EXEC_RC
Definition: lrmd.h:59
const char * output
Definition: lrmd.h:219
int lrmd_internal_proxy_send(lrmd_t *lrmd, xmlNode *msg)
Definition: lrmd_client.c:1580
#define F_LRMD_WATCHDOG
Definition: lrmd.h:62
#define SHLD_STOP
Definition: lrmd_client.c:1644
#define LRMD_OP_POKE
Definition: lrmd.h:91
lrmd_rsc_info_t * lrmd_copy_rsc_info(lrmd_rsc_info_t *rsc_info)
Definition: lrmd_client.c:1479
long crm_ipc_read(crm_ipc_t *client)
Definition: ipc.c:1050
#define REQ_STOP
Definition: lrmd_client.c:1642
gboolean mainloop_destroy_trigger(crm_trigger_t *source)
Definition: mainloop.c:233
#define REQ_START
Definition: lrmd_client.c:1641
int(* cancel)(lrmd_t *lrmd, const char *rsc_id, const char *action, int interval)
Cancel a recurring command.
Definition: lrmd.h:408
#define F_LRMD_RSC_ID
Definition: lrmd.h:73
int crm_remote_tcp_connect(const char *host, int port)
Definition: remote.c:929
Wrappers for and extensions to glib mainloop.
#define F_LRMD_PROTOCOL_VERSION
Definition: lrmd.h:50
#define F_LRMD_RC
Definition: lrmd.h:58
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:2211
stonith_t * stonith_api_new(void)
Definition: st_client.c:2450
#define CRM_OP_REGISTER
Definition: crm.h:115
xmlNode * string2xml(const char *input)
Definition: xml.c:2774
char version[256]
Definition: plugin.c:84
const char * crm_ipc_buffer(crm_ipc_t *client)
Definition: ipc.c:1096
int remote_proxy_check(lrmd_t *lrmd, GHashTable *hash)
Definition: lrmd_client.c:899
const char * val
Definition: lrmd.h:268
#define LRMD_OP_RSC_UNREG
Definition: lrmd.h:88
#define F_LRMD_CLIENTID
Definition: lrmd.h:49
#define DEFAULT_REMOTE_PORT
Definition: lrmd.h:43
#define DEFAULT_REMOTE_KEY_LOCATION
Definition: lrmd.h:41
struct trigger_s crm_trigger_t
Definition: mainloop.h:34
void hash2smartfield(gpointer key, gpointer value, gpointer user_data)
Definition: xml.c:4861
struct lrmd_private_s lrmd_private_t
xmlNode * copy_xml(xmlNode *src_node)
Definition: xml.c:2711
#define PROVIDES
Definition: lrmd_client.c:1640
int(* free)(stonith_t *st)
Destroy the stonith api structure.
Definition: stonith-ng.h:126
int(* dispatch)(gpointer userdata)
Definition: mainloop.h:90
#define DESCRIPTION
Definition: lrmd_client.c:1648
void * params
Definition: lrmd.h:234
#define crm_warn(fmt, args...)
Definition: logging.h:249
int(* poke_connection)(lrmd_t *lrmd)
Poke lrmd connection to verify it is still capable of serving requests.
Definition: lrmd.h:311
const char * exit_reason
Definition: lrmd.h:242
#define PCMK_RESOURCE_CLASS_OCF
Definition: services.h:56
#define crm_debug(fmt, args...)
Definition: logging.h:253
int crm_initiate_client_tls_handshake(crm_remote_t *remote, int timeout_ms)
#define DFLT_START
Definition: lrmd_client.c:1645
#define lsb_metadata_template
Definition: lrmd_client.c:1607
struct crm_ipc_s crm_ipc_t
Definition: ipc.h:61
#define F_LRMD_RSC_EXIT_REASON
Definition: lrmd.h:77
#define ALT_REMOTE_KEY_LOCATION
Definition: lrmd.h:42
bool lrmd_dispatch(lrmd_t *lrmd)
Use after lrmd_poll returns 1 to read and dispatch a message.
Definition: lrmd_client.c:456
char * key
Definition: lrmd.h:33
struct lrmd_list_s * next
Definition: lrmd.h:269
gboolean services_action_sync(svc_action_t *op)
Definition: services.c:793
char * stdout_data
Definition: services.h:184
#define LRMD_PROTOCOL_VERSION
Definition: lrmd.h:38
xmlNode * crm_remote_parse_buffer(crm_remote_t *remote)
Definition: remote.c:380
int(* get_metadata)(lrmd_t *lrmd, const char *class, const char *provider, const char *agent, char **output, enum lrmd_call_options options)
Get the metadata documentation for a resource.
Definition: lrmd.h:418
#define F_LRMD_TIMEOUT
Definition: lrmd.h:61
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:340
void lrmd_list_freeall(lrmd_list_t *head)
Definition: lrmd_client.c:138
#define PCMK_RESOURCE_CLASS_SERVICE
Definition: services.h:57
int(* connect)(lrmd_t *lrmd, const char *client_name, int *fd)
Connect from the lrmd.
Definition: lrmd.h:282
#define F_LRMD_CALLDATA
Definition: lrmd.h:57
#define crm_trace(fmt, args...)
Definition: logging.h:254
#define F_LRMD_TYPE
Definition: lrmd.h:65
#define F_LRMD_CLASS
Definition: lrmd.h:63
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:92
xmlNode * create_xml_node(xmlNode *parent, const char *name)
Definition: xml.c:2587
int crm_element_value_int(xmlNode *data, const char *name, int *dest)
Definition: xml.c:3868
const char * crm_element_value(xmlNode *data, const char *name)
Definition: xml.c:5134
void stonith_key_value_freeall(stonith_key_value_t *kvp, int keys, int values)
Definition: st_client.c:2529
#define ECOMM
Definition: portability.h:231
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:879
lrmd_t * lrmd_api_new(void)
Create a new local lrmd connection.
Definition: lrmd_client.c:2178
#define LSB_INITSCRIPT_INFOEND_TAG
Definition: lrmd_client.c:1639
struct lrmd_key_value_s * next
Definition: lrmd.h:35
#define F_LRMD_RSC_USERDATA_STR
Definition: lrmd.h:75
gboolean add_message_xml(xmlNode *msg, const char *field, xmlNode *xml)
Definition: xml.c:3195
void free_xml(xmlNode *child)
Definition: xml.c:2705
#define F_LRMD_RSC_INTERVAL
Definition: lrmd.h:79
void lrmd_free_rsc_info(lrmd_rsc_info_t *rsc_info)
Definition: lrmd_client.c:1496
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:844
#define LSB_ROOT_DIR
Definition: services.h:42
CRM_TRACE_INIT_DATA(lrmd)
#define LRMD_OP_RSC_EXEC
Definition: lrmd.h:86
gboolean crm_str_eq(const char *a, const char *b, gboolean use_case)
Definition: strings.c:213
#define F_LRMD_OP_STATUS
Definition: lrmd.h:60
int(* unregister_rsc)(lrmd_t *lrmd, const char *rsc_id, enum lrmd_call_options options)
Unregister a resource from the lrmd.
Definition: lrmd.h:357
#define F_LRMD_RSC_START_DELAY
Definition: lrmd.h:78
int(* disconnect)(lrmd_t *lrmd)
Disconnect from the lrmd.
Definition: lrmd.h:319
const char * op_type
Definition: lrmd.h:199
#define LRMD_OP_RSC_REG
Definition: lrmd.h:85
#define SHORT_DSCR
Definition: lrmd_client.c:1647
bool crm_ipc_connected(crm_ipc_t *client)
Definition: ipc.c:956
void * private
Definition: lrmd.h:461
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:431
const char * crm_xml_add(xmlNode *node, const char *name, const char *value)
Definition: xml.c:2489
#define PCMK_RESOURCE_CLASS_STONITH
Definition: services.h:63
const char * crm_xml_add_int(xmlNode *node, const char *name, int value)
Definition: xml.c:2577
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:69
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:432
#define lsb_meta_helper_free_value(m)
Definition: lrmd_client.c:1650
char * type
Definition: lrmd.h:257
#define crm_log_xml_err(xml, text)
Definition: logging.h:257
#define F_LRMD_PROVIDER
Definition: lrmd.h:64
void lrmd_api_delete(lrmd_t *lrmd)
Destroy lrmd object.
Definition: lrmd_client.c:2240
#define PCMK_RESOURCE_CLASS_NAGIOS
Definition: services.h:62
#define F_LRMD_REMOTE_MSG_ID
Definition: lrmd.h:52
#define PCMK_RESOURCE_CLASS_LSB
Definition: services.h:58
#define crm_perror(level, fmt, args...)
Log a system error message.
Definition: logging.h:226
const char * remote_nodename
Definition: lrmd.h:239
lrmd_api_operations_t * cmds
Definition: lrmd.h:460
crm_ipc_t * mainloop_get_ipc_client(mainloop_io_t *client)
Definition: mainloop.c:801
GList * resources_list_standards(void)
Definition: services.c:835
#define crm_err(fmt, args...)
Definition: logging.h:248
#define T_LRMD
Definition: lrmd.h:114
enum lrmd_callback_event type
Definition: lrmd.h:194
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:370
int crm_ipc_send(crm_ipc_t *client, xmlNode *message, enum crm_ipc_flags flags, int32_t ms_timeout, xmlNode **reply)
Definition: ipc.c:1199
#define PCMK_RESOURCE_CLASS_HB
Definition: services.h:61
Fencing aka. STONITH.
#define F_LRMD_CALLID
Definition: lrmd.h:54
int(* list_standards)(lrmd_t *lrmd, lrmd_list_t **standards)
Retrieve a list of standards supported by this machine/installation.
Definition: lrmd.h:455
crm_ipc_t * crm_ipc_new(const char *name, size_t max_size)
Definition: ipc.c:845
#define F_LRMD_CALLOPTS
Definition: lrmd.h:56
GList * resources_list_agents(const char *standard, const char *provider)
Get a list of resource agents.
Definition: services.c:889
#define CRM_SYSTEM_LRMD
Definition: crm.h:91
#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:68
char * provider
Definition: lrmd.h:259
Definition: lrmd.h:459
int add_node_nocopy(xmlNode *parent, const char *name, xmlNode *child)
Definition: xml.c:2418
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:329
int(* list_ocf_providers)(lrmd_t *lrmd, const char *agent, lrmd_list_t **providers)
Retrieve a list of resource agent providers.
Definition: lrmd.h:445
void lrmd_internal_set_proxy_callback(lrmd_t *lrmd, void *userdata, void(*callback)(lrmd_t *lrmd, void *userdata, xmlNode *msg))
Definition: lrmd_client.c:1560
#define crm_log_xml_trace(xml, text)
Definition: logging.h:262
xmlNode * first_named_child(xmlNode *parent, const char *name)
Definition: xml.c:5046
#define F_LRMD_CLIENTNAME
Definition: lrmd.h:47
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:71
#define F_LRMD_RSC_DELETED
Definition: lrmd.h:81
#define F_LRMD_OPERATION
Definition: lrmd.h:46
#define CRM_OP_IPC_FWD
Definition: crm.h:116
#define safe_str_eq(a, b)
Definition: util.h:64
#define F_LRMD_CALLBACK_TOKEN
Definition: lrmd.h:53
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:198
char * crm_strdup_printf(char const *format,...) __attribute__((__format__(__printf__
#define crm_str_hash
Definition: crm.h:208
#define F_XML_TAGNAME
Definition: msg_xml.h:42
void lrmd_free_event(lrmd_event_data_t *event)
Definition: lrmd_client.c:233
#define F_LRMD_REMOTE_MSG_TYPE
Definition: lrmd.h:51
void crm_ipc_close(crm_ipc_t *client)
Definition: ipc.c:904
GList * GListPtr
Definition: crm.h:202
char * value
Definition: lrmd.h:34
#define DFLT_STOP
Definition: lrmd_client.c:1646
int crm_remote_send(crm_remote_t *remote, xmlNode *msg)
Definition: remote.c:332
#define crm_info(fmt, args...)
Definition: logging.h:251
#define NAGIOS_METADATA_DIR
Definition: config.h:615
int(* is_connected)(lrmd_t *lrmd)
Is connected to lrmd daemon?
Definition: lrmd.h:302
void g_hash_destroy_str(gpointer data)
Definition: strings.c:74
int(* dispatch)(const char *buffer, ssize_t length, gpointer userdata)
Definition: mainloop.h:73
void(* set_callback)(lrmd_t *lrmd, lrmd_event_callback callback)
Sets the callback to receive lrmd events on.
Definition: lrmd.h:362
#define LRMD_OP_RSC_INFO
Definition: lrmd.h:89
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:379