Skip to content

Commit 2172a0e

Browse files
committed
Fixed all broken things
1 parent ed26186 commit 2172a0e

File tree

5 files changed

+89
-48
lines changed

5 files changed

+89
-48
lines changed

src/zenml/container_registries/base_container_registry.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -273,9 +273,8 @@ def registry_server_uri(self) -> str:
273273
if not registry_uri.startswith(("http://", "https://")):
274274
domain = registry_uri.split("/")[0]
275275
return f"https://{domain}"
276-
277-
return registry_uri
278276

277+
return registry_uri
279278

280279

281280
class BaseContainerRegistryFlavor(Flavor):

src/zenml/integrations/kubernetes/orchestrators/kube_utils.py

Lines changed: 49 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -386,6 +386,7 @@ def create_secret(
386386
namespace: str,
387387
secret_name: str,
388388
data: Dict[str, Optional[str]],
389+
secret_type: str = "Opaque",
389390
) -> None:
390391
"""Create a Kubernetes secret.
391392
@@ -394,10 +395,13 @@ def create_secret(
394395
namespace: The namespace in which to create the secret.
395396
secret_name: The name of the secret to create.
396397
data: The secret data.
398+
secret_type: The secret type.
397399
"""
398400
core_api.create_namespaced_secret(
399401
namespace=namespace,
400-
body=build_secret_manifest(name=secret_name, data=data),
402+
body=build_secret_manifest(
403+
name=secret_name, data=data, secret_type=secret_type
404+
),
401405
)
402406

403407

