Coverage Report

Created: 2026-01-02 06:28

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