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-2023 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     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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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) {
     /* [previous][next][first][last][top][bottom][index][help] */
 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 " PCMK__BUG_URL;
 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     /* Add the -q option, which cannot be part of the globally supported options
 161      * because some tools use that flag for something else.
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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,
 239                                          (unsigned int) options.timeout);
 240             break;
 241         case cmd_pacemakerd_health:
 242             rc = pcmk__pacemakerd_status(out, options.ipc_name,
 243                                          (unsigned int) options.timeout, true,
 244                                          NULL);
 245             break;
 246         case cmd_list_nodes:
 247             rc = pcmk__list_nodes(out, options.optarg, options.bash_export);
 248             break;
 249         case cmd_whois_dc:
 250             rc = pcmk__designated_controller(out,
 251                                              (unsigned int) options.timeout);
 252             break;
 253         case cmd_none:
 254             rc = pcmk_rc_error;
 255             break;
 256     }
 257 
 258     if (rc != pcmk_rc_ok) {
 259         out->err(out, "error: Command failed: %s", pcmk_rc_str(rc));
 260         exit_code = pcmk_rc2exitc(rc);
 261     }
 262 
 263 done:
 264     g_strfreev(processed_args);
 265     pcmk__free_arg_context(context);
 266 
 267     pcmk__output_and_clear_error(&error, out);
 268 
 269     if (out != NULL) {
 270         out->finish(out, exit_code, true, NULL);
 271         pcmk__output_free(out);
 272     }
 273     pcmk__unregister_formats();
 274     return crm_exit(exit_code);
 275 }

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