This source file includes following definitions.
- attrd_cib_destroy_cb
- attrd_cib_updated_cb
- attrd_cib_connect
- attrd_cib_disconnect
- attrd_erase_cb
- attrd_cib_erase_transient_attrs
- attrd_cib_init
- attribute_timer_cb
- attrd_cib_callback
- add_set_attr_update
- add_unset_attr_update
- add_attr_update
- send_alert_attributes_value
- set_alert_attribute_value
- attrd_add_timer
- write_attribute
- attrd_write_attributes
- attrd_write_or_elect_attribute
1
2
3
4
5
6
7
8
9
10 #include <crm_internal.h>
11
12 #include <errno.h>
13 #include <stdbool.h>
14 #include <stdlib.h>
15 #include <glib.h>
16
17 #include <crm/cib/internal.h>
18 #include <crm/common/logging.h>
19 #include <crm/common/results.h>
20 #include <crm/common/strings_internal.h>
21 #include <crm/common/xml.h>
22 #include <crm/cluster/internal.h>
23
24 #include "pacemaker-attrd.h"
25
26 static int last_cib_op_done = 0;
27
28 static void write_attribute(attribute_t *a, bool ignore_delay);
29
30 static void
31 attrd_cib_destroy_cb(gpointer user_data)
32 {
33 cib_t *cib = user_data;
34
35 cib->cmds->signoff(cib);
36
37 if (attrd_shutting_down(false)) {
38 crm_info("Disconnected from the CIB manager");
39
40 } else {
41
42 crm_crit("Lost connection to the CIB manager, shutting down");
43 attrd_exit_status = CRM_EX_DISCONNECT;
44 attrd_shutdown(0);
45 }
46 }
47
48 static void
49 attrd_cib_updated_cb(const char *event, xmlNode *msg)
50 {
51 const xmlNode *patchset = NULL;
52 const char *client_name = NULL;
53 bool status_changed = false;
54
55 if (cib__get_notify_patchset(msg, &patchset) != pcmk_rc_ok) {
56 return;
57 }
58
59 if (pcmk__cib_element_in_patchset(patchset, PCMK_XE_ALERTS)) {
60 if (attrd_shutting_down(true)) {
61 crm_debug("Ignoring alerts change in CIB during shutdown");
62 } else {
63 mainloop_set_trigger(attrd_config_read);
64 }
65 }
66
67 status_changed = pcmk__cib_element_in_patchset(patchset, PCMK_XE_STATUS);
68
69 client_name = crm_element_value(msg, PCMK__XA_CIB_CLIENTNAME);
70 if (!cib__client_triggers_refresh(client_name)) {
71
72
73
74 return;
75 }
76
77 if (!attrd_election_won()) {
78
79 return;
80 }
81
82 if (status_changed
83 || pcmk__cib_element_in_patchset(patchset, PCMK_XE_NODES)) {
84
85 if (attrd_shutting_down(true)) {
86 crm_debug("Ignoring node change in CIB during shutdown");
87 return;
88 }
89
90
91
92
93
94 if (client_name == NULL) {
95 client_name = crm_element_value(msg, PCMK__XA_CIB_CLIENTID);
96 }
97 crm_notice("Updating all attributes after %s event triggered by %s",
98 event, pcmk__s(client_name, "unidentified client"));
99
100 attrd_write_attributes(attrd_write_all);
101 }
102 }
103
104 int
105 attrd_cib_connect(int max_retry)
106 {
107 static int attempts = 0;
108
109 int rc = -ENOTCONN;
110
111 the_cib = cib_new();
112 if (the_cib == NULL) {
113 return -ENOTCONN;
114 }
115
116 do {
117 if (attempts > 0) {
118 sleep(attempts);
119 }
120 attempts++;
121 crm_debug("Connection attempt %d to the CIB manager", attempts);
122 rc = the_cib->cmds->signon(the_cib, crm_system_name, cib_command);
123
124 } while ((rc != pcmk_ok) && (attempts < max_retry));
125
126 if (rc != pcmk_ok) {
127 crm_err("Connection to the CIB manager failed: %s " QB_XS " rc=%d",
128 pcmk_strerror(rc), rc);
129 goto cleanup;
130 }
131
132 crm_debug("Connected to the CIB manager after %d attempts", attempts);
133
134 rc = the_cib->cmds->set_connection_dnotify(the_cib, attrd_cib_destroy_cb);
135 if (rc != pcmk_ok) {
136 crm_err("Could not set disconnection callback");
137 goto cleanup;
138 }
139
140 rc = the_cib->cmds->add_notify_callback(the_cib,
141 PCMK__VALUE_CIB_DIFF_NOTIFY,
142 attrd_cib_updated_cb);
143 if (rc != pcmk_ok) {
144 crm_err("Could not set CIB notification callback");
145 goto cleanup;
146 }
147
148 return pcmk_ok;
149
150 cleanup:
151 cib__clean_up_connection(&the_cib);
152 return -ENOTCONN;
153 }
154
155 void
156 attrd_cib_disconnect(void)
157 {
158 CRM_CHECK(the_cib != NULL, return);
159 the_cib->cmds->del_notify_callback(the_cib, PCMK__VALUE_CIB_DIFF_NOTIFY,
160 attrd_cib_updated_cb);
161 cib__clean_up_connection(&the_cib);
162 mainloop_destroy_trigger(attrd_config_read);
163 }
164
165 static void
166 attrd_erase_cb(xmlNode *msg, int call_id, int rc, xmlNode *output,
167 void *user_data)
168 {
169 const char *node = pcmk__s((const char *) user_data, "a node");
170
171 if (rc == pcmk_ok) {
172 crm_info("Cleared transient node attributes for %s from CIB", node);
173 } else {
174 crm_err("Unable to clear transient node attributes for %s from CIB: %s",
175 node, pcmk_strerror(rc));
176 }
177 }
178
179 #define XPATH_TRANSIENT "//" PCMK__XE_NODE_STATE \
180 "[@" PCMK_XA_UNAME "='%s']" \
181 "/" PCMK__XE_TRANSIENT_ATTRIBUTES
182
183
184
185
186
187
188
189 void
190 attrd_cib_erase_transient_attrs(const char *node)
191 {
192 int call_id = 0;
193 char *xpath = NULL;
194
195 CRM_CHECK(node != NULL, return);
196
197 xpath = crm_strdup_printf(XPATH_TRANSIENT, node);
198
199 crm_debug("Clearing transient node attributes for %s from CIB using %s",
200 node, xpath);
201
202 call_id = the_cib->cmds->remove(the_cib, xpath, NULL, cib_xpath);
203 free(xpath);
204
205 the_cib->cmds->register_callback_full(the_cib, call_id, 120, FALSE,
206 pcmk__str_copy(node),
207 "attrd_erase_cb", attrd_erase_cb,
208 free);
209 }
210
211
212
213
214
215 void
216 attrd_cib_init(void)
217 {
218
219
220
221
222
223
224
225
226
227
228 attrd_cib_erase_transient_attrs(attrd_cluster->priv->node_name);
229
230
231 attrd_config_read = mainloop_add_trigger(G_PRIORITY_HIGH, attrd_read_options, NULL);
232
233
234 mainloop_set_trigger(attrd_config_read);
235 }
236
237 static gboolean
238 attribute_timer_cb(gpointer data)
239 {
240 attribute_t *a = data;
241 crm_trace("Dampen interval expired for %s", a->id);
242 attrd_write_or_elect_attribute(a);
243 return FALSE;
244 }
245
246 static void
247 attrd_cib_callback(xmlNode *msg, int call_id, int rc, xmlNode *output, void *user_data)
248 {
249 int level = LOG_ERR;
250 GHashTableIter iter;
251 const char *peer = NULL;
252 attribute_value_t *v = NULL;
253
254 char *name = user_data;
255 attribute_t *a = g_hash_table_lookup(attributes, name);
256
257 if(a == NULL) {
258 crm_info("Attribute %s no longer exists", name);
259 return;
260 }
261
262 a->update = 0;
263 if (rc == pcmk_ok && call_id < 0) {
264 rc = call_id;
265 }
266
267 switch (rc) {
268 case pcmk_ok:
269 level = LOG_INFO;
270 last_cib_op_done = call_id;
271 if (a->timer && !a->timeout_ms) {
272
273 mainloop_timer_del(a->timer);
274 a->timer = NULL;
275 }
276 break;
277
278 case -pcmk_err_diff_failed:
279 case -ETIME:
280 case -ENXIO:
281
282
283 level = LOG_WARNING;
284 break;
285 }
286
287 do_crm_log(level, "CIB update %d result for %s: %s " QB_XS " rc=%d",
288 call_id, a->id, pcmk_strerror(rc), rc);
289
290 g_hash_table_iter_init(&iter, a->values);
291 while (g_hash_table_iter_next(&iter, (gpointer *) & peer, (gpointer *) & v)) {
292 if (rc == pcmk_ok) {
293 crm_info("* Wrote %s[%s]=%s",
294 a->id, peer, pcmk__s(v->requested, "(unset)"));
295 pcmk__str_update(&(v->requested), NULL);
296 } else {
297 do_crm_log(level, "* Could not write %s[%s]=%s",
298 a->id, peer, pcmk__s(v->requested, "(unset)"));
299
300 attrd_set_attr_flags(a, attrd_attr_changed);
301 }
302 }
303
304 if (pcmk_is_set(a->flags, attrd_attr_changed) && attrd_election_won()) {
305 if (rc == pcmk_ok) {
306
307
308
309 crm_debug("Pending update for %s can be written now", a->id);
310 write_attribute(a, false);
311
312
313
314
315
316
317
318
319
320
321 } else if (a->timer) {
322
323 if (!mainloop_timer_running(a->timer)) {
324 crm_trace("Delayed re-attempted write for %s by %s",
325 name, pcmk__readable_interval(a->timeout_ms));
326 mainloop_timer_start(a->timer);
327 }
328 } else {
329
330
331
332
333 a->timer = attrd_add_timer(a->id, 2000, a);
334 mainloop_timer_start(a->timer);
335 }
336 }
337 }
338
339
340
341
342
343
344
345
346
347
348
349
350
351 static int
352 add_set_attr_update(const attribute_t *attr, const char *attr_id,
353 const char *node_id, const char *set_id, const char *value)
354 {
355 xmlNode *update = pcmk__xe_create(NULL, PCMK__XE_NODE_STATE);
356 xmlNode *child = update;
357 int rc = ENOMEM;
358
359 crm_xml_add(child, PCMK_XA_ID, node_id);
360
361 child = pcmk__xe_create(child, PCMK__XE_TRANSIENT_ATTRIBUTES);
362 crm_xml_add(child, PCMK_XA_ID, node_id);
363
364 child = pcmk__xe_create(child, attr->set_type);
365 crm_xml_add(child, PCMK_XA_ID, set_id);
366
367 child = pcmk__xe_create(child, PCMK_XE_NVPAIR);
368 crm_xml_add(child, PCMK_XA_ID, attr_id);
369 crm_xml_add(child, PCMK_XA_NAME, attr->id);
370 crm_xml_add(child, PCMK_XA_VALUE, value);
371
372 rc = the_cib->cmds->modify(the_cib, PCMK_XE_STATUS, update,
373 cib_can_create|cib_transaction);
374 rc = pcmk_legacy2rc(rc);
375
376 pcmk__xml_free(update);
377 return rc;
378 }
379
380
381
382
383
384
385
386
387
388
389
390
391 static int
392 add_unset_attr_update(const attribute_t *attr, const char *attr_id,
393 const char *node_id, const char *set_id)
394 {
395 char *xpath = crm_strdup_printf("/" PCMK_XE_CIB
396 "/" PCMK_XE_STATUS
397 "/" PCMK__XE_NODE_STATE
398 "[@" PCMK_XA_ID "='%s']"
399 "/" PCMK__XE_TRANSIENT_ATTRIBUTES
400 "[@" PCMK_XA_ID "='%s']"
401 "/%s[@" PCMK_XA_ID "='%s']"
402 "/" PCMK_XE_NVPAIR
403 "[@" PCMK_XA_ID "='%s' "
404 "and @" PCMK_XA_NAME "='%s']",
405 node_id, node_id, attr->set_type, set_id,
406 attr_id, attr->id);
407
408 int rc = the_cib->cmds->remove(the_cib, xpath, NULL,
409 cib_xpath|cib_transaction);
410
411 free(xpath);
412 return pcmk_legacy2rc(rc);
413 }
414
415
416
417
418
419
420
421
422
423
424
425 static int
426 add_attr_update(const attribute_t *attr, const char *value, const char *node_id)
427 {
428 char *set_id = attrd_set_id(attr, node_id);
429 char *nvpair_id = attrd_nvpair_id(attr, node_id);
430 int rc = pcmk_rc_ok;
431
432 if (value == NULL) {
433 rc = add_unset_attr_update(attr, nvpair_id, node_id, set_id);
434 } else {
435 rc = add_set_attr_update(attr, nvpair_id, node_id, set_id, value);
436 }
437 free(set_id);
438 free(nvpair_id);
439 return rc;
440 }
441
442 static void
443 send_alert_attributes_value(attribute_t *a, GHashTable *t)
444 {
445 int rc = 0;
446 attribute_value_t *at = NULL;
447 GHashTableIter vIter;
448
449 g_hash_table_iter_init(&vIter, t);
450
451 while (g_hash_table_iter_next(&vIter, NULL, (gpointer *) & at)) {
452 const char *node_xml_id = attrd_get_node_xml_id(at->nodename);
453
454 rc = attrd_send_attribute_alert(at->nodename, node_xml_id,
455 a->id, at->current);
456 crm_trace("Sent alerts for %s[%s]=%s with node XML ID %s "
457 "(%s agents failed)",
458 a->id, at->nodename, at->current,
459 pcmk__s(node_xml_id, "unknown"),
460 ((rc == 0)? "no" : ((rc == -1)? "some" : "all")));
461 }
462 }
463
464 static void
465 set_alert_attribute_value(GHashTable *t, attribute_value_t *v)
466 {
467 attribute_value_t *a_v = pcmk__assert_alloc(1, sizeof(attribute_value_t));
468
469 a_v->nodename = pcmk__str_copy(v->nodename);
470 a_v->current = pcmk__str_copy(v->current);
471
472 g_hash_table_replace(t, a_v->nodename, a_v);
473 }
474
475 mainloop_timer_t *
476 attrd_add_timer(const char *id, int timeout_ms, attribute_t *attr)
477 {
478 return mainloop_timer_add(id, timeout_ms, FALSE, attribute_timer_cb, attr);
479 }
480
481
482
483
484
485
486
487
488
489 static void
490 write_attribute(attribute_t *a, bool ignore_delay)
491 {
492 int private_updates = 0, cib_updates = 0;
493 attribute_value_t *v = NULL;
494 GHashTableIter iter;
495 GHashTable *alert_attribute_value = NULL;
496 int rc = pcmk_ok;
497 bool should_write = true;
498
499 if (a == NULL) {
500 return;
501 }
502
503
504 if (stand_alone || pcmk_is_set(a->flags, attrd_attr_is_private)) {
505 should_write = false;
506 }
507
508
509 if (should_write) {
510
511 if (a->update && (a->update < last_cib_op_done)) {
512 crm_info("Write out of '%s' continuing: update %d considered lost",
513 a->id, a->update);
514 a->update = 0;
515
516 } else if (a->update) {
517 crm_info("Write out of '%s' delayed: update %d in progress",
518 a->id, a->update);
519 goto done;
520
521 } else if (mainloop_timer_running(a->timer)) {
522 if (ignore_delay) {
523 mainloop_timer_stop(a->timer);
524 crm_debug("Overriding '%s' write delay", a->id);
525 } else {
526 crm_info("Delaying write of '%s'", a->id);
527 goto done;
528 }
529 }
530
531
532 CRM_CHECK(the_cib != NULL, goto done);
533 the_cib->cmds->set_user(the_cib, a->user);
534 rc = the_cib->cmds->init_transaction(the_cib);
535 if (rc != pcmk_ok) {
536 crm_err("Failed to write %s (set %s): Could not initiate "
537 "CIB transaction",
538 a->id, pcmk__s(a->set_id, "unspecified"));
539 goto done;
540 }
541 }
542
543
544
545
546
547 attrd_clear_attr_flags(a, attrd_attr_changed
548 |attrd_attr_force_write
549 |attrd_attr_node_unknown);
550
551
552 alert_attribute_value = pcmk__strikey_table(NULL,
553 attrd_free_attribute_value);
554
555
556 g_hash_table_iter_init(&iter, a->values);
557 while (g_hash_table_iter_next(&iter, NULL, (gpointer *) &v)) {
558 const char *node_xml_id = NULL;
559 const char *prev_xml_id = NULL;
560
561 if (!should_write) {
562 private_updates++;
563 continue;
564 }
565
566
567
568
569
570
571
572 prev_xml_id = attrd_get_node_xml_id(v->nodename);
573
574 if (pcmk_is_set(v->flags, attrd_value_remote)) {
575
576 node_xml_id = v->nodename;
577
578 } else {
579
580 pcmk__node_status_t *peer = pcmk__get_node(0, v->nodename,
581 prev_xml_id,
582 pcmk__node_search_any);
583
584 node_xml_id = pcmk__cluster_get_xml_id(peer);
585 if (node_xml_id == NULL) {
586 node_xml_id = prev_xml_id;
587 }
588 }
589
590
591 if (node_xml_id == NULL) {
592 attrd_set_attr_flags(a, attrd_attr_node_unknown);
593 crm_notice("Cannot write %s[%s]='%s' to CIB because node's XML ID "
594 "is unknown (will retry if learned)",
595 a->id, v->nodename, v->current);
596 continue;
597 }
598
599 if (!pcmk__str_eq(prev_xml_id, node_xml_id, pcmk__str_none)) {
600 crm_trace("Setting %s[%s] node XML ID to %s (was %s)",
601 a->id, v->nodename, node_xml_id,
602 pcmk__s(prev_xml_id, "unknown"));
603 attrd_set_node_xml_id(v->nodename, node_xml_id);
604 }
605
606
607 rc = add_attr_update(a, v->current, node_xml_id);
608 if (rc != pcmk_rc_ok) {
609 crm_err("Couldn't add %s[%s]='%s' to CIB transaction: %s "
610 QB_XS " node XML ID %s",
611 a->id, v->nodename, v->current, pcmk_rc_str(rc),
612 node_xml_id);
613 continue;
614 }
615
616 crm_debug("Added %s[%s]=%s to CIB transaction (node XML ID %s)",
617 a->id, v->nodename, pcmk__s(v->current, "(unset)"),
618 node_xml_id);
619 cib_updates++;
620
621
622 set_alert_attribute_value(alert_attribute_value, v);
623
624
625 pcmk__str_update(&(v->requested), v->current);
626 }
627
628 if (private_updates) {
629 crm_info("Processed %d private change%s for %s (set %s)",
630 private_updates, pcmk__plural_s(private_updates),
631 a->id, pcmk__s(a->set_id, "unspecified"));
632 }
633 if (cib_updates > 0) {
634 char *id = pcmk__str_copy(a->id);
635
636
637 a->update = the_cib->cmds->end_transaction(the_cib, true, cib_none);
638
639 crm_info("Sent CIB request %d with %d change%s for %s (set %s)",
640 a->update, cib_updates, pcmk__plural_s(cib_updates),
641 a->id, pcmk__s(a->set_id, "unspecified"));
642
643 if (the_cib->cmds->register_callback_full(the_cib, a->update,
644 CIB_OP_TIMEOUT_S, FALSE, id,
645 "attrd_cib_callback",
646 attrd_cib_callback, free)) {
647
648 send_alert_attributes_value(a, alert_attribute_value);
649 }
650 }
651
652 done:
653
654 if (the_cib != NULL) {
655 the_cib->cmds->end_transaction(the_cib, false, cib_none);
656 the_cib->cmds->set_user(the_cib, NULL);
657 }
658
659 if (alert_attribute_value != NULL) {
660 g_hash_table_destroy(alert_attribute_value);
661 }
662 }
663
664
665
666
667
668
669
670 void
671 attrd_write_attributes(uint32_t options)
672 {
673 GHashTableIter iter;
674 attribute_t *a = NULL;
675
676 crm_debug("Writing out %s attributes",
677 pcmk_is_set(options, attrd_write_all)? "all" : "changed");
678 g_hash_table_iter_init(&iter, attributes);
679 while (g_hash_table_iter_next(&iter, NULL, (gpointer *) & a)) {
680 if (!pcmk_is_set(options, attrd_write_all)
681 && pcmk_is_set(a->flags, attrd_attr_node_unknown)) {
682
683 attrd_set_attr_flags(a, attrd_attr_changed);
684 } else if (pcmk_is_set(a->flags, attrd_attr_force_write)) {
685
686 attrd_set_attr_flags(a, attrd_attr_changed);
687 }
688
689 if (pcmk_is_set(options, attrd_write_all) ||
690 pcmk_is_set(a->flags, attrd_attr_changed)) {
691 bool ignore_delay = pcmk_is_set(options, attrd_write_no_delay);
692
693 if (pcmk_is_set(a->flags, attrd_attr_force_write)) {
694
695 ignore_delay = true;
696 }
697 write_attribute(a, ignore_delay);
698 } else {
699 crm_trace("Skipping unchanged attribute %s", a->id);
700 }
701 }
702 }
703
704 void
705 attrd_write_or_elect_attribute(attribute_t *a)
706 {
707 if (attrd_election_won()) {
708 write_attribute(a, false);
709 } else {
710 attrd_start_election_if_needed();
711 }
712 }