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