This source file includes following definitions.
- send_attrd_message
 
- attribute_timer_cb
 
- free_attribute_value
 
- free_attribute
 
- build_attribute_xml
 
- clear_attribute_value_seen
 
- create_attribute
 
- attrd_client_peer_remove
 
- attrd_client_update
 
- attrd_client_clear_failure
 
- attrd_client_refresh
 
- build_query_reply
 
- attrd_client_query
 
- attrd_peer_clear_failure
 
- attrd_broadcast_protocol
 
- attrd_peer_message
 
- attrd_peer_sync
 
- attrd_peer_remove
 
- attrd_lookup_or_create_value
 
- attrd_current_only_attribute_update
 
- attrd_peer_update
 
- write_or_elect_attribute
 
- attrd_election_cb
 
- attrd_peer_change_cb
 
- attrd_cib_callback
 
- write_attributes
 
- build_update_element
 
- set_alert_attribute_value
 
- send_alert_attributes_value
 
- write_attribute
 
   1 
   2 
   3 
   4 
   5 
   6 
   7 
   8 
   9 
  10 #include <crm_internal.h>
  11 
  12 #include <sys/types.h>
  13 #include <regex.h>
  14 #include <glib.h>
  15 
  16 #include <crm/msg_xml.h>
  17 #include <crm/cluster.h>
  18 #include <crm/cib.h>
  19 #include <crm/common/xml_internal.h>
  20 #include <crm/cluster/internal.h>
  21 #include <crm/cluster/election.h>
  22 #include <crm/cib/internal.h>
  23 
  24 #include "pacemaker-attrd.h"
  25 
  26 
  27 
  28 
  29 
  30 
  31 
  32 
  33 
  34 
  35 
  36 
  37 
  38 
  39 
  40 
  41 
  42 
  43 
  44 
  45 
  46 
  47 #define ATTRD_PROTOCOL_VERSION "2"
  48 
  49 int last_cib_op_done = 0;
  50 GHashTable *attributes = NULL;
  51 
  52 void write_attribute(attribute_t *a, bool ignore_delay);
  53 void write_or_elect_attribute(attribute_t *a);
  54 void attrd_current_only_attribute_update(crm_node_t *peer, xmlNode *xml);
  55 void attrd_peer_update(crm_node_t *peer, xmlNode *xml, const char *host, bool filter);
  56 void attrd_peer_sync(crm_node_t *peer, xmlNode *xml);
  57 void attrd_peer_remove(const char *host, gboolean uncache, const char *source);
  58 
  59 static gboolean
  60 send_attrd_message(crm_node_t * node, xmlNode * data)
     
  61 {
  62     crm_xml_add(data, F_TYPE, T_ATTRD);
  63     crm_xml_add(data, PCMK__XA_ATTR_VERSION, ATTRD_PROTOCOL_VERSION);
  64     attrd_xml_add_writer(data);
  65     return send_cluster_message(node, crm_msg_attrd, data, TRUE);
  66 }
  67 
  68 static gboolean
  69 attribute_timer_cb(gpointer data)
     
  70 {
  71     attribute_t *a = data;
  72     crm_trace("Dampen interval expired for %s", a->id);
  73     write_or_elect_attribute(a);
  74     return FALSE;
  75 }
  76 
  77 static void
  78 free_attribute_value(gpointer data)
     
  79 {
  80     attribute_value_t *v = data;
  81 
  82     free(v->nodename);
  83     free(v->current);
  84     free(v->requested);
  85     free(v);
  86 }
  87 
  88 void
  89 free_attribute(gpointer data)
     
  90 {
  91     attribute_t *a = data;
  92     if(a) {
  93         free(a->id);
  94         free(a->set);
  95         free(a->uuid);
  96         free(a->user);
  97 
  98         mainloop_timer_del(a->timer);
  99         g_hash_table_destroy(a->values);
 100 
 101         free(a);
 102     }
 103 }
 104 
 105 static xmlNode *
 106 build_attribute_xml(
     
 107     xmlNode *parent, const char *name, const char *set, const char *uuid, unsigned int timeout_ms, const char *user,
 108     gboolean is_private, const char *peer, uint32_t peerid, const char *value, gboolean is_force_write)
 109 {
 110     xmlNode *xml = create_xml_node(parent, __func__);
 111 
 112     crm_xml_add(xml, PCMK__XA_ATTR_NAME, name);
 113     crm_xml_add(xml, PCMK__XA_ATTR_SET, set);
 114     crm_xml_add(xml, PCMK__XA_ATTR_UUID, uuid);
 115     crm_xml_add(xml, PCMK__XA_ATTR_USER, user);
 116     crm_xml_add(xml, PCMK__XA_ATTR_NODE_NAME, peer);
 117     crm_xml_add_int(xml, PCMK__XA_ATTR_NODE_ID, peerid);
 118     crm_xml_add(xml, PCMK__XA_ATTR_VALUE, value);
 119     crm_xml_add_int(xml, PCMK__XA_ATTR_DAMPENING, timeout_ms/1000);
 120     crm_xml_add_int(xml, PCMK__XA_ATTR_IS_PRIVATE, is_private);
 121     crm_xml_add_int(xml, PCMK__XA_ATTR_FORCE, is_force_write);
 122 
 123     return xml;
 124 }
 125 
 126 static void
 127 clear_attribute_value_seen(void)
     
 128 {
 129     GHashTableIter aIter;
 130     GHashTableIter vIter;
 131     attribute_t *a;
 132     attribute_value_t *v = NULL;
 133 
 134     g_hash_table_iter_init(&aIter, attributes);
 135     while (g_hash_table_iter_next(&aIter, NULL, (gpointer *) & a)) {
 136         g_hash_table_iter_init(&vIter, a->values);
 137         while (g_hash_table_iter_next(&vIter, NULL, (gpointer *) & v)) {
 138             v->seen = FALSE;
 139             crm_trace("Clear seen flag %s[%s] = %s.", a->id, v->nodename, v->current);
 140         }
 141     }
 142 }
 143 
 144 static attribute_t *
 145 create_attribute(xmlNode *xml)
     
 146 {
 147     int dampen = 0;
 148     const char *value = crm_element_value(xml, PCMK__XA_ATTR_DAMPENING);
 149     attribute_t *a = calloc(1, sizeof(attribute_t));
 150 
 151     a->id      = crm_element_value_copy(xml, PCMK__XA_ATTR_NAME);
 152     a->set     = crm_element_value_copy(xml, PCMK__XA_ATTR_SET);
 153     a->uuid    = crm_element_value_copy(xml, PCMK__XA_ATTR_UUID);
 154     a->values = g_hash_table_new_full(crm_strcase_hash, crm_strcase_equal, NULL, free_attribute_value);
 155 
 156     crm_element_value_int(xml, PCMK__XA_ATTR_IS_PRIVATE, &a->is_private);
 157 
 158 #if ENABLE_ACL
 159     a->user = crm_element_value_copy(xml, PCMK__XA_ATTR_USER);
 160     crm_trace("Performing all %s operations as user '%s'", a->id, a->user);
 161 #endif
 162 
 163     if(value) {
 164         dampen = crm_get_msec(value);
 165         crm_trace("Created attribute %s with delay %dms (%s)", a->id, dampen, value);
 166     } else {
 167         crm_trace("Created attribute %s with no delay", a->id);
 168     }
 169 
 170     if(dampen > 0) {
 171         a->timeout_ms = dampen;
 172         a->timer = mainloop_timer_add(a->id, a->timeout_ms, FALSE, attribute_timer_cb, a);
 173     } else if (dampen < 0) {
 174         crm_warn("Ignoring invalid delay %s for attribute %s", value, a->id);
 175     }
 176 
 177     g_hash_table_replace(attributes, a->id, a);
 178     return a;
 179 }
 180 
 181 
 182 
 183 
 184 
 185 
 186 
 187 
 188 
 189 
 190 void
 191 attrd_client_peer_remove(const char *client_name, xmlNode *xml)
     
 192 {
 193     
 194     const char *host = crm_element_value(xml, PCMK__XA_ATTR_NODE_NAME);
 195     char *host_alloc = NULL;
 196 
 197     if (host == NULL) {
 198         int nodeid = 0;
 199 
 200         crm_element_value_int(xml, PCMK__XA_ATTR_NODE_ID, &nodeid);
 201         if (nodeid > 0) {
 202             crm_node_t *node = crm_find_peer(nodeid, NULL);
 203             char *host_alloc = NULL;
 204 
 205             if (node && node->uname) {
 206                 
 207                 host = node->uname;
 208             } else {
 209                 
 210                 host_alloc = get_node_name(nodeid);
 211                 host = host_alloc;
 212             }
 213             crm_xml_add(xml, PCMK__XA_ATTR_NODE_NAME, host);
 214         }
 215     }
 216 
 217     if (host) {
 218         crm_info("Client %s is requesting all values for %s be removed",
 219                  client_name, host);
 220         send_attrd_message(NULL, xml); 
 221         free(host_alloc);
 222     } else {
 223         crm_info("Ignoring request by client %s to remove all peer values without specifying peer",
 224                  client_name);
 225     }
 226 }
 227 
 228 
 229 
 230 
 231 
 232 
 233 
 234 
 235 
 236 void
 237 attrd_client_update(xmlNode *xml)
     
 238 {
 239     attribute_t *a = NULL;
 240     char *host = crm_element_value_copy(xml, PCMK__XA_ATTR_NODE_NAME);
 241     const char *attr = crm_element_value(xml, PCMK__XA_ATTR_NAME);
 242     const char *value = crm_element_value(xml, PCMK__XA_ATTR_VALUE);
 243     const char *regex = crm_element_value(xml, PCMK__XA_ATTR_PATTERN);
 244 
 245     
 246     if ((attr == NULL) && regex) {
 247         GHashTableIter aIter;
 248         regex_t *r_patt = calloc(1, sizeof(regex_t));
 249 
 250         crm_debug("Setting %s to %s", regex, value);
 251         if (regcomp(r_patt, regex, REG_EXTENDED|REG_NOSUB)) {
 252             crm_err("Bad regex '%s' for update", regex);
 253 
 254         } else {
 255             g_hash_table_iter_init(&aIter, attributes);
 256             while (g_hash_table_iter_next(&aIter, (gpointer *) & attr, NULL)) {
 257                 int status = regexec(r_patt, attr, 0, NULL, 0);
 258 
 259                 if (status == 0) {
 260                     crm_trace("Matched %s with %s", attr, regex);
 261                     crm_xml_add(xml, PCMK__XA_ATTR_NAME, attr);
 262                     send_attrd_message(NULL, xml);
 263                 }
 264             }
 265         }
 266 
 267         free(host);
 268         regfree(r_patt);
 269         free(r_patt);
 270         return;
 271 
 272     } else if (attr == NULL) {
 273         crm_err("Update request did not specify attribute or regular expression");
 274         free(host);
 275         return;
 276     }
 277 
 278     if (host == NULL) {
 279         crm_trace("Inferring host");
 280         host = strdup(attrd_cluster->uname);
 281         crm_xml_add(xml, PCMK__XA_ATTR_NODE_NAME, host);
 282         crm_xml_add_int(xml, PCMK__XA_ATTR_NODE_ID, attrd_cluster->nodeid);
 283     }
 284 
 285     a = g_hash_table_lookup(attributes, attr);
 286 
 287     
 288     if (value) {
 289         if (attrd_value_needs_expansion(value)) {
 290             int int_value;
 291             attribute_value_t *v = NULL;
 292 
 293             if (a) {
 294                 v = g_hash_table_lookup(a->values, host);
 295             }
 296             int_value = attrd_expand_value(value, (v? v->current : NULL));
 297 
 298             crm_info("Expanded %s=%s to %d", attr, value, int_value);
 299             crm_xml_add_int(xml, PCMK__XA_ATTR_VALUE, int_value);
 300 
 301             
 302             value = crm_element_value(xml, PCMK__XA_ATTR_VALUE);
 303         }
 304     }
 305 
 306     crm_debug("Broadcasting %s[%s]=%s%s", attr, host, value,
 307               (attrd_election_won()? " (writer)" : ""));
 308 
 309     free(host);
 310 
 311     send_attrd_message(NULL, xml); 
 312 }
 313 
 314 
 315 
 316 
 317 
 318 
 319 
 320 void
 321 attrd_client_clear_failure(xmlNode *xml)
     
 322 {
 323 #if 0
 324     
 325 
 326 
 327     if (compare_version("2", minimum_protocol_version) <= 0) {
 328         
 329 
 330 
 331         send_attrd_message(NULL, xml);
 332         return;
 333     }
 334 #endif
 335 
 336     const char *rsc = crm_element_value(xml, PCMK__XA_ATTR_RESOURCE);
 337     const char *op = crm_element_value(xml, PCMK__XA_ATTR_OPERATION);
 338     const char *interval_spec = crm_element_value(xml, PCMK__XA_ATTR_INTERVAL);
 339 
 340     
 341     crm_xml_add(xml, PCMK__XA_TASK, PCMK__ATTRD_CMD_UPDATE);
 342 
 343     
 344 
 345     if (rsc) {
 346         char *pattern;
 347 
 348         if (op == NULL) {
 349             pattern = crm_strdup_printf(ATTRD_RE_CLEAR_ONE, rsc);
 350 
 351         } else {
 352             guint interval_ms = crm_parse_interval_spec(interval_spec);
 353 
 354             pattern = crm_strdup_printf(ATTRD_RE_CLEAR_OP,
 355                                         rsc, op, interval_ms);
 356         }
 357 
 358         crm_xml_add(xml, PCMK__XA_ATTR_PATTERN, pattern);
 359         free(pattern);
 360 
 361     } else {
 362         crm_xml_add(xml, PCMK__XA_ATTR_PATTERN, ATTRD_RE_CLEAR_ALL);
 363     }
 364 
 365     
 366     if (crm_element_value(xml, PCMK__XA_ATTR_NAME)) {
 367         crm_xml_replace(xml, PCMK__XA_ATTR_NAME, NULL);
 368     }
 369     if (crm_element_value(xml, PCMK__XA_ATTR_VALUE)) {
 370         crm_xml_replace(xml, PCMK__XA_ATTR_VALUE, NULL);
 371     }
 372 
 373     attrd_client_update(xml);
 374 }
 375 
 376 
 377 
 378 
 379 
 380 
 381 
 382 void
 383 attrd_client_refresh(void)
     
 384 {
 385     crm_info("Updating all attributes");
 386     write_attributes(TRUE, TRUE);
 387 }
 388 
 389 
 390 
 391 
 392 
 393 
 394 
 395 
 396 
 397 
 398 
 399 static xmlNode *build_query_reply(const char *attr, const char *host)
     
 400 {
 401     xmlNode *reply = create_xml_node(NULL, __func__);
 402     attribute_t *a;
 403 
 404     if (reply == NULL) {
 405         return NULL;
 406     }
 407     crm_xml_add(reply, F_TYPE, T_ATTRD);
 408     crm_xml_add(reply, PCMK__XA_ATTR_VERSION, ATTRD_PROTOCOL_VERSION);
 409 
 410     
 411     a = g_hash_table_lookup(attributes, attr);
 412     if (a) {
 413         attribute_value_t *v;
 414         xmlNode *host_value;
 415 
 416         crm_xml_add(reply, PCMK__XA_ATTR_NAME, attr);
 417 
 418         
 419         if (pcmk__str_eq(host, "localhost", pcmk__str_casei)) {
 420             host = attrd_cluster->uname;
 421             crm_trace("Mapped localhost to %s", host);
 422         }
 423 
 424         
 425         if (host) {
 426             v = g_hash_table_lookup(a->values, host);
 427             host_value = create_xml_node(reply, XML_CIB_TAG_NODE);
 428             if (host_value == NULL) {
 429                 free_xml(reply);
 430                 return NULL;
 431             }
 432             crm_xml_add(host_value, PCMK__XA_ATTR_NODE_NAME, host);
 433             crm_xml_add(host_value, PCMK__XA_ATTR_VALUE,
 434                         (v? v->current : NULL));
 435 
 436         
 437         } else {
 438             GHashTableIter iter;
 439 
 440             g_hash_table_iter_init(&iter, a->values);
 441             while (g_hash_table_iter_next(&iter, NULL, (gpointer *) &v)) {
 442                 host_value = create_xml_node(reply, XML_CIB_TAG_NODE);
 443                 if (host_value == NULL) {
 444                     free_xml(reply);
 445                     return NULL;
 446                 }
 447                 crm_xml_add(host_value, PCMK__XA_ATTR_NODE_NAME, v->nodename);
 448                 crm_xml_add(host_value, PCMK__XA_ATTR_VALUE, v->current);
 449             }
 450         }
 451     }
 452     return reply;
 453 }
 454 
 455 
 456 
 457 
 458 
 459 
 460 
 461 
 462 
 463 
 464 void
 465 attrd_client_query(pcmk__client_t *client, uint32_t id, uint32_t flags,
     
 466                    xmlNode *query)
 467 {
 468     const char *attr;
 469     const char *origin = crm_element_value(query, F_ORIG);
 470     xmlNode *reply;
 471 
 472     if (origin == NULL) {
 473         origin = "unknown client";
 474     }
 475     crm_debug("Query arrived from %s", origin);
 476 
 477     
 478     attr = crm_element_value(query, PCMK__XA_ATTR_NAME);
 479     if (attr == NULL) {
 480         crm_warn("Ignoring malformed query from %s (no attribute name given)",
 481                  origin);
 482         return;
 483     }
 484 
 485     
 486     reply = build_query_reply(attr, crm_element_value(query,
 487                                                       PCMK__XA_ATTR_NODE_NAME));
 488     if (reply == NULL) {
 489         crm_err("Could not respond to query from %s: could not create XML reply",
 490                  origin);
 491         return;
 492     }
 493     crm_log_xml_trace(reply, "Reply");
 494 
 495     
 496     client->request_id = 0;
 497     {
 498         int rc = pcmk__ipc_send_xml(client, id, reply, flags);
 499 
 500         if (rc != pcmk_rc_ok) {
 501             crm_err("Could not respond to query from %s: %s " CRM_XS " rc=%d",
 502                     origin, pcmk_rc_str(rc), rc);
 503         }
 504     }
 505     free_xml(reply);
 506 }
 507 
 508 
 509 
 510 
 511 
 512 
 513 
 514 
 515 static void
 516 attrd_peer_clear_failure(crm_node_t *peer, xmlNode *xml)
     
 517 {
 518     const char *rsc = crm_element_value(xml, PCMK__XA_ATTR_RESOURCE);
 519     const char *host = crm_element_value(xml, PCMK__XA_ATTR_NODE_NAME);
 520     const char *op = crm_element_value(xml, PCMK__XA_ATTR_OPERATION);
 521     const char *interval_spec = crm_element_value(xml, PCMK__XA_ATTR_INTERVAL);
 522     guint interval_ms = crm_parse_interval_spec(interval_spec);
 523     char *attr = NULL;
 524     GHashTableIter iter;
 525     regex_t regex;
 526 
 527     if (attrd_failure_regex(®ex, rsc, op, interval_ms) != pcmk_ok) {
 528         crm_info("Ignoring invalid request to clear failures for %s",
 529                  (rsc? rsc : "all resources"));
 530         return;
 531     }
 532 
 533     crm_xml_add(xml, PCMK__XA_TASK, PCMK__ATTRD_CMD_UPDATE);
 534 
 535     
 536     if (crm_element_value(xml, PCMK__XA_ATTR_VALUE)) {
 537         crm_xml_replace(xml, PCMK__XA_ATTR_VALUE, NULL);
 538     }
 539 
 540     g_hash_table_iter_init(&iter, attributes);
 541     while (g_hash_table_iter_next(&iter, (gpointer *) &attr, NULL)) {
 542         if (regexec(®ex, attr, 0, NULL, 0) == 0) {
 543             crm_trace("Matched %s when clearing %s",
 544                       attr, (rsc? rsc : "all resources"));
 545             crm_xml_add(xml, PCMK__XA_ATTR_NAME, attr);
 546             attrd_peer_update(peer, xml, host, FALSE);
 547         }
 548     }
 549     regfree(®ex);
 550 }
 551 
 552 
 553 
 554 
 555 
 556 void
 557 attrd_broadcast_protocol()
     
 558 {
 559     xmlNode *attrd_op = create_xml_node(NULL, __func__);
 560 
 561     crm_xml_add(attrd_op, F_TYPE, T_ATTRD);
 562     crm_xml_add(attrd_op, F_ORIG, crm_system_name);
 563     crm_xml_add(attrd_op, PCMK__XA_TASK, PCMK__ATTRD_CMD_UPDATE);
 564     crm_xml_add(attrd_op, PCMK__XA_ATTR_NAME, CRM_ATTR_PROTOCOL);
 565     crm_xml_add(attrd_op, PCMK__XA_ATTR_VALUE, ATTRD_PROTOCOL_VERSION);
 566     crm_xml_add_int(attrd_op, PCMK__XA_ATTR_IS_PRIVATE, 1);
 567     attrd_client_update(attrd_op);
 568     free_xml(attrd_op);
 569 }
 570 
 571 void
 572 attrd_peer_message(crm_node_t *peer, xmlNode *xml)
     
 573 {
 574     const char *op = crm_element_value(xml, PCMK__XA_TASK);
 575     const char *election_op = crm_element_value(xml, F_CRM_TASK);
 576     const char *host = crm_element_value(xml, PCMK__XA_ATTR_NODE_NAME);
 577     bool peer_won = FALSE;
 578 
 579     if (election_op) {
 580         attrd_handle_election_op(peer, xml);
 581         return;
 582     }
 583 
 584     if (attrd_shutting_down()) {
 585         
 586 
 587 
 588 
 589         return;
 590     }
 591 
 592     peer_won = attrd_check_for_new_writer(peer, xml);
 593 
 594     if (pcmk__strcase_any_of(op, PCMK__ATTRD_CMD_UPDATE, PCMK__ATTRD_CMD_UPDATE_BOTH,
 595                              PCMK__ATTRD_CMD_UPDATE_DELAY, NULL)) {
 596         attrd_peer_update(peer, xml, host, FALSE);
 597 
 598     } else if (pcmk__str_eq(op, PCMK__ATTRD_CMD_SYNC, pcmk__str_casei)) {
 599         attrd_peer_sync(peer, xml);
 600 
 601     } else if (pcmk__str_eq(op, PCMK__ATTRD_CMD_PEER_REMOVE, pcmk__str_casei)) {
 602         attrd_peer_remove(host, TRUE, peer->uname);
 603 
 604     } else if (pcmk__str_eq(op, PCMK__ATTRD_CMD_CLEAR_FAILURE, pcmk__str_casei)) {
 605         
 606 
 607 
 608         attrd_peer_clear_failure(peer, xml);
 609 
 610     } else if (pcmk__str_eq(op, PCMK__ATTRD_CMD_SYNC_RESPONSE, pcmk__str_casei)
 611                && !pcmk__str_eq(peer->uname, attrd_cluster->uname, pcmk__str_casei)) {
 612         xmlNode *child = NULL;
 613 
 614         crm_info("Processing %s from %s", op, peer->uname);
 615 
 616         
 617         if (peer_won) {
 618             clear_attribute_value_seen();
 619         }
 620 
 621         for (child = pcmk__xml_first_child(xml); child != NULL;
 622              child = pcmk__xml_next(child)) {
 623             host = crm_element_value(child, PCMK__XA_ATTR_NODE_NAME);
 624             attrd_peer_update(peer, child, host, TRUE);
 625         }
 626 
 627         if (peer_won) {
 628             
 629             attrd_current_only_attribute_update(peer, xml);
 630         }
 631     }
 632 }
 633 
 634 void
 635 attrd_peer_sync(crm_node_t *peer, xmlNode *xml)
     
 636 {
 637     GHashTableIter aIter;
 638     GHashTableIter vIter;
 639 
 640     attribute_t *a = NULL;
 641     attribute_value_t *v = NULL;
 642     xmlNode *sync = create_xml_node(NULL, __func__);
 643 
 644     crm_xml_add(sync, PCMK__XA_TASK, PCMK__ATTRD_CMD_SYNC_RESPONSE);
 645 
 646     g_hash_table_iter_init(&aIter, attributes);
 647     while (g_hash_table_iter_next(&aIter, NULL, (gpointer *) & a)) {
 648         g_hash_table_iter_init(&vIter, a->values);
 649         while (g_hash_table_iter_next(&vIter, NULL, (gpointer *) & v)) {
 650             crm_debug("Syncing %s[%s] = %s to %s", a->id, v->nodename, v->current, peer?peer->uname:"everyone");
 651             build_attribute_xml(sync, a->id, a->set, a->uuid, a->timeout_ms, a->user, a->is_private,
 652                                 v->nodename, v->nodeid, v->current, FALSE);
 653         }
 654     }
 655 
 656     crm_debug("Syncing values to %s", peer?peer->uname:"everyone");
 657     send_attrd_message(peer, sync);
 658     free_xml(sync);
 659 }
 660 
 661 
 662 
 663 
 664 
 665 
 666 
 667 
 668 
 669 void
 670 attrd_peer_remove(const char *host, gboolean uncache, const char *source)
     
 671 {
 672     attribute_t *a = NULL;
 673     GHashTableIter aIter;
 674 
 675     CRM_CHECK(host != NULL, return);
 676     crm_notice("Removing all %s attributes for peer %s", host, source);
 677 
 678     g_hash_table_iter_init(&aIter, attributes);
 679     while (g_hash_table_iter_next(&aIter, NULL, (gpointer *) & a)) {
 680         if(g_hash_table_remove(a->values, host)) {
 681             crm_debug("Removed %s[%s] for peer %s", a->id, host, source);
 682         }
 683     }
 684 
 685     if (uncache) {
 686         crm_remote_peer_cache_remove(host);
 687         reap_crm_member(0, host);
 688     }
 689 }
 690 
 691 
 692 
 693 
 694 
 695 
 696 
 697 
 698 
 699 
 700 
 701 static attribute_value_t *
 702 attrd_lookup_or_create_value(GHashTable *values, const char *host, xmlNode *xml)
     
 703 {
 704     attribute_value_t *v = g_hash_table_lookup(values, host);
 705     int is_remote = 0;
 706 
 707     crm_element_value_int(xml, PCMK__XA_ATTR_IS_REMOTE, &is_remote);
 708     if (is_remote) {
 709         
 710 
 711 
 712         crm_node_t *dup = crm_find_peer(0, host);
 713 
 714         if (dup && (dup->uuid == NULL)) {
 715             reap_crm_member(0, host);
 716         }
 717 
 718         
 719         CRM_ASSERT(crm_remote_peer_get(host) != NULL);
 720     }
 721 
 722     if (v == NULL) {
 723         v = calloc(1, sizeof(attribute_value_t));
 724         CRM_ASSERT(v != NULL);
 725 
 726         v->nodename = strdup(host);
 727         CRM_ASSERT(v->nodename != NULL);
 728 
 729         v->is_remote = is_remote;
 730         g_hash_table_replace(values, v->nodename, v);
 731     }
 732     return(v);
 733 }
 734 
 735 void 
 736 attrd_current_only_attribute_update(crm_node_t *peer, xmlNode *xml)
     
 737 {
 738     GHashTableIter aIter;
 739     GHashTableIter vIter;
 740     attribute_t *a;
 741     attribute_value_t *v = NULL;
 742     xmlNode *sync = create_xml_node(NULL, __func__);
 743     gboolean build = FALSE;    
 744 
 745     crm_xml_add(sync, PCMK__XA_TASK, PCMK__ATTRD_CMD_SYNC_RESPONSE);
 746 
 747     g_hash_table_iter_init(&aIter, attributes);
 748     while (g_hash_table_iter_next(&aIter, NULL, (gpointer *) & a)) {
 749         g_hash_table_iter_init(&vIter, a->values);
 750         while (g_hash_table_iter_next(&vIter, NULL, (gpointer *) & v)) {
 751             if (pcmk__str_eq(v->nodename, attrd_cluster->uname, pcmk__str_casei) && v->seen == FALSE) {
 752                 crm_trace("Syncing %s[%s] = %s to everyone.(from local only attributes)", a->id, v->nodename, v->current);
 753 
 754                 build = TRUE;
 755                 build_attribute_xml(sync, a->id, a->set, a->uuid, a->timeout_ms, a->user, a->is_private,
 756                             v->nodename, v->nodeid, v->current,  (a->timeout_ms && a->timer ? TRUE : FALSE));
 757             } else {
 758                 crm_trace("Local attribute(%s[%s] = %s) was ignore.(another host) : [%s]", a->id, v->nodename, v->current, attrd_cluster->uname);
 759                 continue;
 760             }
 761         }
 762     }
 763 
 764     if (build) {
 765         crm_debug("Syncing values to everyone.(from local only attributes)");
 766         send_attrd_message(NULL, sync);
 767     }
 768     free_xml(sync);
 769 }
 770 
 771 void
 772 attrd_peer_update(crm_node_t *peer, xmlNode *xml, const char *host, bool filter)
     
 773 {
 774     bool update_both = FALSE;
 775     attribute_t *a;
 776     attribute_value_t *v = NULL;
 777     gboolean is_force_write = FALSE;
 778 
 779     const char *op = crm_element_value(xml, PCMK__XA_TASK);
 780     const char *attr = crm_element_value(xml, PCMK__XA_ATTR_NAME);
 781     const char *value = crm_element_value(xml, PCMK__XA_ATTR_VALUE);
 782     crm_element_value_int(xml, PCMK__XA_ATTR_FORCE, &is_force_write);
 783 
 784     if (attr == NULL) {
 785         crm_warn("Could not update attribute: peer did not specify name");
 786         return;
 787     }
 788 
 789     
 790     update_both = pcmk__str_eq(op, PCMK__ATTRD_CMD_UPDATE_BOTH,
 791                                pcmk__str_null_matches | pcmk__str_casei);
 792 
 793     
 794     a = g_hash_table_lookup(attributes, attr);
 795     if (a == NULL) {
 796         if (update_both || pcmk__str_eq(op, PCMK__ATTRD_CMD_UPDATE, pcmk__str_casei)) {
 797             a = create_attribute(xml);
 798         } else {
 799             crm_warn("Could not update %s: attribute not found", attr);
 800             return;
 801         }
 802     }
 803 
 804     
 805     if (update_both || pcmk__str_eq(op, PCMK__ATTRD_CMD_UPDATE_DELAY, pcmk__str_casei)) {
 806         const char *dvalue = crm_element_value(xml, PCMK__XA_ATTR_DAMPENING);
 807         int dampen = 0;
 808 
 809         if (dvalue == NULL) {
 810             crm_warn("Could not update %s: peer did not specify value for delay",
 811                      attr);
 812             return;
 813         }
 814 
 815         dampen = crm_get_msec(dvalue);
 816         if (dampen < 0) {
 817             crm_warn("Could not update %s: invalid delay value %dms (%s)",
 818                      attr, dampen, dvalue);
 819             return;
 820         }
 821 
 822         if (a->timeout_ms != dampen) {
 823             mainloop_timer_del(a->timer);
 824             a->timeout_ms = dampen;
 825             if (dampen > 0) {
 826                 a->timer = mainloop_timer_add(attr, a->timeout_ms, FALSE,
 827                                               attribute_timer_cb, a);
 828                 crm_info("Update attribute %s delay to %dms (%s)",
 829                          attr, dampen, dvalue);
 830             } else {
 831                 a->timer = NULL;
 832                 crm_info("Update attribute %s to remove delay", attr);
 833             }
 834 
 835             
 836 
 837 
 838             write_or_elect_attribute(a);
 839         }
 840 
 841         if (!update_both) {
 842             return;
 843         }
 844     }
 845 
 846     
 847     if (host == NULL) {
 848         GHashTableIter vIter;
 849 
 850         crm_debug("Setting %s for all hosts to %s", attr, value);
 851         xml_remove_prop(xml, PCMK__XA_ATTR_NODE_ID);
 852         g_hash_table_iter_init(&vIter, a->values);
 853         while (g_hash_table_iter_next(&vIter, (gpointer *) & host, NULL)) {
 854             attrd_peer_update(peer, xml, host, filter);
 855         }
 856         return;
 857     }
 858 
 859     
 860 
 861     v = attrd_lookup_or_create_value(a->values, host, xml);
 862 
 863     if (filter && !pcmk__str_eq(v->current, value, pcmk__str_casei)
 864         && pcmk__str_eq(host, attrd_cluster->uname, pcmk__str_casei)) {
 865 
 866         xmlNode *sync = create_xml_node(NULL, __func__);
 867 
 868         crm_notice("%s[%s]: local value '%s' takes priority over '%s' from %s",
 869                    attr, host, v->current, value, peer->uname);
 870 
 871         crm_xml_add(sync, PCMK__XA_TASK, PCMK__ATTRD_CMD_SYNC_RESPONSE);
 872         v = g_hash_table_lookup(a->values, host);
 873         build_attribute_xml(sync, attr, a->set, a->uuid, a->timeout_ms, a->user,
 874                             a->is_private, v->nodename, v->nodeid, v->current, FALSE);
 875 
 876         attrd_xml_add_writer(sync);
 877 
 878         
 879         send_attrd_message(NULL, sync);
 880         free_xml(sync);
 881 
 882     } else if (!pcmk__str_eq(v->current, value, pcmk__str_casei)) {
 883         crm_notice("Setting %s[%s]: %s -> %s " CRM_XS " from %s",
 884                    attr, host, v->current? v->current : "(unset)", value? value : "(unset)", peer->uname);
 885         free(v->current);
 886         v->current = (value? strdup(value) : NULL);
 887         a->changed = TRUE;
 888 
 889         
 890         if (a->timeout_ms && a->timer) {
 891             crm_trace("Delayed write out (%dms) for %s", a->timeout_ms, attr);
 892             mainloop_timer_start(a->timer);
 893         } else {
 894             write_or_elect_attribute(a);
 895         }
 896 
 897     } else {
 898         if (is_force_write && a->timeout_ms && a->timer) {
 899             
 900             
 901             crm_trace("Unchanged %s[%s] from %s is %s(Set the forced write flag)", attr, host, peer->uname, value);
 902             a->force_write = TRUE;
 903         } else {
 904             crm_trace("Unchanged %s[%s] from %s is %s", attr, host, peer->uname, value);
 905         }
 906     }
 907 
 908     
 909     v->seen = TRUE;
 910 
 911     
 912     if ((v->nodeid == 0) && (v->is_remote == FALSE)
 913         && (crm_element_value_int(xml, PCMK__XA_ATTR_NODE_ID,
 914                                   (int*)&v->nodeid) == 0)) {
 915 
 916         crm_node_t *known_peer = crm_get_peer(v->nodeid, host);
 917 
 918         crm_trace("Learned %s has node id %s",
 919                   known_peer->uname, known_peer->uuid);
 920         if (attrd_election_won()) {
 921             write_attributes(FALSE, FALSE);
 922         }
 923     }
 924 }
 925 
 926 void
 927 write_or_elect_attribute(attribute_t *a)
     
 928 {
 929     if (attrd_election_won()) {
 930         write_attribute(a, FALSE);
 931     } else {
 932         attrd_start_election_if_needed();
 933     }
 934 }
 935 
 936 gboolean
 937 attrd_election_cb(gpointer user_data)
     
 938 {
 939     attrd_declare_winner();
 940 
 941     
 942     attrd_peer_sync(NULL, NULL);
 943 
 944     
 945     write_attributes(TRUE, FALSE);
 946     return FALSE;
 947 }
 948 
 949 
 950 void
 951 attrd_peer_change_cb(enum crm_status_type kind, crm_node_t *peer, const void *data)
     
 952 {
 953     bool remove_voter = FALSE;
 954 
 955     switch (kind) {
 956         case crm_status_uname:
 957             break;
 958 
 959         case crm_status_processes:
 960             if (!pcmk_is_set(peer->processes, crm_get_cluster_proc())) {
 961                 remove_voter = TRUE;
 962             }
 963             break;
 964 
 965         case crm_status_nstate:
 966             if (pcmk__str_eq(peer->state, CRM_NODE_MEMBER, pcmk__str_casei)) {
 967                 
 968 
 969 
 970                 if (attrd_election_won()
 971                     && !pcmk_is_set(peer->flags, crm_remote_node)) {
 972                     attrd_peer_sync(peer, NULL);
 973                 }
 974             } else {
 975                 
 976                 attrd_peer_remove(peer->uname, FALSE, "loss");
 977                 remove_voter = TRUE;
 978             }
 979             break;
 980     }
 981 
 982     
 983     if (remove_voter) {
 984         attrd_remove_voter(peer);
 985     }
 986 }
 987 
 988 static void
 989 attrd_cib_callback(xmlNode * msg, int call_id, int rc, xmlNode * output, void *user_data)
     
 990 {
 991     int level = LOG_ERR;
 992     GHashTableIter iter;
 993     const char *peer = NULL;
 994     attribute_value_t *v = NULL;
 995 
 996     char *name = user_data;
 997     attribute_t *a = g_hash_table_lookup(attributes, name);
 998 
 999     if(a == NULL) {
1000         crm_info("Attribute %s no longer exists", name);
1001         return;
1002     }
1003 
1004     a->update = 0;
1005     if (rc == pcmk_ok && call_id < 0) {
1006         rc = call_id;
1007     }
1008 
1009     switch (rc) {
1010         case pcmk_ok:
1011             level = LOG_INFO;
1012             last_cib_op_done = call_id;
1013             if (a->timer && !a->timeout_ms) {
1014                 
1015                 mainloop_timer_del(a->timer);
1016                 a->timer = NULL;
1017             }
1018             break;
1019 
1020         case -pcmk_err_diff_failed:    
1021         case -ETIME:           
1022         case -ENXIO:           
1023 
1024 
1025             level = LOG_WARNING;
1026             break;
1027     }
1028 
1029     do_crm_log(level, "CIB update %d result for %s: %s " CRM_XS " rc=%d",
1030                call_id, a->id, pcmk_strerror(rc), rc);
1031 
1032     g_hash_table_iter_init(&iter, a->values);
1033     while (g_hash_table_iter_next(&iter, (gpointer *) & peer, (gpointer *) & v)) {
1034         do_crm_log(level, "* %s[%s]=%s", a->id, peer, v->requested);
1035         free(v->requested);
1036         v->requested = NULL;
1037         if (rc != pcmk_ok) {
1038             a->changed = TRUE; 
1039         }
1040     }
1041 
1042     if (a->changed && attrd_election_won()) {
1043         if (rc == pcmk_ok) {
1044             
1045 
1046 
1047             write_attribute(a, FALSE);
1048 
1049         
1050 
1051 
1052 
1053 
1054 
1055 
1056 
1057 
1058         } else if (a->timer) {
1059             
1060             if (!mainloop_timer_running(a->timer)) {
1061                 crm_trace("Delayed re-attempted write (%dms) for %s",
1062                           a->timeout_ms, name);
1063                 mainloop_timer_start(a->timer);
1064             }
1065         } else {
1066             
1067 
1068 
1069 
1070             a->timer = mainloop_timer_add(a->id, 2000, FALSE,
1071                                           attribute_timer_cb, a);
1072             mainloop_timer_start(a->timer);
1073         }
1074     }
1075 }
1076 
1077 void
1078 write_attributes(bool all, bool ignore_delay)
     
