cli: add vm factory management subcommand

Add enable_template option to the config file.
When it is set, enable the vm template factory.

cache factory cannot be used by kata cli directly because
it requires a running daemon to maintain the cache VMs.

`kata-runtime factory init` would initialize the vm factory and
`kata-runtime factory destroy` would destroy the vm factory.

When configured, a vm factory is loaded before creating new sandboxes.

Signed-off-by: Peng Tao <bergwolf@gmail.com>
This commit is contained in:
Peng Tao 2018-07-13 17:58:10 +08:00
parent a7d888febc
commit 0309e59cf8
8 changed files with 287 additions and 0 deletions

View File

@ -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 {
@ -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 {
@ -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
}

View File

@ -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@"

View File

@ -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)
}

View File

@ -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"
)
@ -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

98
cli/factory.go Normal file
View File

@ -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
cli/factory_test.go Normal file
View File

@ -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)
}

View File

@ -123,6 +123,7 @@ var runtimeCommands = []cli.Command{
// Kata Containers specific extensions
kataCheckCLICommand,
kataEnvCLICommand,
factoryCLICommand,
}
// runtimeBeforeSubcommands is the function to run before command-line

View File

@ -91,6 +91,12 @@ type CompatOCISpec struct {
Process *CompatOCIProcess `json:"process,omitempty"`
}
// FactoryConfig is a structure to set the VM factory configuration.
type FactoryConfig struct {
// Template enables VM templating support in VM factory.
Template bool
}
// RuntimeConfig aggregates all runtime specific settings
type RuntimeConfig struct {
VMConfig vc.Resources
@ -98,6 +104,8 @@ type RuntimeConfig struct {
HypervisorType vc.HypervisorType
HypervisorConfig vc.HypervisorConfig
FactoryConfig FactoryConfig
AgentType vc.AgentType
AgentConfig interface{}