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