dagster-k8s 0.24.10__tar.gz → 0.24.11__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 dagster-k8s might be problematic. Click here for more details.

Files changed (28) hide show
  1. {dagster-k8s-0.24.10/dagster_k8s.egg-info → dagster-k8s-0.24.11}/PKG-INFO +1 -1
  2. {dagster-k8s-0.24.10 → dagster-k8s-0.24.11}/dagster_k8s/container_context.py +56 -21
  3. {dagster-k8s-0.24.10 → dagster-k8s-0.24.11}/dagster_k8s/executor.py +2 -2
  4. {dagster-k8s-0.24.10 → dagster-k8s-0.24.11}/dagster_k8s/job.py +34 -3
  5. {dagster-k8s-0.24.10 → dagster-k8s-0.24.11}/dagster_k8s/ops/k8s_job_op.py +13 -5
  6. dagster-k8s-0.24.11/dagster_k8s/version.py +1 -0
  7. {dagster-k8s-0.24.10 → dagster-k8s-0.24.11/dagster_k8s.egg-info}/PKG-INFO +1 -1
  8. {dagster-k8s-0.24.10 → dagster-k8s-0.24.11}/dagster_k8s.egg-info/requires.txt +1 -1
  9. {dagster-k8s-0.24.10 → dagster-k8s-0.24.11}/setup.py +1 -1
  10. dagster-k8s-0.24.10/dagster_k8s/version.py +0 -1
  11. {dagster-k8s-0.24.10 → dagster-k8s-0.24.11}/LICENSE +0 -0
  12. {dagster-k8s-0.24.10 → dagster-k8s-0.24.11}/MANIFEST.in +0 -0
  13. {dagster-k8s-0.24.10 → dagster-k8s-0.24.11}/README.md +0 -0
  14. {dagster-k8s-0.24.10 → dagster-k8s-0.24.11}/dagster_k8s/__init__.py +0 -0
  15. {dagster-k8s-0.24.10 → dagster-k8s-0.24.11}/dagster_k8s/client.py +0 -0
  16. {dagster-k8s-0.24.10 → dagster-k8s-0.24.11}/dagster_k8s/kubernetes_version.py +0 -0
  17. {dagster-k8s-0.24.10 → dagster-k8s-0.24.11}/dagster_k8s/launcher.py +0 -0
  18. {dagster-k8s-0.24.10 → dagster-k8s-0.24.11}/dagster_k8s/models.py +0 -0
  19. {dagster-k8s-0.24.10 → dagster-k8s-0.24.11}/dagster_k8s/ops/__init__.py +0 -0
  20. {dagster-k8s-0.24.10 → dagster-k8s-0.24.11}/dagster_k8s/pipes.py +0 -0
  21. {dagster-k8s-0.24.10 → dagster-k8s-0.24.11}/dagster_k8s/py.typed +0 -0
  22. {dagster-k8s-0.24.10 → dagster-k8s-0.24.11}/dagster_k8s/test.py +0 -0
  23. {dagster-k8s-0.24.10 → dagster-k8s-0.24.11}/dagster_k8s/utils.py +0 -0
  24. {dagster-k8s-0.24.10 → dagster-k8s-0.24.11}/dagster_k8s.egg-info/SOURCES.txt +0 -0
  25. {dagster-k8s-0.24.10 → dagster-k8s-0.24.11}/dagster_k8s.egg-info/dependency_links.txt +0 -0
  26. {dagster-k8s-0.24.10 → dagster-k8s-0.24.11}/dagster_k8s.egg-info/not-zip-safe +0 -0
  27. {dagster-k8s-0.24.10 → dagster-k8s-0.24.11}/dagster_k8s.egg-info/top_level.txt +0 -0
  28. {dagster-k8s-0.24.10 → dagster-k8s-0.24.11}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: dagster-k8s
3
- Version: 0.24.10
3
+ Version: 0.24.11
4
4
  Summary: A Dagster integration for k8s
5
5
  Home-page: https://github.com/dagster-io/dagster/tree/master/python_modules/libraries/dagster-k8s
6
6
  Author: Dagster Labs
