This source file includes following definitions.
- attrd_confirmation
- attrd_peer_message
- attrd_cpg_dispatch
- attrd_cpg_destroy
- attrd_broadcast_value
- attrd_peer_change_cb
- record_peer_nodeid
- 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(crm_node_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->uname,
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->uname);
93 attrd_send_message(peer, reply, false);
94 free_xml(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 uint32_t kind = 0;
107 xmlNode *xml = NULL;
108 const char *from = NULL;
109 char *data = pcmk__cpg_message_data(handle, nodeid, pid, msg, &kind, &from);
110
111 if(data == NULL) {
112 return;
113 }
114
115 if (kind == crm_class_cluster) {
116 xml = pcmk__xml_parse(data);
117 }
118
119 if (xml == NULL) {
120 crm_err("Bad message of class %d received from %s[%u]: '%.120s'", kind, from, nodeid, data);
121 } else {
122 attrd_peer_message(pcmk__get_node(nodeid, from, NULL,
123 pcmk__node_search_cluster_member),
124 xml);
125 }
126
127 free_xml(xml);
128 free(data);
129 }
130
131 static void
132 attrd_cpg_destroy(gpointer unused)
133 {
134 if (attrd_shutting_down(false)) {
135 crm_info("Disconnected from Corosync process group");
136
137 } else {
138 crm_crit("Lost connection to Corosync process group, shutting down");
139 attrd_exit_status = CRM_EX_DISCONNECT;
140 attrd_shutdown(0);
141 }
142 }
143
144
145
146
147
148
149
150
151 void
152 attrd_broadcast_value(const attribute_t *a, const attribute_value_t *v)
153 {
154 xmlNode *op = pcmk__xe_create(NULL, PCMK_XE_OP);
155
156 crm_xml_add(op, PCMK_XA_TASK, PCMK__ATTRD_CMD_UPDATE);
157 attrd_add_value_xml(op, a, v, false);
158 attrd_send_message(NULL, op, false);
159 free_xml(op);
160 }
161
162 #define state_text(state) pcmk__s((state), "in unknown state")
163
164 static void
165 attrd_peer_change_cb(enum crm_status_type kind, crm_node_t *peer, const void *data)
166 {
167 bool gone = false;
168 bool is_remote = pcmk_is_set(peer->flags, crm_remote_node);
169
170 switch (kind) {
171 case crm_status_uname:
172 crm_debug("%s node %s is now %s",
173 (is_remote? "Remote" : "Cluster"),
174 peer->uname, state_text(peer->state));
175 break;
176
177 case crm_status_processes:
178 if (!pcmk_is_set(peer->processes, crm_get_cluster_proc())) {
179 gone = true;
180 }
181 crm_debug("Node %s is %s a peer",
182 peer->uname, (gone? "no longer" : "now"));
183 break;
184
185 case crm_status_nstate:
186 crm_debug("%s node %s is now %s (was %s)",
187 (is_remote? "Remote" : "Cluster"),
188 peer->uname, state_text(peer->state), state_text(data));
189 if (pcmk__str_eq(peer->state, CRM_NODE_MEMBER, pcmk__str_casei)) {
190
191
192
193 if (attrd_election_won()
194 && !pcmk_is_set(peer->flags, crm_remote_node)) {
195 attrd_peer_sync(peer);
196 }
197 } else {
198
199 attrd_peer_remove(peer->uname, false, "loss");
200 gone = true;
201 }
202 break;
203 }
204
205
206 if (gone && !is_remote) {
207 attrd_remove_voter(peer);
208 attrd_remove_peer_protocol_ver(peer->uname);
209 attrd_do_not_expect_from_peer(peer->uname);
210 }
211 }
212
213 static void
214 record_peer_nodeid(attribute_value_t *v, const char *host)
215 {
216 crm_node_t *known_peer = pcmk__get_node(v->nodeid, host, NULL,
217 pcmk__node_search_cluster_member);
218
219 crm_trace("Learned %s has node id %s", known_peer->uname, known_peer->uuid);
220 if (attrd_election_won()) {
221 attrd_write_attributes(attrd_write_changed);
222 }
223 }
224
225 #define readable_value(rv_v) pcmk__s((rv_v)->current, "(unset)")
226
227 #define readable_peer(p) \
228 (((p) == NULL)? "all peers" : pcmk__s((p)->uname, "unknown peer"))
229
230 static void
231 update_attr_on_host(attribute_t *a, const crm_node_t *peer, const xmlNode *xml,
232 const char *attr, const char *value, const char *host,
233 bool filter)
234 {
235 int is_remote = 0;
236 bool changed = false;
237 attribute_value_t *v = NULL;
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 crm_element_value_int(xml, PCMK__XA_ATTR_IS_REMOTE, &is_remote);
250 if (is_remote) {
251 attrd_set_value_flags(v, attrd_value_remote);
252 pcmk__assert(pcmk__cluster_lookup_remote_node(host) != NULL);
253 }
254
255
256 changed = !pcmk__str_eq(v->current, value, pcmk__str_casei);
257
258 if (changed && filter && pcmk__str_eq(host, attrd_cluster->uname,
259 pcmk__str_casei)) {
260
261
262
263
264
265 v = g_hash_table_lookup(a->values, attrd_cluster->uname);
266 crm_notice("%s[%s]: local value '%s' takes priority over '%s' from %s",
267 attr, host, readable_value(v), value, peer->uname);
268 attrd_broadcast_value(a, v);
269
270 } else if (changed) {
271 crm_notice("Setting %s[%s]%s%s: %s -> %s "
272 CRM_XS " from %s with %s write delay",
273 attr, host, a->set_type ? " in " : "",
274 pcmk__s(a->set_type, ""), readable_value(v),
275 pcmk__s(value, "(unset)"), peer->uname,
276 (a->timeout_ms == 0)? "no" : pcmk__readable_interval(a->timeout_ms));
277 pcmk__str_update(&v->current, value);
278 attrd_set_attr_flags(a, attrd_attr_changed);
279
280 if (pcmk__str_eq(host, attrd_cluster->uname, pcmk__str_casei)
281 && pcmk__str_eq(attr, PCMK__NODE_ATTR_SHUTDOWN, pcmk__str_none)) {
282
283 if (!pcmk__str_eq(value, "0", pcmk__str_null_matches)) {
284 attrd_set_requesting_shutdown();
285
286 } else {
287 attrd_clear_requesting_shutdown();
288 }
289 }
290
291
292 if (a->timeout_ms && a->timer) {
293 crm_trace("Delaying write of %s %s for dampening",
294 attr, pcmk__readable_interval(a->timeout_ms));
295 mainloop_timer_start(a->timer);
296 } else {
297 attrd_write_or_elect_attribute(a);
298 }
299
300 } else {
301 int is_force_write = 0;
302
303 crm_element_value_int(xml, PCMK__XA_ATTRD_IS_FORCE_WRITE,
304 &is_force_write);
305
306 if (is_force_write == 1 && a->timeout_ms && a->timer) {
307
308
309 crm_trace("%s[%s] from %s is unchanged (%s), forcing write",
310 attr, host, peer->uname, pcmk__s(value, "unset"));
311 attrd_set_attr_flags(a, attrd_attr_force_write);
312 } else {
313 crm_trace("%s[%s] from %s is unchanged (%s)",
314 attr, host, peer->uname, pcmk__s(value, "unset"));
315 }
316 }
317
318
319 attrd_set_value_flags(v, attrd_value_from_peer);
320
321
322 if ((v->nodeid == 0) && !pcmk_is_set(v->flags, attrd_value_remote)
323 && (crm_element_value_int(xml, PCMK__XA_ATTR_HOST_ID,
324 (int*)&v->nodeid) == 0) && (v->nodeid > 0)) {
325 record_peer_nodeid(v, host);
326 }
327 }
328
329 static void
330 attrd_peer_update_one(const crm_node_t *peer, xmlNode *xml, bool filter)
331 {
332 attribute_t *a = NULL;
333 const char *attr = crm_element_value(xml, PCMK__XA_ATTR_NAME);
334 const char *value = crm_element_value(xml, PCMK__XA_ATTR_VALUE);
335 const char *host = crm_element_value(xml, PCMK__XA_ATTR_HOST);
336
337 if (attr == NULL) {
338 crm_warn("Could not update attribute: peer did not specify name");
339 return;
340 }
341
342 a = attrd_populate_attribute(xml, attr);
343 if (a == NULL) {
344 return;
345 }
346
347 if (host == NULL) {
348
349 GHashTableIter vIter;
350
351 crm_debug("Setting %s for all hosts to %s", attr, value);
352 pcmk__xe_remove_attr(xml, PCMK__XA_ATTR_HOST_ID);
353 g_hash_table_iter_init(&vIter, a->values);
354
355 while (g_hash_table_iter_next(&vIter, (gpointer *) & host, NULL)) {
356 update_attr_on_host(a, peer, xml, attr, value, host, filter);
357 }
358
359 } else {
360
361 update_attr_on_host(a, peer, xml, attr, value, host, filter);
362 }
363
364
365
366
367 if (pcmk__str_eq(attr, CRM_ATTR_PROTOCOL, pcmk__str_none)) {
368 attrd_update_minimum_protocol_ver(peer->uname, value);
369 }
370 }
371
372 static void
373 broadcast_unseen_local_values(void)
374 {
375 GHashTableIter aIter;
376 GHashTableIter vIter;
377 attribute_t *a = NULL;
378 attribute_value_t *v = NULL;
379 xmlNode *sync = NULL;
380
381 g_hash_table_iter_init(&aIter, attributes);
382 while (g_hash_table_iter_next(&aIter, NULL, (gpointer *) & a)) {
383
384 g_hash_table_iter_init(&vIter, a->values);
385 while (g_hash_table_iter_next(&vIter, NULL, (gpointer *) & v)) {
386
387 if (!pcmk_is_set(v->flags, attrd_value_from_peer)
388 && pcmk__str_eq(v->nodename, attrd_cluster->uname,
389 pcmk__str_casei)) {
390 crm_trace("* %s[%s]='%s' is local-only",
391 a->id, v->nodename, readable_value(v));
392 if (sync == NULL) {
393 sync = pcmk__xe_create(NULL, __func__);
394 crm_xml_add(sync, PCMK_XA_TASK, PCMK__ATTRD_CMD_SYNC_RESPONSE);
395 }
396 attrd_add_value_xml(sync, a, v, a->timeout_ms && a->timer);
397 }
398 }
399 }
400
401 if (sync != NULL) {
402 crm_debug("Broadcasting local-only values");
403 attrd_send_message(NULL, sync, false);
404 free_xml(sync);
405 }
406 }
407
408 int
409 attrd_cluster_connect(void)
410 {
411 int rc = pcmk_rc_ok;
412
413 attrd_cluster = pcmk_cluster_new();
414
415 pcmk_cluster_set_destroy_fn(attrd_cluster, attrd_cpg_destroy);
416 pcmk_cpg_set_deliver_fn(attrd_cluster, attrd_cpg_dispatch);
417 pcmk_cpg_set_confchg_fn(attrd_cluster, pcmk__cpg_confchg_cb);
418
419 pcmk__cluster_set_status_callback(&attrd_peer_change_cb);
420
421 rc = pcmk_cluster_connect(attrd_cluster);
422 rc = pcmk_rc2legacy(rc);
423 if (rc != pcmk_ok) {
424 crm_err("Cluster connection failed");
425 return rc;
426 }
427 return pcmk_ok;
428 }
429
430 void
431 attrd_peer_clear_failure(pcmk__request_t *request)
432 {
433 xmlNode *xml = request->xml;
434 const char *rsc = crm_element_value(xml, PCMK__XA_ATTR_RESOURCE);
435 const char *host = crm_element_value(xml, PCMK__XA_ATTR_HOST);
436 const char *op = crm_element_value(xml, PCMK__XA_ATTR_CLEAR_OPERATION);
437 const char *interval_spec = crm_element_value(xml,
438 PCMK__XA_ATTR_CLEAR_INTERVAL);
439 guint interval_ms = 0U;
440 char *attr = NULL;
441 GHashTableIter iter;
442 regex_t regex;
443
444 crm_node_t *peer = pcmk__get_node(0, request->peer, NULL,
445 pcmk__node_search_cluster_member);
446
447 pcmk_parse_interval_spec(interval_spec, &interval_ms);
448
449 if (attrd_failure_regex(®ex, rsc, op, interval_ms) != pcmk_ok) {
450 crm_info("Ignoring invalid request to clear failures for %s",
451 pcmk__s(rsc, "all resources"));
452 return;
453 }
454
455 crm_xml_add(xml, PCMK_XA_TASK, PCMK__ATTRD_CMD_UPDATE);
456
457
458 pcmk__xe_remove_attr(xml, PCMK__XA_ATTR_VALUE);
459
460 g_hash_table_iter_init(&iter, attributes);
461 while (g_hash_table_iter_next(&iter, (gpointer *) &attr, NULL)) {
462 if (regexec(®ex, attr, 0, NULL, 0) == 0) {
463 crm_trace("Matched %s when clearing %s",
464 attr, pcmk__s(rsc, "all resources"));
465 crm_xml_add(xml, PCMK__XA_ATTR_NAME, attr);
466 attrd_peer_update(peer, xml, host, false);
467 }
468 }
469 regfree(®ex);
470 }
471
472
473
474
475
476
477
478
479
480 void
481 attrd_peer_sync_response(const crm_node_t *peer, bool peer_won, xmlNode *xml)
482 {
483 crm_info("Processing " PCMK__ATTRD_CMD_SYNC_RESPONSE " from %s",
484 peer->uname);
485
486 if (peer_won) {
487
488
489
490 attrd_clear_value_seen();
491 }
492
493
494 for (xmlNode *child = pcmk__xe_first_child(xml, NULL, NULL, NULL);
495 child != NULL; child = pcmk__xe_next(child)) {
496
497 attrd_peer_update(peer, child,
498 crm_element_value(child, PCMK__XA_ATTR_HOST), true);
499 }
500
501 if (peer_won) {
502
503
504
505 broadcast_unseen_local_values();
506 }
507 }
508
509
510
511
512
513
514
515
516
517 void
518 attrd_peer_remove(const char *host, bool uncache, const char *source)
519 {
520 attribute_t *a = NULL;
521 GHashTableIter aIter;
522
523 CRM_CHECK(host != NULL, return);
524 crm_notice("Removing all %s attributes for node %s "
525 CRM_XS " %s reaping node from cache",
526 host, source, (uncache? "and" : "without"));
527
528 g_hash_table_iter_init(&aIter, attributes);
529 while (g_hash_table_iter_next(&aIter, NULL, (gpointer *) & a)) {
530 if(g_hash_table_remove(a->values, host)) {
531 crm_debug("Removed %s[%s] for peer %s", a->id, host, source);
532 }
533 }
534
535 if (uncache) {
536 pcmk__purge_node_from_cache(host, 0);
537 }
538 }
539
540
541
542
543
544
545
546 void
547 attrd_peer_sync(crm_node_t *peer)
548 {
549 GHashTableIter aIter;
550 GHashTableIter vIter;
551
552 attribute_t *a = NULL;
553 attribute_value_t *v = NULL;
554 xmlNode *sync = pcmk__xe_create(NULL, __func__);
555
556 crm_xml_add(sync, PCMK_XA_TASK, PCMK__ATTRD_CMD_SYNC_RESPONSE);
557
558 g_hash_table_iter_init(&aIter, attributes);
559 while (g_hash_table_iter_next(&aIter, NULL, (gpointer *) & a)) {
560 g_hash_table_iter_init(&vIter, a->values);
561 while (g_hash_table_iter_next(&vIter, NULL, (gpointer *) & v)) {
562 crm_debug("Syncing %s[%s]='%s' to %s",
563 a->id, v->nodename, readable_value(v),
564 readable_peer(peer));
565 attrd_add_value_xml(sync, a, v, false);
566 }
567 }
568
569 crm_debug("Syncing values to %s", readable_peer(peer));
570 attrd_send_message(peer, sync, false);
571 free_xml(sync);
572 }
573
574 void
575 attrd_peer_update(const crm_node_t *peer, xmlNode *xml, const char *host,
576 bool filter)
577 {
578 bool handle_sync_point = false;
579
580 CRM_CHECK((peer != NULL) && (xml != NULL), return);
581 if (xml->children != NULL) {
582 for (xmlNode *child = pcmk__xe_first_child(xml, PCMK_XE_OP, NULL, NULL);
583 child != NULL; child = pcmk__xe_next_same(child)) {
584
585 pcmk__xe_copy_attrs(child, xml, pcmk__xaf_no_overwrite);
586 attrd_peer_update_one(peer, child, filter);
587
588 if (attrd_request_has_sync_point(child)) {
589 handle_sync_point = true;
590 }
591 }
592
593 } else {
594 attrd_peer_update_one(peer, xml, filter);
595
596 if (attrd_request_has_sync_point(xml)) {
597 handle_sync_point = true;
598 }
599 }
600
601
602
603
604 if (handle_sync_point) {
605 crm_trace("Hit local sync point for attribute update");
606 attrd_ack_waitlist_clients(attrd_sync_point_local, xml);
607 }
608 }