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