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 }