~rjarry/dlrepo

This thread contains a patchset. You're looking at the original emails, but you may wish to use the patch review UI. Review patch
2 2

[PATCH dlrepo] container: fix pull with no tag

Details
Message ID
<20241213095453.1432225-1-julien.floret@6wind.com>
DKIM signature
pass
Download raw message
Patch: +24 -4
When doing a container pull with no tag (or ":latest"):

> docker pull <registry>/<branch>/<job>

Before this patch, the "latest" tag was selected from all available
tags in /branches/<branch>, not from the tags available for that
specific container. As a consequence, if the container did not exist
in the latest tag, the "docker pull" or equivalent
command returned an error like:

> Error response from daemon: manifest for <img>:latest not found: manifest unknown: latest

Fix that by adding an optional "filter_names" argument to
Branch.get_tag(): when resolving a dynamic tag like "latest", tags
that are not part of filter_names are skipped.

In the container view, filter_names is set to
self.registry().job_tags(), because that method selects only the tags
available for the requested container (the tags where <job> exists AND
has a "container" format).

So, after this patch, the "latest" tag resolves to "the latest tag for
that container image". This is consistent with the output of the
/v2/<branch>/<job>/tags/list URL route.

The same logic is applied to the product view.

Signed-off-by: Julien Floret <julien.floret@6wind.com>
Acked-by: Olivier Matz <olivier.matz@6wind.com>
---
 dlrepo/fs/branch.py       |  9 ++++++++-
 dlrepo/fs/product.py      |  9 ++++++++-
 dlrepo/views/container.py | 10 ++++++++--
 3 files changed, 24 insertions(+), 4 deletions(-)

diff --git a/dlrepo/fs/branch.py b/dlrepo/fs/branch.py
index 8b6940c19d62..ebbcaf42bc5c 100644
--- a/dlrepo/fs/branch.py
+++ b/dlrepo/fs/branch.py
@@ -35,9 +35,16 @@ class Branch(SubDir):
                continue
            yield t

    def get_tag(self, name: str, access_cb: Callable[[str], bool] = None) -> Tag:
    def get_tag(
        self,
        name: str,
        access_cb: Callable[[str], bool] = None,
        filter_names: list[str] = None,
    ) -> Tag:
        if name in ("latest", "stable", "oldstable"):
            tags = list(self.get_tags(access_cb))
            if filter_names:
                tags = [tag for tag in tags if tag.name in filter_names]
            tags.sort(key=Tag.creation_date, reverse=True)
            first = True
            for t in tags:
diff --git a/dlrepo/fs/product.py b/dlrepo/fs/product.py
index 4c05440ff544..1e974c3765c1 100644
--- a/dlrepo/fs/product.py
+++ b/dlrepo/fs/product.py
@@ -63,10 +63,17 @@ class ProductBranch(SubDir):
            yield v

    def get_version(
        self, name: str, access_cb: Callable[[str], bool] = None
        self,
        name: str,
        access_cb: Callable[[str], bool] = None,
        filter_names: list[str] = None,
    ) -> "Version":
        if name in ("latest", "stable", "oldstable"):
            versions = list(self.get_versions(access_cb))
            if filter_names:
                versions = [
                    version for version in versions if version.name in filter_names
                ]
            versions.sort(key=Version.creation_date, reverse=True)
            first = True
            for v in versions:
diff --git a/dlrepo/views/container.py b/dlrepo/views/container.py
index 73ca7d8b262b..c4bb9b65c2a7 100644
--- a/dlrepo/views/container.py
+++ b/dlrepo/views/container.py
@@ -79,18 +79,24 @@ class ManifestReadOnlyView(ContainerView):
                digest = ref
            else:
                if "product" in match:
                    filter_names = self.registry().product_tags(
                        match["product"], match["variant"], match["product_branch"]
                    )
                    parent = (
                        self.repo()
                        .get_product(match["product"])
                        .get_variant(match["variant"])
                        .get_branch(match["product_branch"])
                        .get_version(ref, self.access_granted)
                        .get_version(ref, self.access_granted, filter_names)
                    )
                else:
                    filter_names = self.registry().job_tags(
                        match["branch"], match["job"]
                    )
                    parent = (
                        self.repo()
                        .get_branch(match["branch"])
                        .get_tag(ref, self.access_granted)
                        .get_tag(ref, self.access_granted, filter_names)
                        .get_job(match["job"])
                    )
                path, digest = registry.manifest_by_parent(parent.path())
-- 
2.39.2

[dlrepo/patches/.build.yml] build success

builds.sr.ht <builds@sr.ht>
Details
Message ID
<D6AHDVJD4Y3N.2NK2BMXRMRAXV@fra01>
In-Reply-To
<20241213095453.1432225-1-julien.floret@6wind.com> (view parent)
DKIM signature
missing
Download raw message
dlrepo/patches/.build.yml: SUCCESS in 42s

[container: fix pull with no tag][0] from [Julien Floret][1]

[0]: https://lists.sr.ht/~rjarry/dlrepo/patches/56410
[1]: julien.floret@6wind.com

✓ #1389069 SUCCESS dlrepo/patches/.build.yml https://builds.sr.ht/~rjarry/job/1389069

Applied: [PATCH dlrepo] container: fix pull with no tag

Details
Message ID
<173409262739.2055252.17101074649527115408@ringo>
In-Reply-To
<20241213095453.1432225-1-julien.floret@6wind.com> (view parent)
DKIM signature
pass
Download raw message
Julien Floret <julien.floret@6wind.com> wrote:
> When doing a container pull with no tag (or ":latest"):
>
> > docker pull <registry>/<branch>/<job>
>
> Before this patch, the "latest" tag was selected from all available
> tags in /branches/<branch>, not from the tags available for that
> specific container. As a consequence, if the container did not exist
> in the latest tag, the "docker pull" or equivalent
> command returned an error like:
>
> > Error response from daemon: manifest for <img>:latest not found: manifest unknown: latest
>
> Fix that by adding an optional "filter_names" argument to
> Branch.get_tag(): when resolving a dynamic tag like "latest", tags
> that are not part of filter_names are skipped.
>
> In the container view, filter_names is set to
> self.registry().job_tags(), because that method selects only the tags
> available for the requested container (the tags where <job> exists AND
> has a "container" format).
>
> So, after this patch, the "latest" tag resolves to "the latest tag for
> that container image". This is consistent with the output of the
> /v2/<branch>/<job>/tags/list URL route.
>
> The same logic is applied to the product view.
>
> Signed-off-by: Julien Floret <julien.floret@6wind.com>
> Acked-by: Olivier Matz <olivier.matz@6wind.com>
> ---

Acked-by: Robin Jarry <robin@jarry.cc>

Applied, thanks.

To git@git.sr.ht:~rjarry/dlrepo
   35d6942b29a0..951fd0251f8c  main -> main
Reply to thread Export thread (mbox)