summaryrefslogtreecommitdiffstats
path: root/ansible_collections/gluster
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-13 12:04:41 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-13 12:04:41 +0000
commit975f66f2eebe9dadba04f275774d4ab83f74cf25 (patch)
tree89bd26a93aaae6a25749145b7e4bca4a1e75b2be /ansible_collections/gluster
parentInitial commit. (diff)
downloadansible-975f66f2eebe9dadba04f275774d4ab83f74cf25.tar.xz
ansible-975f66f2eebe9dadba04f275774d4ab83f74cf25.zip
Adding upstream version 7.7.0+dfsg.upstream/7.7.0+dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'ansible_collections/gluster')
-rw-r--r--ansible_collections/gluster/gluster/.github/workflows/ansible-test-plugins.yml47
-rw-r--r--ansible_collections/gluster/gluster/.gitignore2
-rw-r--r--ansible_collections/gluster/gluster/CHANGELOG.rst33
-rw-r--r--ansible_collections/gluster/gluster/FILES.json166
-rw-r--r--ansible_collections/gluster/gluster/LICENSE288
-rw-r--r--ansible_collections/gluster/gluster/MANIFEST.json32
-rw-r--r--ansible_collections/gluster/gluster/README.md37
-rw-r--r--ansible_collections/gluster/gluster/changelogs/changelog.yaml31
-rw-r--r--ansible_collections/gluster/gluster/changelogs/config.yaml31
-rw-r--r--ansible_collections/gluster/gluster/meta/runtime.yml2
-rw-r--r--ansible_collections/gluster/gluster/plugins/modules/geo_rep.py347
-rw-r--r--ansible_collections/gluster/gluster/plugins/modules/gluster_heal_info.py205
-rw-r--r--ansible_collections/gluster/gluster/plugins/modules/gluster_peer.py177
-rw-r--r--ansible_collections/gluster/gluster/plugins/modules/gluster_volume.py621
-rw-r--r--ansible_collections/gluster/gluster/tests/sanity/ignore-2.10.txt4
-rw-r--r--ansible_collections/gluster/gluster/tests/sanity/ignore-2.11.txt4
16 files changed, 2027 insertions, 0 deletions
diff --git a/ansible_collections/gluster/gluster/.github/workflows/ansible-test-plugins.yml b/ansible_collections/gluster/gluster/.github/workflows/ansible-test-plugins.yml
new file mode 100644
index 000000000..8c6b612cc
--- /dev/null
+++ b/ansible_collections/gluster/gluster/.github/workflows/ansible-test-plugins.yml
@@ -0,0 +1,47 @@
+---
+name: Plugins CI
+on:
+ push:
+ paths:
+ - 'plugins/**'
+ - 'tests/**'
+ - '.github/workflows/ansible-test-plugins.yml'
+ - 'changelogs/*'
+ - 'galaxy.yml'
+ pull_request:
+ paths:
+ - 'plugins/**'
+ - 'tests/**'
+ - '.github/workflows/ansible-test-plugins.yml'
+ schedule:
+ - cron: '0 6 * * *'
+
+jobs:
+ sanity:
+ name: "Sanity (Ansible: ${{ matrix.ansible }})"
+ runs-on: ubuntu-latest
+ strategy:
+ matrix:
+ ansible:
+ - stable-2.9
+ - stable-2.10
+ - devel
+
+ steps:
+ - name: Check out code
+ uses: actions/checkout@v2
+ with:
+ path: ansible_collections/gluster/gluster
+
+ # Just run once as anyway ansible-test sanity using container will run test for all python versions he supports
+ - name: Set up Python
+ uses: actions/setup-python@v2
+ with:
+ python-version: 3.8
+
+ - name: Install ansible-base (${{ matrix.ansible }})
+ run: pip install https://github.com/ansible/ansible/archive/${{ matrix.ansible }}.tar.gz --disable-pip-version-check
+
+ - name: Run sanity tests
+ run: ansible-test sanity --docker -v --color
+ working-directory: ./ansible_collections/gluster/gluster
diff --git a/ansible_collections/gluster/gluster/.gitignore b/ansible_collections/gluster/gluster/.gitignore
new file mode 100644
index 000000000..17f16c032
--- /dev/null
+++ b/ansible_collections/gluster/gluster/.gitignore
@@ -0,0 +1,2 @@
+tests/output/
+changelogs/.plugin-cache.yaml
diff --git a/ansible_collections/gluster/gluster/CHANGELOG.rst b/ansible_collections/gluster/gluster/CHANGELOG.rst
new file mode 100644
index 000000000..fca0b161a
--- /dev/null
+++ b/ansible_collections/gluster/gluster/CHANGELOG.rst
@@ -0,0 +1,33 @@
+========================================
+Gluster Ansible Collection Release Notes
+========================================
+
+.. contents:: Topics
+
+
+v1.0.2
+======
+
+Major Changes
+-------------
+
+- enable client.ssl,server.ssl before starting the gluster volume (https://github.com/gluster/gluster-ansible-collection/pull/19)
+
+v1.0.1
+======
+
+v1.0.0
+======
+
+Major Changes
+-------------
+
+- geo_rep - Added the independent module of geo rep with other gluster modules (https://github.com/gluster/gluster-ansible-collection/pull/2).
+
+New Modules
+-----------
+
+- gluster.gluster.geo_rep - Manage geo-replication sessions
+- gluster.gluster.gluster_heal_info - Gather facts about either self-heal or rebalance status
+- gluster.gluster.gluster_peer - Attach/Detach peers to/from the cluster
+- gluster.gluster.gluster_volume - Manage GlusterFS volumes
diff --git a/ansible_collections/gluster/gluster/FILES.json b/ansible_collections/gluster/gluster/FILES.json
new file mode 100644
index 000000000..3d69367d0
--- /dev/null
+++ b/ansible_collections/gluster/gluster/FILES.json
@@ -0,0 +1,166 @@
+{
+ "files": [
+ {
+ "name": ".",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "changelogs",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "changelogs/config.yaml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "6e1e182c7b4c93f749e0c7db228bc12d402a644619141252c43df5ab431c536f",
+ "format": 1
+ },
+ {
+ "name": "changelogs/changelog.yaml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "d0803d36de0cbf127c9d777632b3b4b89192b90e05b8345c0c3749a80e709e58",
+ "format": 1
+ },
+ {
+ "name": "meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "meta/runtime.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "df18179bb2f5447a56ac92261a911649b96821c0b2c08eea62d5cc6b0195203f",
+ "format": 1
+ },
+ {
+ "name": "tests",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/sanity",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/sanity/ignore-2.10.txt",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "20bbf9ce835ecf43b345c1c86a5eafecaec98737c0a00f3146f6e459fbb2121a",
+ "format": 1
+ },
+ {
+ "name": "tests/sanity/ignore-2.11.txt",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "20bbf9ce835ecf43b345c1c86a5eafecaec98737c0a00f3146f6e459fbb2121a",
+ "format": 1
+ },
+ {
+ "name": "CHANGELOG.rst",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "7f395483772bc670fd201b8aceecee35ae6b9249a1f10fab55ad945a6c2230e0",
+ "format": 1
+ },
+ {
+ "name": "LICENSE",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "77691ea688645a83845ebe7922c529777d99cc34ac18e98c1bb710c576cf6073",
+ "format": 1
+ },
+ {
+ "name": ".github",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": ".github/workflows",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": ".github/workflows/ansible-test-plugins.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "8baecdfb5acea6041a2689fb0f3ae7f87bfaa87be9c7fdf2bdf14ece1ceac786",
+ "format": 1
+ },
+ {
+ "name": "plugins",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "plugins/modules",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/gluster_volume.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "68d4cef121879d83711f137466e13d9f6af40c2abdc00b09ccba4f31fc8762a4",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/gluster_heal_info.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "4e96c378d5e33d8230868f65229dd73b8365e7b3da59170c1c82a7995c6b1ba2",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/geo_rep.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "7d030d566f4be86dd6fb83eaa1aa7b01738fbb27b3b0492e6b18df0026d38ef7",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/gluster_peer.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "3c6c49c79c57f1319f96808c07fd9f05ebc92322aa4f25d9a63608430f8ac010",
+ "format": 1
+ },
+ {
+ "name": ".gitignore",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "f38ba82ecf283574365b673d8b219740fb4a3d6f07e8d9f06012565d2b0d5d84",
+ "format": 1
+ },
+ {
+ "name": "README.md",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "124c8f6c3f4100b7aee5da0546b2da643d8d3ab58348453fbee48fe0f125d9a4",
+ "format": 1
+ }
+ ],
+ "format": 1
+} \ No newline at end of file
diff --git a/ansible_collections/gluster/gluster/LICENSE b/ansible_collections/gluster/gluster/LICENSE
new file mode 100644
index 000000000..85d49a071
--- /dev/null
+++ b/ansible_collections/gluster/gluster/LICENSE
@@ -0,0 +1,288 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ Copyright 2014 Red Hat, Inc.
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
diff --git a/ansible_collections/gluster/gluster/MANIFEST.json b/ansible_collections/gluster/gluster/MANIFEST.json
new file mode 100644
index 000000000..5bcf910e3
--- /dev/null
+++ b/ansible_collections/gluster/gluster/MANIFEST.json
@@ -0,0 +1,32 @@
+{
+ "collection_info": {
+ "namespace": "gluster",
+ "name": "gluster",
+ "version": "1.0.2",
+ "authors": [
+ "gluster (github.com/gluster)```",
+ "Prajith Kesava Prasad <pkesavap@redhat.com>"
+ ],
+ "readme": "README.md",
+ "tags": [
+ "gluster",
+ "storage"
+ ],
+ "description": "Administrate a gluster cluster.",
+ "license": [],
+ "license_file": "./LICENSE",
+ "dependencies": {},
+ "repository": "https://github.com/gluster/gluster-ansible-collection",
+ "documentation": "https://docs.ansible.com/ansible/latest/",
+ "homepage": "https://github.com/gluster/gluster-ansible-collection",
+ "issues": "https://github.com/gluster/gluster-ansible-collection/issues"
+ },
+ "file_manifest_file": {
+ "name": "FILES.json",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "a89d1a6580a92a0bd5fcc7aead7fc08398db51a66b8f8a43e3a2b6a167d10acd",
+ "format": 1
+ },
+ "format": 1
+} \ No newline at end of file
diff --git a/ansible_collections/gluster/gluster/README.md b/ansible_collections/gluster/gluster/README.md
new file mode 100644
index 000000000..5966dd7eb
--- /dev/null
+++ b/ansible_collections/gluster/gluster/README.md
@@ -0,0 +1,37 @@
+gluster ansible collection
+====================================
+
+The `gluster.gluster` manages all ansible modules of gluster-ansible
+
+Note
+----
+Please note that when installing this collection from Ansible Galaxy you are instructed to run following command:
+
+```bash
+$ ansible-galaxy collection install gluster.gluster
+```
+
+
+Requirements
+------------
+
+ * Ansible version 2.9 or higher
+ * Python SDK version 4.3 or higher
+
+Modules documentation
+--------------
+
+Dependencies
+------------
+None.
+
+Example Playbook
+----------------
+
+```
+playbook
+```
+License
+-------
+
+GNU General Public License v2.0
diff --git a/ansible_collections/gluster/gluster/changelogs/changelog.yaml b/ansible_collections/gluster/gluster/changelogs/changelog.yaml
new file mode 100644
index 000000000..788fa6015
--- /dev/null
+++ b/ansible_collections/gluster/gluster/changelogs/changelog.yaml
@@ -0,0 +1,31 @@
+ancestor: null
+releases:
+ 1.0.0:
+ changes:
+ major_changes:
+ - geo_rep - Added the independent module of geo rep with other gluster modules
+ (https://github.com/gluster/gluster-ansible-collection/pull/2).
+ fragments:
+ - 2-geo_rep.py
+ modules:
+ - description: Manage geo-replication sessions
+ name: geo_rep
+ namespace: ''
+ - description: Gather facts about either self-heal or rebalance status
+ name: gluster_heal_info
+ namespace: ''
+ - description: Attach/Detach peers to/from the cluster
+ name: gluster_peer
+ namespace: ''
+ - description: Manage GlusterFS volumes
+ name: gluster_volume
+ namespace: ''
+ release_date: '2020-06-29'
+ 1.0.1:
+ release_date: '2020-08-18'
+ 1.0.2:
+ changes:
+ major_changes:
+ - enable client.ssl,server.ssl before starting the gluster volume
+ (https://github.com/gluster/gluster-ansible-collection/pull/19)
+ release_date: '2021-09-17'
diff --git a/ansible_collections/gluster/gluster/changelogs/config.yaml b/ansible_collections/gluster/gluster/changelogs/config.yaml
new file mode 100644
index 000000000..bf477a77c
--- /dev/null
+++ b/ansible_collections/gluster/gluster/changelogs/config.yaml
@@ -0,0 +1,31 @@
+changelog_filename_template: ../CHANGELOG.rst
+changelog_filename_version_depth: 0
+changes_file: changelog.yaml
+changes_format: combined
+ignore_other_fragment_extensions: true
+keep_fragments: false
+mention_ancestor: true
+new_plugins_after_name: removed_features
+notesdir: fragments
+prelude_section_name: release_summary
+prelude_section_title: Release Summary
+sections:
+- - major_changes
+ - Major Changes
+- - minor_changes
+ - Minor Changes
+- - breaking_changes
+ - Breaking Changes / Porting Guide
+- - deprecated_features
+ - Deprecated Features
+- - removed_features
+ - Removed Features (previously deprecated)
+- - security_fixes
+ - Security Fixes
+- - bugfixes
+ - Bugfixes
+- - known_issues
+ - Known Issues
+title: Gluster Ansible Collection
+trivial_section_name: trivial
+use_fqcn: true
diff --git a/ansible_collections/gluster/gluster/meta/runtime.yml b/ansible_collections/gluster/gluster/meta/runtime.yml
new file mode 100644
index 000000000..2ee3c9fa9
--- /dev/null
+++ b/ansible_collections/gluster/gluster/meta/runtime.yml
@@ -0,0 +1,2 @@
+---
+requires_ansible: '>=2.9.10'
diff --git a/ansible_collections/gluster/gluster/plugins/modules/geo_rep.py b/ansible_collections/gluster/gluster/plugins/modules/geo_rep.py
new file mode 100644
index 000000000..801cbd39f
--- /dev/null
+++ b/ansible_collections/gluster/gluster/plugins/modules/geo_rep.py
@@ -0,0 +1,347 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright 2015 Nandaja Varma <nvarma@redhat.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Library General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+# USA.
+
+from __future__ import absolute_import, division, print_function
+__metaclass__ = type
+
+DOCUMENTATION = """
+module: geo_rep
+short_description: Manage geo-replication sessions
+description:
+ - Create, stop, delete and configure geo-replication session
+author: Sachidananda Urs (@sac)
+options:
+ action:
+ description:
+ - Action to be performed on geo-replication session.
+ required: true
+ choices: ['create', 'start', 'stop', 'delete', 'pause', 'resume', 'config']
+ type: str
+ mastervol:
+ description:
+ - Master volume name.
+ type: str
+ slavevol:
+ description:
+ - Slave volume name.
+ type: str
+ force:
+ description:
+ - force the system to perform the action.
+ type: str
+ georepuser:
+ description:
+ - Username to be used for the action being performed.
+ type: str
+ gluster_log_file:
+ description:
+ - The path to the geo-replication glusterfs log file.
+ type: str
+ gluster_log_level:
+ description:
+ - The log level for glusterfs processes.
+ type: str
+ log_file:
+ description:
+ - The path to the geo-replication log file.
+ type: str
+ log_level:
+ description:
+ - The log level for geo-replication.
+ type: str
+ changelog_log_level:
+ description:
+ - The log level for the changelog.
+ type: str
+ ssh_command:
+ description:
+ - The SSH command to connect to the remote machine.
+ type: str
+ rsync_command:
+ description:
+ - The command to use for setting synchronizing method for the files.
+ type: str
+ use_tarssh:
+ description:
+ - To use tar over ssh.
+ type: str
+ volume_id:
+ description:
+ - deletes the existing master UID for the intermediate/slave node.
+ type: str
+ timeout:
+ description:
+ - timeout period.
+ type: str
+ sync_jobs:
+ description:
+ - number of sync-jobs .
+ type: str
+ ignore_deletes:
+ description:
+ - file deletion on the master will not trigger a delete operation on the slave.
+ type: str
+ checkpoint:
+ description:
+ - Sets a checkpoint with the given option.
+ type: str
+ sync_acls:
+ description:
+ - Syncs acls to the Slave cluster.
+ type: str
+ sync_xattrs:
+ description:
+ - Syncs extended attributes to the Slave cluster.
+ type: str
+ log_rsync_performance:
+ description:
+ - for recording the rsync performance in log files.
+ type: str
+ rsync_options:
+ description:
+ - Additional options to rsync.
+ type: str
+ use_meta_volume:
+ description:
+ - to use meta volume in Geo-replication.
+ type: str
+ meta_volume_mnt:
+ description:
+ - The path of the meta volume mount point.
+ type: str
+"""
+
+EXAMPLES = """
+- name: Create the geo-rep session
+ gluster.gluster.geo_rep:
+ action: create
+ mastervol: 10.70.42.122:mastervolume
+ slavevol: 10.70.43.48:slavevolume
+ force: true
+ georepuser: staff
+- name: Starts the geo-rep session
+ gluster.gluster.geo_rep:
+ action: start
+ mastervol: 10.70.42.122:mastervolume
+ slavevol: 10.70.43.48:slavevolume
+ force: true
+ georepuser: staff
+- name: Pause the geo-rep session
+ gluster.gluster.geo_rep:
+ action: pause
+ mastervol: 10.70.42.122:mastervolume
+ slavevol: 10.70.43.48:slavevolume
+ force: true
+ georepuser: staff
+- name: Resume the geo-rep session
+ gluster.gluster.geo_rep:
+ action: resume
+ mastervol: 10.70.42.122:mastervolume
+ slavevol: 10.70.43.48:slavevolume
+ force: true
+ georepuser: staff
+- name: Stop the geo-rep session
+ gluster.gluster.geo_rep:
+ action: stop
+ mastervol: 10.70.42.122:mastervolume
+ slavevol: 10.70.43.48:slavevolume
+ force: true
+ georepuser: staff
+- name: Configures the geo-rep session
+ gluster.gluster.geo_rep:
+ action: config
+ mastervol: 10.70.42.122:mastervolume
+ slavevol: 10.70.43.48:slavevolume
+ gluster_log_file: /var/log/glusterfs/geo-replication/gluster.log
+ gluster_log_level: INFO
+ log_file: /var/log/glusterfs/geo-replication/file.log
+ log_level: INFO
+ changelog_log_level: INFO
+ ssh_command: SSH
+ rsync_command: rsync
+ use_tarssh: true
+ volume_id: 6a071cfa-b150-4f0b-b1ed-96ab5d4bd671
+ timeout: 60
+ sync_jobs: 3
+ ignore_deletes: 1
+ checkpoint: now
+ sync_acls: true
+ sync_xattr: true
+ log_rsync_performance: true
+ rsync_options: --compress-level=0
+ use_meta_volume: true
+ meta_volume_mnt: /var/run/gluster/shared_storage/
+- name: Delete the geo-rep session
+ gluster.gluster.geo_rep:
+ action: delete
+ mastervol: 10.70.42.122:mastervolume
+ slavevol: 10.70.43.48:slavevolume
+ georepuser: staff
+"""
+
+import re
+from ansible.module_utils.basic import AnsibleModule
+
+
+class GeoRep(object):
+ def __init__(self, module):
+ self.module = module
+ self.action = self._validated_params('action')
+ self.gluster_georep_ops()
+
+ def get_playbook_params(self, opt):
+ return self.module.params[opt]
+
+ def _validated_params(self, opt):
+ value = self.get_playbook_params(opt)
+ if value is None:
+ msg = "Please provide %s option in the playbook!" % opt
+ self.module.fail_json(msg=msg)
+ return value
+
+ def gluster_georep_ops(self):
+ mastervol = self._validated_params('mastervol')
+ slavevol = self._validated_params('slavevol')
+ slavevol = self.check_pool_exclusiveness(mastervol, slavevol)
+ if self.action in ['delete', 'config']:
+ force = ''
+ else:
+ force = self._validated_params('force')
+ force = 'force' if force == 'yes' else ' '
+ options = 'no-verify' if self.action == 'create' \
+ else self.config_georep()
+ if isinstance(options, list):
+ for opt in options:
+ rc, output, err = self.call_gluster_cmd('volume',
+ 'geo-replication',
+ mastervol, slavevol,
+ self.action, opt,
+ force)
+ else:
+ rc, output, err = self.call_gluster_cmd('volume',
+ 'geo-replication',
+ mastervol, slavevol,
+ self.action, options,
+ force)
+ self._get_output(rc, output, err)
+ if self.action in ['stop', 'delete'] and self.user == 'root':
+ self.user = 'geoaccount'
+ rc, output, err = self.call_gluster_cmd('volume', 'geo-replication',
+ mastervol, slavevol.replace(
+ 'root', 'geoaccount'),
+ self.action, options, force)
+ self._get_output(rc, output, err)
+
+ def config_georep(self):
+ if self.action != 'config':
+ return ''
+ options = ['gluster_log_file', 'gluster_log_level', 'log_file',
+ 'log_level', 'changelog_log_level', 'ssh_command',
+ 'rsync_command', 'use_tarssh', 'volume_id', 'timeout',
+ 'sync_jobs', 'ignore_deletes', 'checkpoint', 'sync_acls',
+ 'sync_xattrs', 'log_rsync_performance', 'rsync_options',
+ 'use_meta_volume', 'meta_volume_mnt']
+ configs = []
+ for opt in options:
+ value = self._validated_params(opt)
+ if value:
+ if value == 'reset':
+ configs.append("'!" + opt.replace('_', '-') + "'")
+ configs.append(opt.replace('_', '-') + ' ' + value)
+ if configs:
+ return configs
+ value = self._validated_params('config')
+ op = self._validated_params('op')
+ return value + ' ' + op
+
+ def check_pool_exclusiveness(self, mastervol, slavevol):
+ rc, output, err = self.module.run_command(
+ "gluster pool list")
+ peers_in_cluster = [line.split('\t')[1].strip() for
+ line in filter(None, output.split('\n')[1:])]
+ val_group = re.search("(.*):(.*)", slavevol)
+ if not val_group:
+ self.module.fail_json(msg="Slave volume in Unknown format. "
+ "Correct format: <hostname>:<volume name>")
+ if val_group.group(1) in peers_in_cluster:
+ self.module.fail_json(msg="slave volume is in the trusted "
+ "storage pool of master")
+ self.user = 'root' if self.module.params['georepuser'] is None \
+ else self.module.params['georepuser']
+ return self.user + '@' + val_group.group(1) + '::' + val_group.group(2)
+
+ def call_gluster_cmd(self, *args, **kwargs):
+ params = ' '.join(opt for opt in args)
+ key_value_pair = ' '.join(' %s %s ' % (key, value)
+ for key, value in kwargs)
+ return self._run_command('gluster', ' ' + params + ' ' + key_value_pair)
+
+ def _get_output(self, rc, output, err):
+ carryon = True if self.action in ['stop',
+ 'delete', 'resume'] else False
+ changed = 0 if (carryon and rc) else 1
+ if self.action in ['stop', 'delete'] and (
+ self.user == 'root' and changed == 0):
+ return
+ if not rc or carryon:
+ self.module.exit_json(stdout=output, changed=changed)
+ else:
+ self.module.fail_json(msg=err)
+
+ def _run_command(self, op, opts):
+ cmd = self.module.get_bin_path(op, True) + opts
+ return self.module.run_command(cmd)
+
+
+def main():
+ module = AnsibleModule(
+ argument_spec=dict(
+ action=dict(required=True, choices=['create', 'start',
+ 'stop', 'delete', 'pause', 'resume', 'config']),
+ mastervol=dict(),
+ slavevol=dict(),
+ force=dict(),
+ georepuser=dict(),
+ gluster_log_file=dict(),
+ gluster_log_level=dict(),
+ log_file=dict(),
+ log_level=dict(),
+ changelog_log_level=dict(),
+ ssh_command=dict(),
+ rsync_command=dict(),
+ use_tarssh=dict(),
+ volume_id=dict(),
+ timeout=dict(),
+ sync_jobs=dict(),
+ ignore_deletes=dict(),
+ checkpoint=dict(),
+ sync_acls=dict(),
+ sync_xattrs=dict(),
+ log_rsync_performance=dict(),
+ rsync_options=dict(),
+ use_meta_volume=dict(),
+ meta_volume_mnt=dict()
+ ),
+ )
+ GeoRep(module)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/gluster/gluster/plugins/modules/gluster_heal_info.py b/ansible_collections/gluster/gluster/plugins/modules/gluster_heal_info.py
new file mode 100644
index 000000000..786e0c23f
--- /dev/null
+++ b/ansible_collections/gluster/gluster/plugins/modules/gluster_heal_info.py
@@ -0,0 +1,205 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright: (c) 2016, Red Hat, Inc.
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+from __future__ import absolute_import, division, print_function
+__metaclass__ = type
+
+ANSIBLE_METADATA = {'metadata_version': '1.1',
+ 'status': ['preview'],
+ 'supported_by': 'community'}
+
+
+DOCUMENTATION = '''
+---
+module: gluster_heal_info
+short_description: Gather information on self-heal or rebalance status
+author: "Devyani Kota (@devyanikota)"
+description:
+ - Gather facts about either self-heal or rebalance status.
+ - This module was called C(gluster_heal_facts) before Ansible 2.9, returning C(ansible_facts).
+ Note that the M(gluster.gluster.gluster_heal_info) module no longer returns C(ansible_facts)!
+options:
+ name:
+ description:
+ - The volume name.
+ required: true
+ aliases: ['volume']
+ type: str
+ status_filter:
+ default: "self-heal"
+ choices: ["self-heal", "rebalance"]
+ type: str
+ description:
+ - Determines which facts are to be returned.
+ - If the C(status_filter) is C(self-heal), status of self-heal, along with the number of files still in process are returned.
+ - If the C(status_filter) is C(rebalance), rebalance status is returned.
+requirements:
+ - GlusterFS > 3.2
+'''
+
+EXAMPLES = '''
+- name: Gather self-heal facts about all gluster hosts in the cluster
+ gluster.gluster.gluster_heal_info:
+ name: test_volume
+ status_filter: self-heal
+ register: self_heal_status
+- debug:
+ var: self_heal_status
+
+- name: Gather rebalance facts about all gluster hosts in the cluster
+ gluster.gluster.gluster_heal_info:
+ name: test_volume
+ status_filter: rebalance
+ register: rebalance_status
+- debug:
+ var: rebalance_status
+'''
+
+RETURN = '''
+name:
+ description: GlusterFS volume name
+ returned: always
+ type: str
+status_filter:
+ description: Whether self-heal or rebalance status is to be returned
+ returned: always
+ type: str
+heal_info:
+ description: List of files that still need healing process
+ returned: On success
+ type: list
+rebalance_status:
+ description: Status of rebalance operation
+ returned: On success
+ type: list
+'''
+
+import traceback
+
+from ansible.module_utils.basic import AnsibleModule
+from ansible.module_utils._text import to_native
+from distutils.version import LooseVersion
+
+glusterbin = ''
+
+
+def run_gluster(gargs, **kwargs):
+ global glusterbin
+ global module
+ args = [glusterbin, '--mode=script']
+ args.extend(gargs)
+ try:
+ rc, out, err = module.run_command(args, **kwargs)
+ if rc != 0:
+ module.fail_json(msg='error running gluster (%s) command (rc=%d): %s' %
+ (' '.join(args), rc, out or err), exception=traceback.format_exc())
+ except Exception as e:
+ module.fail_json(msg='error running gluster (%s) command: %s' % (' '.join(args),
+ to_native(e)), exception=traceback.format_exc())
+ return out
+
+
+def get_self_heal_status(name):
+ out = run_gluster(['volume', 'heal', name, 'info'], environ_update=dict(LANG='C', LC_ALL='C', LC_MESSAGES='C'))
+ raw_out = out.split("\n")
+ heal_info = []
+ # return files that still need healing.
+ for line in raw_out:
+ if 'Brick' in line:
+ br_dict = {}
+ br_dict['brick'] = line.strip().strip("Brick")
+ elif 'Status' in line:
+ br_dict['status'] = line.split(":")[1].strip()
+ elif 'Number' in line:
+ br_dict['no_of_entries'] = line.split(":")[1].strip()
+ elif line.startswith('/') or '\n' in line:
+ continue
+ else:
+ br_dict and heal_info.append(br_dict)
+ br_dict = {}
+ return heal_info
+
+
+def get_rebalance_status(name):
+ out = run_gluster(['volume', 'rebalance', name, 'status'], environ_update=dict(LANG='C', LC_ALL='C', LC_MESSAGES='C'))
+ raw_out = out.split("\n")
+ rebalance_status = []
+ # return the files that are either still 'in progress' state or 'completed'.
+ for line in raw_out:
+ line = " ".join(line.split())
+ line_vals = line.split(" ")
+ if line_vals[0].startswith('-') or line_vals[0].startswith('Node'):
+ continue
+ node_dict = {}
+ if len(line_vals) == 1 or len(line_vals) == 4:
+ continue
+ node_dict['node'] = line_vals[0]
+ node_dict['rebalanced_files'] = line_vals[1]
+ node_dict['failures'] = line_vals[4]
+ if 'in progress' in line:
+ node_dict['status'] = line_vals[5] + line_vals[6]
+ rebalance_status.append(node_dict)
+ elif 'completed' in line:
+ node_dict['status'] = line_vals[5]
+ rebalance_status.append(node_dict)
+ return rebalance_status
+
+
+def is_invalid_gluster_version(module, required_version):
+ cmd = module.get_bin_path('gluster', True) + ' --version'
+ result = module.run_command(cmd)
+ ver_line = result[1].split('\n')[0]
+ version = ver_line.split(' ')[1]
+ # If the installed version is less than 3.2, it is an invalid version
+ # return True
+ return LooseVersion(version) < LooseVersion(required_version)
+
+
+def main():
+ global module
+ global glusterbin
+ module = AnsibleModule(
+ argument_spec=dict(
+ name=dict(type='str', required=True, aliases=['volume']),
+ status_filter=dict(type='str', default='self-heal', choices=['self-heal', 'rebalance']),
+ ),
+ )
+ is_old_facts = module._name == 'gluster_heal_facts'
+ if is_old_facts:
+ module.deprecate("The 'gluster_heal_facts' module has been renamed to 'gluster_heal_info', "
+ "and the renamed one no longer returns ansible_facts", version='2.13')
+
+ glusterbin = module.get_bin_path('gluster', True)
+ required_version = "3.2"
+ status_filter = module.params['status_filter']
+ volume_name = module.params['name']
+ heal_info = ''
+ rebalance_status = ''
+
+ # Verify if required GlusterFS version is installed
+ if is_invalid_gluster_version(module, required_version):
+ module.fail_json(msg="GlusterFS version > %s is required" %
+ required_version)
+
+ try:
+ if status_filter == "self-heal":
+ heal_info = get_self_heal_status(volume_name)
+ elif status_filter == "rebalance":
+ rebalance_status = get_rebalance_status(volume_name)
+ except Exception as e:
+ module.fail_json(msg='Error retrieving status: %s' % e, exception=traceback.format_exc())
+
+ facts = {}
+ facts['glusterfs'] = {'volume': volume_name, 'status_filter': status_filter, 'heal_info': heal_info, 'rebalance': rebalance_status}
+
+ if is_old_facts:
+ module.exit_json(ansible_facts=facts)
+ else:
+ module.exit_json(**facts)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/ansible_collections/gluster/gluster/plugins/modules/gluster_peer.py b/ansible_collections/gluster/gluster/plugins/modules/gluster_peer.py
new file mode 100644
index 000000000..213f2b849
--- /dev/null
+++ b/ansible_collections/gluster/gluster/plugins/modules/gluster_peer.py
@@ -0,0 +1,177 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright 2015 Nandaja Varma <nvarma@redhat.com>
+# Copyright 2018 Red Hat, Inc.
+#
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+#
+
+from __future__ import absolute_import, division, print_function
+__metaclass__ = type
+
+ANSIBLE_METADATA = {'metadata_version': '1.1',
+ 'status': ['preview'],
+ 'supported_by': 'community'}
+
+DOCUMENTATION = '''
+---
+module: gluster_peer
+short_description: Attach/Detach peers to/from the cluster
+description:
+ - Create or diminish a GlusterFS trusted storage pool. A set of nodes can be
+ added into an existing trusted storage pool or a new storage pool can be
+ formed. Or, nodes can be removed from an existing trusted storage pool.
+author: Sachidananda Urs (@sac)
+options:
+ state:
+ choices: ["present", "absent"]
+ default: "present"
+ description:
+ - Determines whether the nodes should be attached to the pool or
+ removed from the pool. If the state is present, nodes will be
+ attached to the pool. If state is absent, nodes will be detached
+ from the pool.
+ required: true
+ type: str
+ nodes:
+ description:
+ - List of nodes that have to be probed into the pool.
+ required: true
+ type: list
+ force:
+ type: bool
+ default: "false"
+ description:
+ - Applicable only while removing the nodes from the pool. gluster
+ will refuse to detach a node from the pool if any one of the node
+ is down, in such cases force can be used.
+requirements:
+ - GlusterFS > 3.2
+notes:
+ - This module does not support check mode.
+'''
+
+EXAMPLES = '''
+- name: Create a trusted storage pool
+ gluster.gluster.gluster_peer:
+ state: present
+ nodes:
+ - 10.0.1.5
+ - 10.0.1.10
+
+- name: Delete a node from the trusted storage pool
+ gluster.gluster.gluster_peer:
+ state: absent
+ nodes:
+ - 10.0.1.10
+
+- name: Delete a node from the trusted storage pool by force
+ gluster.gluster.gluster_peer:
+ state: absent
+ nodes:
+ - 10.0.0.1
+ force: true
+'''
+
+RETURN = '''
+'''
+
+from ansible.module_utils.basic import AnsibleModule
+from distutils.version import LooseVersion
+
+
+class Peer(object):
+ def __init__(self, module):
+ self.module = module
+ self.state = self.module.params['state']
+ self.nodes = self.module.params['nodes']
+ self.glustercmd = self.module.get_bin_path('gluster', True)
+ self.lang = dict(LANG='C', LC_ALL='C', LC_MESSAGES='C')
+ self.action = ''
+ self.force = ''
+
+ def gluster_peer_ops(self):
+ if not self.nodes:
+ self.module.fail_json(msg="nodes list cannot be empty")
+ self.force = 'force' if self.module.params.get('force') else ''
+ if self.state == 'present':
+ self.nodes = self.get_to_be_probed_hosts(self.nodes)
+ self.action = 'probe'
+ # In case of peer probe, we do not need `force'
+ self.force = ''
+ else:
+ self.action = 'detach'
+ self.call_peer_commands()
+
+ def get_to_be_probed_hosts(self, hosts):
+ peercmd = [self.glustercmd, 'pool', 'list', '--mode=script']
+ rc, output, err = self.module.run_command(peercmd,
+ environ_update=self.lang)
+ peers_in_cluster = [line.split('\t')[1].strip() for
+ line in filter(None, output.split('\n')[1:])]
+ try:
+ peers_in_cluster.remove('localhost')
+ except ValueError:
+ # It is ok not to have localhost in list
+ pass
+ hosts_to_be_probed = [host for host in hosts if host not in
+ peers_in_cluster]
+ return hosts_to_be_probed
+
+ def call_peer_commands(self):
+ result = {}
+ result['msg'] = ''
+ result['changed'] = False
+
+ for node in self.nodes:
+ peercmd = [self.glustercmd, 'peer', self.action, node, '--mode=script']
+ if self.force:
+ peercmd.append(self.force)
+ rc, out, err = self.module.run_command(peercmd,
+ environ_update=self.lang)
+ if rc:
+ result['rc'] = rc
+ result['msg'] = err
+ # Fail early, do not wait for the loop to finish
+ self.module.fail_json(**result)
+ else:
+ if 'already in peer' in out or \
+ 'localhost not needed' in out:
+ result['changed'] |= False
+ else:
+ result['changed'] = True
+ self.module.exit_json(**result)
+
+
+def main():
+ module = AnsibleModule(
+ argument_spec=dict(
+ force=dict(type='bool', required=False),
+ nodes=dict(type='list', required=True),
+ state=dict(type='str', choices=['absent', 'present'],
+ default='present'),
+ ),
+ supports_check_mode=False
+ )
+ pops = Peer(module)
+ required_version = "3.2"
+ # Verify if required GlusterFS version is installed
+ if is_invalid_gluster_version(module, required_version):
+ module.fail_json(msg="GlusterFS version > %s is required" %
+ required_version)
+ pops.gluster_peer_ops()
+
+
+def is_invalid_gluster_version(module, required_version):
+ cmd = module.get_bin_path('gluster', True) + ' --version'
+ result = module.run_command(cmd)
+ ver_line = result[1].split('\n')[0]
+ version = ver_line.split(' ')[1]
+ # If the installed version is less than 3.2, it is an invalid version
+ # return True
+ return LooseVersion(version) < LooseVersion(required_version)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/gluster/gluster/plugins/modules/gluster_volume.py b/ansible_collections/gluster/gluster/plugins/modules/gluster_volume.py
new file mode 100644
index 000000000..703ad6d75
--- /dev/null
+++ b/ansible_collections/gluster/gluster/plugins/modules/gluster_volume.py
@@ -0,0 +1,621 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Copyright: (c) 2014, Taneli Leppä <taneli@crasman.fi>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+from __future__ import absolute_import, division, print_function
+__metaclass__ = type
+
+ANSIBLE_METADATA = {'metadata_version': '1.1',
+ 'status': ['preview'],
+ 'supported_by': 'community'}
+
+DOCUMENTATION = """
+module: gluster_volume
+short_description: Manage GlusterFS volumes
+description:
+ - Create, remove, start, stop and tune GlusterFS volumes
+options:
+ name:
+ description:
+ - The volume name.
+ required: true
+ aliases: ['volume']
+ type: str
+ state:
+ description:
+ - Use present/absent ensure if a volume exists or not.
+ Use started/stopped to control its availability.
+ required: true
+ choices: ['absent', 'present', 'started', 'stopped']
+ type: str
+ cluster:
+ description:
+ - List of hosts to use for probing and brick setup.
+ type: list
+ host:
+ description:
+ - Override local hostname (for peer probing purposes).
+ type: str
+ replicas:
+ description:
+ - Replica count for volume.
+ type: int
+ arbiters:
+ description:
+ - Arbiter count for volume.
+ type: int
+ stripes:
+ description:
+ - Stripe count for volume.
+ type: int
+ disperses:
+ description:
+ - Disperse count for volume.
+ type: int
+ redundancies:
+ description:
+ - Redundancy count for volume.
+ type: int
+ transport:
+ description:
+ - Transport type for volume.
+ default: tcp
+ choices: [ tcp, rdma, 'tcp,rdma' ]
+ type: str
+ bricks:
+ description:
+ - Brick paths on servers. Multiple brick paths can be separated by commas.
+ aliases: [ brick ]
+ type: str
+ start_on_create:
+ description:
+ - Controls whether the volume is started after creation or not.
+ type: bool
+ default: 'yes'
+ rebalance:
+ description:
+ - Controls whether the cluster is rebalanced after changes.
+ type: bool
+ default: 'no'
+ directory:
+ description:
+ - Directory for limit-usage.
+ type: str
+ options:
+ description:
+ - A dictionary/hash with options/settings for the volume.
+ type: dict
+ quota:
+ description:
+ - Quota value for limit-usage (be sure to use 10.0MB instead of 10MB, see quota list).
+ type: str
+ force:
+ description:
+ - If brick is being created in the root partition, module will fail.
+ Set force to true to override this behaviour.
+ type: bool
+notes:
+ - Requires cli tools for GlusterFS on servers.
+ - Will add new bricks, but not remove them.
+author:
+- Taneli Leppä (@rosmo)
+"""
+
+EXAMPLES = """
+- name: create gluster volume
+ gluster.gluster.gluster_volume:
+ state: present
+ name: test1
+ bricks: /bricks/brick1/g1
+ rebalance: yes
+ cluster:
+ - 192.0.2.10
+ - 192.0.2.11
+ run_once: true
+
+- name: tune
+ gluster.gluster.gluster_volume:
+ state: present
+ name: test1
+ options:
+ performance.cache-size: 256MB
+
+- name: Set multiple options on GlusterFS volume
+ gluster.gluster.gluster_volume:
+ state: present
+ name: test1
+ options:
+ { performance.cache-size: 128MB,
+ write-behind: 'off',
+ quick-read: 'on'
+ }
+
+- name: start gluster volume
+ gluster.gluster.gluster_volume:
+ state: started
+ name: test1
+
+- name: limit usage
+ gluster.gluster.gluster_volume:
+ state: present
+ name: test1
+ directory: /foo
+ quota: 20.0MB
+
+- name: stop gluster volume
+ gluster.gluster.gluster_volume:
+ state: stopped
+ name: test1
+
+- name: remove gluster volume
+ gluster.gluster.gluster_volume:
+ state: absent
+ name: test1
+
+- name: create gluster volume with multiple bricks
+ gluster.gluster.gluster_volume:
+ state: present
+ name: test2
+ bricks: /bricks/brick1/g2,/bricks/brick2/g2
+ cluster:
+ - 192.0.2.10
+ - 192.0.2.11
+ run_once: true
+
+- name: Remove the bricks from gluster volume
+ gluster.gluster.gluster_volume:
+ state: present
+ name: testvol
+ bricks: /bricks/brick1/b1,/bricks/brick2/b2
+ cluster:
+ - 10.70.42.85
+ force: true
+ run_once: true
+
+- name: Reduce cluster configuration
+ gluster.gluster.gluster_volume:
+ state: present
+ name: testvol
+ bricks: /bricks/brick3/b1,/bricks/brick4/b2
+ replicas: 2
+ cluster:
+ - 10.70.42.85
+ force: true
+ run_once: true
+"""
+
+import re
+import socket
+import time
+import traceback
+
+from ansible.module_utils.basic import AnsibleModule
+from ansible.module_utils._text import to_native
+
+glusterbin = ''
+
+
+def run_gluster(gargs, **kwargs):
+ global glusterbin
+ global module
+ args = [glusterbin, '--mode=script']
+ args.extend(gargs)
+ try:
+ rc, out, err = module.run_command(args, **kwargs)
+ if rc != 0:
+ module.fail_json(msg='error running gluster (%s) command (rc=%d): %s' %
+ (' '.join(args), rc, out or err), exception=traceback.format_exc())
+ except Exception as e:
+ module.fail_json(msg='error running gluster (%s) command: %s' % (' '.join(args),
+ to_native(e)), exception=traceback.format_exc())
+ return out
+
+
+def run_gluster_nofail(gargs, **kwargs):
+ global glusterbin
+ global module
+ args = [glusterbin]
+ args.extend(gargs)
+ rc, out, err = module.run_command(args, **kwargs)
+ if rc != 0:
+ return None
+ return out
+
+
+def get_peers():
+ out = run_gluster(['peer', 'status'])
+ peers = {}
+ hostname = None
+ uuid = None
+ state = None
+ shortNames = False
+ for row in out.split('\n'):
+ if ': ' in row:
+ key, value = row.split(': ')
+ if key.lower() == 'hostname':
+ hostname = value
+ shortNames = False
+ if key.lower() == 'uuid':
+ uuid = value
+ if key.lower() == 'state':
+ state = value
+ peers[hostname] = [uuid, state]
+ elif row.lower() == 'other names:':
+ shortNames = True
+ elif row != '' and shortNames is True:
+ peers[row] = [uuid, state]
+ elif row == '':
+ shortNames = False
+ return peers
+
+
+def get_volumes():
+ out = run_gluster(['volume', 'info'])
+
+ volumes = {}
+ volume = {}
+ for row in out.split('\n'):
+ if ': ' in row:
+ key, value = row.split(': ')
+ if key.lower() == 'volume name':
+ volume['name'] = value
+ volume['options'] = {}
+ volume['quota'] = False
+ if key.lower() == 'volume id':
+ volume['id'] = value
+ if key.lower() == 'status':
+ volume['status'] = value
+ if key.lower() == 'transport-type':
+ volume['transport'] = value
+ if value.lower().endswith(' (arbiter)'):
+ if 'arbiters' not in volume:
+ volume['arbiters'] = []
+ value = value[:-10]
+ volume['arbiters'].append(value)
+ elif key.lower() == 'number of bricks':
+ volume['replicas'] = value[-1:]
+ if key.lower() != 'bricks' and key.lower()[:5] == 'brick':
+ if 'bricks' not in volume:
+ volume['bricks'] = []
+ volume['bricks'].append(value)
+ # Volume options
+ if '.' in key:
+ if 'options' not in volume:
+ volume['options'] = {}
+ volume['options'][key] = value
+ if key == 'features.quota' and value == 'on':
+ volume['quota'] = True
+ else:
+ if row.lower() != 'bricks:' and row.lower() != 'options reconfigured:':
+ if len(volume) > 0:
+ volumes[volume['name']] = volume
+ volume = {}
+ return volumes
+
+
+def get_quotas(name, nofail):
+ quotas = {}
+ if nofail:
+ out = run_gluster_nofail(['volume', 'quota', name, 'list'])
+ if not out:
+ return quotas
+ else:
+ out = run_gluster(['volume', 'quota', name, 'list'])
+ for row in out.split('\n'):
+ if row[:1] == '/':
+ q = re.split(r'\s+', row)
+ quotas[q[0]] = q[1]
+ return quotas
+
+
+def wait_for_peer(host):
+ for x in range(0, 4):
+ peers = get_peers()
+ if host in peers and peers[host][1].lower().find('peer in cluster') != -1:
+ return True
+ time.sleep(1)
+ return False
+
+
+def probe(host, myhostname):
+ global module
+ out = run_gluster(['peer', 'probe', host])
+ if out.find('localhost') == -1 and not wait_for_peer(host):
+ module.fail_json(msg='failed to probe peer %s on %s' % (host, myhostname))
+
+
+def probe_all_peers(hosts, peers, myhostname):
+ for host in hosts:
+ host = host.strip() # Clean up any extra space for exact comparison
+ if host not in peers:
+ probe(host, myhostname)
+
+
+def create_volume(name, stripe, replica, arbiter, disperse, redundancy, transport, hosts, bricks, force):
+ args = ['volume', 'create']
+ args.append(name)
+ if stripe:
+ args.append('stripe')
+ args.append(str(stripe))
+ if replica:
+ args.append('replica')
+ args.append(str(replica))
+ if arbiter:
+ args.append('arbiter')
+ args.append(str(arbiter))
+ if disperse:
+ args.append('disperse')
+ args.append(str(disperse))
+ if redundancy:
+ args.append('redundancy')
+ args.append(str(redundancy))
+ args.append('transport')
+ args.append(transport)
+ for brick in bricks:
+ for host in hosts:
+ args.append(('%s:%s' % (host, brick)))
+ if force:
+ args.append('force')
+ run_gluster(args)
+
+
+def start_volume(name):
+ run_gluster(['volume', 'start', name])
+
+
+def stop_volume(name):
+ run_gluster(['volume', 'stop', name])
+
+
+def set_volume_option(name, option, parameter):
+ run_gluster(['volume', 'set', name, option, parameter])
+
+
+def add_bricks(name, new_bricks, stripe, replica, force):
+ args = ['volume', 'add-brick', name]
+ if stripe:
+ args.append('stripe')
+ args.append(str(stripe))
+ if replica:
+ args.append('replica')
+ args.append(str(replica))
+ args.extend(new_bricks)
+ if force:
+ args.append('force')
+ run_gluster(args)
+
+
+def remove_bricks(name, removed_bricks, force):
+ # max-tries=12 with default_interval=10 secs
+ max_tries = 12
+ retries = 0
+ success = False
+ args = ['volume', 'remove-brick', name]
+ args.extend(removed_bricks)
+ # create a copy of args to use for commit operation
+ args_c = args[:]
+ args.append('start')
+ run_gluster(args)
+ # remove-brick operation needs to be followed by commit operation.
+ if not force:
+ module.fail_json(msg="Force option is mandatory.")
+ else:
+ while retries < max_tries:
+ last_brick = removed_bricks[-1]
+ out = run_gluster(['volume', 'remove-brick', name, last_brick, 'status'])
+ for row in out.split('\n')[1:]:
+ if 'completed' in row:
+ # remove-brick successful, call commit operation.
+ args_c.append('commit')
+ out = run_gluster(args_c)
+ success = True
+ break
+ else:
+ time.sleep(10)
+ if success:
+ break
+ retries += 1
+ if not success:
+ # remove-brick still in process, needs to be committed after completion.
+ module.fail_json(msg="Exceeded number of tries, check remove-brick status.\n"
+ "Commit operation needs to be followed.")
+
+
+def reduce_config(name, removed_bricks, replicas, force):
+ out = run_gluster(['volume', 'heal', name, 'info'])
+ summary = out.split("\n")
+ for line in summary:
+ if 'Number' in line and int(line.split(":")[1].strip()) != 0:
+ module.fail_json(msg="Operation aborted, self-heal in progress.")
+ args = ['volume', 'remove-brick', name, 'replica', replicas]
+ args.extend(removed_bricks)
+ if force:
+ args.append('force')
+ else:
+ module.fail_json(msg="Force option is mandatory")
+ run_gluster(args)
+
+
+def do_rebalance(name):
+ run_gluster(['volume', 'rebalance', name, 'start'])
+
+
+def enable_quota(name):
+ run_gluster(['volume', 'quota', name, 'enable'])
+
+
+def set_quota(name, directory, value):
+ run_gluster(['volume', 'quota', name, 'limit-usage', directory, value])
+
+
+def main():
+ # MAIN
+
+ global module
+ module = AnsibleModule(
+ argument_spec=dict(
+ name=dict(type='str', required=True, aliases=['volume']),
+ state=dict(type='str', required=True, choices=['absent', 'started', 'stopped', 'present']),
+ cluster=dict(type='list'),
+ host=dict(type='str'),
+ stripes=dict(type='int'),
+ replicas=dict(type='int'),
+ arbiters=dict(type='int'),
+ disperses=dict(type='int'),
+ redundancies=dict(type='int'),
+ transport=dict(type='str', default='tcp', choices=['tcp', 'rdma', 'tcp,rdma']),
+ bricks=dict(type='str', aliases=['brick']),
+ start_on_create=dict(type='bool', default=True),
+ rebalance=dict(type='bool', default=False),
+ options=dict(type='dict', default={}),
+ quota=dict(type='str'),
+ directory=dict(type='str'),
+ force=dict(type='bool', default=False),
+ ),
+ )
+
+ global glusterbin
+ glusterbin = module.get_bin_path('gluster', True)
+
+ changed = False
+
+ action = module.params['state']
+ volume_name = module.params['name']
+ cluster = module.params['cluster']
+ brick_paths = module.params['bricks']
+ stripes = module.params['stripes']
+ replicas = module.params['replicas']
+ arbiters = module.params['arbiters']
+ disperses = module.params['disperses']
+ redundancies = module.params['redundancies']
+ transport = module.params['transport']
+ myhostname = module.params['host']
+ start_on_create = module.boolean(module.params['start_on_create'])
+ rebalance = module.boolean(module.params['rebalance'])
+ force = module.boolean(module.params['force'])
+
+ if not myhostname:
+ myhostname = socket.gethostname()
+
+ # Clean up if last element is empty. Consider that yml can look like this:
+ # cluster="{% for host in groups['glusterfs'] %}{{ hostvars[host]['private_ip'] }},{% endfor %}"
+ if cluster is not None and len(cluster) > 1 and cluster[-1] == '':
+ cluster = cluster[0:-1]
+
+ if cluster is None:
+ cluster = []
+
+ if brick_paths is not None and "," in brick_paths:
+ brick_paths = brick_paths.split(",")
+ else:
+ brick_paths = [brick_paths]
+
+ options = module.params['options']
+ quota = module.params['quota']
+ directory = module.params['directory']
+
+ # get current state info
+ peers = get_peers()
+ volumes = get_volumes()
+ quotas = {}
+ if volume_name in volumes and volumes[volume_name]['quota'] and volumes[volume_name]['status'].lower() == 'started':
+ quotas = get_quotas(volume_name, True)
+
+ # do the work!
+ if action == 'absent':
+ if volume_name in volumes:
+ if volumes[volume_name]['status'].lower() != 'stopped':
+ stop_volume(volume_name)
+ run_gluster(['volume', 'delete', volume_name])
+ changed = True
+
+ if action == 'present':
+ probe_all_peers(cluster, peers, myhostname)
+
+ # create if it doesn't exist
+ if volume_name not in volumes:
+ create_volume(volume_name, stripes, replicas, arbiters, disperses, redundancies, transport, cluster, brick_paths, force)
+ volumes = get_volumes()
+ changed = True
+
+ if volume_name in volumes:
+ # set options
+ for option in options.keys():
+ if option not in volumes[volume_name]['options'] or volumes[volume_name]['options'][option] != options[option]:
+ set_volume_option(volume_name, option, options[option])
+ changed = True
+
+ if volumes[volume_name]['status'].lower() != 'started' and start_on_create:
+ start_volume(volume_name)
+ changed = True
+
+ # switch bricks
+ new_bricks = []
+ removed_bricks = []
+ all_bricks = []
+ bricks_in_volume = volumes[volume_name]['bricks']
+
+ for node in cluster:
+ for brick_path in brick_paths:
+ brick = '%s:%s' % (node, brick_path)
+ all_bricks.append(brick)
+ if brick not in bricks_in_volume:
+ new_bricks.append(brick)
+
+ if not new_bricks and len(all_bricks) > 0 and \
+ len(all_bricks) < len(bricks_in_volume):
+ for brick in bricks_in_volume:
+ if brick not in all_bricks:
+ removed_bricks.append(brick)
+
+ if new_bricks:
+ add_bricks(volume_name, new_bricks, stripes, replicas, force)
+ changed = True
+
+ if removed_bricks:
+ if replicas and int(replicas) < int(volumes[volume_name]['replicas']):
+ reduce_config(volume_name, removed_bricks, str(replicas), force)
+ else:
+ remove_bricks(volume_name, removed_bricks, force)
+ changed = True
+
+ # handle quotas
+ if quota:
+ if not volumes[volume_name]['quota']:
+ enable_quota(volume_name)
+ quotas = get_quotas(volume_name, False)
+ if directory not in quotas or quotas[directory] != quota:
+ set_quota(volume_name, directory, quota)
+ changed = True
+
+ else:
+ module.fail_json(msg='failed to create volume %s' % volume_name)
+
+ if action != 'absent' and volume_name not in volumes:
+ module.fail_json(msg='volume not found %s' % volume_name)
+
+ if action == 'started':
+ if volumes[volume_name]['status'].lower() != 'started':
+ start_volume(volume_name)
+ changed = True
+
+ if action == 'stopped':
+ if volumes[volume_name]['status'].lower() != 'stopped':
+ stop_volume(volume_name)
+ changed = True
+
+ if changed:
+ volumes = get_volumes()
+ if rebalance:
+ do_rebalance(volume_name)
+
+ facts = {}
+ facts['glusterfs'] = {'peers': peers, 'volumes': volumes, 'quotas': quotas}
+
+ module.exit_json(changed=changed, ansible_facts=facts)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/ansible_collections/gluster/gluster/tests/sanity/ignore-2.10.txt b/ansible_collections/gluster/gluster/tests/sanity/ignore-2.10.txt
new file mode 100644
index 000000000..504540c84
--- /dev/null
+++ b/ansible_collections/gluster/gluster/tests/sanity/ignore-2.10.txt
@@ -0,0 +1,4 @@
+plugins/modules/gluster_peer.py validate-modules:doc-required-mismatch
+plugins/modules/gluster_peer.py validate-modules:parameter-list-no-elements
+plugins/modules/gluster_volume.py validate-modules:parameter-list-no-elements
+plugins/modules/gluster_heal_info.py pylint:ansible-deprecated-no-collection-name
diff --git a/ansible_collections/gluster/gluster/tests/sanity/ignore-2.11.txt b/ansible_collections/gluster/gluster/tests/sanity/ignore-2.11.txt
new file mode 100644
index 000000000..504540c84
--- /dev/null
+++ b/ansible_collections/gluster/gluster/tests/sanity/ignore-2.11.txt
@@ -0,0 +1,4 @@
+plugins/modules/gluster_peer.py validate-modules:doc-required-mismatch
+plugins/modules/gluster_peer.py validate-modules:parameter-list-no-elements
+plugins/modules/gluster_volume.py validate-modules:parameter-list-no-elements
+plugins/modules/gluster_heal_info.py pylint:ansible-deprecated-no-collection-name