Merge pull request #1442 from jodh-intel/add-agent-trace-support

Add agent trace support
This commit is contained in:
Graham Whaley 2019-04-25 14:12:54 +01:00 committed by GitHub
commit f4fe31e74d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
29 changed files with 1204 additions and 2118 deletions

62
Gopkg.lock generated
View File

@ -2,7 +2,7 @@
[[projects]]
digest = "1:79896046d0807ae89b74ae106b6cb0b346c201c02fc57b7c56017edad7493a61"
digest = "1:5d72bbcc9c8667b11c3dc3cbe681c5a6f71e5096744c0bf7726ab5c6425d5dc4"
name = "github.com/BurntSushi/toml"
packages = ["."]
pruneopts = "NUT"
@ -10,7 +10,7 @@
version = "v0.3.1"
[[projects]]
digest = "1:26b14a6dc72ace253599e969997d5ecf2143c63833c015179786bc756c76eaa4"
digest = "1:2be791e7b333ff7c06f8fb3dc18a7d70580e9399dbdffd352621d067ff260b6e"
name = "github.com/Microsoft/go-winio"
packages = ["."]
pruneopts = "NUT"
@ -18,7 +18,7 @@
version = "v0.4.12"
[[projects]]
digest = "1:e4eec8e05fe8611837a9b34a787cf9c714a2fd9228a0a1f41dd2ccccbaa21b7e"
digest = "1:a8e16b4caf3575365c9aa3380d9418f31dd0b810596faebfe3a15c37fabeee4a"
name = "github.com/Microsoft/hcsshim"
packages = [
".",
@ -65,16 +65,6 @@
revision = "ccb8e960c48f04d6935e72476ae4a51028f9e22f"
version = "v9"
[[projects]]
digest = "1:f1bb062def4356e0ffacbf80952a122489df3d26887249a6d351f5b3c98d4c16"
name = "github.com/clearcontainers/proxy"
packages = [
"api",
"client",
]
pruneopts = "NUT"
revision = "1d2a6a3ea132a86abd0731408b7dc34f2fc17d55"
[[projects]]
branch = "master"
digest = "1:8ecb89af7dfe3ac401bdb0c9390b134ef96a97e85f732d2b0604fb7b3977839f"
@ -99,7 +89,7 @@
revision = "0650fd9eeb50bab4fc99dceb9f2e14cf58f36e7f"
[[projects]]
digest = "1:c572858cf95490994cee8faa84a57a8942f735e1a8b6a5a7876d13192754c05e"
digest = "1:b1ddab63ebf3a38cdc2a80fa1f00c45e8dc98e27387968ccc0e5275a43f6cb5e"
name = "github.com/containerd/containerd"
packages = [
"api/events",
@ -120,7 +110,7 @@
revision = "f05672357f56f26751a521175c5a96fc21fa8603"
[[projects]]
digest = "1:4f06807f78ebb5fd6d5fcd539885c0a0be60732eda47189a7feb486ff60a519d"
digest = "1:e7c346f795db5a431ca8bd284faed7aa5b4d544ba6538b20a39b968473f47774"
name = "github.com/containerd/cri-containerd"
packages = [
"pkg/annotations",
@ -216,7 +206,7 @@
version = "v0.3.3"
[[projects]]
digest = "1:2cbc5d9ad66b4eb1e82862757985de8c24d8ca299500e669998694329d05bfc9"
digest = "1:351337e3b022de09e72306f1f9711314cc4bd407c15e8d328e218c655fd55731"
name = "github.com/firecracker-microvm/firecracker-go-sdk"
packages = [
"client",
@ -228,7 +218,7 @@
[[projects]]
branch = "master"
digest = "1:e30aea4f7e276dc80a7041b9e436b45a4c6636e5ba554de835b07beb0f97cc74"
digest = "1:ce0cdcf4a121add67d3c6f7cc08e6233275d0f417852f025b790d35da88fab10"
name = "github.com/globalsign/mgo"
packages = [
"bson",
@ -245,7 +235,7 @@
revision = "20b96f641a5ea98f2f8619ff4f3e061cff4833bd"
[[projects]]
digest = "1:5b7a60e28d9315ba79fb73e6294e5823997673ee64797d28ba2dc7bf71dc6ba6"
digest = "1:e101aa2e25fac7e82ba4d2f66807eedd4bcf11abc5afcb4a4629a88f9a652b84"
name = "github.com/go-openapi/analysis"
packages = [
".",
@ -288,7 +278,7 @@
version = "v0.18.0"
[[projects]]
digest = "1:36b4e8fb9b6f5896fe776b279a6e3a4115ab7d0258d0e0d2ac9c6c58e12531c7"
digest = "1:757a8958779fedcfddafb3ac93f707876db7b4fbc71b76fbc25450b3f057025e"
name = "github.com/go-openapi/runtime"
packages = [
".",
@ -345,7 +335,7 @@
version = "v5.0.1"
[[projects]]
digest = "1:34e8cbba4f0ad2eeda81c98d3f53af4c5862518ec0ebae38730fc36f8a7705f0"
digest = "1:0dfc35f448d29c2ff6a29fb3a6643f44175dc2a07925b1add2dea74e1dd6bf8d"
name = "github.com/gogo/protobuf"
packages = [
"gogoproto",
@ -358,7 +348,7 @@
revision = "342cbe0a04158f6dcb03ca0079991a51a4248c02"
[[projects]]
digest = "1:a8b59d8995b50db3b206d9160817e00aace183e456cb60abf5157de16d12e3c9"
digest = "1:2d0636a8c490d2272dd725db26f74a537111b99b9dbdda0d8b98febe63702aa4"
name = "github.com/golang/protobuf"
packages = [
"proto",
@ -405,16 +395,9 @@
pruneopts = "NUT"
revision = "48dd1c031530fce9bf16b0f6a7305979cedd8fc9"
[[projects]]
digest = "1:04054595e5c5a35d1553a7f3464d18577caf597445d643992998643df56d4afd"
name = "github.com/kubernetes-incubator/cri-o"
packages = ["pkg/annotations"]
pruneopts = "NUT"
revision = "3394b3b2d6af0e41d185bb695c6378be5dd4d61d"
[[projects]]
branch = "master"
digest = "1:ebd709f6c64e850ee37ffd662604b647934ba1b7da39c7ba26381d634a4b6d4d"
digest = "1:84a5a2b67486d5d67060ac393aa255d05d24ed5ee41daecd5635ec22657b6492"
name = "github.com/mailru/easyjson"
packages = [
"buffer",
@ -447,7 +430,7 @@
version = "v1.0.0-rc1"
[[projects]]
digest = "1:d4dcb47c4324ed0af861eda17778f56229d44422819770972183bee0217f9cff"
digest = "1:26537bc93f1e164bbc305117029de9933656ff81c4549609939212aca20a4710"
name = "github.com/opencontainers/runc"
packages = [
"libcontainer/configs",
@ -467,7 +450,7 @@
revision = "5806c35637336642129d03657419829569abc5aa"
[[projects]]
digest = "1:7fea98b6541d058ba0ae5496d57d420d396a3f121a0aec64b4ec2171b0a93846"
digest = "1:7da29c22bcc5c2ffb308324377dc00b5084650348c2799e573ed226d8cc9faf0"
name = "github.com/opentracing/opentracing-go"
packages = [
".",
@ -518,7 +501,7 @@
version = "v0.9.0"
[[projects]]
digest = "1:e2930b698575a7f45df1eaa5473c76109b04a87d6a464e674a68f9c1dff244a1"
digest = "1:432ba4d123dc14d6e3b71ca22051bd1a5aa20a8e466e47edabd9af46405c5cfb"
name = "github.com/sirupsen/logrus"
packages = [
".",
@ -535,7 +518,7 @@
revision = "890a5c3458b43e6104ff5da8dfa139d013d77544"
[[projects]]
digest = "1:d43a3612c85e592ffcefdbc426d3fc0bdbc71435c930664bef8c36034181d681"
digest = "1:87dee780f88f86f300bbd90116e933347cf4a3c65c1960072d412597a8896d50"
name = "github.com/uber/jaeger-client-go"
packages = [
".",
@ -576,7 +559,7 @@
revision = "ac249472b7de27a9e8990819566d9be95ab5b816"
[[projects]]
digest = "1:e53b4392978149151080be2de940b1cfbb542c3b2bc3281e091678a3626397f8"
digest = "1:51b28ecbdddc7e0260899b64d8cf13343bb8f66b4b00585b46c775509755095a"
name = "github.com/vishvananda/netlink"
packages = [
".",
@ -601,7 +584,7 @@
revision = "8dd112bcdc25174059e45e07517d9fc663123347"
[[projects]]
digest = "1:5985d67e107c875e2584b5a65f1590adee7677a4e44eb7e62cd54c7709abba4a"
digest = "1:b20c63a56900e442d5f435613fefc9392cbe8849467510fcc3869dbdad9441bb"
name = "golang.org/x/net"
packages = [
"context",
@ -616,7 +599,7 @@
revision = "a8b9294777976932365dabb6640cf1468d95c70f"
[[projects]]
digest = "1:bfb083c1c1ae3c793c66773f32fa2f5934241d8c6327636f4761f269d018a171"
digest = "1:2fd19a8bed3f4ba8e3b26620f114efec5f39c7b02635a89a915b1cbaefeab5ff"
name = "golang.org/x/sys"
packages = [
"unix",
@ -626,7 +609,7 @@
revision = "1d2aa6dbdea45adaaebb9905d0666e4537563829"
[[projects]]
digest = "1:4e48d0d8df75f1bd0a0afe837599fc9ad96b59eecdd1900fc0dcceccaa5fdffc"
digest = "1:e33513a825fcd765e97b5de639a2f7547542d1a8245df0cef18e1fd390b778a9"
name = "golang.org/x/text"
packages = [
"collate",
@ -658,7 +641,7 @@
revision = "5fe7a883aa19554f42890211544aa549836af7b7"
[[projects]]
digest = "1:c09d7ef1564ca6aee8193b8b9d2d831cb69d29581f53b1b1e6331142d07fddbd"
digest = "1:3d43152515ea791363eb0d1d21378fbf70e7df4a3954fd315898532cf5e64a8c"
name = "google.golang.org/grpc"
packages = [
".",
@ -701,8 +684,6 @@
analyzer-version = 1
input-imports = [
"github.com/BurntSushi/toml",
"github.com/clearcontainers/proxy/api",
"github.com/clearcontainers/proxy/client",
"github.com/containerd/cgroups",
"github.com/containerd/containerd/api/events",
"github.com/containerd/containerd/api/types",
@ -735,7 +716,6 @@
"github.com/kata-containers/agent/pkg/types",
"github.com/kata-containers/agent/protocols/client",
"github.com/kata-containers/agent/protocols/grpc",
"github.com/kubernetes-incubator/cri-o/pkg/annotations",
"github.com/mitchellh/mapstructure",
"github.com/opencontainers/runc/libcontainer/configs",
"github.com/opencontainers/runc/libcontainer/specconv",

View File

@ -1,7 +1,3 @@
[[constraint]]
name = "github.com/clearcontainers/proxy"
revision = "1d2a6a3ea132a86abd0731408b7dc34f2fc17d55"
[[constraint]]
name = "github.com/containernetworking/plugins"
revision = "7f98c94613021d8b57acfa1a2f0c8d0f6fd7ae5a"

View File

@ -222,8 +222,30 @@ path = "@SHIMPATH@"
#enable_tracing = true
[agent.@PROJECT_TYPE@]
# There is no field for this section. The goal is only to be able to
# specify which type of agent the user wants to use.
# If enabled, make the agent display debug-level messages.
# (default: disabled)
#enable_debug = true
# Enable agent tracing.
#
# If enabled, the default trace mode is "dynamic" and the
# default trace type is "isolated". The trace mode and type are set
# explicity with the `trace_type=` and `trace_mode=` options.
#
# Notes:
#
# - Tracing is ONLY enabled when `enable_tracing` is set: explicitly
# setting `trace_mode=` and/or `trace_type=` without setting `enable_tracing`
# will NOT activate agent tracing.
#
# - See https://github.com/kata-containers/agent/blob/master/TRACING.md for
# full details.
#
# (default: disabled)
#enable_tracing = true
#
#trace_mode = "dynamic"
#trace_type = "isolated"
[netmon]
# If enabled, the network monitoring process gets started when the

View File

@ -274,8 +274,30 @@ path = "@SHIMPATH@"
#enable_tracing = true
[agent.@PROJECT_TYPE@]
# There is no field for this section. The goal is only to be able to
# specify which type of agent the user wants to use.
# If enabled, make the agent display debug-level messages.
# (default: disabled)
#enable_debug = true
# Enable agent tracing.
#
# If enabled, the default trace mode is "dynamic" and the
# default trace type is "isolated". The trace mode and type are set
# explicity with the `trace_type=` and `trace_mode=` options.
#
# Notes:
#
# - Tracing is ONLY enabled when `enable_tracing` is set: explicitly
# setting `trace_mode=` and/or `trace_type=` without setting `enable_tracing`
# will NOT activate agent tracing.
#
# - See https://github.com/kata-containers/agent/blob/master/TRACING.md for
# full details.
#
# (default: disabled)
#enable_tracing = true
#
#trace_mode = "dynamic"
#trace_type = "isolated"
[netmon]
# If enabled, the network monitoring process gets started when the

View File

@ -1,4 +1,4 @@
// Copyright (c) 2017-2018 Intel Corporation
// Copyright (c) 2017-2019 Intel Corporation
//
// SPDX-License-Identifier: Apache-2.0
//
@ -27,7 +27,7 @@ import (
//
// XXX: Increment for every change to the output format
// (meaning any change to the EnvInfo type).
const formatVersion = "1.0.21"
const formatVersion = "1.0.23"
// MetaInfo stores information on the format of the output itself
type MetaInfo struct {
@ -112,7 +112,11 @@ type ShimInfo struct {
// AgentInfo stores agent details
type AgentInfo struct {
Type string
Type string
Debug bool
Trace bool
TraceMode string
TraceType string
}
// DistroInfo stores host operating system distribution details.
@ -308,12 +312,26 @@ func getShimInfo(config oci.RuntimeConfig) (ShimInfo, error) {
return shim, nil
}
func getAgentInfo(config oci.RuntimeConfig) AgentInfo {
func getAgentInfo(config oci.RuntimeConfig) (AgentInfo, error) {
agent := AgentInfo{
Type: string(config.AgentType),
}
return agent
switch config.AgentType {
case vc.KataContainersAgent:
agentConfig, ok := config.AgentConfig.(vc.KataAgentConfig)
if !ok {
return AgentInfo{}, errors.New("cannot determine Kata agent config")
}
agent.Debug = agentConfig.Debug
agent.Trace = agentConfig.Trace
agent.TraceMode = agentConfig.TraceMode
agent.TraceType = agentConfig.TraceType
default:
// Nothing useful to report for the other agent types
}
return agent, nil
}
func getHypervisorInfo(config oci.RuntimeConfig) HypervisorInfo {
@ -361,7 +379,10 @@ func getEnvInfo(configFile string, config oci.RuntimeConfig) (env EnvInfo, err e
return EnvInfo{}, err
}
agent := getAgentInfo(config)
agent, err := getAgentInfo(config)
if err != nil {
return EnvInfo{}, err
}
hypervisor := getHypervisorInfo(config)

View File

@ -24,8 +24,7 @@ import (
specs "github.com/opencontainers/runtime-spec/specs-go"
"github.com/urfave/cli"
"strconv"
"github.com/kata-containers/runtime/pkg/katatestutils"
"github.com/kata-containers/runtime/pkg/katautils"
"github.com/kata-containers/runtime/virtcontainers/pkg/oci"
"github.com/stretchr/testify/assert"
@ -36,12 +35,6 @@ const testShimVersion = "shim version 0.1"
const testNetmonVersion = "netmon version 0.1"
const testHypervisorVersion = "QEMU emulator version 2.7.0+git.741f430a96-6.1, Copyright (c) 2003-2016 Fabrice Bellard and the QEMU Project developers"
const defaultVCPUCount uint32 = 1
const defaultMaxVCPUCount uint32 = 0
const defaultMemSize uint32 = 2048 // MiB
const defaultMsize9p uint32 = 8192
const defaultGuestHookPath string = ""
var (
hypervisorDebug = false
proxyDebug = false
@ -49,6 +42,8 @@ var (
runtimeTrace = false
shimDebug = false
netmonDebug = false
agentDebug = false
agentTrace = false
)
// makeVersionBinary creates a shell script with the specified file
@ -81,47 +76,6 @@ func createConfig(configPath string, fileData string) error {
return nil
}
func makeRuntimeConfigFileData(hypervisor, hypervisorPath, kernelPath, imagePath, kernelParams, machineType, shimPath, proxyPath, netmonPath, logPath string, disableBlock bool, blockDeviceDriver string, enableIOThreads bool, hotplugVFIOOnRootBus, disableNewNetNs bool) string {
return `
# Runtime configuration file
[hypervisor.` + hypervisor + `]
path = "` + hypervisorPath + `"
kernel = "` + kernelPath + `"
block_device_driver = "` + blockDeviceDriver + `"
kernel_params = "` + kernelParams + `"
image = "` + imagePath + `"
machine_type = "` + machineType + `"
default_vcpus = ` + strconv.FormatUint(uint64(defaultVCPUCount), 10) + `
default_maxvcpus = ` + strconv.FormatUint(uint64(defaultMaxVCPUCount), 10) + `
default_memory = ` + strconv.FormatUint(uint64(defaultMemSize), 10) + `
disable_block_device_use = ` + strconv.FormatBool(disableBlock) + `
enable_iothreads = ` + strconv.FormatBool(enableIOThreads) + `
hotplug_vfio_on_root_bus = ` + strconv.FormatBool(hotplugVFIOOnRootBus) + `
msize_9p = ` + strconv.FormatUint(uint64(defaultMsize9p), 10) + `
enable_debug = ` + strconv.FormatBool(hypervisorDebug) + `
guest_hook_path = "` + defaultGuestHookPath + `"
[proxy.kata]
enable_debug = ` + strconv.FormatBool(proxyDebug) + `
path = "` + proxyPath + `"
[shim.kata]
path = "` + shimPath + `"
enable_debug = ` + strconv.FormatBool(shimDebug) + `
[agent.kata]
[netmon]
path = "` + netmonPath + `"
enable_debug = ` + strconv.FormatBool(netmonDebug) + `
[runtime]
enable_debug = ` + strconv.FormatBool(runtimeDebug) + `
enable_tracing = ` + strconv.FormatBool(runtimeTrace) + `
disable_new_netns= ` + strconv.FormatBool(disableNewNetNs)
}
func makeRuntimeConfig(prefixDir string) (configFile string, config oci.RuntimeConfig, err error) {
const logPath = "/log/path"
hypervisorPath := filepath.Join(prefixDir, "hypervisor")
@ -172,23 +126,40 @@ func makeRuntimeConfig(prefixDir string) (configFile string, config oci.RuntimeC
return "", oci.RuntimeConfig{}, err
}
runtimeConfig := makeRuntimeConfigFileData(
"qemu",
hypervisorPath,
kernelPath,
imagePath,
kernelParams,
machineType,
shimPath,
proxyPath,
netmonPath,
logPath,
disableBlock,
blockStorageDriver,
enableIOThreads,
hotplugVFIOOnRootBus,
disableNewNetNs,
)
hypConfig := katautils.GetDefaultHypervisorConfig()
configFileOptions := katatestutils.RuntimeConfigOptions{
Hypervisor: "qemu",
HypervisorPath: hypervisorPath,
KernelPath: kernelPath,
ImagePath: imagePath,
KernelParams: kernelParams,
MachineType: machineType,
ShimPath: shimPath,
ProxyPath: proxyPath,
NetmonPath: netmonPath,
LogPath: logPath,
DefaultGuestHookPath: hypConfig.GuestHookPath,
DisableBlock: disableBlock,
BlockDeviceDriver: blockStorageDriver,
EnableIOThreads: enableIOThreads,
HotplugVFIOOnRootBus: hotplugVFIOOnRootBus,
DisableNewNetNs: disableNewNetNs,
DefaultVCPUCount: hypConfig.NumVCPUs,
DefaultMaxVCPUCount: hypConfig.DefaultMaxVCPUs,
DefaultMemSize: hypConfig.MemorySize,
DefaultMsize9p: hypConfig.Msize9p,
HypervisorDebug: hypervisorDebug,
RuntimeDebug: runtimeDebug,
RuntimeTrace: runtimeTrace,
ProxyDebug: proxyDebug,
ShimDebug: shimDebug,
NetmonDebug: netmonDebug,
AgentDebug: agentDebug,
AgentTrace: agentTrace,
}
runtimeConfig := katatestutils.MakeRuntimeConfigFileData(configFileOptions)
configFile = path.Join(prefixDir, "runtime.toml")
err = createConfig(configFile, runtimeConfig)
@ -239,8 +210,20 @@ func getExpectedShimDetails(config oci.RuntimeConfig) (ShimInfo, error) {
}
func getExpectedAgentDetails(config oci.RuntimeConfig) (AgentInfo, error) {
agentConfig, ok := config.AgentConfig.(vc.KataAgentConfig)
if !ok {
return AgentInfo{}, fmt.Errorf("expected KataAgentConfig, got %T", config.AgentConfig)
}
return AgentInfo{
Type: string(config.AgentType),
Type: string(config.AgentType),
Debug: agentConfig.Debug,
Trace: agentConfig.Trace,
// No trace mode/type set by default
TraceMode: "",
TraceType: "",
}, nil
}
@ -519,6 +502,8 @@ func TestEnvGetEnvInfo(t *testing.T) {
runtimeDebug = toggle
runtimeTrace = toggle
shimDebug = toggle
agentDebug = toggle
agentTrace = toggle
configFile, config, err := makeRuntimeConfig(tmpdir)
assert.NoError(t, err)
@ -832,8 +817,33 @@ func TestEnvGetAgentInfo(t *testing.T) {
expectedAgent, err := getExpectedAgentDetails(config)
assert.NoError(t, err)
agent := getAgentInfo(config)
agent, err := getAgentInfo(config)
assert.NoError(t, err)
assert.Equal(t, expectedAgent, agent)
agentConfig, ok := config.AgentConfig.(vc.KataAgentConfig)
assert.True(t, ok)
agentConfig.Debug = true
config.AgentConfig = agentConfig
agent, err = getAgentInfo(config)
assert.NoError(t, err)
assert.True(t, agent.Debug)
agentConfig.Trace = true
agentConfig.TraceMode = "traceMode"
agentConfig.TraceType = "traceType"
config.AgentConfig = agentConfig
agent, err = getAgentInfo(config)
assert.NoError(t, err)
assert.True(t, agent.Trace)
assert.Equal(t, agent.TraceMode, "traceMode")
assert.Equal(t, agent.TraceType, "traceType")
config.AgentConfig = "I am the wrong type"
_, err = getAgentInfo(config)
assert.Error(t, err)
}
func testEnvShowTOMLSettings(t *testing.T, tmpdir string, tmpfile *os.File) error {

View File

@ -0,0 +1,87 @@
// Copyright (c) 2018-2019 Intel Corporation
// Copyright (c) 2018 HyperHQ Inc.
//
// SPDX-License-Identifier: Apache-2.0
//
package katatestutils
import "strconv"
type RuntimeConfigOptions struct {
Hypervisor string
HypervisorPath string
DefaultVCPUCount uint32
DefaultMaxVCPUCount uint32
DefaultMemSize uint32
DefaultMsize9p uint32
DefaultGuestHookPath string
KernelPath string
ImagePath string
KernelParams string
MachineType string
ShimPath string
ProxyPath string
NetmonPath string
LogPath string
BlockDeviceDriver string
AgentTraceMode string
AgentTraceType string
DisableBlock bool
EnableIOThreads bool
HotplugVFIOOnRootBus bool
DisableNewNetNs bool
HypervisorDebug bool
RuntimeDebug bool
RuntimeTrace bool
ProxyDebug bool
ShimDebug bool
NetmonDebug bool
AgentDebug bool
AgentTrace bool
}
func MakeRuntimeConfigFileData(config RuntimeConfigOptions) string {
return `
# Runtime configuration file
[hypervisor.` + config.Hypervisor + `]
path = "` + config.HypervisorPath + `"
kernel = "` + config.KernelPath + `"
block_device_driver = "` + config.BlockDeviceDriver + `"
kernel_params = "` + config.KernelParams + `"
image = "` + config.ImagePath + `"
machine_type = "` + config.MachineType + `"
default_vcpus = ` + strconv.FormatUint(uint64(config.DefaultVCPUCount), 10) + `
default_maxvcpus = ` + strconv.FormatUint(uint64(config.DefaultMaxVCPUCount), 10) + `
default_memory = ` + strconv.FormatUint(uint64(config.DefaultMemSize), 10) + `
disable_block_device_use = ` + strconv.FormatBool(config.DisableBlock) + `
enable_iothreads = ` + strconv.FormatBool(config.EnableIOThreads) + `
hotplug_vfio_on_root_bus = ` + strconv.FormatBool(config.HotplugVFIOOnRootBus) + `
msize_9p = ` + strconv.FormatUint(uint64(config.DefaultMsize9p), 10) + `
enable_debug = ` + strconv.FormatBool(config.HypervisorDebug) + `
guest_hook_path = "` + config.DefaultGuestHookPath + `"
[proxy.kata]
enable_debug = ` + strconv.FormatBool(config.ProxyDebug) + `
path = "` + config.ProxyPath + `"
[shim.kata]
path = "` + config.ShimPath + `"
enable_debug = ` + strconv.FormatBool(config.ShimDebug) + `
[agent.kata]
enable_debug = ` + strconv.FormatBool(config.AgentDebug) + `
enable_tracing = ` + strconv.FormatBool(config.AgentTrace) + `
trace_mode = "` + config.AgentTraceMode + `"` + `
trace_type = "` + config.AgentTraceType + `"` + `
[netmon]
path = "` + config.NetmonPath + `"
enable_debug = ` + strconv.FormatBool(config.NetmonDebug) + `
[runtime]
enable_debug = ` + strconv.FormatBool(config.RuntimeDebug) + `
enable_tracing = ` + strconv.FormatBool(config.RuntimeTrace) + `
disable_new_netns= ` + strconv.FormatBool(config.DisableNewNetNs)
}

View File

@ -136,6 +136,10 @@ type shim struct {
}
type agent struct {
Debug bool `toml:"enable_debug"`
Tracing bool `toml:"enable_tracing"`
TraceMode string `toml:"trace_mode"`
TraceType string `toml:"trace_type"`
}
type netmon struct {
@ -388,6 +392,22 @@ func (s shim) trace() bool {
return s.Tracing
}
func (a agent) debug() bool {
return a.Debug
}
func (a agent) trace() bool {
return a.Tracing
}
func (a agent) traceMode() string {
return a.TraceMode
}
func (a agent) traceType() string {
return a.TraceType
}
func (n netmon) enable() bool {
return n.Enable
}
@ -630,21 +650,32 @@ func updateRuntimeConfigProxy(configPath string, tomlConf tomlConfig, config *oc
func updateRuntimeConfigAgent(configPath string, tomlConf tomlConfig, config *oci.RuntimeConfig, builtIn bool) error {
if builtIn {
var agentConfig vc.KataAgentConfig
// If the agent config section isn't a Kata one, just default
// to everything being disabled.
agentConfig, _ = config.AgentConfig.(vc.KataAgentConfig)
config.AgentType = vc.KataContainersAgent
config.AgentConfig = vc.KataAgentConfig{
LongLiveConn: true,
UseVSock: config.HypervisorConfig.UseVSock,
Debug: agentConfig.Debug,
}
return nil
}
for k := range tomlConf.Agent {
for k, agent := range tomlConf.Agent {
switch k {
case kataAgentTableType:
config.AgentType = vc.KataContainersAgent
config.AgentConfig = vc.KataAgentConfig{
UseVSock: config.HypervisorConfig.UseVSock,
UseVSock: config.HypervisorConfig.UseVSock,
Debug: agent.debug(),
Trace: agent.trace(),
TraceMode: agent.traceMode(),
TraceType: agent.traceType(),
}
default:
return fmt.Errorf("%s agent type is not supported", k)
@ -705,6 +736,22 @@ func SetKernelParams(runtimeConfig *oci.RuntimeConfig) error {
}
}
// next, check for agent specific kernel params
if agentConfig, ok := runtimeConfig.AgentConfig.(vc.KataAgentConfig); ok {
err := vc.KataAgentSetDefaultTraceConfigOptions(&agentConfig)
if err != nil {
return err
}
params := vc.KataAgentKernelParams(agentConfig)
for _, p := range params {
if err := (runtimeConfig).AddKernelParam(p); err != nil {
return err
}
}
}
// now re-add the user-specified values so that they take priority.
for _, p := range userKernelParams {
if err := (runtimeConfig).AddKernelParam(p); err != nil {
@ -752,10 +799,8 @@ func updateRuntimeConfig(configPath string, tomlConf tomlConfig, config *oci.Run
return nil
}
func initConfig() (config oci.RuntimeConfig, err error) {
var defaultAgentConfig interface{}
defaultHypervisorConfig := vc.HypervisorConfig{
func GetDefaultHypervisorConfig() vc.HypervisorConfig {
return vc.HypervisorConfig{
HypervisorPath: defaultHypervisorPath,
KernelPath: defaultKernelPath,
ImagePath: defaultImagePath,
@ -767,6 +812,7 @@ func initConfig() (config oci.RuntimeConfig, err error) {
DefaultMaxVCPUs: defaultMaxVCPUCount,
MemorySize: defaultMemSize,
MemOffset: defaultMemOffset,
DisableBlockDeviceUse: defaultDisableBlockDeviceUse,
DefaultBridges: defaultBridgesCount,
MemPrealloc: defaultEnableMemPrealloc,
HugePages: defaultEnableHugePages,
@ -782,6 +828,10 @@ func initConfig() (config oci.RuntimeConfig, err error) {
HotplugVFIOOnRootBus: defaultHotplugVFIOOnRootBus,
GuestHookPath: defaultGuestHookPath,
}
}
func initConfig() (config oci.RuntimeConfig, err error) {
var defaultAgentConfig interface{}
err = config.InterNetworkModel.SetModel(defaultInterNetworkingModel)
if err != nil {
@ -792,7 +842,7 @@ func initConfig() (config oci.RuntimeConfig, err error) {
config = oci.RuntimeConfig{
HypervisorType: defaultHypervisor,
HypervisorConfig: defaultHypervisorConfig,
HypervisorConfig: GetDefaultHypervisorConfig(),
AgentType: defaultAgent,
AgentConfig: defaultAgentConfig,
ProxyType: defaultProxy,

View File

@ -15,11 +15,11 @@ import (
"path/filepath"
"reflect"
goruntime "runtime"
"strconv"
"strings"
"syscall"
"testing"
"github.com/kata-containers/runtime/pkg/katatestutils"
vc "github.com/kata-containers/runtime/virtcontainers"
"github.com/kata-containers/runtime/virtcontainers/pkg/oci"
"github.com/kata-containers/runtime/virtcontainers/utils"
@ -30,8 +30,11 @@ var (
hypervisorDebug = false
proxyDebug = false
runtimeDebug = false
runtimeTrace = false
shimDebug = false
netmonDebug = false
agentDebug = false
agentTrace = false
)
type testRuntimeConfig struct {
@ -43,46 +46,6 @@ type testRuntimeConfig struct {
LogPath string
}
func makeRuntimeConfigFileData(hypervisor, hypervisorPath, kernelPath, imagePath, kernelParams, machineType, shimPath, proxyPath, netmonPath, logPath string, disableBlock bool, blockDeviceDriver string, enableIOThreads bool, hotplugVFIOOnRootBus, disableNewNetNs bool) string {
return `
# Runtime configuration file
[hypervisor.` + hypervisor + `]
path = "` + hypervisorPath + `"
kernel = "` + kernelPath + `"
block_device_driver = "` + blockDeviceDriver + `"
kernel_params = "` + kernelParams + `"
image = "` + imagePath + `"
machine_type = "` + machineType + `"
default_vcpus = ` + strconv.FormatUint(uint64(defaultVCPUCount), 10) + `
default_maxvcpus = ` + strconv.FormatUint(uint64(defaultMaxVCPUCount), 10) + `
default_memory = ` + strconv.FormatUint(uint64(defaultMemSize), 10) + `
disable_block_device_use = ` + strconv.FormatBool(disableBlock) + `
enable_iothreads = ` + strconv.FormatBool(enableIOThreads) + `
hotplug_vfio_on_root_bus = ` + strconv.FormatBool(hotplugVFIOOnRootBus) + `
msize_9p = ` + strconv.FormatUint(uint64(defaultMsize9p), 10) + `
enable_debug = ` + strconv.FormatBool(hypervisorDebug) + `
guest_hook_path = "` + defaultGuestHookPath + `"
[proxy.kata]
enable_debug = ` + strconv.FormatBool(proxyDebug) + `
path = "` + proxyPath + `"
[shim.kata]
path = "` + shimPath + `"
enable_debug = ` + strconv.FormatBool(shimDebug) + `
[agent.kata]
[netmon]
path = "` + netmonPath + `"
enable_debug = ` + strconv.FormatBool(netmonDebug) + `
[runtime]
enable_debug = ` + strconv.FormatBool(runtimeDebug) + `
disable_new_netns= ` + strconv.FormatBool(disableNewNetNs)
}
func createConfig(configPath string, fileData string) error {
err := ioutil.WriteFile(configPath, []byte(fileData), testFileMode)
@ -121,7 +84,38 @@ func createAllRuntimeConfigFiles(dir, hypervisor string) (config testRuntimeConf
hotplugVFIOOnRootBus := true
disableNewNetNs := false
runtimeConfigFileData := makeRuntimeConfigFileData(hypervisor, hypervisorPath, kernelPath, imagePath, kernelParams, machineType, shimPath, proxyPath, netmonPath, logPath, disableBlockDevice, blockDeviceDriver, enableIOThreads, hotplugVFIOOnRootBus, disableNewNetNs)
configFileOptions := katatestutils.RuntimeConfigOptions{
Hypervisor: "qemu",
HypervisorPath: hypervisorPath,
KernelPath: kernelPath,
ImagePath: imagePath,
KernelParams: kernelParams,
MachineType: machineType,
ShimPath: shimPath,
ProxyPath: proxyPath,
NetmonPath: netmonPath,
LogPath: logPath,
DefaultGuestHookPath: defaultGuestHookPath,
DisableBlock: disableBlockDevice,
BlockDeviceDriver: blockDeviceDriver,
EnableIOThreads: enableIOThreads,
HotplugVFIOOnRootBus: hotplugVFIOOnRootBus,
DisableNewNetNs: disableNewNetNs,
DefaultVCPUCount: defaultVCPUCount,
DefaultMaxVCPUCount: defaultMaxVCPUCount,
DefaultMemSize: defaultMemSize,
DefaultMsize9p: defaultMsize9p,
HypervisorDebug: hypervisorDebug,
RuntimeDebug: runtimeDebug,
RuntimeTrace: runtimeTrace,
ProxyDebug: proxyDebug,
ShimDebug: shimDebug,
NetmonDebug: netmonDebug,
AgentDebug: agentDebug,
AgentTrace: agentTrace,
}
runtimeConfigFileData := katatestutils.MakeRuntimeConfigFileData(configFileOptions)
configPath := path.Join(dir, "runtime.toml")
err = createConfig(configPath, runtimeConfigFileData)
@ -1207,6 +1201,25 @@ func TestShimDefaults(t *testing.T) {
assert.True(s.trace())
}
func TestAgentDefaults(t *testing.T) {
assert := assert.New(t)
a := agent{}
assert.Equal(a.debug(), a.Debug)
a.Debug = true
assert.Equal(a.debug(), a.Debug)
assert.Equal(a.trace(), a.Tracing)
a.Tracing = true
assert.Equal(a.trace(), a.Tracing)
assert.Equal(a.traceMode(), a.TraceMode)
assert.Equal(a.traceType(), a.TraceType)
}
func TestGetDefaultConfigFilePaths(t *testing.T) {
assert := assert.New(t)

View File

@ -1,202 +0,0 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@ -1,84 +0,0 @@
// Copyright (c) 2017 Intel Corporation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Package api defines the API cc-proxy exposes to clients (processes
// connecting to the proxy AF_UNIX socket).
//
// This package contains the low level definitions of the protocol, frame
// structure and the various payloads that can be sent and received.
//
// The proxy protocol is composed of commands, responses and notifications.
// They all share the same frame structure: a header followed by an optional
// payload.
//
// • Commands are always initiated by a client, never by the proxy itself.
//
// • Responses are sent by the proxy to acknowledge commands.
//
// • Notifications are sent by either the proxy or clients and do not generate
// responses.
//
// Frame Structure
//
// The frame format is illustrated below:
//
// 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
// 0 1 2 3 4 5 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
// ┌───────────────────────────┬───────────────┬───────────────┐
// │ Version │ Header Length │ Reserved │
// ├───────────────────────────┼─────┬─┬───────┼───────────────┤
// │ Reserved │ Res.│E│ Type │ Opcode │
// ├───────────────────────────┴─────┴─┴───────┴───────────────┤
// │ Payload Length │
// ├───────────────────────────────────────────────────────────┤
// │ │
// │ Payload │
// │ │
// │ (variable length, optional and opcode-specific) │
// │ │
// └───────────────────────────────────────────────────────────┘
//
// All header fields are encoded in network order (big endian).
//
// • Version (16 bits) is the proxy protocol version. See api.Version for
// details about what information it encodes.
//
// • Header Length (8 bits) is the length of the header in number of 32-bit
// words. Header Length is greater or equal to 3 (12 bytes).
//
// • Type (4 bits) is the frame type: command (0x0), response (0x1),
// stream (0x2) or notification (0x3).
//
// • Opcode (8 bits) specifies the kind of command, response, stream or
// notification this frame represents. In conjunction with Type, this field
// will dictate the payload content.
//
// • E, Error. This flag is set when a response returns an error. Currently
// Error can ony be set in response frames.
//
// • Payload Length (32 bits) is in bytes.
//
// • Payload is optional data that can be sent with the various frames.
// Commands, responses and notifications usually encode their payloads in JSON
// while stream frames have raw data payloads.
//
// • Reserved fields are reserved for future use and must be zeroed.
//
// Frame Size and Header Length
//
// The full size of a frame is (Header Length + Payload Length). The Payload
// starts at offset Header Length from the start of the frame.
//
// It is guaranteed that future header sizes will be at least 12 bytes.
package api

View File

@ -1,235 +0,0 @@
// Copyright (c) 2017 Intel Corporation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package api
import (
"encoding/json"
)
// Version encodes the proxy protocol version.
//
// List of changes:
//
// • version 2: initial version released with Clear Containers 3.0
//
// ⚠⚠⚠ backward incompatible with version 1 ⚠⚠⚠
//
// List of changes:
//
// • Changed the frame header to include additional fields: version,
// header length, type and opcode.
// • Added a log messages for clients to insert log entries to the
// consolidated proxy log.
//
// • version 1: initial version released with Clear Containers 2.1
const Version = 2
// FrameType is the type of frame and is part of the frame header.
type FrameType int
const (
// TypeCommand is a command from a client to the proxy.
TypeCommand FrameType = iota
// TypeResponse is a command response back from the proxy to a client.
TypeResponse
// TypeStream is a stream of data from a client to the proxy. Streams
// are to be forwarded onto the VM agent.
TypeStream
// TypeNotification is a notification sent by either the proxy or
// clients. Notifications are one way only and do not prompt a
// response.
TypeNotification
// TypeMax is the number of types.
TypeMax
)
const unknown = "unknown"
// String implements Stringer for FrameType.
func (t FrameType) String() string {
switch t {
case TypeCommand:
return "command"
case TypeResponse:
return "response"
case TypeStream:
return "stream"
case TypeNotification:
return "notification"
default:
return unknown
}
}
// Command is the kind of command being sent. In the frame header, Opcode must
// have one of these values when Type is api.TypeCommand.
type Command int
const (
// CmdRegisterVM registers a new VM/POD.
CmdRegisterVM Command = iota
// CmdUnregisterVM unregisters a VM/POD.
CmdUnregisterVM
// CmdAttachVM attaches to a registered VM.
CmdAttachVM
// CmdHyper sends a hyperstart command through the proxy.
CmdHyper
// CmdConnectShim identifies the client as a shim.
CmdConnectShim
// CmdDisconnectShim unregisters a shim. DisconnectShim is a bit
// special and doesn't send a Response back but closes the connection.
CmdDisconnectShim
// CmdSignal sends a signal to the process inside the VM. A client
// needs to be connected as a shim before it can issue that command.
CmdSignal
// CmdMax is the number of commands.
CmdMax
)
// String implements Stringer for Command.
func (t Command) String() string {
switch t {
case CmdRegisterVM:
return "RegisterVM"
case CmdUnregisterVM:
return "UnregisterVM"
case CmdAttachVM:
return "AttachVM"
case CmdHyper:
return "Hyper"
case CmdConnectShim:
return "ConnectShim"
case CmdDisconnectShim:
return "DisconnectShim"
case CmdSignal:
return "Signal"
default:
return unknown
}
}
// Stream is the kind of stream being sent. In the frame header, Opcode must
// have one of the these values when Type is api.TypeStream.
type Stream int
const (
// StreamStdin is a stream conveying stdin data.
StreamStdin Stream = iota
// StreamStdout is a stream conveying stdout data.
StreamStdout
// StreamStderr is a stream conveying stderr data.
StreamStderr
// StreamLog is a stream conveying structured logs messages. Each Log frame
// contains a JSON object which fields are the structured log. By convention
// it would be nice to have a few common fields in log entries to ease
// post-processing. See the LogEntry payload for details.
StreamLog
// StreamMax is the number of stream types.
StreamMax
)
// String implements Stringer for Stream.
func (s Stream) String() string {
switch s {
case StreamStdin:
return "stdin"
case StreamStdout:
return "stdout"
case StreamStderr:
return "stderr"
case StreamLog:
return "log"
default:
return unknown
}
}
// Notification is the kind of notification being sent. In the frame header,
// Opcode must have one of the these values when Type is api.TypeNotification.
type Notification int
const (
// NotificationProcessExited is sent to signal a process in the VM has exited.
NotificationProcessExited = iota
// NotificationMax is the number of notification types.
NotificationMax
)
// String implements Stringer for Notification.
func (n Notification) String() string {
switch n {
case NotificationProcessExited:
return "ProcessExited"
default:
return unknown
}
}
// FrameHeader is the header of a Frame.
type FrameHeader struct {
Version int
// HeaderLength in the size of the header in bytes (the on-wire
// HeaderLength is in number of 32-bits words tough).
HeaderLength int
Type FrameType
Opcode int
PayloadLength int
InError bool
}
// Frame is the basic communication unit with the proxy.
type Frame struct {
Header FrameHeader
Payload []byte
}
// NewFrame creates a new Frame with type t, operand op and given payload.
func NewFrame(t FrameType, op int, payload []byte) *Frame {
return &Frame{
Header: FrameHeader{
Version: Version,
HeaderLength: minHeaderLength,
Type: t,
Opcode: op,
PayloadLength: len(payload),
},
Payload: payload,
}
}
// NewFrameJSON creates a new Frame with type t, operand op and given payload.
// The payload structure is marshalled into JSON.
func NewFrameJSON(t FrameType, op int, payload interface{}) (*Frame, error) {
var data []byte
if payload != nil {
var err error
if data, err = json.Marshal(payload); err != nil {
return nil, err
}
}
return &Frame{
Header: FrameHeader{
Version: Version,
HeaderLength: minHeaderLength,
Type: t,
Opcode: op,
PayloadLength: len(data),
},
Payload: data,
}, nil
}

View File

@ -1,183 +0,0 @@
// Copyright (c) 2016,2017 Intel Corporation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package api
import (
"encoding/json"
)
// The RegisterVM payload is issued first after connecting to the proxy socket.
// It is used to let the proxy know about a new container on the system along
// with the paths go hyperstart's command and I/O channels (AF_UNIX sockets).
//
// Console can be used to indicate the path of a socket linked to the VM
// console. The proxy can output this data when asked for verbose output.
//
// {
// "containerId": "756535dc6e9ab9b560f84c8...",
// "ctlSerial": "/tmp/sh.hyper.channel.0.sock",
// "ioSerial": "/tmp/sh.hyper.channel.1.sock",
// "numIOStreams: 1
// }
type RegisterVM struct {
ContainerID string `json:"containerId"`
CtlSerial string `json:"ctlSerial"`
IoSerial string `json:"ioSerial"`
Console string `json:"console,omitempty"`
// NumIOStreams asks for a number of I/O tokens. An I/O token
// represents the communication between a container process inside
// the VM and a shim process outside the VM. This communication
// includes I/O streams (stdin, out, err) but also signals, exit
// status, ...
// The response frame will contain NumIOStreams I/O tokens.
NumIOStreams int `json:"numIOStreams,omitempty"`
}
// IOResponse is the response data in RegisterVMResponse and AttachVMResponse
// when the client is asking for I/O tokens from the proxy (NumIOStreams > 0).
type IOResponse struct {
// URL is the URL a shim process should connect to in order to initiate
// the I/O communication with the process inside the VM
URL string
// IOTokens is a array of I/O tokens of length NumIOStreams. See
// RegisterVM for some details on I/O tokens.
Tokens []string `json:"tokens"`
}
// RegisterVMResponse is the result from a successful RegisterVM.
//
// {
// "io": {
// "url": "unix:///run/clearcontainers/proxy.sock",
// "tokens": [
// "bwgxfmQj9uG3YCsFHrvontwDw41CJJ76Y7qVt4Bi9wc="
// ]
// }
// }
type RegisterVMResponse struct {
// IO contains the proxy answer when asking for I/O tokens.
IO IOResponse `json:"io,omitempty"`
}
// The AttachVM payload can be used to associate clients to an already known
// VM. AttachVM cannot be issued if a RegisterVM for this container hasn't been
// issued beforehand.
//
// {
// "containerId": "756535dc6e9ab9b560f84c8...".
// "numIOStreams: 1
// }
type AttachVM struct {
ContainerID string `json:"containerId"`
// NumIOStreams asks for a number of I/O tokens. See RegisterVM for
// some details on I/O tokens.
NumIOStreams int `json:"numIOStreams,omitempty"`
}
// AttachVMResponse is the result from a successful AttachVM.
//
// {
// "io": {
// "url": "unix:///run/clearcontainers/proxy.sock",
// "tokens": [
// "bwgxfmQj9uG3YCsFHrvontwDw41CJJ76Y7qVt4Bi9wc="
// ]
// }
// }
type AttachVMResponse struct {
// IO contains the proxy answer when asking for I/O tokens.
IO IOResponse `json:"io,omitempty"`
}
// The UnregisterVM payload does the opposite of what RegisterVM does,
// indicating to the proxy it should release resources created by RegisterVM
// for the container identified by containerId.
//
// {
// "containerId": "756535dc6e9ab9b560f84c8..."
// }
type UnregisterVM struct {
ContainerID string `json:"containerId"`
}
// The Hyper payload will forward an hyperstart command to hyperstart.
//
// Note: the newcontainer and execmd hyperstart commands start one or more
// processes. When sending those commands, tokens acquired through either
// RegisterVM or AttachVM need to be sent along in the tokens array. The number
// of tokens sent has to match the number of processes to be started.
//
// {
// "hyperName": "newcontainer",
// "tokens": [
// "bwgxfmQj9uG3YCsFHrvontwDw41CJJ76Y7qVt4Bi9wc="
// ],
// "data": {
// "id": "756535dc6e9ab9b560f84c8...",
// "rootfs": "/foo/bar",
// ...
// }
// }
// }
type Hyper struct {
HyperName string `json:"hyperName"`
Tokens []string `json:"tokens"`
Data json.RawMessage `json:"data,omitempty"`
}
// ConnectShim identifies a shim against the proxy. A shim process is a process
// running on host shadowing a container process running inside the VM. A shim
// will forward stdin and signals to the process inside the VM and will receive
// stdout, stderr and the exit status.
type ConnectShim struct {
// Token is id corresponding to the process the shim wants to handle
// the I/O streams, signals, exit status for. Tokens are allocated with
// a call to RegisterVM or AttachVM.
Token string `json:"token"`
}
// DisconnectShim unregister a shim from the proxy.
type DisconnectShim struct {
}
// Signal is used to send signals to the container process inside the VM. This
// payload is only valid after a successful ConnectShim.
type Signal struct {
SignalNumber int `json:"signalNumber"`
// Columns is only valid for SIGWINCH and is the new number of columns of
// the terminal.
Columns int `json:"columns,omitempty"`
// Rows is only valid for SIGWINCH and is the new number of rows of the
// terminal.
Rows int `json:"rows,omitempty"`
}
// ErrorResponse is the payload send in Responses where the Error flag is set.
type ErrorResponse struct {
Message string `json:"msg"`
}
// LogEntry is the payload for the StreamLog data.
type LogEntry struct {
// Source is the source of the log entry. One of "shim" or "runtime".
Source string `json:"source"`
// ContainerID is the ID of the container the log entry is for (optional).
ContainerID string `json:"containerId,omitempty"`
// Level is the verbosity level of the log entry. One of "debug", "info", "warn"
// or "error".
Level string `json:"level"`
// Message is the log message
Message string `json:"msg"`
}

View File

@ -1,213 +0,0 @@
// Copyright (c) 2016 Intel Corporation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package api
import (
"encoding/binary"
"encoding/json"
"errors"
"fmt"
"io"
)
// minHeaderLength is the length of the header in the version 2 of protocol.
// It is guaranteed later versions will have a header at least that big.
const minHeaderLength = 12 // in bytes
// A Request is a JSON message sent from a client to the proxy. This message
// embed a payload identified by "id". A payload can have data associated with
// it. It's useful to think of Request as an RPC call with "id" as function
// name and "data" as arguments.
//
// The list of possible payloads are documented in this package.
//
// Each Request has a corresponding Response message sent back from the proxy.
type Request struct {
ID string `json:"id"`
Data json.RawMessage `json:"data,omitempty"`
}
// A Response is a JSON message sent back from the proxy to a client after a
// Request has been issued. The Response holds the result of the Request,
// including its success state and optional data. It's useful to think of
// Response as the result of an RPC call with ("success", "error") describing
// if the call has been successful and "data" holding the optional results.
type Response struct {
Success bool `json:"success"`
Error string `json:"error,omitempty"`
Data map[string]interface{} `json:"data,omitempty"`
}
// Offsets (in bytes) of frame headers fields.
const (
versionOffset = 0
headerLengthOffset = 2
typeOffset = 6
flagsOffset = 6
opcodeOffset = 7
payloadLengthOffset = 8
)
// Size (in bytes) of frame header fields (when larger than 1 byte).
const (
versionSize = 2
payloadLengthSize = 4
)
// Masks needed to extract fields
const (
typeMask = 0x0f
flagsMask = 0xf0
)
func maxOpcodeForFrameType(t FrameType) int {
switch t {
default:
fallthrough
case TypeCommand:
return int(CmdMax)
case TypeResponse:
return int(CmdMax)
case TypeStream:
return int(StreamMax)
case TypeNotification:
return int(NotificationMax)
}
}
// ReadFrame reads a full frame (header and payload) from r.
func ReadFrame(r io.Reader) (*Frame, error) {
// Read the header.
buf := make([]byte, minHeaderLength)
n, err := r.Read(buf)
if err != nil {
return nil, err
}
if n != minHeaderLength {
return nil, errors.New("frame: couldn't read the full header")
}
// Decode it.
frame := &Frame{}
header := &frame.Header
header.Version = int(binary.BigEndian.Uint16(buf[versionOffset : versionOffset+versionSize]))
if header.Version < 2 || header.Version > Version {
return nil, fmt.Errorf("frame: bad version %d", header.Version)
}
header.HeaderLength = int(buf[headerLengthOffset]) * 4
header.Type = FrameType(buf[typeOffset] & typeMask)
flags := buf[flagsOffset] & flagsMask
if flags&flagInError != 0 {
header.InError = true
}
if header.Type >= TypeMax {
return nil, fmt.Errorf("frame: bad type %s", header.Type)
}
header.Opcode = int(buf[opcodeOffset])
if header.Opcode >= maxOpcodeForFrameType(header.Type) {
return nil, fmt.Errorf("frame: bad opcode (%d) for type %s", header.Opcode,
header.Type)
}
header.PayloadLength = int(binary.BigEndian.Uint32(buf[payloadLengthOffset : payloadLengthOffset+payloadLengthSize]))
// Read the payload.
received := 0
need := header.HeaderLength - minHeaderLength + header.PayloadLength
payload := make([]byte, need)
for received < need {
n, err := r.Read(payload[received:need])
if err != nil {
return nil, err
}
received += n
}
// Skip the bytes part of a bigger header than expected to just keep
// the payload.
frame.Payload = payload[header.HeaderLength-minHeaderLength : need]
return frame, nil
}
const (
flagInError = 1 << (4 + iota)
)
// WriteFrame writes a frame into w.
//
// Note that frame.Header.PayloadLength dictates the amount of data of
// frame.Payload to write, so frame.Header.Payload must be less or equal to
// len(frame.Payload).
func WriteFrame(w io.Writer, frame *Frame) error {
header := &frame.Header
if len(frame.Payload) < header.PayloadLength {
return fmt.Errorf("frame: bad payload length %d",
header.PayloadLength)
}
// Prepare the header.
len := minHeaderLength + header.PayloadLength
buf := make([]byte, len)
binary.BigEndian.PutUint16(buf[versionOffset:versionOffset+versionSize], uint16(header.Version))
buf[headerLengthOffset] = byte(header.HeaderLength / 4)
flags := byte(0)
if frame.Header.InError {
flags |= flagInError
}
buf[typeOffset] = flags | byte(header.Type)&typeMask
buf[opcodeOffset] = byte(header.Opcode)
binary.BigEndian.PutUint32(buf[payloadLengthOffset:payloadLengthOffset+payloadLengthSize],
uint32(header.PayloadLength))
// Write payload if needed
if header.PayloadLength > 0 {
copy(buf[minHeaderLength:], frame.Payload[0:header.PayloadLength])
}
n, err := w.Write(buf)
if err != nil {
return err
}
if n != len {
return errors.New("frame: couldn't write frame")
}
return nil
}
// WriteCommand is a convenience wrapper around WriteFrame to send commands.
func WriteCommand(w io.Writer, op Command, payload []byte) error {
return WriteFrame(w, NewFrame(TypeCommand, int(op), payload))
}
// WriteResponse is a convenience wrapper around WriteFrame to send responses.
func WriteResponse(w io.Writer, op Command, inError bool, payload []byte) error {
frame := NewFrame(TypeResponse, int(op), payload)
frame.Header.InError = inError
return WriteFrame(w, frame)
}
// WriteStream is a convenience wrapper around WriteFrame to send stream packets.
func WriteStream(w io.Writer, op Stream, payload []byte) error {
return WriteFrame(w, NewFrame(TypeStream, int(op), payload))
}
// WriteNotification is a convenience wrapper around WriteFrame to send notifications.
func WriteNotification(w io.Writer, op Notification, payload []byte) error {
return WriteFrame(w, NewFrame(TypeNotification, int(op), payload))
}

View File

@ -1,410 +0,0 @@
// Copyright (c) 2016 Intel Corporation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package client
import (
"encoding/json"
"errors"
"fmt"
"net"
"syscall"
"github.com/clearcontainers/proxy/api"
)
// The Client struct can be used to issue proxy API calls with a convenient
// high level API.
type Client struct {
conn net.Conn
}
// NewClient creates a new client object to communicate with the proxy using
// the connection conn. The user should call Close() once finished with the
// client object to close conn.
func NewClient(conn net.Conn) *Client {
return &Client{
conn: conn,
}
}
// Close a client, closing the underlying AF_UNIX socket.
func (client *Client) Close() {
client.conn.Close()
}
func (client *Client) sendCommandFull(cmd api.Command, payload interface{},
waitForResponse bool) (*api.Frame, error) {
var data []byte
var frame *api.Frame
var err error
if payload != nil {
if data, err = json.Marshal(payload); err != nil {
return nil, err
}
}
if err := api.WriteCommand(client.conn, cmd, data); err != nil {
return nil, err
}
if !waitForResponse {
return nil, nil
}
if frame, err = api.ReadFrame(client.conn); err != nil {
return nil, err
}
if cmd == api.CmdSignal {
payloadSignal, ok := payload.(*api.Signal)
if !ok {
return nil, err
}
if payloadSignal.SignalNumber == int(syscall.SIGKILL) ||
payloadSignal.SignalNumber == int(syscall.SIGTERM) {
if frame.Header.Type != api.TypeNotification {
return nil, fmt.Errorf("unexpected frame type %v", frame.Header.Type)
}
if frame, err = api.ReadFrame(client.conn); err != nil {
return nil, err
}
}
}
if frame.Header.Type != api.TypeResponse {
return nil, fmt.Errorf("unexpected frame type %v", frame.Header.Type)
}
if frame.Header.Opcode != int(cmd) {
return nil, fmt.Errorf("unexpected opcode %v", frame.Header.Opcode)
}
return frame, nil
}
func (client *Client) sendCommand(cmd api.Command, payload interface{}) (*api.Frame, error) {
return client.sendCommandFull(cmd, payload, true)
}
func (client *Client) sendCommandNoResponse(cmd api.Command, payload interface{}) error {
_, err := client.sendCommandFull(cmd, payload, false)
return err
}
func errorFromResponse(resp *api.Frame) error {
// We should always have an error with the response, but better safe
// than sorry.
if !resp.Header.InError {
return nil
}
decoded := api.ErrorResponse{}
if err := json.Unmarshal(resp.Payload, &decoded); err != nil {
return err
}
if decoded.Message == "" {
return errors.New("unknown error")
}
return errors.New(decoded.Message)
}
func unmarshalResponse(resp *api.Frame, decoded interface{}) error {
if len(resp.Payload) == 0 {
return nil
}
if err := json.Unmarshal(resp.Payload, decoded); err != nil {
return err
}
return nil
}
// RegisterVMOptions holds extra arguments one can pass to the RegisterVM
// function.
//
// See the api.RegisterVM payload for more details.
type RegisterVMOptions struct {
Console string
NumIOStreams int
}
// RegisterVMReturn contains the return values from RegisterVM.
//
// See the api.RegisterVM and api.RegisterVMResponse payloads.
type RegisterVMReturn api.RegisterVMResponse
// RegisterVM wraps the api.RegisterVM payload.
//
// See payload description for more details.
func (client *Client) RegisterVM(containerID, ctlSerial, ioSerial string,
options *RegisterVMOptions) (*RegisterVMReturn, error) {
payload := api.RegisterVM{
ContainerID: containerID,
CtlSerial: ctlSerial,
IoSerial: ioSerial,
}
if options != nil {
payload.Console = options.Console
payload.NumIOStreams = options.NumIOStreams
}
resp, err := client.sendCommand(api.CmdRegisterVM, &payload)
if err != nil {
return nil, err
}
if err := errorFromResponse(resp); err != nil {
return nil, err
}
decoded := RegisterVMReturn{}
err = unmarshalResponse(resp, &decoded)
return &decoded, err
}
// AttachVMOptions holds extra arguments one can pass to the AttachVM function.
//
// See the api.AttachVM payload for more details.
type AttachVMOptions struct {
NumIOStreams int
}
// AttachVMReturn contains the return values from AttachVM.
//
// See the api.AttachVM and api.AttachVMResponse payloads.
type AttachVMReturn api.AttachVMResponse
// AttachVM wraps the api.AttachVM payload.
//
// See the api.AttachVM payload description for more details.
func (client *Client) AttachVM(containerID string, options *AttachVMOptions) (*AttachVMReturn, error) {
payload := api.AttachVM{
ContainerID: containerID,
}
if options != nil {
payload.NumIOStreams = options.NumIOStreams
}
resp, err := client.sendCommand(api.CmdAttachVM, &payload)
if err != nil {
return nil, err
}
if err := errorFromResponse(resp); err != nil {
return nil, err
}
decoded := AttachVMReturn{}
err = unmarshalResponse(resp, &decoded)
return &decoded, err
}
// Hyper wraps the Hyper payload (see payload description for more details)
func (client *Client) Hyper(hyperName string, hyperMessage interface{}) ([]byte, error) {
return client.HyperWithTokens(hyperName, nil, hyperMessage)
}
// HyperWithTokens is a Hyper variant where the users can specify a list of I/O tokens.
//
// See the api.Hyper payload description for more details.
func (client *Client) HyperWithTokens(hyperName string, tokens []string, hyperMessage interface{}) ([]byte, error) {
var data []byte
if hyperMessage != nil {
var err error
data, err = json.Marshal(hyperMessage)
if err != nil {
return nil, err
}
}
hyper := api.Hyper{
HyperName: hyperName,
Data: data,
}
if tokens != nil {
hyper.Tokens = tokens
}
resp, err := client.sendCommand(api.CmdHyper, &hyper)
if err != nil {
return nil, err
}
if err = errorFromResponse(resp); err != nil {
return nil, err
}
return resp.Payload, errorFromResponse(resp)
}
// UnregisterVM wraps the api.UnregisterVM payload.
//
// See the api.UnregisterVM payload description for more details.
func (client *Client) UnregisterVM(containerID string) error {
payload := api.UnregisterVM{
ContainerID: containerID,
}
resp, err := client.sendCommand(api.CmdUnregisterVM, &payload)
if err != nil {
return err
}
return errorFromResponse(resp)
}
// ConnectShim wraps the api.CmdConnectShim command and associated
// api.ConnectShim payload.
func (client *Client) ConnectShim(token string) error {
payload := api.ConnectShim{
Token: token,
}
resp, err := client.sendCommand(api.CmdConnectShim, &payload)
if err != nil {
return err
}
return errorFromResponse(resp)
}
// DisconnectShim wraps the api.CmdDisconnectShim command and associated
// api.DisconnectShim payload.
func (client *Client) DisconnectShim() error {
return client.sendCommandNoResponse(api.CmdDisconnectShim, nil)
}
func (client *Client) signal(signal syscall.Signal, columns, rows int) error {
payload := api.Signal{
SignalNumber: int(signal),
Columns: columns,
Rows: rows,
}
resp, err := client.sendCommand(api.CmdSignal, &payload)
if err != nil {
return err
}
return errorFromResponse(resp)
}
// Kill wraps the api.CmdSignal command and can be used by a shim to send a
// signal to the associated process.
func (client *Client) Kill(signal syscall.Signal) error {
return client.signal(signal, 0, 0)
}
// SendTerminalSize wraps the api.CmdSignal command and can be used by a shim
// to send a new signal to the associated process.
func (client *Client) SendTerminalSize(columns, rows int) error {
return client.signal(syscall.SIGWINCH, columns, rows)
}
func (client *Client) sendStream(op api.Stream, data []byte) error {
return api.WriteStream(client.conn, op, data)
}
// SendStdin sends stdin data. This can only be used from shim clients.
func (client *Client) SendStdin(data []byte) error {
return client.sendStream(api.StreamStdin, data)
}
// LogLevel is the severity of log entries.
type LogLevel uint8
const (
// LogLevelDebug is for log messages only useful debugging.
LogLevelDebug LogLevel = iota
// LogLevelInfo is for reporting landmark events.
LogLevelInfo
// LogLevelWarn is for reporting warnings.
LogLevelWarn
// LogLevelError is for reporting errors.
LogLevelError
logLevelMax
)
var levelToString = []string{"debug", "info", "warn", "error"}
// String implements stringer for LogLevel.
func (l LogLevel) String() string {
if l < logLevelMax {
return levelToString[l]
}
return "unknown"
}
// LogSource is the source of log entries
type LogSource uint8
const (
// LogSourceRuntime represents a runtime.
LogSourceRuntime LogSource = iota
// LogSourceShim represents a shim.
LogSourceShim
logSourceMax
)
var sourceToString = []string{"runtime", "shim"}
// String implements stringer for LogSource
func (s LogSource) String() string {
if s < logSourceMax {
return sourceToString[s]
}
return "unknown"
}
// Log sends log entries.
func (client *Client) Log(level LogLevel, source LogSource, containerID string, args ...interface{}) {
payload := api.LogEntry{
Level: level.String(),
Source: source.String(),
ContainerID: containerID,
Message: fmt.Sprint(args...),
}
data, _ := json.Marshal(&payload)
_ = client.sendStream(api.StreamLog, data)
}
// Logf sends log entries.
func (client *Client) Logf(level LogLevel, source LogSource, containerID string, format string, args ...interface{}) {
payload := api.LogEntry{
Level: level.String(),
Source: source.String(),
ContainerID: containerID,
Message: fmt.Sprintf(format, args...),
}
data, _ := json.Marshal(&payload)
_ = client.sendStream(api.StreamLog, data)
}

File diff suppressed because it is too large Load Diff

View File

@ -3,7 +3,6 @@
package vsock
import (
"errors"
"net"
"os"
"time"
@ -11,31 +10,40 @@ import (
"golang.org/x/sys/unix"
)
var (
// errDeadlinesNotImplemented is returned by the SetDeadline family of methods
// for conn, because access is not yet available to the runtime network poller
// for non-standard sockets types.
// See: https://github.com/golang/go/issues/10565.
errDeadlinesNotImplemented = errors.New("vsock: deadlines not implemented")
)
var _ net.Conn = &conn{}
// A conn is the net.Conn implementation for VM sockets.
type conn struct {
*os.File
file *os.File
localAddr *Addr
remoteAddr *Addr
}
// LocalAddr and RemoteAddr implement the net.Conn interface for conn.
func (c *conn) LocalAddr() net.Addr { return c.localAddr }
func (c *conn) RemoteAddr() net.Addr { return c.remoteAddr }
// Implement net.Conn for type conn.
func (c *conn) LocalAddr() net.Addr { return c.localAddr }
func (c *conn) RemoteAddr() net.Addr { return c.remoteAddr }
func (c *conn) SetDeadline(t time.Time) error { return c.file.SetDeadline(t) }
func (c *conn) SetReadDeadline(t time.Time) error { return c.file.SetReadDeadline(t) }
func (c *conn) SetWriteDeadline(t time.Time) error { return c.file.SetWriteDeadline(t) }
func (c *conn) Read(b []byte) (n int, err error) { return c.file.Read(b) }
func (c *conn) Write(b []byte) (n int, err error) { return c.file.Write(b) }
func (c *conn) Close() error { return c.file.Close() }
// SetDeadline functions implement the net.Conn interface for conn.
func (c *conn) SetDeadline(_ time.Time) error { return errDeadlinesNotImplemented }
func (c *conn) SetReadDeadline(_ time.Time) error { return errDeadlinesNotImplemented }
func (c *conn) SetWriteDeadline(_ time.Time) error { return errDeadlinesNotImplemented }
// newConn creates a conn using an fd with the specified file name, local, and
// remote addresses.
func newConn(cfd fd, file string, local, remote *Addr) (*conn, error) {
// Enable integration with runtime network poller for timeout support
// in Go 1.11+.
if err := cfd.SetNonblock(true); err != nil {
return nil, err
}
return &conn{
file: cfd.NewFile(file),
localAddr: local,
remoteAddr: remote,
}, nil
}
// dialStream is the entry point for DialStream on Linux.
func dialStream(cid, port uint32) (net.Conn, error) {
@ -89,9 +97,6 @@ func dialStreamLinux(cfd fd, cid, port uint32) (net.Conn, error) {
Port: port,
}
return &conn{
File: cfd.NewFile(remoteAddr.fileName()),
localAddr: localAddr,
remoteAddr: remoteAddr,
}, nil
// File name is the name of the local socket.
return newConn(cfd, localAddr.fileName(), localAddr, remoteAddr)
}

View File

@ -11,11 +11,12 @@ import (
type fd interface {
Accept4(flags int) (fd, unix.Sockaddr, error)
Bind(sa unix.Sockaddr) error
Connect(sa unix.Sockaddr) error
Close() error
Connect(sa unix.Sockaddr) error
Getsockname() (unix.Sockaddr, error)
Listen(n int) error
NewFile(name string) *os.File
SetNonblock(nonblocking bool) error
}
var _ fd = &sysFD{}
@ -38,6 +39,7 @@ func (fd *sysFD) Accept4(flags int) (fd, unix.Sockaddr, error) {
func (fd *sysFD) Bind(sa unix.Sockaddr) error { return unix.Bind(fd.fd, sa) }
func (fd *sysFD) Close() error { return unix.Close(fd.fd) }
func (fd *sysFD) Connect(sa unix.Sockaddr) error { return unix.Connect(fd.fd, sa) }
func (fd *sysFD) Getsockname() (unix.Sockaddr, error) { return unix.Getsockname(fd.fd) }
func (fd *sysFD) Listen(n int) error { return unix.Listen(fd.fd, n) }
func (fd *sysFD) NewFile(name string) *os.File { return os.NewFile(uintptr(fd.fd), name) }
func (fd *sysFD) Getsockname() (unix.Sockaddr, error) { return unix.Getsockname(fd.fd) }
func (fd *sysFD) SetNonblock(nonblocking bool) error { return unix.SetNonblock(fd.fd, nonblocking) }

View File

@ -35,11 +35,7 @@ func (l *listener) Accept() (net.Conn, error) {
Port: savm.Port,
}
return &conn{
File: cfd.NewFile(l.addr.fileName()),
localAddr: l.addr,
remoteAddr: remoteAddr,
}, nil
return newConn(cfd, l.addr.fileName(), l.addr, remoteAddr)
}
// listenStream is the entry point for ListenStream on Linux.
@ -87,6 +83,10 @@ func listenStreamLinux(lfd fd, cid, port uint32) (net.Listener, error) {
Port: port,
}
if err := lfd.SetNonblock(true); err != nil {
return nil, err
}
if err := lfd.Bind(sa); err != nil {
return nil, err
}

View File

@ -91,19 +91,19 @@ func newAgent(agentType AgentType) agent {
}
// newAgentConfig returns an agent config from a generic SandboxConfig interface.
func newAgentConfig(agentType AgentType, agentConfig interface{}) interface{} {
func newAgentConfig(agentType AgentType, agentConfig interface{}) (interface{}, error) {
switch agentType {
case NoopAgentType:
return nil
return nil, nil
case KataContainersAgent:
var kataAgentConfig KataAgentConfig
err := mapstructure.Decode(agentConfig, &kataAgentConfig)
if err != nil {
return err
return nil, err
}
return kataAgentConfig
return kataAgentConfig, nil
default:
return nil
return nil, nil
}
}
@ -116,7 +116,7 @@ type agent interface {
// init().
// After init() is called, agent implementations should be initialized and ready
// to handle all other Agent interface methods.
init(ctx context.Context, sandbox *Sandbox, config interface{}) error
init(ctx context.Context, sandbox *Sandbox, config interface{}) (disableVMShutdown bool, err error)
// capabilities should return a structure that specifies the capabilities
// supported by the agent.

View File

@ -86,7 +86,12 @@ func TestNewAgentFromUnknownAgentType(t *testing.T) {
}
func testNewAgentConfig(t *testing.T, config SandboxConfig, expected interface{}) {
agentConfig := newAgentConfig(config.AgentType, config.AgentConfig)
agentConfig, err := newAgentConfig(config.AgentType, config.AgentConfig)
if err != nil {
t.Fatal(err)
}
if reflect.DeepEqual(agentConfig, expected) == false {
t.Fatal()
}

View File

@ -83,11 +83,25 @@ var (
maxHostnameLen = 64
)
const (
agentTraceModeDynamic = "dynamic"
agentTraceModeStatic = "static"
agentTraceTypeIsolated = "isolated"
agentTraceTypeCollated = "collated"
defaultAgentTraceMode = agentTraceModeDynamic
defaultAgentTraceType = agentTraceTypeIsolated
)
// KataAgentConfig is a structure storing information needed
// to reach the Kata Containers agent.
type KataAgentConfig struct {
LongLiveConn bool
UseVSock bool
Debug bool
Trace bool
TraceMode string
TraceType string
}
type kataVSOCK struct {
@ -115,10 +129,11 @@ type kataAgent struct {
sync.Mutex
client *kataclient.AgentClient
reqHandlers map[string]reqFunc
state KataAgentState
keepConn bool
proxyBuiltIn bool
reqHandlers map[string]reqFunc
state KataAgentState
keepConn bool
proxyBuiltIn bool
dynamicTracing bool
vmSocket interface{}
ctx context.Context
@ -175,7 +190,68 @@ func (k *kataAgent) generateVMSocket(id string, c KataAgentConfig) error {
return nil
}
func (k *kataAgent) init(ctx context.Context, sandbox *Sandbox, config interface{}) (err error) {
// KataAgentSetDefaultTraceConfigOptions validates agent trace options and
// sets defaults.
func KataAgentSetDefaultTraceConfigOptions(config *KataAgentConfig) error {
if !config.Trace {
return nil
}
switch config.TraceMode {
case agentTraceModeDynamic:
case agentTraceModeStatic:
case "":
config.TraceMode = defaultAgentTraceMode
default:
return fmt.Errorf("invalid kata agent trace mode: %q (need %q or %q)", config.TraceMode, agentTraceModeDynamic, agentTraceModeStatic)
}
switch config.TraceType {
case agentTraceTypeIsolated:
case agentTraceTypeCollated:
case "":
config.TraceType = defaultAgentTraceType
default:
return fmt.Errorf("invalid kata agent trace type: %q (need %q or %q)", config.TraceType, agentTraceTypeIsolated, agentTraceTypeCollated)
}
return nil
}
// KataAgentKernelParams returns a list of Kata Agent specific kernel
// parameters.
func KataAgentKernelParams(config KataAgentConfig) []Param {
var params []Param
if config.Debug {
params = append(params, Param{Key: "agent.log", Value: "debug"})
}
if config.Trace && config.TraceMode == agentTraceModeStatic {
params = append(params, Param{Key: "agent.trace", Value: config.TraceType})
}
return params
}
func (k *kataAgent) handleTraceSettings(config KataAgentConfig) bool {
if !config.Trace {
return false
}
disableVMShutdown := false
switch config.TraceMode {
case agentTraceModeStatic:
disableVMShutdown = true
case agentTraceModeDynamic:
k.dynamicTracing = true
}
return disableVMShutdown
}
func (k *kataAgent) init(ctx context.Context, sandbox *Sandbox, config interface{}) (disableVMShutdown bool, err error) {
// save
k.ctx = sandbox.ctx
@ -185,21 +261,23 @@ func (k *kataAgent) init(ctx context.Context, sandbox *Sandbox, config interface
switch c := config.(type) {
case KataAgentConfig:
if err := k.generateVMSocket(sandbox.id, c); err != nil {
return err
return false, err
}
disableVMShutdown = k.handleTraceSettings(c)
k.keepConn = c.LongLiveConn
default:
return fmt.Errorf("Invalid config type")
return false, vcTypes.ErrInvalidConfigType
}
k.proxy, err = newProxy(sandbox.config.ProxyType)
if err != nil {
return err
return false, err
}
k.shim, err = newShim(sandbox.config.ShimType)
if err != nil {
return err
return false, err
}
k.proxyBuiltIn = isProxyBuiltIn(sandbox.config.ProxyType)
@ -209,7 +287,7 @@ func (k *kataAgent) init(ctx context.Context, sandbox *Sandbox, config interface
k.Logger().Debug("Could not retrieve anything from storage")
}
return nil
return disableVMShutdown, nil
}
func (k *kataAgent) agentURL() (string, error) {
@ -241,7 +319,7 @@ func (k *kataAgent) internalConfigure(h hypervisor, id, sharePath string, builti
}
k.keepConn = c.LongLiveConn
default:
return fmt.Errorf("Invalid config type")
return vcTypes.ErrInvalidConfigType
}
}
@ -275,7 +353,7 @@ func (k *kataAgent) configure(h hypervisor, id, sharePath string, builtin bool,
}
k.vmSocket = s
default:
return fmt.Errorf("Invalid config type")
return vcTypes.ErrInvalidConfigType
}
// Neither create shared directory nor add 9p device if hypervisor
@ -702,7 +780,18 @@ func (k *kataAgent) startSandbox(sandbox *Sandbox) error {
}
_, err = k.sendReq(req)
return err
if err != nil {
return err
}
if k.dynamicTracing {
_, err = k.sendReq(&grpc.StartTracingRequest{})
if err != nil {
return err
}
}
return nil
}
func (k *kataAgent) stopSandbox(sandbox *Sandbox) error {
@ -719,6 +808,13 @@ func (k *kataAgent) stopSandbox(sandbox *Sandbox) error {
return err
}
if k.dynamicTracing {
_, err := k.sendReq(&grpc.StopTracingRequest{})
if err != nil {
return err
}
}
if err := k.proxy.stop(k.state.ProxyPid); err != nil {
return err
}
@ -1632,6 +1728,12 @@ func (k *kataAgent) installReqFunc(c *kataclient.AgentClient) {
k.reqHandlers["grpc.SetGuestDateTimeRequest"] = func(ctx context.Context, req interface{}, opts ...golangGrpc.CallOption) (interface{}, error) {
return k.client.SetGuestDateTime(ctx, req.(*grpc.SetGuestDateTimeRequest), opts...)
}
k.reqHandlers["grpc.StartTracingRequest"] = func(ctx context.Context, req interface{}, opts ...golangGrpc.CallOption) (interface{}, error) {
return k.client.StartTracing(ctx, req.(*grpc.StartTracingRequest), opts...)
}
k.reqHandlers["grpc.StopTracingRequest"] = func(ctx context.Context, req interface{}, opts ...golangGrpc.CallOption) (interface{}, error) {
return k.client.StopTracing(ctx, req.(*grpc.StopTracingRequest), opts...)
}
}
func (k *kataAgent) sendReq(request interface{}) (interface{}, error) {

View File

@ -191,14 +191,6 @@ func (p *gRPCProxy) DestroySandbox(ctx context.Context, req *pb.DestroySandboxRe
return emptyResp, nil
}
func (p *gRPCProxy) AddInterface(ctx context.Context, req *pb.AddInterfaceRequest) (*aTypes.Interface, error) {
return nil, nil
}
func (p *gRPCProxy) RemoveInterface(ctx context.Context, req *pb.RemoveInterfaceRequest) (*aTypes.Interface, error) {
return nil, nil
}
func (p *gRPCProxy) UpdateInterface(ctx context.Context, req *pb.UpdateInterfaceRequest) (*aTypes.Interface, error) {
return &aTypes.Interface{}, nil
}
@ -256,6 +248,14 @@ func (p *gRPCProxy) CopyFile(ctx context.Context, req *pb.CopyFileRequest) (*gpb
return &gpb.Empty{}, nil
}
func (p *gRPCProxy) StartTracing(ctx context.Context, req *pb.StartTracingRequest) (*gpb.Empty, error) {
return &gpb.Empty{}, nil
}
func (p *gRPCProxy) StopTracing(ctx context.Context, req *pb.StopTracingRequest) (*gpb.Empty, error) {
return &gpb.Empty{}, nil
}
func (p *gRPCProxy) MemHotplugByProbe(ctx context.Context, req *pb.MemHotplugByProbeRequest) (*gpb.Empty, error) {
return &gpb.Empty{}, nil
}
@ -934,3 +934,199 @@ func TestKataCleanupSandbox(t *testing.T) {
t.Fatalf("%s still exists\n", dir)
}
}
func TestKataAgentKernelParams(t *testing.T) {
assert := assert.New(t)
type testData struct {
debug bool
trace bool
traceMode string
traceType string
expectedParams []Param
}
debugParam := Param{Key: "agent.log", Value: "debug"}
traceIsolatedParam := Param{Key: "agent.trace", Value: "isolated"}
traceCollatedParam := Param{Key: "agent.trace", Value: "collated"}
traceFooParam := Param{Key: "agent.trace", Value: "foo"}
data := []testData{
{false, false, "", "", []Param{}},
{true, false, "", "", []Param{debugParam}},
{false, false, "foo", "", []Param{}},
{false, false, "foo", "", []Param{}},
{false, false, "", "foo", []Param{}},
{false, false, "", "foo", []Param{}},
{false, false, "foo", "foo", []Param{}},
{false, true, "foo", "foo", []Param{}},
{false, false, agentTraceModeDynamic, "", []Param{}},
{false, false, agentTraceModeStatic, "", []Param{}},
{false, false, "", agentTraceTypeIsolated, []Param{}},
{false, false, "", agentTraceTypeCollated, []Param{}},
{false, false, "foo", agentTraceTypeIsolated, []Param{}},
{false, false, "foo", agentTraceTypeCollated, []Param{}},
{false, false, agentTraceModeDynamic, agentTraceTypeIsolated, []Param{}},
{false, false, agentTraceModeDynamic, agentTraceTypeCollated, []Param{}},
{false, false, agentTraceModeStatic, agentTraceTypeCollated, []Param{}},
{false, false, agentTraceModeStatic, agentTraceTypeCollated, []Param{}},
{false, true, agentTraceModeDynamic, agentTraceTypeIsolated, []Param{}},
{false, true, agentTraceModeDynamic, agentTraceTypeCollated, []Param{}},
{true, true, agentTraceModeDynamic, agentTraceTypeCollated, []Param{debugParam}},
{false, true, "", agentTraceTypeIsolated, []Param{}},
{false, true, "", agentTraceTypeCollated, []Param{}},
{true, true, "", agentTraceTypeIsolated, []Param{debugParam}},
{true, true, "", agentTraceTypeCollated, []Param{debugParam}},
{false, true, "foo", agentTraceTypeIsolated, []Param{}},
{false, true, "foo", agentTraceTypeCollated, []Param{}},
{true, true, "foo", agentTraceTypeIsolated, []Param{debugParam}},
{true, true, "foo", agentTraceTypeCollated, []Param{debugParam}},
{false, true, agentTraceModeStatic, agentTraceTypeIsolated, []Param{traceIsolatedParam}},
{false, true, agentTraceModeStatic, agentTraceTypeCollated, []Param{traceCollatedParam}},
{true, true, agentTraceModeStatic, agentTraceTypeIsolated, []Param{traceIsolatedParam, debugParam}},
{true, true, agentTraceModeStatic, agentTraceTypeCollated, []Param{traceCollatedParam, debugParam}},
{false, true, agentTraceModeStatic, "foo", []Param{traceFooParam}},
{true, true, agentTraceModeStatic, "foo", []Param{debugParam, traceFooParam}},
}
for i, d := range data {
config := KataAgentConfig{
Debug: d.debug,
Trace: d.trace,
TraceMode: d.traceMode,
TraceType: d.traceType,
}
count := len(d.expectedParams)
params := KataAgentKernelParams(config)
if count == 0 {
assert.Emptyf(params, "test %d (%+v)", i, d)
continue
}
assert.Len(params, count)
for _, p := range d.expectedParams {
assert.Containsf(params, p, "test %d (%+v)", i, d)
}
}
}
func TestKataAgentHandleTraceSettings(t *testing.T) {
assert := assert.New(t)
type testData struct {
traceMode string
trace bool
expectDisableVMShutdown bool
expectDynamicTracing bool
}
data := []testData{
{"", false, false, false},
{"", true, false, false},
{agentTraceModeStatic, true, true, false},
{agentTraceModeDynamic, true, false, true},
}
for i, d := range data {
k := &kataAgent{}
config := KataAgentConfig{
Trace: d.trace,
TraceMode: d.traceMode,
}
disableVMShutdown := k.handleTraceSettings(config)
if d.expectDisableVMShutdown {
assert.Truef(disableVMShutdown, "test %d (%+v)", i, d)
} else {
assert.Falsef(disableVMShutdown, "test %d (%+v)", i, d)
}
if d.expectDynamicTracing {
assert.Truef(k.dynamicTracing, "test %d (%+v)", i, d)
} else {
assert.Falsef(k.dynamicTracing, "test %d (%+v)", i, d)
}
}
}
func TestKataAgentSetDefaultTraceConfigOptions(t *testing.T) {
assert := assert.New(t)
type testData struct {
traceMode string
traceType string
trace bool
expectDefaultTraceMode bool
expectDefaultTraceType bool
expectError bool
}
data := []testData{
{"", "", false, false, false, false},
{agentTraceModeDynamic, agentTraceTypeCollated, false, false, false, false},
{agentTraceModeDynamic, agentTraceTypeIsolated, false, false, false, false},
{agentTraceModeStatic, agentTraceTypeCollated, false, false, false, false},
{agentTraceModeStatic, agentTraceTypeIsolated, false, false, false, false},
{agentTraceModeDynamic, agentTraceTypeCollated, true, false, false, false},
{agentTraceModeDynamic, agentTraceTypeIsolated, true, false, false, false},
{agentTraceModeStatic, agentTraceTypeCollated, true, false, false, false},
{agentTraceModeStatic, agentTraceTypeIsolated, true, false, false, false},
{agentTraceModeDynamic, "", true, false, true, false},
{agentTraceModeDynamic, "invalid", true, false, false, true},
{agentTraceModeStatic, "", true, false, true, false},
{agentTraceModeStatic, "invalid", true, false, false, true},
{"", agentTraceTypeIsolated, true, true, false, false},
{"invalid", agentTraceTypeIsolated, true, false, false, true},
{"", agentTraceTypeCollated, true, true, false, false},
{"invalid", agentTraceTypeCollated, true, false, false, true},
{"", "", true, true, true, false},
{"invalid", "invalid", true, false, false, true},
}
for i, d := range data {
config := &KataAgentConfig{
Trace: d.trace,
TraceMode: d.traceMode,
TraceType: d.traceType,
}
err := KataAgentSetDefaultTraceConfigOptions(config)
if d.expectError {
assert.Error(err, "test %d (%+v)", i, d)
continue
} else {
assert.NoError(err, "test %d (%+v)", i, d)
}
if d.expectDefaultTraceMode {
assert.Equalf(config.TraceMode, defaultAgentTraceMode, "test %d (%+v)", i, d)
}
if d.expectDefaultTraceType {
assert.Equalf(config.TraceType, defaultAgentTraceType, "test %d (%+v)", i, d)
}
}
}

View File

@ -11,13 +11,6 @@ import (
type kataShim struct{}
// KataShimConfig is the structure providing specific configuration
// for kataShim implementation.
type KataShimConfig struct {
Path string
Debug bool
}
// start is the ccShim start implementation.
// It starts the cc-shim binary with URL and token flags provided by
// the proxy.
@ -28,7 +21,7 @@ func (s *kataShim) start(sandbox *Sandbox, params ShimParams) (int, error) {
config, ok := newShimConfig(*(sandbox.config)).(ShimConfig)
if !ok {
return -1, fmt.Errorf("Wrong shim config type, should be KataShimConfig type")
return -1, fmt.Errorf("Wrong shim config type, should be ShimConfig type")
}
if config.Path == "" {

View File

@ -27,8 +27,8 @@ func (n *noopAgent) startProxy(sandbox *Sandbox) error {
}
// init initializes the Noop agent, i.e. it does nothing.
func (n *noopAgent) init(ctx context.Context, sandbox *Sandbox, config interface{}) error {
return nil
func (n *noopAgent) init(ctx context.Context, sandbox *Sandbox, config interface{}) (bool, error) {
return false, nil
}
// createSandbox is the Noop agent sandbox creation implementation. It does nothing.

View File

@ -40,10 +40,14 @@ func TestNoopAgentInit(t *testing.T) {
n := &noopAgent{}
sandbox := &Sandbox{}
err := n.init(context.Background(), sandbox, nil)
disableVMShutdown, err := n.init(context.Background(), sandbox, nil)
if err != nil {
t.Fatal(err)
}
if disableVMShutdown != false {
t.Fatal(err)
}
}
func TestNoopAgentExec(t *testing.T) {

View File

@ -11,9 +11,10 @@ import (
// common error objects used for argument checking
var (
ErrNeedSandbox = errors.New("Sandbox must be specified")
ErrNeedSandboxID = errors.New("Sandbox ID cannot be empty")
ErrNeedContainerID = errors.New("Container ID cannot be empty")
ErrNeedState = errors.New("State cannot be empty")
ErrNoSuchContainer = errors.New("Container does not exist")
ErrNeedSandbox = errors.New("Sandbox must be specified")
ErrNeedSandboxID = errors.New("Sandbox ID cannot be empty")
ErrNeedContainerID = errors.New("Container ID cannot be empty")
ErrNeedState = errors.New("State cannot be empty")
ErrNoSuchContainer = errors.New("Container does not exist")
ErrInvalidConfigType = errors.New("Invalid config type")
)

View File

@ -186,10 +186,11 @@ type Sandbox struct {
wg *sync.WaitGroup
shmSize uint64
sharePidNs bool
stateful bool
seccompSupported bool
shmSize uint64
sharePidNs bool
stateful bool
seccompSupported bool
disableVMShutdown bool
ctx context.Context
}
@ -583,8 +584,12 @@ func newSandbox(ctx context.Context, sandboxConfig SandboxConfig, factory Factor
return nil, err
}
agentConfig := newAgentConfig(sandboxConfig.AgentType, sandboxConfig.AgentConfig)
if err = s.agent.init(ctx, s, agentConfig); err != nil {
agentConfig, err := newAgentConfig(sandboxConfig.AgentType, sandboxConfig.AgentConfig)
if err != nil {
return nil, err
}
if s.disableVMShutdown, err = s.agent.init(ctx, s, agentConfig); err != nil {
return nil, err
}
@ -1030,6 +1035,13 @@ func (s *Sandbox) stopVM() error {
s.Logger().WithError(err).WithField("sandboxid", s.id).Warning("Agent did not stop sandbox")
}
if s.disableVMShutdown {
// Do not kill the VM - allow the agent to shut it down
// (only used to support static agent tracing).
s.Logger().Info("Not stopping VM")
return nil
}
s.Logger().Info("Stopping VM")
return s.hypervisor.stopSandbox()
}

View File

@ -118,7 +118,7 @@ func TestVMConfigGrpc(t *testing.T) {
HypervisorType: QemuHypervisor,
HypervisorConfig: newQemuConfig(),
AgentType: KataContainersAgent,
AgentConfig: KataAgentConfig{false, true},
AgentConfig: KataAgentConfig{false, true, false, false, "", ""},
ProxyType: NoopProxyType,
}