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 <glib.h>
20 #include <libxml/tree.h>
21
22 #include <crm/crm.h>
23 #include <crm/cib/internal.h>
24 #include <crm/msg_xml.h>
25 #include <crm/cluster/internal.h>
26 #include <crm/common/cmdline_internal.h>
27 #include <crm/common/mainloop.h>
28 #include <crm/common/output_internal.h>
29 #include <crm/common/xml.h>
30
31 #include <pacemaker-based.h>
32
33 #define SUMMARY "daemon for managing the configuration of a Pacemaker cluster"
34
35 extern int init_remote_listener(int port, gboolean encrypted);
36 gboolean cib_shutdown_flag = FALSE;
37 int cib_status = pcmk_ok;
38
39 crm_cluster_t *crm_cluster = NULL;
40
41 GMainLoop *mainloop = NULL;
42 gchar *cib_root = NULL;
43 static gboolean preserve_status = FALSE;
44
45 gboolean cib_writes_enabled = TRUE;
46 gboolean stand_alone = FALSE;
47
48 int remote_fd = 0;
49 int remote_tls_fd = 0;
50
51 GHashTable *config_hash = NULL;
52 GHashTable *local_notify_queue = 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 mainloop_add_signal(SIGTERM, cib_shutdown);
201 mainloop_add_signal(SIGPIPE, cib_enable_writes);
202
203 cib_writer = mainloop_add_trigger(G_PRIORITY_LOW, write_cib_contents, NULL);
204
205 if ((g_strv_length(processed_args) >= 2)
206 && pcmk__str_eq(processed_args[1], "metadata", pcmk__str_none)) {
207 cib_metadata();
208 goto done;
209 }
210
211 pcmk__cli_init_logging("pacemaker-based", args->verbosity);
212 crm_log_init(NULL, LOG_INFO, TRUE, FALSE, argc, argv, FALSE);
213 crm_notice("Starting Pacemaker CIB manager");
214
215 old_instance = crm_ipc_new(PCMK__SERVER_BASED_RO, 0);
216 if (old_instance == NULL) {
217
218
219
220 exit_code = CRM_EX_FATAL;
221 goto done;
222 }
223
224 if (pcmk__connect_generic_ipc(old_instance) == pcmk_rc_ok) {
225
226 crm_ipc_close(old_instance);
227 crm_ipc_destroy(old_instance);
228 crm_err("pacemaker-based is already active, aborting startup");
229 goto done;
230 } else {
231
232 crm_ipc_destroy(old_instance);
233 old_instance = NULL;
234 }
235
236 if (stand_alone) {
237 rc = setup_stand_alone(&error);
238 if (rc != pcmk_rc_ok) {
239 goto done;
240 }
241 }
242
243 if (cib_root == NULL) {
244 cib_root = g_strdup(CRM_CONFIG_DIR);
245 } else {
246 crm_notice("Using custom config location: %s", cib_root);
247 }
248
249 if (!pcmk__daemon_can_write(cib_root, NULL)) {
250 exit_code = CRM_EX_FATAL;
251 crm_err("Terminating due to bad permissions on %s", cib_root);
252 g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
253 "Bad permissions on %s (see logs for details)", cib_root);
254 goto done;
255 }
256
257 crm_peer_init();
258
259
260 cib_init();
261
262
263 mainloop = g_main_loop_new(NULL, FALSE);
264 crm_notice("Pacemaker CIB manager successfully started and accepting connections");
265 g_main_loop_run(mainloop);
266
267
268
269
270 crm_cluster_disconnect(crm_cluster);
271 pcmk__stop_based_ipc(ipcs_ro, ipcs_rw, ipcs_shm);
272
273 done:
274 g_strfreev(processed_args);
275 pcmk__free_arg_context(context);
276
277 crm_peer_destroy();
278
279 if (local_notify_queue != NULL) {
280 g_hash_table_destroy(local_notify_queue);
281 }
282
283 if (config_hash != NULL) {
284 g_hash_table_destroy(config_hash);
285 }
286 pcmk__client_cleanup();
287 pcmk_cluster_free(crm_cluster);
288 g_free(cib_root);
289
290 pcmk__output_and_clear_error(&error, out);
291
292 if (out != NULL) {
293 out->finish(out, exit_code, true, NULL);
294 pcmk__output_free(out);
295 }
296 pcmk__unregister_formats();
297 crm_exit(exit_code);
298 }
299
300 #if SUPPORT_COROSYNC
301 static void
302 cib_cs_dispatch(cpg_handle_t handle,
303 const struct cpg_name *groupName,
304 uint32_t nodeid, uint32_t pid, void *msg, size_t msg_len)
305 {
306 uint32_t kind = 0;
307 xmlNode *xml = NULL;
308 const char *from = NULL;
309 char *data = pcmk_message_common_cs(handle, nodeid, pid, msg, &kind, &from);
310
311 if(data == NULL) {
312 return;
313 }
314 if (kind == crm_class_cluster) {
315 xml = string2xml(data);
316 if (xml == NULL) {
317 crm_err("Invalid XML: '%.120s'", data);
318 free(data);
319 return;
320 }
321 crm_xml_add(xml, F_ORIG, from);
322
323 cib_peer_callback(xml, NULL);
324 }
325
326 free_xml(xml);
327 free(data);
328 }
329
330 static void
331 cib_cs_destroy(gpointer user_data)
332 {
333 if (cib_shutdown_flag) {
334 crm_info("Corosync disconnection complete");
335 } else {
336 crm_crit("Lost connection to cluster layer, shutting down");
337 terminate_cib(__func__, CRM_EX_DISCONNECT);
338 }
339 }
340 #endif
341
342 static void
343 cib_peer_update_callback(enum crm_status_type type, crm_node_t * node, const void *data)
344 {
345 switch (type) {
346 case crm_status_processes:
347 if (cib_legacy_mode()
348 && !pcmk_is_set(node->processes, crm_get_cluster_proc())) {
349
350 uint32_t old = data? *(const uint32_t *)data : 0;
351
352 if ((node->processes ^ old) & crm_proc_cpg) {
353 crm_info("Attempting to disable legacy mode after %s left the cluster",
354 node->uname);
355 legacy_mode = FALSE;
356 }
357 }
358 break;
359
360 case crm_status_uname:
361 case crm_status_nstate:
362 if (cib_shutdown_flag && (crm_active_peers() < 2)
363 && (pcmk__ipc_client_count() == 0)) {
364
365 crm_info("No more peers");
366 terminate_cib(__func__, -1);
367 }
368 break;
369 }
370 }
371
372 static void
373 cib_init(void)
374 {
375 crm_cluster = pcmk_cluster_new();
376
377 #if SUPPORT_COROSYNC
378 if (is_corosync_cluster()) {
379 crm_cluster->destroy = cib_cs_destroy;
380 crm_cluster->cpg.cpg_deliver_fn = cib_cs_dispatch;
381 crm_cluster->cpg.cpg_confchg_fn = pcmk_cpg_membership;
382 }
383 #endif
384
385 config_hash = pcmk__strkey_table(free, free);
386
387 if (startCib("cib.xml") == FALSE) {
388 crm_crit("Cannot start CIB... terminating");
389 crm_exit(CRM_EX_NOINPUT);
390 }
391
392 if (!stand_alone) {
393 crm_set_status_callback(&cib_peer_update_callback);
394
395 if (!crm_cluster_connect(crm_cluster)) {
396 crm_crit("Cannot sign in to the cluster... terminating");
397 crm_exit(CRM_EX_FATAL);
398 }
399 }
400
401 pcmk__serve_based_ipc(&ipcs_ro, &ipcs_rw, &ipcs_shm, &ipc_ro_callbacks,
402 &ipc_rw_callbacks);
403
404 if (stand_alone) {
405 based_is_primary = true;
406 }
407 }
408
409 static bool
410 startCib(const char *filename)
411 {
412 gboolean active = FALSE;
413 xmlNode *cib = readCibXmlFile(cib_root, filename, !preserve_status);
414
415 if (activateCibXml(cib, TRUE, "start") == 0) {
416 int port = 0;
417
418 active = TRUE;
419
420 cib_read_config(config_hash, cib);
421
422 pcmk__scan_port(crm_element_value(cib, "remote-tls-port"), &port);
423 if (port >= 0) {
424 remote_tls_fd = init_remote_listener(port, TRUE);
425 }
426
427 pcmk__scan_port(crm_element_value(cib, "remote-clear-port"), &port);
428 if (port >= 0) {
429 remote_fd = init_remote_listener(port, FALSE);
430 }
431 }
432 return active;
433 }