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

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