root/lib/common/options.c

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

DEFINITIONS

This source file includes following definitions.
  1. pcmk__cli_help
  2. pcmk__env_option
  3. pcmk__set_env_option
  4. pcmk__env_option_enabled
  5. pcmk__valid_interval_spec
  6. pcmk__valid_boolean
  7. pcmk__valid_int
  8. pcmk__valid_positive_int
  9. pcmk__valid_no_quorum_policy
  10. pcmk__valid_percentage
  11. pcmk__valid_placement_strategy
  12. cluster_option_value
  13. pcmk__cluster_option
  14. pcmk__output_cluster_options
  15. pcmk__output_primitive_meta
  16. pcmk__output_fencing_params
  17. pcmk__daemon_metadata
  18. pcmk__validate_cluster_options

   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 Lesser General Public License
   7  * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
   8  */
   9 
  10 #ifndef _GNU_SOURCE
  11 #  define _GNU_SOURCE
  12 #endif
  13 
  14 #include <crm_internal.h>
  15 
  16 #include <stdio.h>
  17 #include <string.h>
  18 #include <stdlib.h>
  19 #include <sys/types.h>
  20 #include <sys/stat.h>
  21 
  22 #include <crm/crm.h>
  23 #include <crm/common/xml.h>
  24 
  25 void
  26 pcmk__cli_help(char cmd)
     /* [previous][next][first][last][top][bottom][index][help] */
  27 {
  28     if (cmd == 'v' || cmd == '$') {
  29         printf("Pacemaker %s\n", PACEMAKER_VERSION);
  30         printf("Written by Andrew Beekhof and "
  31                "the Pacemaker project contributors\n");
  32 
  33     } else if (cmd == '!') {
  34         printf("Pacemaker %s (Build: %s): %s\n", PACEMAKER_VERSION, BUILD_VERSION, CRM_FEATURES);
  35     }
  36 
  37     crm_exit(CRM_EX_OK);
  38     while(1); // above does not return
  39 }
  40 
  41 
  42 /*
  43  * Option metadata
  44  */
  45 
  46 static const pcmk__cluster_option_t cluster_options[] = {
  47     /* name, old name, type, allowed values,
  48      * default value, validator,
  49      * flags,
  50      * short description,
  51      * long description
  52      */
  53     {
  54         PCMK_OPT_DC_VERSION, NULL, PCMK_VALUE_VERSION, NULL,
  55         NULL, NULL,
  56         pcmk__opt_controld|pcmk__opt_generated,
  57         N_("Pacemaker version on cluster node elected Designated Controller "
  58             "(DC)"),
  59         N_("Includes a hash which identifies the exact revision the code was "
  60             "built from. Used for diagnostic purposes."),
  61     },
  62     {
  63         PCMK_OPT_CLUSTER_INFRASTRUCTURE, NULL, PCMK_VALUE_STRING, NULL,
  64         NULL, NULL,
  65         pcmk__opt_controld|pcmk__opt_generated,
  66         N_("The messaging layer on which Pacemaker is currently running"),
  67         N_("Used for informational and diagnostic purposes."),
  68     },
  69     {
  70         PCMK_OPT_CLUSTER_NAME, NULL, PCMK_VALUE_STRING, NULL,
  71         NULL, NULL,
  72         pcmk__opt_controld,
  73         N_("An arbitrary name for the cluster"),
  74         N_("This optional value is mostly for users' convenience as desired "
  75             "in administration, but may also be used in Pacemaker "
  76             "configuration rules via the #cluster-name node attribute, and "
  77             "by higher-level tools and resource agents."),
  78     },
  79     {
  80         PCMK_OPT_DC_DEADTIME, NULL, PCMK_VALUE_DURATION, NULL,
  81         "20s", pcmk__valid_interval_spec,
  82         pcmk__opt_controld,
  83         N_("How long to wait for a response from other nodes during start-up"),
  84         N_("The optimal value will depend on the speed and load of your "
  85             "network and the type of switches used."),
  86     },
  87     {
  88         PCMK_OPT_CLUSTER_RECHECK_INTERVAL, NULL, PCMK_VALUE_DURATION, NULL,
  89         "15min", pcmk__valid_interval_spec,
  90         pcmk__opt_controld,
  91         N_("Polling interval to recheck cluster state and evaluate rules "
  92             "with date specifications"),
  93         N_("Pacemaker is primarily event-driven, and looks ahead to know when "
  94             "to recheck cluster state for failure-timeout settings and most "
  95             "time-based rules. However, it will also recheck the cluster after "
  96             "this amount of inactivity, to evaluate rules with date "
  97             "specifications and serve as a fail-safe for certain types of "
  98             "scheduler bugs. A value of 0 disables polling. A positive value "
  99             "sets an interval in seconds, unless other units are specified "
 100             "(for example, \"5min\")."),
 101     },
 102     {
 103         PCMK_OPT_FENCE_REACTION, NULL, PCMK_VALUE_SELECT,
 104             PCMK_VALUE_STOP ", " PCMK_VALUE_PANIC,
 105         PCMK_VALUE_STOP, NULL,
 106         pcmk__opt_controld,
 107         N_("How a cluster node should react if notified of its own fencing"),
 108         N_("A cluster node may receive notification of a \"succeeded\" "
 109             "fencing that targeted it if fencing is misconfigured, or if "
 110             "fabric fencing is in use that doesn't cut cluster communication. "
 111             "Use \"stop\" to attempt to immediately stop Pacemaker and stay "
 112             "stopped, or \"panic\" to attempt to immediately reboot the local "
 113             "node, falling back to stop on failure."),
 114     },
 115     {
 116         PCMK_OPT_ELECTION_TIMEOUT, NULL, PCMK_VALUE_DURATION, NULL,
 117         "2min", pcmk__valid_interval_spec,
 118         pcmk__opt_controld|pcmk__opt_advanced,
 119         N_("Declare an election failed if it is not decided within this much "
 120             "time. If you need to adjust this value, it probably indicates "
 121             "the presence of a bug."),
 122         NULL,
 123     },
 124     {
 125         PCMK_OPT_SHUTDOWN_ESCALATION, NULL, PCMK_VALUE_DURATION, NULL,
 126         "20min", pcmk__valid_interval_spec,
 127         pcmk__opt_controld|pcmk__opt_advanced,
 128         N_("Exit immediately if shutdown does not complete within this much "
 129             "time. If you need to adjust this value, it probably indicates "
 130             "the presence of a bug."),
 131         NULL,
 132     },
 133     {
 134         PCMK_OPT_JOIN_INTEGRATION_TIMEOUT, "crmd-integration-timeout",
 135             PCMK_VALUE_DURATION, NULL,
 136         "3min", pcmk__valid_interval_spec,
 137         pcmk__opt_controld|pcmk__opt_advanced,
 138         N_("If you need to adjust this value, it probably indicates "
 139             "the presence of a bug."),
 140         NULL,
 141     },
 142     {
 143         PCMK_OPT_JOIN_FINALIZATION_TIMEOUT, "crmd-finalization-timeout",
 144             PCMK_VALUE_DURATION, NULL,
 145         "30min", pcmk__valid_interval_spec,
 146         pcmk__opt_controld|pcmk__opt_advanced,
 147         N_("If you need to adjust this value, it probably indicates "
 148             "the presence of a bug."),
 149         NULL,
 150     },
 151     {
 152         PCMK_OPT_TRANSITION_DELAY, "crmd-transition-delay", PCMK_VALUE_DURATION,
 153             NULL,
 154         "0s", pcmk__valid_interval_spec,
 155         pcmk__opt_controld|pcmk__opt_advanced,
 156         N_("Enabling this option will slow down cluster recovery under all "
 157             "conditions"),
 158         N_("Delay cluster recovery for this much time to allow for additional "
 159             "events to occur. Useful if your configuration is sensitive to "
 160             "the order in which ping updates arrive."),
 161     },
 162     {
 163         PCMK_OPT_NO_QUORUM_POLICY, NULL, PCMK_VALUE_SELECT,
 164             PCMK_VALUE_STOP ", " PCMK_VALUE_FREEZE ", " PCMK_VALUE_IGNORE
 165                 ", " PCMK_VALUE_DEMOTE ", " PCMK_VALUE_FENCE ", "
 166                 PCMK_VALUE_FENCE_LEGACY,
 167         PCMK_VALUE_STOP, pcmk__valid_no_quorum_policy,
 168         pcmk__opt_schedulerd,
 169         N_("What to do when the cluster does not have quorum"),
 170         NULL,
 171     },
 172     {
 173         PCMK_OPT_SHUTDOWN_LOCK, NULL, PCMK_VALUE_BOOLEAN, NULL,
 174         PCMK_VALUE_FALSE, pcmk__valid_boolean,
 175         pcmk__opt_schedulerd,
 176         N_("Whether to lock resources to a cleanly shut down node"),
 177         N_("When true, resources active on a node when it is cleanly shut down "
 178             "are kept \"locked\" to that node (not allowed to run elsewhere) "
 179             "until they start again on that node after it rejoins (or for at "
 180             "most shutdown-lock-limit, if set). Stonith resources and "
 181             "Pacemaker Remote connections are never locked. Clone and bundle "
 182             "instances and the promoted role of promotable clones are "
 183             "currently never locked, though support could be added in a future "
 184             "release."),
 185     },
 186     {
 187         PCMK_OPT_SHUTDOWN_LOCK_LIMIT, NULL, PCMK_VALUE_DURATION, NULL,
 188         "0", pcmk__valid_interval_spec,
 189         pcmk__opt_schedulerd,
 190         N_("Do not lock resources to a cleanly shut down node longer than "
 191            "this"),
 192         N_("If shutdown-lock is true and this is set to a nonzero time "
 193             "duration, shutdown locks will expire after this much time has "
 194             "passed since the shutdown was initiated, even if the node has not "
 195             "rejoined."),
 196     },
 197     {
 198         PCMK_OPT_ENABLE_ACL, NULL, PCMK_VALUE_BOOLEAN, NULL,
 199         PCMK_VALUE_FALSE, pcmk__valid_boolean,
 200         pcmk__opt_based,
 201         N_("Enable Access Control Lists (ACLs) for the CIB"),
 202         NULL,
 203     },
 204     {
 205         PCMK_OPT_SYMMETRIC_CLUSTER, NULL, PCMK_VALUE_BOOLEAN, NULL,
 206         PCMK_VALUE_TRUE, pcmk__valid_boolean,
 207         pcmk__opt_schedulerd,
 208         N_("Whether resources can run on any node by default"),
 209         NULL,
 210     },
 211     {
 212         PCMK_OPT_MAINTENANCE_MODE, NULL, PCMK_VALUE_BOOLEAN, NULL,
 213         PCMK_VALUE_FALSE, pcmk__valid_boolean,
 214         pcmk__opt_schedulerd,
 215         N_("Whether the cluster should refrain from monitoring, starting, and "
 216             "stopping resources"),
 217         NULL,
 218     },
 219     {
 220         PCMK_OPT_START_FAILURE_IS_FATAL, NULL, PCMK_VALUE_BOOLEAN, NULL,
 221         PCMK_VALUE_TRUE, pcmk__valid_boolean,
 222         pcmk__opt_schedulerd,
 223         N_("Whether a start failure should prevent a resource from being "
 224             "recovered on the same node"),
 225         N_("When true, the cluster will immediately ban a resource from a node "
 226             "if it fails to start there. When false, the cluster will instead "
 227             "check the resource's fail count against its migration-threshold.")
 228     },
 229     {
 230         PCMK_OPT_ENABLE_STARTUP_PROBES, NULL, PCMK_VALUE_BOOLEAN, NULL,
 231         PCMK_VALUE_TRUE, pcmk__valid_boolean,
 232         pcmk__opt_schedulerd,
 233         N_("Whether the cluster should check for active resources during "
 234             "start-up"),
 235         NULL,
 236     },
 237 
 238     // Fencing-related options
 239     {
 240         PCMK_OPT_STONITH_ENABLED, NULL, PCMK_VALUE_BOOLEAN, NULL,
 241         PCMK_VALUE_TRUE, pcmk__valid_boolean,
 242         pcmk__opt_schedulerd|pcmk__opt_advanced,
 243         N_("Whether nodes may be fenced as part of recovery"),
 244         N_("If false, unresponsive nodes are immediately assumed to be "
 245             "harmless, and resources that were active on them may be recovered "
 246             "elsewhere. This can result in a \"split-brain\" situation, "
 247             "potentially leading to data loss and/or service unavailability."),
 248     },
 249     {
 250         PCMK_OPT_STONITH_ACTION, NULL, PCMK_VALUE_SELECT,
 251             PCMK_ACTION_REBOOT ", " PCMK_ACTION_OFF ", " PCMK__ACTION_POWEROFF,
 252         PCMK_ACTION_REBOOT, pcmk__is_fencing_action,
 253         pcmk__opt_schedulerd,
 254         N_("Action to send to fence device when a node needs to be fenced "
 255             "(\"poweroff\" is a deprecated alias for \"off\")"),
 256         NULL,
 257     },
 258     {
 259         PCMK_OPT_STONITH_TIMEOUT, NULL, PCMK_VALUE_DURATION, NULL,
 260         "60s", pcmk__valid_interval_spec,
 261         pcmk__opt_schedulerd,
 262         N_("How long to wait for on, off, and reboot fence actions to complete "
 263             "by default"),
 264         NULL,
 265     },
 266     {
 267         PCMK_OPT_HAVE_WATCHDOG, NULL, PCMK_VALUE_BOOLEAN, NULL,
 268         PCMK_VALUE_FALSE, pcmk__valid_boolean,
 269         pcmk__opt_schedulerd|pcmk__opt_generated,
 270         N_("Whether watchdog integration is enabled"),
 271         N_("This is set automatically by the cluster according to whether SBD "
 272             "is detected to be in use. User-configured values are ignored. "
 273             "The value `true` is meaningful if diskless SBD is used and "
 274             "`stonith-watchdog-timeout` is nonzero. In that case, if fencing "
 275             "is required, watchdog-based self-fencing will be performed via "
 276             "SBD without requiring a fencing resource explicitly configured."),
 277     },
 278     {
 279         /* @COMPAT Currently, unparsable values default to -1 (auto-calculate),
 280          * while missing values default to 0 (disable). All values are accepted
 281          * (unless the controller finds that the value conflicts with the
 282          * SBD_WATCHDOG_TIMEOUT).
 283          *
 284          * At a compatibility break: properly validate as a timeout, let
 285          * either negative values or a particular string like "auto" mean auto-
 286          * calculate, and use 0 as the single default for when the option either
 287          * is unset or fails to validate.
 288          */
 289         PCMK_OPT_STONITH_WATCHDOG_TIMEOUT, NULL, PCMK_VALUE_TIMEOUT, NULL,
 290         "0", NULL,
 291         pcmk__opt_controld,
 292         N_("How long before nodes can be assumed to be safely down when "
 293            "watchdog-based self-fencing via SBD is in use"),
 294         N_("If this is set to a positive value, lost nodes are assumed to "
 295            "achieve self-fencing using watchdog-based SBD within this much "
 296            "time. This does not require a fencing resource to be explicitly "
 297            "configured, though a fence_watchdog resource can be configured, to "
 298            "limit use to specific nodes. If this is set to 0 (the default), "
 299            "the cluster will never assume watchdog-based self-fencing. If this "
 300            "is set to a negative value, the cluster will use twice the local "
 301            "value of the `SBD_WATCHDOG_TIMEOUT` environment variable if that "
 302            "is positive, or otherwise treat this as 0. WARNING: When used, "
 303            "this timeout must be larger than `SBD_WATCHDOG_TIMEOUT` on all "
 304            "nodes that use watchdog-based SBD, and Pacemaker will refuse to "
 305            "start on any of those nodes where this is not true for the local "
 306            "value or SBD is not active. When this is set to a negative value, "
 307            "`SBD_WATCHDOG_TIMEOUT` must be set to the same value on all nodes "
 308            "that use SBD, otherwise data corruption or loss could occur."),
 309     },
 310     {
 311         PCMK_OPT_STONITH_MAX_ATTEMPTS, NULL, PCMK_VALUE_SCORE, NULL,
 312         "10", pcmk__valid_positive_int,
 313         pcmk__opt_controld,
 314         N_("How many times fencing can fail before it will no longer be "
 315             "immediately re-attempted on a target"),
 316         NULL,
 317     },
 318     {
 319         PCMK_OPT_CONCURRENT_FENCING, NULL, PCMK_VALUE_BOOLEAN, NULL,
 320 #if PCMK__CONCURRENT_FENCING_DEFAULT_TRUE
 321         PCMK_VALUE_TRUE,
 322 #else
 323         PCMK_VALUE_FALSE,
 324 #endif
 325         pcmk__valid_boolean,
 326         pcmk__opt_schedulerd,
 327         N_("Allow performing fencing operations in parallel"),
 328         NULL,
 329     },
 330     {
 331         PCMK_OPT_STARTUP_FENCING, NULL, PCMK_VALUE_BOOLEAN, NULL,
 332         PCMK_VALUE_TRUE, pcmk__valid_boolean,
 333         pcmk__opt_schedulerd|pcmk__opt_advanced,
 334         N_("Whether to fence unseen nodes at start-up"),
 335         N_("Setting this to false may lead to a \"split-brain\" situation, "
 336             "potentially leading to data loss and/or service unavailability."),
 337     },
 338     {
 339         PCMK_OPT_PRIORITY_FENCING_DELAY, NULL, PCMK_VALUE_DURATION, NULL,
 340         "0", pcmk__valid_interval_spec,
 341         pcmk__opt_schedulerd,
 342         N_("Apply fencing delay targeting the lost nodes with the highest "
 343             "total resource priority"),
 344         N_("Apply specified delay for the fencings that are targeting the lost "
 345             "nodes with the highest total resource priority in case we don't "
 346             "have the majority of the nodes in our cluster partition, so that "
 347             "the more significant nodes potentially win any fencing match, "
 348             "which is especially meaningful under split-brain of 2-node "
 349             "cluster. A promoted resource instance takes the base priority + 1 "
 350             "on calculation if the base priority is not 0. Any static/random "
 351             "delays that are introduced by `pcmk_delay_base/max` configured "
 352             "for the corresponding fencing resources will be added to this "
 353             "delay. This delay should be significantly greater than, safely "
 354             "twice, the maximum `pcmk_delay_base/max`. By default, priority "
 355             "fencing delay is disabled."),
 356     },
 357     {
 358         PCMK_OPT_NODE_PENDING_TIMEOUT, NULL, PCMK_VALUE_DURATION, NULL,
 359         "0", pcmk__valid_interval_spec,
 360         pcmk__opt_schedulerd,
 361         N_("How long to wait for a node that has joined the cluster to join "
 362            "the controller process group"),
 363         N_("Fence nodes that do not join the controller process group within "
 364            "this much time after joining the cluster, to allow the cluster "
 365            "to continue managing resources. A value of 0 means never fence "
 366            "pending nodes. Setting the value to 2h means fence nodes after "
 367            "2 hours."),
 368     },
 369     {
 370         PCMK_OPT_CLUSTER_DELAY, NULL, PCMK_VALUE_DURATION, NULL,
 371         "60s", pcmk__valid_interval_spec,
 372         pcmk__opt_schedulerd,
 373         N_("Maximum time for node-to-node communication"),
 374         N_("The node elected Designated Controller (DC) will consider an action "
 375             "failed if it does not get a response from the node executing the "
 376             "action within this time (after considering the action's own "
 377             "timeout). The \"correct\" value will depend on the speed and "
 378             "load of your network and cluster nodes.")
 379     },
 380 
 381     // Limits
 382     {
 383         PCMK_OPT_LOAD_THRESHOLD, NULL, PCMK_VALUE_PERCENTAGE, NULL,
 384         "80%", pcmk__valid_percentage,
 385         pcmk__opt_controld,
 386         N_("Maximum amount of system load that should be used by cluster "
 387             "nodes"),
 388         N_("The cluster will slow down its recovery process when the amount of "
 389             "system resources used (currently CPU) approaches this limit"),
 390     },
 391     {
 392         PCMK_OPT_NODE_ACTION_LIMIT, NULL, PCMK_VALUE_INTEGER, NULL,
 393         "0", pcmk__valid_int,
 394         pcmk__opt_controld,
 395         N_("Maximum number of jobs that can be scheduled per node (defaults to "
 396             "2x cores)"),
 397         NULL,
 398     },
 399     {
 400         PCMK_OPT_BATCH_LIMIT, NULL, PCMK_VALUE_INTEGER, NULL,
 401         "0", pcmk__valid_int,
 402         pcmk__opt_schedulerd,
 403         N_("Maximum number of jobs that the cluster may execute in parallel "
 404             "across all nodes"),
 405         N_("The \"correct\" value will depend on the speed and load of your "
 406             "network and cluster nodes. If set to 0, the cluster will "
 407             "impose a dynamically calculated limit when any node has a "
 408             "high load."),
 409     },
 410     {
 411         PCMK_OPT_MIGRATION_LIMIT, NULL, PCMK_VALUE_INTEGER, NULL,
 412         "-1", pcmk__valid_int,
 413         pcmk__opt_schedulerd,
 414         N_("The number of live migration actions that the cluster is allowed "
 415             "to execute in parallel on a node (-1 means no limit)"),
 416         NULL,
 417     },
 418     {
 419         /* @TODO This is actually ignored if not strictly positive. We should
 420          * overhaul value types in Pacemaker Explained. There are lots of
 421          * inaccurate ranges (assumptions of 32-bit width, "nonnegative" when
 422          * positive is required, etc.).
 423          *
 424          * Maybe a single integer type with the allowed range specified would be
 425          * better.
 426          *
 427          * Drop the PCMK_VALUE_NONNEGATIVE_INTEGER constant if we do this before
 428          * a release.
 429          */
 430         PCMK_OPT_CLUSTER_IPC_LIMIT, NULL, PCMK_VALUE_NONNEGATIVE_INTEGER, NULL,
 431         "500", pcmk__valid_positive_int,
 432         pcmk__opt_based,
 433         N_("Maximum IPC message backlog before disconnecting a cluster daemon"),
 434         N_("Raise this if log has \"Evicting client\" messages for cluster "
 435             "daemon PIDs (a good value is the number of resources in the "
 436             "cluster multiplied by the number of nodes)."),
 437     },
 438 
 439     // Orphans and stopping
 440     {
 441         PCMK_OPT_STOP_ALL_RESOURCES, NULL, PCMK_VALUE_BOOLEAN, NULL,
 442         PCMK_VALUE_FALSE, pcmk__valid_boolean,
 443         pcmk__opt_schedulerd,
 444         N_("Whether the cluster should stop all active resources"),
 445         NULL,
 446     },
 447     {
 448         PCMK_OPT_STOP_ORPHAN_RESOURCES, NULL, PCMK_VALUE_BOOLEAN, NULL,
 449         PCMK_VALUE_TRUE, pcmk__valid_boolean,
 450         pcmk__opt_schedulerd,
 451         N_("Whether to stop resources that were removed from the "
 452             "configuration"),
 453         NULL,
 454     },
 455     {
 456         PCMK_OPT_STOP_ORPHAN_ACTIONS, NULL, PCMK_VALUE_BOOLEAN, NULL,
 457         PCMK_VALUE_TRUE, pcmk__valid_boolean,
 458         pcmk__opt_schedulerd,
 459         N_("Whether to cancel recurring actions removed from the "
 460             "configuration"),
 461         NULL,
 462     },
 463     {
 464         PCMK__OPT_REMOVE_AFTER_STOP, NULL, PCMK_VALUE_BOOLEAN, NULL,
 465         PCMK_VALUE_FALSE, pcmk__valid_boolean,
 466         pcmk__opt_schedulerd|pcmk__opt_deprecated,
 467         N_("Whether to remove stopped resources from the executor"),
 468         N_("Values other than default are poorly tested and potentially "
 469             "dangerous."),
 470     },
 471 
 472     // Storing inputs
 473     {
 474         PCMK_OPT_PE_ERROR_SERIES_MAX, NULL, PCMK_VALUE_INTEGER, NULL,
 475         "-1", pcmk__valid_int,
 476         pcmk__opt_schedulerd,
 477         N_("The number of scheduler inputs resulting in errors to save"),
 478         N_("Zero to disable, -1 to store unlimited."),
 479     },
 480     {
 481         PCMK_OPT_PE_WARN_SERIES_MAX, NULL, PCMK_VALUE_INTEGER, NULL,
 482         "5000", pcmk__valid_int,
 483         pcmk__opt_schedulerd,
 484         N_("The number of scheduler inputs resulting in warnings to save"),
 485         N_("Zero to disable, -1 to store unlimited."),
 486     },
 487     {
 488         PCMK_OPT_PE_INPUT_SERIES_MAX, NULL, PCMK_VALUE_INTEGER, NULL,
 489         "4000", pcmk__valid_int,
 490         pcmk__opt_schedulerd,
 491         N_("The number of scheduler inputs without errors or warnings to save"),
 492         N_("Zero to disable, -1 to store unlimited."),
 493     },
 494 
 495     // Node health
 496     {
 497         PCMK_OPT_NODE_HEALTH_STRATEGY, NULL, PCMK_VALUE_SELECT,
 498             PCMK_VALUE_NONE ", " PCMK_VALUE_MIGRATE_ON_RED ", "
 499                 PCMK_VALUE_ONLY_GREEN ", " PCMK_VALUE_PROGRESSIVE ", "
 500                 PCMK_VALUE_CUSTOM,
 501         PCMK_VALUE_NONE, pcmk__validate_health_strategy,
 502         pcmk__opt_schedulerd,
 503         N_("How cluster should react to node health attributes"),
 504         N_("Requires external entities to create node attributes (named with "
 505             "the prefix \"#health\") with values \"red\", \"yellow\", or "
 506             "\"green\".")
 507     },
 508     {
 509         PCMK_OPT_NODE_HEALTH_BASE, NULL, PCMK_VALUE_SCORE, NULL,
 510         "0", pcmk__valid_int,
 511         pcmk__opt_schedulerd,
 512         N_("Base health score assigned to a node"),
 513         N_("Only used when \"node-health-strategy\" is set to "
 514             "\"progressive\"."),
 515     },
 516     {
 517         PCMK_OPT_NODE_HEALTH_GREEN, NULL, PCMK_VALUE_SCORE, NULL,
 518         "0", pcmk__valid_int,
 519         pcmk__opt_schedulerd,
 520         N_("The score to use for a node health attribute whose value is "
 521             "\"green\""),
 522         N_("Only used when \"node-health-strategy\" is set to \"custom\" or "
 523             "\"progressive\"."),
 524     },
 525     {
 526         PCMK_OPT_NODE_HEALTH_YELLOW, NULL, PCMK_VALUE_SCORE, NULL,
 527         "0", pcmk__valid_int,
 528         pcmk__opt_schedulerd,
 529         N_("The score to use for a node health attribute whose value is "
 530             "\"yellow\""),
 531         N_("Only used when \"node-health-strategy\" is set to \"custom\" or "
 532             "\"progressive\"."),
 533     },
 534     {
 535         PCMK_OPT_NODE_HEALTH_RED, NULL, PCMK_VALUE_SCORE, NULL,
 536         "-INFINITY", pcmk__valid_int,
 537         pcmk__opt_schedulerd,
 538         N_("The score to use for a node health attribute whose value is "
 539             "\"red\""),
 540         N_("Only used when \"node-health-strategy\" is set to \"custom\" or "
 541             "\"progressive\".")
 542     },
 543 
 544     // Placement strategy
 545     {
 546         PCMK_OPT_PLACEMENT_STRATEGY, NULL, PCMK_VALUE_SELECT,
 547             PCMK_VALUE_DEFAULT ", " PCMK_VALUE_UTILIZATION ", "
 548                 PCMK_VALUE_MINIMAL ", " PCMK_VALUE_BALANCED,
 549         PCMK_VALUE_DEFAULT, pcmk__valid_placement_strategy,
 550         pcmk__opt_schedulerd,
 551         N_("How the cluster should allocate resources to nodes"),
 552         NULL,
 553     },
 554 
 555     { NULL, },
 556 };
 557 
 558 static const pcmk__cluster_option_t fencing_params[] = {
 559     /* name, old name, type, allowed values,
 560      * default value, validator,
 561      * flags,
 562      * short description,
 563      * long description
 564      */
 565     {
 566         PCMK_STONITH_HOST_ARGUMENT, NULL, PCMK_VALUE_STRING, NULL,
 567         "port", NULL,
 568         pcmk__opt_advanced,
 569         N_("An alternate parameter to supply instead of 'port'"),
 570         N_("Some devices do not support the standard 'port' parameter or may "
 571             "provide additional ones. Use this to specify an alternate, device-"
 572             "specific, parameter that should indicate the machine to be "
 573             "fenced. A value of \"none\" can be used to tell the cluster not "
 574             "to supply any additional parameters."),
 575     },
 576     {
 577         PCMK_STONITH_HOST_MAP, NULL, PCMK_VALUE_STRING, NULL,
 578         NULL, NULL,
 579         pcmk__opt_none,
 580         N_("A mapping of node names to port numbers for devices that do not "
 581             "support node names."),
 582         N_("For example, \"node1:1;node2:2,3\" would tell the cluster to use "
 583             "port 1 for node1 and ports 2 and 3 for node2."),
 584     },
 585     {
 586         PCMK_STONITH_HOST_LIST, NULL, PCMK_VALUE_STRING, NULL,
 587         NULL, NULL,
 588         pcmk__opt_none,
 589         N_("Nodes targeted by this device"),
 590         N_("Comma-separated list of nodes that can be targeted by this device "
 591            "(for example, \"node1,node2,node3\"). If pcmk_host_check is "
 592            "\"static-list\", either this or pcmk_host_map must be set."),
 593     },
 594     {
 595         PCMK_STONITH_HOST_CHECK, NULL, PCMK_VALUE_SELECT,
 596             PCMK_VALUE_DYNAMIC_LIST ", " PCMK_VALUE_STATIC_LIST ", "
 597             PCMK_VALUE_STATUS ", " PCMK_VALUE_NONE,
 598         NULL, NULL,
 599         pcmk__opt_none,
 600         N_("How to determine which nodes can be targeted by the device"),
 601         N_("Use \"dynamic-list\" to query the device via the 'list' command; "
 602             "\"static-list\" to check the pcmk_host_list attribute; "
 603             "\"status\" to query the device via the 'status' command; or "
 604             "\"none\" to assume every device can fence every node. "
 605             "The default value is \"static-list\" if pcmk_host_map or "
 606             "pcmk_host_list is set; otherwise \"dynamic-list\" if the device "
 607             "supports the list operation; otherwise \"status\" if the device "
 608             "supports the status operation; otherwise \"none\""),
 609     },
 610     {
 611         PCMK_STONITH_DELAY_MAX, NULL, PCMK_VALUE_DURATION, NULL,
 612         "0s", NULL,
 613         pcmk__opt_none,
 614         N_("Enable a delay of no more than the time specified before executing "
 615             "fencing actions."),
 616         N_("Enable a delay of no more than the time specified before executing "
 617             "fencing actions. Pacemaker derives the overall delay by taking "
 618             "the value of pcmk_delay_base and adding a random delay value such "
 619             "that the sum is kept below this maximum."),
 620     },
 621     {
 622         PCMK_STONITH_DELAY_BASE, NULL, PCMK_VALUE_STRING, NULL,
 623         "0s", NULL,
 624         pcmk__opt_none,
 625         N_("Enable a base delay for fencing actions and specify base delay "
 626             "value."),
 627         N_("This enables a static delay for fencing actions, which can help "
 628             "avoid \"death matches\" where two nodes try to fence each other "
 629             "at the same time. If pcmk_delay_max is also used, a random delay "
 630             "will be added such that the total delay is kept below that value. "
 631             "This can be set to a single time value to apply to any node "
 632             "targeted by this device (useful if a separate device is "
 633             "configured for each target), or to a node map (for example, "
 634             "\"node1:1s;node2:5\") to set a different value for each target."),
 635     },
 636     {
 637         PCMK_STONITH_ACTION_LIMIT, NULL, PCMK_VALUE_INTEGER, NULL,
 638         "1", NULL,
 639         pcmk__opt_none,
 640         N_("The maximum number of actions can be performed in parallel on this "
 641             "device"),
 642         N_("Cluster property concurrent-fencing=\"true\" needs to be "
 643             "configured first. Then use this to specify the maximum number of "
 644             "actions can be performed in parallel on this device. A value of "
 645             "-1 means an unlimited number of actions can be performed in "
 646             "parallel."),
 647     },
 648     {
 649         "pcmk_reboot_action", NULL, PCMK_VALUE_STRING, NULL,
 650         PCMK_ACTION_REBOOT, NULL,
 651         pcmk__opt_advanced,
 652         N_("An alternate command to run instead of 'reboot'"),
 653         N_("Some devices do not support the standard commands or may provide "
 654             "additional ones. Use this to specify an alternate, device-"
 655             "specific, command that implements the 'reboot' action."),
 656     },
 657     {
 658         "pcmk_reboot_timeout", NULL, PCMK_VALUE_TIMEOUT, NULL,
 659         "60s", NULL,
 660         pcmk__opt_advanced,
 661         N_("Specify an alternate timeout to use for 'reboot' actions instead "
 662             "of stonith-timeout"),
 663         N_("Some devices need much more/less time to complete than normal. "
 664             "Use this to specify an alternate, device-specific, timeout for "
 665             "'reboot' actions."),
 666     },
 667     {
 668         "pcmk_reboot_retries", NULL, PCMK_VALUE_INTEGER, NULL,
 669         "2", NULL,
 670         pcmk__opt_advanced,
 671         N_("The maximum number of times to try the 'reboot' command within the "
 672             "timeout period"),
 673         N_("Some devices do not support multiple connections. Operations may "
 674             "\"fail\" if the device is busy with another task. In that case, "
 675             "Pacemaker will automatically retry the operation if there is time "
 676             "remaining. Use this option to alter the number of times Pacemaker "
 677             "tries a 'reboot' action before giving up."),
 678     },
 679     {
 680         "pcmk_off_action", NULL, PCMK_VALUE_STRING, NULL,
 681         PCMK_ACTION_OFF, NULL,
 682         pcmk__opt_advanced,
 683         N_("An alternate command to run instead of 'off'"),
 684         N_("Some devices do not support the standard commands or may provide "
 685             "additional ones. Use this to specify an alternate, device-"
 686             "specific, command that implements the 'off' action."),
 687     },
 688     {
 689         "pcmk_off_timeout", NULL, PCMK_VALUE_TIMEOUT, NULL,
 690         "60s", NULL,
 691         pcmk__opt_advanced,
 692         N_("Specify an alternate timeout to use for 'off' actions instead of "
 693             "stonith-timeout"),
 694         N_("Some devices need much more/less time to complete than normal. "
 695             "Use this to specify an alternate, device-specific, timeout for "
 696             "'off' actions."),
 697     },
 698     {
 699         "pcmk_off_retries", NULL, PCMK_VALUE_INTEGER, NULL,
 700         "2", NULL,
 701         pcmk__opt_advanced,
 702         N_("The maximum number of times to try the 'off' command within the "
 703             "timeout period"),
 704         N_("Some devices do not support multiple connections. Operations may "
 705             "\"fail\" if the device is busy with another task. In that case, "
 706             "Pacemaker will automatically retry the operation if there is time "
 707             "remaining. Use this option to alter the number of times Pacemaker "
 708             "tries a 'off' action before giving up."),
 709     },
 710     {
 711         "pcmk_on_action", NULL, PCMK_VALUE_STRING, NULL,
 712         PCMK_ACTION_ON, NULL,
 713         pcmk__opt_advanced,
 714         N_("An alternate command to run instead of 'on'"),
 715         N_("Some devices do not support the standard commands or may provide "
 716             "additional ones. Use this to specify an alternate, device-"
 717             "specific, command that implements the 'on' action."),
 718     },
 719     {
 720         "pcmk_on_timeout", NULL, PCMK_VALUE_TIMEOUT, NULL,
 721         "60s", NULL,
 722         pcmk__opt_advanced,
 723         N_("Specify an alternate timeout to use for 'on' actions instead of "
 724             "stonith-timeout"),
 725         N_("Some devices need much more/less time to complete than normal. "
 726             "Use this to specify an alternate, device-specific, timeout for "
 727             "'on' actions."),
 728     },
 729     {
 730         "pcmk_on_retries", NULL, PCMK_VALUE_INTEGER, NULL,
 731         "2", NULL,
 732         pcmk__opt_advanced,
 733         N_("The maximum number of times to try the 'on' command within the "
 734             "timeout period"),
 735         N_("Some devices do not support multiple connections. Operations may "
 736             "\"fail\" if the device is busy with another task. In that case, "
 737             "Pacemaker will automatically retry the operation if there is time "
 738             "remaining. Use this option to alter the number of times Pacemaker "
 739             "tries a 'on' action before giving up."),
 740     },
 741     {
 742         "pcmk_list_action", NULL, PCMK_VALUE_STRING, NULL,
 743         PCMK_ACTION_LIST, NULL,
 744         pcmk__opt_advanced,
 745         N_("An alternate command to run instead of 'list'"),
 746         N_("Some devices do not support the standard commands or may provide "
 747             "additional ones. Use this to specify an alternate, device-"
 748             "specific, command that implements the 'list' action."),
 749     },
 750     {
 751         "pcmk_list_timeout", NULL, PCMK_VALUE_TIMEOUT, NULL,
 752         "60s", NULL,
 753         pcmk__opt_advanced,
 754         N_("Specify an alternate timeout to use for 'list' actions instead of "
 755             "stonith-timeout"),
 756         N_("Some devices need much more/less time to complete than normal. "
 757             "Use this to specify an alternate, device-specific, timeout for "
 758             "'list' actions."),
 759     },
 760     {
 761         "pcmk_list_retries", NULL, PCMK_VALUE_INTEGER, NULL,
 762         "2", NULL,
 763         pcmk__opt_advanced,
 764         N_("The maximum number of times to try the 'list' command within the "
 765             "timeout period"),
 766         N_("Some devices do not support multiple connections. Operations may "
 767             "\"fail\" if the device is busy with another task. In that case, "
 768             "Pacemaker will automatically retry the operation if there is time "
 769             "remaining. Use this option to alter the number of times Pacemaker "
 770             "tries a 'list' action before giving up."),
 771     },
 772     {
 773         "pcmk_monitor_action", NULL, PCMK_VALUE_STRING, NULL,
 774         PCMK_ACTION_MONITOR, NULL,
 775         pcmk__opt_advanced,
 776         N_("An alternate command to run instead of 'monitor'"),
 777         N_("Some devices do not support the standard commands or may provide "
 778             "additional ones. Use this to specify an alternate, device-"
 779             "specific, command that implements the 'monitor' action."),
 780     },
 781     {
 782         "pcmk_monitor_timeout", NULL, PCMK_VALUE_TIMEOUT, NULL,
 783         "60s", NULL,
 784         pcmk__opt_advanced,
 785         N_("Specify an alternate timeout to use for 'monitor' actions instead "
 786             "of stonith-timeout"),
 787         N_("Some devices need much more/less time to complete than normal. "
 788             "Use this to specify an alternate, device-specific, timeout for "
 789             "'monitor' actions."),
 790     },
 791     {
 792         "pcmk_monitor_retries", NULL, PCMK_VALUE_INTEGER, NULL,
 793         "2", NULL,
 794         pcmk__opt_advanced,
 795         N_("The maximum number of times to try the 'monitor' command within "
 796             "the timeout period"),
 797         N_("Some devices do not support multiple connections. Operations may "
 798             "\"fail\" if the device is busy with another task. In that case, "
 799             "Pacemaker will automatically retry the operation if there is time "
 800             "remaining. Use this option to alter the number of times Pacemaker "
 801             "tries a 'monitor' action before giving up."),
 802     },
 803     {
 804         "pcmk_status_action", NULL, PCMK_VALUE_STRING, NULL,
 805         PCMK_ACTION_STATUS, NULL,
 806         pcmk__opt_advanced,
 807         N_("An alternate command to run instead of 'status'"),
 808         N_("Some devices do not support the standard commands or may provide "
 809             "additional ones. Use this to specify an alternate, device-"
 810             "specific, command that implements the 'status' action."),
 811     },
 812     {
 813         "pcmk_status_timeout", NULL, PCMK_VALUE_TIMEOUT, NULL,
 814         "60s", NULL,
 815         pcmk__opt_advanced,
 816         N_("Specify an alternate timeout to use for 'status' actions instead "
 817             "of stonith-timeout"),
 818         N_("Some devices need much more/less time to complete than normal. "
 819             "Use this to specify an alternate, device-specific, timeout for "
 820             "'status' actions."),
 821     },
 822     {
 823         "pcmk_status_retries", NULL, PCMK_VALUE_INTEGER, NULL,
 824         "2", NULL,
 825         pcmk__opt_advanced,
 826         N_("The maximum number of times to try the 'status' command within "
 827             "the timeout period"),
 828         N_("Some devices do not support multiple connections. Operations may "
 829             "\"fail\" if the device is busy with another task. In that case, "
 830             "Pacemaker will automatically retry the operation if there is time "
 831             "remaining. Use this option to alter the number of times Pacemaker "
 832             "tries a 'status' action before giving up."),
 833     },
 834 
 835     { NULL, },
 836 };
 837 
 838 static const pcmk__cluster_option_t primitive_meta[] = {
 839     /* name, old name, type, allowed values,
 840      * default value, validator,
 841      * flags,
 842      * short description,
 843      * long description
 844      */
 845     {
 846         PCMK_META_PRIORITY, NULL, PCMK_VALUE_SCORE, NULL,
 847         "0", NULL,
 848         pcmk__opt_none,
 849         N_("Resource assignment priority"),
 850         N_("If not all resources can be active, the cluster will stop "
 851             "lower-priority resources in order to keep higher-priority ones "
 852             "active."),
 853     },
 854     {
 855         PCMK_META_CRITICAL, NULL, PCMK_VALUE_BOOLEAN, NULL,
 856         PCMK_VALUE_TRUE, NULL,
 857         pcmk__opt_none,
 858         N_("Default value for influence in colocation constraints"),
 859         N_("Use this value as the default for influence in all colocation "
 860             "constraints involving this resource, as well as in the implicit "
 861             "colocation constraints created if this resource is in a group."),
 862     },
 863     {
 864         PCMK_META_TARGET_ROLE, NULL, PCMK_VALUE_SELECT,
 865             PCMK_ROLE_STOPPED ", " PCMK_ROLE_STARTED ", "
 866             PCMK_ROLE_UNPROMOTED ", " PCMK_ROLE_PROMOTED,
 867         PCMK_ROLE_STARTED, NULL,
 868         pcmk__opt_none,
 869         N_("State the cluster should attempt to keep this resource in"),
 870         N_("\"Stopped\" forces the resource to be stopped. "
 871             "\"Started\" allows the resource to be started (and in the case of "
 872             "promotable clone resources, promoted if appropriate). "
 873             "\"Unpromoted\" allows the resource to be started, but only in the "
 874             "unpromoted role if the resource is promotable. "
 875             "\"Promoted\" is equivalent to \"Started\"."),
 876     },
 877     {
 878         PCMK_META_IS_MANAGED, NULL, PCMK_VALUE_BOOLEAN, NULL,
 879         PCMK_VALUE_TRUE, NULL,
 880         pcmk__opt_none,
 881         N_("Whether the cluster is allowed to actively change the resource's "
 882             "state"),
 883         N_("If false, the cluster will not start, stop, promote, or demote the "
 884             "resource on any node. Recurring actions for the resource are "
 885             "unaffected. If true, a true value for the maintenance-mode "
 886             "cluster option, the maintenance node attribute, or the "
 887             "maintenance resource meta-attribute overrides this."),
 888     },
 889     {
 890         PCMK_META_MAINTENANCE, NULL, PCMK_VALUE_BOOLEAN, NULL,
 891         PCMK_VALUE_FALSE, NULL,
 892         pcmk__opt_none,
 893         N_("If true, the cluster will not schedule any actions involving the "
 894             "resource"),
 895         N_("If true, the cluster will not start, stop, promote, or demote the "
 896             "resource on any node, and will pause any recurring monitors "
 897             "(except those specifying role as \"Stopped\"). If false, a true "
 898             "value for the maintenance-mode cluster option or maintenance node "
 899             "attribute overrides this."),
 900     },
 901     {
 902         PCMK_META_RESOURCE_STICKINESS, NULL, PCMK_VALUE_SCORE, NULL,
 903         NULL, NULL,
 904         pcmk__opt_none,
 905         N_("Score to add to the current node when a resource is already "
 906             "active"),
 907         N_("Score to add to the current node when a resource is already "
 908             "active. This allows running resources to stay where they are, "
 909             "even if they would be placed elsewhere if they were being started "
 910             "from a stopped state. "
 911             "The default is 1 for individual clone instances, and 0 for all "
 912             "other resources."),
 913     },
 914     {
 915         PCMK_META_REQUIRES, NULL, PCMK_VALUE_SELECT,
 916             PCMK_VALUE_NOTHING ", " PCMK_VALUE_QUORUM ", "
 917             PCMK_VALUE_FENCING ", " PCMK_VALUE_UNFENCING,
 918         NULL, NULL,
 919         pcmk__opt_none,
 920         N_("Conditions under which the resource can be started"),
 921         N_("Conditions under which the resource can be started. "
 922             "\"nothing\" means the cluster can always start this resource. "
 923             "\"quorum\" means the cluster can start this resource only if a "
 924             "majority of the configured nodes are active. "
 925             "\"fencing\" means the cluster can start this resource only if a "
 926             "majority of the configured nodes are active and any failed or "
 927             "unknown nodes have been fenced. "
 928             "\"unfencing\" means the cluster can start this resource only if "
 929             "a majority of the configured nodes are active and any failed or "
 930             "unknown nodes have been fenced, and only on nodes that have been "
 931             "unfenced. "
 932             "The default is \"quorum\" for resources with a class of stonith; "
 933             "otherwise, \"unfencing\" if unfencing is active in the cluster; "
 934             "otherwise, \"fencing\" if the stonith-enabled cluster option is "
 935             "true; "
 936             "otherwise, \"quorum\"."),
 937     },
 938     {
 939         PCMK_META_MIGRATION_THRESHOLD, NULL, PCMK_VALUE_SCORE, NULL,
 940         PCMK_VALUE_INFINITY, NULL,
 941         pcmk__opt_none,
 942         N_("Number of failures on a node before the resource becomes "
 943             "ineligible to run there."),
 944         N_("Number of failures that may occur for this resource on a node, "
 945             "before that node is marked ineligible to host this resource. A "
 946             "value of 0 indicates that this feature is disabled (the node will "
 947             "never be marked ineligible). By contrast, the cluster treats "
 948             "\"INFINITY\" (the default) as a very large but finite number. "
 949             "This option has an effect only if the failed operation specifies "
 950             "its on-fail attribute as \"restart\" (the default), and "
 951             "additionally for failed start operations, if the "
 952             "start-failure-is-fatal cluster property is set to false."),
 953     },
 954     {
 955         PCMK_META_FAILURE_TIMEOUT, NULL, PCMK_VALUE_DURATION, NULL,
 956         "0", NULL,
 957         pcmk__opt_none,
 958         N_("Number of seconds before acting as if a failure had not occurred"),
 959         N_("Number of seconds after a failed action for this resource before "
 960             "acting as if the failure had not occurred, and potentially "
 961             "allowing the resource back to the node on which it failed. "
 962             "A value of 0 indicates that this feature is disabled."),
 963     },
 964     {
 965         PCMK_META_MULTIPLE_ACTIVE, NULL, PCMK_VALUE_SELECT,
 966             PCMK_VALUE_BLOCK ", " PCMK_VALUE_STOP_ONLY ", "
 967             PCMK_VALUE_STOP_START ", " PCMK_VALUE_STOP_UNEXPECTED,
 968         PCMK_VALUE_STOP_START, NULL,
 969         pcmk__opt_none,
 970         N_("What to do if the cluster finds the resource active on more than "
 971             "one node"),
 972         N_("What to do if the cluster finds the resource active on more than "
 973             "one node. "
 974             "\"block\" means to mark the resource as unmanaged. "
 975             "\"stop_only\" means to stop all active instances of this resource "
 976             "and leave them stopped. "
 977             "\"stop_start\" means to stop all active instances of this "
 978             "resource and start the resource in one location only. "
 979             "\"stop_unexpected\" means to stop all active instances of this "
 980             "resource except where the resource should be active. (This should "
 981             "be used only when extra instances are not expected to disrupt "
 982             "existing instances, and the resource agent's monitor of an "
 983             "existing instance is capable of detecting any problems that could "
 984             "be caused. Note that any resources ordered after this one will "
 985             "still need to be restarted.)"),
 986     },
 987     {
 988         PCMK_META_ALLOW_MIGRATE, NULL, PCMK_VALUE_BOOLEAN, NULL,
 989         NULL, NULL,
 990         pcmk__opt_none,
 991         N_("Whether the cluster should try to \"live migrate\" this resource "
 992             "when it needs to be moved"),
 993         N_("Whether the cluster should try to \"live migrate\" this resource "
 994             "when it needs to be moved. "
 995             "The default is true for ocf:pacemaker:remote resources, and false "
 996             "otherwise."),
 997     },
 998     {
 999         PCMK_META_ALLOW_UNHEALTHY_NODES, NULL, PCMK_VALUE_BOOLEAN, NULL,
1000         PCMK_VALUE_FALSE, NULL,
1001         pcmk__opt_none,
1002         N_("Whether the resource should be allowed to run on a node even if "
1003             "the node's health score would otherwise prevent it"),
1004         NULL,
1005     },
1006     {
1007         PCMK_META_CONTAINER_ATTRIBUTE_TARGET, NULL, PCMK_VALUE_STRING, NULL,
1008         NULL, NULL,
1009         pcmk__opt_none,
1010         N_("Where to check user-defined node attributes"),
1011         N_("Whether to check user-defined node attributes on the physical host "
1012             "where a container is running or on the local node. This is "
1013             "usually set for a bundle resource and inherited by the bundle's "
1014             "primitive resource. "
1015             "A value of \"host\" means to check user-defined node attributes "
1016             "on the underlying physical host. Any other value means to check "
1017             "user-defined node attributes on the local node (for a bundled "
1018             "primitive resource, this is the bundle node)."),
1019     },
1020     {
1021         PCMK_META_REMOTE_NODE, NULL, PCMK_VALUE_STRING, NULL,
1022         NULL, NULL,
1023         pcmk__opt_none,
1024         N_("Name of the Pacemaker Remote guest node this resource is "
1025             "associated with, if any"),
1026         N_("Name of the Pacemaker Remote guest node this resource is "
1027             "associated with, if any. If specified, this both enables the "
1028             "resource as a guest node and defines the unique name used to "
1029             "identify the guest node. The guest must be configured to run the "
1030             "Pacemaker Remote daemon when it is started. "
1031             "WARNING: This value cannot overlap with any resource or node "
1032             "IDs."),
1033     },
1034     {
1035         PCMK_META_REMOTE_ADDR, NULL, PCMK_VALUE_STRING, NULL,
1036         NULL, NULL,
1037         pcmk__opt_none,
1038         N_("If remote-node is specified, the IP address or hostname used to "
1039             "connect to the guest via Pacemaker Remote"),
1040         N_("If remote-node is specified, the IP address or hostname used to "
1041             "connect to the guest via Pacemaker Remote. The Pacemaker Remote "
1042             "daemon on the guest must be configured to accept connections on "
1043             "this address. "
1044             "The default is the value of the remote-node meta-attribute."),
1045     },
1046     {
1047         PCMK_META_REMOTE_PORT, NULL, PCMK_VALUE_PORT, NULL,
1048         "3121", NULL,
1049         pcmk__opt_none,
1050         N_("If remote-node is specified, port on the guest used for its "
1051             "Pacemaker Remote connection"),
1052         N_("If remote-node is specified, the port on the guest used for its "
1053             "Pacemaker Remote connection. The Pacemaker Remote daemon on the "
1054             "guest must be configured to listen on this port."),
1055     },
1056     {
1057         PCMK_META_REMOTE_CONNECT_TIMEOUT, NULL, PCMK_VALUE_TIMEOUT, NULL,
1058         "60s", NULL,
1059         pcmk__opt_none,
1060         N_("If remote-node is specified, how long before a pending Pacemaker "
1061             "Remote guest connection times out."),
1062         NULL,
1063     },
1064     {
1065         PCMK_META_REMOTE_ALLOW_MIGRATE, NULL, PCMK_VALUE_BOOLEAN, NULL,
1066         PCMK_VALUE_TRUE, NULL,
1067         pcmk__opt_none,
1068         N_("If remote-node is specified, this acts as the allow-migrate "
1069             "meta-attribute for the implicit remote connection resource "
1070             "(ocf:pacemaker:remote)."),
1071         NULL,
1072     },
1073 
1074     { NULL, },
1075 };
1076 
1077 /*
1078  * Environment variable option handling
1079  */
1080 
1081 /*!
1082  * \internal
1083  * \brief Get the value of a Pacemaker environment variable option
1084  *
1085  * If an environment variable option is set, with either a PCMK_ or (for
1086  * backward compatibility) HA_ prefix, log and return the value.
1087  *
1088  * \param[in] option  Environment variable name (without prefix)
1089  *
1090  * \return Value of environment variable option, or NULL in case of
1091  *         option name too long or value not found
1092  */
1093 const char *
1094 pcmk__env_option(const char *option)
     /* [previous][next][first][last][top][bottom][index][help] */