1079 {
1080     GHashTableIter iter;
1081     attribute_t *a = NULL;
1082 
1083     crm_debug("Writing out %s attributes", all? "all" : "changed");
1084     g_hash_table_iter_init(&iter, attributes);
1085     while (g_hash_table_iter_next(&iter, NULL, (gpointer *) & a)) {
1086         if (!all && a->unknown_peer_uuids) {
1087             
1088             a->changed = TRUE;
1089         } else if (a->force_write) {
1090             
1091             a->changed = TRUE;
1092         }
1093 
1094         if(all || a->changed) {
1095             
1096             write_attribute(a, (a->force_write ? TRUE : ignore_delay));
1097         } else {
1098             crm_trace("Skipping unchanged attribute %s", a->id);
1099         }
1100     }
1101 }
1102 
1103 static void
1104 build_update_element(xmlNode *parent, attribute_t *a, const char *nodeid, const char *value)
     
1105 {
1106     const char *set = NULL;
1107     xmlNode *xml_obj = NULL;
1108 
1109     xml_obj = create_xml_node(parent, XML_CIB_TAG_STATE);
1110     crm_xml_add(xml_obj, XML_ATTR_ID, nodeid);
1111 
1112     xml_obj = create_xml_node(xml_obj, XML_TAG_TRANSIENT_NODEATTRS);
1113     crm_xml_add(xml_obj, XML_ATTR_ID, nodeid);
1114 
1115     xml_obj = create_xml_node(xml_obj, XML_TAG_ATTR_SETS);
1116     if (a->set) {
1117         crm_xml_set_id(xml_obj, "%s", a->set);
1118     } else {
1119         crm_xml_set_id(xml_obj, "%s-%s", XML_CIB_TAG_STATUS, nodeid);
1120     }
1121     set = ID(xml_obj);
1122 
1123     xml_obj = create_xml_node(xml_obj, XML_CIB_TAG_NVPAIR);
1124     if (a->uuid) {
1125         crm_xml_set_id(xml_obj, "%s", a->uuid);
1126     } else {
1127         crm_xml_set_id(xml_obj, "%s-%s", set, a->id);
1128     }
1129     crm_xml_add(xml_obj, XML_NVPAIR_ATTR_NAME, a->id);
1130 
1131     if(value) {
1132         crm_xml_add(xml_obj, XML_NVPAIR_ATTR_VALUE, value);
1133 
1134     } else {
1135         crm_xml_add(xml_obj, XML_NVPAIR_ATTR_VALUE, "");
1136         crm_xml_add(xml_obj, "__delete__", XML_NVPAIR_ATTR_VALUE);
1137     }
1138 }
1139 
1140 static void
1141 set_alert_attribute_value(GHashTable *t, attribute_value_t *v)
     
