# (c) 2015, Steve Gargan # (c) 2017 Ansible Project # 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 = """ lookup: consul_kv version_added: "1.9" short_description: Fetch metadata from a Consul key value store. description: - Lookup metadata for a playbook from the key value store in a Consul cluster. Values can be easily set in the kv store with simple rest commands - C(curl -X PUT -d 'some-value' http://localhost:8500/v1/kv/ansible/somedata) requirements: - 'python-consul python library U(http://python-consul.readthedocs.org/en/latest/#installation)' options: _raw: description: List of key(s) to retrieve. type: list required: True recurse: type: boolean description: If true, will retrieve all the values that have the given key as prefix. default: False index: description: If the key has a value with the specified index then this is returned allowing access to historical values. token: description: The acl token to allow access to restricted values. host: default: localhost description: - The target to connect to, must be a resolvable address. env: - name: ANSIBLE_CONSUL_URL port: description: The port of the target host to connect to. default: 8500 """ EXAMPLES = """ - debug: msg: 'key contains {{item}}' with_consul_kv: - 'key/to/retrieve' - name: Parameters can be provided after the key be more specific about what to retrieve debug: msg: 'key contains {{item}}' with_consul_kv: - 'key/to recurse=true token=E6C060A9-26FB-407A-B83E-12DDAFCB4D98' - name: retrieving a KV from a remote cluster on non default port debug: msg: "{{ lookup('consul_kv', 'my/key', host='10.10.10.10', port='2000') }}" """ RETURN = """ _raw: description: - Value(s) stored in consul. """ import os import sys from ansible.module_utils.six.moves.urllib.parse import urlparse from ansible.errors import AnsibleError, AnsibleAssertionError from ansible.plugins.lookup import LookupBase try: import json except ImportError: import simplejson as json try: import consul HAS_CONSUL = True except ImportError as e: HAS_CONSUL = False class LookupModule(LookupBase): def run(self, terms, variables=None, **kwargs): if not HAS_CONSUL: raise AnsibleError('python-consul is required for consul_kv lookup. see http://python-consul.readthedocs.org/en/latest/#installation') values = [] try: for term in terms: params = self.parse_params(term) try: url = os.environ['ANSIBLE_CONSUL_URL'] u = urlparse(url) consul_api = consul.Consul(host=u.hostname, port=u.port) except KeyError: port = kwargs.get('port', '8500') host = kwargs.get('host', 'localhost') consul_api = consul.Consul(host=host, port=port) results = consul_api.kv.get(params['key'], token=params['token'], index=params['index'], recurse=params['recurse']) if results[1]: # responds with a single or list of result maps if isinstance(results[1], list): for r in results[1]: values.append(r['Value']) else: values.append(results[1]['Value']) except Exception as e: raise AnsibleError( "Error locating '%s' in kv store. Error was %s" % (term, e)) return values def parse_params(self, term): params = term.split(' ') paramvals = { 'key': params[0], 'token': None, 'recurse': False, 'index': None } # parameters specified? try: for param in params[1:]: if param and len(param) > 0: name, value = param.split('=') if name not in paramvals: raise AnsibleAssertionError("%s not a valid consul lookup parameter" % name) paramvals[name] = value except (ValueError, AssertionError) as e: raise AnsibleError(e) return paramvals