1095 {
1096     const char *const prefixes[] = {"PCMK_", "HA_"};
1097     char env_name[NAME_MAX];
1098     const char *value = NULL;
1099 
1100     CRM_CHECK(!pcmk__str_empty(option), return NULL);
1101 
1102     for (int i = 0; i < PCMK__NELEM(prefixes); i++) {
1103         int rv = snprintf(env_name, NAME_MAX, "%s%s", prefixes[i], option);
1104 
1105         if (rv < 0) {
1106             crm_err("Failed to write %s%s to buffer: %s", prefixes[i], option,
1107                     strerror(errno));
1108             return NULL;
1109         }
1110 
1111         if (rv >= sizeof(env_name)) {
1112             crm_trace("\"%s%s\" is too long", prefixes[i], option);
1113             continue;
1114         }
1115 
1116         value = getenv(env_name);
1117         if (value != NULL) {
1118             crm_trace("Found %s = %s", env_name, value);
1119             return value;
1120         }
1121     }
1122 
1123     crm_trace("Nothing found for %s", option);
1124     return NULL;
1125 }
1126 
1127 /*!
1128  * \brief Set or unset a Pacemaker environment variable option
1129  *
1130  * Set an environment variable option with a \c "PCMK_" prefix and optionally
1131  * an \c "HA_" prefix for backward compatibility.
1132  *
1133  * \param[in] option  Environment variable name (without prefix)
1134  * \param[in] value   New value (or NULL to unset)
1135  * \param[in] compat  If false and \p value is not \c NULL, set only
1136  *                    \c "PCMK_<option>"; otherwise, set (or unset) both
1137  *                    \c "PCMK_<option>" and \c "HA_<option>"
1138  *
1139  * \note \p compat is ignored when \p value is \c NULL. A \c NULL \p value
1140  *       means we're unsetting \p option. \c pcmk__get_env_option() checks for
1141  *       both prefixes, so we want to clear them both.
1142  */
1143 void
1144 pcmk__set_env_option(const char *option, const char *value, bool compat)
     /* [previous][next][first][last][top][bottom][index][help] */
