From 528772f9f3a10b944d052197fa7b86aa22fb5e59 Mon Sep 17 00:00:00 2001 From: WANG Chao Date: Fri, 28 Jul 2017 14:48:21 +0800 Subject: [PATCH] config: support kernel parameters Add support to pass extra kernel parameters in configuration or directly configured on build. This information can be retrieved from cc-env. The story behind this feature is, I have trouble running centos:6 /bin/bash and it turns out guest kernel is using vsyscall=none which breaks old libc. Fixes: #368 Signed-off-by: WANG Chao --- Makefile | 5 +++++ cc-env.go | 20 +++++++++++++++----- cc-env_test.go | 24 ++++++++++++++++-------- config.go | 13 ++++++++++++- config/configuration.toml.in | 4 ++++ config_test.go | 12 ++++++++++-- 6 files changed, 62 insertions(+), 16 deletions(-) diff --git a/Makefile b/Makefile index 9fb0e719..f2ddb694 100644 --- a/Makefile +++ b/Makefile @@ -71,6 +71,8 @@ PKGLIBEXECDIR := $(LIBEXECDIR)/$(CCDIR) KERNELPATH := $(PKGDATADIR)/vmlinux.container IMAGEPATH := $(PKGDATADIR)/clear-containers.img +KERNELPARAMS := + # The CentOS/RHEL hypervisor binary is not called qemu-lite ifeq (,$(filter-out centos rhel,$(distro))) QEMUCMD := qemu-system-x86_64 @@ -131,6 +133,7 @@ USER_VARS += GLOBALLOGPATH USER_VARS += IMAGEPATH USER_VARS += MACHINETYPE USER_VARS += KERNELPATH +USER_VARS += KERNELPARAMS USER_VARS += LIBEXECDIR USER_VARS += LOCALSTATEDIR USER_VARS += PAUSEBINRELPATH @@ -184,6 +187,7 @@ const version = "$(VERSION)" const defaultHypervisorPath = "$(QEMUPATH)" const defaultImagePath = "$(IMAGEPATH)" const defaultKernelPath = "$(KERNELPATH)" +const defaultKernelParams = "$(KERNELPARAMS)" const defaultMachineType = "$(MACHINETYPE)" const defaultPauseRootPath = "$(PAUSEROOTPATH)" const defaultProxyURL = "$(PROXYURL)" @@ -235,6 +239,7 @@ $(CONFIG): $(CONFIG_IN) -e "s|@CONFIG_IN@|$(CONFIG_IN)|g" \ -e "s|@IMAGEPATH@|$(IMAGEPATH)|g" \ -e "s|@KERNELPATH@|$(KERNELPATH)|g" \ + -e "s|@KERNELPARAMS@|$(KERNELPARAMS)|g" \ -e "s|@LOCALSTATEDIR@|$(LOCALSTATEDIR)|g" \ -e "s|@PAUSEROOTPATH@|$(PAUSEROOTPATH)|g" \ -e "s|@PKGLIBEXECDIR@|$(PKGLIBEXECDIR)|g" \ diff --git a/cc-env.go b/cc-env.go index b34694b7..313f6bab 100644 --- a/cc-env.go +++ b/cc-env.go @@ -18,6 +18,7 @@ import ( "errors" "os" "path/filepath" + "strings" "github.com/BurntSushi/toml" vc "github.com/containers/virtcontainers" @@ -30,7 +31,7 @@ import ( // // XXX: Increment for every change to the output format // (meaning any change to the EnvInfo type). -const formatVersion = "1.0.1" +const formatVersion = "1.0.2" // defaultOutputFile is the default output file to write the gathered // information to. @@ -48,6 +49,12 @@ type PathInfo struct { Resolved string } +// KernelInfo stores kernel details +type KernelInfo struct { + Location PathInfo + Parameters string +} + // CPUInfo stores host CPU details type CPUInfo struct { Vendor string @@ -124,7 +131,7 @@ type EnvInfo struct { Runtime RuntimeInfo Hypervisor HypervisorInfo Image PathInfo - Kernel PathInfo + Kernel KernelInfo Proxy ProxyInfo Shim ShimInfo Agent AgentInfo @@ -325,9 +332,12 @@ func getEnvInfo(configFile, logfilePath string, config oci.RuntimeConfig) (env E Resolved: resolvedHypervisor.ImagePath, } - kernel := PathInfo{ - Path: config.HypervisorConfig.KernelPath, - Resolved: resolvedHypervisor.KernelPath, + kernel := KernelInfo{ + Location: PathInfo{ + Path: config.HypervisorConfig.KernelPath, + Resolved: resolvedHypervisor.KernelPath, + }, + Parameters: strings.Join(vc.SerializeParams(config.HypervisorConfig.KernelParams, "="), " "), } env = EnvInfo{ diff --git a/cc-env_test.go b/cc-env_test.go index 800c3fe7..a8b50e4b 100644 --- a/cc-env_test.go +++ b/cc-env_test.go @@ -42,6 +42,7 @@ func makeRuntimeConfig(prefixDir string) (configFile string, config oci.RuntimeC hypervisorPath := filepath.Join(prefixDir, "hypervisor") kernelPath := filepath.Join(prefixDir, "kernel") imagePath := filepath.Join(prefixDir, "image") + kernelParams := "foo=bar xyz" machineType := "machineType" shimPath := filepath.Join(prefixDir, "cc-shim") proxyPath := filepath.Join(prefixDir, "cc-proxy") @@ -103,6 +104,7 @@ func makeRuntimeConfig(prefixDir string) (configFile string, config oci.RuntimeC hypervisorPath, kernelPath, imagePath, + kernelParams, machineType, shimPath, agentPauseRoot, @@ -261,10 +263,13 @@ func getExpectedImage(config oci.RuntimeConfig) PathInfo { } } -func getExpectedKernel(config oci.RuntimeConfig) PathInfo { - return PathInfo{ - Path: config.HypervisorConfig.KernelPath, - Resolved: config.HypervisorConfig.KernelPath, +func getExpectedKernel(config oci.RuntimeConfig) KernelInfo { + return KernelInfo{ + Location: PathInfo{ + Path: config.HypervisorConfig.KernelPath, + Resolved: config.HypervisorConfig.KernelPath, + }, + Parameters: strings.Join(vc.SerializeParams(config.HypervisorConfig.KernelParams, "="), " "), } } @@ -556,7 +561,7 @@ func TestCCEnvGetEnvInfoNoKernel(t *testing.T) { expected, err := getExpectedSettings(config, tmpdir, configFile, logFile) assert.NoError(t, err) - err = os.Remove(expected.Kernel.Resolved) + err = os.Remove(expected.Kernel.Location.Resolved) assert.NoError(t, err) _, err = getEnvInfo(configFile, logFile, config) @@ -910,9 +915,12 @@ func testCCEnvShowSettings(t *testing.T, tmpdir string, tmpfile *os.File) error Resolved: "/resolved/image/path", } - ccKernel := PathInfo{ - Path: "/kernel/path", - Resolved: "/resolved/kernel/path", + ccKernel := KernelInfo{ + Location: PathInfo{ + Path: "/kernel/path", + Resolved: "/resolved/kernel/path", + }, + Parameters: "foo=bar xyz", } ccProxy := ProxyInfo{ diff --git a/config.go b/config.go index 94f4810d..99e0c786 100644 --- a/config.go +++ b/config.go @@ -21,6 +21,7 @@ import ( "os" "path/filepath" goruntime "runtime" + "strings" "github.com/BurntSushi/toml" vc "github.com/containers/virtcontainers" @@ -76,6 +77,7 @@ type hypervisor struct { Path string `toml:"path"` Kernel string `toml:"kernel"` Image string `toml:"image"` + KernelParams string `toml:"kernel_params"` MachineType string `toml:"machine_type"` DefaultVCPUs int32 `toml:"default_vcpus"` DefaultMemSz uint32 `toml:"default_memory"` @@ -122,6 +124,14 @@ func (h hypervisor) image() string { return h.Image } +func (h hypervisor) kernelParams() string { + if h.KernelParams == "" { + return defaultKernelParams + } + + return h.KernelParams +} + func (h hypervisor) machineType() string { if h.MachineType == "" { return defaultMachineType @@ -180,6 +190,7 @@ func newQemuHypervisorConfig(h hypervisor) (vc.HypervisorConfig, error) { hypervisor := h.path() kernel := h.kernel() image := h.image() + kernelParams := h.kernelParams() machineType := h.machineType() for _, file := range []string{hypervisor, kernel, image} { @@ -188,11 +199,11 @@ func newQemuHypervisorConfig(h hypervisor) (vc.HypervisorConfig, error) { fmt.Errorf("File does not exist: %v", file) } } - return vc.HypervisorConfig{ HypervisorPath: hypervisor, KernelPath: kernel, ImagePath: image, + KernelParams: vc.DeserializeParams(strings.Fields(kernelParams)), HypervisorMachineType: machineType, DefaultVCPUs: h.defaultVCPUs(), DefaultMemSz: h.defaultMemSz(), diff --git a/config/configuration.toml.in b/config/configuration.toml.in index 131e2026..6b9ee5c1 100644 --- a/config/configuration.toml.in +++ b/config/configuration.toml.in @@ -5,6 +5,10 @@ path = "@QEMUPATH@" kernel = "@KERNELPATH@" image = "@IMAGEPATH@" machine_type = "@MACHINETYPE@" +# Optional space-separated list of options to pass to the guest kernel. +# For example, use `kernel_params = "vsyscall=emulate"` if you are having +# trouble running pre-2.15 glibc +kernel_params = "@KERNELPARAMS@" # Default number of vCPUs per POD/VM: # unspecified or 0 --> will be set to @DEFVCPUS@ # < 0 --> will be set to the actual number of physical cores diff --git a/config_test.go b/config_test.go index ddcb9ab8..db7bd9f7 100644 --- a/config_test.go +++ b/config_test.go @@ -43,13 +43,14 @@ type testRuntimeConfig struct { LogPath string } -func makeRuntimeConfigFileData(hypervisor, hypervisorPath, kernelPath, imagePath, machineType, shimPath, agentPauseRootPath, proxyURL, logPath string, disableBlock bool) string { +func makeRuntimeConfigFileData(hypervisor, hypervisorPath, kernelPath, imagePath, kernelParams, machineType, shimPath, agentPauseRootPath, proxyURL, logPath string, disableBlock bool) string { return ` # Clear Containers runtime configuration file [hypervisor.` + hypervisor + `] path = "` + hypervisorPath + `" kernel = "` + kernelPath + `" + kernel_params = "` + kernelParams + `" image = "` + imagePath + `" machine_type = "` + machineType + `" default_vcpus = ` + strconv.FormatUint(uint64(defaultVCPUCount), 10) + ` @@ -94,6 +95,7 @@ func createAllRuntimeConfigFiles(dir, hypervisor string) (config testRuntimeConf hypervisorPath := path.Join(dir, "hypervisor") kernelPath := path.Join(dir, "kernel") + kernelParams := "foo=bar xyz" imagePath := path.Join(dir, "image") shimPath := path.Join(dir, "shim") agentPauseRootPath := path.Join(dir, "agentPauseRoot") @@ -104,7 +106,7 @@ func createAllRuntimeConfigFiles(dir, hypervisor string) (config testRuntimeConf machineType := "machineType" disableBlockDevice := true - runtimeConfigFileData := makeRuntimeConfigFileData(hypervisor, hypervisorPath, kernelPath, imagePath, machineType, shimPath, agentPauseRootPath, proxyURL, logPath, disableBlockDevice) + runtimeConfigFileData := makeRuntimeConfigFileData(hypervisor, hypervisorPath, kernelPath, imagePath, kernelParams, machineType, shimPath, agentPauseRootPath, proxyURL, logPath, disableBlockDevice) configPath := path.Join(dir, "runtime.toml") err = createConfig(configPath, runtimeConfigFileData) @@ -139,6 +141,7 @@ func createAllRuntimeConfigFiles(dir, hypervisor string) (config testRuntimeConf HypervisorPath: hypervisorPath, KernelPath: kernelPath, ImagePath: imagePath, + KernelParams: vc.DeserializeParams(strings.Fields(kernelParams)), HypervisorMachineType: machineType, DefaultVCPUs: defaultVCPUCount, DefaultMemSz: defaultMemSize, @@ -798,6 +801,7 @@ func TestHypervisorDefaults(t *testing.T) { assert.Equal(t, h.path(), defaultHypervisorPath, "default hypervisor path wrong") assert.Equal(t, h.kernel(), defaultKernelPath, "default hypervisor kernel wrong") assert.Equal(t, h.image(), defaultImagePath, "default hypervisor image wrong") + assert.Equal(t, h.kernelParams(), defaultKernelParams, "default hypervisor image wrong") assert.Equal(t, h.machineType(), defaultMachineType, "default hypervisor machine type wrong") assert.Equal(t, h.defaultVCPUs(), defaultVCPUCount, "default vCPU number is wrong") assert.Equal(t, h.defaultMemSz(), defaultMemSize, "default memory size is wrong") @@ -810,6 +814,10 @@ func TestHypervisorDefaults(t *testing.T) { h.Kernel = kernel assert.Equal(t, h.kernel(), kernel, "custom hypervisor kernel wrong") + kernelParams := "foo=bar xyz" + h.KernelParams = kernelParams + assert.Equal(t, h.kernelParams(), kernelParams, "custom hypervisor kernel parameterms wrong") + image := "foo" h.Image = image assert.Equal(t, h.image(), image, "custom hypervisor image wrong")