root/attrd/legacy.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. free_hash_entry
  2. attrd_ipc_dispatch
  3. usage
  4. stop_attrd_timer
  5. log_hash_entry
  6. find_hash_entry
  7. local_clear_failure
  8. remote_clear_callback
  9. remote_clear_failure
  10. process_xml_request
  11. attrd_ha_connection_destroy
  12. attrd_ha_callback
  13. attrd_cs_dispatch
  14. attrd_cs_destroy
  15. attrd_cib_connection_destroy
  16. update_for_hash_entry
  17. local_update_for_hash_entry
  18. do_cib_replaced
  19. cib_connect
  20. main
  21. free_attrd_callback
  22. attrd_cib_callback
  23. attrd_perform_update
  24. expand_attr_value
  25. update_local_attr
  26. remote_attr_callback
  27. update_remote_attr
  28. attrd_client_clear_failure
  29. attrd_local_callback
  30. attrd_timer_callback
  31. attrd_trigger_update

   1 /* 
   2  * Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
   3  * 
   4  * This program is free software; you can redistribute it and/or
   5  * modify it under the terms of the GNU General Public
   6  * License as published by the Free Software Foundation; either
   7  * version 2 of the License, or (at your option) any later version.
   8  * 
   9  * This software 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  * General Public License for more details.
  13  * 
  14  * You should have received a copy of the GNU 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 
  21 #include <sys/param.h>
  22 #include <stdio.h>
  23 #include <sys/types.h>
  24 #include <sys/stat.h>
  25 #include <unistd.h>
  26 
  27 #include <stdlib.h>
  28 #include <errno.h>
  29 #include <fcntl.h>
  30 #include <regex.h>
  31 
  32 #include <crm/crm.h>
  33 #include <crm/cib/internal.h>
  34 #include <crm/msg_xml.h>
  35 #include <crm/pengine/rules.h>
  36 #include <crm/common/ipc.h>
  37 #include <crm/common/ipcs.h>
  38 #include <crm/cluster/internal.h>
  39 #include <crm/common/xml.h>
  40 #include <crm/attrd.h>
  41 
  42 #include <attrd_common.h>
  43 
  44 #define OPTARGS "hV"
  45 #if SUPPORT_HEARTBEAT
  46 ll_cluster_t *attrd_cluster_conn;
  47 #endif
  48 
  49 char *attrd_uname = NULL;
  50 char *attrd_uuid = NULL;
  51 uint32_t attrd_nodeid = 0;
  52 
  53 GHashTable *attr_hash = NULL;
  54 lrmd_t *the_lrmd = NULL;
  55 crm_trigger_t *attrd_config_read = NULL;
  56 
  57 /* Convenience macro for registering a CIB callback.
  58  * Check the_cib != NULL before using.
  59  */
  60 #define register_cib_callback(call_id, data, fn, free_fn) \
  61     the_cib->cmds->register_callback_full(the_cib, call_id, 120, FALSE, \
  62                                            data, #fn, fn, free_fn)
  63 
  64 typedef struct attr_hash_entry_s {
  65     char *uuid;
  66     char *id;
  67     char *set;
  68     char *section;
  69 
  70     char *value;
  71     char *stored_value;
  72 
  73     int timeout;
  74     char *dampen;
  75     guint timer_id;
  76 
  77     char *user;
  78 
  79 } attr_hash_entry_t;
  80 
  81 void attrd_local_callback(xmlNode * msg);
  82 gboolean attrd_timer_callback(void *user_data);
  83 gboolean attrd_trigger_update(attr_hash_entry_t * hash_entry);
  84 void attrd_perform_update(attr_hash_entry_t * hash_entry);
  85 static void update_local_attr(xmlNode *msg, attr_hash_entry_t *hash_entry);
  86 
  87 static void
  88 free_hash_entry(gpointer data)
     /* [previous][next][first][last][top][bottom][index][help] */
  89 {
  90     attr_hash_entry_t *entry = data;
  91 
  92     if (entry == NULL) {
  93         return;
  94     }
  95     free(entry->id);
  96     free(entry->set);
  97     free(entry->dampen);
  98     free(entry->section);
  99     free(entry->uuid);
 100     free(entry->value);
 101     free(entry->stored_value);
 102     free(entry->user);
 103     free(entry);
 104 }
 105 
 106 /* Exit code means? */
 107 static int32_t
 108 attrd_ipc_dispatch(qb_ipcs_connection_t * c, void *data, size_t size)
     /* [previous][next][first][last][top][bottom][index][help] */
 109 {
 110     uint32_t id = 0;
 111     uint32_t flags = 0;
 112     crm_client_t *client = crm_client_get(c);
 113     xmlNode *msg = crm_ipcs_recv(client, data, size, &id, &flags);
 114 
 115     crm_ipcs_send_ack(client, id, flags, "ack", __FUNCTION__, __LINE__);
 116     if (msg == NULL) {
 117         crm_debug("No msg from %d (%p)", crm_ipcs_client_pid(c), c);
 118         return 0;
 119     }
 120 #if ENABLE_ACL
 121     CRM_ASSERT(client->user != NULL);
 122     crm_acl_get_set_user(msg, F_ATTRD_USER, client->user);
 123 #endif
 124 
 125     crm_trace("Processing msg from %d (%p)", crm_ipcs_client_pid(c), c);
 126     crm_log_xml_trace(msg, __FUNCTION__);
 127 
 128     attrd_local_callback(msg);
 129 
 130     free_xml(msg);
 131     return 0;
 132 }
 133 
 134 static void
 135 usage(const char *cmd, int exit_status)
     /* [previous][next][first][last][top][bottom][index][help] */
 136 {
 137     FILE *stream;
 138 
 139     stream = exit_status ? stderr : stdout;
 140 
 141     fprintf(stream, "usage: %s [-srkh] [-c configure file]\n", cmd);
 142 /*      fprintf(stream, "\t-d\tsets debug level\n"); */
 143 /*      fprintf(stream, "\t-s\tgets daemon status\n"); */
 144 /*      fprintf(stream, "\t-r\trestarts daemon\n"); */
 145 /*      fprintf(stream, "\t-k\tstops daemon\n"); */
 146 /*      fprintf(stream, "\t-h\thelp message\n"); */
 147     fflush(stream);
 148 
 149     crm_exit(exit_status);
 150 }
 151 
 152 static void
 153 stop_attrd_timer(attr_hash_entry_t * hash_entry)
     /* [previous][next][first][last][top][bottom][index][help] */
 154 {
 155     if (hash_entry != NULL && hash_entry->timer_id != 0) {
 156         crm_trace("Stopping %s timer", hash_entry->id);
 157         g_source_remove(hash_entry->timer_id);
 158         hash_entry->timer_id = 0;
 159     }
 160 }
 161 
 162 static void
 163 log_hash_entry(int level, attr_hash_entry_t * entry, const char *text)
     /* [previous][next][first][last][top][bottom][index][help] */
 164 {
 165     do_crm_log(level, "%s: Set: %s, Name: %s, Value: %s, Timeout: %s",
 166                text, entry->section, entry->id, entry->value, entry->dampen);
 167 }
 168 
 169 static attr_hash_entry_t *
 170 find_hash_entry(xmlNode * msg)
     /* [previous][next][first][last][top][bottom][index][help] */
 171 {
 172     const char *value = NULL;
 173     const char *attr = crm_element_value(msg, F_ATTRD_ATTRIBUTE);
 174     attr_hash_entry_t *hash_entry = NULL;
 175 
 176     if (attr == NULL) {
 177         crm_info("Ignoring message with no attribute name");
 178         return NULL;
 179     }
 180 
 181     hash_entry = g_hash_table_lookup(attr_hash, attr);
 182 
 183     if (hash_entry == NULL) {
 184         /* create one and add it */
 185         crm_info("Creating hash entry for %s", attr);
 186         hash_entry = calloc(1, sizeof(attr_hash_entry_t));
 187         hash_entry->id = strdup(attr);
 188 
 189         g_hash_table_insert(attr_hash, hash_entry->id, hash_entry);
 190         hash_entry = g_hash_table_lookup(attr_hash, attr);
 191         CRM_CHECK(hash_entry != NULL, return NULL);
 192     }
 193 
 194     value = crm_element_value(msg, F_ATTRD_SET);
 195     if (value != NULL) {
 196         free(hash_entry->set);
 197         hash_entry->set = strdup(value);
 198         crm_debug("\t%s->set: %s", attr, value);
 199     }
 200 
 201     value = crm_element_value(msg, F_ATTRD_SECTION);
 202     if (value == NULL) {
 203         value = XML_CIB_TAG_STATUS;
 204     }
 205     free(hash_entry->section);
 206     hash_entry->section = strdup(value);
 207     crm_trace("\t%s->section: %s", attr, value);
 208 
 209     value = crm_element_value(msg, F_ATTRD_DAMPEN);
 210     if (value != NULL) {
 211         free(hash_entry->dampen);
 212         hash_entry->dampen = strdup(value);
 213 
 214         hash_entry->timeout = crm_get_msec(value);
 215         crm_trace("\t%s->timeout: %s", attr, value);
 216     }
 217 #if ENABLE_ACL
 218     free(hash_entry->user);
 219     hash_entry->user = NULL;
 220 
 221     value = crm_element_value(msg, F_ATTRD_USER);
 222     if (value != NULL) {
 223         hash_entry->user = strdup(value);
 224         crm_trace("\t%s->user: %s", attr, value);
 225     }
 226 #endif
 227 
 228     log_hash_entry(LOG_DEBUG_2, hash_entry, "Found (and updated) entry:");
 229     return hash_entry;
 230 }
 231 
 232 /*!
 233  * \internal
 234  * \brief Clear failure-related attributes for local node
 235  *
 236  * \param[in] xml  XML of ATTRD_OP_CLEAR_FAILURE request
 237  */
 238 static void
 239 local_clear_failure(xmlNode *xml)
     /* [previous][next][first][last][top][bottom][index][help] */
 240 {
 241     const char *rsc = crm_element_value(xml, F_ATTRD_RESOURCE);
 242     const char *what = rsc? rsc : "all resources";
 243     const char *op = crm_element_value(xml, F_ATTRD_OPERATION);
 244     const char *interval_s = crm_element_value(xml, F_ATTRD_INTERVAL);
 245     int interval = crm_get_interval(interval_s);
 246     regex_t regex;
 247     GHashTableIter iter;
 248     attr_hash_entry_t *hash_entry = NULL;
 249 
 250     if (attrd_failure_regex(&regex, rsc, op, interval) != pcmk_ok) {
 251         crm_info("Ignoring invalid request to clear %s",
 252                  (rsc? rsc : "all resources"));
 253         return;
 254     }
 255     crm_debug("Clearing %s locally", what);
 256 
 257     /* Make sure value is not set, so we delete */
 258     if (crm_element_value(xml, F_ATTRD_VALUE)) {
 259         crm_xml_replace(xml, F_ATTRD_VALUE, NULL);
 260     }
 261 
 262     g_hash_table_iter_init(&iter, attr_hash);
 263     while (g_hash_table_iter_next(&iter, NULL, (gpointer *) &hash_entry)) {
 264         if (regexec(&regex, hash_entry->id, 0, NULL, 0) == 0) {
 265             crm_trace("Matched %s when clearing %s", hash_entry->id, what);
 266             update_local_attr(xml, hash_entry);
 267         }
 268     }
 269     regfree(&regex);
 270 }
 271 
 272 static void
 273 remote_clear_callback(xmlNode *msg, int call_id, int rc, xmlNode *output,
     /* [previous][next][first][last][top][bottom][index][help] */
 274                       void *user_data)
 275 {
 276     if (rc == 0) {
 277         crm_debug("Successfully cleared failures using %s", (char *) user_data);
 278     } else {
 279         crm_notice("Failed to clear failures: %s " CRM_XS " call=%d xpath=%s rc=%d",
 280                    pcmk_strerror(rc), call_id, (char *) user_data, rc);
 281     }
 282 }
 283 
 284 /* xpath component to match an id attribute (format takes remote node name) */
 285 #define XPATH_ID "[@" XML_ATTR_UUID "='%s']"
 286 
 287 /* Define the start of an xpath to match a remote node transient attribute
 288  * (argument must be either an empty string to match for all remote nodes,
 289  * or XPATH_ID to match for a single remote node)
 290  */
 291 #define XPATH_REMOTE_ATTR(x) "/" XML_TAG_CIB "/" XML_CIB_TAG_STATUS \
 292     "/" XML_CIB_TAG_STATE "[@" XML_NODE_IS_REMOTE "='true']" x \
 293     "/" XML_TAG_TRANSIENT_NODEATTRS "/" XML_TAG_ATTR_SETS "/" XML_CIB_TAG_NVPAIR
 294 
 295 /* xpath component to match an attribute name exactly */
 296 #define XPATH_NAME_IS(x) "@" XML_NVPAIR_ATTR_NAME "='" x "'"
 297 
 298 /* xpath component to match an attribute name by prefix */
 299 #define XPATH_NAME_START(x) "starts-with(@" XML_NVPAIR_ATTR_NAME ", '" x "')"
 300 
 301 /* xpath ending to clear all resources */
 302 #define XPATH_CLEAR_ALL \
 303     "[" XPATH_NAME_START(CRM_FAIL_COUNT_PREFIX "-") \
 304     " or " XPATH_NAME_START(CRM_LAST_FAILURE_PREFIX "-") "]"
 305 
 306 /* xpath ending to clear all operations for one resource
 307  * (format takes resource name x 4)
 308  *
 309  * @COMPAT attributes set < 1.1.17:
 310  * also match older attributes that do not have the operation part
 311  */
 312 #define XPATH_CLEAR_ONE \
 313     "[" XPATH_NAME_IS(CRM_FAIL_COUNT_PREFIX "-%s") \
 314     " or " XPATH_NAME_IS(CRM_LAST_FAILURE_PREFIX "-%s") \
 315     " or " XPATH_NAME_START(CRM_FAIL_COUNT_PREFIX "-%s#") \
 316     " or " XPATH_NAME_START(CRM_LAST_FAILURE_PREFIX "-%s#") "]"
 317 
 318 /* xpath ending to clear one operation for one resource
 319  * (format takes resource name x 2, resource name + operation + interval x 2)
 320  *
 321  * @COMPAT attributes set < 1.1.17:
 322  * also match older attributes that do not have the operation part
 323  */
 324 #define XPATH_CLEAR_OP \
 325     "[" XPATH_NAME_IS(CRM_FAIL_COUNT_PREFIX "-%s") \
 326     " or " XPATH_NAME_IS(CRM_LAST_FAILURE_PREFIX "-%s") \
 327     " or " XPATH_NAME_IS(CRM_FAIL_COUNT_PREFIX "-%s#%s_%d") \
 328     " or " XPATH_NAME_IS(CRM_LAST_FAILURE_PREFIX "-%s#%s_%d") "]"
 329 
 330 /*!
 331  * \internal
 332  * \brief Clear failure-related attributes for Pacemaker Remote node(s)
 333  *
 334  * \param[in] xml  XML of ATTRD_OP_CLEAR_FAILURE request
 335  */
 336 static void
 337 remote_clear_failure(xmlNode *xml)
     /* [previous][next][first][last][top][bottom][index][help] */
 338 {
 339     const char *rsc = crm_element_value(xml, F_ATTRD_RESOURCE);
 340     const char *host = crm_element_value(xml, F_ATTRD_HOST);
 341     const char *op = crm_element_value(xml, F_ATTRD_OPERATION);
 342     int rc = pcmk_ok;
 343     char *xpath;
 344 
 345     if (the_cib == NULL) {
 346         crm_info("Ignoring request to clear %s on %s because not connected to CIB",
 347                  (rsc? rsc : "all resources"),
 348                  (host? host: "all remote nodes"));
 349         return;
 350     }
 351 
 352     /* Build an xpath to clear appropriate attributes */
 353 
 354     if (rsc == NULL) {
 355         /* No resource specified, clear all resources */
 356 
 357         if (host == NULL) {
 358             xpath = crm_strdup_printf(XPATH_REMOTE_ATTR("") XPATH_CLEAR_ALL);
 359         } else {
 360             xpath = crm_strdup_printf(XPATH_REMOTE_ATTR(XPATH_ID) XPATH_CLEAR_ALL,
 361                                       host);
 362         }
 363 
 364     } else if (op == NULL) {
 365         /* Resource but no operation specified, clear all operations */
 366 
 367         if (host == NULL) {
 368             xpath = crm_strdup_printf(XPATH_REMOTE_ATTR("") XPATH_CLEAR_ONE,
 369                                       rsc, rsc, rsc, rsc);
 370         } else {
 371             xpath = crm_strdup_printf(XPATH_REMOTE_ATTR(XPATH_ID) XPATH_CLEAR_ONE,
 372                                       host, rsc, rsc, rsc, rsc);
 373         }
 374 
 375     } else {
 376         /* Resource and operation specified */
 377 
 378         const char *interval_s = crm_element_value(xml, F_ATTRD_INTERVAL);
 379         int interval = crm_get_interval(interval_s);
 380 
 381         if (host == NULL) {
 382             xpath = crm_strdup_printf(XPATH_REMOTE_ATTR("") XPATH_CLEAR_OP,
 383                                       rsc, rsc, rsc, op, interval,
 384                                       rsc, op, interval);
 385         } else {
 386             xpath = crm_strdup_printf(XPATH_REMOTE_ATTR(XPATH_ID) XPATH_CLEAR_OP,
 387                                       host, rsc, rsc, rsc, op, interval,
 388                                       rsc, op, interval);
 389         }
 390     }
 391 
 392     crm_trace("Clearing attributes matching %s", xpath);
 393     rc = the_cib->cmds->delete(the_cib, xpath, NULL, cib_xpath|cib_multiple);
 394     register_cib_callback(rc, xpath, remote_clear_callback, free);
 395 }
 396 
 397 static void
 398 process_xml_request(xmlNode *xml)
     /* [previous][next][first][last][top][bottom][index][help] */
 399 {
 400     attr_hash_entry_t *hash_entry = NULL;
 401     const char *from = crm_element_value(xml, F_ORIG);
 402     const char *op = crm_element_value(xml, F_ATTRD_TASK);
 403     const char *host = crm_element_value(xml, F_ATTRD_HOST);
 404     const char *ignore = crm_element_value(xml, F_ATTRD_IGNORE_LOCALLY);
 405 
 406     if (host && safe_str_eq(host, attrd_uname)) {
 407         crm_info("%s relayed from %s", (op? op : "Request"), from);
 408         attrd_local_callback(xml);
 409 
 410     } else if (safe_str_eq(op, ATTRD_OP_PEER_REMOVE)) {
 411         CRM_CHECK(host != NULL, return);
 412         crm_debug("Removing %s from peer caches for %s", host, from);
 413         crm_remote_peer_cache_remove(host);
 414         reap_crm_member(0, host);
 415 
 416     } else if (safe_str_eq(op, ATTRD_OP_CLEAR_FAILURE)) {
 417         local_clear_failure(xml);
 418 
 419     } else if ((ignore == NULL) || safe_str_neq(from, attrd_uname)) {
 420         crm_trace("%s message from %s", op, from);
 421         hash_entry = find_hash_entry(xml);
 422         stop_attrd_timer(hash_entry);
 423         attrd_perform_update(hash_entry);
 424     }
 425 }
 426 
 427 #if SUPPORT_HEARTBEAT
 428 static void
 429 attrd_ha_connection_destroy(gpointer user_data)
     /* [previous][next][first][last][top][bottom][index][help] */
 430 {
 431     crm_trace("Invoked");
 432     if (attrd_shutting_down()) {
 433         /* we signed out, so this is expected */
 434         crm_info("Heartbeat disconnection complete");
 435         return;
 436     }
 437 
 438     crm_crit("Lost connection to heartbeat service!");
 439     if (attrd_mainloop_running()) {
 440         attrd_quit_mainloop();
 441         return;
 442     }
 443     crm_exit(pcmk_ok);
 444 }
 445 
 446 static void
 447 attrd_ha_callback(HA_Message * msg, void *private_data)
     /* [previous][next][first][last][top][bottom][index][help] */
 448 {
 449     xmlNode *xml = convert_ha_message(NULL, msg, __FUNCTION__);
 450 
 451     process_xml_request(xml);
 452     free_xml(xml);
 453 }
 454 
 455 #endif
 456 
 457 #if SUPPORT_COROSYNC
 458 static void
 459 attrd_cs_dispatch(cpg_handle_t handle,
     /* [previous][next][first][last][top][bottom][index][help] */
 460                  const struct cpg_name *groupName,
 461                  uint32_t nodeid, uint32_t pid, void *msg, size_t msg_len)
 462 {
 463     uint32_t kind = 0;
 464     xmlNode *xml = NULL;
 465     const char *from = NULL;
 466     char *data = pcmk_message_common_cs(handle, nodeid, pid, msg, &kind, &from);
 467 
 468     if(data == NULL) {
 469         return;
 470     }
 471     if (kind == crm_class_cluster) {
 472         xml = string2xml(data);
 473         if (xml == NULL) {
 474             crm_err("Bad message received: '%.120s'", data);
 475         }
 476     }
 477 
 478     if (xml != NULL) {
 479         /* crm_xml_add_int(xml, F_SEQ, wrapper->id); */
 480         crm_xml_add(xml, F_ORIG, from);
 481         process_xml_request(xml);
 482         free_xml(xml);
 483     }
 484 
 485     free(data);
 486 }
 487 
 488 static void
 489 attrd_cs_destroy(gpointer unused)
     /* [previous][next][first][last][top][bottom][index][help] */
 490 {
 491     if (attrd_shutting_down()) {
 492         /* we signed out, so this is expected */
 493         crm_info("Corosync disconnection complete");
 494         return;
 495     }
 496 
 497     crm_crit("Lost connection to Corosync service!");
 498     if (attrd_mainloop_running()) {
 499         attrd_quit_mainloop();
 500         return;
 501     }
 502     crm_exit(EINVAL);
 503 }
 504 #endif
 505 
 506 static void
 507 attrd_cib_connection_destroy(gpointer user_data)
     /* [previous][next][first][last][top][bottom][index][help] */
 508 {
 509     cib_t *conn = user_data;
 510 
 511     conn->cmds->signoff(conn);  /* Ensure IPC is cleaned up */
 512 
 513     if (attrd_shutting_down()) {
 514         crm_info("Connection to the CIB terminated...");
 515 
 516     } else {
 517         /* eventually this will trigger a reconnect, not a shutdown */
 518         crm_err("Connection to the CIB terminated...");
 519         crm_exit(ENOTCONN);
 520     }
 521 
 522     return;
 523 }
 524 
 525 static void
 526 update_for_hash_entry(gpointer key, gpointer value, gpointer user_data)
     /* [previous][next][first][last][top][bottom][index][help] */
 527 {
 528     attr_hash_entry_t *entry = value;
 529 
 530     if (entry->value != NULL || entry->stored_value != NULL) {
 531         attrd_timer_callback(value);
 532     }
 533 }
 534 
 535 static void
 536 local_update_for_hash_entry(gpointer key, gpointer value, gpointer user_data)
     /* [previous][next][first][last][top][bottom][index][help] */
 537 {
 538     attr_hash_entry_t *entry = value;
 539 
 540     if (entry->timer_id == 0) {
 541         crm_trace("Performing local-only update after replace for %s", entry->id);
 542         attrd_perform_update(entry);
 543         /* } else {
 544          *     just let the timer expire and attrd_timer_callback() will do the right thing
 545          */
 546     }
 547 }
 548 
 549 static void
 550 do_cib_replaced(const char *event, xmlNode * msg)
     /* [previous][next][first][last][top][bottom][index][help] */
 551 {
 552     crm_info("Updating all attributes after %s event", event);
 553     g_hash_table_foreach(attr_hash, local_update_for_hash_entry, NULL);
 554 }
 555 
 556 static gboolean
 557 cib_connect(void *user_data)
     /* [previous][next][first][last][top][bottom][index][help] */
 558 {
 559     static int attempts = 1;
 560     static int max_retry = 20;
 561     gboolean was_err = FALSE;
 562     static cib_t *local_conn = NULL;
 563 
 564     if (local_conn == NULL) {
 565         local_conn = cib_new();
 566     }
 567 
 568     if (was_err == FALSE) {
 569         int rc = -ENOTCONN;
 570 
 571         if (attempts < max_retry) {
 572             crm_debug("CIB signon attempt %d", attempts);
 573             rc = local_conn->cmds->signon(local_conn, T_ATTRD, cib_command);
 574         }
 575 
 576         if (rc != pcmk_ok && attempts > max_retry) {
 577             crm_err("Signon to CIB failed: %s", pcmk_strerror(rc));
 578             was_err = TRUE;
 579 
 580         } else if (rc != pcmk_ok) {
 581             attempts++;
 582             return TRUE;
 583         }
 584     }
 585 
 586     crm_info("Connected to the CIB after %d signon attempts", attempts);
 587 
 588     if (was_err == FALSE) {
 589         int rc = local_conn->cmds->set_connection_dnotify(local_conn, attrd_cib_connection_destroy);
 590 
 591         if (rc != pcmk_ok) {
 592             crm_err("Could not set dnotify callback");
 593             was_err = TRUE;
 594         }
 595     }
 596 
 597     if (was_err == FALSE) {
 598         if (pcmk_ok !=
 599             local_conn->cmds->add_notify_callback(local_conn, T_CIB_REPLACE_NOTIFY,
 600                                                   do_cib_replaced)) {
 601             crm_err("Could not set CIB notification callback");
 602             was_err = TRUE;
 603         }
 604         if (was_err == FALSE) {
 605             if (pcmk_ok != local_conn->cmds->add_notify_callback(local_conn, T_CIB_DIFF_NOTIFY, attrd_cib_updated_cb)) {
 606                 crm_err("Could not set CIB notification callback (update)");
 607                 was_err = TRUE;
 608             }
 609 
 610         }
 611         attrd_config_read = mainloop_add_trigger(G_PRIORITY_HIGH, attrd_read_options, NULL);
 612 
 613         /* Reading of cib(Alert section) after the start */
 614         mainloop_set_trigger(attrd_config_read);
 615     }
 616 
 617     if (was_err) {
 618         crm_err("Aborting startup");
 619         crm_exit(DAEMON_RESPAWN_STOP);
 620     }
 621 
 622     the_cib = local_conn;
 623 
 624     crm_info("Sending full refresh now that we're connected to the cib");
 625     g_hash_table_foreach(attr_hash, local_update_for_hash_entry, NULL);
 626 
 627     return FALSE;
 628 }
 629 
 630 int
 631 main(int argc, char **argv)
     /* [previous][next][first][last][top][bottom][index][help] */
 632 {
 633     int flag = 0;
 634     int argerr = 0;
 635     crm_cluster_t cluster;
 636     gboolean was_err = FALSE;
 637     qb_ipcs_connection_t *c = NULL;
 638     qb_ipcs_service_t *ipcs = NULL;
 639 
 640     crm_log_init(T_ATTRD, LOG_NOTICE, TRUE, FALSE, argc, argv, FALSE);
 641     mainloop_add_signal(SIGTERM, attrd_shutdown);
 642 
 643     while ((flag = getopt(argc, argv, OPTARGS)) != EOF) {
 644         switch (flag) {
 645             case 'V':
 646                 crm_bump_log_level(argc, argv);
 647                 break;
 648             case 'h':          /* Help message */
 649                 usage(T_ATTRD, EX_OK);
 650                 break;
 651             default:
 652                 ++argerr;
 653                 break;
 654         }
 655     }
 656 
 657     if (optind > argc) {
 658         ++argerr;
 659     }
 660 
 661     if (argerr) {
 662         usage(T_ATTRD, EX_USAGE);
 663     }
 664 
 665     attr_hash = g_hash_table_new_full(crm_str_hash, g_str_equal, NULL, free_hash_entry);
 666 
 667     crm_info("Starting up");
 668 
 669     if (was_err == FALSE) {
 670 
 671 #if SUPPORT_COROSYNC
 672         if (is_openais_cluster()) {
 673             cluster.destroy = attrd_cs_destroy;
 674             cluster.cpg.cpg_deliver_fn = attrd_cs_dispatch;
 675             cluster.cpg.cpg_confchg_fn = pcmk_cpg_membership;
 676         }
 677 #endif
 678 
 679 #if SUPPORT_HEARTBEAT
 680         if (is_heartbeat_cluster()) {
 681             cluster.hb_conn = NULL;
 682             cluster.hb_dispatch = attrd_ha_callback;
 683             cluster.destroy = attrd_ha_connection_destroy;
 684         }
 685 #endif
 686 
 687         if (FALSE == crm_cluster_connect(&cluster)) {
 688             crm_err("HA Signon failed");
 689             was_err = TRUE;
 690         }
 691 
 692         attrd_uname = cluster.uname;
 693         attrd_uuid = cluster.uuid;
 694         attrd_nodeid = cluster.nodeid;
 695 #if SUPPORT_HEARTBEAT
 696         attrd_cluster_conn = cluster.hb_conn;
 697 #endif
 698     }
 699 
 700     crm_info("Cluster connection active");
 701 
 702     if (was_err == FALSE) {
 703         attrd_init_ipc(&ipcs, attrd_ipc_dispatch);
 704     }
 705 
 706     crm_info("Accepting attribute updates");
 707 
 708     attrd_init_mainloop();
 709 
 710     if (0 == g_timeout_add_full(G_PRIORITY_LOW + 1, 5000, cib_connect, NULL, NULL)) {
 711         crm_info("Adding timer failed");
 712         was_err = TRUE;
 713     }
 714 
 715     if (was_err) {
 716         crm_err("Aborting startup");
 717         return 100;
 718     }
 719 
 720     crm_notice("Starting mainloop...");
 721     attrd_run_mainloop();
 722     crm_notice("Exiting...");
 723 
 724 #if SUPPORT_HEARTBEAT
 725     if (is_heartbeat_cluster()) {
 726         attrd_cluster_conn->llc_ops->signoff(attrd_cluster_conn, TRUE);
 727         attrd_cluster_conn->llc_ops->delete(attrd_cluster_conn);
 728     }
 729 #endif
 730 
 731     c = qb_ipcs_connection_first_get(ipcs);
 732     while (c != NULL) {
 733         qb_ipcs_connection_t *last = c;
 734 
 735         c = qb_ipcs_connection_next_get(ipcs, last);
 736 
 737         /* There really shouldn't be anyone connected at this point */
 738         crm_notice("Disconnecting client %p, pid=%d...", last, crm_ipcs_client_pid(last));
 739         qb_ipcs_disconnect(last);
 740         qb_ipcs_connection_unref(last);
 741     }
 742 
 743     qb_ipcs_destroy(ipcs);
 744 
 745     attrd_lrmd_disconnect();
 746     attrd_cib_disconnect();
 747 
 748     g_hash_table_destroy(attr_hash);
 749     free(attrd_uuid);
 750 
 751     return crm_exit(pcmk_ok);
 752 }
 753 
 754 struct attrd_callback_s {
 755     char *attr;
 756     char *value;
 757 };
 758 
 759 /*!
 760  * \internal
 761  * \brief Free an attrd callback structure
 762  */
 763 static void
 764 free_attrd_callback(void *user_data)
     /* [previous][next][first][last][top][bottom][index][help] */
 765 {
 766     struct attrd_callback_s *data = user_data;
 767 
 768     free(data->attr);
 769     free(data->value);
 770     free(data);
 771 }
 772 
 773 static void
 774 attrd_cib_callback(xmlNode * msg, int call_id, int rc, xmlNode * output, void *user_data)
     /* [previous][next][first][last][top][bottom][index][help] */
 775 {
 776     attr_hash_entry_t *hash_entry = NULL;
 777     struct attrd_callback_s *data = user_data;
 778 
 779     if (data->value == NULL && rc == -ENXIO) {
 780         rc = pcmk_ok;
 781 
 782     } else if (call_id < 0) {
 783         crm_warn("Update %s=%s failed: %s", data->attr, data->value, pcmk_strerror(call_id));
 784         return;
 785     }
 786 
 787     switch (rc) {
 788         case pcmk_ok:
 789             crm_debug("Update %d for %s=%s passed", call_id, data->attr, data->value);
 790             hash_entry = g_hash_table_lookup(attr_hash, data->attr);
 791 
 792             if (hash_entry) {
 793                 free(hash_entry->stored_value);
 794                 hash_entry->stored_value = NULL;
 795                 if (data->value != NULL) {
 796                     hash_entry->stored_value = strdup(data->value);
 797                 }
 798             }
 799             break;
 800         case -pcmk_err_diff_failed:    /* When an attr changes while the CIB is syncing */
 801         case -ETIME:           /* When an attr changes while there is a DC election */
 802         case -ENXIO:           /* When an attr changes while the CIB is syncing a
 803                                  *   newer config from a node that just came up
 804                                  */
 805             crm_warn("Update %d for %s=%s failed: %s",
 806                      call_id, data->attr, data->value, pcmk_strerror(rc));
 807             break;
 808         default:
 809             crm_err("Update %d for %s=%s failed: %s",
 810                     call_id, data->attr, data->value, pcmk_strerror(rc));
 811     }
 812 }
 813 
 814 void
 815 attrd_perform_update(attr_hash_entry_t * hash_entry)
     /* [previous][next][first][last][top][bottom][index][help] */
 816 {
 817     int rc = pcmk_ok;
 818     struct attrd_callback_s *data = NULL;
 819     const char *user_name = NULL;
 820 
 821     if (hash_entry == NULL) {
 822         return;
 823 
 824     } else if (the_cib == NULL) {
 825         crm_info("Delaying operation %s=%s: cib not connected", hash_entry->id,
 826                  crm_str(hash_entry->value));
 827         return;
 828 
 829     }
 830 #if ENABLE_ACL
 831     if (hash_entry->user) {
 832         user_name = hash_entry->user;
 833         crm_trace("Performing request from user '%s'", hash_entry->user);
 834     }
 835 #endif
 836 
 837     if (hash_entry->value == NULL) {
 838         /* delete the attr */
 839         rc = delete_attr_delegate(the_cib, cib_none, hash_entry->section, attrd_uuid, NULL,
 840                                   hash_entry->set, hash_entry->uuid, hash_entry->id, NULL, FALSE,
 841                                   user_name);
 842 
 843         if (rc >= 0 && hash_entry->stored_value) {
 844             crm_notice("Sent delete %d: node=%s, attr=%s, id=%s, set=%s, section=%s",
 845                        rc, attrd_uuid, hash_entry->id,
 846                        hash_entry->uuid ? hash_entry->uuid : "<n/a>", hash_entry->set,
 847                        hash_entry->section);
 848 
 849         } else if (rc < 0 && rc != -ENXIO) {
 850             crm_notice
 851                 ("Delete operation failed: node=%s, attr=%s, id=%s, set=%s, section=%s: %s (%d)",
 852                  attrd_uuid, hash_entry->id, hash_entry->uuid ? hash_entry->uuid : "<n/a>",
 853                  hash_entry->set, hash_entry->section, pcmk_strerror(rc), rc);
 854 
 855         } else {
 856             crm_trace("Sent delete %d: node=%s, attr=%s, id=%s, set=%s, section=%s",
 857                       rc, attrd_uuid, hash_entry->id,
 858                       hash_entry->uuid ? hash_entry->uuid : "<n/a>", hash_entry->set,
 859                       hash_entry->section);
 860         }
 861     } else {
 862         /* send update */
 863         rc = update_attr_delegate(the_cib, cib_none, hash_entry->section,
 864                                   attrd_uuid, NULL, hash_entry->set, hash_entry->uuid,
 865                                   hash_entry->id, hash_entry->value, FALSE, user_name, NULL);
 866         if (rc < 0) {
 867             crm_notice("Could not update %s=%s: %s (%d)", hash_entry->id,
 868                        hash_entry->value, pcmk_strerror(rc), rc);
 869         } else if (safe_str_neq(hash_entry->value, hash_entry->stored_value)) {
 870             crm_notice("Sent update %d: %s=%s", rc, hash_entry->id, hash_entry->value);
 871         } else {
 872             crm_trace("Sent update %d: %s=%s", rc, hash_entry->id, hash_entry->value);
 873         }
 874     }
 875     attrd_send_attribute_alert(attrd_uname, attrd_nodeid,
 876                                hash_entry->id, hash_entry->value);
 877 
 878     data = calloc(1, sizeof(struct attrd_callback_s));
 879     data->attr = strdup(hash_entry->id);
 880     if (hash_entry->value != NULL) {
 881         data->value = strdup(hash_entry->value);
 882     }
 883     register_cib_callback(rc, data, attrd_cib_callback, free_attrd_callback);
 884     return;
 885 }
 886 
 887 /*!
 888  * \internal
 889  * \brief Expand attribute values that use "++" or "+="
 890  *
 891  * \param[in] value      Attribute value to expand
 892  * \param[in] old_value  Previous value of attribute
 893  *
 894  * \return Newly allocated string with expanded value, or NULL if not expanded
 895  */
 896 static char *
 897 expand_attr_value(const char *value, const char *old_value)
     /* [previous][next][first][last][top][bottom][index][help] */
 898 {
 899     char *expanded = NULL;
 900 
 901     if (attrd_value_needs_expansion(value)) {
 902         expanded = crm_itoa(attrd_expand_value(value, old_value));
 903     }
 904     return expanded;
 905 }
 906 
 907 /*!
 908  * \internal
 909  * \brief Update a single node attribute for this node
 910  *
 911  * \param[in]     msg         XML message with update
 912  * \param[in,out] hash_entry  Node attribute structure
 913  */
 914 static void
 915 update_local_attr(xmlNode *msg, attr_hash_entry_t *hash_entry)
     /* [previous][next][first][last][top][bottom][index][help] */
 916 {
 917     const char *value = crm_element_value(msg, F_ATTRD_VALUE);
 918     char *expanded = NULL;
 919 
 920     if (hash_entry->uuid == NULL) {
 921         const char *key = crm_element_value(msg, F_ATTRD_KEY);
 922 
 923         if (key) {
 924             hash_entry->uuid = strdup(key);
 925         }
 926     }
 927 
 928     crm_debug("Request to update %s (%s) to %s from %s (stored: %s)",
 929               hash_entry->id, (hash_entry->uuid? hash_entry->uuid : "no uuid"),
 930               value, hash_entry->value, hash_entry->stored_value);
 931 
 932     if (safe_str_eq(value, hash_entry->value)
 933         && safe_str_eq(value, hash_entry->stored_value)) {
 934         crm_trace("Ignoring non-change");
 935         return;
 936 
 937     } else if (value) {
 938         expanded = expand_attr_value(value, hash_entry->value);
 939         if (expanded) {
 940             crm_info("Expanded %s=%s to %s", hash_entry->id, value, expanded);
 941             value = expanded;
 942         }
 943     }
 944 
 945     if (safe_str_eq(value, hash_entry->value) && hash_entry->timer_id) {
 946         /* We're already waiting to set this value */
 947         free(expanded);
 948         return;
 949     }
 950 
 951     free(hash_entry->value);
 952     hash_entry->value = NULL;
 953     if (value != NULL) {
 954         hash_entry->value = (expanded? expanded : strdup(value));
 955         crm_debug("New value of %s is %s", hash_entry->id, value);
 956     }
 957 
 958     stop_attrd_timer(hash_entry);
 959 
 960     if (hash_entry->timeout > 0) {
 961         hash_entry->timer_id = g_timeout_add(hash_entry->timeout, attrd_timer_callback, hash_entry);
 962     } else {
 963         attrd_trigger_update(hash_entry);
 964     }
 965 }
 966 
 967 /*!
 968  * \internal
 969  * \brief Log the result of a CIB operation for a remote attribute
 970  *
 971  * \param[in] msg     ignored
 972  * \param[in] id      CIB operation ID
 973  * \param[in] rc      CIB operation result
 974  * \param[in] output  ignored
 975  * \param[in] data    User-friendly string describing operation
 976  */
 977 static void
 978 remote_attr_callback(xmlNode *msg, int id, int rc, xmlNode *output, void *data)
     /* [previous][next][first][last][top][bottom][index][help] */
 979 {
 980     if (rc == pcmk_ok) {
 981         crm_debug("%s succeeded " CRM_XS " call=%d", (char *) data, id);
 982     } else {
 983         crm_notice("%s failed: %s " CRM_XS " call=%d rc=%d",
 984                    (char *) data, pcmk_strerror(rc), id, rc);
 985     }
 986 }
 987 
 988 /*!
 989  * \internal
 990  * \brief Update a Pacemaker Remote node attribute via CIB only
 991  *
 992  * \param[in] host       Pacemaker Remote node name
 993  * \param[in] name       Attribute name
 994  * \param[in] value      New attribute value
 995  * \param[in] section    CIB section to update (defaults to status if NULL)
 996  * \param[in] user_name  User to perform operation as
 997  *
 998  * \note Legacy attrd does not track remote node attributes, so such requests
 999  *       are only sent to the CIB. This means that dampening is ignored, and
1000  *       updates for the same attribute submitted to different nodes cannot be
1001  *       reliably ordered. This is not ideal, but allows remote nodes to
1002  *       be supported, and should be acceptable in practice.
1003  */
1004 static void
1005 update_remote_attr(const char *host, const char *name, const char *value,
     /* [previous][next][first][last][top][bottom][index][help] */
1006                    const char *section, const char *user_name)
1007 {
1008     int rc = pcmk_ok;
1009     char *desc;
1010 
1011     if (value == NULL) {
1012         desc = crm_strdup_printf("Delete of %s in %s for %s",
1013                                  name, section, host);
1014     } else {
1015         desc = crm_strdup_printf("Update of %s=%s in %s for %s",
1016                                  name, value, section, host);
1017     }
1018 
1019     if (name == NULL) {
1020         rc = -EINVAL;
1021     } else if (the_cib == NULL) {
1022         rc = -ENOTCONN;
1023     }
1024     if (rc != pcmk_ok) {
1025         remote_attr_callback(NULL, rc, rc, NULL, desc);
1026         free(desc);
1027         return;
1028     }
1029 
1030     if (value == NULL) {
1031         rc = delete_attr_delegate(the_cib, cib_none, section,
1032                                   host, NULL, NULL, NULL, name, NULL,
1033                                   FALSE, user_name);
1034     } else {
1035         rc = update_attr_delegate(the_cib, cib_none, section,
1036                                   host, NULL, NULL, NULL, name, value,
1037                                   FALSE, user_name, "remote");
1038     }
1039 
1040     attrd_send_attribute_alert(host, 0, name, (value? value : ""));
1041 
1042     crm_trace("%s submitted as CIB call %d", desc, rc);
1043     register_cib_callback(rc, desc, remote_attr_callback, free);
1044 }
1045 
1046 /*!
1047  * \internal
1048  * \brief Handle a client request to clear failures
1049  *
1050  * \param[in] msg  XML of request
1051  *
1052  * \note Handling is according to the host specified in the request:
1053  *       NULL: Relay to all cluster nodes (which do local_clear_failure())
1054  *          and also handle all remote nodes here, using remote_clear_failure();
1055  *       Our uname: Handle here, using local_clear_failure();
1056  *       Known peer: Relay to that peer, which (via process_xml_message() then
1057  *          attrd_local_callback()) comes back here as previous case;
1058  *       Unknown peer: Handle here as remote node, using remote_clear_failure()
1059  */
1060 static void
1061 attrd_client_clear_failure(xmlNode *msg)
     /* [previous][next][first][last][top][bottom][index][help] */
1062 {
1063     const char *host = crm_element_value(msg, F_ATTRD_HOST);
1064 
1065     if (host == NULL) {
1066         /* Clear failure on all cluster nodes */
1067         crm_notice("Broadcasting request to clear failure on all hosts");
1068         send_cluster_message(NULL, crm_msg_attrd, msg, FALSE);
1069 
1070         /* Clear failure on all remote nodes */
1071         remote_clear_failure(msg);
1072 
1073     } else if (safe_str_eq(host, attrd_uname)) {
1074         local_clear_failure(msg);
1075 
1076     } else {
1077         int is_remote = FALSE;
1078         crm_node_t *peer = crm_find_peer(0, host);
1079 
1080         crm_element_value_int(msg, F_ATTRD_IS_REMOTE, &is_remote);
1081 
1082         if (is_remote || (peer == NULL)) {
1083             /* If request is not for a known cluster node, assume remote */
1084             remote_clear_failure(msg);
1085         } else {
1086             /* Relay request to proper node */
1087             crm_notice("Relaying request to clear failure to %s", host);
1088             send_cluster_message(peer, crm_msg_attrd, msg, FALSE);
1089         }
1090     }
1091 }
1092 
1093 void
1094 attrd_local_callback(xmlNode * msg)
     /* [previous][next][first][last][top][bottom][index][help] */
1095 {
1096     attr_hash_entry_t *hash_entry = NULL;
1097     const char *from = crm_element_value(msg, F_ORIG);
1098     const char *op = crm_element_value(msg, F_ATTRD_TASK);
1099     const char *attr = crm_element_value(msg, F_ATTRD_ATTRIBUTE);
1100     const char *pattern = crm_element_value(msg, F_ATTRD_REGEX);
1101     const char *value = crm_element_value(msg, F_ATTRD_VALUE);
1102     const char *host = crm_element_value(msg, F_ATTRD_HOST);
1103     int is_remote = FALSE;
1104 
1105     crm_element_value_int(msg, F_ATTRD_IS_REMOTE, &is_remote);
1106 
1107     if (safe_str_eq(op, ATTRD_OP_REFRESH)) {
1108         crm_notice("Sending full refresh (origin=%s)", from);
1109         g_hash_table_foreach(attr_hash, update_for_hash_entry, NULL);
1110         return;
1111 
1112     } else if (safe_str_eq(op, ATTRD_OP_PEER_REMOVE)) {
1113         if (host) {
1114             crm_notice("Broadcasting removal of peer %s", host);
1115             send_cluster_message(NULL, crm_msg_attrd, msg, FALSE);
1116         }
1117         return;
1118 
1119     } else if (safe_str_eq(op, ATTRD_OP_CLEAR_FAILURE)) {
1120         attrd_client_clear_failure(msg);
1121         return;
1122 
1123     } else if (op && safe_str_neq(op, ATTRD_OP_UPDATE)) {
1124         crm_notice("Ignoring unsupported %s request from %s", op, from);
1125         return;
1126     }
1127 
1128     /* Handle requests for Pacemaker Remote nodes specially */
1129     if (host && is_remote) {
1130         const char *section = crm_element_value(msg, F_ATTRD_SECTION);
1131         const char *user_name = crm_element_value(msg, F_ATTRD_USER);
1132 
1133         if (section == NULL) {
1134             section = XML_CIB_TAG_STATUS;
1135         }
1136         if ((attr == NULL) && (pattern != NULL)) {
1137             /* Attribute(s) specified by regular expression */
1138             /* @TODO query, iterate and update_remote_attr() for matches? */
1139             crm_notice("Update of %s for %s failed: regular expressions "
1140                        "are not supported with Pacemaker Remote nodes",
1141                        pattern, host);
1142         } else {
1143             /* Single attribute specified by exact name */
1144             update_remote_attr(host, attr, value, section, user_name);
1145         }
1146         return;
1147     }
1148 
1149     /* Redirect requests for another cluster node to that node */
1150     if (host != NULL && safe_str_neq(host, attrd_uname)) {
1151         send_cluster_message(crm_get_peer(0, host), crm_msg_attrd, msg, FALSE);
1152         return;
1153     }
1154 
1155     if (attr != NULL) {
1156         /* Single attribute specified by exact name */
1157         crm_debug("%s message from %s: %s=%s", op, from, attr, crm_str(value));
1158         hash_entry = find_hash_entry(msg);
1159         if (hash_entry != NULL) {
1160             update_local_attr(msg, hash_entry);
1161         }
1162 
1163     } else if (pattern != NULL) {
1164         /* Attribute(s) specified by regular expression */
1165         regex_t regex;
1166         GHashTableIter iter;
1167 
1168         if (regcomp(&regex, pattern, REG_EXTENDED|REG_NOSUB)) {
1169             crm_err("Update from %s failed: invalid pattern %s",
1170                     from, pattern);
1171             return;
1172         }
1173 
1174         crm_debug("%s message from %s: %s=%s",
1175                   op, from, pattern, crm_str(value));
1176         g_hash_table_iter_init(&iter, attr_hash);
1177         while (g_hash_table_iter_next(&iter, NULL, (gpointer *) &hash_entry)) {
1178             int rc = regexec(&regex, hash_entry->id, 0, NULL, 0);
1179 
1180             if (rc == 0) {
1181                 crm_trace("Attribute %s matches %s", hash_entry->id, pattern);
1182                 update_local_attr(msg, hash_entry);
1183             }
1184         }
1185         regfree(&regex);
1186 
1187     } else {
1188         crm_info("Ignoring message with no attribute name or expression");
1189     }
1190 }
1191 
1192 gboolean
1193 attrd_timer_callback(void *user_data)
     /* [previous][next][first][last][top][bottom][index][help] */
1194 {
1195     stop_attrd_timer(user_data);
1196     attrd_trigger_update(user_data);
1197     return TRUE;                /* Always return true, removed cleanly by stop_attrd_timer() */
1198 }
1199 
1200 gboolean
1201 attrd_trigger_update(attr_hash_entry_t * hash_entry)
     /* [previous][next][first][last][top][bottom][index][help] */
1202 {
1203     xmlNode *msg = NULL;
1204 
1205     /* send HA message to everyone */
1206     crm_notice("Sending flush op to all hosts for: %s (%s)",
1207                hash_entry->id, crm_str(hash_entry->value));
1208     log_hash_entry(LOG_DEBUG_2, hash_entry, "Sending flush op to all hosts for:");
1209 
1210     msg = create_xml_node(NULL, __FUNCTION__);
1211     crm_xml_add(msg, F_TYPE, T_ATTRD);
1212     crm_xml_add(msg, F_ORIG, attrd_uname);
1213     crm_xml_add(msg, F_ATTRD_TASK, "flush");
1214     crm_xml_add(msg, F_ATTRD_ATTRIBUTE, hash_entry->id);
1215     crm_xml_add(msg, F_ATTRD_SET, hash_entry->set);
1216     crm_xml_add(msg, F_ATTRD_SECTION, hash_entry->section);
1217     crm_xml_add(msg, F_ATTRD_DAMPEN, hash_entry->dampen);
1218     crm_xml_add(msg, F_ATTRD_VALUE, hash_entry->value);
1219 #if ENABLE_ACL
1220     if (hash_entry->user) {
1221         crm_xml_add(msg, F_ATTRD_USER, hash_entry->user);
1222     }
1223 #endif
1224 
1225     if (hash_entry->timeout <= 0) {
1226         crm_xml_add(msg, F_ATTRD_IGNORE_LOCALLY, hash_entry->value);
1227         attrd_perform_update(hash_entry);
1228     }
1229 
1230     send_cluster_message(NULL, crm_msg_attrd, msg, FALSE);
1231     free_xml(msg);
1232 
1233     return TRUE;
1234 }

/* [previous][next][first][last][top][bottom][index][help] */