1145 {
1146     // @COMPAT Drop support for "HA_" options eventually
1147     const char *const prefixes[] = {"PCMK_", "HA_"};
1148     char env_name[NAME_MAX];
1149 
1150     CRM_CHECK(!pcmk__str_empty(option) && (strchr(option, '=') == NULL),
1151               return);
1152 
1153     for (int i = 0; i < PCMK__NELEM(prefixes); i++) {
1154         int rv = snprintf(env_name, NAME_MAX, "%s%s", prefixes[i], option);
1155 
1156         if (rv < 0) {
1157             crm_err("Failed to write %s%s to buffer: %s", prefixes[i], option,
1158                     strerror(errno));
1159             return;
1160         }
1161 
1162         if (rv >= sizeof(env_name)) {
1163             crm_trace("\"%s%s\" is too long", prefixes[i], option);
1164             continue;
1165         }
1166 
1167         if (value != NULL) {
1168             crm_trace("Setting %s to %s", env_name, value);
1169             rv = setenv(env_name, value, 1);
1170         } else {
1171             crm_trace("Unsetting %s", env_name);
1172             rv = unsetenv(env_name);
1173         }
1174 
1175         if (rv < 0) {
1176             crm_err("Failed to %sset %s: %s", (value != NULL)? "" : "un",
1177                     env_name, strerror(errno));
1178         }
1179 
1180         if (!compat && (value != NULL)) {
1181             // For set, don't proceed to HA_<option> unless compat is enabled
1182             break;
1183         }
1184     }
1185 }
1186 
1187 /*!
1188  * \internal
1189  * \brief Check whether Pacemaker environment variable option is enabled
1190  *
1191  * Given a Pacemaker environment variable option that can either be boolean
1192  * or a list of daemon names, return true if the option is enabled for a given
1193  * daemon.
1194  *
1195  * \param[in] daemon   Daemon name (can be NULL)
1196  * \param[in] option   Pacemaker environment variable name
1197  *
1198  * \return true if variable is enabled for daemon, otherwise false
1199  */
1200 bool
1201 pcmk__env_option_enabled(const char *daemon, const char *option)
     /* [previous][next][first][last][top][bottom][index][help] */
