2023-09-17 14:35:00 +02:00
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
|
|
|
|
# Copyright (c) 2022, Håkon Lerring
|
|
|
|
# GNU General Public License v3.0+ (see COPYING 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
|
|
|
|
|
2024-01-21 18:29:29 +01:00
|
|
|
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
|
|
|
|
|
2023-09-17 14:35:00 +02:00
|
|
|
|
|
|
|
def get_consul_url(configuration):
|
|
|
|
return '%s://%s:%s/v1' % (configuration.scheme,
|
|
|
|
configuration.host, configuration.port)
|
|
|
|
|
|
|
|
|
|
|
|
def get_auth_headers(configuration):
|
|
|
|
if configuration.token is None:
|
|
|
|
return {}
|
|
|
|
else:
|
|
|
|
return {'X-Consul-Token': configuration.token}
|
|
|
|
|
|
|
|
|
|
|
|
class RequestError(Exception):
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
def handle_consul_response_error(response):
|
|
|
|
if 400 <= response.status_code < 600:
|
|
|
|
raise RequestError('%d %s' % (response.status_code, response.content))
|
2024-01-21 18:29:29 +01:00
|
|
|
|
|
|
|
|
|
|
|
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)
|