314 lines
8.8 KiB
Python
314 lines
8.8 KiB
Python
#!/usr/bin/python
|
|
# -*- coding: utf-8 -*-
|
|
|
|
# Copyright: (c) 2020, Andrew Klychkov (@Andersson007) <aaklychkov@mail.ru>
|
|
# 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_info
|
|
|
|
short_description: Gather information about MongoDB instance.
|
|
|
|
description:
|
|
- Gather information about MongoDB instance.
|
|
|
|
author: Andrew Klychkov (@Andersson007)
|
|
version_added: "1.0.0"
|
|
|
|
extends_documentation_fragment:
|
|
- community.mongodb.login_options
|
|
- community.mongodb.ssl_options
|
|
|
|
options:
|
|
filter:
|
|
description:
|
|
- Limit the collected information by comma separated string or YAML list.
|
|
- Allowable values are C(general), C(databases), C(total_size), C(parameters), C(users), C(roles).
|
|
- By default, collects all subsets.
|
|
- You can use '!' before value (for example, C(!users)) to exclude it from the information.
|
|
- If you pass including and excluding values to the filter, for example, I(filter=!general,users),
|
|
the excluding values, C(!general) in this case, will be ignored.
|
|
required: no
|
|
type: list
|
|
elements: str
|
|
|
|
notes:
|
|
- Requires the pymongo Python package on the remote host, version 2.4.2+.
|
|
|
|
requirements:
|
|
- pymongo
|
|
'''
|
|
|
|
EXAMPLES = r'''
|
|
- name: Gather all supported information
|
|
community.mongodb.mongodb_info:
|
|
login_user: admin
|
|
login_password: secret
|
|
register: result
|
|
|
|
- name: Show gathered info
|
|
debug:
|
|
msg: '{{ result }}'
|
|
|
|
- name: Gather only information about databases and their total size
|
|
community.mongodb.mongodb_info:
|
|
login_user: admin
|
|
login_password: secret
|
|
filter: databases, total_size
|
|
|
|
- name: Gather all information except parameters
|
|
community.mongodb.mongodb_info:
|
|
login_user: admin
|
|
login_password: secret
|
|
filter: '!parameters'
|
|
'''
|
|
|
|
RETURN = r'''
|
|
general:
|
|
description: General instance information.
|
|
returned: always
|
|
type: dict
|
|
sample: {"allocator": "tcmalloc", "bits": 64, "storageEngines": ["biggie"], "version": "4.2.3", "maxBsonObjectSize": 16777216}
|
|
databases:
|
|
description: Database information.
|
|
returned: always
|
|
type: dict
|
|
sample: {"admin": {"empty": false, "sizeOnDisk": 245760}, "config": {"empty": false, "sizeOnDisk": 110592}}
|
|
total_size:
|
|
description: Total size of all databases in bytes.
|
|
returned: always
|
|
type: int
|
|
sample: 397312
|
|
users:
|
|
description: User information.
|
|
returned: always
|
|
type: dict
|
|
sample: { "db": {"new_user": {"_id": "config.new_user", "mechanisms": ["SCRAM-SHA-1", "SCRAM-SHA-256"], "roles": []}}}
|
|
roles:
|
|
description: Role information.
|
|
returned: always
|
|
type: dict
|
|
sample: { "db": {"restore": {"inheritedRoles": [], "isBuiltin": true, "roles": []}}}
|
|
parameters:
|
|
description: Server parameters information.
|
|
returned: always
|
|
type: dict
|
|
sample: {"maxOplogTruncationPointsAfterStartup": 100, "maxOplogTruncationPointsDuringStartup": 100, "maxSessions": 1000000}
|
|
'''
|
|
|
|
from uuid import UUID
|
|
|
|
from ansible.module_utils.basic import AnsibleModule
|
|
from ansible.module_utils._text import to_native
|
|
from ansible.module_utils.six import iteritems
|
|
from ansible_collections.community.mongodb.plugins.module_utils.mongodb_common import (
|
|
missing_required_lib,
|
|
mongodb_common_argument_spec,
|
|
mongo_auth,
|
|
PYMONGO_IMP_ERR,
|
|
pymongo_found,
|
|
get_mongodb_client,
|
|
)
|
|
|
|
|
|
class MongoDbInfo():
|
|
"""Class for gathering MongoDB instance information.
|
|
|
|
Args:
|
|
module (AnsibleModule): Object of AnsibleModule class.
|
|
client (pymongo): pymongo client object to interact with the database.
|
|
"""
|
|
def __init__(self, module, client):
|
|
self.module = module
|
|
self.client = client
|
|
self.admin_db = self.client.admin
|
|
self.info = {
|
|
'general': {},
|
|
'databases': {},
|
|
'total_size': {},
|
|
'parameters': {},
|
|
'users': {},
|
|
'roles': {},
|
|
}
|
|
|
|
def get_info(self, filter_):
|
|
"""Get MongoDB instance information and return it based on filter_.
|
|
|
|
Args:
|
|
filter_ (list): List of collected subsets (e.g., general, users, etc.),
|
|
when it is empty, return all available information.
|
|
"""
|
|
self.__collect()
|
|
|
|
inc_list = []
|
|
exc_list = []
|
|
|
|
if filter_:
|
|
partial_info = {}
|
|
|
|
for fi in filter_:
|
|
if fi.lstrip('!') not in self.info:
|
|
self.module.warn("filter element '%s' is not allowable, ignored" % fi)
|
|
continue
|
|
|
|
if fi[0] == '!':
|
|
exc_list.append(fi.lstrip('!'))
|
|
|
|
else:
|
|
inc_list.append(fi)
|
|
|
|
if inc_list:
|
|
for i in self.info:
|
|
if i in inc_list:
|
|
partial_info[i] = self.info[i]
|
|
|
|
else:
|
|
for i in self.info:
|
|
if i not in exc_list:
|
|
partial_info[i] = self.info[i]
|
|
|
|
return partial_info
|
|
|
|
else:
|
|
return self.info
|
|
|
|
def __collect(self):
|
|
"""Collect information."""
|
|
# Get general info:
|
|
self.info['general'] = self.client.server_info()
|
|
|
|
# Get parameters:
|
|
self.info['parameters'] = self.get_parameters_info()
|
|
|
|
# Gather info about databases and their total size:
|
|
self.info['databases'], self.info['total_size'] = self.get_db_info()
|
|
|
|
for dbname, val in iteritems(self.info['databases']):
|
|
# Gather info about users for each database:
|
|
self.info['users'].update(self.get_users_info(dbname))
|
|
|
|
# Gather info about roles for each database:
|
|
self.info['roles'].update(self.get_roles_info(dbname))
|
|
|
|
def get_roles_info(self, dbname):
|
|
"""Gather information about roles.
|
|
|
|
Args:
|
|
dbname (str): Database name to get role info from.
|
|
|
|
Returns a dictionary with role information for the given db.
|
|
"""
|
|
db = self.client[dbname]
|
|
result = db.command({'rolesInfo': 1, 'showBuiltinRoles': True})['roles']
|
|
|
|
roles_dict = {}
|
|
for elem in result:
|
|
roles_dict[elem['role']] = {}
|
|
for key, val in iteritems(elem):
|
|
if key in ['role', 'db']:
|
|
continue
|
|
|
|
roles_dict[elem['role']][key] = val
|
|
|
|
return {dbname: roles_dict}
|
|
|
|
def get_users_info(self, dbname):
|
|
"""Gather information about users.
|
|
|
|
Args:
|
|
dbname (str): Database name to get user info from.
|
|
|
|
Returns a dictionary with user information for the given db.
|
|
"""
|
|
db = self.client[dbname]
|
|
result = db.command({'usersInfo': 1})['users']
|
|
|
|
users_dict = {}
|
|
for elem in result:
|
|
users_dict[elem['user']] = {}
|
|
for key, val in iteritems(elem):
|
|
if key in ['user', 'db']:
|
|
continue
|
|
|
|
if isinstance(val, UUID):
|
|
val = val.hex
|
|
|
|
users_dict[elem['user']][key] = val
|
|
|
|
return {dbname: users_dict}
|
|
|
|
def get_db_info(self):
|
|
"""Gather information about databases.
|
|
|
|
Returns a dictionary with database information.
|
|
"""
|
|
result = self.admin_db.command({'listDatabases': 1})
|
|
total_size = int(result['totalSize'])
|
|
result = result['databases']
|
|
|
|
db_dict = {}
|
|
for elem in result:
|
|
db_dict[elem['name']] = {}
|
|
for key, val in iteritems(elem):
|
|
if key == 'name':
|
|
continue
|
|
|
|
if key == 'sizeOnDisk':
|
|
val = int(val)
|
|
|
|
db_dict[elem['name']][key] = val
|
|
|
|
return db_dict, total_size
|
|
|
|
def get_parameters_info(self):
|
|
"""Gather parameters information.
|
|
|
|
Returns a dictionary with parameters.
|
|
"""
|
|
return self.admin_db.command({'getParameter': '*'})
|
|
|
|
|
|
# ================
|
|
# Module execution
|
|
#
|
|
|
|
def main():
|
|
argument_spec = mongodb_common_argument_spec()
|
|
argument_spec.update(
|
|
filter=dict(type='list', elements='str', required=False)
|
|
)
|
|
module = AnsibleModule(
|
|
argument_spec=argument_spec,
|
|
supports_check_mode=True,
|
|
required_together=[['login_user', 'login_password']],
|
|
)
|
|
|
|
if not pymongo_found:
|
|
module.fail_json(msg=missing_required_lib('pymongo'),
|
|
exception=PYMONGO_IMP_ERR)
|
|
|
|
filter_ = module.params['filter']
|
|
|
|
if filter_:
|
|
filter_ = [f.strip() for f in filter_]
|
|
|
|
try:
|
|
client = get_mongodb_client(module)
|
|
client = mongo_auth(module, client)
|
|
except Exception as excep:
|
|
module.fail_json(msg='Unable to connect to MongoDB: %s' % to_native(excep))
|
|
|
|
# Initialize an object and start main work:
|
|
mongodb = MongoDbInfo(module, client)
|
|
|
|
module.exit_json(changed=False, **mongodb.get_info(filter_))
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|