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