diff options
author | Daniel J Walsh <dwalsh@redhat.com> | 2017-11-22 07:57:31 -0500 |
---|---|---|
committer | Atomic Bot <atomic-devel@projectatomic.io> | 2017-11-22 20:53:15 +0000 |
commit | 195d48d86d871f531d72e0669ea96d315845da35 (patch) | |
tree | 8d1aaf245b769a4f9ef666f3a9b794273c7247a0 /cmd/kpod | |
parent | c344fe61c11beaf687da284f71bde2311b91371d (diff) | |
download | podman-195d48d86d871f531d72e0669ea96d315845da35.tar.gz podman-195d48d86d871f531d72e0669ea96d315845da35.tar.bz2 podman-195d48d86d871f531d72e0669ea96d315845da35.zip |
Copy some verification code out of Docker to verify user input
Added lots of verification code to make sure resourses asociated with
containers is correct.
Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
Closes: #60
Approved by: umohnani8
Diffstat (limited to 'cmd/kpod')
-rw-r--r-- | cmd/kpod/common.go | 1 | ||||
-rw-r--r-- | cmd/kpod/create.go | 24 | ||||
-rw-r--r-- | cmd/kpod/create_cli.go | 148 | ||||
-rw-r--r-- | cmd/kpod/spec.go | 20 |
4 files changed, 174 insertions, 19 deletions
diff --git a/cmd/kpod/common.go b/cmd/kpod/common.go index d924f17a3..339f56fdd 100644 --- a/cmd/kpod/common.go +++ b/cmd/kpod/common.go @@ -326,6 +326,7 @@ var createFlags = []cli.Flag{ cli.Int64Flag{ Name: "memory-swappiness", Usage: "Tune container memory swappiness (0 to 100) (default -1)", + Value: -1, }, cli.StringFlag{ Name: "name", diff --git a/cmd/kpod/create.go b/cmd/kpod/create.go index d609d011e..9e4162993 100644 --- a/cmd/kpod/create.go +++ b/cmd/kpod/create.go @@ -35,8 +35,8 @@ var ( ) type createResourceConfig struct { - blkioDevice []string // blkio-weight-device blkioWeight uint16 // blkio-weight + blkioWeightDevice []string // blkio-weight-device cpuPeriod uint64 // cpu-period cpuQuota int64 // cpu-quota cpuRtPeriod uint64 // cpu-rt-period @@ -46,15 +46,15 @@ type createResourceConfig struct { cpusetCpus string cpusetMems string // cpuset-mems deviceReadBps []string // device-read-bps - deviceReadIops []string // device-read-iops + deviceReadIOps []string // device-read-iops deviceWriteBps []string // device-write-bps - deviceWriteIops []string // device-write-iops + deviceWriteIOps []string // device-write-iops disableOomKiller bool // oom-kill-disable kernelMemory int64 // kernel-memory memory int64 //memory memoryReservation int64 // memory-reservation memorySwap int64 //memory-swap - memorySwapiness uint64 // memory-swappiness + memorySwappiness int // memory-swappiness oomScoreAdj int //oom-score-adj pidsLimit int64 // pids-limit shmSize string @@ -373,7 +373,7 @@ func parseCreateOpts(c *cli.Context, runtime *libpod.Runtime) (*createConfig, er readOnlyRootfs: c.Bool("read-only"), resources: createResourceConfig{ blkioWeight: blkioWeight, - blkioDevice: c.StringSlice("blkio-weight-device"), + blkioWeightDevice: c.StringSlice("blkio-weight-device"), cpuShares: c.Uint64("cpu-shares"), cpuPeriod: c.Uint64("cpu-period"), cpusetCpus: c.String("cpu-period"), @@ -383,15 +383,15 @@ func parseCreateOpts(c *cli.Context, runtime *libpod.Runtime) (*createConfig, er cpuRtRuntime: c.Int64("cpu-rt-runtime"), cpus: c.String("cpus"), deviceReadBps: c.StringSlice("device-read-bps"), - deviceReadIops: c.StringSlice("device-read-iops"), + deviceReadIOps: c.StringSlice("device-read-iops"), deviceWriteBps: c.StringSlice("device-write-bps"), - deviceWriteIops: c.StringSlice("device-write-iops"), + deviceWriteIOps: c.StringSlice("device-write-iops"), disableOomKiller: c.Bool("oom-kill-disable"), shmSize: c.String("shm-size"), memory: memoryLimit, memoryReservation: memoryReservation, memorySwap: memorySwap, - memorySwapiness: c.Uint64("memory-swapiness"), + memorySwappiness: c.Int("memory-swappiness"), kernelMemory: memoryKernel, oomScoreAdj: c.Int("oom-score-adj"), @@ -418,6 +418,12 @@ func parseCreateOpts(c *cli.Context, runtime *libpod.Runtime) (*createConfig, er return nil, err } } - + warnings, err := verifyContainerResources(config, false) + if err != nil { + return nil, err + } + for _, warning := range warnings { + fmt.Fprintln(os.Stderr, warning) + } return config, nil } diff --git a/cmd/kpod/create_cli.go b/cmd/kpod/create_cli.go index 91e984785..f90d530bf 100644 --- a/cmd/kpod/create_cli.go +++ b/cmd/kpod/create_cli.go @@ -1,9 +1,17 @@ package main import ( + "fmt" "strings" + "github.com/docker/docker/pkg/sysinfo" "github.com/pkg/errors" + "github.com/sirupsen/logrus" +) + +const ( + // It's not kernel limit, we want this 4M limit to supply a reasonable functional container + linuxMinMemory = 4194304 ) func getAllLabels(labelFile, inputLabels []string) (map[string]string, error) { @@ -26,3 +34,143 @@ func convertStringSliceToMap(strSlice []string, delimiter string) (map[string]st } return sysctl, nil } + +func addWarning(warnings []string, msg string) []string { + logrus.Warn(msg) + return append(warnings, msg) +} + +func verifyContainerResources(config *createConfig, update bool) ([]string, error) { + warnings := []string{} + sysInfo := sysinfo.New(true) + + // memory subsystem checks and adjustments + if config.resources.memory != 0 && config.resources.memory < linuxMinMemory { + return warnings, fmt.Errorf("minimum memory limit allowed is 4MB") + } + if config.resources.memory > 0 && !sysInfo.MemoryLimit { + warnings = addWarning(warnings, "Your kernel does not support memory limit capabilities or the cgroup is not mounted. Limitation discarded.") + config.resources.memory = 0 + config.resources.memorySwap = -1 + } + if config.resources.memory > 0 && config.resources.memorySwap != -1 && !sysInfo.SwapLimit { + warnings = addWarning(warnings, "Your kernel does not support swap limit capabilities,or the cgroup is not mounted. Memory limited without swap.") + config.resources.memorySwap = -1 + } + if config.resources.memory > 0 && config.resources.memorySwap > 0 && config.resources.memorySwap < config.resources.memory { + return warnings, fmt.Errorf("minimum memoryswap limit should be larger than memory limit, see usage") + } + if config.resources.memory == 0 && config.resources.memorySwap > 0 && !update { + return warnings, fmt.Errorf("you should always set the Memory limit when using Memoryswap limit, see usage") + } + if config.resources.memorySwappiness != -1 { + if !sysInfo.MemorySwappiness { + msg := "Your kernel does not support memory swappiness capabilities, or the cgroup is not mounted. Memory swappiness discarded." + warnings = addWarning(warnings, msg) + config.resources.memorySwappiness = -1 + } else { + swappiness := config.resources.memorySwappiness + if swappiness < -1 || swappiness > 100 { + return warnings, fmt.Errorf("invalid value: %v, valid memory swappiness range is 0-100", swappiness) + } + } + } + if config.resources.memoryReservation > 0 && !sysInfo.MemoryReservation { + warnings = addWarning(warnings, "Your kernel does not support memory soft limit capabilities or the cgroup is not mounted. Limitation discarded.") + config.resources.memoryReservation = 0 + } + if config.resources.memoryReservation > 0 && config.resources.memoryReservation < linuxMinMemory { + return warnings, fmt.Errorf("minimum memory reservation allowed is 4MB") + } + if config.resources.memory > 0 && config.resources.memoryReservation > 0 && config.resources.memory < config.resources.memoryReservation { + return warnings, fmt.Errorf("minimum memory limit can not be less than memory reservation limit, see usage") + } + if config.resources.kernelMemory > 0 && !sysInfo.KernelMemory { + warnings = addWarning(warnings, "Your kernel does not support kernel memory limit capabilities or the cgroup is not mounted. Limitation discarded.") + config.resources.kernelMemory = 0 + } + if config.resources.kernelMemory > 0 && config.resources.kernelMemory < linuxMinMemory { + return warnings, fmt.Errorf("minimum kernel memory limit allowed is 4MB") + } + if config.resources.disableOomKiller == true && !sysInfo.OomKillDisable { + // only produce warnings if the setting wasn't to *disable* the OOM Kill; no point + // warning the caller if they already wanted the feature to be off + warnings = addWarning(warnings, "Your kernel does not support OomKillDisable. OomKillDisable discarded.") + config.resources.disableOomKiller = false + } + + if config.resources.pidsLimit != 0 && !sysInfo.PidsLimit { + warnings = addWarning(warnings, "Your kernel does not support pids limit capabilities or the cgroup is not mounted. PIDs limit discarded.") + config.resources.pidsLimit = 0 + } + + if config.resources.cpuShares > 0 && !sysInfo.CPUShares { + warnings = addWarning(warnings, "Your kernel does not support CPU shares or the cgroup is not mounted. Shares discarded.") + config.resources.cpuShares = 0 + } + if config.resources.cpuPeriod > 0 && !sysInfo.CPUCfsPeriod { + warnings = addWarning(warnings, "Your kernel does not support CPU cfs period or the cgroup is not mounted. Period discarded.") + config.resources.cpuPeriod = 0 + } + if config.resources.cpuPeriod != 0 && (config.resources.cpuPeriod < 1000 || config.resources.cpuPeriod > 1000000) { + return warnings, fmt.Errorf("CPU cfs period can not be less than 1ms (i.e. 1000) or larger than 1s (i.e. 1000000)") + } + if config.resources.cpuQuota > 0 && !sysInfo.CPUCfsQuota { + warnings = addWarning(warnings, "Your kernel does not support CPU cfs quota or the cgroup is not mounted. Quota discarded.") + config.resources.cpuQuota = 0 + } + if config.resources.cpuQuota > 0 && config.resources.cpuQuota < 1000 { + return warnings, fmt.Errorf("CPU cfs quota can not be less than 1ms (i.e. 1000)") + } + // cpuset subsystem checks and adjustments + if (config.resources.cpusetCpus != "" || config.resources.cpusetMems != "") && !sysInfo.Cpuset { + warnings = addWarning(warnings, "Your kernel does not support cpuset or the cgroup is not mounted. Cpuset discarded.") + config.resources.cpusetCpus = "" + config.resources.cpusetMems = "" + } + cpusAvailable, err := sysInfo.IsCpusetCpusAvailable(config.resources.cpusetCpus) + if err != nil { + return warnings, fmt.Errorf("invalid value %s for cpuset cpus", config.resources.cpusetCpus) + } + if !cpusAvailable { + return warnings, fmt.Errorf("requested CPUs are not available - requested %s, available: %s", config.resources.cpusetCpus, sysInfo.Cpus) + } + memsAvailable, err := sysInfo.IsCpusetMemsAvailable(config.resources.cpusetMems) + if err != nil { + return warnings, fmt.Errorf("invalid value %s for cpuset mems", config.resources.cpusetMems) + } + if !memsAvailable { + return warnings, fmt.Errorf("requested memory nodes are not available - requested %s, available: %s", config.resources.cpusetMems, sysInfo.Mems) + } + + // blkio subsystem checks and adjustments + if config.resources.blkioWeight > 0 && !sysInfo.BlkioWeight { + warnings = addWarning(warnings, "Your kernel does not support Block I/O weight or the cgroup is not mounted. Weight discarded.") + config.resources.blkioWeight = 0 + } + if config.resources.blkioWeight > 0 && (config.resources.blkioWeight < 10 || config.resources.blkioWeight > 1000) { + return warnings, fmt.Errorf("range of blkio weight is from 10 to 1000") + } + if len(config.resources.blkioWeightDevice) > 0 && !sysInfo.BlkioWeightDevice { + warnings = addWarning(warnings, "Your kernel does not support Block I/O weight_device or the cgroup is not mounted. Weight-device discarded.") + config.resources.blkioWeightDevice = []string{} + } + if len(config.resources.deviceReadBps) > 0 && !sysInfo.BlkioReadBpsDevice { + warnings = addWarning(warnings, "Your kernel does not support BPS Block I/O read limit or the cgroup is not mounted. Block I/O BPS read limit discarded") + config.resources.deviceReadBps = []string{} + } + if len(config.resources.deviceWriteBps) > 0 && !sysInfo.BlkioWriteBpsDevice { + warnings = addWarning(warnings, "Your kernel does not support BPS Block I/O write limit or the cgroup is not mounted. Block I/O BPS write limit discarded.") + config.resources.deviceWriteBps = []string{} + } + if len(config.resources.deviceReadIOps) > 0 && !sysInfo.BlkioReadIOpsDevice { + warnings = addWarning(warnings, "Your kernel does not support IOPS Block read limit or the cgroup is not mounted. Block I/O IOPS read limit discarded.") + config.resources.deviceReadIOps = []string{} + } + if len(config.resources.deviceWriteIOps) > 0 && !sysInfo.BlkioWriteIOpsDevice { + warnings = addWarning(warnings, "Your kernel does not support IOPS Block I/O write limit or the cgroup is not mounted. Block I/O IOPS write limit discarded.") + config.resources.deviceWriteIOps = []string{} + } + + return warnings, nil +} diff --git a/cmd/kpod/spec.go b/cmd/kpod/spec.go index 752827669..0a99d792b 100644 --- a/cmd/kpod/spec.go +++ b/cmd/kpod/spec.go @@ -142,8 +142,8 @@ func createConfigToOCISpec(config *createConfig) (*spec.Spec, error) { if config.resources.kernelMemory != 0 { g.SetLinuxResourcesMemoryKernel(config.resources.kernelMemory) } - if config.resources.memorySwapiness != 0 { - g.SetLinuxResourcesMemorySwappiness(config.resources.memorySwapiness) + if config.resources.memorySwappiness != -1 { + g.SetLinuxResourcesMemorySwappiness(uint64(config.resources.memorySwappiness)) } g.SetLinuxResourcesMemoryDisableOOMKiller(config.resources.disableOomKiller) g.SetProcessOOMScoreAdj(config.resources.oomScoreAdj) @@ -263,9 +263,9 @@ func createConfigToOCISpec(config *createConfig) (*spec.Spec, error) { func (c *createConfig) CreateBlockIO() (spec.LinuxBlockIO, error) { bio := spec.LinuxBlockIO{} bio.Weight = &c.resources.blkioWeight - if len(c.resources.blkioDevice) > 0 { + if len(c.resources.blkioWeightDevice) > 0 { var lwds []spec.LinuxWeightDevice - for _, i := range c.resources.blkioDevice { + for _, i := range c.resources.blkioWeightDevice { wd, err := validateweightDevice(i) if err != nil { return bio, errors.Wrapf(err, "invalid values for blkio-weight-device") @@ -293,19 +293,19 @@ func (c *createConfig) CreateBlockIO() (spec.LinuxBlockIO, error) { } bio.ThrottleWriteBpsDevice = writeBpds } - if len(c.resources.deviceReadIops) > 0 { - readIops, err := makeThrottleArray(c.resources.deviceReadIops) + if len(c.resources.deviceReadIOps) > 0 { + readIOps, err := makeThrottleArray(c.resources.deviceReadIOps) if err != nil { return bio, err } - bio.ThrottleReadIOPSDevice = readIops + bio.ThrottleReadIOPSDevice = readIOps } - if len(c.resources.deviceWriteIops) > 0 { - writeIops, err := makeThrottleArray(c.resources.deviceWriteIops) + if len(c.resources.deviceWriteIOps) > 0 { + writeIOps, err := makeThrottleArray(c.resources.deviceWriteIOps) if err != nil { return bio, err } - bio.ThrottleWriteIOPSDevice = writeIops + bio.ThrottleWriteIOPSDevice = writeIOps } return bio, nil |