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 }