This source file includes following definitions.
- attrd_confirmation
- attrd_peer_message
- attrd_cpg_dispatch
- attrd_cpg_destroy
- attrd_broadcast_value
- attrd_peer_change_cb
- update_attr_on_host
- attrd_peer_update_one
- broadcast_unseen_local_values
- attrd_cluster_connect
- attrd_peer_clear_failure
- attrd_peer_sync_response
- attrd_peer_remove
- attrd_peer_sync
- attrd_peer_update
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 <stdint.h>
15 #include <stdlib.h>
16
17 #include <crm/cluster.h>
18 #include <crm/cluster/internal.h>
19 #include <crm/common/logging.h>
20 #include <crm/common/results.h>
21 #include <crm/common/strings_internal.h>
22 #include <crm/common/xml.h>
23
24 #include "pacemaker-attrd.h"
25
26 static xmlNode *
27 attrd_confirmation(int callid)
28 {
29 xmlNode *node = pcmk__xe_create(NULL, __func__);
30
31 crm_xml_add(node, PCMK__XA_T, PCMK__VALUE_ATTRD);
32 crm_xml_add(node, PCMK__XA_SRC, pcmk__cluster_local_node_name());
33 crm_xml_add(node, PCMK_XA_TASK, PCMK__ATTRD_CMD_CONFIRM);
34 crm_xml_add_int(node, PCMK__XA_CALL_ID, callid);
35
36 return node;
37 }
38
39 static void
40 attrd_peer_message(pcmk__node_status_t *peer, xmlNode *xml)
41 {
42 const char *election_op = crm_element_value(xml, PCMK__XA_CRM_TASK);
43
44 if (election_op) {
45 attrd_handle_election_op(peer, xml);
46 return;
47 }
48
49 if (attrd_shutting_down(false)) {
50
51
52
53
54 return;
55
56 } else {
57 pcmk__request_t request = {
58 .ipc_client = NULL,
59 .ipc_id = 0,
60 .ipc_flags = 0,
61 .peer = peer->name,
62 .xml = xml,
63 .call_options = 0,
64 .result = PCMK__UNKNOWN_RESULT,
65 };
66
67 request.op = crm_element_value_copy(request.xml, PCMK_XA_TASK);
68 CRM_CHECK(request.op != NULL, return);
69
70 attrd_handle_request(&request);
71
72
73
74
75 if (pcmk__xe_attr_is_true(xml, PCMK__XA_CONFIRM) &&
76 !pcmk__str_eq(request.op, PCMK__ATTRD_CMD_CONFIRM, pcmk__str_none)) {
77 int callid = 0;
78 xmlNode *reply = NULL;
79
80
81
82
83
84 crm_element_value_int(xml, PCMK__XA_CALL_ID, &callid);
85 reply = attrd_confirmation(callid);
86
87
88
89
90
91
92 crm_debug("Sending %s a confirmation", peer->name);
93 attrd_send_message(peer, reply, false);
94 pcmk__xml_free(reply);
95 }
96
97 pcmk__reset_request(&request);
98 }
99 }
100
101 static void
102 attrd_cpg_dispatch(cpg_handle_t handle,
103 const struct cpg_name *groupName,
104 uint32_t nodeid, uint32_t pid, void *msg, size_t msg_len)
105 {
106 xmlNode *xml = NULL;
107 const char *from = NULL;
108 char *data = pcmk__cpg_message_data(handle, nodeid, pid, msg, &from);
109
110 if(data == NULL) {
111 return;
112 }
113
114 xml = pcmk__xml_parse(data);
115
116 if (xml == NULL) {
117 crm_err("Bad message received from %s[%" PRIu32 "]: '%.120s'",
118 from, nodeid, data);
119 } else {
120 attrd_peer_message(pcmk__get_node(nodeid, from, NULL,
121 pcmk__node_search_cluster_member),
122 xml);
123 }
124
125 pcmk__xml_free(xml);
126 free(data);
127 }
128
129 static void
130 attrd_cpg_destroy(gpointer unused)
131 {
132 if (attrd_shutting_down(false)) {
133 crm_info("Disconnected from Corosync process group");
134
135 } else {
136 crm_crit("Lost connection to Corosync process group, shutting down");
137 attrd_exit_status = CRM_EX_DISCONNECT;
138 attrd_shutdown(0);
139 }
140 }
141
142
143
144
145
146
147
148
149 void
150 attrd_broadcast_value(const attribute_t *a, const attribute_value_t *v)
151 {
152 xmlNode *op = pcmk__xe_create(NULL, PCMK_XE_OP);
153
154 crm_xml_add(op, PCMK_XA_TASK, PCMK__ATTRD_CMD_UPDATE);
155 attrd_add_value_xml(op, a, v, false);
156 attrd_send_message(NULL, op, false);
157 pcmk__xml_free(op);
158 }
159
160 #define state_text(state) pcmk__s((state), "in unknown state")
161
162 static void
163 attrd_peer_change_cb(enum pcmk__node_update kind, pcmk__node_status_t *peer,
164 const void *data)
165 {
166 bool gone = false;
167 bool is_remote = pcmk_is_set(peer->flags, pcmk__node_status_remote);
168
169 switch (kind) {
170 case pcmk__node_update_name:
171 crm_debug("%s node %s[%" PRIu32 "] is now %s",
172 (is_remote? "Remote" : "Cluster"),
173 pcmk__s(peer->name, "unknown"), peer->cluster_layer_id,
174 state_text(peer->state));
175 break;
176
177 case pcmk__node_update_processes:
178 if (!pcmk_is_set(peer->processes, crm_get_cluster_proc())) {
179 gone = true;
180 }
181 crm_debug("Node %s[%" PRIu32 "] is %s a peer",
182 pcmk__s(peer->name, "unknown"), peer->cluster_layer_id,
183 (gone? "no longer" : "now"));
184 break;
185
186 case pcmk__node_update_state:
187 crm_debug("%s node %s[%" PRIu32 "] is now %s (was %s)",
188 (is_remote? "Remote" : "Cluster"),
189 pcmk__s(peer->name, "unknown"), peer->cluster_layer_id,
190 state_text(peer->state), state_text(data));
191 if (pcmk__str_eq(peer->state, PCMK_VALUE_MEMBER, pcmk__str_none)) {
192
193
194
195 if (!is_remote) {
196 if (attrd_election_won()) {
197 attrd_peer_sync(peer);
198
199 } else {
200
201 attrd_send_protocol(peer);
202 }
203 }
204
205 } else {
206
207 if (peer->name != NULL) {
208 attrd_peer_remove(peer->name, false, "loss");
209 }
210 gone = true;
211 }
212 break;
213 }
214
215
216 if (gone && !is_remote && peer->name != NULL) {
217 attrd_remove_voter(peer);
218 attrd_remove_peer_protocol_ver(peer->name);
219 attrd_do_not_expect_from_peer(peer->name);
220 }
221 }
222
223 #define readable_value(rv_v) pcmk__s((rv_v)->current, "(unset)")
224
225 #define readable_peer(p) \
226 (((p) == NULL)? "all peers" : pcmk__s((p)->name, "unknown peer"))
227
228 static void
229 update_attr_on_host(attribute_t *a, const pcmk__node_status_t *peer,
230 const xmlNode *xml, const char *attr, const char *value,
231 const char *host, bool filter)
232 {
233 int is_remote = 0;
234 bool changed = false;
235 attribute_value_t *v = NULL;
236 const char *prev_xml_id = NULL;
237 const char *node_xml_id = crm_element_value(xml, PCMK__XA_ATTR_HOST_ID);
238
239
240 v = g_hash_table_lookup(a->values, host);
241 if (v == NULL) {
242 v = pcmk__assert_alloc(1, sizeof(attribute_value_t));
243
244 v->nodename = pcmk__str_copy(host);
245 g_hash_table_replace(a->values, v->nodename, v);
246 }
247
248
249
250
251 prev_xml_id = attrd_get_node_xml_id(v->nodename);
252 if (node_xml_id == NULL) {
253 node_xml_id = prev_xml_id;
254 }
255
256
257 crm_element_value_int(xml, PCMK__XA_ATTR_IS_REMOTE, &is_remote);
258 if (is_remote) {
259 attrd_set_value_flags(v, attrd_value_remote);
260 pcmk__assert(pcmk__cluster_lookup_remote_node(host) != NULL);
261 }
262
263
264 changed = !pcmk__str_eq(v->current, value, pcmk__str_casei);
265
266 if (changed && filter
267 && pcmk__str_eq(host, attrd_cluster->priv->node_name,
268 pcmk__str_casei)) {
269
270
271
272
273
274 v = g_hash_table_lookup(a->values, attrd_cluster->priv->node_name);
275 crm_notice("%s[%s]: local value '%s' takes priority over '%s' from %s",
276 attr, host, readable_value(v), value, peer->name);
277 attrd_broadcast_value(a, v);
278
279 } else if (changed) {
280 crm_notice("Setting %s[%s]%s%s: %s -> %s "
281 QB_XS " from %s with %s write delay and node XML ID %s",
282 attr, host, a->set_type ? " in " : "",
283 pcmk__s(a->set_type, ""), readable_value(v),
284 pcmk__s(value, "(unset)"), peer->name,
285 (a->timeout_ms == 0)? "no" : pcmk__readable_interval(a->timeout_ms),
286 pcmk__s(node_xml_id, "unknown"));
287 pcmk__str_update(&v->current, value);
288 attrd_set_attr_flags(a, attrd_attr_changed);
289
290 if (pcmk__str_eq(host, attrd_cluster->priv->node_name, pcmk__str_casei)
291 && pcmk__str_eq(attr, PCMK__NODE_ATTR_SHUTDOWN, pcmk__str_none)) {
292
293 if (!pcmk__str_eq(value, "0", pcmk__str_null_matches)) {
294 attrd_set_requesting_shutdown();
295
296 } else {
297 attrd_clear_requesting_shutdown();
298 }
299 }
300
301
302 if (a->timeout_ms && a->timer) {
303 crm_trace("Delaying write of %s %s for dampening",
304 attr, pcmk__readable_interval(a->timeout_ms));
305 mainloop_timer_start(a->timer);
306 } else {
307 attrd_write_or_elect_attribute(a);
308 }
309
310 } else {
311 int is_force_write = 0;
312
313 crm_element_value_int(xml, PCMK__XA_ATTRD_IS_FORCE_WRITE,
314 &is_force_write);
315
316 if (is_force_write == 1 && a->timeout_ms && a->timer) {
317
318
319 crm_trace("%s[%s] from %s is unchanged (%s), forcing write",
320 attr, host, peer->name, pcmk__s(value, "unset"));
321 attrd_set_attr_flags(a, attrd_attr_force_write);
322 } else {
323 crm_trace("%s[%s] from %s is unchanged (%s)",
324 attr, host, peer->name, pcmk__s(value, "unset"));
325 }
326 }
327
328
329 attrd_set_value_flags(v, attrd_value_from_peer);
330
331
332 if ((node_xml_id != NULL)
333 && !pcmk__str_eq(node_xml_id, prev_xml_id, pcmk__str_none)) {
334
335 pcmk__node_status_t *known_peer =
336 pcmk__get_node(0, host, node_xml_id,
337 pcmk__node_search_cluster_member);
338
339 crm_trace("Learned %s[%s] node XML ID is %s (was %s)",
340 a->id, known_peer->name, node_xml_id,
341 pcmk__s(prev_xml_id, "unknown"));
342 attrd_set_node_xml_id(v->nodename, node_xml_id);
343 if (attrd_election_won()) {
344
345 attrd_write_attributes(attrd_write_changed);
346 }
347 }
348 }
349
350 static void
351 attrd_peer_update_one(const pcmk__node_status_t *peer, xmlNode *xml,
352 bool filter)
353 {
354 attribute_t *a = NULL;
355 const char *attr = crm_element_value(xml, PCMK__XA_ATTR_NAME);
356 const char *value = crm_element_value(xml, PCMK__XA_ATTR_VALUE);
357 const char *host = crm_element_value(xml, PCMK__XA_ATTR_HOST);
358
359 if (attr == NULL) {
360 crm_warn("Could not update attribute: peer did not specify name");
361 return;
362 }
363
364 a = attrd_populate_attribute(xml, attr);
365 if (a == NULL) {
366 return;
367 }
368
369 if (host == NULL) {
370
371 GHashTableIter vIter;
372
373 crm_debug("Setting %s for all hosts to %s", attr, value);
374 pcmk__xe_remove_attr(xml, PCMK__XA_ATTR_HOST_ID);
375 g_hash_table_iter_init(&vIter, a->values);
376
377 while (g_hash_table_iter_next(&vIter, (gpointer *) & host, NULL)) {
378 update_attr_on_host(a, peer, xml, attr, value, host, filter);
379 }
380
381 } else {
382
383 update_attr_on_host(a, peer, xml, attr, value, host, filter);
384 }
385
386
387
388
389 if (pcmk__str_eq(attr, CRM_ATTR_PROTOCOL, pcmk__str_none)) {
390 attrd_update_minimum_protocol_ver(peer->name, value);
391 }
392 }
393
394 static void
395 broadcast_unseen_local_values(void)
396 {
397 GHashTableIter aIter;
398 GHashTableIter vIter;
399 attribute_t *a = NULL;
400 attribute_value_t *v = NULL;
401 xmlNode *sync = NULL;
402
403 g_hash_table_iter_init(&aIter, attributes);
404 while (g_hash_table_iter_next(&aIter, NULL, (gpointer *) & a)) {
405
406 g_hash_table_iter_init(&vIter, a->values);
407 while (g_hash_table_iter_next(&vIter, NULL, (gpointer *) & v)) {
408
409 if (!pcmk_is_set(v->flags, attrd_value_from_peer)
410 && pcmk__str_eq(v->nodename, attrd_cluster->priv->node_name,
411 pcmk__str_casei)) {
412 crm_trace("* %s[%s]='%s' is local-only",
413 a->id, v->nodename, readable_value(v));
414 if (sync == NULL) {
415 sync = pcmk__xe_create(NULL, __func__);
416 crm_xml_add(sync, PCMK_XA_TASK, PCMK__ATTRD_CMD_SYNC_RESPONSE);
417 }
418 attrd_add_value_xml(sync, a, v, a->timeout_ms && a->timer);
419 }
420 }
421 }
422
423 if (sync != NULL) {
424 crm_debug("Broadcasting local-only values");
425 attrd_send_message(NULL, sync, false);
426 pcmk__xml_free(sync);
427 }
428 }
429
430 int
431 attrd_cluster_connect(void)
432 {
433 int rc = pcmk_rc_ok;
434
435 attrd_cluster = pcmk_cluster_new();
436
437 pcmk_cluster_set_destroy_fn(attrd_cluster, attrd_cpg_destroy);
438 pcmk_cpg_set_deliver_fn(attrd_cluster, attrd_cpg_dispatch);
439 pcmk_cpg_set_confchg_fn(attrd_cluster, pcmk__cpg_confchg_cb);
440
441 pcmk__cluster_set_status_callback(&attrd_peer_change_cb);
442
443 rc = pcmk_cluster_connect(attrd_cluster);
444 rc = pcmk_rc2legacy(rc);
445 if (rc != pcmk_ok) {
446 crm_err("Cluster connection failed");
447 return rc;
448 }
449 return pcmk_ok;
450 }
451
452 void
453 attrd_peer_clear_failure(pcmk__request_t *request)
454 {
455 xmlNode *xml = request->xml;
456 const char *rsc = crm_element_value(xml, PCMK__XA_ATTR_RESOURCE);
457 const char *host = crm_element_value(xml, PCMK__XA_ATTR_HOST);
458 const char *op = crm_element_value(xml, PCMK__XA_ATTR_CLEAR_OPERATION);
459 const char *interval_spec = crm_element_value(xml,
460 PCMK__XA_ATTR_CLEAR_INTERVAL);
461 guint interval_ms = 0U;
462 char *attr = NULL;
463 GHashTableIter iter;
464 regex_t regex;
465
466 pcmk__node_status_t *peer =
467 pcmk__get_node(0, request->peer, NULL,
468 pcmk__node_search_cluster_member);
469
470 pcmk_parse_interval_spec(interval_spec, &interval_ms);
471
472 if (attrd_failure_regex(®ex, rsc, op, interval_ms) != pcmk_ok) {
473 crm_info("Ignoring invalid request to clear failures for %s",
474 pcmk__s(rsc, "all resources"));
475 return;
476 }
477
478 crm_xml_add(xml, PCMK_XA_TASK, PCMK__ATTRD_CMD_UPDATE);
479
480
481 pcmk__xe_remove_attr(xml, PCMK__XA_ATTR_VALUE);
482
483 g_hash_table_iter_init(&iter, attributes);
484 while (g_hash_table_iter_next(&iter, (gpointer *) &attr, NULL)) {
485 if (regexec(®ex, attr, 0, NULL, 0) == 0) {
486 crm_trace("Matched %s when clearing %s",
487 attr, pcmk__s(rsc, "all resources"));
488 crm_xml_add(xml, PCMK__XA_ATTR_NAME, attr);
489 attrd_peer_update(peer, xml, host, false);
490 }
491 }
492 regfree(®ex);
493 }
494
495
496
497
498
499
500
501
502
503 void
504 attrd_peer_sync_response(const pcmk__node_status_t *peer, bool peer_won,
505 xmlNode *xml)
506 {
507 crm_info("Processing " PCMK__ATTRD_CMD_SYNC_RESPONSE " from %s",
508 peer->name);
509
510 if (peer_won) {
511
512
513
514 attrd_clear_value_seen();
515 }
516
517
518 for (xmlNode *child = pcmk__xe_first_child(xml, NULL, NULL, NULL);
519 child != NULL; child = pcmk__xe_next(child, NULL)) {
520
521 attrd_peer_update(peer, child,
522 crm_element_value(child, PCMK__XA_ATTR_HOST), true);
523 }
524
525 if (peer_won) {
526
527
528
529 broadcast_unseen_local_values();
530 }
531 }
532
533
534
535
536
537
538
539
540
541 void
542 attrd_peer_remove(const char *host, bool uncache, const char *source)
543 {
544 attribute_t *a = NULL;
545 GHashTableIter aIter;
546
547 CRM_CHECK(host != NULL, return);
548 crm_notice("Removing all %s attributes for node %s "
549 QB_XS " %s reaping node from cache",
550 host, source, (uncache? "and" : "without"));
551
552 g_hash_table_iter_init(&aIter, attributes);
553 while (g_hash_table_iter_next(&aIter, NULL, (gpointer *) & a)) {
554 if(g_hash_table_remove(a->values, host)) {
555 crm_debug("Removed %s[%s] for peer %s", a->id, host, source);
556 }
557 }
558
559 if (uncache) {
560 pcmk__purge_node_from_cache(host, 0);
561 attrd_forget_node_xml_id(host);
562 }
563 }
564
565
566
567
568
569
570
571 void
572 attrd_peer_sync(pcmk__node_status_t *peer)
573 {
574 GHashTableIter aIter;
575 GHashTableIter vIter;
576
577 attribute_t *a = NULL;
578 attribute_value_t *v = NULL;
579 xmlNode *sync = pcmk__xe_create(NULL, __func__);
580
581 crm_xml_add(sync, PCMK_XA_TASK, PCMK__ATTRD_CMD_SYNC_RESPONSE);
582
583 g_hash_table_iter_init(&aIter, attributes);
584 while (g_hash_table_iter_next(&aIter, NULL, (gpointer *) & a)) {
585 g_hash_table_iter_init(&vIter, a->values);
586 while (g_hash_table_iter_next(&vIter, NULL, (gpointer *) & v)) {
587 crm_debug("Syncing %s[%s]='%s' to %s",
588 a->id, v->nodename, readable_value(v),
589 readable_peer(peer));
590 attrd_add_value_xml(sync, a, v, false);
591 }
592 }
593
594 crm_debug("Syncing values to %s", readable_peer(peer));
595 attrd_send_message(peer, sync, false);
596 pcmk__xml_free(sync);
597 }
598
599 void
600 attrd_peer_update(const pcmk__node_status_t *peer, xmlNode *xml,
601 const char *host, bool filter)
602 {
603 bool handle_sync_point = false;
604
605 CRM_CHECK((peer != NULL) && (xml != NULL), return);
606 if (xml->children != NULL) {
607 for (xmlNode *child = pcmk__xe_first_child(xml, PCMK_XE_OP, NULL, NULL);
608 child != NULL; child = pcmk__xe_next(child, PCMK_XE_OP)) {
609
610 pcmk__xe_copy_attrs(child, xml, pcmk__xaf_no_overwrite);
611 attrd_peer_update_one(peer, child, filter);
612
613 if (attrd_request_has_sync_point(child)) {
614 handle_sync_point = true;
615 }
616 }
617
618 } else {
619 attrd_peer_update_one(peer, xml, filter);
620
621 if (attrd_request_has_sync_point(xml)) {
622 handle_sync_point = true;
623 }
624 }
625
626
627
628
629 if (handle_sync_point) {
630 crm_trace("Hit local sync point for attribute update");
631 attrd_ack_waitlist_clients(attrd_sync_point_local, xml);
632 }
633 }