This source file includes following definitions.
- command_cb
- build_arg_context
- main
1
2
3
4
5
6
7
8
9
10 #include <crm_internal.h>
11
12 #include <stdio.h>
13 #include <stdbool.h>
14 #include <stdlib.h>
15
16 #include <glib.h>
17 #include <libxml/tree.h>
18
19 #include <pacemaker-internal.h>
20
21 #include <crm/common/cmdline_internal.h>
22 #include <crm/common/output_internal.h>
23
24 #define SUMMARY "query and manage the Pacemaker controller"
25
26 static enum {
27 cmd_none,
28 cmd_health,
29 cmd_whois_dc,
30 cmd_list_nodes,
31 cmd_pacemakerd_health,
32 } command = cmd_none;
33
34 struct {
35 gboolean health;
36 guint timeout;
37 char *optarg;
38 char *ipc_name;
39 gboolean bash_export;
40 } options = {
41 .timeout = 30000,
42 .optarg = NULL,
43 .ipc_name = NULL,
44 .bash_export = FALSE
45 };
46
47 gboolean command_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error);
48
49 static GOptionEntry command_options[] = {
50 { "status", 'S', 0, G_OPTION_ARG_CALLBACK, command_cb,
51 "Display the status of the specified node."
52 "\n Result is state of node's internal finite state"
53 "\n machine, which can be useful for debugging",
54 "NODE"
55 },
56 { "pacemakerd", 'P', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, command_cb,
57 "Display the status of local pacemakerd."
58 "\n Result is the state of the sub-daemons watched"
59 "\n by pacemakerd.",
60 NULL
61 },
62 { "dc_lookup", 'D', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, command_cb,
63 "Display the uname of the node co-ordinating the cluster."
64 "\n This is an internal detail rarely useful to"
65 "\n administrators except when deciding on which"
66 "\n node to examine the logs.",
67 NULL
68 },
69 { "nodes", 'N', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_CALLBACK, command_cb,
70 "Display the uname of all member nodes [optionally filtered by type (comma-separated)]"
71 "\n Types: all (default), cluster, guest, remote",
72 "TYPE"
73 },
74 { "health", 'H', G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_NONE, &options.health,
75 NULL,
76 NULL
77 },
78
79 { NULL }
80 };
81
82 static GOptionEntry additional_options[] = {
83 { "timeout", 't', 0, G_OPTION_ARG_CALLBACK, command_cb,
84 "Time to wait before declaring the operation"
85 "\n "
86 "failed (default 30s; use 0 to disable timeout)",
87 "DURATION"
88 },
89 { "bash-export", 'B', 0, G_OPTION_ARG_NONE, &options.bash_export,
90 "Display nodes as shell commands of the form 'export uname=uuid'"
91 "\n (valid with -N/--nodes)",
92 },
93 { "ipc-name", 'i', 0, G_OPTION_ARG_STRING, &options.ipc_name,
94 "Name to use for ipc instead of 'crmadmin' (with -P/--pacemakerd).",
95 "NAME"
96 },
97
98 { NULL }
99 };
100
101 gboolean
102 command_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error)
103 {
104 if (!strcmp(option_name, "--status") || !strcmp(option_name, "-S")) {
105 command = cmd_health;
106 crm_trace("Option %c => %s", 'S', optarg);
107 }
108
109 if (!strcmp(option_name, "--pacemakerd") || !strcmp(option_name, "-P")) {
110 command = cmd_pacemakerd_health;
111 }
112
113 if (!strcmp(option_name, "--dc_lookup") || !strcmp(option_name, "-D")) {
114 command = cmd_whois_dc;
115 }
116
117 if (!strcmp(option_name, "--nodes") || !strcmp(option_name, "-N")) {
118 command = cmd_list_nodes;
119 }
120
121 if (!strcmp(option_name, "--timeout") || !strcmp(option_name, "-t")) {
122 return pcmk_parse_interval_spec(optarg, &options.timeout) == pcmk_rc_ok;
123 }
124
125 pcmk__str_update(&options.optarg, optarg);
126 return TRUE;
127 }
128
129 static pcmk__supported_format_t formats[] = {
130 PCMK__SUPPORTED_FORMAT_NONE,
131 PCMK__SUPPORTED_FORMAT_TEXT,
132 PCMK__SUPPORTED_FORMAT_XML,
133 { NULL, NULL, NULL }
134 };
135
136 #define DESC \
137 "Notes:\n\n" \
138 "DURATION in any command line option can be specified as an integer\n" \
139 "number of seconds, an integer plus units (ms, msec, us, usec, s, sec,\n" \
140 "m, min, h, or hr), or an ISO 8601 period specification.\n\n" \
141 "Report bugs to " PCMK__BUG_URL
142
143
144 static GOptionContext *
145 build_arg_context(pcmk__common_args_t *args, GOptionGroup **group) {
146 GOptionContext *context = NULL;
147
148 GOptionEntry extra_prog_entries[] = {
149 { "quiet", 'q', 0, G_OPTION_ARG_NONE, &(args->quiet),
150 "Display only the essential query information",
151 NULL },
152
153 { NULL }
154 };
155
156 context = pcmk__build_arg_context(args, "text (default), xml", group, NULL);
157 g_option_context_set_description(context, DESC);
158
159
160
161
162 pcmk__add_main_args(context, extra_prog_entries);
163
164 pcmk__add_arg_group(context, "command", "Commands:",
165 "Show command options", command_options);
166 pcmk__add_arg_group(context, "additional", "Additional Options:",
167 "Show additional options", additional_options);
168 return context;
169 }
170
171 int
172 main(int argc, char **argv)
173 {
174 crm_exit_t exit_code = CRM_EX_OK;
175 int rc;
176 int argerr = 0;
177
178 GError *error = NULL;
179
180 pcmk__output_t *out = NULL;
181
182 GOptionGroup *output_group = NULL;
183 pcmk__common_args_t *args = pcmk__new_common_args(SUMMARY);
184 gchar **processed_args = pcmk__cmdline_preproc(argv, "itKNS");
185 GOptionContext *context = build_arg_context(args, &output_group);
186
187 pcmk__register_formats(output_group, formats);
188 if (!g_option_context_parse_strv(context, &processed_args, &error)) {
189 exit_code = CRM_EX_USAGE;
190 goto done;
191 }
192
193 pcmk__cli_init_logging("crmadmin", args->verbosity);
194
195 rc = pcmk__output_new(&out, args->output_ty, args->output_dest, argv);
196 if (rc != pcmk_rc_ok) {
197 exit_code = CRM_EX_ERROR;
198 g_set_error(&error, PCMK__EXITC_ERROR, exit_code, "Error creating output format %s: %s",
199 args->output_ty, pcmk_rc_str(rc));
200 goto done;
201 }
202
203 pcmk__register_lib_messages(out);
204
205 out->quiet = args->quiet;
206
207 if (args->version) {
208 out->version(out, false);
209 goto done;
210 }
211
212 if (options.health) {
213 out->err(out, "Cluster-wide health option not supported");
214 ++argerr;
215 }
216
217 if (command == cmd_none) {
218 out->err(out, "error: Must specify a command option");
219 ++argerr;
220 }
221
222 if (argerr) {
223 char *help = g_option_context_get_help(context, TRUE, NULL);
224
225 out->err(out, "%s", help);
226 g_free(help);
227 exit_code = CRM_EX_USAGE;
228 goto done;
229 }
230
231 switch (command) {
232 case cmd_health:
233 rc = pcmk__controller_status(out, options.optarg,
234 (unsigned int) options.timeout);
235 break;
236 case cmd_pacemakerd_health:
237 rc = pcmk__pacemakerd_status(out, options.ipc_name,
238 (unsigned int) options.timeout, true,
239 NULL);
240 break;
241 case cmd_list_nodes:
242 rc = pcmk__list_nodes(out, options.optarg, options.bash_export);
243 break;
244 case cmd_whois_dc:
245 rc = pcmk__designated_controller(out,
246 (unsigned int) options.timeout);
247 break;
248 case cmd_none:
249 rc = pcmk_rc_error;
250 break;
251 }
252
253 if (rc != pcmk_rc_ok) {
254 out->err(out, "error: Command failed: %s", pcmk_rc_str(rc));
255 exit_code = pcmk_rc2exitc(rc);
256 }
257
258 done:
259 g_strfreev(processed_args);
260 pcmk__free_arg_context(context);
261
262 pcmk__output_and_clear_error(&error, out);
263
264 if (out != NULL) {
265 out->finish(out, exit_code, true, NULL);
266 pcmk__output_free(out);
267 }
268 pcmk__unregister_formats();
269 return crm_exit(exit_code);
270 }