1202 {
1203     const char *value = pcmk__env_option(option);
1204 
1205     return (value != NULL)
1206         && (crm_is_true(value)
1207             || ((daemon != NULL) && (strstr(value, daemon) != NULL)));
1208 }
1209 
1210 
1211 /*
1212  * Cluster option handling
1213  */
1214 
1215 /*!
1216  * \internal
1217  * \brief Check whether a string represents a valid interval specification
1218  *
1219  * \param[in] value  String to validate
1220  *
1221  * \return \c true if \p value is a valid interval specification, or \c false
1222  *         otherwise
1223  */
1224 bool
1225 pcmk__valid_interval_spec(const char *value)
     /* [previous][next][first][last][top][bottom][index][help] */
1226 {
1227     return pcmk_parse_interval_spec(value, NULL) == pcmk_rc_ok;
1228 }
1229 
1230 /*!
1231  * \internal
1232  * \brief Check whether a string represents a valid boolean value
1233  *
1234  * \param[in] value  String to validate
1235  *
1236  * \return \c true if \p value is a valid boolean value, or \c false otherwise
1237  */
1238 bool
1239 pcmk__valid_boolean(const char *value)
     /* [previous][next][first][last][top][bottom][index][help] */
1240 {
1241     return crm_str_to_boolean(value, NULL) == 1;
1242 }
1243 
1244 /*!
1245  * \internal
1246  * \brief Check whether a string represents a valid integer
1247  *
1248  * Valid values include \c INFINITY, \c -INFINITY, and all 64-bit integers.
1249  *
1250  * \param[in] value  String to validate
1251  *
1252  * \return \c true if \p value is a valid integer, or \c false otherwise
1253  */
1254 bool
1255 pcmk__valid_int(const char *value)
     /* [previous][next][first][last][top][bottom][index][help] */
