diff --git a/.codacy.yml b/.codacy.yml
index a21c364..a1af41c 100644
--- a/.codacy.yml
+++ b/.codacy.yml
@@ -1,4 +1,6 @@
---
engines:
pylint:
- python_version: 3
\ No newline at end of file
+ python_version: 3
+exclude_paths:
+ - "plugins/modules/cockroach_**" # should be removed once cockroach modules are tested
diff --git a/README.md b/README.md
index cdccfb7..6a4d9d7 100644
--- a/README.md
+++ b/README.md
@@ -296,6 +296,13 @@ Name | Description
[community.missing_collection.checkly_snippets_info](https://github.com/116davinder/ansible.missing_collection/blob/master/docs/community.missing_collection.checkly_snippets_info_module.rst)|Get information about checkly snippets.
[community.missing_collection.checkly_variables](https://github.com/116davinder/ansible.missing_collection/blob/master/docs/community.missing_collection.checkly_variables_module.rst)|Management of the checkly environment variables.
[community.missing_collection.checkly_variables_info](https://github.com/116davinder/ansible.missing_collection/blob/master/docs/community.missing_collection.checkly_variables_info_module.rst)|Get information about checkly environment variables.
+[community.missing_collection.cockroach_cert](https://github.com/116davinder/ansible.missing_collection/blob/master/docs/community.missing_collection.cockroach_cert_module.rst)|Manage user certificates in a cockroach cluster
+[community.missing_collection.cockroach_cluster](https://github.com/116davinder/ansible.missing_collection/blob/master/docs/community.missing_collection.cockroach_cluster_module.rst)|Manage a cockroach cluster
+[community.missing_collection.cockroach_cluster_settings](https://github.com/116davinder/ansible.missing_collection/blob/master/docs/community.missing_collection.cockroach_cluster_settings_module.rst)|Manage settings in a Cockroach cluster
+[community.missing_collection.cockroach_db](https://github.com/116davinder/ansible.missing_collection/blob/master/docs/community.missing_collection.cockroach_db_module.rst)|Manage databases in a cockroach cluster
+[community.missing_collection.cockroach_info](https://github.com/116davinder/ansible.missing_collection/blob/master/docs/community.missing_collection.cockroach_info_module.rst)|Returns facts about a Cockroach Cluster
+[community.missing_collection.cockroach_privs](https://github.com/116davinder/ansible.missing_collection/blob/master/docs/community.missing_collection.cockroach_privs_module.rst)|Manage user privileges in a cockroach db
+[community.missing_collection.cockroach_user](https://github.com/116davinder/ansible.missing_collection/blob/master/docs/community.missing_collection.cockroach_user_module.rst)|Manage users in a cockroach cluster
[community.missing_collection.consul_coordinate_info](https://github.com/116davinder/ansible.missing_collection/blob/master/docs/community.missing_collection.consul_coordinate_info_module.rst)|Get information from Consul (Coordinate).
[community.missing_collection.consul_health](https://github.com/116davinder/ansible.missing_collection/blob/master/docs/community.missing_collection.consul_health_module.rst)|Get information from Consul (Health).
[community.missing_collection.consul_members](https://github.com/116davinder/ansible.missing_collection/blob/master/docs/community.missing_collection.consul_members_module.rst)|Get information from Consul (Members).
diff --git a/docs/community.missing_collection.cockroach_cert_module.rst b/docs/community.missing_collection.cockroach_cert_module.rst
new file mode 100644
index 0000000..7187975
--- /dev/null
+++ b/docs/community.missing_collection.cockroach_cert_module.rst
@@ -0,0 +1,79 @@
+.. _community.missing_collection.cockroach_cert_module:
+
+
+*******************************************
+community.missing_collection.cockroach_cert
+*******************************************
+
+**Manage user certificates in a cockroach cluster**
+
+
+Version added: 0.4.0
+
+.. contents::
+ :local:
+ :depth: 1
+
+
+Synopsis
+--------
+- Manage user certificates in a cockroach cluster
+
+
+
+
+Parameters
+----------
+
+.. raw:: html
+
+
+
+ Parameter |
+ Choices/Defaults |
+ Comments |
+
+
+
+
+ name
+
+
+ -
+ / required
+
+ |
+
+ Default:
"None"
+ |
+
+ The name of the user to generate certificate for
+ |
+
+
+
+
+
+
+
+Examples
+--------
+
+.. code-block:: yaml
+
+ - name: create a certificate for a user
+ cockroach_cert:
+ name: user1
+ path: "/var/lib/cockroach"
+
+
+
+
+Status
+------
+
+
+Authors
+~~~~~~~
+
+- Oscar C, based on the work of Mikael Sandstrom, oravirt@gmail.com, @oravirt
diff --git a/docs/community.missing_collection.cockroach_cluster_module.rst b/docs/community.missing_collection.cockroach_cluster_module.rst
new file mode 100644
index 0000000..5e5b26b
--- /dev/null
+++ b/docs/community.missing_collection.cockroach_cluster_module.rst
@@ -0,0 +1,88 @@
+.. _community.missing_collection.cockroach_cluster_module:
+
+
+**********************************************
+community.missing_collection.cockroach_cluster
+**********************************************
+
+**Manage a cockroach cluster**
+
+
+Version added: 0.4.0
+
+.. contents::
+ :local:
+ :depth: 1
+
+
+Synopsis
+--------
+- Manage a cockroach cluster
+
+
+
+
+Parameters
+----------
+
+.. raw:: html
+
+
+
+ Parameter |
+ Choices/Defaults |
+ Comments |
+
+
+
+
+ name
+
+
+ -
+ / required
+
+ |
+
+ Default:
"None"
+ |
+
+ The name of the service
+ |
+
+
+
+
+
+
+
+Examples
+--------
+
+.. code-block:: yaml
+
+ - name: create a master node
+ cockroach_cluster:
+ path: "/var/lib/cockroach"
+ host: "{{ inventory_hostname }}"
+ state: started
+
+ - name: join a node to a cluster
+ cockroach_cluster:
+ path: "/var/lib/cockroach"
+ host: "{{ inventory_hostname }}"
+ join: true
+ cluster_master: "node1:{{ port }}"
+ state: started
+
+
+
+
+Status
+------
+
+
+Authors
+~~~~~~~
+
+- Mikael Sandström, oravirt@gmail.com, @oravirt
diff --git a/docs/community.missing_collection.cockroach_cluster_settings_module.rst b/docs/community.missing_collection.cockroach_cluster_settings_module.rst
new file mode 100644
index 0000000..c0fa0d5
--- /dev/null
+++ b/docs/community.missing_collection.cockroach_cluster_settings_module.rst
@@ -0,0 +1,99 @@
+.. _community.missing_collection.cockroach_cluster_settings_module:
+
+
+*******************************************************
+community.missing_collection.cockroach_cluster_settings
+*******************************************************
+
+**Manage settings in a Cockroach cluster**
+
+
+Version added: 0.4.0
+
+.. contents::
+ :local:
+ :depth: 1
+
+
+Synopsis
+--------
+- Manage settings in a Cockroach cluster
+
+
+
+
+Parameters
+----------
+
+.. raw:: html
+
+
+
+ Parameter |
+ Choices/Defaults |
+ Comments |
+
+
+
+
+ name
+
+
+ -
+ / required
+
+ |
+
+ Default:
"None"
+ |
+
+ The name of the setting
+ |
+
+
+
+
+ value
+
+
+ -
+ / required
+
+ |
+
+ Default:
"None"
+ |
+
+ The value of the setting
+ |
+
+
+
+
+
+
+
+Examples
+--------
+
+.. code-block:: yaml
+
+ - name: manage a setting
+ cockroach_cluster_settings:
+ name: 'diagnostics.reporting.enabled'
+ value: False
+ path: /var/lib/cockroach
+ host: "{{ inventory_hostname }}"
+ state: present
+
+
+
+
+Status
+------
+
+
+Authors
+~~~~~~~
+
+- Mikael Sandström, oravirt@gmail.com, @oravirt
diff --git a/docs/community.missing_collection.cockroach_db_module.rst b/docs/community.missing_collection.cockroach_db_module.rst
new file mode 100644
index 0000000..2e66462
--- /dev/null
+++ b/docs/community.missing_collection.cockroach_db_module.rst
@@ -0,0 +1,80 @@
+.. _community.missing_collection.cockroach_db_module:
+
+
+*****************************************
+community.missing_collection.cockroach_db
+*****************************************
+
+**Manage databases in a cockroach cluster**
+
+
+Version added: 0.4.0
+
+.. contents::
+ :local:
+ :depth: 1
+
+
+Synopsis
+--------
+- Manage databases in a cockroach cluster
+
+
+
+
+Parameters
+----------
+
+.. raw:: html
+
+
+
+ Parameter |
+ Choices/Defaults |
+ Comments |
+
+
+
+
+ name
+
+
+ -
+ / required
+
+ |
+
+ Default:
"None"
+ |
+
+ The name of the database
+ |
+
+
+
+
+
+
+
+Examples
+--------
+
+.. code-block:: yaml
+
+ # Create a database
+ cockroach_db: name=db1 path=/var/lib/cockroach host={{ inventory_hostname }} state=present
+
+ # Drop a database
+ cockroach_db: name=db1 path=/var/lib/cockroach host={{ inventory_hostname }} state=absent
+
+
+
+
+Status
+------
+
+
+Authors
+~~~~~~~
+
+- Mikael Sandstrom, oravirt@gmail.com, @oravirt
diff --git a/docs/community.missing_collection.cockroach_info_module.rst b/docs/community.missing_collection.cockroach_info_module.rst
new file mode 100644
index 0000000..cb6599f
--- /dev/null
+++ b/docs/community.missing_collection.cockroach_info_module.rst
@@ -0,0 +1,155 @@
+.. _community.missing_collection.cockroach_info_module:
+
+
+*******************************************
+community.missing_collection.cockroach_info
+*******************************************
+
+**Returns facts about a Cockroach Cluster**
+
+
+Version added: 0.4.0
+
+.. contents::
+ :local:
+ :depth: 1
+
+
+Synopsis
+--------
+- Returns facts about a Cockroach Cluster
+
+
+
+Requirements
+------------
+The below requirements are needed on the host that executes this module.
+
+- psycopg2
+
+
+Parameters
+----------
+
+.. raw:: html
+
+
+
+ Parameter |
+ Choices/Defaults |
+ Comments |
+
+
+
+
+ certs_dir
+
+
+ -
+
+ |
+
+ |
+
+ Path to certificates on the cluster host
+ |
+
+
+
+
+ host
+
+
+ -
+
+ |
+
+ Default:
"localhost"
+ |
+
+ The cluster host
+ |
+
+
+
+
+ port
+
+
+ -
+
+ |
+
+ Default:
26257
+ |
+
+ The cluster port
+ |
+
+
+
+
+ user
+
+
+ -
+ / required
+
+ |
+
+ Default:
"root"
+ |
+
+ The cluster user to connect as
+ |
+
+
+
+
+
+Notes
+-----
+
+.. note::
+ - psycopg2 needs to be installed
+
+
+
+Examples
+--------
+
+.. code-block:: yaml
+
+ - name: Gather Facts about CRDB Cluster
+ hosts: clusterhosts
+ become: true
+ vars:
+ cockroach_user: cockroach
+ path: /var/lib/cockroach/2.1.6
+ certs_dir: /var/lib/cockroach/certs
+ user: root
+ tasks:
+ - name: facts
+ cockroach_info:
+ user={{ user |default(omit)}}
+ path={{ path |default(omit)}}
+ host={{ ansible_fqdn }}
+ certs_dir={{ certs_dir |default (omit)}}
+ tags: facts
+ become_user: "{{ cockroach_user }}"
+ register: facts
+
+ - debug: msg="version - {{facts.ansible_facts.cockroach_version}}, node_id - {{facts.ansible_facts.node_id}}"
+ - debug: msg="org - {{ facts.ansible_facts.cluster_settings['cluster.organization'] }}{% if facts.ansible_facts.enterprise_license is defined %}, license - {{ facts.ansible_facts.enterprise_license }}{% endif %}"
+
+
+
+
+Status
+------
+
+
+Authors
+~~~~~~~
+
+- Mikael Sandström, oravirt@gmail.com, @oravirt
diff --git a/docs/community.missing_collection.cockroach_privs_module.rst b/docs/community.missing_collection.cockroach_privs_module.rst
new file mode 100644
index 0000000..6182ebe
--- /dev/null
+++ b/docs/community.missing_collection.cockroach_privs_module.rst
@@ -0,0 +1,112 @@
+.. _community.missing_collection.cockroach_privs_module:
+
+
+********************************************
+community.missing_collection.cockroach_privs
+********************************************
+
+**Manage user privileges in a cockroach db**
+
+
+Version added: 0.4.0
+
+.. contents::
+ :local:
+ :depth: 1
+
+
+Synopsis
+--------
+- Manage user privileges in a cockroach db
+
+
+
+
+Parameters
+----------
+
+.. raw:: html
+
+
+
+ Parameter |
+ Choices/Defaults |
+ Comments |
+
+
+
+
+ db
+
+
+ -
+ / required
+
+ |
+
+ Default:
"None"
+ |
+
+ Name of the database to set permissions in
+ |
+
+
+
+
+ name
+
+
+ -
+ / required
+
+ |
+
+ Default:
"None"
+ |
+
+ the name of the user to set permissions
+ |
+
+
+
+
+ privs
+
+
+ -
+ / required
+
+ |
+
+ Default:
"None"
+ |
+
+ Privileges for the user
+ |
+
+
+
+
+
+
+
+Examples
+--------
+
+.. code-block:: yaml
+
+ # Grant ALL privileges to user1 on db1
+ cockroach_privs: name=user1 db=db1 privs=ALL path=/var/lib/cockroach
+
+
+
+
+Status
+------
+
+
+Authors
+~~~~~~~
+
+- Oscar C
+- Mikael Sandstrom @oravirt
diff --git a/docs/community.missing_collection.cockroach_user_module.rst b/docs/community.missing_collection.cockroach_user_module.rst
new file mode 100644
index 0000000..d45e631
--- /dev/null
+++ b/docs/community.missing_collection.cockroach_user_module.rst
@@ -0,0 +1,81 @@
+.. _community.missing_collection.cockroach_user_module:
+
+
+*******************************************
+community.missing_collection.cockroach_user
+*******************************************
+
+**Manage users in a cockroach cluster**
+
+
+Version added: 0.4.0
+
+.. contents::
+ :local:
+ :depth: 1
+
+
+Synopsis
+--------
+- Manage users in a cockroach cluster
+
+
+
+
+Parameters
+----------
+
+.. raw:: html
+
+
+
+ Parameter |
+ Choices/Defaults |
+ Comments |
+
+
+
+
+ name
+
+
+ -
+ / required
+
+ |
+
+ Default:
"None"
+ |
+
+ The name of the user
+ |
+
+
+
+
+
+
+
+Examples
+--------
+
+.. code-block:: yaml
+
+ # Create a user
+ cockroach_user: name=user1 path=/var/lib/cockroach host={{ inventory_hostname }} state=present
+
+ # Delete a user
+ cockroach_user: name=user1 path=/var/lib/cockroach host={{ inventory_hostname }} state=absent
+
+
+
+
+Status
+------
+
+
+Authors
+~~~~~~~
+
+- Oscar C
+- Mikael Sandström, oravirt@gmail.com, @oravirt
diff --git a/docs/community.missing_collection.doh_module.rst b/docs/community.missing_collection.doh_module.rst
index 8e52198..442dd1c 100644
--- a/docs/community.missing_collection.doh_module.rst
+++ b/docs/community.missing_collection.doh_module.rst
@@ -17,10 +17,11 @@ Version added: 0.4.0
Synopsis
--------
-- DNS Lookup over HTTPS from various Public DOH Servers like Google/Cloudflare/Quad9.
+- DNS Lookup over HTTPS from various Public DOH Servers like Google/Cloudflare/Quad9/Alibaba.
- https://developers.cloudflare.com/1.1.1.1/encrypted-dns/dns-over-https/make-api-requests/dns-json
- https://developers.google.com/speed/public-dns/docs/doh/json
- https://www.quad9.net/news/blog/doh-with-quad9-dns-servers/
+- https://www.alibabacloud.com/help/en/doc-detail/171666.html
@@ -110,6 +111,7 @@ Parameters
google
cloudflare ←
quad9
+ alibaba
@@ -161,6 +163,12 @@ Examples
name: "example.com"
type: "MX"
+ - name: fetch A record from Alibaba DNS over HTTPS
+ community.missing_collection.doh:
+ source: "alibaba"
+ name: "example.com"
+ type: "A"
+
Return Values
diff --git a/plugins/modules/cockroach_cert.py b/plugins/modules/cockroach_cert.py
new file mode 100644
index 0000000..411e29b
--- /dev/null
+++ b/plugins/modules/cockroach_cert.py
@@ -0,0 +1,111 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+DOCUMENTATION = """
+---
+module: cockroach_cert
+short_description: Manage user certificates in a cockroach cluster
+description:
+ - Manage user certificates in a cockroach cluster
+version_added: "0.4.0"
+options:
+ name:
+ description:
+ - The name of the user to generate certificate for
+ required: true
+ default: None
+
+notes:
+author: Oscar C, based on the work of Mikael Sandstrom, oravirt@gmail.com, @oravirt
+"""
+
+EXAMPLES = """
+- name: create a certificate for a user
+ cockroach_cert:
+ name: user1
+ path: "/var/lib/cockroach"
+"""
+
+from ansible.module_utils.basic import *
+import os
+
+
+# Check if the service exists
+def check_user_has_certificate(module, msg, path, name, certs_dir):
+ command = "%s/cockroach cert list" % (path)
+ if not certs_dir:
+ command += " --insecure"
+ elif certs_dir:
+ command += " --certs-dir=%s" % (certs_dir)
+
+ # module.fail_json(msg=command)
+ (rc, stdout, stderr) = module.run_command(command)
+ # module.exit_json(msg=rc)
+ if rc != 0:
+ msg[0] = "Something went wrong, stderr: %s" % (stderr)
+
+ if "client." + name.lower() + ".crt" in stdout.lower():
+ return True
+ else:
+ return False
+
+
+def create_certificate_for_user(module, msg, path, name, certs_dir, ca_key):
+ command = "%s/cockroach cert create-client %s" % (path, name)
+ if certs_dir:
+ command += " --certs-dir=%s" % (certs_dir)
+ if ca_key:
+ command += " --ca-key=%s" % (ca_key)
+
+ # module.fail_json(msg=command)
+ (rc, stdout, stderr) = module.run_command(command)
+ if rc != 0:
+ msg[0] = "Creating user certificate for %s failed. %s" % (name, stderr)
+ return False
+ else:
+ return True
+
+
+def main():
+
+ msg = [""]
+
+ module = AnsibleModule(
+ argument_spec=dict(
+ name=dict(required=True, aliases=["user_name", "user"]),
+ path=dict(required=False),
+ certs_dir=dict(required=False),
+ ca_key=dict(required=False),
+ ),
+ )
+
+ name = module.params["name"]
+ path = module.params["path"]
+ certs_dir = module.params["certs_dir"]
+ ca_key = module.params["ca_key"]
+
+ if not path:
+ try:
+ command = "cockroach version"
+ module.run_command(command)
+ except OSError as e:
+ msg[0] = "Couldnt find cockroach executable. Check the path. stderr: %s" % (
+ e
+ )
+ module.fail_json(msg=msg[0], failed=True)
+
+ if not check_user_has_certificate(module, msg, path, name, certs_dir):
+ if create_certificate_for_user(module, msg, path, name, certs_dir, ca_key):
+ msg[0] = "Successfully created certificate for user %s " % (name)
+ module.exit_json(msg=msg[0], changed=True)
+ else:
+ module.fail_json(msg=msg[0], changed=False)
+ else:
+ msg[0] = "User %s already has certificate" % (name)
+ module.exit_json(msg=msg[0], changed=False)
+
+ module.exit_json(msg="Unhandled exit", changed=False)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/plugins/modules/cockroach_cluster.py b/plugins/modules/cockroach_cluster.py
new file mode 100644
index 0000000..97bf1b5
--- /dev/null
+++ b/plugins/modules/cockroach_cluster.py
@@ -0,0 +1,227 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+DOCUMENTATION = """
+---
+module: cockroach_cluster
+short_description: Manage a cockroach cluster
+description:
+ - Manage a cockroach cluster
+version_added: "0.4.0"
+options:
+ name:
+ description:
+ - The name of the service
+ required: true
+ default: None
+author: Mikael Sandström, oravirt@gmail.com, @oravirt
+"""
+
+EXAMPLES = """
+- name: create a master node
+ cockroach_cluster:
+ path: "/var/lib/cockroach"
+ host: "{{ inventory_hostname }}"
+ state: started
+
+- name: join a node to a cluster
+ cockroach_cluster:
+ path: "/var/lib/cockroach"
+ host: "{{ inventory_hostname }}"
+ join: true
+ cluster_master: "node1:{{ port }}"
+ state: started
+"""
+
+from ansible.module_utils.basic import *
+import os
+
+# Check if the service exists
+def check_node_started(module, msg, path):
+
+ command = "ps -ef"
+ (rc, stdout, stderr) = module.run_command(command)
+ searchstring = "%s/cockroach" % (path)
+ if rc != 0:
+ msg[0] = "Something went wrong, stderr: %s" % (stderr)
+
+ if searchstring in stdout.lower():
+ return True
+ else:
+ return False
+
+
+def start_node(
+ module,
+ msg,
+ path,
+ store,
+ host,
+ port,
+ http_port,
+ join,
+ cache,
+ log_dir,
+ certs_dir,
+ locality,
+ cluster_master,
+):
+
+ command = "nohup %s/cockroach start --http-port=%s --port=%s --host=%s " % (
+ path,
+ http_port,
+ port,
+ host,
+ )
+ if store:
+ command += " --store=%s" % (store)
+ if join:
+ command += " --join=%s:%s" % (cluster_master, port)
+ if cache:
+ command += " --cache=%s" % (cache)
+ if locality:
+ command += " --locality=%s" % (locality)
+ if log_dir:
+ command += " --log-dir %s" % (log_dir)
+ if not certs_dir:
+ command += " --insecure "
+ elif certs_dir:
+ command += " --certs-dir %s" % (certs_dir)
+ command += " --background"
+
+ # module.exit_json(msg=command)
+ (rc, stdout, stderr) = module.run_command(command)
+ if rc != 0:
+ msg[0] = "Starting failed. %s" % (stderr)
+ return False
+ else:
+ msg[0] = "Successfully started node - %s " % (stdout)
+ return True
+
+
+def stop_node(module, msg, path, host, port, certs_dir):
+
+ command = "%s/cockroach quit --host=%s --port=%s " % (path, host, port)
+ if not certs_dir:
+ command += " --insecure"
+ elif certs_dir:
+ command += " --certs-dir=%s" % (certs_dir)
+ (rc, stdout, stderr) = module.run_command(command)
+ if rc != 0:
+ msg[0] = "Failed to stop node. %s" % (stderr)
+ return False
+ else:
+ msg[0] = "Successfully stopped node - %s" % (stdout.strip())
+ return True
+
+
+def status_node(module, msg, path):
+
+ command = "%s/cockroach node status" % (path)
+ (rc, stdout, stderr) = module.run_command(command)
+ if rc != 0:
+ msg[0] = "Failed to check status for node: %s" % (stderr)
+ return False
+ else:
+ msg[0] = stdout
+ return True
+
+
+def main():
+
+ msg = [""]
+
+ module = AnsibleModule(
+ argument_spec=dict(
+ store=dict(required=False),
+ state=dict(default="started", choices=["started", "stopped", "status"]),
+ path=dict(required=False),
+ cache=dict(required=False),
+ log_dir=dict(required=False),
+ certs_dir=dict(required=False),
+ locality=dict(required=False),
+ port=dict(default=26257),
+ http_port=dict(default=8080),
+ host=dict(default="localhost"),
+ join=dict(required=False, type=bool),
+ cluster_master=dict(required=False),
+ ),
+ )
+
+ store = module.params["store"]
+ state = module.params["state"]
+ path = module.params["path"]
+ cache = module.params["cache"]
+ log_dir = module.params["log_dir"]
+ certs_dir = module.params["certs_dir"]
+ locality = module.params["locality"]
+ port = module.params["port"]
+ http_port = module.params["http_port"]
+ host = module.params["host"]
+ join = module.params["join"]
+ cluster_master = module.params["cluster_master"]
+
+ if not path:
+ try:
+ command = "cockroach version"
+ module.run_command(command)
+ except OSError as e:
+ msg[0] = "Couldnt find cockroach executable. Check the path. stderr: %s" % (
+ e
+ )
+ module.fail_json(msg=msg[0], failed=True)
+
+ if not store:
+ store = "%s/cockroach-data" % (path)
+
+ if state == "started":
+ if not check_node_started(module, msg, path):
+ if start_node(
+ module,
+ msg,
+ path,
+ store,
+ host,
+ port,
+ http_port,
+ join,
+ cache,
+ log_dir,
+ certs_dir,
+ locality,
+ cluster_master,
+ ):
+ module.exit_json(msg=msg[0], changed=True)
+ else:
+ module.fail_json(msg=msg[0], changed=False)
+ else:
+ msg[0] = "Already running"
+ module.exit_json(msg=msg[0], changed=False)
+
+ elif state == "stopped":
+ if check_node_started(module, msg, path):
+ if stop_node(module, msg, path, host, port, certs_dir):
+ # msg[0] = 'Successfully dropped database %s ' % (name)
+ module.exit_json(msg=msg[0], changed=True)
+ else:
+ module.fail_json(msg=msg[0], changed=False)
+ else:
+ msg[0] = "Node already stopped"
+ module.exit_json(msg=msg[0], changed=False)
+
+ elif state == "status":
+ if check_node_started(module, msg, path):
+ if status_node(module, msg, path, port, host, certs_dir):
+ # msg[0] = 'Successfully dropped database %s ' % (name)
+ module.exit_json(msg=msg[0], changed=False)
+ else:
+ module.fail_json(msg=msg[0], changed=False)
+ else:
+ msg[0] = "Node not running"
+ module.exit_json(msg=msg[0], changed=False)
+
+ module.exit_json(msg="Unhandled exit", changed=False)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/plugins/modules/cockroach_cluster_settings.py b/plugins/modules/cockroach_cluster_settings.py
new file mode 100644
index 0000000..0ee3f82
--- /dev/null
+++ b/plugins/modules/cockroach_cluster_settings.py
@@ -0,0 +1,123 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+DOCUMENTATION = """
+---
+module: cockroach_cluster_settings
+short_description: Manage settings in a Cockroach cluster
+description:
+ - Manage settings in a Cockroach cluster
+version_added: "0.4.0"
+options:
+ name:
+ description:
+ - The name of the setting
+ required: true
+ default: None
+ value:
+ description:
+ - The value of the setting
+ required: true
+ default: None
+author: Mikael Sandström, oravirt@gmail.com, @oravirt
+"""
+
+EXAMPLES = """
+- name: manage a setting
+ cockroach_cluster_settings:
+ name: 'diagnostics.reporting.enabled'
+ value: False
+ path: /var/lib/cockroach
+ host: "{{ inventory_hostname }}"
+ state: present
+"""
+import os
+
+
+def get_current_setting(module, msg, path, host, port, name, value, certs_dir):
+
+ command = "%s/cockroach sql --host=%s --port=%s " % (path, host, port)
+ if not certs_dir:
+ command += " --insecure"
+ elif certs_dir:
+ command += " --certs-dir=%s" % (certs_dir)
+ command += ' --execute "show cluster setting %s"' % (name)
+
+ (rc, stdout, stderr) = module.run_command(command)
+ if rc != 0:
+ msg = "Something went wrong, stderr: %s" % (stderr)
+
+ if value.lower() in stdout.lower():
+ return True
+ else:
+ return False
+
+
+def enforce_setting(module, msg, path, host, port, name, value, certs_dir):
+
+ currval = get_current_setting(module, msg, path, host, port, name, value, certs_dir)
+ if currval:
+ module.exit_json(msg="Nothing to change", changed=False)
+
+ command = "%s/cockroach sql --host=%s --port=%s " % (path, host, port)
+ if not certs_dir:
+ command += " --insecure"
+ elif certs_dir:
+ command += " --certs-dir=%s" % (certs_dir)
+ command += " --execute \"set cluster setting %s = '%s' \"" % (name, value)
+
+ (rc, stdout, stderr) = module.run_command(command)
+
+ if rc != 0:
+ msg = "stderr: %s" % (stderr)
+ module.fail_json(msg=msg)
+ else:
+ return True
+
+
+def main():
+
+ msg = [""]
+
+ module = AnsibleModule(
+ argument_spec=dict(
+ name=dict(required=True),
+ value=dict(required=True),
+ host=dict(required=False, default="localhost"),
+ port=dict(required=False, default=26257),
+ state=dict(default="present", choices=["present", "absent"]),
+ path=dict(required=False),
+ certs_dir=dict(required=False),
+ ),
+ )
+
+ name = module.params["name"]
+ value = module.params["value"]
+ host = module.params["host"]
+ port = module.params["port"]
+ state = module.params["state"]
+ path = module.params["path"]
+ certs_dir = module.params["certs_dir"]
+
+ if not path:
+ try:
+ command = "cockroach version"
+ module.run_command(command)
+ except OSError as e:
+ msg = "Couldnt find cockroach executable. Check the path. stderr: %s" % (e)
+ module.fail_json(msg=msg, failed=True)
+
+ if state == "present":
+ if enforce_setting(module, msg, path, host, port, name, value, certs_dir):
+ msg = "Successfully changed cluster setting: %s to %s" % (name, value)
+ module.exit_json(msg=msg, changed=True)
+ else:
+ module.fail_json(msg=msg, changed=False)
+
+ module.exit_json(msg="Unhandled exit", changed=False)
+
+
+from ansible.module_utils.basic import *
+
+if __name__ == "__main__":
+ main()
diff --git a/plugins/modules/cockroach_db.py b/plugins/modules/cockroach_db.py
new file mode 100755
index 0000000..af4be3f
--- /dev/null
+++ b/plugins/modules/cockroach_db.py
@@ -0,0 +1,156 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+DOCUMENTATION = """
+---
+module: cockroach_db
+short_description: Manage databases in a cockroach cluster
+description:
+ - Manage databases in a cockroach cluster
+version_added: 0.4.0
+options:
+ name:
+ description:
+ - The name of the database
+ required: true
+ default: None
+
+notes:
+author: Mikael Sandstrom, oravirt@gmail.com, @oravirt
+"""
+
+EXAMPLES = """
+# Create a database
+cockroach_db: name=db1 path=/var/lib/cockroach host={{ inventory_hostname }} state=present
+
+# Drop a database
+cockroach_db: name=db1 path=/var/lib/cockroach host={{ inventory_hostname }} state=absent
+
+"""
+import os
+
+
+# Check if the service exists
+def check_database_exists(module, msg, path, host, port, name, certs_dir):
+
+ # command = "%s/cockroach sql --host=%s --port=%s --insecure --execute \"show databases\"" % (path, host, port)
+ command = "%s/cockroach sql --host=%s --port=%s " % (path, host, port)
+ if not certs_dir:
+ command += " --insecure"
+ elif certs_dir:
+ command += " --certs-dir=%s" % (certs_dir)
+ command += (
+ " --execute \"SELECT datname FROM pg_catalog.pg_database where lower(datname) = lower('%s') \"" # nosec
+ % (name)
+ )
+
+ # module.fail_json(msg=command)
+ (rc, stdout, stderr) = module.run_command(command)
+ # module.exit_json(msg=rc)
+ if rc != 0:
+ msg[0] = "Something went wrong, stderr: %s" % (stderr)
+
+ if name.lower() in stdout.lower():
+ return True
+ else:
+ return False
+
+
+def create_database(module, msg, path, host, port, name, certs_dir):
+ command = "%s/cockroach sql --host=%s --port=%s " % (path, host, port)
+ if not certs_dir:
+ command += " --insecure"
+ elif certs_dir:
+ command += " --certs-dir=%s" % (certs_dir)
+ command += ' --execute "create database %s"' % (name)
+
+ (rc, stdout, stderr) = module.run_command(command)
+ if rc != 0:
+ msg[0] = "Creating database %s failed. %s, command: %s" % (
+ name,
+ stderr,
+ command,
+ )
+ return False
+ else:
+ return True
+
+
+def remove_database(module, msg, path, host, port, name, certs_dir):
+
+ command = "%s/cockroach sql --host=%s --port=%s " % (path, host, port)
+ if not certs_dir:
+ command += " --insecure"
+ elif certs_dir:
+ command += " --certs-dir=%s" % (certs_dir)
+ command += ' --execute "drop database %s"' % (name)
+
+ (rc, stdout, stderr) = module.run_command(command)
+ if rc != 0:
+ msg[0] = "Removing database %s failed: %s" % (name, stderr)
+ return False
+ else:
+ return True
+
+
+def main():
+
+ msg = [""]
+
+ module = AnsibleModule(
+ argument_spec=dict(
+ name=dict(required=True, aliases=["database_name", "db"]),
+ host=dict(required=False, default="localhost"),
+ port=dict(required=False, default=26257),
+ state=dict(default="present", choices=["present", "absent"]),
+ path=dict(required=False),
+ certs_dir=dict(required=False),
+ ),
+ )
+
+ name = module.params["name"]
+ host = module.params["host"]
+ port = module.params["port"]
+ state = module.params["state"]
+ path = module.params["path"]
+ certs_dir = module.params["certs_dir"]
+
+ if not path:
+ try:
+ command = "cockroach version"
+ module.run_command(command)
+ except OSError as e:
+ msg[0] = "Couldnt find cockroach executable. Check the path. stderr: %s" % (
+ e
+ )
+ module.fail_json(msg=msg[0], failed=True)
+
+ if state == "present":
+ if not check_database_exists(module, msg, path, host, port, name, certs_dir):
+ if create_database(module, msg, path, host, port, name, certs_dir):
+ msg[0] = "Successfully created database %s " % (name)
+ module.exit_json(msg=msg[0], changed=True)
+ else:
+ module.fail_json(msg=msg[0], changed=False)
+ else:
+ msg[0] = "Database %s already exists" % (name)
+ module.exit_json(msg=msg[0], changed=False)
+
+ elif state == "absent":
+ if check_database_exists(module, msg, path, host, port, name, certs_dir):
+ if remove_database(module, msg, path, host, port, name, certs_dir):
+ msg[0] = "Successfully dropped database %s " % (name)
+ module.exit_json(msg=msg[0], changed=True)
+ else:
+ module.fail_json(msg=msg[0], changed=False)
+ else:
+ msg[0] = "Database %s doesn't exist" % (name)
+ module.exit_json(msg=msg[0], changed=False)
+
+ module.exit_json(msg="Unhandled exit", changed=False)
+
+
+from ansible.module_utils.basic import *
+
+if __name__ == "__main__":
+ main()
diff --git a/plugins/modules/cockroach_info.py b/plugins/modules/cockroach_info.py
new file mode 100644
index 0000000..c583415
--- /dev/null
+++ b/plugins/modules/cockroach_info.py
@@ -0,0 +1,231 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+DOCUMENTATION = """
+---
+module: cockroach_info
+short_description: Returns facts about a Cockroach Cluster
+description:
+ - Returns facts about a Cockroach Cluster
+version_added: 0.4.0
+options:
+ host:
+ description:
+ - The cluster host
+ required: false
+ default: localhost
+ port:
+ description:
+ - The cluster port
+ required: false
+ default: 26257
+ user:
+ description:
+ - The cluster user to connect as
+ required: True
+ default: root
+ certs_dir:
+ description:
+ - Path to certificates on the cluster host
+
+notes:
+ - psycopg2 needs to be installed
+requirements: [ "psycopg2" ]
+author: Mikael Sandström, oravirt@gmail.com, @oravirt
+"""
+
+EXAMPLES = """
+- name: Gather Facts about CRDB Cluster
+ hosts: clusterhosts
+ become: true
+ vars:
+ cockroach_user: cockroach
+ path: /var/lib/cockroach/2.1.6
+ certs_dir: /var/lib/cockroach/certs
+ user: root
+ tasks:
+ - name: facts
+ cockroach_info:
+ user={{ user |default(omit)}}
+ path={{ path |default(omit)}}
+ host={{ ansible_fqdn }}
+ certs_dir={{ certs_dir |default (omit)}}
+ tags: facts
+ become_user: "{{ cockroach_user }}"
+ register: facts
+
+ - debug: msg="version - {{facts.ansible_facts.cockroach_version}}, node_id - {{facts.ansible_facts.node_id}}"
+ - debug: msg="org - {{ facts.ansible_facts.cluster_settings['cluster.organization'] }}{% if facts.ansible_facts.enterprise_license is defined %}, license - {{ facts.ansible_facts.enterprise_license }}{% endif %}"
+
+"""
+from datetime import datetime
+
+try:
+ from OpenSSL import crypto as c
+except ImportError:
+ pyopenssl_exists = False
+else:
+ pyopenssl_exists = True
+
+try:
+ import psycopg2
+except ImportError:
+ psycopg2_exists = False
+else:
+ psycopg2_exists = True
+
+
+def exec_sql_get(module, cur, query):
+
+ try:
+ cur.execute(query)
+ result = cur.fetchall()
+ except psycopg2.DatabaseError as e:
+ msg = e
+ module.fail_json(msg=msg, failed=True)
+
+ return result
+
+
+def get_enterprise_license(module, path, host, port, certs_dir):
+
+ command = "%s/cockroach sql --host=%s --port=%s " % (path, host, port)
+ if not certs_dir:
+ command += " --insecure"
+ elif certs_dir:
+ command += " --certs-dir=%s" % (certs_dir)
+ command += ' --execute "show cluster setting enterprise.license"'
+
+ (rc, stdout, stderr) = module.run_command(command)
+ if rc != 0:
+ msg = "Something went wrong, stderr: %s, command: %s" % (stderr, command)
+ module.fail_json(msg)
+ return stdout
+
+
+def get_cert_expiry_date(cert):
+ datefmt = "%Y%m%d%H%M%SZ"
+ cert = c.load_certificate(c.FILETYPE_PEM, file(cert).read())
+ return datetime.datetime.strptime(cert.get_notAfter(), datefmt)
+
+
+# Ansible code
+def main():
+
+ msg = [""]
+
+ module = AnsibleModule(
+ argument_spec=dict(
+ host=dict(required=False, default="localhost"),
+ port=dict(required=False, default=26257),
+ path=dict(required=False),
+ user=dict(required=False, default="root"),
+ certs_dir=dict(required=False),
+ ),
+ )
+
+ host = module.params["host"]
+ port = module.params["port"]
+ path = module.params["path"]
+ user = module.params["user"]
+ certs_dir = module.params["certs_dir"]
+
+ cacert = "%s/ca.crt" % (certs_dir)
+ nodecert = "%s/node.crt" % (certs_dir)
+ clientkey = "%s/client.%s.key" % (certs_dir, user)
+ clientcert = "%s/client.%s.crt" % (certs_dir, user)
+
+ if not psycopg2_exists:
+ msg = "psycopg2 does not seem to exist. Please install (e.g pip install psycopg2-binary)"
+ module.fail_json(msg=msg)
+
+ try:
+
+ # dsn = psycopg2.make_dsn(host=host, port=port, database=database, user=user,
+ # sslmode='require', sslkey=sslkey,sslcert=sslcert)
+ # conn = psycopg2.connect(dsn)
+ if certs_dir:
+ conn = psycopg2.connect(
+ user=user,
+ sslmode="require",
+ # sslrootcert=rootcert,
+ sslkey=clientkey,
+ sslcert=clientcert,
+ port=port,
+ host=host,
+ )
+ else:
+ conn = psycopg2.connect(user=user, sslmode="disable", port=port, host=host)
+ except psycopg2.DatabaseError as exc:
+ error = exc
+ msg = "Could not connect: %s" % (error)
+ module.fail_json(msg=msg)
+
+ cur = conn.cursor()
+
+ version_sql = (
+ "select value from system.crdb_internal.node_build_info where field = 'Version'"
+ )
+ node_id_sql = "select distinct(node_id) from system.crdb_internal.node_build_info"
+ database_sql = "select datname from system.pg_catalog.pg_database where datname not in ('system','defaultdb','postgres')"
+ user_sql = "select usename from system.pg_catalog.pg_user where usename not in ('adminui','root')"
+ cluster_settings_sql = (
+ "select variable, value from system.crdb_internal.cluster_settings"
+ )
+ cluster_id_sql = "select * from crdb_internal.cluster_id()"
+ version = exec_sql_get(module, cur, version_sql)[0][0]
+ node_id = exec_sql_get(module, cur, node_id_sql)[0][0]
+ cluster_id = exec_sql_get(module, cur, cluster_id_sql)[0][0]
+ cluster_settings = exec_sql_get(module, cur, cluster_settings_sql)
+ databases_ = exec_sql_get(module, cur, database_sql)
+ users_ = exec_sql_get(module, cur, user_sql)
+
+ db_dict = []
+ for d in databases_:
+ db_dict.append(d[0])
+ user_dict = []
+ for u in users_:
+ user_dict.append(u[0])
+
+ facts = {"cockroach_version": version.lstrip("v")}
+ facts.update({"node_id": node_id})
+ facts.update({"cluster_id": cluster_id})
+ facts.update({"databases": db_dict})
+ facts.update({"dbusers": user_dict})
+ facts.update({"cluster_settings": dict(cluster_settings)})
+
+ # Get Cluster settings
+ if path:
+ license = get_enterprise_license(module, path, host, port, certs_dir)
+ facts.update({"enterprise_license": license.split("\n")[1].rstrip("\n")})
+
+ # Get certificate information
+ if pyopenssl_exists and certs_dir:
+ currdate = datetime.datetime.now()
+ cert_dict = {}
+ rootcertexpiry = get_cert_expiry_date(clientcert)
+ nodecertexpiry = get_cert_expiry_date(nodecert)
+ cacertexpiry = get_cert_expiry_date(cacert)
+ cert_dict["certificate_information"] = {}
+ cert_dict["certificate_information"]["rootcert"] = clientcert
+ cert_dict["certificate_information"]["nodecert"] = nodecert
+ cert_dict["certificate_information"]["cacert"] = cacert
+ cert_dict["certificate_information"]["rootcert_expiration"] = rootcertexpiry
+ cert_dict["certificate_information"]["nodecert_expiration"] = nodecertexpiry
+ cert_dict["certificate_information"]["cacert_expiration"] = cacertexpiry
+ rootdelta = rootcertexpiry - currdate
+ nodedelta = nodecertexpiry - currdate
+ cadelta = cacertexpiry - currdate
+ # module.exit_json(msg=rootdelta.days)
+ cert_dict["certificate_information"]["rootcert_expiry_days"] = rootdelta.days
+ cert_dict["certificate_information"]["nodecert_expiry_days"] = nodedelta.days
+ cert_dict["certificate_information"]["cacert_expiry_days"] = cadelta.days
+ facts.update(cert_dict)
+
+ module.exit_json(changed=False, ansible_facts=facts)
+
+
+from ansible.module_utils.basic import *
+
+if __name__ == "__main__":
+ main()
diff --git a/plugins/modules/cockroach_privs.py b/plugins/modules/cockroach_privs.py
new file mode 100644
index 0000000..70c4e18
--- /dev/null
+++ b/plugins/modules/cockroach_privs.py
@@ -0,0 +1,125 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+DOCUMENTATION = """
+---
+module: cockroach_privs
+short_description: Manage user privileges in a cockroach db
+description:
+ - Manage user privileges in a cockroach db
+version_added: 0.4.0
+options:
+ name:
+ description:
+ - the name of the user to set permissions
+ required: true
+ default: None
+ db:
+ description:
+ - Name of the database to set permissions in
+ required: true
+ default: None
+ privs:
+ description:
+ - Privileges for the user
+ required: true
+ default: None
+author:
+ - Oscar C
+ - Mikael Sandstrom @oravirt
+"""
+
+EXAMPLES = """
+# Grant ALL privileges to user1 on db1
+cockroach_privs: name=user1 db=db1 privs=ALL path=/var/lib/cockroach
+"""
+from ansible.module_utils.basic import AnsibleModule
+import os
+
+# Check if the service exists
+def check_user_privs(module, msg, path, host, port, name, certs_dir, db, privs):
+ command = "%s/cockroach sql --host=%s --port=%s " % (path, host, port)
+ if not certs_dir:
+ command += " --insecure"
+ elif certs_dir:
+ command += " --certs-dir=%s" % (certs_dir)
+ command += ' --execute "SHOW GRANTS ON DATABASE %s FOR %s;"' % (db, name)
+
+ # module.fail_json(msg=command)
+ (rc, stdout, stderr) = module.run_command(command)
+ # module.exit_json(msg=rc)
+ if rc != 0:
+ msg[0] = "Something went wrong, stderr: %s" % (stderr)
+
+ if privs.lower() in stdout.lower():
+ return True
+ else:
+ return False
+
+
+def set_user_privs(module, msg, path, host, port, name, certs_dir, db, privs):
+ command = "%s/cockroach sql --host=%s --port=%s " % (path, host, port)
+ if not certs_dir:
+ command += " --insecure"
+ elif certs_dir:
+ command += " --certs-dir=%s" % (certs_dir)
+ command += ' --execute "GRANT %s ON DATABASE %s TO %s;"' % (privs, db, name)
+
+ # module.fail_json(msg=command)
+ (rc, stdout, stderr) = module.run_command(command)
+ if rc != 0:
+ msg[0] = "Setting user privileges for db %s failed. %s" % (db, stderr)
+ return False
+ else:
+ return True
+
+
+def main():
+
+ msg = [""]
+
+ module = AnsibleModule(
+ argument_spec=dict(
+ name=dict(required=True, aliases=["username", "user"]),
+ host=dict(required=False, default="localhost"),
+ port=dict(required=False, default=26257),
+ path=dict(required=False),
+ certs_dir=dict(required=False),
+ db=dict(required=True),
+ privs=dict(required=False, default="ALL"),
+ ),
+ )
+
+ name = module.params["name"]
+ host = module.params["host"]
+ port = module.params["port"]
+ path = module.params["path"]
+ certs_dir = module.params["certs_dir"]
+ db = module.params["db"]
+ privs = module.params["privs"]
+
+ if not path:
+ try:
+ command = "cockroach version"
+ module.run_command(command)
+ except OSError as e:
+ msg[0] = "Couldnt find cockroach executable. Check the path. stderr: %s" % (
+ e
+ )
+ module.fail_json(msg=msg[0], failed=True)
+
+ if not check_user_privs(module, msg, path, host, port, name, certs_dir, db, privs):
+ if set_user_privs(module, msg, path, host, port, name, certs_dir, db, privs):
+ msg[0] = "Successfully set permissions for user %s on db %s " % (name, db)
+ module.exit_json(msg=msg[0], changed=True)
+ else:
+ module.fail_json(msg=msg[0], changed=False)
+ else:
+ msg[0] = "User %s permissions already set on %s " % (name, db)
+ module.exit_json(msg=msg[0], changed=False)
+
+ module.exit_json(msg="Unhandled exit", changed=False)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/plugins/modules/cockroach_user.py b/plugins/modules/cockroach_user.py
new file mode 100644
index 0000000..a868093
--- /dev/null
+++ b/plugins/modules/cockroach_user.py
@@ -0,0 +1,152 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+DOCUMENTATION = """
+---
+module: cockroach_user
+short_description: Manage users in a cockroach cluster
+description:
+ - Manage users in a cockroach cluster
+version_added: 0.4.0
+options:
+ name:
+ description:
+ - The name of the user
+ required: true
+ default: None
+
+notes:
+author:
+ - Oscar C
+ - Mikael Sandström, oravirt@gmail.com, @oravirt
+"""
+
+EXAMPLES = """
+# Create a user
+cockroach_user: name=user1 path=/var/lib/cockroach host={{ inventory_hostname }} state=present
+
+# Delete a user
+cockroach_user: name=user1 path=/var/lib/cockroach host={{ inventory_hostname }} state=absent
+
+"""
+
+from ansible.module_utils.basic import *
+import os
+
+# Check if the service exists
+def check_user_exists(module, msg, path, host, port, name, certs_dir):
+ command = "%s/cockroach user ls --host=%s --port=%s " % (path, host, port)
+ if not certs_dir:
+ command += " --insecure"
+ elif certs_dir:
+ command += " --certs-dir=%s" % (certs_dir)
+
+ # module.fail_json(msg=command)
+ (rc, stdout, stderr) = module.run_command(command)
+ # module.exit_json(msg=rc)
+ if rc != 0:
+ msg[0] = "Something went wrong, stderr: %s" % (stderr)
+
+ if name.lower() in stdout.lower():
+ return True
+ else:
+ return False
+
+
+def create_user(module, msg, path, host, port, name, certs_dir):
+ command = "%s/cockroach user set %s --host=%s --port=%s " % (
+ path,
+ name,
+ host,
+ port,
+ )
+ if not certs_dir:
+ command += " --insecure"
+ elif certs_dir:
+ command += " --certs-dir=%s" % (certs_dir)
+
+ # module.fail_json(msg=command)
+ (rc, stdout, stderr) = module.run_command(command)
+ if rc != 0:
+ msg[0] = "Creating user %s failed. %s. Command: %s" % (name, stderr, command)
+ return False
+ else:
+ return True
+
+
+def remove_user(module, msg, path, host, port, name, certs_dir):
+
+ command = "%s/cockroach user rm %s --host=%s --port=%s " % (path, name, host, port)
+ if not certs_dir:
+ command += " --insecure"
+ elif certs_dir:
+ command += " --certs-dir=%s" % (certs_dir)
+ # command += ' user rm %s' % (name)
+
+ (rc, stdout, stderr) = module.run_command(command)
+ if rc != 0:
+ msg[0] = "Removing user %s failed: %s" % (name, stderr)
+ return False
+ else:
+ return True
+
+
+def main():
+
+ msg = [""]
+
+ module = AnsibleModule(
+ argument_spec=dict(
+ name=dict(required=True, aliases=["user_name", "user"]),
+ host=dict(required=False, default="localhost"),
+ port=dict(required=False, default=26257),
+ state=dict(default="present", choices=["present", "absent"]),
+ path=dict(required=False),
+ certs_dir=dict(required=False),
+ ),
+ )
+
+ name = module.params["name"]
+ host = module.params["host"]
+ port = module.params["port"]
+ state = module.params["state"]
+ path = module.params["path"]
+ certs_dir = module.params["certs_dir"]
+
+ if not path:
+ try:
+ command = "cockroach version"
+ module.run_command(command)
+ except OSError as e:
+ msg[0] = "Couldnt find cockroach executable. Check the path. stderr: %s" % (
+ e
+ )
+ module.fail_json(msg=msg[0], failed=True)
+
+ if state == "present":
+ if not check_user_exists(module, msg, path, host, port, name, certs_dir):
+ if create_user(module, msg, path, host, port, name, certs_dir):
+ msg[0] = "Successfully created user %s " % (name)
+ module.exit_json(msg=msg[0], changed=True)
+ else:
+ module.fail_json(msg=msg[0], changed=False)
+ else:
+ msg[0] = "User %s already exists" % (name)
+ module.exit_json(msg=msg[0], changed=False)
+
+ elif state == "absent":
+ if check_user_exists(module, msg, path, host, port, name, certs_dir):
+ if remove_user(module, msg, path, host, port, name, certs_dir):
+ msg[0] = "Successfully deleted user %s " % (name)
+ module.exit_json(msg=msg[0], changed=True)
+ else:
+ module.fail_json(msg=msg[0], changed=False)
+ else:
+ msg[0] = "User %s doesn't exist" % (name)
+ module.exit_json(msg=msg[0], changed=False)
+
+ module.exit_json(msg="Unhandled exit", changed=False)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/plugins/modules/doh.py b/plugins/modules/doh.py
index 25dfe7c..94eddc5 100644
--- a/plugins/modules/doh.py
+++ b/plugins/modules/doh.py
@@ -12,10 +12,11 @@
module: doh
short_description: DNS Lookup over HTTPS.
description:
- - DNS Lookup over HTTPS from various Public DOH Servers like Google/Cloudflare/Quad9.
+ - DNS Lookup over HTTPS from various Public DOH Servers like Google/Cloudflare/Quad9/Alibaba.
- U(https://developers.cloudflare.com/1.1.1.1/encrypted-dns/dns-over-https/make-api-requests/dns-json)
- U(https://developers.google.com/speed/public-dns/docs/doh/json)
- U(https://www.quad9.net/news/blog/doh-with-quad9-dns-servers/)
+ - U(https://www.alibabacloud.com/help/en/doc-detail/171666.html)
version_added: 0.4.0
options:
source:
@@ -23,7 +24,7 @@
- DNS over HTTPS can be queried from Google/Cloudflare/Quad9.
required: false
type: str
- choices: ["google", "cloudflare", "quad9"]
+ choices: ["google", "cloudflare", "quad9", "alibaba"]
default: "cloudflare"
domain_name:
description:
@@ -72,6 +73,12 @@
source: "quad9"
name: "example.com"
type: "MX"
+
+- name: fetch A record from Alibaba DNS over HTTPS
+ community.missing_collection.doh:
+ source: "alibaba"
+ name: "example.com"
+ type: "A"
"""
RETURN = """
@@ -109,7 +116,7 @@
def main():
argument_spec = dict(
- source=dict(choices=["google", "cloudflare", "quad9"], default="cloudflare"),
+ source=dict(choices=["google", "cloudflare", "quad9", "alibaba"], default="cloudflare"),
domain_name=dict(required=True, aliases=["name"]),
type=dict(default="A"),
do=dict(type=bool, default=True),
@@ -132,9 +139,10 @@ def main():
"cloudflare": "https://cloudflare-dns.com/dns-query",
"google": "https://dns.google/resolve",
"quad9": "https://dns.quad9.net:5053/dns-query",
+ "alibaba": "https://dns.alidns.com/resolve",
}
- if module.params["source"] in dns_urls.keys():
+ if module.params["source"] in dns_urls:
r = requests.get(
url=dns_urls[module.params["source"]], params=params, headers=headers
)
diff --git a/tests/integration/doh.yaml b/tests/integration/doh.yaml
index 699334b..0e09606 100644
--- a/tests/integration/doh.yaml
+++ b/tests/integration/doh.yaml
@@ -20,3 +20,9 @@
source: "quad9"
name: "example.com"
type: "MX"
+
+ - name: fetch A record from Alibaba DNS over HTTPS
+ doh:
+ source: "alibaba"
+ name: "example.com"
+ type: "A"
|