sovereign 0.29.0__tar.gz → 0.29.0a3__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.

Files changed (64) hide show
  1. {sovereign-0.29.0 → sovereign-0.29.0a3}/PKG-INFO +2 -3
  2. {sovereign-0.29.0 → sovereign-0.29.0a3}/pyproject.toml +2 -2
  3. {sovereign-0.29.0 → sovereign-0.29.0a3}/src/sovereign/discovery.py +16 -8
  4. {sovereign-0.29.0 → sovereign-0.29.0a3}/src/sovereign/dynamic_config/__init__.py +22 -25
  5. {sovereign-0.29.0 → sovereign-0.29.0a3}/src/sovereign/schemas.py +0 -1
  6. {sovereign-0.29.0 → sovereign-0.29.0a3}/src/sovereign/views/discovery.py +15 -18
  7. {sovereign-0.29.0 → sovereign-0.29.0a3}/LICENSE.txt +0 -0
  8. {sovereign-0.29.0 → sovereign-0.29.0a3}/README.md +0 -0
  9. {sovereign-0.29.0 → sovereign-0.29.0a3}/src/sovereign/__init__.py +0 -0
  10. {sovereign-0.29.0 → sovereign-0.29.0a3}/src/sovereign/app.py +0 -0
  11. {sovereign-0.29.0 → sovereign-0.29.0a3}/src/sovereign/configuration.py +0 -0
  12. {sovereign-0.29.0 → sovereign-0.29.0a3}/src/sovereign/constants.py +0 -0
  13. {sovereign-0.29.0 → sovereign-0.29.0a3}/src/sovereign/context.py +0 -0
  14. {sovereign-0.29.0 → sovereign-0.29.0a3}/src/sovereign/dynamic_config/deser.py +0 -0
  15. {sovereign-0.29.0 → sovereign-0.29.0a3}/src/sovereign/dynamic_config/loaders.py +0 -0
  16. {sovereign-0.29.0 → sovereign-0.29.0a3}/src/sovereign/error_info.py +0 -0
  17. {sovereign-0.29.0 → sovereign-0.29.0a3}/src/sovereign/logging/access_logger.py +0 -0
  18. {sovereign-0.29.0 → sovereign-0.29.0a3}/src/sovereign/logging/application_logger.py +0 -0
  19. {sovereign-0.29.0 → sovereign-0.29.0a3}/src/sovereign/logging/base_logger.py +0 -0
  20. {sovereign-0.29.0 → sovereign-0.29.0a3}/src/sovereign/logging/bootstrapper.py +0 -0
  21. {sovereign-0.29.0 → sovereign-0.29.0a3}/src/sovereign/logging/types.py +0 -0
  22. {sovereign-0.29.0 → sovereign-0.29.0a3}/src/sovereign/middlewares.py +0 -0
  23. {sovereign-0.29.0 → sovereign-0.29.0a3}/src/sovereign/modifiers/__init__.py +0 -0
  24. {sovereign-0.29.0 → sovereign-0.29.0a3}/src/sovereign/modifiers/lib.py +0 -0
  25. {sovereign-0.29.0 → sovereign-0.29.0a3}/src/sovereign/response_class.py +0 -0
  26. {sovereign-0.29.0 → sovereign-0.29.0a3}/src/sovereign/server.py +0 -0
  27. {sovereign-0.29.0 → sovereign-0.29.0a3}/src/sovereign/sources/__init__.py +0 -0
  28. {sovereign-0.29.0 → sovereign-0.29.0a3}/src/sovereign/sources/file.py +0 -0
  29. {sovereign-0.29.0 → sovereign-0.29.0a3}/src/sovereign/sources/inline.py +0 -0
  30. {sovereign-0.29.0 → sovereign-0.29.0a3}/src/sovereign/sources/lib.py +0 -0
  31. {sovereign-0.29.0 → sovereign-0.29.0a3}/src/sovereign/sources/poller.py +0 -0
  32. {sovereign-0.29.0 → sovereign-0.29.0a3}/src/sovereign/static/sass/style.scss +0 -0
  33. {sovereign-0.29.0 → sovereign-0.29.0a3}/src/sovereign/static/style.css +0 -0
  34. {sovereign-0.29.0 → sovereign-0.29.0a3}/src/sovereign/statistics.py +0 -0
  35. {sovereign-0.29.0 → sovereign-0.29.0a3}/src/sovereign/templates/base.html +0 -0
  36. {sovereign-0.29.0 → sovereign-0.29.0a3}/src/sovereign/templates/err.html +0 -0
  37. {sovereign-0.29.0 → sovereign-0.29.0a3}/src/sovereign/templates/resources.html +0 -0
  38. {sovereign-0.29.0 → sovereign-0.29.0a3}/src/sovereign/templates/ul_filter.html +0 -0
  39. {sovereign-0.29.0 → sovereign-0.29.0a3}/src/sovereign/testing/loaders.py +0 -0
  40. {sovereign-0.29.0 → sovereign-0.29.0a3}/src/sovereign/testing/modifiers.py +0 -0
  41. {sovereign-0.29.0 → sovereign-0.29.0a3}/src/sovereign/tracing.py +0 -0
  42. {sovereign-0.29.0 → sovereign-0.29.0a3}/src/sovereign/utils/__init__.py +0 -0
  43. {sovereign-0.29.0 → sovereign-0.29.0a3}/src/sovereign/utils/auth.py +0 -0
  44. {sovereign-0.29.0 → sovereign-0.29.0a3}/src/sovereign/utils/crypto/__init__.py +0 -0
  45. {sovereign-0.29.0 → sovereign-0.29.0a3}/src/sovereign/utils/crypto/crypto.py +0 -0
  46. {sovereign-0.29.0 → sovereign-0.29.0a3}/src/sovereign/utils/crypto/suites/__init__.py +0 -0
  47. {sovereign-0.29.0 → sovereign-0.29.0a3}/src/sovereign/utils/crypto/suites/aes_gcm_cipher.py +0 -0
  48. {sovereign-0.29.0 → sovereign-0.29.0a3}/src/sovereign/utils/crypto/suites/base_cipher.py +0 -0
  49. {sovereign-0.29.0 → sovereign-0.29.0a3}/src/sovereign/utils/crypto/suites/disabled_cipher.py +0 -0
  50. {sovereign-0.29.0 → sovereign-0.29.0a3}/src/sovereign/utils/crypto/suites/fernet_cipher.py +0 -0
  51. {sovereign-0.29.0 → sovereign-0.29.0a3}/src/sovereign/utils/dictupdate.py +0 -0
  52. {sovereign-0.29.0 → sovereign-0.29.0a3}/src/sovereign/utils/eds.py +0 -0
  53. {sovereign-0.29.0 → sovereign-0.29.0a3}/src/sovereign/utils/entry_point_loader.py +0 -0
  54. {sovereign-0.29.0 → sovereign-0.29.0a3}/src/sovereign/utils/mock.py +0 -0
  55. {sovereign-0.29.0 → sovereign-0.29.0a3}/src/sovereign/utils/resources.py +0 -0
  56. {sovereign-0.29.0 → sovereign-0.29.0a3}/src/sovereign/utils/templates.py +0 -0
  57. {sovereign-0.29.0 → sovereign-0.29.0a3}/src/sovereign/utils/timer.py +0 -0
  58. {sovereign-0.29.0 → sovereign-0.29.0a3}/src/sovereign/utils/version_info.py +0 -0
  59. {sovereign-0.29.0 → sovereign-0.29.0a3}/src/sovereign/utils/weighted_clusters.py +0 -0
  60. {sovereign-0.29.0 → sovereign-0.29.0a3}/src/sovereign/views/__init__.py +0 -0
  61. {sovereign-0.29.0 → sovereign-0.29.0a3}/src/sovereign/views/admin.py +0 -0
  62. {sovereign-0.29.0 → sovereign-0.29.0a3}/src/sovereign/views/crypto.py +0 -0
  63. {sovereign-0.29.0 → sovereign-0.29.0a3}/src/sovereign/views/healthchecks.py +0 -0
  64. {sovereign-0.29.0 → sovereign-0.29.0a3}/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.0
