sovereign 0.29.0a3__tar.gz → 0.29.1__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.29.0a3 → sovereign-0.29.1}/PKG-INFO +4 -3
- {sovereign-0.29.0a3 → sovereign-0.29.1}/pyproject.toml +3 -3
- {sovereign-0.29.0a3 → sovereign-0.29.1}/src/sovereign/discovery.py +8 -16
- {sovereign-0.29.0a3 → sovereign-0.29.1}/src/sovereign/dynamic_config/__init__.py +25 -22
- {sovereign-0.29.0a3 → sovereign-0.29.1}/src/sovereign/schemas.py +1 -0
- {sovereign-0.29.0a3 → sovereign-0.29.1}/src/sovereign/views/discovery.py +18 -15
- {sovereign-0.29.0a3 → sovereign-0.29.1}/LICENSE.txt +0 -0
- {sovereign-0.29.0a3 → sovereign-0.29.1}/README.md +0 -0
- {sovereign-0.29.0a3 → sovereign-0.29.1}/src/sovereign/__init__.py +0 -0
- {sovereign-0.29.0a3 → sovereign-0.29.1}/src/sovereign/app.py +0 -0
- {sovereign-0.29.0a3 → sovereign-0.29.1}/src/sovereign/configuration.py +0 -0
- {sovereign-0.29.0a3 → sovereign-0.29.1}/src/sovereign/constants.py +0 -0
- {sovereign-0.29.0a3 → sovereign-0.29.1}/src/sovereign/context.py +0 -0
- {sovereign-0.29.0a3 → sovereign-0.29.1}/src/sovereign/dynamic_config/deser.py +0 -0
- {sovereign-0.29.0a3 → sovereign-0.29.1}/src/sovereign/dynamic_config/loaders.py +0 -0
- {sovereign-0.29.0a3 → sovereign-0.29.1}/src/sovereign/error_info.py +0 -0
- {sovereign-0.29.0a3 → sovereign-0.29.1}/src/sovereign/logging/access_logger.py +0 -0
- {sovereign-0.29.0a3 → sovereign-0.29.1}/src/sovereign/logging/application_logger.py +0 -0
- {sovereign-0.29.0a3 → sovereign-0.29.1}/src/sovereign/logging/base_logger.py +0 -0
- {sovereign-0.29.0a3 → sovereign-0.29.1}/src/sovereign/logging/bootstrapper.py +0 -0
- {sovereign-0.29.0a3 → sovereign-0.29.1}/src/sovereign/logging/types.py +0 -0
- {sovereign-0.29.0a3 → sovereign-0.29.1}/src/sovereign/middlewares.py +0 -0
- {sovereign-0.29.0a3 → sovereign-0.29.1}/src/sovereign/modifiers/__init__.py +0 -0
- {sovereign-0.29.0a3 → sovereign-0.29.1}/src/sovereign/modifiers/lib.py +0 -0
- {sovereign-0.29.0a3 → sovereign-0.29.1}/src/sovereign/response_class.py +0 -0
- {sovereign-0.29.0a3 → sovereign-0.29.1}/src/sovereign/server.py +0 -0
- {sovereign-0.29.0a3 → sovereign-0.29.1}/src/sovereign/sources/__init__.py +0 -0
- {sovereign-0.29.0a3 → sovereign-0.29.1}/src/sovereign/sources/file.py +0 -0
- {sovereign-0.29.0a3 → sovereign-0.29.1}/src/sovereign/sources/inline.py +0 -0
- {sovereign-0.29.0a3 → sovereign-0.29.1}/src/sovereign/sources/lib.py +0 -0
- {sovereign-0.29.0a3 → sovereign-0.29.1}/src/sovereign/sources/poller.py +0 -0
- {sovereign-0.29.0a3 → sovereign-0.29.1}/src/sovereign/static/sass/style.scss +0 -0
- {sovereign-0.29.0a3 → sovereign-0.29.1}/src/sovereign/static/style.css +0 -0
- {sovereign-0.29.0a3 → sovereign-0.29.1}/src/sovereign/statistics.py +0 -0
- {sovereign-0.29.0a3 → sovereign-0.29.1}/src/sovereign/templates/base.html +0 -0
- {sovereign-0.29.0a3 → sovereign-0.29.1}/src/sovereign/templates/err.html +0 -0
- {sovereign-0.29.0a3 → sovereign-0.29.1}/src/sovereign/templates/resources.html +0 -0
- {sovereign-0.29.0a3 → sovereign-0.29.1}/src/sovereign/templates/ul_filter.html +0 -0
- {sovereign-0.29.0a3 → sovereign-0.29.1}/src/sovereign/testing/loaders.py +0 -0
- {sovereign-0.29.0a3 → sovereign-0.29.1}/src/sovereign/testing/modifiers.py +0 -0
- {sovereign-0.29.0a3 → sovereign-0.29.1}/src/sovereign/tracing.py +0 -0
- {sovereign-0.29.0a3 → sovereign-0.29.1}/src/sovereign/utils/__init__.py +0 -0
- {sovereign-0.29.0a3 → sovereign-0.29.1}/src/sovereign/utils/auth.py +0 -0
- {sovereign-0.29.0a3 → sovereign-0.29.1}/src/sovereign/utils/crypto/__init__.py +0 -0
- {sovereign-0.29.0a3 → sovereign-0.29.1}/src/sovereign/utils/crypto/crypto.py +0 -0
- {sovereign-0.29.0a3 → sovereign-0.29.1}/src/sovereign/utils/crypto/suites/__init__.py +0 -0
- {sovereign-0.29.0a3 → sovereign-0.29.1}/src/sovereign/utils/crypto/suites/aes_gcm_cipher.py +0 -0
- {sovereign-0.29.0a3 → sovereign-0.29.1}/src/sovereign/utils/crypto/suites/base_cipher.py +0 -0
- {sovereign-0.29.0a3 → sovereign-0.29.1}/src/sovereign/utils/crypto/suites/disabled_cipher.py +0 -0
- {sovereign-0.29.0a3 → sovereign-0.29.1}/src/sovereign/utils/crypto/suites/fernet_cipher.py +0 -0
- {sovereign-0.29.0a3 → sovereign-0.29.1}/src/sovereign/utils/dictupdate.py +0 -0
- {sovereign-0.29.0a3 → sovereign-0.29.1}/src/sovereign/utils/eds.py +0 -0
- {sovereign-0.29.0a3 → sovereign-0.29.1}/src/sovereign/utils/entry_point_loader.py +0 -0
- {sovereign-0.29.0a3 → sovereign-0.29.1}/src/sovereign/utils/mock.py +0 -0
- {sovereign-0.29.0a3 → sovereign-0.29.1}/src/sovereign/utils/resources.py +0 -0
- {sovereign-0.29.0a3 → sovereign-0.29.1}/src/sovereign/utils/templates.py +0 -0
- {sovereign-0.29.0a3 → sovereign-0.29.1}/src/sovereign/utils/timer.py +0 -0
- {sovereign-0.29.0a3 → sovereign-0.29.1}/src/sovereign/utils/version_info.py +0 -0
- {sovereign-0.29.0a3 → sovereign-0.29.1}/src/sovereign/utils/weighted_clusters.py +0 -0
- {sovereign-0.29.0a3 → sovereign-0.29.1}/src/sovereign/views/__init__.py +0 -0
- {sovereign-0.29.0a3 → sovereign-0.29.1}/src/sovereign/views/admin.py +0 -0
- {sovereign-0.29.0a3 → sovereign-0.29.1}/src/sovereign/views/crypto.py +0 -0
- {sovereign-0.29.0a3 → sovereign-0.29.1}/src/sovereign/views/healthchecks.py +0 -0
- {sovereign-0.29.0a3 → sovereign-0.29.1}/src/sovereign/views/interface.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: sovereign
|
|
3
|
-
Version: 0.29.
|
|
3
|
+
Version: 0.29.1
|
|
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
|
|
@@ -18,6 +18,7 @@ Classifier: Natural Language :: English
|
|
|
18
18
|
Classifier: Operating System :: POSIX :: Linux
|
|
19
19
|
Classifier: Programming Language :: Python :: 3
|
|
20
20
|
Classifier: Programming Language :: Python :: 3.11
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
22
|
Classifier: Programming Language :: Python :: 3.10
|
|
22
23
|
Classifier: Programming Language :: Python :: 3.8
|
|
23
24
|
Classifier: Programming Language :: Python :: 3.9
|
|
@@ -37,7 +38,7 @@ Requires-Dist: cachelib (>=0.10.2,<0.11.0)
|
|
|
37
38
|
Requires-Dist: cachetools (>=5.3.2,<6.0.0)
|
|
38
39
|
Requires-Dist: cashews[redis] (>=6.3.0,<7.0.0) ; extra == "caching"
|
|
39
40
|
Requires-Dist: croniter (>=1.4.1,<2.0.0)
|
|
40
|
-
Requires-Dist: cryptography (>=
|
|
41
|
+
Requires-Dist: cryptography (>=43.0.1,<44.0.0)
|
|
41
42
|
Requires-Dist: datadog (>=0.47.0,<0.48.0) ; extra == "statsd"
|
|
42
43
|
Requires-Dist: fastapi (>=0.110.0,<0.111.0)
|
|
43
44
|
Requires-Dist: glom (>=23.3.0,<24.0.0)
|
|
@@ -48,7 +49,7 @@ Requires-Dist: pydantic (>=2.7.2,<3.0.0)
|
|
|
48
49
|
Requires-Dist: pydantic-settings (>=2.3.1,<3.0.0)
|
|
49
50
|
Requires-Dist: redis (<=5.0.0)
|
|
50
51
|
Requires-Dist: requests (>=2.31.0,<3.0.0)
|
|
51
|
-
Requires-Dist: sentry-sdk (>=
|
|
52
|
+
Requires-Dist: sentry-sdk (>=2.14.0,<3.0.0) ; extra == "sentry"
|
|
52
53
|
Requires-Dist: structlog (>=23.1.0,<24.0.0)
|
|
53
54
|
Requires-Dist: ujson (>=5.8.0,<6.0.0) ; extra == "ujson"
|
|
54
55
|
Requires-Dist: uvicorn (>=0.23.2,<0.24.0)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "sovereign"
|
|
3
|
-
version = "0.29.
|
|
3
|
+
version = "0.29.1"
|
|
4
4
|
description = "Envoy Proxy control-plane written in Python"
|
|
5
5
|
license = "Apache-2.0"
|
|
6
6
|
packages = [
|
|
@@ -73,10 +73,10 @@ Jinja2 = "^3.1.2"
|
|
|
73
73
|
structlog = "^23.1.0"
|
|
74
74
|
cachelib = "^0.10.2"
|
|
75
75
|
glom = "^23.3.0"
|
|
76
|
-
cryptography = "^
|
|
76
|
+
cryptography = "^43.0.1"
|
|
77
77
|
fastapi = "^0.110.0"
|
|
78
78
|
uvloop = "^0.19.0"
|
|
79
|
-
sentry-sdk = "^
|
|
79
|
+
sentry-sdk = "^2.14.0"
|
|
80
80
|
boto3 = {version = "^1.28.62", optional = true}
|
|
81
81
|
datadog = {version = "^0.47.0", optional = true}
|
|
82
82
|
ujson = {version = "^5.8.0", optional = true}
|
|
@@ -23,7 +23,6 @@ except ImportError:
|
|
|
23
23
|
from sovereign import XDS_TEMPLATES, config, logs, template_context
|
|
24
24
|
from sovereign.utils.version_info import compute_hash
|
|
25
25
|
from sovereign.schemas import XdsTemplate, DiscoveryRequest, ProcessedTemplate
|
|
26
|
-
from sovereign.tracing import Tracer
|
|
27
26
|
|
|
28
27
|
|
|
29
28
|
try:
|
|
@@ -106,8 +105,7 @@ def response(request: DiscoveryRequest, xds_type: str) -> ProcessedTemplate:
|
|
|
106
105
|
resource_names=request.resources,
|
|
107
106
|
**template_context.get_context(request, template),
|
|
108
107
|
)
|
|
109
|
-
|
|
110
|
-
content = template(**context)
|
|
108
|
+
content = template(**context)
|
|
111
109
|
|
|
112
110
|
# Deserialize YAML output from Jinja2
|
|
113
111
|
if not template.is_python_source:
|
|
@@ -118,19 +116,13 @@ def response(request: DiscoveryRequest, xds_type: str) -> ProcessedTemplate:
|
|
|
118
116
|
content = deserialize_config(content)
|
|
119
117
|
|
|
120
118
|
# Early return if the template is identical
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
return ProcessedTemplate(version_info=config_version, resources=[])
|
|
129
|
-
|
|
130
|
-
if not isinstance(content, dict):
|
|
131
|
-
raise RuntimeError(f"Attempting to filter unstructured data: {content}")
|
|
132
|
-
with Tracer("filtering"):
|
|
133
|
-
resources = filter_resources(content["resources"], request.resources)
|
|
119
|
+
config_version = compute_hash(content)
|
|
120
|
+
if config_version == request.version_info and not config.discovery_cache.enabled:
|
|
121
|
+
return ProcessedTemplate(version_info=config_version, resources=[])
|
|
122
|
+
|
|
123
|
+
if not isinstance(content, dict):
|
|
124
|
+
raise RuntimeError(f"Attempting to filter unstructured data: {content}")
|
|
125
|
+
resources = filter_resources(content["resources"], request.resources)
|
|
134
126
|
return ProcessedTemplate(resources=resources, version_info=config_version)
|
|
135
127
|
|
|
136
128
|
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import inspect
|
|
1
2
|
from typing import Any, Dict, Optional
|
|
2
3
|
|
|
3
4
|
from pydantic import BaseModel
|
|
@@ -13,20 +14,20 @@ class Loadable(BaseModel):
|
|
|
13
14
|
serialization: Optional[str] = None
|
|
14
15
|
|
|
15
16
|
def load(self, default: Any = None) -> Any:
|
|
16
|
-
if self.protocol not in
|
|
17
|
+
if self.protocol not in LOADERS:
|
|
17
18
|
raise KeyError(
|
|
18
|
-
f"Could not find CustomLoader {self.protocol}. Available: {
|
|
19
|
+
f"Could not find CustomLoader {self.protocol}. Available: {LOADERS}"
|
|
19
20
|
)
|
|
20
|
-
loader_ =
|
|
21
|
+
loader_ = LOADERS[self.protocol]
|
|
21
22
|
|
|
22
23
|
ser = self.serialization
|
|
23
24
|
if ser is None:
|
|
24
25
|
ser = loader_.default_deser
|
|
25
|
-
if ser not in
|
|
26
|
+
if ser not in DESERIALIZERS:
|
|
26
27
|
raise KeyError(
|
|
27
|
-
f"Could not find Deserializer {ser}. Available: {
|
|
28
|
+
f"Could not find Deserializer {ser}. Available: {DESERIALIZERS}"
|
|
28
29
|
)
|
|
29
|
-
deserializer =
|
|
30
|
+
deserializer = DESERIALIZERS[ser]
|
|
30
31
|
|
|
31
32
|
try:
|
|
32
33
|
data = loader_.load(self.path)
|
|
@@ -63,23 +64,25 @@ class Loadable(BaseModel):
|
|
|
63
64
|
)
|
|
64
65
|
|
|
65
66
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
for entry_point in loader_entry_point.groups["loaders"]:
|
|
67
|
+
LOADERS: Dict[str, CustomLoader] = {}
|
|
68
|
+
for entry_point in EntryPointLoader("loaders").groups["loaders"]:
|
|
69
69
|
custom_loader = entry_point.load()
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
raise AttributeError(
|
|
74
|
-
|
|
70
|
+
func = custom_loader()
|
|
71
|
+
method = getattr(func, "load")
|
|
72
|
+
if not inspect.ismethod(method):
|
|
73
|
+
raise AttributeError(
|
|
74
|
+
f"CustomLoader {entry_point.name} does not implement .load()"
|
|
75
|
+
)
|
|
76
|
+
LOADERS[entry_point.name] = func
|
|
75
77
|
|
|
76
78
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
for entry_point in deser_entry_point.groups["deserializers"]:
|
|
79
|
+
DESERIALIZERS: Dict[str, ConfigDeserializer] = {}
|
|
80
|
+
for entry_point in EntryPointLoader("deserializers").groups["deserializers"]:
|
|
80
81
|
deserializer = entry_point.load()
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
raise AttributeError(
|
|
85
|
-
|
|
82
|
+
func = deserializer()
|
|
83
|
+
method = getattr(func, "deserialize")
|
|
84
|
+
if not inspect.ismethod(method):
|
|
85
|
+
raise AttributeError(
|
|
86
|
+
f"Deserializer {entry_point.name} does not implement .deserialize()"
|
|
87
|
+
)
|
|
88
|
+
DESERIALIZERS[entry_point.name] = func
|
|
@@ -112,6 +112,7 @@ class DiscoveryCacheConfig(BaseModel):
|
|
|
112
112
|
suppress: bool = False # False = Don't suppress connection errors. True = suppress connection errors
|
|
113
113
|
socket_keepalive: bool = True # Try to keep connections to redis around.
|
|
114
114
|
ttl: int = 60
|
|
115
|
+
extra_keys: Dict[str, Any] = {}
|
|
115
116
|
|
|
116
117
|
@model_validator(mode="after")
|
|
117
118
|
def set_default_protocol(self) -> Self:
|
|
@@ -117,21 +117,24 @@ async def perform_discovery(
|
|
|
117
117
|
authenticate(req)
|
|
118
118
|
if discovery_cache.enabled:
|
|
119
119
|
logs.access_logger.queue_log_fields(CACHE_XDS_HIT=False)
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
120
|
+
metadata_keys = discovery_cache.extra_keys.get("metadata", [])
|
|
121
|
+
extra_metadata = [req.node.metadata.get(key, None) for key in metadata_keys]
|
|
122
|
+
hash_keys = [
|
|
123
|
+
api_version,
|
|
124
|
+
resource_type,
|
|
125
|
+
req.envoy_version,
|
|
126
|
+
req.resource_names,
|
|
127
|
+
req.desired_controlplane,
|
|
128
|
+
req.hide_private_keys,
|
|
129
|
+
req.type_url,
|
|
130
|
+
req.node.cluster,
|
|
131
|
+
req.node.locality,
|
|
132
|
+
req.node.metadata.get("auth", None),
|
|
133
|
+
req.node.metadata.get("num_cpus", None),
|
|
134
|
+
] + extra_metadata
|
|
135
|
+
|
|
136
|
+
cache_key = compute_hash(hash_keys)
|
|
137
|
+
|
|
135
138
|
if template := await cache.get(key=cache_key, default=None):
|
|
136
139
|
logs.access_logger.queue_log_fields(CACHE_XDS_HIT=True)
|
|
137
140
|
return template # type: ignore[no-any-return]
|
|
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
|
{sovereign-0.29.0a3 → sovereign-0.29.1}/src/sovereign/utils/crypto/suites/disabled_cipher.py
RENAMED
|
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
|