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 break;
243 case cmd_list_nodes:
244 rc = pcmk__list_nodes(out, options.optarg, options.BASH_EXPORT);
245 break;
246 case cmd_whois_dc:
247 rc = pcmk__designated_controller(out, options.timeout);
248 break;
249 case cmd_none:
250 rc = pcmk_rc_error;
251 break;
252 }
253
254 if (rc != pcmk_rc_ok) {
255 out->err(out, "error: Command failed: %s", pcmk_rc_str(rc));
256 exit_code = pcmk_rc2exitc(rc);
257 }
258
259 done:
260
261 g_strfreev(processed_args);
262 pcmk__free_arg_context(context);
263
264 pcmk__output_and_clear_error(error, out);
265
266 if (out != NULL) {
267 out->finish(out, exit_code, true, NULL);
268 pcmk__output_free(out);
269 }
270 return crm_exit(exit_code);
271
272 }