avtomatika 1.0b1__py3-none-any.whl → 1.0b2__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.
- avtomatika/api.html +14 -0
- avtomatika/blueprint.py +8 -1
- avtomatika/engine.py +13 -0
- avtomatika/security.py +5 -3
- avtomatika/worker_config_loader.py +4 -1
- {avtomatika-1.0b1.dist-info → avtomatika-1.0b2.dist-info}/METADATA +9 -2
- {avtomatika-1.0b1.dist-info → avtomatika-1.0b2.dist-info}/RECORD +10 -10
- {avtomatika-1.0b1.dist-info → avtomatika-1.0b2.dist-info}/WHEEL +0 -0
- {avtomatika-1.0b1.dist-info → avtomatika-1.0b2.dist-info}/licenses/LICENSE +0 -0
- {avtomatika-1.0b1.dist-info → avtomatika-1.0b2.dist-info}/top_level.txt +0 -0
avtomatika/api.html
CHANGED
|
@@ -305,6 +305,20 @@
|
|
|
305
305
|
responses: [
|
|
306
306
|
{ code: '200 OK', description: 'Successful response.', body: "{...}" }
|
|
307
307
|
]
|
|
308
|
+
},
|
|
309
|
+
{
|
|
310
|
+
id: 'post-reload-worker-configs',
|
|
311
|
+
name: 'Reload Worker Configurations',
|
|
312
|
+
method: 'POST',
|
|
313
|
+
path: '/api/{version}/admin/reload-workers',
|
|
314
|
+
description: 'Triggers a dynamic reload of worker configurations from the TOML file. Requires client authentication.',
|
|
315
|
+
parameters: [
|
|
316
|
+
{ name: 'version', type: 'string', description: 'API Version', example: 'v1' }
|
|
317
|
+
],
|
|
318
|
+
request: { body: null },
|
|
319
|
+
responses: [
|
|
320
|
+
{ code: '200 OK', description: 'Successful response.', body: { "status": "worker_configs_reloaded" } }
|
|
321
|
+
]
|
|
308
322
|
}
|
|
309
323
|
]
|
|
310
324
|
},
|
avtomatika/blueprint.py
CHANGED
|
@@ -178,10 +178,13 @@ class StateMachineBlueprint:
|
|
|
178
178
|
def render_graph(self, output_filename: Optional[str] = None, output_format: str = "png"):
|
|
179
179
|
import ast
|
|
180
180
|
import inspect
|
|
181
|
+
import logging
|
|
181
182
|
import textwrap
|
|
182
183
|
|
|
183
184
|
from graphviz import Digraph # type: ignore[import]
|
|
184
185
|
|
|
186
|
+
logger = logging.getLogger(__name__)
|
|
187
|
+
|
|
185
188
|
dot = Digraph(comment=f"State Machine for {self.name}")
|
|
186
189
|
dot.attr("node", shape="box", style="rounded")
|
|
187
190
|
all_handlers = list(self.handlers.items()) + [(ch.state, ch.func) for ch in self.conditional_handlers]
|
|
@@ -222,7 +225,11 @@ class StateMachineBlueprint:
|
|
|
222
225
|
value,
|
|
223
226
|
label=f"on {key}",
|
|
224
227
|
)
|
|
225
|
-
except (TypeError, OSError):
|
|
228
|
+
except (TypeError, OSError) as e:
|
|
229
|
+
logger.warning(
|
|
230
|
+
f"Could not parse handler '{handler_func.__name__}' for state '{handler_state}'. "
|
|
231
|
+
f"Graph may be incomplete. Error: {e}"
|
|
232
|
+
)
|
|
226
233
|
pass
|
|
227
234
|
for state in states:
|
|
228
235
|
dot.node(state, state)
|
avtomatika/engine.py
CHANGED
|
@@ -584,6 +584,18 @@ class OrchestratorEngine:
|
|
|
584
584
|
jobs = await self.storage.get_quarantined_jobs()
|
|
585
585
|
return web.json_response(jobs)
|
|
586
586
|
|
|
587
|
+
async def _reload_worker_configs_handler(self, request: web.Request) -> web.Response:
|
|
588
|
+
"""Handles the dynamic reloading of worker configurations."""
|
|
589
|
+
logger.info("Received request to reload worker configurations.")
|
|
590
|
+
if not self.config.WORKERS_CONFIG_PATH:
|
|
591
|
+
return web.json_response(
|
|
592
|
+
{"error": "WORKERS_CONFIG_PATH is not set, cannot reload configs."},
|
|
593
|
+
status=400,
|
|
594
|
+
)
|
|
595
|
+
|
|
596
|
+
await load_worker_configs_to_redis(self.storage, self.config.WORKERS_CONFIG_PATH)
|
|
597
|
+
return web.json_response({"status": "worker_configs_reloaded"})
|
|
598
|
+
|
|
587
599
|
async def _flush_db_handler(self, request: web.Request) -> web.Response:
|
|
588
600
|
logger.warning("Received request to flush the database.")
|
|
589
601
|
await self.storage.flush_all()
|
|
@@ -643,6 +655,7 @@ class OrchestratorEngine:
|
|
|
643
655
|
app.router.add_get("/workers", self._get_workers_handler)
|
|
644
656
|
app.router.add_get("/jobs", self._get_jobs_handler)
|
|
645
657
|
app.router.add_get("/dashboard", self._get_dashboard_handler)
|
|
658
|
+
app.router.add_post("/admin/reload-workers", self._reload_worker_configs_handler)
|
|
646
659
|
|
|
647
660
|
if has_unversioned_routes:
|
|
648
661
|
self.app.add_subapp("/api/", protected_app)
|
avtomatika/security.py
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
from hashlib import sha256
|
|
1
2
|
from typing import Any, Awaitable, Callable
|
|
2
3
|
|
|
3
4
|
from aiohttp import web
|
|
@@ -89,9 +90,10 @@ def worker_auth_middleware_factory(
|
|
|
89
90
|
)
|
|
90
91
|
|
|
91
92
|
# --- Individual Token Check ---
|
|
92
|
-
|
|
93
|
-
if
|
|
94
|
-
|
|
93
|
+
expected_token_hash = await storage.get_worker_token(worker_id)
|
|
94
|
+
if expected_token_hash:
|
|
95
|
+
hashed_provided_token = sha256(provided_token.encode()).hexdigest()
|
|
96
|
+
if hashed_provided_token == expected_token_hash:
|
|
95
97
|
request["worker_id"] = worker_id # Attach authenticated worker_id
|
|
96
98
|
return await handler(request)
|
|
97
99
|
else:
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
from hashlib import sha256
|
|
1
2
|
from logging import getLogger
|
|
2
3
|
from os.path import exists
|
|
3
4
|
from tomllib import load
|
|
@@ -36,8 +37,10 @@ async def load_worker_configs_to_redis(storage: StorageBackend, config_path: str
|
|
|
36
37
|
continue
|
|
37
38
|
|
|
38
39
|
try:
|
|
40
|
+
# Hash the token before storing it
|
|
41
|
+
hashed_token = sha256(token.encode()).hexdigest()
|
|
39
42
|
# Store the token in a way that's easily retrievable by worker_id
|
|
40
|
-
await storage.set_worker_token(worker_id,
|
|
43
|
+
await storage.set_worker_token(worker_id, hashed_token)
|
|
41
44
|
logger.info(f"Loaded token for worker_id '{worker_id}'.")
|
|
42
45
|
except Exception as e:
|
|
43
46
|
logger.error(f"Failed to store token for worker_id '{worker_id}' in Redis: {e}")
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: avtomatika
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.0b2
|
|
4
4
|
Summary: A state-machine based orchestrator for long-running jobs.
|
|
5
5
|
Project-URL: Homepage, https://github.com/avtomatika-ai/avtomatika
|
|
6
6
|
Project-URL: Bug Tracker, https://github.com/avtomatika-ai/avtomatika/issues
|
|
@@ -251,6 +251,11 @@ async def handle_normal(actions):
|
|
|
251
251
|
actions.transition_to("normal_processing")
|
|
252
252
|
```
|
|
253
253
|
|
|
254
|
+
> **Note on Limitations:** The current version of `.when()` uses a simple parser with the following limitations:
|
|
255
|
+
> * **No Nested Attributes:** You can only access direct fields of `context.initial_data` or `context.state_history` (e.g., `context.initial_data.field`). Nested objects (e.g., `context.initial_data.area.field`) are not supported.
|
|
256
|
+
> * **Simple Comparisons Only:** Only the following operators are supported: `==`, `!=`, `>`, `<`, `>=`, `<=`. Complex logical expressions with `AND`, `OR`, or `NOT` are not allowed.
|
|
257
|
+
> * **Limited Value Types:** The parser only recognizes strings (in quotes), integers, and floats. Boolean values (`True`, `False`) and `None` are not correctly parsed and will be treated as strings.
|
|
258
|
+
|
|
254
259
|
### 2. Delegating Tasks to Workers (`dispatch_task`)
|
|
255
260
|
|
|
256
261
|
This is the primary function for delegating work. The orchestrator will queue the task and wait for a worker to pick it up and return a result.
|
|
@@ -368,7 +373,9 @@ The orchestrator uses tokens to authenticate API requests.
|
|
|
368
373
|
* **Client Authentication**: All API clients must provide a token in the `X-Avtomatika-Token` header. The orchestrator validates this token against client configurations.
|
|
369
374
|
* **Worker Authentication**: Workers must provide a token in the `X-Worker-Token` header.
|
|
370
375
|
* `GLOBAL_WORKER_TOKEN`: You can set a global token for all workers using this environment variable. For development and testing, it defaults to `"secure-worker-token"`.
|
|
371
|
-
* **Individual Tokens**: For production, it is recommended to define individual tokens for each worker in a separate configuration file and provide its path via the `WORKERS_CONFIG_PATH` environment variable.
|
|
376
|
+
* **Individual Tokens**: For production, it is recommended to define individual tokens for each worker in a separate configuration file and provide its path via the `WORKERS_CONFIG_PATH` environment variable. Tokens from this file are stored in a hashed format for security.
|
|
377
|
+
|
|
378
|
+
> **Note on Dynamic Reloading:** The worker configuration file can be reloaded without restarting the orchestrator by sending an authenticated `POST` request to the `/api/v1/admin/reload-workers` endpoint. This allows for dynamic updates of worker tokens.
|
|
372
379
|
|
|
373
380
|
### Observability
|
|
374
381
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
avtomatika/__init__.py,sha256=BtYVoi9xy3yuMDMmzvLTO3AfbL2xeEjVz2bP9GhQeHU,675
|
|
2
|
-
avtomatika/api.html,sha256=
|
|
3
|
-
avtomatika/blueprint.py,sha256=
|
|
2
|
+
avtomatika/api.html,sha256=Z-Ikqrle7YPXagx2D-C5ylVZicLQFSsIzPsHCQgqMHM,33628
|
|
3
|
+
avtomatika/blueprint.py,sha256=RvDidn2xkziZOOnJlkV30SMp59GuscASz11GolxK7fE,9445
|
|
4
4
|
avtomatika/client_config_loader.py,sha256=N41juqx9CF2XZ3-WRXspkLG2eoGhj9LkWdaMCCCk33E,1962
|
|
5
5
|
avtomatika/compression.py,sha256=bhA1kw4YrCR3I3kdquZSY0fAzCrRrjtz55uepzLUDKI,2498
|
|
6
6
|
avtomatika/config.py,sha256=0vlMfVMjxwVUC8m_NglGocC_EoklzAc0qmt3UJbxm10,2087
|
|
@@ -8,7 +8,7 @@ avtomatika/context.py,sha256=rnF09jqQGkaKlax8P5ku9USwijSm6dommDGZbeVrzLk,4295
|
|
|
8
8
|
avtomatika/data_types.py,sha256=g-g5hPnCpzeATgOn5v7EvDm5ps314owFJD5iWJ6IPR0,1425
|
|
9
9
|
avtomatika/datastore.py,sha256=ERMyiFYQpAhVYijxzTrrdm6jtIPFf4dngWIa0qod3Wc,551
|
|
10
10
|
avtomatika/dispatcher.py,sha256=2YW-A0QXD4T6RF3KiNHflGs8LeLNrMlo5NScE4T49-o,10015
|
|
11
|
-
avtomatika/engine.py,sha256=
|
|
11
|
+
avtomatika/engine.py,sha256=IeBy7pnWjERZwTIAp02wcaKggRMi5Jof-02kB2LfAKc,37482
|
|
12
12
|
avtomatika/executor.py,sha256=-gbLfluZfwtLnAYI8GdK1xswA_DYp_-yoLnP4AWlcyQ,21157
|
|
13
13
|
avtomatika/health_checker.py,sha256=WXwvRJ-3cZC2Udc_ogsyIQp7VzcvJjq_IaqzkTdE0TE,1265
|
|
14
14
|
avtomatika/logging_config.py,sha256=e0-eEEGHw1zz9ZshzXaxfavV0uZfamRNdcAeHnrgBYQ,1370
|
|
@@ -17,10 +17,10 @@ avtomatika/py.typed,sha256=CT_L7gw2MLcQY-X0vs-xB5Vr0wzvGo7GuQYPI_qwJE8,65
|
|
|
17
17
|
avtomatika/quota.py,sha256=DNcaL6k0J1REeP8sVqbY9FprY_3BSr2SxM2Vf4mEqdw,1612
|
|
18
18
|
avtomatika/ratelimit.py,sha256=bZSmdCHviSGMVDNOKTBSswDl6P9Dc63BKLqKU50twpg,1579
|
|
19
19
|
avtomatika/reputation.py,sha256=XFEqDW4TEqjrWgGB2KwnBBJF1RpwLlZPgFwxjPl2z8w,3221
|
|
20
|
-
avtomatika/security.py,sha256=
|
|
20
|
+
avtomatika/security.py,sha256=afj28O3xB20EmA75DAQCQm_QKzx_tX2Qv9zE9TlcFvM,4441
|
|
21
21
|
avtomatika/telemetry.py,sha256=FIbbYjNX0JhpfT7UHjx6EdcFUGF1DpQDrbicIp0ZGvA,2353
|
|
22
22
|
avtomatika/watcher.py,sha256=djqwgK8wu73LL2Rtxa6mV-EXimFO7T-iRQV5U_26dc8,2571
|
|
23
|
-
avtomatika/worker_config_loader.py,sha256=
|
|
23
|
+
avtomatika/worker_config_loader.py,sha256=2Fu2gU3O5H9VJ62D_Yc4gT19vV_be8DJZWzrTTovq8E,1788
|
|
24
24
|
avtomatika/ws_manager.py,sha256=X420oV9_vnujV78VWuOVNqiMZAMQzfw6_0Ep694LJjQ,3069
|
|
25
25
|
avtomatika/history/base.py,sha256=p0zItsdxFzd889LujV8py6GwK4CUfqAt8QL915mrT4k,1680
|
|
26
26
|
avtomatika/history/noop.py,sha256=Hk5yJsS4S5G5A7NRRMEafIV_IFI9hddSwEvRg2Reh0M,982
|
|
@@ -30,8 +30,8 @@ avtomatika/storage/__init__.py,sha256=TFb3_Ab6K1tlGaBihMqhzwdwCarMG2uRpATDW372YN
|
|
|
30
30
|
avtomatika/storage/base.py,sha256=rcHbTB_0s4ZhkxIACnp9f6Ow7Jvr9pHx96t3VUf4lIc,9581
|
|
31
31
|
avtomatika/storage/memory.py,sha256=Wqi879hw1cZBIhMDk_bKPaWhnH33QEl4aUIxu9g3M0M,10282
|
|
32
32
|
avtomatika/storage/redis.py,sha256=eT65_tvRufy-txiKfSSs5UmKBeEio8aWG0UTBfj9DdY,17088
|
|
33
|
-
avtomatika-1.
|
|
34
|
-
avtomatika-1.
|
|
35
|
-
avtomatika-1.
|
|
36
|
-
avtomatika-1.
|
|
37
|
-
avtomatika-1.
|
|
33
|
+
avtomatika-1.0b2.dist-info/licenses/LICENSE,sha256=tqCjw9Y1vbU-hLcWi__7wQstLbt2T1XWPdbQYqCxuWY,1072
|
|
34
|
+
avtomatika-1.0b2.dist-info/METADATA,sha256=IofXNi3-o-YDIfLKrBIT0mV5osHPvRyYX95b_9WI8dY,18083
|
|
35
|
+
avtomatika-1.0b2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
36
|
+
avtomatika-1.0b2.dist-info/top_level.txt,sha256=gLDWhA_wxHj0I6fG5X8vw9fE0HSN4hTE2dEJzeVS2x8,11
|
|
37
|
+
avtomatika-1.0b2.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|