github.com/containers/libpod@v1.9.4-0.20220419124438-4284fd425507/pkg/specgen/container_validate.go (about)

     1  package specgen
     2  
     3  import (
     4  	"strings"
     5  
     6  	"github.com/containers/libpod/pkg/rootless"
     7  	"github.com/containers/libpod/pkg/util"
     8  	"github.com/pkg/errors"
     9  )
    10  
    11  var (
    12  	// ErrInvalidSpecConfig describes an error that the given SpecGenerator is invalid
    13  	ErrInvalidSpecConfig error = errors.New("invalid configuration")
    14  	// SystemDValues describes the only values that SystemD can be
    15  	SystemDValues = []string{"true", "false", "always"}
    16  	// ImageVolumeModeValues describes the only values that ImageVolumeMode can be
    17  	ImageVolumeModeValues = []string{"ignore", "tmpfs", "bind"}
    18  )
    19  
    20  func exclusiveOptions(opt1, opt2 string) error {
    21  	return errors.Errorf("%s and %s are mutually exclusive options", opt1, opt2)
    22  }
    23  
    24  // Validate verifies that the given SpecGenerator is valid and satisfies required
    25  // input for creating a container.
    26  func (s *SpecGenerator) Validate() error {
    27  
    28  	//
    29  	// ContainerBasicConfig
    30  	//
    31  	// Rootfs and Image cannot both populated
    32  	if len(s.ContainerStorageConfig.Image) > 0 && len(s.ContainerStorageConfig.Rootfs) > 0 {
    33  		return errors.Wrap(ErrInvalidSpecConfig, "both image and rootfs cannot be simultaneously")
    34  	}
    35  	// Cannot set hostname and utsns
    36  	if len(s.ContainerBasicConfig.Hostname) > 0 && !s.ContainerBasicConfig.UtsNS.IsPrivate() {
    37  		return errors.Wrap(ErrInvalidSpecConfig, "cannot set hostname when creating an UTS namespace")
    38  	}
    39  	// systemd values must be true, false, or always
    40  	if len(s.ContainerBasicConfig.Systemd) > 0 && !util.StringInSlice(strings.ToLower(s.ContainerBasicConfig.Systemd), SystemDValues) {
    41  		return errors.Wrapf(ErrInvalidSpecConfig, "SystemD values must be one of %s", strings.Join(SystemDValues, ","))
    42  	}
    43  
    44  	//
    45  	// ContainerStorageConfig
    46  	//
    47  	// rootfs and image cannot both be set
    48  	if len(s.ContainerStorageConfig.Image) > 0 && len(s.ContainerStorageConfig.Rootfs) > 0 {
    49  		return exclusiveOptions("rootfs", "image")
    50  	}
    51  	// imagevolumemode must be one of ignore, tmpfs, or anonymous if given
    52  	if len(s.ContainerStorageConfig.ImageVolumeMode) > 0 && !util.StringInSlice(strings.ToLower(s.ContainerStorageConfig.ImageVolumeMode), ImageVolumeModeValues) {
    53  		return errors.Errorf("ImageVolumeMode values must be one of %s", strings.Join(ImageVolumeModeValues, ","))
    54  	}
    55  	// shmsize conflicts with IPC namespace
    56  	if s.ContainerStorageConfig.ShmSize != nil && !s.ContainerStorageConfig.IpcNS.IsPrivate() {
    57  		return errors.New("cannot set shmsize when creating an IPC namespace")
    58  	}
    59  
    60  	//
    61  	// ContainerSecurityConfig
    62  	//
    63  	// groups and privileged are exclusive
    64  	if len(s.Groups) > 0 && s.Privileged {
    65  		return exclusiveOptions("Groups", "privileged")
    66  	}
    67  	// capadd and privileged are exclusive
    68  	if len(s.CapAdd) > 0 && s.Privileged {
    69  		return exclusiveOptions("CapAdd", "privileged")
    70  	}
    71  	// selinuxprocesslabel and privileged are exclusive
    72  	if len(s.SelinuxProcessLabel) > 0 && s.Privileged {
    73  		return exclusiveOptions("SelinuxProcessLabel", "privileged")
    74  	}
    75  	// selinuxmounmtlabel and privileged are exclusive
    76  	if len(s.SelinuxMountLabel) > 0 && s.Privileged {
    77  		return exclusiveOptions("SelinuxMountLabel", "privileged")
    78  	}
    79  	// selinuxopts and privileged are exclusive
    80  	if len(s.SelinuxOpts) > 0 && s.Privileged {
    81  		return exclusiveOptions("SelinuxOpts", "privileged")
    82  	}
    83  	// apparmor and privileged are exclusive
    84  	if len(s.ApparmorProfile) > 0 && s.Privileged {
    85  		return exclusiveOptions("AppArmorProfile", "privileged")
    86  	}
    87  	// userns and idmappings conflict
    88  	if s.UserNS.IsPrivate() && s.IDMappings == nil {
    89  		return errors.Wrap(ErrInvalidSpecConfig, "IDMappings are required when not creating a User namespace")
    90  	}
    91  
    92  	//
    93  	// ContainerCgroupConfig
    94  	//
    95  	//
    96  	// None for now
    97  
    98  	//
    99  	// ContainerNetworkConfig
   100  	//
   101  	if !s.NetNS.IsPrivate() && s.ConfigureNetNS {
   102  		return errors.New("can only configure network namespace when creating a network a network namespace")
   103  	}
   104  	// useimageresolveconf conflicts with dnsserver, dnssearch, dnsoption
   105  	if s.UseImageResolvConf {
   106  		if len(s.DNSServer) > 0 {
   107  			return exclusiveOptions("UseImageResolvConf", "DNSServer")
   108  		}
   109  		if len(s.DNSSearch) > 0 {
   110  			return exclusiveOptions("UseImageResolvConf", "DNSSearch")
   111  		}
   112  		if len(s.DNSOption) > 0 {
   113  			return exclusiveOptions("UseImageResolvConf", "DNSOption")
   114  		}
   115  	}
   116  	// UseImageHosts and HostAdd are exclusive
   117  	if s.UseImageHosts && len(s.HostAdd) > 0 {
   118  		return exclusiveOptions("UseImageHosts", "HostAdd")
   119  	}
   120  
   121  	// TODO the specgen does not appear to handle this?  Should it
   122  	//switch config.Cgroup.Cgroups {
   123  	//case "disabled":
   124  	//	if addedResources {
   125  	//		return errors.New("cannot specify resource limits when cgroups are disabled is specified")
   126  	//	}
   127  	//	configSpec.Linux.Resources = &spec.LinuxResources{}
   128  	//case "enabled", "no-conmon", "":
   129  	//	// Do nothing
   130  	//default:
   131  	//	return errors.New("unrecognized option for cgroups; supported are 'default', 'disabled', 'no-conmon'")
   132  	//}
   133  
   134  	// Namespaces
   135  	if err := s.UtsNS.validate(); err != nil {
   136  		return err
   137  	}
   138  	if err := s.IpcNS.validate(); err != nil {
   139  		return err
   140  	}
   141  	if err := s.PidNS.validate(); err != nil {
   142  		return err
   143  	}
   144  	if err := s.CgroupNS.validate(); err != nil {
   145  		return err
   146  	}
   147  	if err := s.UserNS.validate(); err != nil {
   148  		return err
   149  	}
   150  
   151  	// The following are defaults as needed by container creation
   152  	if len(s.WorkDir) < 1 {
   153  		s.WorkDir = "/"
   154  	}
   155  
   156  	// Set defaults if network info is not provided
   157  	if s.NetNS.NSMode == "" {
   158  		s.NetNS.NSMode = Bridge
   159  		if rootless.IsRootless() {
   160  			s.NetNS.NSMode = Slirp
   161  		}
   162  	}
   163  	if err := validateNetNS(&s.NetNS); err != nil {
   164  		return err
   165  	}
   166  	return nil
   167  }