150 lines
		
	
	
	
		
			2.8 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			150 lines
		
	
	
	
		
			2.8 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
// 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,
 | 
						|
	}
 | 
						|
}
 |