1142 {
1143     attribute_value_t *a_v = NULL;
1144     a_v = calloc(1, sizeof(attribute_value_t));
1145     CRM_ASSERT(a_v != NULL);
1146 
1147     a_v->nodeid = v->nodeid;
1148     a_v->nodename = strdup(v->nodename);
1149 
1150     if (v->current != NULL) {
1151         a_v->current = strdup(v->current);
1152     }
1153 
1154     g_hash_table_replace(t, a_v->nodename, a_v);
1155 }
1156 
1157 static void
1158 send_alert_attributes_value(attribute_t *a, GHashTable *t)
     
1159 {
1160     int rc = 0;
1161     attribute_value_t *at = NULL;
1162     GHashTableIter vIter;
1163 
1164     g_hash_table_iter_init(&vIter, t);
1165 
1166     while (g_hash_table_iter_next(&vIter, NULL, (gpointer *) & at)) {
1167         rc = attrd_send_attribute_alert(at->nodename, at->nodeid,
1168                                         a->id, at->current);
1169         crm_trace("Sent alerts for %s[%s]=%s: nodeid=%d rc=%d",
1170                   a->id, at->nodename, at->current, at->nodeid, rc);
1171     }
1172 }
1173 
1174 void
1175 write_attribute(attribute_t *a, bool ignore_delay)
     
