|
25 | 25 | from .constants import DIRECTOR_SIMCORE_SERVICES_PREFIX |
26 | 26 | from .core.errors import ( |
27 | 27 | DirectorRuntimeError, |
| 28 | + DockerRegistryUnsupportedManifestSchemaVersionError, |
28 | 29 | RegistryConnectionError, |
29 | 30 | ServiceNotAvailableError, |
30 | 31 | ) |
@@ -375,22 +376,55 @@ async def get_image_labels( |
375 | 376 | app: FastAPI, image: str, tag: str, *, update_cache=False |
376 | 377 | ) -> tuple[dict[str, str], str | None]: |
377 | 378 | """Returns image labels and the image manifest digest""" |
| 379 | + with log_context(_logger, logging.DEBUG, msg=f"get {image}:{tag} labels"): |
| 380 | + request_result, headers = await registry_request( |
| 381 | + app, |
| 382 | + path=f"{image}/manifests/{tag}", |
| 383 | + method="GET", |
| 384 | + use_cache=not update_cache, |
| 385 | + ) |
378 | 386 |
|
379 | | - _logger.debug("getting image labels of %s:%s", image, tag) |
380 | | - path = f"{image}/manifests/{tag}" |
381 | | - request_result, headers = await registry_request( |
382 | | - app, path=path, method="GET", use_cache=not update_cache |
383 | | - ) |
384 | | - v1_compatibility_key = json_loads(request_result["history"][0]["v1Compatibility"]) |
385 | | - container_config: dict[str, Any] = v1_compatibility_key.get( |
386 | | - "container_config", v1_compatibility_key["config"] |
387 | | - ) |
388 | | - labels: dict[str, str] = container_config["Labels"] |
389 | | - |
390 | | - headers = headers or {} |
391 | | - manifest_digest: str | None = headers.get(_DOCKER_CONTENT_DIGEST_HEADER, None) |
| 387 | + schema_version = request_result["schemaVersion"] |
| 388 | + labels: dict[str, str] = {} |
| 389 | + match schema_version: |
| 390 | + case 2: |
| 391 | + # Image Manifest Version 2, Schema 2 -> defaults in registries v3 (https://distribution.github.io/distribution/spec/manifest-v2-2/) |
| 392 | + media_type = request_result["mediaType"] |
| 393 | + if ( |
| 394 | + media_type |
| 395 | + == "application/vnd.docker.distribution.manifest.list.v2+json" |
| 396 | + ): |
| 397 | + raise DockerRegistryUnsupportedManifestSchemaVersionError( |
| 398 | + version=schema_version, |
| 399 | + service_name=image, |
| 400 | + service_tag=tag, |
| 401 | + reason="Multiple architectures images are currently not supported and need to be implemented", |
| 402 | + ) |
| 403 | + config_digest = request_result["config"]["digest"] |
| 404 | + # Fetch the config blob |
| 405 | + config_result, _ = await registry_request( |
| 406 | + app, |
| 407 | + path=f"{image}/blobs/{config_digest}", |
| 408 | + method="GET", |
| 409 | + use_cache=not update_cache, |
| 410 | + ) |
| 411 | + labels = config_result.get("config", {}).get("Labels", {}) |
| 412 | + case 1: |
| 413 | + # Image Manifest Version 2, Schema 1 deprecated in docker hub since 2024-11-04 |
| 414 | + v1_compatibility_key = json_loads( |
| 415 | + request_result["history"][0]["v1Compatibility"] |
| 416 | + ) |
| 417 | + container_config: dict[str, Any] = v1_compatibility_key.get( |
| 418 | + "container_config", v1_compatibility_key.get("config", {}) |
| 419 | + ) |
| 420 | + labels = container_config.get("Labels", {}) |
| 421 | + case _: |
| 422 | + raise DockerRegistryUnsupportedManifestSchemaVersionError( |
| 423 | + version=schema_version, service_name=image, service_tag=tag |
| 424 | + ) |
392 | 425 |
|
393 | | - _logger.debug("retrieved labels of image %s:%s", image, tag) |
| 426 | + headers = headers or {} |
| 427 | + manifest_digest: str | None = headers.get(_DOCKER_CONTENT_DIGEST_HEADER, None) |
394 | 428 |
|
395 | 429 | return (labels, manifest_digest) |
396 | 430 |
|
|
0 commit comments