mirror of
https://github.com/linuxkit/linuxkit.git
synced 2025-07-19 09:16:29 +00:00
Remove the moby tool from this repo
Updated go-compile to be able to compile remotely. Note I did not update the oter users of go-compile as it does not affect them. Update `go get` instructions to fetch new one, or `make && make install` will still work. Signed-off-by: Justin Cormack <justin.cormack@docker.com>
This commit is contained in:
parent
35d8070abc
commit
252e32aac5
8
Makefile
8
Makefile
@ -5,7 +5,7 @@ all: default
|
|||||||
VERSION="0.0" # dummy for now
|
VERSION="0.0" # dummy for now
|
||||||
GIT_COMMIT=$(shell git rev-list -1 HEAD)
|
GIT_COMMIT=$(shell git rev-list -1 HEAD)
|
||||||
|
|
||||||
GO_COMPILE=linuxkit/go-compile:4513068d9a7e919e4ec42e2d7ee879ff5b95b7f5@sha256:bdfadbe3e4ec699ca45b67453662321ec270f2d1a1dbdbf09625776d3ebd68c5
|
GO_COMPILE=linuxkit/go-compile:5bf17af781df44f07906099402680b9a661f999b@sha256:0bf523bcebb96ccc525f983a118f1fd8cb5e17dbf90e83044ca71bb983000e70
|
||||||
|
|
||||||
MOBY?=bin/moby
|
MOBY?=bin/moby
|
||||||
LINUXKIT?=bin/linuxkit
|
LINUXKIT?=bin/linuxkit
|
||||||
@ -17,10 +17,8 @@ endif
|
|||||||
|
|
||||||
PREFIX?=/usr/local/
|
PREFIX?=/usr/local/
|
||||||
|
|
||||||
MOBY_DEPS=$(wildcard src/cmd/moby/*.go) Makefile vendor.conf
|
bin/moby: | bin
|
||||||
MOBY_DEPS+=$(wildcard src/initrd/*.go) $(wildcard src/pad4/*.go)
|
docker run --rm --log-driver=none $(CROSS) $(GO_COMPILE) --clone-path github.com/moby/tool --clone https://github.com/moby/tool.git --package github.com/moby/tool/cmd/moby --ldflags "-X main.GitCommit=$(GIT_COMMIT) -X main.Version=$(VERSION)" -o $@ > tmp_moby_bin.tar
|
||||||
bin/moby: $(MOBY_DEPS) | bin
|
|
||||||
tar cf - vendor src/initrd src/pad4 -C src/cmd/moby . | docker run --rm --net=none --log-driver=none -i $(CROSS) $(GO_COMPILE) --package github.com/linuxkit/linuxkit --ldflags "-X main.GitCommit=$(GIT_COMMIT) -X main.Version=$(VERSION)" -o $@ > tmp_moby_bin.tar
|
|
||||||
tar xf tmp_moby_bin.tar > $@
|
tar xf tmp_moby_bin.tar > $@
|
||||||
rm tmp_moby_bin.tar
|
rm tmp_moby_bin.tar
|
||||||
touch $@
|
touch $@
|
||||||
|
@ -22,7 +22,7 @@ LinuxKit uses the `moby` tool for image builds, and the `linuxkit` tool for push
|
|||||||
Simple build instructions: use `make` to build. This will build the tools in `bin/`. Add this
|
Simple build instructions: use `make` to build. This will build the tools in `bin/`. Add this
|
||||||
to your `PATH` or copy it to somewhere in your `PATH` eg `sudo cp bin/* /usr/local/bin/`. Or you can use `sudo make install`.
|
to your `PATH` or copy it to somewhere in your `PATH` eg `sudo cp bin/* /usr/local/bin/`. Or you can use `sudo make install`.
|
||||||
|
|
||||||
If you already have `go` installed you can use `go get -u github.com/linuxkit/linuxkit/src/cmd/moby` to install
|
If you already have `go` installed you can use `go get -u github.com/moby/tool/cmd/moby` to install
|
||||||
the `moby` build tool, and `go get -u github.com/linuxkit/linuxkit/src/cmd/linuxkit` to install the `linuxkit` tool.
|
the `moby` build tool, and `go get -u github.com/linuxkit/linuxkit/src/cmd/linuxkit` to install the `linuxkit` tool.
|
||||||
|
|
||||||
Once you have built the tool, use `moby build linuxkit.yml` to build the example configuration,
|
Once you have built the tool, use `moby build linuxkit.yml` to build the example configuration,
|
||||||
|
@ -1,248 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"archive/tar"
|
|
||||||
"bytes"
|
|
||||||
"errors"
|
|
||||||
"flag"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
log "github.com/Sirupsen/logrus"
|
|
||||||
"github.com/linuxkit/linuxkit/src/initrd"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Process the build arguments and execute build
|
|
||||||
func build(args []string) {
|
|
||||||
buildCmd := flag.NewFlagSet("build", flag.ExitOnError)
|
|
||||||
buildCmd.Usage = func() {
|
|
||||||
fmt.Printf("USAGE: %s build [options] <file>[.yml]\n\n", os.Args[0])
|
|
||||||
fmt.Printf("Options:\n")
|
|
||||||
buildCmd.PrintDefaults()
|
|
||||||
}
|
|
||||||
buildName := buildCmd.String("name", "", "Name to use for output files")
|
|
||||||
buildPull := buildCmd.Bool("pull", false, "Always pull images")
|
|
||||||
|
|
||||||
if err := buildCmd.Parse(args); err != nil {
|
|
||||||
log.Fatal("Unable to parse args")
|
|
||||||
}
|
|
||||||
remArgs := buildCmd.Args()
|
|
||||||
|
|
||||||
if len(remArgs) == 0 {
|
|
||||||
fmt.Println("Please specify a configuration file")
|
|
||||||
buildCmd.Usage()
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
conf := remArgs[0]
|
|
||||||
if !(filepath.Ext(conf) == ".yml" || filepath.Ext(conf) == ".yaml") {
|
|
||||||
conf = conf + ".yml"
|
|
||||||
}
|
|
||||||
|
|
||||||
buildInternal(*buildName, *buildPull, conf)
|
|
||||||
}
|
|
||||||
|
|
||||||
func initrdAppend(iw *initrd.Writer, r io.Reader) {
|
|
||||||
_, err := initrd.Copy(iw, r)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("initrd write error: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func enforceContentTrust(fullImageName string, config *TrustConfig) bool {
|
|
||||||
for _, img := range config.Image {
|
|
||||||
// First check for an exact name match
|
|
||||||
if img == fullImageName {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
// Also check for an image name only match
|
|
||||||
// by removing a possible tag (with possibly added digest):
|
|
||||||
if img == strings.TrimSuffix(fullImageName, ":") {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
// and by removing a possible digest:
|
|
||||||
if img == strings.TrimSuffix(fullImageName, "@sha256:") {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, org := range config.Org {
|
|
||||||
if strings.HasPrefix(fullImageName, org+"/") {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// Perform the actual build process
|
|
||||||
func buildInternal(name string, pull bool, conf string) {
|
|
||||||
if name == "" {
|
|
||||||
name = filepath.Base(conf)
|
|
||||||
ext := filepath.Ext(conf)
|
|
||||||
if ext != "" {
|
|
||||||
name = name[:len(name)-len(ext)]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
config, err := ioutil.ReadFile(conf)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("Cannot open config file: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
m, err := NewConfig(config)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("Invalid config: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
w := new(bytes.Buffer)
|
|
||||||
iw := initrd.NewWriter(w)
|
|
||||||
|
|
||||||
if pull || enforceContentTrust(m.Kernel.Image, &m.Trust) {
|
|
||||||
log.Infof("Pull kernel image: %s", m.Kernel.Image)
|
|
||||||
err := dockerPull(m.Kernel.Image, enforceContentTrust(m.Kernel.Image, &m.Trust))
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("Could not pull image %s: %v", m.Kernel.Image, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// get kernel bzImage and initrd tarball from container
|
|
||||||
// TODO examine contents to see what names they might have
|
|
||||||
log.Infof("Extract kernel image: %s", m.Kernel.Image)
|
|
||||||
const (
|
|
||||||
bzimageName = "bzImage"
|
|
||||||
ktarName = "kernel.tar"
|
|
||||||
)
|
|
||||||
out, err := dockerRun(m.Kernel.Image, "tar", "cf", "-", bzimageName, ktarName)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("Failed to extract kernel image and tarball: %v", err)
|
|
||||||
}
|
|
||||||
buf := bytes.NewBuffer(out)
|
|
||||||
bzimage, ktar, err := untarKernel(buf, bzimageName, ktarName)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("Could not extract bzImage and kernel filesystem from tarball. %v", err)
|
|
||||||
}
|
|
||||||
initrdAppend(iw, ktar)
|
|
||||||
|
|
||||||
// convert init images to tarballs
|
|
||||||
log.Infof("Add init containers:")
|
|
||||||
for _, ii := range m.Init {
|
|
||||||
if pull || enforceContentTrust(ii, &m.Trust) {
|
|
||||||
log.Infof("Pull init image: %s", ii)
|
|
||||||
err := dockerPull(ii, enforceContentTrust(ii, &m.Trust))
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("Could not pull image %s: %v", ii, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
log.Infof("Process init image: %s", ii)
|
|
||||||
init, err := ImageExtract(ii, "")
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("Failed to build init tarball from %s: %v", ii, err)
|
|
||||||
}
|
|
||||||
buffer := bytes.NewBuffer(init)
|
|
||||||
initrdAppend(iw, buffer)
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Infof("Add onboot containers:")
|
|
||||||
for i, image := range m.Onboot {
|
|
||||||
if pull || enforceContentTrust(image.Image, &m.Trust) {
|
|
||||||
log.Infof(" Pull: %s", image.Image)
|
|
||||||
err := dockerPull(image.Image, enforceContentTrust(image.Image, &m.Trust))
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("Could not pull image %s: %v", image.Image, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
log.Infof(" Create OCI config for %s", image.Image)
|
|
||||||
config, err := ConfigToOCI(&image)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("Failed to create config.json for %s: %v", image.Image, err)
|
|
||||||
}
|
|
||||||
so := fmt.Sprintf("%03d", i)
|
|
||||||
path := "containers/onboot/" + so + "-" + image.Name
|
|
||||||
out, err := ImageBundle(path, image.Image, config)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("Failed to extract root filesystem for %s: %v", image.Image, err)
|
|
||||||
}
|
|
||||||
buffer := bytes.NewBuffer(out)
|
|
||||||
initrdAppend(iw, buffer)
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Infof("Add service containers:")
|
|
||||||
for _, image := range m.Services {
|
|
||||||
if pull || enforceContentTrust(image.Image, &m.Trust) {
|
|
||||||
log.Infof(" Pull: %s", image.Image)
|
|
||||||
err := dockerPull(image.Image, enforceContentTrust(image.Image, &m.Trust))
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("Could not pull image %s: %v", image.Image, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
log.Infof(" Create OCI config for %s", image.Image)
|
|
||||||
config, err := ConfigToOCI(&image)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("Failed to create config.json for %s: %v", image.Image, err)
|
|
||||||
}
|
|
||||||
path := "containers/services/" + image.Name
|
|
||||||
out, err := ImageBundle(path, image.Image, config)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("Failed to extract root filesystem for %s: %v", image.Image, err)
|
|
||||||
}
|
|
||||||
buffer := bytes.NewBuffer(out)
|
|
||||||
initrdAppend(iw, buffer)
|
|
||||||
}
|
|
||||||
|
|
||||||
// add files
|
|
||||||
buffer, err := filesystem(m)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("failed to add filesystem parts: %v", err)
|
|
||||||
}
|
|
||||||
initrdAppend(iw, buffer)
|
|
||||||
err = iw.Close()
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("initrd close error: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Infof("Create outputs:")
|
|
||||||
err = outputs(m, name, bzimage.Bytes(), w.Bytes())
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("Error writing outputs: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func untarKernel(buf *bytes.Buffer, bzimageName, ktarName string) (*bytes.Buffer, *bytes.Buffer, error) {
|
|
||||||
tr := tar.NewReader(buf)
|
|
||||||
|
|
||||||
var bzimage, ktar *bytes.Buffer
|
|
||||||
|
|
||||||
for {
|
|
||||||
hdr, err := tr.Next()
|
|
||||||
if err == io.EOF {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalln(err)
|
|
||||||
}
|
|
||||||
switch hdr.Name {
|
|
||||||
case bzimageName:
|
|
||||||
bzimage = new(bytes.Buffer)
|
|
||||||
_, err := io.Copy(bzimage, tr)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
case ktarName:
|
|
||||||
ktar = new(bytes.Buffer)
|
|
||||||
_, err := io.Copy(ktar, tr)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ktar == nil || bzimage == nil {
|
|
||||||
return nil, nil, errors.New("did not find bzImage and kernel.tar in tarball")
|
|
||||||
}
|
|
||||||
|
|
||||||
return bzimage, ktar, nil
|
|
||||||
}
|
|
@ -1,490 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"archive/tar"
|
|
||||||
"bytes"
|
|
||||||
"encoding/json"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"path"
|
|
||||||
"path/filepath"
|
|
||||||
"sort"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
log "github.com/Sirupsen/logrus"
|
|
||||||
"github.com/docker/engine-api/types"
|
|
||||||
"github.com/opencontainers/runtime-spec/specs-go"
|
|
||||||
"github.com/xeipuuv/gojsonschema"
|
|
||||||
"gopkg.in/yaml.v2"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Moby is the type of a Moby config file
|
|
||||||
type Moby struct {
|
|
||||||
Kernel struct {
|
|
||||||
Image string
|
|
||||||
Cmdline string
|
|
||||||
}
|
|
||||||
Init []string
|
|
||||||
Onboot []MobyImage
|
|
||||||
Services []MobyImage
|
|
||||||
Trust TrustConfig
|
|
||||||
Files []struct {
|
|
||||||
Path string
|
|
||||||
Directory bool
|
|
||||||
Contents string
|
|
||||||
}
|
|
||||||
Outputs []struct {
|
|
||||||
Format string
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TrustConfig is the type of a content trust config
|
|
||||||
type TrustConfig struct {
|
|
||||||
Image []string
|
|
||||||
Org []string
|
|
||||||
}
|
|
||||||
|
|
||||||
// MobyImage is the type of an image config
|
|
||||||
type MobyImage struct {
|
|
||||||
Name string
|
|
||||||
Image string
|
|
||||||
Capabilities []string
|
|
||||||
Mounts []specs.Mount
|
|
||||||
Binds []string
|
|
||||||
Tmpfs []string
|
|
||||||
Command []string
|
|
||||||
Env []string
|
|
||||||
Cwd string
|
|
||||||
Net string
|
|
||||||
Pid string
|
|
||||||
Ipc string
|
|
||||||
Uts string
|
|
||||||
Readonly bool
|
|
||||||
MaskedPaths []string `yaml:"maskedPaths"`
|
|
||||||
ReadonlyPaths []string `yaml:"readonlyPaths"`
|
|
||||||
UID uint32 `yaml:"uid"`
|
|
||||||
GID uint32 `yaml:"gid"`
|
|
||||||
AdditionalGids []uint32 `yaml:"additionalGids"`
|
|
||||||
NoNewPrivileges bool `yaml:"noNewPrivileges"`
|
|
||||||
Hostname string
|
|
||||||
OomScoreAdj int `yaml:"oomScoreAdj"`
|
|
||||||
DisableOOMKiller bool `yaml:"disableOOMKiller"`
|
|
||||||
RootfsPropagation string `yaml:"rootfsPropagation"`
|
|
||||||
CgroupsPath string `yaml:"cgroupsPath"`
|
|
||||||
Sysctl map[string]string
|
|
||||||
}
|
|
||||||
|
|
||||||
// github.com/go-yaml/yaml treats map keys as interface{} while encoding/json
|
|
||||||
// requires them to be strings, integers or to implement encoding.TextMarshaler.
|
|
||||||
// Fix this up by recursively mapping all map[interface{}]interface{} types into
|
|
||||||
// map[string]interface{}.
|
|
||||||
// see http://stackoverflow.com/questions/40737122/convert-yaml-to-json-without-struct-golang#answer-40737676
|
|
||||||
func convert(i interface{}) interface{} {
|
|
||||||
switch x := i.(type) {
|
|
||||||
case map[interface{}]interface{}:
|
|
||||||
m2 := map[string]interface{}{}
|
|
||||||
for k, v := range x {
|
|
||||||
m2[k.(string)] = convert(v)
|
|
||||||
}
|
|
||||||
return m2
|
|
||||||
case []interface{}:
|
|
||||||
for i, v := range x {
|
|
||||||
x[i] = convert(v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return i
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewConfig parses a config file
|
|
||||||
func NewConfig(config []byte) (*Moby, error) {
|
|
||||||
m := Moby{}
|
|
||||||
|
|
||||||
// Parse raw yaml
|
|
||||||
var rawYaml interface{}
|
|
||||||
err := yaml.Unmarshal(config, &rawYaml)
|
|
||||||
if err != nil {
|
|
||||||
return &m, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert to raw JSON
|
|
||||||
rawJSON := convert(rawYaml)
|
|
||||||
|
|
||||||
// Validate raw yaml with JSON schema
|
|
||||||
schemaLoader := gojsonschema.NewStringLoader(schema)
|
|
||||||
documentLoader := gojsonschema.NewGoLoader(rawJSON)
|
|
||||||
result, err := gojsonschema.Validate(schemaLoader, documentLoader)
|
|
||||||
if err != nil {
|
|
||||||
return &m, err
|
|
||||||
}
|
|
||||||
if !result.Valid() {
|
|
||||||
fmt.Printf("The configuration file is invalid:\n")
|
|
||||||
for _, desc := range result.Errors() {
|
|
||||||
fmt.Printf("- %s\n", desc)
|
|
||||||
}
|
|
||||||
return &m, fmt.Errorf("invalid configuration file")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse yaml
|
|
||||||
err = yaml.Unmarshal(config, &m)
|
|
||||||
if err != nil {
|
|
||||||
return &m, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return &m, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ConfigToOCI converts a config specification to an OCI config file
|
|
||||||
func ConfigToOCI(image *MobyImage) ([]byte, error) {
|
|
||||||
|
|
||||||
// TODO pass through same docker client to all functions
|
|
||||||
cli, err := dockerClient()
|
|
||||||
if err != nil {
|
|
||||||
return []byte{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
inspect, err := dockerInspectImage(cli, image.Image)
|
|
||||||
if err != nil {
|
|
||||||
return []byte{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return ConfigInspectToOCI(image, inspect)
|
|
||||||
}
|
|
||||||
|
|
||||||
func defaultMountpoint(tp string) string {
|
|
||||||
switch tp {
|
|
||||||
case "proc":
|
|
||||||
return "/proc"
|
|
||||||
case "devpts":
|
|
||||||
return "/dev/pts"
|
|
||||||
case "sysfs":
|
|
||||||
return "/sys"
|
|
||||||
case "cgroup":
|
|
||||||
return "/sys/fs/cgroup"
|
|
||||||
case "mqueue":
|
|
||||||
return "/dev/mqueue"
|
|
||||||
default:
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sort mounts by number of path components so /dev/pts is listed after /dev
|
|
||||||
type mlist []specs.Mount
|
|
||||||
|
|
||||||
func (m mlist) Len() int {
|
|
||||||
return len(m)
|
|
||||||
}
|
|
||||||
func (m mlist) Less(i, j int) bool {
|
|
||||||
return m.parts(i) < m.parts(j)
|
|
||||||
}
|
|
||||||
func (m mlist) Swap(i, j int) {
|
|
||||||
m[i], m[j] = m[j], m[i]
|
|
||||||
}
|
|
||||||
func (m mlist) parts(i int) int {
|
|
||||||
return strings.Count(filepath.Clean(m[i].Destination), string(os.PathSeparator))
|
|
||||||
}
|
|
||||||
|
|
||||||
// ConfigInspectToOCI converts a config and the output of image inspect to an OCI config file
|
|
||||||
func ConfigInspectToOCI(image *MobyImage, inspect types.ImageInspect) ([]byte, error) {
|
|
||||||
oci := specs.Spec{}
|
|
||||||
|
|
||||||
config := inspect.Config
|
|
||||||
if config == nil {
|
|
||||||
return []byte{}, errors.New("empty image config")
|
|
||||||
}
|
|
||||||
|
|
||||||
args := append(config.Entrypoint, config.Cmd...)
|
|
||||||
if len(image.Command) != 0 {
|
|
||||||
args = image.Command
|
|
||||||
}
|
|
||||||
env := config.Env
|
|
||||||
if len(image.Env) != 0 {
|
|
||||||
env = image.Env
|
|
||||||
}
|
|
||||||
cwd := config.WorkingDir
|
|
||||||
if image.Cwd != "" {
|
|
||||||
cwd = image.Cwd
|
|
||||||
}
|
|
||||||
if cwd == "" {
|
|
||||||
cwd = "/"
|
|
||||||
}
|
|
||||||
// default options match what Docker does
|
|
||||||
procOptions := []string{"nosuid", "nodev", "noexec", "relatime"}
|
|
||||||
devOptions := []string{"nosuid", "strictatime", "mode=755", "size=65536k"}
|
|
||||||
if image.Readonly {
|
|
||||||
devOptions = append(devOptions, "ro")
|
|
||||||
}
|
|
||||||
ptsOptions := []string{"nosuid", "noexec", "newinstance", "ptmxmode=0666", "mode=0620"}
|
|
||||||
sysOptions := []string{"nosuid", "noexec", "nodev"}
|
|
||||||
if image.Readonly {
|
|
||||||
sysOptions = append(sysOptions, "ro")
|
|
||||||
}
|
|
||||||
cgroupOptions := []string{"nosuid", "noexec", "nodev", "relatime", "ro"}
|
|
||||||
// note omits "standard" /dev/shm and /dev/mqueue
|
|
||||||
mounts := map[string]specs.Mount{
|
|
||||||
"/proc": {Destination: "/proc", Type: "proc", Source: "proc", Options: procOptions},
|
|
||||||
"/dev": {Destination: "/dev", Type: "tmpfs", Source: "tmpfs", Options: devOptions},
|
|
||||||
"/dev/pts": {Destination: "/dev/pts", Type: "devpts", Source: "devpts", Options: ptsOptions},
|
|
||||||
"/sys": {Destination: "/sys", Type: "sysfs", Source: "sysfs", Options: sysOptions},
|
|
||||||
"/sys/fs/cgroup": {Destination: "/sys/fs/cgroup", Type: "cgroup", Source: "cgroup", Options: cgroupOptions},
|
|
||||||
}
|
|
||||||
for _, t := range image.Tmpfs {
|
|
||||||
parts := strings.Split(t, ":")
|
|
||||||
if len(parts) > 2 {
|
|
||||||
return []byte{}, fmt.Errorf("Cannot parse tmpfs, too many ':': %s", t)
|
|
||||||
}
|
|
||||||
dest := parts[0]
|
|
||||||
opts := []string{}
|
|
||||||
if len(parts) == 2 {
|
|
||||||
opts = strings.Split(parts[2], ",")
|
|
||||||
}
|
|
||||||
mounts[dest] = specs.Mount{Destination: dest, Type: "tmpfs", Source: "tmpfs", Options: opts}
|
|
||||||
}
|
|
||||||
for _, b := range image.Binds {
|
|
||||||
parts := strings.Split(b, ":")
|
|
||||||
if len(parts) < 2 {
|
|
||||||
return []byte{}, fmt.Errorf("Cannot parse bind, missing ':': %s", b)
|
|
||||||
}
|
|
||||||
if len(parts) > 3 {
|
|
||||||
return []byte{}, fmt.Errorf("Cannot parse bind, too many ':': %s", b)
|
|
||||||
}
|
|
||||||
src := parts[0]
|
|
||||||
dest := parts[1]
|
|
||||||
opts := []string{"rw", "rbind", "rprivate"}
|
|
||||||
if len(parts) == 3 {
|
|
||||||
opts = strings.Split(parts[2], ",")
|
|
||||||
}
|
|
||||||
mounts[dest] = specs.Mount{Destination: dest, Type: "bind", Source: src, Options: opts}
|
|
||||||
}
|
|
||||||
for _, m := range image.Mounts {
|
|
||||||
tp := m.Type
|
|
||||||
src := m.Source
|
|
||||||
dest := m.Destination
|
|
||||||
opts := m.Options
|
|
||||||
if tp == "" {
|
|
||||||
switch src {
|
|
||||||
case "mqueue", "devpts", "proc", "sysfs", "cgroup":
|
|
||||||
tp = src
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if tp == "" && dest == "/dev" {
|
|
||||||
tp = "tmpfs"
|
|
||||||
}
|
|
||||||
if tp == "" {
|
|
||||||
return []byte{}, fmt.Errorf("Mount for destination %s is missing type", dest)
|
|
||||||
}
|
|
||||||
if src == "" {
|
|
||||||
// usually sane, eg proc, tmpfs etc
|
|
||||||
src = tp
|
|
||||||
}
|
|
||||||
if dest == "" {
|
|
||||||
dest = defaultMountpoint(tp)
|
|
||||||
}
|
|
||||||
if dest == "" {
|
|
||||||
return []byte{}, fmt.Errorf("Mount type %s is missing destination", tp)
|
|
||||||
}
|
|
||||||
mounts[dest] = specs.Mount{Destination: dest, Type: tp, Source: src, Options: opts}
|
|
||||||
}
|
|
||||||
mountList := mlist{}
|
|
||||||
for _, m := range mounts {
|
|
||||||
mountList = append(mountList, m)
|
|
||||||
}
|
|
||||||
sort.Sort(mountList)
|
|
||||||
|
|
||||||
namespaces := []specs.LinuxNamespace{}
|
|
||||||
// to attach to an existing namespace, easiest to bind mount with nsfs in a system container
|
|
||||||
if image.Net != "host" {
|
|
||||||
namespaces = append(namespaces, specs.LinuxNamespace{Type: specs.NetworkNamespace, Path: image.Net})
|
|
||||||
}
|
|
||||||
if image.Pid != "host" {
|
|
||||||
namespaces = append(namespaces, specs.LinuxNamespace{Type: specs.PIDNamespace, Path: image.Pid})
|
|
||||||
}
|
|
||||||
if image.Ipc != "host" {
|
|
||||||
namespaces = append(namespaces, specs.LinuxNamespace{Type: specs.IPCNamespace, Path: image.Ipc})
|
|
||||||
}
|
|
||||||
if image.Uts != "host" {
|
|
||||||
namespaces = append(namespaces, specs.LinuxNamespace{Type: specs.UTSNamespace, Path: image.Uts})
|
|
||||||
}
|
|
||||||
// TODO user, cgroup namespaces, maybe mount=host if useful
|
|
||||||
namespaces = append(namespaces, specs.LinuxNamespace{Type: specs.MountNamespace})
|
|
||||||
|
|
||||||
caps := image.Capabilities
|
|
||||||
if len(caps) == 1 && strings.ToLower(caps[0]) == "all" {
|
|
||||||
caps = []string{
|
|
||||||
"CAP_AUDIT_CONTROL",
|
|
||||||
"CAP_AUDIT_READ",
|
|
||||||
"CAP_AUDIT_WRITE",
|
|
||||||
"CAP_BLOCK_SUSPEND",
|
|
||||||
"CAP_CHOWN",
|
|
||||||
"CAP_DAC_OVERRIDE",
|
|
||||||
"CAP_DAC_READ_SEARCH",
|
|
||||||
"CAP_FOWNER",
|
|
||||||
"CAP_FSETID",
|
|
||||||
"CAP_IPC_LOCK",
|
|
||||||
"CAP_IPC_OWNER",
|
|
||||||
"CAP_KILL",
|
|
||||||
"CAP_LEASE",
|
|
||||||
"CAP_LINUX_IMMUTABLE",
|
|
||||||
"CAP_MAC_ADMIN",
|
|
||||||
"CAP_MAC_OVERRIDE",
|
|
||||||
"CAP_MKNOD",
|
|
||||||
"CAP_NET_ADMIN",
|
|
||||||
"CAP_NET_BIND_SERVICE",
|
|
||||||
"CAP_NET_BROADCAST",
|
|
||||||
"CAP_NET_RAW",
|
|
||||||
"CAP_SETFCAP",
|
|
||||||
"CAP_SETGID",
|
|
||||||
"CAP_SETPCAP",
|
|
||||||
"CAP_SETUID",
|
|
||||||
"CAP_SYSLOG",
|
|
||||||
"CAP_SYS_ADMIN",
|
|
||||||
"CAP_SYS_BOOT",
|
|
||||||
"CAP_SYS_CHROOT",
|
|
||||||
"CAP_SYS_MODULE",
|
|
||||||
"CAP_SYS_NICE",
|
|
||||||
"CAP_SYS_PACCT",
|
|
||||||
"CAP_SYS_PTRACE",
|
|
||||||
"CAP_SYS_RAWIO",
|
|
||||||
"CAP_SYS_RESOURCE",
|
|
||||||
"CAP_SYS_TIME",
|
|
||||||
"CAP_SYS_TTY_CONFIG",
|
|
||||||
"CAP_WAKE_ALARM",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
oci.Version = specs.Version
|
|
||||||
|
|
||||||
oci.Platform = specs.Platform{
|
|
||||||
OS: inspect.Os,
|
|
||||||
Arch: inspect.Architecture,
|
|
||||||
}
|
|
||||||
|
|
||||||
oci.Process = specs.Process{
|
|
||||||
Terminal: false,
|
|
||||||
//ConsoleSize
|
|
||||||
User: specs.User{
|
|
||||||
UID: image.UID,
|
|
||||||
GID: image.GID,
|
|
||||||
AdditionalGids: image.AdditionalGids,
|
|
||||||
// Username (Windows)
|
|
||||||
},
|
|
||||||
Args: args,
|
|
||||||
Env: env,
|
|
||||||
Cwd: cwd,
|
|
||||||
Capabilities: &specs.LinuxCapabilities{
|
|
||||||
Bounding: caps,
|
|
||||||
Effective: caps,
|
|
||||||
Inheritable: caps,
|
|
||||||
Permitted: caps,
|
|
||||||
Ambient: []string{},
|
|
||||||
},
|
|
||||||
Rlimits: []specs.LinuxRlimit{},
|
|
||||||
NoNewPrivileges: image.NoNewPrivileges,
|
|
||||||
// ApparmorProfile
|
|
||||||
// SelinuxLabel
|
|
||||||
}
|
|
||||||
|
|
||||||
oci.Root = specs.Root{
|
|
||||||
Path: "rootfs",
|
|
||||||
Readonly: image.Readonly,
|
|
||||||
}
|
|
||||||
|
|
||||||
oci.Hostname = image.Hostname
|
|
||||||
oci.Mounts = mountList
|
|
||||||
|
|
||||||
oci.Linux = &specs.Linux{
|
|
||||||
// UIDMappings
|
|
||||||
// GIDMappings
|
|
||||||
Sysctl: image.Sysctl,
|
|
||||||
Resources: &specs.LinuxResources{
|
|
||||||
// Devices
|
|
||||||
DisableOOMKiller: &image.DisableOOMKiller,
|
|
||||||
// Memory
|
|
||||||
// CPU
|
|
||||||
// Pids
|
|
||||||
// BlockIO
|
|
||||||
// HugepageLimits
|
|
||||||
// Network
|
|
||||||
},
|
|
||||||
CgroupsPath: image.CgroupsPath,
|
|
||||||
Namespaces: namespaces,
|
|
||||||
// Devices
|
|
||||||
// Seccomp
|
|
||||||
RootfsPropagation: image.RootfsPropagation,
|
|
||||||
MaskedPaths: image.MaskedPaths,
|
|
||||||
ReadonlyPaths: image.ReadonlyPaths,
|
|
||||||
// MountLabel
|
|
||||||
// IntelRdt
|
|
||||||
}
|
|
||||||
|
|
||||||
return json.MarshalIndent(oci, "", " ")
|
|
||||||
}
|
|
||||||
|
|
||||||
func filesystem(m *Moby) (*bytes.Buffer, error) {
|
|
||||||
buf := new(bytes.Buffer)
|
|
||||||
tw := tar.NewWriter(buf)
|
|
||||||
defer tw.Close()
|
|
||||||
|
|
||||||
log.Infof("Add files:")
|
|
||||||
for _, f := range m.Files {
|
|
||||||
log.Infof(" %s", f.Path)
|
|
||||||
if f.Path == "" {
|
|
||||||
return buf, errors.New("Did not specify path for file")
|
|
||||||
}
|
|
||||||
if !f.Directory && f.Contents == "" {
|
|
||||||
return buf, errors.New("Contents of file not specified")
|
|
||||||
}
|
|
||||||
// we need all the leading directories
|
|
||||||
parts := strings.Split(path.Dir(f.Path), "/")
|
|
||||||
root := ""
|
|
||||||
for _, p := range parts {
|
|
||||||
if p == "." || p == "/" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if root == "" {
|
|
||||||
root = p
|
|
||||||
} else {
|
|
||||||
root = root + "/" + p
|
|
||||||
}
|
|
||||||
hdr := &tar.Header{
|
|
||||||
Name: root,
|
|
||||||
Typeflag: tar.TypeDir,
|
|
||||||
Mode: 0700,
|
|
||||||
}
|
|
||||||
err := tw.WriteHeader(hdr)
|
|
||||||
if err != nil {
|
|
||||||
return buf, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if f.Directory {
|
|
||||||
if f.Contents != "" {
|
|
||||||
return buf, errors.New("Directory with contents not allowed")
|
|
||||||
}
|
|
||||||
hdr := &tar.Header{
|
|
||||||
Name: f.Path,
|
|
||||||
Typeflag: tar.TypeDir,
|
|
||||||
Mode: 0700,
|
|
||||||
}
|
|
||||||
err := tw.WriteHeader(hdr)
|
|
||||||
if err != nil {
|
|
||||||
return buf, err
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
hdr := &tar.Header{
|
|
||||||
Name: f.Path,
|
|
||||||
Mode: 0600,
|
|
||||||
Size: int64(len(f.Contents)),
|
|
||||||
}
|
|
||||||
err := tw.WriteHeader(hdr)
|
|
||||||
if err != nil {
|
|
||||||
return buf, err
|
|
||||||
}
|
|
||||||
_, err = tw.Write([]byte(f.Contents))
|
|
||||||
if err != nil {
|
|
||||||
return buf, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return buf, nil
|
|
||||||
}
|
|
@ -1,318 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
// We want to replace much of this with use of containerd tools
|
|
||||||
// and also using the Docker API not shelling out
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
|
||||||
"os/exec"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
log "github.com/Sirupsen/logrus"
|
|
||||||
"github.com/docker/engine-api/client"
|
|
||||||
"github.com/docker/engine-api/types"
|
|
||||||
"golang.org/x/net/context"
|
|
||||||
)
|
|
||||||
|
|
||||||
func dockerRun(args ...string) ([]byte, error) {
|
|
||||||
log.Debugf("docker run: %s", strings.Join(args, " "))
|
|
||||||
docker, err := exec.LookPath("docker")
|
|
||||||
if err != nil {
|
|
||||||
return []byte{}, errors.New("Docker does not seem to be installed")
|
|
||||||
}
|
|
||||||
args = append([]string{"run", "--rm", "--log-driver=none"}, args...)
|
|
||||||
cmd := exec.Command(docker, args...)
|
|
||||||
|
|
||||||
stderrPipe, err := cmd.StderrPipe()
|
|
||||||
if err != nil {
|
|
||||||
return []byte{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
stdoutPipe, err := cmd.StdoutPipe()
|
|
||||||
if err != nil {
|
|
||||||
return []byte{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = cmd.Start()
|
|
||||||
if err != nil {
|
|
||||||
return []byte{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
stdout, err := ioutil.ReadAll(stdoutPipe)
|
|
||||||
if err != nil {
|
|
||||||
return []byte{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
stderr, err := ioutil.ReadAll(stderrPipe)
|
|
||||||
if err != nil {
|
|
||||||
return []byte{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = cmd.Wait()
|
|
||||||
if err != nil {
|
|
||||||
return []byte{}, fmt.Errorf("%v: %s", err, stderr)
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Debugf("docker run: %s...Done", strings.Join(args, " "))
|
|
||||||
return stdout, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func dockerRunInput(input io.Reader, args ...string) ([]byte, error) {
|
|
||||||
log.Debugf("docker run (input): %s", strings.Join(args, " "))
|
|
||||||
docker, err := exec.LookPath("docker")
|
|
||||||
if err != nil {
|
|
||||||
return []byte{}, errors.New("Docker does not seem to be installed")
|
|
||||||
}
|
|
||||||
args = append([]string{"run", "--rm", "-i"}, args...)
|
|
||||||
cmd := exec.Command(docker, args...)
|
|
||||||
cmd.Stdin = input
|
|
||||||
|
|
||||||
stderrPipe, err := cmd.StderrPipe()
|
|
||||||
if err != nil {
|
|
||||||
return []byte{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
stdoutPipe, err := cmd.StdoutPipe()
|
|
||||||
if err != nil {
|
|
||||||
return []byte{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = cmd.Start()
|
|
||||||
if err != nil {
|
|
||||||
return []byte{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
stdout, err := ioutil.ReadAll(stdoutPipe)
|
|
||||||
if err != nil {
|
|
||||||
return []byte{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
stderr, err := ioutil.ReadAll(stderrPipe)
|
|
||||||
if err != nil {
|
|
||||||
return []byte{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = cmd.Wait()
|
|
||||||
if err != nil {
|
|
||||||
return []byte{}, fmt.Errorf("%v: %s", err, stderr)
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Debugf("docker run (input): %s...Done", strings.Join(args, " "))
|
|
||||||
return stdout, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func dockerCreate(image string) (string, error) {
|
|
||||||
log.Debugf("docker create: %s", image)
|
|
||||||
docker, err := exec.LookPath("docker")
|
|
||||||
if err != nil {
|
|
||||||
return "", errors.New("Docker does not seem to be installed")
|
|
||||||
}
|
|
||||||
// we do not ever run the container, so /dev/null is used as command
|
|
||||||
args := []string{"create", image, "/dev/null"}
|
|
||||||
cmd := exec.Command(docker, args...)
|
|
||||||
|
|
||||||
stderrPipe, err := cmd.StderrPipe()
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
stdoutPipe, err := cmd.StdoutPipe()
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = cmd.Start()
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
stdout, err := ioutil.ReadAll(stdoutPipe)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
stderr, err := ioutil.ReadAll(stderrPipe)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = cmd.Wait()
|
|
||||||
if err != nil {
|
|
||||||
return "", fmt.Errorf("%v: %s", err, stderr)
|
|
||||||
}
|
|
||||||
|
|
||||||
container := strings.TrimSpace(string(stdout))
|
|
||||||
log.Debugf("docker create: %s...Done", image)
|
|
||||||
return container, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func dockerExport(container string) ([]byte, error) {
|
|
||||||
log.Debugf("docker export: %s", container)
|
|
||||||
docker, err := exec.LookPath("docker")
|
|
||||||
if err != nil {
|
|
||||||
return []byte{}, errors.New("Docker does not seem to be installed")
|
|
||||||
}
|
|
||||||
args := []string{"export", container}
|
|
||||||
cmd := exec.Command(docker, args...)
|
|
||||||
|
|
||||||
stderrPipe, err := cmd.StderrPipe()
|
|
||||||
if err != nil {
|
|
||||||
return []byte{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
stdoutPipe, err := cmd.StdoutPipe()
|
|
||||||
if err != nil {
|
|
||||||
return []byte{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = cmd.Start()
|
|
||||||
if err != nil {
|
|
||||||
return []byte{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
stdout, err := ioutil.ReadAll(stdoutPipe)
|
|
||||||
if err != nil {
|
|
||||||
return []byte{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
stderr, err := ioutil.ReadAll(stderrPipe)
|
|
||||||
if err != nil {
|
|
||||||
return []byte{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = cmd.Wait()
|
|
||||||
if err != nil {
|
|
||||||
return []byte{}, fmt.Errorf("%v: %s", err, stderr)
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Debugf("docker export: %s...Done", container)
|
|
||||||
return stdout, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func dockerRm(container string) error {
|
|
||||||
log.Debugf("docker rm: %s", container)
|
|
||||||
docker, err := exec.LookPath("docker")
|
|
||||||
if err != nil {
|
|
||||||
return errors.New("Docker does not seem to be installed")
|
|
||||||
}
|
|
||||||
args := []string{"rm", container}
|
|
||||||
cmd := exec.Command(docker, args...)
|
|
||||||
|
|
||||||
stderrPipe, err := cmd.StderrPipe()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
stdoutPipe, err := cmd.StdoutPipe()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = cmd.Start()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = ioutil.ReadAll(stdoutPipe)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
stderr, err := ioutil.ReadAll(stderrPipe)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = cmd.Wait()
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("%v: %s", err, stderr)
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Debugf("docker rm: %s...Done", container)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func dockerPull(image string, trustedPull bool) error {
|
|
||||||
log.Debugf("docker pull: %s", image)
|
|
||||||
docker, err := exec.LookPath("docker")
|
|
||||||
if err != nil {
|
|
||||||
return errors.New("Docker does not seem to be installed")
|
|
||||||
}
|
|
||||||
var args = []string{"pull"}
|
|
||||||
if trustedPull {
|
|
||||||
log.Debugf("pulling %s with content trust", image)
|
|
||||||
args = append(args, "--disable-content-trust=false")
|
|
||||||
}
|
|
||||||
args = append(args, image)
|
|
||||||
cmd := exec.Command(docker, args...)
|
|
||||||
|
|
||||||
stderrPipe, err := cmd.StderrPipe()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
stdoutPipe, err := cmd.StdoutPipe()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = cmd.Start()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = ioutil.ReadAll(stdoutPipe)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
stderr, err := ioutil.ReadAll(stderrPipe)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = cmd.Wait()
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("%v: %s", err, stderr)
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Debugf("docker pull: %s...Done", image)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func dockerClient() (*client.Client, error) {
|
|
||||||
// for maximum compatibility as we use nothing new
|
|
||||||
err := os.Setenv("DOCKER_API_VERSION", "1.23")
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return client.NewEnvClient()
|
|
||||||
}
|
|
||||||
|
|
||||||
func dockerInspectImage(cli *client.Client, image string) (types.ImageInspect, error) {
|
|
||||||
log.Debugf("docker inspect image: %s", image)
|
|
||||||
|
|
||||||
inspect, _, err := cli.ImageInspectWithRaw(context.Background(), image, false)
|
|
||||||
if err != nil {
|
|
||||||
if client.IsErrImageNotFound(err) {
|
|
||||||
pullErr := dockerPull(image, false)
|
|
||||||
if pullErr != nil {
|
|
||||||
return types.ImageInspect{}, pullErr
|
|
||||||
}
|
|
||||||
inspect, _, err = cli.ImageInspectWithRaw(context.Background(), image, false)
|
|
||||||
if err != nil {
|
|
||||||
return types.ImageInspect{}, err
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return types.ImageInspect{}, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Debugf("docker inspect image: %s...Done", image)
|
|
||||||
|
|
||||||
return inspect, nil
|
|
||||||
}
|
|
@ -1,195 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"archive/tar"
|
|
||||||
"bytes"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"io/ioutil"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
log "github.com/Sirupsen/logrus"
|
|
||||||
)
|
|
||||||
|
|
||||||
// This uses Docker to convert a Docker image into a tarball. It would be an improvement if we
|
|
||||||
// used the containerd libraries to do this instead locally direct from a local image
|
|
||||||
// cache as it would be much simpler.
|
|
||||||
|
|
||||||
var exclude = map[string]bool{
|
|
||||||
".dockerenv": true,
|
|
||||||
"Dockerfile": true,
|
|
||||||
"dev/console": true,
|
|
||||||
"dev/pts": true,
|
|
||||||
"dev/shm": true,
|
|
||||||
}
|
|
||||||
|
|
||||||
var replace = map[string]string{
|
|
||||||
"etc/hosts": `127.0.0.1 localhost
|
|
||||||
::1 localhost ip6-localhost ip6-loopback
|
|
||||||
fe00::0 ip6-localnet
|
|
||||||
ff00::0 ip6-mcastprefix
|
|
||||||
ff02::1 ip6-allnodes
|
|
||||||
ff02::2 ip6-allrouters
|
|
||||||
`,
|
|
||||||
"etc/resolv.conf": `nameserver 8.8.8.8
|
|
||||||
nameserver 8.8.4.4
|
|
||||||
nameserver 2001:4860:4860::8888
|
|
||||||
nameserver 2001:4860:4860::8844
|
|
||||||
`,
|
|
||||||
"etc/hostname": "moby",
|
|
||||||
}
|
|
||||||
|
|
||||||
// ImageExtract extracts the filesystem from an image and returns a tarball with the files prefixed by the given path
|
|
||||||
func ImageExtract(image, prefix string) ([]byte, error) {
|
|
||||||
log.Debugf("image extract: %s %s", image, prefix)
|
|
||||||
out := new(bytes.Buffer)
|
|
||||||
tw := tar.NewWriter(out)
|
|
||||||
err := tarPrefix(prefix, tw)
|
|
||||||
if err != nil {
|
|
||||||
return []byte{}, err
|
|
||||||
}
|
|
||||||
err = imageTar(image, prefix, tw)
|
|
||||||
if err != nil {
|
|
||||||
return []byte{}, err
|
|
||||||
}
|
|
||||||
err = tw.Close()
|
|
||||||
if err != nil {
|
|
||||||
return []byte{}, err
|
|
||||||
}
|
|
||||||
return out.Bytes(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// tarPrefix creates the leading directories for a path
|
|
||||||
func tarPrefix(path string, tw *tar.Writer) error {
|
|
||||||
if path == "" {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if path[len(path)-1] != byte('/') {
|
|
||||||
return fmt.Errorf("path does not end with /: %s", path)
|
|
||||||
}
|
|
||||||
path = path[:len(path)-1]
|
|
||||||
if path[0] == byte('/') {
|
|
||||||
return fmt.Errorf("path should be relative: %s", path)
|
|
||||||
}
|
|
||||||
mkdir := ""
|
|
||||||
for _, dir := range strings.Split(path, "/") {
|
|
||||||
mkdir = mkdir + dir
|
|
||||||
hdr := &tar.Header{
|
|
||||||
Name: mkdir,
|
|
||||||
Mode: 0755,
|
|
||||||
Typeflag: tar.TypeDir,
|
|
||||||
}
|
|
||||||
if err := tw.WriteHeader(hdr); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
mkdir = mkdir + "/"
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func imageTar(image, prefix string, tw *tar.Writer) error {
|
|
||||||
log.Debugf("image tar: %s %s", image, prefix)
|
|
||||||
if prefix != "" && prefix[len(prefix)-1] != byte('/') {
|
|
||||||
return fmt.Errorf("prefix does not end with /: %s", prefix)
|
|
||||||
}
|
|
||||||
container, err := dockerCreate(image)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("Failed to docker create image %s: %v", image, err)
|
|
||||||
}
|
|
||||||
contents, err := dockerExport(container)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("Failed to docker export container from container %s: %v", container, err)
|
|
||||||
}
|
|
||||||
err = dockerRm(container)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("Failed to docker rm container %s: %v", container, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// now we need to filter out some files from the resulting tar archive
|
|
||||||
|
|
||||||
r := bytes.NewReader(contents)
|
|
||||||
tr := tar.NewReader(r)
|
|
||||||
|
|
||||||
for {
|
|
||||||
hdr, err := tr.Next()
|
|
||||||
if err == io.EOF {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if exclude[hdr.Name] {
|
|
||||||
log.Debugf("image tar: %s %s exclude %s", image, prefix, hdr.Name)
|
|
||||||
_, err = io.Copy(ioutil.Discard, tr)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
} else if replace[hdr.Name] != "" {
|
|
||||||
contents := replace[hdr.Name]
|
|
||||||
hdr.Size = int64(len(contents))
|
|
||||||
hdr.Name = prefix + hdr.Name
|
|
||||||
log.Debugf("image tar: %s %s add %s", image, prefix, hdr.Name)
|
|
||||||
if err := tw.WriteHeader(hdr); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
buf := bytes.NewBufferString(contents)
|
|
||||||
_, err = io.Copy(tw, buf)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
_, err = io.Copy(ioutil.Discard, tr)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
log.Debugf("image tar: %s %s add %s", image, prefix, hdr.Name)
|
|
||||||
hdr.Name = prefix + hdr.Name
|
|
||||||
if err := tw.WriteHeader(hdr); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
_, err = io.Copy(tw, tr)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
err = tw.Close()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ImageBundle produces an OCI bundle at the given path in a tarball, given an image and a config.json
|
|
||||||
func ImageBundle(path string, image string, config []byte) ([]byte, error) {
|
|
||||||
log.Debugf("image bundle: %s %s cfg: %s", path, image, string(config))
|
|
||||||
out := new(bytes.Buffer)
|
|
||||||
tw := tar.NewWriter(out)
|
|
||||||
err := tarPrefix(path+"/rootfs/", tw)
|
|
||||||
if err != nil {
|
|
||||||
return []byte{}, err
|
|
||||||
}
|
|
||||||
hdr := &tar.Header{
|
|
||||||
Name: path + "/" + "config.json",
|
|
||||||
Mode: 0644,
|
|
||||||
Size: int64(len(config)),
|
|
||||||
}
|
|
||||||
err = tw.WriteHeader(hdr)
|
|
||||||
if err != nil {
|
|
||||||
return []byte{}, err
|
|
||||||
}
|
|
||||||
buf := bytes.NewBuffer(config)
|
|
||||||
_, err = io.Copy(tw, buf)
|
|
||||||
if err != nil {
|
|
||||||
return []byte{}, err
|
|
||||||
}
|
|
||||||
err = imageTar(image, path+"/rootfs/", tw)
|
|
||||||
if err != nil {
|
|
||||||
return []byte{}, err
|
|
||||||
}
|
|
||||||
err = tw.Close()
|
|
||||||
if err != nil {
|
|
||||||
return []byte{}, err
|
|
||||||
}
|
|
||||||
return out.Bytes(), nil
|
|
||||||
}
|
|
@ -1,92 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"flag"
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
|
|
||||||
log "github.com/Sirupsen/logrus"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
defaultLogFormatter = &log.TextFormatter{}
|
|
||||||
|
|
||||||
// Version is the human-readable version
|
|
||||||
Version = "unknown"
|
|
||||||
|
|
||||||
// GitCommit hash, set at compile time
|
|
||||||
GitCommit = "unknown"
|
|
||||||
)
|
|
||||||
|
|
||||||
// infoFormatter overrides the default format for Info() log events to
|
|
||||||
// provide an easier to read output
|
|
||||||
type infoFormatter struct {
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *infoFormatter) Format(entry *log.Entry) ([]byte, error) {
|
|
||||||
if entry.Level == log.InfoLevel {
|
|
||||||
return append([]byte(entry.Message), '\n'), nil
|
|
||||||
}
|
|
||||||
return defaultLogFormatter.Format(entry)
|
|
||||||
}
|
|
||||||
|
|
||||||
func version() {
|
|
||||||
fmt.Printf("%s version %s\n", filepath.Base(os.Args[0]), Version)
|
|
||||||
fmt.Printf("commit: %s\n", GitCommit)
|
|
||||||
os.Exit(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
flag.Usage = func() {
|
|
||||||
fmt.Printf("USAGE: %s [options] COMMAND\n\n", filepath.Base(os.Args[0]))
|
|
||||||
fmt.Printf("Commands:\n")
|
|
||||||
fmt.Printf(" build Build a Moby image from a YAML file\n")
|
|
||||||
fmt.Printf(" version Print version information\n")
|
|
||||||
fmt.Printf(" help Print this message\n")
|
|
||||||
fmt.Printf("\n")
|
|
||||||
fmt.Printf("Run '%s COMMAND --help' for more information on the command\n", filepath.Base(os.Args[0]))
|
|
||||||
fmt.Printf("\n")
|
|
||||||
fmt.Printf("Options:\n")
|
|
||||||
flag.PrintDefaults()
|
|
||||||
}
|
|
||||||
flagQuiet := flag.Bool("q", false, "Quiet execution")
|
|
||||||
flagVerbose := flag.Bool("v", false, "Verbose execution")
|
|
||||||
|
|
||||||
// Set up logging
|
|
||||||
log.SetFormatter(new(infoFormatter))
|
|
||||||
log.SetLevel(log.InfoLevel)
|
|
||||||
flag.Parse()
|
|
||||||
if *flagQuiet && *flagVerbose {
|
|
||||||
fmt.Printf("Can't set quiet and verbose flag at the same time\n")
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
if *flagQuiet {
|
|
||||||
log.SetLevel(log.ErrorLevel)
|
|
||||||
}
|
|
||||||
if *flagVerbose {
|
|
||||||
// Switch back to the standard formatter
|
|
||||||
log.SetFormatter(defaultLogFormatter)
|
|
||||||
log.SetLevel(log.DebugLevel)
|
|
||||||
}
|
|
||||||
|
|
||||||
args := flag.Args()
|
|
||||||
if len(args) < 1 {
|
|
||||||
fmt.Printf("Please specify a command.\n\n")
|
|
||||||
flag.Usage()
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
switch args[0] {
|
|
||||||
case "build":
|
|
||||||
build(args[1:])
|
|
||||||
case "version":
|
|
||||||
version()
|
|
||||||
case "help":
|
|
||||||
flag.Usage()
|
|
||||||
default:
|
|
||||||
fmt.Printf("%q is not valid command.\n\n", args[0])
|
|
||||||
flag.Usage()
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,158 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"archive/tar"
|
|
||||||
"bytes"
|
|
||||||
"fmt"
|
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
|
||||||
|
|
||||||
log "github.com/Sirupsen/logrus"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
bios = "linuxkit/mkimage-iso-bios:6ebdce90f63991eb1d5a578e6570dc1e5781e9fe@sha256:0c6116d4c069d17ebdaa86737841b3be6ae84f6c69a5e79fe59cd8310156aa96"
|
|
||||||
efi = "linuxkit/mkimage-iso-efi:008fac48c41ec38b36ce1ae62f93a69ee9328569@sha256:35282010b95680fe754e557bc65f0b2ffd85e925bd62f427fb77bf494145083b"
|
|
||||||
gcp = "linuxkit/mkimage-gcp:a8b909202c0a0ed2ac31b5c21f6701d3253ff29a@sha256:2ba307e537d6fae37115848c8a0f5a9b3ed578e102c93c5d2578ece4a91cb828"
|
|
||||||
qcow = "linuxkit/mkimage-qcow:a1053b5dc80834adcba2e5f49354f62797e35f84@sha256:3312d523a67e7c7efb3c3eaa5a4dfbd46659549681d6d62cdeb02bd475b3a22c"
|
|
||||||
vhd = "linuxkit/mkimage-vhd:98d6c879a52cb85b87269bc6ecf9df7dd134427a@sha256:0ca6f46690c7890c77295cc6c531f95fc8bb41df42c237ae4b32eea338cec4e7"
|
|
||||||
vmdk = "linuxkit/mkimage-vmdk:10b8717b6a2099741b702c31af2d9a42ce50425e@sha256:bf7cf6029e61685e9085a1883b1be1167a7f06199f3b76a944ea87b6f23f60d8"
|
|
||||||
)
|
|
||||||
|
|
||||||
func outputs(m *Moby, base string, bzimage []byte, initrd []byte) error {
|
|
||||||
log.Debugf("output: %s %s", m.Outputs, base)
|
|
||||||
for _, o := range m.Outputs {
|
|
||||||
switch o.Format {
|
|
||||||
case "kernel+initrd":
|
|
||||||
err := outputKernelInitrd(base, bzimage, initrd, m.Kernel.Cmdline)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("Error writing %s output: %v", o.Format, err)
|
|
||||||
}
|
|
||||||
case "iso-bios":
|
|
||||||
err := outputISO(bios, base+".iso", bzimage, initrd, m.Kernel.Cmdline)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("Error writing %s output: %v", o.Format, err)
|
|
||||||
}
|
|
||||||
case "iso-efi":
|
|
||||||
err := outputISO(efi, base+"-efi.iso", bzimage, initrd, m.Kernel.Cmdline)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("Error writing %s output: %v", o.Format, err)
|
|
||||||
}
|
|
||||||
case "gcp-img":
|
|
||||||
err := outputImg(gcp, base+".img.tar.gz", bzimage, initrd, m.Kernel.Cmdline)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("Error writing %s output: %v", o.Format, err)
|
|
||||||
}
|
|
||||||
case "qcow", "qcow2":
|
|
||||||
err := outputImg(qcow, base+".qcow2", bzimage, initrd, m.Kernel.Cmdline)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("Error writing %s output: %v", o.Format, err)
|
|
||||||
}
|
|
||||||
case "vhd":
|
|
||||||
err := outputImg(vhd, base+".vhd", bzimage, initrd, m.Kernel.Cmdline)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("Error writing %s output: %v", o.Format, err)
|
|
||||||
}
|
|
||||||
case "vmdk":
|
|
||||||
err := outputImg(vmdk, base+".vmdk", bzimage, initrd, m.Kernel.Cmdline)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("Error writing %s output: %v", o.Format, err)
|
|
||||||
}
|
|
||||||
case "":
|
|
||||||
return fmt.Errorf("No format specified for output")
|
|
||||||
default:
|
|
||||||
return fmt.Errorf("Unknown output type %s", o.Format)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func tarInitrdKernel(bzimage, initrd []byte) (*bytes.Buffer, error) {
|
|
||||||
buf := new(bytes.Buffer)
|
|
||||||
tw := tar.NewWriter(buf)
|
|
||||||
hdr := &tar.Header{
|
|
||||||
Name: "bzImage",
|
|
||||||
Mode: 0600,
|
|
||||||
Size: int64(len(bzimage)),
|
|
||||||
}
|
|
||||||
err := tw.WriteHeader(hdr)
|
|
||||||
if err != nil {
|
|
||||||
return buf, err
|
|
||||||
}
|
|
||||||
_, err = tw.Write(bzimage)
|
|
||||||
if err != nil {
|
|
||||||
return buf, err
|
|
||||||
}
|
|
||||||
hdr = &tar.Header{
|
|
||||||
Name: "initrd.img",
|
|
||||||
Mode: 0600,
|
|
||||||
Size: int64(len(initrd)),
|
|
||||||
}
|
|
||||||
err = tw.WriteHeader(hdr)
|
|
||||||
if err != nil {
|
|
||||||
return buf, err
|
|
||||||
}
|
|
||||||
_, err = tw.Write(initrd)
|
|
||||||
if err != nil {
|
|
||||||
return buf, err
|
|
||||||
}
|
|
||||||
err = tw.Close()
|
|
||||||
if err != nil {
|
|
||||||
return buf, err
|
|
||||||
}
|
|
||||||
return buf, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func outputImg(image, filename string, bzimage []byte, initrd []byte, args ...string) error {
|
|
||||||
log.Debugf("output img: %s %s", image, filename)
|
|
||||||
log.Infof(" %s", filename)
|
|
||||||
buf, err := tarInitrdKernel(bzimage, initrd)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
img, err := dockerRunInput(buf, append([]string{image}, args...)...)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
err = ioutil.WriteFile(filename, img, os.FileMode(0644))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func outputISO(image, filename string, bzimage []byte, initrd []byte, args ...string) error {
|
|
||||||
log.Debugf("output iso: %s %s", image, filename)
|
|
||||||
log.Infof(" %s", filename)
|
|
||||||
buf, err := tarInitrdKernel(bzimage, initrd)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
iso, err := dockerRunInput(buf, append([]string{image}, args...)...)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
err = ioutil.WriteFile(filename, iso, os.FileMode(0644))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func outputKernelInitrd(base string, bzimage []byte, initrd []byte, cmdline string) error {
|
|
||||||
log.Debugf("output kernel/initrd: %s %s", base, cmdline)
|
|
||||||
log.Infof(" %s %s %s", base+"-bzImage", base+"-initrd.img", base+"-cmdline")
|
|
||||||
err := ioutil.WriteFile(base+"-initrd.img", initrd, os.FileMode(0644))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
err = ioutil.WriteFile(base+"-bzImage", bzimage, os.FileMode(0644))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
err = ioutil.WriteFile(base+"-cmdline", []byte(cmdline), os.FileMode(0644))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
@ -1,121 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
var schema = string(`
|
|
||||||
{
|
|
||||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
|
||||||
"title": "Moby Config",
|
|
||||||
"additionalProperties": false,
|
|
||||||
"definitions": {
|
|
||||||
"kernel": {
|
|
||||||
"type": "object",
|
|
||||||
"additionalProperties": false,
|
|
||||||
"properties": {
|
|
||||||
"image": { "type": "string"},
|
|
||||||
"cmdline": { "type": "string"}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"file": {
|
|
||||||
"type": "object",
|
|
||||||
"additionalProperties": false,
|
|
||||||
"properties": {
|
|
||||||
"path": {"type": "string"},
|
|
||||||
"directory": {"type": "boolean"},
|
|
||||||
"contents": {"type": "string"}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"files": {
|
|
||||||
"type": "array",
|
|
||||||
"items": { "$ref": "#/definitions/file" }
|
|
||||||
},
|
|
||||||
"output": {
|
|
||||||
"type": "object",
|
|
||||||
"additionalProperties": false,
|
|
||||||
"properties": {
|
|
||||||
"format": {"type": "string"}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": { "$ref": "#/definitions/output" }
|
|
||||||
},
|
|
||||||
"trust": {
|
|
||||||
"type": "object",
|
|
||||||
"additionalProperties": false,
|
|
||||||
"properties": {
|
|
||||||
"image": { "$ref": "#/definitions/strings" },
|
|
||||||
"org": { "$ref": "#/definitions/strings" }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"strings": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {"type": "string"}
|
|
||||||
},
|
|
||||||
"mount": {
|
|
||||||
"type": "object",
|
|
||||||
"additionalProperties": false,
|
|
||||||
"properties": {
|
|
||||||
"destination": { "type": "string" },
|
|
||||||
"type": { "type": "string" },
|
|
||||||
"source": { "type": "string" },
|
|
||||||
"options": { "$ref": "#/definitions/strings" }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"mounts": {
|
|
||||||
"type": "array",
|
|
||||||
"items": { "$ref": "#/definitions/mount" }
|
|
||||||
},
|
|
||||||
"image": {
|
|
||||||
"type": "object",
|
|
||||||
"additionalProperties": false,
|
|
||||||
"required": ["name", "image"],
|
|
||||||
"properties": {
|
|
||||||
"name": {"type": "string"},
|
|
||||||
"image": {"type": "string"},
|
|
||||||
"capabilities": { "$ref": "#/definitions/strings" },
|
|
||||||
"mounts": { "$ref": "#/definitions/mounts" },
|
|
||||||
"binds": { "$ref": "#/definitions/strings" },
|
|
||||||
"tmpfs": { "$ref": "#/definitions/strings" },
|
|
||||||
"command": { "$ref": "#/definitions/strings" },
|
|
||||||
"env": { "$ref": "#/definitions/strings" },
|
|
||||||
"cwd": { "type": "string"},
|
|
||||||
"net": { "type": "string"},
|
|
||||||
"pid": { "type": "string"},
|
|
||||||
"ipc": { "type": "string"},
|
|
||||||
"uts": { "type": "string"},
|
|
||||||
"readonly": { "type": "boolean"},
|
|
||||||
"maskedPaths": { "$ref": "#/definitions/strings" },
|
|
||||||
"readonlyPaths": { "$ref": "#/definitions/strings" },
|
|
||||||
"uid": {"type": "integer"},
|
|
||||||
"gid": {"type": "integer"},
|
|
||||||
"additionalGids": {
|
|
||||||
"type": "array",
|
|
||||||
"items": { "type": "integer" }
|
|
||||||
},
|
|
||||||
"noNewPrivileges": {"type": "boolean"},
|
|
||||||
"hostname": {"type": "string"},
|
|
||||||
"oomScoreAdj": {"type": "integer"},
|
|
||||||
"disableOOMKiller": {"type": "boolean"},
|
|
||||||
"rootfsPropagation": {"type": "string"},
|
|
||||||
"cgroupsPath": {"type": "string"},
|
|
||||||
"sysctl": {
|
|
||||||
"type": "array",
|
|
||||||
"items": { "$ref": "#/definitions/strings" }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"images": {
|
|
||||||
"type": "array",
|
|
||||||
"items": { "$ref": "#/definitions/image" }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"properties": {
|
|
||||||
"kernel": { "$ref": "#/definitions/kernel" },
|
|
||||||
"init": { "$ref": "#/definitions/strings" },
|
|
||||||
"onboot": { "$ref": "#/definitions/images" },
|
|
||||||
"services": { "$ref": "#/definitions/images" },
|
|
||||||
"trust": { "$ref": "#/definitions/trust" },
|
|
||||||
"files": { "$ref": "#/definitions/files" },
|
|
||||||
"outputs": { "$ref": "#/definitions/outputs" }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`)
|
|
@ -30,6 +30,18 @@ do
|
|||||||
ldflags="$2"
|
ldflags="$2"
|
||||||
shift
|
shift
|
||||||
;;
|
;;
|
||||||
|
--clone-path)
|
||||||
|
clonepath="$2"
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
--clone)
|
||||||
|
clone="$2"
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
--commit)
|
||||||
|
commit="$2"
|
||||||
|
shift
|
||||||
|
;;
|
||||||
*)
|
*)
|
||||||
echo "Unknown option $1"
|
echo "Unknown option $1"
|
||||||
exit 1
|
exit 1
|
||||||
@ -44,12 +56,22 @@ done
|
|||||||
|
|
||||||
dir="$GOPATH/src/$package"
|
dir="$GOPATH/src/$package"
|
||||||
|
|
||||||
mkdir -p $dir
|
if [ -z "$clone" ]
|
||||||
|
then
|
||||||
|
mkdir -p "$dir"
|
||||||
|
cd "$dir"
|
||||||
|
# untar input
|
||||||
|
tar xf -
|
||||||
|
else
|
||||||
|
mkdir -p "$GOPATH/src/$clonepath"
|
||||||
|
cd "$GOPATH/src/$clonepath"
|
||||||
|
git clone "$clone" .
|
||||||
|
[ ! -z "$commit" ] && git checkout "$commit"
|
||||||
|
mkdir -p "$dir"
|
||||||
|
cd "$dir"
|
||||||
|
fi
|
||||||
|
|
||||||
# untar input
|
cd "$dir"
|
||||||
tar xf - -C $dir
|
|
||||||
|
|
||||||
cd $dir
|
|
||||||
|
|
||||||
# lint before building
|
# lint before building
|
||||||
>&2 echo "gofmt..."
|
>&2 echo "gofmt..."
|
||||||
|
Loading…
Reference in New Issue
Block a user