3
+ Version: 0.29.0a3
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,7 +18,6 @@ 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
22
21
  Classifier: Programming Language :: Python :: 3.10
23
22
  Classifier: Programming Language :: Python :: 3.8
24
23
  Classifier: Programming Language :: Python :: 3.9
@@ -38,7 +37,7 @@ Requires-Dist: cachelib (>=0.10.2,<0.11.0)
38
37
  Requires-Dist: cachetools (>=5.3.2,<6.0.0)
39
38
  Requires-Dist: cashews[redis] (>=6.3.0,<7.0.0) ; extra == "caching"
40
39
  Requires-Dist: croniter (>=1.4.1,<2.0.0)
41
- Requires-Dist: cryptography (>=43.0.1,<44.0.0)
40
+ Requires-Dist: cryptography (>=42.0.5,<43.0.0)
42
41
  Requires-Dist: datadog (>=0.47.0,<0.48.0) ; extra == "statsd"
43
42
  Requires-Dist: fastapi (>=0.110.0,<0.111.0)
44
43
  Requires-Dist: glom (>=23.3.0,<24.0.0)
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "sovereign"
3
- version = "0.29.0"
3
+ version = "0.29.0a3"
4
4
  description = "Envoy Proxy control-plane written in Python"
5
5
  license = "Apache-2.0"
