diff options
Diffstat (limited to 'fun/quinistry/image.go')
-rw-r--r-- | fun/quinistry/image.go | 150 |
1 files changed, 150 insertions, 0 deletions
diff --git a/fun/quinistry/image.go b/fun/quinistry/image.go new file mode 100644 index 000000000000..3daeac34d6bb --- /dev/null +++ b/fun/quinistry/image.go @@ -0,0 +1,150 @@ +// The code in this file creates a Docker image layer containing the binary of the +// application itself. + +package main + +import ( + "archive/tar" + "bytes" + "compress/gzip" + "crypto/sha256" + "encoding/json" + "fmt" + "io/ioutil" + "log" + "os" + "time" +) + +// This function creates a Docker-image digest (i.e. SHA256 hash with +// algorithm-specification prefix) +func Digest(b []byte) string { + hash := sha256.New() + hash.Write(b) + + return fmt.Sprintf("sha256:%x", hash.Sum(nil)) +} + +func GetImageOfCurrentExecutable() Image { + binary := getCurrentBinary() + tarArchive := createTarArchive(&map[string][]byte{ + "/main": binary, + }) + + configJson, configElem := createConfig([]string{Digest(tarArchive)}) + compressed := gzipArchive("Quinistry image", tarArchive) + manifest := createManifest(&configElem, &compressed) + manifestJson, _ := json.Marshal(manifest) + + return Image{ + Layer: compressed, + LayerDigest: Digest(compressed), + Manifest: manifestJson, + ManifestDigest: Digest(manifestJson), + Config: configJson, + ConfigDigest: Digest(configJson), + } + +} + +func getCurrentBinary() []byte { + path, _ := os.Executable() + file, _ := ioutil.ReadFile(path) + return file +} + +func createTarArchive(files *map[string][]byte) []byte { + buf := new(bytes.Buffer) + w := tar.NewWriter(buf) + + for name, file := range *files { + hdr := &tar.Header{ + Name: name, + // Everything is executable \o/ + Mode: 0755, + Size: int64(len(file)), + } + w.WriteHeader(hdr) + w.Write(file) + } + + if err := w.Close(); err != nil { + log.Fatalln(err) + os.Exit(1) + } + + return buf.Bytes() +} + +func gzipArchive(name string, archive []byte) []byte { + buf := new(bytes.Buffer) + w := gzip.NewWriter(buf) + w.Name = name + w.Write(archive) + + if err := w.Close(); err != nil { + log.Fatalln(err) + os.Exit(1) + } + + return buf.Bytes() +} + +func createConfig(layerDigests []string) (configJson []byte, elem Element) { + now := time.Now() + + imageConfig := &ImageConfig{ + Cmd: []string{"/main"}, + Env: []string{"PATH=/"}, + } + + rootFs := RootFs{ + DiffIds: layerDigests, + Type: "layers", + } + + history := []History{ + { + Created: now, + CreatedBy: "Quinistry magic", + }, + } + + config := Config{ + Created: now, + Author: "tazjin", + Architecture: "amd64", + Os: "linux", + Config: imageConfig, + RootFs: rootFs, + History: history, + } + + configJson, _ = json.Marshal(config) + + elem = Element{ + MediaType: ImageConfigMediaType, + Size: len(configJson), + Digest: Digest(configJson), + } + + return +} + +func createManifest(config *Element, layer *[]byte) Manifest { + layers := []Element{ + { + MediaType: LayerMediaType, + Size: len(*layer), + // Layers must contain the digest of the *gzipped* layer. + Digest: Digest(*layer), + }, + } + + return Manifest{ + SchemaVersion: 2, + MediaType: ManifestMediaType, + Config: *config, + Layers: layers, + } +} |