diff --git a/.ansible-lint b/.ansible-lint index 60ea22b6..8ff1ec7e 100644 --- a/.ansible-lint +++ b/.ansible-lint @@ -18,6 +18,7 @@ skip_list: exclude_paths: - tests/roles/ - .github/ + - .markdownlint.yaml - examples/roles/ mock_roles: - linux-system-roles.ha_cluster diff --git a/.github/workflows/ansible-test.yml b/.github/workflows/ansible-test.yml index 6dbd5486..4285be34 100644 --- a/.github/workflows/ansible-test.yml +++ b/.github/workflows/ansible-test.yml @@ -38,6 +38,8 @@ jobs: - name: Convert role to collection format run: | set -euxo pipefail + # Remove dot files to avoid running ansible-test on them + rm -f .pandoc_template.html5 TOXENV=collection lsr_ci_runtox # copy the ignore files coll_dir=".tox/ansible_collections/$LSR_ROLE2COLL_NAMESPACE/$LSR_ROLE2COLL_NAME" diff --git a/.github/workflows/build_docs.yml b/.github/workflows/build_docs.yml new file mode 100644 index 00000000..13efaab1 --- /dev/null +++ b/.github/workflows/build_docs.yml @@ -0,0 +1,101 @@ +--- +# yamllint disable rule:line-length +name: Convert README.md to HTML and push to docs branch +on: # yamllint disable-line rule:truthy + push: + branches: + - main + paths: + - README.md + release: + types: + - published +permissions: + contents: read +jobs: + build_docs: + runs-on: ubuntu-latest + permissions: + contents: write + steps: + - name: Update pip, git + run: | + set -euxo pipefail + sudo apt update + sudo apt install -y git + + - name: Check out code + uses: actions/checkout@v3 + with: + fetch-depth: 0 + - name: Ensure the docs branch + run: | + set -euxo pipefail + branch=docs + existed_in_remote=$(git ls-remote --heads origin $branch) + + if [ -z "${existed_in_remote}" ]; then + echo "Creating $branch branch" + git config --global user.name "${{ github.actor }}" + git config --global user.email "${{ github.actor }}@users.noreply.github.com" + git checkout --orphan $branch + git reset --hard + git commit --allow-empty -m "Initializing $branch branch" + git push origin $branch + echo "Created $branch branch" + else + echo "Branch $branch already exists" + fi + + - name: Checkout the docs branch + uses: actions/checkout@v3 + with: + ref: docs + + - name: Fetch README.md and .pandoc_template.html5 template from the workflow branch + uses: actions/checkout@v3 + with: + sparse-checkout: | + README.md + .pandoc_template.html5 + sparse-checkout-cone-mode: false + path: ref_branch + - name: Set RELEASE_VERSION based on whether run on release or on push + run: | + set -euxo pipefail + if [ ${{ github.event_name }} = release ]; then + echo "RELEASE_VERSION=${{ github.event.release.tag_name }}" >> $GITHUB_ENV + elif [ ${{ github.event_name }} = push ]; then + echo "RELEASE_VERSION=latest" >> $GITHUB_ENV + else + echo Unsupported event + exit 1 + fi + + - name: Ensure that version and docs directories exist + run: mkdir -p ${{ env.RELEASE_VERSION }} docs + + - name: Convert README.md to HTML and save to the version directory + uses: docker://pandoc/core:latest + with: + args: >- + --from gfm --to html5 --toc --shift-heading-level-by=-1 + --template ref_branch/.pandoc_template.html5 + --output ${{ env.RELEASE_VERSION }}/README.html ref_branch/README.md + + - name: Copy latest README.html to docs/index.html for GitHub pages + if: env.RELEASE_VERSION == 'latest' + run: cp ${{ env.RELEASE_VERSION }}/README.html docs/index.html + + - name: Commit changes + run: | + git config --global user.name "${{ github.actor }}" + git config --global user.email "${{ github.actor }}@users.noreply.github.com" + git add ${{ env.RELEASE_VERSION }}/README.html docs/index.html + git commit -m "Update README.html for ${{ env.RELEASE_VERSION }}" + + - name: Push changes + uses: ad-m/github-push-action@master + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + branch: docs diff --git a/.github/workflows/markdownlint.yml b/.github/workflows/markdownlint.yml new file mode 100644 index 00000000..98e3c4c3 --- /dev/null +++ b/.github/workflows/markdownlint.yml @@ -0,0 +1,34 @@ +--- +# yamllint disable rule:line-length +name: Markdown Lint +on: # yamllint disable-line rule:truthy + pull_request: + merge_group: + branches: + - main + types: + - checks_requested + push: + branches: + - main + workflow_dispatch: +permissions: + contents: read +jobs: + markdownlint: + runs-on: ubuntu-latest + steps: + - name: Update pip, git + run: | + set -euxo pipefail + sudo apt update + sudo apt install -y git + + - name: Check out code + uses: actions/checkout@v3 + + - name: Lint README.md + uses: docker://avtodev/markdown-lint:master + with: + args: README.md + config: .markdownlint.yaml diff --git a/.github/workflows/test_converting_readme.yml b/.github/workflows/test_converting_readme.yml new file mode 100644 index 00000000..e5456137 --- /dev/null +++ b/.github/workflows/test_converting_readme.yml @@ -0,0 +1,43 @@ +--- +# yamllint disable rule:line-length +name: Test converting README.md to README.html +on: # yamllint disable-line rule:truthy + pull_request: + merge_group: + branches: + - main + types: + - checks_requested + push: + branches: + - main +permissions: + contents: read +jobs: + test_converting_readme: + runs-on: ubuntu-latest + permissions: + contents: write + steps: + - name: Update pip, git + run: | + set -euxo pipefail + sudo apt update + sudo apt install -y git + + - name: Check out code + uses: actions/checkout@v3 + + - name: Convert README.md to HTML and save to the version directory + uses: docker://pandoc/core:latest + with: + args: >- + --from gfm --to html5 --toc --shift-heading-level-by=-1 + --template .pandoc_template.html5 + --output README.html README.md + + - name: Upload README.html as an artifact + uses: actions/upload-artifact@master + with: + name: README.html + path: README.html diff --git a/.markdownlint.yaml b/.markdownlint.yaml new file mode 100644 index 00000000..4f8a9799 --- /dev/null +++ b/.markdownlint.yaml @@ -0,0 +1,260 @@ +# Default state for all rules +default: true + +# Path to configuration file to extend +extends: null + +# MD001/heading-increment/header-increment - Heading levels should only increment by one level at a time +MD001: true + +# MD002/first-heading-h1/first-header-h1 - First heading should be a top-level heading +MD002: + # Heading level + level: 1 + +# MD003/heading-style/header-style - Heading style +MD003: + # Heading style + style: "consistent" + +# MD004/ul-style - Unordered list style +MD004: + # List style + style: "consistent" + +# MD005/list-indent - Inconsistent indentation for list items at the same level +MD005: true + +# MD006/ul-start-left - Consider starting bulleted lists at the beginning of the line +MD006: true + +# MD007/ul-indent - Unordered list indentation +MD007: + # Spaces for indent + indent: 2 + # Whether to indent the first level of the list + start_indented: false + # Spaces for first level indent (when start_indented is set) + start_indent: 2 + +# MD009/no-trailing-spaces - Trailing spaces +MD009: + # Spaces for line break + br_spaces: 2 + # Allow spaces for empty lines in list items + list_item_empty_lines: false + # Include unnecessary breaks + strict: false + +# MD010/no-hard-tabs - Hard tabs +MD010: + # Include code blocks + code_blocks: true + # Fenced code languages to ignore + ignore_code_languages: [] + # Number of spaces for each hard tab + spaces_per_tab: 1 + +# MD011/no-reversed-links - Reversed link syntax +MD011: true + +# MD012/no-multiple-blanks - Multiple consecutive blank lines +MD012: + # Consecutive blank lines + maximum: 1 + +# Modified for LSR +# GFM does not limit line length +# MD013/line-length - Line length +MD013: false + # # Number of characters + # # line_length: 80 + # line_length: 999 + # # Number of characters for headings + # heading_line_length: 80 + # # Number of characters for code blocks + # code_block_line_length: 80 + # # Include code blocks + # code_blocks: true + # # Include tables + # tables: true + # # Include headings + # headings: true + # # Include headings + # headers: true + # # Strict length checking + # strict: false + # # Stern length checking + # stern: false + +# MD014/commands-show-output - Dollar signs used before commands without showing output +MD014: true + +# MD018/no-missing-space-atx - No space after hash on atx style heading +MD018: true + +# MD019/no-multiple-space-atx - Multiple spaces after hash on atx style heading +MD019: true + +# MD020/no-missing-space-closed-atx - No space inside hashes on closed atx style heading +MD020: true + +# MD021/no-multiple-space-closed-atx - Multiple spaces inside hashes on closed atx style heading +MD021: true + +# MD022/blanks-around-headings/blanks-around-headers - Headings should be surrounded by blank lines +MD022: + # Blank lines above heading + lines_above: 1 + # Blank lines below heading + lines_below: 1 + +# MD023/heading-start-left/header-start-left - Headings must start at the beginning of the line +MD023: true + +# MD024/no-duplicate-heading/no-duplicate-header - Multiple headings with the same content +MD024: true + +# MD025/single-title/single-h1 - Multiple top-level headings in the same document +MD025: + # Heading level + level: 1 + # RegExp for matching title in front matter + front_matter_title: "^\\s*title\\s*[:=]" + +# MD026/no-trailing-punctuation - Trailing punctuation in heading +MD026: + # Punctuation characters not allowed at end of headings + punctuation: ".,;:!。,;:!" + +# MD027/no-multiple-space-blockquote - Multiple spaces after blockquote symbol +MD027: true + +# MD028/no-blanks-blockquote - Blank line inside blockquote +MD028: true + +# MD029/ol-prefix - Ordered list item prefix +MD029: + # List style + style: "one_or_ordered" + +# MD030/list-marker-space - Spaces after list markers +MD030: + # Spaces for single-line unordered list items + ul_single: 1 + # Spaces for single-line ordered list items + ol_single: 1 + # Spaces for multi-line unordered list items + ul_multi: 1 + # Spaces for multi-line ordered list items + ol_multi: 1 + +# MD031/blanks-around-fences - Fenced code blocks should be surrounded by blank lines +MD031: + # Include list items + list_items: true + +# MD032/blanks-around-lists - Lists should be surrounded by blank lines +MD032: true + +# MD033/no-inline-html - Inline HTML +MD033: + # Allowed elements + allowed_elements: [] + +# MD034/no-bare-urls - Bare URL used +MD034: true + +# MD035/hr-style - Horizontal rule style +MD035: + # Horizontal rule style + style: "consistent" + +# MD036/no-emphasis-as-heading/no-emphasis-as-header - Emphasis used instead of a heading +MD036: + # Punctuation characters + punctuation: ".,;:!?。,;:!?" + +# MD037/no-space-in-emphasis - Spaces inside emphasis markers +MD037: true + +# MD038/no-space-in-code - Spaces inside code span elements +MD038: true + +# MD039/no-space-in-links - Spaces inside link text +MD039: true + +# MD040/fenced-code-language - Fenced code blocks should have a language specified +MD040: + # List of languages + allowed_languages: [] + # Require language only + language_only: false + +# MD041/first-line-heading/first-line-h1 - First line in a file should be a top-level heading +MD041: + # Heading level + level: 1 + # RegExp for matching title in front matter + front_matter_title: "^\\s*title\\s*[:=]" + +# MD042/no-empty-links - No empty links +MD042: true + +# Modified for LSR +# Disabling, we do not need this +# MD043/required-headings/required-headers - Required heading structure +MD043: false + # # List of headings + # headings: [] + # # List of headings + # headers: [] + # # Match case of headings + # match_case: false + +# MD044/proper-names - Proper names should have the correct capitalization +MD044: + # List of proper names + names: [] + # Include code blocks + code_blocks: true + # Include HTML elements + html_elements: true + +# MD045/no-alt-text - Images should have alternate text (alt text) +MD045: true + +# MD046/code-block-style - Code block style +MD046: + # Block style + style: "consistent" + +# MD047/single-trailing-newline - Files should end with a single newline character +MD047: true + +# MD048/code-fence-style - Code fence style +MD048: + # Code fence style + style: "consistent" + +# MD049/emphasis-style - Emphasis style should be consistent +MD049: + # Emphasis style should be consistent + style: "consistent" + +# MD050/strong-style - Strong style should be consistent +MD050: + # Strong style should be consistent + style: "consistent" + +# MD051/link-fragments - Link fragments should be valid +MD051: true + +# MD052/reference-links-images - Reference links and images should use a label that is defined +MD052: true + +# MD053/link-image-reference-definitions - Link and image reference definitions should be needed +MD053: + # Ignored definitions + ignored_definitions: + - "//" diff --git a/.pandoc_template.html5 b/.pandoc_template.html5 new file mode 100644 index 00000000..f2146610 --- /dev/null +++ b/.pandoc_template.html5 @@ -0,0 +1,166 @@ +$--| GitHub HTML5 Pandoc Template" v2.2 | 2020/08/12 | pandoc v2.1.1 + + +$-------------------------------------------------------------------------> lang + + +$--============================================================================= +$-- METADATA +$--============================================================================= + + + +$-----------------------------------------------------------------------> author +$for(author-meta)$ + +$endfor$ +$-------------------------------------------------------------------------> date +$if(date-meta)$ + +$endif$ +$---------------------------------------------------------------------> keywords +$if(keywords)$ + +$endif$ +$------------------------------------------------------------------> description +$if(description)$ + +$endif$ +$------------------------------------------------------------------------> title + $if(title-prefix)$$title-prefix$ – $endif$$pagetitle$ +$--=========================================================================== +$-- CSS STYLESHEETS +$--=========================================================================== +$-- Here comes the placeholder (within double braces) that will be replaced +$-- by the CSS file in the finalized template: + +$------------------------------------------------------------------------------- + +$------------------------------------------------------------------------------- +$if(quotes)$ + +$endif$ +$-------------------------------------------------------------> highlighting-css +$if(highlighting-css)$ + +$endif$ +$--------------------------------------------------------------------------> css +$for(css)$ + +$endfor$ +$-------------------------------------------------------------------------> math +$if(math)$ + $math$ +$endif$ +$------------------------------------------------------------------------------- + +$--------------------------------------------------------------> header-includes +$for(header-includes)$ + $header-includes$ +$endfor$ +$------------------------------------------------------------------------------- + + +
+$---------------------------------------------------------------> include-before +$for(include-before)$ +$include-before$ +$endfor$ +$-->>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> IF: title +$if(title)$ +
+

