This source file includes following definitions.
- attribute_timer_cb
- attrd_cib_callback
- build_update_element
- send_alert_attributes_value
- set_alert_attribute_value
- attrd_add_timer
- attrd_write_attribute
- attrd_write_attributes
- attrd_write_or_elect_attribute
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 <stdlib.h>
15 #include <glib.h>
16
17 #include <crm/msg_xml.h>
18 #include <crm/common/logging.h>
19 #include <crm/common/results.h>
20 #include <crm/common/strings_internal.h>
21 #include <crm/common/xml.h>
22
23 #include "pacemaker-attrd.h"
24
25 static int last_cib_op_done = 0;
26
27 static gboolean
28 attribute_timer_cb(gpointer data)
29 {
30 attribute_t *a = data;
31 crm_trace("Dampen interval expired for %s", a->id);
32 attrd_write_or_elect_attribute(a);
33 return FALSE;
34 }
35
36 static void
37 attrd_cib_callback(xmlNode *msg, int call_id, int rc, xmlNode *output, void *user_data)
38 {
39 int level = LOG_ERR;
40 GHashTableIter iter;
41 const char *peer = NULL;
42 attribute_value_t *v = NULL;
43
44 char *name = user_data;
45 attribute_t *a = g_hash_table_lookup(attributes, name);
46
47 if(a == NULL) {
48 crm_info("Attribute %s no longer exists", name);
49 return;
50 }
51
52 a->update = 0;
53 if (rc == pcmk_ok && call_id < 0) {
54 rc = call_id;
55 }
56
57 switch (rc) {
58 case pcmk_ok:
59 level = LOG_INFO;
60 last_cib_op_done = call_id;
61 if (a->timer && !a->timeout_ms) {
62
63 mainloop_timer_del(a->timer);
64 a->timer = NULL;
65 }
66 break;
67
68 case -pcmk_err_diff_failed:
69 case -ETIME:
70 case -ENXIO:
71
72
73 level = LOG_WARNING;
74 break;
75 }
76
77 do_crm_log(level, "CIB update %d result for %s: %s " CRM_XS " rc=%d",
78 call_id, a->id, pcmk_strerror(rc), rc);
79
80 g_hash_table_iter_init(&iter, a->values);
81 while (g_hash_table_iter_next(&iter, (gpointer *) & peer, (gpointer *) & v)) {
82 do_crm_log(level, "* %s[%s]=%s", a->id, peer, v->requested);
83 free(v->requested);
84 v->requested = NULL;
85 if (rc != pcmk_ok) {
86 a->changed = true;
87 }
88 }
89
90 if (a->changed && attrd_election_won()) {
91 if (rc == pcmk_ok) {
92
93
94
95 attrd_write_attribute(a, false);
96
97
98
99
100
101
102
103
104
105
106 } else if (a->timer) {
107
108 if (!mainloop_timer_running(a->timer)) {
109 crm_trace("Delayed re-attempted write for %s by %s",
110 name, pcmk__readable_interval(a->timeout_ms));
111 mainloop_timer_start(a->timer);
112 }
113 } else {
114
115
116
117
118 a->timer = attrd_add_timer(a->id, 2000, a);
119 mainloop_timer_start(a->timer);
120 }
121 }
122 }
123
124 static void
125 build_update_element(xmlNode *parent, attribute_t *a, const char *nodeid, const char *value)
126 {
127 const char *set = NULL;
128 xmlNode *xml_obj = NULL;
129
130 xml_obj = create_xml_node(parent, XML_CIB_TAG_STATE);
131 crm_xml_add(xml_obj, XML_ATTR_ID, nodeid);
132
133 xml_obj = create_xml_node(xml_obj, XML_TAG_TRANSIENT_NODEATTRS);
134 crm_xml_add(xml_obj, XML_ATTR_ID, nodeid);
135
136 xml_obj = create_xml_node(xml_obj, XML_TAG_ATTR_SETS);
137 if (a->set) {
138 crm_xml_set_id(xml_obj, "%s", a->set);
139 } else {
140 crm_xml_set_id(xml_obj, "%s-%s", XML_CIB_TAG_STATUS, nodeid);
141 }
142 set = ID(xml_obj);
143
144 xml_obj = create_xml_node(xml_obj, XML_CIB_TAG_NVPAIR);
145 if (a->uuid) {
146 crm_xml_set_id(xml_obj, "%s", a->uuid);
147 } else {
148 crm_xml_set_id(xml_obj, "%s-%s", set, a->id);
149 }
150 crm_xml_add(xml_obj, XML_NVPAIR_ATTR_NAME, a->id);
151
152 if(value) {
153 crm_xml_add(xml_obj, XML_NVPAIR_ATTR_VALUE, value);
154
155 } else {
156 crm_xml_add(xml_obj, XML_NVPAIR_ATTR_VALUE, "");
157 crm_xml_add(xml_obj, "__delete__", XML_NVPAIR_ATTR_VALUE);
158 }
159 }
160
161 static void
162 send_alert_attributes_value(attribute_t *a, GHashTable *t)
163 {
164 int rc = 0;
165 attribute_value_t *at = NULL;
166 GHashTableIter vIter;
167
168 g_hash_table_iter_init(&vIter, t);
169
170 while (g_hash_table_iter_next(&vIter, NULL, (gpointer *) & at)) {
171 rc = attrd_send_attribute_alert(at->nodename, at->nodeid,
172 a->id, at->current);
173 crm_trace("Sent alerts for %s[%s]=%s: nodeid=%d rc=%d",
174 a->id, at->nodename, at->current, at->nodeid, rc);
175 }
176 }
177
178 static void
179 set_alert_attribute_value(GHashTable *t, attribute_value_t *v)
180 {
181 attribute_value_t *a_v = NULL;
182 a_v = calloc(1, sizeof(attribute_value_t));
183 CRM_ASSERT(a_v != NULL);
184
185 a_v->nodeid = v->nodeid;
186 a_v->nodename = strdup(v->nodename);
187 pcmk__str_update(&a_v->current, v->current);
188
189 g_hash_table_replace(t, a_v->nodename, a_v);
190 }
191
192 mainloop_timer_t *
193 attrd_add_timer(const char *id, int timeout_ms, attribute_t *attr)
194 {
195 return mainloop_timer_add(id, timeout_ms, FALSE, attribute_timer_cb, attr);
196 }
197
198 void
199 attrd_write_attribute(attribute_t *a, bool ignore_delay)
200 {
201 int private_updates = 0, cib_updates = 0;
202 xmlNode *xml_top = NULL;
203 attribute_value_t *v = NULL;
204 GHashTableIter iter;
205 enum cib_call_options flags = cib_quorum_override;
206 GHashTable *alert_attribute_value = NULL;
207
208 if (a == NULL) {
209 return;
210 }
211
212
213 if (!a->is_private) {
214
215
216 CRM_CHECK(the_cib != NULL, return);
217 if (a->update && (a->update < last_cib_op_done)) {
218 crm_info("Write out of '%s' continuing: update %d considered lost", a->id, a->update);
219 a->update = 0;
220
221 } else if (a->update) {
222 crm_info("Write out of '%s' delayed: update %d in progress", a->id, a->update);
223 return;
224
225 } else if (mainloop_timer_running(a->timer)) {
226 if (ignore_delay) {
227
228
229
230 mainloop_timer_stop(a->timer);
231 crm_debug("Write out of '%s': timer is running but ignore delay", a->id);
232 } else {
233 crm_info("Write out of '%s' delayed: timer is running", a->id);
234 return;
235 }
236 }
237
238
239 xml_top = create_xml_node(NULL, XML_CIB_TAG_STATUS);
240 }
241
242
243 a->changed = false;
244
245
246 a->unknown_peer_uuids = false;
247
248
249 a->force_write = FALSE;
250
251
252 alert_attribute_value = pcmk__strikey_table(NULL, attrd_free_attribute_value);
253
254
255 g_hash_table_iter_init(&iter, a->values);
256 while (g_hash_table_iter_next(&iter, NULL, (gpointer *) & v)) {
257 crm_node_t *peer = crm_get_peer_full(v->nodeid, v->nodename, CRM_GET_PEER_ANY);
258
259
260 if (peer == NULL) {
261 crm_notice("Cannot update %s[%s]=%s because peer not known",
262 a->id, v->nodename, v->current);
263 continue;
264 }
265
266
267 if (peer->id && (v->nodeid == 0)) {
268 crm_trace("Learned ID %u for node %s", peer->id, v->nodename);
269 v->nodeid = peer->id;
270 }
271
272
273 if (a->is_private) {
274 private_updates++;
275 continue;
276 }
277
278
279 if (peer->uuid == NULL) {
280 a->unknown_peer_uuids = true;
281 crm_notice("Cannot update %s[%s]=%s because peer UUID not known "
282 "(will retry if learned)",
283 a->id, v->nodename, v->current);
284 continue;
285 }
286
287
288 crm_debug("Updating %s[%s]=%s (peer known as %s, UUID %s, ID %u/%u)",
289 a->id, v->nodename, v->current,
290 peer->uname, peer->uuid, peer->id, v->nodeid);
291 build_update_element(xml_top, a, peer->uuid, v->current);
292 cib_updates++;
293
294
295 set_alert_attribute_value(alert_attribute_value, v);
296
297 free(v->requested);
298 v->requested = NULL;
299 if (v->current) {
300 v->requested = strdup(v->current);
301 } else {
302
303
304
305 cib__set_call_options(flags, crm_system_name,
306 cib_mixed_update|cib_scope_local);
307 }
308 }
309
310 if (private_updates) {
311 crm_info("Processed %d private change%s for %s, id=%s, set=%s",
312 private_updates, pcmk__plural_s(private_updates),
313 a->id, pcmk__s(a->uuid, "n/a"), pcmk__s(a->set, "n/a"));
314 }
315 if (cib_updates) {
316 crm_log_xml_trace(xml_top, __func__);
317
318 a->update = cib_internal_op(the_cib, PCMK__CIB_REQUEST_MODIFY, NULL,
319 XML_CIB_TAG_STATUS, xml_top, NULL, flags,
320 a->user);
321
322 crm_info("Sent CIB request %d with %d change%s for %s (id %s, set %s)",
323 a->update, cib_updates, pcmk__plural_s(cib_updates),
324 a->id, pcmk__s(a->uuid, "n/a"), pcmk__s(a->set, "n/a"));
325
326 the_cib->cmds->register_callback_full(the_cib, a->update,
327 CIB_OP_TIMEOUT_S, FALSE,
328 strdup(a->id),
329 "attrd_cib_callback",
330 attrd_cib_callback, free);
331
332 send_alert_attributes_value(a, alert_attribute_value);
333 }
334
335 g_hash_table_destroy(alert_attribute_value);
336 free_xml(xml_top);
337 }
338
339 void
340 attrd_write_attributes(bool all, bool ignore_delay)
341 {
342 GHashTableIter iter;
343 attribute_t *a = NULL;
344
345 crm_debug("Writing out %s attributes", all? "all" : "changed");
346 g_hash_table_iter_init(&iter, attributes);
347 while (g_hash_table_iter_next(&iter, NULL, (gpointer *) & a)) {
348 if (!all && a->unknown_peer_uuids) {
349
350 a->changed = true;
351 } else if (a->force_write) {
352
353 a->changed = true;
354 }
355
356 if(all || a->changed) {
357
358 attrd_write_attribute(a, (a->force_write ? true : ignore_delay));
359 } else {
360 crm_trace("Skipping unchanged attribute %s", a->id);
361 }
362 }
363 }
364
365 void
366 attrd_write_or_elect_attribute(attribute_t *a)
367 {
368 if (attrd_election_won()) {
369 attrd_write_attribute(a, false);
370 } else {
371 attrd_start_election_if_needed();
372 }
373 }