This source file includes following definitions.
- attrd_cib_destroy_cb
- attrd_erase_cb
- attrd_erase_attrs
- attrd_cib_connect
- attrd_cib_init
- ipc_already_running
- build_arg_context
- main
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 <sys/stat.h>
16 #include <unistd.h>
17
18 #include <stdlib.h>
19 #include <errno.h>
20 #include <fcntl.h>
21
22 #include <crm/crm.h>
23 #include <crm/cib/internal.h>
24 #include <crm/msg_xml.h>
25 #include <crm/pengine/rules.h>
26 #include <crm/common/cmdline_internal.h>
27 #include <crm/common/iso8601.h>
28 #include <crm/common/ipc.h>
29 #include <crm/common/ipc_internal.h>
30 #include <crm/common/output_internal.h>
31 #include <crm/common/xml.h>
32 #include <crm/cluster/internal.h>
33
34 #include <crm/common/attrd_internal.h>
35 #include "pacemaker-attrd.h"
36
37 #define SUMMARY "daemon for managing Pacemaker node attributes"
38
39 gboolean stand_alone = FALSE;
40 gchar **log_files = NULL;
41
42 static GOptionEntry entries[] = {
43 { "stand-alone", 's', G_OPTION_FLAG_NONE, G_OPTION_ARG_NONE, &stand_alone,
44 "(Advanced use only) Run in stand-alone mode", NULL },
45
46 { "logfile", 'l', G_OPTION_FLAG_NONE, G_OPTION_ARG_FILENAME_ARRAY,
47 &log_files, "Send logs to the additional named logfile", NULL },
48
49 { NULL }
50 };
51
52 static pcmk__output_t *out = NULL;
53
54 static pcmk__supported_format_t formats[] = {
55 PCMK__SUPPORTED_FORMAT_NONE,
56 PCMK__SUPPORTED_FORMAT_TEXT,
57 PCMK__SUPPORTED_FORMAT_XML,
58 { NULL, NULL, NULL }
59 };
60
61 lrmd_t *the_lrmd = NULL;
62 crm_cluster_t *attrd_cluster = NULL;
63 crm_trigger_t *attrd_config_read = NULL;
64 crm_exit_t attrd_exit_status = CRM_EX_OK;
65
66 static void
67 attrd_cib_destroy_cb(gpointer user_data)
68 {
69 cib_t *conn = user_data;
70
71 conn->cmds->signoff(conn);
72
73 if (attrd_shutting_down()) {
74 crm_info("Connection disconnection complete");
75
76 } else {
77
78 crm_crit("Lost connection to the CIB manager, shutting down");
79 attrd_exit_status = CRM_EX_DISCONNECT;
80 attrd_shutdown(0);
81 }
82
83 return;
84 }
85
86 static void
87 attrd_erase_cb(xmlNode *msg, int call_id, int rc, xmlNode *output,
88 void *user_data)
89 {
90 do_crm_log_unlikely((rc? LOG_NOTICE : LOG_DEBUG),
91 "Cleared transient attributes: %s "
92 CRM_XS " xpath=%s rc=%d",
93 pcmk_strerror(rc), (char *) user_data, rc);
94 }
95
96 #define XPATH_TRANSIENT "//node_state[@uname='%s']/" XML_TAG_TRANSIENT_NODEATTRS
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112 static void
113 attrd_erase_attrs(void)
114 {
115 int call_id;
116 char *xpath = crm_strdup_printf(XPATH_TRANSIENT, attrd_cluster->uname);
117
118 crm_info("Clearing transient attributes from CIB " CRM_XS " xpath=%s",
119 xpath);
120
121 call_id = the_cib->cmds->remove(the_cib, xpath, NULL, cib_xpath);
122 the_cib->cmds->register_callback_full(the_cib, call_id, 120, FALSE, xpath,
123 "attrd_erase_cb", attrd_erase_cb,
124 free);
125 }
126
127 static int
128 attrd_cib_connect(int max_retry)
129 {
130 static int attempts = 0;
131
132 int rc = -ENOTCONN;
133
134 the_cib = cib_new();
135 if (the_cib == NULL) {
136 return -ENOTCONN;
137 }
138
139 do {
140 if(attempts > 0) {
141 sleep(attempts);
142 }
143
144 attempts++;
145 crm_debug("Connection attempt %d to the CIB manager", attempts);
146 rc = the_cib->cmds->signon(the_cib, T_ATTRD, cib_command);
147
148 } while(rc != pcmk_ok && attempts < max_retry);
149
150 if (rc != pcmk_ok) {
151 crm_err("Connection to the CIB manager failed: %s " CRM_XS " rc=%d",
152 pcmk_strerror(rc), rc);
153 goto cleanup;
154 }
155
156 crm_debug("Connected to the CIB manager after %d attempts", attempts);
157
158 rc = the_cib->cmds->set_connection_dnotify(the_cib, attrd_cib_destroy_cb);
159 if (rc != pcmk_ok) {
160 crm_err("Could not set disconnection callback");
161 goto cleanup;
162 }
163
164 rc = the_cib->cmds->add_notify_callback(the_cib, T_CIB_REPLACE_NOTIFY, attrd_cib_replaced_cb);
165 if(rc != pcmk_ok) {
166 crm_err("Could not set CIB notification callback");
167 goto cleanup;
168 }
169
170 rc = the_cib->cmds->add_notify_callback(the_cib, T_CIB_DIFF_NOTIFY, attrd_cib_updated_cb);
171 if (rc != pcmk_ok) {
172 crm_err("Could not set CIB notification callback (update)");
173 goto cleanup;
174 }
175
176 return pcmk_ok;
177
178 cleanup:
179 cib__clean_up_connection(&the_cib);
180 return -ENOTCONN;
181 }
182
183
184
185
186
187 static void
188 attrd_cib_init(void)
189 {
190
191 attrd_erase_attrs();
192
193
194 attrd_config_read = mainloop_add_trigger(G_PRIORITY_HIGH, attrd_read_options, NULL);
195
196
197 mainloop_set_trigger(attrd_config_read);
198 }
199
200 static bool
201 ipc_already_running(void)
202 {
203 pcmk_ipc_api_t *old_instance = NULL;
204 int rc = pcmk_rc_ok;
205
206 rc = pcmk_new_ipc_api(&old_instance, pcmk_ipc_attrd);
207 if (rc != pcmk_rc_ok) {
208 return false;
209 }
210
211 rc = pcmk_connect_ipc(old_instance, pcmk_ipc_dispatch_sync);
212 if (rc != pcmk_rc_ok) {
213 pcmk_free_ipc_api(old_instance);
214 return false;
215 }
216
217 pcmk_disconnect_ipc(old_instance);
218 pcmk_free_ipc_api(old_instance);
219 return true;
220 }
221
222 static GOptionContext *
223 build_arg_context(pcmk__common_args_t *args, GOptionGroup **group) {
224 GOptionContext *context = NULL;
225
226 context = pcmk__build_arg_context(args, "text (default), xml", group, NULL);
227 pcmk__add_main_args(context, entries);
228 return context;
229 }
230
231 int
232 main(int argc, char **argv)
233 {
234 int rc = pcmk_rc_ok;
235
236 GError *error = NULL;
237 bool initialized = false;
238
239 GOptionGroup *output_group = NULL;
240 pcmk__common_args_t *args = pcmk__new_common_args(SUMMARY);
241 gchar **processed_args = pcmk__cmdline_preproc(argv, NULL);
242 GOptionContext *context = build_arg_context(args, &output_group);
243
244 attrd_init_mainloop();
245 crm_log_preinit(NULL, argc, argv);
246 mainloop_add_signal(SIGTERM, attrd_shutdown);
247
248 pcmk__register_formats(output_group, formats);
249 if (!g_option_context_parse_strv(context, &processed_args, &error)) {
250 attrd_exit_status = CRM_EX_USAGE;
251 goto done;
252 }
253
254 rc = pcmk__output_new(&out, args->output_ty, args->output_dest, argv);
255 if ((rc != pcmk_rc_ok) || (out == NULL)) {
256 attrd_exit_status = CRM_EX_ERROR;
257 g_set_error(&error, PCMK__EXITC_ERROR, attrd_exit_status,
258 "Error creating output format %s: %s",
259 args->output_ty, pcmk_rc_str(rc));
260 goto done;
261 }
262
263 if (args->version) {
264 out->version(out, false);
265 goto done;
266 }
267
268
269 pcmk__add_logfiles(log_files, out);
270
271 crm_log_init(T_ATTRD, LOG_INFO, TRUE, FALSE, argc, argv, FALSE);
272 crm_notice("Starting Pacemaker node attribute manager%s",
273 stand_alone ? " in standalone mode" : "");
274
275 if (ipc_already_running()) {
276 const char *msg = "pacemaker-attrd is already active, aborting startup";
277
278 attrd_exit_status = CRM_EX_OK;
279 g_set_error(&error, PCMK__EXITC_ERROR, attrd_exit_status, "%s", msg);
280 crm_err(msg);
281 goto done;
282 }
283
284 initialized = true;
285
286 attributes = pcmk__strkey_table(NULL, attrd_free_attribute);
287
288
289
290
291
292 if (!stand_alone) {
293 if (attrd_cib_connect(30) != pcmk_ok) {
294 attrd_exit_status = CRM_EX_FATAL;
295 g_set_error(&error, PCMK__EXITC_ERROR, attrd_exit_status,
296 "Could not connect to the CIB");
297 goto done;
298 }
299 crm_info("CIB connection active");
300 }
301
302 if (attrd_cluster_connect() != pcmk_ok) {
303 attrd_exit_status = CRM_EX_FATAL;
304 g_set_error(&error, PCMK__EXITC_ERROR, attrd_exit_status,
305 "Could not connect to the cluster");
306 goto done;
307 }
308 crm_info("Cluster connection active");
309
310
311 attrd_election_init();
312
313 if (!stand_alone) {
314 attrd_cib_init();
315 }
316
317
318
319
320
321
322 attrd_broadcast_protocol();
323
324 attrd_init_ipc();
325 crm_notice("Pacemaker node attribute manager successfully started and accepting connections");
326 attrd_run_mainloop();
327
328 done:
329 if (initialized) {
330 crm_info("Shutting down attribute manager");
331
332 attrd_election_fini();
333 attrd_ipc_fini();
334 attrd_lrmd_disconnect();
335
336 if (!stand_alone) {
337 attrd_cib_disconnect();
338 }
339
340 attrd_free_waitlist();
341 pcmk_cluster_free(attrd_cluster);
342 g_hash_table_destroy(attributes);
343 }
344
345 g_strfreev(processed_args);
346 pcmk__free_arg_context(context);
347
348 g_strfreev(log_files);
349
350 pcmk__output_and_clear_error(&error, out);
351
352 if (out != NULL) {
353 out->finish(out, attrd_exit_status, true, NULL);
354 pcmk__output_free(out);
355 }
356 pcmk__unregister_formats();
357 crm_exit(attrd_exit_status);
358 }