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-2021 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     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) {
     /* [previous][next][first][last][top][bottom][index][help] */
 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     /* Add the -q option, which cannot be part of the globally supported options
 167      * because some tools use that flag for something else.
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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, "itBDEHKNPS");
 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 }

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