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 extern crm_exit_t attrd_exit_status;
27
28 static xmlNode *
29 attrd_confirmation(int callid)
30 {
31 xmlNode *node = create_xml_node(NULL, __func__);
32
33 crm_xml_add(node, F_TYPE, T_ATTRD);
34 crm_xml_add(node, F_ORIG, get_local_node_name());
35 crm_xml_add(node, PCMK__XA_TASK, PCMK__ATTRD_CMD_CONFIRM);
36 crm_xml_add_int(node, XML_LRM_ATTR_CALLID, callid);
37
38 return node;
39 }
40
41 static void
42 attrd_peer_message(crm_node_t *peer, xmlNode *xml)
43 {
44 const char *election_op = crm_element_value(xml, F_CRM_TASK);
45
46 if (election_op) {
47 attrd_handle_election_op(peer, xml);
48 return;
49 }
50
51 if (attrd_shutting_down()) {
52
53
54
55
56 return;
57
58 } else {
59 pcmk__request_t request = {
60 .ipc_client = NULL,
61 .ipc_id = 0,
62 .ipc_flags = 0,
63 .peer = peer->uname,
64 .xml = xml,
65 .call_options = 0,
66 .result = PCMK__UNKNOWN_RESULT,
67 };
68
69 request.op = crm_element_value_copy(request.xml, PCMK__XA_TASK);
70 CRM_CHECK(request.op != NULL, return);
71
72 attrd_handle_request(&request);
73
74
75
76
77 if (pcmk__xe_attr_is_true(xml, PCMK__XA_CONFIRM) &&
78 !pcmk__str_eq(request.op, PCMK__ATTRD_CMD_CONFIRM, pcmk__str_none)) {
79 int callid = 0;
80 xmlNode *reply = NULL;
81
82
83
84
85
86 crm_element_value_int(xml, XML_LRM_ATTR_CALLID, &callid);
87 reply = attrd_confirmation(callid);
88
89
90
91
92
93
94 crm_debug("Sending %s a confirmation", peer->uname);
95 attrd_send_message(peer, reply, false);
96 free_xml(reply);
97 }
98
99 pcmk__reset_request(&request);
100 }
101 }
102
103 static void
104 attrd_cpg_dispatch(cpg_handle_t handle,
105 const struct cpg_name *groupName,
106 uint32_t nodeid, uint32_t pid, void *msg, size_t msg_len)
107 {
108 uint32_t kind = 0;
109 xmlNode *xml = NULL;
110 const char *from = NULL;
111 char *data = pcmk_message_common_cs(handle, nodeid, pid, msg, &kind, &from);
112
113 if(data == NULL) {
114 return;
115 }
116
117 if (kind == crm_class_cluster) {
118 xml = string2xml(data);
119 }
120
121 if (xml == NULL) {
122 crm_err("Bad message of class %d received from %s[%u]: '%.120s'", kind, from, nodeid, data);
123 } else {
124 crm_node_t *peer = crm_get_peer(nodeid, from);
125
126 attrd_peer_message(peer, xml);
127 }
128
129 free_xml(xml);
130 free(data);
131 }
132
133 static void
134 attrd_cpg_destroy(gpointer unused)
135 {
136 if (attrd_shutting_down()) {
137 crm_info("Corosync disconnection complete");
138
139 } else {
140 crm_crit("Lost connection to cluster layer, shutting down");
141 attrd_exit_status = CRM_EX_DISCONNECT;
142 attrd_shutdown(0);
143 }
144 }
145
146
147
148
149
150
151
152
153
154
155
156
157
158 static attribute_value_t *
159 broadcast_local_value(const attribute_t *a)
160 {
161 attribute_value_t *v = g_hash_table_lookup(a->values, attrd_cluster->uname);
162 xmlNode *sync = create_xml_node(NULL, __func__);
163
164 crm_xml_add(sync, PCMK__XA_TASK, PCMK__ATTRD_CMD_SYNC_RESPONSE);
165 attrd_add_value_xml(sync, a, v, false);
166 attrd_send_message(NULL, sync, false);
167 free_xml(sync);
168 return v;
169 }
170
171
172
173
174
175
176
177 static void
178 cache_remote_node(const char *node_name)
179 {
180
181
182
183 crm_node_t *dup = pcmk__search_cluster_node_cache(0, node_name);
184
185 if (dup && (dup->uuid == NULL)) {
186 reap_crm_member(0, node_name);
187 }
188
189
190 CRM_ASSERT(crm_remote_peer_get(node_name) != NULL);
191 }
192
193 #define state_text(state) pcmk__s((state), "in unknown state")
194
195
196
197
198
199
200
201
202
203
204
205 static attribute_value_t *
206 attrd_lookup_or_create_value(GHashTable *values, const char *host,
207 const xmlNode *xml)
208 {
209 attribute_value_t *v = g_hash_table_lookup(values, host);
210 int is_remote = 0;
211
212 crm_element_value_int(xml, PCMK__XA_ATTR_IS_REMOTE, &is_remote);
213 if (is_remote) {
214 cache_remote_node(host);
215 }
216
217 if (v == NULL) {
218 v = calloc(1, sizeof(attribute_value_t));
219 CRM_ASSERT(v != NULL);
220
221 pcmk__str_update(&v->nodename, host);
222 v->is_remote = is_remote;
223 g_hash_table_replace(values, v->nodename, v);
224 }
225 return(v);
226 }
227
228 static void
229 attrd_peer_change_cb(enum crm_status_type kind, crm_node_t *peer, const void *data)
230 {
231 bool gone = false;
232 bool is_remote = pcmk_is_set(peer->flags, crm_remote_node);
233
234 switch (kind) {
235 case crm_status_uname:
236 crm_debug("%s node %s is now %s",
237 (is_remote? "Remote" : "Cluster"),
238 peer->uname, state_text(peer->state));
239 break;
240
241 case crm_status_processes:
242 if (!pcmk_is_set(peer->processes, crm_get_cluster_proc())) {
243 gone = true;
244 }
245 crm_debug("Node %s is %s a peer",
246 peer->uname, (gone? "no longer" : "now"));
247 break;
248
249 case crm_status_nstate:
250 crm_debug("%s node %s is now %s (was %s)",
251 (is_remote? "Remote" : "Cluster"),
252 peer->uname, state_text(peer->state), state_text(data));
253 if (pcmk__str_eq(peer->state, CRM_NODE_MEMBER, pcmk__str_casei)) {
254
255
256
257 if (attrd_election_won()
258 && !pcmk_is_set(peer->flags, crm_remote_node)) {
259 attrd_peer_sync(peer, NULL);
260 }
261 } else {
262
263 attrd_peer_remove(peer->uname, false, "loss");
264 gone = true;
265 }
266 break;
267 }
268
269
270 if (gone && !is_remote) {
271 attrd_remove_voter(peer);
272 attrd_remove_peer_protocol_ver(peer->uname);
273 attrd_do_not_expect_from_peer(peer->uname);
274
275
276 } else if (!gone && is_remote) {
277 cache_remote_node(peer->uname);
278 }
279 }
280
281 static void
282 record_peer_nodeid(attribute_value_t *v, const char *host)
283 {
284 crm_node_t *known_peer = crm_get_peer(v->nodeid, host);
285
286 crm_trace("Learned %s has node id %s", known_peer->uname, known_peer->uuid);
287 if (attrd_election_won()) {
288 attrd_write_attributes(false, false);
289 }
290 }
291
292 static void
293 update_attr_on_host(attribute_t *a, const crm_node_t *peer, const xmlNode *xml,
294 const char *attr, const char *value, const char *host,
295 bool filter, int is_force_write)
296 {
297 attribute_value_t *v = NULL;
298
299 v = attrd_lookup_or_create_value(a->values, host, xml);
300
301 if (filter && !pcmk__str_eq(v->current, value, pcmk__str_casei)
302 && pcmk__str_eq(host, attrd_cluster->uname, pcmk__str_casei)) {
303
304 crm_notice("%s[%s]: local value '%s' takes priority over '%s' from %s",
305 attr, host, v->current, value, peer->uname);
306 v = broadcast_local_value(a);
307
308 } else if (!pcmk__str_eq(v->current, value, pcmk__str_casei)) {
309 crm_notice("Setting %s[%s]%s%s: %s -> %s "
310 CRM_XS " from %s with %s write delay",
311 attr, host, a->set_type ? " in " : "",
312 pcmk__s(a->set_type, ""), pcmk__s(v->current, "(unset)"),
313 pcmk__s(value, "(unset)"), peer->uname,
314 (a->timeout_ms == 0)? "no" : pcmk__readable_interval(a->timeout_ms));
315 pcmk__str_update(&v->current, value);
316 a->changed = true;
317
318 if (pcmk__str_eq(host, attrd_cluster->uname, pcmk__str_casei)
319 && pcmk__str_eq(attr, XML_CIB_ATTR_SHUTDOWN, pcmk__str_none)) {
320
321 if (!pcmk__str_eq(value, "0", pcmk__str_null_matches)) {
322 attrd_set_requesting_shutdown();
323
324 } else {
325 attrd_clear_requesting_shutdown();
326 }
327 }
328
329
330 if (a->timeout_ms && a->timer) {
331 crm_trace("Delayed write out (%dms) for %s", a->timeout_ms, attr);
332 mainloop_timer_start(a->timer);
333 } else {
334 attrd_write_or_elect_attribute(a);
335 }
336
337 } else {
338 if (is_force_write == 1 && a->timeout_ms && a->timer) {
339
340
341 crm_trace("Unchanged %s[%s] from %s is %s(Set the forced write flag)",
342 attr, host, peer->uname, value);
343 a->force_write = TRUE;
344 } else {
345 crm_trace("Unchanged %s[%s] from %s is %s", attr, host, peer->uname, value);
346 }
347 }
348
349
350 v->seen = TRUE;
351
352
353 if ((v->nodeid == 0) && (v->is_remote == FALSE)
354 && (crm_element_value_int(xml, PCMK__XA_ATTR_NODE_ID,
355 (int*)&v->nodeid) == 0) && (v->nodeid > 0)) {
356 record_peer_nodeid(v, host);
357 }
358 }
359
360 static void
361 attrd_peer_update_one(const crm_node_t *peer, xmlNode *xml, bool filter)
362 {
363 attribute_t *a = NULL;
364 const char *attr = crm_element_value(xml, PCMK__XA_ATTR_NAME);
365 const char *value = crm_element_value(xml, PCMK__XA_ATTR_VALUE);
366 const char *host = crm_element_value(xml, PCMK__XA_ATTR_NODE_NAME);
367 int is_force_write = 0;
368
369 if (attr == NULL) {
370 crm_warn("Could not update attribute: peer did not specify name");
371 return;
372 }
373
374 crm_element_value_int(xml, PCMK__XA_ATTR_FORCE, &is_force_write);
375
376 a = attrd_populate_attribute(xml, attr);
377 if (a == NULL) {
378 return;
379 }
380
381 if (host == NULL) {
382
383 GHashTableIter vIter;
384
385 crm_debug("Setting %s for all hosts to %s", attr, value);
386 xml_remove_prop(xml, PCMK__XA_ATTR_NODE_ID);
387 g_hash_table_iter_init(&vIter, a->values);
388
389 while (g_hash_table_iter_next(&vIter, (gpointer *) & host, NULL)) {
390 update_attr_on_host(a, peer, xml, attr, value, host, filter, is_force_write);
391 }
392
393 } else {
394
395 update_attr_on_host(a, peer, xml, attr, value, host, filter, is_force_write);
396 }
397
398
399
400
401 if (pcmk__str_eq(attr, CRM_ATTR_PROTOCOL, pcmk__str_none)) {
402 attrd_update_minimum_protocol_ver(peer->uname, value);
403 }
404 }
405
406 static void
407 broadcast_unseen_local_values(void)
408 {
409 GHashTableIter aIter;
410 GHashTableIter vIter;
411 attribute_t *a = NULL;
412 attribute_value_t *v = NULL;
413 xmlNode *sync = NULL;
414
415 g_hash_table_iter_init(&aIter, attributes);
416 while (g_hash_table_iter_next(&aIter, NULL, (gpointer *) & a)) {
417 g_hash_table_iter_init(&vIter, a->values);
418 while (g_hash_table_iter_next(&vIter, NULL, (gpointer *) & v)) {
419 if (!(v->seen) && pcmk__str_eq(v->nodename, attrd_cluster->uname,
420 pcmk__str_casei)) {
421 if (sync == NULL) {
422 sync = create_xml_node(NULL, __func__);
423 crm_xml_add(sync, PCMK__XA_TASK, PCMK__ATTRD_CMD_SYNC_RESPONSE);
424 }
425 attrd_add_value_xml(sync, a, v, a->timeout_ms && a->timer);
426 }
427 }
428 }
429
430 if (sync != NULL) {
431 crm_debug("Broadcasting local-only values");
432 attrd_send_message(NULL, sync, false);
433 free_xml(sync);
434 }
435 }
436
437 int
438 attrd_cluster_connect(void)
439 {
440 attrd_cluster = pcmk_cluster_new();
441
442 attrd_cluster->destroy = attrd_cpg_destroy;
443 attrd_cluster->cpg.cpg_deliver_fn = attrd_cpg_dispatch;
444 attrd_cluster->cpg.cpg_confchg_fn = pcmk_cpg_membership;
445
446 crm_set_status_callback(&attrd_peer_change_cb);
447
448 if (crm_cluster_connect(attrd_cluster) == FALSE) {
449 crm_err("Cluster connection failed");
450 return -ENOTCONN;
451 }
452 return pcmk_ok;
453 }
454
455 void
456 attrd_peer_clear_failure(pcmk__request_t *request)
457 {
458 xmlNode *xml = request->xml;
459 const char *rsc = crm_element_value(xml, PCMK__XA_ATTR_RESOURCE);
460 const char *host = crm_element_value(xml, PCMK__XA_ATTR_NODE_NAME);
461 const char *op = crm_element_value(xml, PCMK__XA_ATTR_OPERATION);
462 const char *interval_spec = crm_element_value(xml, PCMK__XA_ATTR_INTERVAL);
463 guint interval_ms = crm_parse_interval_spec(interval_spec);
464 char *attr = NULL;
465 GHashTableIter iter;
466 regex_t regex;
467
468 crm_node_t *peer = crm_get_peer(0, request->peer);
469
470 if (attrd_failure_regex(®ex, rsc, op, interval_ms) != pcmk_ok) {
471 crm_info("Ignoring invalid request to clear failures for %s",
472 pcmk__s(rsc, "all resources"));
473 return;
474 }
475
476 crm_xml_add(xml, PCMK__XA_TASK, PCMK__ATTRD_CMD_UPDATE);
477
478
479 if (crm_element_value(xml, PCMK__XA_ATTR_VALUE)) {
480 crm_xml_replace(xml, PCMK__XA_ATTR_VALUE, NULL);
481 }
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 crm_node_t *peer, bool peer_won, xmlNode *xml)
505 {
506 crm_info("Processing " PCMK__ATTRD_CMD_SYNC_RESPONSE " from %s",
507 peer->uname);
508
509 if (peer_won) {
510
511
512
513 attrd_clear_value_seen();
514 }
515
516
517 for (xmlNode *child = pcmk__xml_first_child(xml); child != NULL;
518 child = pcmk__xml_next(child)) {
519 attrd_peer_update(peer, child,
520 crm_element_value(child, PCMK__XA_ATTR_NODE_NAME),
521 true);
522 }
523
524 if (peer_won) {
525
526
527
528 broadcast_unseen_local_values();
529 }
530 }
531
532
533
534
535
536
537
538
539
540 void
541 attrd_peer_remove(const char *host, bool uncache, const char *source)
542 {
543 attribute_t *a = NULL;
544 GHashTableIter aIter;
545
546 CRM_CHECK(host != NULL, return);
547 crm_notice("Removing all %s attributes for peer %s", host, source);
548
549 g_hash_table_iter_init(&aIter, attributes);
550 while (g_hash_table_iter_next(&aIter, NULL, (gpointer *) & a)) {
551 if(g_hash_table_remove(a->values, host)) {
552 crm_debug("Removed %s[%s] for peer %s", a->id, host, source);
553 }
554 }
555
556 if (uncache) {
557 crm_remote_peer_cache_remove(host);
558 reap_crm_member(0, host);
559 }
560 }
561
562 void
563 attrd_peer_sync(crm_node_t *peer, xmlNode *xml)
564 {
565 GHashTableIter aIter;
566 GHashTableIter vIter;
567
568 attribute_t *a = NULL;
569 attribute_value_t *v = NULL;
570 xmlNode *sync = create_xml_node(NULL, __func__);
571
572 crm_xml_add(sync, PCMK__XA_TASK, PCMK__ATTRD_CMD_SYNC_RESPONSE);
573
574 g_hash_table_iter_init(&aIter, attributes);
575 while (g_hash_table_iter_next(&aIter, NULL, (gpointer *) & a)) {
576 g_hash_table_iter_init(&vIter, a->values);
577 while (g_hash_table_iter_next(&vIter, NULL, (gpointer *) & v)) {
578 crm_debug("Syncing %s[%s] = %s to %s", a->id, v->nodename, v->current, peer?peer->uname:"everyone");
579 attrd_add_value_xml(sync, a, v, false);
580 }
581 }
582
583 crm_debug("Syncing values to %s", peer?peer->uname:"everyone");
584 attrd_send_message(peer, sync, false);
585 free_xml(sync);
586 }
587
588 void
589 attrd_peer_update(const crm_node_t *peer, xmlNode *xml, const char *host,
590 bool filter)
591 {
592 bool handle_sync_point = false;
593
594 if (xml_has_children(xml)) {
595 for (xmlNode *child = first_named_child(xml, XML_ATTR_OP); child != NULL;
596 child = crm_next_same_xml(child)) {
597 attrd_copy_xml_attributes(xml, child);
598 attrd_peer_update_one(peer, child, filter);
599
600 if (attrd_request_has_sync_point(child)) {
601 handle_sync_point = true;
602 }
603 }
604
605 } else {
606 attrd_peer_update_one(peer, xml, filter);
607
608 if (attrd_request_has_sync_point(xml)) {
609 handle_sync_point = true;
610 }
611 }
612
613
614
615
616 if (handle_sync_point) {
617 crm_trace("Hit local sync point for attribute update");
618 attrd_ack_waitlist_clients(attrd_sync_point_local, xml);
619 }
620 }