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

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