factory: start proxy after create new VM

The PR moves ahead the start of proxy process for vm factory so that
it waits for both vm and proxy to be up at the same time. This saves
about 300ms for new container creation in my local test machine.

Fixes: #683

Signed-off-by: Peng Tao <bergwolf@gmail.com>
This commit is contained in:
Peng Tao 2018-08-28 12:02:06 +08:00
parent 4738d4e87a
commit 07c1f18e51
13 changed files with 226 additions and 65 deletions

View File

@ -21,7 +21,7 @@ type FactoryBase interface {
Config() vc.VMConfig Config() vc.VMConfig
// GetBaseVM returns a paused VM created by the base factory. // GetBaseVM returns a paused VM created by the base factory.
GetBaseVM(ctx context.Context) (*vc.VM, error) GetBaseVM(ctx context.Context, config vc.VMConfig) (*vc.VM, error)
// CloseFactory closes the base factory. // CloseFactory closes the base factory.
CloseFactory(ctx context.Context) CloseFactory(ctx context.Context)

View File

@ -37,7 +37,7 @@ func New(ctx context.Context, count uint, b base.FactoryBase) base.FactoryBase {
c.wg.Add(1) c.wg.Add(1)
go func() { go func() {
for { for {
vm, err := b.GetBaseVM(ctx) vm, err := b.GetBaseVM(ctx, c.Config())
if err != nil { if err != nil {
c.wg.Done() c.wg.Done()
c.CloseFactory(ctx) c.CloseFactory(ctx)
@ -63,7 +63,7 @@ func (c *cache) Config() vc.VMConfig {
} }
// GetBaseVM returns a base VM from cache factory's base factory. // GetBaseVM returns a base VM from cache factory's base factory.
func (c *cache) GetBaseVM(ctx context.Context) (*vc.VM, error) { func (c *cache) GetBaseVM(ctx context.Context, config vc.VMConfig) (*vc.VM, error) {
vm, ok := <-c.cacheCh vm, ok := <-c.cacheCh
if ok { if ok {
return vm, nil return vm, nil

View File

@ -27,6 +27,7 @@ func TestTemplateFactory(t *testing.T) {
vmConfig := vc.VMConfig{ vmConfig := vc.VMConfig{
HypervisorType: vc.MockHypervisor, HypervisorType: vc.MockHypervisor,
AgentType: vc.NoopAgentType, AgentType: vc.NoopAgentType,
ProxyType: vc.NoopProxyType,
HypervisorConfig: hyperConfig, HypervisorConfig: hyperConfig,
} }
@ -39,7 +40,7 @@ func TestTemplateFactory(t *testing.T) {
assert.Equal(f.Config(), vmConfig) assert.Equal(f.Config(), vmConfig)
// GetBaseVM // GetBaseVM
_, err := f.GetBaseVM(ctx) _, err := f.GetBaseVM(ctx, vmConfig)
assert.Nil(err) assert.Nil(err)
// CloseFactory // CloseFactory

View File

@ -28,8 +28,8 @@ func (d *direct) Config() vc.VMConfig {
} }
// GetBaseVM create a new VM directly. // GetBaseVM create a new VM directly.
func (d *direct) GetBaseVM(ctx context.Context) (*vc.VM, error) { func (d *direct) GetBaseVM(ctx context.Context, config vc.VMConfig) (*vc.VM, error) {
vm, err := vc.NewVM(ctx, d.config) vm, err := vc.NewVM(ctx, config)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -26,6 +26,7 @@ func TestTemplateFactory(t *testing.T) {
vmConfig := vc.VMConfig{ vmConfig := vc.VMConfig{
HypervisorType: vc.MockHypervisor, HypervisorType: vc.MockHypervisor,
AgentType: vc.NoopAgentType, AgentType: vc.NoopAgentType,
ProxyType: vc.NoopProxyType,
HypervisorConfig: hyperConfig, HypervisorConfig: hyperConfig,
} }
@ -38,7 +39,7 @@ func TestTemplateFactory(t *testing.T) {
assert.Equal(f.Config(), vmConfig) assert.Equal(f.Config(), vmConfig)
// GetBaseVM // GetBaseVM
_, err := f.GetBaseVM(ctx) _, err := f.GetBaseVM(ctx, vmConfig)
assert.Nil(err) assert.Nil(err)
// CloseFactory // CloseFactory

View File

@ -29,10 +29,6 @@ type Config struct {
VMConfig vc.VMConfig VMConfig vc.VMConfig
} }
func (f *Config) validate() error {
return f.VMConfig.Valid()
}
type factory struct { type factory struct {
base base.FactoryBase base base.FactoryBase
} }
@ -50,7 +46,7 @@ func NewFactory(ctx context.Context, config Config, fetchOnly bool) (vc.Factory,
span, _ := trace(ctx, "NewFactory") span, _ := trace(ctx, "NewFactory")
defer span.Finish() defer span.Finish()
err := config.validate() err := config.VMConfig.Valid()
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -93,13 +89,15 @@ func (f *factory) log() *logrus.Entry {
return factoryLogger.WithField("subsystem", "factory") return factoryLogger.WithField("subsystem", "factory")
} }
func resetHypervisorConfig(config *vc.HypervisorConfig) { func resetHypervisorConfig(config *vc.VMConfig) {
config.NumVCPUs = 0 config.HypervisorConfig.NumVCPUs = 0
config.MemorySize = 0 config.HypervisorConfig.MemorySize = 0
config.BootToBeTemplate = false config.HypervisorConfig.BootToBeTemplate = false
config.BootFromTemplate = false config.HypervisorConfig.BootFromTemplate = false
config.MemoryPath = "" config.HypervisorConfig.MemoryPath = ""
config.DevicesStatePath = "" config.HypervisorConfig.DevicesStatePath = ""
config.ProxyType = vc.NoopProxyType
config.ProxyConfig = vc.ProxyConfig{}
} }
// It's important that baseConfig and newConfig are passed by value! // It's important that baseConfig and newConfig are passed by value!
@ -113,8 +111,8 @@ func checkVMConfig(config1, config2 vc.VMConfig) error {
} }
// check hypervisor config details // check hypervisor config details
resetHypervisorConfig(&config1.HypervisorConfig) resetHypervisorConfig(&config1)
resetHypervisorConfig(&config2.HypervisorConfig) resetHypervisorConfig(&config2)
if !reflect.DeepEqual(config1, config2) { if !reflect.DeepEqual(config1, config2) {
return fmt.Errorf("hypervisor config does not match, base: %+v. new: %+v", config1, config2) return fmt.Errorf("hypervisor config does not match, base: %+v. new: %+v", config1, config2)
@ -129,13 +127,25 @@ func (f *factory) checkConfig(config vc.VMConfig) error {
return checkVMConfig(config, baseConfig) return checkVMConfig(config, baseConfig)
} }
func (f *factory) validateNewVMConfig(config vc.VMConfig) error {
if len(config.AgentType.String()) == 0 {
return fmt.Errorf("Missing agent type")
}
if len(config.ProxyType.String()) == 0 {
return fmt.Errorf("Missing proxy type")
}
return config.Valid()
}
// GetVM returns a working blank VM created by the factory. // GetVM returns a working blank VM created by the factory.
func (f *factory) GetVM(ctx context.Context, config vc.VMConfig) (*vc.VM, error) { func (f *factory) GetVM(ctx context.Context, config vc.VMConfig) (*vc.VM, error) {
span, _ := trace(ctx, "GetVM") span, _ := trace(ctx, "GetVM")
defer span.Finish() defer span.Finish()
hypervisorConfig := config.HypervisorConfig hypervisorConfig := config.HypervisorConfig
err := config.Valid() err := f.validateNewVMConfig(config)
if err != nil { if err != nil {
f.log().WithError(err).Error("invalid hypervisor config") f.log().WithError(err).Error("invalid hypervisor config")
return nil, err return nil, err
@ -144,11 +154,11 @@ func (f *factory) GetVM(ctx context.Context, config vc.VMConfig) (*vc.VM, error)
err = f.checkConfig(config) err = f.checkConfig(config)
if err != nil { if err != nil {
f.log().WithError(err).Info("fallback to direct factory vm") f.log().WithError(err).Info("fallback to direct factory vm")
return direct.New(ctx, config).GetBaseVM(ctx) return direct.New(ctx, config).GetBaseVM(ctx, config)
} }
f.log().Info("get base VM") f.log().Info("get base VM")
vm, err := f.base.GetBaseVM(ctx) vm, err := f.base.GetBaseVM(ctx, config)
if err != nil { if err != nil {
f.log().WithError(err).Error("failed to get base VM") f.log().WithError(err).Error("failed to get base VM")
return nil, err return nil, err

View File

@ -94,23 +94,21 @@ func TestFactorySetLogger(t *testing.T) {
func TestVMConfigValid(t *testing.T) { func TestVMConfigValid(t *testing.T) {
assert := assert.New(t) assert := assert.New(t)
config := Config{}
err := config.validate()
assert.Error(err)
testDir, _ := ioutil.TempDir("", "vmfactory-tmp-") testDir, _ := ioutil.TempDir("", "vmfactory-tmp-")
config.VMConfig = vc.VMConfig{ config := vc.VMConfig{
HypervisorType: vc.MockHypervisor, HypervisorType: vc.MockHypervisor,
AgentType: vc.NoopAgentType, AgentType: vc.NoopAgentType,
ProxyType: vc.NoopProxyType,
HypervisorConfig: vc.HypervisorConfig{ HypervisorConfig: vc.HypervisorConfig{
KernelPath: testDir, KernelPath: testDir,
ImagePath: testDir, ImagePath: testDir,
}, },
} }
err = config.validate() f := factory{}
err := f.validateNewVMConfig(config)
assert.Nil(err) assert.Nil(err)
} }
@ -165,8 +163,9 @@ func TestFactoryGetVM(t *testing.T) {
} }
vmConfig := vc.VMConfig{ vmConfig := vc.VMConfig{
HypervisorType: vc.MockHypervisor, HypervisorType: vc.MockHypervisor,
AgentType: vc.NoopAgentType,
HypervisorConfig: hyperConfig, HypervisorConfig: hyperConfig,
AgentType: vc.NoopAgentType,
ProxyType: vc.NoopProxyType,
} }
ctx := context.Background() ctx := context.Background()

View File

@ -23,6 +23,10 @@ type template struct {
config vc.VMConfig config vc.VMConfig
} }
var templateProxyType = vc.KataBuiltInProxyType
var templateWaitForAgent = 2 * time.Second
var templateWaitForMigration = 1 * time.Second
// Fetch finds and returns a pre-built template factory. // Fetch finds and returns a pre-built template factory.
// TODO: save template metadata and fetch from storage. // TODO: save template metadata and fetch from storage.
func Fetch(config vc.VMConfig) (base.FactoryBase, error) { func Fetch(config vc.VMConfig) (base.FactoryBase, error) {
@ -63,8 +67,8 @@ func (t *template) Config() vc.VMConfig {
} }
// GetBaseVM creates a new paused VM from the template VM. // GetBaseVM creates a new paused VM from the template VM.
func (t *template) GetBaseVM(ctx context.Context) (*vc.VM, error) { func (t *template) GetBaseVM(ctx context.Context, config vc.VMConfig) (*vc.VM, error) {
return t.createFromTemplateVM(ctx) return t.createFromTemplateVM(ctx, config)
} }
// CloseFactory cleans up the template VM. // CloseFactory cleans up the template VM.
@ -100,6 +104,8 @@ func (t *template) createTemplateVM(ctx context.Context) error {
config.HypervisorConfig.BootFromTemplate = false config.HypervisorConfig.BootFromTemplate = false
config.HypervisorConfig.MemoryPath = t.statePath + "/memory" config.HypervisorConfig.MemoryPath = t.statePath + "/memory"
config.HypervisorConfig.DevicesStatePath = t.statePath + "/state" config.HypervisorConfig.DevicesStatePath = t.statePath + "/state"
// template vm uses builtin proxy
config.ProxyType = templateProxyType
vm, err := vc.NewVM(ctx, config) vm, err := vc.NewVM(ctx, config)
if err != nil { if err != nil {
@ -107,28 +113,41 @@ func (t *template) createTemplateVM(ctx context.Context) error {
} }
defer vm.Stop() defer vm.Stop()
err = vm.Pause() if err = vm.Disconnect(); err != nil {
if err != nil {
return err return err
} }
err = vm.Save() // Sleep a bit to let the agent grpc server clean up
if err != nil { // When we close connection to the agent, it needs sometime to cleanup
// and restart listening on the communication( serial or vsock) port.
// That time can be saved if we sleep a bit to wait for the agent to
// come around and start listening again. The sleep is only done when
// creating new vm templates and saves time for every new vm that are
// created from template, so it worth the invest.
time.Sleep(templateWaitForAgent)
if err = vm.Pause(); err != nil {
return err
}
if err = vm.Save(); err != nil {
return err return err
} }
// qemu QMP does not wait for migration to finish... // qemu QMP does not wait for migration to finish...
time.Sleep(1 * time.Second) time.Sleep(templateWaitForMigration)
return nil return nil
} }
func (t *template) createFromTemplateVM(ctx context.Context) (*vc.VM, error) { func (t *template) createFromTemplateVM(ctx context.Context, c vc.VMConfig) (*vc.VM, error) {
config := t.config config := t.config
config.HypervisorConfig.BootToBeTemplate = false config.HypervisorConfig.BootToBeTemplate = false
config.HypervisorConfig.BootFromTemplate = true config.HypervisorConfig.BootFromTemplate = true
config.HypervisorConfig.MemoryPath = t.statePath + "/memory" config.HypervisorConfig.MemoryPath = t.statePath + "/memory"
config.HypervisorConfig.DevicesStatePath = t.statePath + "/state" config.HypervisorConfig.DevicesStatePath = t.statePath + "/state"
config.ProxyType = c.ProxyType
config.ProxyConfig = c.ProxyConfig
return vc.NewVM(ctx, config) return vc.NewVM(ctx, config)
} }

View File

@ -10,6 +10,7 @@ import (
"io/ioutil" "io/ioutil"
"os" "os"
"testing" "testing"
"time"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
@ -19,6 +20,9 @@ import (
func TestTemplateFactory(t *testing.T) { func TestTemplateFactory(t *testing.T) {
assert := assert.New(t) assert := assert.New(t)
templateWaitForMigration = 1 * time.Microsecond
templateWaitForAgent = 1 * time.Microsecond
testDir, _ := ioutil.TempDir("", "vmfactory-tmp-") testDir, _ := ioutil.TempDir("", "vmfactory-tmp-")
hyperConfig := vc.HypervisorConfig{ hyperConfig := vc.HypervisorConfig{
KernelPath: testDir, KernelPath: testDir,
@ -26,8 +30,9 @@ func TestTemplateFactory(t *testing.T) {
} }
vmConfig := vc.VMConfig{ vmConfig := vc.VMConfig{
HypervisorType: vc.MockHypervisor, HypervisorType: vc.MockHypervisor,
AgentType: vc.NoopAgentType,
HypervisorConfig: hyperConfig, HypervisorConfig: hyperConfig,
AgentType: vc.NoopAgentType,
ProxyType: vc.NoopProxyType,
} }
ctx := context.Background() ctx := context.Background()
@ -39,7 +44,7 @@ func TestTemplateFactory(t *testing.T) {
assert.Equal(f.Config(), vmConfig) assert.Equal(f.Config(), vmConfig)
// GetBaseVM // GetBaseVM
_, err := f.GetBaseVM(ctx) _, err := f.GetBaseVM(ctx, vmConfig)
assert.Nil(err) assert.Nil(err)
// Fetch // Fetch
@ -62,9 +67,16 @@ func TestTemplateFactory(t *testing.T) {
assert.Nil(err) assert.Nil(err)
err = tt.createTemplateVM(ctx) err = tt.createTemplateVM(ctx)
assert.Error(err)
_, err = f.GetBaseVM(ctx, vmConfig)
assert.Nil(err) assert.Nil(err)
_, err = tt.GetBaseVM(ctx) templateProxyType = vc.NoopProxyType
err = tt.createTemplateVM(ctx)
assert.Nil(err)
_, err = f.GetBaseVM(ctx, vmConfig)
assert.Nil(err) assert.Nil(err)
// CloseFactory // CloseFactory

View File

@ -0,0 +1,26 @@
// Copyright (c) 2018 HyperHQ Inc.
//
// SPDX-License-Identifier: Apache-2.0
//
package virtcontainers
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestNoopProxy(t *testing.T) {
n := &noopProxy{}
assert := assert.New(t)
_, url, err := n.start(proxyParams{})
assert.Nil(err)
assert.Equal(url, noopProxyURL)
err = n.stop(0)
assert.Nil(err)
assert.False(n.consoleWatched())
}

View File

@ -1104,6 +1104,8 @@ func (s *Sandbox) startVM() error {
HypervisorConfig: s.config.HypervisorConfig, HypervisorConfig: s.config.HypervisorConfig,
AgentType: s.config.AgentType, AgentType: s.config.AgentType,
AgentConfig: s.config.AgentConfig, AgentConfig: s.config.AgentConfig,
ProxyType: s.config.ProxyType,
ProxyConfig: s.config.ProxyConfig,
}) })
if err != nil { if err != nil {
return err return err
@ -1593,9 +1595,9 @@ func (s *Sandbox) HotplugAddDevice(device api.Device, devType config.DeviceType)
if _, err := s.hypervisor.hotplugAddDevice(dev, vfioDev); err != nil { if _, err := s.hypervisor.hotplugAddDevice(dev, vfioDev); err != nil {
s.Logger(). s.Logger().
WithFields(logrus.Fields{ WithFields(logrus.Fields{
"sandboxid": s.id, "sandbox": s.id,
"vfio device ID": dev.ID, "vfio-device-ID": dev.ID,
"vfio device BDF": dev.BDF, "vfio-device-BDF": dev.BDF,
}).WithError(err).Error("failed to hotplug VFIO device") }).WithError(err).Error("failed to hotplug VFIO device")
return err return err
} }
@ -1630,9 +1632,9 @@ func (s *Sandbox) HotplugRemoveDevice(device api.Device, devType config.DeviceTy
if _, err := s.hypervisor.hotplugRemoveDevice(dev, vfioDev); err != nil { if _, err := s.hypervisor.hotplugRemoveDevice(dev, vfioDev); err != nil {
s.Logger().WithError(err). s.Logger().WithError(err).
WithFields(logrus.Fields{ WithFields(logrus.Fields{
"sandboxid": s.id, "sandbox": s.id,
"vfio device ID": dev.ID, "vfio-device-ID": dev.ID,
"vfio device BDF": dev.BDF, "vfio-device-BDF": dev.BDF,
}).Error("failed to hot unplug VFIO device") }).Error("failed to hot unplug VFIO device")
return err return err
} }

View File

@ -21,6 +21,10 @@ type VM struct {
hypervisor hypervisor hypervisor hypervisor
agent agent agent agent
proxy proxy
proxyPid int
proxyURL string
cpu uint32 cpu uint32
memory uint32 memory uint32
@ -34,6 +38,9 @@ type VMConfig struct {
AgentType AgentType AgentType AgentType
AgentConfig interface{} AgentConfig interface{}
ProxyType ProxyType
ProxyConfig ProxyConfig
} }
// Valid check VMConfig validity. // Valid check VMConfig validity.
@ -41,8 +48,56 @@ func (c *VMConfig) Valid() error {
return c.HypervisorConfig.valid() return c.HypervisorConfig.valid()
} }
func setupProxy(h hypervisor, agent agent, config VMConfig, id string) (int, string, proxy, error) {
consoleURL, err := h.getSandboxConsole(id)
if err != nil {
return -1, "", nil, err
}
agentURL, err := agent.getAgentURL()
if err != nil {
return -1, "", nil, err
}
// default to kata builtin proxy
proxyType := config.ProxyType
if len(proxyType.String()) == 0 {
proxyType = KataBuiltInProxyType
}
proxy, err := newProxy(proxyType)
if err != nil {
return -1, "", nil, err
}
proxyParams := proxyParams{
id: id,
path: config.ProxyConfig.Path,
agentURL: agentURL,
consoleURL: consoleURL,
logger: virtLog.WithField("vm", id),
debug: config.ProxyConfig.Debug,
}
pid, url, err := proxy.start(proxyParams)
if err != nil {
virtLog.WithFields(logrus.Fields{
"vm": id,
"proxy type": config.ProxyType,
"params": proxyParams,
}).WithError(err).Error("failed to start proxy")
return -1, "", nil, err
}
return pid, url, proxy, nil
}
// NewVM creates a new VM based on provided VMConfig. // NewVM creates a new VM based on provided VMConfig.
func NewVM(ctx context.Context, config VMConfig) (*VM, error) { func NewVM(ctx context.Context, config VMConfig) (*VM, error) {
var (
proxy proxy
pid int
url string
)
// 1. setup hypervisor
hypervisor, err := newHypervisor(config.HypervisorType) hypervisor, err := newHypervisor(config.HypervisorType)
if err != nil { if err != nil {
return nil, err return nil, err
@ -54,11 +109,11 @@ func NewVM(ctx context.Context, config VMConfig) (*VM, error) {
id := uuid.Generate().String() id := uuid.Generate().String()
virtLog.WithField("vm id", id).WithField("config", config).Info("create new vm") virtLog.WithField("vm", id).WithField("config", config).Info("create new vm")
defer func() { defer func() {
if err != nil { if err != nil {
virtLog.WithField("vm id", id).WithError(err).Error("failed to create new vm") virtLog.WithField("vm", id).WithError(err).Error("failed to create new vm")
} }
}() }()
@ -70,37 +125,48 @@ func NewVM(ctx context.Context, config VMConfig) (*VM, error) {
return nil, err return nil, err
} }
// 2. setup agent
agent := newAgent(config.AgentType) agent := newAgent(config.AgentType)
agentConfig := newAgentConfig(config.AgentType, config.AgentConfig)
// do not keep connection for temp agent
if c, ok := agentConfig.(KataAgentConfig); ok {
c.LongLiveConn = false
}
vmSharePath := buildVMSharePath(id) vmSharePath := buildVMSharePath(id)
err = agent.configure(hypervisor, id, vmSharePath, true, agentConfig) err = agent.configure(hypervisor, id, vmSharePath, isProxyBuiltIn(config.ProxyType), config.AgentConfig)
if err != nil { if err != nil {
return nil, err return nil, err
} }
// 3. boot up guest vm
if err = hypervisor.startSandbox(); err != nil { if err = hypervisor.startSandbox(); err != nil {
return nil, err return nil, err
} }
if err = hypervisor.waitSandbox(vmStartTimeout); err != nil {
return nil, err
}
defer func() { defer func() {
if err != nil { if err != nil {
virtLog.WithField("vm id", id).WithError(err).Info("clean up vm") virtLog.WithField("vm", id).WithError(err).Info("clean up vm")
hypervisor.stopSandbox() hypervisor.stopSandbox()
} }
}() }()
// 4. setup proxy
pid, url, proxy, err = setupProxy(hypervisor, agent, config, id)
if err != nil {
return nil, err
}
defer func() {
if err != nil {
virtLog.WithField("vm", id).WithError(err).Info("clean up proxy")
proxy.stop(pid)
}
}()
if err = agent.setProxy(nil, proxy, pid, url); err != nil {
return nil, err
}
// 5. check agent aliveness
// VMs booted from template are paused, do not check // VMs booted from template are paused, do not check
if !config.HypervisorConfig.BootFromTemplate { if !config.HypervisorConfig.BootFromTemplate {
err = hypervisor.waitSandbox(vmStartTimeout) virtLog.WithField("vm", id).Info("check agent status")
if err != nil {
return nil, err
}
virtLog.WithField("vm id", id).Info("check agent status")
err = agent.check() err = agent.check()
if err != nil { if err != nil {
return nil, err return nil, err
@ -111,6 +177,9 @@ func NewVM(ctx context.Context, config VMConfig) (*VM, error) {
id: id, id: id,
hypervisor: hypervisor, hypervisor: hypervisor,
agent: agent, agent: agent,
proxy: proxy,
proxyPid: pid,
proxyURL: url,
cpu: config.HypervisorConfig.NumVCPUs, cpu: config.HypervisorConfig.NumVCPUs,
memory: config.HypervisorConfig.MemorySize, memory: config.HypervisorConfig.MemorySize,
}, nil }, nil
@ -121,7 +190,7 @@ func buildVMSharePath(id string) string {
} }
func (v *VM) logger() logrus.FieldLogger { func (v *VM) logger() logrus.FieldLogger {
return virtLog.WithField("vm id", v.id) return virtLog.WithField("vm", v.id)
} }
// Pause pauses a VM. // Pause pauses a VM.
@ -148,9 +217,24 @@ func (v *VM) Start() error {
return v.hypervisor.startSandbox() return v.hypervisor.startSandbox()
} }
// Disconnect agent and proxy connections to a VM
func (v *VM) Disconnect() error {
v.logger().Info("kill vm")
if err := v.agent.disconnect(); err != nil {
v.logger().WithError(err).Error("failed to disconnect agent")
}
if err := v.proxy.stop(v.proxyPid); err != nil {
v.logger().WithError(err).Error("failed to stop proxy")
}
return nil
}
// Stop stops a VM process. // Stop stops a VM process.
func (v *VM) Stop() error { func (v *VM) Stop() error {
v.logger().Info("kill vm") v.logger().Info("kill vm")
return v.hypervisor.stopSandbox() return v.hypervisor.stopSandbox()
} }
@ -227,8 +311,14 @@ func (v *VM) assignSandbox(s *Sandbox) error {
"vmSockDir": vmSockDir, "vmSockDir": vmSockDir,
"sbSharePath": sbSharePath, "sbSharePath": sbSharePath,
"sbSockDir": sbSockDir, "sbSockDir": sbSockDir,
"proxy-pid": v.proxyPid,
"proxy-url": v.proxyURL,
}).Infof("assign vm to sandbox %s", s.id) }).Infof("assign vm to sandbox %s", s.id)
if err := s.agent.setProxy(s, v.proxy, v.proxyPid, v.proxyURL); err != nil {
return err
}
// First make sure the symlinks do not exist // First make sure the symlinks do not exist
os.RemoveAll(sbSharePath) os.RemoveAll(sbSharePath)
os.RemoveAll(sbSockDir) os.RemoveAll(sbSockDir)

View File

@ -20,6 +20,7 @@ func TestNewVM(t *testing.T) {
config := VMConfig{ config := VMConfig{
HypervisorType: MockHypervisor, HypervisorType: MockHypervisor,
AgentType: NoopAgentType, AgentType: NoopAgentType,
ProxyType: NoopProxyType,
} }
hyperConfig := HypervisorConfig{ hyperConfig := HypervisorConfig{
KernelPath: testDir, KernelPath: testDir,