diff --git a/cmd/buildpack/main.go b/cmd/buildpack/main.go index 5d8790b..090dfa8 100644 --- a/cmd/buildpack/main.go +++ b/cmd/buildpack/main.go @@ -126,7 +126,7 @@ func (s *server) serveBuildpackManifest(w http.ResponseWriter, r *http.Request) // image tag. if commitRE.MatchString(revision) { ck := cacheKey(path, revision) - if err := s.storage.BlobExists(ctx, ck); err == nil { + if _, err := s.storage.BlobExists(ctx, ck); err == nil { s.info.Println("serving cached manifest:", ck) serve.Blob(w, r, ck) return @@ -231,7 +231,7 @@ func (s *server) prepareWorkspace() (string, string, error) { } func (s *server) fetchAndBuild(src, layers, ghOwner, ghRepo, revision, path string) (string, error) { - image := fmt.Sprintf("gcr.io/%s/built-%d", projectID, time.Now().Unix) + image := fmt.Sprintf("gcr.io/%s/built-%d", projectID, time.Now().Unix()) source := fmt.Sprintf("https://github.com/%s/%s/archive/%s.tar.gz", ghOwner, ghRepo, revision) if resp, err := http.Head(source); err != nil { diff --git a/cmd/flatten/main.go b/cmd/flatten/main.go index 7f78ae1..a87705a 100644 --- a/cmd/flatten/main.go +++ b/cmd/flatten/main.go @@ -108,7 +108,7 @@ func (s *server) serveFlattenManifest(w http.ResponseWriter, r *http.Request) { // Check if we have a flattened manifest cached, and if so serve it // directly. ck := cacheKey(d.Digest.String()) - if err := s.storage.BlobExists(ctx, ck); err == nil { + if _, err := s.storage.BlobExists(ctx, ck); err == nil { s.info.Println("serving cached manifest:", ck) serve.Blob(w, r, ck) return diff --git a/cmd/kaniko/main.go b/cmd/kaniko/main.go index 98cb4dc..97e86ad 100644 --- a/cmd/kaniko/main.go +++ b/cmd/kaniko/main.go @@ -119,7 +119,7 @@ func (s *server) serveKanikoManifest(w http.ResponseWriter, r *http.Request) { // image tag. if commitRE.MatchString(revision) { ck := cacheKey(path, revision) - if err := s.storage.BlobExists(ctx, ck); err == nil { + if _, err := s.storage.BlobExists(ctx, ck); err == nil { s.info.Println("serving cached manifest:", ck) serve.Blob(w, r, ck) return @@ -223,7 +223,7 @@ func (s *server) prepareWorkspace() error { } func (s *server) fetchAndBuild(ghOwner, ghRepo, revision, path string) (string, error) { - image := fmt.Sprintf("gcr.io/%s/built-%d", projectID, time.Now().Unix) + image := fmt.Sprintf("gcr.io/%s/built-%d", projectID, time.Now().Unix()) source := fmt.Sprintf("https://github.com/%s/%s/archive/%s.tar.gz", ghOwner, ghRepo, revision) if resp, err := http.Head(source); err != nil { diff --git a/cmd/mirror/main.go b/cmd/mirror/main.go index 6b0065f..c92dddb 100644 --- a/cmd/mirror/main.go +++ b/cmd/mirror/main.go @@ -89,6 +89,21 @@ func (s *server) serveMirrorManifest(w http.ResponseWriter, r *http.Request) { return } + // If it's a HEAD request, and request was by digest, and we have that + // manifest mirrored by digest already, serve HEAD response from GCS. + // If it's a HEAD request and the other conditions aren't met, we'll + // handle this later by consulting the real registry. + if r.Method == http.MethodHead { + if d, ok := ref.(name.Digest); ok { + if desc, err := s.storage.BlobExists(ctx, d.DigestStr()); err == nil { + w.Header().Set("Docker-Content-Digest", d.DigestStr()) + w.Header().Set("Content-Type", string(desc.MediaType)) + w.Header().Set("Content-Length", fmt.Sprintf("%d", desc.Size)) + return + } + } + } + // Get the original image's digest, and check if we have that manifest // blob. d, err := remote.Head(ref, remote.WithContext(ctx)) @@ -97,7 +112,13 @@ func (s *server) serveMirrorManifest(w http.ResponseWriter, r *http.Request) { serve.Error(w, err) return } - if err := s.storage.BlobExists(ctx, d.Digest.String()); err == nil { + if r.Method == http.MethodHead { + w.Header().Set("Docker-Content-Digest", d.Digest.String()) + w.Header().Set("Content-Type", string(d.MediaType)) + w.Header().Set("Content-Length", fmt.Sprintf("%d", d.Size)) + return + } + if _, err := s.storage.BlobExists(ctx, d.Digest.String()); err == nil { serve.Blob(w, r, d.Digest.String()) return } else { diff --git a/cmd/wait/main.go b/cmd/wait/main.go index 0b29af3..865e3cf 100644 --- a/cmd/wait/main.go +++ b/cmd/wait/main.go @@ -86,7 +86,7 @@ func (s *server) serveWaitManifest(w http.ResponseWriter, r *http.Request) { // The image has already been built; serve it. ck := cacheKey(name) - if err := s.storage.BlobExists(ctx, ck); err == nil { + if _, err := s.storage.BlobExists(ctx, ck); err == nil { s.info.Printf("blob %q exists, serving", ck) serve.Blob(w, r, ck) return @@ -95,7 +95,7 @@ func (s *server) serveWaitManifest(w http.ResponseWriter, r *http.Request) { // If a placeholder exists, a wait is ongoing; serve the placeholder // contents. phn := fmt.Sprintf("placeholder-%s", ck) - if err := s.storage.BlobExists(ctx, phn); err == nil { + if _, err := s.storage.BlobExists(ctx, phn); err == nil { s.info.Printf("placeholder %q exists", phn) serve.Error(w, fmt.Errorf("waiting for image...")) return @@ -143,7 +143,7 @@ const size = 100 const num = 10 var laterFunc = delay.Func("later", func(ctx context.Context, ck string) error { - log.Println("generating random image for cache key %q", ck) + log.Printf("generating random image for cache key %q", ck) img, err := random.Image(size, num) if err != nil { return err diff --git a/pkg/serve/serve.go b/pkg/serve/serve.go index 99e0de4..315f6e3 100644 --- a/pkg/serve/serve.go +++ b/pkg/serve/serve.go @@ -13,6 +13,7 @@ import ( "cloud.google.com/go/storage" v1 "github.com/google/go-containerregistry/pkg/v1" + "github.com/google/go-containerregistry/pkg/v1/types" "golang.org/x/sync/errgroup" "google.golang.org/api/googleapi" ) @@ -36,9 +37,15 @@ func NewStorage(ctx context.Context) (*Storage, error) { return &Storage{client}, nil } -func (s *Storage) BlobExists(ctx context.Context, name string) error { - _, err := s.client.Bucket(bucket).Object(fmt.Sprintf("blobs/%s", name)).Attrs(ctx) - return err +func (s *Storage) BlobExists(ctx context.Context, name string) (v1.Descriptor, error) { + obj, err := s.client.Bucket(bucket).Object(fmt.Sprintf("blobs/%s", name)).Attrs(ctx) + if err != nil { + return v1.Descriptor{}, err + } + return v1.Descriptor{ + MediaType: types.MediaType(obj.ContentType), + Size: obj.Size, + }, nil } func (s *Storage) WriteObject(ctx context.Context, name, contents string) error {