diff --git a/pkg/v1/remote/check.go b/pkg/v1/remote/check.go index 25d86956f..e714a330f 100644 --- a/pkg/v1/remote/check.go +++ b/pkg/v1/remote/check.go @@ -39,7 +39,7 @@ func CheckPushPermission(ref name.Reference, kc authn.Keychain, t http.RoundTrip client: &http.Client{Transport: tr}, context: context.Background(), } - loc, _, err := w.initiateUpload("", "") + loc, _, err := w.initiateUpload("", "", "") if loc != "" { // Since we're only initiating the upload to check whether we // can, we should attempt to cancel it, in case initiating diff --git a/pkg/v1/remote/write.go b/pkg/v1/remote/write.go index d412f953c..fb3dd7974 100644 --- a/pkg/v1/remote/write.go +++ b/pkg/v1/remote/write.go @@ -267,13 +267,16 @@ func (w *writer) checkExistingManifest(h v1.Hash, mt types.MediaType) (bool, err // On success, the layer was either mounted (nothing more to do) or a blob // upload was initiated and the body of that blob should be sent to the returned // location. -func (w *writer) initiateUpload(from, mount string) (location string, mounted bool, err error) { +func (w *writer) initiateUpload(from, mount, origin string) (location string, mounted bool, err error) { u := w.url(fmt.Sprintf("/v2/%s/blobs/uploads/", w.repo.RepositoryStr())) uv := url.Values{} if mount != "" && from != "" { // Quay will fail if we specify a "mount" without a "from". - uv["mount"] = []string{mount} - uv["from"] = []string{from} + uv.Set("mount", mount) + uv.Set("from", from) + if origin != "" { + uv.Set("origin", origin) + } } u.RawQuery = uv.Encode() @@ -411,7 +414,7 @@ func (w *writer) incrProgress(written int64) { // uploadOne performs a complete upload of a single layer. func (w *writer) uploadOne(ctx context.Context, l v1.Layer) error { tryUpload := func() error { - var from, mount string + var from, mount, origin string if h, err := l.Digest(); err == nil { // If we know the digest, this isn't a streaming layer. Do an existence // check so we can skip uploading the layer if possible. @@ -432,12 +435,11 @@ func (w *writer) uploadOne(ctx context.Context, l v1.Layer) error { mount = h.String() } if ml, ok := l.(*MountableLayer); ok { - if w.repo.RegistryStr() == ml.Reference.Context().RegistryStr() { - from = ml.Reference.Context().RepositoryStr() - } + from = ml.Reference.Context().RepositoryStr() + origin = ml.Reference.Context().RegistryStr() } - location, mounted, err := w.initiateUpload(from, mount) + location, mounted, err := w.initiateUpload(from, mount, origin) if err != nil { return err } else if mounted { diff --git a/pkg/v1/remote/write_test.go b/pkg/v1/remote/write_test.go index 399628c82..3d031c1a8 100644 --- a/pkg/v1/remote/write_test.go +++ b/pkg/v1/remote/write_test.go @@ -257,7 +257,7 @@ func TestInitiateUploadNoMountsExists(t *testing.T) { } defer closer.Close() - _, mounted, err := w.initiateUpload("baz/bar", h.String()) + _, mounted, err := w.initiateUpload("baz/bar", h.String(), "") if err != nil { t.Errorf("intiateUpload() = %v", err) } @@ -295,7 +295,7 @@ func TestInitiateUploadNoMountsInitiated(t *testing.T) { } defer closer.Close() - location, mounted, err := w.initiateUpload("baz/bar", h.String()) + location, mounted, err := w.initiateUpload("baz/bar", h.String(), "") if err != nil { t.Errorf("intiateUpload() = %v", err) } @@ -334,7 +334,7 @@ func TestInitiateUploadNoMountsBadStatus(t *testing.T) { } defer closer.Close() - location, mounted, err := w.initiateUpload("baz/bar", h.String()) + location, mounted, err := w.initiateUpload("baz/bar", h.String(), "") if err == nil { t.Errorf("intiateUpload() = %v, %v; wanted error", location, mounted) } @@ -367,7 +367,7 @@ func TestInitiateUploadMountsWithMountFromDifferentRegistry(t *testing.T) { } defer closer.Close() - _, mounted, err := w.initiateUpload("baz/bar", h.String()) + _, mounted, err := w.initiateUpload("baz/bar", h.String(), "") if err != nil { t.Errorf("intiateUpload() = %v", err) } @@ -407,7 +407,49 @@ func TestInitiateUploadMountsWithMountFromTheSameRegistry(t *testing.T) { } defer closer.Close() - _, mounted, err := w.initiateUpload(expectedMountRepo, h.String()) + _, mounted, err := w.initiateUpload(expectedMountRepo, h.String(), "") + if err != nil { + t.Errorf("intiateUpload() = %v", err) + } + if !mounted { + t.Error("initiateUpload() = !mounted, want mounted") + } +} + +func TestInitiateUploadMountsWithOrigin(t *testing.T) { + img := setupImage(t) + h := mustConfigName(t, img) + expectedMountRepo := "a/different/repo" + expectedRepo := "yet/again" + expectedPath := fmt.Sprintf("/v2/%s/blobs/uploads/", expectedRepo) + expectedOrigin := "fakeOrigin" + expectedQuery := url.Values{ + "mount": []string{h.String()}, + "from": []string{expectedMountRepo}, + "origin": []string{expectedOrigin}, + }.Encode() + + serverHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.Method != http.MethodPost { + t.Errorf("Method; got %v, want %v", r.Method, http.MethodPost) + } + if r.URL.Path != expectedPath { + t.Errorf("URL; got %v, want %v", r.URL.Path, expectedPath) + } + if r.URL.RawQuery != expectedQuery { + t.Errorf("RawQuery; got %v, want %v", r.URL.RawQuery, expectedQuery) + } + http.Error(w, "Mounted", http.StatusCreated) + }) + server := httptest.NewServer(serverHandler) + + w, closer, err := setupWriterWithServer(server, expectedRepo) + if err != nil { + t.Fatalf("setupWriterWithServer() = %v", err) + } + defer closer.Close() + + _, mounted, err := w.initiateUpload(expectedMountRepo, h.String(), "fakeOrigin") if err != nil { t.Errorf("intiateUpload() = %v", err) }