package main
import (
"archive/tar"
"bytes"
"compress/gzip"
"crypto/sha256"
"encoding/json"
"fmt"
"io/ioutil"
"log"
"net/http"
"os"
)
type Layer struct {
MediaType string `json:"mediaType"`
Size int `json:"size"`
Digest string `json:"digest"`
}
type Manifest struct {
SchemaVersion int `json:"schemaVersion"`
MediaType string `json:"mediaType"`
Config map[string]string `json:"config"`
Layers []Layer `json:"layers"`
}
// A really "dumb" representation of an image, with a data blob (tar.gz image) and its hash as the type expected
// in the manifest.
type Image struct {
Layer Layer
Data []byte
}
const ManifestContentType string = "application/vnd.docker.distribution.manifest.v2+json"
const LayerContentType string = "application/vnd.docker.image.rootfs.diff.tar.gzip"
func main() {
img := getImage()
manifest := Manifest{
SchemaVersion: 2,
MediaType: "application/vnd.docker.distribution.manifest.v2+json",
Config: map[string]string{},
Layers: []Layer{
img.Layer,
},
}
log.Fatal(http.ListenAndServe(":8080", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Acknowledge that we speak V2
if r.RequestURI == "/v2/" {
log.Println("Acknowleding V2 API")
fmt.Fprintln(w)
return
}
// Serve manifest
if r.RequestURI == "/v2/quinistry/manifests/latest" {
log.Printf("Serving manifest for %v\n", *r)
w.Header().Add("Content-Type", ManifestContentType)
resp, _ := json.Marshal(manifest)
w.Header().Add("Docker-Content-Digest", digest(resp))
log.Println(digest(resp))
fmt.Fprintln(w, string(resp))
return
}
// Serve actual image layer
if r.RequestURI == fmt.Sprintf("/v2/quinistry/blob/%s", img.Layer.Digest) {
fmt.Printf("Serving layer for %v\n", *r)
fmt.Fprint(w, img.Data)
return
}
fmt.Printf("Unhandled: %v\n", *r)
})))
}
func digest(b []byte) string {
hash := sha256.New()
hash.Write(b)
return fmt.Sprintf("sha256:%x", hash.Sum(nil))
}
// Creates an image of the currently running binary (spooky!)
func getImage() *Image {
// Current binary, imagine this is some other output or whatever
path, _ := os.Executable()
// don't care about error! :O
file, _ := ioutil.ReadFile(path)
// First create tar archive
tarBuf := new(bytes.Buffer)
tarW := tar.NewWriter(tarBuf)
hdr := &tar.Header{
Name: "main",
Mode: 0755,
Size: int64(len(file)),
}
tarW.WriteHeader(hdr)
tarW.Write(file)
if err := tarW.Close(); err != nil {
log.Fatalln(err)
os.Exit(1)
}
// Then GZIP it
zBuf := new(bytes.Buffer)
zw := gzip.NewWriter(zBuf)
zw.Name = "Docker registry fake test"
zw.Write(tarBuf.Bytes())
if err := zw.Close(); err != nil {
log.Fatal(err)
os.Exit(1)
}
return &Image{
Layer: Layer{
MediaType: LayerContentType,
Size: zBuf.Len(),
Digest: digest(zBuf.Bytes()),
},
Data: zBuf.Bytes(),
}
}