@@ -416,10 +420,20 @@ def update_secret(
416420
data: The secret data. If the value is None, the key will be removed
417421
from the secret.
418422
"""
423+
# For updates, we only patch the data field, not the type (which is immutable)
424+
import base64
425+
426+
encoded_data = {
427+
key: base64.b64encode(value.encode()).decode() if value else None
428+
for key, value in data.items()
429+
}
430+
431+
patch_body = {"data": encoded_data}
432+
419433
core_api.patch_namespaced_secret(
420434
namespace=namespace,
421435
name=secret_name,
422-
body=build_secret_manifest(name=secret_name, data=data),
436+
body=patch_body,
423437
)
424438

425439

@@ -428,6 +442,7 @@ def create_or_update_secret(
428442
namespace: str,
429443
secret_name: str,
430444
data: Dict[str, Optional[str]],
445+
secret_type: str = "Opaque",
431446
) -> None:
432447
"""Create a Kubernetes secret if it doesn't exist, or update it if it does.
433448
@@ -437,17 +452,35 @@ def create_or_update_secret(
437452
secret_name: The name of the secret to create or update.
438453
data: The secret data. If the value is None, the key will be removed
439454
from the secret.
455+
secret_type: The secret type.
440456
441457
Raises:
442458
ApiException: If the secret creation failed for any reason other than
443459
the secret already existing.
444460
"""
445461
try:
446-
create_secret(core_api, namespace, secret_name, data)
462+
create_secret(core_api, namespace, secret_name, data, secret_type)
447463
except ApiException as e:
448464
if e.status != 409:
449465
raise
450-
update_secret(core_api, namespace, secret_name, data)
466+
467+
# Check if the existing secret has a different type
468+
try:
469+
existing_secret = core_api.read_namespaced_secret(
470+
name=secret_name, namespace=namespace
471+
)
472+
if existing_secret.type != secret_type:
473+
# Delete the secret if the type is different (type is immutable)
474+
delete_secret(core_api, namespace, secret_name)
475+
create_secret(
476+
core_api, namespace, secret_name, data, secret_type
477+
)
478+
else:
479+
# Same type, just update the data
480+
update_secret(core_api, namespace, secret_name, data)
481+
except ApiException:
482+
# If we can't read the existing secret, try to update anyway
483+
update_secret(core_api, namespace, secret_name, data)
451484

452485

453486
def create_or_update_secret_from_manifest(
@@ -466,30 +499,37 @@ def create_or_update_secret_from_manifest(
466499
"""
467500
namespace = secret_manifest["metadata"]["namespace"]
468501
secret_name = secret_manifest["metadata"]["name"]
469-
502+
470503
# Extract data from manifest - handle both 'data' and 'stringData' fields
471504
secret_data = {}
472-
505+
473506
# Handle base64-encoded 'data' field
474507
if "data" in secret_manifest:
475508
import base64
509+
476510
for key, encoded_value in secret_manifest["data"].items():
477511
if encoded_value is not None:
478512
# Decode base64 data back to string
479-
secret_data[key] = base64.b64decode(encoded_value).decode('utf-8')
513+
secret_data[key] = base64.b64decode(encoded_value).decode(
514+
"utf-8"
515+
)
480516
else:
481517
secret_data[key] = None
482-
518+
483519
# Handle plain text 'stringData' field
484520
if "stringData" in secret_manifest:
485521
secret_data.update(secret_manifest["stringData"])
486-
522+
523+
# Extract secret type from manifest, default to "Opaque" if not specified
524+
secret_type = secret_manifest.get("type", "Opaque")
525+
487526
# Use the existing create_or_update_secret function
488527
create_or_update_secret(
489528
core_api=core_api,
490529
namespace=namespace,
491530
secret_name=secret_name,
492531
data=secret_data,
532+
secret_type=secret_type,
493533
)
494534

495535

src/zenml/integrations/kubernetes/orchestrators/kubernetes_orchestrator.py

Lines changed: 15 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -532,12 +532,12 @@ def submit_pipeline(
532532
"schedule. Use `Schedule(cron_expression=...)` instead."
533533
)
534534
cron_expression = deployment.schedule.cron_expression
535-
535+
536536
# Prepare dependencies for pod creation
537-
registry_credentials, local_stores_path = self._prepare_pod_dependencies(
538-
settings, stack
537+
registry_credentials, local_stores_path = (
538+
self._prepare_pod_dependencies(settings, stack)
539539
)
540-
540+
541541
cron_job_manifest, secret_manifests = build_cron_job_manifest(
542542
cron_expression=cron_expression,
543543
pod_name=pod_name,
@@ -574,13 +574,12 @@ def submit_pipeline(
574574
return None
575575
else:
576576
# Prepare dependencies for pod creation
577-
registry_credentials, local_stores_path = self._prepare_pod_dependencies(
578-
settings, stack
577+
registry_credentials, local_stores_path = (
578+
self._prepare_pod_dependencies(settings, stack)
579579
)
580-
580+
581581
# Create and run the orchestrator pod.
582582
pod_manifest, secret_manifests = build_pod_manifest(
583-
run_name=orchestrator_run_name,
584583
pod_name=pod_name,
585584
image_name=image,
586585
command=command,
@@ -675,16 +674,14 @@ def _get_service_account_name(
675674
return service_account_name
676675

677676
def _prepare_pod_dependencies(
678-
self,
679-
settings: KubernetesOrchestratorSettings,
680-
stack: "Stack"
677+
self, settings: KubernetesOrchestratorSettings, stack: "Stack"
681678
) -> Tuple[Optional[Tuple[str, str, str]], Optional[str]]:
682679
"""Prepare dependencies needed for pod manifest creation.
683-
680+
684681
Args:
685682
settings: The orchestrator settings.
686683
stack: The stack the pipeline will run on.
687-
684+
688685
Returns:
689686
Tuple of (registry_credentials, local_stores_path).
690687
"""
@@ -694,23 +691,23 @@ def _prepare_pod_dependencies(
694691
registry_credentials = self.get_kubernetes_image_pull_secret_data(
695692
stack.container_registry
696693
)
697-
694+
698695
# Get local stores path if mounting local stores
699696
local_stores_path = None
700697
if self.config.is_local:
701698
from zenml.config.global_config import GlobalConfiguration
702-
699+
703700
stack.check_local_paths()
704701
local_stores_path = GlobalConfiguration().local_stores_path
705-
702+
706703
return registry_credentials, local_stores_path
707704

708705
def _create_image_pull_secrets(
709706
self,
710707
secret_manifests: List[Dict[str, str]],
711708
) -> None:
712709
"""Create imagePullSecrets in the cluster.
713-
710+
714711
Args:
715712
secret_manifests: List of secret manifests for imagePullSecrets.
716713
"""
@@ -750,7 +747,7 @@ def get_kubernetes_image_pull_secret_data(
750747
751748
Returns:
752749
Tuple of (registry_uri, username, password) if credentials are available,
753-
None otherwise. The registry_uri is normalized for use in Kubernetes
750+
None otherwise. The registry_uri is normalized for use in Kubernetes
754751
imagePullSecrets.
755752
"""
756753
from zenml.logger import get_logger

src/zenml/integrations/kubernetes/orchestrators/kubernetes_orchestrator_entrypoint.py

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,15 @@ def run_step_on_kubernetes(step_name: str) -> None:
239239

240240
logger.info(f"Container registry: {active_stack.container_registry}")
241241

242+
# Get registry credentials for imagePullSecrets
243+
registry_credentials = None
244+
if pipeline_settings.auto_generate_image_pull_secrets:
245+
registry_credentials = (
246+
orchestrator.get_kubernetes_image_pull_secret_data(
247+
active_stack.container_registry
248+
)
249+
)
250+
242251
# Define Kubernetes pod manifest and any required secrets.
243252
pod_manifest, secret_manifests = build_pod_manifest(
244253
pod_name=pod_name,
@@ -252,20 +261,18 @@ def run_step_on_kubernetes(step_name: str) -> None:
252261
or settings.service_account_name,
253262
mount_local_stores=mount_local_stores,
254263
owner_references=owner_references,
255-
namespace=args.kubernetes_namespace,
264+
namespace=namespace,
256265
auto_generate_image_pull_secrets=pipeline_settings.auto_generate_image_pull_secrets,
257-
container_registry=active_stack.container_registry,
266+
registry_credentials=registry_credentials,
258267
core_api=core_api,
268+
labels=step_pod_labels,
259269
)
260270

261271
# Step pods should reuse secrets created by the orchestrator pod
262272
# Only create secrets if they don't already exist
263273
create_image_pull_secrets_from_manifests(
264274
secret_manifests=secret_manifests,
265275
core_api=core_api,
266-
namespace=args.kubernetes_namespace,
267-
reuse_existing=True, # Step pods reuse orchestrator-created secrets
268-
labels=step_pod_labels,
269276
)
270277

271278
kube_utils.create_and_wait_for_pod_to_start(
@@ -386,7 +393,7 @@ def finalize_run(node_states: Dict[str, NodeStatus]) -> None:
386393
logger.info("Cleaning up old imagePullSecrets...")
387394
cleanup_old_image_pull_secrets(
388395
core_api=core_api,
389-
namespace=args.kubernetes_namespace,
396+
namespace=namespace,
390397
max_age_hours=24, # Keep secrets for 24 hours
391398
)
392399

src/zenml/integrations/kubernetes/orchestrators/manifest_utils.py

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
from zenml.integrations.airflow.orchestrators.dag_generator import (
2727
ENV_ZENML_LOCAL_STORES_PATH,
2828
)
29+
from zenml.integrations.kubernetes.orchestrators import kube_utils
2930
from zenml.integrations.kubernetes.pod_settings import KubernetesPodSettings
3031
from zenml.logger import get_logger
3132

@@ -143,26 +144,25 @@ def _generate_image_pull_secrets(
143144
safe_registry_name = safe_registry_name[8:]
144145
elif safe_registry_name.startswith("http://"):
145146
safe_registry_name = safe_registry_name[7:]
146-
147+
147148
# Replace invalid characters for Kubernetes names
148149
safe_registry_name = (
149-
safe_registry_name
150-
.replace(".", "-")
150+
safe_registry_name.replace(".", "-")
151151
.replace("/", "-")
152152
.replace(":", "-")
153153
.replace("_", "-")
154154
.lower()
155155
)
156-
156+
157157
# Ensure it starts and ends with alphanumeric character
158158
safe_registry_name = safe_registry_name.strip("-")
159159
if not safe_registry_name:
160160
safe_registry_name = "registry"
161-
161+
162162
secret_name = f"zenml-registry-{safe_registry_name}-{i}"[
163163
:63
164164
] # K8s name limit
165-
165+
166166
# Final validation: ensure name is valid for Kubernetes
167167
# Must start and end with alphanumeric character
168168
if not secret_name[0].isalnum():
@@ -239,7 +239,7 @@ def create_image_pull_secrets_from_manifests(
239239
"""
240240
for secret_manifest in secret_manifests:
241241
secret_name = secret_manifest["metadata"]["name"]
242-
242+
243243
try:
244244
kube_utils.create_or_update_secret_from_manifest(
245245
core_api=core_api,
@@ -449,12 +449,10 @@ def build_pod_manifest(
449449
# Auto-generate imagePullSecrets from container registry credentials
450450
if auto_generate_image_pull_secrets and registry_credentials:
451451
try:
452-
generated_secrets, generated_refs = (
453-
_generate_image_pull_secrets(
454-
namespace=namespace,
455-
registry_credentials=registry_credentials,
456-
core_api=core_api,
457-
)
452+
generated_secrets, generated_refs = _generate_image_pull_secrets(
453+
namespace=namespace,
454+
registry_credentials=registry_credentials,
455+
core_api=core_api,
458456
)
459457
secret_manifests.extend(generated_secrets)
460458
image_pull_secrets.extend(generated_refs)

0 commit comments

Comments
 (0)