Skip to content
This repository has been archived by the owner on Feb 27, 2020. It is now read-only.

Commit

Permalink
Merge pull request #84 from taskcluster/qemu
Browse files Browse the repository at this point in the history
Qemu
  • Loading branch information
jonasfj authored Jul 8, 2016
2 parents fe999db + 6248518 commit 2e0a7c9
Show file tree
Hide file tree
Showing 175 changed files with 10,388 additions and 7,864 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
/taskcluster-worker
coverage.out
/.vagrant
coverage.out
12 changes: 12 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
FROM golang:1.6
MAINTAINER Jonas Finnemann Jensen <[email protected]>

RUN apt-get update -y
RUN apt-get upgrade -y
RUN apt-get install -y qemu dnsmasq-base build-essential liblz4-tool iptables

ENV APP_PATH github.com/taskcluster/taskcluster-worker

RUN mkdir -p /go/src/$APP_PATH
RUN ln -s /go/src/$APP_PATH /src
WORKDIR /go/src/$APP_PATH
109 changes: 95 additions & 14 deletions Godeps/Godeps.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

158 changes: 158 additions & 0 deletions commands/qemu-build/cmd.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
package qemubuild

import (
"errors"
"io/ioutil"
"os"
"os/exec"
"os/signal"
"path/filepath"
"strconv"

"github.com/taskcluster/taskcluster-worker/commands/qemu-run"
"github.com/taskcluster/taskcluster-worker/engines/qemu/image"
"github.com/taskcluster/taskcluster-worker/engines/qemu/network"
"github.com/taskcluster/taskcluster-worker/engines/qemu/vm"
"github.com/taskcluster/taskcluster-worker/runtime"
)

type cmd struct{}

func (cmd) Summary() string {
return "Build an image for the QEMU engine"
}

func (cmd) Usage() string {
return `
taskcluster-worker qemu-build takes a machine definition as JSON or an existing
image and two ISO files to mounted as CDs and creates a virtual machine that
will be saved to disk when terminated.
usage:
taskcluster-worker qemu-build [options] from-new <machine.json> <result.tar.lz4>
taskcluster-worker qemu-build [options] from-image <image.tar.lz4> <result.tar.lz4>
options:
--no-vnc Do not open a VNC display.
--size <size> Size of the image in GiB [default: 10].
--boot <file> File to use as cd-rom 1 and boot medium.
--cdrom <file> File to use as cd-rom 2 (drivers etc).
-h --help Show this screen.
`
}

func (cmd) Execute(arguments map[string]interface{}) {
// Setup logging
logger, _ := runtime.CreateLogger("info")
log := logger.WithField("component", "qemu-build")

// Parse arguments
inputImageFile, _ := arguments["<image.tar.lz4>"].(string)
machineFile, _ := arguments["<machine.json>"].(string)
outputFile := arguments["<result.tar.lz4>"].(string)
fromNew := arguments["from-new"].(bool)
fromImage := arguments["from-image"].(bool)
novnc := arguments["--no-vnc"].(bool)
boot, _ := arguments["--boot"].(string)
cdrom, _ := arguments["--cdrom"].(string)
size, err := strconv.ParseInt(arguments["--size"].(string), 10, 32)
if err != nil {
log.Fatal("Couldn't parse --size, error: ", err)
}
if size > 80 {
log.Fatal("Images have a sanity limit of 80 GiB!")
}

// Find absolute outputFile
outputFile, err = filepath.Abs(outputFile)
if err != nil {
log.Fatal("Failed to resolve output file, error: ", err)
}

// Create temp folder for the image
tempFolder, err := ioutil.TempDir("", "taskcluster-worker-build-image-")
if err != nil {
log.Fatal("Failed to create temporary folder, error: ", err)
}
defer os.RemoveAll(tempFolder)

var img *image.MutableImage
if fromNew {
// Read machine definition
machine, err := vm.LoadMachine(machineFile)
if err != nil {
log.Fatal("Failed to load machine file from ", machineFile, " error: ", err)
}

// Construct MutableImage
log.Info("Creating MutableImage")
img, err = image.NewMutableImage(tempFolder, int(size), machine)
if err != nil {
log.Fatal("Failed to create image, error: ", err)
}
}
if fromImage {
img, err = image.NewMutableImageFromFile(inputImageFile, tempFolder)
if err != nil {
log.Fatal("Failed to load image, error: ", err)
}
}

// Create temp folder for sockets
socketFolder, err := ioutil.TempDir("", "taskcluster-worker-sockets-")
if err != nil {
log.Fatal("Failed to create temporary folder, error: ", err)
}
defer os.RemoveAll(socketFolder)

// Setup a user-space network
log.Info("Creating user-space network")
net, err := network.NewUserNetwork(tempFolder)
if err != nil {
log.Fatal("Failed to create user-space network, error: ", err)
}

// Create virtual machine
log.Info("Creating virtual machine")
vm := vm.NewVirtualMachine(img, net, socketFolder, boot, cdrom)

// Start the virtual machine
log.Info("Starting virtual machine")
vm.Start()

// Open VNC display
if !novnc {
go qemurun.StartVNCViewer(vm.VNCSocket(), vm.Done)
}

// Wait for interrupt to gracefully kill everything
interrupted := make(chan os.Signal, 1)
signal.Notify(interrupted, os.Interrupt)

// Wait for virtual machine to be done, or we get interrupted
select {
case <-interrupted:
vm.Kill()
err = errors.New("SIGINT recieved, aborting virtual machine")
case <-vm.Done:
err = vm.Error
}
<-vm.Done
signal.Stop(interrupted)
defer img.Dispose()

if err != nil {
if e, ok := err.(*exec.ExitError); ok {
log.Fatal("QEMU error: ", string(e.Stderr))
}
log.Info("Error running virtual machine: ", err)
return
}

// Package up the finished image
log.Info("Package virtual machine image")
err = img.Package(outputFile)
if err != nil {
log.Fatal("Failed to package finished image, error: ", err)
}
}
9 changes: 9 additions & 0 deletions commands/qemu-build/init_linux.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package qemubuild

import "github.com/taskcluster/taskcluster-worker/commands/extpoints"

func init() {
// This command should only be available on linux, so we register it in a file
// that ends with _linux.go
extpoints.CommandProviders.Register(cmd{}, "qemu-build")
}
41 changes: 41 additions & 0 deletions commands/qemu-guest-tools/cmd.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package qemuguesttools

import (
"github.com/taskcluster/taskcluster-worker/commands/extpoints"
"github.com/taskcluster/taskcluster-worker/runtime"
)

var debug = runtime.Debug("guesttools")

func init() {
extpoints.CommandProviders.Register(cmd{}, "qemu-guest-tools")
}

type cmd struct{}

func (cmd) Summary() string {
return "Run guest-tools, for use in VMs for the QEMU engine"
}

func (cmd) Usage() string {
return `
taskcluster-worker qemu-guest-tools start the guest tools that should run inside
the virtual machines used with QEMU engine.
usage: taskcluster-worker qemu-guest-tools [options]
options:
--host <ip> IP-address of meta-data server [default: 169.254.169.254].
-h --help Show this screen.
`
}

func (cmd) Execute(arguments map[string]interface{}) {
host := arguments["--host"].(string)

logger, _ := runtime.CreateLogger("info")
log := logger.WithField("component", "qemu-guest-tools")

g := new(host, log)
g.Run()
}
Loading

0 comments on commit 2e0a7c9

Please sign in to comment.