diff --git a/cts/cli/regression.agents.exp b/cts/cli/regression.agents.exp
index 20218fac3a..3ac93c1e25 100644
--- a/cts/cli/regression.agents.exp
+++ b/cts/cli/regression.agents.exp
@@ -1,33 +1,33 @@
=#=#=#= Begin test: Validate a valid resource configuration =#=#=#=
-Operation validate (ocf:pacemaker:Dummy) returned 0 (ok)
+Operation validate (ocf:pacemaker:Dummy) returned 0 (OK)
=#=#=#= End test: Validate a valid resource configuration - OK (0) =#=#=#=
* Passed: crm_resource - Validate a valid resource configuration
=#=#=#= Begin test: Validate a valid resource configuration (XML) =#=#=#=
-
+
=#=#=#= End test: Validate a valid resource configuration (XML) - OK (0) =#=#=#=
* Passed: crm_resource - Validate a valid resource configuration (XML)
=#=#=#= Begin test: Validate an invalid resource configuration =#=#=#=
crm_resource: Error performing operation: Not configured
-Operation validate (ocf:pacemaker:Dummy) returned 6 (not configured)
+Operation validate (ocf:pacemaker:Dummy) returned 6 (Not configured)
=#=#=#= End test: Validate an invalid resource configuration - Not configured (6) =#=#=#=
-* Passed: crm_resource - Validate an invalid resource configuration
+* Passed: crm_resource - Validate an invalid resource configuration
=#=#=#= Begin test: Validate an invalid resource configuration (XML) =#=#=#=
-
+
crm_resource: Error performing operation: Not configured
=#=#=#= End test: Validate an invalid resource configuration (XML) - Not configured (6) =#=#=#=
-* Passed: crm_resource - Validate an invalid resource configuration (XML)
+* Passed: crm_resource - Validate an invalid resource configuration (XML)
diff --git a/doc/sphinx/Pacemaker_Administration/upgrading.rst b/doc/sphinx/Pacemaker_Administration/upgrading.rst
index c06151fb51..b23c65ea89 100644
--- a/doc/sphinx/Pacemaker_Administration/upgrading.rst
+++ b/doc/sphinx/Pacemaker_Administration/upgrading.rst
@@ -1,565 +1,565 @@
.. index:: upgrade
Upgrading a Pacemaker Cluster
-----------------------------
.. index:: version
Pacemaker Versioning
####################
Pacemaker has an overall release version, plus separate version numbers for
certain internal components.
.. index::
single: version; release
* **Pacemaker release version:** This version consists of three numbers
(*x.y.z*).
The major version number (the *x* in *x.y.z*) increases when at least some
rolling upgrades are not possible from the previous major version. For example,
a rolling upgrade from 1.0.8 to 1.1.15 should always be supported, but a
rolling upgrade from 1.0.8 to 2.0.0 may not be possible.
The minor version (the *y* in *x.y.z*) increases when there are significant
changes in cluster default behavior, tool behavior, and/or the API interface
(for software that utilizes Pacemaker libraries). The main benefit is to alert
you to pay closer attention to the release notes, to see if you might be
affected.
The release counter (the *z* in *x.y.z*) is increased with all public releases
of Pacemaker, which typically include both bug fixes and new features.
.. index::
single: feature set
single: version; feature set
* **CRM feature set:** This version number applies to the communication between
full cluster nodes, and is used to avoid problems in mixed-version clusters.
The major version number increases when nodes with different versions would not
work (rolling upgrades are not allowed). The minor version number increases
when mixed-version clusters are allowed only during rolling upgrades. The
minor-minor version number is ignored, but allows resource agents to detect
cluster support for various features. [#]_
Pacemaker ensures that the longest-running node is the cluster's DC. This
ensures new features are not enabled until all nodes are upgraded to support
them.
.. index::
single: version; Pacemaker Remote protocol
* **Pacemaker Remote protocol version:** This version applies to communication
between a Pacemaker Remote node and the cluster. It increases when an older
cluster node would have problems hosting the connection to a newer
Pacemaker Remote node. To avoid these problems, Pacemaker Remote nodes will
accept connections only from cluster nodes with the same or newer
Pacemaker Remote protocol version.
Unlike with CRM feature set differences between full cluster nodes,
mixed Pacemaker Remote protocol versions between Pacemaker Remote nodes and
full cluster nodes are fine, as long as the Pacemaker Remote nodes have the
older version. This can be useful, for example, to host a legacy application
in an older operating system version used as a Pacemaker Remote node.
.. index::
single: version; XML schema
* **XML schema version:** Pacemaker’s configuration syntax — what's allowed in
the Configuration Information Base (CIB) — has its own version. This allows
the configuration syntax to evolve over time while still allowing clusters
with older configurations to work without change.
.. index::
single: upgrade; methods
Upgrading Cluster Software
##########################
There are three approaches to upgrading a cluster, each with advantages and
disadvantages.
.. table:: **Upgrade Methods**
+---------------------------------------------------+----------+----------+--------+---------+----------+----------+
| Method | Available| Can be | Service| Service | Exercises| Allows |
| | between | used with| outage | recovery| failover | change of|
| | all | Pacemaker| during | during | logic | messaging|
| | versions | Remote | upgrade| upgrade | | layer |
| | | nodes | | | | [#]_ |
+===================================================+==========+==========+========+=========+==========+==========+
| Complete cluster shutdown | yes | yes | always | N/A | no | yes |
+---------------------------------------------------+----------+----------+--------+---------+----------+----------+
| Rolling (node by node) | no | yes | always | yes | yes | no |
| | | | [#]_ | | | |
+---------------------------------------------------+----------+----------+--------+---------+----------+----------+
| Detach and reattach | yes | no | only | no | no | yes |
| | | | due to | | | |
| | | | failure| | | |
+---------------------------------------------------+----------+----------+--------+---------+----------+----------+
.. index::
single: upgrade; shutdown
Complete Cluster Shutdown
_________________________
In this scenario, one shuts down all cluster nodes and resources,
then upgrades all the nodes before restarting the cluster.
#. On each node:
a. Shutdown the cluster software (pacemaker and the messaging layer).
#. Upgrade the Pacemaker software. This may also include upgrading the
messaging layer and/or the underlying operating system.
#. Check the configuration with the ``crm_verify`` tool.
#. On each node:
a. Start the cluster software.
Currently, only Corosync version 2 and greater is supported as the cluster
layer, but if another stack is supported in the future, the stack does not
need to be the same one before the upgrade.
One variation of this approach is to build a new cluster on new hosts.
This allows the new version to be tested beforehand, and minimizes downtime by
having the new nodes ready to be placed in production as soon as the old nodes
are shut down.
.. index::
single: upgrade; rolling upgrade
Rolling (node by node)
______________________
In this scenario, each node is removed from the cluster, upgraded, and then
brought back online, until all nodes are running the newest version.
Special considerations when planning a rolling upgrade:
* If you plan to upgrade other cluster software -- such as the messaging layer --
at the same time, consult that software's documentation for its compatibility
with a rolling upgrade.
* If the major version number is changing in the Pacemaker version you are
upgrading to, a rolling upgrade may not be possible. Read the new version's
release notes (as well the information here) for what limitations may exist.
* If the CRM feature set is changing in the Pacemaker version you are upgrading
to, you should run a mixed-version cluster only during a small rolling
upgrade window. If one of the older nodes drops out of the cluster for any
reason, it will not be able to rejoin until it is upgraded.
* If the Pacemaker Remote protocol version is changing, all cluster nodes
should be upgraded before upgrading any Pacemaker Remote nodes.
See the
`Pacemaker release calendar
`_
on the ClusterLabs wiki to figure out whether the CRM feature set and/or
Pacemaker Remote protocol version changed between the Pacemaker release versions
in your rolling upgrade.
To perform a rolling upgrade, on each node in turn:
#. Put the node into standby mode, and wait for any active resources
to be moved cleanly to another node. (This step is optional, but
allows you to deal with any resource issues before the upgrade.)
#. Shut down Pacemaker or ``pacemaker-remoted``.
#. If a cluster node, shut down the messaging layer.
#. Upgrade the Pacemaker software. This may also include upgrading the
messaging layer and/or the underlying operating system.
#. If this is the first node to be upgraded, check the configuration
with the ``crm_verify`` tool.
#. If a cluster node, start the messaging layer.
This must be the same messaging layer (currently only Corosync version 2 and
greater is supported) that the rest of the cluster is using.
#. Start Pacemaker or ``pacemaker-remoted``.
.. note::
Even if a rolling upgrade from the current version of the cluster to the
newest version is not directly possible, it may be possible to perform a
rolling upgrade in multiple steps, by upgrading to an intermediate version
first.
The following table lists compatible versions for all other nodes in the cluster
when upgrading a cluster node.
.. list-table:: **Version Compatibility for Cluster Nodes**
:class: longtable
:widths: 1 1
:header-rows: 1
* - Version Being Installed
- Minimum Compatible Version
* - Pacemaker 3.y.z
- Pacemaker 2.0.0
* - Pacemaker 2.y.z
- Pacemaker 1.1.11 [#]_
* - Pacemaker 1.y.z
- Pacemaker 1.0.0
* - Pacemaker 0.6.z to 0.7.z
- - Pacemaker 0.6.z
+ - Pacemaker 0.6.0
When upgrading a Pacemaker Remote node, all cluster nodes must be running at
least the minimum version listed in the table below.
.. list-table:: **Cluster Node Version Compatibility for Pacemaker Remote Nodes**
:class: longtable
:widths: 1 1
:header-rows: 1
* - Pacemaker Remote Version
- Minimum Cluster Node Version
* - Pacemaker 3.y.z
- Pacemaker 2.0.0
* - Pacemaker 1.1.9 to 2.1.z
- Pacemaker 1.1.9 [#]_
.. index::
single: upgrade; detach and reattach
Detach and Reattach
___________________
The reattach method is a variant of a complete cluster shutdown, where the
resources are left active and get re-detected when the cluster is restarted.
This method may not be used if the cluster contains any Pacemaker Remote nodes.
#. Tell the cluster to stop managing services. This is required to allow the
services to remain active after the cluster shuts down.
.. code-block:: none
# crm_attribute --name maintenance-mode --update true
#. On each node, shutdown the cluster software (pacemaker and the messaging
layer), and upgrade the Pacemaker software. This may also include upgrading
the messaging layer. While the underlying operating system may be upgraded
at the same time, that will be more likely to cause outages in the detached
services (certainly, if a reboot is required).
#. Check the configuration with the ``crm_verify`` tool.
#. On each node, start the cluster software.
Currently, only Corosync version 2 and greater is supported as the cluster
layer, but if another stack is supported in the future, the stack does not
need to be the same one before the upgrade.
#. Verify that the cluster re-detected all resources correctly.
#. Allow the cluster to resume managing resources again:
.. code-block:: none
# crm_attribute --name maintenance-mode --delete
.. note::
While the goal of the detach-and-reattach method is to avoid disturbing
running services, resources may still move after the upgrade if any
resource's location is governed by a rule based on transient node
attributes. Transient node attributes are erased when the node leaves the
cluster. A common example is using the ``ocf:pacemaker:ping`` resource to
set a node attribute used to locate other resources.
.. index::
pair: upgrade; CIB
Upgrading the Configuration
###########################
The CIB schema version can change from one Pacemaker version to another.
After cluster software is upgraded, the cluster will continue to use the older
schema version that it was previously using. This can be useful, for example,
when administrators have written tools that modify the configuration, and are
based on the older syntax. [#]_
However, when using an older syntax, new features may be unavailable, and there
is a performance impact, since the cluster must do a non-persistent
configuration upgrade before each transition. So while using the old syntax is
possible, it is not advisable to continue using it indefinitely.
Even if you wish to continue using the old syntax, it is a good idea to
follow the upgrade procedure outlined below, except for the last step, to ensure
that the new software has no problems with your existing configuration (since it
will perform much the same task internally).
If you are brave, it is sufficient simply to run ``cibadmin --upgrade``.
A more cautious approach would proceed like this:
#. Create a shadow copy of the configuration. The later commands will
automatically operate on this copy, rather than the live configuration.
.. code-block:: none
# crm_shadow --create shadow
.. index::
single: configuration; verify
#. Verify the configuration is valid with the new software (which may be
stricter about syntax mistakes, or may have dropped support for deprecated
features):
.. code-block:: none
# crm_verify --live-check
#. Fix any errors or warnings.
#. Perform the upgrade:
.. code-block:: none
# cibadmin --upgrade
#. If this step fails, there are three main possibilities:
a. The configuration was not valid to start with (did you do steps 2 and
3?).
#. The transformation failed; `report a bug `_.
#. The transformation was successful but produced an invalid result.
If the result of the transformation is invalid, you may see a number of
errors from the validation library. If these are not helpful, try the manual
upgrade procedure described below.
#. Check the changes:
.. code-block:: none
# crm_shadow --diff
If at this point there is anything about the upgrade that you wish to
fine-tune (for example, to change some of the automatic IDs), now is the
time to do so:
.. code-block:: none
# crm_shadow --edit
This will open the configuration in your favorite editor (whichever is
specified by the standard ``$EDITOR`` environment variable).
#. Preview how the cluster will react:
.. code-block:: none
# crm_simulate --live-check --save-dotfile shadow.dot -S
# dot -Tsvg shadow.dot -o shadow.svg
You can then view shadow.svg with any compatible image viewer or web
browser. Verify that either no resource actions will occur or that you are
happy with any that are scheduled. If the output contains actions you do
not expect (possibly due to changes to the score calculations), you may need
to make further manual changes. See :ref:`crm_simulate` for further details
on how to interpret the output of ``crm_simulate`` and ``dot``.
#. Upload the changes:
.. code-block:: none
# crm_shadow --commit shadow --force
In the unlikely event this step fails, please report a bug.
.. note::
It is also possible to perform the configuration upgrade steps manually:
#. Locate the ``upgrade*.xsl`` conversion scripts provided with the source
code. These will often be installed in a location such as
``/usr/share/pacemaker``, or may be obtained from the
`source repository `_.
#. Run the conversion scripts that apply to your older version, for example:
.. code-block:: none
# xsltproc /path/to/upgrade06.xsl config06.xml > config10.xml
#. Locate the ``pacemaker.rng`` script (from the same location as the xsl
files).
#. Check the XML validity:
.. code-block:: none
# xmllint --relaxng /path/to/pacemaker.rng config10.xml
The advantage of this method is that it can be performed without the cluster
running, and any validation errors are often more informative.
What Changed in 2.1
###################
The Pacemaker 2.1 release is fully backward-compatible in both the CIB XML and
the C API. Highlights:
* Pacemaker now supports the **OCF Resource Agent API version 1.1**.
Most notably, the ``Master`` and ``Slave`` role names have been renamed to
``Promoted`` and ``Unpromoted``.
* Pacemaker now supports colocations where the dependent resource does not
affect the primary resource's placement (via a new ``influence`` colocation
constraint option and ``critical`` resource meta-attribute). This is intended
for cases where a less-important resource must be colocated with an essential
resource, but it is preferred to leave the less-important resource stopped if
it fails, rather than move both resources.
* If Pacemaker is built with libqb 2.0 or later, the detail log will use
**millisecond-resolution timestamps**.
* In addition to crm_mon and stonith_admin, the crmadmin, crm_resource,
crm_simulate, and crm_verify commands now support the ``--output-as`` and
``--output-to`` options, including **XML output** (which scripts and
higher-level tools are strongly recommended to use instead of trying to parse
the text output, which may change from release to release).
For a detailed list of changes, see the release notes and
`Pacemaker 2.1 Changes
`_
on the ClusterLabs wiki.
What Changed in 2.0
###################
The main goal of the 2.0 release was to remove support for deprecated syntax,
along with some small changes in default configuration behavior and tool
behavior. Highlights:
* Only Corosync version 2 and greater is now supported as the underlying
cluster layer. Support for Heartbeat and Corosync 1 (including CMAN) is
removed.
* The Pacemaker detail log file is now stored in
``/var/log/pacemaker/pacemaker.log`` by default.
* The record-pending cluster property now defaults to true, which
allows status tools such as crm_mon to show operations that are in
progress.
* Support for a number of deprecated build options, environment variables,
and configuration settings has been removed.
* The ``master`` tag has been deprecated in favor of using the ``clone`` tag
with the new ``promotable`` meta-attribute set to ``true``. "Master/slave"
clone resources are now referred to as "promotable" clone resources.
* The public API for Pacemaker libraries that software applications can use
has changed significantly.
For a detailed list of changes, see the release notes and
`Pacemaker 2.0 Changes
`_
on the ClusterLabs wiki.
What Changed in 1.0
###################
New
___
* Failure timeouts.
* New section for resource and operation defaults.
* Tool for making offline configuration changes.
* ``Rules``, ``instance_attributes``, ``meta_attributes`` and sets of
operations can be defined once and referenced in multiple places.
* The CIB now accepts XPath-based create/modify/delete operations. See
``cibadmin --help``.
* Multi-dimensional colocation and ordering constraints.
* The ability to connect to the CIB from non-cluster machines.
* Allow recurring actions to be triggered at known times.
Changed
_______
* Syntax
* All resource and cluster options now use dashes (-) instead of underscores
(_)
* ``master_slave`` was renamed to ``master``
* The ``attributes`` container tag was removed
* The operation field ``pre-req`` has been renamed ``requires``
* All operations must have an ``interval``, ``start``/``stop`` must have it
set to zero
* The ``stonith-enabled`` option now defaults to true.
* The cluster will refuse to start resources if ``stonith-enabled`` is true (or
unset) and no STONITH resources have been defined
* The attributes of colocation and ordering constraints were renamed for
clarity.
* ``resource-failure-stickiness`` has been replaced by ``migration-threshold``.
* The parameters for command-line tools have been made consistent
* Switched to 'RelaxNG' schema validation and 'libxml2' parser
* id fields are now XML IDs which have the following limitations:
* id's cannot contain colons (:)
* id's cannot begin with a number
* id's must be globally unique (not just unique for that tag)
* Some fields (such as those in constraints that refer to resources) are
IDREFs.
This means that they must reference existing resources or objects in
order for the configuration to be valid. Removing an object which is
referenced elsewhere will therefore fail.
* The CIB representation, from which a MD5 digest is calculated to verify
CIBs on the nodes, has changed.
This means that every CIB update will require a full refresh on any
upgraded nodes until the cluster is fully upgraded to 1.0. This will result
in significant performance degradation and it is therefore highly
inadvisable to run a mixed 1.0/0.6 cluster for any longer than absolutely
necessary.
* Ping node information no longer needs to be added to ``ha.cf``. Simply
include the lists of hosts in your ping resource(s).
Removed
_______
* Syntax
* It is no longer possible to set resource meta options as top-level
attributes. Use meta-attributes instead.
* Resource and operation defaults are no longer read from ``crm_config``.
.. rubric:: Footnotes
.. [#] Before CRM feature set 3.1.0 (Pacemaker 2.0.0), the minor-minor version
number was treated the same as the minor version.
.. [#] Currently, Corosync version 2 and greater is the only supported cluster
stack, but other stacks have been supported by past versions, and may be
supported by future versions.
.. [#] Any active resources will be moved off the node being upgraded, so there
will be at least a brief outage unless all resources can be migrated
"live".
.. [#] Rolling upgrades from Pacemaker 1.1.z to 2.y.z are possible only if the
cluster uses corosync version 2 or greater as its messaging layer, and
the Cluster Information Base (CIB) uses schema 1.0 or higher in its
``validate-with`` property.
.. [#] Pacemaker Remote versions 1.1.15 through 1.1.17 require cluster nodes to
be at least version 1.1.15. Version 1.1.15 introduced an accidental
remote protocol version bump, breaking rolling upgrade compatibility with
older versions. This was fixed in 1.1.18.
.. [#] As of Pacemaker 2.0.0, only schema versions pacemaker-1.0 and higher
are supported (excluding pacemaker-1.1, which was a special case).
diff --git a/doc/sphinx/Pacemaker_Development/c.rst b/doc/sphinx/Pacemaker_Development/c.rst
index 91efe7cddb..3f3c9746fb 100644
--- a/doc/sphinx/Pacemaker_Development/c.rst
+++ b/doc/sphinx/Pacemaker_Development/c.rst
@@ -1,1129 +1,1129 @@
.. index::
single: C
pair: C; guidelines
C Coding Guidelines
-------------------
Pacemaker is a large project accepting contributions from developers with a
wide range of skill levels and organizational affiliations, and maintained by
multiple people over long periods of time. Following consistent guidelines
makes reading, writing, and reviewing code easier, and helps avoid common
mistakes.
Some existing Pacemaker code does not follow these guidelines, for historical
reasons and API backward compatibility, but new code should.
Code Organization
#################
Pacemaker's C code is organized as follows:
+-----------------+-----------------------------------------------------------+
| Directory | Contents |
+=================+===========================================================+
| daemons | the Pacemaker daemons (pacemakerd, pacemaker-based, etc.) |
+-----------------+-----------------------------------------------------------+
| include | header files for library APIs |
+-----------------+-----------------------------------------------------------+
| lib | libraries |
+-----------------+-----------------------------------------------------------+
| tools | command-line tools |
+-----------------+-----------------------------------------------------------+
Source file names should be unique across the entire project, to allow for
individual tracing via ``PCMK_trace_files``.
.. index::
single: C; library
single: C library
Pacemaker Libraries
###################
+---------------+---------+---------------+---------------------------+-------------------------------------+
| Library | Symbol | Source | API Headers | Description |
| | prefix | location | | |
+===============+=========+===============+===========================+=====================================+
| libcib | cib | lib/cib | | include/crm/cib.h | .. index:: |
| | | | | include/crm/cib/* | single: C library; libcib |
| | | | | single: libcib |
| | | | | |
| | | | | API for pacemaker-based IPC and |
| | | | | the CIB |
+---------------+---------+---------------+---------------------------+-------------------------------------+
| libcrmcluster | pcmk | lib/cluster | | include/crm/cluster.h | .. index:: |
| | | | | include/crm/cluster/* | single: C library; libcrmcluster |
| | | | | single: libcrmcluster |
| | | | | |
| | | | | Abstract interface to underlying |
| | | | | cluster layer |
+---------------+---------+---------------+---------------------------+-------------------------------------+
| libcrmcommon | pcmk | lib/common | | include/crm/common/* | .. index:: |
| | | | | some of include/crm/* | single: C library; libcrmcommon |
| | | | | single: libcrmcommon |
| | | | | |
| | | | | Everything else |
+---------------+---------+---------------+---------------------------+-------------------------------------+
| libcrmservice | svc | lib/services | | include/crm/services.h | .. index:: |
| | | | | single: C library; libcrmservice |
| | | | | single: libcrmservice |
| | | | | |
| | | | | Abstract interface to supported |
| | | | | resource types (OCF, LSB, etc.) |
+---------------+---------+---------------+---------------------------+-------------------------------------+
| liblrmd | lrmd | lib/lrmd | | include/crm/lrmd*.h | .. index:: |
| | | | | single: C library; liblrmd |
| | | | | single: liblrmd |
| | | | | |
| | | | | API for pacemaker-execd IPC |
+---------------+---------+---------------+---------------------------+-------------------------------------+
| libpacemaker | pcmk | lib/pacemaker | | include/pacemaker*.h | .. index:: |
| | | | | include/pcmki/* | single: C library; libpacemaker |
| | | | | single: libpacemaker |
| | | | | |
| | | | | High-level APIs equivalent to |
| | | | | command-line tool capabilities |
| | | | | (and high-level internal APIs) |
+---------------+---------+---------------+---------------------------+-------------------------------------+
| libpe_rules | pe | lib/pengine | | include/crm/pengine/* | .. index:: |
| | | | | single: C library; libpe_rules |
| | | | | single: libpe_rules |
| | | | | |
| | | | | Scheduler functionality related |
| | | | | to evaluating rules |
+---------------+---------+---------------+---------------------------+-------------------------------------+
| libpe_status | pe | lib/pengine | | include/crm/pengine/* | .. index:: |
| | | | | single: C library; libpe_status |
| | | | | single: libpe_status |
| | | | | |
| | | | | Low-level scheduler functionality |
+---------------+---------+---------------+---------------------------+-------------------------------------+
| libstonithd | stonith | lib/fencing | | include/crm/stonith-ng.h| .. index:: |
| | | | | include/crm/fencing/* | single: C library; libstonithd |
| | | | | single: libstonithd |
| | | | | |
| | | | | API for pacemaker-fenced IPC |
+---------------+---------+---------------+---------------------------+-------------------------------------+
Public versus Internal APIs
___________________________
Pacemaker libraries have both internal and public APIs. Internal APIs are those
used only within Pacemaker; public APIs are those offered (via header files and
documentation) for external code to use.
Generic functionality needed by Pacemaker itself, such as string processing or
XML processing, should remain internal, while functions providing useful
high-level access to Pacemaker capabilities should be public. When in doubt,
keep APIs internal, because it's easier to expose a previously internal API
than hide a previously public API.
Internal APIs can be changed as needed.
The public API/ABI should maintain a degree of stability so that external
applications using it do not need to be rewritten or rebuilt frequently. Many
OSes/distributions avoid breaking API/ABI compatibility within a major release,
so if Pacemaker breaks compatibility, that significantly delays when OSes
can package the new version. Therefore, changes to public APIs should be
backward-compatible (as detailed throughout this chapter), unless we are doing
a (rare) release where we specifically intend to break compatibility.
External applications known to use Pacemaker's public C API include
`sbd `_ and dlm_controld.
.. index::
pair: C; naming
API Symbol Naming
_________________
Exposed API symbols (non-``static`` function names, ``struct`` and ``typedef``
names in header files, etc.) must begin with the prefix appropriate to the
library (shown in the table at the beginning of this section). This reduces the
chance of naming collisions when external software links against the library.
The prefix is usually lowercase but may be all-caps for some defined constants
and macros.
Public API symbols should follow the library prefix with a single underbar
(for example, ``pcmk_something``), and internal API symbols with a double
underbar (for example, ``pcmk__other_thing``).
File-local symbols (such as static functions) and non-library code do not
require a prefix, though a unique prefix indicating an executable (controld,
crm_mon, etc.) can be helpful when symbols are shared between multiple
source files for the executable.
API Header File Naming
______________________
* Internal API headers should be named ending in ``_internal.h``, in the same
location as public headers, with the exception of libpacemaker, which for
historical reasons keeps internal headers in ``include/pcmki/pcmki_*.h``).
* If a library needs to share symbols just within the library, header files for
these should be named ending in ``_private.h`` and located in the library
source directory (not ``include``). Such functions should be declared as
``G_GNUC_INTERNAL``, to aid compiler efficiency (glib defines this
symbol appropriately for the compiler).
Header files that are not library API are kept in the same directory as the
source code they're included from.
The easiest way to tell what kind of API a symbol is, is to see where it's
declared. If it's in a public header, it's public API; if it's in an internal
header, it's internal API; if it's in a library-private header, it's
library-private API; otherwise, it's not an API.
.. index::
pair: C; API documentation
single: Doxygen
API Documentation
_________________
Pacemaker uses `Doxygen `_
to automatically generate its
`online API documentation `_,
so all public API (header files, functions, structs, enums, etc.) should be
documented with Doxygen comment blocks. Other code may be documented in the
same way if desired, with an ``\internal`` tag in the Doxygen comment.
Simple example of an internal function with a Doxygen comment block:
.. code-block:: c
/*!
* \internal
* \brief Return string length plus 1
*
* Return the number of characters in a given string, plus one.
*
* \param[in] s A string (must not be NULL)
*
* \return The length of \p s plus 1.
*/
static int
f(const char *s)
{
return strlen(s) + 1;
}
Function arguments are marked as ``[in]`` for input only, ``[out]`` for output
only, or ``[in,out]`` for both input and output.
``[in,out]`` should be used for struct pointer arguments if the function can
change any data accessed via the pointer. For example, if the struct contains
a ``GHashTable *`` member, the argument should be marked as ``[in,out]`` if the
function inserts data into the table, even if the struct members themselves are
not changed. However, an argument is not ``[in,out]`` if something reachable
via the argument is modified via a separate argument. For example, both
``pcmk_resource_t`` and ``pcmk_node_t`` contain pointers to their
``pcmk_scheduler_t`` and thus indirectly to each other, but if the function
modifies the resource via the resource argument, the node argument does not
have to be ``[in,out]``.
Public API Deprecation
______________________
Public APIs may not be removed in most Pacemaker releases, but they may be
deprecated.
When a public API is deprecated, it is moved to a header whose name ends in
``compat.h``. The original header includes the compatibility header only if the
``PCMK_ALLOW_DEPRECATED`` symbol is undefined or defined to 1. This allows
external code to continue using the deprecated APIs, but internal code is
prevented from using them because the ``crm_internal.h`` header defines the
symbol to 0.
.. index::
pair: C; boilerplate
pair: license; C
pair: copyright; C
C Boilerplate
#############
Every C file should start with a short copyright and license notice:
.. code-block:: c
/*
* Copyright the Pacemaker project contributors
*
* The version control history for this file may have further details.
*
* This source code is licensed under WITHOUT ANY WARRANTY.
*/
** should follow the policy set forth in the
`COPYING `_ file,
generally one of "GNU General Public License version 2 or later (GPLv2+)"
or "GNU Lesser General Public License version 2.1 or later (LGPLv2.1+)".
Header files should additionally protect against multiple inclusion by defining
a unique symbol of the form ``PCMK____H``, and declare
C compatibility for inclusion by C++. For example:
.. code-block:: c
#ifndef PCMK__MY_HEADER__H
#define PCMK__MY_HEADER__H
// put #include directives here
#ifdef __cplusplus
extern "C" {
#endif
// put header code here
#ifdef __cplusplus
}
#endif
#endif // PCMK__MY_HEADER__H
Public API header files should give a Doxygen file description at the top of
the header code. For example:
.. code-block:: c
/*!
* \file
* \brief My brief description here
* \ingroup core
*/
.. index::
pair: C; whitespace
Line Formatting
###############
* Indentation must be 4 spaces, no tabs.
* Do not leave trailing whitespace.
* Lines should be no longer than 80 characters unless limiting line length
hurts readability.
.. index::
pair: C; comment
Comments
########
.. code-block:: c
/* Single-line comments may look like this */
// ... or this
/* Multi-line comments should start immediately after the comment opening.
* Subsequent lines should start with an aligned asterisk. The comment
* closing should be aligned and on a line by itself.
*/
.. index::
pair: C; operator
Operators
#########
.. code-block:: c
// Operators have spaces on both sides
x = a;
/* (1) Do not rely on operator precedence; use parentheses when mixing
* operators with different priority, for readability.
* (2) No space is used after an opening parenthesis or before a closing
* parenthesis.
*/
x = a + b - (c * d);
.. index::
single: C; if
single: C; else
single: C; while
single: C; for
single: C; switch
Control Statements (if, else, while, for, switch)
#################################################
.. code-block:: c
/*
* (1) The control keyword is followed by a space, a left parenthesis
* without a space, the condition, a right parenthesis, a space, and the
* opening bracket on the same line.
* (2) Always use braces around control statement blocks, even if they only
* contain one line. This makes code review diffs smaller if a line gets
* added in the future, and avoids the chance of bad indenting making a
* line incorrectly appear to be part of the block.
* (3) The closing bracket is on a line by itself.
*/
if (v < 0) {
return 0;
}
/* "else" and "else if" are on the same line with the previous ending brace
* and next opening brace, separated by a space. Blank lines may be used
* between blocks to help readability.
*/
if (v > 0) {
return 0;
} else if (a == 0) {
return 1;
} else {
return 2;
}
/* Do not use assignments in conditions. This ensures that the developer's
* intent is always clear, makes code reviews easier, and reduces the chance
* of using assignment where comparison is intended.
*/
// Do this ...
a = f();
if (a) {
return 0;
}
// ... NOT this
if (a = f()) {
return 0;
}
/* It helps readability to use the "!" operator only in boolean
* comparisons, and explicitly compare numeric values against 0,
* pointers against NULL, etc. This helps remind the reader of the
* type being compared.
*/
int i = 0;
char *s = NULL;
bool cond = false;
if (!cond) {
return 0;
}
if (i == 0) {
return 0;
}
if (s == NULL) {
return 0;
}
/* In a "switch" statement, indent "case" one level, and indent the body of
* each "case" another level.
*/
switch (expression) {
case 0:
command1;
break;
case 1:
command2;
break;
default:
command3;
break;
}
.. index::
pair: C; macro
Macros
######
Macros are a powerful but easily misused feature of the C preprocessor, and
Pacemaker uses a lot of obscure macro features. If you need to brush up, the
`GCC documentation for macros
`_ is excellent.
Some common issues:
* Beware of side effects in macro arguments that may be evaluated more than
once
* Always parenthesize macro arguments used in the macro body to avoid
precedence issues if the argument is an expression
* Multi-statement macro bodies should be enclosed in do...while(0) to make them
behave more like a single statement and avoid control flow issues
Often, a static inline function defined in a header is preferable to a macro,
to avoid the numerous issues that plague macros and gain the benefit of
argument and return value type checking.
.. index::
pair: C; memory
Memory Management
#################
* Always use ``calloc()`` rather than ``malloc()``. It has no additional cost on
modern operating systems, and reduces the severity and security risks of
uninitialized memory usage bugs.
* Ensure that all dynamically allocated memory is freed when no longer needed,
and not used after it is freed. This can be challenging in the more
event-driven, callback-oriented sections of code.
* Free dynamically allocated memory using the free function corresponding to
how it was allocated. For example, use ``free()`` with ``calloc()``, and
``g_free()`` with most glib functions that allocate objects.
.. index::
single: C; struct
Structures
##########
Changes to structures defined in public API headers (adding or removing
members, or changing member types) are generally not possible without breaking
API compatibility. However, there are exceptions:
* Public API structures can be designed such that they can be allocated only
via API functions, not declared directly or allocated with standard memory
functions using ``sizeof``.
* This can be enforced simply by documentating the limitation, in which case
new ``struct`` members can be added to the end of the structure without
breaking compatibility.
* Alternatively, the structure definition can be kept in an internal header,
with only a pointer type definition kept in a public header, in which case
the structure definition can be changed however needed.
.. index::
single: C; variable
Variables
#########
.. index::
single: C; pointer
Pointers
________
.. code-block:: c
/* (1) The asterisk goes by the variable name, not the type;
* (2) Avoid leaving pointers uninitialized, to lessen the impact of
* use-before-assignment bugs
*/
char *my_string = NULL;
// Use space before asterisk and after closing parenthesis in a cast
char *foo = (char *) bar;
.. index::
single: C; global variable
Globals
_______
Global variables should be avoided in libraries when possible. State
information should instead be passed as function arguments (often as a
structure). This is not for thread safety -- Pacemaker's use of forking
ensures it will never be threaded -- but it does minimize overhead,
improve readability, and avoid obscure side effects.
Variable Naming
_______________
Time intervals are sometimes represented in Pacemaker code as user-defined
text specifications (for example, "10s"), other times as an integer number of
seconds or milliseconds, and still other times as a string representation
of an integer number. Variables for these should be named with an indication
of which is being used (for example, use ``interval_spec``, ``interval_ms``,
or ``interval_ms_s`` instead of ``interval``).
.. index::
pair: C; booleans
pair: C; bool
pair: C; gboolean
Booleans
________
Booleans in C can be represented by an integer type, ``bool``, or ``gboolean``.
Integers are sometimes useful for storing booleans when they must be converted
to and from a string, such as an XML attribute value (for which
``crm_element_value_int()`` can be used). Integer booleans use 0 for false and
nonzero (usually 1) for true.
``gboolean`` should be used with glib APIs that specify it. ``gboolean`` should
always be used with glib's ``TRUE`` and ``FALSE`` constants.
Otherwise, ``bool`` should be preferred. ``bool`` should be used with the
``true`` and ``false`` constants from the ``stdbool.h`` header.
Do not use equality operators when testing booleans. For example:
.. code-block:: c
// Do this
if (bool1) {
fn();
}
if (!bool2) {
fn2();
}
// Not this
if (bool1 == true) {
fn();
}
if (bool2 == false) {
fn2();
}
// Otherwise there's no logical end ...
if ((bool1 == false) == true) {
fn();
}
.. index::
pair: C; strings
String Handling
###############
Define Constants for Magic Strings
__________________________________
A "magic" string is one used for control purposes rather than human reading,
and which must be exactly the same every time it is used. Examples would be
configuration option names, XML attribute names, or environment variable names.
These should always be defined constants, rather than using the string literal
everywhere. If someone mistypes a defined constant, the code won't compile, but
if they mistype a literal, it could go unnoticed until a user runs into a
problem.
String-Related Library Functions
________________________________
Pacemaker's libcrmcommon has a large number of functions to assist in string
handling. The most commonly used ones are:
* ``pcmk__str_eq()`` tests string equality (similar to ``strcmp()``), but can
handle NULL, and takes options for case-insensitive, whether NULL should be
considered a match, etc.
* ``crm_strdup_printf()`` takes ``printf()``-style arguments and creates a
string from them (dynamically allocated, so it must be freed with
``free()``). It asserts on memory failure, so the return value is always
non-NULL.
String handling functions should almost always be internal API, since Pacemaker
isn't intended to be used as a general-purpose library. Most are declared in
``include/crm/common/strings_internal.h``. ``util.h`` has some older ones that
are public API (for now, but will eventually be made internal).
char*, gchar*, and GString
__________________________
When using dynamically allocated strings, be careful to always use the
appropriate free function.
* ``char*`` strings allocated with something like ``calloc()`` must be freed
with ``free()``. Most Pacemaker library functions that allocate strings use
this implementation.
* glib functions often use ``gchar*`` instead, which must be freed with
``g_free()``.
* Occasionally, it's convenient to use glib's flexible ``GString*`` type, which
must be freed with ``g_string_free()``.
.. index::
pair: C; regular expression
Regular Expressions
___________________
- Use ``REG_NOSUB`` with ``regcomp()`` whenever possible, for efficiency.
- Be sure to use ``regfree()`` appropriately.
.. index::
single: C; enum
Enumerations
############
* Enumerations should not have a ``typedef``, and do not require any naming
convention beyond what applies to all exposed symbols.
* New values should usually be added to the end of public API enumerations,
because the compiler will define the values to 0, 1, etc., in the order
given, and inserting a value in the middle would change the numerical values
of all later values, breaking code compiled with the old values. However, if
enum numerical values are explicitly specified rather than left to the
compiler, new values can be added anywhere.
* When defining constant integer values, enum should be preferred over
``#define`` or ``const`` when possible. This allows type checking without
consuming memory.
Flag groups
___________
Pacemaker often uses flag groups (also called bit fields or bitmasks) for a
collection of boolean options (flags/bits).
This is more efficient for storage and manipulation than individual booleans,
but its main advantage is when used in public APIs, because using another bit
in a bitmask is backward compatible, whereas adding a new function argument (or
sometimes even a structure member) is not.
.. code-block:: c
#include
/* (1) Define an enumeration to name the individual flags, for readability.
* An enumeration is preferred to a series of "#define" constants
* because it is typed, and logically groups the related names.
* (2) Define the values using left-shifting, which is more readable and
* less error-prone than hexadecimal literals (0x0001, 0x0002, 0x0004,
* etc.).
* (3) Using a comma after the last entry makes diffs smaller for reviewing
* if a new value needs to be added or removed later.
*/
enum pcmk__some_bitmask_type {
pcmk__some_value = (1 << 0),
pcmk__other_value = (1 << 1),
pcmk__another_value = (1 << 2),
};
/* The flag group itself should be an unsigned type from stdint.h (not
* the enum type, since it will be a mask of the enum values and not just
* one of them). uint32_t is the most common, since we rarely need more than
* 32 flags, but a smaller or larger type could be appropriate in some
* cases.
*/
uint32_t flags = pcmk__some_value|pcmk__other_value;
/* If the values will be used only with uint64_t, define them accordingly,
* to make compilers happier.
*/
enum pcmk__something_else {
pcmk__whatever = (UINT64_C(1) << 0),
};
We have convenience functions for checking flags (see ``pcmk_any_flags_set()``,
``pcmk_all_flags_set()``, and ``pcmk_is_set()``) as well as setting and
clearing them (see ``pcmk__set_flags_as()`` and ``pcmk__clear_flags_as()``,
usually used via wrapper macros defined for specific flag groups). These
convenience functions should be preferred to direct bitwise arithmetic, for
readability and logging consistency.
.. index::
pair: C; function
Functions
#########
Function Naming
_______________
Function names should be unique across the entire project, to allow for
individual tracing via ``PCMK_trace_functions``, and make it easier to search
code and follow detail logs.
.. _sort_func:
Sorting
^^^^^^^
A function that sorts an entire list should have ``sort`` in its name. It sorts
elements using a :ref:`comparison ` function, which may be either
hard-coded or passed as an argument.
.. _compare_func:
Comparison
^^^^^^^^^^
A comparison function for :ref:`sorting ` should have ``cmp`` in its
name and should *not* have ``sort`` in its name.
.. _constructor_func:
Constructors
^^^^^^^^^^^^
A constructor creates a new dynamically allocated object. It may perform some
initialization procedure on the new object.
* If the constructor always creates an independent object instance, its name
should include ``new``.
* If the constructor may add the new object to some existing object, its name
should include ``create``.
Function Definitions
____________________
.. code-block:: c
/*
* (1) The return type goes on its own line
* (2) The opening brace goes by itself on a line
* (3) Use "const" with pointer arguments whenever appropriate, to allow the
* function to be used by more callers.
*/
int
my_func1(const char *s)
{
return 0;
}
/* Functions with no arguments must explicitly list them as void,
* for compatibility with strict compilers
*/
int
my_func2(void)
{
return 0;
}
/*
* (1) For functions with enough arguments that they must break to the next
* line, align arguments with the first argument.
* (2) When a function argument is a function itself, use the pointer form.
* (3) Declare functions and file-global variables as ``static`` whenever
* appropriate. This gains a slight efficiency in shared libraries, and
* helps the reader know that it is not used outside the one file.
*/
static int
my_func3(int bar, const char *a, const char *b, const char *c,
void (*callback)())
{
return 0;
}
Return Values
_____________
Functions that need to indicate success or failure should follow one of the
following guidelines. More details, including functions for using them in user
messages and converting from one to another, can be found in
``include/crm/common/results.h``.
* A **standard Pacemaker return code** is one of the ``pcmk_rc_*`` enum values
or a system errno code, as an ``int``.
* ``crm_exit_t`` (the ``CRM_EX_*`` enum values) is a system-independent code
suitable for the exit status of a process, or for interchange between nodes.
* Other special-purpose status codes exist, such as ``enum ocf_exitcode`` for
the possible exit statuses of OCF resource agents (along with some
Pacemaker-specific extensions). It is usually obvious when the context calls
for such.
* Some older Pacemaker APIs use the now-deprecated "legacy" return values of
``pcmk_ok`` or the positive or negative value of one of the ``pcmk_err_*``
constants or system errno codes.
* Functions registered with external libraries (as callbacks for example)
should use the appropriate signature defined by those libraries, rather than
follow Pacemaker guidelines.
Of course, functions may have return values that aren't success/failure
indicators, such as a pointer, integer count, or bool.
:ref:`Comparison ` functions should return
* a negative integer if the first argument should sort first
* 0 if its arguments are equal for sorting purposes
* a positive integer is the second argument should sort first
Public API Functions
____________________
Unless we are doing a (rare) release where we break public API compatibility,
new public API functions can be added, but existing function signatures (return
type, name, and argument types) should not be changed. To work around this, an
existing function can become a wrapper for a new function.
.. index::
pair: C; logging
pair: C; output
Logging and Output
##################
Logging Vs. Output
__________________
Log messages and output messages are logically similar but distinct.
Oversimplifying a bit, daemons log, and tools output.
Log messages are intended to help with troubleshooting and debugging.
They may have a high level of technical detail, and are usually filtered by
severity -- for example, the system log by default gets messages of notice
level and higher.
Output is intended to let the user know what a tool is doing, and is generally
terser and less technical, and may even be parsed by scripts. Output might have
"verbose" and "quiet" modes, but it is not filtered by severity.
Common Guidelines for All Messages
__________________________________
* When format strings are used for derived data types whose implementation may
vary across platforms (``pid_t``, ``time_t``, etc.), the safest approach is
to use ``%lld`` in the format string, and cast the value to ``long long``.
* Do not rely on ``%s`` handling ``NULL`` values properly. While the standard
library functions might, not all functions using printf-style formatting
does, and it's safest to get in the habit of always ensuring format values
are non-NULL. If a value can be NULL, the ``pcmk__s()`` function is a
convenient way to say "this string if not NULL otherwise this default".
* The convenience macros ``pcmk__plural_s()`` and ``pcmk__plural_alt()`` are
handy when logging a word that may be singular or plural.
Log Levels
__________
When to use each log level:
* **critical:** fatal error (usually something that would make a daemon exit)
* **error:** failure of something that affects the cluster (such as a resource
action, fencing action, etc.) or daemon operation
* **warning:** minor, potential, or recoverable failures (such as something
only affecting a daemon client, or invalid configuration that can be left to
default)
* **notice:** important successful events (such as a node joining or leaving,
resource action results, or configuration changes)
* **info:** events that would be helpful with troubleshooting (such as status
section updates or elections)
* **debug:** information that would be helpful for debugging code or complex
problems
* **trace:** like debug but for very noisy or low-level stuff
By default, critical through notice are logged to the system log and detail
log, info is logged to the detail log only, and debug and trace are not logged
(if enabled, they go to the detail log only).
Logging
_______
Pacemaker uses libqb for logging, but wraps it with a higher level of
functionality (see ``include/crm/common/logging*h``).
A few macros ``crm_err()``, ``crm_warn()``, etc. do most of the heavy lifting.
By default, Pacemaker sends logs at notice level and higher to the system log,
and logs at info level and higher to the detail log (typically
``/var/log/pacemaker/pacemaker.log``). The intent is that most users will only
ever need the system log, but for deeper troubleshooting and developer
debugging, the detail log may be helpful, at the cost of being more technical
and difficult to follow.
The same message can have more detail in the detail log than in the system log,
using libqb's "extended logging" feature:
.. code-block:: c
/* The following will log a simple message in the system log, like:
warning: Action failed: Node not found
with extra detail in the detail log, like:
warning: Action failed: Node not found | rc=-1005 id=hgjjg-51006
*/
crm_warn("Action failed: %s " QB_XS " rc=%d id=%s",
pcmk_rc_str(rc), rc, id);
Assertion Logging
_________________
``pcmk__assert(expr)``
- If ``expr`` is false, this will call crm_err()
with a "Triggered
- fatal assertion" message (with details), then abort execution. This should be
+ If ``expr`` is false, this will call ``crm_err()`` with a "Triggered fatal
+ assertion" message (with details), then abort execution. This should be
used for logic errors that should be impossible (such as a NULL function
argument where not accepted) and environmental errors that can't be handled
gracefully (for example, memory allocation failures, though returning
``ENOMEM`` is often better).
``CRM_LOG_ASSERT(expr)``
If ``expr`` is false, this will generally log a message without aborting. If
the log level is below trace, it just calls ``crm_err()`` with a "Triggered
assert" message (with details). If the log level is trace, and the caller is
a daemon, then it will fork a child process in which to dump core, as well as
logging the message. If the log level is trace, and the caller is not a
daemon, then it will behave like ``pcmk__assert()`` (i.e. log and abort).
This should be used for logic or protocol errors that require no special
handling.
``CRM_CHECK(expr, failed_action)``
If ``expr`` is false, behave like ``CRM_LOG_ASSERT(expr)`` (that is, log a
message and dump core if requested) then perform ``failed_action`` (which
must not contain ``continue``, ``break``, or ``errno``). This should be used
for logic or protocol errors that can be handled, usually by returning an
error status.
Output
______
Pacemaker has a somewhat complicated system for tool output. The main benefit
is that the user can select the output format with the ``--output-as`` option
(usually "text" for human-friendly output or "xml" for reliably script-parsable
output, though ``crm_mon`` additionally supports "console" and "html").
A custom message can be defined with a unique string identifier, plus
implementation functions for each supported format. The caller invokes the
message using the identifier. The user selects the output format via
``--output-as``, and the output code automatically calls the appropriate
implementation function. Custom messages are useful when you want to output
messages that are more complex than a one-line error or informational message,
reproducible, and automatically handled by the output formatting system.
Custom messages can contain other custom messages.
Custom message functions are implemented as follows: Start with the macro
``PCMK__OUTPUT_ARGS``, whose arguments are the message name, followed by the
arguments to the message. Then there is the function declaration, for which the
arguments are the pointer to the current output object, then a variable argument
list.
To output a custom message, you first need to create, i.e. register, the custom
message that you want to output. Either call ``register_message``, which
registers a custom message at runtime, or make use of the collection of
predefined custom messages in ``fmt_functions``, which is defined in
``lib/pacemaker/pcmk_output.c``. Once you have the message to be outputted,
output it by calling ``message``.
Note: The ``fmt_functions`` functions accommodate all of the output formats;
the default implementation accommodates any format that isn't explicitly
accommodated. The default output provides valid output for any output format,
but you may still want to implement a specific output, i.e. xml, text, or html.
The ``message`` function automatically knows which implementation to use,
because the ``pcmk__output_s`` contains this information.
The interface (most importantly ``pcmk__output_t``) is declared in
``include/crm/common/output*h``. See the API comments and existing tools for
examples.
Some of its important member functions are ``err``, which formats error messages
and ``info``, which formats informational messages. Also, ``list_item``,
which formats list items, ``begin_list``, which starts lists, and ``end_list``,
which ends lists, are important because lists can be useful, yet differently
handled by the different output types.
.. index::
pair: C; XML
XML
###
External Libraries
__________________
Pacemaker uses `libxml2 `_ and
`libxslt `_ to process XML. These
libraries implement only version 1.0 of the XML, XPath, and XSLT specifications.
Naming
______
Names of functions, constants, and enum values related to XML should contain
substrings indicating the type of object they're used with, according to the
following convention:
* ``xml``: XML subtree, or XML generically
* ``xe``: XML element node, including the attributes belonging to an element
* ``xa``: XML attribute node
* ``xc``: XML comment node
Private Data
____________
Libxml2 data structures such as ``xmlNode`` and ``xmlDoc`` contain a
``void *_private`` member for application-specific data. Pacemaker uses this
field to store internal bookkeeping data, such as changes relative to another
XML tree, or ACLs.
XML documents, elements, attributes, and comments have private data. The private
data field must be allocated immediately after the node is created and freed
immediately before the node is freed.
Wrapper Functions
_________________
Pacemaker provides wrappers for a variety of libxml2 and libxslt functions. They
should be used whenever possible. Some are merely for convenience. However, many
perform additional, Pacemaker-specific tasks, such as change tracking, ACL
checking, and allocation/deallocation of XML documents and private data.
Pacemaker assumes that every XML node is part of a document and has private data
allocated. If libxml2 APIs are used directly instead of the wrapper functions,
Pacemaker may crash with a segmentation fault, or change tracking and ACL
checking may be incorrectly disabled.
.. index::
single: Makefile.am
Makefiles
#########
Pacemaker uses
`automake `_
for building, so the Makefile.am in each directory should be edited rather than
Makefile.in or Makefile, which are automatically generated.
* Public API headers are installed (by adding them to a ``HEADERS`` variable in
``Makefile.am``), but internal API headers are not (by adding them to
``noinst_HEADERS``).
.. index::
pair: C; vim settings
vim Settings
############
Developers who use ``vim`` to edit source code can add the following settings
to their ``~/.vimrc`` file to follow Pacemaker C coding guidelines:
.. code-block:: none
" follow Pacemaker coding guidelines when editing C source code files
filetype plugin indent on
au FileType c setlocal expandtab tabstop=4 softtabstop=4 shiftwidth=4 textwidth=80
autocmd BufNewFile,BufRead *.h set filetype=c
let c_space_errors = 1
diff --git a/doc/sphinx/Pacemaker_Development/helpers.rst b/doc/sphinx/Pacemaker_Development/helpers.rst
index 2fa9b4d9b6..5a7da9bae0 100644
--- a/doc/sphinx/Pacemaker_Development/helpers.rst
+++ b/doc/sphinx/Pacemaker_Development/helpers.rst
@@ -1,641 +1,642 @@
C Development Helpers
---------------------
.. index::
single: unit testing
Refactoring
###########
Pacemaker uses an optional tool called `coccinelle `_
to do automatic refactoring. coccinelle is a very complicated tool that can be
difficult to understand, and the existing documentation makes it pretty tough
to get started. Much of the documentation is either aimed at kernel developers
or takes the form of grammars.
However, it can apply very complex transformations across an entire source tree.
This is useful for tasks like code refactoring, changing APIs (number or type of
arguments, etc.), catching functions that should not be called, and changing
existing patterns.
coccinelle is driven by input scripts called `semantic patches `_
written in its own language. These scripts bear a passing resemblance to source
code patches and tell coccinelle how to match and modify a piece of source
code. They are stored in ``devel/coccinelle`` and each script either contains
a single source transformation or several related transformations. In general,
we try to keep these as simple as possible.
In Pacemaker development, we use a couple targets in ``devel/Makefile.am`` to
control coccinelle. The ``cocci`` target tries to apply each script to every
Pacemaker source file, printing out any changes it would make to the console.
The ``cocci-inplace`` target does the same but also makes those changes to the
source files. A variety of warnings might also be printed. If you aren't working
on a new script, these can usually be ignored.
If you are working on a new coccinelle script, it can be useful (and faster) to
skip everything else and only run the new script. The ``COCCI_FILES`` variable
can be used for this:
.. code-block:: none
$ make -C devel COCCI_FILES=coccinelle/new-file.cocci cocci
This variable is also used for preventing some coccinelle scripts in the Pacemaker
source tree from running. Some scripts are disabled because they are not currently
fully working or because they are there as templates. When adding a new script,
remember to add it to this variable if it should always be run.
One complication when writing coccinelle scripts is that certain Pacemaker source
files may not use private functions (those whose name starts with ``pcmk__``).
Handling this requires work in both the Makefile and in the coccinelle scripts.
The Makefile deals with this by maintaining two lists of source files: those that
may use private functions and those that may not. For those that may, a special
argument (``-D internal``) is added to the coccinelle command line. This creates
a virtual dependency named ``internal``.
In the coccinelle scripts, those transformations that modify source code to use
a private function also have a dependency on ``internal``. If that dependency
was given on the command line, the transformation will be run. Otherwise, it will
be skipped.
This means that not all instances of an older style of code will be changed after
running a given transformation. Some developer intervention is still necessary
to know whether a source code block should have been changed or not.
Probably the easiest way to learn how to use coccinelle is by following other
people's scripts. In addition to the ones in the Pacemaker source directory,
there's several others on the `coccinelle website `_.
Sanitizers
##########
gcc supports a variety of run-time checks called sanitizers. These can be used to
catch programming errors with memory, race conditions, various undefined behavior
conditions, and more. Because these are run-time checks, they should only be used
during development and not in compiled packages or production code.
Certain sanitizers cannot be combined with others because their run-time checks
cause interfere. Instead of trying to figure out which combinations work, it is
simplest to just enable one at a time.
Each supported sanitizer requires an installed libray. In addition to just
enabling the sanitizer, their use can be configured with environment variables.
For example:
.. code-block:: none
$ ASAN_OPTIONS=verbosity=1:replace_str=true crm_mon -1R
Pacemaker supports the following subset of gcc's sanitizers:
+--------------------+-------------------------+----------+----------------------+
| Sanitizer | Configure Option | Library | Environment Variable |
+====================+=========================+==========+======================+
| Address | --with-sanitizers=asan | libasan | ASAN_OPTIONS |
+--------------------+-------------------------+----------+----------------------+
| Threads | --with-sanitizers=tsan | libtsan | TSAN_OPTIONS |
+--------------------+-------------------------+----------+----------------------+
| Undefined behavior | --with-sanitizers=ubsan | libubsan | UBSAN_OPTIONS |
+--------------------+-------------------------+----------+----------------------+
The undefined behavior sanitizer further supports suboptions that need to be
given as CFLAGS when configuring pacemaker:
.. code-block:: none
$ CFLAGS=-fsanitize=integer-divide-by-zero ./configure --with-sanitizers=ubsan
For more information, see the `gcc documentation `_
which also provides links to more information on each sanitizer.
Unit Testing
############
Where possible, changes to the C side of Pacemaker should be accompanied by unit
tests. Much of Pacemaker cannot effectively be unit tested (and there are other
testing systems used for those parts), but the ``lib`` subdirectory is pretty easy
to write tests for.
Pacemaker uses the `cmocka unit testing framework `_ which looks
a lot like other unit testing frameworks for C and should be fairly familiar. In
addition to regular unit tests, cmocka also gives us the ability to use
`mock functions `_ for unit testing
functions that would otherwise be difficult to test.
Organization
____________
Pay close attention to the organization and naming of test cases to ensure the
unit tests continue to work as they should.
Tests are spread throughout the source tree, alongside the source code they test.
For instance, all the tests for the source code in ``lib/common/`` are in the
``lib/common/tests`` directory. If there is no ``tests`` subdirectory, there are no
tests for that library yet.
Under that directory, there is a ``Makefile.am`` and additional subdirectories. Each
subdirectory contains the tests for a single library source file. For instance,
all the tests for ``lib/common/strings.c`` are in the ``lib/common/tests/strings``
directory. Note that the test subdirectory does not have a ``.c`` suffix. If there
is no test subdirectory, there are no tests for that file yet.
Finally, under that directory, there is a ``Makefile.am`` and then various source
files. Each of these source files tests the single function that it is named
after. For instance, ``lib/common/tests/strings/pcmk__btoa_test.c`` tests the
``pcmk__btoa()`` function in ``lib/common/strings.c``. If there is no test
source file, there are no tests for that function yet.
The ``_test`` suffix on the test source file is important. All tests have this
suffix, which means all the compiled test cases will also end with this suffix.
That lets us ignore all the compiled tests with a single line in ``.gitignore``:
.. code-block:: none
/lib/*/tests/*/*_test
Adding a test
_____________
Testing a new function in an already testable source file
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Follow these steps if you want to test a function in a source file where there
are already other tested functions. For the purposes of this example, we will
add a test for the ``pcmk__scan_port()`` function in ``lib/common/strings.c``. As
you can see, there are already tests for other functions in this same file in
the ``lib/common/tests/strings`` directory.
* cd into ``lib/common/tests/strings``
* Add the new file to the ``check_PROGRAMS`` variable in ``Makefile.am``, making
it something like this:
.. code-block:: none
check_PROGRAMS = \
pcmk__add_word_test \
pcmk__btoa_test \
pcmk__scan_port_test
* Create a new ``pcmk__scan_port_test.c`` file, copying the copyright and include
boilerplate from another file in the same directory.
* Continue with the steps in `Writing the test`_.
Testing a function in a source file without tests
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Follow these steps if you want to test a function in a source file where there
are not already other tested functions, but there are tests for other files in
the same library. For the purposes of this example, we will add a test for the
``pcmk_acl_required()`` function in ``lib/common/acls.c``. At the time of this
documentation being written, no tests existed for that source file, so there
is no ``lib/common/tests/acls`` directory.
* Add to ``AC_CONFIG_FILES`` in the top-level ``configure.ac`` file so the build
process knows to use directory we're about to create. That variable would
now look something like:
.. code-block:: none
dnl Other files we output
AC_CONFIG_FILES(Makefile \
...
lib/common/tests/Makefile \
lib/common/tests/acls/Makefile \
lib/common/tests/agents/Makefile \
...
)
* cd into ``lib/common/tests``
* Add to the ``SUBDIRS`` variable in ``Makefile.am``, making it something like:
.. code-block:: none
SUBDIRS = agents acls cmdline flags operations strings utils xpath results
* Create a new ``acls`` directory, copying the ``Makefile.am`` from some other
directory. At this time, each ``Makefile.am`` is largely boilerplate with
very little that needs to change from directory to directory.
* cd into ``acls``
* Get rid of any existing values for ``check_PROGRAMS`` and set it to
``pcmk_acl_required_test`` like so:
.. code-block:: none
check_PROGRAMS = pcmk_acl_required_test
* Double check that the following includes are at the top of ``Makefile.am``:
.. code-block:: none
include $(top_srcdir)/mk/common.mk
include $(top_srcdir)/mk/tap.mk
include $(top_srcdir)/mk/unittest.mk
* If necessary, settings from those includes can be overridden like so:
.. code-block:: none
AM_TESTS_ENVIRONMENT += PCMK_CTS_CLI_DIR=$(top_srcdir)/cts/cli
AM_CPPFLAGS += -I$(top_srcdir)
LDADD += $(top_builddir)/lib/pengine/libpe_status_test.la
* Follow the steps in `Testing a new function in an already testable source file`_
to create the new ``pcmk_acl_required_test.c`` file.
Testing a function in a library without tests
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Adding a test case for a function in a library that doesn't have any test cases
to begin with is only slightly more complicated. In general, the steps are the
same as for the previous section, except with an additional layer of directory
creation.
For the purposes of this example, we will add a test case for the
``lrmd_send_resource_alert()`` function in ``lib/lrmd/lrmd_alerts.c``. Note that this
may not be a very good function or even library to write actual unit tests for.
* Add to ``AC_CONFIG_FILES`` in the top-level ``configure.ac`` file so the build
process knows to use directory we're about to create. That variable would
now look something like:
.. code-block:: none
dnl Other files we output
AC_CONFIG_FILES(Makefile \
...
lib/lrmd/Makefile \
lib/lrmd/tests/Makefile \
lib/services/Makefile \
...
)
* cd into ``lib/lrmd``
* Create a ``SUBDIRS`` variable in ``Makefile.am`` if it doesn't already exist.
Most libraries should not have this variable already.
.. code-block:: none
SUBDIRS = tests
* Create a new ``tests`` directory and add a ``Makefile.am`` with the following
contents:
.. code-block:: none
SUBDIRS = lrmd_alerts
* Follow the steps in `Testing a function in a source file without tests`_ to create
the rest of the new directory structure.
* Follow the steps in `Testing a new function in an already testable source file`_
to create the new ``lrmd_send_resource_alert_test.c`` file.
Adding to an existing test case
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
If all you need to do is add additional test cases to an existing file, none of
the above work is necessary. All you need to do is find the test source file
with the name matching your function and add to it and then follow the
instructions in `Writing the test`_.
Writing the test
________________
A test case file contains a fair amount of boilerplate. For this reason, it's
usually easiest to just copy an existing file and adapt it to your needs. However,
here's the basic structure:
.. code-block:: c
/*
* Copyright 2021 the Pacemaker project contributors
*
* The version control history for this file may have further details.
*
* This source code is licensed under the GNU Lesser General Public License
* version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
*/
#include
#include
/* Put your test-specific includes here */
/* Put your test functions here */
PCMK__UNIT_TEST(NULL, NULL,
/* Register your test functions here */)
Each test-specific function should test one aspect of the library function,
though it can include many assertions if there are many ways of testing that
one aspect. For instance, there might be multiple ways of testing regular
expression matching:
.. code-block:: c
static void
regex(void **state) {
const char *s1 = "abcd";
const char *s2 = "ABCD";
assert_true(pcmk__strcmp(NULL, "a..d", pcmk__str_regex) < 0);
assert_true(pcmk__strcmp(s1, NULL, pcmk__str_regex) > 0);
assert_int_equal(pcmk__strcmp(s1, "a..d", pcmk__str_regex), 0);
}
Each test-specific function must also be registered or it will not be called.
This is done with ``cmocka_unit_test()`` in the ``PCMK__UNIT_TEST`` macro:
.. code-block:: c
PCMK__UNIT_TEST(NULL, NULL,
cmocka_unit_test(regex))
Most unit tests do not require a setup and teardown function to be executed
around the entire group of tests. On occassion, this may be necessary. Simply
pass those functions in as the first two parameters to ``PCMK__UNIT_TEST``
instead of using NULL.
Assertions
__________
-In addition to the `assertions provided by `_,
-``unittest_internal.h`` also provides ``pcmk__assert_asserts``. This macro takes an
-expression and verifies that the expression aborts due to a failed call to
-``pcmk__assert()`` or some other similar function. It can be used like so:
+In addition to the `assertions provided by cmocka
+`_, ``unittest_internal.h``
+also provides ``pcmk__assert_asserts``. This macro takes an expression and
+verifies that the expression aborts due to a failed call to ``pcmk__assert()``
+or some other similar function. It can be used like so:
.. code-block:: c
static void
null_input_variables(void **state)
{
long long start, end;
pcmk__assert_asserts(pcmk__parse_ll_range("1234", NULL, &end));
pcmk__assert_asserts(pcmk__parse_ll_range("1234", &start, NULL));
}
Here, ``pcmk__parse_ll_range`` expects non-NULL for its second and third
arguments. If one of those arguments is NULL, ``pcmk__assert()`` will fail and
the program will abort. ``pcmk__assert_asserts`` checks that the code would
abort and the test passes. If the code does not abort, the test fails.
Running
_______
If you had to create any new files or directories, you will first need to run
``./configure`` from the top level of the source directory. This will regenerate
the Makefiles throughout the tree. If you skip this step, your changes will be
skipped and you'll be left wondering why the output doesn't match what you
expected.
To run the tests, simply run ``make check`` after previously building the source
with ``make``. The test cases in each directory will be built and then run.
This should not take long. If all the tests succeed, you will be back at the
prompt. Scrolling back through the history, you should see lines like the
following:
.. code-block:: none
PASS: pcmk__strcmp_test 1 - same_pointer
PASS: pcmk__strcmp_test 2 - one_is_null
PASS: pcmk__strcmp_test 3 - case_matters
PASS: pcmk__strcmp_test 4 - case_insensitive
PASS: pcmk__strcmp_test 5 - regex
============================================================================
Testsuite summary for pacemaker 2.1.0
============================================================================
# TOTAL: 33
# PASS: 33
# SKIP: 0
# XFAIL: 0
# FAIL: 0
# XPASS: 0
# ERROR: 0
============================================================================
make[7]: Leaving directory '/home/clumens/src/pacemaker/lib/common/tests/strings'
The testing process will quit on the first failed test, and you will see lines
like these:
.. code-block:: none
PASS: pcmk__scan_double_test 3 - trailing_chars
FAIL: pcmk__scan_double_test 4 - typical_case
PASS: pcmk__scan_double_test 5 - double_overflow
PASS: pcmk__scan_double_test 6 - double_underflow
ERROR: pcmk__scan_double_test - exited with status 1
PASS: pcmk__starts_with_test 1 - bad_input
============================================================================
Testsuite summary for pacemaker 2.1.0
============================================================================
# TOTAL: 56
# PASS: 54
# SKIP: 0
# XFAIL: 0
# FAIL: 1
# XPASS: 0
# ERROR: 1
============================================================================
See lib/common/tests/strings/test-suite.log
Please report to users@clusterlabs.org
============================================================================
make[7]: *** [Makefile:1218: test-suite.log] Error 1
make[7]: Leaving directory '/home/clumens/src/pacemaker/lib/common/tests/strings'
The failure is in ``lib/common/tests/strings/test-suite.log``:
.. code-block:: none
ERROR: pcmk__scan_double_test
=============================
1..6
ok 1 - empty_input_string
PASS: pcmk__scan_double_test 1 - empty_input_string
ok 2 - bad_input_string
PASS: pcmk__scan_double_test 2 - bad_input_string
ok 3 - trailing_chars
PASS: pcmk__scan_double_test 3 - trailing_chars
not ok 4 - typical_case
FAIL: pcmk__scan_double_test 4 - typical_case
# 0.000000 != 3.000000
# pcmk__scan_double_test.c:80: error: Failure!
ok 5 - double_overflow
PASS: pcmk__scan_double_test 5 - double_overflow
ok 6 - double_underflow
PASS: pcmk__scan_double_test 6 - double_underflow
# not ok - tests
ERROR: pcmk__scan_double_test - exited with status 1
At this point, you need to determine whether your test case is incorrect or
whether the code being tested is incorrect. Fix whichever is wrong and continue.
Fuzz Testing
############
Pacemaker is integrated with the
`OSS-Fuzz `_ project. OSS-Fuzz calls
selected Pacemaker APIs with random argument values to catch edge cases that
might be missed by other forms of testing.
The OSS-Fuzz project has a contact address for Pacemaker in
projects/pacemaker/project.yaml that will receive bug reports. The address must
have been used to commit to Pacemaker, and should be tied to a Google account.
Open reports that aren't security-related can be seen at `OSS-Fuzz testcases
`_.
Fuzzers
_______
Each fuzz-tested library has a fuzzers subdirectory (for example,
``lib/common/fuzzers``). That directory has a file for each fuzzed source file,
named the same except ending in ``_fuzzer.c`` (for example,
``lib/common/fuzzers/strings_fuzzer.c`` has fuzzing for
``lib/common/strings.c``). Those files are not built or distributed as part of
Pacemaker but are used by OSS-Fuzz (see ``projects/pacemaker/build.sh`` in the
OSS-Fuzz repository).
By default, fuzzing uses `libFuzzer `_.
Only Pacemaker APIs that accept any input and do not exit can be fuzzed.
Ideally, fuzzed functions will not modify global state or vary code paths by
anything other than the fuzzed input (such as environment variable values,
date/time, etc.).
Local Fuzzing
_____________
You can use OSS-Fuzz locally to run fuzz testing or reproduce issues reported
by OSS-Fuzz.
To prep a test host:
1. If podman is installed, it will conflict with Docker, so remove it first.
Example for RHEL-like OSes:
* ``dnf remove runc``
1. Install and start Docker. Example for RHEL-like OSes:
* ``dnf config-manager --add-repo
https://download.docker.com/linux/rhel/docker-ce.repo``
* ``dnf install docker-ce docker-ce-cli containerd.io docker-buildx-plugin
docker-compose-plugin``
* ``usermod -a -G docker $USER``
2. Clone the OSS-Fuzz repository:
* ``cd`` to wherever you want to put it
* ``git clone https://github.com/google/oss-fuzz.git``
* ``cd oss-fuzz``
3. Specify the Pacemaker source you want to test:
* Edit ``projects/pacemaker/Dockerfile`` and replace the last ``git clone``
with the source that you want to test. For example, if you have a branch
``my-fuzzing-branch`` that you've pushed to your GitHub account, you could
use: ``git clone -b my-fuzzing-branch --single-branch --depth 1
https://github.com/$USER/pacemaker``.
To fuzz the code:
1. Ensure Docker is running:
* ``systemctl start docker``
2. Build the necessary Docker containers:
* ``python3 infra/helper.py build_image pacemaker``
3. Build the fuzzers. Choose a sanitizer (for example, ``SANITIZER=address``).
There are three possible sanitizers: address, memory, and undefined. The
memory sanitizer requires special preparation and is generally not used. If
you are reproducing an OSS-Fuzz-reported issue, the issue will list the
sanitizer that was used.
* ``python3 infra/helper.py build_fuzzers --sanitizer $SANITIZER pacemaker``
4. Ensure the build succeeded (use the same sanitizer as the previous step):
* ``python3 infra/helper.py check_build --sanitizer $SANITIZER pacemaker``
5. If you want to run fuzzing yourself, choose a fuzzer (for example,
``FUZZER=iso8601_fuzzer``). Create a temporary directory for the fuzzer's
outputs, then run the fuzzing command, which will fuzz for 25 seconds then
time out:
* ``rm -rf /tmp/corpus >/dev/null 2>&/dev/null``
* ``mkdir /tmp/corpus``
* ``python3 infra/helper.py run_fuzzer --corpus-dir=/tmp/corpus pacemaker
$FUZZER``
* This can be repeated with different fuzzers. The ``build_fuzzers`` step
can also be repeated with a different sanitizer, and the fuzzers tested
again.
6. If you want to reproduce an OSS-Fuzz-reported issue, make a note of the
fuzzer that was used (``$FUZZER`` in this example) and download the provided
reproducer test case file (``$TESTCASE`` in this example), then run:
* ``python3 infra/helper.py reproduce pacemaker $FUZZER $TESTCASE``
For details, see the `OSS-Fuzz documentation
`_.
Code Coverage
#############
Figuring out what needs unit tests written is the purpose of a code coverage tool.
The Pacemaker build process uses ``lcov`` and special make targets to generate
an HTML coverage report that can be inspected with any web browser.
To start, you'll need to install the ``lcov`` package which is included in most
distributions. Next, reconfigure the source tree:
.. code-block:: none
$ ./configure --with-coverage
Then run ``make -C devel coverage``. This will do the same thing as ``make check``,
but will generate a bunch of intermediate files as part of the compiler's output.
Essentially, the coverage tools run all the unit tests and make a note if a given
line if code is executed as a part of some test program. This will include not
just things run as part of the tests but anything in the setup and teardown
functions as well.
Afterwards, the HTML report will be in ``coverage/index.html``. You can drill down
into individual source files to see exactly which lines are covered and which are
not, which makes it easy to target new unit tests. Note that sometimes, it is
impossible to achieve 100% coverage for a source file. For instance, how do you
test a function with a return type of void that simply returns on some condition?
Note that Pacemaker's overall code coverage numbers are very low at the moment.
One reason for this is the large amount of code in the ``daemons`` directory that
will be very difficult to write unit tests for. For now, it is best to focus
efforts on increasing the coverage on individual libraries.
Additionally, there is a ``coverage-cts`` target that does the same thing but
instead of testing ``make check``, it tests ``cts/cts-cli``. The idea behind this
target is to see what parts of our command line tools are covered by our regression
tests. It is probably best to clean and rebuild the source tree when switching
between these various targets.
Debugging
#########
gdb
___
If you use ``gdb`` for debugging, some helper functions are defined in
``devel/gdbhelpers``, which can be given to ``gdb`` using the ``-x`` option.
From within the debugger, you can then invoke the ``pcmk`` command that
will describe the helper functions available.
diff --git a/doc/sphinx/Pacemaker_Explained/collective.rst b/doc/sphinx/Pacemaker_Explained/collective.rst
index f327059984..3665557574 100644
--- a/doc/sphinx/Pacemaker_Explained/collective.rst
+++ b/doc/sphinx/Pacemaker_Explained/collective.rst
@@ -1,1199 +1,1199 @@
.. index:
single: collective resource
single: resource; collective
Collective Resources
--------------------
Pacemaker supports several types of *collective* resources, which consist of
multiple, related resource instances.
.. index:
single: group resource
single: resource; group
.. _group-resources:
Groups - A Syntactic Shortcut
#############################
One of the most common elements of a cluster is a set of resources
that need to be located together, start sequentially, and stop in the
reverse order. To simplify this configuration, we support the concept
of groups.
.. topic:: A group of two primitive resources
.. code-block:: xml
Although the example above contains only two resources, there is no
limit to the number of resources a group can contain. The example is
also sufficient to explain the fundamental properties of a group:
* Resources are started in the order they appear in (**Public-IP** first,
then **Email**)
* Resources are stopped in the reverse order to which they appear in
(**Email** first, then **Public-IP**)
If a resource in the group can't run anywhere, then nothing after that
is allowed to run, too.
* If **Public-IP** can't run anywhere, neither can **Email**;
* but if **Email** can't run anywhere, this does not affect **Public-IP**
in any way
The group above is logically equivalent to writing:
.. topic:: How the cluster sees a group resource
.. code-block:: xml
Obviously as the group grows bigger, the reduced configuration effort
can become significant.
Another (typical) example of a group is a DRBD volume, the filesystem
mount, an IP address, and an application that uses them.
.. index::
pair: XML element; group
Group Properties
________________
.. table:: **Properties of a Group Resource**
:widths: 1 4
+-------------+------------------------------------------------------------------+
| Field | Description |
+=============+==================================================================+
| id | .. index:: |
| | single: group; property, id |
| | single: property; id (group) |
| | single: id; group property |
| | |
| | A unique name for the group |
+-------------+------------------------------------------------------------------+
| description | .. index:: |
| | single: group; attribute, description |
| | single: attribute; description (group) |
| | single: description; group attribute |
| | |
| | An optional description of the group, for the user's own |
| | purposes. |
| | E.g. ``resources needed for website`` |
+-------------+------------------------------------------------------------------+
Group Options
_____________
Groups inherit the ``priority``, ``target-role``, and ``is-managed`` properties
from primitive resources. See :ref:`resource_options` for information about
those properties.
Group Instance Attributes
_________________________
Groups have no instance attributes. However, any that are set for the group
object will be inherited by the group's children.
Group Contents
______________
Groups may only contain a collection of cluster resources (see
:ref:`primitive-resource`). To refer to a child of a group resource, just use
the child's ``id`` instead of the group's.
Group Constraints
_________________
Although it is possible to reference a group's children in
constraints, it is usually preferable to reference the group itself.
.. topic:: Some constraints involving groups
.. code-block:: xml
.. index::
pair: resource-stickiness; group
Group Stickiness
________________
Stickiness, the measure of how much a resource wants to stay where it
is, is additive in groups. Every active resource of the group will
contribute its stickiness value to the group's total. So if the
default ``resource-stickiness`` is 100, and a group has seven members,
five of which are active, then the group as a whole will prefer its
current location with a score of 500.
.. index::
single: clone
single: resource; clone
.. _s-resource-clone:
Clones - Resources That Can Have Multiple Active Instances
##########################################################
*Clone* resources are resources that can have more than one copy active at the
same time. This allows you, for example, to run a copy of a daemon on every
node. You can clone any primitive or group resource [#]_.
Anonymous versus Unique Clones
______________________________
A clone resource is configured to be either *anonymous* or *globally unique*.
Anonymous clones are the simplest. These behave completely identically
everywhere they are running. Because of this, there can be only one instance of
an anonymous clone active per node.
The instances of globally unique clones are distinct entities. All instances
are launched identically, but one instance of the clone is not identical to any
other instance, whether running on the same node or a different node. As an
example, a cloned IP address can use special kernel functionality such that
each instance handles a subset of requests for the same IP address.
.. index::
single: promotable clone
single: resource; promotable
.. _s-resource-promotable:
Promotable clones
_________________
If a clone is *promotable*, its instances can perform a special role that
Pacemaker will manage via the ``promote`` and ``demote`` actions of the resource
agent.
Services that support such a special role have various terms for the special
role and the default role: primary and secondary, master and replica,
controller and worker, etc. Pacemaker uses the terms *promoted* and
*unpromoted* to be agnostic to what the service calls them or what they do.
All that Pacemaker cares about is that an instance comes up in the unpromoted role
when started, and the resource agent supports the ``promote`` and ``demote`` actions
to manage entering and exiting the promoted role.
.. index::
pair: XML element; clone
Clone Properties
________________
.. table:: **Properties of a Clone Resource**
:widths: 1 4
+-------------+------------------------------------------------------------------+
| Field | Description |
+=============+==================================================================+
| id | .. index:: |
| | single: clone; property, id |
| | single: property; id (clone) |
| | single: id; clone property |
| | |
| | A unique name for the clone |
+-------------+------------------------------------------------------------------+
| description | .. index:: |
| | single: clone; attribute, description |
| | single: attribute; description (clone) |
| | single: description; clone attribute |
| | |
| | An optional description of the clone, for the user's own |
| | purposes. |
| | E.g. ``IP address for website`` |
+-------------+------------------------------------------------------------------+
.. index::
pair: options; clone
Clone Options
_____________
:ref:`Options ` inherited from primitive resources:
``priority, target-role, is-managed``
.. table:: **Clone-specific configuration options**
:class: longtable
:widths: 1 1 3
+-------------------+-----------------+-------------------------------------------------------+
| Field | Default | Description |
+===================+=================+=======================================================+
- | globally-unique | true if | .. index:: |
+ | globally-unique | **true** if | .. index:: |
| | clone-node-max | single: clone; option, globally-unique |
| | is greater than | single: option; globally-unique (clone) |
| | 1, otherwise | single: globally-unique; clone option |
- | | false | |
+ | | **false** | |
| | | If **true**, each clone instance performs a |
| | | distinct function, such that a single node can run |
| | | more than one instance at the same time |
+-------------------+-----------------+-------------------------------------------------------+
| clone-max | 0 | .. index:: |
| | | single: clone; option, clone-max |
| | | single: option; clone-max (clone) |
| | | single: clone-max; clone option |
| | | |
| | | The maximum number of clone instances that can |
| | | be started across the entire cluster. If 0, the |
| | | number of nodes in the cluster will be used. |
+-------------------+-----------------+-------------------------------------------------------+
| clone-node-max | 1 | .. index:: |
| | | single: clone; option, clone-node-max |
| | | single: option; clone-node-max (clone) |
| | | single: clone-node-max; clone option |
| | | |
| | | If the clone is globally unique, this is the maximum |
| | | number of clone instances that can be started |
| | | on a single node |
+-------------------+-----------------+-------------------------------------------------------+
| clone-min | 0 | .. index:: |
| | | single: clone; option, clone-min |
| | | single: option; clone-min (clone) |
| | | single: clone-min; clone option |
| | | |
| | | Require at least this number of clone instances |
| | | to be runnable before allowing resources |
| | | depending on the clone to be runnable. A value |
| | | of 0 means require all clone instances to be |
| | | runnable. |
+-------------------+-----------------+-------------------------------------------------------+
| notify | false | .. index:: |
| | | single: clone; option, notify |
| | | single: option; notify (clone) |
| | | single: notify; clone option |
| | | |
| | | Call the resource agent's **notify** action for |
| | | all active instances, before and after starting |
| | | or stopping any clone instance. The resource |
| | | agent must support this action. |
| | | Allowed values: **false**, **true** |
+-------------------+-----------------+-------------------------------------------------------+
| ordered | false | .. index:: |
| | | single: clone; option, ordered |
| | | single: option; ordered (clone) |
| | | single: ordered; clone option |
| | | |
| | | If **true**, clone instances must be started |
| | | sequentially instead of in parallel. |
| | | Allowed values: **false**, **true** |
+-------------------+-----------------+-------------------------------------------------------+
| interleave | false | .. index:: |
| | | single: clone; option, interleave |
| | | single: option; interleave (clone) |
| | | single: interleave; clone option |
| | | |
| | | When this clone is ordered relative to another |
| | | clone, if this option is **false** (the default), |
| | | the ordering is relative to *all* instances of |
| | | the other clone, whereas if this option is |
| | | **true**, the ordering is relative only to |
| | | instances on the same node. |
| | | Allowed values: **false**, **true** |
+-------------------+-----------------+-------------------------------------------------------+
| promotable | false | .. index:: |
| | | single: clone; option, promotable |
| | | single: option; promotable (clone) |
| | | single: promotable; clone option |
| | | |
| | | If **true**, clone instances can perform a |
| | | special role that Pacemaker will manage via the |
| | | resource agent's **promote** and **demote** |
| | | actions. The resource agent must support these |
| | | actions. |
| | | Allowed values: **false**, **true** |
+-------------------+-----------------+-------------------------------------------------------+
| promoted-max | 1 | .. index:: |
| | | single: clone; option, promoted-max |
| | | single: option; promoted-max (clone) |
| | | single: promoted-max; clone option |
| | | |
| | | If ``promotable`` is **true**, the number of |
| | | instances that can be promoted at one time |
| | | across the entire cluster |
+-------------------+-----------------+-------------------------------------------------------+
| promoted-node-max | 1 | .. index:: |
| | | single: clone; option, promoted-node-max |
| | | single: option; promoted-node-max (clone) |
| | | single: promoted-node-max; clone option |
| | | |
| | | If the clone is promotable and globally unique, this |
| | | is the number of instances that can be promoted at |
- | | | one time on a single node (up to `clone-node-max`) |
+ | | | one time on a single node (up to ``clone-node-max``) |
+-------------------+-----------------+-------------------------------------------------------+
.. note:: **Deprecated Terminology**
In older documentation and online examples, you may see promotable clones
referred to as *multi-state*, *stateful*, or *master/slave*; these mean the
same thing as *promotable*. Certain syntax is supported for backward
compatibility, but is deprecated and will be removed in a future version:
* Using the ``master-max`` meta-attribute instead of ``promoted-max``
* Using the ``master-node-max`` meta-attribute instead of
``promoted-node-max``
* Using ``Master`` as a role name instead of ``Promoted``
* Using ``Slave`` as a role name instead of ``Unpromoted``
Clone Contents
______________
Clones must contain exactly one primitive or group resource.
.. topic:: A clone that runs a web server on all nodes
.. code-block:: xml
.. warning::
You should never reference the name of a clone's child (the primitive or group
resource being cloned). If you think you need to do this, you probably need to
re-evaluate your design.
Clone Instance Attribute
________________________
Clones have no instance attributes; however, any that are set here will be
inherited by the clone's child.
.. index::
single: clone; constraint
Clone Constraints
_________________
In most cases, a clone will have a single instance on each active cluster
node. If this is not the case, you can indicate which nodes the
cluster should preferentially assign copies to with resource location
constraints. These constraints are written no differently from those
for primitive resources except that the clone's **id** is used.
.. topic:: Some constraints involving clones
.. code-block:: xml
Ordering constraints behave slightly differently for clones. In the
example above, ``apache-stats`` will wait until all copies of ``apache-clone``
that need to be started have done so before being started itself.
Only if *no* copies can be started will ``apache-stats`` be prevented
from being active. Additionally, the clone will wait for
``apache-stats`` to be stopped before stopping itself.
Colocation of a primitive or group resource with a clone means that
the resource can run on any node with an active instance of the clone.
The cluster will choose an instance based on where the clone is running and
the resource's own location preferences.
Colocation between clones is also possible. If one clone **A** is colocated
with another clone **B**, the set of allowed locations for **A** is limited to
nodes on which **B** is (or will be) active. Placement is then performed
normally.
.. index::
single: promotable clone; constraint
.. _promotable-clone-constraints:
Promotable Clone Constraints
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
For promotable clone resources, the ``first-action`` and/or ``then-action`` fields
for ordering constraints may be set to ``promote`` or ``demote`` to constrain the
promoted role, and colocation constraints may contain ``rsc-role`` and/or
``with-rsc-role`` fields.
.. topic:: Constraints involving promotable clone resources
.. code-block:: xml
In the example above, **myApp** will wait until one of the database
copies has been started and promoted before being started
itself on the same node. Only if no copies can be promoted will **myApp** be
prevented from being active. Additionally, the cluster will wait for
**myApp** to be stopped before demoting the database.
Colocation of a primitive or group resource with a promotable clone
resource means that it can run on any node with an active instance of
the promotable clone resource that has the specified role (``Promoted`` or
``Unpromoted``). In the example above, the cluster will choose a location
based on where database is running in the promoted role, and if there are
multiple promoted instances it will also factor in **myApp**'s own location
preferences when deciding which location to choose.
Colocation with regular clones and other promotable clone resources is also
possible. In such cases, the set of allowed locations for the **rsc**
clone is (after role filtering) limited to nodes on which the
``with-rsc`` promotable clone resource is (or will be) in the specified role.
Placement is then performed as normal.
Using Promotable Clone Resources in Colocation Sets
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
When a promotable clone is used in a :ref:`resource set `
inside a colocation constraint, the resource set may take a ``role`` attribute.
In the following example, an instance of **B** may be promoted only on a node
where **A** is in the promoted role. Additionally, resources **C** and **D**
must be located on a node where both **A** and **B** are promoted.
.. topic:: Colocate C and D with A's and B's promoted instances
.. code-block:: xml
Using Promotable Clone Resources in Ordered Sets
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
When a promotable clone is used in a :ref:`resource set `
inside an ordering constraint, the resource set may take an ``action``
attribute.
.. topic:: Start C and D after first promoting A and B
.. code-block:: xml
In the above example, **B** cannot be promoted until **A** has been promoted.
Additionally, resources **C** and **D** must wait until **A** and **B** have
been promoted before they can start.
.. index::
pair: resource-stickiness; clone
.. _s-clone-stickiness:
Clone Stickiness
________________
To achieve stable assignments, clones are slightly sticky by default. If no
value for ``resource-stickiness`` is provided, the clone will use a value of 1.
Being a small value, it causes minimal disturbance to the score calculations of
other resources but is enough to prevent Pacemaker from needlessly moving
instances around the cluster.
.. note::
For globally unique clones, this may result in multiple instances of the
clone staying on a single node, even after another eligible node becomes
active (for example, after being put into standby mode then made active again).
If you do not want this behavior, specify a ``resource-stickiness`` of 0
for the clone temporarily and let the cluster adjust, then set it back
to 1 if you want the default behavior to apply again.
.. important::
If ``resource-stickiness`` is set in the ``rsc_defaults`` section, it will
apply to clone instances as well. This means an explicit ``resource-stickiness``
of 0 in ``rsc_defaults`` works differently from the implicit default used when
``resource-stickiness`` is not specified.
Monitoring Promotable Clone Resources
_____________________________________
The usual monitor actions are insufficient to monitor a promotable clone
resource, because Pacemaker needs to verify not only that the resource is
active, but also that its actual role matches its intended one.
Define two monitoring actions: the usual one will cover the unpromoted role,
and an additional one with ``role="Promoted"`` will cover the promoted role.
.. topic:: Monitoring both states of a promotable clone resource
.. code-block:: xml
.. important::
It is crucial that *every* monitor operation has a different interval!
Pacemaker currently differentiates between operations
only by resource and interval; so if (for example) a promotable clone resource
had the same monitor interval for both roles, Pacemaker would ignore the
role when checking the status -- which would cause unexpected return
codes, and therefore unnecessary complications.
.. _s-promotion-scores:
Determining Which Instance is Promoted
______________________________________
Pacemaker can choose a promotable clone instance to be promoted in one of two
ways:
* Promotion scores: These are node attributes set via the ``crm_attribute``
command using the ``--promotion`` option, which generally would be called by
the resource agent's start action if it supports promotable clones. This tool
automatically detects both the resource and host, and should be used to set a
preference for being promoted. Based on this, ``promoted-max``, and
``promoted-node-max``, the instance(s) with the highest preference will be
promoted.
* Constraints: Location constraints can indicate which nodes are most preferred
to be promoted.
.. topic:: Explicitly preferring node1 to be promoted
.. code-block:: xml
.. index:
single: bundle
single: resource; bundle
pair: container; Docker
pair: container; podman
.. _s-resource-bundle:
Bundles - Containerized Resources
#################################
Pacemaker supports a special syntax for launching a service inside a
`container `_
with any infrastructure it requires: the *bundle*.
Pacemaker bundles support `Docker `_ and
`podman `_ *(since 2.0.1)* container technologies. [#]_
.. topic:: A bundle for a containerized web server
.. code-block:: xml
Bundle Prerequisites
____________________
Before configuring a bundle in Pacemaker, the user must install the appropriate
container launch technology (Docker or podman), and supply a fully configured
container image, on every node allowed to run the bundle.
Pacemaker will create an implicit resource of type **ocf:heartbeat:docker** or
**ocf:heartbeat:podman** to manage a bundle's container. The user must ensure
that the appropriate resource agent is installed on every node allowed to run
the bundle.
.. index::
pair: XML element; bundle
Bundle Properties
_________________
.. table:: **XML Attributes of a bundle Element**
:widths: 1 4
+-------------+------------------------------------------------------------------+
| Field | Description |
+=============+==================================================================+
| id | .. index:: |
| | single: bundle; attribute, id |
| | single: attribute; id (bundle) |
| | single: id; bundle attribute |
| | |
| | A unique name for the bundle (required) |
+-------------+------------------------------------------------------------------+
| description | .. index:: |
| | single: bundle; attribute, description |
| | single: attribute; description (bundle) |
| | single: description; bundle attribute |
| | |
| | An optional description of the group, for the user's own |
| | purposes. |
| | E.g. ``manages the container that runs the service`` |
+-------------+------------------------------------------------------------------+
A bundle must contain exactly one ``docker`` or ``podman`` element.
.. index::
pair: XML element; docker
pair: XML element; podman
Bundle Container Properties
___________________________
.. table:: **XML attributes of a docker or podman Element**
:class: longtable
:widths: 2 3 4
+-------------------+------------------------------------+---------------------------------------------------+
| Attribute | Default | Description |
+===================+====================================+===================================================+
| image | | .. index:: |
| | | single: docker; attribute, image |
| | | single: attribute; image (docker) |
| | | single: image; docker attribute |
| | | single: podman; attribute, image |
| | | single: attribute; image (podman) |
| | | single: image; podman attribute |
| | | |
| | | Container image tag (required) |
+-------------------+------------------------------------+---------------------------------------------------+
| replicas | Value of ``promoted-max`` | .. index:: |
| | if that is positive, else 1 | single: docker; attribute, replicas |
| | | single: attribute; replicas (docker) |
| | | single: replicas; docker attribute |
| | | single: podman; attribute, replicas |
| | | single: attribute; replicas (podman) |
| | | single: replicas; podman attribute |
| | | |
| | | A positive integer specifying the number of |
| | | container instances to launch |
+-------------------+------------------------------------+---------------------------------------------------+
| replicas-per-host | 1 | .. index:: |
| | | single: docker; attribute, replicas-per-host |
| | | single: attribute; replicas-per-host (docker) |
| | | single: replicas-per-host; docker attribute |
| | | single: podman; attribute, replicas-per-host |
| | | single: attribute; replicas-per-host (podman) |
| | | single: replicas-per-host; podman attribute |
| | | |
| | | A positive integer specifying the number of |
| | | container instances allowed to run on a |
| | | single node |
+-------------------+------------------------------------+---------------------------------------------------+
| promoted-max | 0 | .. index:: |
| | | single: docker; attribute, promoted-max |
| | | single: attribute; promoted-max (docker) |
| | | single: promoted-max; docker attribute |
| | | single: podman; attribute, promoted-max |
| | | single: attribute; promoted-max (podman) |
| | | single: promoted-max; podman attribute |
| | | |
| | | A non-negative integer that, if positive, |
| | | indicates that the containerized service |
| | | should be treated as a promotable service, |
| | | with this many replicas allowed to run the |
| | | service in the promoted role |
+-------------------+------------------------------------+---------------------------------------------------+
| network | | .. index:: |
| | | single: docker; attribute, network |
| | | single: attribute; network (docker) |
| | | single: network; docker attribute |
| | | single: podman; attribute, network |
| | | single: attribute; network (podman) |
| | | single: network; podman attribute |
| | | |
| | | If specified, this will be passed to the |
| | | ``docker run`` or ``podman run`` command as the |
| | | network setting for the container. |
+-------------------+------------------------------------+---------------------------------------------------+
| run-command | ``/usr/sbin/pacemaker-remoted`` if | .. index:: |
| | bundle contains a **primitive**, | single: docker; attribute, run-command |
| | otherwise none | single: attribute; run-command (docker) |
| | | single: run-command; docker attribute |
| | | single: podman; attribute, run-command |
| | | single: attribute; run-command (podman) |
| | | single: run-command; podman attribute |
| | | |
| | | This command will be run inside the container |
| | | when launching it ("PID 1"). If the bundle |
| | | contains a **primitive**, this command *must* |
| | | start ``pacemaker-remoted`` (but could, for |
| | | example, be a script that does other stuff, too). |
+-------------------+------------------------------------+---------------------------------------------------+
| options | | .. index:: |
| | | single: docker; attribute, options |
| | | single: attribute; options (docker) |
| | | single: options; docker attribute |
| | | single: podman; attribute, options |
| | | single: attribute; options (podman) |
| | | single: options; podman attribute |
| | | |
| | | Extra command-line options to pass to the |
| | | ``docker run`` or ``podman run`` command |
+-------------------+------------------------------------+---------------------------------------------------+
.. note::
Considerations when using cluster configurations or container images from
Pacemaker 1.1:
* If the container image has a pre-2.0.0 version of Pacemaker, set ``run-command``
to ``/usr/sbin/pacemaker_remoted`` (note the underbar instead of dash).
* ``masters`` is accepted as an alias for ``promoted-max``, but is deprecated since
2.0.0, and support for it will be removed in a future version.
Bundle Network Properties
_________________________
A bundle may optionally contain one ```` element.
.. index::
pair: XML element; network
single: bundle; network
.. table:: **XML attributes of a network Element**
:widths: 2 1 5
+----------------+---------+------------------------------------------------------------+
| Attribute | Default | Description |
+================+=========+============================================================+
| add-host | TRUE | .. index:: |
| | | single: network; attribute, add-host |
| | | single: attribute; add-host (network) |
| | | single: add-host; network attribute |
| | | |
| | | If TRUE, and ``ip-range-start`` is used, Pacemaker will |
| | | automatically ensure that ``/etc/hosts`` inside the |
| | | containers has entries for each |
| | | :ref:`replica name ` |
| | | and its assigned IP. |
+----------------+---------+------------------------------------------------------------+
| ip-range-start | | .. index:: |
| | | single: network; attribute, ip-range-start |
| | | single: attribute; ip-range-start (network) |
| | | single: ip-range-start; network attribute |
| | | |
| | | If specified, Pacemaker will create an implicit |
| | | ``ocf:heartbeat:IPaddr2`` resource for each container |
| | | instance, starting with this IP address, using up to |
| | | ``replicas`` sequential addresses. These addresses can be |
| | | used from the host's network to reach the service inside |
| | | the container, though it is not visible within the |
| | | container itself. Only IPv4 addresses are currently |
| | | supported. |
+----------------+---------+------------------------------------------------------------+
| host-netmask | 32 | .. index:: |
| | | single: network; attribute; host-netmask |
| | | single: attribute; host-netmask (network) |
| | | single: host-netmask; network attribute |
| | | |
| | | If ``ip-range-start`` is specified, the IP addresses |
| | | are created with this CIDR netmask (as a number of bits). |
+----------------+---------+------------------------------------------------------------+
| host-interface | | .. index:: |
| | | single: network; attribute; host-interface |
| | | single: attribute; host-interface (network) |
| | | single: host-interface; network attribute |
| | | |
| | | If ``ip-range-start`` is specified, the IP addresses are |
| | | created on this host interface (by default, it will be |
| | | determined from the IP address). |
+----------------+---------+------------------------------------------------------------+
| control-port | 3121 | .. index:: |
| | | single: network; attribute; control-port |
| | | single: attribute; control-port (network) |
| | | single: control-port; network attribute |
| | | |
| | | If the bundle contains a ``primitive``, the cluster will |
| | | use this integer TCP port for communication with |
| | | Pacemaker Remote inside the container. Changing this is |
| | | useful when the container is unable to listen on the |
| | | default port, for example, when the container uses the |
| | | host's network rather than ``ip-range-start`` (in which |
| | | case ``replicas-per-host`` must be 1), or when the bundle |
| | | may run on a Pacemaker Remote node that is already |
| | | listening on the default port. Any ``PCMK_remote_port`` |
| | | environment variable set on the host or in the container |
| | | is ignored for bundle connections. |
+----------------+---------+------------------------------------------------------------+
.. _s-resource-bundle-note-replica-names:
.. note::
Replicas are named by the bundle id plus a dash and an integer counter starting
with zero. For example, if a bundle named **httpd-bundle** has **replicas=2**, its
containers will be named **httpd-bundle-0** and **httpd-bundle-1**.
.. index::
pair: XML element; port-mapping
Additionally, a ``network`` element may optionally contain one or more
``port-mapping`` elements.
.. table:: **Attributes of a port-mapping Element**
:widths: 2 1 5
+---------------+-------------------+------------------------------------------------------+
| Attribute | Default | Description |
+===============+===================+======================================================+
| id | | .. index:: |
| | | single: port-mapping; attribute, id |
| | | single: attribute; id (port-mapping) |
| | | single: id; port-mapping attribute |
| | | |
| | | A unique name for the port mapping (required) |
+---------------+-------------------+------------------------------------------------------+
| port | | .. index:: |
| | | single: port-mapping; attribute, port |
| | | single: attribute; port (port-mapping) |
| | | single: port; port-mapping attribute |
| | | |
| | | If this is specified, connections to this TCP port |
| | | number on the host network (on the container's |
| | | assigned IP address, if ``ip-range-start`` is |
| | | specified) will be forwarded to the container |
| | | network. Exactly one of ``port`` or ``range`` |
| | | must be specified in a ``port-mapping``. |
+---------------+-------------------+------------------------------------------------------+
| internal-port | value of ``port`` | .. index:: |
| | | single: port-mapping; attribute, internal-port |
| | | single: attribute; internal-port (port-mapping) |
| | | single: internal-port; port-mapping attribute |
| | | |
| | | If ``port`` and this are specified, connections |
| | | to ``port`` on the host's network will be |
| | | forwarded to this port on the container network. |
+---------------+-------------------+------------------------------------------------------+
| range | | .. index:: |
| | | single: port-mapping; attribute, range |
| | | single: attribute; range (port-mapping) |
| | | single: range; port-mapping attribute |
| | | |
| | | If this is specified, connections to these TCP |
| | | port numbers (expressed as *first_port*-*last_port*) |
| | | on the host network (on the container's assigned IP |
| | | address, if ``ip-range-start`` is specified) will |
| | | be forwarded to the same ports in the container |
| | | network. Exactly one of ``port`` or ``range`` |
| | | must be specified in a ``port-mapping``. |
+---------------+-------------------+------------------------------------------------------+
.. note::
If the bundle contains a ``primitive``, Pacemaker will automatically map the
``control-port``, so it is not necessary to specify that port in a
``port-mapping``.
.. index:
pair: XML element; storage
pair: XML element; storage-mapping
single: bundle; storage
.. _s-bundle-storage:
Bundle Storage Properties
_________________________
A bundle may optionally contain one ``storage`` element. A ``storage`` element
has no properties of its own, but may contain one or more ``storage-mapping``
elements.
.. table:: **Attributes of a storage-mapping Element**
:widths: 2 1 5
+-----------------+---------+-------------------------------------------------------------+
| Attribute | Default | Description |
+=================+=========+=============================================================+
| id | | .. index:: |
| | | single: storage-mapping; attribute, id |
| | | single: attribute; id (storage-mapping) |
| | | single: id; storage-mapping attribute |
| | | |
| | | A unique name for the storage mapping (required) |
+-----------------+---------+-------------------------------------------------------------+
| source-dir | | .. index:: |
| | | single: storage-mapping; attribute, source-dir |
| | | single: attribute; source-dir (storage-mapping) |
| | | single: source-dir; storage-mapping attribute |
| | | |
| | | The absolute path on the host's filesystem that will be |
| | | mapped into the container. Exactly one of ``source-dir`` |
| | | and ``source-dir-root`` must be specified in a |
| | | ``storage-mapping``. |
+-----------------+---------+-------------------------------------------------------------+
| source-dir-root | | .. index:: |
| | | single: storage-mapping; attribute, source-dir-root |
| | | single: attribute; source-dir-root (storage-mapping) |
| | | single: source-dir-root; storage-mapping attribute |
| | | |
| | | The start of a path on the host's filesystem that will |
| | | be mapped into the container, using a different |
| | | subdirectory on the host for each container instance. |
| | | The subdirectory will be named the same as the |
| | | :ref:`replica name `. |
| | | Exactly one of ``source-dir`` and ``source-dir-root`` |
| | | must be specified in a ``storage-mapping``. |
+-----------------+---------+-------------------------------------------------------------+
| target-dir | | .. index:: |
| | | single: storage-mapping; attribute, target-dir |
| | | single: attribute; target-dir (storage-mapping) |
| | | single: target-dir; storage-mapping attribute |
| | | |
| | | The path name within the container where the host |
| | | storage will be mapped (required) |
+-----------------+---------+-------------------------------------------------------------+
| options | | .. index:: |
| | | single: storage-mapping; attribute, options |
| | | single: attribute; options (storage-mapping) |
| | | single: options; storage-mapping attribute |
| | | |
| | | A comma-separated list of file system mount |
| | | options to use when mapping the storage |
+-----------------+---------+-------------------------------------------------------------+
.. note::
Pacemaker does not define the behavior if the source directory does not already
exist on the host. However, it is expected that the container technology and/or
its resource agent will create the source directory in that case.
.. note::
If the bundle contains a ``primitive``,
Pacemaker will automatically map the equivalent of
``source-dir=/etc/pacemaker/authkey target-dir=/etc/pacemaker/authkey``
and ``source-dir-root=/var/log/pacemaker/bundles target-dir=/var/log`` into the
container, so it is not necessary to specify those paths in a
``storage-mapping``.
.. important::
The ``PCMK_authkey_location`` environment variable must not be set to anything
other than the default of ``/etc/pacemaker/authkey`` on any node in the cluster.
.. important::
If SELinux is used in enforcing mode on the host, you must ensure the container
is allowed to use any storage you mount into it. For Docker and podman bundles,
adding "Z" to the mount options will create a container-specific label for the
mount that allows the container access.
.. index::
single: bundle; primitive
Bundle Primitive
________________
A bundle may optionally contain one :ref:`primitive `
resource. The primitive may have operations, instance attributes, and
meta-attributes defined, as usual.
If a bundle contains a primitive resource, the container image must include
the Pacemaker Remote daemon, and at least one of ``ip-range-start`` or
``control-port`` must be configured in the bundle. Pacemaker will create an
implicit **ocf:pacemaker:remote** resource for the connection, launch
Pacemaker Remote within the container, and monitor and manage the primitive
resource via Pacemaker Remote.
If the bundle has more than one container instance (replica), the primitive
resource will function as an implicit :ref:`clone ` -- a
:ref:`promotable clone ` if the bundle has ``promoted-max``
greater than zero.
.. note::
If you want to pass environment variables to a bundle's Pacemaker Remote
connection or primitive, you have two options:
* Environment variables whose value is the same regardless of the underlying host
may be set using the container element's ``options`` attribute.
* If you want variables to have host-specific values, you can use the
:ref:`storage-mapping ` element to map a file on the host as
``/etc/pacemaker/pcmk-init.env`` in the container *(since 2.0.3)*.
Pacemaker Remote will parse this file as a shell-like format, with
variables set as NAME=VALUE, ignoring blank lines and comments starting
with "#".
.. important::
When a bundle has a ``primitive``, Pacemaker on all cluster nodes must be able to
contact Pacemaker Remote inside the bundle's containers.
* The containers must have an accessible network (for example, ``network`` should
not be set to "none" with a ``primitive``).
* The default, using a distinct network space inside the container, works in
combination with ``ip-range-start``. Any firewall must allow access from all
cluster nodes to the ``control-port`` on the container IPs.
* If the container shares the host's network space (for example, by setting
``network`` to "host"), a unique ``control-port`` should be specified for each
bundle. Any firewall must allow access from all cluster nodes to the
``control-port`` on all cluster and remote node IPs.
.. index::
single: bundle; node attributes
.. _s-bundle-attributes:
Bundle Node Attributes
______________________
If the bundle has a ``primitive``, the primitive's resource agent may want to set
node attributes such as :ref:`promotion scores `. However, with
containers, it is not apparent which node should get the attribute.
If the container uses shared storage that is the same no matter which node the
container is hosted on, then it is appropriate to use the promotion score on the
bundle node itself.
On the other hand, if the container uses storage exported from the underlying host,
then it may be more appropriate to use the promotion score on the underlying host.
Since this depends on the particular situation, the
``container-attribute-target`` resource meta-attribute allows the user to specify
which approach to use. If it is set to ``host``, then user-defined node attributes
will be checked on the underlying host. If it is anything else, the local node
(in this case the bundle node) is used as usual.
This only applies to user-defined attributes; the cluster will always check the
local node for cluster-defined attributes such as ``#uname``.
If ``container-attribute-target`` is ``host``, the cluster will pass additional
environment variables to the primitive's resource agent that allow it to set
node attributes appropriately: ``CRM_meta_container_attribute_target`` (identical
to the meta-attribute value) and ``CRM_meta_physical_host`` (the name of the
underlying host).
.. note::
When called by a resource agent, the ``attrd_updater`` and ``crm_attribute``
commands will automatically check those environment variables and set
attributes appropriately.
.. index::
single: bundle; meta-attributes
Bundle Meta-Attributes
______________________
Any meta-attribute set on a bundle will be inherited by the bundle's
primitive and any resources implicitly created by Pacemaker for the bundle.
This includes options such as ``priority``, ``target-role``, and ``is-managed``. See
:ref:`resource_options` for more information.
Bundles support clone meta-attributes including ``notify``, ``ordered``, and
``interleave``.
Limitations of Bundles
______________________
Restarting pacemaker while a bundle is unmanaged or the cluster is in
maintenance mode may cause the bundle to fail.
Bundles may not be explicitly cloned or included in groups. This includes the
bundle's primitive and any resources implicitly created by Pacemaker for the
bundle. (If ``replicas`` is greater than 1, the bundle will behave like a clone
implicitly.)
Bundles do not have instance attributes, utilization attributes, or operations,
though a bundle's primitive may have them.
A bundle with a primitive can run on a Pacemaker Remote node only if the bundle
uses a distinct ``control-port``.
.. [#] Of course, the service must support running multiple instances.
.. [#] Docker is a trademark of Docker, Inc. No endorsement by or association with
Docker, Inc. is implied.
diff --git a/doc/sphinx/Pacemaker_Explained/local-options.rst b/doc/sphinx/Pacemaker_Explained/local-options.rst
index 7731f6c918..fc51491f67 100644
--- a/doc/sphinx/Pacemaker_Explained/local-options.rst
+++ b/doc/sphinx/Pacemaker_Explained/local-options.rst
@@ -1,724 +1,723 @@
Host-Local Configuration
------------------------
.. index::
pair: XML element; configuration
.. note:: Directory and file paths below may differ on your system depending on
your Pacemaker build settings. Check your Pacemaker configuration
file to find the correct paths.
Configuration Value Types
#########################
Throughout this document, configuration values will be designated as having one
of the following types:
.. list-table:: **Configuration Value Types**
:class: longtable
:widths: 1 3
:header-rows: 1
* - Type
- Description
* - .. _boolean:
.. index::
pair: type; boolean
boolean
- Case-insensitive text value where ``1``, ``yes``, ``y``, ``on``,
and ``true`` evaluate as true and ``0``, ``no``, ``n``, ``off``,
``false``, and unset evaluate as false
* - .. _date_time:
.. index::
pair: type; date/time
date/time
- Textual timestamp like ``Sat Dec 21 11:47:45 2013``
* - .. _duration:
.. index::
pair: type; duration
duration
- A nonnegative time duration, specified either like a
:ref:`timeout ` or an
`ISO 8601 duration `_.
A duration may be up to approximately 49 days but is intended for much
smaller time periods.
* - .. _enumeration:
.. index::
pair: type; enumeration
enumeration
- Text that must be one of a set of defined values (which will be listed
in the description)
* - .. _epoch_time:
.. index::
pair: type; epoch_time
epoch_time
- Time as the integer number of seconds since the Unix epoch,
``1970-01-01 00:00:00 +0000 (UTC)``.
* - .. _id:
.. index::
pair: type; id
id
- A text string starting with a letter or underbar, followed by any
combination of letters, numbers, dashes, dots, and/or underbars; when
used for a property named ``id``, the string must be unique across all
``id`` properties in the CIB
* - .. _integer:
.. index::
pair: type; integer
integer
- 32-bit signed integer value (-2,147,483,648 to 2,147,483,647)
* - .. _iso8601:
.. index::
pair: type; iso8601
ISO 8601
- An `ISO 8601 `_ date/time.
* - .. _nonnegative_integer:
.. index::
pair: type; nonnegative integer
nonnegative integer
- 32-bit nonnegative integer value (0 to 2,147,483,647)
* - .. _percentage:
.. index::
pair: type; percentage
percentage
- Floating-point number followed by an optional percent sign ('%')
* - .. _port:
.. index::
pair: type; port
port
- Integer TCP port number (0 to 65535)
* - .. _range:
.. index::
pair: type; range
range
- A range may be a single nonnegative integer or a dash-separated range of
nonnegative integers. Either the first or last value may be omitted to
leave the range open-ended. Examples: ``0``, ``3-``, ``-5``, ``4-6``.
* - .. _score:
.. index::
pair: type; score
score
- A Pacemaker score can be an integer between -1,000,000 and 1,000,000, or
a string alias: ``INFINITY`` or ``+INFINITY`` is equivalent to
1,000,000, ``-INFINITY`` is equivalent to -1,000,000, and ``red``,
``yellow``, and ``green`` are equivalent to integers as described in
:ref:`node-health`.
* - .. _text:
.. index::
pair: type; text
text
- A text string
* - .. _timeout:
.. index::
pair: type; timeout
timeout
- A time duration, specified as a bare number (in which case it is
considered to be in seconds) or a number with a unit (``ms`` or ``msec``
for milliseconds, ``us`` or ``usec`` for microseconds, ``s`` or ``sec``
for seconds, ``m`` or ``min`` for minutes, ``h`` or ``hr`` for hours)
optionally with whitespace before and/or after the number.
* - .. _version:
.. index::
pair: type; version
version
- Version number (any combination of alphanumeric characters, dots, and
dashes, starting with a number).
Scores
______
Scores are integral to how Pacemaker works. Practically everything from moving
a resource to deciding which resource to stop in a degraded cluster is achieved
by manipulating scores in some way.
Scores are calculated per resource and node. Any node with a negative score for
a resource can't run that resource. The cluster places a resource on the node
with the highest score for it.
Score addition and subtraction follow these rules:
* Any value (including ``INFINITY``) - ``INFINITY`` = ``-INFINITY``
* ``INFINITY`` + any value other than ``-INFINITY`` = ``INFINITY``
.. note::
What if you want to use a score higher than 1,000,000? Typically this possibility
arises when someone wants to base the score on some external metric that might
go above 1,000,000.
The short answer is you can't.
The long answer is it is sometimes possible work around this limitation
creatively. You may be able to set the score to some computed value based on
the external metric rather than use the metric directly. For nodes, you can
store the metric as a node attribute, and query the attribute when computing
the score (possibly as part of a custom resource agent).
Local Options
#############
Most Pacemaker configuration is in the cluster-wide CIB, but some host-local
-configuration options either are needed at startup, before the CIB is read, or
+configuration options either are needed at startup (before the CIB is read) or
provide per-host overrides of cluster-wide options.
These options are configured as environment variables set when Pacemaker is
started, in the format ``=""``. These are typically set in a file
whose location varies by OS (most commonly ``/etc/sysconfig/pacemaker`` or
``/etc/default/pacemaker``; this documentation was generated on a system using
|PCMK_CONFIG_FILE|).
.. list-table:: **Local Options**
:class: longtable
:widths: 2 2 2 5
:header-rows: 1
* - Name
- Type
- Default
- Description
* - .. _cib_pam_service:
.. index::
pair: node option; CIB_pam_service
CIB_pam_service
- :ref:`text `
- login
- PAM service to use for remote CIB client authentication (passed to
``pam_start``).
* - .. _pcmk_logfacility:
.. index::
pair: node option; PCMK_logfacility
PCMK_logfacility
- :ref:`enumeration `
- daemon
- Enable logging via the system log or journal, using the specified log
facility. Messages sent here are of value to all Pacemaker
administrators. This can be disabled using ``none``, but that is not
recommended. Allowed values:
* ``none``
* ``daemon``
* ``user``
* ``local0``
* ``local1``
* ``local2``
* ``local3``
* ``local4``
* ``local5``
* ``local6``
* ``local7``
* - .. _pcmk_logpriority:
.. index::
pair: node option; PCMK_logpriority
PCMK_logpriority
- :ref:`enumeration `
- notice
- Unless system logging is disabled using ``PCMK_logfacility=none``,
messages of the specified log severity and higher will be sent to the
system log. The default is appropriate for most installations. Allowed
values:
* ``emerg``
* ``alert``
* ``crit``
* ``error``
* ``warning``
* ``notice``
* ``info``
* ``debug``
* - .. _pcmk_logfile:
.. index::
pair: node option; PCMK_logfile
PCMK_logfile
- :ref:`text `
- |PCMK_LOG_FILE|
- Unless set to ``none``, more detailed log messages will be sent to the
specified file (in addition to the system log, if enabled). These
messages may have extended information, and will include messages of info
severity. This log is of more use to developers and advanced system
administrators, and when reporting problems. Note: The default is
|PCMK_CONTAINER_LOG_FILE| (inside the container) for bundled container
nodes; this would typically be mapped to a different path on the host
running the container.
* - .. _pcmk_logfile_mode:
.. index::
pair: node option; PCMK_logfile_mode
PCMK_logfile_mode
- :ref:`text `
- 0660
- Pacemaker will set the permissions on the detail log to this value (see
``chmod(1)``).
* - .. _pcmk_debug:
.. index::
pair: node option; PCMK_debug
PCMK_debug
- :ref:`enumeration `
- no
- Whether to send debug severity messages to the detail log. This may be
set for all subsystems (``yes`` or ``no``) or for specific (comma-
separated) subsystems. Allowed subsystems are:
* ``pacemakerd``
* ``pacemaker-attrd``
* ``pacemaker-based``
* ``pacemaker-controld``
* ``pacemaker-execd``
* ``pacemaker-fenced``
* ``pacemaker-schedulerd``
Example: ``PCMK_debug="pacemakerd,pacemaker-execd"``
* - .. _pcmk_stderr:
.. index::
pair: node option; PCMK_stderr
PCMK_stderr
- :ref:`boolean `
- no
- *Advanced Use Only:* Whether to send daemon log messages to stderr. This
would be useful only during troubleshooting, when starting Pacemaker
manually on the command line.
Setting this option in the configuration file is pointless, since the
file is not read when starting Pacemaker manually. However, it can be set
directly as an environment variable on the command line.
* - .. _pcmk_trace_functions:
.. index::
pair: node option; PCMK_trace_functions
PCMK_trace_functions
- :ref:`text `
-
- *Advanced Use Only:* Send debug and trace severity messages from these
(comma-separated) source code functions to the detail log.
Example:
``PCMK_trace_functions="func1,func2"``
* - .. _pcmk_trace_files:
.. index::
pair: node option; PCMK_trace_files
PCMK_trace_files
- :ref:`text `
-
- *Advanced Use Only:* Send debug and trace severity messages from all
functions in these (comma-separated) source file names to the detail log.
Example: ``PCMK_trace_files="file1.c,file2.c"``
* - .. _pcmk_trace_formats:
.. index::
pair: node option; PCMK_trace_formats
PCMK_trace_formats
- :ref:`text `
-
- *Advanced Use Only:* Send trace severity messages that are generated by
these (comma-separated) format strings in the source code to the detail
log.
Example: ``PCMK_trace_formats="Error: %s (%d)"``
* - .. _pcmk_trace_tags:
.. index::
pair: node option; PCMK_trace_tags
PCMK_trace_tags
- :ref:`text `
-
- *Advanced Use Only:* Send debug and trace severity messages related to
these (comma-separated) resource IDs to the detail log.
Example: ``PCMK_trace_tags="client-ip,dbfs"``
* - .. _pcmk_blackbox:
.. index::
pair: node option; PCMK_blackbox
PCMK_blackbox
- :ref:`enumeration `
- no
- *Advanced Use Only:* Enable blackbox logging globally (``yes`` or ``no``)
or by subsystem. A blackbox contains a rolling buffer of all logs (of all
severities). Blackboxes are stored under |CRM_BLACKBOX_DIR| by default,
by default, and their contents can be viewed using the ``qb-blackbox(8)``
command.
The blackbox recorder can be enabled at start using this variable, or at
runtime by sending a Pacemaker subsystem daemon process a ``SIGUSR1`` or
``SIGTRAP`` signal, and disabled by sending ``SIGUSR2`` (see
``kill(1)``). The blackbox will be written after a crash, assertion
failure, or ``SIGTRAP`` signal.
See :ref:`PCMK_debug ` for allowed subsystems.
Example:
``PCMK_blackbox="pacemakerd,pacemaker-execd"``
* - .. _pcmk_trace_blackbox:
.. index::
pair: node option; PCMK_trace_blackbox
PCMK_trace_blackbox
- :ref:`enumeration `
-
- *Advanced Use Only:* Write a blackbox whenever the message at the
specified function and line is logged. Multiple entries may be comma-
separated.
Example: ``PCMK_trace_blackbox="remote.c:144,remote.c:149"``
* - .. _pcmk_node_start_state:
.. index::
pair: node option; PCMK_node_start_state
PCMK_node_start_state
- :ref:`enumeration `
- default
- By default, the local host will join the cluster in an online or standby
state when Pacemaker first starts depending on whether it was previously
put into standby mode. If this variable is set to ``standby`` or
``online``, it will force the local host to join in the specified state.
* - .. _pcmk_node_action_limit:
.. index::
pair: node option; PCMK_node_action_limit
PCMK_node_action_limit
- :ref:`nonnegative integer `
-
- If set, this overrides the :ref:`node-action-limit `
cluster option on this node to specify the maximum number of jobs that
can be scheduled on this node (or 0 to use twice the number of CPU
cores).
* - .. _pcmk_fail_fast:
.. index::
pair: node option; PCMK_fail_fast
PCMK_fail_fast
- :ref:`boolean `
- no
- By default, if a Pacemaker subsystem crashes, the main ``pacemakerd``
process will attempt to restart it. If this variable is set to ``yes``,
``pacemakerd`` will panic the local host instead.
* - .. _pcmk_panic_action:
.. index::
pair: node option; PCMK_panic_action
PCMK_panic_action
- :ref:`enumeration `
- reboot
- Pacemaker will panic the local host under certain conditions. By default,
this means rebooting the host. This variable can change that behavior: if
``crash``, trigger a kernel crash (useful if you want a kernel dump to
investigate); if ``sync-reboot`` or ``sync-crash``, synchronize
filesystems before rebooting the host or triggering a kernel crash. The
sync values are more likely to preserve log messages, but with the risk
that the host may be left active if the synchronization hangs.
* - .. _pcmk_authkey_location:
.. index::
pair: node option; PCMK_authkey_location
PCMK_authkey_location
- :ref:`text `
- |PCMK_AUTHKEY_FILE|
- Use the contents of this file as the authorization key to use with
:ref:`Pacemaker Remote ` connections. This file must
be readable by Pacemaker daemons (that is, it must allow read
permissions to either the |CRM_DAEMON_USER| user or the
|CRM_DAEMON_GROUP| group), and its contents must be identical on all
nodes.
* - .. _pcmk_remote_address:
.. index::
pair: node option; PCMK_remote_address
PCMK_remote_address
- :ref:`text `
-
- By default, if the :ref:`Pacemaker Remote ` service is
run on the local node, it will listen for connections on all IP
addresses. This may be set to one address to listen on instead, as a
resolvable hostname or as a numeric IPv4 or IPv6 address. When resolving
names or listening on all addresses, IPv6 will be preferred if
available. When listening on an IPv6 address, IPv4 clients will be
supported via IPv4-mapped IPv6 addresses.
Example: ``PCMK_remote_address="192.0.2.1"``
* - .. _pcmk_remote_port:
.. index::
pair: node option; PCMK_remote_port
PCMK_remote_port
- :ref:`port `
- 3121
- Use this TCP port number for :ref:`Pacemaker Remote `
node connections. This value must be the same on all nodes.
* - .. _pcmk_remote_pid1:
.. index::
pair: node option; PCMK_remote_pid1
PCMK_remote_pid1
- :ref:`enumeration `
- default
- *Advanced Use Only:* When a bundle resource's ``run-command`` option is
left to default, :ref:`Pacemaker Remote ` runs as PID
1 in the bundle's containers. When it does so, it loads environment
variables from the container's |PCMK_INIT_ENV_FILE| and performs the PID
1 responsibility of reaping dead subprocesses.
This option controls whether those actions are performed when Pacemaker
Remote is not running as PID 1. It is intended primarily for developer
testing but can be useful when ``run-command`` is set to a separate,
custom PID 1 process that launches Pacemaker Remote.
* ``full``: Pacemaker Remote loads environment variables from
|PCMK_INIT_ENV_FILE| and reaps dead subprocesses.
* ``vars``: Pacemaker Remote loads environment variables from
|PCMK_INIT_ENV_FILE| but does not reap dead subprocesses.
* ``default``: Pacemaker Remote performs neither action.
If Pacemaker Remote is running as PID 1, this option is ignored, and the
behavior is the same as for ``full``.
* - .. _pcmk_tls_priorities:
.. index::
pair: node option; PCMK_tls_priorities
PCMK_tls_priorities
- :ref:`text `
- |PCMK__GNUTLS_PRIORITIES|
- - *Advanced Use Only:* These GnuTLS cipher priorities will be used for TLS
- connections (whether for :ref:`Pacemaker Remote `
- connections or remote CIB access, when enabled). See:
-
- https://gnutls.org/manual/html_node/Priority-Strings.html
+ - *Advanced Use Only:* These `GnuTLS cipher priorities
+ `_ will be
+ used for TLS connections (whether for :ref:`Pacemaker Remote
+ ` connections or remote CIB access, when enabled).
Pacemaker will append ``":+ANON-DH"`` for remote CIB access and
``":+DHE-PSK:+PSK"`` for Pacemaker Remote connections, as they are
required for the respective functionality.
Example:
``PCMK_tls_priorities="SECURE128:+SECURE192"``
* - .. _pcmk_dh_max_bits:
.. index::
pair: node option; PCMK_dh_max_bits
PCMK_dh_max_bits
- :ref:`nonnegative integer `
- 0 (no maximum)
- *Advanced Use Only:* Set an upper bound on the bit length of the prime
number generated for Diffie-Hellman parameters needed by TLS connections.
The default is no maximum.
The server (:ref:`Pacemaker Remote ` daemon, or CIB
manager configured to accept remote clients) will use this value to
provide a ceiling for the value recommended by the GnuTLS library. The
library will only accept a limited number of specific values, which vary
by library version, so setting these is recommended only when required
for compatibility with specific client versions.
Clients do not use ``PCMK_dh_max_bits``.
* - .. _pcmk_ipc_type:
.. index::
pair: node option; PCMK_ipc_type
PCMK_ipc_type
- :ref:`enumeration `
- shared-mem
- *Advanced Use Only:* Force use of a particular IPC method. Allowed values:
* ``shared-mem``
* ``socket``
* ``posix``
* ``sysv``
* - .. _pcmk_ipc_buffer:
.. index::
pair: node option; PCMK_ipc_buffer
PCMK_ipc_buffer
- :ref:`nonnegative integer `
- 131072
- *Advanced Use Only:* Specify an IPC buffer size in bytes. This can be
useful when connecting to large clusters that result in messages
exceeding the default size (which will also result in log messages
referencing this variable).
* - .. _pcmk_cluster_type:
.. index::
pair: node option; PCMK_cluster_type
PCMK_cluster_type
- :ref:`enumeration `
- corosync
- *Advanced Use Only:* Specify the cluster layer to be used. If unset,
Pacemaker will detect and use a supported cluster layer, if available.
Currently, ``"corosync"`` is the only supported cluster layer. If
multiple layers are supported in the future, this will allow overriding
Pacemaker's automatic detection to select a specific one.
* - .. _pcmk_schema_directory:
.. index::
pair: node option; PCMK_schema_directory
PCMK_schema_directory
- :ref:`text `
- |PCMK_SCHEMA_DIR|
- *Advanced Use Only:* Specify an alternate location for RNG schemas and
XSL transforms.
* - .. _pcmk_remote_schema_directory:
.. index::
pair: node option; PCMK_remote_schema_directory
PCMK_remote_schema_directory
- :ref:`text `
- |PCMK__REMOTE_SCHEMA_DIR|
- *Advanced Use Only:* Specify an alternate location on
:ref:`Pacemaker Remote ` nodes for storing newer RNG
schemas and XSL transforms fetched from the cluster.
* - .. _pcmk_valgrind_enabled:
.. index::
pair: node option; PCMK_valgrind_enabled
PCMK_valgrind_enabled
- :ref:`enumeration `
- no
- *Advanced Use Only:* Whether subsystem daemons should be run under
``valgrind``. Allowed values are the same as for ``PCMK_debug``.
* - .. _pcmk_callgrind_enabled:
.. index::
pair: node option; PCMK_callgrind_enabled
PCMK_callgrind_enabled
- :ref:`enumeration `
- no
- *Advanced Use Only:* Whether subsystem daemons should be run under
``valgrind`` with the ``callgrind`` tool enabled. Allowed values are the
same as for ``PCMK_debug``.
* - .. _sbd_sync_resource_startup:
.. index::
pair: node option; SBD_SYNC_RESOURCE_STARTUP
SBD_SYNC_RESOURCE_STARTUP
- :ref:`boolean `
-
- If true, ``pacemakerd`` waits for a ping from ``sbd`` during startup
before starting other Pacemaker daemons, and during shutdown after
stopping other Pacemaker daemons but before exiting. Default value is set
based on the ``--with-sbd-sync-default`` configure script option.
* - .. _sbd_watchdog_timeout:
.. index::
pair: node option; SBD_WATCHDOG_TIMEOUT
SBD_WATCHDOG_TIMEOUT
- :ref:`duration `
-
- If the ``stonith-watchdog-timeout`` cluster property is set to a negative
or invalid value, use double this value as the default if positive, or
use 0 as the default otherwise. This value must be greater than the value
of ``stonith-watchdog-timeout`` if both are set.
* - .. _valgrind_opts:
.. index::
pair: node option; VALGRIND_OPTS
VALGRIND_OPTS
- :ref:`text `
-
- *Advanced Use Only:* Pass these options to valgrind, when enabled (see
``valgrind(1)``). ``"--vgdb=no"`` should usually be specified because
``pacemaker-execd`` can lower privileges when executing commands, which
would otherwise leave a bunch of unremovable files in ``/tmp``.
diff --git a/lib/cib/Makefile.am b/lib/cib/Makefile.am
index 88b708f485..54462696f9 100644
--- a/lib/cib/Makefile.am
+++ b/lib/cib/Makefile.am
@@ -1,29 +1,29 @@
#
# Copyright 2004-2024 the Pacemaker project contributors
#
# The version control history for this file may have further details.
#
# This source code is licensed under the GNU General Public License version 2
# or later (GPLv2+) WITHOUT ANY WARRANTY.
#
include $(top_srcdir)/mk/common.mk
## libraries
lib_LTLIBRARIES = libcib.la
## Library sources (*must* use += format for bumplibs)
libcib_la_SOURCES = cib_attrs.c
libcib_la_SOURCES += cib_client.c
libcib_la_SOURCES += cib_file.c
libcib_la_SOURCES += cib_native.c
libcib_la_SOURCES += cib_ops.c
libcib_la_SOURCES += cib_remote.c
libcib_la_SOURCES += cib_utils.c
-libcib_la_LDFLAGS = -version-info 33:1:6
+libcib_la_LDFLAGS = -version-info 54:0:0
libcib_la_LDFLAGS += $(LDFLAGS_HARDENED_LIB)
libcib_la_CFLAGS = $(CFLAGS_HARDENED_LIB)
libcib_la_LIBADD = $(top_builddir)/lib/pengine/libpe_rules.la \
$(top_builddir)/lib/common/libcrmcommon.la
diff --git a/lib/cluster/Makefile.am b/lib/cluster/Makefile.am
index 20b0028754..0abe0ecacd 100644
--- a/lib/cluster/Makefile.am
+++ b/lib/cluster/Makefile.am
@@ -1,34 +1,34 @@
#
# Copyright 2004-2024 the Pacemaker project contributors
#
# The version control history for this file may have further details.
#
# This source code is licensed under the GNU General Public License version 2
# or later (GPLv2+) WITHOUT ANY WARRANTY.
#
include $(top_srcdir)/mk/common.mk
SUBDIRS = tests
noinst_HEADERS = crmcluster_private.h
## libraries
lib_LTLIBRARIES = libcrmcluster.la
-libcrmcluster_la_LDFLAGS = -version-info 32:1:3
+libcrmcluster_la_LDFLAGS = -version-info 53:0:0
libcrmcluster_la_CFLAGS = $(CFLAGS_HARDENED_LIB)
libcrmcluster_la_LDFLAGS += $(LDFLAGS_HARDENED_LIB)
libcrmcluster_la_LIBADD = $(top_builddir)/lib/fencing/libstonithd.la
libcrmcluster_la_LIBADD += $(top_builddir)/lib/common/libcrmcommon.la
libcrmcluster_la_LIBADD += $(CLUSTERLIBS)
## Library sources (*must* use += format for bumplibs)
libcrmcluster_la_SOURCES = cluster.c
libcrmcluster_la_SOURCES += election.c
libcrmcluster_la_SOURCES += membership.c
if BUILD_CS_SUPPORT
libcrmcluster_la_SOURCES += corosync.c
libcrmcluster_la_SOURCES += cpg.c
endif
diff --git a/lib/common/Makefile.am b/lib/common/Makefile.am
index e6142db334..753211ea67 100644
--- a/lib/common/Makefile.am
+++ b/lib/common/Makefile.am
@@ -1,141 +1,141 @@
#
# Copyright 2004-2024 the Pacemaker project contributors
#
# The version control history for this file may have further details.
#
# This source code is licensed under the GNU General Public License version 2
# or later (GPLv2+) WITHOUT ANY WARRANTY.
#
include $(top_srcdir)/mk/common.mk
## libraries
lib_LTLIBRARIES = libcrmcommon.la
check_LTLIBRARIES = libcrmcommon_test.la
# Disable -Wcast-qual if used, because we do some hacky casting,
# and because libxml2 has some signatures that should be const but aren't
# for backward compatibility reasons.
# s390 needs -fPIC
# s390-suse-linux/bin/ld: .libs/ipc.o: relocation R_390_PC32DBL against `__stack_chk_fail@@GLIBC_2.4' can not be used when making a shared object; recompile with -fPIC
CFLAGS = $(CFLAGS_COPY:-Wcast-qual=) -fPIC
# Without "." here, check-recursive will run through the subdirectories first
# and then run "make check" here. This will fail, because there's things in
# the subdirectories that need check_LTLIBRARIES built first. Adding "." here
# changes the order so the subdirectories are processed afterwards.
SUBDIRS = . tests
noinst_HEADERS = crmcommon_private.h \
mock_private.h
-libcrmcommon_la_LDFLAGS = -version-info 47:1:13
+libcrmcommon_la_LDFLAGS = -version-info 68:0:0
libcrmcommon_la_CFLAGS = $(CFLAGS_HARDENED_LIB)
libcrmcommon_la_LDFLAGS += $(LDFLAGS_HARDENED_LIB)
# If configured with --with-profiling or --with-coverage, BUILD_PROFILING will
# be set and -fno-builtin will be added to the CFLAGS. However, libcrmcommon
# uses the fabs() function which is normally supplied by gcc as one of its
# builtins. Therefore we need to explicitly link against libm here or the
# tests won't link.
if BUILD_PROFILING
libcrmcommon_la_LIBADD = -lm
endif
## Library sources (*must* use += format for bumplibs)
libcrmcommon_la_SOURCES =
libcrmcommon_la_SOURCES += acl.c
libcrmcommon_la_SOURCES += actions.c
libcrmcommon_la_SOURCES += agents.c
libcrmcommon_la_SOURCES += alerts.c
libcrmcommon_la_SOURCES += attrs.c
libcrmcommon_la_SOURCES += cib.c
if BUILD_CIBSECRETS
libcrmcommon_la_SOURCES += cib_secrets.c
endif
libcrmcommon_la_SOURCES += cmdline.c
libcrmcommon_la_SOURCES += digest.c
libcrmcommon_la_SOURCES += health.c
libcrmcommon_la_SOURCES += io.c
libcrmcommon_la_SOURCES += ipc_attrd.c
libcrmcommon_la_SOURCES += ipc_client.c
libcrmcommon_la_SOURCES += ipc_common.c
libcrmcommon_la_SOURCES += ipc_controld.c
libcrmcommon_la_SOURCES += ipc_pacemakerd.c
libcrmcommon_la_SOURCES += ipc_schedulerd.c
libcrmcommon_la_SOURCES += ipc_server.c
libcrmcommon_la_SOURCES += iso8601.c
libcrmcommon_la_SOURCES += lists.c
libcrmcommon_la_SOURCES += logging.c
libcrmcommon_la_SOURCES += mainloop.c
libcrmcommon_la_SOURCES += messages.c
libcrmcommon_la_SOURCES += nodes.c
libcrmcommon_la_SOURCES += nvpair.c
libcrmcommon_la_SOURCES += options.c
libcrmcommon_la_SOURCES += options_display.c
libcrmcommon_la_SOURCES += output.c
libcrmcommon_la_SOURCES += output_html.c
libcrmcommon_la_SOURCES += output_log.c
libcrmcommon_la_SOURCES += output_none.c
libcrmcommon_la_SOURCES += output_text.c
libcrmcommon_la_SOURCES += output_xml.c
libcrmcommon_la_SOURCES += patchset.c
libcrmcommon_la_SOURCES += patchset_display.c
libcrmcommon_la_SOURCES += pid.c
libcrmcommon_la_SOURCES += probes.c
libcrmcommon_la_SOURCES += procfs.c
libcrmcommon_la_SOURCES += remote.c
libcrmcommon_la_SOURCES += resources.c
libcrmcommon_la_SOURCES += results.c
libcrmcommon_la_SOURCES += roles.c
libcrmcommon_la_SOURCES += rules.c
libcrmcommon_la_SOURCES += scheduler.c
libcrmcommon_la_SOURCES += schemas.c
libcrmcommon_la_SOURCES += scores.c
libcrmcommon_la_SOURCES += servers.c
libcrmcommon_la_SOURCES += strings.c
libcrmcommon_la_SOURCES += utils.c
libcrmcommon_la_SOURCES += watchdog.c
libcrmcommon_la_SOURCES += xml.c
libcrmcommon_la_SOURCES += xml_attr.c
libcrmcommon_la_SOURCES += xml_comment.c
libcrmcommon_la_SOURCES += xml_display.c
libcrmcommon_la_SOURCES += xml_element.c
libcrmcommon_la_SOURCES += xml_idref.c
libcrmcommon_la_SOURCES += xml_io.c
libcrmcommon_la_SOURCES += xpath.c
#
# libcrmcommon_test is used only with unit tests, so we can mock system calls.
# See mock.c for details.
#
include $(top_srcdir)/mk/tap.mk
libcrmcommon_test_la_SOURCES = $(libcrmcommon_la_SOURCES)
libcrmcommon_test_la_SOURCES += mock.c
libcrmcommon_test_la_SOURCES += unittest.c
libcrmcommon_test_la_LDFLAGS = $(libcrmcommon_la_LDFLAGS) \
-rpath $(libdir) \
$(LDFLAGS_WRAP)
# If GCC emits a builtin function in place of something we've mocked up, that will
# get used instead of the mocked version which leads to unexpected test results. So
# disable all builtins. Older versions of GCC (at least, on RHEL7) will still emit
# replacement code for strdup (and possibly other functions) unless -fno-inline is
# also added.
libcrmcommon_test_la_CFLAGS = $(libcrmcommon_la_CFLAGS) \
-DPCMK__UNIT_TESTING \
-fno-builtin \
-fno-inline
# If -fno-builtin is used, -lm also needs to be added. See the comment at
# BUILD_PROFILING above.
libcrmcommon_test_la_LIBADD = $(libcrmcommon_la_LIBADD)
if BUILD_COVERAGE
libcrmcommon_test_la_LIBADD += -lgcov
endif
libcrmcommon_test_la_LIBADD += -lcmocka
libcrmcommon_test_la_LIBADD += -lm
nodist_libcrmcommon_test_la_SOURCES = $(nodist_libcrmcommon_la_SOURCES)
diff --git a/lib/fencing/Makefile.am b/lib/fencing/Makefile.am
index 6c3f4978ff..d8918779b1 100644
--- a/lib/fencing/Makefile.am
+++ b/lib/fencing/Makefile.am
@@ -1,33 +1,33 @@
#
# Original Author: Sun Jiang Dong
# Copyright 2004 International Business Machines
#
# with later changes copyright 2004-2022 the Pacemaker project contributors.
# The version control history for this file may have further details.
#
# This source code is licensed under the GNU General Public License version 2
# or later (GPLv2+) WITHOUT ANY WARRANTY.
#
include $(top_srcdir)/mk/common.mk
noinst_HEADERS = fencing_private.h
lib_LTLIBRARIES = libstonithd.la
-libstonithd_la_LDFLAGS = -version-info 35:0:9
+libstonithd_la_LDFLAGS = -version-info 56:0:0
libstonithd_la_CFLAGS = $(CFLAGS_HARDENED_LIB)
libstonithd_la_LDFLAGS += $(LDFLAGS_HARDENED_LIB)
libstonithd_la_LIBADD = $(top_builddir)/lib/services/libcrmservice.la
libstonithd_la_LIBADD += $(top_builddir)/lib/common/libcrmcommon.la
libstonithd_la_LIBADD += @DL_LIBS@ @STONITH_LIBS@
## Library sources (*must* use += format for bumplibs)
libstonithd_la_SOURCES = st_actions.c
libstonithd_la_SOURCES += st_client.c
if BUILD_LHA_SUPPORT
libstonithd_la_SOURCES += st_lha.c
endif
libstonithd_la_SOURCES += st_output.c
libstonithd_la_SOURCES += st_rhcs.c
diff --git a/lib/lrmd/Makefile.am b/lib/lrmd/Makefile.am
index a8b716c03d..f706be97ee 100644
--- a/lib/lrmd/Makefile.am
+++ b/lib/lrmd/Makefile.am
@@ -1,26 +1,26 @@
#
# Copyright 2012-2023 the Pacemaker project contributors
#
# The version control history for this file may have further details.
#
# This source code is licensed under the GNU Lesser General Public License
# version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
#
include $(top_srcdir)/mk/common.mk
lib_LTLIBRARIES = liblrmd.la
-liblrmd_la_LDFLAGS = -version-info 31:1:3
+liblrmd_la_LDFLAGS = -version-info 52:0:0
liblrmd_la_CFLAGS = $(CFLAGS_HARDENED_LIB)
liblrmd_la_LDFLAGS += $(LDFLAGS_HARDENED_LIB)
liblrmd_la_LIBADD = $(top_builddir)/lib/fencing/libstonithd.la
liblrmd_la_LIBADD += $(top_builddir)/lib/services/libcrmservice.la
liblrmd_la_LIBADD += $(top_builddir)/lib/common/libcrmcommon.la
## Library sources (*must* use += format for bumplibs)
liblrmd_la_SOURCES = lrmd_alerts.c
liblrmd_la_SOURCES += lrmd_client.c
liblrmd_la_SOURCES += lrmd_output.c
liblrmd_la_SOURCES += proxy_common.c
diff --git a/lib/pacemaker/Makefile.am b/lib/pacemaker/Makefile.am
index 6147fa4feb..8ffa00bd82 100644
--- a/lib/pacemaker/Makefile.am
+++ b/lib/pacemaker/Makefile.am
@@ -1,73 +1,73 @@
#
# Copyright 2004-2024 the Pacemaker project contributors
#
# The version control history for this file may have further details.
#
# This source code is licensed under the GNU General Public License version 2
# or later (GPLv2+) WITHOUT ANY WARRANTY.
#
include $(top_srcdir)/mk/common.mk
SUBDIRS = tests
noinst_HEADERS = libpacemaker_private.h
## libraries
lib_LTLIBRARIES = libpacemaker.la
-libpacemaker_la_LDFLAGS = -version-info 9:1:8
+libpacemaker_la_LDFLAGS = -version-info 30:0:0
libpacemaker_la_CFLAGS = $(CFLAGS_HARDENED_LIB)
libpacemaker_la_LDFLAGS += $(LDFLAGS_HARDENED_LIB)
libpacemaker_la_LIBADD = $(top_builddir)/lib/pengine/libpe_status.la
libpacemaker_la_LIBADD += $(top_builddir)/lib/cib/libcib.la
libpacemaker_la_LIBADD += $(top_builddir)/lib/lrmd/liblrmd.la
libpacemaker_la_LIBADD += $(top_builddir)/lib/fencing/libstonithd.la
libpacemaker_la_LIBADD += $(top_builddir)/lib/services/libcrmservice.la
libpacemaker_la_LIBADD += $(top_builddir)/lib/common/libcrmcommon.la
# -L$(top_builddir)/lib/pils -lpils -export-dynamic -module -avoid-version
## Library sources (*must* use += format for bumplibs)
libpacemaker_la_SOURCES =
libpacemaker_la_SOURCES += pcmk_acl.c
libpacemaker_la_SOURCES += pcmk_agents.c
libpacemaker_la_SOURCES += pcmk_cluster_queries.c
libpacemaker_la_SOURCES += pcmk_fence.c
libpacemaker_la_SOURCES += pcmk_graph_consumer.c
libpacemaker_la_SOURCES += pcmk_graph_logging.c
libpacemaker_la_SOURCES += pcmk_graph_producer.c
libpacemaker_la_SOURCES += pcmk_injections.c
libpacemaker_la_SOURCES += pcmk_options.c
libpacemaker_la_SOURCES += pcmk_output.c
libpacemaker_la_SOURCES += pcmk_resource.c
libpacemaker_la_SOURCES += pcmk_result_code.c
libpacemaker_la_SOURCES += pcmk_rule.c
libpacemaker_la_SOURCES += pcmk_sched_actions.c
libpacemaker_la_SOURCES += pcmk_sched_bundle.c
libpacemaker_la_SOURCES += pcmk_sched_clone.c
libpacemaker_la_SOURCES += pcmk_sched_colocation.c
libpacemaker_la_SOURCES += pcmk_sched_constraints.c
libpacemaker_la_SOURCES += pcmk_sched_fencing.c
libpacemaker_la_SOURCES += pcmk_sched_group.c
libpacemaker_la_SOURCES += pcmk_sched_instances.c
libpacemaker_la_SOURCES += pcmk_sched_location.c
libpacemaker_la_SOURCES += pcmk_sched_migration.c
libpacemaker_la_SOURCES += pcmk_sched_nodes.c
libpacemaker_la_SOURCES += pcmk_sched_ordering.c
libpacemaker_la_SOURCES += pcmk_sched_primitive.c
libpacemaker_la_SOURCES += pcmk_sched_probes.c
libpacemaker_la_SOURCES += pcmk_sched_promotable.c
libpacemaker_la_SOURCES += pcmk_sched_recurring.c
libpacemaker_la_SOURCES += pcmk_sched_remote.c
libpacemaker_la_SOURCES += pcmk_sched_resource.c
libpacemaker_la_SOURCES += pcmk_sched_tickets.c
libpacemaker_la_SOURCES += pcmk_sched_utilization.c
libpacemaker_la_SOURCES += pcmk_scheduler.c
libpacemaker_la_SOURCES += pcmk_setup.c
libpacemaker_la_SOURCES += pcmk_simulate.c
libpacemaker_la_SOURCES += pcmk_status.c
libpacemaker_la_SOURCES += pcmk_ticket.c
libpacemaker_la_SOURCES += pcmk_verify.c
diff --git a/lib/pengine/Makefile.am b/lib/pengine/Makefile.am
index d267ac15c3..15369f230d 100644
--- a/lib/pengine/Makefile.am
+++ b/lib/pengine/Makefile.am
@@ -1,80 +1,80 @@
#
# Copyright 2004-2024 the Pacemaker project contributors
#
# The version control history for this file may have further details.
#
# This source code is licensed under the GNU General Public License version 2
# or later (GPLv2+) WITHOUT ANY WARRANTY.
#
include $(top_srcdir)/mk/common.mk
# Without "." here, check-recursive will run through the subdirectories first
# and then run "make check" here. This will fail, because there's things in
# the subdirectories that need check_LTLIBRARIES built first. Adding "." here
# changes the order so the subdirectories are processed afterwards.
SUBDIRS = . tests
## libraries
lib_LTLIBRARIES = libpe_rules.la \
libpe_status.la
check_LTLIBRARIES = libpe_status_test.la
noinst_HEADERS = pe_status_private.h
-libpe_rules_la_LDFLAGS = -version-info 30:3:4
+libpe_rules_la_LDFLAGS = -version-info 51:0:0
libpe_rules_la_CFLAGS = $(CFLAGS_HARDENED_LIB)
libpe_rules_la_LDFLAGS += $(LDFLAGS_HARDENED_LIB)
libpe_rules_la_LIBADD = $(top_builddir)/lib/common/libcrmcommon.la
## Library sources (*must* use += format for bumplibs)
libpe_rules_la_SOURCES = rules.c
libpe_rules_la_SOURCES += rules_alerts.c
-libpe_status_la_LDFLAGS = -version-info 35:2:7
+libpe_status_la_LDFLAGS = -version-info 56:0:0
libpe_status_la_CFLAGS = $(CFLAGS_HARDENED_LIB)
libpe_status_la_LDFLAGS += $(LDFLAGS_HARDENED_LIB)
libpe_status_la_LIBADD = $(top_builddir)/lib/common/libcrmcommon.la
## Library sources (*must* use += format for bumplibs)
libpe_status_la_SOURCES =
libpe_status_la_SOURCES += bundle.c
libpe_status_la_SOURCES += clone.c
libpe_status_la_SOURCES += complex.c
libpe_status_la_SOURCES += failcounts.c
libpe_status_la_SOURCES += group.c
libpe_status_la_SOURCES += native.c
libpe_status_la_SOURCES += pe_actions.c
libpe_status_la_SOURCES += pe_health.c
libpe_status_la_SOURCES += pe_digest.c
libpe_status_la_SOURCES += pe_notif.c
libpe_status_la_SOURCES += pe_output.c
libpe_status_la_SOURCES += remote.c
libpe_status_la_SOURCES += rules.c
libpe_status_la_SOURCES += status.c
libpe_status_la_SOURCES += tags.c
libpe_status_la_SOURCES += unpack.c
libpe_status_la_SOURCES += utils.c
#
# libpe_status_test is only used with unit tests, so we can
# mock system calls. See lib/common/mock.c for details.
#
include $(top_srcdir)/mk/tap.mk
libpe_status_test_la_SOURCES = $(libpe_status_la_SOURCES)
libpe_status_test_la_LDFLAGS = $(libpe_status_la_LDFLAGS) \
-rpath $(libdir) \
$(LDFLAGS_WRAP)
# See comments on libcrmcommon_test_la in lib/common/Makefile.am regarding these flags.
libpe_status_test_la_CFLAGS = $(libpe_status_la_CFLAGS) \
-DPCMK__UNIT_TESTING \
-fno-builtin \
-fno-inline
libpe_status_test_la_LIBADD = $(top_builddir)/lib/common/libcrmcommon_test.la \
-lcmocka \
-lm
diff --git a/lib/services/Makefile.am b/lib/services/Makefile.am
index 56a77c1181..f0c2f030af 100644
--- a/lib/services/Makefile.am
+++ b/lib/services/Makefile.am
@@ -1,33 +1,33 @@
#
# Copyright 2012-2024 the Pacemaker project contributors
#
# The version control history for this file may have further details.
#
# This source code is licensed under the GNU Lesser General Public License
# version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
#
include $(top_srcdir)/mk/common.mk
lib_LTLIBRARIES = libcrmservice.la
noinst_HEADERS = $(wildcard *.h)
-libcrmservice_la_LDFLAGS = -version-info 32:2:4
+libcrmservice_la_LDFLAGS = -version-info 53:0:0
libcrmservice_la_CFLAGS =
libcrmservice_la_CFLAGS += $(CFLAGS_HARDENED_LIB)
libcrmservice_la_LDFLAGS += $(LDFLAGS_HARDENED_LIB)
libcrmservice_la_LIBADD = $(top_builddir)/lib/common/libcrmcommon.la \
$(DBUS_LIBS)
## Library sources (*must* use += format for bumplibs)
libcrmservice_la_SOURCES = services.c
libcrmservice_la_SOURCES += services_linux.c
libcrmservice_la_SOURCES += services_ocf.c
if BUILD_LSB
libcrmservice_la_SOURCES += services_lsb.c
endif
if BUILD_SYSTEMD
libcrmservice_la_SOURCES += dbus.c
libcrmservice_la_SOURCES += systemd.c
endif
diff --git a/maint/bumplibs.in b/maint/bumplibs.in
index ddaa1a9b59..915b5227a5 100644
--- a/maint/bumplibs.in
+++ b/maint/bumplibs.in
@@ -1,296 +1,298 @@
#!@BASH_PATH@
#
-# Copyright 2012-2023 the Pacemaker project contributors
+# Copyright 2012-2024 the Pacemaker project contributors
#
# The version control history for this file may have further details.
#
# This source code is licensed under the GNU General Public License version 2
# or later (GPLv2+) WITHOUT ANY WARRANTY.
#
# List regular expressions (not globs) that match all of a library's public API
# headers. Any files ending in "internal.h" will be excluded from matches.
declare -A HEADERS
-HEADERS[cib]="include/crm/cib.h include/crm/cib/.*.h"
-HEADERS[crmcommon]="include/crm/crm.h
+HEADERS[cib]="include/crm/cib.*.h
+ include/crm/cib/.*.h"
+HEADERS[crmcluster]="include/crm/cluster.h
+ include/crm/cluster/.*.h"
+HEADERS[crmcommon]="include/crm/crm.*.h
include/crm/msg_xml.h
include/crm/common/.*.h"
-HEADERS[crmcluster]="include/crm/cluster.h include/crm/cluster/.*.h"
HEADERS[crmservice]="include/crm/services.*.h"
HEADERS[lrmd]="include/crm/lrmd.*.h"
HEADERS[pacemaker]="include/pacemaker.*.h"
HEADERS[pe_rules]="include/crm/pengine/ru.*.h"
-HEADERS[pe_status]="include/crm/pengine/[^r].*.h include/crm/pengine/r[^u].*.h"
+HEADERS[pe_status]="include/crm/pengine/.*.h"
HEADERS[stonithd]="include/crm/stonith-ng.h include/crm/fencing/.*.h"
yesno() {
local RESPONSE
read -p "$1 " RESPONSE
case $(echo "$RESPONSE" | tr '[:upper:]' '[:lower:]') in
y|yes|ano|ja|si|oui) return 0 ;;
*) return 1 ;;
esac
}
prompt_to_continue() {
yesno "Continue?" || exit 0
}
sed_in_place() {
cp -p "$1" "$1.$$"
sed -e "$2" "$1" > "$1.$$"
mv "$1.$$" "$1"
}
find_last_release() {
if [ -n "$1" ]; then
echo "$1"
else
git tag -l | grep Pacemaker | grep -v rc | sort -Vr | head -n 1
fi
}
find_libs() {
find lib -name "*.am" -exec grep "lib.*_la_LDFLAGS.*version-info" \{\} \; \
| sed -e 's/lib\(.*\)_la_LDFLAGS.*/\1/'
}
find_makefile() {
find lib -name Makefile.am -exec grep -l "lib${1}_la.*version-info" \{\} \;
}
find_sources() {
local LIB="$1"
local AMFILE="$2"
local SOURCES
# Library makefiles should use "+=" to break up long sources lines rather
# than backslashed continuation lines, to allow this script to detect
# source files correctly. Warn if that's not the case.
if
grep "lib${LIB}_la_SOURCES.*\\\\" "$AMFILE"
then
echo -e "\033[1;35m -- Sources list for lib$LIB is probably truncated! --\033[0m"
echo "Edit to use '+=' rather than backslashed continuation lines"
prompt_to_continue
fi
SOURCES=$(grep "^lib${LIB}_la_SOURCES" "$AMFILE" \
| sed -e 's/.*=//' -e 's/\\//' -e 's:\.\./gnu/:lib/gnu/:')
for SOURCE in $SOURCES; do
if
echo "$SOURCE" | grep -q "/"
then
echo "$SOURCE"
else
echo "$(dirname "$AMFILE")/$SOURCE"
fi
done
}
find_headers_as_of() {
local TAG
local LIB
local FILE
local PATTERN
TAG="$1"
LIB="$2"
for FILE in $(git ls-tree -r --name-only "$TAG"); do
for PATTERN in ${HEADERS[$LIB]}; do
if [[ $FILE =~ $PATTERN ]] && [[ ! $FILE =~ internal.h$ ]]; then
echo "$FILE"
break
fi
done
done
}
extract_version() {
grep "lib${1}_la.*version-info" | sed -e 's/.*version-info\s*\(\S*\)/\1/'
}
shared_lib_name() {
local LIB="$1"
local VERSION="$2"
echo "lib${LIB}.so.$(echo "$VERSION" | cut -d: -f 1)"
}
process_lib() {
local LIB="$1"
local LAST_RELEASE="$2"
local AMFILE
local SOURCES
local HEADERS_LAST
local HEADERS_HEAD
local HEADERS_DIFF
local HEADERS_GONE
local HEADERS_ADDED
local CHANGE
local DEFAULT_CHANGE
if [ -z "${HEADERS[$LIB]}" ]; then
echo "Can't check lib$LIB until this script is updated with its headers"
prompt_to_continue
fi
AMFILE="$(find_makefile "$LIB")"
# Get current shared library version
VER_NOW=$(extract_version "$LIB" < "$AMFILE")
# Check whether library existed at last release
if ! git cat-file -e "$LAST_RELEASE:$AMFILE" 2>/dev/null; then
echo "lib$LIB is new, not changing version ($VER_NOW)"
prompt_to_continue
echo ""
return
fi
HEADERS_LAST="$(find_headers_as_of "$LAST_RELEASE" "$LIB")"
HEADERS_HEAD="$(find_headers_as_of "HEAD" "$LIB")"
HEADERS_DIFF="$(diff <(echo "$HEADERS_LAST") <(echo "$HEADERS_HEAD"))"
HEADERS_GONE="$(echo "$HEADERS_DIFF" | sed -n -e 's/^< //p')"
HEADERS_ADDED="$(echo "$HEADERS_DIFF" | sed -n -e 's/^> //p')"
# Check whether there were any changes to headers or sources
SOURCES="$(find_sources "$LIB" "$AMFILE")"
if [ -n "$HEADERS_GONE" ]; then
DEFAULT_CHANGE="i" # Removed public header is incompatible change
elif [ -n "$HEADERS_ADDED" ]; then
DEFAULT_CHANGE="c" # Additions are likely compatible
elif git diff --quiet -w "$LAST_RELEASE..HEAD" $HEADERS_HEAD $SOURCES ; then
echo "No changes to $LIB interface"
prompt_to_continue
echo ""
return
else
DEFAULT_CHANGE="f" # Sources changed, so it's at least a fix
fi
# Show all header changes since last release
echo "- Changes in lib$LIB public headers since $LAST_RELEASE:"
if [ -n "$HEADERS_GONE" ]; then
for HEADER in $HEADERS_GONE; do
echo "-- $HEADER was removed"
done
fi
if [ -n "$HEADERS_ADDED" ]; then
for HEADER in $HEADERS_ADDED; do
echo "++ $HEADER is new"
done
fi
git --no-pager diff --color -w "$LAST_RELEASE..HEAD" $HEADERS_HEAD
echo ""
if yesno "Show commits (minus refactor/build/merge) touching lib$LIB since $LAST_RELEASE [y/N]?"
then
git log --color "$LAST_RELEASE..HEAD" -z $HEADERS_HEAD $SOURCES "$AMFILE" \
| grep -vzE "Refactor:|Build:|Merge pull request"
echo
prompt_to_continue
fi
# @TODO this seems broken ...
#echo ""
#if yesno "Show merged PRs touching lib$LIB since $LAST_RELEASE [y/N]?"
#then
# git log --merges $LAST_RELEASE..HEAD $HEADERS_HEAD $SOURCES $AMFILE
# echo
# prompt_to_continue
#fi
# Show summary of source changes since last release
echo ""
echo "- Headers: $HEADERS_HEAD"
echo "- Changed sources since $LAST_RELEASE:"
git --no-pager diff --color -w "$LAST_RELEASE..HEAD" --stat $SOURCES
echo ""
# Ask for human guidance
echo "Are the changes to lib$LIB:"
read -p "[c]ompatible additions, [i]ncompatible additions/removals or [f]ixes? [$DEFAULT_CHANGE]: " CHANGE
[ -z "$CHANGE" ] && CHANGE="$DEFAULT_CHANGE"
# Get (and show) shared library version at last release
VER=$(git show "$LAST_RELEASE:$AMFILE" | extract_version "$LIB")
VER_1=$(echo "$VER" | awk -F: '{print $1}')
VER_2=$(echo "$VER" | awk -F: '{print $2}')
VER_3=$(echo "$VER" | awk -F: '{print $3}')
echo "lib$LIB version at $LAST_RELEASE: $VER"
# Show current shared library version if changed
if [ "$VER_NOW" != "$VER" ]; then
echo "lib$LIB version currently: $VER_NOW"
fi
# Calculate new library version
case $CHANGE in
i|I)
echo "New backwards-incompatible version: x+1:0:0"
(( VER_1++ ))
VER_2=0
VER_3=0
# Some headers define constants for shared library names,
# update them if the name changed
for H in $HEADERS_HEAD; do
sed_in_place "$H" "s/$(shared_lib_name "$LIB" "$VER_NOW")/$(shared_lib_name "$LIB" "$VER_1:0:0")/"
done
;;
c|C)
echo "New version with backwards-compatible extensions: x+1:0:z+1"
(( VER_1++ ))
VER_2=0
(( VER_3++ ))
;;
F|f)
echo "Code changed though interfaces didn't: x:y+1:z"
(( VER_2++ ))
;;
*)
echo "Not updating lib$LIB version"
prompt_to_continue
CHANGE=""
;;
esac
VER_NEW=$VER_1:$VER_2:$VER_3
if [ -n "$CHANGE" ]; then
if [ "$VER_NEW" != "$VER_NOW" ]; then
echo "Updating lib$LIB version from $VER_NOW to $VER_NEW"
prompt_to_continue
sed_in_place "$AMFILE" "s/version-info\s*$VER_NOW/version-info $VER_NEW/"
else
echo "No version change needed for lib$LIB"
prompt_to_continue
fi
fi
echo ""
}
echo "Definitions:"
echo "- Compatible additions: new public API functions, structs, etc."
echo "- Incompatible additions/removals: new arguments to public API functions,"
echo " new members added to the middle of public API structs,"
echo " removal of any public API, etc."
echo "- Fixes: any other code changes at all"
echo ""
echo "When possible, improve backward compatibility first:"
echo "- move new members to the end of structs"
echo "- use bitfields instead of booleans"
echo "- when adding arguments, create a new function that the old one can wrap"
echo ""
prompt_to_continue
LAST_RELEASE=$(find_last_release "$1")
for LIB in $(find_libs); do
process_lib "$LIB" "$LAST_RELEASE"
done
# Show all proposed changes
git --no-pager diff --color -w
diff --git a/po/zh_CN.po b/po/zh_CN.po
index 9434210056..c2d8ab5c0f 100644
--- a/po/zh_CN.po
+++ b/po/zh_CN.po
@@ -1,1452 +1,1462 @@
#
# Copyright 2003-2024 the Pacemaker project contributors
#
# The version control history for this file may have further details.
#
# This source code is licensed under the GNU Lesser General Public License
# version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: Pacemaker 2\n"
"Report-Msgid-Bugs-To: developers@clusterlabs.org\n"
-"POT-Creation-Date: 2024-05-22 09:04-0500\n"
+"POT-Creation-Date: 2024-11-14 10:45-0600\n"
"PO-Revision-Date: 2021-11-08 11:04+0800\n"
"Last-Translator: Vivi \n"
"Language-Team: CHINESE \n"
"Language: zh_CN\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-#: daemons/fenced/pacemaker-fenced.c:498
+#: daemons/fenced/pacemaker-fenced.c:492
msgid "Instance attributes available for all \"stonith\"-class resources"
msgstr " 可用于所有stonith类资源的实例属性"
-#: daemons/fenced/pacemaker-fenced.c:500
+#: daemons/fenced/pacemaker-fenced.c:494
+#, fuzzy
msgid ""
"Instance attributes available for all \"stonith\"-class resources and used "
-"by Pacemaker's fence daemon, formerly known as stonithd"
+"by Pacemaker's fence daemon"
msgstr ""
" 可用于所有stonith类资源的实例属性,并由Pacemaker的fence守护程序使用(以前称"
"为stonithd)"
-#: daemons/fenced/pacemaker-fenced.c:511
-msgid "Deprecated (will be removed in a future release)"
-msgstr "已弃用(将在未来版本中删除)"
-
-#: daemons/fenced/pacemaker-fenced.c:514
+#: daemons/fenced/pacemaker-fenced.c:504
msgid "Intended for use in regression testing only"
msgstr "仅适用于回归测试"
-#: daemons/fenced/pacemaker-fenced.c:517
+#: daemons/fenced/pacemaker-fenced.c:508
msgid "Send logs to the additional named logfile"
msgstr "将日志发送到其他命名日志文件"
-#: lib/common/options.c:57
+#: lib/common/options.c:53
msgid "Pacemaker version on cluster node elected Designated Controller (DC)"
msgstr "集群选定的控制器节点(DC)的 Pacemaker 版本"
-#: lib/common/options.c:59
+#: lib/common/options.c:55
#, fuzzy
msgid ""
"Includes a hash which identifies the exact revision the code was built from. "
"Used for diagnostic purposes."
msgstr "它包含一个标识所构建代码修订版本的哈希值. 其可用于诊断."
-#: lib/common/options.c:66
+#: lib/common/options.c:62
#, fuzzy
msgid "The messaging layer on which Pacemaker is currently running"
msgstr "Pacemaker 当前运行的消息传递层"
-#: lib/common/options.c:67
+#: lib/common/options.c:63
msgid "Used for informational and diagnostic purposes."
msgstr "用于提供信息和诊断."
-#: lib/common/options.c:73
+#: lib/common/options.c:69
msgid "An arbitrary name for the cluster"
msgstr "任意的集群名称"
-#: lib/common/options.c:74
+#: lib/common/options.c:70
msgid ""
"This optional value is mostly for users' convenience as desired in "
"administration, but may also be used in Pacemaker configuration rules via "
"the #cluster-name node attribute, and by higher-level tools and resource "
"agents."
msgstr ""
"该可选值主要是为了方便用户根据管理的需要使用, 可以通过 #cluster-name 节点属性"
"在 Pacemaker 配置规则中使用, 以及被更高级的工具和资源代理使用."
-#: lib/common/options.c:83
+#: lib/common/options.c:79
msgid "How long to wait for a response from other nodes during start-up"
msgstr "启动过程中等待其他节点响应的时间"
-#: lib/common/options.c:84
+#: lib/common/options.c:80
msgid ""
"The optimal value will depend on the speed and load of your network and the "
"type of switches used."
msgstr "其最佳值将取决于您的网络速度和负载以及使用的交换机类型."
-#: lib/common/options.c:91
+#: lib/common/options.c:87
msgid ""
"Polling interval to recheck cluster state and evaluate rules with date "
"specifications"
msgstr "重新检查集群状态及评估日期规范规则的轮询间隔"
-#: lib/common/options.c:93
+#: lib/common/options.c:89
#, fuzzy
msgid ""
"Pacemaker is primarily event-driven, and looks ahead to know when to recheck "
"cluster state for failure-timeout settings and most time-based rules. "
"However, it will also recheck the cluster after this amount of inactivity, "
"to evaluate rules with date specifications and serve as a fail-safe for "
"certain types of scheduler bugs. A value of 0 disables polling. A positive "
"value sets an interval in seconds, unless other units are specified (for "
"example, \"5min\")."
msgstr ""
"Pacemaker 主要是通过事件驱动的, 并会提前预测何时重新检查集群状态以评估大多数"
"基于时间的规则以及 failure-timeout 配置, 然而无论如何, 经过指定的时间后如果没"
"有活动, 它将重新检查集群, 以评估具有日期规范的规则, 并为某些类型的调度程序缺"
"陷提供故障保护. 如果值为0, 将禁用轮询. 如果值为正数, 则设置以秒为单位的时间间"
"隔, 除非指定了其它单位 (例如, \"5min\")."
-#: lib/common/options.c:107
+#: lib/common/options.c:103
msgid "How a cluster node should react if notified of its own fencing"
msgstr "集群节点在收到针对自己的 fence 操作结果通知时应如何反应"
-#: lib/common/options.c:108
+#: lib/common/options.c:104
#, fuzzy
msgid ""
"A cluster node may receive notification of a \"succeeded\" fencing that "
"targeted it if fencing is misconfigured, or if fabric fencing is in use that "
"doesn't cut cluster communication. Use \"stop\" to attempt to immediately "
"stop Pacemaker and stay stopped, or \"panic\" to attempt to immediately "
"reboot the local node, falling back to stop on failure."
msgstr ""
"如果有错误的 fence 配置, 或者在使用 fabric fence 机制 (并不会切断集群通信), "
"则集群节点可能会收到针对自己的 \"succeeded\" fence 结果通知. 使用 \"stop\" 尝"
"试立即停止 pacemaker 并保持停止状态,或者使用 \"panic\" 尝试立即重新启动本地节"
"点,如果失败则返回执行 stop."
-#: lib/common/options.c:119
+#: lib/common/options.c:115
msgid ""
"Declare an election failed if it is not decided within this much time. If "
"you need to adjust this value, it probably indicates the presence of a bug."
msgstr ""
"如果集群在本项设置时间内没有作出决定则宣布选举失败. 这可能表明当前存在错误, "
"您需要调整该值."
-#: lib/common/options.c:128
+#: lib/common/options.c:124
msgid ""
"Exit immediately if shutdown does not complete within this much time. If you "
"need to adjust this value, it probably indicates the presence of a bug."
msgstr ""
"如果在这段时间内关机仍未完成, pacemaker 将立即退出. 这可能表明当前存在错误, "
"您需要调整该值."
-#: lib/common/options.c:138 lib/common/options.c:147
+#: lib/common/options.c:133 lib/common/options.c:141
msgid ""
"If you need to adjust this value, it probably indicates the presence of a "
"bug."
msgstr "这可能表明当前存在错误, 您需要调整该值."
-#: lib/common/options.c:156
+#: lib/common/options.c:149
#, fuzzy
msgid ""
"Enabling this option will slow down cluster recovery under all conditions"
msgstr "启用此选项将在所有情况下减慢集群恢复的速度"
-#: lib/common/options.c:158
+#: lib/common/options.c:151
msgid ""
"Delay cluster recovery for this much time to allow for additional events to "
"occur. Useful if your configuration is sensitive to the order in which ping "
"updates arrive."
msgstr ""
"集群恢复将被推迟指定的时间间隔, 以等待更多事件发生. 如果您的配置对 ping 更新"
"到达的顺序很敏感, 则可以使用此选项."
-#: lib/common/options.c:168
+#: lib/common/options.c:162
msgid "What to do when the cluster does not have quorum"
msgstr "当集群没有达到必需票数时该如何做"
-#: lib/common/options.c:175
+#: lib/common/options.c:169
msgid "Whether to lock resources to a cleanly shut down node"
msgstr "是否锁定资源到完全关闭的节点"
-#: lib/common/options.c:176
+#: lib/common/options.c:170
msgid ""
"When true, resources active on a node when it is cleanly shut down are kept "
"\"locked\" to that node (not allowed to run elsewhere) until they start "
"again on that node after it rejoins (or for at most shutdown-lock-limit, if "
"set). Stonith resources and Pacemaker Remote connections are never locked. "
"Clone and bundle instances and the promoted role of promotable clones are "
"currently never locked, though support could be added in a future release."
msgstr ""
"设置为 true 时, 在完全关闭的节点上活动的资源将被 \"locked\" 到该节点 (不允许"
"在其它方运行), 直到该节点重新加入后它们再次在该节点上启动 (最长为 shutdown-"
"lock-limit,如果已设置). Stonith 资源和 Pacemaker Remote 连接永远不会被锁定. "
"克隆和捆绑实例以及可提升克隆的提升角色目前不会被锁定, 尽管可能在未来的发行版"
"中添加支持. "
-#: lib/common/options.c:189
+#: lib/common/options.c:183
msgid "Do not lock resources to a cleanly shut down node longer than this"
msgstr "资源会被锁定到完全关闭的节点的最长时间"
-#: lib/common/options.c:191
+#: lib/common/options.c:185
msgid ""
"If shutdown-lock is true and this is set to a nonzero time duration, "
"shutdown locks will expire after this much time has passed since the "
"shutdown was initiated, even if the node has not rejoined."
msgstr ""
"如果 shutdown-lock 为 true, 并且将此选项设置为非零时间间隔, 则自关闭操作执行"
"经过此时间后,shutdown lock 将过期, 即使该节点尚未重新加入也是如此. "
-#: lib/common/options.c:200
+#: lib/common/options.c:194
msgid "Enable Access Control Lists (ACLs) for the CIB"
msgstr "为 CIB 启用访问控制列表 (ACL) "
-#: lib/common/options.c:207
+#: lib/common/options.c:201
msgid "Whether resources can run on any node by default"
msgstr "默认情况下资源是否可以在任何节点上运行"
-#: lib/common/options.c:214
+#: lib/common/options.c:208
msgid ""
"Whether the cluster should refrain from monitoring, starting, and stopping "
"resources"
msgstr "集群是否应避免监视, 启动和停止资源"
-#: lib/common/options.c:222
+#: lib/common/options.c:216
msgid ""
"Whether a start failure should prevent a resource from being recovered on "
"the same node"
msgstr "资源启动失败是否应阻止在同一节点上恢复该资源"
-#: lib/common/options.c:224
+#: lib/common/options.c:218
msgid ""
"When true, the cluster will immediately ban a resource from a node if it "
"fails to start there. When false, the cluster will instead check the "
"resource's fail count against its migration-threshold."
msgstr ""
"当为true, 如果资源启动失败, 集群将立即禁止节点启动该资源, 当为false, 集群将检"
"查资源的失败次数是否超过了其 migration-threshold. "
-#: lib/common/options.c:232
+#: lib/common/options.c:226
msgid "Whether the cluster should check for active resources during start-up"
msgstr "集群是否在启动期间检查活动的资源"
-#: lib/common/options.c:242
+#: lib/common/options.c:236
#, fuzzy
msgid "Whether nodes may be fenced as part of recovery"
msgstr "节点是否可以被 fence 作为集群恢复的一部分"
-#: lib/common/options.c:243
+#: lib/common/options.c:237
msgid ""
"If false, unresponsive nodes are immediately assumed to be harmless, and "
"resources that were active on them may be recovered elsewhere. This can "
"result in a \"split-brain\" situation, potentially leading to data loss and/"
"or service unavailability."
msgstr ""
"如果为 false, 则立即假定无响应的节点是无害的, 并且可以在其它位置恢复在其上活"
"动的资源. 这可能会导致 \"split-brain\" 情况, 从而可能导致数据丢失和(或)服务不"
"可用. "
-#: lib/common/options.c:253
-msgid ""
-"Action to send to fence device when a node needs to be fenced (\"poweroff\" "
-"is a deprecated alias for \"off\")"
+#: lib/common/options.c:247
+#, fuzzy
+msgid "Action to send to fence device when a node needs to be fenced"
msgstr ""
"当节点需要被 fence 时, 向 fence 设备发送的操作 (\"poweroff\" 作为 \"off\" 的"
"别名已被弃用)"
-#: lib/common/options.c:261
+#: lib/common/options.c:254
msgid ""
"How long to wait for on, off, and reboot fence actions to complete by default"
msgstr "默认情况下, 等待 on, off, 和 reboot fence 操作完成的时间"
-#: lib/common/options.c:269
+#: lib/common/options.c:262
msgid "Whether watchdog integration is enabled"
msgstr "是否启用 watchdog 集成设置"
-#: lib/common/options.c:270
+#: lib/common/options.c:263
msgid ""
"This is set automatically by the cluster according to whether SBD is "
"detected to be in use. User-configured values are ignored. The value `true` "
"is meaningful if diskless SBD is used and `stonith-watchdog-timeout` is "
"nonzero. In that case, if fencing is required, watchdog-based self-fencing "
"will be performed via SBD without requiring a fencing resource explicitly "
"configured."
msgstr ""
"集群会根据是否检测到 SBD 正在使用来自动设置此值. 用户配置的值将被忽略. 如果使"
"用了无盘 SBD 并且 `stonith-watchdog-timeout` 不为零, 则值 `true` 才有实际意"
"义. 在这种情况下, 如果需要fence, 将通过 SBD 执行基于 watchdog 的自我 fence, "
"而不需要明确配置 fence 资源."
-#: lib/common/options.c:291
+#: lib/common/options.c:284
#, fuzzy
msgid ""
"How long before nodes can be assumed to be safely down when watchdog-based "
"self-fencing via SBD is in use"
msgstr ""
"当基于 watchdog 的自我 fence 机制通过SBD 被执行时, 节点被认为安全下线的等待时"
"间有多长"
-#: lib/common/options.c:293
+#: lib/common/options.c:286
#, fuzzy
msgid ""
"If this is set to a positive value, lost nodes are assumed to achieve self-"
"fencing using watchdog-based SBD within this much time. This does not "
"require a fencing resource to be explicitly configured, though a "
"fence_watchdog resource can be configured, to limit use to specific nodes. "
"If this is set to 0 (the default), the cluster will never assume watchdog-"
"based self-fencing. If this is set to a negative value, the cluster will use "
"twice the local value of the `SBD_WATCHDOG_TIMEOUT` environment variable if "
"that is positive, or otherwise treat this as 0. WARNING: When used, this "
"timeout must be larger than `SBD_WATCHDOG_TIMEOUT` on all nodes that use "
"watchdog-based SBD, and Pacemaker will refuse to start on any of those nodes "
"where this is not true for the local value or SBD is not active. When this "
"is set to a negative value, `SBD_WATCHDOG_TIMEOUT` must be set to the same "
"value on all nodes that use SBD, otherwise data corruption or loss could "
"occur."
msgstr ""
"如果设为正值, 丢失的节点将在设定的时间内被认定使用基于 watchdog 的 SBD 完成自"
"我 fence. 这不需要明确配置一个 fence 资源, 但可以配置一个 fence_watchdog 资源"
"来限制对特定节点使用. 如果设为0 (默认值), 集群将永远不会认定节点使用基于 "
"watchdog 的自我 fence. 如果设为负值, 集群将使用本地 `SBD_WATCHDOG_TIMEOUT` 环"
"境变量的两倍值(如果该值为正), 否则会将该值视为0. 警告: 在所有使用基于 "
"watchdog 的 SBD 的节点上, 此超时值需大于 `SBD_WATCHDOG_TIMEOUT` 的值, 否则 "
"Pacemaker 不会在任何不符合此条件的节点上启动, 也不会在任何未启用 SBD 的节点上"
"启动. 当设为负值时所有使用 SBD 的节点上 `SBD_WATCHDOG_TIMEOUT` 的值必须设置为"
"相同的值, 否则可能导致数据损坏或丢失."
-#: lib/common/options.c:313
+#: lib/common/options.c:306
msgid ""
"How many times fencing can fail before it will no longer be immediately re-"
"attempted on a target"
msgstr "fence 操作失败多少次会停止立即尝试"
-#: lib/common/options.c:321
+#: lib/common/options.c:319
msgid "Allow performing fencing operations in parallel"
msgstr "允许并行执行 fencing 操作"
-#: lib/common/options.c:328
+#: lib/common/options.c:326
#, fuzzy
msgid "Whether to fence unseen nodes at start-up"
msgstr "*** 仅高级使用 *** 是否在启动时fence不可见节点"
-#: lib/common/options.c:329
+#: lib/common/options.c:327
#, fuzzy
msgid ""
"Setting this to false may lead to a \"split-brain\" situation, potentially "
"leading to data loss and/or service unavailability."
msgstr ""
"将此设置为 false 可能会导致 \"split-brain\" 的情况,可能导致数据丢失和(或)服"
"务不可用。"
-#: lib/common/options.c:336
+#: lib/common/options.c:334
msgid ""
"Apply fencing delay targeting the lost nodes with the highest total resource "
"priority"
msgstr "针对具有最高总资源优先级的丢失节点应用fencing延迟"
-#: lib/common/options.c:338
+#: lib/common/options.c:336
msgid ""
"Apply specified delay for the fencings that are targeting the lost nodes "
"with the highest total resource priority in case we don't have the majority "
"of the nodes in our cluster partition, so that the more significant nodes "
"potentially win any fencing match, which is especially meaningful under "
"split-brain of 2-node cluster. A promoted resource instance takes the base "
"priority + 1 on calculation if the base priority is not 0. Any static/random "
"delays that are introduced by `pcmk_delay_base/max` configured for the "
"corresponding fencing resources will be added to this delay. This delay "
"should be significantly greater than, safely twice, the maximum "
"`pcmk_delay_base/max`. By default, priority fencing delay is disabled."
msgstr ""
"如果我们所在的集群分区并不拥有大多数集群节点,则针对丢失节点的fence操作应用指"
"定的延迟,这样更重要的节点就能够赢得fence竞赛。这对于双节点集群在split-brain"
"状况下尤其有意义。如果基本优先级不为0,在计算时主资源实例获得基本优先级+1。任"
"何对于相应的 fence 资源由 pcmk_delay_base/max 配置所引入的静态/随机延迟会被添"
"加到此延迟。为了安全, 这个延迟应该明显大于 pcmk_delay_base/max 的最大设置值,"
"例如两倍。默认情况下,优先级fencing延迟已禁用。"
-#: lib/common/options.c:355
+#: lib/common/options.c:353
msgid ""
"How long to wait for a node that has joined the cluster to join the "
"controller process group"
msgstr "等待已加入集群的节点加入控制器进程组的时间"
-#: lib/common/options.c:357
+#: lib/common/options.c:355
msgid ""
"Fence nodes that do not join the controller process group within this much "
"time after joining the cluster, to allow the cluster to continue managing "
"resources. A value of 0 means never fence pending nodes. Setting the value "
"to 2h means fence nodes after 2 hours."
msgstr ""
"如果节点加入集群后在此时间内不加入控制器进程组,Fence该节点,以便群集继续管理"
"资源。值为0表示永远不 fence 待定节点。将值设置为2h表示2小时后 fence 待定节"
"点。"
-#: lib/common/options.c:367
+#: lib/common/options.c:365
msgid "Maximum time for node-to-node communication"
msgstr "最大节点间通信时间"
-#: lib/common/options.c:368
+#: lib/common/options.c:366
msgid ""
"The node elected Designated Controller (DC) will consider an action failed "
"if it does not get a response from the node executing the action within this "
"time (after considering the action's own timeout). The \"correct\" value "
"will depend on the speed and load of your network and cluster nodes."
msgstr ""
"如果一个操作未在该时间内(并且考虑操作本身的超时时长)从执行该操作的节点获得"
"响应,则会被选为指定控制器(DC)的节点认定为失败。\"正确\" 值将取决于速度和您"
"的网络和集群节点的负载。"
-#: lib/common/options.c:380
+#: lib/common/options.c:378
msgid "Maximum amount of system load that should be used by cluster nodes"
msgstr "集群节点应该使用的最大系统负载量"
-#: lib/common/options.c:382
+#: lib/common/options.c:380
msgid ""
"The cluster will slow down its recovery process when the amount of system "
"resources used (currently CPU) approaches this limit"
msgstr "当使用的系统资源量(当前指 CPU)接近此限制时, 集群将减慢其恢复过程"
-#: lib/common/options.c:389
+#: lib/common/options.c:387
msgid ""
"Maximum number of jobs that can be scheduled per node (defaults to 2x cores)"
msgstr "每个节点可以调度的最大作业数(默认为2x内核数)"
-#: lib/common/options.c:397
+#: lib/common/options.c:395
#, fuzzy
msgid ""
"Maximum number of jobs that the cluster may execute in parallel across all "
"nodes"
msgstr "集群可以在所有节点上并发执行的最大作业数"
-#: lib/common/options.c:399
+#: lib/common/options.c:397
msgid ""
"The \"correct\" value will depend on the speed and load of your network and "
"cluster nodes. If set to 0, the cluster will impose a dynamically calculated "
"limit when any node has a high load."
msgstr ""
"\"正确\" 值将取决于速度和您的网络与集群节点的负载。如果设置为0,当任何节点具"
"有高负载时,集群将施加一个动态计算的限制。"
-#: lib/common/options.c:408
+#: lib/common/options.c:406
msgid ""
"The number of live migration actions that the cluster is allowed to execute "
"in parallel on a node (-1 means no limit)"
msgstr "允许集群在一个节点上并行执行的实时迁移操作的数量(-1表示没有限制)"
-#: lib/common/options.c:427
+#: lib/common/options.c:425
msgid "Maximum IPC message backlog before disconnecting a cluster daemon"
msgstr "断开集群守护程序之前的最大IPC消息积压"
-#: lib/common/options.c:428
+#: lib/common/options.c:426
msgid ""
"Raise this if log has \"Evicting client\" messages for cluster daemon PIDs "
"(a good value is the number of resources in the cluster multiplied by the "
"number of nodes)."
msgstr ""
"如果日志中有针对集群守护程序PID的消息“Evicting client”,(则建议将值设为集群"
"中的资源数量乘以节点数量)"
-#: lib/common/options.c:438
+#: lib/common/options.c:436
#, fuzzy
msgid "Whether the cluster should stop all active resources"
msgstr "集群是否在启动期间检查运行资源"
-#: lib/common/options.c:445
+#: lib/common/options.c:443
msgid "Whether to stop resources that were removed from the configuration"
msgstr "是否停止配置已被删除的资源"
-#: lib/common/options.c:453
+#: lib/common/options.c:451
msgid "Whether to cancel recurring actions removed from the configuration"
msgstr "是否取消配置已被删除的的重复操作"
#: lib/common/options.c:461
-#, fuzzy
-msgid "Whether to remove stopped resources from the executor"
-msgstr "是否从pacemaker-execd 守护进程中清除已停止的资源"
-
-#: lib/common/options.c:462
-#, fuzzy
-msgid "Values other than default are poorly tested and potentially dangerous."
-msgstr "非默认值未经过充分的测试,有潜在的风险。该选项将在未来的版本中删除。"
-
-#: lib/common/options.c:471
msgid "The number of scheduler inputs resulting in errors to save"
msgstr "保存导致错误的调度程序输入的数量"
-#: lib/common/options.c:472 lib/common/options.c:479 lib/common/options.c:486
+#: lib/common/options.c:462 lib/common/options.c:469 lib/common/options.c:476
msgid "Zero to disable, -1 to store unlimited."
msgstr "零表示禁用,-1表示存储不受限制。"
-#: lib/common/options.c:478
+#: lib/common/options.c:468
msgid "The number of scheduler inputs resulting in warnings to save"
msgstr "保存导致警告的调度程序输入的数量"
-#: lib/common/options.c:485
+#: lib/common/options.c:475
msgid "The number of scheduler inputs without errors or warnings to save"
msgstr "保存没有错误或警告的调度程序输入的数量"
-#: lib/common/options.c:497
+#: lib/common/options.c:487
#, fuzzy
msgid "How cluster should react to node health attributes"
msgstr "集群节点对节点健康属性如何反应"
-#: lib/common/options.c:498
+#: lib/common/options.c:488
msgid ""
"Requires external entities to create node attributes (named with the prefix "
"\"#health\") with values \"red\", \"yellow\", or \"green\"."
msgstr ""
"需要外部实体创建具有“red”,“yellow”或“green”值的节点属性(前缀为“#health”)"
-#: lib/common/options.c:506
+#: lib/common/options.c:496
msgid "Base health score assigned to a node"
msgstr "分配给节点的基本健康分数"
-#: lib/common/options.c:507
+#: lib/common/options.c:497
msgid "Only used when \"node-health-strategy\" is set to \"progressive\"."
msgstr "仅在“node-health-strategy”设置为“progressive”时使用。"
-#: lib/common/options.c:514
+#: lib/common/options.c:504
msgid "The score to use for a node health attribute whose value is \"green\""
msgstr "为节点健康属性值为“green”所使用的分数"
-#: lib/common/options.c:516 lib/common/options.c:525 lib/common/options.c:534
+#: lib/common/options.c:506 lib/common/options.c:515 lib/common/options.c:524
msgid ""
"Only used when \"node-health-strategy\" is set to \"custom\" or \"progressive"
"\"."
msgstr "仅在“node-health-strategy”设置为“custom”或“progressive”时使用。"
-#: lib/common/options.c:523
+#: lib/common/options.c:513
msgid "The score to use for a node health attribute whose value is \"yellow\""
msgstr "为节点健康属性值为“yellow”所使用的分数"
-#: lib/common/options.c:532
+#: lib/common/options.c:522
msgid "The score to use for a node health attribute whose value is \"red\""
msgstr "为节点健康属性值为“red”所使用的分数"
-#: lib/common/options.c:545
+#: lib/common/options.c:535
#, fuzzy
msgid "How the cluster should allocate resources to nodes"
msgstr "集群应该如何分配资源到节点"
-#: lib/common/options.c:563
-#, fuzzy
-msgid "An alternate parameter to supply instead of 'port'"
-msgstr "用于替代 'port' 的其它参数"
+#: lib/common/options.c:553
+msgid "Name of agent parameter that should be set to the fencing target"
+msgstr ""
-#: lib/common/options.c:564
-#, fuzzy
+#: lib/common/options.c:554
msgid ""
-"Some devices do not support the standard 'port' parameter or may provide "
-"additional ones. Use this to specify an alternate, device-specific, "
-"parameter that should indicate the machine to be fenced. A value of \"none\" "
-"can be used to tell the cluster not to supply any additional parameters."
+"If the fencing agent metadata advertises support for the \"port\" or \"plug"
+"\" parameter, that will be used as the default, otherwise \"none\" will be "
+"used, which tells the cluster not to supply any additional parameters."
msgstr ""
-"一些设备不支持标准的 'port' 参数, 或者可能会提供其它的参数. 使用此选项可指定"
-"一个替代的, 该设备专用的参数, 该参数应该指出需要 fence 的机器. 可以使用 "
-"\"none\" 值用于告诉集群不要提供任何其它的参数. "
-#: lib/common/options.c:574
+#: lib/common/options.c:563
#, fuzzy
msgid ""
"A mapping of node names to port numbers for devices that do not support node "
"names."
msgstr "为不支持主机名的设备提供主机名到端口号的映射. "
-#: lib/common/options.c:576
+#: lib/common/options.c:565
#, fuzzy
msgid ""
"For example, \"node1:1;node2:2,3\" would tell the cluster to use port 1 for "
"node1 and ports 2 and 3 for node2."
msgstr ""
"例如, \"node1:1;node2:2,3\" 将会告诉集群对node1使用端口1, 对node2使用端口2和"
"3."
-#: lib/common/options.c:583
+#: lib/common/options.c:572
msgid "Nodes targeted by this device"
msgstr "此设备针对的节点"
-#: lib/common/options.c:584
+#: lib/common/options.c:573
#, fuzzy
msgid ""
"Comma-separated list of nodes that can be targeted by this device (for "
"example, \"node1,node2,node3\"). If pcmk_host_check is \"static-list\", "
"either this or pcmk_host_map must be set."
msgstr ""
"此设备可以针对的节点列表,节点之间用逗号分隔(例如,node1,node2, node3).如果"
"pcmk_host_list=\"static-list\")"
-#: lib/common/options.c:594
+#: lib/common/options.c:583
#, fuzzy
msgid "How to determine which nodes can be targeted by the device"
msgstr "如何确定设备可以针对哪些节点"
-#: lib/common/options.c:595
+#: lib/common/options.c:584
#, fuzzy
msgid ""
"Use \"dynamic-list\" to query the device via the 'list' command; \"static-"
"list\" to check the pcmk_host_list attribute; \"status\" to query the device "
"via the 'status' command; or \"none\" to assume every device can fence every "
"node. The default value is \"static-list\" if pcmk_host_map or "
"pcmk_host_list is set; otherwise \"dynamic-list\" if the device supports the "
"list operation; otherwise \"status\" if the device supports the status "
"operation; otherwise \"none\""
msgstr ""
"选项值 \"dynamic-list\" 表示通过 'list' 命令查询设备; 选项值 \"static-list"
"\"表示检查 pcmk_host_list 属性; 选项值 \"status\" 表示通过 'status' 命令查询"
"设备; 或使用选项值 \"none\" 假设每个设备都可以 fence 所有节点. 如果"
"\"pcmk_host_map\"或\"pcmk_host_list\"被设置,默认值为\"static-list\";否则,"
"如果设备支持列表操作,则为\"dynamic-list\";如果设备支持状态操作,则为"
"\"status\";否则为\"none\""
-#: lib/common/options.c:608
+#: lib/common/options.c:597
msgid ""
"Enable a delay of no more than the time specified before executing fencing "
"actions."
msgstr "在执行 fence 操作前启用不超过指定时间的延迟"
-#: lib/common/options.c:610
+#: lib/common/options.c:599
msgid ""
"Enable a delay of no more than the time specified before executing fencing "
"actions. Pacemaker derives the overall delay by taking the value of "
"pcmk_delay_base and adding a random delay value such that the sum is kept "
"below this maximum."
msgstr ""
"在执行 fence 操作前启用不超过指定时间的延迟. Pacemaker通过获取 "
"pcmk_delay_base 的值并添加随机延迟值来得出总延迟, 并且确保总和不超过此最大值."
-#: lib/common/options.c:619
+#: lib/common/options.c:608
msgid "Enable a base delay for fencing actions and specify base delay value."
msgstr "为 fence 操作启用一个指定的基础延迟. "
-#: lib/common/options.c:621
+#: lib/common/options.c:610
#, fuzzy
msgid ""
"This enables a static delay for fencing actions, which can help avoid "
"\"death matches\" where two nodes try to fence each other at the same time. "
"If pcmk_delay_max is also used, a random delay will be added such that the "
"total delay is kept below that value. This can be set to a single time value "
"to apply to any node targeted by this device (useful if a separate device is "
"configured for each target), or to a node map (for example, \"node1:1s;"
"node2:5\") to set a different value for each target."
msgstr ""
"这为 fence 操作启用一个静态延迟, 这有助于避免 \"death matches\" 即两个节点同"
"时尝试互相 fence. 如果还同时使用了pcmk_delay_max, 则会添加一个随机延迟, 并确"
"保总延迟保持在该值以下. 可以将其设置为单个时间值, 以应用于该设备的所有目标节"
"点 (如果为每个目标节点都配置了单独的设备的情况下, 这很有用) 或设置成一个节点"
"映射形式 (例如,\"node1:1s;node2:5\") 从而为每个目标节点设置不同值. "
-#: lib/common/options.c:634
+#: lib/common/options.c:623
msgid ""
"The maximum number of actions can be performed in parallel on this device"
msgstr "可以在该设备上并发执行的最多操作数量"
-#: lib/common/options.c:636
+#: lib/common/options.c:625
#, fuzzy
msgid ""
-"Cluster property concurrent-fencing=\"true\" needs to be configured first. "
-"Then use this to specify the maximum number of actions can be performed in "
-"parallel on this device. A value of -1 means an unlimited number of actions "
-"can be performed in parallel."
+"If the concurrent-fencing cluster property is \"true\", this specifies the "
+"maximum number of actions that can be performed in parallel on this device. "
+"A value of -1 means unlimited."
msgstr ""
"需要先配置集群属性 concurrent-fencing=\"true\". 然后使用此参数指定可以在该设"
"备上并发执行的最多操作数量. -1 表示可以并行执行无限数量的操作. "
-#: lib/common/options.c:646
+#: lib/common/options.c:633
#, fuzzy
msgid "An alternate command to run instead of 'reboot'"
msgstr "运行替代命令,而不是'reboot'"
-#: lib/common/options.c:647
+#: lib/common/options.c:634
#, fuzzy
msgid ""
"Some devices do not support the standard commands or may provide additional "
"ones. Use this to specify an alternate, device-specific, command that "
"implements the 'reboot' action."
msgstr ""
"一些设备不支持标准命令或可能提供其他命令,使用此选项可以指定一个该设备特定的"
"替代命令,用来实现'reboot'操作。"
-#: lib/common/options.c:655
+#: lib/common/options.c:642
#, fuzzy
msgid ""
"Specify an alternate timeout to use for 'reboot' actions instead of stonith-"
"timeout"
msgstr "指定用于'reboot' 操作的替代超时,而不是stonith-timeout"
-#: lib/common/options.c:657
+#: lib/common/options.c:644
#, fuzzy
msgid ""
"Some devices need much more/less time to complete than normal. Use this to "
"specify an alternate, device-specific, timeout for 'reboot' actions."
msgstr ""
"一些设备需要比正常情况下更多或更少的时间来完成操作,使用此选项指定一个用"
"于'reboot'操作的该设备特定的替代超时。"
-#: lib/common/options.c:665
+#: lib/common/options.c:652
#, fuzzy
msgid ""
"The maximum number of times to try the 'reboot' command within the timeout "
"period"
msgstr "在超时前重试'reboot'命令的最大次数"
-#: lib/common/options.c:667
+#: lib/common/options.c:654
#, fuzzy
msgid ""
"Some devices do not support multiple connections. Operations may \"fail\" if "
"the device is busy with another task. In that case, Pacemaker will "
"automatically retry the operation if there is time remaining. Use this "
"option to alter the number of times Pacemaker tries a 'reboot' action before "
"giving up."
msgstr ""
"一些设备不支持多个连接。 如果设备忙于另一个任务,则操作可能会'失败' ,因此"
"Pacemaker将自动重试(如果时间允许)。 使用此选项更改Pacemaker在放弃之前重"
"试'reboot' 操作的次数."
-#: lib/common/options.c:677
+#: lib/common/options.c:664
#, fuzzy
msgid "An alternate command to run instead of 'off'"
msgstr "运行替代命令,而不是'off'"
-#: lib/common/options.c:678
+#: lib/common/options.c:665
#, fuzzy
msgid ""
"Some devices do not support the standard commands or may provide additional "
"ones. Use this to specify an alternate, device-specific, command that "
"implements the 'off' action."
msgstr ""
"一些设备不支持标准命令或可能提供其他命令,使用此选项可指定一个该设备专用的替代"
"命令,用来实现'off'操作。"
-#: lib/common/options.c:686
+#: lib/common/options.c:673
#, fuzzy
msgid ""
"Specify an alternate timeout to use for 'off' actions instead of stonith-"
"timeout"
msgstr "指定用于off 操作的替代超时,而不是stonith-timeout"
-#: lib/common/options.c:688
+#: lib/common/options.c:675
#, fuzzy
msgid ""
"Some devices need much more/less time to complete than normal. Use this to "
"specify an alternate, device-specific, timeout for 'off' actions."
msgstr ""
"一些设备需要比正常情况下更多或更少的时间来完成操作,使用此选项指定一个用"
"于'off'操作的该设备特定的替代超时。"
-#: lib/common/options.c:696
+#: lib/common/options.c:683
#, fuzzy
msgid ""
"The maximum number of times to try the 'off' command within the timeout "
"period"
msgstr "在超时前重试'off'命令的最大次数"
-#: lib/common/options.c:698
+#: lib/common/options.c:685
#, fuzzy
msgid ""
"Some devices do not support multiple connections. Operations may \"fail\" if "
"the device is busy with another task. In that case, Pacemaker will "
"automatically retry the operation if there is time remaining. Use this "
"option to alter the number of times Pacemaker tries a 'off' action before "
"giving up."
msgstr ""
" 一些设备不支持多个连接。 如果设备忙于另一个任务,则操作可能会'失败' , 因此"
"Pacemaker将自动重试(如果时间允许)。 使用此选项更改Pacemaker在放弃之前重"
"试'off' 操作的次数."
-#: lib/common/options.c:708
+#: lib/common/options.c:695
#, fuzzy
msgid "An alternate command to run instead of 'on'"
msgstr "仅高级使用:运行替代命令,而不是'on'"
-#: lib/common/options.c:709
+#: lib/common/options.c:696
#, fuzzy
msgid ""
"Some devices do not support the standard commands or may provide additional "
"ones. Use this to specify an alternate, device-specific, command that "
"implements the 'on' action."
msgstr ""
"一些设备不支持标准命令或可能提供其他命令,使用此选项可指定一个该设备特定的替"
"代命令,用来实现'on'操作。"
-#: lib/common/options.c:717
+#: lib/common/options.c:704
#, fuzzy
msgid ""
"Specify an alternate timeout to use for 'on' actions instead of stonith-"
"timeout"
msgstr "指定用于on 操作的替代超时,而不是stonith-timeout"
-#: lib/common/options.c:719
+#: lib/common/options.c:706
#, fuzzy
msgid ""
"Some devices need much more/less time to complete than normal. Use this to "
"specify an alternate, device-specific, timeout for 'on' actions."
msgstr ""
"一些设备需要比正常情况下更多或更少的时间来完成操作,使用此选项指定一个用"
"于'on'操作的该设备特定的替代超时。"
-#: lib/common/options.c:727
+#: lib/common/options.c:714
#, fuzzy
msgid ""
"The maximum number of times to try the 'on' command within the timeout period"
msgstr "在超时前重试'on'命令的最大次数"
-#: lib/common/options.c:729
+#: lib/common/options.c:716
#, fuzzy
msgid ""
"Some devices do not support multiple connections. Operations may \"fail\" if "
"the device is busy with another task. In that case, Pacemaker will "
"automatically retry the operation if there is time remaining. Use this "
"option to alter the number of times Pacemaker tries a 'on' action before "
"giving up."
msgstr ""
" 一些设备不支持多个连接。 如果设备忙于另一个任务,则操作可能会'失败' , 因此"
"Pacemaker将自动重试(如果时间允许)。 使用此选项更改Pacemaker在放弃之前重"
"试'on' 操作的次数."
-#: lib/common/options.c:739
+#: lib/common/options.c:726
#, fuzzy
msgid "An alternate command to run instead of 'list'"
msgstr "运行替代命令,而不是'list'"
-#: lib/common/options.c:740
+#: lib/common/options.c:727
#, fuzzy
msgid ""
"Some devices do not support the standard commands or may provide additional "
"ones. Use this to specify an alternate, device-specific, command that "
"implements the 'list' action."
msgstr ""
"一些设备不支持标准命令或可能提供其他命令,使用此选项可指定一个该设备特定的替"
"代命令,用来实现'list'操作。"
-#: lib/common/options.c:748
+#: lib/common/options.c:735
#, fuzzy
msgid ""
"Specify an alternate timeout to use for 'list' actions instead of stonith-"
"timeout"
msgstr "指定用于list 操作的替代超时,而不是stonith-timeout"
-#: lib/common/options.c:750
+#: lib/common/options.c:737
#, fuzzy
msgid ""
"Some devices need much more/less time to complete than normal. Use this to "
"specify an alternate, device-specific, timeout for 'list' actions."
msgstr ""
"一些设备需要比正常情况下更多或更少的时间来完成操作,使用此选项指定一个用"
"于'list'操作的该设备特定的替代超时。"
-#: lib/common/options.c:758
+#: lib/common/options.c:745
#, fuzzy
msgid ""
"The maximum number of times to try the 'list' command within the timeout "
"period"
msgstr "在超时前重试'list'命令的最大次数"
-#: lib/common/options.c:760
+#: lib/common/options.c:747
#, fuzzy
msgid ""
"Some devices do not support multiple connections. Operations may \"fail\" if "
"the device is busy with another task. In that case, Pacemaker will "
"automatically retry the operation if there is time remaining. Use this "
"option to alter the number of times Pacemaker tries a 'list' action before "
"giving up."
msgstr ""
" 一些设备不支持多个连接。 如果设备忙于另一个任务,则操作可能会'失败' , 因此"
"Pacemaker将自动重试(如果时间允许)。 使用此选项更改Pacemaker在放弃之前重"
"试'list' 操作的次数."
-#: lib/common/options.c:770
+#: lib/common/options.c:757
#, fuzzy
msgid "An alternate command to run instead of 'monitor'"
msgstr "运行替代命令,而不是'monitor'"
-#: lib/common/options.c:771
+#: lib/common/options.c:758
#, fuzzy
msgid ""
"Some devices do not support the standard commands or may provide additional "
"ones. Use this to specify an alternate, device-specific, command that "
"implements the 'monitor' action."
msgstr ""
"一些设备不支持标准命令或可能提供其他命令,使用此选项可指定一个该设备特定的替"
"代命令,用来实现'monitor'操作。"
-#: lib/common/options.c:779
+#: lib/common/options.c:766
#, fuzzy
msgid ""
"Specify an alternate timeout to use for 'monitor' actions instead of stonith-"
"timeout"
msgstr "指定用于monitor 操作的替代超时,而不是stonith-timeout"
-#: lib/common/options.c:781
+#: lib/common/options.c:768
#, fuzzy
msgid ""
"Some devices need much more/less time to complete than normal. Use this to "
"specify an alternate, device-specific, timeout for 'monitor' actions."
msgstr ""
"一些设备需要比正常情况下更多或更少的时间来完成操作,使用此选项指定一个用"
"于'monitor'操作的该设备特定的替代超时。"
-#: lib/common/options.c:789
+#: lib/common/options.c:776
#, fuzzy
msgid ""
"The maximum number of times to try the 'monitor' command within the timeout "
"period"
msgstr "在超时前重试'monitor'命令的最大次数"
-#: lib/common/options.c:791
+#: lib/common/options.c:778
#, fuzzy
msgid ""
"Some devices do not support multiple connections. Operations may \"fail\" if "
"the device is busy with another task. In that case, Pacemaker will "
"automatically retry the operation if there is time remaining. Use this "
"option to alter the number of times Pacemaker tries a 'monitor' action "
"before giving up."
msgstr ""
" 一些设备不支持多个连接。 如果设备忙于另一个任务,则操作可能会'失败' , 因此"
"Pacemaker将自动重试(如果时间允许)。 使用此选项更改Pacemaker在放弃之前重"
"试'monitor' 操作的次数."
-#: lib/common/options.c:801
+#: lib/common/options.c:788
#, fuzzy
msgid "An alternate command to run instead of 'status'"
msgstr "运行替代命令,而不是'status'"
-#: lib/common/options.c:802
+#: lib/common/options.c:789
#, fuzzy
msgid ""
"Some devices do not support the standard commands or may provide additional "
"ones. Use this to specify an alternate, device-specific, command that "
"implements the 'status' action."
msgstr ""
"一些设备不支持标准命令或可能提供其他命令,使用此选项可指定一个该设备特定的替"
"代命令,用来实现'status'操作。"
-#: lib/common/options.c:810
+#: lib/common/options.c:797
#, fuzzy
msgid ""
"Specify an alternate timeout to use for 'status' actions instead of stonith-"
"timeout"
msgstr "指定用于status 操作的替代超时,而不是stonith-timeout"
-#: lib/common/options.c:812
+#: lib/common/options.c:799
#, fuzzy
msgid ""
"Some devices need much more/less time to complete than normal. Use this to "
"specify an alternate, device-specific, timeout for 'status' actions."
msgstr ""
"一些设备需要比正常情况下更多或更少的时间来完成操作,使用此选项指定一个用"
"于'status'操作的该设备特定的替代超时"
-#: lib/common/options.c:820
+#: lib/common/options.c:807
#, fuzzy
msgid ""
"The maximum number of times to try the 'status' command within the timeout "
"period"
msgstr "仅高级使用:在超时前重试'status'命令的最大次数"
-#: lib/common/options.c:822
+#: lib/common/options.c:809
#, fuzzy
msgid ""
"Some devices do not support multiple connections. Operations may \"fail\" if "
"the device is busy with another task. In that case, Pacemaker will "
"automatically retry the operation if there is time remaining. Use this "
"option to alter the number of times Pacemaker tries a 'status' action before "
"giving up."
msgstr ""
" 一些设备不支持多个连接。 如果设备忙于另一个任务,则操作可能会'失败' , 因此"
"Pacemaker将自动重试(如果时间允许)。 使用此选项更改Pacemaker在放弃之前重"
"试'status' 操作的次数."
-#: lib/common/options.c:843
+#: lib/common/options.c:830
msgid "Resource assignment priority"
msgstr ""
-#: lib/common/options.c:844
+#: lib/common/options.c:831
msgid ""
"If not all resources can be active, the cluster will stop lower-priority "
"resources in order to keep higher-priority ones active."
msgstr ""
-#: lib/common/options.c:852
+#: lib/common/options.c:839
msgid "Default value for influence in colocation constraints"
msgstr ""
-#: lib/common/options.c:853
+#: lib/common/options.c:840
msgid ""
"Use this value as the default for influence in all colocation constraints "
"involving this resource, as well as in the implicit colocation constraints "
"created if this resource is in a group."
msgstr ""
-#: lib/common/options.c:863
+#: lib/common/options.c:850
#, fuzzy
msgid "State the cluster should attempt to keep this resource in"
msgstr "集群是否在启动期间检查运行资源"
-#: lib/common/options.c:864
+#: lib/common/options.c:851
msgid ""
"\"Stopped\" forces the resource to be stopped. \"Started\" allows the "
"resource to be started (and in the case of promotable clone resources, "
"promoted if appropriate). \"Unpromoted\" allows the resource to be started, "
"but only in the unpromoted role if the resource is promotable. \"Promoted\" "
"is equivalent to \"Started\"."
msgstr ""
-#: lib/common/options.c:875
+#: lib/common/options.c:862
#, fuzzy
msgid "Whether the cluster is allowed to actively change the resource's state"
msgstr "集群是否在启动期间检查运行资源"
-#: lib/common/options.c:877
+#: lib/common/options.c:864
msgid ""
"If false, the cluster will not start, stop, promote, or demote the resource "
"on any node. Recurring actions for the resource are unaffected. If true, a "
"true value for the maintenance-mode cluster option, the maintenance node "
"attribute, or the maintenance resource meta-attribute overrides this."
msgstr ""
-#: lib/common/options.c:887
+#: lib/common/options.c:874
msgid ""
"If true, the cluster will not schedule any actions involving the resource"
msgstr ""
-#: lib/common/options.c:889
+#: lib/common/options.c:876
msgid ""
"If true, the cluster will not start, stop, promote, or demote the resource "
"on any node, and will pause any recurring monitors (except those specifying "
"role as \"Stopped\"). If false, a true value for the maintenance-mode "
"cluster option or maintenance node attribute overrides this."
msgstr ""
-#: lib/common/options.c:899
+#: lib/common/options.c:886
msgid "Score to add to the current node when a resource is already active"
msgstr ""
-#: lib/common/options.c:901
+#: lib/common/options.c:888
msgid ""
"Score to add to the current node when a resource is already active. This "
"allows running resources to stay where they are, even if they would be "
"placed elsewhere if they were being started from a stopped state. The "
"default is 1 for individual clone instances, and 0 for all other resources."
msgstr ""
-#: lib/common/options.c:914
+#: lib/common/options.c:901
msgid "Conditions under which the resource can be started"
msgstr ""
-#: lib/common/options.c:915
+#: lib/common/options.c:902
msgid ""
"Conditions under which the resource can be started. \"nothing\" means the "
"cluster can always start this resource. \"quorum\" means the cluster can "
"start this resource only if a majority of the configured nodes are active. "
"\"fencing\" means the cluster can start this resource only if a majority of "
"the configured nodes are active and any failed or unknown nodes have been "
"fenced. \"unfencing\" means the cluster can start this resource only if a "
"majority of the configured nodes are active and any failed or unknown nodes "
"have been fenced, and only on nodes that have been unfenced. The default is "
"\"quorum\" for resources with a class of stonith; otherwise, \"unfencing\" "
"if unfencing is active in the cluster; otherwise, \"fencing\" if the stonith-"
"enabled cluster option is true; otherwise, \"quorum\"."
msgstr ""
-#: lib/common/options.c:936
+#: lib/common/options.c:923
msgid ""
"Number of failures on a node before the resource becomes ineligible to run "
"there."
msgstr ""
-#: lib/common/options.c:938
+#: lib/common/options.c:925
msgid ""
"Number of failures that may occur for this resource on a node, before that "
"node is marked ineligible to host this resource. A value of 0 indicates that "
"this feature is disabled (the node will never be marked ineligible). By "
"contrast, the cluster treats \"INFINITY\" (the default) as a very large but "
"finite number. This option has an effect only if the failed operation "
"specifies its on-fail attribute as \"restart\" (the default), and "
"additionally for failed start operations, if the start-failure-is-fatal "
"cluster property is set to false."
msgstr ""
-#: lib/common/options.c:952
+#: lib/common/options.c:939
msgid "Number of seconds before acting as if a failure had not occurred"
msgstr ""
-#: lib/common/options.c:953
+#: lib/common/options.c:940
msgid ""
"Number of seconds after a failed action for this resource before acting as "
"if the failure had not occurred, and potentially allowing the resource back "
"to the node on which it failed. A value of 0 indicates that this feature is "
"disabled."
msgstr ""
-#: lib/common/options.c:964
+#: lib/common/options.c:951
msgid ""
"What to do if the cluster finds the resource active on more than one node"
msgstr ""
-#: lib/common/options.c:966
+#: lib/common/options.c:953
msgid ""
"What to do if the cluster finds the resource active on more than one node. "
"\"block\" means to mark the resource as unmanaged. \"stop_only\" means to "
"stop all active instances of this resource and leave them stopped. "
"\"stop_start\" means to stop all active instances of this resource and start "
"the resource in one location only. \"stop_unexpected\" means to stop all "
"active instances of this resource except where the resource should be "
"active. (This should be used only when extra instances are not expected to "
"disrupt existing instances, and the resource agent's monitor of an existing "
"instance is capable of detecting any problems that could be caused. Note "
"that any resources ordered after this one will still need to be restarted.)"
msgstr ""
-#: lib/common/options.c:985
+#: lib/common/options.c:972
#, fuzzy
msgid ""
"Whether the cluster should try to \"live migrate\" this resource when it "
"needs to be moved"
msgstr "集群是否在启动期间检查运行资源"
-#: lib/common/options.c:987
+#: lib/common/options.c:974
msgid ""
"Whether the cluster should try to \"live migrate\" this resource when it "
"needs to be moved. The default is true for ocf:pacemaker:remote resources, "
"and false otherwise."
msgstr ""
-#: lib/common/options.c:996
+#: lib/common/options.c:983
msgid ""
"Whether the resource should be allowed to run on a node even if the node's "
"health score would otherwise prevent it"
msgstr ""
-#: lib/common/options.c:1004
+#: lib/common/options.c:991
#, fuzzy
msgid "Where to check user-defined node attributes"
msgstr "*** 仅高级使用 *** 是否在启动时fence不可见节点"
-#: lib/common/options.c:1005
+#: lib/common/options.c:992
msgid ""
"Whether to check user-defined node attributes on the physical host where a "
"container is running or on the local node. This is usually set for a bundle "
"resource and inherited by the bundle's primitive resource. A value of \"host"
"\" means to check user-defined node attributes on the underlying physical "
"host. Any other value means to check user-defined node attributes on the "
"local node (for a bundled primitive resource, this is the bundle node)."
msgstr ""
-#: lib/common/options.c:1018
+#: lib/common/options.c:1005
msgid ""
"Name of the Pacemaker Remote guest node this resource is associated with, if "
"any"
msgstr ""
-#: lib/common/options.c:1020
+#: lib/common/options.c:1007
msgid ""
"Name of the Pacemaker Remote guest node this resource is associated with, if "
"any. If specified, this both enables the resource as a guest node and "
"defines the unique name used to identify the guest node. The guest must be "
"configured to run the Pacemaker Remote daemon when it is started. WARNING: "
"This value cannot overlap with any resource or node IDs."
msgstr ""
-#: lib/common/options.c:1032
+#: lib/common/options.c:1019
msgid ""
"If remote-node is specified, the IP address or hostname used to connect to "
"the guest via Pacemaker Remote"
msgstr ""
-#: lib/common/options.c:1034
+#: lib/common/options.c:1021
msgid ""
"If remote-node is specified, the IP address or hostname used to connect to "
"the guest via Pacemaker Remote. The Pacemaker Remote daemon on the guest "
"must be configured to accept connections on this address. The default is the "
"value of the remote-node meta-attribute."
msgstr ""
-#: lib/common/options.c:1044
+#: lib/common/options.c:1031
msgid ""
"If remote-node is specified, port on the guest used for its Pacemaker Remote "
"connection"
msgstr ""
-#: lib/common/options.c:1046
+#: lib/common/options.c:1033
msgid ""
"If remote-node is specified, the port on the guest used for its Pacemaker "
"Remote connection. The Pacemaker Remote daemon on the guest must be "
"configured to listen on this port."
msgstr ""
-#: lib/common/options.c:1054
+#: lib/common/options.c:1041
msgid ""
"If remote-node is specified, how long before a pending Pacemaker Remote "
"guest connection times out."
msgstr ""
-#: lib/common/options.c:1062
+#: lib/common/options.c:1049
msgid ""
"If remote-node is specified, this acts as the allow-migrate meta-attribute "
"for the implicit remote connection resource (ocf:pacemaker:remote)."
msgstr ""
#: lib/common/cmdline.c:70
msgid "Display software version and exit"
msgstr "显示软件版本信息"
#: lib/common/cmdline.c:73
msgid "Increase debug output (may be specified multiple times)"
msgstr "显示更多调试信息(可多次指定)"
#: lib/common/cmdline.c:92
msgid "FORMAT"
msgstr "格式"
#: lib/common/cmdline.c:94
msgid "Specify file name for output (or \"-\" for stdout)"
msgstr "指定输出的文件名 或指定'-' 表示标准输出"
#: lib/common/cmdline.c:94
msgid "DEST"
msgstr "目标"
#: lib/common/cmdline.c:100
msgid "Output Options:"
msgstr "输出选项"
#: lib/common/cmdline.c:100
msgid "Show output help"
msgstr "显示输出帮助"
-#: tools/crm_resource.c:204
+#: tools/crm_resource.c:201
#, c-format
msgid "Aborting because no messages received in %d seconds"
msgstr "中止,因为在%d秒内没有接收到消息"
-#: tools/crm_resource.c:374
+#: tools/crm_resource.c:371
#, c-format
msgid "Invalid check level setting: %s"
msgstr "无效的检查级别设置:%s"
-#: tools/crm_resource.c:891
+#: tools/crm_resource.c:866
#, c-format
msgid ""
"Resource '%s' not moved: active in %d locations (promoted in %d).\n"
"To prevent '%s' from running on a specific location, specify a node.To "
"prevent '%s' from being promoted at a specific location, specify a node and "
"the --promoted option."
msgstr ""
"资源'%s'未移动:在%d个位置运行(其中在%d个位置为主实例)\n"
"若要阻止'%s'在特定位置运行,请指定一个节点。若要防止'%s'在指定位置升级,指定"
"一个节点并使用--promoted选项"
-#: tools/crm_resource.c:902
+#: tools/crm_resource.c:877
#, c-format
msgid ""
"Resource '%s' not moved: active in %d locations.\n"
"To prevent '%s' from running on a specific location, specify a node."
msgstr ""
"资源%s未移动:在%d个位置运行\n"
"若要防止'%s'运行在特定位置,指定一个节点"
-#: tools/crm_resource.c:979
+#: tools/crm_resource.c:955
#, c-format
msgid "Could not get modified CIB: %s\n"
msgstr "无法获得修改的CIB:%s\n"
-#: tools/crm_resource.c:1077
+#: tools/crm_resource.c:1035
#, c-format
msgid "No cluster connection to Pacemaker Remote node %s detected"
msgstr "未检测到至pacemaker远程节点%s的集群连接"
-#: tools/crm_resource.c:1138
-msgid "Must specify -t with resource type"
-msgstr "需要使用-t指定资源类型"
-
-#: tools/crm_resource.c:1144
-msgid "Must supply -v with new value"
-msgstr "必须使用-v指定新值"
-
-#: tools/crm_resource.c:1176
+#: tools/crm_resource.c:1101
msgid "Could not create executor connection"
msgstr "无法创建到pacemaker-execd守护进程的连接"
-#: tools/crm_resource.c:1201
+#: tools/crm_resource.c:1126
#, fuzzy, c-format
msgid "Metadata query for %s failed: %s"
msgstr ",查询%s的元数据失败: %s\n"
-#: tools/crm_resource.c:1207
+#: tools/crm_resource.c:1132
#, c-format
msgid "'%s' is not a valid agent specification"
msgstr "'%s' 是一个无效的代理"
-#: tools/crm_resource.c:1220
+#: tools/crm_resource.c:1145
msgid "--resource cannot be used with --class, --agent, and --provider"
msgstr "--resource 不能与 --class, --agent, --provider一起使用"
-#: tools/crm_resource.c:1225
+#: tools/crm_resource.c:1150
msgid ""
"--class, --agent, and --provider can only be used with --validate and --"
"force-*"
msgstr "--class, --agent和--provider只能被用于--validate和--force-*"
-#: tools/crm_resource.c:1234
+#: tools/crm_resource.c:1159
msgid "stonith does not support providers"
msgstr "stonith 不支持提供者"
-#: tools/crm_resource.c:1238
+#: tools/crm_resource.c:1163
#, c-format
msgid "%s is not a known stonith agent"
msgstr "%s 不是一个已知stonith代理"
-#: tools/crm_resource.c:1243
+#: tools/crm_resource.c:1168
#, c-format
msgid "%s:%s:%s is not a known resource"
msgstr "%s:%s:%s 不是一个已知资源"
-#: tools/crm_resource.c:1551
+#: tools/crm_resource.c:1467
#, c-format
msgid "Error creating output format %s: %s"
msgstr "创建输出格式错误 %s:%s"
-#: tools/crm_resource.c:1572
+#: tools/crm_resource.c:1488
msgid "--expired requires --clear or -U"
msgstr "--expired需要和--clear或-U一起使用"
-#: tools/crm_resource.c:1589
+#: tools/crm_resource.c:1505
#, c-format
msgid "Error parsing '%s' as a name=value pair"
msgstr "'%s'解析错误,格式为name=value"
-#: tools/crm_resource.c:1688
+#: tools/crm_resource.c:1597
+msgid "--option must be used with --validate and without -r"
+msgstr ""
+
+#: tools/crm_resource.c:1606
msgid "Must supply a resource id with -r"
msgstr "必须使用-r指定资源id"
-#: tools/crm_resource.c:1694
+#: tools/crm_resource.c:1612
msgid "Must supply a node name with -N"
msgstr "必须使用-N指定节点名称"
-#: tools/crm_resource.c:1708
+#: tools/crm_resource.c:1626
msgid "Could not create CIB connection"
msgstr "无法创建到CIB的连接"
-#: tools/crm_resource.c:1716
+#: tools/crm_resource.c:1634
#, c-format
msgid "Could not connect to the CIB: %s"
msgstr "不能连接到CIB:%s"
-#: tools/crm_resource.c:1739
+#: tools/crm_resource.c:1657
#, c-format
msgid "Resource '%s' not found"
msgstr "没有发现'%s'资源"
-#: tools/crm_resource.c:1751
+#: tools/crm_resource.c:1670
#, c-format
msgid "Cannot operate on clone resource instance '%s'"
msgstr "不能操作克隆资源实例'%s'"
-#: tools/crm_resource.c:1763
+#: tools/crm_resource.c:1682
#, c-format
msgid "Node '%s' not found"
msgstr "没有发现%s节点"
-#: tools/crm_resource.c:1774
+#: tools/crm_resource.c:1693
#, c-format
msgid "Error connecting to the controller: %s"
msgstr "连接到控制器错误:%s"
-#: tools/crm_resource.c:1783
+#: tools/crm_resource.c:1702
#, fuzzy, c-format
msgid "Error connecting to %s: %s"
msgstr "连接到控制器错误:%s"
-#: tools/crm_resource.c:2052
+#: tools/crm_resource.c:1959
msgid "You need to supply a value with the -v option"
msgstr "需要使用-v选项提供一个值"
-#: tools/crm_resource.c:2106
+#: tools/crm_resource.c:2012
msgid "You need to specify a resource type with -t"
msgstr "需要使用-t指定资源类型"
-#: tools/crm_resource.c:2113
+#: tools/crm_resource.c:2019
#, fuzzy, c-format
msgid "Could not delete resource %s: %s"
msgstr "无法删除资源:%s:%s"
-#: tools/crm_resource.c:2123
+#: tools/crm_resource.c:2029
#, c-format
msgid "Unimplemented command: %d"
msgstr "无效的命令:%d"
-#: tools/crm_resource.c:2153
+#: tools/crm_resource.c:2059
#, c-format
msgid "Error performing operation: %s"
msgstr "执行操作错误:%s"
+#~ msgid "Deprecated (will be removed in a future release)"
+#~ msgstr "已弃用(将在未来版本中删除)"
+
+#, fuzzy
+#~ msgid "Whether to remove stopped resources from the executor"
+#~ msgstr "是否从pacemaker-execd 守护进程中清除已停止的资源"
+
+#, fuzzy
+#~ msgid ""
+#~ "Values other than default are poorly tested and potentially dangerous."
+#~ msgstr ""
+#~ "非默认值未经过充分的测试,有潜在的风险。该选项将在未来的版本中删除。"
+
+#, fuzzy
+#~ msgid "An alternate parameter to supply instead of 'port'"
+#~ msgstr "用于替代 'port' 的其它参数"
+
+#, fuzzy
+#~ msgid ""
+#~ "Some devices do not support the standard 'port' parameter or may provide "
+#~ "additional ones. Use this to specify an alternate, device-specific, "
+#~ "parameter that should indicate the machine to be fenced. A value of \"none"
+#~ "\" can be used to tell the cluster not to supply any additional "
+#~ "parameters."
+#~ msgstr ""
+#~ "一些设备不支持标准的 'port' 参数, 或者可能会提供其它的参数. 使用此选项可指"
+#~ "定一个替代的, 该设备专用的参数, 该参数应该指出需要 fence 的机器. 可以使用 "
+#~ "\"none\" 值用于告诉集群不要提供任何其它的参数. "
+
+#~ msgid "Must specify -t with resource type"
+#~ msgstr "需要使用-t指定资源类型"
+
+#~ msgid "Must supply -v with new value"
+#~ msgstr "必须使用-v指定新值"
+
#, fuzzy
#~ msgid "For example, \"node1,node2,node3\"."
#~ msgstr "例如, \"node1,node2,node3\"."
#, fuzzy
#~ msgid "*** Advanced Use Only ***"
#~ msgstr "*** Advanced Use Only(仅限高级用户使用) ***"
#, fuzzy
#~ msgid ""
#~ "Zero disables polling, while positive values are an interval in seconds "
#~ "(unless other units are specified, for example \"5min\")"
#~ msgstr ""
#~ "0 表示禁用轮询,而正值表示以秒为单位的时间间隔(除非指定了其他单位, 例如 "
#~ "\"5min\" 表示5分钟)"
#~ msgid " Allowed values: "
#~ msgstr " 允许的值: "
#~ msgid ""
#~ "This value is not used by Pacemaker, but is kept for backward "
#~ "compatibility, and certain legacy fence agents might use it."
#~ msgstr ""
#~ "Pacemaker不使用此值,但保留此值是为了向后兼容,某些传统的fence 代理可能会"
#~ "使用它。"
#~ msgid "No agents found for standard '%s'"
#~ msgstr "没有发现指定的'%s'标准代理"
#, fuzzy
#~ msgid "No agents found for standard '%s' and provider '%s'"
#~ msgstr "没有发现指定的标准%s和提供者%S的资源代理"
#~ msgid "No %s found for %s"
#~ msgstr "没有发现%s符合%s"
#~ msgid "No %s found"
#~ msgstr "没有发现%s"
#~ msgid ""
#~ "If nonzero, along with `have-watchdog=true` automatically set by the "
#~ "cluster, when fencing is required, watchdog-based self-fencing will be "
#~ "performed via SBD without requiring a fencing resource explicitly "
#~ "configured. If `stonith-watchdog-timeout` is set to a positive value, "
#~ "unseen nodes are assumed to self-fence within this much time. +WARNING:+ "
#~ "It must be ensured that this value is larger than the "
#~ "`SBD_WATCHDOG_TIMEOUT` environment variable on all nodes. Pacemaker "
#~ "verifies the settings individually on all nodes and prevents startup or "
#~ "shuts down if configured wrongly on the fly. It's strongly recommended "
#~ "that `SBD_WATCHDOG_TIMEOUT` is set to the same value on all nodes. If "
#~ "`stonith-watchdog-timeout` is set to a negative value, and "
#~ "`SBD_WATCHDOG_TIMEOUT` is set, twice that value will be used. +WARNING:+ "
#~ "In this case, it's essential (currently not verified by Pacemaker) that "
#~ "`SBD_WATCHDOG_TIMEOUT` is set to the same value on all nodes."
#~ msgstr ""
#~ "如果值非零,且集群设置了 `have-watchdog=true` ,当需要 fence 操作时,基于 "
#~ "watchdog 的自我 fence 机制将通过SBD执行,而不需要显式配置 fence 资源。如"
#~ "果 `stonith-watchdog-timeout` 被设为正值,则假定不可见的节点在这段时间内自"
#~ "我fence。 +WARNING:+ 必须确保该值大于所有节点上的`SBD_WATCHDOG_TIMEOUT` 环"
#~ "境变量。Pacemaker将在所有节点上单独验证设置,如发现有错误的动态配置,将防"
#~ "止节点启动或关闭。强烈建议在所有节点上将 `SBD_WATCHDOG_TIMEOUT` 设置为相同"
#~ "的值。如果 `stonith-watchdog-timeout` 设置为负值。并且设置了 "
#~ "`SBD_WATCHDOG_TIMEOUT` ,则将使用该值的两倍, +WARNING:+ 在这种情况下,必"
#~ "须将所有节点上 `SBD_WATCHDOG_TIMEOUT` 设置为相同的值(目前没有通过pacemaker"
#~ "验证)。"
diff --git a/xml/README.md b/xml/README.md
index a53805154f..f1016eaf7d 100644
--- a/xml/README.md
+++ b/xml/README.md
@@ -1,141 +1,143 @@
# Schema Reference
Pacemaker's XML schema has a version of its own, independent of the version of
Pacemaker itself.
## Versioned Schema Evolution
A versioned schema offers transparent backward and forward compatibility.
- It reflects the timeline of schema-backed features (introduction,
changes to the syntax, possibly deprecation) through the versioned
stable schema increments, while keeping schema versions used by default
by older Pacemaker versions untouched.
- Pacemaker internally uses the latest stable schema version, and relies on
supplemental transformations to promote cluster configurations based on
older, incompatible schema versions into the desired form.
## Mapping Pacemaker Versions to Schema Versions
| Pacemaker | Latest Schema | Changed
| --------- | ------------- | ----------------------------------------------
+| `3.0.0` | `4.0` | `alerts`, `constraints`, `fencing`, `nodes`,
+| | | `nvset`, `options`, `resources`, `rule`
| `2.1.8` | `3.10` | `alerts`, `constraints`, `nodes`, `nvset`,
| | | `options`, `resources`, `rule`
| `2.1.5` | `3.9` | `alerts`, `constraints`, `nodes`, `nvset`,
| | | `options`, `resources`, `rule`
| `2.1.3` | `3.8` | `acls`
| `2.1.0` | `3.7` | `constraints`, `resources`
| `2.0.5` | `3.5` | `api`, `resources`, `rule`
| `2.0.4` | `3.3` | `tags`
| `2.0.1` | `3.2` | `resources`
| `2.0.0` | `3.1` | `constraints`, `resources`
| `1.1.18` | `2.10` | `resources`, `alerts`
| `1.1.17` | `2.9` | `resources`, `rule`
| `1.1.16` | `2.6` | `constraints`
| `1.1.15` | `2.5` | `alerts`
| `1.1.14` | `2.4` | `fencing`
| `1.1.13` | `2.3` | `constraints`
| `1.1.12` | `2.0` | `nodes`, `nvset`, `resources`, `tags`, `acls`
| `1.1.8` | `1.2` |
## Schema generation
Each logical portion of the schema goes into its own RNG file, named like
`${base}-${X}.${Y}.rng`. `${base}` identifies the portion of the schema
(e.g. constraints, resources); ${X}.${Y} is the latest schema version that
contained changes in this portion of the schema.
The complete, overall schema, `pacemaker-${X}.${Y}.rng`, is automatically
generated from the other files via the Makefile.
# Updating schema files #
## New features ##
The current schema version is determined at runtime when
crm\_schema\_init() scans the CRM\_SCHEMA\_DIRECTORY.
It will have the form `pacemaker-${X}.${Y}` and the highest
`${X}.${Y}` wins.
### Simple Additions
When the new syntax is a simple addition to the previous one, create a
new entry, incrementing `${Y}`.
### Feature Removal or otherwise Incompatible Changes
When the new syntax is not a simple addition to the previous one,
create a new entry, incrementing `${X}` and setting `${Y} = 0`.
An XSLT file is also required that converts an old syntax to the new
one and must be named `upgrade-${Xold}.${Yold}.xsl`.
See `xml/upgrade-1.3.xsl` for an example.
Since `xml/upgrade-2.10.xsl`, rather self-descriptive approach is taken,
separating metadata of the replacements and other modifications to
perform from the actual executive parts, which is leveraged, e.g., with
the on-the-fly overview as obtained with `./regression.sh -X test2to3`.
Also this was the first time particular key names of `nvpair`s,
i.e. below the granularity of the schemas so far, received attention,
and consequently, no longer expected names became systemically banned
in the after-upgrade schemas, using `` construct in the
data type specification pertaining the affected XML path.
The implied complexity also resulted in establishing a new compound,
stepwise transformation, alleviating the procedural burden from the
core upgrade recipe. In particular, `id-ref` based syntactic
simplification granted in the CIB format introduces nonnegligible
internal "noise" because of the extra indirection encumbered with
generally non-bijective character of such a scheme (context-dependent
interpretation). To reduce this strain, a symmetric arrangement is
introduced as a pair of _enter_/_leave_ (pre-upgrade/post-upgrade)
transformations where the latter is meant to eventually reversibly
restore what the former intentionally simplified (normalized) for
upgrade transformation's peruse. It's optional (even the post-upgrade
counterpart is optional alone) and depends on whether the suitable
files are found along the upgrade transformation itself: e.g., for
`upgrade-2.10.xsl`, such files are `upgrade-2.10-enter.xsl` and
`upgrade-2.10-leave.xsl`. Note that unfolding + refolding `id-ref`
shortcuts is just a practically imposed individual case of how to
reversibly make the configuration space tractable in the upgrade
itself, allowing for more sophistication down the road.
### General Procedure
1. Run `make -C xml schemas SCHEMAS="${base}" NEW_VERSION="${X}.${Y}"` to copy
the most recent version of `${base}` to a higher version than the highest
version of any schema file.
Multiple `SCHEMAS` can be entered (space-separated), and `${Y}` will be
automatically increased if `NEW_VERSION` is omitted.
Run `make -C xml schemas` to list all versions of the schemas, schema-list
for easy copy/paste, and usage info.
2. Commit the copy, e.g. `"Low: xml: clone ${base} schema in preparation for
changes"`. This way, the actual change will be obvious in the commit history.
3. Modify `${base}-${X}.${Y}.rng` as required.
4. If required, add an XSLT file, and update `xslt\_SCRIPTS` in `xml/Makefile.am`.
5. Commit.
6. Run `make -C xml clean; make -C xml` to rebuild the schemas in the local
source directory.
7. The CIB validity and upgrade regression tests will break after the schema is
updated. Run `cts/cts-cli -s` to make the expected outputs reflect the
changes made so far, and run `git diff` to ensure that these changes look
sane. Finally, commit the changes.
8. Similarly, with the new major version `${X}`, it's advisable to refresh
scheduler tests at some point. See the instructions in `cts/README.md`.
## Using a New Schema
New features will not be available until the cluster administrator:
1. Updates all the nodes
2. Runs the equivalent of `cibadmin --upgrade --force`
## Random Notes
From the source directory, run `make -C xml diff` to see the changes
in the current schema (compared to the previous ones).
Alternatively, if the intention is to grok the overall historical schema
evolution, use `make -C xml fulldiff`.