summaryrefslogtreecommitdiffstats
path: root/ansible_collections/community/mongodb/plugins
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-18 05:52:35 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-18 05:52:35 +0000
commit7fec0b69a082aaeec72fee0612766aa42f6b1b4d (patch)
treeefb569b86ca4da888717f5433e757145fa322e08 /ansible_collections/community/mongodb/plugins
parentReleasing progress-linux version 7.7.0+dfsg-3~progress7.99u1. (diff)
downloadansible-7fec0b69a082aaeec72fee0612766aa42f6b1b4d.tar.xz
ansible-7fec0b69a082aaeec72fee0612766aa42f6b1b4d.zip
Merging upstream version 9.4.0+dfsg.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'ansible_collections/community/mongodb/plugins')
-rw-r--r--ansible_collections/community/mongodb/plugins/cache/mongodb.py2
-rw-r--r--ansible_collections/community/mongodb/plugins/doc_fragments/atlas_options.py54
-rw-r--r--ansible_collections/community/mongodb/plugins/module_utils/mongodb_atlas.py220
-rw-r--r--ansible_collections/community/mongodb/plugins/module_utils/mongodb_common.py7
-rw-r--r--ansible_collections/community/mongodb/plugins/modules/mongodb_atlas_cluster.py238
-rw-r--r--ansible_collections/community/mongodb/plugins/modules/mongodb_atlas_ldap_user.py165
-rw-r--r--ansible_collections/community/mongodb/plugins/modules/mongodb_atlas_user.py196
-rw-r--r--ansible_collections/community/mongodb/plugins/modules/mongodb_atlas_whitelist.py111
-rw-r--r--ansible_collections/community/mongodb/plugins/modules/mongodb_balancer.py2
-rw-r--r--ansible_collections/community/mongodb/plugins/modules/mongodb_monitoring.py197
-rw-r--r--ansible_collections/community/mongodb/plugins/modules/mongodb_replicaset.py5
-rw-r--r--ansible_collections/community/mongodb/plugins/modules/mongodb_role.py4
-rw-r--r--ansible_collections/community/mongodb/plugins/modules/mongodb_user.py3
13 files changed, 998 insertions, 206 deletions
diff --git a/ansible_collections/community/mongodb/plugins/cache/mongodb.py b/ansible_collections/community/mongodb/plugins/cache/mongodb.py
index b51b7b293..0fa7a2cd8 100644
--- a/ansible_collections/community/mongodb/plugins/cache/mongodb.py
+++ b/ansible_collections/community/mongodb/plugins/cache/mongodb.py
@@ -182,7 +182,7 @@ class CacheModule(BaseCacheModule):
def contains(self, key):
with self._collection() as collection:
- return bool(collection.count({'_id': self._make_key(key)}))
+ return bool(collection.count_documents({'_id': self._make_key(key)}))
def delete(self, key):
del self._cache[key]
diff --git a/ansible_collections/community/mongodb/plugins/doc_fragments/atlas_options.py b/ansible_collections/community/mongodb/plugins/doc_fragments/atlas_options.py
new file mode 100644
index 000000000..dfdee3325
--- /dev/null
+++ b/ansible_collections/community/mongodb/plugins/doc_fragments/atlas_options.py
@@ -0,0 +1,54 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2021 T-Systems MMS
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+#
+# This module 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 software 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this software. If not, see <http://www.gnu.org/licenses/>.
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+
+class ModuleDocFragment(object):
+ # Documentation for global options that are always the same
+ DOCUMENTATION = r'''
+options:
+ api_username:
+ description:
+ - The username for use in authentication with the Atlas API.
+ - Can use API users and tokens (public key is username)
+ type: str
+ required: True
+ aliases: [apiUsername]
+ api_password:
+ description:
+ - The password for use in authentication with the Atlas API.
+ - Can use API users and tokens (private key is password)
+ type: str
+ required: True
+ aliases: [apiPassword]
+ group_id:
+ description:
+ - Unique identifier for the Atlas project.
+ type: str
+ required: True
+ aliases: [groupId]
+ state:
+ description:
+ - State of the ressource.
+ choices: [ "present", "absent" ]
+ default: present
+ type: str
+'''
diff --git a/ansible_collections/community/mongodb/plugins/module_utils/mongodb_atlas.py b/ansible_collections/community/mongodb/plugins/module_utils/mongodb_atlas.py
new file mode 100644
index 000000000..a32f3e1de
--- /dev/null
+++ b/ansible_collections/community/mongodb/plugins/module_utils/mongodb_atlas.py
@@ -0,0 +1,220 @@
+# -*- coding: utf-8 -*-
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+import json
+from collections import defaultdict
+
+from ansible.module_utils.urls import fetch_url
+
+try:
+ from urllib import quote
+except ImportError:
+ # noinspection PyCompatibility, PyUnresolvedReferences
+ from urllib.parse import (
+ quote,
+ ) # pylint: disable=locally-disabled, import-error, no-name-in-module
+
+
+class AtlasAPIObject:
+ module = None
+
+ def __init__(
+ self, module, object_name, group_id, path, data, data_is_array=False
+ ):
+ self.module = module
+ self.path = path
+ self.data = data
+ self.group_id = group_id
+ self.object_name = object_name
+ self.data_is_array = data_is_array
+
+ self.module.params["url_username"] = self.module.params["api_username"]
+ self.module.params["url_password"] = self.module.params["api_password"]
+
+ def call_url(self, path, data="", method="GET"):
+ headers = {
+ "Accept": "application/json",
+ "Content-Type": "application/json",
+ }
+
+ if self.data_is_array and data != "":
+ data = "[" + data + "]"
+
+ url = (
+ "https://cloud.mongodb.com/api/atlas/v1.0/groups/"
+ + self.group_id
+ + path
+ )
+ rsp, info = fetch_url(
+ module=self.module,
+ url=url,
+ data=data,
+ headers=headers,
+ method=method,
+ )
+
+ content = ""
+ error = ""
+ if rsp and info["status"] not in (204, 404):
+ content = json.loads(rsp.read())
+ if info["status"] >= 400:
+ try:
+ content = json.loads(info["body"])
+ error = content["reason"]
+ if "detail" in content:
+ error += ". Detail: " + content["detail"]
+ except ValueError:
+ error = info["msg"]
+ if info["status"] < 0:
+ error = info["msg"]
+ return {"code": info["status"], "data": content, "error": error}
+
+ def exists(self):
+ additional_path = ""
+ if self.path == "/databaseUsers":
+ additional_path = "/admin"
+ ret = self.call_url(
+ path=self.path
+ + additional_path
+ + "/"
+ + quote(self.data[self.object_name], "")
+ )
+ if ret["code"] == 200:
+ return True
+ return False
+
+ def create(self):
+ ret = self.call_url(
+ path=self.path,
+ data=self.module.jsonify(self.data),
+ method="POST",
+ )
+ return ret
+
+ def delete(self):
+ additional_path = ""
+ if self.path == "/databaseUsers":
+ additional_path = "/admin"
+ ret = self.call_url(
+ path=self.path
+ + additional_path
+ + "/"
+ + quote(self.data[self.object_name], ""),
+ method="DELETE",
+ )
+ return ret
+
+ def modify(self):
+ additional_path = ""
+ if self.path == "/databaseUsers":
+ additional_path = "/admin"
+ ret = self.call_url(
+ path=self.path
+ + additional_path
+ + "/"
+ + quote(self.data[self.object_name], ""),
+ data=self.module.jsonify(self.data),
+ method="PATCH",
+ )
+ return ret
+
+ def diff(self):
+ additional_path = ""
+ if self.path == "/databaseUsers":
+ additional_path = "/admin"
+ ret = self.call_url(
+ path=self.path
+ + additional_path
+ + "/"
+ + quote(self.data[self.object_name], ""),
+ method="GET",
+ )
+
+ data_from_atlas = json.loads(self.module.jsonify(ret["data"]))
+ data_from_task = json.loads(self.module.jsonify(self.data))
+
+ diff = defaultdict(dict)
+ for key, value in data_from_atlas.items():
+ if key in data_from_task.keys() and value != data_from_task[key]:
+ diff["before"][key] = "{val}".format(val=value)
+ diff["after"][key] = "{val}".format(val=data_from_task[key])
+ return diff
+
+ def update(self, state):
+ changed = False
+ diff_result = {"before": "", "after": ""}
+ if self.exists():
+ diff_result.update({"before": "state: present\n"})
+ if state == "absent":
+ if self.module.check_mode:
+ diff_result.update({"after": "state: absent\n"})
+ self.module.exit_json(
+ changed=True,
+ object_name=self.data[self.object_name],
+ diff=diff_result,
+ )
+ else:
+ try:
+ ret = self.delete()
+ if ret["code"] == 204 or ret["code"] == 202:
+ changed = True
+ diff_result.update({"after": "state: absent\n"})
+ else:
+ self.module.fail_json(
+ msg="bad return code while deleting: %d. Error message: %s"
+ % (ret["code"], ret["error"])
+ )
+ except Exception as e:
+ self.module.fail_json(
+ msg="exception when deleting: " + str(e)
+ )
+
+ else:
+ diff_result.update(self.diff())
+ if self.module.check_mode:
+ if diff_result["after"] != "":
+ changed = True
+ self.module.exit_json(
+ changed=changed,
+ object_name=self.data[self.object_name],
+ data=self.data,
+ diff=diff_result,
+ )
+ if diff_result["after"] != "":
+ if self.path == "/whitelist":
+ ret = self.create()
+ else:
+ ret = self.modify()
+ if ret["code"] == 200 or ret["code"] == 201:
+ changed = True
+ else:
+ self.module.fail_json(
+ msg="bad return code while modifying: %d. Error message: %s"
+ % (ret["code"], ret["error"])
+ )
+
+ else:
+ diff_result.update({"before": "state: absent\n"})
+ if state == "present":
+ if self.module.check_mode:
+ changed = True
+ diff_result.update({"after": "state: created\n"})
+ else:
+ try:
+ ret = self.create()
+ if ret["code"] == 201:
+ changed = True
+ diff_result.update({"after": "state: created\n"})
+ else:
+ self.module.fail_json(
+ msg="bad return code while creating: %d. Error message: %s"
+ % (ret["code"], ret["error"])
+ )
+ except Exception as e:
+ self.module.fail_json(
+ msg="exception while creating: " + str(e)
+ )
+ return changed, diff_result
diff --git a/ansible_collections/community/mongodb/plugins/module_utils/mongodb_common.py b/ansible_collections/community/mongodb/plugins/module_utils/mongodb_common.py
index e1ab27293..2a748b96f 100644
--- a/ansible_collections/community/mongodb/plugins/module_utils/mongodb_common.py
+++ b/ansible_collections/community/mongodb/plugins/module_utils/mongodb_common.py
@@ -168,9 +168,9 @@ def rename_ssl_option_for_pymongo4(connection_options):
when the driver use is >= PyMongo 4
"""
if int(PyMongoVersion[0]) >= 4:
- if connection_options.get('ssl_cert_reqs', None) == 'CERT_NONE':
- connection_options['tlsAllowInvalidCertificates'] = False
- elif connection_options.get('ssl_cert_reqs', None) == 'CERT_REQUIRED':
+ if connection_options.get('ssl_cert_reqs', None) in ('CERT_NONE', ssl_lib.CERT_NONE):
+ connection_options['tlsAllowInvalidCertificates'] = True
+ elif connection_options.get('ssl_cert_reqs', None) in ('CERT_REQUIRED', ssl_lib.CERT_REQUIRED):
connection_options['tlsAllowInvalidCertificates'] = False
connection_options.pop('ssl_cert_reqs', None)
if connection_options.get('ssl_ca_certs', None) is not None:
@@ -395,6 +395,7 @@ def member_dicts_different(conf, member_config):
"hidden": False,
"priority": {"nonarbiter": 1.0, "arbiter": 0},
"tags": {},
+ "horizons": {},
"secondardDelaySecs": 0,
"votes": 1
}
diff --git a/ansible_collections/community/mongodb/plugins/modules/mongodb_atlas_cluster.py b/ansible_collections/community/mongodb/plugins/modules/mongodb_atlas_cluster.py
new file mode 100644
index 000000000..e8aa6e43f
--- /dev/null
+++ b/ansible_collections/community/mongodb/plugins/modules/mongodb_atlas_cluster.py
@@ -0,0 +1,238 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2020 T-Systems MMS
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+#
+# This module 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 software 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this software. If not, see <http://www.gnu.org/licenses/>.
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+DOCUMENTATION = '''
+---
+module: mongodb_atlas_cluster
+short_description: Manage database clusters in Atlas
+description:
+ - The clusters module provides access to your cluster configurations.
+ - The module lets you create, edit and delete clusters.
+ - L(API Documentation,https://docs.atlas.mongodb.com/reference/api/clusters/)
+author: "Martin Schurz (@schurzi)"
+extends_documentation_fragment: community.mongodb.atlas_options
+options:
+ name:
+ description:
+ - Name of the cluster as it appears in Atlas. Once the cluster is created, its name cannot be changed.
+ type: str
+ required: True
+ mongo_db_major_version:
+ description:
+ - Version of the cluster to deploy.
+ - Atlas always deploys the cluster with the latest stable release of the specified version.
+ - You can upgrade to a newer version of MongoDB when you modify a cluster.
+ choices: [ "4.2", "4.4", "5.0", "6.0", "7.0" ]
+ type: str
+ aliases: [ "mongoDBMajorVersion" ]
+ cluster_type:
+ description:
+ - Type of the cluster that you want to create.
+ choices: [ "REPLICASET", "SHARDED" ]
+ default: "REPLICASET"
+ type: str
+ aliases: [ "clusterType" ]
+ replication_factor:
+ description:
+ - Number of replica set members. Each member keeps a copy of your databases, providing high availability and data redundancy.
+ choices: [ 3, 5, 7 ]
+ default: 3
+ type: int
+ aliases: [ "replicationFactor" ]
+ auto_scaling:
+ description:
+ - Configure your cluster to automatically scale its storage and cluster tier.
+ suboptions:
+ disk_gb_enabled:
+ type: bool
+ description:
+ - Specifies whether disk auto-scaling is enabled. The default is true.
+ aliases: [ "diskGBEnabled" ]
+ required: False
+ type: dict
+ aliases: [ "autoScaling" ]
+ provider_settings:
+ description:
+ - Configuration for the provisioned servers on which MongoDB runs.
+ - The available options are specific to the cloud service provider.
+ suboptions:
+ provider_name:
+ required: True
+ type: str
+ description:
+ - Cloud service provider on which the servers are provisioned.
+ aliases: [ "providerName" ]
+ region_name:
+ required: True
+ type: str
+ description:
+ - Physical location of your MongoDB cluster.
+ aliases: [ "regionName" ]
+ instance_size_name:
+ required: True
+ type: str
+ description:
+ - Atlas provides different cluster tiers, each with a default storage capacity and RAM size.
+ - The cluster you select is used for all the data-bearing servers in your cluster tier.
+ aliases: [ "instanceSizeName" ]
+ required: True
+ type: dict
+ aliases: [ "providerSettings" ]
+ disk_size_gb:
+ description:
+ - Capacity, in gigabytes, of the host's root volume. Increase this number to add capacity,
+ up to a maximum possible value of 4096 (i.e., 4 TB). This value must be a positive integer.
+ type: int
+ aliases: [ "diskSizeGB" ]
+ provider_backup_enabled:
+ description:
+ - Flag that indicates if the cluster uses Cloud Backups for backups.
+ type: bool
+ aliases: [ "providerBackupEnabled" ]
+ pit_enabled:
+ description:
+ - Flag that indicates the cluster uses continuous cloud backups.
+ type: bool
+ aliases: [ "pitEnabled" ]
+'''
+
+EXAMPLES = '''
+ - name: test cluster
+ community.mongodb.mongodb_atlas_cluster:
+ api_username: "API_user"
+ api_password: "API_passwort_or_token"
+ group_id: "GROUP_ID"
+ name: "testcluster"
+ mongo_db_major_version: "4.0"
+ cluster_type: "REPLICASET"
+ provider_settings:
+ provider_name: "GCP"
+ region_name: "EUROPE_WEST_3"
+ instance_size_name: "M10"
+...
+'''
+
+from ansible.module_utils.basic import AnsibleModule
+from ansible_collections.community.mongodb.plugins.module_utils.mongodb_atlas import (
+ AtlasAPIObject,
+)
+
+
+# ===========================================
+# Module execution.
+#
+def main():
+ # add our own arguments
+ argument_spec = dict(
+ state=dict(default="present", choices=["absent", "present"]),
+ api_username=dict(required=True, aliases=['apiUsername']),
+ api_password=dict(required=True, no_log=True, aliases=['apiPassword']),
+ group_id=dict(required=True, aliases=['groupId']),
+ name=dict(required=True),
+ mongo_db_major_version=dict(
+ choices=["4.2", "4.4", "5.0", "6.0", "7.0"],
+ aliases=["mongoDBMajorVersion"]
+ ),
+ cluster_type=dict(
+ default="REPLICASET", choices=["REPLICASET", "SHARDED"],
+ aliases=["clusterType"]
+ ),
+ replication_factor=dict(default=3, type="int", choices=[3, 5, 7], aliases=["replicationFactor"]),
+ auto_scaling=dict(
+ type="dict",
+ options=dict(
+ disk_gb_enabled=dict(type="bool", aliases=["diskGBEnabled"]),
+ ),
+ aliases=["autoScaling"]
+ ),
+ provider_settings=dict(
+ type="dict",
+ required=True,
+ options=dict(
+ provider_name=dict(required=True, aliases=["providerName"]),
+ region_name=dict(required=True, aliases=["regionName"]),
+ instance_size_name=dict(required=True, aliases=["instanceSizeName"]),
+ ),
+ aliases=["providerSettings"]
+ ),
+ disk_size_gb=dict(type="int", aliases=["diskSizeGB"]),
+ provider_backup_enabled=dict(type="bool", aliases=["providerBackupEnabled"]),
+ pit_enabled=dict(type="bool", aliases=["pitEnabled"]),
+ )
+
+ # Define the main module
+ module = AnsibleModule(
+ argument_spec=argument_spec, supports_check_mode=True
+ )
+
+ data = {
+ "name": module.params["name"],
+ "clusterType": module.params["cluster_type"],
+ "replicationFactor": module.params["replication_factor"],
+ "providerSettings": {
+ "providerName": module.params["provider_settings"]["provider_name"],
+ "regionName": module.params["provider_settings"]["region_name"],
+ "instanceSizeName": module.params["provider_settings"]["instance_size_name"],
+ }
+ }
+
+ # handle optional options
+ optional_vars = {
+ "mongo_db_major_version": "mongoDBMajorVersion",
+ "auto_scaling": "autoScaling",
+ "disk_size_gb": "diskSizeGB",
+ "provider_backup_enabled": "providerBackupEnabled",
+ "pit_enabled": "pitEnabled",
+ }
+
+ for key in optional_vars:
+ if module.params[key] is not None:
+ if key == "auto_scaling":
+ data.update({optional_vars[key]: {"diskGBEnabled": module.params[key]["disk_gb_enabled"]}})
+ else:
+ data.update({optional_vars[key]: module.params[key]})
+
+ try:
+ atlas = AtlasAPIObject(
+ module=module,
+ path="/clusters",
+ object_name="name",
+ group_id=module.params["group_id"],
+ data=data,
+ )
+ except Exception as e:
+ module.fail_json(
+ msg="unable to connect to Atlas API. Exception message: %s" % e
+ )
+
+ changed, diff = atlas.update(module.params["state"])
+ module.exit_json(
+ changed=changed,
+ data=atlas.data,
+ diff=diff,
+ )
+
+
+# import module snippets
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/community/mongodb/plugins/modules/mongodb_atlas_ldap_user.py b/ansible_collections/community/mongodb/plugins/modules/mongodb_atlas_ldap_user.py
new file mode 100644
index 000000000..e816a264c
--- /dev/null
+++ b/ansible_collections/community/mongodb/plugins/modules/mongodb_atlas_ldap_user.py
@@ -0,0 +1,165 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2020 T-Systems MMS
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+#
+# This module 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 software 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this software. If not, see <http://www.gnu.org/licenses/>.
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+DOCUMENTATION = '''
+---
+module: mongodb_atlas_ldap_user
+short_description: Manage LDAP users in Atlas
+description:
+ - The mongodb_atlas_ldap_user module lets you create LDAP groups on the admin database by mapping LDAP groups to MongoDB roles on your Atlas databases.
+ - Each user or group has a set of roles that provide access to the project's databases.
+ - L(API Documentation,https://docs.atlas.mongodb.com/security-ldaps/)
+author: "Martin Schurz (@schurzi) / Derek Giri"
+extends_documentation_fragment: community.mongodb.atlas_options
+options:
+ database_name:
+ description:
+ - Database against which Atlas authenticates the user.
+ choices: ["admin", "$external"]
+ default: "admin"
+ type: str
+ aliases: [ "databaseName" ]
+ ldap_auth_type:
+ description:
+ - Type of LDAP authorization for the user i.e. USER or GROUP
+ choices: ["GROUP", "USER"]
+ default: "GROUP"
+ type: str
+ aliases: [ "ldapAuthType" ]
+ username:
+ description:
+ - Username for authenticating to MongoDB.
+ required: true
+ type: str
+ roles:
+ description:
+ - Array of this user's roles and the databases / collections on which the roles apply.
+ - A role must include folliwing elements
+ suboptions:
+ database_name:
+ required: true
+ type: str
+ description:
+ - Database on which the user has the specified role.
+ - A role on the admin database can include privileges that apply to the other databases.
+ aliases: [ "databaseName" ]
+ role_name:
+ required: true
+ type: str
+ description:
+ - Name of the role. This value can either be a built-in role or a custom role.
+ aliases: ["roleName" ]
+ required: true
+ type: list
+ elements: dict
+'''
+
+EXAMPLES = '''
+ - name: LDAP Group or Username
+ community.mongodb.mongodb_atlas_ldap_user:
+ api_username: "API_user"
+ api_password: "API_passwort_or_token"
+ atlas_ldap_user: "USER DN or GROUP DN"
+ group_id: "GROUP_ID"
+ database_name: "admin"
+ username: my_app_user
+ roles:
+ - database_name: private_info
+ role_name: read
+ - database_name: public_info
+ role_name: readWrite
+'''
+
+from ansible.module_utils.basic import AnsibleModule
+from ansible_collections.community.mongodb.plugins.module_utils.mongodb_atlas import (
+ AtlasAPIObject,
+)
+
+
+# ===========================================
+# Module execution.
+#
+def main():
+ # add our own arguments
+ argument_spec = dict(
+ state=dict(default="present", choices=["absent", "present"]),
+ api_username=dict(required=True, aliases=['apiUsername']),
+ api_password=dict(required=True, no_log=True, aliases=['apiPassword']),
+ group_id=dict(required=True, aliases=['groupId']),
+ ldap_auth_type=dict(default="GROUP", choices=["GROUP", "USER"], aliases=["ldapAuthType"]),
+ database_name=dict(default="admin", choices=["admin", "$external"], aliases=["databaseName"]),
+ username=dict(required=True),
+ roles=dict(
+ required=True,
+ type="list",
+ elements="dict",
+ options=dict(
+ database_name=dict(required=True, aliases=["databaseName"]),
+ role_name=dict(required=True, aliases=["roleName"]),
+ ),
+ ),
+ )
+
+ # Define the main module
+ module = AnsibleModule(
+ argument_spec=argument_spec, supports_check_mode=True
+ )
+
+ data = {
+ "databaseName": module.params["database_name"],
+ "ldapAuthType": module.params["ldap_auth_type"],
+ "username": module.params["username"],
+ "roles": [],
+ }
+
+ # remap keys to API format
+ for role in module.params.get("roles"):
+ data["roles"].append({
+ "databaseName": role.get("database_name"),
+ "roleName": role.get("role_name")
+ })
+
+ try:
+ atlas = AtlasAPIObject(
+ module=module,
+ path="/databaseUsers",
+ object_name="username",
+ group_id=module.params["group_id"],
+ data=data,
+ )
+ except Exception as e:
+ module.fail_json(
+ msg="unable to connect to Atlas API. Exception message: %s" % e
+ )
+
+ changed, diff = atlas.update(module.params["state"])
+ module.exit_json(
+ changed=changed,
+ data=atlas.data,
+ diff=diff,
+ )
+
+
+# import module snippets
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/community/mongodb/plugins/modules/mongodb_atlas_user.py b/ansible_collections/community/mongodb/plugins/modules/mongodb_atlas_user.py
new file mode 100644
index 000000000..ac8427b03
--- /dev/null
+++ b/ansible_collections/community/mongodb/plugins/modules/mongodb_atlas_user.py
@@ -0,0 +1,196 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2020 T-Systems MMS
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+#
+# This module 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 software 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this software. If not, see <http://www.gnu.org/licenses/>.
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+DOCUMENTATION = '''
+---
+module: mongodb_atlas_user
+short_description: Manage database users in Atlas
+description:
+ - The mongodb_atlas_user module lets you create, modify and delete the database users in your cluster.
+ - Each user has a set of roles that provide access to the project's databases.
+ - A user's roles apply to all the clusters in the project
+ - if two clusters have a products database and a user has a role granting read access on the products database,
+ - the user has that access on both clusters.
+ - L(API Documentation,https://docs.atlas.mongodb.com/reference/api/database-users/)
+author: "Martin Schurz (@schurzi)"
+extends_documentation_fragment: community.mongodb.atlas_options
+options:
+ database_name:
+ description:
+ - Database against which Atlas authenticates the user.
+ choices: ["admin", "$external"]
+ default: "admin"
+ type: str
+ aliases: [ "databaseName" ]
+ username:
+ description:
+ - Username for authenticating to MongoDB.
+ required: true
+ type: str
+ password:
+ description:
+ - User's password.
+ required: true
+ type: str
+ roles:
+ description:
+ - Array of this user's roles and the databases / collections on which the roles apply.
+ - A role must include following elements
+ suboptions:
+ database_name:
+ required: true
+ type: str
+ description:
+ - Database on which the user has the specified role.
+ - A role on the admin database can include privileges that apply to the other databases.
+ aliases: [ "databaseName" ]
+ role_name:
+ required: true
+ type: str
+ description:
+ - Name of the role. This value can either be a built-in role or a custom role.
+ aliases: [ "roleName" ]
+ required: true
+ type: list
+ elements: dict
+ scopes:
+ description:
+ - List of clusters and Atlas Data Lakes that this user can access.
+ - Atlas grants database users access to all resources by default.
+ suboptions:
+ name:
+ required: true
+ type: str
+ description:
+ - Name of the cluster or Atlas Data Lake that the database user can access.
+ type:
+ type: str
+ choices: ["CLUSTER", "DATA_LAKE"]
+ default: "CLUSTER"
+ description:
+ - Type of resource that the database user can access.
+ required: false
+ default: []
+ type: list
+ elements: dict
+'''
+
+EXAMPLES = '''
+ - name: test user
+ community.mongodb.mongodb_atlas_user:
+ api_username: "API_user"
+ api_password: "API_passwort_or_token"
+ group_id: "GROUP_ID"
+ username: my_app_user
+ password: SuperSecret!
+ roles:
+ - database_name: private_info
+ role_name: read
+ - database_name: public_info
+ role_name: readWrite
+'''
+
+from ansible.module_utils.basic import AnsibleModule
+from ansible_collections.community.mongodb.plugins.module_utils.mongodb_atlas import (
+ AtlasAPIObject,
+)
+
+
+# ===========================================
+# Module execution.
+#
+def main():
+ # add our own arguments
+ argument_spec = dict(
+ state=dict(default="present", choices=["absent", "present"]),
+ api_username=dict(required=True, aliases=['apiUsername']),
+ api_password=dict(required=True, no_log=True, aliases=['apiPassword']),
+ group_id=dict(required=True, aliases=['groupId']),
+ database_name=dict(default="admin", choices=["admin", "$external"], aliases=["databaseName"]),
+ username=dict(required=True),
+ password=dict(required=True, no_log=True),
+ roles=dict(
+ required=True,
+ type="list",
+ elements="dict",
+ options=dict(
+ database_name=dict(required=True, aliases=["databaseName"]),
+ role_name=dict(required=True, aliases=["roleName"]),
+ ),
+ ),
+ scopes=dict(
+ required=False,
+ type="list",
+ elements="dict",
+ options=dict(
+ name=dict(required=True),
+ type=dict(default="CLUSTER", choices=["CLUSTER", "DATA_LAKE"]),
+ ),
+ default=[],
+ ),
+ )
+
+ # Define the main module
+ module = AnsibleModule(
+ argument_spec=argument_spec, supports_check_mode=True
+ )
+
+ data = {
+ "databaseName": module.params["database_name"],
+ "username": module.params["username"],
+ "password": module.params["password"],
+ "roles": [],
+ "scopes": module.params["scopes"],
+ }
+
+ # remap keys to API format
+ for role in module.params.get("roles"):
+ data["roles"].append({
+ "databaseName": role.get("database_name"),
+ "roleName": role.get("role_name")
+ })
+
+ try:
+ atlas = AtlasAPIObject(
+ module=module,
+ path="/databaseUsers",
+ object_name="username",
+ group_id=module.params["group_id"],
+ data=data,
+ )
+ except Exception as e:
+ module.fail_json(
+ msg="unable to connect to Atlas API. Exception message: %s" % e
+ )
+
+ changed, diff = atlas.update(module.params["state"])
+ module.exit_json(
+ changed=changed,
+ data=atlas.data,
+ diff=diff,
+ )
+
+
+# import module snippets
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/community/mongodb/plugins/modules/mongodb_atlas_whitelist.py b/ansible_collections/community/mongodb/plugins/modules/mongodb_atlas_whitelist.py
new file mode 100644
index 000000000..5354321a6
--- /dev/null
+++ b/ansible_collections/community/mongodb/plugins/modules/mongodb_atlas_whitelist.py
@@ -0,0 +1,111 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2020 T-Systems MMS
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+#
+# This module 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 software 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this software. If not, see <http://www.gnu.org/licenses/>.
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+DOCUMENTATION = '''
+---
+module: mongodb_atlas_whitelist
+short_description: Manage IP whitelists in Atlas
+description:
+ - The mongodb_atlas_whitelist module manages a Atlas project's IP whitelist.
+ - L(API Documentation,https://docs.atlas.mongodb.com/reference/api/whitelist/)
+author: "Martin Schurz (@schurzi)"
+extends_documentation_fragment: community.mongodb.atlas_options
+options:
+ cidr_block:
+ description:
+ - Whitelist entry in Classless Inter-Domain Routing (CIDR) notation.
+ type: str
+ required: True
+ aliases: [ "cidrBlock" ]
+ comment:
+ description:
+ - Optional Comment associated with the whitelist entry.
+ type: str
+ default: "created by Ansible"
+'''
+
+EXAMPLES = '''
+ - name: test whitelist
+ community.mongodb.mongodb_atlas_whitelist:
+ api_username: "API_user"
+ api_password: "API_passwort_or_token"
+ group_id: "GROUP_ID"
+ cidr_block: "192.168.0.0/24"
+ comment: "test"
+'''
+
+from ansible.module_utils.basic import AnsibleModule
+from ansible_collections.community.mongodb.plugins.module_utils.mongodb_atlas import (
+ AtlasAPIObject,
+)
+
+
+# ===========================================
+# Module execution.
+#
+def main():
+ # add our own arguments
+ argument_spec = dict(
+ state=dict(default="present", choices=["absent", "present"]),
+ api_username=dict(required=True, aliases=['apiUsername']),
+ api_password=dict(required=True, no_log=True, aliases=['apiPassword']),
+ group_id=dict(required=True, aliases=['groupId']),
+ cidr_block=dict(required=True, aliases=["cidrBlock"]),
+ comment=dict(default="created by Ansible"),
+ )
+
+ # Define the main module
+ module = AnsibleModule(
+ argument_spec=argument_spec, supports_check_mode=True
+ )
+
+ data = {
+ "cidrBlock": module.params["cidr_block"],
+ "comment": module.params["comment"],
+ }
+
+ try:
+ atlas = AtlasAPIObject(
+ module=module,
+ path="/whitelist",
+ object_name="cidrBlock",
+ group_id=module.params["group_id"],
+ data=data,
+ data_is_array=True,
+ )
+ except Exception as e:
+ module.fail_json(
+ msg="unable to connect to Atlas API. Exception message: %s" % e
+ )
+
+ changed, diff = atlas.update(module.params["state"])
+ module.exit_json(
+ changed=changed,
+ data=atlas.data,
+ diff=diff,
+ )
+
+
+# import module snippets
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/community/mongodb/plugins/modules/mongodb_balancer.py b/ansible_collections/community/mongodb/plugins/modules/mongodb_balancer.py
index 0e9b33a34..77ce37ed0 100644
--- a/ansible_collections/community/mongodb/plugins/modules/mongodb_balancer.py
+++ b/ansible_collections/community/mongodb/plugins/modules/mongodb_balancer.py
@@ -29,6 +29,8 @@ options:
autosplit:
description:
- Disable or enable the autosplit flag in the config.settings collection.
+ - From MongoDB 6.1 automatic chunk splitting is not performed so this parameter is not valid in this and later versions. See more see [enableAutoSplit](https://www.mongodb.com/docs/manual/reference/method/sh.enableAutoSplit/). # noqa: E501
+ - This parameter is deprecated and will be removed in a future release.
required: false
type: bool
chunksize:
diff --git a/ansible_collections/community/mongodb/plugins/modules/mongodb_monitoring.py b/ansible_collections/community/mongodb/plugins/modules/mongodb_monitoring.py
deleted file mode 100644
index d399a9907..000000000
--- a/ansible_collections/community/mongodb/plugins/modules/mongodb_monitoring.py
+++ /dev/null
@@ -1,197 +0,0 @@
-#!/usr/bin/python
-
-# Copyright: (c) 2021, Rhys Campbell rhyscampbell@blueiwn.ch
-# 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
-
-
-DOCUMENTATION = r'''
----
-module: mongodb_monitoring
-short_description: Manages the free monitoring feature.
-description:
- - Manages the free monitoring feature.
- - Optionally return the monitoring url.
-author: Rhys Campbell (@rhysmeister)
-version_added: "1.3.0"
-
-extends_documentation_fragment:
- - community.mongodb.login_options
- - community.mongodb.ssl_options
-
-options:
- state:
- description: Manage the free monitoring feature.
- type: str
- choices:
- - "started"
- - "stopped"
- default: "started"
- return_url:
- description: When true return the monitoring url if available.
- type: bool
- default: false
-
-notes:
-- Requires the pymongo Python package on the remote host, version 2.4.2+. This
- can be installed using pip or the OS package manager. @see U(http://api.mongodb.org/python/current/installation.html)
-requirements:
- - pymongo
-'''
-
-EXAMPLES = r'''
-- name: Enable monitoring
- community.mongodb.mongodb_monitoring:
- state: "started"
-
-- name: Disable monitoring
- community.mongodb.mongodb_monitoring:
- state: "stopped"
-
-- name: Enable monitoring and return the monitoring url
- community.mongodb_monitoring:
- state: "started"
- return_url: "yes"
-'''
-
-RETURN = r'''
-changed:
- description: Whether the monitoring status changed.
- returned: success
- type: bool
-msg:
- description: A short description of what happened.
- returned: success
- type: str
-failed:
- description: If something went wrong
- returned: failed
- type: bool
-url:
- description: The MongoDB instance Monitoring url.
- returned: When requested and available.
- type: str
-'''
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils._text import to_native
-from ansible_collections.community.mongodb.plugins.module_utils.mongodb_common import (
- missing_required_lib,
- mongodb_common_argument_spec,
- PYMONGO_IMP_ERR,
- pymongo_found,
- mongo_auth,
- get_mongodb_client,
-)
-
-has_ordereddict = False
-try:
- from collections import OrderedDict
- has_ordereddict = True
-except ImportError as excep:
- try:
- from ordereddict import OrderedDict
- has_ordereddict = True
- except ImportError as excep:
- pass
-
-
-def stop_monitoring(client):
- '''
- Stops MongoDB Free Monitoring
- '''
- cmd_doc = OrderedDict([('setFreeMonitoring', 1),
- ('action', 'disable')])
- client['admin'].command(cmd_doc)
-
-
-def start_monitoring(client):
- '''
- Stops MongoDB Free Monitoring
- '''
- cmd_doc = OrderedDict([('setFreeMonitoring', 1),
- ('action', 'enable')])
- client['admin'].command(cmd_doc)
-
-
-def get_monitoring_status(client):
- '''
- Gets the state of MongoDB Monitoring.
- N.B. If Monitoring has never been enabled the
- free_monitoring record in admin.system.version
- will not yet exist.
- '''
- monitoring_state = None
- url = None
- result = client["admin"]['system.version'].find_one({"_id": "free_monitoring"})
- if not result:
- monitoring_state = "stopped"
- else:
- url = result["informationalURL"]
- if result["state"] == "enabled":
- monitoring_state = "started"
- else:
- monitoring_state = "stopped"
- return monitoring_state, url
-
-
-def main():
- argument_spec = mongodb_common_argument_spec()
- argument_spec.update(
- state=dict(type='str', default='started', choices=['started', 'stopped']),
- return_url=dict(type='bool', default=False)
- )
-
- module = AnsibleModule(
- argument_spec=argument_spec,
- supports_check_mode=True,
- required_together=[['login_user', 'login_password']],
- )
-
- if not has_ordereddict:
- module.fail_json(msg='Cannot import OrderedDict class. You can probably install with: pip install ordereddict')
-
- if not pymongo_found:
- module.fail_json(msg=missing_required_lib('pymongo'),
- exception=PYMONGO_IMP_ERR)
-
- state = module.params['state']
- return_url = module.params['return_url']
-
- try:
- client = get_mongodb_client(module, directConnection=True)
- client = mongo_auth(module, client, directConnection=True)
- except Exception as e:
- module.fail_json(msg='Unable to connect to database: %s' % to_native(e))
-
- current_monitoring_state, url = get_monitoring_status(client)
- result = {}
- if state == "started":
- if current_monitoring_state == "started":
- result['changed'] = False
- result['msg'] = "Free monitoring is already started"
- else:
- if module.check_mode is False:
- start_monitoring(client)
- result['changed'] = True
- result['msg'] = "Free monitoring has been started"
- else:
- if current_monitoring_state == "started":
- if module.check_mode is False:
- stop_monitoring(client)
- result['changed'] = True
- result['msg'] = "Free monitoring has been stopped"
- else:
- result['changed'] = False
- result['msg'] = "Free monitoring is already stopped"
-
- if return_url and url:
- result['url'] = url
-
- module.exit_json(**result)
-
-
-if __name__ == '__main__':
- main()
diff --git a/ansible_collections/community/mongodb/plugins/modules/mongodb_replicaset.py b/ansible_collections/community/mongodb/plugins/modules/mongodb_replicaset.py
index d0baf661e..d6cdaae26 100644
--- a/ansible_collections/community/mongodb/plugins/modules/mongodb_replicaset.py
+++ b/ansible_collections/community/mongodb/plugins/modules/mongodb_replicaset.py
@@ -554,8 +554,11 @@ def main():
debug = module.params['debug']
cluster_cmd = module.params['cluster_cmd']
+ # Count voting members
+ voting_members = sum([1 if not isinstance(m, dict) or m.get("votes", 1) == 1 else 0 for m in members])
+
if validate and reconfigure is False:
- if len(members) <= 2 or len(members) % 2 == 0:
+ if len(members) <= 2 or voting_members % 2 == 0:
module.fail_json(msg="MongoDB Replicaset validation failed. Invalid number of replicaset members.")
if arbiter_at_index is not None and len(members) - 1 < arbiter_at_index:
module.fail_json(msg="MongoDB Replicaset validation failed. Invalid arbiter index.")
diff --git a/ansible_collections/community/mongodb/plugins/modules/mongodb_role.py b/ansible_collections/community/mongodb/plugins/modules/mongodb_role.py
index 012f553a0..23f653c32 100644
--- a/ansible_collections/community/mongodb/plugins/modules/mongodb_role.py
+++ b/ansible_collections/community/mongodb/plugins/modules/mongodb_role.py
@@ -303,8 +303,8 @@ def check_if_role_changed(client, role, db_name, privileges, authenticationRestr
'roles' not in role_dict and roles != []):
changed = True
elif ('authenticationRestrictions' in role_dict and
- sorted(reformat_authenticationRestrictions, key=lambda x: (x['clientSource'], x['serverAddress'])) !=
- sorted(authenticationRestrictions, key=lambda x: (x['clientSource'], x['serverAddress'])) or
+ sorted(reformat_authenticationRestrictions, key=lambda x: (x.get('clientSource', ''), x.get('serverAddress', ''))) !=
+ sorted(authenticationRestrictions, key=lambda x: (x.get('clientSource', ''), x.get('serverAddress', ''))) or
'authenticationRestrictions' not in role_dict and authenticationRestrictions != []):
changed = True
else:
diff --git a/ansible_collections/community/mongodb/plugins/modules/mongodb_user.py b/ansible_collections/community/mongodb/plugins/modules/mongodb_user.py
index eab0d186c..fee4c48c1 100644
--- a/ansible_collections/community/mongodb/plugins/modules/mongodb_user.py
+++ b/ansible_collections/community/mongodb/plugins/modules/mongodb_user.py
@@ -189,7 +189,6 @@ user:
import os
import traceback
-from operator import itemgetter
from ansible.module_utils.basic import AnsibleModule, missing_required_lib
@@ -307,7 +306,7 @@ def check_if_roles_changed(uinfo, roles, db_name):
roles_as_list_of_dict = make_sure_roles_are_a_list_of_dict(roles, db_name)
uinfo_roles = uinfo.get('roles', [])
- if sorted(roles_as_list_of_dict, key=itemgetter('db')) == sorted(uinfo_roles, key=itemgetter('db')):
+ if sorted(roles_as_list_of_dict, key=lambda roles: sorted(roles.items())) == sorted(uinfo_roles, key=lambda roles: sorted(roles.items())):
return False
return True