1
0
Fork 0
mirror of https://github.com/imjasonh/kontain.me synced 2026-07-08 00:55:14 +00:00

add flatten

This commit is contained in:
Jason Hall 2020-12-16 11:52:44 -05:00
parent 8f7760732c
commit f15d0fae8b
2 changed files with 132 additions and 0 deletions

129
cmd/flatten/main.go Normal file
View file

@ -0,0 +1,129 @@
// Copyright 2020 Google LLC All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package main
import (
"fmt"
"io"
"log"
"net/http"
"os"
"strings"
"github.com/google/go-containerregistry/pkg/name"
"github.com/google/go-containerregistry/pkg/v1/empty"
"github.com/google/go-containerregistry/pkg/v1/mutate"
"github.com/google/go-containerregistry/pkg/v1/remote"
"github.com/google/go-containerregistry/pkg/v1/tarball"
"github.com/imjasonh/kontain.me/pkg/serve"
)
func main() {
http.Handle("/v2/", &server{
info: log.New(os.Stdout, "I ", log.Ldate|log.Ltime|log.Lshortfile),
error: log.New(os.Stderr, "E ", log.Ldate|log.Ltime|log.Lshortfile),
})
http.Handle("/", http.RedirectHandler("https://kontain.me", http.StatusMovedPermanently))
log.Println("Starting...")
port := os.Getenv("PORT")
if port == "" {
port = "8080"
log.Printf("Defaulting to port %s", port)
}
log.Printf("Listening on port %s", port)
log.Fatal(http.ListenAndServe(fmt.Sprintf(":%s", port), nil))
}
type server struct {
info, error *log.Logger
}
func (s *server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
s.info.Println("handler:", r.Method, r.URL)
path := strings.TrimPrefix(r.URL.String(), "/v2/")
switch {
case path == "":
// API Version check.
w.Header().Set("Docker-Distribution-API-Version", "registry/2.0")
return
case strings.Contains(path, "/blobs/"),
strings.Contains(path, "/manifests/sha256:"):
// Extract requested blob digest and redirect to serve it from GCS.
// If it doesn't exist, this will return 404.
parts := strings.Split(r.URL.Path, "/")
digest := parts[len(parts)-1]
serve.Blob(w, r, digest)
case strings.Contains(path, "/manifests/"):
s.serveMirrorManifest(w, r)
default:
serve.Error(w, serve.ErrNotFound)
}
}
// mirror.kontain.me/ubuntu -> mirror ubuntu and serve
func (s *server) serveMirrorManifest(w http.ResponseWriter, r *http.Request) {
path := strings.TrimPrefix(r.URL.Path, "/v2/")
parts := strings.Split(path, "/")
refstr := strings.Join(parts[:len(parts)-2], "/")
tagOrDigest := parts[len(parts)-1]
if strings.HasPrefix(tagOrDigest, "sha256:") {
refstr += "@" + tagOrDigest
} else {
refstr += ":" + tagOrDigest
}
for strings.HasPrefix(refstr, "flatten.kontain.me/") {
refstr = strings.TrimPrefix(refstr, "flatten.kontain.me/")
}
ref, err := name.ParseReference(refstr)
if err != nil {
s.error.Printf("ERROR (ParseReference(%q)): %v", refstr, err)
serve.Error(w, err)
return
}
// TODO: remote.Head(ref) and check for blobs/{digest}-flattened to
// serve that instead.
// TODO: support manifest lists.
img, err := remote.Image(ref)
if err != nil {
s.error.Printf("ERROR (remote.Image): %v", err)
serve.Error(w, err)
return
}
l, err := tarball.LayerFromOpener(func() (io.ReadCloser, error) { return mutate.Extract(img), nil })
if err != nil {
s.error.Printf("ERROR (tarball.LayerFromOpener): %v", err)
serve.Error(w, err)
return
}
fimg, err := mutate.AppendLayers(empty.Image, l)
if err != nil {
s.error.Printf("ERROR (mutate.AppendLayers): %v", err)
serve.Error(w, err)
return
}
if err := serve.Manifest(w, r, fimg); err != nil {
s.error.Printf("ERROR (serve.Manifest): %v", err)
serve.Error(w, err)
return
}
}