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