sovereign 1.0.0b125__py3-none-any.whl → 1.0.0b127__py3-none-any.whl
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/rendering.py +46 -29
- sovereign/static/darkmode.js +51 -0
- sovereign/static/node_expression.js +26 -0
- sovereign/static/resources.css +246 -0
- sovereign/static/resources.js +642 -0
- sovereign/static/sass/style.scss +24 -18
- sovereign/templates/base.html +59 -46
- sovereign/templates/resources.html +40 -835
- sovereign/utils/mock.py +6 -2
- sovereign/views/interface.py +34 -15
- sovereign/worker.py +15 -28
- {sovereign-1.0.0b125.dist-info → sovereign-1.0.0b127.dist-info}/METADATA +1 -1
- {sovereign-1.0.0b125.dist-info → sovereign-1.0.0b127.dist-info}/RECORD +16 -14
- sovereign/static/style.css +0 -13553
- {sovereign-1.0.0b125.dist-info → sovereign-1.0.0b127.dist-info}/LICENSE.txt +0 -0
- {sovereign-1.0.0b125.dist-info → sovereign-1.0.0b127.dist-info}/WHEEL +0 -0
- {sovereign-1.0.0b125.dist-info → sovereign-1.0.0b127.dist-info}/entry_points.txt +0 -0
sovereign/utils/mock.py
CHANGED
|
@@ -7,6 +7,10 @@ from sovereign.schemas import DiscoveryRequest, Node, Locality, Status
|
|
|
7
7
|
scrub = re.compile(r"[^a-zA-Z_\.]")
|
|
8
8
|
|
|
9
9
|
|
|
10
|
+
class NodeExpressionError(Exception):
|
|
11
|
+
pass
|
|
12
|
+
|
|
13
|
+
|
|
10
14
|
def mock_discovery_request(
|
|
11
15
|
api_version: Optional[str] = "V3",
|
|
12
16
|
resource_type: Optional[str] = None,
|
|
@@ -54,7 +58,7 @@ def set_node_expressions(node, expressions):
|
|
|
54
58
|
field, value = re.split(r"\s*=\s*", expr, maxsplit=1)
|
|
55
59
|
value = f'"{value}"'
|
|
56
60
|
except ValueError:
|
|
57
|
-
raise
|
|
61
|
+
raise NodeExpressionError(f"Invalid node filter format: {expr}")
|
|
58
62
|
|
|
59
63
|
field = scrub.sub("", field)
|
|
60
64
|
parts = field.split(".")
|
|
@@ -62,7 +66,7 @@ def set_node_expressions(node, expressions):
|
|
|
62
66
|
try:
|
|
63
67
|
value = ast.literal_eval(value)
|
|
64
68
|
except Exception as e:
|
|
65
|
-
raise
|
|
69
|
+
raise NodeExpressionError(f"Invalid node filter value: {value}") from e
|
|
66
70
|
|
|
67
71
|
current = node
|
|
68
72
|
for part in parts[:-1]:
|
sovereign/views/interface.py
CHANGED
|
@@ -7,10 +7,10 @@ from fastapi.encoders import jsonable_encoder
|
|
|
7
7
|
from fastapi.requests import Request
|
|
8
8
|
from fastapi.responses import HTMLResponse, JSONResponse, Response
|
|
9
9
|
|
|
10
|
-
from sovereign import html_templates, cache
|
|
10
|
+
from sovereign import html_templates, cache, __version__
|
|
11
11
|
from sovereign.schemas import DiscoveryTypes, XDS_TEMPLATES
|
|
12
12
|
from sovereign.response_class import json_response_class
|
|
13
|
-
from sovereign.utils.mock import mock_discovery_request
|
|
13
|
+
from sovereign.utils.mock import NodeExpressionError, mock_discovery_request
|
|
14
14
|
|
|
15
15
|
router = APIRouter()
|
|
16
16
|
|
|
@@ -25,9 +25,7 @@ async def ui_main(request: Request) -> HTMLResponse:
|
|
|
25
25
|
request=request,
|
|
26
26
|
name="base.html",
|
|
27
27
|
media_type="text/html",
|
|
28
|
-
context={
|
|
29
|
-
"all_types": all_types,
|
|
30
|
-
},
|
|
28
|
+
context={"all_types": all_types, "sovereign_version": __version__},
|
|
31
29
|
)
|
|
32
30
|
except IndexError:
|
|
33
31
|
return html_templates.TemplateResponse(
|
|
@@ -36,9 +34,12 @@ async def ui_main(request: Request) -> HTMLResponse:
|
|
|
36
34
|
media_type="text/html",
|
|
37
35
|
context={
|
|
38
36
|
"title": "No resource types configured",
|
|
39
|
-
"message":
|
|
40
|
-
|
|
37
|
+
"message": (
|
|
38
|
+
"A template should be defined for every resource "
|
|
39
|
+
"type that you want your envoy proxies to discover."
|
|
40
|
+
),
|
|
41
41
|
"doc_link": "https://developer.atlassian.com/platform/sovereign/tutorial/templates/#templates",
|
|
42
|
+
"sovereign_version": __version__,
|
|
42
43
|
},
|
|
43
44
|
)
|
|
44
45
|
|
|
@@ -63,18 +64,31 @@ async def resources(
|
|
|
63
64
|
) -> HTMLResponse:
|
|
64
65
|
ret: Dict[str, List[Dict[str, Any]]] = defaultdict(list)
|
|
65
66
|
response = None
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
67
|
+
try:
|
|
68
|
+
mock_request = mock_discovery_request(
|
|
69
|
+
api_version,
|
|
70
|
+
xds_type,
|
|
71
|
+
version=envoy_version,
|
|
72
|
+
region=region,
|
|
73
|
+
expressions=node_expression.split(),
|
|
74
|
+
)
|
|
75
|
+
clear_cookie = False
|
|
76
|
+
error = None
|
|
77
|
+
except NodeExpressionError as e:
|
|
78
|
+
mock_request = mock_discovery_request(
|
|
79
|
+
api_version,
|
|
80
|
+
xds_type,
|
|
81
|
+
version=envoy_version,
|
|
82
|
+
region=region,
|
|
83
|
+
)
|
|
84
|
+
clear_cookie = True
|
|
85
|
+
error = str(e)
|
|
86
|
+
|
|
73
87
|
response = await cache.blocking_read(mock_request)
|
|
74
88
|
if response:
|
|
75
89
|
ret["resources"] = json.loads(response.text).get("resources", [])
|
|
76
90
|
|
|
77
|
-
|
|
91
|
+
resp = html_templates.TemplateResponse(
|
|
78
92
|
request=request,
|
|
79
93
|
name="resources.html",
|
|
80
94
|
media_type="text/html",
|
|
@@ -87,8 +101,13 @@ async def resources(
|
|
|
87
101
|
"all_types": all_types,
|
|
88
102
|
"version": envoy_version,
|
|
89
103
|
"available_versions": list(XDS_TEMPLATES.keys()),
|
|
104
|
+
"error": error,
|
|
105
|
+
"sovereign_version": __version__,
|
|
90
106
|
},
|
|
91
107
|
)
|
|
108
|
+
if clear_cookie:
|
|
109
|
+
resp.delete_cookie("node_expression", path="/ui/resources/")
|
|
110
|
+
return resp
|
|
92
111
|
|
|
93
112
|
|
|
94
113
|
@router.get(
|
sovereign/worker.py
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import asyncio
|
|
2
2
|
from typing import Optional, final
|
|
3
|
-
from multiprocessing import Process, cpu_count
|
|
4
3
|
from contextlib import asynccontextmanager
|
|
5
4
|
|
|
6
5
|
from fastapi import FastAPI, Body
|
|
@@ -61,7 +60,6 @@ class RenderQueue:
|
|
|
61
60
|
|
|
62
61
|
|
|
63
62
|
ONDEMAND = RenderQueue()
|
|
64
|
-
RENDER_SEMAPHORE = asyncio.Semaphore(cpu_count())
|
|
65
63
|
|
|
66
64
|
|
|
67
65
|
def hidden_field(*args, **kwargs):
|
|
@@ -99,42 +97,23 @@ if config.sources is not None:
|
|
|
99
97
|
context_middleware.append(poller.add_to_context)
|
|
100
98
|
|
|
101
99
|
|
|
102
|
-
def render(job: rendering.RenderJob):
|
|
103
|
-
log.debug(f"Spawning render process for {job.id}")
|
|
104
|
-
process = Process(target=rendering.generate, args=[job])
|
|
105
|
-
process.start()
|
|
106
|
-
return process
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
async def submit_render(job: rendering.RenderJob):
|
|
110
|
-
async with RENDER_SEMAPHORE:
|
|
111
|
-
process = render(job)
|
|
112
|
-
# Wait for the process to complete to ensure semaphore is held
|
|
113
|
-
# until the actual rendering work is done
|
|
114
|
-
await asyncio.get_event_loop().run_in_executor(None, process.join)
|
|
115
|
-
|
|
116
|
-
|
|
117
100
|
async def render_on_event():
|
|
118
101
|
while True:
|
|
119
102
|
# block forever until new context arrives
|
|
120
|
-
await NEW_CONTEXT.wait()
|
|
103
|
+
_ = await NEW_CONTEXT.wait()
|
|
121
104
|
log.debug("New context detected, re-rendering templates")
|
|
122
105
|
try:
|
|
123
106
|
if registered := cache.clients():
|
|
124
107
|
log.debug("New context detected, re-rendering templates")
|
|
125
|
-
|
|
126
|
-
|
|
108
|
+
size = len(registered)
|
|
109
|
+
stats.increment("template.render_on_event", tags=[f"batch_size:{size}"])
|
|
110
|
+
for client, request in registered:
|
|
111
|
+
job = rendering.RenderJob(
|
|
127
112
|
id=client,
|
|
128
113
|
request=request,
|
|
129
114
|
context=template_context.get_context(request),
|
|
130
115
|
)
|
|
131
|
-
|
|
132
|
-
]
|
|
133
|
-
tasks = [submit_render(job) for job in jobs]
|
|
134
|
-
size = len(tasks)
|
|
135
|
-
stats.increment("template.render_on_event", tags=[f"batch_size:{size}"])
|
|
136
|
-
await asyncio.gather(*tasks)
|
|
137
|
-
log.debug(f"Completed rendering {size} jobs")
|
|
116
|
+
job.spawn()
|
|
138
117
|
finally:
|
|
139
118
|
NEW_CONTEXT.clear()
|
|
140
119
|
|
|
@@ -147,16 +126,24 @@ async def render_on_demand():
|
|
|
147
126
|
job = rendering.RenderJob(
|
|
148
127
|
id=id, request=request, context=template_context.get_context(request)
|
|
149
128
|
)
|
|
150
|
-
|
|
129
|
+
job.spawn()
|
|
151
130
|
ONDEMAND.task_done()
|
|
152
131
|
|
|
153
132
|
|
|
133
|
+
async def monitor_render_queue():
|
|
134
|
+
"""Periodically report render queue size metrics"""
|
|
135
|
+
while True:
|
|
136
|
+
await asyncio.sleep(10)
|
|
137
|
+
stats.gauge("template.on_demand_queue_size", ONDEMAND._queue.qsize())
|
|
138
|
+
|
|
139
|
+
|
|
154
140
|
@asynccontextmanager
|
|
155
141
|
async def lifespan(_: FastAPI):
|
|
156
142
|
# Template Rendering
|
|
157
143
|
log.debug("Starting rendering loops")
|
|
158
144
|
asyncio.create_task(render_on_event())
|
|
159
145
|
asyncio.create_task(render_on_demand())
|
|
146
|
+
asyncio.create_task(monitor_render_queue())
|
|
160
147
|
|
|
161
148
|
# Template context
|
|
162
149
|
log.debug("Starting context loop")
|
|
@@ -15,7 +15,7 @@ sovereign/logging/types.py,sha256=rGqJAEVvgvzHy4aPfvEH6yQ-yblXNkEcWG7G8l9ALEA,28
|
|
|
15
15
|
sovereign/middlewares.py,sha256=6w4JpvtNGvQA4rocQsYQjuu-ckhpKT6gKYA16T-kiqA,3082
|
|
16
16
|
sovereign/modifiers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
17
17
|
sovereign/modifiers/lib.py,sha256=Cx0VrpTKbSjb3YmHyG4Jy6YEaPlrwpeqNaom3zu1_hw,2885
|
|
18
|
-
sovereign/rendering.py,sha256=
|
|
18
|
+
sovereign/rendering.py,sha256=hxlu_K7h1fVNYRLVA4-YM_KY4rhaEOzHq-4dCVwgdWE,5688
|
|
19
19
|
sovereign/response_class.py,sha256=beMAFV-4L6DwyWzJzy71GkEW4gb7fzH1jd8-Tul13cU,427
|
|
20
20
|
sovereign/schemas.py,sha256=Jf_w2mAX1b31eCAtJuxSZgy9KMVRKntmnEbbCZGZCxQ,38067
|
|
21
21
|
sovereign/server.py,sha256=uviXN0mX-Wbhv36xjWlHiybzIlZrJsCwRf4xyRnibXQ,2970
|
|
@@ -24,14 +24,16 @@ sovereign/sources/file.py,sha256=prUThsDCSPNwZaZpkKXhAm-GVRZWbBoGKGU0It4HHXs,690
|
|
|
24
24
|
sovereign/sources/inline.py,sha256=pP77m7bHjqE3sSoqZthcuw1ARVMf9gooVwbz4B8OAek,1003
|
|
25
25
|
sovereign/sources/lib.py,sha256=0hk_G6mKJrB65WokVZnqF5kdJ3vsQZMNPuJqJO0mBsI,1031
|
|
26
26
|
sovereign/sources/poller.py,sha256=zpNUhQft-NoJbbxO1kCFp6jJSRSkBmf181xodnF_TiI,18469
|
|
27
|
-
sovereign/static/
|
|
27
|
+
sovereign/static/darkmode.js,sha256=3ip-eKGctDvNhN7UgmaHhzls7r5qIY-Jvh2EpefHbQ0,1449
|
|
28
|
+
sovereign/static/node_expression.js,sha256=GKxKTSRc_96IbL3H4L_31ueJFXq4N7scm5R1RNqxP24,1489
|
|
28
29
|
sovereign/static/panel.js,sha256=i5mGExjv-I4Gtt9dQiTyFwPZa8pg5rXeuTeidXNUiTE,2695
|
|
29
|
-
sovereign/static/
|
|
30
|
-
sovereign/static/
|
|
30
|
+
sovereign/static/resources.css,sha256=Rt_ir_FkoI-VIAOqPhk0vILy8kB2egAYbQU26SOs1io,4500
|
|
31
|
+
sovereign/static/resources.js,sha256=-TaXZ6tohyKA1SkX5YwrTcV5M8mOZ68cvEXpvZWznTo,24506
|
|
32
|
+
sovereign/static/sass/style.scss,sha256=LdGXXuHi_tyMc7XhijIOrlIxyfLt827AAs2Z7DYpFpg,990
|
|
31
33
|
sovereign/statistics.py,sha256=QhDB0bs5kZDGjy248AOIv_bzNbz_c2U7xmJ0hoUNOmw,2033
|
|
32
|
-
sovereign/templates/base.html,sha256=
|
|
34
|
+
sovereign/templates/base.html,sha256=MMhhvvClTixKibYfhXm8Ezx6ttu6Sqki44niciCPMO4,2990
|
|
33
35
|
sovereign/templates/err.html,sha256=a3cEzOqyqWOIe3YxfTEjkxbTfxBxq1knD6GwzEFljfs,603
|
|
34
|
-
sovereign/templates/resources.html,sha256=
|
|
36
|
+
sovereign/templates/resources.html,sha256=5MfXHW8s3tAWda66Q48zVgDhZNLwHGsdCKkKHLZohIs,10420
|
|
35
37
|
sovereign/testing/loaders.py,sha256=mcmErhI9ZkJUBZl8jv2qP-PCBRFeAIgyBFlfCgU4Vvk,199
|
|
36
38
|
sovereign/testing/modifiers.py,sha256=7_c2hWXn_sYJ6997N1_uSWtClOikcOzu1yRCY56-l-4,361
|
|
37
39
|
sovereign/tracing.py,sha256=Xo3npgh6yesACSlynv9j6qnXxvYEBzXv5LL4Zkc1QDw,2446
|
|
@@ -47,7 +49,7 @@ sovereign/utils/crypto/suites/fernet_cipher.py,sha256=rP6M5ys1vctyadOxDGNFoyerWP
|
|
|
47
49
|
sovereign/utils/dictupdate.py,sha256=Bi7QaC7en-k3EOepwNJqpOKRNBgp6ZsBZVOvH_0nMtc,2558
|
|
48
50
|
sovereign/utils/eds.py,sha256=sCEDj1y-0Crs40cHZLiPGVb7ed1f8vFqgHLY5R2LMbw,4377
|
|
49
51
|
sovereign/utils/entry_point_loader.py,sha256=BEVodk-um70RvT1nSOu_IB-hr1K4ppthXod0VZEiZJ8,526
|
|
50
|
-
sovereign/utils/mock.py,sha256=
|
|
52
|
+
sovereign/utils/mock.py,sha256=j9zaLT39MSuF7vGKvhGRJtrXSTU7WFB1rirUWWBGYm4,2388
|
|
51
53
|
sovereign/utils/resources.py,sha256=rPrWgcIt4YhV-Dz88_kr5WrQNiSKt-jTlOZ8EIJxJx8,472
|
|
52
54
|
sovereign/utils/templates.py,sha256=FE_H_oE7VrS3X_VN1z_g10b9-rpmi1_gL-cMxi5XtXU,1057
|
|
53
55
|
sovereign/utils/timer.py,sha256=_dUtEasj0BKbWYuQ_T3HFIyjurXXj-La-dNSMAwKMSo,795
|
|
@@ -58,10 +60,10 @@ sovereign/views/api.py,sha256=jKVjSvi0Tr1HHix3hc0H8yGZoyDind2sJ4w7a4pJvy0,2168
|
|
|
58
60
|
sovereign/views/crypto.py,sha256=7y0eHWtt-bbr2CwHEkH7odPaJ1IEviU-71U-MYJD0Kc,3360
|
|
59
61
|
sovereign/views/discovery.py,sha256=B_D1ckfbN1dSKBvuFCTyfB79GUUriCADTB53OwZ8D4Q,2409
|
|
60
62
|
sovereign/views/healthchecks.py,sha256=TaXbxkX679jyQ8v5FxtBa2Qa0Z7KuqQ10WgAqfuVGUc,1743
|
|
61
|
-
sovereign/views/interface.py,sha256=
|
|
62
|
-
sovereign/worker.py,sha256=
|
|
63
|
-
sovereign-1.0.
|
|
64
|
-
sovereign-1.0.
|
|
65
|
-
sovereign-1.0.
|
|
66
|
-
sovereign-1.0.
|
|
67
|
-
sovereign-1.0.
|
|
63
|
+
sovereign/views/interface.py,sha256=o6DaOqoh2M09_SsZrCOxr9rCVxMUZHXRXj4TNq800Ho,6999
|
|
64
|
+
sovereign/worker.py,sha256=Y4le54cZU1Enj8scu1G1sM_KPVPUmZ7vmTuxpd59X2Q,5855
|
|
65
|
+
sovereign-1.0.0b127.dist-info/LICENSE.txt,sha256=2X125zvAb9AYLjCgdMDQZuufhm0kwcg31A8pGKj_-VY,560
|
|
66
|
+
sovereign-1.0.0b127.dist-info/METADATA,sha256=oU2lYwJzDy4asWnC88rWcstr-lrjycu0Os6jtrQPAdE,6304
|
|
67
|
+
sovereign-1.0.0b127.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
|
|
68
|
+
sovereign-1.0.0b127.dist-info/entry_points.txt,sha256=VKJdnnN_HNL8xYQMXsFXfFmN6QkdXMEk5S964avxQJI,1404
|
|
69
|
+
sovereign-1.0.0b127.dist-info/RECORD,,
|