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