root/tools/crmadmin.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. command_cb
  2. build_arg_context
  3. main

   1 /*
   2  * Copyright 2004-2024 the Pacemaker project contributors
   3  *
   4  * The version control history for this file may have further details.
   5  *
   6  * This source code is licensed under the GNU General Public License version 2
   7  * or later (GPLv2+) WITHOUT ANY WARRANTY.
   8  */
   9 
  10 #include <crm_internal.h>
  11 
  12 #include <stdio.h>
  13 #include <stdbool.h>
  14 #include <stdlib.h>             // atoi()
  15 
  16 #include <glib.h>               // gboolean, GMainLoop, etc.
  17 #include <libxml/tree.h>        // xmlNode
  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, // Default to 30 seconds
  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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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) {
     /* [previous][next][first][last][top][bottom][index][help] */
 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     /* Add the -q option, which cannot be part of the globally supported options
 160      * because some tools use that flag for something else.
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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 }

/* [previous][next][first][last][top][bottom][index][help] */