Merge pull request #71 from justincormack/output-file

Use streaming output where possible
This commit is contained in:
Justin Cormack 2017-06-07 14:28:44 +01:00 committed by GitHub
commit ca677b3c40
5 changed files with 330 additions and 289 deletions

View File

@ -9,6 +9,7 @@ import (
"io" "io"
"io/ioutil" "io/ioutil"
"os" "os"
"path"
"path/filepath" "path/filepath"
"sort" "sort"
"strconv" "strconv"
@ -33,11 +34,18 @@ func (o *outputList) Set(value string) error {
return nil return nil
} }
var streamable = map[string]bool{
"tar": true,
}
// Process the build arguments and execute build // Process the build arguments and execute build
func build(args []string) { func build(args []string) {
var buildOut outputList var buildOut outputList
outputTypes := []string{} outputTypes := []string{}
for k := range streamable {
outputTypes = append(outputTypes, k)
}
for k := range outFuns { for k := range outFuns {
outputTypes = append(outputTypes, k) outputTypes = append(outputTypes, k)
} }
@ -51,6 +59,7 @@ func build(args []string) {
} }
buildName := buildCmd.String("name", "", "Name to use for output files") buildName := buildCmd.String("name", "", "Name to use for output files")
buildDir := buildCmd.String("dir", "", "Directory for output files, default current directory") buildDir := buildCmd.String("dir", "", "Directory for output files, default current directory")
buildOutputFile := buildCmd.String("o", "", "File to use for a single output, or '-' for stdout")
buildSize := buildCmd.String("size", "1024M", "Size for output image, if supported and fixed size") buildSize := buildCmd.String("size", "1024M", "Size for output image, if supported and fixed size")
buildPull := buildCmd.Bool("pull", false, "Always pull images") buildPull := buildCmd.Bool("pull", false, "Always pull images")
buildDisableTrust := buildCmd.Bool("disable-content-trust", false, "Skip image trust verification specified in trust section of config (default false)") buildDisableTrust := buildCmd.Bool("disable-content-trust", false, "Skip image trust verification specified in trust section of config (default false)")
@ -68,26 +77,86 @@ func build(args []string) {
os.Exit(1) os.Exit(1)
} }
name := *buildName
if name == "" {
conf := remArgs[len(remArgs)-1]
if conf == "-" {
name = defaultNameForStdin
} else {
name = strings.TrimSuffix(filepath.Base(conf), filepath.Ext(conf))
}
}
// There are two types of output, they will probably be split into "build" and "package" later
// the basic outputs are tarballs, while the packaged ones are the LinuxKit out formats that
// cannot be streamed but we do allow multiple ones to be built.
if len(buildOut) == 0 { if len(buildOut) == 0 {
if *buildOutputFile == "" {
buildOut = outputList{"kernel+initrd"} buildOut = outputList{"kernel+initrd"}
} else {
buildOut = outputList{"tar"}
}
} }
log.Debugf("Outputs selected: %s", buildOut.String()) log.Debugf("Outputs selected: %s", buildOut.String())
if len(buildOut) > 1 {
for _, o := range buildOut {
if streamable[o] {
log.Fatalf("Output type %s must be the only output specified", o)
}
}
}
if len(buildOut) == 1 && streamable[buildOut[0]] {
if *buildOutputFile == "" {
*buildOutputFile = filepath.Join(*buildDir, name+"."+buildOut[0])
// stop the errors in the validation below
*buildName = ""
*buildDir = ""
}
} else {
err := validateOutputs(buildOut) err := validateOutputs(buildOut)
if err != nil { if err != nil {
log.Errorf("Error parsing outputs: %v", err) log.Errorf("Error parsing outputs: %v", err)
buildCmd.Usage() buildCmd.Usage()
os.Exit(1) os.Exit(1)
} }
}
var outputFile *os.File
if *buildOutputFile != "" {
if len(buildOut) > 1 {
log.Fatal("The -output option can only be specified when generating a single output format")
}
if *buildName != "" {
log.Fatal("The -output option cannot be specified with -name")
}
if *buildDir != "" {
log.Fatal("The -output option cannot be specified with -dir")
}
if !streamable[buildOut[0]] {
log.Fatalf("The -output option cannot be specified for build type %s as it cannot be streamed", buildOut[0])
}
if *buildOutputFile == "-" {
outputFile = os.Stdout
} else {
var err error
outputFile, err = os.Create(*buildOutputFile)
if err != nil {
log.Fatalf("Cannot open output file: %v", err)
}
defer outputFile.Close()
}
}
size, err := getDiskSizeMB(*buildSize) size, err := getDiskSizeMB(*buildSize)
if err != nil { if err != nil {
log.Fatalf("Unable to parse disk size: %v", err) log.Fatalf("Unable to parse disk size: %v", err)
} }
name := *buildName
var moby Moby var moby Moby
for _, arg := range remArgs { for _, arg := range remArgs {
var config []byte var config []byte
@ -97,21 +166,12 @@ func build(args []string) {
if err != nil { if err != nil {
log.Fatalf("Cannot read stdin: %v", err) log.Fatalf("Cannot read stdin: %v", err)
} }
if name == "" {
name = defaultNameForStdin
}
} else { } else {
if !(filepath.Ext(conf) == ".yml" || filepath.Ext(conf) == ".yaml") {
conf = conf + ".yml"
}
var err error var err error
config, err = ioutil.ReadFile(conf) config, err = ioutil.ReadFile(conf)
if err != nil { if err != nil {
log.Fatalf("Cannot open config file: %v", err) log.Fatalf("Cannot open config file: %v", err)
} }
if name == "" {
name = strings.TrimSuffix(filepath.Base(conf), filepath.Ext(conf))
}
} }
m, err := NewConfig(config) m, err := NewConfig(config)
@ -126,14 +186,25 @@ func build(args []string) {
moby.Trust = TrustConfig{} moby.Trust = TrustConfig{}
} }
image := buildInternal(moby, *buildPull) var buf *bytes.Buffer
var w io.Writer
if outputFile != nil {
w = outputFile
} else {
buf = new(bytes.Buffer)
w = buf
}
buildInternal(moby, w, *buildPull)
if outputFile == nil {
image := buf.Bytes()
log.Infof("Create outputs:") log.Infof("Create outputs:")
err = outputs(filepath.Join(*buildDir, name), image, buildOut, size, *buildHyperkit) err = outputs(filepath.Join(*buildDir, name), image, buildOut, size, *buildHyperkit)
if err != nil { if err != nil {
log.Fatalf("Error writing outputs: %v", err) log.Fatalf("Error writing outputs: %v", err)
} }
} }
}
// Parse a string which is either a number in MB, or a number with // Parse a string which is either a number in MB, or a number with
// either M (for Megabytes) or G (for GigaBytes) as a suffix and // either M (for Megabytes) or G (for GigaBytes) as a suffix and
@ -156,27 +227,6 @@ func getDiskSizeMB(s string) (int, error) {
return strconv.Atoi(s) return strconv.Atoi(s)
} }
func initrdAppend(iw *tar.Writer, r io.Reader) {
tr := tar.NewReader(r)
for {
hdr, err := tr.Next()
if err == io.EOF {
break
}
if err != nil {
log.Fatalln(err)
}
err = iw.WriteHeader(hdr)
if err != nil {
log.Fatalln(err)
}
_, err = io.Copy(iw, tr)
if err != nil {
log.Fatalln(err)
}
}
}
func enforceContentTrust(fullImageName string, config *TrustConfig) bool { func enforceContentTrust(fullImageName string, config *TrustConfig) bool {
for _, img := range config.Image { for _, img := range config.Image {
// First check for an exact name match // First check for an exact name match
@ -222,30 +272,21 @@ func enforceContentTrust(fullImageName string, config *TrustConfig) bool {
// Perform the actual build process // Perform the actual build process
// TODO return error not panic // TODO return error not panic
func buildInternal(m Moby, pull bool) []byte { func buildInternal(m Moby, w io.Writer, pull bool) {
w := new(bytes.Buffer)
iw := tar.NewWriter(w) iw := tar.NewWriter(w)
if m.Kernel.Image != "" { if m.Kernel.Image != "" {
// get kernel and initrd tarball from container // get kernel and initrd tarball from container
log.Infof("Extract kernel image: %s", m.Kernel.Image) log.Infof("Extract kernel image: %s", m.Kernel.Image)
const ( kf := newKernelFilter(iw, m.Kernel.Cmdline)
kernelName = "kernel" err := ImageTar(m.Kernel.Image, "", kf, enforceContentTrust(m.Kernel.Image, &m.Trust), pull)
kernelAltName = "bzImage"
ktarName = "kernel.tar"
)
out, err := ImageExtract(m.Kernel.Image, "", enforceContentTrust(m.Kernel.Image, &m.Trust), pull)
if err != nil { if err != nil {
log.Fatalf("Failed to extract kernel image and tarball: %v", err) log.Fatalf("Failed to extract kernel image and tarball: %v", err)
} }
buf := bytes.NewBuffer(out) err = kf.Close()
kernel, ktar, err := untarKernel(buf, kernelName, kernelAltName, ktarName, m.Kernel.Cmdline)
if err != nil { if err != nil {
log.Fatalf("Could not extract kernel image and filesystem from tarball. %v", err) log.Fatalf("Close error: %v", err)
} }
initrdAppend(iw, kernel)
initrdAppend(iw, ktar)
} }
// convert init images to tarballs // convert init images to tarballs
@ -254,12 +295,10 @@ func buildInternal(m Moby, pull bool) []byte {
} }
for _, ii := range m.Init { for _, ii := range m.Init {
log.Infof("Process init image: %s", ii) log.Infof("Process init image: %s", ii)
init, err := ImageExtract(ii, "", enforceContentTrust(ii, &m.Trust), pull) err := ImageTar(ii, "", iw, enforceContentTrust(ii, &m.Trust), pull)
if err != nil { if err != nil {
log.Fatalf("Failed to build init tarball from %s: %v", ii, err) log.Fatalf("Failed to build init tarball from %s: %v", ii, err)
} }
buffer := bytes.NewBuffer(init)
initrdAppend(iw, buffer)
} }
if len(m.Onboot) != 0 { if len(m.Onboot) != 0 {
@ -274,12 +313,10 @@ func buildInternal(m Moby, pull bool) []byte {
} }
so := fmt.Sprintf("%03d", i) so := fmt.Sprintf("%03d", i)
path := "containers/onboot/" + so + "-" + image.Name path := "containers/onboot/" + so + "-" + image.Name
out, err := ImageBundle(path, image.Image, config, useTrust, pull) err = ImageBundle(path, image.Image, config, iw, useTrust, pull)
if err != nil { if err != nil {
log.Fatalf("Failed to extract root filesystem for %s: %v", image.Image, err) log.Fatalf("Failed to extract root filesystem for %s: %v", image.Image, err)
} }
buffer := bytes.NewBuffer(out)
initrdAppend(iw, buffer)
} }
if len(m.Services) != 0 { if len(m.Services) != 0 {
@ -293,58 +330,111 @@ func buildInternal(m Moby, pull bool) []byte {
log.Fatalf("Failed to create config.json for %s: %v", image.Image, err) log.Fatalf("Failed to create config.json for %s: %v", image.Image, err)
} }
path := "containers/services/" + image.Name path := "containers/services/" + image.Name
out, err := ImageBundle(path, image.Image, config, useTrust, pull) err = ImageBundle(path, image.Image, config, iw, useTrust, pull)
if err != nil { if err != nil {
log.Fatalf("Failed to extract root filesystem for %s: %v", image.Image, err) log.Fatalf("Failed to extract root filesystem for %s: %v", image.Image, err)
} }
buffer := bytes.NewBuffer(out)
initrdAppend(iw, buffer)
} }
// add files // add files
buffer, err := filesystem(m) err := filesystem(m, iw)
if err != nil { if err != nil {
log.Fatalf("failed to add filesystem parts: %v", err) log.Fatalf("failed to add filesystem parts: %v", err)
} }
initrdAppend(iw, buffer)
err = iw.Close() err = iw.Close()
if err != nil { if err != nil {
log.Fatalf("initrd close error: %v", err) log.Fatalf("initrd close error: %v", err)
} }
return w.Bytes() return
} }
func untarKernel(buf *bytes.Buffer, kernelName, kernelAltName, ktarName string, cmdline string) (*bytes.Buffer, *bytes.Buffer, error) { // kernelFilter is a tar.Writer that transforms a kernel image into the output we want on underlying tar writer
tr := tar.NewReader(buf) type kernelFilter struct {
tw *tar.Writer
var kernel, ktar *bytes.Buffer buffer *bytes.Buffer
foundKernel := false cmdline string
discard bool
for { foundKernel bool
hdr, err := tr.Next() foundKTar bool
if err == io.EOF {
break
} }
func newKernelFilter(tw *tar.Writer, cmdline string) *kernelFilter {
return &kernelFilter{tw: tw, cmdline: cmdline}
}
func (k *kernelFilter) finishTar() error {
if k.buffer == nil {
return nil
}
tr := tar.NewReader(k.buffer)
err := tarAppend(k.tw, tr)
k.buffer = nil
return err
}
func (k *kernelFilter) Close() error {
if !k.foundKernel {
return errors.New("did not find kernel in kernel image")
}
if !k.foundKTar {
return errors.New("did not find kernel.tar in kernel image")
}
return k.finishTar()
}
func (k *kernelFilter) Flush() error {
err := k.finishTar()
if err != nil { if err != nil {
log.Fatalln(err) return err
} }
return k.tw.Flush()
}
func (k *kernelFilter) Write(b []byte) (n int, err error) {
if k.discard {
return len(b), nil
}
if k.buffer != nil {
return k.buffer.Write(b)
}
return k.tw.Write(b)
}
func (k *kernelFilter) WriteHeader(hdr *tar.Header) error {
err := k.finishTar()
if err != nil {
return err
}
tw := k.tw
switch hdr.Name { switch hdr.Name {
case kernelName, kernelAltName: case "kernel":
if foundKernel { if k.foundKernel {
return nil, nil, errors.New("found more than one possible kernel image") return errors.New("found more than one possible kernel image")
} }
foundKernel = true k.foundKernel = true
kernel = new(bytes.Buffer) k.discard = false
// make a new tarball with kernel in /boot/kernel
tw := tar.NewWriter(kernel)
whdr := &tar.Header{ whdr := &tar.Header{
Name: "boot", Name: "boot",
Mode: 0700, Mode: 0755,
Typeflag: tar.TypeDir, Typeflag: tar.TypeDir,
} }
if err := tw.WriteHeader(whdr); err != nil { if err := tw.WriteHeader(whdr); err != nil {
return nil, nil, err return err
}
// add the cmdline in /boot/cmdline
whdr = &tar.Header{
Name: "boot/cmdline",
Mode: 0644,
Size: int64(len(k.cmdline)),
}
if err := tw.WriteHeader(whdr); err != nil {
return err
}
buf := bytes.NewBufferString(k.cmdline)
_, err = io.Copy(tw, buf)
if err != nil {
return err
} }
whdr = &tar.Header{ whdr = &tar.Header{
Name: "boot/kernel", Name: "boot/kernel",
@ -352,46 +442,123 @@ func untarKernel(buf *bytes.Buffer, kernelName, kernelAltName, ktarName string,
Size: hdr.Size, Size: hdr.Size,
} }
if err := tw.WriteHeader(whdr); err != nil { if err := tw.WriteHeader(whdr); err != nil {
return nil, nil, err return err
}
_, err = io.Copy(tw, tr)
if err != nil {
return nil, nil, err
}
// add the cmdline in /boot/cmdline
whdr = &tar.Header{
Name: "boot/cmdline",
Mode: 0700,
Size: int64(len(cmdline)),
}
if err := tw.WriteHeader(whdr); err != nil {
return nil, nil, err
}
buf := bytes.NewBufferString(cmdline)
_, err = io.Copy(tw, buf)
if err != nil {
return nil, nil, err
}
if err := tw.Close(); err != nil {
return nil, nil, err
}
case ktarName:
ktar = new(bytes.Buffer)
_, err := io.Copy(ktar, tr)
if err != nil {
return nil, nil, err
} }
case "kernel.tar":
k.foundKTar = true
k.discard = false
k.buffer = new(bytes.Buffer)
default: default:
k.discard = true
}
return nil
}
func tarAppend(iw *tar.Writer, tr *tar.Reader) error {
for {
hdr, err := tr.Next()
if err == io.EOF {
break
}
if err != nil {
return err
}
err = iw.WriteHeader(hdr)
if err != nil {
return err
}
_, err = io.Copy(iw, tr)
if err != nil {
return err
}
}
return nil
}
func filesystem(m Moby, tw *tar.Writer) error {
if len(m.Files) != 0 {
log.Infof("Add files:")
}
for _, f := range m.Files {
log.Infof(" %s", f.Path)
if f.Path == "" {
return errors.New("Did not specify path for file")
}
if !f.Directory && f.Contents == "" && f.Symlink == "" {
if f.Source == "" {
return errors.New("Contents of file not specified")
}
contents, err := ioutil.ReadFile(f.Source)
if err != nil {
return err
}
f.Contents = string(contents)
}
// we need all the leading directories
parts := strings.Split(path.Dir(f.Path), "/")
root := ""
for _, p := range parts {
if p == "." || p == "/" {
continue 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 err
}
} }
if kernel == nil { if f.Directory {
return nil, nil, errors.New("did not find kernel in kernel image") if f.Contents != "" {
return errors.New("Directory with contents not allowed")
} }
if ktar == nil { hdr := &tar.Header{
return nil, nil, errors.New("did not find kernel.tar in kernel image") Name: f.Path,
Typeflag: tar.TypeDir,
Mode: 0700,
} }
err := tw.WriteHeader(hdr)
return kernel, ktar, nil if err != nil {
return err
}
} else if f.Symlink != "" {
hdr := &tar.Header{
Name: f.Path,
Typeflag: tar.TypeSymlink,
Mode: 0600,
Linkname: f.Symlink,
}
err := tw.WriteHeader(hdr)
if err != nil {
return err
}
} else {
hdr := &tar.Header{
Name: f.Path,
Mode: 0600,
Size: int64(len(f.Contents)),
}
err := tw.WriteHeader(hdr)
if err != nil {
return err
}
_, err = tw.Write([]byte(f.Contents))
if err != nil {
return err
}
}
}
return nil
} }

View File

@ -1,14 +1,9 @@
package main package main
import ( import (
"archive/tar"
"bytes"
"encoding/json" "encoding/json"
"errors"
"fmt" "fmt"
"io/ioutil"
"os" "os"
"path"
"path/filepath" "path/filepath"
"sort" "sort"
"strings" "strings"
@ -697,94 +692,3 @@ func ConfigInspectToOCI(yaml MobyImage, inspect types.ImageInspect) (specs.Spec,
return oci, nil return oci, nil
} }
func filesystem(m Moby) (*bytes.Buffer, error) {
buf := new(bytes.Buffer)
tw := tar.NewWriter(buf)
defer tw.Close()
if len(m.Files) != 0 {
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 == "" && f.Symlink == "" {
if f.Source == "" {
return buf, errors.New("Contents of file not specified")
}
contents, err := ioutil.ReadFile(f.Source)
if err != nil {
return buf, err
}
f.Contents = string(contents)
}
// 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 if f.Symlink != "" {
hdr := &tar.Header{
Name: f.Path,
Typeflag: tar.TypeSymlink,
Mode: 0600,
Linkname: f.Symlink,
}
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
}

View File

@ -11,6 +11,13 @@ import (
log "github.com/Sirupsen/logrus" log "github.com/Sirupsen/logrus"
) )
type tarWriter interface {
Close() error
Flush() error
Write(b []byte) (n int, err error)
WriteHeader(hdr *tar.Header) error
}
// This uses Docker to convert a Docker image into a tarball. It would be an improvement if we // 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 // used the containerd libraries to do this instead locally direct from a local image
// cache as it would be much simpler. // cache as it would be much simpler.
@ -39,28 +46,8 @@ nameserver 2001:4860:4860::8844
"etc/hostname": "moby", "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, trust bool, pull bool) ([]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, trust, pull)
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 // tarPrefix creates the leading directories for a path
func tarPrefix(path string, tw *tar.Writer) error { func tarPrefix(path string, tw tarWriter) error {
if path == "" { if path == "" {
return nil return nil
} }
@ -87,12 +74,18 @@ func tarPrefix(path string, tw *tar.Writer) error {
return nil return nil
} }
func imageTar(image, prefix string, tw *tar.Writer, trust bool, pull bool) error { // ImageTar takes a Docker image and outputs it to a tar stream
func ImageTar(image, prefix string, tw tarWriter, trust bool, pull bool) error {
log.Debugf("image tar: %s %s", image, prefix) log.Debugf("image tar: %s %s", image, prefix)
if prefix != "" && prefix[len(prefix)-1] != byte('/') { if prefix != "" && prefix[len(prefix)-1] != byte('/') {
return fmt.Errorf("prefix does not end with /: %s", prefix) return fmt.Errorf("prefix does not end with /: %s", prefix)
} }
err := tarPrefix(prefix, tw)
if err != nil {
return err
}
if pull || trust { if pull || trust {
err := dockerPull(image, pull, trust) err := dockerPull(image, pull, trust)
if err != nil { if err != nil {
@ -172,21 +165,15 @@ func imageTar(image, prefix string, tw *tar.Writer, trust bool, pull bool) error
} }
} }
} }
err = tw.Close()
if err != nil {
return err
}
return nil return nil
} }
// ImageBundle produces an OCI bundle at the given path in a tarball, given an image and a config.json // 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, trust bool, pull bool) ([]byte, error) { func ImageBundle(path string, image string, config []byte, tw tarWriter, trust bool, pull bool) error {
log.Debugf("image bundle: %s %s cfg: %s", path, image, string(config)) log.Debugf("image bundle: %s %s cfg: %s", path, image, string(config))
out := new(bytes.Buffer) err := ImageTar(image, path+"/rootfs/", tw, trust, pull)
tw := tar.NewWriter(out)
err := tarPrefix(path+"/rootfs/", tw)
if err != nil { if err != nil {
return []byte{}, err return err
} }
hdr := &tar.Header{ hdr := &tar.Header{
Name: path + "/" + "config.json", Name: path + "/" + "config.json",
@ -195,20 +182,13 @@ func ImageBundle(path string, image string, config []byte, trust bool, pull bool
} }
err = tw.WriteHeader(hdr) err = tw.WriteHeader(hdr)
if err != nil { if err != nil {
return []byte{}, err return err
} }
buf := bytes.NewBuffer(config) buf := bytes.NewBuffer(config)
_, err = io.Copy(tw, buf) _, err = io.Copy(tw, buf)
if err != nil { if err != nil {
return []byte{}, err return err
} }
err = imageTar(image, path+"/rootfs/", tw, trust, pull)
if err != nil { return nil
return []byte{}, err
}
err = tw.Close()
if err != nil {
return []byte{}, err
}
return out.Bytes(), nil
} }

View File

@ -1,6 +1,7 @@
package main package main
import ( import (
"bytes"
"crypto/sha256" "crypto/sha256"
"fmt" "fmt"
"io" "io"
@ -58,7 +59,9 @@ func ensureLinuxkitImage(name string) error {
return err return err
} }
// TODO pass through --pull to here // TODO pass through --pull to here
image := buildInternal(m, false) buf := new(bytes.Buffer)
buildInternal(m, buf, false)
image := buf.Bytes()
kernel, initrd, cmdline, err := tarToInitrd(image) kernel, initrd, cmdline, err := tarToInitrd(image)
if err != nil { if err != nil {
return fmt.Errorf("Error converting to initrd: %v", err) return fmt.Errorf("Error converting to initrd: %v", err)

View File

@ -23,13 +23,6 @@ const (
) )
var outFuns = map[string]func(string, []byte, int, bool) error{ var outFuns = map[string]func(string, []byte, int, bool) error{
"tar": func(base string, image []byte, size int, hyperkit bool) error {
err := outputTar(base, image)
if err != nil {
return fmt.Errorf("Error writing tar output: %v", err)
}
return nil
},
"kernel+initrd": func(base string, image []byte, size int, hyperkit bool) error { "kernel+initrd": func(base string, image []byte, size int, hyperkit bool) error {
kernel, initrd, cmdline, err := tarToInitrd(image) kernel, initrd, cmdline, err := tarToInitrd(image)
if err != nil { if err != nil {
@ -336,9 +329,3 @@ func outputKernelInitrd(base string, kernel []byte, initrd []byte, cmdline strin
} }
return nil return nil
} }
func outputTar(base string, initrd []byte) error {
log.Debugf("output tar: %s", base)
log.Infof(" %s", base+".tar")
return ioutil.WriteFile(base+".tar", initrd, os.FileMode(0644))
}