Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace deprecated token query param by X-Consul-Token header #81

Merged
merged 2 commits into from
Aug 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 21 additions & 2 deletions conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,8 +89,27 @@ def start_consul_container(version, acl_master_token=None):
merged_config = {**base_config, **acl_config}
docker_config["environment"]["CONSUL_LOCAL_CONFIG"] = json.dumps(merged_config)

container = client.containers.run(
f"hashicorp/consul:{version}", command="agent -dev -client=0.0.0.0 -log-level trace", **docker_config
def start_consul_container_with_retry(client, command, version, docker_config, max_retries=3, retry_delay=2): # pylint: disable=inconsistent-return-statements
"""
Start a Consul container with retries as a few initial attempts sometimes fail.
"""
for attempt in range(max_retries):
try:
container = client.containers.run(f"hashicorp/consul:{version}", command=command, **docker_config)
return container
except docker.errors.APIError:
# Cleanup that stray container as it might cause a naming conflict
try:
container = client.containers.get(docker_config["name"])
container.remove(force=True)
except docker.errors.NotFound:
pass
if attempt == max_retries - 1:
raise
time.sleep(retry_delay)

container = start_consul_container_with_retry(
client, command="agent -dev -client=0.0.0.0 -log-level trace", version=version, docker_config=docker_config
)

# Wait for Consul to be ready
Expand Down
27 changes: 17 additions & 10 deletions consul/aio.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import asyncio
from typing import Dict, Optional

import aiohttp

Expand All @@ -23,33 +24,39 @@ def __init__(self, *args, loop=None, connections_limit=None, connections_timeout
session_kwargs["timeout"] = timeout
self._session = aiohttp.ClientSession(connector=connector, **session_kwargs)

async def _request(self, callback, method, uri, data=None, connections_timeout=None):
async def _request(
self, callback, method, uri, headers: Optional[Dict[str, str]], data=None, connections_timeout=None
):
session_kwargs = {}
if connections_timeout:
timeout = aiohttp.ClientTimeout(total=connections_timeout)
session_kwargs["timeout"] = timeout
resp = await self._session.request(method, uri, data=data, **session_kwargs)
resp = await self._session.request(method, uri, headers=headers, data=data, **session_kwargs)
body = await resp.text(encoding="utf-8")
if resp.status == 599:
raise Timeout
r = base.Response(resp.status, resp.headers, body)
return callback(r)

def get(self, callback, path, params=None, connections_timeout=None):
def get(self, callback, path, params=None, headers: Optional[Dict[str, str]] = None, connections_timeout=None):
uri = self.uri(path, params)
return self._request(callback, "GET", uri, connections_timeout=connections_timeout)
return self._request(callback, "GET", uri, headers=headers, connections_timeout=connections_timeout)

def put(self, callback, path, params=None, data="", connections_timeout=None):
def put(
self, callback, path, params=None, data="", headers: Optional[Dict[str, str]] = None, connections_timeout=None
):
uri = self.uri(path, params)
return self._request(callback, "PUT", uri, data=data, connections_timeout=connections_timeout)
return self._request(callback, "PUT", uri, headers=headers, data=data, connections_timeout=connections_timeout)

def delete(self, callback, path, params=None, connections_timeout=None):
def delete(self, callback, path, params=None, headers: Optional[Dict[str, str]] = None, connections_timeout=None):
uri = self.uri(path, params)
return self._request(callback, "DELETE", uri, connections_timeout=connections_timeout)
return self._request(callback, "DELETE", uri, headers=headers, connections_timeout=connections_timeout)

def post(self, callback, path, params=None, data="", connections_timeout=None):
def post(
self, callback, path, params=None, data="", headers: Optional[Dict[str, str]] = None, connections_timeout=None
):
uri = self.uri(path, params)
return self._request(callback, "POST", uri, data=data, connections_timeout=connections_timeout)
return self._request(callback, "POST", uri, headers=headers, data=data, connections_timeout=connections_timeout)

def close(self):
return self._session.close()
Expand Down
18 changes: 7 additions & 11 deletions consul/api/acl/policy.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,9 @@ def list(self, token=None):
Requires a token with acl:read capability. ACLPermissionDenied raised otherwise
"""
params = []
token = token or self.agent.token
if token:
params.append(("token", token))
return self.agent.http.get(CB.json(), "/v1/acl/policies", params=params)

headers = self.agent.prepare_headers(token)
return self.agent.http.get(CB.json(), "/v1/acl/policies", params=params, headers=headers)

def read(self, uuid, token=None):
"""
Expand All @@ -28,10 +27,8 @@ def read(self, uuid, token=None):
:return: selected Polic information
"""
params = []
token = token or self.agent.token
if token:
params.append(("token", token))
return self.agent.http.get(CB.json(), f"/v1/acl/policy/{uuid}", params=params)
headers = self.agent.prepare_headers(token)
return self.agent.http.get(CB.json(), f"/v1/acl/policy/{uuid}", params=params, headers=headers)

def create(self, name, token=None, description=None, rules=None):
"""
Expand All @@ -44,17 +41,16 @@ def create(self, name, token=None, description=None, rules=None):
:return: The cloned token information
"""
params = []
token = token or self.agent.token
if token:
params.append(("token", token))
json_data = {"name": name}
if rules:
json_data["rules"] = json.dumps(rules)
if description:
json_data["Description"] = description
headers = self.agent.prepare_headers(token)
return self.agent.http.put(
CB.json(),
"/v1/acl/policy",
params=params,
headers=headers,
data=json.dumps(json_data),
)
33 changes: 12 additions & 21 deletions consul/api/acl/token.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,8 @@ def list(self, token=None):
Requires a token with acl:read capability. ACLPermissionDenied raised otherwise
"""
params = []
token = token or self.agent.token
if token:
params.append(("token", token))
return self.agent.http.get(CB.json(), "/v1/acl/tokens", params=params)
headers = self.agent.prepare_headers(token)
return self.agent.http.get(CB.json(), "/v1/acl/tokens", params=params, headers=headers)

def read(self, accessor_id, token=None):
"""
Expand All @@ -28,10 +26,8 @@ def read(self, accessor_id, token=None):
:return: selected token information
"""
params = []
token = token or self.agent.token
if token:
params.append(("token", token))
return self.agent.http.get(CB.json(), f"/v1/acl/token/{accessor_id}", params=params)
headers = self.agent.prepare_headers(token)
return self.agent.http.get(CB.json(), f"/v1/acl/token/{accessor_id}", params=params, headers=headers)

def delete(self, accessor_id, token=None):
"""
Expand All @@ -41,10 +37,8 @@ def delete(self, accessor_id, token=None):
:return: True if the token was deleted
"""
params = []
token = token or self.agent.token
if token:
params.append(("token", token))
return self.agent.http.delete(CB.bool(), f"/v1/acl/token/{accessor_id}", params=params)
headers = self.agent.prepare_headers(token)
return self.agent.http.delete(CB.bool(), f"/v1/acl/token/{accessor_id}", params=params, headers=headers)

def clone(self, accessor_id, token=None, description=""):
"""
Expand All @@ -55,15 +49,14 @@ def clone(self, accessor_id, token=None, description=""):
:return: The cloned token information
"""
params = []
token = token or self.agent.token
if token:
params.append(("token", token))

json_data = {"Description": description}
headers = self.agent.prepare_headers(token)
return self.agent.http.put(
CB.json(),
f"/v1/acl/token/{accessor_id}/clone",
params=params,
headers=headers,
data=json.dumps(json_data),
)

Expand All @@ -79,9 +72,6 @@ def create(self, token=None, accessor_id=None, secret_id=None, policies_id=None,
:return: The cloned token information
"""
params = []
token = token or self.agent.token
if token:
params.append(("token", token))

json_data = {}
if accessor_id:
Expand All @@ -93,10 +83,12 @@ def create(self, token=None, accessor_id=None, secret_id=None, policies_id=None,
if policies_id:
json_data["Policies"] = [{"ID": policy} for policy in policies_id]

headers = self.agent.prepare_headers(token)
return self.agent.http.put(
CB.json(),
"/v1/acl/token",
params=params,
headers=headers,
data=json.dumps(json_data),
)

Expand All @@ -111,18 +103,17 @@ def update(self, accessor_id, token=None, secret_id=None, description=""):
:return: The updated token information
"""
params = []
token = token or self.agent.token
if token:
params.append(("token", token))

json_data = {"AccessorID": accessor_id}
if secret_id:
json_data["SecretID"] = secret_id
if description:
json_data["Description"] = description
headers = self.agent.prepare_headers(token)
return self.agent.http.put(
CB.json(),
f"/v1/acl/token/{accessor_id}",
params=params,
headers=headers,
data=json.dumps(json_data),
)
Loading