├── .ansible-lint ├── .gitignore ├── .travis.yml ├── .yamllint ├── LICENSE ├── Pipfile ├── Pipfile.lock ├── README.md ├── defaults └── main.yml ├── files └── heartbeat │ └── command_raw ├── handlers └── main.yml ├── meta └── main.yml ├── molecule └── default │ ├── converge.yml │ ├── molecule.yml │ ├── prepare.yml │ ├── requirements.yml │ └── verify.yml ├── requirements.yml ├── tasks ├── auth │ ├── collect.yml │ ├── exchange.yml │ ├── generate.yml │ └── main.yml ├── config.yml ├── heartbeats.yml ├── hosts.yml ├── main.yml └── packages.yml ├── templates └── corosync.conf.j2 └── tests └── test.yml /.ansible-lint: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iosifpeterfi/ansible-corosync-pacemaker/dea75c6976bdb0239be84d46b8f7295a80642994/.ansible-lint -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | inventory 2 | *.retry 3 | *.log 4 | vars.yml 5 | ._* 6 | *.py[co] 7 | .python-version -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | --- 2 | language: python 3 | services: docker 4 | 5 | python: 6 | - "3.8" 7 | 8 | cache: 9 | - pip: 10 | - directories: 11 | - /home/travis/.cache/pipenv 12 | 13 | branches: 14 | only: 15 | - master 16 | - develop 17 | 18 | before_install: 19 | - python --version 20 | 21 | 22 | install: 23 | - pip3 install pipenv 24 | - pipenv install 25 | 26 | script: 27 | - pipenv run python -V 28 | - pipenv run molecule --version 29 | - pipenv run molecule test 30 | 31 | notifications: 32 | webhooks: https://galaxy.ansible.com/api/v1/notifications/ 33 | -------------------------------------------------------------------------------- /.yamllint: -------------------------------------------------------------------------------- 1 | --- 2 | # Based on ansible-lint config 3 | extends: default 4 | 5 | rules: 6 | braces: 7 | max-spaces-inside: 1 8 | level: error 9 | brackets: 10 | max-spaces-inside: 1 11 | level: error 12 | colons: 13 | max-spaces-after: -1 14 | level: error 15 | commas: 16 | max-spaces-after: -1 17 | level: error 18 | comments: disable 19 | comments-indentation: disable 20 | document-start: disable 21 | empty-lines: 22 | max: 3 23 | level: error 24 | hyphens: 25 | level: error 26 | indentation: disable 27 | key-duplicates: enable 28 | line-length: disable 29 | new-line-at-end-of-file: disable 30 | new-lines: 31 | type: unix 32 | trailing-spaces: disable 33 | truthy: disable 34 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2019 Marian C 4 | Copyright (c) 2021 Iosif Peterfi 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | -------------------------------------------------------------------------------- /Pipfile: -------------------------------------------------------------------------------- 1 | [[source]] 2 | name = "pypi" 3 | url = "https://pypi.org/simple" 4 | verify_ssl = true 5 | 6 | [dev-packages] 7 | 8 | [packages] 9 | ansible = "==2.9.15" 10 | ansible-lint = "==4.3.7" 11 | yamllint = "==1.25.0" 12 | molecule = "==3.2.0a0" 13 | molecule-docker = "==0.3.3" 14 | 15 | [requires] 16 | python_version = "3.8" 17 | 18 | 19 | [pipenv] 20 | allow_prereleases = true 21 | -------------------------------------------------------------------------------- /Pipfile.lock: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "hash": { 4 | "sha256": "e25bd7598189e3cd5dd045ec0f25369cc21927150314439a112606fc1d43f9a1" 5 | }, 6 | "pipfile-spec": 6, 7 | "requires": { 8 | "python_version": "3.8" 9 | }, 10 | "sources": [ 11 | { 12 | "name": "pypi", 13 | "url": "https://pypi.org/simple", 14 | "verify_ssl": true 15 | } 16 | ] 17 | }, 18 | "default": { 19 | "ansible": { 20 | "hashes": [ 21 | "sha256:736a19fa6d608b4df2d6b48d31fec057b3f95abf62b7fda69ffa4a743e2f55b6" 22 | ], 23 | "index": "pypi", 24 | "version": "==2.9.15" 25 | }, 26 | "ansible-lint": { 27 | "hashes": [ 28 | "sha256:1012fc3f5c4c0c58eece515860f19c34c5088faa5be412eec6fae5b45bda9c4f", 29 | "sha256:300e841f690b556a08d44902d6414283dc101079b27909e3a892f1cf1d10d7ff" 30 | ], 31 | "index": "pypi", 32 | "version": "==4.3.7" 33 | }, 34 | "arrow": { 35 | "hashes": [ 36 | "sha256:e098abbd9af3665aea81bdd6c869e93af4feb078e98468dd351c383af187aac5", 37 | "sha256:ff08d10cda1d36c68657d6ad20d74fbea493d980f8b2d45344e00d6ed2bf6ed4" 38 | ], 39 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", 40 | "version": "==0.17.0" 41 | }, 42 | "bcrypt": { 43 | "hashes": [ 44 | "sha256:5b93c1726e50a93a033c36e5ca7fdcd29a5c7395af50a6892f5d9e7c6cfbfb29", 45 | "sha256:63d4e3ff96188e5898779b6057878fecf3f11cfe6ec3b313ea09955d587ec7a7", 46 | "sha256:81fec756feff5b6818ea7ab031205e1d323d8943d237303baca2c5f9c7846f34", 47 | "sha256:a67fb841b35c28a59cebed05fbd3e80eea26e6d75851f0574a9273c80f3e9b55", 48 | "sha256:c95d4cbebffafcdd28bd28bb4e25b31c50f6da605c81ffd9ad8a3d1b2ab7b1b6", 49 | "sha256:cd1ea2ff3038509ea95f687256c46b79f5fc382ad0aa3664d200047546d511d1", 50 | "sha256:cdcdcb3972027f83fe24a48b1e90ea4b584d35f1cc279d76de6fc4b13376239d" 51 | ], 52 | "markers": "python_version >= '3.6'", 53 | "version": "==3.2.0" 54 | }, 55 | "binaryornot": { 56 | "hashes": [ 57 | "sha256:359501dfc9d40632edc9fac890e19542db1a287bbcfa58175b66658392018061", 58 | "sha256:b8b71173c917bddcd2c16070412e369c3ed7f0528926f70cac18a6c97fd563e4" 59 | ], 60 | "version": "==0.4.4" 61 | }, 62 | "cerberus": { 63 | "hashes": [ 64 | "sha256:302e6694f206dd85cb63f13fd5025b31ab6d38c99c50c6d769f8fa0b0f299589" 65 | ], 66 | "markers": "python_version >= '2.7'", 67 | "version": "==1.3.2" 68 | }, 69 | "certifi": { 70 | "hashes": [ 71 | "sha256:5930595817496dd21bb8dc35dad090f1c2cd0adfaf21204bf6732ca5d8ee34d3", 72 | "sha256:8fc0819f1f30ba15bdb34cceffb9ef04d99f420f68eb75d901e9560b8749fc41" 73 | ], 74 | "version": "==2020.6.20" 75 | }, 76 | "cffi": { 77 | "hashes": [ 78 | "sha256:005f2bfe11b6745d726dbb07ace4d53f057de66e336ff92d61b8c7e9c8f4777d", 79 | "sha256:09e96138280241bd355cd585148dec04dbbedb4f46128f340d696eaafc82dd7b", 80 | "sha256:0b1ad452cc824665ddc682400b62c9e4f5b64736a2ba99110712fdee5f2505c4", 81 | "sha256:0ef488305fdce2580c8b2708f22d7785ae222d9825d3094ab073e22e93dfe51f", 82 | "sha256:15f351bed09897fbda218e4db5a3d5c06328862f6198d4fb385f3e14e19decb3", 83 | "sha256:22399ff4870fb4c7ef19fff6eeb20a8bbf15571913c181c78cb361024d574579", 84 | "sha256:23e5d2040367322824605bc29ae8ee9175200b92cb5483ac7d466927a9b3d537", 85 | "sha256:2791f68edc5749024b4722500e86303a10d342527e1e3bcac47f35fbd25b764e", 86 | "sha256:2f9674623ca39c9ebe38afa3da402e9326c245f0f5ceff0623dccdac15023e05", 87 | "sha256:3363e77a6176afb8823b6e06db78c46dbc4c7813b00a41300a4873b6ba63b171", 88 | "sha256:33c6cdc071ba5cd6d96769c8969a0531be2d08c2628a0143a10a7dcffa9719ca", 89 | "sha256:3b8eaf915ddc0709779889c472e553f0d3e8b7bdf62dab764c8921b09bf94522", 90 | "sha256:3cb3e1b9ec43256c4e0f8d2837267a70b0e1ca8c4f456685508ae6106b1f504c", 91 | "sha256:3eeeb0405fd145e714f7633a5173318bd88d8bbfc3dd0a5751f8c4f70ae629bc", 92 | "sha256:44f60519595eaca110f248e5017363d751b12782a6f2bd6a7041cba275215f5d", 93 | "sha256:4d7c26bfc1ea9f92084a1d75e11999e97b62d63128bcc90c3624d07813c52808", 94 | "sha256:529c4ed2e10437c205f38f3691a68be66c39197d01062618c55f74294a4a4828", 95 | "sha256:6642f15ad963b5092d65aed022d033c77763515fdc07095208f15d3563003869", 96 | "sha256:85ba797e1de5b48aa5a8427b6ba62cf69607c18c5d4eb747604b7302f1ec382d", 97 | "sha256:8f0f1e499e4000c4c347a124fa6a27d37608ced4fe9f7d45070563b7c4c370c9", 98 | "sha256:a624fae282e81ad2e4871bdb767e2c914d0539708c0f078b5b355258293c98b0", 99 | "sha256:b0358e6fefc74a16f745afa366acc89f979040e0cbc4eec55ab26ad1f6a9bfbc", 100 | "sha256:bbd2f4dfee1079f76943767fce837ade3087b578aeb9f69aec7857d5bf25db15", 101 | "sha256:bf39a9e19ce7298f1bd6a9758fa99707e9e5b1ebe5e90f2c3913a47bc548747c", 102 | "sha256:c11579638288e53fc94ad60022ff1b67865363e730ee41ad5e6f0a17188b327a", 103 | "sha256:c150eaa3dadbb2b5339675b88d4573c1be3cb6f2c33a6c83387e10cc0bf05bd3", 104 | "sha256:c53af463f4a40de78c58b8b2710ade243c81cbca641e34debf3396a9640d6ec1", 105 | "sha256:cb763ceceae04803adcc4e2d80d611ef201c73da32d8f2722e9d0ab0c7f10768", 106 | "sha256:cc75f58cdaf043fe6a7a6c04b3b5a0e694c6a9e24050967747251fb80d7bce0d", 107 | "sha256:d80998ed59176e8cba74028762fbd9b9153b9afc71ea118e63bbf5d4d0f9552b", 108 | "sha256:de31b5164d44ef4943db155b3e8e17929707cac1e5bd2f363e67a56e3af4af6e", 109 | "sha256:e66399cf0fc07de4dce4f588fc25bfe84a6d1285cc544e67987d22663393926d", 110 | "sha256:f0620511387790860b249b9241c2f13c3a80e21a73e0b861a2df24e9d6f56730", 111 | "sha256:f4eae045e6ab2bb54ca279733fe4eb85f1effda392666308250714e01907f394", 112 | "sha256:f92cdecb618e5fa4658aeb97d5eb3d2f47aa94ac6477c6daf0f306c5a3b9e6b1", 113 | "sha256:f92f789e4f9241cd262ad7a555ca2c648a98178a953af117ef7fad46aa1d5591" 114 | ], 115 | "version": "==1.14.3" 116 | }, 117 | "chardet": { 118 | "hashes": [ 119 | "sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae", 120 | "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691" 121 | ], 122 | "version": "==3.0.4" 123 | }, 124 | "click": { 125 | "hashes": [ 126 | "sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a", 127 | "sha256:dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc" 128 | ], 129 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", 130 | "version": "==7.1.2" 131 | }, 132 | "click-completion": { 133 | "hashes": [ 134 | "sha256:5bf816b81367e638a190b6e91b50779007d14301b3f9f3145d68e3cade7bce86" 135 | ], 136 | "version": "==0.5.2" 137 | }, 138 | "click-help-colors": { 139 | "hashes": [ 140 | "sha256:0d841a4058ec88c47f93ff6f32547a055f8e0a0273f6bd6cb3e08430f195131d", 141 | "sha256:119e5faf69cfc919c995c5962326ac8fd87f11e56a371af594e3dfd8458f4c6e" 142 | ], 143 | "version": "==0.8" 144 | }, 145 | "colorama": { 146 | "hashes": [ 147 | "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b", 148 | "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2" 149 | ], 150 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", 151 | "version": "==0.4.4" 152 | }, 153 | "commonmark": { 154 | "hashes": [ 155 | "sha256:452f9dc859be7f06631ddcb328b6919c67984aca654e5fefb3914d54691aed60", 156 | "sha256:da2f38c92590f83de410ba1a3cbceafbc74fee9def35f9251ba9a971d6d66fd9" 157 | ], 158 | "version": "==0.9.1" 159 | }, 160 | "cookiecutter": { 161 | "hashes": [ 162 | "sha256:430eb882d028afb6102c084bab6cf41f6559a77ce9b18dc6802e3bc0cc5f4a30", 163 | "sha256:efb6b2d4780feda8908a873e38f0e61778c23f6a2ea58215723bcceb5b515dac" 164 | ], 165 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", 166 | "version": "==1.7.2" 167 | }, 168 | "cryptography": { 169 | "hashes": [ 170 | "sha256:07ca431b788249af92764e3be9a488aa1d39a0bc3be313d826bbec690417e538", 171 | "sha256:13b88a0bd044b4eae1ef40e265d006e34dbcde0c2f1e15eb9896501b2d8f6c6f", 172 | "sha256:32434673d8505b42c0de4de86da8c1620651abd24afe91ae0335597683ed1b77", 173 | "sha256:3cd75a683b15576cfc822c7c5742b3276e50b21a06672dc3a800a2d5da4ecd1b", 174 | "sha256:4e7268a0ca14536fecfdf2b00297d4e407da904718658c1ff1961c713f90fd33", 175 | "sha256:545a8550782dda68f8cdc75a6e3bf252017aa8f75f19f5a9ca940772fc0cb56e", 176 | "sha256:55d0b896631412b6f0c7de56e12eb3e261ac347fbaa5d5e705291a9016e5f8cb", 177 | "sha256:5849d59358547bf789ee7e0d7a9036b2d29e9a4ddf1ce5e06bb45634f995c53e", 178 | "sha256:6dc59630ecce8c1f558277ceb212c751d6730bd12c80ea96b4ac65637c4f55e7", 179 | "sha256:7117319b44ed1842c617d0a452383a5a052ec6aa726dfbaffa8b94c910444297", 180 | "sha256:75e8e6684cf0034f6bf2a97095cb95f81537b12b36a8fedf06e73050bb171c2d", 181 | "sha256:7b8d9d8d3a9bd240f453342981f765346c87ade811519f98664519696f8e6ab7", 182 | "sha256:a035a10686532b0587d58a606004aa20ad895c60c4d029afa245802347fab57b", 183 | "sha256:a4e27ed0b2504195f855b52052eadcc9795c59909c9d84314c5408687f933fc7", 184 | "sha256:a733671100cd26d816eed39507e585c156e4498293a907029969234e5e634bc4", 185 | "sha256:a75f306a16d9f9afebfbedc41c8c2351d8e61e818ba6b4c40815e2b5740bb6b8", 186 | "sha256:bd717aa029217b8ef94a7d21632a3bb5a4e7218a4513d2521c2a2fd63011e98b", 187 | "sha256:d25cecbac20713a7c3bc544372d42d8eafa89799f492a43b79e1dfd650484851", 188 | "sha256:d26a2557d8f9122f9bf445fc7034242f4375bd4e95ecda007667540270965b13", 189 | "sha256:d3545829ab42a66b84a9aaabf216a4dce7f16dbc76eb69be5c302ed6b8f4a29b", 190 | "sha256:d3d5e10be0cf2a12214ddee45c6bd203dab435e3d83b4560c03066eda600bfe3", 191 | "sha256:efe15aca4f64f3a7ea0c09c87826490e50ed166ce67368a68f315ea0807a20df" 192 | ], 193 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", 194 | "version": "==3.2.1" 195 | }, 196 | "distro": { 197 | "hashes": [ 198 | "sha256:0e58756ae38fbd8fc3020d54badb8eae17c5b9dcbed388b17bb55b8a5928df92", 199 | "sha256:df74eed763e18d10d0da624258524ae80486432cd17392d9c3d96f5e83cd2799" 200 | ], 201 | "version": "==1.5.0" 202 | }, 203 | "docker": { 204 | "hashes": [ 205 | "sha256:13966471e8bc23b36bfb3a6fb4ab75043a5ef1dac86516274777576bed3b9828", 206 | "sha256:bad94b8dd001a8a4af19ce4becc17f41b09f228173ffe6a4e0355389eef142f2" 207 | ], 208 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", 209 | "version": "==4.3.1" 210 | }, 211 | "idna": { 212 | "hashes": [ 213 | "sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6", 214 | "sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0" 215 | ], 216 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", 217 | "version": "==2.10" 218 | }, 219 | "jinja2": { 220 | "hashes": [ 221 | "sha256:89aab215427ef59c34ad58735269eb58b1a5808103067f7bb9d5836c651b3bb0", 222 | "sha256:f0a4641d3cf955324a89c04f3d94663aa4d638abe8f733ecd3582848e1c37035" 223 | ], 224 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", 225 | "version": "==2.11.2" 226 | }, 227 | "jinja2-time": { 228 | "hashes": [ 229 | "sha256:d14eaa4d315e7688daa4969f616f226614350c48730bfa1692d2caebd8c90d40", 230 | "sha256:d3eab6605e3ec8b7a0863df09cc1d23714908fa61aa6986a845c20ba488b4efa" 231 | ], 232 | "version": "==0.2.0" 233 | }, 234 | "markupsafe": { 235 | "hashes": [ 236 | "sha256:00bc623926325b26bb9605ae9eae8a215691f33cae5df11ca5424f06f2d1f473", 237 | "sha256:09027a7803a62ca78792ad89403b1b7a73a01c8cb65909cd876f7fcebd79b161", 238 | "sha256:09c4b7f37d6c648cb13f9230d847adf22f8171b1ccc4d5682398e77f40309235", 239 | "sha256:1027c282dad077d0bae18be6794e6b6b8c91d58ed8a8d89a89d59693b9131db5", 240 | "sha256:13d3144e1e340870b25e7b10b98d779608c02016d5184cfb9927a9f10c689f42", 241 | "sha256:24982cc2533820871eba85ba648cd53d8623687ff11cbb805be4ff7b4c971aff", 242 | "sha256:29872e92839765e546828bb7754a68c418d927cd064fd4708fab9fe9c8bb116b", 243 | "sha256:43a55c2930bbc139570ac2452adf3d70cdbb3cfe5912c71cdce1c2c6bbd9c5d1", 244 | "sha256:46c99d2de99945ec5cb54f23c8cd5689f6d7177305ebff350a58ce5f8de1669e", 245 | "sha256:500d4957e52ddc3351cabf489e79c91c17f6e0899158447047588650b5e69183", 246 | "sha256:535f6fc4d397c1563d08b88e485c3496cf5784e927af890fb3c3aac7f933ec66", 247 | "sha256:596510de112c685489095da617b5bcbbac7dd6384aeebeda4df6025d0256a81b", 248 | "sha256:62fe6c95e3ec8a7fad637b7f3d372c15ec1caa01ab47926cfdf7a75b40e0eac1", 249 | "sha256:6788b695d50a51edb699cb55e35487e430fa21f1ed838122d722e0ff0ac5ba15", 250 | "sha256:6dd73240d2af64df90aa7c4e7481e23825ea70af4b4922f8ede5b9e35f78a3b1", 251 | "sha256:717ba8fe3ae9cc0006d7c451f0bb265ee07739daf76355d06366154ee68d221e", 252 | "sha256:79855e1c5b8da654cf486b830bd42c06e8780cea587384cf6545b7d9ac013a0b", 253 | "sha256:7c1699dfe0cf8ff607dbdcc1e9b9af1755371f92a68f706051cc8c37d447c905", 254 | "sha256:88e5fcfb52ee7b911e8bb6d6aa2fd21fbecc674eadd44118a9cc3863f938e735", 255 | "sha256:8defac2f2ccd6805ebf65f5eeb132adcf2ab57aa11fdf4c0dd5169a004710e7d", 256 | "sha256:98c7086708b163d425c67c7a91bad6e466bb99d797aa64f965e9d25c12111a5e", 257 | "sha256:9add70b36c5666a2ed02b43b335fe19002ee5235efd4b8a89bfcf9005bebac0d", 258 | "sha256:9bf40443012702a1d2070043cb6291650a0841ece432556f784f004937f0f32c", 259 | "sha256:ade5e387d2ad0d7ebf59146cc00c8044acbd863725f887353a10df825fc8ae21", 260 | "sha256:b00c1de48212e4cc9603895652c5c410df699856a2853135b3967591e4beebc2", 261 | "sha256:b1282f8c00509d99fef04d8ba936b156d419be841854fe901d8ae224c59f0be5", 262 | "sha256:b2051432115498d3562c084a49bba65d97cf251f5a331c64a12ee7e04dacc51b", 263 | "sha256:ba59edeaa2fc6114428f1637ffff42da1e311e29382d81b339c1817d37ec93c6", 264 | "sha256:c8716a48d94b06bb3b2524c2b77e055fb313aeb4ea620c8dd03a105574ba704f", 265 | "sha256:cd5df75523866410809ca100dc9681e301e3c27567cf498077e8551b6d20e42f", 266 | "sha256:cdb132fc825c38e1aeec2c8aa9338310d29d337bebbd7baa06889d09a60a1fa2", 267 | "sha256:e249096428b3ae81b08327a63a485ad0878de3fb939049038579ac0ef61e17e7", 268 | "sha256:e8313f01ba26fbbe36c7be1966a7b7424942f670f38e666995b88d012765b9be" 269 | ], 270 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", 271 | "version": "==1.1.1" 272 | }, 273 | "molecule": { 274 | "hashes": [ 275 | "sha256:608252d8aab17ae3554d1c51e077ea2f82e7c50d7db13669bb2f24302ce66c68", 276 | "sha256:99a8a406005a481910548f61d18defa5f826a78e3b3ec77d16c3be0f6c3e702b" 277 | ], 278 | "index": "pypi", 279 | "version": "==3.2.0a0" 280 | }, 281 | "molecule-docker": { 282 | "hashes": [ 283 | "sha256:1799d94dc9dcf3d9205b359e5ddecaaed5083e8ae39221570e57c9f1f5d45fc4", 284 | "sha256:5e0a633c86aa4d27603e5043be4d71d91fa15cbedf61345a5c17aab2421505fd" 285 | ], 286 | "index": "pypi", 287 | "version": "==0.3.3" 288 | }, 289 | "packaging": { 290 | "hashes": [ 291 | "sha256:4357f74f47b9c12db93624a82154e9b120fa8293699949152b22065d556079f8", 292 | "sha256:998416ba6962ae7fbd6596850b80e17859a5753ba17c32284f67bfff33784181" 293 | ], 294 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", 295 | "version": "==20.4" 296 | }, 297 | "paramiko": { 298 | "hashes": [ 299 | "sha256:4f3e316fef2ac628b05097a637af35685183111d4bc1b5979bd397c2ab7b5898", 300 | "sha256:7f36f4ba2c0d81d219f4595e35f70d56cc94f9ac40a6acdf51d6ca210ce65035" 301 | ], 302 | "version": "==2.7.2" 303 | }, 304 | "pathspec": { 305 | "hashes": [ 306 | "sha256:7d91249d21749788d07a2d0f94147accd8f845507400749ea19c1ec9054a12b0", 307 | "sha256:da45173eb3a6f2a5a487efba21f050af2b41948be6ab52b6a1e3ff22bb8b7061" 308 | ], 309 | "version": "==0.8.0" 310 | }, 311 | "pexpect": { 312 | "hashes": [ 313 | "sha256:0b48a55dcb3c05f3329815901ea4fc1537514d6ba867a152b581d69ae3710937", 314 | "sha256:fc65a43959d153d0114afe13997d439c22823a27cefceb5ff35c2178c6784c0c" 315 | ], 316 | "version": "==4.8.0" 317 | }, 318 | "pluggy": { 319 | "hashes": [ 320 | "sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0", 321 | "sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d" 322 | ], 323 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", 324 | "version": "==0.13.1" 325 | }, 326 | "poyo": { 327 | "hashes": [ 328 | "sha256:3e2ca8e33fdc3c411cd101ca395668395dd5dc7ac775b8e809e3def9f9fe041a", 329 | "sha256:e26956aa780c45f011ca9886f044590e2d8fd8b61db7b1c1cf4e0869f48ed4dd" 330 | ], 331 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", 332 | "version": "==0.5.0" 333 | }, 334 | "ptyprocess": { 335 | "hashes": [ 336 | "sha256:923f299cc5ad920c68f2bc0bc98b75b9f838b93b599941a6b63ddbc2476394c0", 337 | "sha256:d7cc528d76e76342423ca640335bd3633420dc1366f258cb31d05e865ef5ca1f" 338 | ], 339 | "version": "==0.6.0" 340 | }, 341 | "pycparser": { 342 | "hashes": [ 343 | "sha256:2d475327684562c3a96cc71adf7dc8c4f0565175cf86b6d7a404ff4c771f15f0", 344 | "sha256:7582ad22678f0fcd81102833f60ef8d0e57288b6b5fb00323d101be910e35705" 345 | ], 346 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", 347 | "version": "==2.20" 348 | }, 349 | "pygments": { 350 | "hashes": [ 351 | "sha256:381985fcc551eb9d37c52088a32914e00517e57f4a21609f48141ba08e193fa0", 352 | "sha256:88a0bbcd659fcb9573703957c6b9cff9fab7295e6e76db54c9d00ae42df32773" 353 | ], 354 | "markers": "python_version >= '3.5'", 355 | "version": "==2.7.2" 356 | }, 357 | "pynacl": { 358 | "hashes": [ 359 | "sha256:06cbb4d9b2c4bd3c8dc0d267416aaed79906e7b33f114ddbf0911969794b1cc4", 360 | "sha256:11335f09060af52c97137d4ac54285bcb7df0cef29014a1a4efe64ac065434c4", 361 | "sha256:2fe0fc5a2480361dcaf4e6e7cea00e078fcda07ba45f811b167e3f99e8cff574", 362 | "sha256:30f9b96db44e09b3304f9ea95079b1b7316b2b4f3744fe3aaecccd95d547063d", 363 | "sha256:4e10569f8cbed81cb7526ae137049759d2a8d57726d52c1a000a3ce366779634", 364 | "sha256:511d269ee845037b95c9781aa702f90ccc36036f95d0f31373a6a79bd8242e25", 365 | "sha256:537a7ccbea22905a0ab36ea58577b39d1fa9b1884869d173b5cf111f006f689f", 366 | "sha256:54e9a2c849c742006516ad56a88f5c74bf2ce92c9f67435187c3c5953b346505", 367 | "sha256:757250ddb3bff1eecd7e41e65f7f833a8405fede0194319f87899690624f2122", 368 | "sha256:7757ae33dae81c300487591c68790dfb5145c7d03324000433d9a2c141f82af7", 369 | "sha256:7c6092102219f59ff29788860ccb021e80fffd953920c4a8653889c029b2d420", 370 | "sha256:8122ba5f2a2169ca5da936b2e5a511740ffb73979381b4229d9188f6dcb22f1f", 371 | "sha256:9c4a7ea4fb81536c1b1f5cc44d54a296f96ae78c1ebd2311bd0b60be45a48d96", 372 | "sha256:c914f78da4953b33d4685e3cdc7ce63401247a21425c16a39760e282075ac4a6", 373 | "sha256:cd401ccbc2a249a47a3a1724c2918fcd04be1f7b54eb2a5a71ff915db0ac51c6", 374 | "sha256:d452a6746f0a7e11121e64625109bc4468fc3100452817001dbe018bb8b08514", 375 | "sha256:ea6841bc3a76fa4942ce00f3bda7d436fda21e2d91602b9e21b7ca9ecab8f3ff", 376 | "sha256:f8851ab9041756003119368c1e6cd0b9c631f46d686b3904b18c0139f4419f80" 377 | ], 378 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", 379 | "version": "==1.4.0" 380 | }, 381 | "pyparsing": { 382 | "hashes": [ 383 | "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1", 384 | "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b" 385 | ], 386 | "markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'", 387 | "version": "==2.4.7" 388 | }, 389 | "python-dateutil": { 390 | "hashes": [ 391 | "sha256:73ebfe9dbf22e832286dafa60473e4cd239f8592f699aa5adaf10050e6e1823c", 392 | "sha256:75bb3f31ea686f1197762692a9ee6a7550b59fc6ca3a1f4b5d7e32fb98e2da2a" 393 | ], 394 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", 395 | "version": "==2.8.1" 396 | }, 397 | "python-slugify": { 398 | "hashes": [ 399 | "sha256:69a517766e00c1268e5bbfc0d010a0a8508de0b18d30ad5a1ff357f8ae724270" 400 | ], 401 | "version": "==4.0.1" 402 | }, 403 | "pyyaml": { 404 | "hashes": [ 405 | "sha256:06a0d7ba600ce0b2d2fe2e78453a470b5a6e000a985dd4a4e54e436cc36b0e97", 406 | "sha256:240097ff019d7c70a4922b6869d8a86407758333f02203e0fc6ff79c5dcede76", 407 | "sha256:4f4b913ca1a7319b33cfb1369e91e50354d6f07a135f3b901aca02aa95940bd2", 408 | "sha256:69f00dca373f240f842b2931fb2c7e14ddbacd1397d57157a9b005a6a9942648", 409 | "sha256:73f099454b799e05e5ab51423c7bcf361c58d3206fa7b0d555426b1f4d9a3eaf", 410 | "sha256:74809a57b329d6cc0fdccee6318f44b9b8649961fa73144a98735b0aaf029f1f", 411 | "sha256:7739fc0fa8205b3ee8808aea45e968bc90082c10aef6ea95e855e10abf4a37b2", 412 | "sha256:95f71d2af0ff4227885f7a6605c37fd53d3a106fcab511b8860ecca9fcf400ee", 413 | "sha256:b8eac752c5e14d3eca0e6dd9199cd627518cb5ec06add0de9d32baeee6fe645d", 414 | "sha256:cc8955cfbfc7a115fa81d85284ee61147059a753344bc51098f3ccd69b0d7e0c", 415 | "sha256:d13155f591e6fcc1ec3b30685d50bf0711574e2c0dfffd7644babf8b5102ca1a" 416 | ], 417 | "version": "==5.3.1" 418 | }, 419 | "requests": { 420 | "hashes": [ 421 | "sha256:b3559a131db72c33ee969480840fff4bb6dd111de7dd27c8ee1f820f4f00231b", 422 | "sha256:fe75cc94a9443b9246fc7049224f75604b113c36acb93f87b80ed42c44cbb898" 423 | ], 424 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", 425 | "version": "==2.24.0" 426 | }, 427 | "rich": { 428 | "hashes": [ 429 | "sha256:05f1cf4dc191c483867b098d8572546de266440d61911d8270069023e325d14a", 430 | "sha256:5dd934a0f8953b59d9a5d8d58864012174f0b5ad2de687fd04f4df195f7f7066" 431 | ], 432 | "markers": "python_version >= '3.6' and python_version < '4.0'", 433 | "version": "==9.1.0" 434 | }, 435 | "ruamel.yaml": { 436 | "hashes": [ 437 | "sha256:012b9470a0ea06e4e44e99e7920277edf6b46eee0232a04487ea73a7386340a5", 438 | "sha256:076cc0bc34f1966d920a49f18b52b6ad559fbe656a0748e3535cf7b3f29ebf9e" 439 | ], 440 | "markers": "python_version >= '3.7'", 441 | "version": "==0.16.12" 442 | }, 443 | "ruamel.yaml.clib": { 444 | "hashes": [ 445 | "sha256:058a1cc3df2a8aecc12f983a48bda99315cebf55a3b3a5463e37bb599b05727b", 446 | "sha256:2602e91bd5c1b874d6f93d3086f9830f3e907c543c7672cf293a97c3fabdcd91", 447 | "sha256:28116f204103cb3a108dfd37668f20abe6e3cafd0d3fd40dba126c732457b3cc", 448 | "sha256:2d24bd98af676f4990c4d715bcdc2a60b19c56a3fb3a763164d2d8ca0e806ba7", 449 | "sha256:30dca9bbcbb1cc858717438218d11eafb78666759e5094dd767468c0d577a7e7", 450 | "sha256:44c7b0498c39f27795224438f1a6be6c5352f82cb887bc33d962c3a3acc00df6", 451 | "sha256:464e66a04e740d754170be5e740657a3b3b6d2bcc567f0c3437879a6e6087ff6", 452 | "sha256:4df5019e7783d14b79217ad9c56edf1ba7485d614ad5a385d1b3c768635c81c0", 453 | "sha256:4e52c96ca66de04be42ea2278012a2342d89f5e82b4512fb6fb7134e377e2e62", 454 | "sha256:5254af7d8bdf4d5484c089f929cb7f5bafa59b4f01d4f48adda4be41e6d29f99", 455 | "sha256:52ae5739e4b5d6317b52f5b040b1b6639e8af68a5b8fd606a8b08658fbd0cab5", 456 | "sha256:53b9dd1abd70e257a6e32f934ebc482dac5edb8c93e23deb663eac724c30b026", 457 | "sha256:73b3d43e04cc4b228fa6fa5d796409ece6fcb53a6c270eb2048109cbcbc3b9c2", 458 | "sha256:74161d827407f4db9072011adcfb825b5258a5ccb3d2cd518dd6c9edea9e30f1", 459 | "sha256:839dd72545ef7ba78fd2aa1a5dd07b33696adf3e68fae7f31327161c1093001b", 460 | "sha256:8e8fd0a22c9d92af3a34f91e8a2594eeb35cba90ab643c5e0e643567dc8be43e", 461 | "sha256:a873e4d4954f865dcb60bdc4914af7eaae48fb56b60ed6daa1d6251c72f5337c", 462 | "sha256:ab845f1f51f7eb750a78937be9f79baea4a42c7960f5a94dde34e69f3cce1988", 463 | "sha256:b1e981fe1aff1fd11627f531524826a4dcc1f26c726235a52fcb62ded27d150f", 464 | "sha256:b4b0d31f2052b3f9f9b5327024dc629a253a83d8649d4734ca7f35b60ec3e9e5", 465 | "sha256:c6ac7e45367b1317e56f1461719c853fd6825226f45b835df7436bb04031fd8a", 466 | "sha256:daf21aa33ee9b351f66deed30a3d450ab55c14242cfdfcd377798e2c0d25c9f1", 467 | "sha256:e9f7d1d8c26a6a12c23421061f9022bb62704e38211fe375c645485f38df34a2", 468 | "sha256:f6061a31880c1ed6b6ce341215336e2f3d0c1deccd84957b6fa8ca474b41e89f" 469 | ], 470 | "markers": "python_version < '3.9' and platform_python_implementation == 'CPython'", 471 | "version": "==0.2.2" 472 | }, 473 | "selinux": { 474 | "hashes": [ 475 | "sha256:820adcf1b4451c9cc7759848797703263ba0eb6a4cad76d73548a9e0d57b7926", 476 | "sha256:d435f514e834e3fdc0941f6a29d086b80b2ea51b28112aee6254bd104ee42a74" 477 | ], 478 | "markers": "sys_platform == 'linux' and sys_platform == 'linux'", 479 | "version": "==0.2.1" 480 | }, 481 | "shellingham": { 482 | "hashes": [ 483 | "sha256:576c1982bea0ba82fb46c36feb951319d7f42214a82634233f58b40d858a751e", 484 | "sha256:7f6206ae169dc1a03af8a138681b3f962ae61cc93ade84d0585cca3aaf770044" 485 | ], 486 | "markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'", 487 | "version": "==1.3.2" 488 | }, 489 | "six": { 490 | "hashes": [ 491 | "sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259", 492 | "sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced" 493 | ], 494 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", 495 | "version": "==1.15.0" 496 | }, 497 | "subprocess-tee": { 498 | "hashes": [ 499 | "sha256:51ac728467619e4d1688fc8607e3104f95e079f8c9cf046383eb7867f2b5e8cd", 500 | "sha256:c47c6da612caac466cb2d849ef2859d6dccf09e899f59611ed729aa65ca4c91a" 501 | ], 502 | "markers": "python_version >= '3.6'", 503 | "version": "==0.1.3" 504 | }, 505 | "text-unidecode": { 506 | "hashes": [ 507 | "sha256:1311f10e8b895935241623731c2ba64f4c455287888b18189350b67134a822e8", 508 | "sha256:bad6603bb14d279193107714b288be206cac565dfa49aa5b105294dd5c4aab93" 509 | ], 510 | "version": "==1.3" 511 | }, 512 | "typing-extensions": { 513 | "hashes": [ 514 | "sha256:7cb407020f00f7bfc3cb3e7881628838e69d8f3fcab2f64742a5e76b2f841918", 515 | "sha256:99d4073b617d30288f569d3f13d2bd7548c3a7e4c8de87db09a9d29bb3a4a60c", 516 | "sha256:dafc7639cde7f1b6e1acc0f457842a83e722ccca8eef5270af2d74792619a89f" 517 | ], 518 | "version": "==3.7.4.3" 519 | }, 520 | "urllib3": { 521 | "hashes": [ 522 | "sha256:8d7eaa5a82a1cac232164990f04874c594c9453ec55eef02eab885aa02fc17a2", 523 | "sha256:f5321fbe4bf3fefa0efd0bfe7fb14e90909eb62a48ccda331726b4319897dd5e" 524 | ], 525 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4'", 526 | "version": "==1.25.11" 527 | }, 528 | "websocket-client": { 529 | "hashes": [ 530 | "sha256:0fc45c961324d79c781bab301359d5a1b00b13ad1b10415a4780229ef71a5549", 531 | "sha256:d735b91d6d1692a6a181f2a8c9e0238e5f6373356f561bb9dc4c7af36f452010" 532 | ], 533 | "version": "==0.57.0" 534 | }, 535 | "yamllint": { 536 | "hashes": [ 537 | "sha256:b1549cbe5b47b6ba67bdeea31720f5c51431a4d0c076c1557952d841f7223519", 538 | "sha256:c7be4d0d2584a1b561498fa9acb77ad22eb434a109725c7781373ae496d823b3" 539 | ], 540 | "index": "pypi", 541 | "version": "==1.25.0" 542 | } 543 | }, 544 | "develop": {} 545 | } 546 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

