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