6
6
  packages = [
@@ -73,7 +73,7 @@ Jinja2 = "^3.1.2"
73
73
  structlog = "^23.1.0"
74
74
  cachelib = "^0.10.2"
75
75
  glom = "^23.3.0"
76
- cryptography = "^43.0.1"
76
+ cryptography = "^42.0.5"
77
77
  fastapi = "^0.110.0"
78
78
  uvloop = "^0.19.0"
79
79
  sentry-sdk = "^1.23.1"
@@ -23,6 +23,7 @@ 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
26
27
 
27
28
 
28
29
  try:
@@ -105,7 +106,8 @@ def response(request: DiscoveryRequest, xds_type: str) -> ProcessedTemplate:
105
106
  resource_names=request.resources,
106
107
  **template_context.get_context(request, template),
107
108
  )
108
- content = template(**context)
109
+ with Tracer("template rendering"):
110
+ content = template(**context)
109
111
 
110
112
  # Deserialize YAML output from Jinja2
111
113
  if not template.is_python_source:
@@ -116,13 +118,19 @@ def response(request: DiscoveryRequest, xds_type: str) -> ProcessedTemplate:
116
118
  content = deserialize_config(content)
117
119
 
118
120
  # Early return if the template is identical
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)
121
+ with Tracer("nested test"):
122
+ with Tracer("hashing"):
123
+ config_version = compute_hash(content)
124
+ if (
125
+ config_version == request.version_info
126
+ and not config.discovery_cache.enabled
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)
126
134
  return ProcessedTemplate(resources=resources, version_info=config_version)
127
135
 
128
136
 
@@ -1,4 +1,3 @@
1
- import inspect
2
1
  from typing import Any, Dict, Optional
3
2
 
4
3
  from pydantic import BaseModel
@@ -14,20 +13,20 @@ class Loadable(BaseModel):
14
13
  serialization: Optional[str] = None
15
14
 
16
15
  def load(self, default: Any = None) -> Any:
17
- if self.protocol not in LOADERS:
16
+ if self.protocol not in custom_loaders:
18
17
  raise KeyError(
19
- f"Could not find CustomLoader {self.protocol}. Available: {LOADERS}"
18
+ f"Could not find CustomLoader {self.protocol}. Available: {custom_loaders}"
20
19
  )
21
- loader_ = LOADERS[self.protocol]
20
+ loader_ = custom_loaders[self.protocol]
22
21
 
23
22
  ser = self.serialization
24
23
  if ser is None:
25
24
  ser = loader_.default_deser
26
- if ser not in DESERIALIZERS:
25
+ if ser not in deserializers:
27
26
  raise KeyError(
28
- f"Could not find Deserializer {ser}. Available: {DESERIALIZERS}"
27
+ f"Could not find Deserializer {ser}. Available: {deserializers}"
29
28
  )
30
- deserializer = DESERIALIZERS[ser]
29
+ deserializer = deserializers[ser]
31
30
 
32
31
  try:
33
32
  data = loader_.load(self.path)
@@ -64,25 +63,23 @@ class Loadable(BaseModel):
64
63
  )
65
64
 
66
65
 
67
- LOADERS: Dict[str, CustomLoader] = {}
68
- for entry_point in EntryPointLoader("loaders").groups["loaders"]:
66
+ custom_loaders: Dict[str, CustomLoader] = {}
67
+ loader_entry_point = EntryPointLoader("loaders")
68
+ for entry_point in loader_entry_point.groups["loaders"]:
69
69
  custom_loader = entry_point.load()
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
70
+ try:
71
+ func = custom_loader()
72
+ except AttributeError:
73
+ raise AttributeError("CustomLoader does not implement .load()")
74
+ custom_loaders[entry_point.name] = func
77
75
 
78
76
 
79
- DESERIALIZERS: Dict[str, ConfigDeserializer] = {}
80
- for entry_point in EntryPointLoader("deserializers").groups["deserializers"]:
77
+ deserializers: Dict[str, ConfigDeserializer] = {}
78
+ deser_entry_point = EntryPointLoader("deserializers")
79
+ for entry_point in deser_entry_point.groups["deserializers"]:
81
80
  deserializer = entry_point.load()
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
81
+ try:
82
+ func = deserializer()
83
+ except AttributeError:
84
+ raise AttributeError("Deserializer does not implement .deserialize()")
85
+ deserializers[entry_point.name] = func
@@ -112,7 +112,6 @@ 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] = {}
116
115
 
117
116
  @model_validator(mode="after")
118
117
  def set_default_protocol(self) -> Self:
@@ -117,24 +117,21 @@ 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
- 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
-
120
+ cache_key = compute_hash(
121
+ [
122
+ api_version,
123
+ resource_type,
124
+ req.envoy_version,
125
+ req.resource_names,
126
+ req.desired_controlplane,
127
+ req.hide_private_keys,
128
+ req.type_url,
129
+ req.node.cluster,
130
+ req.node.locality,
131
+ req.node.metadata.get("auth", None),
132
+ req.node.metadata.get("num_cpus", None),
133
+ ]
134
+ )
138
135
  if template := await cache.get(key=cache_key, default=None):
139
136
  logs.access_logger.queue_log_fields(CACHE_XDS_HIT=True)
140
137
  return template # type: ignore[no-any-return]
File without changes
File without changes