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