github.com/containers/podman/v4@v4.9.4/libpod/container_validate.go (about) 1 //go:build !remote 2 // +build !remote 3 4 package libpod 5 6 import ( 7 "fmt" 8 9 "github.com/containers/image/v5/docker" 10 "github.com/containers/image/v5/pkg/shortnames" 11 "github.com/containers/image/v5/transports/alltransports" 12 "github.com/containers/podman/v4/libpod/define" 13 spec "github.com/opencontainers/runtime-spec/specs-go" 14 ) 15 16 // Validate that the configuration of a container is valid. 17 func (c *Container) validate() error { 18 imageIDSet := c.config.RootfsImageID != "" 19 imageNameSet := c.config.RootfsImageName != "" 20 rootfsSet := c.config.Rootfs != "" 21 22 // If one of RootfsImageIDor RootfsImageName are set, both must be set. 23 if (imageIDSet || imageNameSet) && !(imageIDSet && imageNameSet) { 24 return fmt.Errorf("both RootfsImageName and RootfsImageID must be set if either is set: %w", define.ErrInvalidArg) 25 } 26 27 // Cannot set RootfsImageID and Rootfs at the same time 28 if imageIDSet && rootfsSet { 29 return fmt.Errorf("cannot set both an image ID and rootfs for a container: %w", define.ErrInvalidArg) 30 } 31 32 // Must set at least one of RootfsImageID or Rootfs 33 if !(imageIDSet || rootfsSet) { 34 return fmt.Errorf("must set root filesystem source to either image or rootfs: %w", define.ErrInvalidArg) 35 } 36 37 // A container cannot be marked as an infra and service container at 38 // the same time. 39 if c.IsInfra() && c.IsService() { 40 return fmt.Errorf("cannot be infra and service container at the same time: %w", define.ErrInvalidArg) 41 } 42 43 // Cannot make a network namespace if we are joining another container's 44 // network namespace 45 if c.config.CreateNetNS && c.config.NetNsCtr != "" { 46 return fmt.Errorf("cannot both create a network namespace and join another container's network namespace: %w", define.ErrInvalidArg) 47 } 48 49 if c.config.CgroupsMode == cgroupSplit && c.config.CgroupParent != "" { 50 return fmt.Errorf("cannot specify --cgroup-mode=split with a cgroup-parent: %w", define.ErrInvalidArg) 51 } 52 53 // Not creating cgroups has a number of requirements, mostly related to 54 // the PID namespace. 55 if c.config.NoCgroups || c.config.CgroupsMode == "disabled" { 56 if c.config.PIDNsCtr != "" { 57 return fmt.Errorf("cannot join another container's PID namespace if not creating cgroups: %w", define.ErrInvalidArg) 58 } 59 60 if c.config.CgroupParent != "" { 61 return fmt.Errorf("cannot set cgroup parent if not creating cgroups: %w", define.ErrInvalidArg) 62 } 63 64 // Ensure we have a PID namespace 65 if c.config.Spec.Linux == nil { 66 return fmt.Errorf("must provide Linux namespace configuration in OCI spec when using NoCgroups: %w", define.ErrInvalidArg) 67 } 68 foundPid := false 69 for _, ns := range c.config.Spec.Linux.Namespaces { 70 if ns.Type == spec.PIDNamespace { 71 foundPid = true 72 if ns.Path != "" { 73 return fmt.Errorf("containers not creating Cgroups must create a private PID namespace - cannot use another: %w", define.ErrInvalidArg) 74 } 75 break 76 } 77 } 78 if !foundPid { 79 return fmt.Errorf("containers not creating Cgroups must create a private PID namespace: %w", define.ErrInvalidArg) 80 } 81 } 82 83 // Can only set static IP or MAC is creating a network namespace. 84 if !c.config.CreateNetNS && (c.config.StaticIP != nil || c.config.StaticMAC != nil) { 85 return fmt.Errorf("cannot set static IP or MAC address if not creating a network namespace: %w", define.ErrInvalidArg) 86 } 87 88 // Cannot set static IP or MAC if joining >1 network. 89 if len(c.config.Networks) > 1 && (c.config.StaticIP != nil || c.config.StaticMAC != nil) { 90 return fmt.Errorf("cannot set static IP or MAC address if joining more than one network: %w", define.ErrInvalidArg) 91 } 92 93 // Using image resolv.conf conflicts with various DNS settings. 94 if c.config.UseImageResolvConf && 95 (len(c.config.DNSSearch) > 0 || len(c.config.DNSServer) > 0 || 96 len(c.config.DNSOption) > 0) { 97 return fmt.Errorf("cannot configure DNS options if using image's resolv.conf: %w", define.ErrInvalidArg) 98 } 99 100 if c.config.UseImageHosts && len(c.config.HostAdd) > 0 { 101 return fmt.Errorf("cannot add to /etc/hosts if using image's /etc/hosts: %w", define.ErrInvalidArg) 102 } 103 104 // Check named volume, overlay volume and image volume destination conflist 105 destinations := make(map[string]bool) 106 for _, vol := range c.config.NamedVolumes { 107 // Don't check if they already exist. 108 // If they don't we will automatically create them. 109 if _, ok := destinations[vol.Dest]; ok { 110 return fmt.Errorf("two volumes found with destination %s: %w", vol.Dest, define.ErrInvalidArg) 111 } 112 destinations[vol.Dest] = true 113 } 114 for _, vol := range c.config.OverlayVolumes { 115 // Don't check if they already exist. 116 // If they don't we will automatically create them. 117 if _, ok := destinations[vol.Dest]; ok { 118 return fmt.Errorf("two volumes found with destination %s: %w", vol.Dest, define.ErrInvalidArg) 119 } 120 destinations[vol.Dest] = true 121 } 122 for _, vol := range c.config.ImageVolumes { 123 // Don't check if they already exist. 124 // If they don't we will automatically create them. 125 if _, ok := destinations[vol.Dest]; ok { 126 return fmt.Errorf("two volumes found with destination %s: %w", vol.Dest, define.ErrInvalidArg) 127 } 128 destinations[vol.Dest] = true 129 } 130 131 // If User in the OCI spec is set, require that c.config.User is set for 132 // security reasons (a lot of our code relies on c.config.User). 133 if c.config.User == "" && (c.config.Spec.Process.User.UID != 0 || c.config.Spec.Process.User.GID != 0) { 134 return fmt.Errorf("please set User explicitly via WithUser() instead of in OCI spec directly: %w", define.ErrInvalidArg) 135 } 136 137 // Init-ctrs must be used inside a Pod. Check if an init container type is 138 // passed and if no pod is passed 139 if len(c.config.InitContainerType) > 0 && len(c.config.Pod) < 1 { 140 return fmt.Errorf("init containers must be created in a pod: %w", define.ErrInvalidArg) 141 } 142 143 if c.config.SdNotifyMode == define.SdNotifyModeIgnore && len(c.config.SdNotifySocket) > 0 { 144 return fmt.Errorf("cannot set sd-notify socket %q with sd-notify mode %q", c.config.SdNotifySocket, c.config.SdNotifyMode) 145 } 146 147 if c.config.HealthCheckOnFailureAction != define.HealthCheckOnFailureActionNone && c.config.HealthCheckConfig == nil { 148 return fmt.Errorf("cannot set on-failure action to %s without a health check", c.config.HealthCheckOnFailureAction.String()) 149 } 150 151 if value, exists := c.config.Labels[define.AutoUpdateLabel]; exists { 152 // TODO: we cannot reference pkg/autoupdate here due to 153 // circular dependencies. It's worth considering moving the 154 // auto-update logic into the libpod package. 155 if value == "registry" || value == "image" { 156 if err := validateAutoUpdateImageReference(c.config.RawImageName); err != nil { 157 return err 158 } 159 } 160 } 161 162 // Cannot set startup HC without a healthcheck 163 if c.config.HealthCheckConfig == nil && c.config.StartupHealthCheckConfig != nil { 164 return fmt.Errorf("cannot set a startup healthcheck when there is no regular healthcheck: %w", define.ErrInvalidArg) 165 } 166 167 return nil 168 } 169 170 // validateAutoUpdateImageReference checks if the specified imageName is a 171 // fully-qualified image reference to the docker transport. Such a reference 172 // includes a domain, name and tag (e.g., quay.io/podman/stable:latest). The 173 // reference may also be prefixed with "docker://" explicitly indicating that 174 // it's a reference to the docker transport. 175 func validateAutoUpdateImageReference(imageName string) error { 176 // Make sure the input image is a docker. 177 imageRef, err := alltransports.ParseImageName(imageName) 178 if err == nil && imageRef.Transport().Name() != docker.Transport.Name() { 179 return fmt.Errorf("auto updates require the docker image transport but image is of transport %q", imageRef.Transport().Name()) 180 } else if err != nil { 181 if shortnames.IsShortName(imageName) { 182 return fmt.Errorf("short name: auto updates require fully-qualified image reference: %q", imageName) 183 } 184 } 185 return nil 186 }