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/common/xml.h>
23 #include <crm/cib.h>
24 #include <crm/cib/internal.h>
25 #include <crm/common/ipc_controld.h>
26 #include <crm/common/attrs_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, PCMK_XE_NODE_INFO,
163 PCMK_XA_NODEID, id_s,
164 NULL);
165
166 free(id_s);
167 return pcmk_rc_ok;
168 }
169
170 PCMK__OUTPUT_ARGS("simple-node-list", "GList *")
171 static int
172 simple_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("simple-node-list", "GList *")
186 static int
187 simple_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, PCMK_XE_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, PCMK_XE_NODE,
198 PCMK_XA_ID, id_s,
199 PCMK_XA_NAME, node->uname,
200 PCMK_XA_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, PCMK_XE_NODE_INFO,
230 PCMK_XA_NODEID, id_s,
231 PCMK_XA_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, PCMK_XE_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, PCMK_XE_NODE,
277 PCMK_XA_ID, id_s,
278 PCMK_XA_NAME, node->uname,
279 PCMK_XA_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, PCMK_XE_CLUSTER_INFO,
304 PCMK_XA_QUORUM, pcmk__btoa(have_quorum),
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-name", "default", node_name_default },
313 { "node-name", "xml", node_name_xml },
314 { "partition-list", "default", partition_list_default },
315 { "partition-list", "xml", partition_list_xml },
316 { "quorum", "default", quorum_default },
317 { "quorum", "xml", quorum_xml },
318 { "simple-node-list", "default", simple_node_list_default },
319 { "simple-node-list", "xml", simple_node_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, "simple-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 = 0;
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 "_"
469 PCMK__META_ON_NODE);
470
471 if (name != NULL) {
472 rc = out->message(out, "node-name", 0UL, name);
473 goto done;
474 }
475 }
476
477
478
479
480
481
482
483 rc = pcmk__query_node_name(out, nodeid, &node_name, 0);
484 if (rc != pcmk_rc_ok) {
485 exit_code = pcmk_rc2exitc(rc);
486 return;
487 }
488
489 rc = out->message(out, "node-name", 0UL, node_name);
490
491 done:
492 if (node_name != NULL) {
493 free(node_name);
494 }
495
496 if (rc != pcmk_rc_ok) {
497 g_set_error(&error, PCMK__RC_ERROR, rc, "Could not print node name: %s",
498 pcmk_rc_str(rc));
499 }
500
501 exit_code = pcmk_rc2exitc(rc);
502 }
503
504 static void
505 print_quorum(void)
506 {
507 bool quorum;
508 int rc = pcmk__query_node_info(out, NULL, NULL, NULL, NULL, &quorum, NULL,
509 false, 0);
510
511 if (rc != pcmk_rc_ok) {
512
513
514
515
516 exit_code = pcmk_rc2exitc(rc);
517 return;
518 }
519
520 rc = out->message(out, "quorum", quorum);
521
522 if (rc != pcmk_rc_ok) {
523 g_set_error(&error, PCMK__RC_ERROR, rc, "Could not print quorum status: %s",
524 pcmk_rc_str(rc));
525 }
526
527 exit_code = pcmk_rc2exitc(rc);
528 }
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543 static int
544 remove_from_section(cib_t *cib, const char *element, const char *section,
545 const char *node_name, long node_id)
546 {
547 int rc = pcmk_rc_ok;
548 xmlNode *xml = pcmk__xe_create(NULL, element);
549
550 crm_xml_add(xml, PCMK_XA_UNAME, node_name);
551 if (node_id > 0) {
552 crm_xml_add_ll(xml, PCMK_XA_ID, node_id);
553 }
554
555 rc = cib->cmds->remove(cib, section, xml, cib_transaction);
556 free_xml(xml);
557 return (rc >= 0)? pcmk_rc_ok : pcmk_legacy2rc(rc);
558 }
559
560
561
562
563
564
565
566
567
568
569
570 static int
571 purge_node_from_cib(const char *node_name, long node_id)
572 {
573 int rc = pcmk_rc_ok;
574 int commit_rc = pcmk_rc_ok;
575 cib_t *cib = NULL;
576
577
578 cib = cib_new();
579 if (cib == NULL) {
580 return ENOTCONN;
581 }
582 rc = cib__signon_attempts(cib, crm_system_name, cib_command, 5);
583 if (rc == pcmk_ok) {
584 rc = cib->cmds->init_transaction(cib);
585 }
586 if (rc != pcmk_ok) {
587 rc = pcmk_legacy2rc(rc);
588 cib__clean_up_connection(&cib);
589 return rc;
590 }
591
592
593 rc = remove_from_section(cib, PCMK_XE_NODE, PCMK_XE_NODES, node_name,
594 node_id);
595 if (rc == pcmk_rc_ok) {
596 rc = remove_from_section(cib, PCMK__XE_NODE_STATE, PCMK_XE_STATUS,
597 node_name, node_id);
598 }
599
600
601 commit_rc = cib->cmds->end_transaction(cib, (rc == pcmk_rc_ok),
602 cib_sync_call);
603 cib__clean_up_connection(&cib);
604
605 if ((rc == pcmk_rc_ok) && (commit_rc == pcmk_ok)) {
606 crm_debug("Purged node %s (%ld) from CIB",
607 pcmk__s(node_name, "by ID"), node_id);
608 }
609 return rc;
610 }
611
612
613
614
615
616
617
618
619
620
621
622
623 static int
624 purge_node_from(enum pcmk_ipc_server server, const char *node_name,
625 long node_id)
626 {
627 pcmk_ipc_api_t *api = NULL;
628 int rc;
629
630 rc = pcmk_new_ipc_api(&api, server);
631 if (rc != pcmk_rc_ok) {
632 goto done;
633 }
634
635 rc = pcmk__connect_ipc(api, pcmk_ipc_dispatch_sync, 5);
636 if (rc != pcmk_rc_ok) {
637 goto done;
638 }
639
640 rc = pcmk_ipc_purge_node(api, node_name, node_id);
641 done:
642 if (rc != pcmk_rc_ok) {
643 g_set_error(&error, PCMK__RC_ERROR, rc,
644 "Could not purge node %s from %s: %s",
645 pcmk__s(node_name, "by ID"), pcmk_ipc_name(api, true),
646 pcmk_rc_str(rc));
647 }
648 pcmk_free_ipc_api(api);
649 return rc;
650 }
651
652
653
654
655
656
657
658
659
660
661
662 static int
663 purge_node_from_fencer(const char *node_name, long node_id)
664 {
665 int rc = pcmk_rc_ok;
666 crm_ipc_t *conn = NULL;
667 xmlNode *cmd = NULL;
668
669 conn = crm_ipc_new("stonith-ng", 0);
670 if (conn == NULL) {
671 rc = ENOTCONN;
672 exit_code = pcmk_rc2exitc(rc);
673 g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
674 "Could not connect to fencer to purge node %s",
675 pcmk__s(node_name, "by ID"));
676 return rc;
677 }
678
679 rc = pcmk__connect_generic_ipc(conn);
680 if (rc != pcmk_rc_ok) {
681 exit_code = pcmk_rc2exitc(rc);
682 g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
683 "Could not connect to fencer to purge node %s: %s",
684 pcmk__s(node_name, "by ID"), pcmk_rc_str(rc));
685 crm_ipc_destroy(conn);
686 return rc;
687 }
688
689 cmd = create_request(CRM_OP_RM_NODE_CACHE, NULL, NULL, "stonith-ng",
690 crm_system_name, NULL);
691 if (node_id > 0) {
692 crm_xml_add_ll(cmd, PCMK_XA_ID, node_id);
693 }
694 crm_xml_add(cmd, PCMK_XA_UNAME, node_name);
695
696 rc = crm_ipc_send(conn, cmd, 0, 0, NULL);
697 if (rc >= 0) {
698 rc = pcmk_rc_ok;
699 crm_debug("Purged node %s (%ld) from fencer",
700 pcmk__s(node_name, "by ID"), node_id);
701 } else {
702 rc = pcmk_legacy2rc(rc);
703 fprintf(stderr, "Could not purge node %s from fencer: %s\n",
704 pcmk__s(node_name, "by ID"), pcmk_rc_str(rc));
705 }
706 free_xml(cmd);
707 crm_ipc_close(conn);
708 crm_ipc_destroy(conn);
709 return rc;
710 }
711
712 static void
713 remove_node(const char *target_uname)
714 {
715 int rc = pcmk_rc_ok;
716 long nodeid = 0;
717 const char *node_name = NULL;
718 char *endptr = NULL;
719 const enum pcmk_ipc_server servers[] = {
720 pcmk_ipc_controld,
721 pcmk_ipc_attrd,
722 };
723
724
725 errno = 0;
726 nodeid = strtol(target_uname, &endptr, 10);
727 if ((errno != 0) || (endptr == target_uname) || (*endptr != '\0')
728 || (nodeid <= 0)) {
729
730 nodeid = 0;
731 node_name = target_uname;
732 }
733
734 for (int i = 0; i < PCMK__NELEM(servers); ++i) {
735 rc = purge_node_from(servers[i], node_name, nodeid);
736 if (rc != pcmk_rc_ok) {
737 exit_code = pcmk_rc2exitc(rc);
738 return;
739 }
740 }
741
742
743 rc = purge_node_from_fencer(node_name, nodeid);
744 if (rc != pcmk_rc_ok) {
745 exit_code = pcmk_rc2exitc(rc);
746 return;
747 }
748
749
750 rc = purge_node_from_cib(node_name, nodeid);
751 exit_code = pcmk_rc2exitc(rc);
752 }
753
754 static GOptionContext *
755 build_arg_context(pcmk__common_args_t *args, GOptionGroup **group) {
756 GOptionContext *context = NULL;
757
758 GOptionEntry extra_prog_entries[] = {
759 { "quiet", 'Q', 0, G_OPTION_ARG_NONE, &(args->quiet),
760 "Be less descriptive in output.",
761 NULL },
762
763 { NULL }
764 };
765
766 context = pcmk__build_arg_context(args, "text (default), xml", group, NULL);
767
768
769
770
771 pcmk__add_main_args(context, extra_prog_entries);
772
773 pcmk__add_arg_group(context, "commands", "Commands:",
774 "Show command help", command_entries);
775 pcmk__add_arg_group(context, "additional", "Additional Options:",
776 "Show additional options", addl_entries);
777 return context;
778 }
779
780 int
781 main(int argc, char **argv)
782 {
783 int rc = pcmk_rc_ok;
784
785 GOptionGroup *output_group = NULL;
786 pcmk__common_args_t *args = pcmk__new_common_args(SUMMARY);
787 gchar **processed_args = pcmk__cmdline_preproc(argv, "NR");
788 GOptionContext *context = build_arg_context(args, &output_group);
789
790 pcmk__register_formats(output_group, formats);
791 if (!g_option_context_parse_strv(context, &processed_args, &error)) {
792 exit_code = CRM_EX_USAGE;
793 goto done;
794 }
795
796 pcmk__cli_init_logging("crm_node", args->verbosity);
797
798 rc = pcmk__output_new(&out, args->output_ty, args->output_dest, argv);
799 if (rc != pcmk_rc_ok) {
800 exit_code = pcmk_rc2exitc(rc);
801 g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
802 "Error creating output format %s: %s", args->output_ty,
803 pcmk_rc_str(rc));
804 goto done;
805 }
806
807 if (args->version) {
808 out->version(out, false);
809 goto done;
810 }
811
812 if (options.command == 0) {
813 char *help = g_option_context_get_help(context, TRUE, NULL);
814
815 out->err(out, "%s", help);
816 g_free(help);
817 exit_code = CRM_EX_USAGE;
818 goto done;
819 }
820
821 if (options.dangerous_cmd && options.force_flag == FALSE) {
822 exit_code = CRM_EX_USAGE;
823 g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
824 "The supplied command is considered dangerous."
825 " To prevent accidental destruction of the cluster,"
826 " the --force flag is required in order to proceed.");
827 goto done;
828 }
829
830 pcmk__register_lib_messages(out);
831 pcmk__register_messages(out, fmt_functions);
832
833 switch (options.command) {
834 case 'i':
835 print_node_id();
836 break;
837
838 case 'n':
839 print_node_name(0);
840 break;
841
842 case 'q':
843 print_quorum();
844 break;
845
846 case 'N':
847 print_node_name(options.nodeid);
848 break;
849
850 case 'R':
851 remove_node(options.target_uname);
852 break;
853
854 case 'l':
855 case 'p':
856 run_controller_mainloop();
857 break;
858
859 default:
860 break;
861 }
862
863 done:
864 g_strfreev(processed_args);
865 pcmk__free_arg_context(context);
866
867 pcmk__output_and_clear_error(&error, out);
868
869 if (out != NULL) {
870 out->finish(out, exit_code, true, NULL);
871 pcmk__output_free(out);
872 }
873 pcmk__unregister_formats();
874 return crm_exit(exit_code);
875 }