From 6cace20ef5c79d67028448dd39f59529fdff8367 Mon Sep 17 00:00:00 2001 From: Prince Rachit Sinha Date: Tue, 21 Jun 2022 06:08:33 +0000 Subject: [PATCH] [image-builder] replace alias ref with repo for x-mount --- .../image-builder-bob/pkg/proxy/proxy.go | 20 +++++--- .../image-builder-bob/pkg/proxy/proxy_test.go | 47 ++++++++++++++++++- 2 files changed, 58 insertions(+), 9 deletions(-) diff --git a/components/image-builder-bob/pkg/proxy/proxy.go b/components/image-builder-bob/pkg/proxy/proxy.go index 63bfcd82514c41..4fda88121a6f08 100644 --- a/components/image-builder-bob/pkg/proxy/proxy.go +++ b/components/image-builder-bob/pkg/proxy/proxy.go @@ -52,7 +52,7 @@ type Repo struct { Auth func() docker.Authorizer } -func rewriteDockerAPIURL(u *url.URL, fromRepo, toRepo, host, tag string) { +func (proxy *Proxy) rewriteDockerAPIURL(u *url.URL, fromRepo, toRepo, host, tag string) { var ( from = "/v2/" + strings.Trim(fromRepo, "/") + "/" to = "/v2/" + strings.Trim(toRepo, "/") + "/" @@ -75,13 +75,19 @@ func rewriteDockerAPIURL(u *url.URL, fromRepo, toRepo, host, tag string) { u.Path = strings.Join(segs, "/") } } - + if u.RawQuery != "" { + // As per OCI distribution spec this (from=) should be the only possible reference to a cross repo + // https://github.com/opencontainers/distribution-spec/blob/main/spec.md#push + for k, v := range proxy.Aliases { + u.RawQuery = strings.Replace(u.RawQuery, "from="+k, "from="+v.Repo, 1) + } + } u.Host = host } // rewriteNonDockerAPIURL is used when a url has to be rewritten but the url // contains a non docker api path -func rewriteNonDockerAPIURL(u *url.URL, fromPrefix, toPrefix, host string) { +func (proxy *Proxy) rewriteNonDockerAPIURL(u *url.URL, fromPrefix, toPrefix, host string) { var ( from = "/" + strings.Trim(fromPrefix, "/") + "/" to = "/" + strings.Trim(toPrefix, "/") + "/" @@ -113,7 +119,7 @@ func (proxy *Proxy) ServeHTTP(w http.ResponseWriter, r *http.Request) { if strings.HasPrefix(r.URL.Path, "/v2/"+k+"/") { repo = &v alias = k - rewriteDockerAPIURL(r.URL, alias, repo.Repo, repo.Host, repo.Tag) + proxy.rewriteDockerAPIURL(r.URL, alias, repo.Repo, repo.Host, repo.Tag) break } // Non-Docker api request @@ -122,7 +128,7 @@ func (proxy *Proxy) ServeHTTP(w http.ResponseWriter, r *http.Request) { // repo as empty repo = &v alias = k - rewriteNonDockerAPIURL(r.URL, alias, "", repo.Host) + proxy.rewriteNonDockerAPIURL(r.URL, alias, "", repo.Host) break } } @@ -225,13 +231,13 @@ func (proxy *Proxy) reverse(alias string) *httputil.ReverseProxy { } if strings.HasPrefix(loc, "/v2/") { - rewriteDockerAPIURL(lurl, repo.Repo, alias, proxy.Host.Host, "") + proxy.rewriteDockerAPIURL(lurl, repo.Repo, alias, proxy.Host.Host, "") } else { // since this is a non docker api location we // do not need to process the path. // All docker api URLs always start with /v2/. See spec // https://github.com/opencontainers/distribution-spec/blob/main/spec.md#endpoints - rewriteNonDockerAPIURL(lurl, "", alias, repo.Host) + proxy.rewriteNonDockerAPIURL(lurl, "", alias, repo.Host) } lurl.Host = proxy.Host.Host diff --git a/components/image-builder-bob/pkg/proxy/proxy_test.go b/components/image-builder-bob/pkg/proxy/proxy_test.go index f1dc6c03c53269..f7eb19dd8cd77f 100644 --- a/components/image-builder-bob/pkg/proxy/proxy_test.go +++ b/components/image-builder-bob/pkg/proxy/proxy_test.go @@ -11,6 +11,7 @@ import ( func TestRewriteNonDockerAPIURL(t *testing.T) { type input struct { + proxy *Proxy u url.URL fromPrefix string toPrefix string @@ -24,6 +25,7 @@ func TestRewriteNonDockerAPIURL(t *testing.T) { { Name: "toPrefix is empty", in: input{ + proxy: &Proxy{}, fromPrefix: "base", toPrefix: "", host: "europe-docker.pkg.dev", @@ -40,6 +42,7 @@ func TestRewriteNonDockerAPIURL(t *testing.T) { { Name: "fromPrefix is empty", in: input{ + proxy: &Proxy{}, fromPrefix: "", toPrefix: "base", host: "localhost.com", @@ -56,6 +59,7 @@ func TestRewriteNonDockerAPIURL(t *testing.T) { { Name: "fromPrefix and toPrefix are not empty", in: input{ + proxy: &Proxy{}, fromPrefix: "from", toPrefix: "to", host: "localhost.com", @@ -72,6 +76,7 @@ func TestRewriteNonDockerAPIURL(t *testing.T) { { Name: "fromPrefix and toPrefix are empty", in: input{ + proxy: &Proxy{}, fromPrefix: "", toPrefix: "", host: "localhost.com", @@ -89,7 +94,7 @@ func TestRewriteNonDockerAPIURL(t *testing.T) { for _, test := range tests { t.Run(test.Name, func(t *testing.T) { - rewriteNonDockerAPIURL(&test.in.u, test.in.fromPrefix, test.in.toPrefix, test.in.host) + test.in.proxy.rewriteNonDockerAPIURL(&test.in.u, test.in.fromPrefix, test.in.toPrefix, test.in.host) if test.in.u.Path != test.u.Path { t.Errorf("expected path: %s but got %s", test.u.Path, test.in.u.Path) } @@ -106,6 +111,7 @@ func TestRewriteNonDockerAPIURL(t *testing.T) { func TestRewriteDockerAPIURL(t *testing.T) { type input struct { + proxy *Proxy u url.URL fromRepo string toRepo string @@ -120,6 +126,7 @@ func TestRewriteDockerAPIURL(t *testing.T) { { Name: "remote to localhost", in: input{ + proxy: &Proxy{}, fromRepo: "base-images", toRepo: "base", host: "localhost.com", @@ -137,6 +144,7 @@ func TestRewriteDockerAPIURL(t *testing.T) { { Name: "localhost to remote", in: input{ + proxy: &Proxy{}, fromRepo: "base", toRepo: "base-images", host: "prince.azurecr.io", @@ -154,6 +162,7 @@ func TestRewriteDockerAPIURL(t *testing.T) { { Name: "manifest reference update with tag", in: input{ + proxy: &Proxy{}, fromRepo: "base", toRepo: "base-images", host: "prince.azurecr.io", @@ -168,14 +177,48 @@ func TestRewriteDockerAPIURL(t *testing.T) { Path: "/v2/base-images/uploads/manifests/tag12345", }, }, + { + Name: "updates alias reference when it is cross blob mount", + in: input{ + proxy: &Proxy{ + Host: url.URL{Host: "localhost:8080", Scheme: "http"}, + Aliases: map[string]Repo{ + "base": { + Repo: "/gitpod/base-images", + }, + "target": { + Repo: "/gitpod/workspace-images", + }, + }, + proxies: nil, + }, + fromRepo: "base", + toRepo: "/gitpod/base-images", + host: "registry.gitlab.com", + tag: "tag12345", + u: url.URL{ + Host: "localhost.com", + RawQuery: "mount=sha:12345&from=base", + Path: "/v2/base/mounts/uploads/", + }, + }, + u: url.URL{ + Host: "registry.gitlab.com", + Path: "/v2/gitpod/base-images/mounts/uploads/", + RawQuery: "mount=sha:12345&from=/gitpod/base-images", + }, + }, } for _, test := range tests { t.Run(test.Name, func(t *testing.T) { - rewriteDockerAPIURL(&test.in.u, test.in.fromRepo, test.in.toRepo, test.in.host, test.in.tag) + test.in.proxy.rewriteDockerAPIURL(&test.in.u, test.in.fromRepo, test.in.toRepo, test.in.host, test.in.tag) if test.in.u.Path != test.u.Path { t.Errorf("expected path: %s but got %s", test.u.Path, test.in.u.Path) } + if test.in.u.RawQuery != test.u.RawQuery { + t.Errorf("expected raw query: %s but got %s", test.u.RawQuery, test.in.u.RawQuery) + } if test.in.u.Host != test.u.Host { t.Errorf("expected Host: %s but got %s", test.u.Host, test.in.u.Host) }