1256 {
1257     return (value != NULL)
1258            && (pcmk_str_is_infinity(value)
1259                || pcmk_str_is_minus_infinity(value)
1260                || (pcmk__scan_ll(value, NULL, 0LL) == pcmk_rc_ok));
1261 }
1262 
1263 /*!
1264  * \internal
1265  * \brief Check whether a string represents a valid positive integer
1266  *
1267  * Valid values include \c INFINITY and all 64-bit positive integers.
1268  *
1269  * \param[in] value  String to validate
1270  *
1271  * \return \c true if \p value is a valid positive integer, or \c false
1272  *         otherwise
1273  */
1274 bool
1275 pcmk__valid_positive_int(const char *value)
     /* [previous][next][first][last][top][bottom][index][help] */
1276 {
1277     long long num = 0LL;
1278 
1279     return pcmk_str_is_infinity(value)
1280            || ((pcmk__scan_ll(value, &num, 0LL) == pcmk_rc_ok)
1281                && (num > 0));
1282 }
1283 
1284 /*!
1285  * \internal
1286  * \brief Check whether a string represents a valid
1287  *        \c PCMK__OPT_NO_QUORUM_POLICY value
1288  *
1289  * \param[in] value  String to validate
1290  *
1291  * \return \c true if \p value is a valid \c PCMK__OPT_NO_QUORUM_POLICY value,
1292  *         or \c false otherwise
1293  */
1294 bool
1295 pcmk__valid_no_quorum_policy(const char *value)
     /* [previous][next][first][last][top][bottom][index][help] */
