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 gint 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 options.timeout = crm_parse_interval_spec(optarg);
121 if (errno == EINVAL) {
122 return FALSE;
123 }
124 return TRUE;
125 }
126
127 pcmk__str_update(&options.optarg, optarg);
128 return TRUE;
129 }
130
131 static pcmk__supported_format_t formats[] = {
132 PCMK__SUPPORTED_FORMAT_NONE,
133 PCMK__SUPPORTED_FORMAT_TEXT,
134 PCMK__SUPPORTED_FORMAT_XML,
135 { NULL, NULL, NULL }
136 };
137
138 static GOptionContext *
139 build_arg_context(pcmk__common_args_t *args, GOptionGroup **group) {
140 GOptionContext *context = NULL;
141
142 const char *description = "Notes:\n\n"
143 "Time Specification:\n\n"
144 "The TIMESPEC in any command line option can be specified in many different\n"
145 "formats. It can be just an integer number of seconds, a number plus units\n"
146 "(ms/msec/us/usec/s/sec/m/min/h/hr), or an ISO 8601 period specification.\n\n"
147 "Report bugs to users@clusterlabs.org";
148
149 GOptionEntry extra_prog_entries[] = {
150 { "quiet", 'q', 0, G_OPTION_ARG_NONE, &(args->quiet),
151 "Display only the essential query information",
152 NULL },
153
154 { NULL }
155 };
156
157 context = pcmk__build_arg_context(args, "text (default), xml", group, NULL);
158 g_option_context_set_description(context, description);
159
160
161
162
163 pcmk__add_main_args(context, extra_prog_entries);
164
165 pcmk__add_arg_group(context, "command", "Commands:",
166 "Show command options", command_options);
167 pcmk__add_arg_group(context, "additional", "Additional Options:",
168 "Show additional options", additional_options);
169 return context;
170 }
171
172 int
173 main(int argc, char **argv)
174 {
175 crm_exit_t exit_code = CRM_EX_OK;
176 int rc;
177 int argerr = 0;
178
179 GError *error = NULL;
180
181 pcmk__output_t *out = NULL;
182
183 GOptionGroup *output_group = NULL;
184 pcmk__common_args_t *args = pcmk__new_common_args(SUMMARY);
185 gchar **processed_args = pcmk__cmdline_preproc(argv, "itKNS");
186 GOptionContext *context = build_arg_context(args, &output_group);
187
188 pcmk__register_formats(output_group, formats);
189 if (!g_option_context_parse_strv(context, &processed_args, &error)) {
190 exit_code = CRM_EX_USAGE;
191 goto done;
192 }
193
194 pcmk__cli_init_logging("crmadmin", args->verbosity);
195
196 rc = pcmk__output_new(&out, args->output_ty, args->output_dest, argv);
197 if (rc != pcmk_rc_ok) {
198 exit_code = CRM_EX_ERROR;
199 g_set_error(&error, PCMK__EXITC_ERROR, exit_code, "Error creating output format %s: %s",
200 args->output_ty, pcmk_rc_str(rc));
201 goto done;
202 }
203
204 pcmk__register_lib_messages(out);
205
206 out->quiet = args->quiet;
207
208 if (!pcmk__force_args(context, &error, "%s --xml-simple-list --xml-substitute", g_get_prgname())) {
209 goto done;
210 }
211
212 if (args->version) {
213 out->version(out, false);
214 goto done;
215 }
216
217 if (options.health) {
218 out->err(out, "Cluster-wide health option not supported");
219 ++argerr;
220 }
221
222 if (command == cmd_none) {
223 out->err(out, "error: Must specify a command option");
224 ++argerr;
225 }
226
227 if (argerr) {
228 char *help = g_option_context_get_help(context, TRUE, NULL);
229
230 out->err(out, "%s", help);
231 g_free(help);
232 exit_code = CRM_EX_USAGE;
233 goto done;
234 }
235
236 switch (command) {
237 case cmd_health:
238 rc = pcmk__controller_status(out, options.optarg, options.timeout);
239 break;
240 case cmd_pacemakerd_health:
241 rc = pcmk__pacemakerd_status(out, options.ipc_name, options.timeout,
242 NULL);
243 break;
244 case cmd_list_nodes:
245 rc = pcmk__list_nodes(out, options.optarg, options.bash_export);
246 break;
247 case cmd_whois_dc:
248 rc = pcmk__designated_controller(out, options.timeout);
249 break;
250 case cmd_none:
251 rc = pcmk_rc_error;
252 break;
253 }
254
255 if (rc != pcmk_rc_ok) {
256 out->err(out, "error: Command failed: %s", pcmk_rc_str(rc));
257 exit_code = pcmk_rc2exitc(rc);
258 }
259
260 done:
261
262 g_strfreev(processed_args);
263 pcmk__free_arg_context(context);
264
265 pcmk__output_and_clear_error(error, out);
266
267 if (out != NULL) {
268 out->finish(out, exit_code, true, NULL);
269 pcmk__output_free(out);
270 }
271 return crm_exit(exit_code);
272
273 }