mirror of
https://github.com/ansible-collections/community.general.git
synced 2026-02-04 16:01:55 +00:00
remove required=false from docs (#11055)
(cherry picked from commit a9a4f89033)
Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
295 lines
8.6 KiB
Python
295 lines
8.6 KiB
Python
#!/usr/bin/python
|
|
# Copyright 2015 WP Engine, Inc. All rights reserved.
|
|
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
|
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
from __future__ import annotations
|
|
|
|
|
|
DOCUMENTATION = r"""
|
|
module: znode
|
|
short_description: Create, delete, retrieve, and update znodes using ZooKeeper
|
|
description:
|
|
- Create, delete, retrieve, and update znodes using ZooKeeper.
|
|
attributes:
|
|
check_mode:
|
|
support: none
|
|
diff_mode:
|
|
support: none
|
|
extends_documentation_fragment:
|
|
- community.general.attributes
|
|
options:
|
|
hosts:
|
|
description:
|
|
- A list of ZooKeeper servers (format V([server]:[port])).
|
|
required: true
|
|
type: str
|
|
name:
|
|
description:
|
|
- The path of the znode.
|
|
required: true
|
|
type: str
|
|
value:
|
|
description:
|
|
- The value assigned to the znode.
|
|
type: str
|
|
op:
|
|
description:
|
|
- An operation to perform. Mutually exclusive with state.
|
|
choices: [get, wait, list]
|
|
type: str
|
|
state:
|
|
description:
|
|
- The state to enforce. Mutually exclusive with op.
|
|
choices: [present, absent]
|
|
type: str
|
|
timeout:
|
|
description:
|
|
- The amount of time to wait for a node to appear.
|
|
default: 300
|
|
type: int
|
|
recursive:
|
|
description:
|
|
- Recursively delete node and all its children.
|
|
type: bool
|
|
default: false
|
|
auth_scheme:
|
|
description:
|
|
- Authentication scheme.
|
|
choices: [digest, sasl]
|
|
type: str
|
|
default: "digest"
|
|
version_added: 5.8.0
|
|
auth_credential:
|
|
description:
|
|
- The authentication credential value. Depends on O(auth_scheme).
|
|
- The format for O(auth_scheme=digest) is C(user:password), and the format for O(auth_scheme=sasl) is C(user:password).
|
|
type: str
|
|
version_added: 5.8.0
|
|
use_tls:
|
|
description:
|
|
- Using TLS/SSL or not.
|
|
type: bool
|
|
default: false
|
|
version_added: '6.5.0'
|
|
requirements:
|
|
- kazoo >= 2.1
|
|
author: "Trey Perry (@treyperry)"
|
|
"""
|
|
|
|
EXAMPLES = r"""
|
|
- name: Creating or updating a znode with a given value
|
|
community.general.znode:
|
|
hosts: 'localhost:2181'
|
|
name: /mypath
|
|
value: myvalue
|
|
state: present
|
|
|
|
- name: Getting the value and stat structure for a znode
|
|
community.general.znode:
|
|
hosts: 'localhost:2181'
|
|
name: /mypath
|
|
op: get
|
|
|
|
- name: Getting the value and stat structure for a znode using digest authentication
|
|
community.general.znode:
|
|
hosts: 'localhost:2181'
|
|
auth_credential: 'user1:s3cr3t'
|
|
name: /secretmypath
|
|
op: get
|
|
|
|
- name: Listing a particular znode's children
|
|
community.general.znode:
|
|
hosts: 'localhost:2181'
|
|
name: /zookeeper
|
|
op: list
|
|
|
|
- name: Waiting 20 seconds for a znode to appear at path /mypath
|
|
community.general.znode:
|
|
hosts: 'localhost:2181'
|
|
name: /mypath
|
|
op: wait
|
|
timeout: 20
|
|
|
|
- name: Deleting a znode at path /mypath
|
|
community.general.znode:
|
|
hosts: 'localhost:2181'
|
|
name: /mypath
|
|
state: absent
|
|
|
|
- name: Creating or updating a znode with a given value on a remote Zookeeper
|
|
community.general.znode:
|
|
hosts: 'my-zookeeper-node:2181'
|
|
name: /mypath
|
|
value: myvalue
|
|
state: present
|
|
delegate_to: 127.0.0.1
|
|
"""
|
|
|
|
import time
|
|
import traceback
|
|
|
|
KAZOO_IMP_ERR = None
|
|
try:
|
|
from kazoo.client import KazooClient
|
|
from kazoo.handlers.threading import KazooTimeoutError
|
|
|
|
KAZOO_INSTALLED = True
|
|
except ImportError:
|
|
KAZOO_IMP_ERR = traceback.format_exc()
|
|
KAZOO_INSTALLED = False
|
|
|
|
from ansible.module_utils.basic import AnsibleModule, missing_required_lib
|
|
from ansible.module_utils.common.text.converters import to_bytes
|
|
|
|
|
|
def main():
|
|
module = AnsibleModule(
|
|
argument_spec=dict(
|
|
hosts=dict(required=True, type="str"),
|
|
name=dict(required=True, type="str"),
|
|
value=dict(type="str"),
|
|
op=dict(choices=["get", "wait", "list"]),
|
|
state=dict(choices=["present", "absent"]),
|
|
timeout=dict(default=300, type="int"),
|
|
recursive=dict(default=False, type="bool"),
|
|
auth_scheme=dict(default="digest", choices=["digest", "sasl"]),
|
|
auth_credential=dict(type="str", no_log=True),
|
|
use_tls=dict(default=False, type="bool"),
|
|
),
|
|
supports_check_mode=False,
|
|
)
|
|
|
|
if not KAZOO_INSTALLED:
|
|
module.fail_json(msg=missing_required_lib("kazoo >= 2.1"), exception=KAZOO_IMP_ERR)
|
|
|
|
check = check_params(module.params)
|
|
if not check["success"]:
|
|
module.fail_json(msg=check["msg"])
|
|
|
|
zoo = KazooCommandProxy(module)
|
|
try:
|
|
zoo.start()
|
|
except KazooTimeoutError:
|
|
module.fail_json(msg="The connection to the ZooKeeper ensemble timed out.")
|
|
|
|
command_dict = {
|
|
"op": {"get": zoo.get, "list": zoo.list, "wait": zoo.wait},
|
|
"state": {"present": zoo.present, "absent": zoo.absent},
|
|
}
|
|
|
|
command_type = "op" if "op" in module.params and module.params["op"] is not None else "state"
|
|
method = module.params[command_type]
|
|
result, result_dict = command_dict[command_type][method]()
|
|
zoo.shutdown()
|
|
|
|
if result:
|
|
module.exit_json(**result_dict)
|
|
else:
|
|
module.fail_json(**result_dict)
|
|
|
|
|
|
def check_params(params):
|
|
if not params["state"] and not params["op"]:
|
|
return {"success": False, "msg": "Please define an operation (op) or a state."}
|
|
|
|
if params["state"] and params["op"]:
|
|
return {"success": False, "msg": "Please choose an operation (op) or a state, but not both."}
|
|
|
|
return {"success": True}
|
|
|
|
|
|
class KazooCommandProxy:
|
|
def __init__(self, module):
|
|
self.module = module
|
|
self.zk = KazooClient(module.params["hosts"], use_ssl=module.params["use_tls"])
|
|
|
|
def absent(self):
|
|
return self._absent(self.module.params["name"])
|
|
|
|
def exists(self, znode):
|
|
return self.zk.exists(znode)
|
|
|
|
def list(self):
|
|
children = self.zk.get_children(self.module.params["name"])
|
|
return True, {
|
|
"count": len(children),
|
|
"items": children,
|
|
"msg": "Retrieved znodes in path.",
|
|
"znode": self.module.params["name"],
|
|
}
|
|
|
|
def present(self):
|
|
return self._present(self.module.params["name"], self.module.params["value"])
|
|
|
|
def get(self):
|
|
return self._get(self.module.params["name"])
|
|
|
|
def shutdown(self):
|
|
self.zk.stop()
|
|
self.zk.close()
|
|
|
|
def start(self):
|
|
self.zk.start()
|
|
if self.module.params["auth_credential"]:
|
|
self.zk.add_auth(self.module.params["auth_scheme"], self.module.params["auth_credential"])
|
|
|
|
def wait(self):
|
|
return self._wait(self.module.params["name"], self.module.params["timeout"])
|
|
|
|
def _absent(self, znode):
|
|
if self.exists(znode):
|
|
self.zk.delete(znode, recursive=self.module.params["recursive"])
|
|
return True, {"changed": True, "msg": "The znode was deleted."}
|
|
else:
|
|
return True, {"changed": False, "msg": "The znode does not exist."}
|
|
|
|
def _get(self, path):
|
|
if self.exists(path):
|
|
value, zstat = self.zk.get(path)
|
|
stat_dict = {}
|
|
for i in dir(zstat):
|
|
if not i.startswith("_"):
|
|
attr = getattr(zstat, i)
|
|
if isinstance(attr, (int, str)):
|
|
stat_dict[i] = attr
|
|
result = True, {"msg": "The node was retrieved.", "znode": path, "value": value, "stat": stat_dict}
|
|
else:
|
|
result = False, {"msg": "The requested node does not exist."}
|
|
|
|
return result
|
|
|
|
def _present(self, path, value):
|
|
if self.exists(path):
|
|
(current_value, zstat) = self.zk.get(path)
|
|
if value != current_value:
|
|
self.zk.set(path, to_bytes(value))
|
|
return True, {"changed": True, "msg": "Updated the znode value.", "znode": path, "value": value}
|
|
else:
|
|
return True, {"changed": False, "msg": "No changes were necessary.", "znode": path, "value": value}
|
|
else:
|
|
self.zk.create(path, to_bytes(value), makepath=True)
|
|
return True, {"changed": True, "msg": "Created a new znode.", "znode": path, "value": value}
|
|
|
|
def _wait(self, path, timeout, interval=5):
|
|
lim = time.time() + timeout
|
|
|
|
while time.time() < lim:
|
|
if self.exists(path):
|
|
return True, {
|
|
"msg": "The node appeared before the configured timeout.",
|
|
"znode": path,
|
|
"timeout": timeout,
|
|
}
|
|
else:
|
|
time.sleep(interval)
|
|
|
|
return False, {
|
|
"msg": "The node did not appear before the operation timed out.",
|
|
"timeout": timeout,
|
|
"znode": path,
|
|
}
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|