1296 {
1297     return pcmk__strcase_any_of(value,
1298                                 PCMK_VALUE_STOP, PCMK_VALUE_FREEZE,
1299                                 PCMK_VALUE_IGNORE, PCMK_VALUE_DEMOTE,
1300                                 PCMK_VALUE_FENCE, PCMK_VALUE_FENCE_LEGACY,
1301                                 NULL);
1302 }
1303 
1304 /*!
1305  * \internal
1306  * \brief Check whether a string represents a valid percentage
1307  *
1308  * Valid values include long integers, with an optional trailing string
1309  * beginning with '%'.
1310  *
1311  * \param[in] value  String to validate
1312  *
1313  * \return \c true if \p value is a valid percentage value, or \c false
1314  *         otherwise
1315  */
1316 bool
1317 pcmk__valid_percentage(const char *value)
     /* [previous][next][first][last][top][bottom][index][help] */
1318 {
1319     char *end = NULL;
1320     float number = strtof(value, &end);
1321 
1322     return ((end == NULL) || (end[0] == '%')) && (number >= 0);
1323 }
1324 
1325 /*!
1326  * \internal
1327  * \brief Check whether a string represents a valid placement strategy
1328  *
1329  * \param[in] value  String to validate
1330  *
1331  * \return \c true if \p value is a valid placement strategy, or \c false
1332  *         otherwise
1333  */
1334 bool
1335 pcmk__valid_placement_strategy(const char *value)
     /* [previous][next][first][last][top][bottom][index][help] */
