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