summaryrefslogtreecommitdiffstats
path: root/ansible_collections/community/mongodb/plugins/lookup/mongodb.py
diff options
context:
space:
mode:
Diffstat (limited to 'ansible_collections/community/mongodb/plugins/lookup/mongodb.py')
-rw-r--r--ansible_collections/community/mongodb/plugins/lookup/mongodb.py269
1 files changed, 269 insertions, 0 deletions
diff --git a/ansible_collections/community/mongodb/plugins/lookup/mongodb.py b/ansible_collections/community/mongodb/plugins/lookup/mongodb.py
new file mode 100644
index 000000000..b49c3f334
--- /dev/null
+++ b/ansible_collections/community/mongodb/plugins/lookup/mongodb.py
@@ -0,0 +1,269 @@
+# (c) 2016, Marcos Diez <marcos@unitron.com.br>
+# https://github.com/marcosdiez/
+#
+# This file is part of Ansible
+#
+# Ansible 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.
+#
+# Ansible 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 Ansible. If not, see <http://www.gnu.org/licenses/>.
+
+from __future__ import (absolute_import, division, print_function)
+
+__metaclass__ = type
+
+DOCUMENTATION = '''
+name: mongodb
+author:
+ - Marcos Diez (@marcosdiez)
+version_added: "1.0.0"
+short_description: lookup info from MongoDB
+description:
+ - 'The ``MongoDB`` lookup runs the *find()* command on a given *collection* on a given *MongoDB* server.'
+ - 'The result is a list of jsons, so slightly different from what PyMongo returns. In particular, *timestamps* are converted to epoch integers.'
+options:
+ connect_string:
+ description:
+ - Can be any valid MongoDB connection string, supporting authentication, replica sets, etc.
+ - "More info at U(https://docs.mongodb.org/manual/reference/connection-string/)"
+ default: "mongodb://localhost/"
+ database:
+ description:
+ - Name of the database which the query will be made
+ required: True
+ collection:
+ description:
+ - Name of the collection which the query will be made
+ required: True
+ filter:
+ description:
+ - Criteria of the output
+ type: 'dict'
+ default: {}
+ projection:
+ description:
+ - Fields you want returned
+ type: dict
+ default: {}
+ skip:
+ description:
+ - How many results should be skipped
+ type: integer
+ limit:
+ description:
+ - How many results should be shown
+ type: integer
+ sort:
+ description:
+ - Sorting rules.
+ - Please use the strings C(ASCENDING) and C(DESCENDING) to set the order.
+ - Check the example for more information.
+ type: list
+ elements: list
+ default: []
+ extra_connection_parameters:
+ description:
+ - Extra connection parameters that to be sent to pymongo.MongoClient
+ - Check the example to see how to connect to mongo using an SSL certificate.
+ - "All possible parameters are here: U(https://api.mongodb.com/python/current/api/pymongo/mongo_client.html#pymongo.mongo_client.MongoClient)"
+ type: dict
+ default: {}
+notes:
+ - "Please check https://api.mongodb.org/python/current/api/pymongo/collection.html?highlight=find#pymongo.collection.Collection.find for more details."
+requirements:
+ - pymongo >= 2.4 (python library)
+'''
+
+EXAMPLES = '''
+- hosts: localhost
+ gather_facts: false
+ vars:
+ mongodb_parameters:
+ #mandatory parameters
+ database: 'local'
+ collection: "startup_log"
+ #optional
+ connection_string: "mongodb://localhost/"
+ # connection_string: "mongodb://username:password@my.server.com:27017/"
+ # extra_connection_parameters: { "ssl" : True , "ssl_certfile": /etc/self_signed_certificate.pem" }
+ #optional query parameters, we accept any parameter from the normal mongodb query.
+ # filter: { "hostname": "u18" }
+ projection: { "pid": True , "_id" : False , "hostname" : True }
+ skip: 0
+ limit: 1
+ sort: [ [ "startTime" , "ASCENDING" ] , [ "age", "DESCENDING" ] ]
+ tasks:
+ - debug: msg="The PID from MongoDB is {{ lookup('mongodb', mongodb_parameters ).pid }}"
+
+ - debug: msg="The HostName from the MongoDB server is {{ lookup('mongodb', mongodb_parameters ).hostname }}"
+
+ - debug: msg="Mongo DB is stored at {{ lookup('mongodb', mongodb_parameters_inline )}}"
+ vars:
+ mongodb_parameters_inline:
+ database: 'local'
+ collection: "startup_log"
+ connection_string: "mongodb://localhost/"
+ limit: 1
+ projection: { "cmdline.storage": True }
+
+ # lookup syntax, does the same as below
+ - debug: msg="The hostname is {{ item.hostname }} and the pid is {{ item.pid }}"
+ loop: "{{ lookup('mongodb', mongodb_parameters, wantlist=True) }}"
+
+ # query syntax, does the same as above
+ - debug: msg="The hostname is {{ item.hostname }} and the pid is {{ item.pid }}"
+ loop: "{{ query('mongodb', mongodb_parameters) }}"
+
+ - name: "Raw output from the mongodb lookup (a json with pid and hostname )"
+ debug: msg="{{ lookup('mongodb', mongodb_parameters) }}"
+
+ - name: "Yet another mongodb query, now with the parameters on the task itself"
+ debug: msg="pid={{item.pid}} hostname={{item.hostname}} version={{ item.buildinfo.version }}"
+ with_mongodb:
+ - database: 'local'
+ collection: "startup_log"
+ connection_string: "mongodb://localhost/"
+ limit: 1
+ projection: { "pid": True , "hostname": True , "buildinfo.version": True }
+
+ # Please notice this specific query may result more than one result. This is expected
+ - name: "Shows the whole output from mongodb"
+ debug: msg="{{ item }}"
+ with_mongodb:
+ - database: 'local'
+ collection: "startup_log"
+ connection_string: "mongodb://localhost/"
+
+
+'''
+
+RETURN = """
+ _list_of_jsons:
+ description:
+ - a list of JSONs with the results of the MongoDB query.
+ type: list
+"""
+
+import datetime
+
+from ansible.module_utils.six import string_types, integer_types
+from ansible.module_utils._text import to_native
+from ansible.errors import AnsibleError
+from ansible.plugins.lookup import LookupBase
+
+try:
+ from pymongo import ASCENDING, DESCENDING
+ from pymongo.errors import ConnectionFailure
+ from pymongo import MongoClient
+except ImportError:
+ try: # for older PyMongo 2.2
+ from pymongo import Connection as MongoClient
+ except ImportError:
+ pymongo_found = False
+ else:
+ pymongo_found = True
+else:
+ pymongo_found = True
+
+
+class LookupModule(LookupBase):
+
+ def _fix_sort_parameter(self, sort_parameter):
+ if sort_parameter is None:
+ return sort_parameter
+
+ if not isinstance(sort_parameter, list):
+ raise AnsibleError(u"Error. Sort parameters must be a list, not [ {0} ]".format(sort_parameter))
+
+ for item in sort_parameter:
+ self._convert_sort_string_to_constant(item)
+
+ return sort_parameter
+
+ def _convert_sort_string_to_constant(self, item):
+ original_sort_order = item[1]
+ sort_order = original_sort_order.upper()
+ if sort_order == u"ASCENDING":
+ item[1] = ASCENDING
+ elif sort_order == u"DESCENDING":
+ item[1] = DESCENDING
+ # else the user knows what s/he is doing and we won't predict. PyMongo will return an error if necessary
+
+ def convert_mongo_result_to_valid_json(self, result):
+ if result is None:
+ return result
+ if isinstance(result, integer_types + (float, bool)):
+ return result
+ if isinstance(result, string_types):
+ return result
+ elif isinstance(result, list):
+ new_list = []
+ for elem in result:
+ new_list.append(self.convert_mongo_result_to_valid_json(elem))
+ return new_list
+ elif isinstance(result, dict):
+ new_dict = {}
+ for key in result.keys():
+ value = result[key] # python2 and 3 compatible....
+ new_dict[key] = self.convert_mongo_result_to_valid_json(value)
+ return new_dict
+ elif isinstance(result, datetime.datetime):
+ # epoch
+ return (result - datetime.datetime(1970, 1, 1)). total_seconds()
+ else:
+ # failsafe
+ return u"{0}".format(result)
+
+ def run(self, terms, variables, **kwargs):
+ try:
+ return self._run_helper(terms)
+ except Exception as e:
+ print(u"There was an exception on the mongodb_lookup: {0}".format(to_native(e)))
+ raise e
+
+ def _run_helper(self, terms):
+ if not pymongo_found:
+ raise AnsibleError(u"pymongo is required in the control node (this machine) for mongodb lookup.")
+ ret = []
+ for term in terms:
+ for required_parameter in [u"database", u"collection"]:
+ if required_parameter not in term:
+ raise AnsibleError(u"missing mandatory parameter [{0}]".format(required_parameter))
+
+ connection_string = term.get(u'connection_string', u"mongodb://localhost")
+ database = term[u"database"]
+ collection = term[u'collection']
+ extra_connection_parameters = term.get(u'extra_connection_parameters', {})
+
+ if u"extra_connection_parameters" in term:
+ del term[u"extra_connection_parameters"]
+ if u"connection_string" in term:
+ del term[u"connection_string"]
+ del term[u"database"]
+ del term[u"collection"]
+
+ if u"sort" in term:
+ term[u"sort"] = self._fix_sort_parameter(term[u"sort"])
+
+ # all other parameters are sent to mongo, so we are future and past proof
+
+ try:
+ client = MongoClient(connection_string, **extra_connection_parameters)
+ results = client[database][collection].find(**term)
+
+ for result in results:
+ result = self.convert_mongo_result_to_valid_json(result)
+ ret.append(result)
+
+ except ConnectionFailure as e:
+ raise AnsibleError(u'unable to connect to database: %s' % str(e))
+
+ return ret