github.com/containers/libpod@v1.9.4-0.20220419124438-4284fd425507/cmd/podman/shared/create_cli.go (about) 1 package shared 2 3 import ( 4 "fmt" 5 "strings" 6 7 "github.com/containers/libpod/pkg/cgroups" 8 cc "github.com/containers/libpod/pkg/spec" 9 "github.com/containers/libpod/pkg/sysinfo" 10 "github.com/pkg/errors" 11 "github.com/sirupsen/logrus" 12 ) 13 14 // validateSysctl validates a sysctl and returns it. 15 func validateSysctl(strSlice []string) (map[string]string, error) { 16 sysctl := make(map[string]string) 17 validSysctlMap := map[string]bool{ 18 "kernel.msgmax": true, 19 "kernel.msgmnb": true, 20 "kernel.msgmni": true, 21 "kernel.sem": true, 22 "kernel.shmall": true, 23 "kernel.shmmax": true, 24 "kernel.shmmni": true, 25 "kernel.shm_rmid_forced": true, 26 } 27 validSysctlPrefixes := []string{ 28 "net.", 29 "fs.mqueue.", 30 } 31 32 for _, val := range strSlice { 33 foundMatch := false 34 arr := strings.Split(val, "=") 35 if len(arr) < 2 { 36 return nil, errors.Errorf("%s is invalid, sysctl values must be in the form of KEY=VALUE", val) 37 } 38 if validSysctlMap[arr[0]] { 39 sysctl[arr[0]] = arr[1] 40 continue 41 } 42 43 for _, prefix := range validSysctlPrefixes { 44 if strings.HasPrefix(arr[0], prefix) { 45 sysctl[arr[0]] = arr[1] 46 foundMatch = true 47 break 48 } 49 } 50 if !foundMatch { 51 return nil, errors.Errorf("sysctl '%s' is not whitelisted", arr[0]) 52 } 53 } 54 return sysctl, nil 55 } 56 57 func addWarning(warnings []string, msg string) []string { 58 logrus.Warn(msg) 59 return append(warnings, msg) 60 } 61 62 func verifyContainerResources(config *cc.CreateConfig, update bool) ([]string, error) { 63 warnings := []string{} 64 65 cgroup2, err := cgroups.IsCgroup2UnifiedMode() 66 if err != nil || cgroup2 { 67 return warnings, err 68 } 69 70 sysInfo := sysinfo.New(true) 71 72 // memory subsystem checks and adjustments 73 if config.Resources.Memory > 0 && !sysInfo.MemoryLimit { 74 warnings = addWarning(warnings, "Your kernel does not support memory limit capabilities or the cgroup is not mounted. Limitation discarded.") 75 config.Resources.Memory = 0 76 config.Resources.MemorySwap = -1 77 } 78 if config.Resources.Memory > 0 && config.Resources.MemorySwap != -1 && !sysInfo.SwapLimit { 79 warnings = addWarning(warnings, "Your kernel does not support swap limit capabilities,or the cgroup is not mounted. Memory limited without swap.") 80 config.Resources.MemorySwap = -1 81 } 82 if config.Resources.Memory > 0 && config.Resources.MemorySwap > 0 && config.Resources.MemorySwap < config.Resources.Memory { 83 return warnings, fmt.Errorf("minimum memoryswap limit should be larger than memory limit, see usage") 84 } 85 if config.Resources.Memory == 0 && config.Resources.MemorySwap > 0 && !update { 86 return warnings, fmt.Errorf("you should always set the memory limit when using memoryswap limit, see usage") 87 } 88 if config.Resources.MemorySwappiness != -1 { 89 if !sysInfo.MemorySwappiness { 90 msg := "Your kernel does not support memory swappiness capabilities, or the cgroup is not mounted. Memory swappiness discarded." 91 warnings = addWarning(warnings, msg) 92 config.Resources.MemorySwappiness = -1 93 } else { 94 swappiness := config.Resources.MemorySwappiness 95 if swappiness < -1 || swappiness > 100 { 96 return warnings, fmt.Errorf("invalid value: %v, valid memory swappiness range is 0-100", swappiness) 97 } 98 } 99 } 100 if config.Resources.MemoryReservation > 0 && !sysInfo.MemoryReservation { 101 warnings = addWarning(warnings, "Your kernel does not support memory soft limit capabilities or the cgroup is not mounted. Limitation discarded.") 102 config.Resources.MemoryReservation = 0 103 } 104 if config.Resources.Memory > 0 && config.Resources.MemoryReservation > 0 && config.Resources.Memory < config.Resources.MemoryReservation { 105 return warnings, fmt.Errorf("minimum memory limit cannot be less than memory reservation limit, see usage") 106 } 107 if config.Resources.KernelMemory > 0 && !sysInfo.KernelMemory { 108 warnings = addWarning(warnings, "Your kernel does not support kernel memory limit capabilities or the cgroup is not mounted. Limitation discarded.") 109 config.Resources.KernelMemory = 0 110 } 111 if config.Resources.DisableOomKiller && !sysInfo.OomKillDisable { 112 // only produce warnings if the setting wasn't to *disable* the OOM Kill; no point 113 // warning the caller if they already wanted the feature to be off 114 warnings = addWarning(warnings, "Your kernel does not support OomKillDisable. OomKillDisable discarded.") 115 config.Resources.DisableOomKiller = false 116 } 117 118 if config.Resources.PidsLimit != 0 && !sysInfo.PidsLimit { 119 warnings = addWarning(warnings, "Your kernel does not support pids limit capabilities or the cgroup is not mounted. PIDs limit discarded.") 120 config.Resources.PidsLimit = 0 121 } 122 123 if config.Resources.CPUShares > 0 && !sysInfo.CPUShares { 124 warnings = addWarning(warnings, "Your kernel does not support CPU shares or the cgroup is not mounted. Shares discarded.") 125 config.Resources.CPUShares = 0 126 } 127 if config.Resources.CPUPeriod > 0 && !sysInfo.CPUCfsPeriod { 128 warnings = addWarning(warnings, "Your kernel does not support CPU cfs period or the cgroup is not mounted. Period discarded.") 129 config.Resources.CPUPeriod = 0 130 } 131 if config.Resources.CPUPeriod != 0 && (config.Resources.CPUPeriod < 1000 || config.Resources.CPUPeriod > 1000000) { 132 return warnings, fmt.Errorf("CPU cfs period cannot be less than 1ms (i.e. 1000) or larger than 1s (i.e. 1000000)") 133 } 134 if config.Resources.CPUQuota > 0 && !sysInfo.CPUCfsQuota { 135 warnings = addWarning(warnings, "Your kernel does not support CPU cfs quota or the cgroup is not mounted. Quota discarded.") 136 config.Resources.CPUQuota = 0 137 } 138 if config.Resources.CPUQuota > 0 && config.Resources.CPUQuota < 1000 { 139 return warnings, fmt.Errorf("CPU cfs quota cannot be less than 1ms (i.e. 1000)") 140 } 141 // cpuset subsystem checks and adjustments 142 if (config.Resources.CPUsetCPUs != "" || config.Resources.CPUsetMems != "") && !sysInfo.Cpuset { 143 warnings = addWarning(warnings, "Your kernel does not support cpuset or the cgroup is not mounted. CPUset discarded.") 144 config.Resources.CPUsetCPUs = "" 145 config.Resources.CPUsetMems = "" 146 } 147 cpusAvailable, err := sysInfo.IsCpusetCpusAvailable(config.Resources.CPUsetCPUs) 148 if err != nil { 149 return warnings, fmt.Errorf("invalid value %s for cpuset cpus", config.Resources.CPUsetCPUs) 150 } 151 if !cpusAvailable { 152 return warnings, fmt.Errorf("requested CPUs are not available - requested %s, available: %s", config.Resources.CPUsetCPUs, sysInfo.Cpus) 153 } 154 memsAvailable, err := sysInfo.IsCpusetMemsAvailable(config.Resources.CPUsetMems) 155 if err != nil { 156 return warnings, fmt.Errorf("invalid value %s for cpuset mems", config.Resources.CPUsetMems) 157 } 158 if !memsAvailable { 159 return warnings, fmt.Errorf("requested memory nodes are not available - requested %s, available: %s", config.Resources.CPUsetMems, sysInfo.Mems) 160 } 161 162 // blkio subsystem checks and adjustments 163 if config.Resources.BlkioWeight > 0 && !sysInfo.BlkioWeight { 164 warnings = addWarning(warnings, "Your kernel does not support Block I/O weight or the cgroup is not mounted. Weight discarded.") 165 config.Resources.BlkioWeight = 0 166 } 167 if config.Resources.BlkioWeight > 0 && (config.Resources.BlkioWeight < 10 || config.Resources.BlkioWeight > 1000) { 168 return warnings, fmt.Errorf("range of blkio weight is from 10 to 1000") 169 } 170 if len(config.Resources.BlkioWeightDevice) > 0 && !sysInfo.BlkioWeightDevice { 171 warnings = addWarning(warnings, "Your kernel does not support Block I/O weight_device or the cgroup is not mounted. Weight-device discarded.") 172 config.Resources.BlkioWeightDevice = []string{} 173 } 174 if len(config.Resources.DeviceReadBps) > 0 && !sysInfo.BlkioReadBpsDevice { 175 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") 176 config.Resources.DeviceReadBps = []string{} 177 } 178 if len(config.Resources.DeviceWriteBps) > 0 && !sysInfo.BlkioWriteBpsDevice { 179 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.") 180 config.Resources.DeviceWriteBps = []string{} 181 } 182 if len(config.Resources.DeviceReadIOps) > 0 && !sysInfo.BlkioReadIOpsDevice { 183 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.") 184 config.Resources.DeviceReadIOps = []string{} 185 } 186 if len(config.Resources.DeviceWriteIOps) > 0 && !sysInfo.BlkioWriteIOpsDevice { 187 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.") 188 config.Resources.DeviceWriteIOps = []string{} 189 } 190 191 return warnings, nil 192 }