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

Commit

Permalink
Merge pull request #303 from bergwolf/vmfactory
Browse files Browse the repository at this point in the history
add vm factory support
  • Loading branch information
laijs authored Jul 21, 2018
2 parents e001061 + 0a11230 commit 14d25b8
Show file tree
Hide file tree
Showing 49 changed files with 2,387 additions and 279 deletions.
15 changes: 15 additions & 0 deletions cli/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,11 @@ type tomlConfig struct {
Shim map[string]shim
Agent map[string]agent
Runtime runtime
Factory factory
}

type factory struct {
Template bool `toml:"enable_template"`
}

type hypervisor struct {
Expand Down Expand Up @@ -353,6 +358,10 @@ func newQemuHypervisorConfig(h hypervisor) (vc.HypervisorConfig, error) {
}, nil
}

func newFactoryConfig(f factory) (oci.FactoryConfig, error) {
return oci.FactoryConfig{Template: f.Template}, nil
}

func newShimConfig(s shim) (vc.ShimConfig, error) {
path, err := s.path()
if err != nil {
Expand Down Expand Up @@ -423,6 +432,12 @@ func updateRuntimeConfig(configPath string, tomlConf tomlConfig, config *oci.Run
config.ShimConfig = shConfig
}

fConfig, err := newFactoryConfig(tomlConf.Factory)
if err != nil {
return fmt.Errorf("%v: %v", configPath, err)
}
config.FactoryConfig = fConfig

return nil
}

Expand Down
12 changes: 12 additions & 0 deletions cli/config/configuration.toml.in
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,18 @@ enable_iothreads = @DEFENABLEIOTHREADS@
# used for 9p packet payload.
#msize_9p = @DEFMSIZE9P@

[factory]
# VM templating support. Once enabled, new VMs are created from template
# using vm cloning. They will share the same initial kernel, initramfs and
# agent memory by mapping it readonly. It helps speeding up new container
# creation and saves a lot of memory if there are many kata containers running
# on the same host.
#
# When disabled, new VMs are created from scratch.
#
# Default false
#enable_template = true

[proxy.@PROJECT_TYPE@]
path = "@PROXYPATH@"

Expand Down
16 changes: 16 additions & 0 deletions cli/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1146,3 +1146,19 @@ func TestUpdateRuntimeConfigurationVMConfig(t *testing.T) {

assert.Equal(expectedVMConfig, config.VMConfig)
}

func TestUpdateRuntimeConfigurationFactoryConfig(t *testing.T) {
assert := assert.New(t)

config := oci.RuntimeConfig{}
expectedFactoryConfig := oci.FactoryConfig{
Template: true,
}

tomlConf := tomlConfig{Factory: factory{Template: true}}

err := updateRuntimeConfig("", tomlConf, &config)
assert.NoError(err)

assert.Equal(expectedFactoryConfig, config.FactoryConfig)
}
31 changes: 23 additions & 8 deletions cli/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
"strings"

vc "github.com/kata-containers/runtime/virtcontainers"
vf "github.com/kata-containers/runtime/virtcontainers/factory"
"github.com/kata-containers/runtime/virtcontainers/pkg/oci"
"github.com/urfave/cli"
)
Expand Down Expand Up @@ -106,6 +107,25 @@ func create(containerID, bundlePath, console, pidFilePath string, detach bool,
return err
}

if runtimeConfig.FactoryConfig.Template {
factoryConfig := vf.Config{
Template: true,
VMConfig: vc.VMConfig{
HypervisorType: runtimeConfig.HypervisorType,
HypervisorConfig: runtimeConfig.HypervisorConfig,
AgentType: runtimeConfig.AgentType,
AgentConfig: runtimeConfig.AgentConfig,
},
}
kataLog.WithField("factory", factoryConfig).Info("load vm factory")
f, err := vf.NewFactory(factoryConfig, true)
if err != nil {
kataLog.WithError(err).Info("load vm factory failed")
} else {
vci.SetFactory(f)
}
}

disableOutput := noNeedForOutput(detach, ociSpec.Process.Terminal)

var process vc.Process
Expand Down Expand Up @@ -167,13 +187,8 @@ var systemdKernelParam = []vc.Param{
},
}

