Merge pull request #1463 from rneugeba/cli

Improve the CLI tool
This commit is contained in:
Rolf Neugebauer 2017-04-02 22:00:30 +01:00 committed by GitHub
commit e89d03b43e
3 changed files with 91 additions and 46 deletions

View File

@ -19,8 +19,7 @@ import (
func build(args []string) { func build(args []string) {
buildCmd := flag.NewFlagSet("build", flag.ExitOnError) buildCmd := flag.NewFlagSet("build", flag.ExitOnError)
buildCmd.Usage = func() { buildCmd.Usage = func() {
fmt.Printf("USAGE: %s build [options] [file.yml]\n\n", os.Args[0]) fmt.Printf("USAGE: %s build [options] <file>[.yml]\n\n", os.Args[0])
fmt.Printf("'file.yml' defaults to 'moby.yml' if not specified.\n\n")
fmt.Printf("Options:\n") fmt.Printf("Options:\n")
buildCmd.PrintDefaults() buildCmd.PrintDefaults()
} }
@ -30,9 +29,14 @@ func build(args []string) {
buildCmd.Parse(args) buildCmd.Parse(args)
remArgs := buildCmd.Args() remArgs := buildCmd.Args()
conf := "moby.yml" if len(remArgs) == 0 {
if len(remArgs) > 0 { fmt.Println("Please specify a configuration file\n")
conf = remArgs[0] buildCmd.Usage()
os.Exit(1)
}
conf := remArgs[0]
if filepath.Ext(conf) == "" {
conf = conf + ".yml"
} }
buildInternal(*buildName, *buildPull, conf) buildInternal(*buildName, *buildPull, conf)

View File

@ -8,56 +8,79 @@ import (
log "github.com/Sirupsen/logrus" log "github.com/Sirupsen/logrus"
"github.com/docker/hyperkit/go" "github.com/docker/hyperkit/go"
"github.com/rneugeba/iso9660wrap"
) )
// Process the run arguments and execute run // Process the run arguments and execute run
func runHyperKit(args []string) { func runHyperKit(args []string) {
hyperkitCmd := flag.NewFlagSet("hyperkit", flag.ExitOnError) hyperkitCmd := flag.NewFlagSet("hyperkit", flag.ExitOnError)
hyperkitCmd.Usage = func() { hyperkitCmd.Usage = func() {
fmt.Printf("USAGE: %s run hyperkit [options] [prefix]\n\n", os.Args[0]) fmt.Printf("USAGE: %s run hyperkit [options] prefix\n\n", os.Args[0])
fmt.Printf("'prefix' specifies the path to the VM image.\n") fmt.Printf("'prefix' specifies the path to the VM image.\n")
fmt.Printf("It defaults to './moby'.\n")
fmt.Printf("\n") fmt.Printf("\n")
fmt.Printf("Options:\n") fmt.Printf("Options:\n")
hyperkitCmd.PrintDefaults() hyperkitCmd.PrintDefaults()
} }
runHyperKit := hyperkitCmd.String("hyperkit", "", "Path to hyperkit binary (if not in default location)") hyperkitPath := hyperkitCmd.String("hyperkit", "", "Path to hyperkit binary (if not in default location)")
runCPUs := hyperkitCmd.Int("cpus", 1, "Number of CPUs") cpus := hyperkitCmd.Int("cpus", 1, "Number of CPUs")
runMem := hyperkitCmd.Int("mem", 1024, "Amount of memory in MB") mem := hyperkitCmd.Int("mem", 1024, "Amount of memory in MB")
runDiskSz := hyperkitCmd.Int("disk-size", 0, "Size of Disk in MB") diskSz := hyperkitCmd.Int("disk-size", 0, "Size of Disk in MB")
runDisk := hyperkitCmd.String("disk", "", "Path to disk image to used") disk := hyperkitCmd.String("disk", "", "Path to disk image to used")
data := hyperkitCmd.String("data", "", "Metadata to pass to VM (either a path to a file or a string)")
hyperkitCmd.Parse(args) hyperkitCmd.Parse(args)
remArgs := hyperkitCmd.Args() remArgs := hyperkitCmd.Args()
if len(remArgs) == 0 {
fmt.Println("Please specify the prefix to the image to boot\n")
hyperkitCmd.Usage()
os.Exit(1)
}
prefix := remArgs[0]
prefix := "moby" isoPath := ""
if len(remArgs) > 0 { if *data != "" {
prefix = remArgs[0] var d []byte
if _, err := os.Stat(*data); os.IsNotExist(err) {
d = []byte(*data)
} else {
d, err = ioutil.ReadFile(*data)
if err != nil {
log.Fatalf("Cannot read user data: %v", err)
}
}
isoPath = prefix + "-data.iso"
outfh, err := os.OpenFile(isoPath, os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
log.Fatalf("Cannot create user data ISO: %v", err)
}
err = iso9660wrap.WriteBuffer(outfh, d, "config")
if err != nil {
log.Fatalf("Cannot write user data ISO: %v", err)
}
outfh.Close()
} }
runHyperKitInternal(*runHyperKit, *runCPUs, *runMem, *runDiskSz, *runDisk, prefix) // Run
}
func runHyperKitInternal(hyperkitPath string, cpus, mem, diskSz int, disk, prefix string) {
cmdline, err := ioutil.ReadFile(prefix + "-cmdline") cmdline, err := ioutil.ReadFile(prefix + "-cmdline")
if err != nil { if err != nil {
log.Fatalf("Cannot open cmdline file: %v", err) log.Fatalf("Cannot open cmdline file: %v", err)
} }
if diskSz != 0 && disk == "" { if *diskSz != 0 && *disk == "" {
disk = prefix + "-disk.img" *disk = prefix + "-disk.img"
} }
h, err := hyperkit.New(hyperkitPath, "", "auto", disk) h, err := hyperkit.New(*hyperkitPath, "", "auto", *disk)
if err != nil { if err != nil {
log.Fatalln("Error creating hyperkit: ", err) log.Fatalln("Error creating hyperkit: ", err)
} }
h.Kernel = prefix + "-bzImage" h.Kernel = prefix + "-bzImage"
h.Initrd = prefix + "-initrd.img" h.Initrd = prefix + "-initrd.img"
h.CPUs = cpus h.ISOImage = isoPath
h.Memory = mem h.CPUs = *cpus
h.DiskSize = diskSz h.Memory = *mem
h.DiskSize = *diskSz
err = h.Run(string(cmdline)) err = h.Run(string(cmdline))
if err != nil { if err != nil {

View File

@ -2,6 +2,7 @@ package iso9660wrap
import ( import (
"bufio" "bufio"
"bytes"
"encoding/binary" "encoding/binary"
"fmt" "fmt"
"io" "io"
@ -154,21 +155,38 @@ const rootDirectorySectorNum uint32 = primaryVolumeSectorNum + numVolumeSectors
// WriteFile writes the contents of infh to an iso at outfh with the name provided // WriteFile writes the contents of infh to an iso at outfh with the name provided
func WriteFile(outfh, infh *os.File) error { func WriteFile(outfh, infh *os.File) error {
inputFileSize, inputFilename, err := getInputFileSizeAndName(infh) fileSize, filename, err := getInputFileSizeAndName(infh)
if err != nil { if err != nil {
return err return err
} }
if inputFileSize == 0 { if fileSize == 0 {
return fmt.Errorf("input file must be at least 1 byte in size") return fmt.Errorf("input file must be at least 1 byte in size")
} }
inputFilename = strings.ToUpper(inputFilename) filename = strings.ToUpper(filename)
if !filenameSatisfiesISOConstraints(inputFilename) { if !filenameSatisfiesISOConstraints(filename) {
return fmt.Errorf("Input file name %s does not satisfy the ISO9660 character set constraints", inputFilename) return fmt.Errorf("Input file name %s does not satisfy the ISO9660 character set constraints", filename)
} }
buf := make([]byte, fileSize, fileSize)
_, err = infh.Read(buf)
if err != nil {
return err
}
return WriteBuffer(outfh, buf, filename)
}
// WriteBuffer writes the contents of buf to an iso at outfh with the name provided
func WriteBuffer(outfh *os.File, buf []byte, filename string) error {
fileSize := uint32(len(buf))
if fileSize == 0 {
return fmt.Errorf("input buffer must be at least 1 byte in size")
}
r := bytes.NewReader(buf)
// reserved sectors // reserved sectors
reservedAreaLength := int64(16 * SectorSize) reservedAreaLength := int64(16 * SectorSize)
_, err = outfh.Write([]byte(reservedAreaData)) _, err := outfh.Write([]byte(reservedAreaData))
if err != nil { if err != nil {
return fmt.Errorf("could not write to output file: %s", err) return fmt.Errorf("could not write to output file: %s", err)
} }
@ -198,11 +216,11 @@ func WriteFile(outfh, infh *os.File) error {
w := NewISO9660Writer(bufw) w := NewISO9660Writer(bufw)
writePrimaryVolumeDescriptor(w, inputFileSize, inputFilename) writePrimaryVolumeDescriptor(w, fileSize, filename)
writeVolumeDescriptorSetTerminator(w) writeVolumeDescriptorSetTerminator(w)
writePathTable(w, binary.LittleEndian) writePathTable(w, binary.LittleEndian)
writePathTable(w, binary.BigEndian) writePathTable(w, binary.BigEndian)
writeData(w, infh, inputFileSize, inputFilename) writeData(w, r, fileSize, filename)
w.Finish() w.Finish()
@ -217,9 +235,9 @@ func WriteFile(outfh, infh *os.File) error {
return nil return nil
} }
func writePrimaryVolumeDescriptor(w *ISO9660Writer, inputFileSize uint32, inputFilename string) { func writePrimaryVolumeDescriptor(w *ISO9660Writer, fileSize uint32, filename string) {
if len(inputFilename) > 32 { if len(filename) > 32 {
inputFilename = inputFilename[:32] filename = filename[:32]
} }
now := time.Now() now := time.Now()
@ -233,10 +251,10 @@ func writePrimaryVolumeDescriptor(w *ISO9660Writer, inputFileSize uint32, inputF
sw.WriteByte('\x00') sw.WriteByte('\x00')
sw.WritePaddedString("", 32) sw.WritePaddedString("", 32)
sw.WritePaddedString(inputFilename, 32) sw.WritePaddedString(filename, 32)
sw.WriteZeros(8) sw.WriteZeros(8)
sw.WriteBothEndianDWord(numTotalSectors(inputFileSize)) sw.WriteBothEndianDWord(numTotalSectors(fileSize))
sw.WriteZeros(32) sw.WriteZeros(32)
sw.WriteBothEndianWord(1) // volume set size sw.WriteBothEndianWord(1) // volume set size
@ -294,7 +312,7 @@ func writePathTable(w *ISO9660Writer, bo binary.ByteOrder) {
sw.PadWithZeros() sw.PadWithZeros()
} }
func writeData(w *ISO9660Writer, infh io.Reader, inputFileSize uint32, inputFilename string) { func writeData(w *ISO9660Writer, infh io.Reader, fileSize uint32, filename string) {
sw := w.NextSector() sw := w.NextSector()
if w.CurrentSector() != rootDirectorySectorNum { if w.CurrentSector() != rootDirectorySectorNum {
Panicf("internal error: unexpected root directory sector %d", w.CurrentSector()) Panicf("internal error: unexpected root directory sector %d", w.CurrentSector())
@ -302,7 +320,7 @@ func writeData(w *ISO9660Writer, infh io.Reader, inputFileSize uint32, inputFile
WriteDirectoryRecord(sw, "\x00", w.CurrentSector()) WriteDirectoryRecord(sw, "\x00", w.CurrentSector())
WriteDirectoryRecord(sw, "\x01", rootDirectorySectorNum) WriteDirectoryRecord(sw, "\x01", rootDirectorySectorNum)
WriteFileRecordHeader(sw, inputFilename, w.CurrentSector()+1, inputFileSize) WriteFileRecordHeader(sw, filename, w.CurrentSector()+1, fileSize)
// Now stream the data. Note that the first buffer is never of SectorSize, // Now stream the data. Note that the first buffer is never of SectorSize,
// since we've already filled a part of the sector. // since we've already filled a part of the sector.
@ -322,17 +340,17 @@ func writeData(w *ISO9660Writer, infh io.Reader, inputFileSize uint32, inputFile
break break
} }
} }
if total != inputFileSize { if total != fileSize {
Panicf("input file size changed while the ISO file was being created (expected to read %d, read %d)", inputFileSize, total) Panicf("input file size changed while the ISO file was being created (expected to read %d, read %d)", fileSize, total)
} else if w.CurrentSector() != numTotalSectors(inputFileSize)-1 { } else if w.CurrentSector() != numTotalSectors(fileSize)-1 {
Panicf("internal error: unexpected last sector number (expected %d, actual %d)", Panicf("internal error: unexpected last sector number (expected %d, actual %d)",
numTotalSectors(inputFileSize)-1, w.CurrentSector()) numTotalSectors(fileSize)-1, w.CurrentSector())
} }
} }
func numTotalSectors(inputFileSize uint32) uint32 { func numTotalSectors(fileSize uint32) uint32 {
var numDataSectors uint32 var numDataSectors uint32
numDataSectors = (inputFileSize + (SectorSize - 1)) / SectorSize numDataSectors = (fileSize + (SectorSize - 1)) / SectorSize
return 1 + rootDirectorySectorNum + numDataSectors return 1 + rootDirectorySectorNum + numDataSectors
} }