This source file includes following definitions.
- build_query_reply
- attrd_client_clear_failure
- attrd_client_peer_remove
- attrd_client_query
- attrd_client_refresh
- handle_missing_host
- expand_regexes
- handle_regexes
- handle_value_expansion
- send_update_msg_to_cluster
- send_child_update
- attrd_client_update
- attrd_ipc_accept
- attrd_ipc_closed
- attrd_ipc_destroy
- attrd_ipc_dispatch
- attrd_ipc_fini
- attrd_init_ipc
1
2
3
4
5
6
7
8
9
10 #include <crm_internal.h>
11
12 #include <errno.h>
13 #include <stdint.h>
14 #include <stdlib.h>
15 #include <inttypes.h>
16 #include <sys/types.h>
17
18 #include <crm/cluster.h>
19 #include <crm/cluster/internal.h>
20 #include <crm/common/acl_internal.h>
21 #include <crm/common/ipc_internal.h>
22 #include <crm/common/logging.h>
23 #include <crm/common/results.h>
24 #include <crm/common/strings_internal.h>
25 #include <crm/common/util.h>
26 #include <crm/common/xml.h>
27
28 #include "pacemaker-attrd.h"
29
30 static qb_ipcs_service_t *ipcs = NULL;
31
32
33
34
35
36
37
38
39
40
41
42 static xmlNode *build_query_reply(const char *attr, const char *host)
43 {
44 xmlNode *reply = pcmk__xe_create(NULL, __func__);
45 attribute_t *a;
46
47 crm_xml_add(reply, PCMK__XA_T, PCMK__VALUE_ATTRD);
48 crm_xml_add(reply, PCMK__XA_SUBT, PCMK__ATTRD_CMD_QUERY);
49 crm_xml_add(reply, PCMK__XA_ATTR_VERSION, ATTRD_PROTOCOL_VERSION);
50
51
52 a = g_hash_table_lookup(attributes, attr);
53 if (a) {
54 attribute_value_t *v;
55 xmlNode *host_value;
56
57 crm_xml_add(reply, PCMK__XA_ATTR_NAME, attr);
58
59
60 if (pcmk__str_eq(host, "localhost", pcmk__str_casei)) {
61 host = attrd_cluster->priv->node_name;
62 crm_trace("Mapped localhost to %s", host);
63 }
64
65
66 if (host) {
67 v = g_hash_table_lookup(a->values, host);
68 host_value = pcmk__xe_create(reply, PCMK_XE_NODE);
69 crm_xml_add(host_value, PCMK__XA_ATTR_HOST, host);
70 crm_xml_add(host_value, PCMK__XA_ATTR_VALUE,
71 (v? v->current : NULL));
72
73
74 } else {
75 GHashTableIter iter;
76
77 g_hash_table_iter_init(&iter, a->values);
78 while (g_hash_table_iter_next(&iter, NULL, (gpointer *) &v)) {
79 host_value = pcmk__xe_create(reply, PCMK_XE_NODE);
80 crm_xml_add(host_value, PCMK__XA_ATTR_HOST, v->nodename);
81 crm_xml_add(host_value, PCMK__XA_ATTR_VALUE, v->current);
82 }
83 }
84 }
85 return reply;
86 }
87
88 xmlNode *
89 attrd_client_clear_failure(pcmk__request_t *request)
90 {
91 xmlNode *xml = request->xml;
92 const char *rsc, *op, *interval_spec;
93
94 if (minimum_protocol_version >= 2) {
95
96
97
98 attrd_send_message(NULL, xml, false);
99 pcmk__set_result(&request->result, CRM_EX_OK, PCMK_EXEC_DONE, NULL);
100 return NULL;
101 }
102
103 rsc = crm_element_value(xml, PCMK__XA_ATTR_RESOURCE);
104 op = crm_element_value(xml, PCMK__XA_ATTR_CLEAR_OPERATION);
105 interval_spec = crm_element_value(xml, PCMK__XA_ATTR_CLEAR_INTERVAL);
106
107
108 crm_xml_add(xml, PCMK_XA_TASK, PCMK__ATTRD_CMD_UPDATE);
109
110
111
112 if (rsc) {
113 char *pattern;
114
115 if (op == NULL) {
116 pattern = crm_strdup_printf(ATTRD_RE_CLEAR_ONE, rsc);
117
118 } else {
119 guint interval_ms = 0U;
120
121 pcmk_parse_interval_spec(interval_spec, &interval_ms);
122 pattern = crm_strdup_printf(ATTRD_RE_CLEAR_OP,
123 rsc, op, interval_ms);
124 }
125
126 crm_xml_add(xml, PCMK__XA_ATTR_REGEX, pattern);
127 free(pattern);
128
129 } else {
130 crm_xml_add(xml, PCMK__XA_ATTR_REGEX, ATTRD_RE_CLEAR_ALL);
131 }
132
133
134 pcmk__xe_remove_attr(xml, PCMK__XA_ATTR_NAME);
135 pcmk__xe_remove_attr(xml, PCMK__XA_ATTR_VALUE);
136
137 return attrd_client_update(request);
138 }
139
140 xmlNode *
141 attrd_client_peer_remove(pcmk__request_t *request)
142 {
143 xmlNode *xml = request->xml;
144
145
146 const char *host = crm_element_value(xml, PCMK__XA_ATTR_HOST);
147 char *host_alloc = NULL;
148
149 attrd_send_ack(request->ipc_client, request->ipc_id, request->ipc_flags);
150
151 if (host == NULL) {
152 int nodeid = 0;
153
154 crm_element_value_int(xml, PCMK__XA_ATTR_HOST_ID, &nodeid);
155 if (nodeid > 0) {
156 pcmk__node_status_t *node = NULL;
157 char *host_alloc = NULL;
158
159 node = pcmk__search_node_caches(nodeid, NULL, NULL,
160 pcmk__node_search_cluster_member);
161 if ((node != NULL) && (node->name != NULL)) {
162
163 host = node->name;
164 } else {
165
166 host_alloc = pcmk__cluster_node_name(nodeid);
167 host = host_alloc;
168 }
169 crm_xml_add(xml, PCMK__XA_ATTR_HOST, host);
170 }
171 }
172
173 if (host) {
174 crm_info("Client %s is requesting all values for %s be removed",
175 pcmk__client_name(request->ipc_client), host);
176 attrd_send_message(NULL, xml, false);
177 free(host_alloc);
178 } else {
179 crm_info("Ignoring request by client %s to remove all peer values without specifying peer",
180 pcmk__client_name(request->ipc_client));
181 }
182
183 pcmk__set_result(&request->result, CRM_EX_OK, PCMK_EXEC_DONE, NULL);
184 return NULL;
185 }
186
187 xmlNode *
188 attrd_client_query(pcmk__request_t *request)
189 {
190 xmlNode *query = request->xml;
191 xmlNode *reply = NULL;
192 const char *attr = NULL;
193
194 crm_debug("Query arrived from %s", pcmk__client_name(request->ipc_client));
195
196
197 attr = crm_element_value(query, PCMK__XA_ATTR_NAME);
198 if (attr == NULL) {
199 pcmk__format_result(&request->result, CRM_EX_ERROR, PCMK_EXEC_ERROR,
200 "Ignoring malformed query from %s (no attribute name given)",
201 pcmk__client_name(request->ipc_client));
202 return NULL;
203 }
204
205
206 reply = build_query_reply(attr,
207 crm_element_value(query, PCMK__XA_ATTR_HOST));
208 if (reply == NULL) {
209 pcmk__format_result(&request->result, CRM_EX_ERROR, PCMK_EXEC_ERROR,
210 "Could not respond to query from %s: could not create XML reply",
211 pcmk__client_name(request->ipc_client));
212 return NULL;
213 } else {
214 pcmk__set_result(&request->result, CRM_EX_OK, PCMK_EXEC_DONE, NULL);
215 }
216
217 request->ipc_client->request_id = 0;
218 return reply;
219 }
220
221 xmlNode *
222 attrd_client_refresh(pcmk__request_t *request)
223 {
224 crm_info("Updating all attributes");
225
226 attrd_send_ack(request->ipc_client, request->ipc_id, request->ipc_flags);
227 attrd_write_attributes(attrd_write_all|attrd_write_no_delay);
228
229 pcmk__set_result(&request->result, CRM_EX_OK, PCMK_EXEC_DONE, NULL);
230 return NULL;
231 }
232
233 static void
234 handle_missing_host(xmlNode *xml)
235 {
236 if (crm_element_value(xml, PCMK__XA_ATTR_HOST) == NULL) {
237 crm_trace("Inferring local node %s with XML ID %s",
238 attrd_cluster->priv->node_name,
239 attrd_cluster->priv->node_xml_id);
240 crm_xml_add(xml, PCMK__XA_ATTR_HOST, attrd_cluster->priv->node_name);
241 crm_xml_add(xml, PCMK__XA_ATTR_HOST_ID,
242 attrd_cluster->priv->node_xml_id);
243 }
244 }
245
246
247
248
249 static int
250 expand_regexes(xmlNode *xml, const char *attr, const char *value, const char *regex)
251 {
252 if (attr == NULL && regex) {
253 bool matched = false;
254 GHashTableIter aIter;
255 regex_t r_patt;
256
257 crm_debug("Setting %s to %s", regex, value);
258 if (regcomp(&r_patt, regex, REG_EXTENDED|REG_NOSUB)) {
259 return EINVAL;
260 }
261
262 g_hash_table_iter_init(&aIter, attributes);
263 while (g_hash_table_iter_next(&aIter, (gpointer *) & attr, NULL)) {
264 int status = regexec(&r_patt, attr, 0, NULL, 0);
265
266 if (status == 0) {
267 xmlNode *child = pcmk__xe_create(xml, PCMK_XE_OP);
268
269 crm_trace("Matched %s with %s", attr, regex);
270 matched = true;
271
272
273
274
275 pcmk__xe_copy_attrs(child, xml, pcmk__xaf_no_overwrite);
276 pcmk__xe_remove_attr(child, PCMK__XA_ATTR_REGEX);
277 crm_xml_add(child, PCMK__XA_ATTR_NAME, attr);
278 }
279 }
280
281 regfree(&r_patt);
282
283
284
285
286
287
288 if (!matched) {
289 return pcmk_rc_op_unsatisfied;
290 }
291
292 } else if (attr == NULL) {
293 return pcmk_rc_bad_nvpair;
294 }
295
296 return pcmk_rc_ok;
297 }
298
299 static int
300 handle_regexes(pcmk__request_t *request)
301 {
302 xmlNode *xml = request->xml;
303 int rc = pcmk_rc_ok;
304
305 const char *attr = crm_element_value(xml, PCMK__XA_ATTR_NAME);
306 const char *value = crm_element_value(xml, PCMK__XA_ATTR_VALUE);
307 const char *regex = crm_element_value(xml, PCMK__XA_ATTR_REGEX);
308
309 rc = expand_regexes(xml, attr, value, regex);
310
311 if (rc == EINVAL) {
312 pcmk__format_result(&request->result, CRM_EX_ERROR, PCMK_EXEC_ERROR,
313 "Bad regex '%s' for update from client %s", regex,
314 pcmk__client_name(request->ipc_client));
315
316 } else if (rc == pcmk_rc_bad_nvpair) {
317 crm_err("Update request did not specify attribute or regular expression");
318 pcmk__format_result(&request->result, CRM_EX_ERROR, PCMK_EXEC_ERROR,
319 "Client %s update request did not specify attribute or regular expression",
320 pcmk__client_name(request->ipc_client));
321 }
322
323 return rc;
324 }
325
326 static int
327 handle_value_expansion(const char **value, xmlNode *xml, const char *op,
328 const char *attr)
329 {
330 attribute_t *a = g_hash_table_lookup(attributes, attr);
331
332 if (a == NULL && pcmk__str_eq(op, PCMK__ATTRD_CMD_UPDATE_DELAY, pcmk__str_none)) {
333 return EINVAL;
334 }
335
336 if (*value && attrd_value_needs_expansion(*value)) {
337 int int_value;
338 attribute_value_t *v = NULL;
339
340 if (a) {
341 const char *host = crm_element_value(xml, PCMK__XA_ATTR_HOST);
342 v = g_hash_table_lookup(a->values, host);
343 }
344
345 int_value = attrd_expand_value(*value, (v? v->current : NULL));
346
347 crm_info("Expanded %s=%s to %d", attr, *value, int_value);
348 crm_xml_add_int(xml, PCMK__XA_ATTR_VALUE, int_value);
349
350
351 *value = crm_element_value(xml, PCMK__XA_ATTR_VALUE);
352 }
353
354 return pcmk_rc_ok;
355 }
356
357 static void
358 send_update_msg_to_cluster(pcmk__request_t *request, xmlNode *xml)
359 {
360 if (pcmk__str_eq(attrd_request_sync_point(xml), PCMK__VALUE_CLUSTER, pcmk__str_none)) {
361
362
363
364
365 attrd_expect_confirmations(request, attrd_cluster_sync_point_update);
366 attrd_send_message(NULL, xml, true);
367
368 } else {
369
370
371
372
373
374
375 attrd_send_message(NULL, xml, false);
376 }
377 }
378
379 static int
380 send_child_update(xmlNode *child, void *data)
381 {
382 pcmk__request_t *request = (pcmk__request_t *) data;
383
384
385
386
387 request->xml = child;
388 attrd_client_update(request);
389 return pcmk_rc_ok;
390 }
391
392 xmlNode *
393 attrd_client_update(pcmk__request_t *request)
394 {
395 xmlNode *xml = NULL;
396 const char *attr, *value, *regex;
397
398 CRM_CHECK((request != NULL) && (request->xml != NULL), return NULL);
399
400 xml = request->xml;
401
402
403
404
405
406 if (xml->children != NULL) {
407 if (ATTRD_SUPPORTS_MULTI_MESSAGE(minimum_protocol_version)) {
408
409
410
411
412
413 for (xmlNode *child = pcmk__xe_first_child(xml, PCMK_XE_OP, NULL,
414 NULL);
415 child != NULL; child = pcmk__xe_next(child, PCMK_XE_OP)) {
416
417 attr = crm_element_value(child, PCMK__XA_ATTR_NAME);
418 value = crm_element_value(child, PCMK__XA_ATTR_VALUE);
419
420 handle_missing_host(child);
421
422 if (handle_value_expansion(&value, child, request->op, attr) == EINVAL) {
423 pcmk__format_result(&request->result, CRM_EX_NOSUCH, PCMK_EXEC_ERROR,
424 "Attribute %s does not exist", attr);
425 return NULL;
426 }
427 }
428
429 send_update_msg_to_cluster(request, xml);
430 pcmk__set_result(&request->result, CRM_EX_OK, PCMK_EXEC_DONE, NULL);
431
432 } else {
433
434
435
436 xmlNode *orig_xml = request->xml;
437
438
439
440
441
442 pcmk__xe_foreach_child(xml, PCMK_XE_OP, send_child_update, request);
443 request->xml = orig_xml;
444 }
445
446 return NULL;
447 }
448
449 attr = crm_element_value(xml, PCMK__XA_ATTR_NAME);
450 value = crm_element_value(xml, PCMK__XA_ATTR_VALUE);
451 regex = crm_element_value(xml, PCMK__XA_ATTR_REGEX);
452
453 if (handle_regexes(request) != pcmk_rc_ok) {
454
455 return NULL;
456 } else if (regex) {
457
458
459
460
461 return attrd_client_update(request);
462 }
463
464 handle_missing_host(xml);
465
466 if (handle_value_expansion(&value, xml, request->op, attr) == EINVAL) {
467 pcmk__format_result(&request->result, CRM_EX_NOSUCH, PCMK_EXEC_ERROR,
468 "Attribute %s does not exist", attr);
469 return NULL;
470 }
471
472 crm_debug("Broadcasting %s[%s]=%s%s",
473 attr, crm_element_value(xml, PCMK__XA_ATTR_HOST),
474 value, (attrd_election_won()? " (writer)" : ""));
475
476 send_update_msg_to_cluster(request, xml);
477 pcmk__set_result(&request->result, CRM_EX_OK, PCMK_EXEC_DONE, NULL);
478 return NULL;
479 }
480
481
482
483
484
485
486
487
488
489
490
491 static int32_t
492 attrd_ipc_accept(qb_ipcs_connection_t *c, uid_t uid, gid_t gid)
493 {
494 crm_trace("New client connection %p", c);
495 if (attrd_shutting_down(false)) {
496 crm_info("Ignoring new connection from pid %d during shutdown",
497 pcmk__client_pid(c));
498 return -ECONNREFUSED;
499 }
500
501 if (pcmk__new_client(c, uid, gid) == NULL) {
502 return -ENOMEM;
503 }
504 return pcmk_ok;
505 }
506
507
508
509
510
511
512
513
514
515 static int32_t
516 attrd_ipc_closed(qb_ipcs_connection_t *c)
517 {
518 pcmk__client_t *client = pcmk__find_client(c);
519
520 if (client == NULL) {
521 crm_trace("Ignoring request to clean up unknown connection %p", c);
522 } else {
523 crm_trace("Cleaning up closed client connection %p", c);
524
525
526 attrd_remove_client_from_waitlist(client);
527
528
529 attrd_do_not_wait_for_client(client);
530
531 pcmk__free_client(client);
532 }
533
534 return FALSE;
535 }
536
537
538
539
540
541
542
543
544
545
546 static void
547 attrd_ipc_destroy(qb_ipcs_connection_t *c)
548 {
549 crm_trace("Destroying client connection %p", c);
550 attrd_ipc_closed(c);
551 }
552
553 static int32_t
554 attrd_ipc_dispatch(qb_ipcs_connection_t * c, void *data, size_t size)
555 {
556 int rc = pcmk_rc_ok;
557 uint32_t id = 0;
558 uint32_t flags = 0;
559 pcmk__client_t *client = pcmk__find_client(c);
560 xmlNode *xml = NULL;
561
562
563 CRM_CHECK((c != NULL) && (client != NULL), return 0);
564 if (data == NULL) {
565 crm_debug("No IPC data from PID %d", pcmk__client_pid(c));
566 return 0;
567 }
568
569 rc = pcmk__ipc_msg_append(&client->buffer, data);
570
571 if (rc == pcmk_rc_ipc_more) {
572
573 return 0;
574
575 } else if (rc == pcmk_rc_ok) {
576
577
578
579 xml = pcmk__client_data2xml(client, &id, &flags);
580 g_byte_array_free(client->buffer, TRUE);
581 client->buffer = NULL;
582
583 } else {
584
585
586
587 crm_err("Error when reading IPC message: %s", pcmk_rc_str(rc));
588
589 if (client->buffer != NULL) {
590 g_byte_array_free(client->buffer, TRUE);
591 client->buffer = NULL;
592 }
593
594 return 0;
595 }
596
597 if (xml == NULL) {
598 crm_debug("Unrecognizable IPC data from PID %d", pcmk__client_pid(c));
599 pcmk__ipc_send_ack(client, id, flags, PCMK__XE_ACK, NULL,
600 CRM_EX_PROTOCOL);
601 return 0;
602
603 } else {
604 pcmk__request_t request = {
605 .ipc_client = client,
606 .ipc_id = id,
607 .ipc_flags = flags,
608 .peer = NULL,
609 .xml = xml,
610 .call_options = 0,
611 .result = PCMK__UNKNOWN_RESULT,
612 };
613
614 pcmk__assert(client->user != NULL);
615 pcmk__update_acl_user(xml, PCMK__XA_ATTR_USER, client->user);
616
617 request.op = crm_element_value_copy(request.xml, PCMK_XA_TASK);
618 CRM_CHECK(request.op != NULL, return 0);
619
620 attrd_handle_request(&request);
621 pcmk__reset_request(&request);
622 }
623
624 pcmk__xml_free(xml);
625 return 0;
626 }
627
628 static struct qb_ipcs_service_handlers ipc_callbacks = {
629 .connection_accept = attrd_ipc_accept,
630 .connection_created = NULL,
631 .msg_process = attrd_ipc_dispatch,
632 .connection_closed = attrd_ipc_closed,
633 .connection_destroyed = attrd_ipc_destroy
634 };
635
636 void
637 attrd_ipc_fini(void)
638 {
639 if (ipcs != NULL) {
640 pcmk__drop_all_clients(ipcs);
641 qb_ipcs_destroy(ipcs);
642 ipcs = NULL;
643 }
644
645 attrd_unregister_handlers();
646 pcmk__client_cleanup();
647 }
648
649
650
651
652
653 void
654 attrd_init_ipc(void)
655 {
656 pcmk__serve_attrd_ipc(&ipcs, &ipc_callbacks);
657 }