pacemaker  1.1.18-7fdfbbe
Scalable High-Availability cluster resource manager
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
legacy.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
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 #include <crm_internal.h>
20 #include <crm/cluster/internal.h>
21 #include <bzlib.h>
22 #include <crm/common/ipc.h>
23 #include <crm/cluster.h>
24 #include <crm/common/mainloop.h>
25 #include <sys/utsname.h>
26 #include <sys/socket.h>
27 #include <netdb.h>
28 
29 #if SUPPORT_COROSYNC
30 # include <corosync/confdb.h>
31 # include <corosync/corodefs.h>
32 # include <corosync/cpg.h>
33 # include <corosync/cfg.h>
34 #endif
35 
36 #if HAVE_CMAP
37 # include <corosync/cmap.h>
38 #endif
39 
40 #if SUPPORT_CMAN
41 # include <libcman.h>
42 cman_handle_t pcmk_cman_handle = NULL;
43 #endif
44 
46 gboolean ais_membership_force = FALSE;
47 int plugin_dispatch(gpointer user_data);
48 
49 int ais_fd_sync = -1;
50 int ais_fd_async = -1; /* never send messages via this channel */
51 void *ais_ipc_ctx = NULL;
52 
53 hdb_handle_t ais_ipc_handle = 0;
54 
55 #if SUPPORT_CMAN
56 static bool valid_cman_name(const char *name, uint32_t nodeid)
57 {
58  bool rc = TRUE;
59 
60  /* Yes, %d, because that's what CMAN does */
61  char *fakename = crm_strdup_printf("Node%d", nodeid);
62 
63  if(crm_str_eq(fakename, name, TRUE)) {
64  rc = FALSE;
65  crm_notice("Ignoring inferred name from cman: %s", fakename);
66  }
67  free(fakename);
68  return rc;
69 }
70 #endif
71 
72 static gboolean
73 plugin_get_details(uint32_t * id, char **uname)
74 {
75  struct iovec iov;
76  int retries = 0;
77  int rc = CS_OK;
79  struct crm_ais_nodeid_resp_s answer;
80 
81  static uint32_t local_id = 0;
82  static char *local_uname = NULL;
83 
84  if(local_id) {
85  if(id) *id = local_id;
86  if(uname) *uname = strdup(local_uname);
87  return TRUE;
88  }
89 
90  header.error = CS_OK;
91  header.id = crm_class_nodeid;
92  header.size = sizeof(cs_ipc_header_response_t);
93 
94  iov.iov_base = &header;
95  iov.iov_len = header.size;
96 
97  retry:
98  errno = 0;
99  rc = coroipcc_msg_send_reply_receive(ais_ipc_handle, &iov, 1, &answer, sizeof(answer));
100  if (rc == CS_OK) {
101  CRM_CHECK(answer.header.size == sizeof(struct crm_ais_nodeid_resp_s),
102  crm_err("Odd message: id=%d, size=%d, error=%d",
103  answer.header.id, answer.header.size, answer.header.error));
104  CRM_CHECK(answer.header.id == crm_class_nodeid,
105  crm_err("Bad response id: %d", answer.header.id));
106  }
107 
108  if ((rc == CS_ERR_TRY_AGAIN || rc == CS_ERR_QUEUE_FULL) && retries < 20) {
109  retries++;
110  crm_info("Peer overloaded: Re-sending message (Attempt %d of 20)", retries);
111  sleep(retries); /* Proportional back off */
112  goto retry;
113  }
114 
115  if (rc != CS_OK) {
116  crm_err("Sending nodeid request: FAILED (rc=%d): %s", rc, ais_error2text(rc));
117  return FALSE;
118 
119  } else if (answer.header.error != CS_OK) {
120  crm_err("Bad response from peer: (rc=%d): %s", rc, ais_error2text(rc));
121  return FALSE;
122  }
123 
124  crm_info("Server details: id=%u uname=%s cname=%s", answer.id, answer.uname, answer.cname);
125 
126  local_id = answer.id;
127  local_uname = strdup(answer.uname);
128 
129  if(id) *id = local_id;
130  if(uname) *uname = strdup(local_uname);
131  return TRUE;
132 }
133 
134 bool
135 send_plugin_text(int class, struct iovec *iov)
136 {
137  int rc = CS_OK;
138  int retries = 0;
139  int buf_len = sizeof(cs_ipc_header_response_t);
140  char *buf = malloc(buf_len);
141  AIS_Message *ais_msg = (AIS_Message*)iov[0].iov_base;
142  cs_ipc_header_response_t *header = (cs_ipc_header_response_t *)(void*)buf;
143 
144  CRM_ASSERT(buf != NULL);
145  /* There are only 6 handlers registered to crm_lib_service in plugin.c */
146  CRM_CHECK(class < 6, crm_err("Invalid message class: %d", class);
147  return FALSE);
148 
149  do {
150  if (rc == CS_ERR_TRY_AGAIN || rc == CS_ERR_QUEUE_FULL) {
151  retries++;
152  crm_info("Peer overloaded or membership in flux:"
153  " Re-sending message (Attempt %d of 20)", retries);
154  sleep(retries); /* Proportional back off */
155  }
156 
157  errno = 0;
158  rc = coroipcc_msg_send_reply_receive(ais_ipc_handle, iov, 1, buf, buf_len);
159 
160  } while ((rc == CS_ERR_TRY_AGAIN || rc == CS_ERR_QUEUE_FULL) && retries < 20);
161 
162  if (rc == CS_OK) {
163  CRM_CHECK(header->size == sizeof(cs_ipc_header_response_t),
164  crm_err("Odd message: id=%d, size=%d, class=%d, error=%d",
165  header->id, header->size, class, header->error));
166 
167  CRM_ASSERT(buf_len >= header->size);
168  CRM_CHECK(header->id == CRM_MESSAGE_IPC_ACK,
169  crm_err("Bad response id (%d) for request (%d)", header->id,
170  ais_msg->header.id));
171  CRM_CHECK(header->error == CS_OK, rc = header->error);
172 
173  } else {
174  crm_perror(LOG_ERR, "Sending plugin message %d FAILED: %s (%d)",
175  ais_msg->id, ais_error2text(rc), rc);
176  }
177 
178  free(iov[0].iov_base);
179  free(iov);
180  free(buf);
181 
182  return (rc == CS_OK);
183 }
184 
185 void
187 {
188  crm_info("Disconnecting from Corosync");
189 
190  if (is_classic_ais_cluster()) {
191  if (ais_ipc_handle) {
192  crm_trace("Disconnecting plugin");
193  coroipcc_service_disconnect(ais_ipc_handle);
194  ais_ipc_handle = 0;
195  } else {
196  crm_info("No plugin connection");
197  }
198  }
199  cluster_disconnect_cpg(cluster);
200 
201 # if SUPPORT_CMAN
202  if (is_cman_cluster()) {
203  if (pcmk_cman_handle) {
204  crm_info("Disconnecting cman");
205  if (cman_stop_notification(pcmk_cman_handle) >= 0) {
206  crm_info("Destroying cman");
207  cman_finish(pcmk_cman_handle);
208  }
209 
210  } else {
211  crm_info("No cman connection");
212  }
213  }
214 # endif
215  ais_fd_async = -1;
216  ais_fd_sync = -1;
217 
218  crm_notice("Disconnected from Corosync");
219 }
220 
221 void
223 {
224  if (msg->header.id == crm_class_members || msg->header.id == crm_class_quorum) {
225  xmlNode *member = NULL;
226  const char *value = NULL;
227  gboolean quorate = FALSE;
228  xmlNode *xml = string2xml(msg->data);
229 
230  if (xml == NULL) {
231  crm_err("Invalid membership update: %s", msg->data);
232  return;
233  }
234 
235  value = crm_element_value(xml, "quorate");
236  CRM_CHECK(value != NULL, crm_log_xml_err(xml, "No quorum value:"); return);
237  if (crm_is_true(value)) {
238  quorate = TRUE;
239  }
240 
241  value = crm_element_value(xml, "id");
242  CRM_CHECK(value != NULL, crm_log_xml_err(xml, "No membership id"); return);
243  crm_peer_seq = crm_int_helper(value, NULL);
244 
245  if (quorate != crm_have_quorum) {
246  crm_notice("Membership %s: quorum %s", value, quorate ? "acquired" : "lost");
248 
249  } else {
250  crm_info("Membership %s: quorum %s", value, quorate ? "retained" : "still lost");
251  }
252 
253  for (member = __xml_first_child(xml); member != NULL; member = __xml_next(member)) {
254  const char *id_s = crm_element_value(member, "id");
255  const char *addr = crm_element_value(member, "addr");
256  const char *uname = crm_element_value(member, "uname");
257  const char *state = crm_element_value(member, "state");
258  const char *born_s = crm_element_value(member, "born");
259  const char *seen_s = crm_element_value(member, "seen");
260  const char *votes_s = crm_element_value(member, "votes");
261  const char *procs_s = crm_element_value(member, "processes");
262 
263  int votes = crm_int_helper(votes_s, NULL);
264  unsigned int id = crm_int_helper(id_s, NULL);
265  unsigned int procs = crm_int_helper(procs_s, NULL);
266 
267  /* TODO: These values will contain garbage if version < 0.7.1 */
268  uint64_t born = crm_int_helper(born_s, NULL);
269  uint64_t seen = crm_int_helper(seen_s, NULL);
270 
271  crm_update_peer(__FUNCTION__, id, born, seen, votes, procs, uname, uname, addr, state);
272  }
273  free_xml(xml);
274  }
275 }
276 
277 static void
278 plugin_default_deliver_message(cpg_handle_t handle,
279  const struct cpg_name *groupName,
280  uint32_t nodeid, uint32_t pid, void *msg, size_t msg_len)
281 {
282  uint32_t kind = 0;
283  const char *from = NULL;
284  char *data = pcmk_message_common_cs(handle, nodeid, pid, msg, &kind, &from);
285 
286  free(data);
287 }
288 
289 int
290 plugin_dispatch(gpointer user_data)
291 {
292  int rc = CS_OK;
293  crm_cluster_t *cluster = (crm_cluster_t *) user_data;
294 
295  do {
296  char *buffer = NULL;
297 
298  rc = coroipcc_dispatch_get(ais_ipc_handle, (void **)&buffer, 0);
299  if (rc == CS_ERR_TRY_AGAIN || rc == CS_ERR_QUEUE_FULL) {
300  return 0;
301  }
302  if (rc != CS_OK) {
303  crm_perror(LOG_ERR, "Receiving message body failed: (%d) %s", rc, ais_error2text(rc));
304  return -1;
305  }
306  if (buffer == NULL) {
307  /* NULL is a legal "no message afterall" value */
308  return 0;
309  }
310  /*
311  cpg_deliver_fn_t(cpg_handle_t handle, const struct cpg_name *group_name,
312  uint32_t nodeid, uint32_t pid, void *msg, size_t msg_len);
313  */
314  if (cluster && cluster->cpg.cpg_deliver_fn) {
315  cluster->cpg.cpg_deliver_fn(0, NULL, 0, 0, buffer, 0);
316 
317  } else {
318  plugin_default_deliver_message(0, NULL, 0, 0, buffer, 0);
319  }
320 
321  coroipcc_dispatch_put(ais_ipc_handle);
322 
323  } while (ais_ipc_handle);
324 
325  return 0;
326 }
327 
328 static void
329 plugin_destroy(gpointer user_data)
330 {
331  crm_err("AIS connection terminated");
332  ais_fd_sync = -1;
333  crm_exit(ENOTCONN);
334 }
335 
336 # if SUPPORT_CMAN
337 
338 static int
339 pcmk_cman_dispatch(gpointer user_data)
340 {
341  int rc = cman_dispatch(pcmk_cman_handle, CMAN_DISPATCH_ALL);
342 
343  if (rc < 0) {
344  crm_err("Connection to cman failed: %d", rc);
345  pcmk_cman_handle = 0;
346  return FALSE;
347  }
348  return TRUE;
349 }
350 
351 # define MAX_NODES 256
352 
353 static void
354 cman_event_callback(cman_handle_t handle, void *privdata, int reason, int arg)
355 {
356  int rc = 0, lpc = 0, node_count = 0;
357 
358  cman_cluster_t cluster;
359  static cman_node_t cman_nodes[MAX_NODES];
360 
361  gboolean(*dispatch) (unsigned long long, gboolean) = privdata;
362 
363  switch (reason) {
364  case CMAN_REASON_STATECHANGE:
365 
366  memset(&cluster, 0, sizeof(cluster));
367  rc = cman_get_cluster(pcmk_cman_handle, &cluster);
368  if (rc < 0) {
369  crm_err("Couldn't query cman cluster details: %d %d", rc, errno);
370  return;
371  }
372 
373  crm_peer_seq = cluster.ci_generation;
374  if (arg != crm_have_quorum) {
375  crm_notice("Membership %llu: quorum %s", crm_peer_seq, arg ? "acquired" : "lost");
376  crm_have_quorum = arg;
377 
378  } else {
379  crm_info("Membership %llu: quorum %s", crm_peer_seq,
380  arg ? "retained" : "still lost");
381  }
382 
383  memset(cman_nodes, 0, MAX_NODES * sizeof(cman_node_t));
384  rc = cman_get_nodes(pcmk_cman_handle, MAX_NODES, &node_count, cman_nodes);
385  if (rc < 0) {
386  crm_err("Couldn't query cman node list: %d %d", rc, errno);
387  return;
388  }
389 
390  for (lpc = 0; lpc < node_count; lpc++) {
391  crm_node_t *peer = NULL;
392  const char *name = NULL;
393 
394  if (cman_nodes[lpc].cn_nodeid == 0) {
395  /* Never allow node ID 0 to be considered a member #315711 */
396  /* Skip entirely, it's a qdisk */
397  continue;
398  }
399 
400  if(valid_cman_name(cman_nodes[lpc].cn_name, cman_nodes[lpc].cn_nodeid)) {
401  name = cman_nodes[lpc].cn_name;
402  }
403 
404  peer = crm_get_peer(cman_nodes[lpc].cn_nodeid, name);
405  if(cman_nodes[lpc].cn_member) {
406  crm_update_peer_state(__FUNCTION__, peer, CRM_NODE_MEMBER, crm_peer_seq);
407 
408  } else if(peer->state) {
409  crm_update_peer_state(__FUNCTION__, peer, CRM_NODE_LOST, 0);
410 
411  } else {
412  crm_info("State of node %s[%u] is still unknown", peer->uname, peer->id);
413  }
414  }
415 
416  if (dispatch) {
417  dispatch(crm_peer_seq, crm_have_quorum);
418  }
419  break;
420 
421  case CMAN_REASON_TRY_SHUTDOWN:
422  /* Always reply with a negative - pacemaker needs to be stopped first */
423  crm_notice("CMAN wants to shut down: %s", arg ? "forced" : "optional");
424  cman_replyto_shutdown(pcmk_cman_handle, 0);
425  break;
426 
427  case CMAN_REASON_CONFIG_UPDATE:
428  /* Ignore */
429  break;
430  }
431 }
432 # endif
433 
434 gboolean
435 init_cman_connection(gboolean(*dispatch) (unsigned long long, gboolean), void (*destroy) (gpointer))
436 {
437 # if SUPPORT_CMAN
438  int rc = -1, fd = -1;
439  cman_cluster_t cluster;
440 
441  struct mainloop_fd_callbacks cman_fd_callbacks = {
442  .dispatch = pcmk_cman_dispatch,
443  .destroy = destroy,
444  };
445 
446  crm_info("Configuring Pacemaker to obtain quorum from cman");
447 
448  memset(&cluster, 0, sizeof(cluster));
449 
450  pcmk_cman_handle = cman_init(dispatch);
451  if (pcmk_cman_handle == NULL || cman_is_active(pcmk_cman_handle) == FALSE) {
452  crm_err("Couldn't connect to cman");
453  goto cman_bail;
454  }
455 
456  rc = cman_start_notification(pcmk_cman_handle, cman_event_callback);
457  if (rc < 0) {
458  crm_err("Couldn't register for cman notifications: %d %d", rc, errno);
459  goto cman_bail;
460  }
461 
462  /* Get the current membership state */
463  cman_event_callback(pcmk_cman_handle, dispatch, CMAN_REASON_STATECHANGE,
464  cman_is_quorate(pcmk_cman_handle));
465 
466  fd = cman_get_fd(pcmk_cman_handle);
467 
468  mainloop_add_fd("cman", G_PRIORITY_MEDIUM, fd, dispatch, &cman_fd_callbacks);
469 
470  cman_bail:
471  if (rc < 0) {
472  cman_finish(pcmk_cman_handle);
473  return FALSE;
474  }
475 # else
476  crm_err("cman qorum is not supported in this build");
478 # endif
479  return TRUE;
480 }
481 
482 # ifdef SUPPORT_COROSYNC
483 
484 gboolean
485 cluster_connect_quorum(gboolean(*dispatch) (unsigned long long, gboolean),
486  void (*destroy) (gpointer))
487 {
488  crm_err("The Corosync quorum API is not supported in this build");
490  return TRUE;
491 }
492 
493 static gboolean
494 init_cs_connection_classic(crm_cluster_t * cluster)
495 {
496  int rc;
497  int pid = 0;
498  char *pid_s = NULL;
499  const char *name = NULL;
500  crm_node_t *peer = NULL;
501  enum crm_proc_flag proc = 0;
502 
503  struct mainloop_fd_callbacks ais_fd_callbacks = {
505  .destroy = cluster->destroy,
506  };
507 
508  crm_info("Creating connection to our Corosync plugin");
509  rc = coroipcc_service_connect(COROSYNC_SOCKET_NAME, PCMK_SERVICE_ID,
511  &ais_ipc_handle);
512  if (ais_ipc_handle) {
513  coroipcc_fd_get(ais_ipc_handle, &ais_fd_async);
514  } else {
515  crm_info("Connection to our Corosync plugin (%d) failed: %s (%d)",
516  PCMK_SERVICE_ID, strerror(errno), errno);
517  return FALSE;
518  }
519  if (ais_fd_async <= 0 && rc == CS_OK) {
520  crm_err("No context created, but connection reported 'ok'");
521  rc = CS_ERR_LIBRARY;
522  }
523  if (rc != CS_OK) {
524  crm_info("Connection to our Corosync plugin (%d) failed: %s (%d)", PCMK_SERVICE_ID,
525  ais_error2text(rc), rc);
526  }
527 
528  if (rc != CS_OK) {
529  return FALSE;
530  }
531 
532  if (ais_fd_callbacks.destroy == NULL) {
533  ais_fd_callbacks.destroy = plugin_destroy;
534  }
535 
536  mainloop_add_fd("corosync-plugin", G_PRIORITY_MEDIUM, ais_fd_async, cluster, &ais_fd_callbacks);
537  crm_info("AIS connection established");
538 
539  pid = getpid();
540  pid_s = crm_itoa(pid);
541  send_cluster_text(crm_class_cluster, pid_s, TRUE, NULL, crm_msg_ais);
542  free(pid_s);
543 
544  cluster->nodeid = get_local_nodeid(0);
545 
546  name = get_local_node_name();
547  plugin_get_details(NULL, &(cluster->uname));
548  if (safe_str_neq(name, cluster->uname)) {
549  crm_crit("Node name mismatch! Corosync supplied %s but our lookup returned %s",
550  cluster->uname, name);
551  crm_notice
552  ("Node name mismatches usually occur when assigned automatically by DHCP servers");
554  }
555 
556  proc = text2proc(crm_system_name);
557  peer = crm_get_peer(cluster->nodeid, cluster->uname);
558  crm_update_peer_proc(__FUNCTION__, peer, proc|crm_proc_plugin, ONLINESTATUS);
559 
560  return TRUE;
561 }
562 
563 static int
564 pcmk_mcp_dispatch(const char *buffer, ssize_t length, gpointer userdata)
565 {
566  xmlNode *msg = string2xml(buffer);
567 
568  if (msg && is_classic_ais_cluster()) {
569  xmlNode *node = NULL;
570 
571  for (node = __xml_first_child(msg); node != NULL; node = __xml_next(node)) {
572  int id = 0;
573  int children = 0;
574  const char *uname = crm_element_value(node, "uname");
575 
576  crm_element_value_int(node, "id", &id);
577  crm_element_value_int(node, "processes", &children);
578  if (id == 0) {
579  crm_log_xml_err(msg, "Bad Update");
580  } else {
581  crm_node_t *peer = crm_get_peer(id, uname);
582 
583  crm_update_peer_proc(__FUNCTION__, peer, children, NULL);
584  }
585  }
586  }
587 
588  free_xml(msg);
589  return 0;
590 }
591 
592 static void
593 pcmk_mcp_destroy(gpointer user_data)
594 {
595  void (*callback) (gpointer data) = user_data;
596 
597  if (callback) {
598  callback(NULL);
599  }
600 }
601 
602 gboolean
604 {
605  int retries = 0;
606 
607  static struct ipc_client_callbacks mcp_callbacks = {
608  .dispatch = pcmk_mcp_dispatch,
609  .destroy = pcmk_mcp_destroy
610  };
611 
612  while (retries < 5) {
613  int rc = init_cs_connection_once(cluster);
614 
615  retries++;
616  switch (rc) {
617  case CS_OK:
618  if (getenv("HA_mcp") && get_cluster_type() != pcmk_cluster_cman) {
619  xmlNode *poke = create_xml_node(NULL, "poke");
620  mainloop_io_t *ipc =
622  cluster->destroy, &mcp_callbacks);
623 
624  crm_ipc_send(mainloop_get_ipc_client(ipc), poke, 0, 0, NULL);
625  free_xml(poke);
626  }
627  return TRUE;
628  break;
629  case CS_ERR_TRY_AGAIN:
630  case CS_ERR_QUEUE_FULL:
631  sleep(retries);
632  break;
633  default:
634  return FALSE;
635  }
636  }
637 
638  crm_err("Retry count exceeded: %d", retries);
639  return FALSE;
640 }
641 
642 char *
643 classic_node_name(uint32_t nodeid)
644 {
645  return NULL; /* Always use the uname() default for localhost. No way to look up peers */
646 }
647 
648 char *
649 cman_node_name(uint32_t nodeid)
650 {
651  char *name = NULL;
652 
653 # if SUPPORT_CMAN
654  cman_node_t us;
655  cman_handle_t cman;
656 
657  cman = cman_init(NULL);
658  if (cman != NULL && cman_is_active(cman)) {
659 
660  memset(&us, 0, sizeof(cman_node_t));
661  cman_get_node(cman, nodeid, &us);
662  if(valid_cman_name(us.cn_name, nodeid)) {
663  name = strdup(us.cn_name);
664  crm_info("Using CMAN node name %s for %u", name, nodeid);
665  }
666  }
667 
668  cman_finish(cman);
669 # endif
670  if (name == NULL) {
671  crm_debug("Unable to get node name for nodeid %u", nodeid);
672  }
673  return name;
674 }
675 
676 extern int set_cluster_type(enum cluster_type_e type);
677 
678 gboolean
680 {
681  crm_node_t *peer = NULL;
682  enum cluster_type_e stack = get_cluster_type();
683 
684  crm_peer_init();
685 
686  /* Here we just initialize comms */
687  switch (stack) {
689  if (init_cs_connection_classic(cluster) == FALSE) {
690  return FALSE;
691  }
692  break;
693  case pcmk_cluster_cman:
694  if (cluster_connect_cpg(cluster) == FALSE) {
695  return FALSE;
696  }
697  break;
699  crm_info("Could not find an active corosync based cluster");
700  return FALSE;
701  break;
702  default:
703  crm_err("Invalid cluster type: %s (%d)", name_for_cluster_type(stack), stack);
704  return FALSE;
705  break;
706  }
707 
708  crm_info("Connection to '%s': established", name_for_cluster_type(stack));
709 
710  cluster->nodeid = get_local_nodeid(0);
711  if(cluster->nodeid == 0) {
712  crm_err("Could not establish local nodeid");
713  return FALSE;
714  }
715 
716  cluster->uname = get_node_name(0);
717  if(cluster->uname == NULL) {
718  crm_err("Could not establish local node name");
719  return FALSE;
720  }
721 
722  /* Ensure the local node always exists */
723  peer = crm_get_peer(cluster->nodeid, cluster->uname);
724  cluster->uuid = get_corosync_uuid(peer);
725 
726  return TRUE;
727 }
728 
729 gboolean
730 check_message_sanity(const AIS_Message * msg, const char *data)
731 {
732  gboolean sane = TRUE;
733  int dest = msg->host.type;
734  int tmp_size = msg->header.size - sizeof(AIS_Message);
735 
736  if (sane && msg->header.size == 0) {
737  crm_warn("Message with no size");
738  sane = FALSE;
739  }
740 
741  if (sane && msg->header.error != CS_OK) {
742  crm_warn("Message header contains an error: %d", msg->header.error);
743  sane = FALSE;
744  }
745 
746  if (sane && ais_data_len(msg) != tmp_size) {
747  crm_warn("Message payload size is incorrect: expected %d, got %d", ais_data_len(msg),
748  tmp_size);
749  sane = TRUE;
750  }
751 
752  if (sane && ais_data_len(msg) == 0) {
753  crm_warn("Message with no payload");
754  sane = FALSE;
755  }
756 
757  if (sane && data && msg->is_compressed == FALSE) {
758  int str_size = strlen(data) + 1;
759 
760  if (ais_data_len(msg) != str_size) {
761  int lpc = 0;
762 
763  crm_warn("Message payload is corrupted: expected %d bytes, got %d",
764  ais_data_len(msg), str_size);
765  sane = FALSE;
766  for (lpc = (str_size - 10); lpc < msg->size; lpc++) {
767  if (lpc < 0) {
768  lpc = 0;
769  }
770  crm_debug("bad_data[%d]: %d / '%c'", lpc, data[lpc], data[lpc]);
771  }
772  }
773  }
774 
775  if (sane == FALSE) {
776  crm_err("Invalid message %d: (dest=%s:%s, from=%s:%s.%d, compressed=%d, size=%d, total=%d)",
777  msg->id, ais_dest(&(msg->host)), msg_type2text(dest),
778  ais_dest(&(msg->sender)), msg_type2text(msg->sender.type),
779  msg->sender.pid, msg->is_compressed, ais_data_len(msg), msg->header.size);
780 
781  } else {
782  crm_trace
783  ("Verified message %d: (dest=%s:%s, from=%s:%s.%d, compressed=%d, size=%d, total=%d)",
784  msg->id, ais_dest(&(msg->host)), msg_type2text(dest), ais_dest(&(msg->sender)),
785  msg_type2text(msg->sender.type), msg->sender.pid, msg->is_compressed,
786  ais_data_len(msg), msg->header.size);
787  }
788 
789  return sane;
790 }
791 #endif
792 
793 static int
794 get_config_opt(confdb_handle_t config,
795  hdb_handle_t object_handle, const char *key, char **value, const char *fallback)
796 {
797  size_t len = 0;
798  char *env_key = NULL;
799  const char *env_value = NULL;
800  char buffer[256];
801 
802  if (*value) {
803  free(*value);
804  *value = NULL;
805  }
806 
807  if (object_handle > 0) {
808  if (CS_OK == confdb_key_get(config, object_handle, key, strlen(key), &buffer, &len)) {
809  *value = strdup(buffer);
810  }
811  }
812 
813  if (*value) {
814  crm_info("Found '%s' for option: %s", *value, key);
815  return 0;
816  }
817 
818  env_key = crm_concat("HA", key, '_');
819  env_value = getenv(env_key);
820  free(env_key);
821 
822  if (*value) {
823  crm_info("Found '%s' in ENV for option: %s", *value, key);
824  *value = strdup(env_value);
825  return 0;
826  }
827 
828  if (fallback) {
829  crm_info("Defaulting to '%s' for option: %s", fallback, key);
830  *value = strdup(fallback);
831 
832  } else {
833  crm_info("No default for option: %s", key);
834  }
835 
836  return -1;
837 }
838 
839 static confdb_handle_t
840 config_find_init(confdb_handle_t config)
841 {
842  cs_error_t rc = CS_OK;
843  confdb_handle_t local_handle = OBJECT_PARENT_HANDLE;
844 
845  rc = confdb_object_find_start(config, local_handle);
846  if (rc == CS_OK) {
847  return local_handle;
848  } else {
849  crm_err("Couldn't create search context: %d", rc);
850  }
851  return 0;
852 }
853 
854 static hdb_handle_t
855 config_find_next(confdb_handle_t config, const char *name, confdb_handle_t top_handle)
856 {
857  cs_error_t rc = CS_OK;
858  hdb_handle_t local_handle = 0;
859 
860  if (top_handle == 0) {
861  crm_err("Couldn't search for %s: no valid context", name);
862  return 0;
863  }
864 
865  crm_trace("Searching for %s in " HDB_X_FORMAT, name, top_handle);
866  rc = confdb_object_find(config, top_handle, name, strlen(name), &local_handle);
867  if (rc != CS_OK) {
868  crm_info("No additional configuration supplied for: %s", name);
869  local_handle = 0;
870  } else {
871  crm_info("Processing additional %s options...", name);
872  }
873  return local_handle;
874 }
875 
876 enum cluster_type_e
878 {
879  confdb_handle_t config;
881 
882  int rc;
883  char *value = NULL;
884  confdb_handle_t top_handle = 0;
885  hdb_handle_t local_handle = 0;
886  static confdb_callbacks_t callbacks = { };
887 
888  rc = confdb_initialize(&config, &callbacks);
889  if (rc != CS_OK) {
890  crm_debug("Could not initialize Cluster Configuration Database API instance error %d", rc);
891  return found;
892  }
893 
894  top_handle = config_find_init(config);
895  local_handle = config_find_next(config, "service", top_handle);
896  while (local_handle) {
897  get_config_opt(config, local_handle, "name", &value, NULL);
898  if (safe_str_eq("pacemaker", value)) {
899  found = pcmk_cluster_classic_ais;
900 
901  get_config_opt(config, local_handle, "ver", &value, "0");
902  crm_trace("Found Pacemaker plugin version: %s", value);
903  break;
904  }
905 
906  local_handle = config_find_next(config, "service", top_handle);
907  }
908 
909  if (found == pcmk_cluster_unknown) {
910  top_handle = config_find_init(config);
911  local_handle = config_find_next(config, "quorum", top_handle);
912  get_config_opt(config, local_handle, "provider", &value, NULL);
913 
914  if (safe_str_eq("quorum_cman", value)) {
915  crm_trace("Found CMAN quorum provider");
916  found = pcmk_cluster_cman;
917  }
918  }
919  free(value);
920 
921  confdb_finalize(config);
922  if (found == pcmk_cluster_unknown) {
923  crm_err
924  ("Corosync is running, but Pacemaker could not find the CMAN or Pacemaker plugin loaded");
925  found = pcmk_cluster_invalid;
926  }
927  return found;
928 }
929 
930 gboolean
932 {
933  enum crm_proc_flag proc = crm_proc_none;
934 
935  if (node == NULL) {
936  crm_trace("NULL");
937  return FALSE;
938 
939  } else if (safe_str_neq(node->state, CRM_NODE_MEMBER)) {
940  crm_trace("%s: state=%s", node->uname, node->state);
941  return FALSE;
942 
943  } else if (is_cman_cluster() && (node->processes & crm_proc_cpg)) {
944  /* If we can still talk to our peer process on that node,
945  * then it's also part of the corosync membership
946  */
947  crm_trace("%s: processes=%.8x", node->uname, node->processes);
948  return TRUE;
949 
950  } else if (is_classic_ais_cluster()) {
951  if (node->processes < crm_proc_none) {
952  crm_debug("%s: unknown process list, assuming active for now", node->uname);
953  return TRUE;
954 
955  } else if (is_set(node->processes, crm_proc_none)) {
956  crm_debug("%s: all processes are inactive", node->uname);
957  return FALSE;
958 
959  } else if (is_not_set(node->processes, crm_proc_plugin)) {
960  crm_trace("%s: processes=%.8x", node->uname, node->processes);
961  return FALSE;
962  }
963  }
964 
965  proc = text2proc(crm_system_name);
966  if (proc > crm_proc_none && (node->processes & proc) == 0) {
967  crm_trace("%s: proc %.8x not in %.8x", node->uname, proc, node->processes);
968  return FALSE;
969  }
970 
971  return TRUE;
972 }
bool send_plugin_text(int class, struct iovec *iov)
Definition: legacy.c:135
uint32_t votes
Definition: internal.h:50
enum crm_ais_msg_types type
Definition: internal.h:38
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:164
char data[0]
Definition: internal.h:55
#define crm_notice(fmt, args...)
Definition: logging.h:250
#define CRM_NODE_LOST
Definition: cluster.h:43
gboolean is_compressed
Definition: internal.h:47
uint32_t size
Definition: internal.h:52
#define crm_crit(fmt, args...)
Definition: logging.h:247
gboolean safe_str_neq(const char *a, const char *b)
Definition: strings.c:150
mainloop_io_t * mainloop_add_fd(const char *name, int priority, int fd, void *userdata, struct mainloop_fd_callbacks *callbacks)
Definition: mainloop.c:810
hdb_handle_t config_find_init(struct corosync_api_v1 *config, char *name)
Definition: utils.c:620
uint32_t nodeid
Definition: cluster.h:97
uint32_t quorate
Definition: internal.h:52
uint32_t id
Definition: cluster.h:73
gboolean crm_have_quorum
Definition: membership.c:65
char * get_corosync_uuid(crm_node_t *peer)
Definition: cluster.c:106
void terminate_cs_connection(crm_cluster_t *cluster)
Definition: corosync.c:140
const char * get_local_node_name(void)
Definition: cluster.c:289
void crm_peer_init(void)
Definition: membership.c:419
void(* destroy)(gpointer)
Definition: cluster.h:99
long long crm_int_helper(const char *text, char **end_text)
Definition: strings.c:80
struct mainloop_io_s mainloop_io_t
Definition: mainloop.h:35
crm_node_t * crm_get_peer(unsigned int id, const char *uname)
Definition: membership.c:676
int(* dispatch)(gpointer userdata)
Definition: mainloop.h:90
char * crm_system_name
Definition: utils.c:70
char * uuid
Definition: cluster.h:95
uint32_t pid
Definition: internal.h:49
char * get_node_name(uint32_t nodeid)
Definition: cluster.c:301
char * strerror(int errnum)
char * pcmk_message_common_cs(cpg_handle_t handle, uint32_t nodeid, uint32_t pid, void *content, uint32_t *kind, const char **from)
Definition: cpg.c:233
#define AIS_IPC_MESSAGE_SIZE
Definition: internal.h:24
gboolean cluster_connect_quorum(gboolean(*dispatch)(unsigned long long, gboolean), void(*destroy)(gpointer))
Definition: corosync.c:249
Wrappers for and extensions to glib mainloop.
xmlNode * string2xml(const char *input)
Definition: xml.c:2750
crm_node_t * crm_update_peer(const char *source, unsigned int id, uint64_t born, uint64_t seen, int32_t votes, uint32_t children, const char *uuid, const char *uname, const char *addr, const char *state)
Definition: membership.c:755
gboolean init_cs_connection(crm_cluster_t *cluster)
Definition: corosync.c:312
#define CRM_SYSTEM_MCP
Definition: crm.h:95
hdb_handle_t ais_ipc_handle
Definition: legacy.c:53
gboolean crm_is_corosync_peer_active(const crm_node_t *node)
Definition: corosync.c:468
#define PCMK_SERVICE_ID
Definition: config.h:670
int plugin_dispatch(gpointer user_data)
Definition: legacy.c:290
void plugin_handle_membership(AIS_Message *msg)
Definition: legacy.c:222
void cluster_disconnect_cpg(crm_cluster_t *cluster)
Definition: cpg.c:58
char uname[MAX_NAME]
Definition: internal.h:53
#define crm_warn(fmt, args...)
Definition: logging.h:249
uint32_t processes
Definition: cluster.h:79
int ais_fd_sync
Definition: legacy.c:49
#define crm_debug(fmt, args...)
Definition: logging.h:253
void(* destroy)(gpointer userdata)
Definition: mainloop.h:91
int get_config_opt(struct corosync_api_v1 *config, hdb_handle_t object_service_handle, char *key, char **value, const char *fallback)
Definition: utils.c:660
cluster_type_e
Definition: cluster.h:210
#define crm_trace(fmt, args...)
Definition: logging.h:254
crm_node_t * crm_update_peer_proc(const char *source, crm_node_t *peer, uint32_t flag, const char *status)
Definition: membership.c:891
#define CRM_MESSAGE_IPC_ACK
Definition: internal.h:25
AIS_Host sender
Definition: internal.h:50
uint32_t id
Definition: internal.h:46
gboolean send_cluster_text(int class, const char *data, gboolean local, crm_node_t *node, enum crm_ais_msg_types dest)
Definition: cpg.c:521
gboolean check_message_sanity(const AIS_Message *msg, const char *data)
Definition: plugin.c:1356
xmlNode * create_xml_node(xmlNode *parent, const char *name)
Definition: xml.c:2588
struct crm_ais_msg_s AIS_Message
Definition: internal.h:32
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
#define ais_data_len(msg)
Definition: internal.h:208
struct qb_ipc_response_header cs_ipc_header_response_t
Definition: crm_internal.h:300
#define CRM_NODE_MEMBER
Definition: cluster.h:44
enum cluster_type_e find_corosync_variant(void)
Definition: corosync.c:440
unsigned long long crm_peer_seq
Definition: membership.c:64
gboolean ais_membership_force
Definition: corosync.c:159
gboolean is_cman_cluster(void)
Definition: cluster.c:612
int ais_membership_timer
Definition: corosync.c:158
void free_xml(xmlNode *child)
Definition: xml.c:2706
gboolean crm_str_eq(const char *a, const char *b, gboolean use_case)
Definition: strings.c:213
const char * name_for_cluster_type(enum cluster_type_e type)
Definition: cluster.c:468
int set_cluster_type(enum cluster_type_e type)
Definition: cluster.c:493
#define DAEMON_RESPAWN_STOP
Definition: crm.h:65
gboolean init_cs_connection_once(crm_cluster_t *cluster)
Definition: corosync.c:339
hdb_handle_t config_find_next(struct corosync_api_v1 *config, char *name, hdb_handle_t top_handle)
Definition: utils.c:633
crm_node_t * crm_update_peer_state(const char *source, crm_node_t *node, const char *state, int membership)
Update a node&#39;s state and membership information.
Definition: membership.c:1077
char * local_uname
Definition: plugin.c:61
char * uname
Definition: cluster.h:96
#define crm_log_xml_err(xml, text)
Definition: logging.h:257
#define crm_perror(level, fmt, args...)
Log a system error message.
Definition: logging.h:226
uint32_t get_local_nodeid(cpg_handle_t handle)
Definition: cpg.c:72
crm_ipc_t * mainloop_get_ipc_client(mainloop_io_t *client)
Definition: mainloop.c:801
#define crm_err(fmt, args...)
Definition: logging.h:248
#define G_PRIORITY_MEDIUM
Definition: mainloop.h:124
#define ENOTUNIQ
Definition: portability.h:229
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
void * ais_ipc_ctx
Definition: legacy.c:51
#define uint32_t
Definition: stdint.in.h:158
#define CRM_ASSERT(expr)
Definition: error.h:35
char data[0]
Definition: internal.h:58
int crm_exit(int rc)
Definition: utils.c:83
char * state
Definition: cluster.h:84
int ais_fd_async
Definition: legacy.c:50
Wrappers for and extensions to libqb IPC.
uint32_t pid
Definition: internal.h:36
char * uname
Definition: cluster.h:82
gboolean crm_is_true(const char *s)
Definition: strings.c:165
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
AIS_Host host
Definition: internal.h:49
char * crm_concat(const char *prefix, const char *suffix, char join)
Definition: strings.c:32
gboolean init_cman_connection(gboolean(*dispatch)(unsigned long long, gboolean), void(*destroy)(gpointer))
Definition: legacy.c:435
char * crm_itoa(int an_int)
Definition: strings.c:60
#define safe_str_eq(a, b)
Definition: util.h:72
#define ONLINESTATUS
Definition: util.h:52
char * crm_strdup_printf(char const *format,...) __attribute__((__format__(__printf__
#define crm_info(fmt, args...)
Definition: logging.h:251
crm_proc_flag
Definition: internal.h:76
int(* dispatch)(const char *buffer, ssize_t length, gpointer userdata)
Definition: mainloop.h:73
gboolean cluster_connect_cpg(crm_cluster_t *cluster)
Definition: cpg.c:436
gboolean is_classic_ais_cluster(void)
Definition: cluster.c:624
enum crm_ais_msg_types type
Definition: internal.h:51
enum cluster_type_e get_cluster_type(void)
Definition: cluster.c:513