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_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
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
279
280
281
282
283
284
285
286
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
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
414
415
416
417
418
419
420
421
422
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
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
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
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
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
554
555
556
557
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
834
835
836
837
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
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087 const char *
1088 pcmk__env_option(const char *option)
1089 {
1090 const char *const prefixes[] = {"PCMK_", "HA_"};
1091 char env_name[NAME_MAX];
1092 const char *value = NULL;
1093
1094 CRM_CHECK(!pcmk__str_empty(option), return NULL);
1095
1096 for (int i = 0; i < PCMK__NELEM(prefixes); i++) {
1097 int rv = snprintf(env_name, NAME_MAX, "%s%s", prefixes[i], option);
1098
1099 if (rv < 0) {
1100 crm_err("Failed to write %s%s to buffer: %s", prefixes[i], option,
1101 strerror(errno));
1102 return NULL;
1103 }
1104
1105 if (rv >= sizeof(env_name)) {
1106 crm_trace("\"%s%s\" is too long", prefixes[i], option);
1107 continue;
1108 }
1109
1110 value = getenv(env_name);
1111 if (value != NULL) {
1112 crm_trace("Found %s = %s", env_name, value);
1113 return value;
1114 }
1115 }
1116
1117 crm_trace("Nothing found for %s", option);
1118 return NULL;
1119 }
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137 void
1138 pcmk__set_env_option(const char *option, const char *value, bool compat)
1139 {
1140
1141 const char *const prefixes[] = {"PCMK_", "HA_"};
1142 char env_name[NAME_MAX];
1143
1144 CRM_CHECK(!pcmk__str_empty(option) && (strchr(option, '=') == NULL),
1145 return);
1146
1147 for (int i = 0; i < PCMK__NELEM(prefixes); i++) {
1148 int rv = snprintf(env_name, NAME_MAX, "%s%s", prefixes[i], option);
1149
1150 if (rv < 0) {
1151 crm_err("Failed to write %s%s to buffer: %s", prefixes[i], option,
1152 strerror(errno));
1153 return;
1154 }
1155
1156 if (rv >= sizeof(env_name)) {
1157 crm_trace("\"%s%s\" is too long", prefixes[i], option);
1158 continue;
1159 }
1160
1161 if (value != NULL) {
1162 crm_trace("Setting %s to %s", env_name, value);
1163 rv = setenv(env_name, value, 1);
1164 } else {
1165 crm_trace("Unsetting %s", env_name);
1166 rv = unsetenv(env_name);
1167 }
1168
1169 if (rv < 0) {
1170 crm_err("Failed to %sset %s: %s", (value != NULL)? "" : "un",
1171 env_name, strerror(errno));
1172 }
1173
1174 if (!compat && (value != NULL)) {
1175
1176 break;
1177 }
1178 }
1179 }
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194 bool
1195 pcmk__env_option_enabled(const char *daemon, const char *option)
1196 {
1197 const char *value = pcmk__env_option(option);
1198
1199 return (value != NULL)
1200 && (crm_is_true(value)
1201 || ((daemon != NULL) && (strstr(value, daemon) != NULL)));
1202 }
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218 bool
1219 pcmk__valid_interval_spec(const char *value)
1220 {
1221 return pcmk_parse_interval_spec(value, NULL) == pcmk_rc_ok;
1222 }
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232 bool
1233 pcmk__valid_boolean(const char *value)
1234 {
1235 return crm_str_to_boolean(value, NULL) == 1;
1236 }
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248 bool
1249 pcmk__valid_int(const char *value)
1250 {
1251 return (value != NULL)
1252 && (pcmk_str_is_infinity(value)
1253 || pcmk_str_is_minus_infinity(value)
1254 || (pcmk__scan_ll(value, NULL, 0LL) == pcmk_rc_ok));
1255 }
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268 bool
1269 pcmk__valid_positive_int(const char *value)
1270 {
1271 long long num = 0LL;
1272
1273 return pcmk_str_is_infinity(value)
1274 || ((pcmk__scan_ll(value, &num, 0LL) == pcmk_rc_ok)
1275 && (num > 0));
1276 }
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288 bool
1289 pcmk__valid_no_quorum_policy(const char *value)
1290 {
1291 return pcmk__strcase_any_of(value,
1292 PCMK_VALUE_STOP, PCMK_VALUE_FREEZE,
1293 PCMK_VALUE_IGNORE, PCMK_VALUE_DEMOTE,
1294 PCMK_VALUE_FENCE_LEGACY, NULL);
1295 }
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309 bool
1310 pcmk__valid_percentage(const char *value)
1311 {
1312 char *end = NULL;
1313 float number = strtof(value, &end);
1314
1315 return ((end == NULL) || (end[0] == '%')) && (number >= 0);
1316 }
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327 bool
1328 pcmk__valid_placement_strategy(const char *value)
1329 {
1330 return pcmk__strcase_any_of(value,
1331 PCMK_VALUE_DEFAULT, PCMK_VALUE_UTILIZATION,
1332 PCMK_VALUE_MINIMAL, PCMK_VALUE_BALANCED, NULL);
1333 }
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344 static const char *
1345 cluster_option_value(GHashTable *table, const pcmk__cluster_option_t *option)
1346 {
1347 const char *value = NULL;
1348
1349 CRM_ASSERT((option != NULL) && (option->name != NULL));
1350
1351 if (table != NULL) {
1352 value = g_hash_table_lookup(table, option->name);
1353
1354 if ((value == NULL) && (option->alt_name != NULL)) {
1355 value = g_hash_table_lookup(table, option->alt_name);
1356 if (value != NULL) {
1357 pcmk__config_warn("Support for legacy name '%s' for cluster "
1358 "option '%s' is deprecated and will be "
1359 "removed in a future release",
1360 option->alt_name, option->name);
1361
1362
1363 pcmk__insert_dup(table, option->name, value);
1364 }
1365 }
1366
1367 if ((value != NULL) && (option->is_valid != NULL)
1368 && !option->is_valid(value)) {
1369
1370 pcmk__config_err("Using default value for cluster option '%s' "
1371 "because '%s' is invalid", option->name, value);
1372 value = NULL;
1373 }
1374
1375 if (value != NULL) {
1376 return value;
1377 }
1378 }
1379
1380
1381 value = option->default_value;
1382
1383 if (value == NULL) {
1384 crm_trace("No value or default provided for cluster option '%s'",
1385 option->name);
1386 return NULL;
1387 }
1388
1389 CRM_CHECK((option->is_valid == NULL) || option->is_valid(value),
1390 crm_err("Bug: default value for cluster option '%s' is invalid",
1391 option->name);
1392 return NULL);
1393
1394 crm_trace("Using default value '%s' for cluster option '%s'",
1395 value, option->name);
1396 if (table != NULL) {
1397 pcmk__insert_dup(table, option->name, value);
1398 }
1399 return value;
1400 }
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411 const char *
1412 pcmk__cluster_option(GHashTable *options, const char *name)
1413 {
1414 for (const pcmk__cluster_option_t *option = cluster_options;
1415 option->name != NULL; option++) {
1416
1417 if (pcmk__str_eq(name, option->name, pcmk__str_casei)) {
1418 return cluster_option_value(options, option);
1419 }
1420 }
1421 CRM_CHECK(FALSE, crm_err("Bug: looking for unknown option '%s'", name));
1422 return NULL;
1423 }
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444 int
1445 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 return out->message(out, "option-list", name, desc_short, desc_long, filter,
1450 cluster_options, all);
1451 }
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467 int
1468 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 return out->message(out, "option-list", name, desc_short, desc_long,
1473 pcmk__opt_none, primitive_meta, all);
1474 }
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494 int
1495 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 return out->message(out, "option-list", name, desc_short, desc_long,
1500 pcmk__opt_none, fencing_params, all);
1501 }
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516 int
1517 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
1522 pcmk__output_t *tmp_out = NULL;
1523 xmlNode *top = NULL;
1524 const xmlNode *metadata = NULL;
1525 GString *metadata_s = NULL;
1526
1527 int rc = pcmk__output_new(&tmp_out, "xml", "/dev/null", NULL);
1528
1529 if (rc != pcmk_rc_ok) {
1530 return rc;
1531 }
1532
1533 pcmk__output_set_legacy_xml(tmp_out);
1534
1535 if (filter == pcmk__opt_fencing) {
1536 pcmk__output_fencing_params(tmp_out, name, desc_short, desc_long, true);
1537 } else {
1538 pcmk__output_cluster_options(tmp_out, name, desc_short, desc_long,
1539 (uint32_t) filter, true);
1540 }
1541
1542 tmp_out->finish(tmp_out, CRM_EX_OK, false, (void **) &top);
1543 metadata = pcmk__xe_first_child(top, PCMK_XE_RESOURCE_AGENT, NULL, NULL);
1544
1545 metadata_s = g_string_sized_new(16384);
1546 pcmk__xml_string(metadata, pcmk__xml_fmt_pretty|pcmk__xml_fmt_text,
1547 metadata_s, 0);
1548
1549 out->output_xml(out, PCMK_XE_METADATA, metadata_s->str);
1550
1551 pcmk__output_free(tmp_out);
1552 free_xml(top);
1553 g_string_free(metadata_s, TRUE);
1554 return pcmk_rc_ok;
1555 }
1556
1557 void
1558 pcmk__validate_cluster_options(GHashTable *options)
1559 {
1560 for (const pcmk__cluster_option_t *option = cluster_options;
1561 option->name != NULL; option++) {
1562
1563 cluster_option_value(options, option);
1564 }
1565 }