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-2022 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 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     /* 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, 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 }

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