Skip to content

Commit

Permalink
Implement cross-registry blob mounting experiment (#1388)
Browse files Browse the repository at this point in the history
This is currently only implemented by Google but we'd like to upstream
this to the distribution spec. There's a small possibility that this
will break registries that don't implement the spec properly.

We signal the domain of the origin registry with the "origin"
querystring parameter.
  • Loading branch information
jonjohnsonjr committed Jun 16, 2022
1 parent 03a77f4 commit 623023e
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 14 deletions.
2 changes: 1 addition & 1 deletion pkg/v1/remote/check.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
18 changes: 10 additions & 8 deletions pkg/v1/remote/write.go
Original file line number Diff line number Diff line change
Expand Up @@ -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()

Expand Down Expand Up @@ -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.
Expand All @@ -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 {
Expand Down
52 changes: 47 additions & 5 deletions pkg/v1/remote/write_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand Down Expand Up @@ -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)
}
Expand Down Expand Up @@ -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)
}
Expand Down Expand Up @@ -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)
}
Expand Down Expand Up @@ -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)
}
Expand Down

0 comments on commit 623023e

Please sign in to comment.