Line data Source code
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 0 : pcmk__cli_help(char cmd)
27 : {
28 0 : if (cmd == 'v' || cmd == '$') {
29 0 : printf("Pacemaker %s\n", PACEMAKER_VERSION);
30 0 : printf("Written by Andrew Beekhof and "
31 : "the Pacemaker project contributors\n");
32 :
33 0 : } else if (cmd == '!') {
34 0 : printf("Pacemaker %s (Build: %s): %s\n", PACEMAKER_VERSION, BUILD_VERSION, CRM_FEATURES);
35 : }
36 :
37 0 : 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 7263 : pcmk__env_option(const char *option)
1089 : {
1090 7263 : const char *const prefixes[] = {"PCMK_", "HA_"};
1091 : char env_name[NAME_MAX];
1092 7263 : const char *value = NULL;
1093 :
1094 7263 : CRM_CHECK(!pcmk__str_empty(option), return NULL);
1095 :
1096 21469 : for (int i = 0; i < PCMK__NELEM(prefixes); i++) {
1097 14365 : int rv = snprintf(env_name, NAME_MAX, "%s%s", prefixes[i], option);
1098 :
1099 14365 : if (rv < 0) {
1100 0 : crm_err("Failed to write %s%s to buffer: %s", prefixes[i], option,
1101 : strerror(errno));
1102 0 : return NULL;
1103 : }
1104 :
1105 14365 : if (rv >= sizeof(env_name)) {
1106 3 : crm_trace("\"%s%s\" is too long", prefixes[i], option);
1107 3 : continue;
1108 : }
1109 :
1110 14362 : value = getenv(env_name);
1111 14362 : if (value != NULL) {
1112 155 : crm_trace("Found %s = %s", env_name, value);
1113 155 : return value;
1114 : }
1115 : }
1116 :
1117 7104 : crm_trace("Nothing found for %s", option);
1118 7104 : 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 107 : pcmk__set_env_option(const char *option, const char *value, bool compat)
1139 : {
1140 : // @COMPAT Drop support for "HA_" options eventually
1141 107 : const char *const prefixes[] = {"PCMK_", "HA_"};
1142 : char env_name[NAME_MAX];
1143 :
1144 107 : CRM_CHECK(!pcmk__str_empty(option) && (strchr(option, '=') == NULL),
1145 : return);
1146 :
1147 197 : for (int i = 0; i < PCMK__NELEM(prefixes); i++) {
1148 149 : int rv = snprintf(env_name, NAME_MAX, "%s%s", prefixes[i], option);
1149 :
1150 149 : if (rv < 0) {
1151 0 : crm_err("Failed to write %s%s to buffer: %s", prefixes[i], option,
1152 : strerror(errno));
1153 0 : return;
1154 : }
1155 :
1156 149 : if (rv >= sizeof(env_name)) {
1157 6 : crm_trace("\"%s%s\" is too long", prefixes[i], option);
1158 6 : continue;
1159 : }
1160 :
1161 143 : if (value != NULL) {
1162 138 : crm_trace("Setting %s to %s", env_name, value);
1163 138 : rv = setenv(env_name, value, 1);
1164 : } else {
1165 5 : crm_trace("Unsetting %s", env_name);
1166 5 : rv = unsetenv(env_name);
1167 : }
1168 :
1169 143 : if (rv < 0) {
1170 0 : crm_err("Failed to %sset %s: %s", (value != NULL)? "" : "un",
1171 : env_name, strerror(errno));
1172 : }
1173 :
1174 143 : if (!compat && (value != NULL)) {
1175 : // For set, don't proceed to HA_<option> unless compat is enabled
1176 53 : 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 91 : pcmk__env_option_enabled(const char *daemon, const char *option)
1196 : {
1197 91 : const char *value = pcmk__env_option(option);
1198 :
1199 : return (value != NULL)
1200 98 : && (crm_is_true(value)
1201 7 : || ((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 0 : pcmk__valid_interval_spec(const char *value)
1220 : {
1221 0 : 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 0 : pcmk__valid_boolean(const char *value)
1234 : {
1235 0 : 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 0 : pcmk__valid_int(const char *value)
1250 : {
1251 : return (value != NULL)
1252 0 : && (pcmk_str_is_infinity(value)
1253 0 : || pcmk_str_is_minus_infinity(value)
1254 0 : || (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 0 : pcmk__valid_positive_int(const char *value)
1270 : {
1271 0 : long long num = 0LL;
1272 :
1273 0 : return pcmk_str_is_infinity(value)
1274 0 : || ((pcmk__scan_ll(value, &num, 0LL) == pcmk_rc_ok)
1275 0 : && (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 0 : pcmk__valid_no_quorum_policy(const char *value)
1290 : {
1291 0 : 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 0 : pcmk__valid_percentage(const char *value)
1311 : {
1312 0 : char *end = NULL;
1313 0 : float number = strtof(value, &end);
1314 :
1315 0 : 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 0 : pcmk__valid_placement_strategy(const char *value)
1329 : {
1330 0 : 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 0 : cluster_option_value(GHashTable *table, const pcmk__cluster_option_t *option)
1346 : {
1347 0 : const char *value = NULL;
1348 :
1349 0 : CRM_ASSERT((option != NULL) && (option->name != NULL));
1350 :
1351 0 : if (table != NULL) {
1352 0 : value = g_hash_table_lookup(table, option->name);
1353 :
1354 0 : if ((value == NULL) && (option->alt_name != NULL)) {
1355 0 : value = g_hash_table_lookup(table, option->alt_name);
1356 0 : if (value != NULL) {
1357 0 : 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 0 : pcmk__insert_dup(table, option->name, value);
1364 : }
1365 : }
1366 :
1367 0 : if ((value != NULL) && (option->is_valid != NULL)
1368 0 : && !option->is_valid(value)) {
1369 :
1370 0 : pcmk__config_err("Using default value for cluster option '%s' "
1371 : "because '%s' is invalid", option->name, value);
1372 0 : value = NULL;
1373 : }
1374 :
1375 0 : if (value != NULL) {
1376 0 : return value;
1377 : }
1378 : }
1379 :
1380 : // No value found, use default
1381 0 : value = option->default_value;
1382 :
1383 0 : if (value == NULL) {
1384 0 : crm_trace("No value or default provided for cluster option '%s'",
1385 : option->name);
1386 0 : return NULL;
1387 : }
1388 :
1389 0 : 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 0 : crm_trace("Using default value '%s' for cluster option '%s'",
1395 : value, option->name);
1396 0 : if (table != NULL) {
1397 0 : pcmk__insert_dup(table, option->name, value);
1398 : }
1399 0 : 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 0 : pcmk__cluster_option(GHashTable *options, const char *name)
1413 : {
1414 0 : for (const pcmk__cluster_option_t *option = cluster_options;
1415 0 : option->name != NULL; option++) {
1416 :
1417 0 : if (pcmk__str_eq(name, option->name, pcmk__str_casei)) {
1418 0 : return cluster_option_value(options, option);
1419 : }
1420 : }
1421 0 : CRM_CHECK(FALSE, crm_err("Bug: looking for unknown option '%s'", name));
1422 0 : 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 0 : pcmk__output_cluster_options(pcmk__output_t *out, const char *name,
1446 : const char *desc_short, const char *desc_long,
1447 : uint32_t filter, bool all)
1448 : {
1449 0 : 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 0 : pcmk__output_primitive_meta(pcmk__output_t *out, const char *name,
1469 : const char *desc_short, const char *desc_long,
1470 : bool all)
1471 : {
1472 0 : 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 0 : pcmk__output_fencing_params(pcmk__output_t *out, const char *name,
1496 : const char *desc_short, const char *desc_long,
1497 : bool all)
1498 : {
1499 0 : 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 0 : pcmk__daemon_metadata(pcmk__output_t *out, const char *name,
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 0 : pcmk__output_t *tmp_out = NULL;
1523 0 : xmlNode *top = NULL;
1524 0 : const xmlNode *metadata = NULL;
1525 0 : GString *metadata_s = NULL;
1526 :
1527 0 : int rc = pcmk__output_new(&tmp_out, "xml", "/dev/null", NULL);
1528 :
1529 0 : if (rc != pcmk_rc_ok) {
1530 0 : return rc;
1531 : }
1532 :
1533 0 : pcmk__output_set_legacy_xml(tmp_out);
1534 :
1535 0 : if (filter == pcmk__opt_fencing) {
1536 0 : pcmk__output_fencing_params(tmp_out, name, desc_short, desc_long, true);
1537 : } else {
1538 0 : pcmk__output_cluster_options(tmp_out, name, desc_short, desc_long,
1539 : (uint32_t) filter, true);
1540 : }
1541 :
1542 0 : tmp_out->finish(tmp_out, CRM_EX_OK, false, (void **) &top);
1543 0 : metadata = pcmk__xe_first_child(top, PCMK_XE_RESOURCE_AGENT, NULL, NULL);
1544 :
1545 0 : metadata_s = g_string_sized_new(16384);
1546 0 : pcmk__xml_string(metadata, pcmk__xml_fmt_pretty|pcmk__xml_fmt_text,
1547 : metadata_s, 0);
1548 :
1549 0 : out->output_xml(out, PCMK_XE_METADATA, metadata_s->str);
1550 :
1551 0 : pcmk__output_free(tmp_out);
1552 0 : free_xml(top);
1553 0 : g_string_free(metadata_s, TRUE);
1554 0 : return pcmk_rc_ok;
1555 : }
1556 :
1557 : void
1558 0 : pcmk__validate_cluster_options(GHashTable *options)
1559 : {
1560 0 : for (const pcmk__cluster_option_t *option = cluster_options;
1561 0 : option->name != NULL; option++) {
1562 :
1563 0 : cluster_option_value(options, option);
1564 : }
1565 0 : }
|