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

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