about summary refs log blame commit diff
path: root/main.go
blob: 89935c49ae3dfd3cf39e7bdae2293b5defa08f6e (plain) (tree)


































































































































                                                                                                                
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(),
	}
}