Skip to content
This repository was archived by the owner on Feb 8, 2021. It is now read-only.

enable template for runv and runv-containerd #303

Merged
merged 7 commits into from
Aug 24, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 38 additions & 3 deletions containerd/containerd.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package containerd

import (
"encoding/json"
"flag"
"net"
"os"
Expand All @@ -16,8 +17,11 @@ import (
"github.com/hyperhq/runv/containerd/api/grpc/server"
"github.com/hyperhq/runv/driverloader"
"github.com/hyperhq/runv/factory"
singlefactory "github.com/hyperhq/runv/factory/single"
templatefactory "github.com/hyperhq/runv/factory/template"
"github.com/hyperhq/runv/hypervisor"
"github.com/hyperhq/runv/supervisor"
templatecore "github.com/hyperhq/runv/template"
"google.golang.org/grpc"
)

Expand Down Expand Up @@ -53,8 +57,10 @@ var ContainerdCommand = cli.Command{
},
},
Action: func(context *cli.Context) {
driver := context.GlobalString("driver")
kernel := context.GlobalString("kernel")
initrd := context.GlobalString("initrd")
template := context.GlobalString("template")
stateDir := context.String("state-dir")
containerdDir := context.String("containerd-dir")
if containerdDir == "" {
Expand All @@ -67,18 +73,47 @@ var ContainerdCommand = cli.Command{
flag.CommandLine.Parse([]string{"-v", "1", "--log_dir", context.GlobalString("log_dir")})
}

if kernel == "" || initrd == "" {
var tconfig *templatecore.TemplateVmConfig
if template != "" {
path := filepath.Join(template, "config.json")
f, err := os.Open(path)
if err != nil {
glog.Errorf("open template JSON configuration file failed: %v\n", err)
os.Exit(-1)
}
if err := json.NewDecoder(f).Decode(&tconfig); err != nil {
glog.Errorf("parse template JSON configuration file failed: %v\n", err)
f.Close()
os.Exit(-1)
}
f.Close()

if (driver != "" && driver != tconfig.Driver) ||
(kernel != "" && kernel != tconfig.Kernel) ||
(initrd != "" && initrd != tconfig.Initrd) {
glog.Infof("template config is not match the driver, kernel or initrd argument, disable template")
template = ""
} else if driver == "" {
driver = tconfig.Driver
}
} else if kernel == "" || initrd == "" {
glog.Infof("argument kernel and initrd must be set")
os.Exit(1)
}

hypervisor.InterfaceCount = 0
var err error
if hypervisor.HDriver, err = driverloader.Probe(context.GlobalString("driver")); err != nil {
if hypervisor.HDriver, err = driverloader.Probe(driver); err != nil {
glog.V(1).Infof("%s\n", err.Error())
os.Exit(1)
}

f := factory.NewFromConfigs(kernel, initrd, nil)
var f factory.Factory
if template != "" {
f = singlefactory.New(templatefactory.NewFromExisted(tconfig))
} else {
f = factory.NewFromConfigs(kernel, initrd, nil)
}
sv, err := supervisor.New(stateDir, containerdDir, f)
if err != nil {
glog.Infof("%v", err)
Expand Down
10 changes: 5 additions & 5 deletions factory/template/template.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,19 @@ import (
)

type templateFactory struct {
s *template.TemplateVmState
s *template.TemplateVmConfig
}

func New(templatePath string, cpu, mem int, kernel, initrd string) base.Factory {
func New(templateRoot string, cpu, mem int, kernel, initrd string) base.Factory {
var vmName string

for {
vmName = fmt.Sprintf("template-vm-%s", pod.RandStr(10, "alpha"))
if _, err := os.Stat(templatePath + "/" + vmName); os.IsNotExist(err) {
if _, err := os.Stat(templateRoot + "/" + vmName); os.IsNotExist(err) {
break
}
}
s, err := template.CreateTemplateVM(templatePath, vmName, cpu, mem, kernel, initrd)
s, err := template.CreateTemplateVM(templateRoot+"/"+vmName, vmName, cpu, mem, kernel, initrd)
if err != nil {
glog.Infof("failed to create template factory: %v", err)
glog.Infof("use direct factory instead")
Expand All @@ -34,7 +34,7 @@ func New(templatePath string, cpu, mem int, kernel, initrd string) base.Factory
return &templateFactory{s: s}
}

func NewFromExisted(s *template.TemplateVmState) base.Factory {
func NewFromExisted(s *template.TemplateVmConfig) base.Factory {
return &templateFactory{s: s}
}

Expand Down
5 changes: 5 additions & 0 deletions hypervisor/driver.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ type GuestNicInfo struct {
}

type HypervisorDriver interface {
Name() string
InitContext(homeDir string) DriverContext

LoadContext(persisted map[string]interface{}) (DriverContext, error)
Expand Down Expand Up @@ -99,6 +100,10 @@ func (ed *EmptyDriver) Initialize() error {
return nil
}

func (ed *EmptyDriver) Name() string {
return "empty"
}

func (ed *EmptyDriver) InitContext(homeDir string) DriverContext {
return &EmptyContext{}
}
Expand Down
4 changes: 4 additions & 0 deletions hypervisor/libvirt/libvirt.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ func InitDriver() *LibvirtDriver {
}
}

func (ld *LibvirtDriver) Name() string {
return "libvirt"
}

func (ld *LibvirtDriver) InitContext(homeDir string) hypervisor.DriverContext {
return &LibvirtContext{
driver: ld,
Expand Down
4 changes: 4 additions & 0 deletions hypervisor/qemu/qemu.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ func InitDriver() *QemuDriver {
}
}

func (qd *QemuDriver) Name() string {
return "qemu"
}

func (qd *QemuDriver) InitContext(homeDir string) hypervisor.DriverContext {
if _, err := os.Stat(QemuLogDir); os.IsNotExist(err) {
os.Mkdir(QemuLogDir, 0755)
Expand Down
4 changes: 4 additions & 0 deletions hypervisor/vbox/vbox.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ func InitDriver() *VBoxDriver {
return vd
}

func (vd *VBoxDriver) Name() string {
return "vbox"
}

func (vd *VBoxDriver) InitContext(homeDir string) hypervisor.DriverContext {
return &VBoxContext{
Driver: vd,
Expand Down
3 changes: 3 additions & 0 deletions hypervisor/xen/xen.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,9 @@ func InitDriver() *XenDriver {
}

//judge if the xl is available and if the version and cap is acceptable
func (xd *XenDriver) Name() string {
return "xen"
}

func (xd *XenDriver) InitContext(homeDir string) hypervisor.DriverContext {
return &XenContext{
Expand Down
16 changes: 4 additions & 12 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import (
"log"
"net"
"os"
"runtime"
"time"

"github.com/codegangsta/cli"
Expand Down Expand Up @@ -84,7 +83,6 @@ func main() {
},
cli.StringFlag{
Name: "driver",
Value: getDefaultDriver(),
Usage: "hypervisor driver (supports: kvm xen vbox)",
},
cli.StringFlag{
Expand All @@ -95,6 +93,10 @@ func main() {
Name: "initrd",
Usage: "runv-compatible initrd for the container",
},
cli.StringFlag{
Name: "template",
Usage: "path to the template vm state directory",
},
cli.StringFlag{
Name: "vbox",
Usage: "runv-compatible boot ISO for the container for vbox driver",
Expand All @@ -114,16 +116,6 @@ func main() {
}
}

func getDefaultDriver() string {
if runtime.GOOS == "linux" {
return "qemu"
}
if runtime.GOOS == "darwin" {
return "vbox"
}
return ""
}

func getClient(address string) types.APIClient {
// reset the logger for grpc to log to dev/null so that it does not mess with our stdio
grpclog.SetLogger(log.New(ioutil.Discard, "", log.LstdFlags))
Expand Down
23 changes: 15 additions & 8 deletions start.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,6 @@ command(s) that get executed on start, edit the args parameter of the spec. See
}
}

driver := context.GlobalString("driver")
kernel := context.GlobalString("kernel")
initrd := context.GlobalString("initrd")
// only set the default kernel/initrd when it is the first container(sharedContainer == "")
Expand Down Expand Up @@ -163,14 +162,22 @@ command(s) that get executed on start, edit the args parameter of the spec. See
os.Exit(-1)
}

args := []string{
"runv",
"--driver", driver,
"--kernel", kernel,
"--initrd", initrd,
}
args := []string{"runv", "--kernel", kernel, "--initrd", initrd}
if context.GlobalBool("debug") {
args = append(args, "--debug", "--log_dir", context.GlobalString("log_dir"))
args = append(args, "--debug")
}
if context.GlobalIsSet("driver") {
args = append(args, "--driver", context.GlobalString("driver"))
}
for _, goption := range []string{"log_dir", "template"} {
if context.GlobalIsSet(goption) {
abs_path, err := filepath.Abs(context.GlobalString(goption))
if err != nil {
fmt.Printf("Cannot get abs path for %s: %v\n", goption, err)
os.Exit(-1)
}
args = append(args, "--"+goption, abs_path)
}
}
args = append(args,
"containerd", "--solo-namespaced",
Expand Down
42 changes: 33 additions & 9 deletions template/template.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
package template

import (
"encoding/json"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"syscall"
"time"

Expand All @@ -16,23 +19,23 @@ import (
// is StatePath/state
//
// New Vm can be booted from the saved TemplateVm states with all the initial
// memory is shared(copy-on-write) with the TemplateVm(templatePath/vmName/memory)
// memory is shared(copy-on-write) with the TemplateVm(statePath/memory)
//
// Phoenix rising from the ashes

type TemplateVmState struct {
type TemplateVmConfig struct {
StatePath string `json:"statepath"`
Driver string `json:"driver"`
Cpu int `json:"cpu"`
Memory int `json:"memory"`
Kernel string `json:"kernel"`
Initrd string `json:"initrd"`
}

func CreateTemplateVM(templatePath, vmName string, cpu, mem int, kernel, initrd string) (t *TemplateVmState, err error) {
statePath := templatePath + "/" + vmName
func CreateTemplateVM(statePath, vmName string, cpu, mem int, kernel, initrd string) (t *TemplateVmConfig, err error) {
defer func() {
if err != nil {
(&TemplateVmState{StatePath: statePath}).Destroy()
(&TemplateVmConfig{StatePath: statePath}).Destroy()
}
}()

Expand Down Expand Up @@ -86,10 +89,31 @@ func CreateTemplateVM(templatePath, vmName string, cpu, mem int, kernel, initrd
// so we wait here. We should fix it in the qemu driver side.
time.Sleep(1 * time.Second)

return &TemplateVmState{StatePath: statePath, Cpu: cpu, Memory: mem, Kernel: kernel, Initrd: initrd}, nil
config := &TemplateVmConfig{
StatePath: statePath,
Driver: hypervisor.HDriver.Name(),
Cpu: cpu,
Memory: mem,
Kernel: kernel,
Initrd: initrd,
}

configData, err := json.MarshalIndent(config, "", "\t")
if err != nil {
glog.V(1).Infof("%s\n", err.Error())
return nil, err
}
configFile := filepath.Join(statePath, "config.json")
err = ioutil.WriteFile(configFile, configData, 0644)
if err != nil {
glog.V(1).Infof("%s\n", err.Error())
return nil, err
}

return config, nil
}

func (t *TemplateVmState) BootConfigFromTemplate() *hypervisor.BootConfig {
func (t *TemplateVmConfig) BootConfigFromTemplate() *hypervisor.BootConfig {
return &hypervisor.BootConfig{
CPU: t.Cpu,
Memory: t.Memory,
Expand All @@ -104,11 +128,11 @@ func (t *TemplateVmState) BootConfigFromTemplate() *hypervisor.BootConfig {
}

// boot vm from template, the returned vm is paused
func (t *TemplateVmState) NewVmFromTemplate(vmName string) (*hypervisor.Vm, error) {
func (t *TemplateVmConfig) NewVmFromTemplate(vmName string) (*hypervisor.Vm, error) {
return hypervisor.GetVm(vmName, t.BootConfigFromTemplate(), true, false)
}

func (t *TemplateVmState) Destroy() {
func (t *TemplateVmConfig) Destroy() {
for i := 0; i < 5; i++ {
err := syscall.Unmount(t.StatePath, 0)
if err != nil {
Expand Down