sovereign 0.25.3__tar.gz → 0.26.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of sovereign might be problematic. Click here for more details.
- {sovereign-0.25.3 → sovereign-0.26.0}/PKG-INFO +2 -2
- {sovereign-0.25.3 → sovereign-0.26.0}/pyproject.toml +6 -3
- {sovereign-0.25.3 → sovereign-0.26.0}/src/sovereign/app.py +4 -2
- {sovereign-0.25.3 → sovereign-0.26.0}/src/sovereign/config_loader.py +45 -46
- {sovereign-0.25.3 → sovereign-0.26.0}/src/sovereign/context.py +32 -26
- {sovereign-0.25.3 → sovereign-0.26.0}/src/sovereign/schemas.py +3 -3
- sovereign-0.26.0/src/sovereign/testing/loaders.py +9 -0
- {sovereign-0.25.3 → sovereign-0.26.0}/LICENSE.txt +0 -0
- {sovereign-0.25.3 → sovereign-0.26.0}/README.md +0 -0
- {sovereign-0.25.3 → sovereign-0.26.0}/src/sovereign/__init__.py +0 -0
- {sovereign-0.25.3 → sovereign-0.26.0}/src/sovereign/configuration.py +0 -0
- {sovereign-0.25.3 → sovereign-0.26.0}/src/sovereign/constants.py +0 -0
- {sovereign-0.25.3 → sovereign-0.26.0}/src/sovereign/discovery.py +0 -0
- {sovereign-0.25.3 → sovereign-0.26.0}/src/sovereign/error_info.py +0 -0
- {sovereign-0.25.3 → sovereign-0.26.0}/src/sovereign/logging/access_logger.py +0 -0
- {sovereign-0.25.3 → sovereign-0.26.0}/src/sovereign/logging/application_logger.py +0 -0
- {sovereign-0.25.3 → sovereign-0.26.0}/src/sovereign/logging/base_logger.py +0 -0
- {sovereign-0.25.3 → sovereign-0.26.0}/src/sovereign/logging/bootstrapper.py +0 -0
- {sovereign-0.25.3 → sovereign-0.26.0}/src/sovereign/logging/types.py +0 -0
- {sovereign-0.25.3 → sovereign-0.26.0}/src/sovereign/middlewares.py +0 -0
- {sovereign-0.25.3 → sovereign-0.26.0}/src/sovereign/modifiers/__init__.py +0 -0
- {sovereign-0.25.3 → sovereign-0.26.0}/src/sovereign/modifiers/lib.py +0 -0
- {sovereign-0.25.3 → sovereign-0.26.0}/src/sovereign/response_class.py +0 -0
- {sovereign-0.25.3 → sovereign-0.26.0}/src/sovereign/server.py +0 -0
- {sovereign-0.25.3 → sovereign-0.26.0}/src/sovereign/sources/__init__.py +0 -0
- {sovereign-0.25.3 → sovereign-0.26.0}/src/sovereign/sources/file.py +0 -0
- {sovereign-0.25.3 → sovereign-0.26.0}/src/sovereign/sources/inline.py +0 -0
- {sovereign-0.25.3 → sovereign-0.26.0}/src/sovereign/sources/lib.py +0 -0
- {sovereign-0.25.3 → sovereign-0.26.0}/src/sovereign/sources/poller.py +0 -0
- {sovereign-0.25.3 → sovereign-0.26.0}/src/sovereign/static/sass/style.scss +0 -0
- {sovereign-0.25.3 → sovereign-0.26.0}/src/sovereign/static/style.css +0 -0
- {sovereign-0.25.3 → sovereign-0.26.0}/src/sovereign/statistics.py +0 -0
- {sovereign-0.25.3 → sovereign-0.26.0}/src/sovereign/templates/base.html +0 -0
- {sovereign-0.25.3 → sovereign-0.26.0}/src/sovereign/templates/err.html +0 -0
- {sovereign-0.25.3 → sovereign-0.26.0}/src/sovereign/templates/resources.html +0 -0
- {sovereign-0.25.3 → sovereign-0.26.0}/src/sovereign/templates/ul_filter.html +0 -0
- /sovereign-0.25.3/src/sovereign/modifiers/test.py → /sovereign-0.26.0/src/sovereign/testing/modifiers.py +0 -0
- {sovereign-0.25.3 → sovereign-0.26.0}/src/sovereign/utils/__init__.py +0 -0
- {sovereign-0.25.3 → sovereign-0.26.0}/src/sovereign/utils/auth.py +0 -0
- {sovereign-0.25.3 → sovereign-0.26.0}/src/sovereign/utils/crypto/__init__.py +0 -0
- {sovereign-0.25.3 → sovereign-0.26.0}/src/sovereign/utils/crypto/crypto.py +0 -0
- {sovereign-0.25.3 → sovereign-0.26.0}/src/sovereign/utils/crypto/suites/__init__.py +0 -0
- {sovereign-0.25.3 → sovereign-0.26.0}/src/sovereign/utils/crypto/suites/aes_gcm_cipher.py +0 -0
- {sovereign-0.25.3 → sovereign-0.26.0}/src/sovereign/utils/crypto/suites/base_cipher.py +0 -0
- {sovereign-0.25.3 → sovereign-0.26.0}/src/sovereign/utils/crypto/suites/disabled_cipher.py +0 -0
- {sovereign-0.25.3 → sovereign-0.26.0}/src/sovereign/utils/crypto/suites/fernet_cipher.py +0 -0
- {sovereign-0.25.3 → sovereign-0.26.0}/src/sovereign/utils/dictupdate.py +0 -0
- {sovereign-0.25.3 → sovereign-0.26.0}/src/sovereign/utils/eds.py +0 -0
- {sovereign-0.25.3 → sovereign-0.26.0}/src/sovereign/utils/entry_point_loader.py +0 -0
- {sovereign-0.25.3 → sovereign-0.26.0}/src/sovereign/utils/mock.py +0 -0
- {sovereign-0.25.3 → sovereign-0.26.0}/src/sovereign/utils/resources.py +0 -0
- {sovereign-0.25.3 → sovereign-0.26.0}/src/sovereign/utils/templates.py +0 -0
- {sovereign-0.25.3 → sovereign-0.26.0}/src/sovereign/utils/timer.py +0 -0
- {sovereign-0.25.3 → sovereign-0.26.0}/src/sovereign/utils/version_info.py +0 -0
- {sovereign-0.25.3 → sovereign-0.26.0}/src/sovereign/utils/weighted_clusters.py +0 -0
- {sovereign-0.25.3 → sovereign-0.26.0}/src/sovereign/views/__init__.py +0 -0
- {sovereign-0.25.3 → sovereign-0.26.0}/src/sovereign/views/admin.py +0 -0
- {sovereign-0.25.3 → sovereign-0.26.0}/src/sovereign/views/crypto.py +0 -0
- {sovereign-0.25.3 → sovereign-0.26.0}/src/sovereign/views/discovery.py +0 -0
- {sovereign-0.25.3 → sovereign-0.26.0}/src/sovereign/views/healthchecks.py +0 -0
- {sovereign-0.25.3 → sovereign-0.26.0}/src/sovereign/views/interface.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: sovereign
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.26.0
|
|
4
4
|
Summary: Envoy Proxy control-plane written in Python
|
|
5
5
|
Home-page: https://pypi.org/project/sovereign/
|
|
6
6
|
License: Apache-2.0
|
|
@@ -41,7 +41,7 @@ Requires-Dist: cryptography (>=42.0.5,<43.0.0)
|
|
|
41
41
|
Requires-Dist: datadog (>=0.47.0,<0.48.0) ; extra == "statsd"
|
|
42
42
|
Requires-Dist: fastapi (>=0.110.0,<0.111.0)
|
|
43
43
|
Requires-Dist: glom (>=23.3.0,<24.0.0)
|
|
44
|
-
Requires-Dist: gunicorn (>=
|
|
44
|
+
Requires-Dist: gunicorn (>=22.0.0,<23.0.0)
|
|
45
45
|
Requires-Dist: httptools (>=0.6.0,<0.7.0) ; extra == "httptools"
|
|
46
46
|
Requires-Dist: orjson (>=3.9.15,<4.0.0) ; extra == "orjson"
|
|
47
47
|
Requires-Dist: redis (<=5.0.0)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "sovereign"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.26.0"
|
|
4
4
|
description = "Envoy Proxy control-plane written in Python"
|
|
5
5
|
license = "Apache-2.0"
|
|
6
6
|
packages = [
|
|
@@ -37,12 +37,15 @@ sovereign = 'sovereign.server:main'
|
|
|
37
37
|
"inline" = "sovereign.sources.inline:Inline"
|
|
38
38
|
|
|
39
39
|
[tool.poetry.plugins."sovereign.modifiers"]
|
|
40
|
-
"sovereign_3rd_party_test" = "sovereign.modifiers
|
|
40
|
+
"sovereign_3rd_party_test" = "sovereign.testing.modifiers:Test"
|
|
41
|
+
|
|
42
|
+
[tool.poetry.plugins."sovereign.loaders"]
|
|
43
|
+
"example" = "sovereign.testing.loaders:Multiply"
|
|
41
44
|
|
|
42
45
|
[tool.poetry.dependencies]
|
|
43
46
|
python = "^3.11"
|
|
44
47
|
uvicorn = "^0.23.2"
|
|
45
|
-
gunicorn = "^
|
|
48
|
+
gunicorn = "^22.0.0"
|
|
46
49
|
aiofiles = "^23.2.1"
|
|
47
50
|
requests = "^2.31.0"
|
|
48
51
|
PyYAML = "^6.0.1"
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import asyncio
|
|
2
2
|
import traceback
|
|
3
|
-
import uvicorn
|
|
4
3
|
from collections import namedtuple
|
|
4
|
+
|
|
5
|
+
import uvicorn
|
|
5
6
|
from fastapi import FastAPI, Request
|
|
6
7
|
from fastapi.responses import RedirectResponse, FileResponse, Response, JSONResponse
|
|
8
|
+
|
|
7
9
|
from sovereign import (
|
|
8
10
|
__version__,
|
|
9
11
|
config,
|
|
@@ -14,12 +16,12 @@ from sovereign import (
|
|
|
14
16
|
logs,
|
|
15
17
|
)
|
|
16
18
|
from sovereign.error_info import ErrorInfo
|
|
19
|
+
from sovereign.utils.resources import get_package_file
|
|
17
20
|
from sovereign.views import crypto, discovery, healthchecks, admin, interface
|
|
18
21
|
from sovereign.middlewares import (
|
|
19
22
|
RequestContextLogMiddleware,
|
|
20
23
|
LoggingMiddleware,
|
|
21
24
|
)
|
|
22
|
-
from sovereign.utils.resources import get_package_file
|
|
23
25
|
|
|
24
26
|
Router = namedtuple("Router", "module tags prefix")
|
|
25
27
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import os
|
|
2
2
|
import json
|
|
3
3
|
from enum import Enum
|
|
4
|
-
from typing import Any, Dict, Callable, Union
|
|
4
|
+
from typing import Any, Dict, Callable, Union, Protocol
|
|
5
5
|
from types import ModuleType
|
|
6
6
|
import yaml
|
|
7
7
|
import jinja2
|
|
@@ -14,6 +14,11 @@ from sovereign.utils.resources import get_package_file_bytes
|
|
|
14
14
|
|
|
15
15
|
|
|
16
16
|
class Serialization(Enum):
|
|
17
|
+
"""
|
|
18
|
+
Types of deserialization available in Sovereign
|
|
19
|
+
for loading configuration field values.
|
|
20
|
+
"""
|
|
21
|
+
|
|
17
22
|
yaml = "yaml"
|
|
18
23
|
json = "json"
|
|
19
24
|
orjson = "orjson"
|
|
@@ -22,18 +27,7 @@ class Serialization(Enum):
|
|
|
22
27
|
jinja2 = "jinja2"
|
|
23
28
|
string = "string"
|
|
24
29
|
raw = "raw"
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
class Protocol(Enum):
|
|
28
|
-
file = "file"
|
|
29
|
-
http = "http"
|
|
30
|
-
https = "https"
|
|
31
|
-
pkgdata = "pkgdata"
|
|
32
|
-
env = "env"
|
|
33
|
-
module = "module"
|
|
34
|
-
s3 = "s3"
|
|
35
|
-
python = "python"
|
|
36
|
-
inline = "inline"
|
|
30
|
+
skip = "skip"
|
|
37
31
|
|
|
38
32
|
|
|
39
33
|
jinja_env = jinja2.Environment(autoescape=True)
|
|
@@ -56,6 +50,7 @@ serializers: Dict[Serialization, Callable[[Any], Any]] = {
|
|
|
56
50
|
Serialization.raw: passthrough,
|
|
57
51
|
}
|
|
58
52
|
|
|
53
|
+
|
|
59
54
|
try:
|
|
60
55
|
import ujson
|
|
61
56
|
|
|
@@ -99,8 +94,13 @@ except ImportError:
|
|
|
99
94
|
boto3 = None
|
|
100
95
|
|
|
101
96
|
|
|
97
|
+
class CustomLoader(Protocol):
|
|
98
|
+
def load(self, path: str, ser: Serialization) -> Any:
|
|
99
|
+
...
|
|
100
|
+
|
|
101
|
+
|
|
102
102
|
class Loadable(BaseModel):
|
|
103
|
-
protocol:
|
|
103
|
+
protocol: str = "http"
|
|
104
104
|
serialization: Serialization = Serialization.yaml
|
|
105
105
|
path: str
|
|
106
106
|
|
|
@@ -113,26 +113,25 @@ class Loadable(BaseModel):
|
|
|
113
113
|
raise
|
|
114
114
|
|
|
115
115
|
@staticmethod
|
|
116
|
-
def from_legacy_fmt(
|
|
117
|
-
if "://" not in
|
|
116
|
+
def from_legacy_fmt(fmt_string: str) -> "Loadable":
|
|
117
|
+
if "://" not in fmt_string:
|
|
118
118
|
return Loadable(
|
|
119
|
-
protocol=
|
|
119
|
+
protocol="inline", serialization=Serialization.string, path=fmt_string
|
|
120
120
|
)
|
|
121
121
|
try:
|
|
122
|
-
scheme, path =
|
|
122
|
+
scheme, path = fmt_string.split("://")
|
|
123
123
|
except ValueError:
|
|
124
|
-
raise ValueError(
|
|
124
|
+
raise ValueError(fmt_string)
|
|
125
125
|
try:
|
|
126
|
-
|
|
126
|
+
proto, ser = scheme.split("+")
|
|
127
127
|
except ValueError:
|
|
128
|
-
|
|
128
|
+
proto, ser = scheme, "yaml"
|
|
129
129
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
if proto in (Protocol.python, Protocol.module):
|
|
130
|
+
serialization: Serialization = Serialization(ser)
|
|
131
|
+
if proto in ("python", "module"):
|
|
133
132
|
serialization = Serialization.raw
|
|
134
|
-
if proto in (
|
|
135
|
-
path = "://".join([proto
|
|
133
|
+
if proto in ("http", "https"):
|
|
134
|
+
path = "://".join([proto, path])
|
|
136
135
|
|
|
137
136
|
return Loadable(
|
|
138
137
|
protocol=proto,
|
|
@@ -145,32 +144,32 @@ def raise_(e: Exception) -> Exception:
|
|
|
145
144
|
raise e
|
|
146
145
|
|
|
147
146
|
|
|
148
|
-
def load_file(path: str,
|
|
147
|
+
def load_file(path: str, ser: Serialization) -> Any:
|
|
149
148
|
with open(path) as f:
|
|
150
149
|
contents = f.read()
|
|
151
150
|
try:
|
|
152
|
-
return serializers[
|
|
151
|
+
return serializers[ser](contents)
|
|
153
152
|
except FileNotFoundError:
|
|
154
153
|
raise FileNotFoundError(f"Unable to load {path}")
|
|
155
154
|
|
|
156
155
|
|
|
157
|
-
def load_package_data(path: str,
|
|
156
|
+
def load_package_data(path: str, ser: Serialization) -> Any:
|
|
158
157
|
pkg, pkg_file = path.split(":")
|
|
159
158
|
data = get_package_file_bytes(pkg, pkg_file)
|
|
160
|
-
return serializers[
|
|
159
|
+
return serializers[ser](data)
|
|
161
160
|
|
|
162
161
|
|
|
163
|
-
def load_http(path: str,
|
|
162
|
+
def load_http(path: str, ser: Serialization) -> Any:
|
|
164
163
|
response = requests.get(path)
|
|
165
164
|
response.raise_for_status()
|
|
166
165
|
data = response.text
|
|
167
|
-
return serializers[
|
|
166
|
+
return serializers[ser](data)
|
|
168
167
|
|
|
169
168
|
|
|
170
|
-
def load_env(variable: str,
|
|
169
|
+
def load_env(variable: str, ser: Serialization = Serialization.raw) -> Any:
|
|
171
170
|
data = os.getenv(variable)
|
|
172
171
|
try:
|
|
173
|
-
return serializers[
|
|
172
|
+
return serializers[ser](data)
|
|
174
173
|
except AttributeError as e:
|
|
175
174
|
raise AttributeError(
|
|
176
175
|
f"Unable to read environment variable {variable}: {repr(e)}"
|
|
@@ -188,7 +187,7 @@ def load_module(name: str, _: Serialization = Serialization.raw) -> Any:
|
|
|
188
187
|
return imported
|
|
189
188
|
|
|
190
189
|
|
|
191
|
-
def load_s3(path: str,
|
|
190
|
+
def load_s3(path: str, ser: Serialization = Serialization.raw) -> Any:
|
|
192
191
|
if isinstance(boto3, type(None)):
|
|
193
192
|
raise ImportError(
|
|
194
193
|
"boto3 must be installed to load S3 paths. Use ``pip install sovereign[boto]``"
|
|
@@ -197,7 +196,7 @@ def load_s3(path: str, loader: Serialization = Serialization.raw) -> Any:
|
|
|
197
196
|
s3 = boto3.client("s3")
|
|
198
197
|
response = s3.get_object(Bucket=bucket, Key=key)
|
|
199
198
|
data = "".join([chunk.decode() for chunk in response["Body"]])
|
|
200
|
-
return serializers[
|
|
199
|
+
return serializers[ser](data)
|
|
201
200
|
|
|
202
201
|
|
|
203
202
|
def load_python(path: str, _: Serialization = Serialization.raw) -> ModuleType:
|
|
@@ -210,14 +209,14 @@ def load_inline(path: str, _: Serialization = Serialization.raw) -> Any:
|
|
|
210
209
|
return str(path)
|
|
211
210
|
|
|
212
211
|
|
|
213
|
-
loaders: Dict[
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
212
|
+
loaders: Dict[str, Callable[[str, Serialization], Union[str, Any]]] = {
|
|
213
|
+
"file": load_file,
|
|
214
|
+
"pkgdata": load_package_data,
|
|
215
|
+
"http": load_http,
|
|
216
|
+
"https": load_http,
|
|
217
|
+
"env": load_env,
|
|
218
|
+
"module": load_module,
|
|
219
|
+
"s3": load_s3,
|
|
220
|
+
"python": load_python,
|
|
221
|
+
"inline": load_inline,
|
|
223
222
|
}
|
|
@@ -13,6 +13,8 @@ from typing import (
|
|
|
13
13
|
)
|
|
14
14
|
|
|
15
15
|
from fastapi import HTTPException
|
|
16
|
+
from sovereign import config_loader
|
|
17
|
+
from sovereign.utils.entry_point_loader import EntryPointLoader
|
|
16
18
|
from structlog.stdlib import BoundLogger
|
|
17
19
|
|
|
18
20
|
from sovereign.config_loader import Loadable
|
|
@@ -53,6 +55,14 @@ class TemplateContext:
|
|
|
53
55
|
self.stats = stats
|
|
54
56
|
# initial load
|
|
55
57
|
self.context: Dict[str, Any] = {}
|
|
58
|
+
entry_points = EntryPointLoader("loaders")
|
|
59
|
+
for entry_point in entry_points.groups["loaders"]:
|
|
60
|
+
custom_loader = entry_point.load()
|
|
61
|
+
try:
|
|
62
|
+
func = custom_loader.load
|
|
63
|
+
except AttributeError:
|
|
64
|
+
raise AttributeError("Custom loader does not implement .load()")
|
|
65
|
+
config_loader.loaders[entry_point.name] = func
|
|
56
66
|
asyncio.run(self.load_context_variables())
|
|
57
67
|
|
|
58
68
|
async def start_refresh_context(self) -> NoReturn:
|
|
@@ -60,7 +70,6 @@ class TemplateContext:
|
|
|
60
70
|
await poll_forever_cron(self.refresh_cron, self.refresh_context)
|
|
61
71
|
elif self.refresh_rate is not None:
|
|
62
72
|
await poll_forever(self.refresh_rate, self.refresh_context)
|
|
63
|
-
|
|
64
73
|
raise RuntimeError("Failed to start refresh_context, this should never happen")
|
|
65
74
|
|
|
66
75
|
async def refresh_context(self) -> None:
|
|
@@ -68,25 +77,25 @@ class TemplateContext:
|
|
|
68
77
|
|
|
69
78
|
async def _load_context(
|
|
70
79
|
self,
|
|
71
|
-
|
|
72
|
-
|
|
80
|
+
name: str,
|
|
81
|
+
loader: Loadable | str,
|
|
73
82
|
refresh_num_retries: int,
|
|
74
83
|
refresh_retry_interval_secs: int,
|
|
75
84
|
) -> LoadContextResponse:
|
|
76
85
|
retries_left = refresh_num_retries
|
|
77
|
-
|
|
86
|
+
response = {}
|
|
78
87
|
|
|
79
88
|
while True:
|
|
80
89
|
try:
|
|
81
|
-
if isinstance(
|
|
82
|
-
|
|
83
|
-
elif isinstance(
|
|
84
|
-
|
|
90
|
+
if isinstance(loader, Loadable):
|
|
91
|
+
response = loader.load()
|
|
92
|
+
elif isinstance(loader, str):
|
|
93
|
+
response = Loadable.from_legacy_fmt(loader).load()
|
|
85
94
|
self.stats.increment(
|
|
86
95
|
"context.refresh.success",
|
|
87
|
-
tags=[f"context:{
|
|
96
|
+
tags=[f"context:{name}"],
|
|
88
97
|
)
|
|
89
|
-
return LoadContextResponse(
|
|
98
|
+
return LoadContextResponse(name, response)
|
|
90
99
|
# pylint: disable=broad-except
|
|
91
100
|
except Exception as e:
|
|
92
101
|
retries_left -= 1
|
|
@@ -95,34 +104,29 @@ class TemplateContext:
|
|
|
95
104
|
self.logger.error(str(e), traceback=tb)
|
|
96
105
|
self.stats.increment(
|
|
97
106
|
"context.refresh.error",
|
|
98
|
-
tags=[f"context:{
|
|
107
|
+
tags=[f"context:{name}"],
|
|
99
108
|
)
|
|
100
|
-
return LoadContextResponse(
|
|
109
|
+
return LoadContextResponse(name, response, False)
|
|
101
110
|
else:
|
|
102
111
|
await asyncio.sleep(refresh_retry_interval_secs)
|
|
103
112
|
|
|
104
113
|
async def load_context_variables(self) -> None:
|
|
105
|
-
|
|
106
|
-
for
|
|
107
|
-
|
|
114
|
+
coroutines: list[Awaitable[LoadContextResponse]] = []
|
|
115
|
+
for name, conf in self.configured_context.items():
|
|
116
|
+
coroutines.append(
|
|
108
117
|
self._load_context(
|
|
109
|
-
|
|
110
|
-
|
|
118
|
+
name,
|
|
119
|
+
conf,
|
|
111
120
|
self.refresh_num_retries,
|
|
112
121
|
self.refresh_retry_interval_secs,
|
|
113
122
|
)
|
|
114
123
|
)
|
|
115
124
|
|
|
116
|
-
|
|
117
|
-
*context_coroutines
|
|
118
|
-
)
|
|
125
|
+
results: list[LoadContextResponse] = await asyncio.gather(*coroutines)
|
|
119
126
|
|
|
120
|
-
for
|
|
121
|
-
if
|
|
122
|
-
|
|
123
|
-
or context_result.context_name not in self.context
|
|
124
|
-
):
|
|
125
|
-
self.context[context_result.context_name] = context_result.context
|
|
127
|
+
for res in results:
|
|
128
|
+
if res.success or res.context_name not in self.context:
|
|
129
|
+
self.context[res.context_name] = res.context
|
|
126
130
|
|
|
127
131
|
if "crypto" not in self.context and self.crypto:
|
|
128
132
|
self.context["crypto"] = self.crypto
|
|
@@ -162,7 +166,9 @@ class TemplateContext:
|
|
|
162
166
|
ret = self.build_new_context_from_instances(
|
|
163
167
|
node_value=self.poller.extract_node_key(request.node),
|
|
164
168
|
)
|
|
169
|
+
ret["__hide_from_ui"] = lambda v: v
|
|
165
170
|
if request.hide_private_keys:
|
|
171
|
+
ret["__hide_from_ui"] = lambda _: "(value hidden)"
|
|
166
172
|
ret["crypto"] = CipherContainer.from_encryption_configs(
|
|
167
173
|
encryption_configs=[EncryptionConfig("", EncryptionType.DISABLED)],
|
|
168
174
|
logger=self.logger,
|
|
@@ -19,7 +19,7 @@ from pydantic import (
|
|
|
19
19
|
validator,
|
|
20
20
|
)
|
|
21
21
|
|
|
22
|
-
from sovereign.config_loader import Loadable,
|
|
22
|
+
from sovereign.config_loader import Loadable, Serialization, jinja_env
|
|
23
23
|
from sovereign.utils.crypto.suites import EncryptionType
|
|
24
24
|
from sovereign.utils.version_info import compute_hash
|
|
25
25
|
|
|
@@ -132,7 +132,7 @@ class XdsTemplate:
|
|
|
132
132
|
self.loadable: Loadable = Loadable.from_legacy_fmt(path)
|
|
133
133
|
elif isinstance(path, Loadable):
|
|
134
134
|
self.loadable = path
|
|
135
|
-
self.is_python_source = self.loadable.protocol ==
|
|
135
|
+
self.is_python_source = self.loadable.protocol == "python"
|
|
136
136
|
self.source = self.load_source()
|
|
137
137
|
template_ast = jinja_env.parse(self.source)
|
|
138
138
|
self.jinja_variables = meta.find_undeclared_variables(template_ast)
|
|
@@ -177,7 +177,7 @@ class XdsTemplate:
|
|
|
177
177
|
# we can simply read and return the source of it.
|
|
178
178
|
old_protocol = self.loadable.protocol
|
|
179
179
|
old_serialization = self.loadable.serialization
|
|
180
|
-
self.loadable.protocol =
|
|
180
|
+
self.loadable.protocol = "inline"
|
|
181
181
|
self.loadable.serialization = Serialization("string")
|
|
182
182
|
ret = self.loadable.load()
|
|
183
183
|
self.loadable.protocol = old_protocol
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|