Skip to content

Commit

Permalink
Refactor of consul modules (#7826)
Browse files Browse the repository at this point in the history
* Extract common functionality.

* Refactor duplicated code into module_utils.

* Fixed ansible-test issues.

* Address review comments.

* Revert changes to consul_acl.

It uses deprecated APIs disabled since Consul 1.11 (which is EOL), don't
bother updating the module anymore.

* Remove unused code.

* Merge token into default doc fragment.

* JSON all the way down.

* extract validation tests into custom file and prep for requests removal.

* Removed dependency on requests.

* Initial test for consul_kv.

* fixup license headers.

* Revert changes to consul.py since it utilizes python-consul.

* Disable the lookup test for now.

* Fix python 2.7 support.

* Address review comments.

* Address review comments.

* Addec changelog fragment.

* Mark ConsulModule as private.
  • Loading branch information
apollo13 authored Jan 21, 2024
1 parent cd77d67 commit 44679e7
Show file tree
Hide file tree
Showing 10 changed files with 366 additions and 477 deletions.
2 changes: 2 additions & 0 deletions changelogs/fragments/7826-consul-modules-refactoring.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
minor_changes:
- 'consul_policy, consul_role, consul_session - removed dependency on ``requests`` and factored out common parts (https://github.com/ansible-collections/community.general/pull/7826).'
44 changes: 44 additions & 0 deletions plugins/doc_fragments/consul.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# -*- coding: utf-8 -*-
# Copyright (c) Ansible project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later


from __future__ import absolute_import, division, print_function
__metaclass__ = type


class ModuleDocFragment:
# Common parameters for Consul modules
DOCUMENTATION = r"""
options:
host:
description:
- Host of the consul agent, defaults to V(localhost).
default: localhost
type: str
port:
type: int
description:
- The port on which the consul agent is running.
default: 8500
scheme:
description:
- The protocol scheme on which the consul agent is running.
Defaults to V(http) and can be set to V(https) for secure connections.
default: http
type: str
validate_certs:
type: bool
description:
- Whether to verify the TLS certificate of the consul agent.
default: true
token:
description:
- The token to use for authorization.
type: str
ca_path:
description:
- The CA bundle to use for https connections
type: str
"""
88 changes: 88 additions & 0 deletions plugins/module_utils/consul.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@
from __future__ import absolute_import, division, print_function
__metaclass__ = type

import json

from ansible.module_utils.six.moves.urllib import error as urllib_error
from ansible.module_utils.six.moves.urllib.parse import urlencode
from ansible.module_utils.urls import open_url


def get_consul_url(configuration):
return '%s://%s:%s/v1' % (configuration.scheme,
Expand All @@ -27,3 +33,85 @@ class RequestError(Exception):
def handle_consul_response_error(response):
if 400 <= response.status_code < 600:
raise RequestError('%d %s' % (response.status_code, response.content))


def auth_argument_spec():
return dict(
host=dict(default="localhost"),
port=dict(type="int", default=8500),
scheme=dict(default="http"),
validate_certs=dict(type="bool", default=True),
token=dict(no_log=True),
ca_path=dict(),
)


class _ConsulModule:
"""Base class for Consul modules.
This class is considered private, till the API is fully fleshed out.
As such backwards incompatible changes can occur even in bugfix releases.
"""

def __init__(self, module):
self.module = module

def _request(self, method, url_parts, data=None, params=None):
module_params = self.module.params

if isinstance(url_parts, str):
url_parts = [url_parts]
if params:
# Remove values that are None
params = {k: v for k, v in params.items() if v is not None}

ca_path = module_params.get("ca_path")
base_url = "%s://%s:%s/v1" % (
module_params["scheme"],
module_params["host"],
module_params["port"],
)
url = "/".join([base_url] + list(url_parts))

headers = {}
token = self.module.params.get("token")
if token:
headers["X-Consul-Token"] = token

try:
if data:
data = json.dumps(data)
headers["Content-Type"] = "application/json"
if params:
url = "%s?%s" % (url, urlencode(params))
response = open_url(
url,
method=method,
data=data,
headers=headers,
validate_certs=module_params["validate_certs"],
ca_path=ca_path,
)
response_data = response.read()
except urllib_error.URLError as e:
self.module.fail_json(
msg="Could not connect to consul agent at %s:%s, error was %s"
% (module_params["host"], module_params["port"], str(e))
)
else:
status = (
response.status if hasattr(response, "status") else response.getcode()
)
if 400 <= status < 600:
raise RequestError("%d %s" % (status, response_data))

return json.loads(response_data)

def get(self, url_parts, **kwargs):
return self._request("GET", url_parts, **kwargs)

def put(self, url_parts, **kwargs):
return self._request("PUT", url_parts, **kwargs)

def delete(self, url_parts, **kwargs):
return self._request("DELETE", url_parts, **kwargs)
Loading

0 comments on commit 44679e7

Please sign in to comment.