func getKernelParams(containerID string, needSystemd bool) []vc.Param {
p := []vc.Param{
{
Key: "ip",
Value: fmt.Sprintf("::::::%s::off::", containerID),
},
}
func getKernelParams(needSystemd bool) []vc.Param {
p := []vc.Param{}

if needSystemd {
p = append(p, systemdKernelParam...)
Expand All @@ -189,7 +204,7 @@ func needSystemd(config vc.HypervisorConfig) bool {
// setKernelParams adds the user-specified kernel parameters (from the
// configuration file) to the defaults so that the former take priority.
func setKernelParams(containerID string, runtimeConfig *oci.RuntimeConfig) error {
defaultKernelParams := getKernelParamsFunc(containerID, needSystemd(runtimeConfig.HypervisorConfig))
defaultKernelParams := getKernelParamsFunc(needSystemd(runtimeConfig.HypervisorConfig))

if runtimeConfig.HypervisorConfig.Debug {
strParams := vc.SerializeParams(defaultKernelParams, "=")
Expand Down
6 changes: 4 additions & 2 deletions cli/create_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -838,7 +838,7 @@ func TestCreateInvalidKernelParams(t *testing.T) {
getKernelParamsFunc = savedFunc
}()

getKernelParamsFunc = func(containerID string, needSystemd bool) []vc.Param {
getKernelParamsFunc = func(needSystemd bool) []vc.Param {
return []vc.Param{
{
Key: "",
Expand Down Expand Up @@ -1135,7 +1135,9 @@ func TestSetKernelParams(t *testing.T) {
err := setKernelParams(testContainerID, &config)
assert.NoError(err)

assert.NotEmpty(config.HypervisorConfig.KernelParams)
if needSystemd(config.HypervisorConfig) {
assert.NotEmpty(config.HypervisorConfig.KernelParams)
}
}

func TestSetKernelParamsUserOptionTakesPriority(t *testing.T) {
Expand Down
98 changes: 98 additions & 0 deletions cli/factory.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
// Copyright (c) 2018 HyperHQ Inc.
//
// SPDX-License-Identifier: Apache-2.0
//

package main

import (
"errors"
"fmt"

vc "github.com/kata-containers/runtime/virtcontainers"
vf "github.com/kata-containers/runtime/virtcontainers/factory"
"github.com/kata-containers/runtime/virtcontainers/pkg/oci"
"github.com/urfave/cli"
)

var factorySubCmds = []cli.Command{
initFactoryCommand,
destroyFactoryCommand,
}

var factoryCLICommand = cli.Command{
Name: "factory",
Usage: "manage vm factory",
Subcommands: factorySubCmds,
Action: func(context *cli.Context) {
cli.ShowSubcommandHelp(context)
},
}

var initFactoryCommand = cli.Command{
Name: "init",
Usage: "initialize a VM factory based on kata-runtime configuration",
Action: func(context *cli.Context) error {
runtimeConfig, ok := context.App.Metadata["runtimeConfig"].(oci.RuntimeConfig)
if !ok {
return errors.New("invalid runtime config")
}

if runtimeConfig.FactoryConfig.Template {
factoryConfig := vf.Config{
Template: true,
VMConfig: vc.VMConfig{
HypervisorType: runtimeConfig.HypervisorType,
HypervisorConfig: runtimeConfig.HypervisorConfig,
AgentType: runtimeConfig.AgentType,
AgentConfig: runtimeConfig.AgentConfig,
},
}
kataLog.WithField("factory", factoryConfig).Info("create vm factory")
_, err := vf.NewFactory(factoryConfig, false)
if err != nil {
kataLog.WithError(err).Error("create vm factory failed")
return err
}
fmt.Println("vm factory initialized")
} else {
kataLog.Error("vm factory is not enabled")
fmt.Println("vm factory is not enabled")
}

return nil
},
}

var destroyFactoryCommand = cli.Command{
Name: "destroy",
Usage: "destroy the VM factory",
Action: func(context *cli.Context) error {
runtimeConfig, ok := context.App.Metadata["runtimeConfig"].(oci.RuntimeConfig)
if !ok {
return errors.New("invalid runtime config")
}

if runtimeConfig.FactoryConfig.Template {
factoryConfig := vf.Config{
Template: true,
VMConfig: vc.VMConfig{
HypervisorType: runtimeConfig.HypervisorType,
HypervisorConfig: runtimeConfig.HypervisorConfig,
AgentType: runtimeConfig.AgentType,
AgentConfig: runtimeConfig.AgentConfig,
},
}
kataLog.WithField("factory", factoryConfig).Info("load vm factory")
f, err := vf.NewFactory(factoryConfig, true)
if err != nil {
kataLog.WithError(err).Error("load vm factory failed")
// ignore error
} else {
f.CloseFactory()
}
}
fmt.Println("vm factory destroyed")
return nil
},
}
117 changes: 117 additions & 0 deletions cli/factory_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
// Copyright (c) 2018 HyperHQ Inc.
//
// SPDX-License-Identifier: Apache-2.0
//

package main

import (
"flag"
"io/ioutil"
"os"
"testing"

"github.com/stretchr/testify/assert"
"github.com/urfave/cli"

vc "github.com/kata-containers/runtime/virtcontainers"
)

func TestFactoryCLIFunctionNoRuntimeConfig(t *testing.T) {
assert := assert.New(t)

app := cli.NewApp()
ctx := cli.NewContext(app, nil, nil)
app.Name = "foo"
ctx.App.Metadata = map[string]interface{}{
"foo": "bar",
}

fn, ok := initFactoryCommand.Action.(func(context *cli.Context) error)
assert.True(ok)
err := fn(ctx)
// no runtime config in the Metadata
assert.Error(err)

fn, ok = destroyFactoryCommand.Action.(func(context *cli.Context) error)
assert.True(ok)
err = fn(ctx)
// no runtime config in the Metadata
assert.Error(err)
}

func TestFactoryCLIFunctionInit(t *testing.T) {
assert := assert.New(t)

tmpdir, err := ioutil.TempDir("", "")
assert.NoError(err)
defer os.RemoveAll(tmpdir)

runtimeConfig, err := newTestRuntimeConfig(tmpdir, testConsole, true)
assert.NoError(err)

set := flag.NewFlagSet("", 0)

set.String("console-socket", "", "")

app := cli.NewApp()
ctx := cli.NewContext(app, set, nil)
app.Name = "foo"

// No template
ctx.App.Metadata = map[string]interface{}{
"runtimeConfig": runtimeConfig,
}
fn, ok := initFactoryCommand.Action.(func(context *cli.Context) error)
assert.True(ok)
err = fn(ctx)
assert.Nil(err)

// With template
runtimeConfig.FactoryConfig.Template = true
runtimeConfig.HypervisorType = vc.MockHypervisor
runtimeConfig.AgentType = vc.NoopAgentType
ctx.App.Metadata["runtimeConfig"] = runtimeConfig
fn, ok = initFactoryCommand.Action.(func(context *cli.Context) error)
assert.True(ok)
err = fn(ctx)
assert.Nil(err)
}

func TestFactoryCLIFunctionDestroy(t *testing.T) {
assert := assert.New(t)

tmpdir, err := ioutil.TempDir("", "")
assert.NoError(err)
defer os.RemoveAll(tmpdir)

runtimeConfig, err := newTestRuntimeConfig(tmpdir, testConsole, true)
assert.NoError(err)

set := flag.NewFlagSet("", 0)

set.String("console-socket", "", "")

app := cli.NewApp()
ctx := cli.NewContext(app, set, nil)
app.Name = "foo"

// No template
ctx.App.Metadata = map[string]interface{}{
"runtimeConfig": runtimeConfig,
}
fn, ok := destroyFactoryCommand.Action.(func(context *cli.Context) error)
assert.True(ok)
err = fn(ctx)
assert.Nil(err)

// With template
runtimeConfig.FactoryConfig.Template = true
runtimeConfig.HypervisorType = vc.MockHypervisor
runtimeConfig.AgentType = vc.NoopAgentType
ctx.App.Metadata["runtimeConfig"] = runtimeConfig
fn, ok = destroyFactoryCommand.Action.(func(context *cli.Context) error)
assert.True(ok)
err = fn(ctx)
assert.Nil(err)
}
1 change: 1 addition & 0 deletions cli/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ var runtimeCommands = []cli.Command{
// Kata Containers specific extensions
kataCheckCLICommand,
kataEnvCLICommand,
factoryCLICommand,
}

// runtimeBeforeSubcommands is the function to run before command-line
Expand Down
Loading

0 comments on commit 14d25b8

Please sign in to comment.