@@ -51,7 +51,6 @@ class K8sContainerContext(
51
51
  ("server_k8s_config", UserDefinedDagsterK8sConfig),
52
52
  ("run_k8s_config", UserDefinedDagsterK8sConfig),
53
53
  ("namespace", Optional[str]),
54
- ("labels", Mapping[str, str]),
55
54
  ],
56
55
  )
57
56
  ):
@@ -106,12 +105,19 @@ class K8sContainerContext(
106
105
  )
107
106
 
108
107
  run_k8s_config = K8sContainerContext._merge_k8s_config(
109
- top_level_k8s_config,
108
+ top_level_k8s_config._replace( # remove k8s service/deployment fields
109
+ deployment_metadata={},
110
+ service_metadata={},
111
+ ),
110
112
  run_k8s_config or UserDefinedDagsterK8sConfig.from_dict({}),
111
113
  )
112
114
 
113
115
  server_k8s_config = K8sContainerContext._merge_k8s_config(
114
- top_level_k8s_config,
116
+ top_level_k8s_config._replace( # remove k8s job fields
117
+ job_config={},
118
+ job_metadata={},
119
+ job_spec_config={},
120
+ ),
115
121
  server_k8s_config or UserDefinedDagsterK8sConfig.from_dict({}),
116
122
  )
117
123
 
@@ -120,7 +126,6 @@ class K8sContainerContext(
120
126
  run_k8s_config=run_k8s_config,
121
127
  server_k8s_config=server_k8s_config,
122
128
  namespace=namespace,
123
- labels=check.opt_mapping_param(labels, "labels"),
124
129
  )
125
130
 
126
131
  @staticmethod
