diff --git a/Makefile b/Makefile index ad79f31dd6..4f419b9638 100644 --- a/Makefile +++ b/Makefile @@ -328,6 +328,7 @@ const defaultDisableNestingChecks bool = $(DEFDISABLENESTINGCHECKS) const defaultMsize9p uint32 = $(DEFMSIZE9P) const defaultHotplugVFIOOnRootBus bool = $(DEFHOTPLUGVFIOONROOTBUS) const defaultEntropySource = "$(DEFENTROPYSOURCE)" +const defaultGuestHookPath string = "" // Default config file used by stateless systems. var defaultRuntimeConfiguration = "$(CONFIG_PATH)" diff --git a/cli/config.go b/cli/config.go index bc3215909f..bf44f7c94a 100644 --- a/cli/config.go +++ b/cli/config.go @@ -98,6 +98,7 @@ type hypervisor struct { UseVSock bool `toml:"use_vsock"` HotplugVFIOOnRootBus bool `toml:"hotplug_vfio_on_root_bus"` DisableVhostNet bool `toml:"disable_vhost_net"` + GuestHookPath string `toml:"guest_hook_path"` } type proxy struct { @@ -302,6 +303,13 @@ func (h hypervisor) useVSock() bool { return h.UseVSock } +func (h hypervisor) guestHookPath() string { + if h.GuestHookPath == "" { + return defaultGuestHookPath + } + return h.GuestHookPath +} + func (p proxy) path() string { if p.Path == "" { return defaultProxyPath @@ -426,6 +434,7 @@ func newQemuHypervisorConfig(h hypervisor) (vc.HypervisorConfig, error) { UseVSock: useVSock, HotplugVFIOOnRootBus: h.HotplugVFIOOnRootBus, DisableVhostNet: h.DisableVhostNet, + GuestHookPath: h.guestHookPath(), }, nil } @@ -547,6 +556,7 @@ func loadConfiguration(configPath string, ignoreLogging bool) (resolvedConfigPat EnableIOThreads: defaultEnableIOThreads, Msize9p: defaultMsize9p, HotplugVFIOOnRootBus: defaultHotplugVFIOOnRootBus, + GuestHookPath: defaultGuestHookPath, } err = config.InterNetworkModel.SetModel(defaultInterNetworkingModel) diff --git a/cli/config/configuration.toml.in b/cli/config/configuration.toml.in index 154ba77c58..831f94cbb7 100644 --- a/cli/config/configuration.toml.in +++ b/cli/config/configuration.toml.in @@ -167,6 +167,23 @@ enable_iothreads = @DEFENABLEIOTHREADS@ # all practical purposes. #entropy_source= "@DEFENTROPYSOURCE@" +# Path to OCI hook binaries in the *guest rootfs*. +# This does not affect host-side hooks which must instead be added to +# the OCI spec passed to the runtime. +# +# You can create a rootfs with hooks by customizing the osbuilder scripts: +# https://github.com/kata-containers/osbuilder +# +# Hooks must be stored in a subdirectory of guest_hook_path according to their +# hook type, i.e. "guest_hook_path/{prestart,postart,poststop}". +# The agent will scan these directories for executable files and add them, in +# lexicographical order, to the lifecycle of the guest container. +# Hooks are executed in the runtime namespace of the guest. See the official documentation: +# https://github.com/opencontainers/runtime-spec/blob/v1.0.1/config.md#posix-platform-hooks +# Warnings will be logged if any error is encountered will scanning for hooks, +# but it will not abort container execution. +#guest_hook_path = "/usr/share/oci/hooks" + [factory] # VM templating support. Once enabled, new VMs are created from template # using vm cloning. They will share the same initial kernel, initramfs and diff --git a/cli/config_test.go b/cli/config_test.go index d3e7c9fbc4..2a08f01dd1 100644 --- a/cli/config_test.go +++ b/cli/config_test.go @@ -61,6 +61,7 @@ func makeRuntimeConfigFileData(hypervisor, hypervisorPath, kernelPath, imagePath 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) + ` @@ -161,6 +162,7 @@ func createAllRuntimeConfigFiles(dir, hypervisor string) (config testRuntimeConf Msize9p: defaultMsize9p, MemSlots: defaultMemSlots, EntropySource: defaultEntropySource, + GuestHookPath: defaultGuestHookPath, } agentConfig := vc.KataAgentConfig{} @@ -596,6 +598,7 @@ func TestMinimalRuntimeConfig(t *testing.T) { Mlock: !defaultEnableSwap, BlockDeviceDriver: defaultBlockDeviceDriver, Msize9p: defaultMsize9p, + GuestHookPath: defaultGuestHookPath, } expectedAgentConfig := vc.KataAgentConfig{} @@ -1078,6 +1081,21 @@ func TestHypervisorDefaultsImage(t *testing.T) { assert.Equal(p, "") } +func TestHypervisorDefaultsGuestHookPath(t *testing.T) { + assert := assert.New(t) + + h := hypervisor{} + guestHookPath := h.guestHookPath() + assert.Equal(guestHookPath, defaultGuestHookPath, "default guest hook path wrong") + + testGuestHookPath := "/test/guest/hook/path" + h = hypervisor{ + GuestHookPath: testGuestHookPath, + } + guestHookPath = h.guestHookPath() + assert.Equal(guestHookPath, testGuestHookPath, "custom guest hook path wrong") +} + func TestProxyDefaults(t *testing.T) { p := proxy{} diff --git a/virtcontainers/hypervisor.go b/virtcontainers/hypervisor.go index d94591ff7f..1d69eee121 100644 --- a/virtcontainers/hypervisor.go +++ b/virtcontainers/hypervisor.go @@ -250,6 +250,9 @@ type HypervisorConfig struct { // DisableVhostNet is used to indicate if host supports vhost_net DisableVhostNet bool + + // GuestHookPath is the path within the VM that will be used for 'drop-in' hooks + GuestHookPath string } func (conf *HypervisorConfig) checkTemplateConfig() error { diff --git a/virtcontainers/kata_agent.go b/virtcontainers/kata_agent.go index 4a7dbaf073..8cba7efa58 100644 --- a/virtcontainers/kata_agent.go +++ b/virtcontainers/kata_agent.go @@ -631,10 +631,11 @@ func (k *kataAgent) startSandbox(sandbox *Sandbox) error { } req := &grpc.CreateSandboxRequest{ - Hostname: hostname, - Storages: storages, - SandboxPidns: sandbox.sharePidNs, - SandboxId: sandbox.id, + Hostname: hostname, + Storages: storages, + SandboxPidns: sandbox.sharePidNs, + SandboxId: sandbox.id, + GuestHookPath: sandbox.config.HypervisorConfig.GuestHookPath, } _, err = k.sendReq(req)