This source file includes following definitions.
- cib_notify_send_one
- cib_notify_send
- cib_diff_notify
- do_cib_notify
- attach_cib_generation
- cib_replace_notify
1
2
3
4
5
6
7
8
9
10 #include <crm_internal.h>
11
12 #include <sys/param.h>
13 #include <stdio.h>
14 #include <sys/types.h>
15 #include <unistd.h>
16 #include <inttypes.h>
17
18 #include <stdlib.h>
19 #include <errno.h>
20 #include <fcntl.h>
21
22 #include <time.h>
23
24 #include <crm/crm.h>
25 #include <crm/cib/internal.h>
26 #include <crm/msg_xml.h>
27
28 #include <crm/common/xml.h>
29 #include <crm/common/remote_internal.h>
30 #include <pacemaker-based.h>
31
32 int pending_updates = 0;
33
34 struct cib_notification_s {
35 xmlNode *msg;
36 struct iovec *iov;
37 int32_t iov_size;
38 };
39
40 void attach_cib_generation(xmlNode * msg, const char *field, xmlNode * a_cib);
41
42 static void do_cib_notify(int options, const char *op, xmlNode *update,
43 int result, xmlNode * result_data,
44 const char *msg_type);
45
46 static void
47 cib_notify_send_one(gpointer key, gpointer value, gpointer user_data)
48 {
49 const char *type = NULL;
50 gboolean do_send = FALSE;
51 int rc = pcmk_rc_ok;
52
53 pcmk__client_t *client = value;
54 struct cib_notification_s *update = user_data;
55
56 if (client->ipcs == NULL && client->remote == NULL) {
57 crm_warn("Skipping client with NULL channel");
58 return;
59 }
60
61 type = crm_element_value(update->msg, F_SUBTYPE);
62 CRM_LOG_ASSERT(type != NULL);
63
64 if (pcmk_is_set(client->flags, cib_notify_diff)
65 && pcmk__str_eq(type, T_CIB_DIFF_NOTIFY, pcmk__str_casei)) {
66
67 do_send = TRUE;
68
69 } else if (pcmk_is_set(client->flags, cib_notify_replace)
70 && pcmk__str_eq(type, T_CIB_REPLACE_NOTIFY, pcmk__str_casei)) {
71 do_send = TRUE;
72
73 } else if (pcmk_is_set(client->flags, cib_notify_confirm)
74 && pcmk__str_eq(type, T_CIB_UPDATE_CONFIRM, pcmk__str_casei)) {
75 do_send = TRUE;
76
77 } else if (pcmk_is_set(client->flags, cib_notify_pre)
78 && pcmk__str_eq(type, T_CIB_PRE_NOTIFY, pcmk__str_casei)) {
79 do_send = TRUE;
80
81 } else if (pcmk_is_set(client->flags, cib_notify_post)
82 && pcmk__str_eq(type, T_CIB_POST_NOTIFY, pcmk__str_casei)) {
83
84 do_send = TRUE;
85 }
86
87 if (do_send) {
88 switch (PCMK__CLIENT_TYPE(client)) {
89 case pcmk__client_ipc:
90 rc = pcmk__ipc_send_iov(client, update->iov,
91 crm_ipc_server_event);
92 if (rc != pcmk_rc_ok) {
93 crm_warn("Could not notify client %s: %s " CRM_XS " id=%s",
94 pcmk__client_name(client), pcmk_rc_str(rc),
95 client->id);
96 }
97 break;
98 #ifdef HAVE_GNUTLS_GNUTLS_H
99 case pcmk__client_tls:
100 #endif
101 case pcmk__client_tcp:
102 crm_debug("Sent %s notification to client %s (id %s)",
103 type, pcmk__client_name(client), client->id);
104 pcmk__remote_send_xml(client->remote, update->msg);
105 break;
106 default:
107 crm_err("Unknown transport for client %s "
108 CRM_XS " flags=%#016" PRIx64,
109 pcmk__client_name(client), client->flags);
110 }
111 }
112 }
113
114 static void
115 cib_notify_send(xmlNode * xml)
116 {
117 struct iovec *iov;
118 struct cib_notification_s update;
119
120 ssize_t bytes = 0;
121 int rc = pcmk__ipc_prepare_iov(0, xml, 0, &iov, &bytes);
122
123 if (rc == pcmk_rc_ok) {
124 update.msg = xml;
125 update.iov = iov;
126 update.iov_size = bytes;
127 pcmk__foreach_ipc_client(cib_notify_send_one, &update);
128
129 } else {
130 crm_notice("Could not notify clients: %s " CRM_XS " rc=%d",
131 pcmk_rc_str(rc), rc);
132 }
133 pcmk_free_ipc_event(iov);
134 }
135
136 void
137 cib_diff_notify(int options, const char *client, const char *call_id, const char *op,
138 xmlNode * update, int result, xmlNode * diff)
139 {
140 int add_updates = 0;
141 int add_epoch = 0;
142 int add_admin_epoch = 0;
143
144 int del_updates = 0;
145 int del_epoch = 0;
146 int del_admin_epoch = 0;
147
148 int log_level = LOG_TRACE;
149
150 if (diff == NULL) {
151 return;
152 }
153
154 if (result != pcmk_ok) {
155 log_level = LOG_WARNING;
156 }
157
158 cib_diff_version_details(diff, &add_admin_epoch, &add_epoch, &add_updates,
159 &del_admin_epoch, &del_epoch, &del_updates);
160
161 if (add_updates != del_updates) {
162 do_crm_log(log_level,
163 "Update (client: %s%s%s): %d.%d.%d -> %d.%d.%d (%s)",
164 client, call_id ? ", call:" : "", call_id ? call_id : "",
165 del_admin_epoch, del_epoch, del_updates,
166 add_admin_epoch, add_epoch, add_updates, pcmk_strerror(result));
167
168 } else if (diff != NULL) {
169 do_crm_log(log_level,
170 "Local-only Change (client:%s%s%s): %d.%d.%d (%s)",
171 client, call_id ? ", call: " : "", call_id ? call_id : "",
172 add_admin_epoch, add_epoch, add_updates, pcmk_strerror(result));
173 }
174
175 do_cib_notify(options, op, update, result, diff, T_CIB_DIFF_NOTIFY);
176 }
177
178 static void
179 do_cib_notify(int options, const char *op, xmlNode * update,
180 int result, xmlNode * result_data, const char *msg_type)
181 {
182 xmlNode *update_msg = NULL;
183 const char *id = NULL;
184
185 update_msg = create_xml_node(NULL, "notify");
186
187 if (result_data != NULL) {
188 id = crm_element_value(result_data, XML_ATTR_ID);
189 }
190
191 crm_xml_add(update_msg, F_TYPE, T_CIB_NOTIFY);
192 crm_xml_add(update_msg, F_SUBTYPE, msg_type);
193 crm_xml_add(update_msg, F_CIB_OPERATION, op);
194 crm_xml_add_int(update_msg, F_CIB_RC, result);
195
196 if (id != NULL) {
197 crm_xml_add(update_msg, F_CIB_OBJID, id);
198 }
199
200 if (update != NULL) {
201 crm_trace("Setting type to update->name: %s", crm_element_name(update));
202 crm_xml_add(update_msg, F_CIB_OBJTYPE, crm_element_name(update));
203
204 } else if (result_data != NULL) {
205 crm_trace("Setting type to new_obj->name: %s", crm_element_name(result_data));
206 crm_xml_add(update_msg, F_CIB_OBJTYPE, crm_element_name(result_data));
207
208 } else {
209 crm_trace("Not Setting type");
210 }
211
212 attach_cib_generation(update_msg, "cib_generation", the_cib);
213 if (update != NULL) {
214 add_message_xml(update_msg, F_CIB_UPDATE, update);
215 }
216 if (result_data != NULL) {
217 add_message_xml(update_msg, F_CIB_UPDATE_RESULT, result_data);
218 }
219
220 cib_notify_send(update_msg);
221 free_xml(update_msg);
222 }
223
224 void
225 attach_cib_generation(xmlNode * msg, const char *field, xmlNode * a_cib)
226 {
227 xmlNode *generation = create_xml_node(NULL, XML_CIB_TAG_GENERATION_TUPPLE);
228
229 if (a_cib != NULL) {
230 copy_in_properties(generation, a_cib);
231 }
232 add_message_xml(msg, field, generation);
233 free_xml(generation);
234 }
235
236 void
237 cib_replace_notify(const char *origin, xmlNode * update, int result, xmlNode * diff, int change_section)
238 {
239 xmlNode *replace_msg = NULL;
240
241 int add_updates = 0;
242 int add_epoch = 0;
243 int add_admin_epoch = 0;
244
245 int del_updates = 0;
246 int del_epoch = 0;
247 int del_admin_epoch = 0;
248
249 if (diff == NULL) {
250 return;
251 }
252
253 cib_diff_version_details(diff, &add_admin_epoch, &add_epoch, &add_updates,
254 &del_admin_epoch, &del_epoch, &del_updates);
255
256 if (del_updates < 0) {
257 crm_log_xml_debug(diff, "Bad replace diff");
258 }
259
260 if (add_updates != del_updates) {
261 crm_info("Replaced: %d.%d.%d -> %d.%d.%d from %s",
262 del_admin_epoch, del_epoch, del_updates,
263 add_admin_epoch, add_epoch, add_updates, crm_str(origin));
264 } else if (diff != NULL) {
265 crm_info("Local-only Replace: %d.%d.%d from %s",
266 add_admin_epoch, add_epoch, add_updates, crm_str(origin));
267 }
268
269 replace_msg = create_xml_node(NULL, "notify-replace");
270 crm_xml_add(replace_msg, F_TYPE, T_CIB_NOTIFY);
271 crm_xml_add(replace_msg, F_SUBTYPE, T_CIB_REPLACE_NOTIFY);
272 crm_xml_add(replace_msg, F_CIB_OPERATION, CIB_OP_REPLACE);
273 crm_xml_add_int(replace_msg, F_CIB_RC, result);
274 crm_xml_add_int(replace_msg, F_CIB_CHANGE_SECTION, change_section);
275 attach_cib_generation(replace_msg, "cib-replace-generation", update);
276
277 crm_log_xml_trace(replace_msg, "CIB Replaced");
278
279 cib_notify_send(replace_msg);
280 free_xml(replace_msg);
281 }