Merge ~adam-collard/maas:3.3-vault-proxy into maas:3.3

Proposed by Adam Collard
Status: Merged
Approved by: Adam Collard
Approved revision: 9443e8dd4396d4fbadf7ac9efe9ee7ee6e071078
Merge reported by: MAAS Lander
Merged at revision: not available
Proposed branch: ~adam-collard/maas:3.3-vault-proxy
Merge into: maas:3.3
Diff against target: 131 lines (+54/-27)
3 files modified
src/maasserver/bootsources.py (+1/-0)
src/maasserver/pytest_tests/test_vault.py (+47/-19)
src/maasserver/vault.py (+6/-8)
Reviewer Review Type Date Requested Status
Adam Collard (community) Approve
Review via email: mp+435596@code.launchpad.net

Commit message

LP:2002111 explicitly set proxies for hvac.Client

Cherry-pick 79bc358e2

To post a comment you must log in.
Revision history for this message
Adam Collard (adam-collard) wrote :

self-approve backport

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/src/maasserver/bootsources.py b/src/maasserver/bootsources.py
2index 58c6cb7..5c2b081 100644
3--- a/src/maasserver/bootsources.py
4+++ b/src/maasserver/bootsources.py
5@@ -378,6 +378,7 @@ def cache_boot_sources():
6
7 # FIXME: This modifies the environment of the entire process, which is Not
8 # Cool. We should integrate with simplestreams in a more Pythonic manner.
9+ # See maasserver.vault._create_hvac_client - LP:2002111
10 pristine_env = yield deferToDatabase(set_simplestreams_env)
11
12 errors = []
13diff --git a/src/maasserver/pytest_tests/test_vault.py b/src/maasserver/pytest_tests/test_vault.py
14index 7277dbb..94db5ff 100644
15--- a/src/maasserver/pytest_tests/test_vault.py
16+++ b/src/maasserver/pytest_tests/test_vault.py
17@@ -1,10 +1,11 @@
18+from contextlib import suppress
19 from datetime import datetime, timedelta, timezone
20-from os import environ
21 from unittest.mock import ANY, MagicMock
22
23 from django.core.exceptions import ImproperlyConfigured
24 from hvac.exceptions import VaultError as HVACVaultError
25 import pytest
26+from requests.adapters import HTTPAdapter
27
28 from maasserver import vault
29 from maasserver.models import Config
30@@ -143,25 +144,52 @@ class TestVaultClient:
31 ensure_auth.assert_called_once()
32
33
34+@pytest.mark.parametrize("scheme", ["http", "https"])
35 class TestNoProxySettingForHVAC:
36- def test_no_proxy_set(self, monkeypatch):
37- url = "http://url.to.vault:8200"
38- monkeypatch.delenv("no_proxy", raising=False)
39- _create_hvac_client(url)
40- assert environ.get("no_proxy") == url
41-
42- def test_no_proxy_appended(self, monkeypatch):
43- url = "http://url.to.vault:8200"
44- monkeypatch.setenv("no_proxy", "localhost,127.0.0.1")
45- _create_hvac_client(url)
46- assert environ.get("no_proxy") == f"localhost,127.0.0.1,{url}"
47-
48- def test_idempotency(self, monkeypatch):
49- url = "http://url.to.vault:8200"
50- monkeypatch.delenv("no_proxy", raising=False)
51- _create_hvac_client(url)
52- _create_hvac_client(url)
53- assert environ.get("no_proxy") == url
54+ def test_proxy_for_vault_scheme_set_to_None(self, scheme):
55+ """HVAC client should be configured to not use a proxy."""
56+ hvac_client = _create_hvac_client(f"{scheme}://url.to.vault:8200")
57+ assert hvac_client.session.proxies == {scheme: None}
58+
59+ def test_proxy_for_with_env(self, scheme, monkeypatch):
60+ """HVAC client should ignore standard proxy environment variables."""
61+ monkeypatch.setenv("http_proxy", "http://squid.proxy:3128")
62+ monkeypatch.setenv("https_proxy", "http://squid.proxy:3128")
63+ monkeypatch.setenv("no_proxy", "127.0.0.1.localhost")
64+
65+ hvac_client = _create_hvac_client(f"{scheme}://url.to.vault:8200")
66+ assert hvac_client.session.proxies == {scheme: None}
67+
68+ def test_request_honours_proxies(self, scheme, monkeypatch):
69+ """Verify that the request made by requests follows the rules."""
70+ monkeypatch.setenv("http_proxy", "http://squid.proxy:3128")
71+ monkeypatch.setenv("https_proxy", "http://squid.proxy:3128")
72+ monkeypatch.setenv("no_proxy", "127.0.0.1.localhost")
73+ hvac_client = _create_hvac_client(f"{scheme}://url.to.vault:8200")
74+
75+ class ProxyRecordingAdapter(HTTPAdapter):
76+ """
77+ A basic subclass of the HTTPAdapter that records the arguments used to
78+ ``send``.
79+ """
80+
81+ def __init__(self2, *args, **kwargs):
82+ super().__init__(*args, **kwargs)
83+ self2.proxies = []
84+
85+ def send(self2, request, **kwargs):
86+ self2.proxies.append(kwargs.get("proxies"))
87+ return
88+
89+ adapter = ProxyRecordingAdapter()
90+ hvac_client.session.mount(f"{scheme}://", adapter)
91+
92+ # Since we return None from ProxyRecordingAdapter.send, it throws
93+ # AttributeErrors, we just want to see the request that was
94+ # attempted
95+ with suppress(AttributeError):
96+ hvac_client.seal_status
97+ assert scheme not in adapter.proxies[0]
98
99
100 class TestGetRegionVaultClient:
101diff --git a/src/maasserver/vault.py b/src/maasserver/vault.py
102index 9ff213f..2b28a3d 100644
103--- a/src/maasserver/vault.py
104+++ b/src/maasserver/vault.py
105@@ -1,8 +1,8 @@
106 from datetime import datetime, timedelta, timezone
107 from functools import cache, wraps
108 import logging
109-import os
110 from typing import Any, Callable, NamedTuple, Optional
111+from urllib.parse import urlparse
112
113 from dateutil.parser import isoparse
114 from django.core.exceptions import ImproperlyConfigured
115@@ -48,13 +48,11 @@ def wrap_errors(func: Callable) -> Callable:
116
117 def _create_hvac_client(url: str, **kwargs) -> hvac.Client:
118 """Create HVAC client for the given URL, with no proxies set."""
119- # This is gross, and unfortunately necessary due to bootsources.get_simplestreams_env
120- # and https://github.com/psf/requests/issues/2018
121- if no_proxy := os.environ.get("no_proxy"):
122- if url not in no_proxy.split(","):
123- os.environ["no_proxy"] = f"{no_proxy},{url}"
124- else:
125- os.environ["no_proxy"] = url
126+ # FIXME: This is gross, and unfortunately necessary due to
127+ # bootsources.get_simplestreams_env and
128+ # https://github.com/psf/requests/issues/2018
129+ # LP:2002528
130+ kwargs["proxies"] = {urlparse(url).scheme: None}
131 return hvac.Client(url=url, **kwargs)
132
133

Subscribers

People subscribed via source and target branches