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