1176 {
1177     int private_updates = 0, cib_updates = 0;
1178     xmlNode *xml_top = NULL;
1179     attribute_value_t *v = NULL;
1180     GHashTableIter iter;
1181     enum cib_call_options flags = cib_quorum_override;
1182     GHashTable *alert_attribute_value = NULL;
1183 
1184     if (a == NULL) {
1185         return;
1186     }
1187 
1188     
1189     if (!a->is_private) {
1190 
1191         
1192         CRM_CHECK(the_cib != NULL, return);
1193         if (a->update && (a->update < last_cib_op_done)) {
1194             crm_info("Write out of '%s' continuing: update %d considered lost", a->id, a->update);
1195             a->update = 0; 
1196 
1197         } else if (a->update) {
1198             crm_info("Write out of '%s' delayed: update %d in progress", a->id, a->update);
1199             return;
1200 
1201         } else if (mainloop_timer_running(a->timer)) {
1202             if (ignore_delay) {
1203                 
1204 
1205 
1206                 mainloop_timer_stop(a->timer);
1207                 crm_debug("Write out of '%s': timer is running but ignore delay", a->id);
1208             } else {
1209                 crm_info("Write out of '%s' delayed: timer is running", a->id);
1210                 return;
1211             }
1212         }
1213 
1214         
1215         xml_top = create_xml_node(NULL, XML_CIB_TAG_STATUS);
1216     }
1217 
1218     
1219     a->changed = FALSE;
1220 
1221     
1222     a->unknown_peer_uuids = FALSE;
1223 
1224     
1225     a->force_write = FALSE;    
1226 
1227     
1228     alert_attribute_value = g_hash_table_new_full(crm_strcase_hash,
1229                                                   crm_strcase_equal, NULL,
1230                                                   free_attribute_value);
1231 
1232     
1233     g_hash_table_iter_init(&iter, a->values);
1234     while (g_hash_table_iter_next(&iter, NULL, (gpointer *) & v)) {
1235         crm_node_t *peer = crm_get_peer_full(v->nodeid, v->nodename, CRM_GET_PEER_ANY);
1236 
1237         
1238         if (peer == NULL) {
1239             crm_notice("Cannot update %s[%s]=%s because peer not known",
1240                        a->id, v->nodename, v->current);
1241             continue;
1242         }
1243 
1244         
1245         if (peer->id && (v->nodeid == 0)) {
1246             crm_trace("Learned ID %u for node %s", peer->id, v->nodename);
1247             v->nodeid = peer->id;
1248         }
1249 
1250         
1251         if (a->is_private) {
1252             private_updates++;
1253             continue;
1254         }
1255 
1256         
1257         if (peer->uuid == NULL) {
1258             a->unknown_peer_uuids = TRUE;
1259             crm_notice("Cannot update %s[%s]=%s because peer UUID not known "
1260                        "(will retry if learned)",
1261                        a->id, v->nodename, v->current);
1262             continue;
1263         }
1264 
1265         
1266         crm_debug("Updating %s[%s]=%s (peer known as %s, UUID %s, ID %u/%u)",
1267                   a->id, v->nodename, v->current,
1268                   peer->uname, peer->uuid, peer->id, v->nodeid);
1269         build_update_element(xml_top, a, peer->uuid, v->current);
1270         cib_updates++;
1271 
1272         
1273         set_alert_attribute_value(alert_attribute_value, v);
1274 
1275         free(v->requested);
1276         v->requested = NULL;
1277         if (v->current) {
1278             v->requested = strdup(v->current);
1279         } else {
1280             
1281 
1282 
1283             cib__set_call_options(flags, crm_system_name,
1284                                   cib_mixed_update|cib_scope_local);
1285         }
1286     }
1287 
1288     if (private_updates) {
1289         crm_info("Processed %d private change%s for %s, id=%s, set=%s",
1290                  private_updates, pcmk__plural_s(private_updates),
1291                  a->id, (a->uuid? a->uuid : "n/a"), (a->set? a->set : "n/a"));
1292     }
1293     if (cib_updates) {
1294         crm_log_xml_trace(xml_top, __func__);
1295 
1296         a->update = cib_internal_op(the_cib, CIB_OP_MODIFY, NULL, XML_CIB_TAG_STATUS, xml_top, NULL,
1297                                     flags, a->user);
1298 
1299         crm_info("Sent CIB request %d with %d change%s for %s (id %s, set %s)",
1300                  a->update, cib_updates, pcmk__plural_s(cib_updates),
1301                  a->id, (a->uuid? a->uuid : "n/a"), (a->set? a->set : "n/a"));
1302 
1303         the_cib->cmds->register_callback_full(the_cib, a->update,
1304                                               CIB_OP_TIMEOUT_S, FALSE,
1305                                               strdup(a->id),
1306                                               "attrd_cib_callback",
1307                                               attrd_cib_callback, free);
1308         
1309         send_alert_attributes_value(a, alert_attribute_value);
1310     }
1311 
1312     g_hash_table_destroy(alert_attribute_value);
1313     free_xml(xml_top);
1314 }