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
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