@@ -143,6 +148,8 @@ class K8sContainerContext(
143
148
  pod_spec_config = {}
144
149
  pod_template_spec_metadata = {}
145
150
  job_metadata = {}
151
+ deployment_metadata = {}
152
+ service_metadata = {}
146
153
 
147
154
  if volume_mounts:
148
155
  container_config["volume_mounts"] = volume_mounts
@@ -159,6 +166,8 @@ class K8sContainerContext(
159
166
  if labels:
160
167
  pod_template_spec_metadata["labels"] = labels
161
168
  job_metadata["labels"] = labels
169
+ deployment_metadata["labels"] = labels
170
+ service_metadata["labels"] = labels
162
171
 
163
172
  if image_pull_policy:
164
173
  container_config["image_pull_policy"] = image_pull_policy
@@ -196,6 +205,8 @@ class K8sContainerContext(
196
205
  pod_spec_config=pod_spec_config,
197
206
  pod_template_spec_metadata=pod_template_spec_metadata,
198
207
  job_metadata=job_metadata,
208
+ service_metadata=service_metadata,
209
+ deployment_metadata=deployment_metadata,
199
210
  )
200
211
 
201
212
  @staticmethod
@@ -260,7 +271,6 @@ class K8sContainerContext(
260
271
  ),
261
272
  run_k8s_config=self._merge_k8s_config(self.run_k8s_config, other.run_k8s_config),
262
273
  namespace=other.namespace if other.namespace else self.namespace,
263
- labels={**self.labels, **other.labels},
264
274
  )
265
275
 
266
276
  def _snake_case_allowed_fields(
@@ -269,9 +279,18 @@ class K8sContainerContext(
269
279
  result = {}
270
280
 
271
281
  for key in only_allow_user_defined_k8s_config_fields:
282
+ if key == "namespace":
283
+ result[key] = only_allow_user_defined_k8s_config_fields[key]
284
+ continue
285
+
272
286
  if key == "container_config":
273
287
  model_class = kubernetes.client.V1Container
274
- elif key in {"job_metadata", "pod_template_spec_metadata"}:
288
+ elif key in {
289
+ "job_metadata",
290
+ "pod_template_spec_metadata",
291
+ "deployment_metadata",
292
+ "service_metadata",
293
+ }:
275
294
  model_class = kubernetes.client.V1ObjectMeta
276
295
  elif key == "pod_spec_config":
277
296
  model_class = kubernetes.client.V1PodSpec
@@ -284,12 +303,35 @@ class K8sContainerContext(
284
303
  )
285
304
  return result
286
305
 
287
- def validate_user_k8s_config(
306
+ def validate_user_k8s_config_for_run(
288
307
  self,
289
308
  only_allow_user_defined_k8s_config_fields: Optional[Mapping[str, Any]],
290
309
  only_allow_user_defined_env_vars: Optional[Sequence[str]],
310
+ ):
311
+ return self._validate_user_k8s_config(
312
+ self.run_k8s_config,
313
+ only_allow_user_defined_k8s_config_fields,
314
+ only_allow_user_defined_env_vars,
315
+ )
316
+
317
+ def validate_user_k8s_config_for_code_server(
318
+ self,
319
+ only_allow_user_defined_k8s_config_fields: Optional[Mapping[str, Any]],
320
+ only_allow_user_defined_env_vars: Optional[Sequence[str]],
321
+ ):
322
+ return self._validate_user_k8s_config(
323
+ self.server_k8s_config,
324
+ only_allow_user_defined_k8s_config_fields,
325
+ only_allow_user_defined_env_vars,
326
+ )
327
+
328
+ def _validate_user_k8s_config(
329
+ self,
330
+ user_defined_k8s_config: UserDefinedDagsterK8sConfig,
331
+ only_allow_user_defined_k8s_config_fields: Optional[Mapping[str, Any]],
332
+ only_allow_user_defined_env_vars: Optional[Sequence[str]],
291
333
  ) -> "K8sContainerContext":
292
- used_fields = self._get_used_k8s_config_fields()
334
+ used_fields = self._get_used_k8s_config_fields(user_defined_k8s_config)
293
335
 
294
336
  if only_allow_user_defined_k8s_config_fields is not None:
295
337
  snake_case_allowlist = self._snake_case_allowed_fields(
@@ -383,17 +425,11 @@ class K8sContainerContext(
383
425
  server_k8s_config=new_server_k8s_config,
384
426
  )
385
427
 
386
- def _get_used_k8s_config_fields(self) -> Mapping[str, Mapping[str, Set[str]]]:
428
+ def _get_used_k8s_config_fields(
429
+ self, user_defined_k8s_config: UserDefinedDagsterK8sConfig
430
+ ) -> Mapping[str, Mapping[str, Set[str]]]:
387
431
  used_fields = {}
388
- for key, fields in self.run_k8s_config.to_dict().items():
389
- if key == "merge_behavior":
390
- continue
391
-
392
- used_fields[key] = used_fields.get(key, set()).union(
393
- {field_key for field_key in fields}
394
- )
395
-
396
- for key, fields in self.server_k8s_config.to_dict().items():
432
+ for key, fields in user_defined_k8s_config.to_dict().items():
397
433
  if key == "merge_behavior":
398
434
  continue
399
435
 
@@ -402,8 +438,7 @@ class K8sContainerContext(
402
438
  )
403
439
 
404
440
  if self.namespace:
405
- used_fields["pod_template_spec_metadata"].add("namespace")
406
- used_fields["job_metadata"].add("namespace")
441
+ used_fields["namespace"] = True
407
442
 
408
443
  return used_fields
409
444
 
@@ -457,7 +492,7 @@ class K8sContainerContext(
457
492
  # If there's an allowlist, make sure user_defined_container_context doesn't violate it
458
493
  if run_launcher:
459
494
  user_defined_container_context = (
460
- user_defined_container_context.validate_user_k8s_config(
495
+ user_defined_container_context.validate_user_k8s_config_for_run(
461
496
  run_launcher.only_allow_user_defined_k8s_config_fields,
462
497
  run_launcher.only_allow_user_defined_env_vars,
463
498
  )
@@ -27,7 +27,7 @@ from dagster._utils.merger import merge_dicts
27
27
  from dagster_k8s.client import DagsterKubernetesClient
28
28
  from dagster_k8s.container_context import K8sContainerContext
29
29
  from dagster_k8s.job import (
30
- USER_DEFINED_K8S_CONFIG_SCHEMA,
30
+ USER_DEFINED_K8S_JOB_CONFIG_SCHEMA,
31
31
  DagsterK8sJobConfig,
32
32
  UserDefinedDagsterK8sConfig,
33
33
  construct_dagster_k8s_job,
@@ -69,7 +69,7 @@ _K8S_EXECUTOR_CONFIG_SCHEMA = merge_dicts(
69
69
  ),
70
70
  "tag_concurrency_limits": get_tag_concurrency_limits_config(),
71
71
  "step_k8s_config": Field(
72
- USER_DEFINED_K8S_CONFIG_SCHEMA,
72
+ USER_DEFINED_K8S_JOB_CONFIG_SCHEMA,
73
73
  is_required=False,
74
74
  description="Raw Kubernetes configuration for each step launched by the executor.",
75
75
  ),
@@ -63,7 +63,7 @@ class K8sConfigMergeBehavior(Enum):
63
63
 
64
64
 
65
65
  USER_DEFINED_K8S_CONFIG_KEY = "dagster-k8s/config"
66
- USER_DEFINED_K8S_CONFIG_SCHEMA = Shape(
66
+ USER_DEFINED_K8S_JOB_CONFIG_SCHEMA = Shape(
67
67
  {
68
68
  "container_config": Permissive(),
69
69
  "pod_template_spec_metadata": Permissive(),
@@ -94,18 +94,23 @@ class UserDefinedDagsterK8sConfig(
94
94
  ("job_config", Mapping[str, Any]),
95
95
  ("job_metadata", Mapping[str, Any]),
96
96
  ("job_spec_config", Mapping[str, Any]),
97
+ ("deployment_metadata", Mapping[str, Any]),
98
+ ("service_metadata", Mapping[str, Any]),
97
99
  ("merge_behavior", K8sConfigMergeBehavior),
98
100
  ],
99
101
  )
100
102
  ):
101
103
  def __new__(
102
104
  cls,
105
+ *,
103
106
  container_config: Optional[Mapping[str, Any]] = None,
104
107
  pod_template_spec_metadata: Optional[Mapping[str, Any]] = None,
105
108
  pod_spec_config: Optional[Mapping[str, Any]] = None,
106
109
  job_config: Optional[Mapping[str, Any]] = None,
107
110
  job_metadata: Optional[Mapping[str, Any]] = None,
108
111
  job_spec_config: Optional[Mapping[str, Any]] = None,
112
+ deployment_metadata: Optional[Mapping[str, Any]] = None,
113
+ service_metadata: Optional[Mapping[str, Any]] = None,
109
114
  merge_behavior: K8sConfigMergeBehavior = K8sConfigMergeBehavior.DEEP,
110
115
  ):
111
116
  container_config = check.opt_mapping_param(
@@ -119,6 +124,13 @@ class UserDefinedDagsterK8sConfig(
119
124
  job_metadata = check.opt_mapping_param(job_metadata, "job_metadata", key_type=str)
120
125
  job_spec_config = check.opt_mapping_param(job_spec_config, "job_spec_config", key_type=str)
121
126
 
127
+ deployment_metadata = check.opt_mapping_param(
128
+ deployment_metadata, "deployment_metadata", key_type=str
129
+ )
130
+ service_metadata = check.opt_mapping_param(
131
+ service_metadata, "service_metadata", key_type=str
132
+ )
133
+
122
134
  if container_config:
123
135
  container_config = k8s_snake_case_dict(kubernetes.client.V1Container, container_config)
124
136
 
@@ -139,6 +151,14 @@ class UserDefinedDagsterK8sConfig(
139
151
  if job_spec_config:
140
152
  job_spec_config = k8s_snake_case_dict(kubernetes.client.V1JobSpec, job_spec_config)
141
153
 
154
+ if deployment_metadata:
155
+ deployment_metadata = k8s_snake_case_dict(
156
+ kubernetes.client.V1ObjectMeta, deployment_metadata
157
+ )
158
+
159
+ if service_metadata:
160
+ service_metadata = k8s_snake_case_dict(kubernetes.client.V1ObjectMeta, service_metadata)
161
+
142
162
  return super(UserDefinedDagsterK8sConfig, cls).__new__(
143
163
  cls,
144
164
  container_config=container_config,
@@ -147,6 +167,8 @@ class UserDefinedDagsterK8sConfig(
147
167
  job_config=job_config,
148
168
  job_metadata=job_metadata,
149
169
  job_spec_config=job_spec_config,
170
+ deployment_metadata=deployment_metadata,
171
+ service_metadata=service_metadata,
150
172
  merge_behavior=check.inst_param(
151
173
  merge_behavior, "merge_behavior", K8sConfigMergeBehavior
152
174
  ),
@@ -160,6 +182,8 @@ class UserDefinedDagsterK8sConfig(
160
182
  "job_config": self.job_config,
161
183
  "job_metadata": self.job_metadata,
162
184
  "job_spec_config": self.job_spec_config,
185
+ "deployment_metadata": self.deployment_metadata,
186
+ "service_metadata": self.service_metadata,
163
187
  "merge_behavior": self.merge_behavior.value,
164
188
  }
165
189
 
@@ -172,6 +196,8 @@ class UserDefinedDagsterK8sConfig(
172
196
  job_config=config_dict.get("job_config"),
173
197
  job_metadata=config_dict.get("job_metadata"),
174
198
  job_spec_config=config_dict.get("job_spec_config"),
199
+ deployment_metadata=config_dict.get("deployment_metadata"),
200
+ service_metadata=config_dict.get("service_metadata"),
175
201
  merge_behavior=K8sConfigMergeBehavior(
176
202
  config_dict.get("merge_behavior", K8sConfigMergeBehavior.DEEP.value)
177
203
  ),
@@ -205,7 +231,7 @@ def get_user_defined_k8s_config(tags: Mapping[str, str]):
205
231
 
206
232
  if USER_DEFINED_K8S_CONFIG_KEY in tags:
207
233
  user_defined_k8s_config_value = json.loads(tags[USER_DEFINED_K8S_CONFIG_KEY])
208
- result = validate_config(USER_DEFINED_K8S_CONFIG_SCHEMA, user_defined_k8s_config_value)
234
+ result = validate_config(USER_DEFINED_K8S_JOB_CONFIG_SCHEMA, user_defined_k8s_config_value)
209
235
 
210
236
  if not result.success:
211
237
  raise DagsterInvalidConfigError(
@@ -232,6 +258,8 @@ def get_user_defined_k8s_config(tags: Mapping[str, str]):
232
258
  job_config=user_defined_k8s_config.get("job_config"),
233
259
  job_metadata=user_defined_k8s_config.get("job_metadata"),
234
260
  job_spec_config=user_defined_k8s_config.get("job_spec_config"),
261
+ deployment_metadata=user_defined_k8s_config.get("deployment_metadata"),
262
+ service_metadata=user_defined_k8s_config.get("service_metadata"),
235
263
  merge_behavior=K8sConfigMergeBehavior(
236
264
  user_defined_k8s_config.get("merge_behavior", K8sConfigMergeBehavior.DEEP.value)
237
265
  ),
@@ -465,6 +493,7 @@ class DagsterK8sJobConfig(
465
493
  "job_spec_config": Field(
466
494
  Map(key_type=str, inner_type=bool), is_required=False
467
495
  ),
496
+ "namespace": Field(BoolSource, is_required=False),
468
497
  }
469
498
  ),
470
499
  is_required=False,
@@ -647,7 +676,7 @@ class DagsterK8sJobConfig(
647
676
  ),
648
677
  ),
649
678
  "run_k8s_config": Field(
650
- USER_DEFINED_K8S_CONFIG_SCHEMA,
679
+ USER_DEFINED_K8S_JOB_CONFIG_SCHEMA,
651
680
  is_required=False,
652
681
  description="Raw Kubernetes configuration for launched runs.",
653
682
  ),
@@ -661,6 +690,8 @@ class DagsterK8sJobConfig(
661
690
  DagsterEnum.from_python_enum(K8sConfigMergeBehavior),
662
691
  is_required=False,
663
692
  ),
693
+ "deployment_metadata": Permissive(),
694
+ "service_metadata": Permissive(),
664
695
  }
665
696
  ),
666
697
  is_required=False,
@@ -163,6 +163,8 @@ def execute_k8s_job(
163
163
  job_spec_config: Optional[Dict[str, Any]] = None,
164
164
  k8s_job_name: Optional[str] = None,
165
165
  merge_behavior: K8sConfigMergeBehavior = K8sConfigMergeBehavior.DEEP,
166
+ delete_failed_k8s_jobs: Optional[bool] = True,
167
+ _kubeconfig_file_context: Optional[str] = None,
166
168
  ):
167
169
  """This function is a utility for executing a Kubernetes job from within a Dagster op.
168
170
 
@@ -238,6 +240,11 @@ def execute_k8s_job(
238
240
  are recursively merged, appending list fields together and merging dictionary fields.
239
241
  Setting it to SHALLOW will make the dictionaries shallowly merged - any shared values
240
242
  in the dictionaries will be replaced by the values set on this op.
243
+ delete_failed_k8s_jobs (bool): Whether to immediately delete failed Kubernetes jobs. If False,
244
+ failed jobs will remain accessible through the Kubernetes API until deleted by a user or cleaned up by the
245
+ .spec.ttlSecondsAfterFinished parameter of the job.
246
+ (https://kubernetes.io/docs/concepts/workloads/controllers/ttlafterfinished/).
247
+ Defaults to True.
241
248
  """
242
249
  run_container_context = K8sContainerContext.create_for_run(
243
250
  context.dagster_run,
@@ -320,7 +327,7 @@ def execute_k8s_job(
320
327
  if load_incluster_config:
321
328
  kubernetes.config.load_incluster_config()
322
329
  else:
323
- kubernetes.config.load_kube_config(kubeconfig_file)
330
+ kubernetes.config.load_kube_config(kubeconfig_file, context=_kubeconfig_file_context)
324
331
 
325
332
  # changing this to be able to be passed in will allow for unit testing
326
333
  api_client = DagsterKubernetesClient.production_client()
@@ -409,10 +416,11 @@ def execute_k8s_job(
409
416
  num_pods_to_wait_for=num_pods_to_wait_for,
410
417
  )
411
418
  except (DagsterExecutionInterruptedError, Exception) as e:
412
- context.log.info(
413
- f"Deleting Kubernetes job {job_name} in namespace {namespace} due to exception"
414
- )
415
- api_client.delete_job(job_name=job_name, namespace=namespace)
419
+ if delete_failed_k8s_jobs:
420
+ context.log.info(
421
+ f"Deleting Kubernetes job {job_name} in namespace {namespace} due to exception"
422
+ )
423
+ api_client.delete_job(job_name=job_name, namespace=namespace)
416
424
  raise e
417
425
 
418
426
 
@@ -0,0 +1 @@
1
+ __version__ = "0.24.11"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: dagster-k8s
3
- Version: 0.24.10
3
+ Version: 0.24.11
4
4
  Summary: A Dagster integration for k8s
5
5
  Home-page: https://github.com/dagster-io/dagster/tree/master/python_modules/libraries/dagster-k8s
6
6
  Author: Dagster Labs
@@ -1,3 +1,3 @@
1
- dagster==1.8.10
1
+ dagster==1.8.11
2
2
  kubernetes<32
3
3
  google-auth!=2.23.1
@@ -44,7 +44,7 @@ setup(
44
44
  include_package_data=True,
45
45
  python_requires=">=3.8,<3.13",
46
46
  install_requires=[
47
- "dagster==1.8.10",
47
+ "dagster==1.8.11",
48
48
  f"kubernetes<{KUBERNETES_VERSION_UPPER_BOUND}",
49
49
  # exclude a google-auth release that added an overly restrictive urllib3 pin that confuses dependency resolvers
50
50
  "google-auth!=2.23.1",
@@ -1 +0,0 @@
1
- __version__ = "0.24.10"
File without changes
File without changes
File without changes
File without changes