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
- handle_value_expansion
- 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 attrd_send_ack(request->ipc_client, request->ipc_id, request->ipc_flags);
105
106 if (minimum_protocol_version >= 2) {
107
108
109
110 attrd_send_message(NULL, xml);
111 pcmk__set_result(&request->result, CRM_EX_OK, PCMK_EXEC_DONE, NULL);
112 return NULL;
113 }
114
115 rsc = crm_element_value(xml, PCMK__XA_ATTR_RESOURCE);
116 op = crm_element_value(xml, PCMK__XA_ATTR_OPERATION);
117 interval_spec = crm_element_value(xml, PCMK__XA_ATTR_INTERVAL);
118
119
120 crm_xml_add(xml, PCMK__XA_TASK, PCMK__ATTRD_CMD_UPDATE);
121
122
123
124 if (rsc) {
125 char *pattern;
126
127 if (op == NULL) {
128 pattern = crm_strdup_printf(ATTRD_RE_CLEAR_ONE, rsc);
129
130 } else {
131 guint interval_ms = crm_parse_interval_spec(interval_spec);
132
133 pattern = crm_strdup_printf(ATTRD_RE_CLEAR_OP,
134 rsc, op, interval_ms);
135 }
136
137 crm_xml_add(xml, PCMK__XA_ATTR_PATTERN, pattern);
138 free(pattern);
139
140 } else {
141 crm_xml_add(xml, PCMK__XA_ATTR_PATTERN, ATTRD_RE_CLEAR_ALL);
142 }
143
144
145 if (crm_element_value(xml, PCMK__XA_ATTR_NAME)) {
146 crm_xml_replace(xml, PCMK__XA_ATTR_NAME, NULL);
147 }
148 if (crm_element_value(xml, PCMK__XA_ATTR_VALUE)) {
149 crm_xml_replace(xml, PCMK__XA_ATTR_VALUE, NULL);
150 }
151
152 return attrd_client_update(request);
153 }
154
155 xmlNode *
156 attrd_client_peer_remove(pcmk__request_t *request)
157 {
158 xmlNode *xml = request->xml;
159
160
161 const char *host = crm_element_value(xml, PCMK__XA_ATTR_NODE_NAME);
162 char *host_alloc = NULL;
163
164 attrd_send_ack(request->ipc_client, request->ipc_id, request->ipc_flags);
165
166 if (host == NULL) {
167 int nodeid = 0;
168
169 crm_element_value_int(xml, PCMK__XA_ATTR_NODE_ID, &nodeid);
170 if (nodeid > 0) {
171 crm_node_t *node = pcmk__search_cluster_node_cache(nodeid, NULL);
172 char *host_alloc = NULL;
173
174 if (node && node->uname) {
175
176 host = node->uname;
177 } else {
178
179 host_alloc = get_node_name(nodeid);
180 host = host_alloc;
181 }
182 pcmk__xe_add_node(xml, host, 0);
183 }
184 }
185
186 if (host) {
187 crm_info("Client %s is requesting all values for %s be removed",
188 pcmk__client_name(request->ipc_client), host);
189 attrd_send_message(NULL, xml);
190 free(host_alloc);
191 } else {
192 crm_info("Ignoring request by client %s to remove all peer values without specifying peer",
193 pcmk__client_name(request->ipc_client));
194 }
195
196 pcmk__set_result(&request->result, CRM_EX_OK, PCMK_EXEC_DONE, NULL);
197 return NULL;
198 }
199
200 xmlNode *
201 attrd_client_query(pcmk__request_t *request)
202 {
203 xmlNode *query = request->xml;
204 xmlNode *reply = NULL;
205 const char *attr = NULL;
206
207 crm_debug("Query arrived from %s", pcmk__client_name(request->ipc_client));
208
209
210 attr = crm_element_value(query, PCMK__XA_ATTR_NAME);
211 if (attr == NULL) {
212 pcmk__format_result(&request->result, CRM_EX_ERROR, PCMK_EXEC_ERROR,
213 "Ignoring malformed query from %s (no attribute name given)",
214 pcmk__client_name(request->ipc_client));
215 return NULL;
216 }
217
218
219 reply = build_query_reply(attr, crm_element_value(query,
220 PCMK__XA_ATTR_NODE_NAME));
221 if (reply == NULL) {
222 pcmk__format_result(&request->result, CRM_EX_ERROR, PCMK_EXEC_ERROR,
223 "Could not respond to query from %s: could not create XML reply",
224 pcmk__client_name(request->ipc_client));
225 return NULL;
226 } else {
227 pcmk__set_result(&request->result, CRM_EX_OK, PCMK_EXEC_DONE, NULL);
228 }
229
230 request->ipc_client->request_id = 0;
231 return reply;
232 }
233
234 xmlNode *
235 attrd_client_refresh(pcmk__request_t *request)
236 {
237 crm_info("Updating all attributes");
238
239 attrd_send_ack(request->ipc_client, request->ipc_id, request->ipc_flags);
240 attrd_write_attributes(true, true);
241
242 pcmk__set_result(&request->result, CRM_EX_OK, PCMK_EXEC_DONE, NULL);
243 return NULL;
244 }
245
246 static void
247 handle_missing_host(xmlNode *xml)
248 {
249 const char *host = crm_element_value(xml, PCMK__XA_ATTR_NODE_NAME);
250
251 if (host == NULL) {
252 crm_trace("Inferring host");
253 pcmk__xe_add_node(xml, attrd_cluster->uname, attrd_cluster->nodeid);
254 }
255 }
256
257 static int
258 handle_value_expansion(const char **value, xmlNode *xml, const char *op,
259 const char *attr)
260 {
261 attribute_t *a = g_hash_table_lookup(attributes, attr);
262
263 if (a == NULL && pcmk__str_eq(op, PCMK__ATTRD_CMD_UPDATE_DELAY, pcmk__str_none)) {
264 return EINVAL;
265 }
266
267 if (*value && attrd_value_needs_expansion(*value)) {
268 int int_value;
269 attribute_value_t *v = NULL;
270
271 if (a) {
272 const char *host = crm_element_value(xml, PCMK__XA_ATTR_NODE_NAME);
273 v = g_hash_table_lookup(a->values, host);
274 }
275
276 int_value = attrd_expand_value(*value, (v? v->current : NULL));
277
278 crm_info("Expanded %s=%s to %d", attr, *value, int_value);
279 crm_xml_add_int(xml, PCMK__XA_ATTR_VALUE, int_value);
280
281
282 *value = crm_element_value(xml, PCMK__XA_ATTR_VALUE);
283 }
284
285 return pcmk_rc_ok;
286 }
287
288 xmlNode *
289 attrd_client_update(pcmk__request_t *request)
290 {
291 xmlNode *xml = request->xml;
292 const char *attr, *value, *regex;
293
294
295
296
297
298 if (xml_has_children(xml)) {
299 if (minimum_protocol_version >= 4) {
300
301
302
303
304
305 for (xmlNode *child = first_named_child(xml, XML_ATTR_OP); child != NULL;
306 child = crm_next_same_xml(child)) {
307 attr = crm_element_value(child, PCMK__XA_ATTR_NAME);
308 value = crm_element_value(child, PCMK__XA_ATTR_VALUE);
309
310 handle_missing_host(child);
311
312 if (handle_value_expansion(&value, child, request->op, attr) == EINVAL) {
313 pcmk__format_result(&request->result, CRM_EX_NOSUCH, PCMK_EXEC_ERROR,
314 "Attribute %s does not exist", attr);
315 return NULL;
316 }
317 }
318
319 attrd_send_message(NULL, xml);
320 pcmk__set_result(&request->result, CRM_EX_OK, PCMK_EXEC_DONE, NULL);
321
322 } else {
323
324
325
326
327 for (xmlNode *child = first_named_child(xml, XML_ATTR_OP); child != NULL;
328 child = crm_next_same_xml(child)) {
329 request->xml = child;
330
331
332
333 attrd_client_update(request);
334 }
335 }
336
337 return NULL;
338 }
339
340 attr = crm_element_value(xml, PCMK__XA_ATTR_NAME);
341 value = crm_element_value(xml, PCMK__XA_ATTR_VALUE);
342 regex = crm_element_value(xml, PCMK__XA_ATTR_PATTERN);
343
344
345 if ((attr == NULL) && regex) {
346 GHashTableIter aIter;
347 regex_t *r_patt = calloc(1, sizeof(regex_t));
348
349 crm_debug("Setting %s to %s", regex, value);
350 if (regcomp(r_patt, regex, REG_EXTENDED|REG_NOSUB)) {
351 pcmk__format_result(&request->result, CRM_EX_ERROR, PCMK_EXEC_ERROR,
352 "Bad regex '%s' for update from client %s", regex,
353 pcmk__client_name(request->ipc_client));
354
355 } else {
356 g_hash_table_iter_init(&aIter, attributes);
357 while (g_hash_table_iter_next(&aIter, (gpointer *) & attr, NULL)) {
358 int status = regexec(r_patt, attr, 0, NULL, 0);
359
360 if (status == 0) {
361 crm_trace("Matched %s with %s", attr, regex);
362 crm_xml_add(xml, PCMK__XA_ATTR_NAME, attr);
363 attrd_send_message(NULL, xml);
364 }
365 }
366
367 pcmk__set_result(&request->result, CRM_EX_OK, PCMK_EXEC_DONE, NULL);
368 }
369
370 regfree(r_patt);
371 free(r_patt);
372 return NULL;
373
374 } else if (attr == NULL) {
375 crm_err("Update request did not specify attribute or regular expression");
376 pcmk__format_result(&request->result, CRM_EX_ERROR, PCMK_EXEC_ERROR,
377 "Client %s update request did not specify attribute or regular expression",
378 pcmk__client_name(request->ipc_client));
379 return NULL;
380 }
381
382 handle_missing_host(xml);
383
384 if (handle_value_expansion(&value, xml, request->op, attr) == EINVAL) {
385 pcmk__format_result(&request->result, CRM_EX_NOSUCH, PCMK_EXEC_ERROR,
386 "Attribute %s does not exist", attr);
387 return NULL;
388 }
389
390 crm_debug("Broadcasting %s[%s]=%s%s", attr, crm_element_value(xml, PCMK__XA_ATTR_NODE_NAME),
391 value, (attrd_election_won()? " (writer)" : ""));
392
393 attrd_send_message(NULL, xml);
394 pcmk__set_result(&request->result, CRM_EX_OK, PCMK_EXEC_DONE, NULL);
395 return NULL;
396 }
397
398
399
400
401
402
403
404
405
406
407
408 static int32_t
409 attrd_ipc_accept(qb_ipcs_connection_t *c, uid_t uid, gid_t gid)
410 {
411 crm_trace("New client connection %p", c);
412 if (attrd_shutting_down()) {
413 crm_info("Ignoring new connection from pid %d during shutdown",
414 pcmk__client_pid(c));
415 return -EPERM;
416 }
417
418 if (pcmk__new_client(c, uid, gid) == NULL) {
419 return -EIO;
420 }
421 return pcmk_ok;
422 }
423
424
425
426
427
428
429
430
431
432 static int32_t
433 attrd_ipc_closed(qb_ipcs_connection_t *c)
434 {
435 pcmk__client_t *client = pcmk__find_client(c);
436
437 if (client == NULL) {
438 crm_trace("Ignoring request to clean up unknown connection %p", c);
439 } else {
440 crm_trace("Cleaning up closed client connection %p", c);
441 pcmk__free_client(client);
442 }
443 return FALSE;
444 }
445
446
447
448
449
450
451
452
453
454
455 static void
456 attrd_ipc_destroy(qb_ipcs_connection_t *c)
457 {
458 crm_trace("Destroying client connection %p", c);
459 attrd_ipc_closed(c);
460 }
461
462 static int32_t
463 attrd_ipc_dispatch(qb_ipcs_connection_t * c, void *data, size_t size)
464 {
465 uint32_t id = 0;
466 uint32_t flags = 0;
467 pcmk__client_t *client = pcmk__find_client(c);
468 xmlNode *xml = NULL;
469
470
471 CRM_CHECK((c != NULL) && (client != NULL), return 0);
472 if (data == NULL) {
473 crm_debug("No IPC data from PID %d", pcmk__client_pid(c));
474 return 0;
475 }
476
477 xml = pcmk__client_data2xml(client, data, &id, &flags);
478
479 if (xml == NULL) {
480 crm_debug("Unrecognizable IPC data from PID %d", pcmk__client_pid(c));
481 pcmk__ipc_send_ack(client, id, flags, "ack", NULL, CRM_EX_PROTOCOL);
482 return 0;
483
484 } else {
485 pcmk__request_t request = {
486 .ipc_client = client,
487 .ipc_id = id,
488 .ipc_flags = flags,
489 .peer = NULL,
490 .xml = xml,
491 .call_options = 0,
492 .result = PCMK__UNKNOWN_RESULT,
493 };
494
495 CRM_ASSERT(client->user != NULL);
496 pcmk__update_acl_user(xml, PCMK__XA_ATTR_USER, client->user);
497
498 request.op = crm_element_value_copy(request.xml, PCMK__XA_TASK);
499 CRM_CHECK(request.op != NULL, return 0);
500
501 attrd_handle_request(&request);
502 pcmk__reset_request(&request);
503 }
504
505 free_xml(xml);
506 return 0;
507 }
508
509 static struct qb_ipcs_service_handlers ipc_callbacks = {
510 .connection_accept = attrd_ipc_accept,
511 .connection_created = NULL,
512 .msg_process = attrd_ipc_dispatch,
513 .connection_closed = attrd_ipc_closed,
514 .connection_destroyed = attrd_ipc_destroy
515 };
516
517 void
518 attrd_ipc_fini(void)
519 {
520 if (ipcs != NULL) {
521 pcmk__drop_all_clients(ipcs);
522 qb_ipcs_destroy(ipcs);
523 ipcs = NULL;
524 }
525 }
526
527
528
529
530
531 void
532 attrd_init_ipc(void)
533 {
534 pcmk__serve_attrd_ipc(&ipcs, &ipc_callbacks);
535 }