1336 {
1337     return pcmk__strcase_any_of(value,
1338                                 PCMK_VALUE_DEFAULT, PCMK_VALUE_UTILIZATION,
1339                                 PCMK_VALUE_MINIMAL, PCMK_VALUE_BALANCED, NULL);
1340 }
1341 
1342 /*!
1343  * \internal
1344  * \brief Check a table of configured options for a particular option
1345  *
1346  * \param[in,out] table   Name/value pairs for configured options
1347  * \param[in]     option  Option to look up
1348  *
1349  * \return Option value (from supplied options table or default value)
1350  */
1351 static const char *
1352 cluster_option_value(GHashTable *table, const pcmk__cluster_option_t *option)
     /* [previous][next][first][last][top][bottom][index][help] */
1353 {
1354     const char *value = NULL;
1355 
1356     pcmk__assert((option != NULL) && (option->name != NULL));
1357 
1358     if (table != NULL) {
1359         value = g_hash_table_lookup(table, option->name);
1360 
1361         if ((value == NULL) && (option->alt_name != NULL)) {
1362             value = g_hash_table_lookup(table, option->alt_name);
1363             if (value != NULL) {
1364                 pcmk__config_warn("Support for legacy name '%s' for cluster "
1365                                   "option '%s' is deprecated and will be "
1366                                   "removed in a future release",
1367                                   option->alt_name, option->name);
1368 
1369                 // Inserting copy with current name ensures we only warn once
1370                 pcmk__insert_dup(table, option->name, value);
1371             }
1372         }
1373 
1374         if ((value != NULL) && (option->is_valid != NULL)
1375             && !option->is_valid(value)) {
1376 
1377             pcmk__config_err("Using default value for cluster option '%s' "
1378                              "because '%s' is invalid", option->name, value);
1379             value = NULL;
1380         }
1381 
1382         if (value != NULL) {
1383             return value;
1384         }
1385     }
1386 
1387     // No value found, use default
1388     value = option->default_value;
1389 
1390     if (value == NULL) {
1391         crm_trace("No value or default provided for cluster option '%s'",
1392                   option->name);
1393         return NULL;
1394     }
1395 
1396     CRM_CHECK((option->is_valid == NULL) || option->is_valid(value),
1397               crm_err("Bug: default value for cluster option '%s' is invalid",
1398                       option->name);
1399               return NULL);
1400 
1401     crm_trace("Using default value '%s' for cluster option '%s'",
1402               value, option->name);
1403     if (table != NULL) {
1404         pcmk__insert_dup(table, option->name, value);
1405     }
1406     return value;
1407 }
1408 
1409 /*!
1410  * \internal
1411  * \brief Get the value of a cluster option
1412  *
1413  * \param[in,out] options  Name/value pairs for configured options
1414  * \param[in]     name     (Primary) option name to look for
1415  *
1416  * \return Option value
1417  */
1418 const char *
1419 pcmk__cluster_option(GHashTable *options, const char *name)
     /* [previous][next][first][last][top][bottom][index][help] */
