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