konduktor-nightly 0.1.0.dev20250616105058__py3-none-any.whl → 0.1.0.dev20250617053930__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.
konduktor/__init__.py CHANGED
@@ -14,7 +14,7 @@ __all__ = [
14
14
  ]
15
15
 
16
16
  # Replaced with the current commit when building the wheels.
17
- _KONDUKTOR_COMMIT_SHA = '703fd488ab698fa7ea8f92841bdc19fcdca49f92'
17
+ _KONDUKTOR_COMMIT_SHA = 'babfa5dcf2f304f8895837754d26a46dc1ad8c0a'
18
18
  os.makedirs(os.path.expanduser('~/.konduktor'), exist_ok=True)
19
19
 
20
20
 
@@ -48,5 +48,5 @@ def _get_git_commit():
48
48
 
49
49
 
50
50
  __commit__ = _get_git_commit()
51
- __version__ = '1.0.0.dev0.1.0.dev20250616105058'
51
+ __version__ = '1.0.0.dev0.1.0.dev20250617053930'
52
52
  __root_dir__ = os.path.dirname(os.path.abspath(__file__))
@@ -24,6 +24,7 @@ from konduktor.utils import (
24
24
  kubernetes_utils,
25
25
  log_utils,
26
26
  ux_utils,
27
+ validator,
27
28
  )
28
29
 
29
30
  if typing.TYPE_CHECKING:
@@ -270,9 +271,9 @@ def create_pod_spec(task: 'konduktor.Task') -> Dict[str, Any]:
270
271
  env_map.values()
271
272
  )
272
273
 
273
- # TODO(asaiacai): have some schema validations. see
274
- # https://github.com/skypilot-org/skypilot/pull/4466
275
- # TODO(asaiacai): where can we include policies for the pod spec.
274
+ # validate pod spec using json schema
275
+ # schema: https://github.com/instrumenta/kubernetes-json-schema/blob/master/v1.9.8-standalone-strict/podspec.json
276
+ validator.validate_pod_spec(pod_config['kubernetes']['pod_config']['spec'])
276
277
 
277
278
  return pod_config
278
279
 
@@ -310,7 +311,9 @@ def create_jobset(
310
311
  temp.name,
311
312
  )
312
313
  jobset_spec = common_utils.read_yaml(temp.name)
313
- jobset_spec['jobset']['metadata']['labels'].update(**task.resources.labels)
314
+ jobset_spec['jobset']['metadata']['labels'].update(
315
+ **(task.resources.labels or {})
316
+ )
314
317
  assert task.resources.labels is not None
315
318
  maxRunDurationSeconds = task.resources.labels.get('maxRunDurationSeconds', None)
316
319
  if not maxRunDurationSeconds:
@@ -5,7 +5,18 @@ allow for case-insensitive enum matching since this is currently not supported
5
5
  by the JSON Schema specification.
