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