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