6
6
  """
7
7
 
8
+ import json
9
+ import time
10
+ from pathlib import Path
11
+
8
12
  import jsonschema
13
+ import requests
14
+ from colorama import Fore, Style
15
+
16
+ SCHEMA_VERSION = 'v1.32.0-standalone-strict'
17
+ SCHEMA_URL = f'https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/{SCHEMA_VERSION}/podspec.json'
18
+ SCHEMA_CACHE_PATH = Path.home() / '.konduktor/schemas/podspec.json'
19
+ CACHE_MAX_AGE_SECONDS = 86400 # 24 hours
9
20
 
10
21
 
11
22
  def case_insensitive_enum(validator, enums, instance, schema):
@@ -18,3 +29,46 @@ SchemaValidator = jsonschema.validators.extend(
18
29
  jsonschema.Draft7Validator,
19
30
  validators={'case_insensitive_enum': case_insensitive_enum},
20
31
  )
32
+
33
+
34
+ def get_cached_schema() -> dict:
35
+ # Check if schema file exists and is fresh
36
+ if SCHEMA_CACHE_PATH.exists():
37
+ age = time.time() - SCHEMA_CACHE_PATH.stat().st_mtime
38
+ # if old
39
+ if age < CACHE_MAX_AGE_SECONDS:
40
+ with open(SCHEMA_CACHE_PATH, 'r') as f:
41
+ return json.load(f)
42
+
43
+ # Download schema
44
+ resp = requests.get(SCHEMA_URL)
45
+ resp.raise_for_status()
46
+
47
+ SCHEMA_CACHE_PATH.parent.mkdir(parents=True, exist_ok=True)
48
+ with open(SCHEMA_CACHE_PATH, 'w') as f:
49
+ f.write(resp.text)
50
+
51
+ return resp.json()
52
+
53
+
54
+ def validate_pod_spec(pod_spec: dict) -> None:
55
+ schema = get_cached_schema()
56
+
57
+ validator = jsonschema.Draft7Validator(schema)
58
+ errors = sorted(validator.iter_errors(pod_spec), key=lambda e: e.path)
59
+
60
+ if not errors:
61
+ return
62
+
63
+ formatted = [
64
+ f'{Fore.RED}- {error.message}'
65
+ + (f" at path: {' → '.join(str(p) for p in error.path)}" if error.path else '')
66
+ + Style.RESET_ALL
67
+ for error in errors
68
+ ]
69
+
70
+ raise ValueError(
71
+ f'\n{Fore.RED}Invalid k8s pod spec/config: \
72
+ {Style.RESET_ALL}\n'
73
+ + '\n'.join(formatted)
74
+ )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: konduktor-nightly
3
- Version: 0.1.0.dev20250616105058
3
+ Version: 0.1.0.dev20250617053930
4
4
  Summary: GPU Cluster Health Management
5
5
  Author: Andrew Aikawa
6
6
  Author-email: asai@berkeley.edu
@@ -1,4 +1,4 @@
1
- konduktor/__init__.py,sha256=PJPREu2puz248XNfbLjPN9mDex0polrjAOhIOWaPe80,1540
1
+ konduktor/__init__.py,sha256=7FZjW6utVolfaEo49Xw64Oq9gm_yIVLqOBxipiKL0W4,1540
2
2
  konduktor/adaptors/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
3
  konduktor/adaptors/aws.py,sha256=s47Ra-GaqCQibzVfmD0pmwEWHif1EGO5opMbwkLxTCU,8244
4
4
  konduktor/adaptors/common.py,sha256=ZIqzjx77PIHUwpjfAQ1uX8B2aX78YMuGj4Bppd-MdyM,4183
@@ -7,7 +7,7 @@ konduktor/authentication.py,sha256=_mVy3eqoKohicHostFiGwG1-2ybxP-l7ouofQ0LRlCY,4
7
7
  konduktor/backends/__init__.py,sha256=1Q6sqqdeMYarpTX_U-QVywJYf7idiUTRsyP-E4BQSOw,129
8
8
  konduktor/backends/backend.py,sha256=qh0bp94lzoTYZkzyQv2-CVrB5l91FkG2vclXg24UFC0,2910
9
9
  konduktor/backends/jobset.py,sha256=UdhwAuZODLMbLY51Y2zOBsh6wg4Pb84oHVvUKzx3Z2w,8434
10
- konduktor/backends/jobset_utils.py,sha256=zBo-DTYbOLppH7fYSEhYqOjeFJz_RYNoid-dImu_Uj0,22068
10
+ konduktor/backends/jobset_utils.py,sha256=mOjK3oFgmNacpg956r0qtR7cdZ0PPzXYVVuIr3QqKuI,22170
11
11
  konduktor/check.py,sha256=JennyWoaqSKhdyfUldd266KwVXTPJpcYQa4EED4a_BA,7569
12
12
  konduktor/cli.py,sha256=i5vXN_p21Tj7etX_QIkq1HCJ3I2Pn_OpKdddBMqRR-g,33877
13
13
  konduktor/config.py,sha256=J50JxC6MsXMnlrJPXdDUMr38C89xvOO7mR8KJ6fyils,15520
@@ -90,9 +90,9 @@ konduktor/utils/rich_utils.py,sha256=ycADW6Ij3wX3uT8ou7T8qxX519RxlkJivsLvUahQaJo
90
90
  konduktor/utils/schemas.py,sha256=VGPERAso2G4sVAznsJ80qT2Q-I_EFxXw6Rfcw-vkYgQ,16535
91
91
  konduktor/utils/subprocess_utils.py,sha256=WoFkoFhGecPR8-rF8WJxbIe-YtV94LXz9UG64SDhCY4,9448
92
92
  konduktor/utils/ux_utils.py,sha256=czCwiS1bDqgeKtzAJctczpLwFZzAse7WuozdvzEFYJ4,7437
93
- konduktor/utils/validator.py,sha256=tgBghVyedyzGx84-U2Qfoh_cJBE3oUk9gclMW90ORks,691
94
- konduktor_nightly-0.1.0.dev20250616105058.dist-info/LICENSE,sha256=MuuqTZbHvmqXR_aNKAXzggdV45ANd3wQ5YI7tnpZhm0,6586
95
- konduktor_nightly-0.1.0.dev20250616105058.dist-info/METADATA,sha256=dUwxTL4s4kctsmbSleWNlmXpbgbgemePysLhjA_FIFM,4289
96
- konduktor_nightly-0.1.0.dev20250616105058.dist-info/WHEEL,sha256=XbeZDeTWKc1w7CSIyre5aMDU_-PohRwTQceYnisIYYY,88
97
- konduktor_nightly-0.1.0.dev20250616105058.dist-info/entry_points.txt,sha256=k3nG5wDFIJhNqsZWrHk4d0irIB2Ns9s47cjRWYsTCT8,48
98
- konduktor_nightly-0.1.0.dev20250616105058.dist-info/RECORD,,
93
+ konduktor/utils/validator.py,sha256=MSQ2EO7Bod8IVkNa2UsKLjg0qvDRvf7q3z-tOwSUkwo,2227
94
+ konduktor_nightly-0.1.0.dev20250617053930.dist-info/LICENSE,sha256=MuuqTZbHvmqXR_aNKAXzggdV45ANd3wQ5YI7tnpZhm0,6586
95
+ konduktor_nightly-0.1.0.dev20250617053930.dist-info/METADATA,sha256=gsj-UQMYSFgug5J9pZNL4vUbaYgyr8my5bioB65DfxE,4289
96
+ konduktor_nightly-0.1.0.dev20250617053930.dist-info/WHEEL,sha256=XbeZDeTWKc1w7CSIyre5aMDU_-PohRwTQceYnisIYYY,88
97
+ konduktor_nightly-0.1.0.dev20250617053930.dist-info/entry_points.txt,sha256=k3nG5wDFIJhNqsZWrHk4d0irIB2Ns9s47cjRWYsTCT8,48
98
+ konduktor_nightly-0.1.0.dev20250617053930.dist-info/RECORD,,