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