Skip to content

Commit

Permalink
fix: Temporarily remove urls from manifest, because containerd can no…
Browse files Browse the repository at this point in the history
…t fetch external urls from self-signed registry
  • Loading branch information
shabbywu committed Apr 12, 2024
1 parent bcc45d6 commit 97fb711
Show file tree
Hide file tree
Showing 4 changed files with 95 additions and 16 deletions.
2 changes: 1 addition & 1 deletion moby_distribution/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
OCIManifestSchema1,
)

__version__ = "0.8.1"
__version__ = "0.8.2"
__all__ = [
"DockerRegistryV2Client",
"Blob",
Expand Down
64 changes: 50 additions & 14 deletions moby_distribution/registry/resources/manifests.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,24 @@

import libtrust

from moby_distribution.registry.client import DockerRegistryV2Client, URLBuilder, default_client
from moby_distribution.registry.client import (
DockerRegistryV2Client,
URLBuilder,
default_client,
)
from moby_distribution.registry.exceptions import ResourceNotFound, UnSupportMediaType
from moby_distribution.registry.resources import RepositoryResource
from moby_distribution.registry.utils import TypeTimeout, client_default_timeout, get_private_key
from moby_distribution.spec.manifest import ManifestDescriptor, ManifestSchema1, ManifestSchema2, OCIManifestSchema1
from moby_distribution.registry.utils import (
TypeTimeout,
client_default_timeout,
get_private_key,
)
from moby_distribution.spec.manifest import (
ManifestDescriptor,
ManifestSchema1,
ManifestSchema2,
OCIManifestSchema1,
)


class ManifestRef(RepositoryResource):
Expand All @@ -33,18 +46,24 @@ def get(self, media_type: str = ManifestSchema2.content_type()):
raise UnSupportMediaType(media_type)

type_ = self.TYPES[media_type]
url = URLBuilder.build_manifests_url(self.client.api_base_url, self.repo, self.reference)
url = URLBuilder.build_manifests_url(
self.client.api_base_url, self.repo, self.reference
)
headers = {"Accept": media_type}
data = self.client.get(url=url, headers=headers, timeout=self.timeout).json()
return type_(**data)

def get_metadata(self, media_type: str = ManifestSchema2.content_type()) -> Optional[ManifestDescriptor]:
def get_metadata(
self, media_type: str = ManifestSchema2.content_type()
) -> Optional[ManifestDescriptor]:
"""return ManifestDescriptor if the manifest exists."""
if media_type not in self.TYPES:
raise UnSupportMediaType(media_type)

headers = {"Accept": media_type}
url = URLBuilder.build_manifests_url(self.client.api_base_url, self.repo, self.reference)
url = URLBuilder.build_manifests_url(
self.client.api_base_url, self.repo, self.reference
)
try:
resp = self.client.head(url=url, headers=headers, timeout=self.timeout)
except ResourceNotFound:
Expand All @@ -69,7 +88,9 @@ def delete(self, raise_not_found: bool = True) -> bool:
raise ResourceNotFound
return False

url = URLBuilder.build_manifests_url(self.client.api_base_url, self.repo, descriptor.digest)
url = URLBuilder.build_manifests_url(
self.client.api_base_url, self.repo, descriptor.digest
)
try:
resp = self.client.delete(url=url, timeout=self.timeout)
except ResourceNotFound:
Expand All @@ -79,7 +100,9 @@ def delete(self, raise_not_found: bool = True) -> bool:

return resp.ok

def put(self, manifest: Union[ManifestSchema1, ManifestSchema2, OCIManifestSchema1]) -> bool:
def put(
self, manifest: Union[ManifestSchema1, ManifestSchema2, OCIManifestSchema1]
) -> bool:
"""creates or updates the given manifest."""
if isinstance(manifest, ManifestSchema1):
resp = self._put_legacy_manifest(manifest)
Expand All @@ -90,7 +113,9 @@ def put(self, manifest: Union[ManifestSchema1, ManifestSchema2, OCIManifestSchem

def _put_legacy_manifest(self, manifest: ManifestSchema1):
"""put the docker schema 1 manifest with signed signature to the repository"""
url = URLBuilder.build_manifests_url(self.client.api_base_url, self.repo, self.reference)
url = URLBuilder.build_manifests_url(
self.client.api_base_url, self.repo, self.reference
)
private_key = get_private_key()
data = manifest.json(
include={
Expand All @@ -100,18 +125,29 @@ def _put_legacy_manifest(self, manifest: ManifestSchema1):
"fsLayers",
"history",
"schemaVersion",
}
},
)
js = libtrust.JSONSignature.new(data)
js.sign(private_key)

headers = {"Content-Type": manifest.content_type()}
data = js.to_pretty_signature("signatures")
return self.client.put(url=url, data=data, headers=headers, timeout=self.timeout)
return self.client.put(
url=url, data=data, headers=headers, timeout=self.timeout
)

def _put_new_manifest(self, manifest: Union[ManifestSchema2, OCIManifestSchema1]):
"""put the docker schema 2 manifest or OCI manifest to the repository"""
url = URLBuilder.build_manifests_url(self.client.api_base_url, self.repo, self.reference)
url = URLBuilder.build_manifests_url(
self.client.api_base_url, self.repo, self.reference
)
headers = {"Content-Type": manifest.content_type()}
data = manifest.json()
return self.client.put(url=url, data=data, headers=headers, timeout=self.timeout)
data = manifest.json(
exclude={
"config": {"urls"},
"layers": {"__all__": {"urls"}},
}
)
return self.client.put(
url=url, data=data, headers=headers, timeout=self.timeout
)
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "moby-distribution"
version = "0.8.1"
version = "0.8.2"
description = "Yet another moby(docker) distribution implement by python."
authors = ["shabbywu <[email protected]>"]
license = "Apache-2.0"
Expand Down
43 changes: 43 additions & 0 deletions tests/integration/resources/test_manifests.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
import hashlib
import json

import docker
import pytest
from moby_distribution.registry.resources.image import (
ImageRef,
LayerRef,
ManifestSchema2,
)
from moby_distribution.registry.client import URLBuilder

try:
from pydantic import __version__ as pydantic_version
Expand Down Expand Up @@ -74,3 +81,39 @@ def test_get_metadata(
descriptor.digest
== f"sha256:{hashlib.sha256(dumped.encode()).hexdigest()}"
)


class TestIntegration:
@pytest.fixture()
def docker_cli(self):
return docker.from_env()

@pytest.fixture(autouse=True)
def _init_image(
self,
registry_client,
tmp_path,
alpine_tar,
alpine_append_layer,
docker_cli,
registry_netloc,
):
ref = ImageRef.from_tarball(
workplace=tmp_path,
src=alpine_tar,
to_repo="alpine",
to_reference="manifest",
client=registry_client,
)
ref.add_layer(LayerRef(local_path=alpine_append_layer))
ref.push()

def test_inspect(self, registry_client):
url = URLBuilder.build_manifests_url(
registry_client.api_base_url, repo="alpine", reference="manifest"
)
headers = {"Accept": ManifestSchema2.content_type()}
data = registry_client.get(url=url, headers=headers).json()
assert data["config"].get("urls", []) == []
for layer in data["layers"]:
assert layer.get("urls", []) == []

0 comments on commit 97fb711

Please sign in to comment.