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``.