arkitekt-next 0.7.32__py3-none-any.whl → 0.7.34__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 arkitekt-next might be problematic. Click here for more details.

Files changed (36) hide show
  1. arkitekt_next/__blok__.py +37 -0
  2. arkitekt_next/bloks/__init__.py +2 -0
  3. arkitekt_next/bloks/admin.py +45 -0
  4. arkitekt_next/bloks/arkitekt.py +38 -0
  5. arkitekt_next/bloks/config.py +42 -0
  6. arkitekt_next/bloks/fluss.py +88 -0
  7. arkitekt_next/bloks/funcs.py +86 -0
  8. arkitekt_next/bloks/gateway.py +173 -0
  9. arkitekt_next/bloks/internal_docker.py +80 -0
  10. arkitekt_next/bloks/kabinet.py +93 -0
  11. arkitekt_next/bloks/livekit.py +92 -0
  12. arkitekt_next/bloks/lok.py +381 -0
  13. arkitekt_next/bloks/mikro.py +98 -0
  14. arkitekt_next/bloks/minio.py +180 -0
  15. arkitekt_next/bloks/mount.py +35 -0
  16. arkitekt_next/bloks/postgres.py +86 -0
  17. arkitekt_next/bloks/redis.py +77 -0
  18. arkitekt_next/bloks/rekuest.py +93 -0
  19. arkitekt_next/bloks/services/__init__.py +0 -0
  20. arkitekt_next/bloks/services/admin.py +22 -0
  21. arkitekt_next/bloks/services/config.py +18 -0
  22. arkitekt_next/bloks/services/db.py +27 -0
  23. arkitekt_next/bloks/services/gateway.py +20 -0
  24. arkitekt_next/bloks/services/livekit.py +19 -0
  25. arkitekt_next/bloks/services/lok.py +27 -0
  26. arkitekt_next/bloks/services/mount.py +15 -0
  27. arkitekt_next/bloks/services/redis.py +28 -0
  28. arkitekt_next/bloks/services/s3.py +26 -0
  29. arkitekt_next/bloks/services/socket.py +16 -0
  30. arkitekt_next/bloks/socket.py +38 -0
  31. arkitekt_next/cli/commands/server/init.py +4 -63
  32. {arkitekt_next-0.7.32.dist-info → arkitekt_next-0.7.34.dist-info}/METADATA +1 -1
  33. {arkitekt_next-0.7.32.dist-info → arkitekt_next-0.7.34.dist-info}/RECORD +36 -6
  34. {arkitekt_next-0.7.32.dist-info → arkitekt_next-0.7.34.dist-info}/LICENSE +0 -0
  35. {arkitekt_next-0.7.32.dist-info → arkitekt_next-0.7.34.dist-info}/WHEEL +0 -0
  36. {arkitekt_next-0.7.32.dist-info → arkitekt_next-0.7.34.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,92 @@
1
+ from typing import Dict, Any
2
+ import secrets
3
+
4
+ from arkitekt_next.bloks.services.gateway import GatewayService
5
+ from arkitekt_next.bloks.services.livekit import LivekitService, LivekitCredentials
6
+ from blok import blok, InitContext, ExecutionContext, Option
7
+ from blok.tree import YamlFile, Repo
8
+
9
+
10
+ @blok(LivekitService)
11
+ class LocalLiveKitBlok:
12
+ def __init__(self) -> None:
13
+ self.host = "livekit"
14
+ self.command = ["--dev", "--bind", "0.0.0.0"]
15
+ self.image = "livekit/livekit-server:latest"
16
+ self.mount_repo = True
17
+ self.build_repo = True
18
+ self.secret_key = secrets.token_hex(16)
19
+ self.ensured_repos = []
20
+ self.port_range = [50000, 50030]
21
+ self.api_key = "devkey"
22
+ self.api_secret = "secret"
23
+ self.skip = False
24
+
25
+
26
+ def preflight(self, init: InitContext, gateway: GatewayService):
27
+ for key, value in init.kwargs.items():
28
+ setattr(self, key, value)
29
+
30
+ deps = init.dependencies
31
+
32
+ if self.skip:
33
+ return
34
+
35
+ gateway.expose_port(7880, self.host, True)
36
+ gateway.expose_port(7881, self.host, True)
37
+
38
+ self.initialized = True
39
+
40
+ def retrieve_access(self):
41
+ return LivekitCredentials(**{
42
+ "api_key": self.api_key,
43
+ "api_secret": self.api_secret,
44
+ "api_url": f"http://{self.host}:7880",
45
+ })
46
+
47
+ def build(self, context: ExecutionContext):
48
+ if self.skip:
49
+ return
50
+ db_service = {
51
+ "labels": [
52
+ "fakts.service=io.livekit.livekit",
53
+ "fakts.builder=livekitio.livekit",
54
+ ],
55
+ "image": self.image,
56
+ "command": self.command,
57
+ "ports": [
58
+ f"{self.port_range[0]}-{self.port_range[1]}:{self.port_range[0]}-{self.port_range[1]}"
59
+ ],
60
+ }
61
+
62
+ context.docker_compose.set_nested("services", self.host, db_service)
63
+
64
+ def get_options(self):
65
+ with_command = Option(
66
+ subcommand="command",
67
+ help="The fakts url for connection",
68
+ default=self.command,
69
+ )
70
+ with_host = Option(
71
+ subcommand="host",
72
+ help="The fakts url for connection",
73
+ default=self.host,
74
+ )
75
+ with_skip = Option(
76
+ subcommand="skip",
77
+ help="The fakts url for connection",
78
+ default=False,
79
+ type=bool,
80
+ is_flag=True,
81
+ )
82
+
83
+ return [
84
+ with_host,
85
+ with_command,
86
+ with_skip,
87
+ ]
88
+
89
+ def __str__(self) -> str:
90
+ return (
91
+ f"LiveKitBlok(host={self.host}, command={self.command}, image={self.image})"
92
+ )
@@ -0,0 +1,381 @@
1
+ import click
2
+
3
+ from pydantic import BaseModel
4
+ from cryptography.hazmat.primitives import serialization as crypto_serialization
5
+ from cryptography.hazmat.primitives.asymmetric import rsa
6
+ from cryptography.hazmat.backends import default_backend as crypto_default_backend
7
+ from typing import Dict
8
+ from arkitekt_next.bloks.services.admin import AdminService
9
+ from arkitekt_next.bloks.services.db import DBService
10
+ from arkitekt_next.bloks.services.gateway import GatewayService
11
+ from arkitekt_next.bloks.services.livekit import LivekitService
12
+ from arkitekt_next.bloks.services.lok import LokCredentials, LokService
13
+ import yaml
14
+ import secrets
15
+ from dataclasses import asdict
16
+
17
+ from arkitekt_next.bloks.services.redis import RedisService
18
+ from blok import blok, InitContext, ExecutionContext, Option
19
+ from blok.tree import YamlFile, Repo
20
+ from blok import blok, InitContext
21
+
22
+
23
+
24
+ DEFAULT_ARKITEKT_URL = "http://localhost:8000"
25
+
26
+
27
+ # Define a custom user type that will parse and validate the user input
28
+ class UserParamType(click.ParamType):
29
+ name = "user"
30
+
31
+ def convert(self, value, param, ctx):
32
+ if isinstance(value, dict):
33
+ return value
34
+ try:
35
+ name, password = value.split(":")
36
+ return {"name": name, "password": password}
37
+ except ValueError:
38
+ self.fail(
39
+ f"User '{value}' is not in the correct format. It should be 'name:password'.",
40
+ param,
41
+ ctx,
42
+ )
43
+
44
+
45
+ USER = UserParamType()
46
+
47
+
48
+ # Define a custom user type that will parse and validate the user input
49
+ class GroupParamType(click.ParamType):
50
+ name = "group"
51
+
52
+ def convert(self, value, param, ctx):
53
+ if isinstance(value, dict):
54
+ return value
55
+ try:
56
+ name, description = value.split(":")
57
+ return {"name": name, "description": description}
58
+ except ValueError:
59
+ self.fail(
60
+ f"User '{value}' is not in the correct format. It should be 'name:password'.",
61
+ param,
62
+ ctx,
63
+ )
64
+
65
+
66
+ GROUP = GroupParamType()
67
+
68
+
69
+ class RedeemTokenParamType(click.ParamType):
70
+ name = "redeem_token"
71
+
72
+ def convert(self, value, param, ctx):
73
+ if isinstance(value, dict):
74
+ assert "user" in value, f"scope is required {value}"
75
+ assert "token" in value, f"description is required {value}"
76
+ return value
77
+
78
+ try:
79
+ user, token = value.split(":")
80
+ return {"user": user, "token": token}
81
+ except ValueError:
82
+ self.fail(
83
+ f"RedeemToken '{value}' is not in the correct format. It should be 'username:token'.",
84
+ param,
85
+ ctx,
86
+ )
87
+
88
+
89
+ TOKEN = RedeemTokenParamType()
90
+
91
+
92
+ class ScopeParamType(click.ParamType):
93
+ name = "scope"
94
+
95
+ def convert(self, value, param, ctx):
96
+ if isinstance(value, dict):
97
+ assert "scope" in value, f"scope is required {value}"
98
+ assert "description" in value, f"description is required {value}"
99
+ return value
100
+
101
+ try:
102
+ name, description = value.split(":")
103
+ return {"scope": name, "description": description}
104
+ except ValueError:
105
+ self.fail(
106
+ f"Scopes '{value}' is not in the correct format. It should be 'scope:description'.",
107
+ param,
108
+ ctx,
109
+ )
110
+
111
+
112
+ SCOPE = ScopeParamType()
113
+
114
+
115
+ @blok(LokService)
116
+ class LokBlok:
117
+ db_name: str
118
+
119
+ def __init__(self) -> None:
120
+ self.db_name = "lok_db"
121
+ self.mount_repo = False
122
+ self.build_repo = False
123
+ self.private_key = None
124
+ self.public_key = None
125
+ self.host = "lok"
126
+ self.with_repo = False
127
+ self.command = "bash run-debug.sh"
128
+ self.repo = "https://github.com/jhnnsrs/lok-server-next"
129
+ self.image = "jhnnsrs/lok:next"
130
+ self.users = []
131
+ self.tokens = []
132
+ self.groups = []
133
+ self.secret_key = secrets.token_hex(16)
134
+ self.scopes = {"hallo": "welt"}
135
+ self.key = None
136
+ self.deployment_name = "default"
137
+ self.base_routes = [
138
+ "ht",
139
+ "o",
140
+ "graphql",
141
+ ".well-known",
142
+ "f",
143
+ "admin",
144
+ "static",
145
+ "accounts",
146
+ ]
147
+ self.token_expiry_seconds = 700000
148
+
149
+ def get_dependencies(self):
150
+ return [
151
+ "io.livekit.livekit",
152
+ "live.arkitekt.postgres",
153
+ "live.arkitekt.redis",
154
+ "live.arkitekt.admin",
155
+ "live.arkitekt.gateway",
156
+ ]
157
+
158
+ def retrieve_credentials(self) -> LokCredentials:
159
+ return LokCredentials(
160
+ public_key=self.public_key, key_type="RS256", issuer="lok"
161
+ )
162
+
163
+ def retrieve_labels(self, service_name: str) -> list[str]:
164
+ return [
165
+ f"fakts.service={service_name}",
166
+ f"fakts.builder=arkitekt.{service_name}",
167
+ ]
168
+
169
+ def register_scopes(self, scopes_dict: Dict[str, str]) -> LokCredentials:
170
+ self.scopes = self.scopes | scopes_dict
171
+
172
+ def preflight(self, init: InitContext, gateway: GatewayService, db: DBService, redis: RedisService, admin: AdminService, livekit: LivekitService, scopes: list[Dict[str, str]]):
173
+ for key, value in init.kwargs.items():
174
+ setattr(self, key, value)
175
+
176
+ assert self.public_key, "Public key is required"
177
+ assert self.private_key, "Private key is required"
178
+
179
+ self.scopes = {scope["scope"]: scope["description"] for scope in scopes}
180
+
181
+ for i in self.base_routes:
182
+ gateway.expose(
183
+ i, 80, self.host, strip_prefix=False
184
+ )
185
+
186
+ self.postgress_access = db.register_db(self.host)
187
+ self.redis_access = redis.register()
188
+ self.admin_access = admin.retrieve()
189
+ self.local_access = livekit.retrieve_access()
190
+ self.initialized = True
191
+
192
+ def build(self, context: ExecutionContext):
193
+ depends_on = []
194
+
195
+ if self.redis_access.dependency:
196
+ depends_on.append(self.redis_access.dependency)
197
+
198
+ if self.postgress_access.dependency:
199
+ depends_on.append(self.postgress_access.dependency)
200
+
201
+ db_service = {
202
+ "labels": ["fakts.service=live.arkitekt.lok", "fakts.builder=arkitekt.lok"],
203
+ "depends_on": depends_on,
204
+ "volumes": [
205
+ "/var/run/docker.sock:/var/run/docker.sock",
206
+ "./configs/lok.yaml:/workspace/config.yaml",
207
+ "./certs:/certs",
208
+ ],
209
+ }
210
+
211
+ if self.mount_repo:
212
+ context.file_tree.set_nested("mounts", "lok", Repo(self.repo))
213
+ db_service["volumes"].append("./mounts/lok:/lok")
214
+
215
+ if self.build_repo:
216
+ context.file_tree.set_nested("mounts", "lok", Repo(self.repo))
217
+ db_service["build"] = "./mounts/lok"
218
+ else:
219
+ db_service["image"] = self.image
220
+
221
+ db_service["command"] = self.command
222
+
223
+ configuration = YamlFile(
224
+ **{
225
+ "db": asdict(self.postgress_access),
226
+ "users": [user for user in self.users],
227
+ "django": {
228
+ "admin": asdict(self.admin_access),
229
+ "debug": True,
230
+ "hosts": ["*"],
231
+ "secret_key": self.secret_key,
232
+ },
233
+ "redis": asdict(self.redis_access),
234
+ "lok": asdict(self.retrieve_credentials()),
235
+ "private_key": self.private_key,
236
+ "public_key": self.public_key,
237
+ "scopes": self.scopes,
238
+ "redeem_tokens": [token for token in self.tokens],
239
+ "groups": [group for group in self.groups],
240
+ "deployment": {"name": self.deployment_name},
241
+ "livekit": asdict(self.local_access),
242
+ "token_expire_seconds": self.token_expiry_seconds,
243
+ "apps": [],
244
+ }
245
+ )
246
+
247
+ context.file_tree.set_nested("configs", "lok.yaml", configuration)
248
+
249
+ context.docker_compose.set_nested("services", self.host, db_service)
250
+
251
+ def get_options(self):
252
+ key = rsa.generate_private_key(
253
+ public_exponent=65537, key_size=2048, backend=crypto_default_backend()
254
+ )
255
+
256
+ private_key = key.private_bytes(
257
+ crypto_serialization.Encoding.PEM,
258
+ crypto_serialization.PrivateFormat.PKCS8,
259
+ crypto_serialization.NoEncryption(),
260
+ ).decode()
261
+
262
+ public_key = (
263
+ key.public_key()
264
+ .public_bytes(
265
+ crypto_serialization.Encoding.OpenSSH,
266
+ crypto_serialization.PublicFormat.OpenSSH,
267
+ )
268
+ .decode()
269
+ )
270
+
271
+ with_fakts_url = Option(
272
+ subcommand="db_name",
273
+ help="The fakts url for connection",
274
+ default="db_name",
275
+ )
276
+ with_users = Option(
277
+ subcommand="users",
278
+ help="The fakts url for connection",
279
+ default=["admin:admin"],
280
+ multiple=True,
281
+ type=USER,
282
+ )
283
+ with_groups = Option(
284
+ subcommand="groups",
285
+ help="The fakts url for connection",
286
+ default=["admin:admin_group"],
287
+ multiple=True,
288
+ type=GROUP,
289
+ )
290
+ with_redeem_token = Option(
291
+ subcommand="tokens",
292
+ help="The fakts url for connection",
293
+ default=[],
294
+ multiple=True,
295
+ type=TOKEN,
296
+ )
297
+ with_scopes = Option(
298
+ subcommand="scopes",
299
+ help="The scopes",
300
+ default=[f"{key}:{value}" for key, value in self.scopes.items()],
301
+ multiple=True,
302
+ type=SCOPE,
303
+ )
304
+ with_repo = Option(
305
+ subcommand="with_repo",
306
+ help="The fakts url for connection",
307
+ default=self.repo,
308
+ )
309
+ with_repo = Option(
310
+ subcommand="command",
311
+ help="The fakts url for connection",
312
+ default=self.command,
313
+ )
314
+ mount_repo = Option(
315
+ subcommand="mount_repo",
316
+ help="The fakts url for connection",
317
+ is_flag=True,
318
+ default=False,
319
+ )
320
+ build_repo = Option(
321
+ subcommand="build_repo",
322
+ help="The fakts url for connection",
323
+ is_flag=True,
324
+ default=False,
325
+ )
326
+ with_host = Option(
327
+ subcommand="host",
328
+ help="The fakts url for connection",
329
+ default=self.host,
330
+ )
331
+ #
332
+ with_public_key = Option(
333
+ subcommand="public_key",
334
+ help="The fakts url for connection",
335
+ default=public_key,
336
+ required=True,
337
+ callback=validate_public_key,
338
+ )
339
+ with_private_key = Option(
340
+ subcommand="private_key",
341
+ help="The fakts url for connection",
342
+ default=private_key,
343
+ callback=validate_private_key,
344
+ required=True,
345
+ )
346
+ with_secret_key = Option(
347
+ subcommand="secret_key",
348
+ help="The fakts url for connection",
349
+ default=self.secret_key,
350
+ )
351
+
352
+ return [
353
+ with_fakts_url,
354
+ with_users,
355
+ with_repo,
356
+ mount_repo,
357
+ with_groups,
358
+ build_repo,
359
+ with_host,
360
+ with_redeem_token,
361
+ with_private_key,
362
+ with_public_key,
363
+ with_scopes,
364
+ with_secret_key,
365
+ ]
366
+
367
+
368
+ def validate_public_key(ctx, param, value):
369
+ if not value.startswith("ssh-rsa"):
370
+ raise click.BadParameter(
371
+ f"Public key must be in ssh-rsa format. Started with {value}"
372
+ )
373
+ return value
374
+
375
+
376
+ def validate_private_key(ctx, param, value):
377
+ if not value.startswith("-----BEGIN PRIVATE KEY-----"):
378
+ raise click.BadParameter(
379
+ f"Private key must be in PEM format. Started with {value}"
380
+ )
381
+ return value
@@ -0,0 +1,98 @@
1
+ import click
2
+ from pydantic import BaseModel
3
+ from typing import Dict, Any
4
+ import yaml
5
+ import secrets
6
+ from blok import blok, InitContext
7
+
8
+ from blok import blok, InitContext, ExecutionContext, Option
9
+ from blok.tree import YamlFile, Repo
10
+ from arkitekt_next.bloks.funcs import create_default_service_yaml
11
+
12
+
13
+ class AccessCredentials(BaseModel):
14
+ password: str
15
+ username: str
16
+ host: str
17
+ port: str
18
+ db_name: str
19
+
20
+
21
+ @blok("live.arkitekt.mikro")
22
+ class MikroBlok:
23
+ def __init__(self) -> None:
24
+ self.host = "mikro"
25
+ self.command = "bash run-debug.sh"
26
+ self.repo = "https://github.com/jhnnsrs/mikro-server-next"
27
+ self.scopes = {"read_image": "Read image from the database"}
28
+ self.image = "jhnnsrs/mikro:next"
29
+ self.mount_repo = False
30
+ self.build_repo = False
31
+ self.buckets = ["media", "zarr", "parquet"]
32
+ self.secret_key = secrets.token_hex(16)
33
+
34
+ def get_dependencies(self):
35
+ return [
36
+ "live.arkitekt.mount",
37
+ "live.arkitekt.config",
38
+ "live.arkitekt.gateway",
39
+ "live.arkitekt.postgres",
40
+ "live.arkitekt.lok",
41
+ "live.arkitekt.admin",
42
+ "live.arkitekt.redis",
43
+ "live.arkitekt.s3",
44
+ ]
45
+
46
+ def preflight(self, init: InitContext):
47
+ for key, value in init.kwargs.items():
48
+ setattr(self, key, value)
49
+
50
+ self.service = create_default_service_yaml(init, self)
51
+
52
+ self.initialized = True
53
+
54
+ def build(self, context: ExecutionContext):
55
+ context.docker_compose.set_nested("services", self.host, self.service)
56
+
57
+ def get_options(self):
58
+ with_repo = Option(
59
+ subcommand="with_repo",
60
+ help="The fakts url for connection",
61
+ default=self.repo,
62
+ )
63
+ with_command = Option(
64
+ subcommand="command",
65
+ help="The fakts url for connection",
66
+ default=self.command,
67
+ )
68
+ mount_repo = Option(
69
+ subcommand="mount_repo",
70
+ help="The fakts url for connection",
71
+ is_flag=True,
72
+ default=self.mount_repo,
73
+ )
74
+ build_repo = Option(
75
+ subcommand="build_repo",
76
+ help="The fakts url for connection",
77
+ is_flag=True,
78
+ default=self.build_repo,
79
+ )
80
+ with_host = Option(
81
+ subcommand="host",
82
+ help="The fakts url for connection",
83
+ default=self.host,
84
+ )
85
+ with_secret_key = Option(
86
+ subcommand="secret_key",
87
+ help="The fakts url for connection",
88
+ default=self.secret_key,
89
+ )
90
+
91
+ return [
92
+ with_repo,
93
+ mount_repo,
94
+ build_repo,
95
+ with_host,
96
+ with_command,
97
+ with_secret_key,
98
+ ]