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  }