This source file includes following definitions.
- attrd_confirmation
- attrd_peer_message
- attrd_cpg_dispatch
- attrd_cpg_destroy
- broadcast_local_value
- cache_remote_node
- attrd_lookup_or_create_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/msg_xml.h>
23
24 #include "pacemaker-attrd.h"
25
26 static xmlNode *
27 attrd_confirmation(int callid)
28 {
29 xmlNode *node = create_xml_node(NULL, __func__);
30
31 crm_xml_add(node, F_TYPE, T_ATTRD);
32 crm_xml_add(node, F_ORIG, get_local_node_name());
33 crm_xml_add(node, PCMK__XA_TASK, PCMK__ATTRD_CMD_CONFIRM);
34 crm_xml_add_int(node, XML_LRM_ATTR_CALLID, 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, F_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, XML_LRM_ATTR_CALLID, &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_message_common_cs(handle, nodeid, pid, msg, &kind, &from);
110
111 if(data == NULL) {
112 return;
113 }
114
115 if (kind == crm_class_cluster) {
116 xml = string2xml(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 crm_node_t *peer = crm_get_peer(nodeid, from);
123
124 attrd_peer_message(peer, 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
152
153
154
155
156 static attribute_value_t *
157 broadcast_local_value(const attribute_t *a)
158 {
159 attribute_value_t *v = g_hash_table_lookup(a->values, attrd_cluster->uname);
160 xmlNode *sync = create_xml_node(NULL, __func__);
161
162 crm_xml_add(sync, PCMK__XA_TASK, PCMK__ATTRD_CMD_SYNC_RESPONSE);
163 attrd_add_value_xml(sync, a, v, false);
164 attrd_send_message(NULL, sync, false);
165 free_xml(sync);
166 return v;
167 }
168
169
170
171
172
173
174
175 static void
176 cache_remote_node(const char *node_name)
177 {
178
179
180
181 crm_node_t *dup = pcmk__search_cluster_node_cache(0, node_name, NULL);
182
183 if (dup && (dup->uuid == NULL)) {
184 reap_crm_member(0, node_name);
185 }
186
187
188 CRM_ASSERT(crm_remote_peer_get(node_name) != NULL);
189 }
190
191 #define state_text(state) pcmk__s((state), "in unknown state")
192
193
194
195
196
197
198
199
200
201
202
203 static attribute_value_t *
204 attrd_lookup_or_create_value(GHashTable *values, const char *host,
205 const xmlNode *xml)
206 {
207 attribute_value_t *v = g_hash_table_lookup(values, host);
208 int is_remote = 0;
209
210 crm_element_value_int(xml, PCMK__XA_ATTR_IS_REMOTE, &is_remote);
211 if (is_remote) {
212 cache_remote_node(host);
213 }
214
215 if (v == NULL) {
216 v = calloc(1, sizeof(attribute_value_t));
217 CRM_ASSERT(v != NULL);
218
219 pcmk__str_update(&v->nodename, host);
220 v->is_remote = is_remote;
221 g_hash_table_replace(values, v->nodename, v);
222 }
223 return(v);
224 }
225
226 static void
227 attrd_peer_change_cb(enum crm_status_type kind, crm_node_t *peer, const void *data)
228 {
229 bool gone = false;
230 bool is_remote = pcmk_is_set(peer->flags, crm_remote_node);
231
232 switch (kind) {
233 case crm_status_uname:
234 crm_debug("%s node %s is now %s",
235 (is_remote? "Remote" : "Cluster"),
236 peer->uname, state_text(peer->state));
237 break;
238
239 case crm_status_processes:
240 if (!pcmk_is_set(peer->processes, crm_get_cluster_proc())) {
241 gone = true;
242 }
243 crm_debug("Node %s is %s a peer",
244 peer->uname, (gone? "no longer" : "now"));
245 break;
246
247 case crm_status_nstate:
248 crm_debug("%s node %s is now %s (was %s)",
249 (is_remote? "Remote" : "Cluster"),
250 peer->uname, state_text(peer->state), state_text(data));
251 if (pcmk__str_eq(peer->state, CRM_NODE_MEMBER, pcmk__str_casei)) {
252
253
254
255 if (attrd_election_won()
256 && !pcmk_is_set(peer->flags, crm_remote_node)) {
257 attrd_peer_sync(peer, NULL);
258 }
259 } else {
260
261 attrd_peer_remove(peer->uname, false, "loss");
262 gone = true;
263 }
264 break;
265 }
266
267
268 if (gone && !is_remote) {
269 attrd_remove_voter(peer);
270 attrd_remove_peer_protocol_ver(peer->uname);
271 attrd_do_not_expect_from_peer(peer->uname);
272
273
274 } else if (!gone && is_remote) {
275 cache_remote_node(peer->uname);
276 }
277 }
278
279 static void
280 record_peer_nodeid(attribute_value_t *v, const char *host)
281 {
282 crm_node_t *known_peer = crm_get_peer(v->nodeid, host);
283
284 crm_trace("Learned %s has node id %s", known_peer->uname, known_peer->uuid);
285 if (attrd_election_won()) {
286 attrd_write_attributes(attrd_write_changed);
287 }
288 }
289
290 static void
291 update_attr_on_host(attribute_t *a, const crm_node_t *peer, const xmlNode *xml,
292 const char *attr, const char *value, const char *host,
293 bool filter, int is_force_write)
294 {
295 attribute_value_t *v = NULL;
296
297 v = attrd_lookup_or_create_value(a->values, host, xml);
298
299 if (filter && !pcmk__str_eq(v->current, value, pcmk__str_casei)
300 && pcmk__str_eq(host, attrd_cluster->uname, pcmk__str_casei)) {
301
302 crm_notice("%s[%s]: local value '%s' takes priority over '%s' from %s",
303 attr, host, v->current, value, peer->uname);
304 v = broadcast_local_value(a);
305
306 } else if (!pcmk__str_eq(v->current, value, pcmk__str_casei)) {
307 crm_notice("Setting %s[%s]%s%s: %s -> %s "
308 CRM_XS " from %s with %s write delay",
309 attr, host, a->set_type ? " in " : "",
310 pcmk__s(a->set_type, ""), pcmk__s(v->current, "(unset)"),
311 pcmk__s(value, "(unset)"), peer->uname,
312 (a->timeout_ms == 0)? "no" : pcmk__readable_interval(a->timeout_ms));
313 pcmk__str_update(&v->current, value);
314 a->changed = true;
315
316 if (pcmk__str_eq(host, attrd_cluster->uname, pcmk__str_casei)
317 && pcmk__str_eq(attr, XML_CIB_ATTR_SHUTDOWN, pcmk__str_none)) {
318
319 if (!pcmk__str_eq(value, "0", pcmk__str_null_matches)) {
320 attrd_set_requesting_shutdown();
321
322 } else {
323 attrd_clear_requesting_shutdown();
324 }
325 }
326
327
328 if (a->timeout_ms && a->timer) {
329 crm_trace("Delayed write out (%dms) for %s", a->timeout_ms, attr);
330 mainloop_timer_start(a->timer);
331 } else {
332 attrd_write_or_elect_attribute(a);
333 }
334
335 } else {
336 if (is_force_write == 1 && a->timeout_ms && a->timer) {
337
338
339 crm_trace("Unchanged %s[%s] from %s is %s(Set the forced write flag)",
340 attr, host, peer->uname, value);
341 a->force_write = TRUE;
342 } else {
343 crm_trace("Unchanged %s[%s] from %s is %s", attr, host, peer->uname, value);
344 }
345 }
346
347
348 v->seen = TRUE;
349
350
351 if ((v->nodeid == 0) && (v->is_remote == FALSE)
352 && (crm_element_value_int(xml, PCMK__XA_ATTR_NODE_ID,
353 (int*)&v->nodeid) == 0) && (v->nodeid > 0)) {
354 record_peer_nodeid(v, host);
355 }
356 }
357
358 static void
359 attrd_peer_update_one(const crm_node_t *peer, xmlNode *xml, bool filter)
360 {
361 attribute_t *a = NULL;
362 const char *attr = crm_element_value(xml, PCMK__XA_ATTR_NAME);
363 const char *value = crm_element_value(xml, PCMK__XA_ATTR_VALUE);
364 const char *host = crm_element_value(xml, PCMK__XA_ATTR_NODE_NAME);
365 int is_force_write = 0;
366
367 if (attr == NULL) {
368 crm_warn("Could not update attribute: peer did not specify name");
369 return;
370 }
371
372 crm_element_value_int(xml, PCMK__XA_ATTR_FORCE, &is_force_write);
373
374 a = attrd_populate_attribute(xml, attr);
375 if (a == NULL) {
376 return;
377 }
378
379 if (host == NULL) {
380
381 GHashTableIter vIter;
382
383 crm_debug("Setting %s for all hosts to %s", attr, value);
384 xml_remove_prop(xml, PCMK__XA_ATTR_NODE_ID);
385 g_hash_table_iter_init(&vIter, a->values);
386
387 while (g_hash_table_iter_next(&vIter, (gpointer *) & host, NULL)) {
388 update_attr_on_host(a, peer, xml, attr, value, host, filter, is_force_write);
389 }
390
391 } else {
392
393 update_attr_on_host(a, peer, xml, attr, value, host, filter, is_force_write);
394 }
395
396
397
398
399 if (pcmk__str_eq(attr, CRM_ATTR_PROTOCOL, pcmk__str_none)) {
400 attrd_update_minimum_protocol_ver(peer->uname, value);
401 }
402 }
403
404 static void
405 broadcast_unseen_local_values(void)
406 {
407 GHashTableIter aIter;
408 GHashTableIter vIter;
409 attribute_t *a = NULL;
410 attribute_value_t *v = NULL;
411 xmlNode *sync = NULL;
412
413 g_hash_table_iter_init(&aIter, attributes);
414 while (g_hash_table_iter_next(&aIter, NULL, (gpointer *) & a)) {
415 g_hash_table_iter_init(&vIter, a->values);
416 while (g_hash_table_iter_next(&vIter, NULL, (gpointer *) & v)) {
417 if (!(v->seen) && pcmk__str_eq(v->nodename, attrd_cluster->uname,
418 pcmk__str_casei)) {
419 if (sync == NULL) {
420 sync = create_xml_node(NULL, __func__);
421 crm_xml_add(sync, PCMK__XA_TASK, PCMK__ATTRD_CMD_SYNC_RESPONSE);
422 }
423 attrd_add_value_xml(sync, a, v, a->timeout_ms && a->timer);
424 }
425 }
426 }
427
428 if (sync != NULL) {
429 crm_debug("Broadcasting local-only values");
430 attrd_send_message(NULL, sync, false);
431 free_xml(sync);
432 }
433 }
434
435 int
436 attrd_cluster_connect(void)
437 {
438 attrd_cluster = pcmk_cluster_new();
439
440 attrd_cluster->destroy = attrd_cpg_destroy;
441 attrd_cluster->cpg.cpg_deliver_fn = attrd_cpg_dispatch;
442 attrd_cluster->cpg.cpg_confchg_fn = pcmk_cpg_membership;
443
444 crm_set_status_callback(&attrd_peer_change_cb);
445
446 if (crm_cluster_connect(attrd_cluster) == FALSE) {
447 crm_err("Cluster connection failed");
448 return -ENOTCONN;
449 }
450 return pcmk_ok;
451 }
452
453 void
454 attrd_peer_clear_failure(pcmk__request_t *request)
455 {
456 xmlNode *xml = request->xml;
457 const char *rsc = crm_element_value(xml, PCMK__XA_ATTR_RESOURCE);
458 const char *host = crm_element_value(xml, PCMK__XA_ATTR_NODE_NAME);
459 const char *op = crm_element_value(xml, PCMK__XA_ATTR_OPERATION);
460 const char *interval_spec = crm_element_value(xml, PCMK__XA_ATTR_INTERVAL);
461 guint interval_ms = crm_parse_interval_spec(interval_spec);
462 char *attr = NULL;
463 GHashTableIter iter;
464 regex_t regex;
465
466 crm_node_t *peer = crm_get_peer(0, request->peer);
467
468 if (attrd_failure_regex(®ex, rsc, op, interval_ms) != pcmk_ok) {
469 crm_info("Ignoring invalid request to clear failures for %s",
470 pcmk__s(rsc, "all resources"));
471 return;
472 }
473
474 crm_xml_add(xml, PCMK__XA_TASK, PCMK__ATTRD_CMD_UPDATE);
475
476
477 xml_remove_prop(xml, PCMK__XA_ATTR_VALUE);
478
479 g_hash_table_iter_init(&iter, attributes);
480 while (g_hash_table_iter_next(&iter, (gpointer *) &attr, NULL)) {
481 if (regexec(®ex, attr, 0, NULL, 0) == 0) {
482 crm_trace("Matched %s when clearing %s",
483 attr, pcmk__s(rsc, "all resources"));
484 crm_xml_add(xml, PCMK__XA_ATTR_NAME, attr);
485 attrd_peer_update(peer, xml, host, false);
486 }
487 }
488 regfree(®ex);
489 }
490
491
492
493
494
495
496
497
498
499 void
500 attrd_peer_sync_response(const crm_node_t *peer, bool peer_won, xmlNode *xml)
501 {
502 crm_info("Processing " PCMK__ATTRD_CMD_SYNC_RESPONSE " from %s",
503 peer->uname);
504
505 if (peer_won) {
506
507
508
509 attrd_clear_value_seen();
510 }
511
512
513 for (xmlNode *child = pcmk__xml_first_child(xml); child != NULL;
514 child = pcmk__xml_next(child)) {
515 attrd_peer_update(peer, child,
516 crm_element_value(child, PCMK__XA_ATTR_NODE_NAME),
517 true);
518 }
519
520 if (peer_won) {
521
522
523
524 broadcast_unseen_local_values();
525 }
526 }
527
528
529
530
531
532
533
534
535
536 void
537 attrd_peer_remove(const char *host, bool uncache, const char *source)
538 {
539 attribute_t *a = NULL;
540 GHashTableIter aIter;
541
542 CRM_CHECK(host != NULL, return);
543 crm_notice("Removing all %s attributes for peer %s", host, source);
544
545 g_hash_table_iter_init(&aIter, attributes);
546 while (g_hash_table_iter_next(&aIter, NULL, (gpointer *) & a)) {
547 if(g_hash_table_remove(a->values, host)) {
548 crm_debug("Removed %s[%s] for peer %s", a->id, host, source);
549 }
550 }
551
552 if (uncache) {
553 crm_remote_peer_cache_remove(host);
554 reap_crm_member(0, host);
555 }
556 }
557
558 void
559 attrd_peer_sync(crm_node_t *peer, xmlNode *xml)
560 {
561 GHashTableIter aIter;
562 GHashTableIter vIter;
563
564 attribute_t *a = NULL;
565 attribute_value_t *v = NULL;
566 xmlNode *sync = create_xml_node(NULL, __func__);
567
568 crm_xml_add(sync, PCMK__XA_TASK, PCMK__ATTRD_CMD_SYNC_RESPONSE);
569
570 g_hash_table_iter_init(&aIter, attributes);
571 while (g_hash_table_iter_next(&aIter, NULL, (gpointer *) & a)) {
572 g_hash_table_iter_init(&vIter, a->values);
573 while (g_hash_table_iter_next(&vIter, NULL, (gpointer *) & v)) {
574 crm_debug("Syncing %s[%s] = %s to %s", a->id, v->nodename, v->current, peer?peer->uname:"everyone");
575 attrd_add_value_xml(sync, a, v, false);
576 }
577 }
578
579 crm_debug("Syncing values to %s", peer?peer->uname:"everyone");
580 attrd_send_message(peer, sync, false);
581 free_xml(sync);
582 }
583
584 void
585 attrd_peer_update(const crm_node_t *peer, xmlNode *xml, const char *host,
586 bool filter)
587 {
588 bool handle_sync_point = false;
589
590 CRM_CHECK((peer != NULL) && (xml != NULL), return);
591 if (xml->children != NULL) {
592 for (xmlNode *child = first_named_child(xml, XML_ATTR_OP); child != NULL;
593 child = crm_next_same_xml(child)) {
594 attrd_copy_xml_attributes(xml, child);
595 attrd_peer_update_one(peer, child, filter);
596
597 if (attrd_request_has_sync_point(child)) {
598 handle_sync_point = true;
599 }
600 }
601
602 } else {
603 attrd_peer_update_one(peer, xml, filter);
604
605 if (attrd_request_has_sync_point(xml)) {
606 handle_sync_point = true;
607 }
608 }
609
610
611
612
613 if (handle_sync_point) {
614 crm_trace("Hit local sync point for attribute update");
615 attrd_ack_waitlist_clients(attrd_sync_point_local, xml);
616 }
617 }