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