1420 {
1421     for (const pcmk__cluster_option_t *option = cluster_options;
1422          option->name != NULL; option++) {
1423 
1424         if (pcmk__str_eq(name, option->name, pcmk__str_casei)) {
1425             return cluster_option_value(options, option);
1426         }
1427     }
1428     CRM_CHECK(FALSE, crm_err("Bug: looking for unknown option '%s'", name));
1429     return NULL;
1430 }
1431 
1432 /*!
1433  * \internal
1434  * \brief Output cluster option metadata as OCF-like XML
1435  *
1436  * \param[in,out] out         Output object
1437  * \param[in]     name        Fake resource agent name for the option list
1438  * \param[in]     desc_short  Short description of the option list
1439  * \param[in]     desc_long   Long description of the option list
1440  * \param[in]     filter      Group of <tt>enum pcmk__opt_flags</tt>; output an
1441  *                            option only if its \c flags member has all these
1442  *                            flags set
1443  * \param[in]     all         If \c true, output all options; otherwise, exclude
1444  *                            advanced and deprecated options unless
1445  *                            \c pcmk__opt_advanced and \c pcmk__opt_deprecated
1446  *                            flags (respectively) are set in \p filter. This is
1447  *                            always treated as true for XML output objects.
1448  *
1449  * \return Standard Pacemaker return code
1450  */
1451 int
1452 pcmk__output_cluster_options(pcmk__output_t *out, const char *name,
     /* [previous][next][first][last][top][bottom][index][help] */
1453                              const char *desc_short, const char *desc_long,
1454                              uint32_t filter, bool all)
1455 {
1456     return out->message(out, "option-list", name, desc_short, desc_long, filter,
1457                         cluster_options, all);
1458 }
1459 
1460 /*!
1461  * \internal
1462  * \brief Output primitive resource meta-attributes as OCF-like XML
1463  *
1464  * \param[in,out] out         Output object
1465  * \param[in]     name        Fake resource agent name for the option list
1466  * \param[in]     desc_short  Short description of the option list
1467  * \param[in]     desc_long   Long description of the option list
1468  * \param[in]     all         If \c true, output all options; otherwise, exclude
1469  *                            advanced and deprecated options. This is always
1470  *                            treated as true for XML output objects.
1471  *
1472  * \return Standard Pacemaker return code
1473  */
1474 int
1475 pcmk__output_primitive_meta(pcmk__output_t *out, const char *name,
     /* [previous][next][first][last][top][bottom][index][help] */
1476                             const char *desc_short, const char *desc_long,
1477                             bool all)
1478 {
1479     return out->message(out, "option-list", name, desc_short, desc_long,
1480                         pcmk__opt_none, primitive_meta, all);
1481 }
1482 
1483 /*!
1484  * \internal
1485  * \brief Output fence device common parameter metadata as OCF-like XML
1486  *
1487  * These are parameters that are available for all fencing resources, regardless
1488  * of type. They are processed by Pacemaker, rather than by the fence agent or
1489  * the fencing library.
1490  *
1491  * \param[in,out] out         Output object
1492  * \param[in]     name        Fake resource agent name for the option list
1493  * \param[in]     desc_short  Short description of the option list
1494  * \param[in]     desc_long   Long description of the option list
1495  * \param[in]     all         If \c true, output all options; otherwise, exclude
1496  *                            advanced and deprecated options. This is always
1497  *                            treated as true for XML output objects.
1498  *
1499  * \return Standard Pacemaker return code
1500  */
1501 int
1502 pcmk__output_fencing_params(pcmk__output_t *out, const char *name,
     /* [previous][next][first][last][top][bottom][index][help] */
1503                           const char *desc_short, const char *desc_long,
1504                           bool all)
1505 {
1506     return out->message(out, "option-list", name, desc_short, desc_long,
1507                         pcmk__opt_none, fencing_params, all);
1508 }
1509 
1510 /*!
1511  * \internal
1512  * \brief Output a list of cluster options for a daemon
1513  *
1514  * \brief[in,out] out         Output object
1515  * \brief[in]     name        Daemon name
1516  * \brief[in]     desc_short  Short description of the option list
1517  * \brief[in]     desc_long   Long description of the option list
1518  * \brief[in]     filter      <tt>enum pcmk__opt_flags</tt> flag corresponding
1519  *                            to daemon
1520  *
1521  * \return Standard Pacemaker return code
1522  */
1523 int
1524 pcmk__daemon_metadata(pcmk__output_t *out, const char *name,
     /* [previous][next][first][last][top][bottom][index][help] */
1525                       const char *desc_short, const char *desc_long,
1526                       enum pcmk__opt_flags filter)
1527 {
1528     // @COMPAT Drop this function when we drop daemon metadata
1529     pcmk__output_t *tmp_out = NULL;
1530     xmlNode *top = NULL;
1531     const xmlNode *metadata = NULL;
1532     GString *metadata_s = NULL;
1533 
1534     int rc = pcmk__output_new(&tmp_out, "xml", "/dev/null", NULL);
1535 
1536     if (rc != pcmk_rc_ok) {
1537         return rc;
1538     }
1539 
1540     pcmk__output_set_legacy_xml(tmp_out);
1541 
1542     if (filter == pcmk__opt_fencing) {
1543         pcmk__output_fencing_params(tmp_out, name, desc_short, desc_long, true);
1544     } else {
1545         pcmk__output_cluster_options(tmp_out, name, desc_short, desc_long,
1546                                      (uint32_t) filter, true);
1547     }
1548 
1549     tmp_out->finish(tmp_out, CRM_EX_OK, false, (void **) &top);
1550     metadata = pcmk__xe_first_child(top, PCMK_XE_RESOURCE_AGENT, NULL, NULL);
1551 
1552     metadata_s = g_string_sized_new(16384);
1553     pcmk__xml_string(metadata, pcmk__xml_fmt_pretty|pcmk__xml_fmt_text,
1554                      metadata_s, 0);
1555 
1556     out->output_xml(out, PCMK_XE_METADATA, metadata_s->str);
1557 
1558     pcmk__output_free(tmp_out);
1559     free_xml(top);
1560     g_string_free(metadata_s, TRUE);
1561     return pcmk_rc_ok;
1562 }
1563 
1564 void
1565 pcmk__validate_cluster_options(GHashTable *options)
     /* [previous][next][first][last][top][bottom][index][help] */
1566 {
1567     for (const pcmk__cluster_option_t *option = cluster_options;
1568          option->name != NULL; option++) {
1569 
1570         cluster_option_value(options, option);
1571     }
1572 }

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