This source file includes following definitions.
- command_cb
- name_cb
- remove_cb
- PCMK__OUTPUT_ARGS
- PCMK__OUTPUT_ARGS
- PCMK__OUTPUT_ARGS
- PCMK__OUTPUT_ARGS
- PCMK__OUTPUT_ARGS
- PCMK__OUTPUT_ARGS
- PCMK__OUTPUT_ARGS
- PCMK__OUTPUT_ARGS
- PCMK__OUTPUT_ARGS
- PCMK__OUTPUT_ARGS
- sort_node
- controller_event_cb
- run_controller_mainloop
- print_node_id
- print_node_name
- print_quorum
- remove_from_section
- purge_node_from_cib
- purge_node_from
- purge_node_from_fencer
- remove_node
- build_arg_context
- main
1
2
3
4
5
6
7
8
9
10 #include <crm_internal.h>
11
12 #include <inttypes.h>
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <errno.h>
16 #include <sys/types.h>
17
18 #include <crm/crm.h>
19 #include <crm/common/cmdline_internal.h>
20 #include <crm/common/output_internal.h>
21 #include <crm/common/mainloop.h>
22 #include <crm/msg_xml.h>
23 #include <crm/cib.h>
24 #include <crm/cib/internal.h>
25 #include <crm/common/ipc_controld.h>
26 #include <crm/common/attrd_internal.h>
27
28 #include <pacemaker-internal.h>
29
30 #define SUMMARY "crm_node - Tool for displaying low-level node information"
31
32 struct {
33 gboolean corosync;
34 gboolean dangerous_cmd;
35 gboolean force_flag;
36 char command;
37 int nodeid;
38 char *target_uname;
39 } options = {
40 .command = '\0',
41 .force_flag = FALSE
42 };
43
44 gboolean command_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error);
45 gboolean name_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error);
46 gboolean remove_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error);
47
48 static GError *error = NULL;
49 static GMainLoop *mainloop = NULL;
50 static crm_exit_t exit_code = CRM_EX_OK;
51 static pcmk__output_t *out = NULL;
52
53 #define INDENT " "
54
55 static GOptionEntry command_entries[] = {
56 { "cluster-id", 'i', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, command_cb,
57 "Display this node's cluster id",
58 NULL },
59 { "list", 'l', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, command_cb,
60 "Display all known members (past and present) of this cluster",
61 NULL },
62 { "name", 'n', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, command_cb,
63 "Display the name used by the cluster for this node",
64 NULL },
65 { "partition", 'p', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, command_cb,
66 "Display the members of this partition",
67 NULL },
68 { "quorum", 'q', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, command_cb,
69 "Display a 1 if our partition has quorum, 0 if not",
70 NULL },
71 { "name-for-id", 'N', 0, G_OPTION_ARG_CALLBACK, name_cb,
72 "Display the name used by the cluster for the node with the specified ID",
73 "ID" },
74 { "remove", 'R', 0, G_OPTION_ARG_CALLBACK, remove_cb,
75 "(Advanced) Remove the (stopped) node with the specified name from Pacemaker's\n"
76 INDENT "configuration and caches (the node must already have been removed from\n"
77 INDENT "the underlying cluster stack configuration",
78 "NAME" },
79
80 { NULL }
81 };
82
83 static GOptionEntry addl_entries[] = {
84 { "force", 'f', 0, G_OPTION_ARG_NONE, &options.force_flag,
85 NULL,
86 NULL },
87 #if SUPPORT_COROSYNC
88
89 { "corosync", 'C', G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_NONE, &options.corosync,
90 NULL,
91 NULL },
92 #endif
93
94
95
96 { NULL }
97 };
98
99 static pcmk__supported_format_t formats[] = {
100 PCMK__SUPPORTED_FORMAT_NONE,
101 PCMK__SUPPORTED_FORMAT_TEXT,
102 PCMK__SUPPORTED_FORMAT_XML,
103 { NULL, NULL, NULL }
104 };
105
106 gboolean
107 command_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error) {
108 if (pcmk__str_eq("-i", option_name, pcmk__str_casei) || pcmk__str_eq("--cluster-id", option_name, pcmk__str_casei)) {
109 options.command = 'i';
110 } else if (pcmk__str_eq("-l", option_name, pcmk__str_casei) || pcmk__str_eq("--list", option_name, pcmk__str_casei)) {
111 options.command = 'l';
112 } else if (pcmk__str_eq("-n", option_name, pcmk__str_casei) || pcmk__str_eq("--name", option_name, pcmk__str_casei)) {
113 options.command = 'n';
114 } else if (pcmk__str_eq("-p", option_name, pcmk__str_casei) || pcmk__str_eq("--partition", option_name, pcmk__str_casei)) {
115 options.command = 'p';
116 } else if (pcmk__str_eq("-q", option_name, pcmk__str_casei) || pcmk__str_eq("--quorum", option_name, pcmk__str_casei)) {
117 options.command = 'q';
118 } else {
119 g_set_error(error, PCMK__EXITC_ERROR, CRM_EX_INVALID_PARAM, "Unknown param passed to command_cb: %s", option_name);
120 return FALSE;
121 }
122
123 return TRUE;
124 }
125
126 gboolean
127 name_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error) {
128 options.command = 'N';
129 pcmk__scan_min_int(optarg, &(options.nodeid), 0);
130 return TRUE;
131 }
132
133 gboolean
134 remove_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error) {
135 if (optarg == NULL) {
136 g_set_error(error, PCMK__EXITC_ERROR, CRM_EX_INVALID_PARAM, "-R option requires an argument");
137 return FALSE;
138 }
139
140 options.command = 'R';
141 options.dangerous_cmd = TRUE;
142 pcmk__str_update(&options.target_uname, optarg);
143 return TRUE;
144 }
145
146 PCMK__OUTPUT_ARGS("node-id", "uint32_t")
147 static int
148 node_id_default(pcmk__output_t *out, va_list args) {
149 uint32_t node_id = va_arg(args, uint32_t);
150
151 out->info(out, "%" PRIu32, node_id);
152 return pcmk_rc_ok;
153 }
154
155 PCMK__OUTPUT_ARGS("node-id", "uint32_t")
156 static int
157 node_id_xml(pcmk__output_t *out, va_list args) {
158 uint32_t node_id = va_arg(args, uint32_t);
159
160 char *id_s = crm_strdup_printf("%" PRIu32, node_id);
161
162 pcmk__output_create_xml_node(out, "node-info",
163 "nodeid", id_s,
164 NULL);
165
166 free(id_s);
167 return pcmk_rc_ok;
168 }
169
170 PCMK__OUTPUT_ARGS("node-list", "GList *")
171 static int
172 node_list_default(pcmk__output_t *out, va_list args)
173 {
174 GList *nodes = va_arg(args, GList *);
175
176 for (GList *node_iter = nodes; node_iter != NULL; node_iter = node_iter->next) {
177 pcmk_controld_api_node_t *node = node_iter->data;
178 out->info(out, "%" PRIu32 " %s %s", node->id, pcmk__s(node->uname, ""),
179 pcmk__s(node->state, ""));
180 }
181
182 return pcmk_rc_ok;
183 }
184
185 PCMK__OUTPUT_ARGS("node-list", "GList *")
186 static int
187 node_list_xml(pcmk__output_t *out, va_list args)
188 {
189 GList *nodes = va_arg(args, GList *);
190
191 out->begin_list(out, NULL, NULL, "nodes");
192
193 for (GList *node_iter = nodes; node_iter != NULL; node_iter = node_iter->next) {
194 pcmk_controld_api_node_t *node = node_iter->data;
195 char *id_s = crm_strdup_printf("%" PRIu32, node->id);
196
197 pcmk__output_create_xml_node(out, "node",
198 "id", id_s,
199 "name", node->uname,
200 "state", node->state,
201 NULL);
202
203 free(id_s);
204 }
205
206 out->end_list(out);
207
208 return pcmk_rc_ok;
209 }
210
211 PCMK__OUTPUT_ARGS("node-name", "uint32_t", "const char *")
212 static int
213 node_name_default(pcmk__output_t *out, va_list args) {
214 uint32_t node_id G_GNUC_UNUSED = va_arg(args, uint32_t);
215 const char *node_name = va_arg(args, const char *);
216
217 out->info(out, "%s", node_name);
218 return pcmk_rc_ok;
219 }
220
221 PCMK__OUTPUT_ARGS("node-name", "uint32_t", "const char *")
222 static int
223 node_name_xml(pcmk__output_t *out, va_list args) {
224 uint32_t node_id = va_arg(args, uint32_t);
225 const char *node_name = va_arg(args, const char *);
226
227 char *id_s = crm_strdup_printf("%" PRIu32, node_id);
228
229 pcmk__output_create_xml_node(out, "node-info",
230 "nodeid", id_s,
231 XML_ATTR_UNAME, node_name,
232 NULL);
233
234 free(id_s);
235 return pcmk_rc_ok;
236 }
237
238 PCMK__OUTPUT_ARGS("partition-list", "GList *")
239 static int
240 partition_list_default(pcmk__output_t *out, va_list args)
241 {
242 GList *nodes = va_arg(args, GList *);
243
244 GString *buffer = NULL;
245
246 for (GList *node_iter = nodes; node_iter != NULL; node_iter = node_iter->next) {
247 pcmk_controld_api_node_t *node = node_iter->data;
248 if (pcmk__str_eq(node->state, "member", pcmk__str_none)) {
249 pcmk__add_separated_word(&buffer, 128, pcmk__s(node->uname, ""), " ");
250 }
251 }
252
253 if (buffer != NULL) {
254 out->info(out, "%s", buffer->str);
255 g_string_free(buffer, TRUE);
256 return pcmk_rc_ok;
257 }
258
259 return pcmk_rc_no_output;
260 }
261
262 PCMK__OUTPUT_ARGS("partition-list", "GList *")
263 static int
264 partition_list_xml(pcmk__output_t *out, va_list args)
265 {
266 GList *nodes = va_arg(args, GList *);
267
268 out->begin_list(out, NULL, NULL, "nodes");
269
270 for (GList *node_iter = nodes; node_iter != NULL; node_iter = node_iter->next) {
271 pcmk_controld_api_node_t *node = node_iter->data;
272
273 if (pcmk__str_eq(node->state, "member", pcmk__str_none)) {
274 char *id_s = crm_strdup_printf("%" PRIu32, node->id);
275
276 pcmk__output_create_xml_node(out, "node",
277 "id", id_s,
278 "name", node->uname,
279 "state", node->state,
280 NULL);
281 free(id_s);
282 }
283 }
284
285 out->end_list(out);
286 return pcmk_rc_ok;
287 }
288
289 PCMK__OUTPUT_ARGS("quorum", "bool")
290 static int
291 quorum_default(pcmk__output_t *out, va_list args) {
292 bool have_quorum = va_arg(args, int);
293
294 out->info(out, "%d", have_quorum);
295 return pcmk_rc_ok;
296 }
297
298 PCMK__OUTPUT_ARGS("quorum", "bool")
299 static int
300 quorum_xml(pcmk__output_t *out, va_list args) {
301 bool have_quorum = va_arg(args, int);
302
303 pcmk__output_create_xml_node(out, "cluster-info",
304 "quorum", have_quorum ? "true" : "false",
305 NULL);
306 return pcmk_rc_ok;
307 }
308
309 static pcmk__message_entry_t fmt_functions[] = {
310 { "node-id", "default", node_id_default },
311 { "node-id", "xml", node_id_xml },
312 { "node-list", "default", node_list_default },
313 { "node-list", "xml", node_list_xml },
314 { "node-name", "default", node_name_default },
315 { "node-name", "xml", node_name_xml },
316 { "quorum", "default", quorum_default },
317 { "quorum", "xml", quorum_xml },
318 { "partition-list", "default", partition_list_default },
319 { "partition-list", "xml", partition_list_xml },
320
321 { NULL, NULL, NULL }
322 };
323
324 static gint
325 sort_node(gconstpointer a, gconstpointer b)
326 {
327 const pcmk_controld_api_node_t *node_a = a;
328 const pcmk_controld_api_node_t *node_b = b;
329
330 return pcmk__numeric_strcasecmp((node_a->uname? node_a->uname : ""),
331 (node_b->uname? node_b->uname : ""));
332 }
333
334 static void
335 controller_event_cb(pcmk_ipc_api_t *controld_api,
336 enum pcmk_ipc_event event_type, crm_exit_t status,
337 void *event_data, void *user_data)
338 {
339 pcmk_controld_api_reply_t *reply = event_data;
340
341 switch (event_type) {
342 case pcmk_ipc_event_disconnect:
343 if (exit_code == CRM_EX_DISCONNECT) {
344 g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
345 "Lost connection to controller");
346 }
347 goto done;
348 break;
349
350 case pcmk_ipc_event_reply:
351 break;
352
353 default:
354 return;
355 }
356
357 if (status != CRM_EX_OK) {
358 exit_code = status;
359 g_set_error(&error, PCMK__EXITC_ERROR, status,
360 "Bad reply from controller: %s",
361 crm_exit_str(status));
362 goto done;
363 }
364
365 if (reply->reply_type != pcmk_controld_reply_nodes) {
366 g_set_error(&error, PCMK__EXITC_ERROR, CRM_EX_INDETERMINATE,
367 "Unknown reply type %d from controller",
368 reply->reply_type);
369 goto done;
370 }
371
372 reply->data.nodes = g_list_sort(reply->data.nodes, sort_node);
373
374 if (options.command == 'p') {
375 out->message(out, "partition-list", reply->data.nodes);
376 } else if (options.command == 'l') {
377 out->message(out, "node-list", reply->data.nodes);
378 }
379
380
381 exit_code = CRM_EX_OK;
382 done:
383 pcmk_disconnect_ipc(controld_api);
384 pcmk_quit_main_loop(mainloop, 10);
385 }
386
387 static void
388 run_controller_mainloop(void)
389 {
390 pcmk_ipc_api_t *controld_api = NULL;
391 int rc;
392
393
394 exit_code = CRM_EX_DISCONNECT;
395
396
397 rc = pcmk_new_ipc_api(&controld_api, pcmk_ipc_controld);
398 if (rc != pcmk_rc_ok) {
399 g_set_error(&error, PCMK__RC_ERROR, rc,
400 "Could not connect to controller: %s",
401 pcmk_rc_str(rc));
402 return;
403 }
404 pcmk_register_ipc_callback(controld_api, controller_event_cb, NULL);
405
406
407 rc = pcmk__connect_ipc(controld_api, pcmk_ipc_dispatch_main, 5);
408 if (rc != pcmk_rc_ok) {
409 exit_code = pcmk_rc2exitc(rc);
410 g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
411 "Could not connect to %s: %s",
412 pcmk_ipc_name(controld_api, true), pcmk_rc_str(rc));
413 return;
414 }
415
416 rc = pcmk_controld_api_list_nodes(controld_api);
417
418 if (rc != pcmk_rc_ok) {
419 pcmk_disconnect_ipc(controld_api);
420 exit_code = pcmk_rc2exitc(rc);
421 g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
422 "Could not ping controller: %s", pcmk_rc_str(rc));
423 return;
424 }
425
426
427 mainloop = g_main_loop_new(NULL, FALSE);
428 g_main_loop_run(mainloop);
429 g_main_loop_unref(mainloop);
430 mainloop = NULL;
431 pcmk_free_ipc_api(controld_api);
432 }
433
434 static void
435 print_node_id(void)
436 {
437 uint32_t nodeid;
438 int rc = pcmk__query_node_info(out, &nodeid, NULL, NULL, NULL, NULL, NULL,
439 false, 0);
440
441 if (rc != pcmk_rc_ok) {
442
443
444
445
446 exit_code = pcmk_rc2exitc(rc);
447 return;
448 }
449
450 rc = out->message(out, "node-id", nodeid);
451
452 if (rc != pcmk_rc_ok) {
453 g_set_error(&error, PCMK__RC_ERROR, rc, "Could not print node ID: %s",
454 pcmk_rc_str(rc));
455 }
456
457 exit_code = pcmk_rc2exitc(rc);
458 }
459
460 static void
461 print_node_name(uint32_t nodeid)
462 {
463 int rc = pcmk_rc_ok;
464 char *node_name = NULL;
465
466 if (nodeid == 0) {
467
468 const char *name = getenv("OCF_RESKEY_" CRM_META "_" XML_LRM_ATTR_TARGET);
469
470 if (name != NULL) {
471 rc = out->message(out, "node-name", 0, name);
472 goto done;
473 }
474 }
475
476
477
478
479
480
481
482 rc = pcmk__query_node_name(out, nodeid, &node_name, 0);
483 if (rc != pcmk_rc_ok) {
484 exit_code = pcmk_rc2exitc(rc);
485 return;
486 }
487
488 rc = out->message(out, "node-name", 0, node_name);
489
490 done:
491 if (node_name != NULL) {
492 free(node_name);
493 }
494
495 if (rc != pcmk_rc_ok) {
496 g_set_error(&error, PCMK__RC_ERROR, rc, "Could not print node name: %s",
497 pcmk_rc_str(rc));
498 }
499
500 exit_code = pcmk_rc2exitc(rc);
501 }
502
503 static void
504 print_quorum(void)
505 {
506 bool quorum;
507 int rc = pcmk__query_node_info(out, NULL, NULL, NULL, NULL, &quorum, NULL,
508 false, 0);
509
510 if (rc != pcmk_rc_ok) {
511
512
513
514
515 exit_code = pcmk_rc2exitc(rc);
516 return;
517 }
518
519 rc = out->message(out, "quorum", quorum);
520
521 if (rc != pcmk_rc_ok) {
522 g_set_error(&error, PCMK__RC_ERROR, rc, "Could not print quorum status: %s",
523 pcmk_rc_str(rc));
524 }
525
526 exit_code = pcmk_rc2exitc(rc);
527 }
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542 static int
543 remove_from_section(cib_t *cib, const char *element, const char *section,
544 const char *node_name, long node_id)
545 {
546 xmlNode *xml = NULL;
547 int rc = pcmk_rc_ok;
548
549 xml = create_xml_node(NULL, element);
550 if (xml == NULL) {
551 return pcmk_rc_error;
552 }
553 crm_xml_add(xml, XML_ATTR_UNAME, node_name);
554 if (node_id > 0) {
555 crm_xml_set_id(xml, "%ld", node_id);
556 }
557 rc = cib->cmds->remove(cib, section, xml, cib_transaction);
558 free_xml(xml);
559 return (rc >= 0)? pcmk_rc_ok : pcmk_legacy2rc(rc);
560 }
561
562
563
564
565
566
567
568
569
570
571
572 static int
573 purge_node_from_cib(const char *node_name, long node_id)
574 {
575 int rc = pcmk_rc_ok;
576 int commit_rc = pcmk_rc_ok;
577 cib_t *cib = NULL;
578
579
580 cib = cib_new();
581 if (cib == NULL) {
582 return ENOTCONN;
583 }
584 rc = cib->cmds->signon(cib, crm_system_name, cib_command);
585 if (rc == pcmk_ok) {
586 rc = cib->cmds->init_transaction(cib);
587 }
588 if (rc != pcmk_ok) {
589 rc = pcmk_legacy2rc(rc);
590 cib__clean_up_connection(&cib);
591 return rc;
592 }
593
594
595 rc = remove_from_section(cib, XML_CIB_TAG_NODE, XML_CIB_TAG_NODES,
596 node_name, node_id);
597 if (rc == pcmk_rc_ok) {
598 rc = remove_from_section(cib, XML_CIB_TAG_STATE, XML_CIB_TAG_STATUS,
599 node_name, node_id);
600 }
601
602
603 commit_rc = cib->cmds->end_transaction(cib, (rc == pcmk_rc_ok),
604 cib_sync_call);
605 cib__clean_up_connection(&cib);
606
607 if ((rc == pcmk_rc_ok) && (commit_rc == pcmk_ok)) {
608 crm_debug("Purged node %s (%ld) from CIB",
609 pcmk__s(node_name, "by ID"), node_id);
610 }
611 return rc;
612 }
613
614
615
616
617
618
619
620
621
622
623
624
625 static int
626 purge_node_from(enum pcmk_ipc_server server, const char *node_name,
627 long node_id)
628 {
629 pcmk_ipc_api_t *api = NULL;
630 int rc;
631
632 rc = pcmk_new_ipc_api(&api, server);
633 if (rc != pcmk_rc_ok) {
634 goto done;
635 }
636
637 rc = pcmk__connect_ipc(api, pcmk_ipc_dispatch_sync, 5);
638 if (rc != pcmk_rc_ok) {
639 goto done;
640 }
641
642 rc = pcmk_ipc_purge_node(api, node_name, node_id);
643 done:
644 if (rc != pcmk_rc_ok) {
645 g_set_error(&error, PCMK__RC_ERROR, rc,
646 "Could not purge node %s from %s: %s",
647 pcmk__s(node_name, "by ID"), pcmk_ipc_name(api, true),
648 pcmk_rc_str(rc));
649 }
650 pcmk_free_ipc_api(api);
651 return rc;
652 }
653
654
655
656
657
658
659
660
661
662
663
664 static int
665 purge_node_from_fencer(const char *node_name, long node_id)
666 {
667 int rc = pcmk_rc_ok;
668 crm_ipc_t *conn = NULL;
669 xmlNode *cmd = NULL;
670
671 conn = crm_ipc_new("stonith-ng", 0);
672 if (conn == NULL) {
673 rc = ENOTCONN;
674 exit_code = pcmk_rc2exitc(rc);
675 g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
676 "Could not connect to fencer to purge node %s",
677 pcmk__s(node_name, "by ID"));
678 return rc;
679 }
680
681 rc = pcmk__connect_generic_ipc(conn);
682 if (rc != pcmk_rc_ok) {
683 exit_code = pcmk_rc2exitc(rc);
684 g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
685 "Could not connect to fencer to purge node %s: %s",
686 pcmk__s(node_name, "by ID"), pcmk_rc_str(rc));
687 crm_ipc_destroy(conn);
688 return rc;
689 }
690
691 cmd = create_request(CRM_OP_RM_NODE_CACHE, NULL, NULL, "stonith-ng",
692 crm_system_name, NULL);
693 if (node_id > 0) {
694 crm_xml_set_id(cmd, "%ld", node_id);
695 }
696 crm_xml_add(cmd, XML_ATTR_UNAME, node_name);
697
698 rc = crm_ipc_send(conn, cmd, 0, 0, NULL);
699 if (rc >= 0) {
700 rc = pcmk_rc_ok;
701 crm_debug("Purged node %s (%ld) from fencer",
702 pcmk__s(node_name, "by ID"), node_id);
703 } else {
704 rc = pcmk_legacy2rc(rc);
705 fprintf(stderr, "Could not purge node %s from fencer: %s\n",
706 pcmk__s(node_name, "by ID"), pcmk_rc_str(rc));
707 }
708 free_xml(cmd);
709 crm_ipc_close(conn);
710 crm_ipc_destroy(conn);
711 return rc;
712 }
713
714 static void
715 remove_node(const char *target_uname)
716 {
717 int rc = pcmk_rc_ok;
718 long nodeid = 0;
719 const char *node_name = NULL;
720 char *endptr = NULL;
721 const enum pcmk_ipc_server servers[] = {
722 pcmk_ipc_controld,
723 pcmk_ipc_attrd,
724 };
725
726
727 errno = 0;
728 nodeid = strtol(target_uname, &endptr, 10);
729 if ((errno != 0) || (endptr == target_uname) || (*endptr != '\0')
730 || (nodeid <= 0)) {
731
732 nodeid = 0;
733 node_name = target_uname;
734 }
735
736 for (int i = 0; i < PCMK__NELEM(servers); ++i) {
737 rc = purge_node_from(servers[i], node_name, nodeid);
738 if (rc != pcmk_rc_ok) {
739 exit_code = pcmk_rc2exitc(rc);
740 return;
741 }
742 }
743
744
745 rc = purge_node_from_fencer(node_name, nodeid);
746 if (rc != pcmk_rc_ok) {
747 exit_code = pcmk_rc2exitc(rc);
748 return;
749 }
750
751
752 rc = purge_node_from_cib(node_name, nodeid);
753 exit_code = pcmk_rc2exitc(rc);
754 }
755
756 static GOptionContext *
757 build_arg_context(pcmk__common_args_t *args, GOptionGroup **group) {
758 GOptionContext *context = NULL;
759
760 GOptionEntry extra_prog_entries[] = {
761 { "quiet", 'Q', 0, G_OPTION_ARG_NONE, &(args->quiet),
762 "Be less descriptive in output.",
763 NULL },
764
765 { NULL }
766 };
767
768 context = pcmk__build_arg_context(args, "text (default), xml", group, NULL);
769
770
771
772
773 pcmk__add_main_args(context, extra_prog_entries);
774
775 pcmk__add_arg_group(context, "commands", "Commands:",
776 "Show command help", command_entries);
777 pcmk__add_arg_group(context, "additional", "Additional Options:",
778 "Show additional options", addl_entries);
779 return context;
780 }
781
782 int
783 main(int argc, char **argv)
784 {
785 int rc = pcmk_rc_ok;
786
787 GOptionGroup *output_group = NULL;
788 pcmk__common_args_t *args = pcmk__new_common_args(SUMMARY);
789 gchar **processed_args = pcmk__cmdline_preproc(argv, "NR");
790 GOptionContext *context = build_arg_context(args, &output_group);
791
792 pcmk__register_formats(output_group, formats);
793 if (!g_option_context_parse_strv(context, &processed_args, &error)) {
794 exit_code = CRM_EX_USAGE;
795 goto done;
796 }
797
798 pcmk__cli_init_logging("crm_node", args->verbosity);
799
800 rc = pcmk__output_new(&out, args->output_ty, args->output_dest, argv);
801 if (rc != pcmk_rc_ok) {
802 exit_code = pcmk_rc2exitc(rc);
803 g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
804 "Error creating output format %s: %s", args->output_ty,
805 pcmk_rc_str(rc));
806 goto done;
807 }
808
809 if (!pcmk__force_args(context, &error, "%s --xml-simple-list", g_get_prgname())) {
810 exit_code = CRM_EX_SOFTWARE;
811 goto done;
812 }
813
814 if (args->version) {
815 out->version(out, false);
816 goto done;
817 }
818
819 if (options.command == 0) {
820 char *help = g_option_context_get_help(context, TRUE, NULL);
821
822 out->err(out, "%s", help);
823 g_free(help);
824 exit_code = CRM_EX_USAGE;
825 goto done;
826 }
827
828 if (options.dangerous_cmd && options.force_flag == FALSE) {
829 exit_code = CRM_EX_USAGE;
830 g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
831 "The supplied command is considered dangerous."
832 " To prevent accidental destruction of the cluster,"
833 " the --force flag is required in order to proceed.");
834 goto done;
835 }
836
837 pcmk__register_lib_messages(out);
838 pcmk__register_messages(out, fmt_functions);
839
840 switch (options.command) {
841 case 'i':
842 print_node_id();
843 break;
844
845 case 'n':
846 print_node_name(0);
847 break;
848
849 case 'q':
850 print_quorum();
851 break;
852
853 case 'N':
854 print_node_name(options.nodeid);
855 break;
856
857 case 'R':
858 remove_node(options.target_uname);
859 break;
860
861 case 'l':
862 case 'p':
863 run_controller_mainloop();
864 break;
865
866 default:
867 break;
868 }
869
870 done:
871 g_strfreev(processed_args);
872 pcmk__free_arg_context(context);
873
874 pcmk__output_and_clear_error(&error, out);
875
876 if (out != NULL) {
877 out->finish(out, exit_code, true, NULL);
878 pcmk__output_free(out);
879 }
880 pcmk__unregister_formats();
881 return crm_exit(exit_code);
882 }