Pacemaker and Corosync cluster ansible role

2 |
3 | 4 |
5 | 6 | Ansible Galaxy 7 | 8 | 9 | Ansible Quality Score 10 | 11 | 12 | MIT License 13 | 14 |
15 |
16 | 17 | Ansible role to install and configure a cluster with Corosync and Pacemaker 18 | 19 | ## Introduction 20 | 21 | Pacemaker and Corosync is one of the mostly used high availability cluster stack. 22 | Pacemaker/Corosync Configuration System on the other hand is a tool to easily configure both Pacemaker and Corosync. 23 | 24 | 25 | ### Ansible 26 | This role was tested against Ansible version 2.8 2.9 2.10 . 27 | The supported platforms are 28 | - Ubuntu 29 | - focal 30 | - bionic 31 | 32 | Mixing different distros might end up with different package versions being installed. It is strongly recommended to use a single version across all cluster. 33 | For example focal comes with corosync 3.0, while bionic with version 2.4 34 | 35 | ## Variables 36 | Configuration example 37 | ```yaml 38 | group_vars: 39 | all: 40 | corosync_hacluster_password: 1q2w3e4r5t 41 | corosync_cluster_settings: 42 | - key: stonith-enabled 43 | value: "false" 44 | - key: no-quorum-policy 45 | value: ignore 46 | - key: start-failure-is-fatal 47 | value: "false" 48 | - key: symmetric-cluster 49 | value: "false" 50 | corosync_cluster_defaults: 51 | - key: resource-stickiness 52 | value: 100 53 | ``` 54 | 55 | If you want to use an internal network 56 | ```yaml 57 | group_vars: 58 | all: 59 | corosync_use_internal_ip: true 60 | host_vars: 61 | node1: 62 | internal_ip: 10.0.0.1 63 | node2: 64 | internal_ip: 10.0.0.2 65 | node3: 66 | internal_ip: 10.0.0.3 67 | ``` 68 | 69 | Multi-site cluster configuration 70 | ```yaml 71 | all: 72 | children: 73 | newyork: 74 | vars: 75 | totem_cluster_name: 'NewYork' 76 | hacluster_password: 'randomgeneratedpassword' 77 | ansible_connection: local 78 | booth_type: 'site' 79 | booth_ip: '10.254.1.15' 80 | booth_config: 'setup' 81 | hosts: 82 | ny01: 83 | ansible_host: '10.254.1.15' 84 | ansible_hostname: 'ny01' 85 | london: 86 | vars: 87 | totem_cluster_name: 'London' 88 | hacluster_password: 'randomgeneratedpassword' 89 | ansible_connection: ssh 90 | booth_type: site 91 | booth_ip: '10.254.2.15' 92 | booth_config: 'pull' 93 | hosts: 94 | ld01: 95 | ansible_host: '10.254.2.8' 96 | ansible_hostname: 'ld01' 97 | ld02: 98 | ansible_host: '10.254.2.9' 99 | ansible_hostname: 'ld02' 100 | munich: 101 | vars: 102 | totem_cluster_name: 'Munich' 103 | hacluster_password: 'randomgeneratedpassword' 104 | ansible_connection: ssh 105 | booth_type: arbitrator 106 | booth_ip: '10.254.3.15' 107 | booth_config: 'pull' 108 | hosts: 109 | muc01: 110 | ansible_host: '10.254.3.9' 111 | ansible_hostname: 'muc01' 112 | muc02: 113 | ansible_host: '10.254.3.10' 114 | ansible_hostname: 'muc01' 115 | muc03: 116 | ansible_host: '10.254.3.11' 117 | ansible_hostname: 'muc01' 118 | ``` 119 | 120 | The cluster site with booth_config 'setup' generates the booth configuration. 121 | Subsequently the other cluster sites will pull the booth configuration. 122 | There should be only one cluster site configured as 'setup' and all others as 'pull' 123 | When deploying is required to prioritize the booth_config 'setup' site first to ensure configuration is performed on the 'pull' sites accordingly. 124 | 125 | ## Testing 126 | 127 | Molecule with docker is being used. 128 | 129 | Running the tests: 130 | ```bash 131 | pipenv install 132 | pipenv run molecule test 133 | ``` 134 | -------------------------------------------------------------------------------- /defaults/main.yml: -------------------------------------------------------------------------------- 1 | internal_ip: 2 | corosync_exchange_hosts: false 3 | corosync_use_internal_ip: false 4 | corosync_hacluster_password: 5 | corosync_web_ui: true 6 | corosync_cluster_settings: 7 | - key: stonith-enabled 8 | value: "false" 9 | - key: no-quorum-policy 10 | value: ignore 11 | corosync_cluster_defaults: [] -------------------------------------------------------------------------------- /files/heartbeat/command_raw: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # command_raw: runs commands 4 | # 5 | # Author: Marian Craciun 6 | # 7 | # License: MIT 8 | # 9 | # Copyright: (C) 2020 Marian Craciun 10 | # 11 | # OCF parameters are as below: 12 | # OCF_RESKEY_start_cmd 13 | # OCF_RESKEY_stop_cmd 14 | # OCF_RESKEY_monitor_cmd 15 | # 16 | # testing with ocf-tester 17 | # ocf-tester -n command_raw_test \ 18 | # -o start_cmd="/usr/sbin/iptables -A INPUT -m mark --mark 5434 -j REJECT" \ 19 | # -o stop_cmd="/usr/sbin/iptables -D INPUT -m mark --mark 5434 -j REJECT" \ 20 | # -o monitor_cmd="/usr/sbin/iptables -C INPUT -m mark --mark 5434 -j REJECT" \ 21 | # -n command_raw 22 | # 23 | ####################################################################### 24 | # Initialization: 25 | 26 | : ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat} 27 | . ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs 28 | 29 | # Parameter defaults 30 | 31 | OCF_RESKEY_start_cmd_default="" 32 | OCF_RESKEY_stop_cmd_default="" 33 | OCF_RESKEY_monitor_cmd_default="" 34 | 35 | : ${OCF_RESKEY_start_cmd=${OCF_RESKEY_start_cmd_default}} 36 | : ${OCF_RESKEY_stop_cmd=${OCF_RESKEY_stop_cmd_default}} 37 | : ${OCF_RESKEY_monitor_cmd=${OCF_RESKEY_monitor_cmd_default}} 38 | 39 | ####################################################################### 40 | CMD=`basename $0` 41 | 42 | meta_data() { 43 | cat < 45 | 46 | 47 | 1.0 48 | Resource script for adding raw commands 49 | Raw commands to start/stop and monitor 50 | 51 | 52 | The start command 53 | Rule start command 54 | 55 | 56 | 57 | The stop command 58 | Rule stop command 59 | 60 | 61 | 62 | The monitor comman 63 | Role monitor command 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | END 76 | } 77 | 78 | ####################################################################### 79 | 80 | command_status() { 81 | ocf_log debug "Running ${OCF_RESKEY_monitor_cmd}" 82 | eval "${OCF_RESKEY_monitor_cmd} > /dev/null 2>&1" 83 | rc=$? 84 | if [ $rc -eq 0 ]; 85 | then 86 | return $OCF_RUNNING 87 | else 88 | return $OCF_NOT_RUNNING 89 | fi 90 | } 91 | 92 | cmd_usage() { 93 | cat <- 15 | pcs cluster status did not return the 16 | {{ play_hosts | length }} as hosts configured 17 | quiet: yes 18 | -------------------------------------------------------------------------------- /requirements.yml: -------------------------------------------------------------------------------- 1 | - src: mariancraciun1983.install_python 2 | -------------------------------------------------------------------------------- /tasks/auth/collect.yml: -------------------------------------------------------------------------------- 1 | - name: auth | check existing authkey 2 | stat: 3 | path: /etc/corosync/authkey 4 | register: authkey_stat 5 | 6 | - name: auth | collect any existing authkey 7 | block: 8 | - name: slurp /etc/corosync/authkey 9 | slurp: 10 | src: /etc/corosync/authkey 11 | register: authkey_slurp 12 | 13 | - name: save /etc/corosync/authkey into dummy host 14 | add_host: 15 | name: _authkey_dummy 16 | authkey_content: "{{ authkey_slurp['content'] | b64decode }}" 17 | no_log: yes 18 | changed_when: no 19 | when: authkey_stat.stat.exists|bool 20 | -------------------------------------------------------------------------------- /tasks/auth/exchange.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: exchange | verify key is collected 3 | assert: 4 | that: 5 | - hostvars['_authkey_dummy'] is defined 6 | - hostvars['_authkey_dummy']['authkey_content'] is defined 7 | - hostvars['_authkey_dummy']['authkey_content'] | length > 0 8 | quiet: yes 9 | fail_msg: at this point authkey was supposed to be collected in the dummy host for later use 10 | 11 | - name: exchange | deploy authkey 12 | copy: 13 | content: "{{ hostvars['_authkey_dummy']['authkey_content'] }}" 14 | dest: /etc/corosync/authkey 15 | mode: 0400 16 | notify: restart corosync 17 | -------------------------------------------------------------------------------- /tasks/auth/generate.yml: -------------------------------------------------------------------------------- 1 | - name: generate | initialize corosync authkey 2 | block: 3 | - name: generate | install haveged 4 | apt: 5 | name: haveged 6 | state: present 7 | 8 | - name: generate | reset auth 9 | file: 10 | path: /etc/corosync/authkey 11 | state: absent 12 | 13 | - name: generate | generate a new authkey 14 | command: /usr/sbin/corosync-keygen 15 | 16 | - name: generate | wait for key 17 | wait_for: 18 | path: /etc/corosync/authkey 19 | timeout: 30 20 | notify: restart corosync 21 | 22 | - name: generate | slurp /etc/corosync/authkey 23 | slurp: 24 | src: /etc/corosync/authkey 25 | register: authkey_slurp 26 | 27 | - name: generate | save /etc/corosync/authkey into dummy host 28 | add_host: 29 | name: _authkey_dummy 30 | authkey_content: "{{ authkey_slurp['content'] | b64decode }}" 31 | no_log: yes 32 | changed_when: no 33 | 34 | - name: generate | unininstall haveged 35 | apt: 36 | name: haveged 37 | state: absent 38 | purge: true 39 | -------------------------------------------------------------------------------- /tasks/auth/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: auth | collect key 3 | import_tasks: collect.yml 4 | 5 | - name: auth | generate key 6 | import_tasks: generate.yml 7 | when: >- 8 | inventory_hostname == play_hosts[0] and 9 | hostvars['_authkey_dummy'] is not defined 10 | 11 | - name: auth | exchange 12 | import_tasks: exchange.yml 13 | -------------------------------------------------------------------------------- /tasks/config.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: config | verify requirements 4 | assert: 5 | that: 6 | - corosync_hacluster_password|length > 3 7 | quiet: yes 8 | fail_msg: corosync_hacluster_password must be defined 9 | 10 | - name: config | create hacluster user 11 | user: 12 | name: hacluster 13 | password: "{{ corosync_hacluster_password | mandatory | password_hash('sha512', ansible_hostname|replace('-','x') | truncate(16, True, '', 0)) }}" 14 | shell: /sbin/nologin 15 | create_home: no 16 | comment: "HA cluster admin" 17 | 18 | - name: config | update corosync.conf 19 | template: 20 | src: corosync.conf.j2 21 | dest: /etc/corosync/corosync.conf 22 | mode: 0644 23 | notify: 24 | - restart corosync 25 | - restart pacemaker 26 | 27 | - name: config | enable services site 28 | service: 29 | name: "{{ item }}" 30 | enabled: true 31 | state: started 32 | with_items: 33 | - corosync 34 | - pacemaker 35 | - pcsd 36 | 37 | - name: config | authenticate cluster 38 | block: 39 | 40 | - name: config | check if auth was made already 41 | stat: 42 | path: /var/lib/pcsd/{{ item }} 43 | with_items: 44 | - known-hosts 45 | - tokens 46 | register: stat_auth_files 47 | 48 | - name: config | authenticate all nodes 49 | command: "{{ item }}" 50 | with_items: 51 | - pcs cluster auth -u hacluster -p {{ corosync_hacluster_password | quote }} 52 | - pcs cluster auth {% for item in query('inventory_hostnames', 'all') %}{% if item != '_authkey_dummy' %}{% if hostvars[item]['booth_config'] == 'setup'%}{{ hostvars[item]['ansible_hostname'] | quote }}{% endif %}{% endif %}{% endfor %} -u hacluster -p {% for item in query('inventory_hostnames', 'all') %}{% if item != '_authkey_dummy' %}{% if hostvars[item]['booth_config'] == 'setup'%}{{ hostvars[item]['hacluster_password'] | quote }}{% endif %}{% endif %}{% endfor %} 53 | - pcs cluster enable --all 54 | - pcs cluster start --all 55 | when: >- 56 | not stat_auth_files.results.0.stat.exists 57 | and not stat_auth_files.results.1.stat.exists 58 | 59 | - name: config | check if booth config is done already 60 | stat: 61 | path: /etc/booth/booth.key 62 | register: stat_booth_key 63 | 64 | - name: config | booth setup 65 | command: pcs booth setup sites{% for item in query('inventory_hostnames', 'all') %}{% if item != '_authkey_dummy' %}{% if hostvars[item]['booth_type'] == 'site' %} {{ hostvars[item]['booth_ip'] }}{% endif %}{% endif %}{% endfor %} arbitrators{% for item in query('inventory_hostnames', 'all') %}{% if item != '_authkey_dummy' %}{% if hostvars[item]['booth_type'] == 'arbitrator' %} {{ hostvars[item]['booth_ip'] }}{% endif %}{% endif %}{% endfor %} 66 | when: >- 67 | (not stat_booth_key.stat.exists) and 68 | (booth_config == 'setup') 69 | 70 | - name: config | booth pull 71 | command: pcs booth pull {% for item in query('inventory_hostnames', 'all') %}{% if item != '_authkey_dummy' %}{% if hostvars[item]['booth_config'] == 'setup'%}{{ hostvars[item]['ansible_hostname'] }}{% endif %}{% endif %}{% endfor %} 72 | when: >- 73 | (not stat_booth_key.stat.exists) and 74 | (booth_config == 'pull') 75 | 76 | - name: config | booth sync 77 | command: pcs booth sync 78 | when: >- 79 | not stat_booth_key.stat.exists 80 | 81 | - name: config | booth site ip 82 | command: pcs booth create ip {{ booth_ip }} 83 | when: >- 84 | (not stat_booth_key.stat.exists) and 85 | (booth_type == 'site') 86 | 87 | - name: config | booth arbitrator start 88 | command: pcs booth start 89 | when: >- 90 | booth_type == 'arbitrator' 91 | 92 | - name: config | booth arbitrator enable 93 | command: pcs booth enable 94 | when: >- 95 | booth_type == 'arbitrator' 96 | 97 | throttle: 1 98 | 99 | - name: config | properties from first host 100 | block: 101 | 102 | - name: config | get properties 103 | command: pcs property show 104 | register: pcs_props_out 105 | changed_when: false 106 | 107 | - name: config | set cluster properties 108 | command: pcs property set {{ item.key }}={{ item.value }} 109 | with_items: '{{ corosync_cluster_settings }}' 110 | when: "(item.key|string + ':' + ' ' + item.value|string) not in pcs_props_out.stdout" 111 | 112 | - name: config | set cluster defaults 113 | command: pcs resource defaults {{ item.key }}={{ item.value }} 114 | with_items: '{{ corosync_cluster_defaults }}' 115 | when: "(item.key|string + ':' + ' ' + item.value|string) not in pcs_props_out.stdout" 116 | 117 | when: >- 118 | (inventory_hostname == play_hosts[0]) and 119 | (booth_type == 'site') 120 | 121 | 122 | - name: config | set PCSD web GUI config 123 | lineinfile: 124 | dest: /etc/default/pcsd 125 | regexp: 'PCSD_DISABLE_GUI=.*' 126 | line: "PCSD_DISABLE_GUI={{ corosync_web_ui|bool|ternary('false','true') }}" 127 | notify: 128 | - restart pcsd 129 | -------------------------------------------------------------------------------- /tasks/heartbeats.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: heartbeats | deploy custom heartbeat scripts 3 | copy: 4 | src: "{{ item }}" 5 | dest: /usr/lib/ocf/resource.d/heartbeat/ 6 | owner: root 7 | group: root 8 | mode: 0755 9 | with_fileglob: 10 | - files/heartbeat/* 11 | -------------------------------------------------------------------------------- /tasks/hosts.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: hosts | exchange hostnames in hosts file 4 | blockinfile: 5 | path: /etc/hosts 6 | block: | 7 | {% if item != '_authkey_dummy' %}{% if corosync_use_internal_ip|bool %} {{ hostvars[item]['internal_ip'] }} {{ hostvars[item]['ansible_hostname'] }}{% else %}{{ hostvars[item]['ansible_host'] }} {{ hostvars[item]['ansible_hostname'] }}{% endif %}{% endif %} 8 | marker: "# {mark} ANSIBLE MANAGED BLOCK {{ item }}" 9 | loop: "{{ query('inventory_hostnames', 'all') }}" 10 | -------------------------------------------------------------------------------- /tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: packages 3 | import_tasks: packages.yml 4 | tags: 5 | - packages 6 | 7 | - name: heartbeats 8 | import_tasks: heartbeats.yml 9 | tags: 10 | - heartbeats 11 | 12 | - name: auth 13 | import_tasks: auth/main.yml 14 | tags: 15 | - auth 16 | 17 | - name: hosts 18 | import_tasks: hosts.yml 19 | when: corosync_exchange_hosts|bool 20 | tags: 21 | - hosts 22 | 23 | - name: config 24 | import_tasks: config.yml 25 | tags: 26 | - config 27 | -------------------------------------------------------------------------------- /tasks/packages.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: packages | dependencies 4 | apt: 5 | name: 6 | - gnupg2 7 | - apt-transport-https 8 | - ca-certificates 9 | - software-properties-common 10 | - corosync 11 | - pacemaker 12 | - cluster-glue 13 | - fence-agents 14 | - resource-agents 15 | - pcs 16 | - crmsh 17 | - libxml2-utils 18 | - booth-pacemaker 19 | update_cache: true 20 | state: present 21 | -------------------------------------------------------------------------------- /templates/corosync.conf.j2: -------------------------------------------------------------------------------- 1 | totem { 2 | # version and name 3 | version: 2 4 | cluster_name: {% if totem_cluster_name is defined %}{{totem_cluster_name}}{% else %}default{% endif %} 5 | 6 | # token configuration 7 | token: {% if totem_token is defined %}{{totem_token}}{% else %}3000{% endif %} 8 | 9 | token_retransmits_before_loss_const: 10 10 | clear_node_high_bit: yes 11 | 12 | # transpor configuration 13 | ip_version: ipv4 14 | transport: udpu 15 | 16 | # interface configuration 17 | interface { 18 | ringnumber: 0 19 | ttl: 1 20 | bindnetaddr: {% if corosync_use_internal_ip|bool %} {{ internal_ip|mandatory }} {% else %} {{ ansible_default_ipv4['address'] }} {% endif %} 21 | 22 | mcastport: 5405 23 | ttl: 1 24 | } 25 | } 26 | 27 | nodelist { 28 | {% for node in play_hosts %} 29 | node { 30 | name: {{ hostvars[node]['ansible_hostname'] }} 31 | ring0_addr: {% if corosync_use_internal_ip|bool %} {{ hostvars[node]['internal_ip']|mandatory }} {% else %} {{ hostvars[node]['ansible_default_ipv4']['address'] }} {% endif %} 32 | 33 | nodeid: {{ loop.index }} 34 | } 35 | {% endfor %} 36 | } 37 | 38 | logging { 39 | fileline: off 40 | to_stderr: no 41 | to_logfile: yes 42 | logfile: /var/log/corosync/corosync.log 43 | to_syslog: yes 44 | syslog_facility: daemon 45 | debug: off 46 | timestamp: on 47 | logger_subsys { 48 | subsys: QUORUM 49 | debug: off 50 | } 51 | } 52 | 53 | quorum { 54 | two_node: 1 55 | auto_tie_breaker: 1 56 | last_man_standing: 0 57 | last_man_standing_window: 10000 58 | provider: corosync_votequorum 59 | wait_for_all: 0 60 | } 61 | -------------------------------------------------------------------------------- /tests/test.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: localhost 3 | gather_facts: true 4 | roles: 5 | - ../../ 6 | --------------------------------------------------------------------------------