about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--main.go131
1 files changed, 131 insertions, 0 deletions
diff --git a/main.go b/main.go
new file mode 100644
index 000000000000..89935c49ae3d
--- /dev/null
+++ b/main.go
@@ -0,0 +1,131 @@
+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(),
+	}
+}