This source file includes following definitions.
- cib_enable_writes
- setup_stand_alone
- based_metadata
- build_arg_context
- main
- cib_cs_dispatch
- cib_cs_destroy
- cib_peer_update_callback
- cib_init
- startCib
1
2
3
4
5
6
7
8
9
10 #include <crm_internal.h>
11
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <pwd.h>
15 #include <grp.h>
16 #include <bzlib.h>
17 #include <sys/types.h>
18
19 #include <glib.h>
20 #include <libxml/tree.h>
21
22 #include <crm/crm.h>
23 #include <crm/cib/internal.h>
24 #include <crm/cluster/internal.h>
25 #include <crm/common/cmdline_internal.h>
26 #include <crm/common/mainloop.h>
27 #include <crm/common/output_internal.h>
28 #include <crm/common/xml.h>
29
30 #include <pacemaker-based.h>
31
32 #define SUMMARY "daemon for managing the configuration of a Pacemaker cluster"
33
34 extern int init_remote_listener(int port, gboolean encrypted);
35 gboolean cib_shutdown_flag = FALSE;
36 int cib_status = pcmk_ok;
37
38 pcmk_cluster_t *crm_cluster = NULL;
39
40 GMainLoop *mainloop = NULL;
41 gchar *cib_root = NULL;
42 static gboolean preserve_status = FALSE;
43
44 gboolean cib_writes_enabled = TRUE;
45 gboolean stand_alone = FALSE;
46
47 int remote_fd = 0;
48 int remote_tls_fd = 0;
49
50 GHashTable *config_hash = NULL;
51
52 static void cib_init(void);
53 void cib_shutdown(int nsig);
54 static bool startCib(const char *filename);
55 extern int write_cib_contents(gpointer p);
56
57 static crm_exit_t exit_code = CRM_EX_OK;
58
59 static void
60 cib_enable_writes(int nsig)
61 {
62 crm_info("(Re)enabling disk writes");
63 cib_writes_enabled = TRUE;
64 }
65
66
67
68
69
70
71
72
73
74 static int
75 setup_stand_alone(GError **error)
76 {
77 int rc = 0;
78 struct passwd *pwentry = NULL;
79
80 preserve_status = TRUE;
81 cib_writes_enabled = FALSE;
82
83 errno = 0;
84 pwentry = getpwnam(CRM_DAEMON_USER);
85 if (pwentry == NULL) {
86 exit_code = CRM_EX_FATAL;
87 if (errno != 0) {
88 g_set_error(error, PCMK__EXITC_ERROR, exit_code,
89 "Error getting password DB entry for %s: %s",
90 CRM_DAEMON_USER, strerror(errno));
91 return errno;
92 }
93 g_set_error(error, PCMK__EXITC_ERROR, exit_code,
94 "Password DB entry for '%s' not found", CRM_DAEMON_USER);
95 return ENXIO;
96 }
97
98 rc = setgid(pwentry->pw_gid);
99 if (rc < 0) {
100 exit_code = CRM_EX_FATAL;
101 g_set_error(error, PCMK__EXITC_ERROR, exit_code,
102 "Could not set group to %d: %s",
103 pwentry->pw_gid, strerror(errno));
104 return errno;
105 }
106
107 rc = initgroups(CRM_DAEMON_USER, pwentry->pw_gid);
108 if (rc < 0) {
109 exit_code = CRM_EX_FATAL;
110 g_set_error(error, PCMK__EXITC_ERROR, exit_code,
111 "Could not setup groups for user %d: %s",
112 pwentry->pw_uid, strerror(errno));
113 return errno;
114 }
115
116 rc = setuid(pwentry->pw_uid);
117 if (rc < 0) {
118 exit_code = CRM_EX_FATAL;
119 g_set_error(error, PCMK__EXITC_ERROR, exit_code,
120 "Could not set user to %d: %s",
121 pwentry->pw_uid, strerror(errno));
122 return errno;
123 }
124 return pcmk_rc_ok;
125 }
126
127
128
129
130
131
132 static int
133 based_metadata(pcmk__output_t *out)
134 {
135 return pcmk__daemon_metadata(out, PCMK__SERVER_BASED,
136 "Cluster Information Base manager options",
137 "Cluster options used by Pacemaker's Cluster "
138 "Information Base manager",
139 pcmk__opt_based);
140 }
141
142 static GOptionEntry entries[] = {
143 { "stand-alone", 's', G_OPTION_FLAG_NONE, G_OPTION_ARG_NONE, &stand_alone,
144 "(Advanced use only) Run in stand-alone mode", NULL },
145
146 { "disk-writes", 'w', G_OPTION_FLAG_NONE, G_OPTION_ARG_NONE,
147 &cib_writes_enabled,
148 "(Advanced use only) Enable disk writes (enabled by default unless in "
149 "stand-alone mode)", NULL },
150
151 { "cib-root", 'r', G_OPTION_FLAG_NONE, G_OPTION_ARG_FILENAME, &cib_root,
152 "(Advanced use only) Directory where the CIB XML file should be located "
153 "(default: " CRM_CONFIG_DIR ")", NULL },
154
155 { NULL }
156 };
157
158 static pcmk__supported_format_t formats[] = {
159 PCMK__SUPPORTED_FORMAT_NONE,
160 PCMK__SUPPORTED_FORMAT_TEXT,
161 PCMK__SUPPORTED_FORMAT_XML,
162 { NULL, NULL, NULL }
163 };
164
165 static GOptionContext *
166 build_arg_context(pcmk__common_args_t *args, GOptionGroup **group)
167 {
168 GOptionContext *context = NULL;
169
170 context = pcmk__build_arg_context(args, "text (default), xml", group, NULL);
171 pcmk__add_main_args(context, entries);
172 return context;
173 }
174
175 int
176 main(int argc, char **argv)
177 {
178 int rc = pcmk_rc_ok;
179 crm_ipc_t *old_instance = NULL;
180
181 pcmk__output_t *out = NULL;
182
183 GError *error = NULL;
184
185 GOptionGroup *output_group = NULL;
186 pcmk__common_args_t *args = pcmk__new_common_args(SUMMARY);
187 gchar **processed_args = pcmk__cmdline_preproc(argv, "r");
188 GOptionContext *context = build_arg_context(args, &output_group);
189
190 crm_log_preinit(NULL, argc, argv);
191
192 pcmk__register_formats(output_group, formats);
193 if (!g_option_context_parse_strv(context, &processed_args, &error)) {
194 exit_code = CRM_EX_USAGE;
195 goto done;
196 }
197
198 rc = pcmk__output_new(&out, args->output_ty, args->output_dest, argv);
199 if (rc != pcmk_rc_ok) {
200 exit_code = CRM_EX_ERROR;
201 g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
202 "Error creating output format %s: %s",
203 args->output_ty, pcmk_rc_str(rc));
204 goto done;
205 }
206
207 if (args->version) {
208 out->version(out, false);
209 goto done;
210 }
211
212 mainloop_add_signal(SIGTERM, cib_shutdown);
213 mainloop_add_signal(SIGPIPE, cib_enable_writes);
214
215 cib_writer = mainloop_add_trigger(G_PRIORITY_LOW, write_cib_contents, NULL);
216
217 if ((g_strv_length(processed_args) >= 2)
218 && pcmk__str_eq(processed_args[1], "metadata", pcmk__str_none)) {
219
220 rc = based_metadata(out);
221 if (rc != pcmk_rc_ok) {
222 exit_code = CRM_EX_FATAL;
223 g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
224 "Unable to display metadata: %s", pcmk_rc_str(rc));
225 }
226 goto done;
227 }
228
229 pcmk__cli_init_logging(PCMK__SERVER_BASED, args->verbosity);
230 crm_log_init(NULL, LOG_INFO, TRUE, FALSE, argc, argv, FALSE);
231 crm_notice("Starting Pacemaker CIB manager");
232
233 old_instance = crm_ipc_new(PCMK__SERVER_BASED_RO, 0);
234 if (old_instance == NULL) {
235
236
237
238 exit_code = CRM_EX_FATAL;
239 goto done;
240 }
241
242 if (pcmk__connect_generic_ipc(old_instance) == pcmk_rc_ok) {
243
244 crm_ipc_close(old_instance);
245 crm_ipc_destroy(old_instance);
246 crm_crit("Aborting start-up because another CIB manager instance is "
247 "already active");
248 goto done;
249 } else {
250
251 crm_ipc_destroy(old_instance);
252 old_instance = NULL;
253 }
254
255 if (stand_alone) {
256 rc = setup_stand_alone(&error);
257 if (rc != pcmk_rc_ok) {
258 goto done;
259 }
260 }
261
262 if (cib_root == NULL) {
263 cib_root = g_strdup(CRM_CONFIG_DIR);
264 } else {
265 crm_notice("Using custom config location: %s", cib_root);
266 }
267
268 if (!pcmk__daemon_can_write(cib_root, NULL)) {
269 exit_code = CRM_EX_FATAL;
270 crm_err("Terminating due to bad permissions on %s", cib_root);
271 g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
272 "Bad permissions on %s (see logs for details)", cib_root);
273 goto done;
274 }
275
276 pcmk__cluster_init_node_caches();
277
278
279 cib_init();
280
281
282 mainloop = g_main_loop_new(NULL, FALSE);
283 crm_notice("Pacemaker CIB manager successfully started and accepting connections");
284 g_main_loop_run(mainloop);
285
286
287
288
289 pcmk_cluster_disconnect(crm_cluster);
290 pcmk__stop_based_ipc(ipcs_ro, ipcs_rw, ipcs_shm);
291
292 done:
293 g_strfreev(processed_args);
294 pcmk__free_arg_context(context);
295
296 pcmk__cluster_destroy_node_caches();
297
298 if (config_hash != NULL) {
299 g_hash_table_destroy(config_hash);
300 }
301 pcmk__client_cleanup();
302 pcmk_cluster_free(crm_cluster);
303 g_free(cib_root);
304
305 pcmk__output_and_clear_error(&error, out);
306
307 if (out != NULL) {
308 out->finish(out, exit_code, true, NULL);
309 pcmk__output_free(out);
310 }
311 pcmk__unregister_formats();
312 crm_exit(exit_code);
313 }
314
315 #if SUPPORT_COROSYNC
316 static void
317 cib_cs_dispatch(cpg_handle_t handle,
318 const struct cpg_name *groupName,
319 uint32_t nodeid, uint32_t pid, void *msg, size_t msg_len)
320 {
321 xmlNode *xml = NULL;
322 const char *from = NULL;
323 char *data = pcmk__cpg_message_data(handle, nodeid, pid, msg, &from);
324
325 if(data == NULL) {
326 return;
327 }
328
329 xml = pcmk__xml_parse(data);
330 if (xml == NULL) {
331 crm_err("Invalid XML: '%.120s'", data);
332 free(data);
333 return;
334 }
335 crm_xml_add(xml, PCMK__XA_SRC, from);
336 cib_peer_callback(xml, NULL);
337
338 pcmk__xml_free(xml);
339 free(data);
340 }
341
342 static void
343 cib_cs_destroy(gpointer user_data)
344 {
345 if (cib_shutdown_flag) {
346 crm_info("Corosync disconnection complete");
347 } else {
348 crm_crit("Lost connection to cluster layer, shutting down");
349 terminate_cib(__func__, CRM_EX_DISCONNECT);
350 }
351 }
352 #endif
353
354 static void
355 cib_peer_update_callback(enum pcmk__node_update type,
356 pcmk__node_status_t *node, const void *data)
357 {
358 switch (type) {
359 case pcmk__node_update_name:
360 case pcmk__node_update_state:
361 if (cib_shutdown_flag && (pcmk__cluster_num_active_nodes() < 2)
362 && (pcmk__ipc_client_count() == 0)) {
363
364 crm_info("No more peers");
365 terminate_cib(__func__, -1);
366 }
367 break;
368
369 default:
370 break;
371 }
372 }
373
374 static void
375 cib_init(void)
376 {
377 crm_cluster = pcmk_cluster_new();
378
379 #if SUPPORT_COROSYNC
380 if (pcmk_get_cluster_layer() == pcmk_cluster_layer_corosync) {
381 pcmk_cluster_set_destroy_fn(crm_cluster, cib_cs_destroy);
382 pcmk_cpg_set_deliver_fn(crm_cluster, cib_cs_dispatch);
383 pcmk_cpg_set_confchg_fn(crm_cluster, pcmk__cpg_confchg_cb);
384 }
385 #endif
386
387 config_hash = pcmk__strkey_table(free, free);
388
389 if (startCib("cib.xml") == FALSE) {
390 crm_crit("Cannot start CIB... terminating");
391 crm_exit(CRM_EX_NOINPUT);
392 }
393
394 if (!stand_alone) {
395 pcmk__cluster_set_status_callback(&cib_peer_update_callback);
396
397 if (pcmk_cluster_connect(crm_cluster) != pcmk_rc_ok) {
398 crm_crit("Cannot sign in to the cluster... terminating");
399 crm_exit(CRM_EX_FATAL);
400 }
401 }
402
403 pcmk__serve_based_ipc(&ipcs_ro, &ipcs_rw, &ipcs_shm, &ipc_ro_callbacks,
404 &ipc_rw_callbacks);
405
406 if (stand_alone) {
407 based_is_primary = true;
408 }
409 }
410
411 static bool
412 startCib(const char *filename)
413 {
414 gboolean active = FALSE;
415 xmlNode *cib = readCibXmlFile(cib_root, filename, !preserve_status);
416
417 if (activateCibXml(cib, TRUE, "start") == 0) {
418 int port = 0;
419
420 active = TRUE;
421
422 cib_read_config(config_hash, cib);
423
424 pcmk__scan_port(crm_element_value(cib, PCMK_XA_REMOTE_TLS_PORT), &port);
425 if (port >= 0) {
426 remote_tls_fd = init_remote_listener(port, TRUE);
427 }
428
429 pcmk__scan_port(crm_element_value(cib, PCMK_XA_REMOTE_CLEAR_PORT),
430 &port);
431 if (port >= 0) {
432 remote_fd = init_remote_listener(port, FALSE);
433 }
434 }
435 return active;
436 }