$title$

+$---------------------------------------------------------------------> subtitle +$if(subtitle)$ +

$subtitle$

+$endif$ +$-----------------------------------------------------------------------> author +$for(author)$ +

$author$

+$endfor$ +$-------------------------------------------------------------------------> date +$if(date)$ +

$date$

+$endif$ +$----------------------------------------------------------------------> summary +$if(summary)$ +
+$summary$ +
+$endif$ +$------------------------------------------------------------------------------- +
+$endif$ +$--<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< END IF: title +$--------------------------------------------------------------------------> toc +$if(toc)$ +
+ +
+$endif$ +$-------------------------------------------------------------------------> body +$body$ +$----------------------------------------------------------------> include-after +$for(include-after)$ +$include-after$ +$endfor$ +$------------------------------------------------------------------------------- +
+ + diff --git a/README.md b/README.md index 0ce5f477..08709c45 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,7 @@ satisfied. Otherwise, please run the following command line to install the collection. -``` +```bash ansible-galaxy collection install -r meta/collection-requirements.yml ``` @@ -131,7 +131,7 @@ string, no default - must be specified Password of the `hacluster` user. This user has full access to a cluster. It is recommended to vault encrypt the value, see -https://docs.ansible.com/ansible/latest/user_guide/vault.html for details. + for details. #### `ha_cluster_hacluster_qdevice_password` @@ -139,7 +139,7 @@ string, no default - optional Needed only if a `ha_cluster_quorum` is configured to use a qdevice of type `net` AND password of the `hacluster` user on the qdevice is different from `ha_cluster_hacluster_password`. This user has full access to a cluster. It is recommended to vault encrypt the value, see -https://docs.ansible.com/ansible/latest/user_guide/vault.html for details. + for details. #### `ha_cluster_corosync_key_src` @@ -150,7 +150,7 @@ recommended to have a unique value for each cluster. The key should be 256 bytes of random data. If value is provided, it is recommended to vault encrypt it. See -https://docs.ansible.com/ansible/latest/user_guide/vault.html for details. + for details. If no key is specified, a key already present on the nodes will be used. If nodes don't have the same key, a key from one node will be distributed to other @@ -168,7 +168,7 @@ recommended to have a unique value for each cluster. The key should be 256 bytes of random data. If value is provided, it is recommended to vault encrypt it. See -https://docs.ansible.com/ansible/latest/user_guide/vault.html for details. + for details. If no key is specified, a key already present on the nodes will be used. If nodes don't have the same key, a key from one node will be distributed to other @@ -184,7 +184,7 @@ path to fence-virt or fence-xvm pre-shared key file, default: `null` Authentication key for fence-virt or fence-xvm fence agent. If value is provided, it is recommended to vault encrypt it. See -https://docs.ansible.com/ansible/latest/user_guide/vault.html for details. + for details. If no key is specified, a key already present on the nodes will be used. If nodes don't have the same key, a key from one node will be distributed to other @@ -205,7 +205,7 @@ certificate - key pair already present on the nodes will be used. If certificate - key pair is not present, a random new one will be generated. If private key value is provided, it is recommended to vault encrypt it. See -https://docs.ansible.com/ansible/latest/user_guide/vault.html for details. + for details. If these variables are set, `ha_cluster_regenerate_keys` is ignored for this certificate - key pair. @@ -257,6 +257,7 @@ See also: #### `ha_cluster_pcs_permission_list` structure and default value: + ```yaml ha_cluster_pcs_permission_list: - type: group @@ -758,6 +759,7 @@ pattern matching more resources. Nodes can be specified by their name or a rule. Structure for constraints with resource ID and node name: + ```yaml ha_cluster_constraints_location: - resource: @@ -770,6 +772,7 @@ ha_cluster_constraints_location: - name: option-name value: option-value ``` + * `resource` (mandatory) - Specification of a resource the constraint applies to. * `node` (mandatory) - Name of a node the resource should prefer or avoid. @@ -786,6 +789,7 @@ You may take a look at [an example](#creating-a-cluster-with-resource-constraints). Structure for constraints with resource pattern and node name: + ```yaml ha_cluster_constraints_location: - resource: @@ -798,6 +802,7 @@ ha_cluster_constraints_location: - name: resource-discovery value: resource-discovery-value ``` + * This is the same as the previous type, except the resource specification. * `pattern` (mandatory) - POSIX extended regular expression resource IDs are matched against. @@ -806,6 +811,7 @@ You may take a look at [an example](#creating-a-cluster-with-resource-constraints). Structure for constraints with resource ID and a rule: + ```yaml ha_cluster_constraints_location: - resource: @@ -819,6 +825,7 @@ ha_cluster_constraints_location: - name: resource-discovery value: resource-discovery-value ``` + * `resource` (mandatory) - Specification of a resource the constraint applies to. * `id` (mandatory) - Resource ID. @@ -832,6 +839,7 @@ You may take a look at [an example](#creating-a-cluster-with-resource-constraints). Structure for constraints with resource pattern and a rule: + ```yaml ha_cluster_constraints_location: - resource: @@ -845,6 +853,7 @@ ha_cluster_constraints_location: - name: resource-discovery value: resource-discovery-value ``` + * This is the same as the previous type, except the resource specification. * `pattern` (mandatory) - POSIX extended regular expression resource IDs are matched against. @@ -862,6 +871,7 @@ are two types of colocation constraints: a simple one for two resources, and a set constraint for multiple resources. Structure for simple constraints: + ```yaml ha_cluster_constraints_colocation: - resource_follower: @@ -877,6 +887,7 @@ ha_cluster_constraints_colocation: - name: option-name value: option-value ``` + * `resource_follower` (mandatory) - A resource that should be located relative to `resource_leader`. * `id` (mandatory) - Resource ID. @@ -900,6 +911,7 @@ You may take a look at [an example](#creating-a-cluster-with-resource-constraints). Structure for set constraints: + ```yaml ha_cluster_constraints_colocation: - resource_sets: @@ -916,6 +928,7 @@ ha_cluster_constraints_colocation: - name: option-name value: option-value ``` + * `resource_sets` (mandatory) - List of resource sets. * `resource_ids` (mandatory) - List of resources in a set. * `options` (optional) - List of name-value dictionaries fine-tuning how @@ -936,6 +949,7 @@ order constraints: a simple one for two resources, and a set constraint for multiple resources. Structure for simple constraints: + ```yaml ha_cluster_constraints_order: - resource_first: @@ -951,6 +965,7 @@ ha_cluster_constraints_order: - name: option-name value: option-value ``` + * `resource_first` (mandatory) - Resource that the `resource_then` depends on. * `id` (mandatory) - Resource ID. * `action` (optional) - The action that the resource must complete before an @@ -969,6 +984,7 @@ You may take a look at [an example](#creating-a-cluster-with-resource-constraints). Structure for set constraints: + ```yaml ha_cluster_constraints_order: - resource_sets: @@ -985,6 +1001,7 @@ ha_cluster_constraints_order: - name: option-name value: option-value ``` + * `resource_sets` (mandatory) - List of resource sets. * `resource_ids` (mandatory) - List of resources in a set. * `options` (optional) - List of name-value dictionaries fine-tuning how @@ -1005,6 +1022,7 @@ constraints: a simple one for two resources, and a set constraint for multiple resources. Structure for simple constraints: + ```yaml ha_cluster_constraints_ticket: - resource: @@ -1018,6 +1036,7 @@ ha_cluster_constraints_ticket: - name: option-name value: option-value ``` + * `resource` (mandatory) - Specification of a resource the constraint applies to. * `id` (mandatory) - Resource ID. @@ -1034,6 +1053,7 @@ You may take a look at [an example](#creating-a-cluster-with-resource-constraints). Structure for set constraints: + ```yaml ha_cluster_constraints_ticket: - resource_sets: @@ -1049,6 +1069,7 @@ ha_cluster_constraints_ticket: - name: option-name value: option-value ``` + * `resource_sets` (mandatory) - List of resource sets. * `resource_ids` (mandatory) - List of resources in a set. * `options` (optional) - List of name-value dictionaries fine-tuning how @@ -1063,6 +1084,7 @@ You may take a look at #### `ha_cluster_qnetd` structure and default value: + ```yaml ha_cluster_qnetd: present: boolean @@ -1093,10 +1115,12 @@ example](#configuring-a-cluster-using-a-quorum-device). ### Inventory #### Nodes' names and addresses + Nodes' names and addresses can be configured in inventory. This is optional. If no names or addresses are configured, play's targets will be used. Example inventory with targets `node1` and `node2`: + ```yaml all: hosts: @@ -1123,6 +1147,7 @@ all: have the same number of addresses and the order of the addresses matters #### SBD watchdog and devices + When using SBD, you may optionally configure watchdog and SBD devices for each node in inventory. Even though all SBD devices must be shared to and accessible from all nodes, each node may use different names for the devices. The loaded @@ -1130,6 +1155,7 @@ watchdog modules and used devices may also be different for each node. See also [SBD variables](#ha_cluster_sbd_enabled). Example inventory with targets `node1` and `node2`: + ```yaml all: hosts: @@ -1204,6 +1230,7 @@ in /var/lib/pcsd with the file name FILENAME.crt and FILENAME.key, respectively. ``` ### Creating a cluster running no resources + ```yaml - name: Manage HA cluster with no resources hosts: node1 node2 @@ -1216,6 +1243,7 @@ in /var/lib/pcsd with the file name FILENAME.crt and FILENAME.key, respectively. ``` ### Advanced Corosync configuration + ```yaml - name: Manage HA cluster with Corosync options hosts: node1 node2 @@ -1345,6 +1373,7 @@ SBD stonith resource. ``` ### Configuring cluster properties + ```yaml - hosts: node1 node2 vars: @@ -1362,6 +1391,7 @@ SBD stonith resource. ``` ### Creating a cluster with fencing and several resources + ```yaml - hosts: node1 node2 vars: @@ -1491,6 +1521,7 @@ SBD stonith resource. ``` ### Configuring resource and resource operation defaults + ```yaml - hosts: node1 node2 vars: @@ -1528,6 +1559,7 @@ SBD stonith resource. ``` ### Creating a cluster with resource constraints + ```yaml - hosts: node1 node2 vars: @@ -1663,6 +1695,7 @@ SBD stonith resource. ### Configuring a cluster using a quorum device #### Configuring a quorum device + Before you can add a quorum device to a cluster, you need to set the device up. This is only needed to be done once for each quorum device. Once it has been set up, you can use a quorom device in any number of clusters. @@ -1682,6 +1715,7 @@ Note that you cannot run a quorum device on a cluster node. ``` #### Configuring a cluster to use a quorum device + ```yaml - hosts: node1 node2 vars: @@ -1701,6 +1735,7 @@ Note that you cannot run a quorum device on a cluster node. ``` ### Purging all cluster configuration + ```yaml - hosts: node1 node2 vars: