Merge pull request #23440 from TomSweeneyRedHat/dev/tsweeney/compat-volumes

Bump to Buildah v1.37.0 and wire in --compat-volumes option
This commit is contained in:
openshift-merge-bot[bot] 2024-07-31 14:29:54 +00:00 committed by GitHub
commit ebc7debbb0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
41 changed files with 848 additions and 293 deletions

View File

@ -520,6 +520,7 @@ func buildFlagsWrapperToOptions(c *cobra.Command, contextDir string, flags *Buil
CacheTTL: cacheTTL,
ConfidentialWorkload: confidentialWorkloadOptions,
CommonBuildOpts: commonOpts,
CompatVolumes: types.NewOptionalBool(flags.CompatVolumes),
Compression: compression,
ConfigureNetwork: networkPolicy,
ContextDirectory: contextDir,

View File

@ -0,0 +1,11 @@
####> This option file is used in:
####> podman build, farm build
####> If file is edited, make sure the changes
####> are applicable to all of those.
#### **--compat-volumes**
Handle directories marked using the VOLUME instruction (both in this build, and
those inherited from base images) such that their contents can only be modified
by ADD and COPY instructions. Any changes made in those locations by RUN
instructions will be reverted. Before the introduction of this option, this
behavior was the default, but it is now disabled by default.

View File

@ -92,6 +92,8 @@ host. (Examples: arm, arm64, 386, amd64, ppc64le, s390x)
@@option cgroupns.image
@@option compat-volumes
#### **--compress**
This option is added to be aligned with other containers CLIs.

View File

@ -57,6 +57,8 @@ Note: Since the images built are directly pushed to a registry, the user must pa
Remove built images from farm nodes on success (Default: false).
@@option compat-volumes
@@option cpp-flag
@@option cpu-period

16
go.mod
View File

@ -12,15 +12,15 @@ require (
github.com/checkpoint-restore/checkpointctl v1.2.1
github.com/checkpoint-restore/go-criu/v7 v7.1.0
github.com/containernetworking/plugins v1.5.1
github.com/containers/buildah v1.36.1-0.20240715114330-4a82e0a3f382
github.com/containers/common v0.59.1-0.20240717135212-fdbae3a180cb
github.com/containers/buildah v1.37.0
github.com/containers/common v0.60.0
github.com/containers/conmon v2.0.20+incompatible
github.com/containers/gvisor-tap-vsock v0.7.4
github.com/containers/image/v5 v5.31.1-0.20240711123249-1dbd8fbbe516
github.com/containers/image/v5 v5.32.0
github.com/containers/libhvee v0.7.1
github.com/containers/ocicrypt v1.2.0
github.com/containers/psgo v1.9.0
github.com/containers/storage v1.54.1-0.20240724150347-86a0c425388b
github.com/containers/storage v1.55.0
github.com/containers/winquit v1.1.0
github.com/coreos/go-systemd/v22 v22.5.1-0.20231103132048-7d375ecc2b09
github.com/coreos/stream-metadata-go v0.4.4
@ -29,7 +29,7 @@ require (
github.com/cyphar/filepath-securejoin v0.3.1
github.com/digitalocean/go-qemu v0.0.0-20230711162256-2e3d0186973e
github.com/docker/distribution v2.8.3+incompatible
github.com/docker/docker v27.1.0+incompatible
github.com/docker/docker v27.1.1+incompatible
github.com/docker/go-connections v0.5.0
github.com/docker/go-plugins-helpers v0.0.0-20211224144127-6eecb7beb651
github.com/docker/go-units v0.5.0
@ -59,7 +59,7 @@ require (
github.com/opencontainers/runtime-spec v1.2.0
github.com/opencontainers/runtime-tools v0.9.1-0.20230914150019-408c51e934dc
github.com/opencontainers/selinux v1.11.0
github.com/openshift/imagebuilder v1.2.11
github.com/openshift/imagebuilder v1.2.14
github.com/rootless-containers/rootlesskit/v2 v2.2.0
github.com/shirou/gopsutil/v3 v3.24.5
github.com/sirupsen/logrus v1.9.3
@ -102,7 +102,7 @@ require (
github.com/containerd/log v0.1.0 // indirect
github.com/containerd/stargz-snapshotter/estargz v0.15.1 // indirect
github.com/containerd/typeurl/v2 v2.1.1 // indirect
github.com/containernetworking/cni v1.2.2 // indirect
github.com/containernetworking/cni v1.2.3 // indirect
github.com/containers/libtrust v0.0.0-20230121012942-c1716e8a8d01 // indirect
github.com/containers/luksy v0.0.0-20240618143119-a8846e21c08c // indirect
github.com/coreos/go-oidc/v3 v3.10.0 // indirect
@ -115,7 +115,7 @@ require (
github.com/docker/docker-credential-helpers v0.8.2 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/fsnotify/fsnotify v1.7.0 // indirect
github.com/fsouza/go-dockerclient v1.11.0 // indirect
github.com/fsouza/go-dockerclient v1.11.1 // indirect
github.com/gabriel-vasile/mimetype v1.4.3 // indirect
github.com/gin-contrib/sse v0.1.0 // indirect
github.com/gin-gonic/gin v1.9.1 // indirect

40
go.sum
View File

@ -73,20 +73,20 @@ github.com/containerd/stargz-snapshotter/estargz v0.15.1 h1:eXJjw9RbkLFgioVaTG+G
github.com/containerd/stargz-snapshotter/estargz v0.15.1/go.mod h1:gr2RNwukQ/S9Nv33Lt6UC7xEx58C+LHRdoqbEKjz1Kk=
github.com/containerd/typeurl/v2 v2.1.1 h1:3Q4Pt7i8nYwy2KmQWIw2+1hTvwTE/6w9FqcttATPO/4=
github.com/containerd/typeurl/v2 v2.1.1/go.mod h1:IDp2JFvbwZ31H8dQbEIY7sDl2L3o3HZj1hsSQlywkQ0=
github.com/containernetworking/cni v1.2.2 h1:9IbP6KJQQxVKo4hhnm8r50YcVKrJbJu3Dqw+Rbt1vYk=
github.com/containernetworking/cni v1.2.2/go.mod h1:DuLgF+aPd3DzcTQTtp/Nvl1Kim23oFKdm2okJzBQA5M=
github.com/containernetworking/cni v1.2.3 h1:hhOcjNVUQTnzdRJ6alC5XF+wd9mfGIUaj8FuJbEslXM=
github.com/containernetworking/cni v1.2.3/go.mod h1:DuLgF+aPd3DzcTQTtp/Nvl1Kim23oFKdm2okJzBQA5M=
github.com/containernetworking/plugins v1.5.1 h1:T5ji+LPYjjgW0QM+KyrigZbLsZ8jaX+E5J/EcKOE4gQ=
github.com/containernetworking/plugins v1.5.1/go.mod h1:MIQfgMayGuHYs0XdNudf31cLLAC+i242hNm6KuDGqCM=
github.com/containers/buildah v1.36.1-0.20240715114330-4a82e0a3f382 h1:NUScZGjAC6Cd1KuPcnCac10Q/gz01PULzh7Em/VXZOc=
github.com/containers/buildah v1.36.1-0.20240715114330-4a82e0a3f382/go.mod h1:HlwJHYRlP5j8siiPY46I8py00hlGxWPC/vCZZ/01EEU=
github.com/containers/common v0.59.1-0.20240717135212-fdbae3a180cb h1:9OgHqOACzWRzPFewtx/lOSKnPvWAMMlW3ruvXQL4fP4=
github.com/containers/common v0.59.1-0.20240717135212-fdbae3a180cb/go.mod h1:KrQ9y5qa7TBVzp7qs7I1MVi6Uxntu0hM5wjd5bmvMnM=
github.com/containers/buildah v1.37.0 h1:jvHwu1vIwIqnHyOSg9eef9Apdpry+5oWLrm43gdf8Rk=
github.com/containers/buildah v1.37.0/go.mod h1:MKd79tkluMf6vtH06SedhBQK5OB7E0pFVIuiTTw3dJk=
github.com/containers/common v0.60.0 h1:QMNygqiiit9LU/yqee9Dv0N0oQ+rQq41ElfdOBQtw7w=
github.com/containers/common v0.60.0/go.mod h1:dtKVe11xkV89tqzRX9s/B0ORjeB2dy5UB46aGjunMn8=
github.com/containers/conmon v2.0.20+incompatible h1:YbCVSFSCqFjjVwHTPINGdMX1F6JXHGTUje2ZYobNrkg=
github.com/containers/conmon v2.0.20+incompatible/go.mod h1:hgwZ2mtuDrppv78a/cOBNiCm6O0UMWGx1mu7P00nu5I=
github.com/containers/gvisor-tap-vsock v0.7.4 h1:iOtr/KEi+r599OOx1+9Qbss91jD5yxh1HO35MKTdths=
github.com/containers/gvisor-tap-vsock v0.7.4/go.mod h1:orUOSdxU/IGEOxhecu2i7EzV7k7e2TgQlyCBfUngS0A=
github.com/containers/image/v5 v5.31.1-0.20240711123249-1dbd8fbbe516 h1:BVyB11XLbT7s0tMF1qzdc5R04gO2BRAdjbftRwNoLXM=
github.com/containers/image/v5 v5.31.1-0.20240711123249-1dbd8fbbe516/go.mod h1:iAUT9Iy/z0QPrYeILorryErMUxm4GlRzBE0Yz65l/uE=
github.com/containers/image/v5 v5.32.0 h1:yjbweazPfr8xOzQ2hkkYm1A2V0jN96/kES6Gwyxj7hQ=
github.com/containers/image/v5 v5.32.0/go.mod h1:x5e0RDfGaY6bnQ13gJ2LqbfHvzssfB/y5a8HduGFxJc=
github.com/containers/libhvee v0.7.1 h1:dWGF5GLq9DZvXo3P8aDp3cNieL5eCaSell4UmeA/jY4=
github.com/containers/libhvee v0.7.1/go.mod h1:fRKB3AyIqHMvq6xaeYhTpckM2cdoq0oecolyoiuLP7M=
github.com/containers/libtrust v0.0.0-20230121012942-c1716e8a8d01 h1:Qzk5C6cYglewc+UyGf6lc8Mj2UaPTHy/iF2De0/77CA=
@ -97,8 +97,8 @@ github.com/containers/ocicrypt v1.2.0 h1:X14EgRK3xNFvJEfI5O4Qn4T3E25ANudSOZz/sir
github.com/containers/ocicrypt v1.2.0/go.mod h1:ZNviigQajtdlxIZGibvblVuIFBKIuUI2M0QM12SD31U=
github.com/containers/psgo v1.9.0 h1:eJ74jzSaCHnWt26OlKZROSyUyRcGDf+gYBdXnxrMW4g=
github.com/containers/psgo v1.9.0/go.mod h1:0YoluUm43Mz2UnBIh1P+6V6NWcbpTL5uRtXyOcH0B5A=
github.com/containers/storage v1.54.1-0.20240724150347-86a0c425388b h1:xWuoWniyeweN/rNmTQJTaGSth5rKQ3V6EcQ4V3XVa/A=
github.com/containers/storage v1.54.1-0.20240724150347-86a0c425388b/go.mod h1:NbpcPTBSlREa7GfqzHqPaAD28CtBsZu+xsryPkOLnHg=
github.com/containers/storage v1.55.0 h1:wTWZ3YpcQf1F+dSP4KxG9iqDfpQY1otaUXjPpffuhgg=
github.com/containers/storage v1.55.0/go.mod h1:28cB81IDk+y7ok60Of6u52RbCeBRucbFOeLunhER1RQ=
github.com/containers/winquit v1.1.0 h1:jArun04BNDQvt2W0Y78kh9TazN2EIEMG5Im6/JY7+pE=
github.com/containers/winquit v1.1.0/go.mod h1:PsPeZlnbkmGGIToMPHF1zhWjBUkd8aHjMOr/vFcPxw8=
github.com/coreos/go-oidc/v3 v3.10.0 h1:tDnXHnLyiTVyT/2zLDGj09pFPkhND8Gl8lnTRhoEaJU=
@ -132,12 +132,12 @@ github.com/disiqueira/gotree/v3 v3.0.2 h1:ik5iuLQQoufZBNPY518dXhiO5056hyNBIK9lWh
github.com/disiqueira/gotree/v3 v3.0.2/go.mod h1:ZuyjE4+mUQZlbpkI24AmruZKhg3VHEgPLDY8Qk+uUu8=
github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
github.com/docker/cli v27.0.3+incompatible h1:usGs0/BoBW8MWxGeEtqPMkzOY56jZ6kYlSN5BLDioCQ=
github.com/docker/cli v27.0.3+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
github.com/docker/cli v27.1.1+incompatible h1:goaZxOqs4QKxznZjjBWKONQci/MywhtRv2oNn0GkeZE=
github.com/docker/cli v27.1.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk=
github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
github.com/docker/docker v27.1.0+incompatible h1:rEHVQc4GZ0MIQKifQPHSFGV/dVgaZafgRf8fCPtDYBs=
github.com/docker/docker v27.1.0+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker v27.1.1+incompatible h1:hO/M4MtV36kzKldqnA37IWhebRA+LnqqcqDja6kVaKY=
github.com/docker/docker v27.1.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker-credential-helpers v0.8.2 h1:bX3YxiGzFP5sOXWc3bTPEXdEaZSeVMrFgOr3T+zrFAo=
github.com/docker/docker-credential-helpers v0.8.2/go.mod h1:P3ci7E3lwkZg6XiHdRKft1KckHiO9a2rNtyFbZ/ry9M=
github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c=
@ -161,8 +161,8 @@ github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSw
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
github.com/fsouza/go-dockerclient v1.11.0 h1:4ZAk6W7rPAtPXm7198EFqA5S68rwnNQORxlOA5OurCA=
github.com/fsouza/go-dockerclient v1.11.0/go.mod h1:0I3TQCRseuPTzqlY4Y3ajfsg2VAdMQoazrkxJTiJg8s=
github.com/fsouza/go-dockerclient v1.11.1 h1:i5Vk9riDxW2uP9pVS5FYkpquMTFT5lsx2pt7oErRTjI=
github.com/fsouza/go-dockerclient v1.11.1/go.mod h1:UfjOOaspAq+RGh7GX1aZ0HeWWGHQWWsh+H5BgEWB3Pk=
github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0=
github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk=
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
@ -398,8 +398,8 @@ github.com/opencontainers/runtime-tools v0.9.1-0.20230914150019-408c51e934dc h1:
github.com/opencontainers/runtime-tools v0.9.1-0.20230914150019-408c51e934dc/go.mod h1:8tx1helyqhUC65McMm3x7HmOex8lO2/v9zPuxmKHurs=
github.com/opencontainers/selinux v1.11.0 h1:+5Zbo97w3Lbmb3PeqQtpmTkMwsW5nRI3YaLpt7tQ7oU=
github.com/opencontainers/selinux v1.11.0/go.mod h1:E5dMC3VPuVvVHDYmi78qvhJp8+M586T4DlDRYpFkyec=
github.com/openshift/imagebuilder v1.2.11 h1:4EmEMyiLr7jlskS1h6V6smdcrQSGLRdcIeaXeV3F8EM=
github.com/openshift/imagebuilder v1.2.11/go.mod h1:KkkXOyRjJlZEXWQtHNBNzVHqh4vf/0xX5cDIQ2gr+5I=
github.com/openshift/imagebuilder v1.2.14 h1:l4gUw0KIsjZrX7otfS4WoKxzGBrxYldU3pF4+5W/ud8=
github.com/openshift/imagebuilder v1.2.14/go.mod h1:KkkXOyRjJlZEXWQtHNBNzVHqh4vf/0xX5cDIQ2gr+5I=
github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs=
github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc=
github.com/ostreedev/ostree-go v0.0.0-20210805093236-719684c64e4f h1:/UDgs8FGMqwnHagNDPGOlts35QkhAZ8by3DR7nMih7M=
@ -426,8 +426,8 @@ github.com/prometheus/client_model v0.6.0 h1:k1v3CzpSRUTrKMppY35TLwPvxHqBu0bYgxZ
github.com/prometheus/client_model v0.6.0/go.mod h1:NTQHnmxFpouOD0DpvP4XujX3CdOAGQPoaGhyTchlyt8=
github.com/prometheus/common v0.51.1 h1:eIjN50Bwglz6a/c3hAgSMcofL3nD+nFQkV6Dd4DsQCw=
github.com/prometheus/common v0.51.1/go.mod h1:lrWtQx+iDfn2mbH5GUzlH9TSHyfZpHkSiG1W7y3sF2Q=
github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo=
github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo=
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=

View File

@ -97,6 +97,7 @@ func BuildImage(w http.ResponseWriter, r *http.Request) {
CacheTo string `schema:"cacheto"`
CacheTTL string `schema:"cachettl"`
CgroupParent string `schema:"cgroupparent"`
CompatVolumes bool `schema:"compatvolumes"`
Compression uint64 `schema:"compression"`
ConfigureNetwork string `schema:"networkmode"`
CPPFlags string `schema:"cppflags"`
@ -702,6 +703,7 @@ func BuildImage(w http.ResponseWriter, r *http.Request) {
Secrets: secrets,
Volumes: query.Volumes,
},
CompatVolumes: types.NewOptionalBool(query.CompatVolumes),
Compression: compression,
ConfigureNetwork: parseNetworkConfigurationPolicy(query.ConfigureNetwork),
ContextDirectory: contextDirectory,

View File

@ -540,6 +540,13 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error {
// description: |
// Suppress verbose build output
// - in: query
// name: compatvolumes
// type: boolean
// default: false
// description: |
// Contents of base images to be modified on ADD or COPY only
// (As of version 1.37)
// - in: query
// name: nocache
// type: boolean
// default: false
@ -1494,6 +1501,13 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error {
// description: |
// Suppress verbose build output
// - in: query
// name: compatvolumes
// type: boolean
// default: false
// description: |
// Contents of base images to be modified on ADD or COPY only
// (As of version 1.37)
// - in: query
// name: nocache
// type: boolean
// default: false

View File

@ -281,6 +281,12 @@ func Build(ctx context.Context, containerFiles []string, options types.BuildOpti
if mem := options.CommonBuildOpts.Memory; mem > 0 {
params.Set("memory", strconv.Itoa(int(mem)))
}
switch options.CompatVolumes {
case imageTypes.OptionalBoolTrue:
params.Set("compatvolumes", "1")
case imageTypes.OptionalBoolFalse:
params.Set("compatvolumes", "0")
}
if options.NoCache {
params.Set("nocache", "1")
}

View File

@ -1,4 +1,4 @@
From 09b115ea501320bde7cf979f280f42dc803aa70b Mon Sep 17 00:00:00 2001
From 6f7a27f4787ec91ecf7bd7c4de048b23c3cdb74f Mon Sep 17 00:00:00 2001
From: Ed Santiago <santiago@redhat.com>
Date: Thu, 6 Oct 2022 17:32:59 -0600
Subject: [PATCH] tweaks for running buildah tests under podman
@ -9,13 +9,13 @@ Signed-off-by: Ed Santiago <santiago@redhat.com>
1 file changed, 115 insertions(+), 4 deletions(-)
diff --git a/tests/helpers.bash b/tests/helpers.bash
index f4245c8bc..8df18c0cc 100644
index b47939284..ce6dde76e 100644
--- a/tests/helpers.bash
+++ b/tests/helpers.bash
@@ -71,6 +71,38 @@ EOF
BUILDAH_REGISTRY_OPTS="--registries-conf ${TEST_SOURCES}/registries.conf --registries-conf-dir ${TEST_SCRATCH_DIR}/registries.d --short-name-alias-conf ${TEST_SCRATCH_DIR}/cache/shortnames.conf"
COPY_REGISTRY_OPTS="--registries-conf ${TEST_SOURCES}/registries.conf --registries-conf-dir ${TEST_SCRATCH_DIR}/registries.d --short-name-alias-conf ${TEST_SCRATCH_DIR}/cache/shortnames.conf"
PODMAN_REGISTRY_OPTS="--registries-conf ${TEST_SOURCES}/registries.conf"
@@ -79,6 +79,38 @@ EOF
BUILDAH_REGISTRY_OPTS="${regconfopt} ${regconfdir} --short-name-alias-conf ${TEST_SCRATCH_DIR}/cache/shortnames.conf"
COPY_REGISTRY_OPTS="${BUILDAH_REGISTRY_OPTS}"
PODMAN_REGISTRY_OPTS="${regconfopt}"
+
+ PODMAN_SERVER_PID=
+ PODMAN_NATIVE="${PODMAN_BINARY} ${ROOTDIR_OPTS} ${PODMAN_REGISTRY_OPTS}"
@ -51,7 +51,7 @@ index f4245c8bc..8df18c0cc 100644
}
function starthttpd() {
@@ -114,6 +146,32 @@ function teardown_tests() {
@@ -122,6 +154,32 @@ function teardown_tests() {
stop_git_daemon
stop_registry
@ -84,7 +84,7 @@ index f4245c8bc..8df18c0cc 100644
# Workaround for #1991 - buildah + overlayfs leaks mount points.
# Many tests leave behind /var/tmp/.../root/overlay and sub-mounts;
# let's find those and clean them up, otherwise 'rm -rf' fails.
@@ -203,7 +261,12 @@ function copy() {
@@ -211,7 +269,12 @@ function copy() {
}
function podman() {
@ -98,7 +98,7 @@ index f4245c8bc..8df18c0cc 100644
}
# There are various scenarios where we would like to execute `tests` as rootless user, however certain commands like `buildah mount`
@@ -267,8 +330,36 @@ function run_buildah() {
@@ -275,8 +338,36 @@ function run_buildah() {
--retry) retry=3; shift;; # retry network flakes
esac
@ -136,7 +136,7 @@ index f4245c8bc..8df18c0cc 100644
# If session is rootless and `buildah mount` is invoked, perform unshare,
# since normal user cannot mount a filesystem unless they're in a user namespace along with its own mount namespace.
@@ -282,8 +373,8 @@ function run_buildah() {
@@ -290,8 +381,8 @@ function run_buildah() {
retry=$(( retry - 1 ))
# stdout is only emitted upon error; this echo is to help a debugger
@ -147,7 +147,7 @@ index f4245c8bc..8df18c0cc 100644
# without "quotes", multiple lines are glommed together into one
if [ -n "$output" ]; then
echo "$output"
@@ -644,6 +735,26 @@ function skip_if_no_unshare() {
@@ -652,6 +743,26 @@ function skip_if_no_unshare() {
fi
}
@ -175,5 +175,4 @@ index f4245c8bc..8df18c0cc 100644
daemondir=${TEST_SCRATCH_DIR}/git-daemon
mkdir -p ${daemondir}/repo
--
2.44.0
2.45.2

View File

@ -0,0 +1,116 @@
/*
Copyright The containerd Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Package errdefs defines the common errors used throughout containerd
// packages.
//
// Use with fmt.Errorf to add context to an error.
//
// To detect an error class, use the IsXXX functions to tell whether an error
// is of a certain type.
//
// The functions ToGRPC and FromGRPC can be used to map server-side and
// client-side errors to the correct types.
package errdefs
import (
"github.com/containerd/errdefs"
)
// Definitions of common error types used throughout containerd. All containerd
// errors returned by most packages will map into one of these errors classes.
// Packages should return errors of these types when they want to instruct a
// client to take a particular action.
//
// For the most part, we just try to provide local grpc errors. Most conditions
// map very well to those defined by grpc.
var (
ErrUnknown = errdefs.ErrUnknown
ErrInvalidArgument = errdefs.ErrInvalidArgument
ErrNotFound = errdefs.ErrNotFound
ErrAlreadyExists = errdefs.ErrAlreadyExists
ErrFailedPrecondition = errdefs.ErrFailedPrecondition
ErrUnavailable = errdefs.ErrUnavailable
ErrNotImplemented = errdefs.ErrNotImplemented
)
// IsInvalidArgument returns true if the error is due to an invalid argument
func IsInvalidArgument(err error) bool {
return errdefs.IsInvalidArgument(err)
}
// IsNotFound returns true if the error is due to a missing object
func IsNotFound(err error) bool {
return errdefs.IsNotFound(err)
}
// IsAlreadyExists returns true if the error is due to an already existing
// metadata item
func IsAlreadyExists(err error) bool {
return errdefs.IsAlreadyExists(err)
}
// IsFailedPrecondition returns true if an operation could not proceed to the
// lack of a particular condition
func IsFailedPrecondition(err error) bool {
return errdefs.IsFailedPrecondition(err)
}
// IsUnavailable returns true if the error is due to a resource being unavailable
func IsUnavailable(err error) bool {
return errdefs.IsUnavailable(err)
}
// IsNotImplemented returns true if the error is due to not being implemented
func IsNotImplemented(err error) bool {
return errdefs.IsNotImplemented(err)
}
// IsCanceled returns true if the error is due to `context.Canceled`.
func IsCanceled(err error) bool {
return errdefs.IsCanceled(err)
}
// IsDeadlineExceeded returns true if the error is due to
// `context.DeadlineExceeded`.
func IsDeadlineExceeded(err error) bool {
return errdefs.IsDeadlineExceeded(err)
}
// ToGRPC will attempt to map the backend containerd error into a grpc error,
// using the original error message as a description.
//
// Further information may be extracted from certain errors depending on their
// type.
//
// If the error is unmapped, the original error will be returned to be handled
// by the regular grpc error handling stack.
func ToGRPC(err error) error {
return errdefs.ToGRPC(err)
}
// ToGRPCf maps the error to grpc error codes, assembling the formatting string
// and combining it with the target error string.
//
// This is equivalent to errdefs.ToGRPC(fmt.Errorf("%s: %w", fmt.Sprintf(format, args...), err))
func ToGRPCf(err error, format string, args ...interface{}) error {
return errdefs.ToGRPCf(err, format, args...)
}
// FromGRPC returns the underlying error from a grpc service based on the grpc error code
func FromGRPC(err error) error {
return errdefs.FromGRPC(err)
}

View File

@ -817,6 +817,8 @@ func (c *CNIConfig) GCNetworkList(ctx context.Context, list *NetworkConfigList,
}
if args != nil {
inject["cni.dev/valid-attachments"] = args.ValidAttachments
// #1101: spec used incorrect variable name
inject["cni.dev/attachments"] = args.ValidAttachments
}
for _, plugin := range list.Plugins {

View File

@ -32,7 +32,7 @@ env:
DEBIAN_NAME: "debian-13"
# Image identifiers
IMAGE_SUFFIX: "c20240620t153000z-f40f39d13"
IMAGE_SUFFIX: "c20240708t152000z-f40f39d13"
FEDORA_CACHE_IMAGE_NAME: "fedora-${IMAGE_SUFFIX}"
PRIOR_FEDORA_CACHE_IMAGE_NAME: "prior-fedora-${IMAGE_SUFFIX}"
DEBIAN_CACHE_IMAGE_NAME: "debian-${IMAGE_SUFFIX}"

View File

@ -2,6 +2,78 @@
# Changelog
## vv1.37.0 (2024-07-26)
Bump c/storage, c/image, c/common for v1.37.0
"build with basename resolving user arg" tests: correct ARG use
bud-multiple-platform-no-run test: correct ARG use
imagebuildah: always have default values for $TARGET... args ready
bump github.com/openshift/imagebuilder to v1.2.14
fix(deps): update module github.com/docker/docker to v27.1.1+incompatible
fix(deps): update module github.com/cyphar/filepath-securejoin to v0.3.1
fix(deps): update module github.com/docker/docker to v27.1.0+incompatible
CI: use local registry, part 2 of 2
CI: use local registry, part 1 of 2
fix(deps): update module github.com/fsouza/go-dockerclient to v1.11.1
Revert "fix(deps): update github.com/containers/image/v5 to v5.31.1"
Replace libimage.LookupReferenceFunc with the manifests version
conformance tests: enable testing CompatVolumes
conformance tests: add a test that tries to chown a volume
imagebuildah: make traditional volume handling not the default
StageExecutor.prepare(): mark base image volumes for preservation
fix(deps): update module github.com/containers/image/v5 to v5.31.1
Vendor in latest containers/(common, storage, image)
fix(deps): update module golang.org/x/term to v0.22.0
fix(deps): update module golang.org/x/sys to v0.22.0
fix(deps): update golang.org/x/exp digest to 7f521ea
fix(deps): update github.com/containers/luksy digest to a8846e2
imagebuildah.StageExecutor.Copy(): reject new flags for now
bump github.com/openshift/imagebuilder to v1.2.11
Rework parsing of --pull flags
fix(deps): update module github.com/containers/image/v5 to v5.31.1
imagebuildah.StageExecutor.prepare(): log the --platform flag
CI VMs: bump
buildah copy: preserve owner info with --from= a container or image
conformance tests: enable testing CompatSetParent
containerImageRef.NewImageSource(): move the FROM comment to first
commit: set "parent" for docker format only when requested
Update godoc for Builder.EnsureContainerPathAs
fix(deps): update module github.com/spf13/cobra to v1.8.1
fix(deps): update module github.com/containernetworking/cni to v1.2.0
fix(deps): update module github.com/opencontainers/runc to v1.1.13
Change default for podman build to --pull missing
fix(deps): update module github.com/containers/common to v0.59.1
Clarify definition of --pull options
buildah: fix a nil pointer reference on FreeBSD
Use /var/tmp for $TMPDIR for vfs conformance jobs
Cirrus: run `df` during job setup
conformance: use quay.io/libpod/centos:7 instead of centos:8
Stop setting "parent" in docker format
conformance: check if workdir trims path separator suffixes
push integration test: pass password to docker login via stdin
Re-enable the "copy with chown" conformance test
healthcheck: Add support for `--start-interval`
fix(deps): update module github.com/docker/docker to v26.1.4+incompatible
fix(deps): update module github.com/containerd/containerd to v1.7.18
tests: set _CONTAINERS_USERNS_CONFIGURED=done for libnetwork
Cross-build on Fedora
Drop copyStringSlice() and copyStringStringMap()
fix(deps): update module golang.org/x/crypto to v0.24.0
fix(deps): update module github.com/openshift/imagebuilder to v1.2.10
Provide an uptime_netbsd.go
Spell unix as "!windows"
Add netbsd to lists-of-OSes
fix(deps): update golang.org/x/exp digest to fd00a4e
[skip-ci] Packit: enable c10s downstream sync
CI VMs: bump, to debian with cgroups v2
Document when BlobDirectory is overridden
fix secret mounts for env vars when using chroot isolation
Change to take a types.ImageReference arg
imagebuildah: Support custom image reference lookup for cache push/pull
fix(deps): update module github.com/onsi/ginkgo/v2 to v2.19.0
Bump to v1.37.0-dev
CI: Clarify Debian use for conformance tests
## v1.36.0 (2024-05-23)
build: be more selective about specifying the default OS

View File

@ -1,3 +1,74 @@
- Changelog for vv1.37.0 (2024-07-26)
* Bump c/storage, c/image, c/common for v1.37.0
* "build with basename resolving user arg" tests: correct ARG use
* bud-multiple-platform-no-run test: correct ARG use
* imagebuildah: always have default values for $TARGET... args ready
* bump github.com/openshift/imagebuilder to v1.2.14
* fix(deps): update module github.com/docker/docker to v27.1.1+incompatible
* fix(deps): update module github.com/cyphar/filepath-securejoin to v0.3.1
* fix(deps): update module github.com/docker/docker to v27.1.0+incompatible
* CI: use local registry, part 2 of 2
* CI: use local registry, part 1 of 2
* fix(deps): update module github.com/fsouza/go-dockerclient to v1.11.1
* Revert "fix(deps): update github.com/containers/image/v5 to v5.31.1"
* Replace libimage.LookupReferenceFunc with the manifests version
* conformance tests: enable testing CompatVolumes
* conformance tests: add a test that tries to chown a volume
* imagebuildah: make traditional volume handling not the default
* StageExecutor.prepare(): mark base image volumes for preservation
* fix(deps): update module github.com/containers/image/v5 to v5.31.1
* Vendor in latest containers/(common, storage, image)
* fix(deps): update module golang.org/x/term to v0.22.0
* fix(deps): update module golang.org/x/sys to v0.22.0
* fix(deps): update golang.org/x/exp digest to 7f521ea
* fix(deps): update github.com/containers/luksy digest to a8846e2
* imagebuildah.StageExecutor.Copy(): reject new flags for now
* bump github.com/openshift/imagebuilder to v1.2.11
* Rework parsing of --pull flags
* fix(deps): update module github.com/containers/image/v5 to v5.31.1
* imagebuildah.StageExecutor.prepare(): log the --platform flag
* CI VMs: bump
* buildah copy: preserve owner info with --from= a container or image
* conformance tests: enable testing CompatSetParent
* containerImageRef.NewImageSource(): move the FROM comment to first
* commit: set "parent" for docker format only when requested
* Update godoc for Builder.EnsureContainerPathAs
* fix(deps): update module github.com/spf13/cobra to v1.8.1
* fix(deps): update module github.com/containernetworking/cni to v1.2.0
* fix(deps): update module github.com/opencontainers/runc to v1.1.13
* Change default for podman build to --pull missing
* fix(deps): update module github.com/containers/common to v0.59.1
* Clarify definition of --pull options
* buildah: fix a nil pointer reference on FreeBSD
* Use /var/tmp for $TMPDIR for vfs conformance jobs
* Cirrus: run `df` during job setup
* conformance: use quay.io/libpod/centos:7 instead of centos:8
* Stop setting "parent" in docker format
* conformance: check if workdir trims path separator suffixes
* push integration test: pass password to docker login via stdin
* Re-enable the "copy with chown" conformance test
* healthcheck: Add support for `--start-interval`
* fix(deps): update module github.com/docker/docker to v26.1.4+incompatible
* fix(deps): update module github.com/containerd/containerd to v1.7.18
* tests: set _CONTAINERS_USERNS_CONFIGURED=done for libnetwork
* Cross-build on Fedora
* Drop copyStringSlice() and copyStringStringMap()
* fix(deps): update module golang.org/x/crypto to v0.24.0
* fix(deps): update module github.com/openshift/imagebuilder to v1.2.10
* Provide an uptime_netbsd.go
* Spell unix as "!windows"
* Add netbsd to lists-of-OSes
* fix(deps): update golang.org/x/exp digest to fd00a4e
* [skip-ci] Packit: enable c10s downstream sync
* CI VMs: bump, to debian with cgroups v2
* Document when BlobDirectory is overridden
* fix secret mounts for env vars when using chroot isolation
* Change to take a types.ImageReference arg
* imagebuildah: Support custom image reference lookup for cache push/pull
* fix(deps): update module github.com/onsi/ginkgo/v2 to v2.19.0
* Bump to v1.37.0-dev
* CI: Clarify Debian use for conformance tests
- Changelog for v1.36.0 (2024-05-23)
* build: be more selective about specifying the default OS
* Bump to c/common v0.59.0

View File

@ -4,7 +4,7 @@ import (
"io"
"time"
"github.com/containers/common/libimage"
"github.com/containers/common/libimage/manifests"
nettypes "github.com/containers/common/libnetwork/types"
"github.com/containers/image/v5/docker/reference"
"github.com/containers/image/v5/types"
@ -349,25 +349,29 @@ type BuildOptions struct {
CDIConfigDir string
// CachePullSourceLookupReferenceFunc is an optional LookupReferenceFunc
// used to look up source references for cache pulls.
CachePullSourceLookupReferenceFunc libimage.LookupReferenceFunc
CachePullSourceLookupReferenceFunc manifests.LookupReferenceFunc
// CachePullDestinationLookupReferenceFunc is an optional generator
// function which provides a LookupReferenceFunc used to look up
// destination references for cache pulls.
//
// BlobDirectory will be ignored for cache pulls if this option is set.
CachePullDestinationLookupReferenceFunc func(srcRef types.ImageReference) libimage.LookupReferenceFunc
CachePullDestinationLookupReferenceFunc func(srcRef types.ImageReference) manifests.LookupReferenceFunc
// CachePushSourceLookupReferenceFunc is an optional generator function
// which provides a LookupReferenceFunc used to look up source
// references for cache pushes.
//
// BlobDirectory will be ignored for cache pushes if this option is set.
CachePushSourceLookupReferenceFunc func(dest types.ImageReference) libimage.LookupReferenceFunc
CachePushSourceLookupReferenceFunc func(dest types.ImageReference) manifests.LookupReferenceFunc
// CachePushDestinationLookupReferenceFunc is an optional
// LookupReferenceFunc used to look up destination references for cache
// pushes
CachePushDestinationLookupReferenceFunc libimage.LookupReferenceFunc
CachePushDestinationLookupReferenceFunc manifests.LookupReferenceFunc
// CompatSetParent causes the "parent" field to be set in the image's
// configuration when committing in Docker format. Newer
// BuildKit-based docker build doesn't set this field.
CompatSetParent types.OptionalBool
// CompatVolumes causes the contents of locations marked as volumes in
// base images or by a VOLUME instruction to be preserved during RUN
// instructions. Newer BuildKit-based docker build doesn't bother.
CompatVolumes types.OptionalBool
}

View File

@ -29,7 +29,7 @@ const (
// identify working containers.
Package = "buildah"
// Version for the Package. Also used by .packit.sh for Packit builds.
Version = "1.37.0-dev"
Version = "1.37.0"
// DefaultRuntime if containers.conf fails.
DefaultRuntime = "runc"

View File

@ -38,6 +38,7 @@ import (
specs "github.com/opencontainers/runtime-spec/specs-go"
"github.com/openshift/imagebuilder"
"github.com/sirupsen/logrus"
"golang.org/x/exp/maps"
"golang.org/x/exp/slices"
"golang.org/x/sync/semaphore"
)
@ -204,6 +205,9 @@ func BuildDockerfiles(ctx context.Context, store storage.Store, options define.B
if options.SystemContext == nil {
options.SystemContext = &types.SystemContext{}
}
if options.AdditionalBuildContexts == nil {
options.AdditionalBuildContexts = make(map[string]*define.AdditionalBuildContext)
}
if len(options.Platforms) == 0 {
options.Platforms = append(options.Platforms, struct{ OS, Arch, Variant string }{
@ -213,9 +217,6 @@ func BuildDockerfiles(ctx context.Context, store storage.Store, options define.B
}
if options.AllPlatforms {
if options.AdditionalBuildContexts == nil {
options.AdditionalBuildContexts = make(map[string]*define.AdditionalBuildContext)
}
options.Platforms, err = platformsForBaseImages(ctx, logger, paths, files, options.From, options.Args, options.AdditionalBuildContexts, options.SystemContext)
if err != nil {
return "", nil, err
@ -251,11 +252,7 @@ func BuildDockerfiles(ctx context.Context, store storage.Store, options define.B
logPrefix = "[" + platforms.Format(platformSpec) + "] "
}
// Deep copy args to prevent concurrent read/writes over Args.
argsCopy := make(map[string]string)
for key, value := range options.Args {
argsCopy[key] = value
}
platformOptions.Args = argsCopy
platformOptions.Args = maps.Clone(options.Args)
builds.Go(func() error {
loggerPerPlatform := logger
if platformOptions.LogFile != "" && platformOptions.LogSplitByPlatform {
@ -395,36 +392,38 @@ func buildDockerfilesOnce(ctx context.Context, store storage.Store, logger *logr
// --platform was explicitly selected for this build
// so set correct TARGETPLATFORM in args if it is not
// already selected by the user.
builtinArgDefaults := make(map[string]string)
if options.SystemContext.OSChoice != "" && options.SystemContext.ArchitectureChoice != "" {
// os component from --platform string populates TARGETOS
// buildkit parity: give priority to user's `--build-arg`
if _, ok := options.Args["TARGETOS"]; !ok {
options.Args["TARGETOS"] = options.SystemContext.OSChoice
}
builtinArgDefaults["TARGETOS"] = options.SystemContext.OSChoice
// arch component from --platform string populates TARGETARCH
// buildkit parity: give priority to user's `--build-arg`
if _, ok := options.Args["TARGETARCH"]; !ok {
options.Args["TARGETARCH"] = options.SystemContext.ArchitectureChoice
}
builtinArgDefaults["TARGETARCH"] = options.SystemContext.ArchitectureChoice
// variant component from --platform string populates TARGETVARIANT
// buildkit parity: give priority to user's `--build-arg`
if _, ok := options.Args["TARGETVARIANT"]; !ok {
if options.SystemContext.VariantChoice != "" {
options.Args["TARGETVARIANT"] = options.SystemContext.VariantChoice
}
}
builtinArgDefaults["TARGETVARIANT"] = options.SystemContext.VariantChoice
// buildkit parity: give priority to user's `--build-arg`
if _, ok := options.Args["TARGETPLATFORM"]; !ok {
// buildkit parity: TARGETPLATFORM should be always created
// from SystemContext and not `TARGETOS` and `TARGETARCH` because
// users can always override values of `TARGETOS` and `TARGETARCH`
// but `TARGETPLATFORM` should be set independent of those values.
options.Args["TARGETPLATFORM"] = options.SystemContext.OSChoice + "/" + options.SystemContext.ArchitectureChoice
if options.SystemContext.VariantChoice != "" {
options.Args["TARGETPLATFORM"] = options.Args["TARGETPLATFORM"] + "/" + options.SystemContext.VariantChoice
}
// buildkit parity: TARGETPLATFORM should be always created
// from SystemContext and not `TARGETOS` and `TARGETARCH` because
// users can always override values of `TARGETOS` and `TARGETARCH`
// but `TARGETPLATFORM` should be set independent of those values.
builtinArgDefaults["TARGETPLATFORM"] = builtinArgDefaults["TARGETOS"] + "/" + builtinArgDefaults["TARGETARCH"]
if options.SystemContext.VariantChoice != "" {
builtinArgDefaults["TARGETPLATFORM"] += "/" + options.SystemContext.VariantChoice
}
} else {
// fill them in using values for the default platform
defaultPlatform := platforms.DefaultSpec()
builtinArgDefaults["TARGETOS"] = defaultPlatform.OS
builtinArgDefaults["TARGETVARIANT"] = defaultPlatform.Variant
builtinArgDefaults["TARGETARCH"] = defaultPlatform.Architecture
builtinArgDefaults["TARGETPLATFORM"] = defaultPlatform.OS + "/" + defaultPlatform.Architecture
if defaultPlatform.Variant != "" {
builtinArgDefaults["TARGETPLATFORM"] += "/" + defaultPlatform.Variant
}
}
delete(options.Args, "TARGETPLATFORM")
for i, d := range dockerfilecontents[1:] {
additionalNode, err := imagebuilder.ParseDockerfile(bytes.NewReader(d))
@ -440,6 +439,9 @@ func buildDockerfilesOnce(ctx context.Context, store storage.Store, logger *logr
return "", nil, fmt.Errorf("creating build executor: %w", err)
}
b := imagebuilder.NewBuilder(options.Args)
for k, v := range builtinArgDefaults {
b.BuiltinArgDefaults[k] = v
}
defaultContainerConfig, err := config.Default()
if err != nil {
return "", nil, fmt.Errorf("failed to get container config: %w", err)

View File

@ -161,6 +161,7 @@ type Executor struct {
sbomScanOptions []define.SBOMScanOptions
cdiConfigDir string
compatSetParent types.OptionalBool
compatVolumes types.OptionalBool
}
type imageTypeAndHistoryAndDiffIDs struct {
@ -318,6 +319,7 @@ func newExecutor(logger *logrus.Logger, logPrefix string, store storage.Store, o
sbomScanOptions: options.SBOMScanOptions,
cdiConfigDir: options.CDIConfigDir,
compatSetParent: options.CompatSetParent,
compatVolumes: options.CompatVolumes,
}
if exec.err == nil {
exec.err = os.Stderr
@ -771,18 +773,19 @@ func (b *Executor) Build(ctx context.Context, stages imagebuilder.Stages) (image
base = child.Next.Value
}
}
builtinArgs := argsMapToSlice(stage.Builder.BuiltinArgDefaults)
headingArgs := argsMapToSlice(stage.Builder.HeadingArgs)
userArgs := argsMapToSlice(stage.Builder.Args)
// append heading args so if --build-arg key=value is not
// specified but default value is set in Containerfile
// via `ARG key=value` so default value can be used.
userArgs = append(headingArgs, userArgs...)
userArgs = append(builtinArgs, append(userArgs, headingArgs...)...)
baseWithArg, err := imagebuilder.ProcessWord(base, userArgs)
if err != nil {
return "", nil, fmt.Errorf("while replacing arg variables with values for format %q: %w", base, err)
}
b.baseMap[baseWithArg] = struct{}{}
logrus.Debugf("base for stage %d: %q", stageIndex, base)
logrus.Debugf("base for stage %d: %q resolves to %q", stageIndex, base, baseWithArg)
// Check if selected base is not an additional
// build context and if base is a valid stage
// add it to current stage's dependency tree.
@ -809,16 +812,18 @@ func (b *Executor) Build(ctx context.Context, stages imagebuilder.Stages) (image
// if following ADD or COPY needs any other
// stage.
stageName := rootfs
builtinArgs := argsMapToSlice(stage.Builder.BuiltinArgDefaults)
headingArgs := argsMapToSlice(stage.Builder.HeadingArgs)
userArgs := argsMapToSlice(stage.Builder.Args)
// append heading args so if --build-arg key=value is not
// specified but default value is set in Containerfile
// via `ARG key=value` so default value can be used.
userArgs = append(headingArgs, userArgs...)
userArgs = append(builtinArgs, append(userArgs, headingArgs...)...)
baseWithArg, err := imagebuilder.ProcessWord(stageName, userArgs)
if err != nil {
return "", nil, fmt.Errorf("while replacing arg variables with values for format %q: %w", stageName, err)
}
logrus.Debugf("stage %d name: %q resolves to %q", stageIndex, stageName, baseWithArg)
stageName = baseWithArg
// If --from=<index> convert index to name
if index, err := strconv.Atoi(stageName); err == nil {

View File

@ -44,6 +44,7 @@ import (
"github.com/openshift/imagebuilder/dockerfile/command"
"github.com/openshift/imagebuilder/dockerfile/parser"
"github.com/sirupsen/logrus"
"golang.org/x/exp/slices"
)
// StageExecutor bundles up what we need to know when executing one stage of a
@ -80,42 +81,22 @@ type StageExecutor struct {
// Preserve informs the stage executor that from this point on, it needs to
// ensure that only COPY and ADD instructions can modify the contents of this
// directory or anything below it.
// The StageExecutor handles this by caching the contents of directories which
// have been marked this way before executing a RUN instruction, invalidating
// that cache when an ADD or COPY instruction sets any location under the
// directory as the destination, and using the cache to reset the contents of
// the directory tree after processing each RUN instruction.
// When CompatVolumes is enabled, the StageExecutor handles this by caching the
// contents of directories which have been marked this way before executing a
// RUN instruction, invalidating that cache when an ADD or COPY instruction
// sets any location under the directory as the destination, and using the
// cache to reset the contents of the directory tree after processing each RUN
// instruction.
// It would be simpler if we could just mark the directory as a read-only bind
// mount of itself during Run(), but the directory is expected to be remain
// writeable while the RUN instruction is being handled, even if any changes
// made within the directory are ultimately discarded.
func (s *StageExecutor) Preserve(path string) error {
logrus.Debugf("PRESERVE %q", path)
if s.volumes.Covers(path) {
// This path is already a subdirectory of a volume path that
// we're already preserving, so there's nothing new to be done
// except ensure that it exists.
createdDirPerms := os.FileMode(0755)
if err := copier.Mkdir(s.mountPoint, filepath.Join(s.mountPoint, path), copier.MkdirOptions{ChmodNew: &createdDirPerms}); err != nil {
return fmt.Errorf("ensuring volume path exists: %w", err)
}
if err := s.volumeCacheInvalidate(path); err != nil {
return fmt.Errorf("ensuring volume path %q is preserved: %w", filepath.Join(s.mountPoint, path), err)
}
return nil
}
// Figure out where the cache for this volume would be stored.
s.preserved++
cacheDir, err := s.executor.store.ContainerDirectory(s.builder.ContainerID)
if err != nil {
return fmt.Errorf("unable to locate temporary directory for container")
}
cacheFile := filepath.Join(cacheDir, fmt.Sprintf("volume%d.tar", s.preserved))
// Save info about the top level of the location that we'll be archiving.
var archivedPath string
logrus.Debugf("PRESERVE %q in %q", path, s.builder.ContainerID)
// Try and resolve the symlink (if one exists)
// Set archivedPath and path based on whether a symlink is found or not
var archivedPath string
if evaluated, err := copier.Eval(s.mountPoint, filepath.Join(s.mountPoint, path), copier.EvalOptions{}); err == nil {
symLink, err := filepath.Rel(s.mountPoint, evaluated)
if err != nil {
@ -130,9 +111,55 @@ func (s *StageExecutor) Preserve(path string) error {
return fmt.Errorf("evaluating path %q: %w", path, err)
}
const createdDirPerms = os.FileMode(0o755)
if s.executor.compatVolumes != types.OptionalBoolTrue {
logrus.Debugf("ensuring volume path %q exists", path)
createdDirPerms := createdDirPerms
if err := copier.Mkdir(s.mountPoint, archivedPath, copier.MkdirOptions{ChmodNew: &createdDirPerms}); err != nil {
return fmt.Errorf("ensuring volume path exists: %w", err)
}
logrus.Debugf("not doing volume save-and-restore of %q in %q", path, s.builder.ContainerID)
return nil
}
if s.volumes.Covers(path) {
// This path is a subdirectory of a volume path that we're
// already preserving, so there's nothing new to be done except
// ensure that it exists.
st, err := os.Stat(archivedPath)
if errors.Is(err, os.ErrNotExist) {
// We do have to create it. That means it's not in any
// cached copy of the path that covers it, so we have
// to invalidate such cached copy.
logrus.Debugf("have to create volume %q", path)
createdDirPerms := createdDirPerms
if err := copier.Mkdir(s.mountPoint, filepath.Join(s.mountPoint, path), copier.MkdirOptions{ChmodNew: &createdDirPerms}); err != nil {
return fmt.Errorf("ensuring volume path exists: %w", err)
}
if err := s.volumeCacheInvalidate(path); err != nil {
return fmt.Errorf("ensuring volume path %q is preserved: %w", filepath.Join(s.mountPoint, path), err)
}
if st, err = os.Stat(archivedPath); err != nil {
return fmt.Errorf("checking on just-created volume path: %w", err)
}
}
s.volumeCacheInfo[path] = st
return nil
}
// Figure out where the cache for this volume would be stored.
s.preserved++
cacheDir, err := s.executor.store.ContainerDirectory(s.builder.ContainerID)
if err != nil {
return fmt.Errorf("unable to locate temporary directory for container")
}
cacheFile := filepath.Join(cacheDir, fmt.Sprintf("volume%d.tar", s.preserved))
// Save info about the top level of the location that we'll be archiving.
st, err := os.Stat(archivedPath)
if errors.Is(err, os.ErrNotExist) {
createdDirPerms := os.FileMode(0755)
logrus.Debugf("have to create volume %q", path)
createdDirPerms := os.FileMode(0o755)
if err = copier.Mkdir(s.mountPoint, archivedPath, copier.MkdirOptions{ChmodNew: &createdDirPerms}); err != nil {
return fmt.Errorf("ensuring volume path exists: %w", err)
}
@ -145,11 +172,13 @@ func (s *StageExecutor) Preserve(path string) error {
s.volumeCacheInfo[path] = st
if !s.volumes.Add(path) {
// This path is not a subdirectory of a volume path that we're
// already preserving, so adding it to the list should work.
// already preserving, so adding it to the list should have
// worked.
return fmt.Errorf("adding %q to the volume cache", path)
}
s.volumeCache[path] = cacheFile
// Now prune cache files for volumes that are now supplanted by this one.
// Now prune cache files for volumes that are newly supplanted by this one.
removed := []string{}
for cachedPath := range s.volumeCache {
// Walk our list of cached volumes, and check that they're
@ -168,6 +197,7 @@ func (s *StageExecutor) Preserve(path string) error {
removed = append(removed, cachedPath)
}
}
// Actually remove the caches that we decided to remove.
for _, cachedPath := range removed {
archivedPath := filepath.Join(s.mountPoint, cachedPath)
@ -274,7 +304,7 @@ func (s *StageExecutor) volumeCacheRestoreVFS() (err error) {
if err := copier.Remove(s.mountPoint, archivedPath, copier.RemoveOptions{All: true}); err != nil {
return err
}
createdDirPerms := os.FileMode(0755)
createdDirPerms := os.FileMode(0o755)
if err := copier.Mkdir(s.mountPoint, archivedPath, copier.MkdirOptions{ChmodNew: &createdDirPerms}); err != nil {
return err
}
@ -772,32 +802,33 @@ func (s *StageExecutor) Run(run imagebuilder.Run, config docker.Config) error {
}
namespaceOptions := append([]define.NamespaceOption{}, s.executor.namespaceOptions...)
options := buildah.RunOptions{
Args: s.executor.runtimeArgs,
Cmd: config.Cmd,
ContextDir: s.executor.contextDir,
ConfigureNetwork: s.executor.configureNetwork,
Entrypoint: config.Entrypoint,
Env: config.Env,
Hostname: config.Hostname,
Logger: s.executor.logger,
Mounts: s.executor.transientMounts,
NamespaceOptions: namespaceOptions,
NoHostname: s.executor.noHostname,
NoHosts: s.executor.noHosts,
NoPivot: os.Getenv("BUILDAH_NOPIVOT") != "",
Quiet: s.executor.quiet,
RunMounts: run.Mounts,
Runtime: s.executor.runtime,
Secrets: s.executor.secrets,
SSHSources: s.executor.sshsources,
StageMountPoints: stageMountPoints,
Stderr: s.executor.err,
Stdin: stdin,
Stdout: s.executor.out,
SystemContext: s.executor.systemContext,
Terminal: buildah.WithoutTerminal,
User: config.User,
WorkingDir: config.WorkingDir,
Args: s.executor.runtimeArgs,
Cmd: config.Cmd,
ContextDir: s.executor.contextDir,
ConfigureNetwork: s.executor.configureNetwork,
Entrypoint: config.Entrypoint,
Env: config.Env,
Hostname: config.Hostname,
Logger: s.executor.logger,
Mounts: slices.Clone(s.executor.transientMounts),
NamespaceOptions: namespaceOptions,
NoHostname: s.executor.noHostname,
NoHosts: s.executor.noHosts,
NoPivot: os.Getenv("BUILDAH_NOPIVOT") != "",
Quiet: s.executor.quiet,
CompatBuiltinVolumes: types.OptionalBoolFalse,
RunMounts: run.Mounts,
Runtime: s.executor.runtime,
Secrets: s.executor.secrets,
SSHSources: s.executor.sshsources,
StageMountPoints: stageMountPoints,
Stderr: s.executor.err,
Stdin: stdin,
Stdout: s.executor.out,
SystemContext: s.executor.systemContext,
Terminal: buildah.WithoutTerminal,
User: config.User,
WorkingDir: config.WorkingDir,
}
// Honor `RUN --network=<>`.
@ -824,20 +855,40 @@ func (s *StageExecutor) Run(run imagebuilder.Run, config docker.Config) error {
args = append([]string{"/bin/sh", "-c"}, args...)
}
}
mounts, err := s.volumeCacheSave()
if err != nil {
return err
if s.executor.compatVolumes == types.OptionalBoolTrue {
// Only bother with saving/restoring the contents of volumes if
// we've been specifically asked to.
mounts, err := s.volumeCacheSave()
if err != nil {
return err
}
options.Mounts = append(options.Mounts, mounts...)
}
options.Mounts = append(options.Mounts, mounts...)
// The list of built-in volumes isn't passed in via RunOptions, so make
// sure the builder's list of built-in volumes includes anything that
// the configuration thinks is a built-in volume.
s.builder.ClearVolumes()
for v := range config.Volumes {
s.builder.AddVolume(v)
}
if len(heredocMounts) > 0 {
options.Mounts = append(options.Mounts, heredocMounts...)
}
err = s.builder.Run(args, options)
if err2 := s.volumeCacheRestore(); err2 != nil {
if err == nil {
return err2
if s.executor.compatVolumes == types.OptionalBoolTrue {
// Only bother with saving/restoring the contents of volumes if
// we've been specifically asked to.
if err2 := s.volumeCacheRestore(); err2 != nil {
if err == nil {
return err2
}
}
}
return err
}
@ -1027,6 +1078,14 @@ func (s *StageExecutor) prepare(ctx context.Context, from string, initializeIBCo
// Make this our "current" working container.
s.mountPoint = mountPoint
s.builder = builder
// Now that the rootfs is mounted, set up handling of volumes from the base image.
s.volumeCache = make(map[string]string)
s.volumeCacheInfo = make(map[string]os.FileInfo)
for _, v := range builder.Volumes() {
if err := s.Preserve(v); err != nil {
return nil, fmt.Errorf("marking base image volume %q for preservation: %w", v, err)
}
}
}
logrus.Debugln("Container ID:", builder.ContainerID)
return builder, nil

View File

@ -361,6 +361,7 @@ func GenBuildOptions(c *cobra.Command, inputArgs []string, iopts BuildOptions) (
CDIConfigDir: iopts.CDIConfigDir,
CNIConfigDir: iopts.CNIConfigDir,
CNIPluginPath: iopts.CNIPlugInPath,
CompatVolumes: types.NewOptionalBool(iopts.CompatVolumes),
ConfidentialWorkload: confidentialWorkloadOptions,
CPPFlags: iopts.CPPFlags,
CommonBuildOpts: commonOpts,

View File

@ -119,6 +119,7 @@ type BudResults struct {
OSVersion string
CWOptions string
SBOMOptions []string
CompatVolumes bool
}
// FromAndBugResults represents the results for common flags
@ -228,6 +229,7 @@ func GetBudFlags(flags *BudResults) pflag.FlagSet {
fs.StringVar(&flags.CacheTTL, "cache-ttl", "", "only consider cache images under specified duration.")
fs.StringVar(&flags.CertDir, "cert-dir", "", "use certificates at the specified path to access the registry")
fs.BoolVar(&flags.Compress, "compress", false, "this is a legacy option, which has no effect on the image")
fs.BoolVar(&flags.CompatVolumes, "compat-volumes", false, "preserve the contents of VOLUMEs during RUN instructions")
fs.StringArrayVar(&flags.CPPFlags, "cpp-flag", []string{}, "set additional flag to pass to C preprocessor (cpp)")
fs.StringVar(&flags.Creds, "creds", "", "use `[username[:password]]` for accessing the registry")
fs.StringVarP(&flags.CWOptions, "cw", "", "", "confidential workload `options`")

View File

@ -170,6 +170,12 @@ type RunOptions struct {
// CDIConfigDir is the location of CDI configuration files, if the files in
// the default configuration locations shouldn't be used.
CDIConfigDir string
// CompatBuiltinVolumes causes the contents of locations marked as
// volumes in the container's configuration to be set up as bind mounts to
// directories which are not in the container's rootfs, hiding changes
// made to contents of those changes when the container is subsequently
// committed.
CompatBuiltinVolumes types.OptionalBool
}
// RunMountArtifacts are the artifacts created when using a run mount.

View File

@ -39,6 +39,7 @@ import (
netUtil "github.com/containers/common/libnetwork/util"
"github.com/containers/common/pkg/config"
"github.com/containers/common/pkg/subscriptions"
"github.com/containers/image/v5/types"
imageTypes "github.com/containers/image/v5/types"
"github.com/containers/storage"
"github.com/containers/storage/pkg/fileutils"
@ -1304,7 +1305,7 @@ func init() {
}
// If this succeeds, the caller must call cleanupMounts().
func (b *Builder) setupMounts(mountPoint string, spec *specs.Spec, bundlePath string, optionMounts []specs.Mount, bindFiles map[string]string, builtinVolumes, volumeMounts []string, runFileMounts []string, runMountInfo runMountInfo) (*runMountArtifacts, error) {
func (b *Builder) setupMounts(mountPoint string, spec *specs.Spec, bundlePath string, optionMounts []specs.Mount, bindFiles map[string]string, builtinVolumes []string, compatBuiltinVolumes types.OptionalBool, volumeMounts []string, runFileMounts []string, runMountInfo runMountInfo) (*runMountArtifacts, error) {
// Start building a new list of mounts.
var mounts []specs.Mount
haveMount := func(destination string) bool {
@ -1374,7 +1375,7 @@ func (b *Builder) setupMounts(mountPoint string, spec *specs.Spec, bundlePath st
}()
// Add temporary copies of the contents of volume locations at the
// volume locations, unless we already have something there.
builtins, err := runSetupBuiltinVolumes(b.MountLabel, mountPoint, cdir, builtinVolumes, int(rootUID), int(rootGID))
builtins, err := runSetupBuiltinVolumes(b.MountLabel, mountPoint, cdir, builtinVolumes, compatBuiltinVolumes, int(rootUID), int(rootGID))
if err != nil {
return nil, err
}
@ -1411,17 +1412,31 @@ func (b *Builder) setupMounts(mountPoint string, spec *specs.Spec, bundlePath st
return mountArtifacts, nil
}
func runSetupBuiltinVolumes(mountLabel, mountPoint, containerDir string, builtinVolumes []string, rootUID, rootGID int) ([]specs.Mount, error) {
func runSetupBuiltinVolumes(mountLabel, mountPoint, containerDir string, builtinVolumes []string, compatBuiltinVolumes types.OptionalBool, rootUID, rootGID int) ([]specs.Mount, error) {
var mounts []specs.Mount
hostOwner := idtools.IDPair{UID: rootUID, GID: rootGID}
// Add temporary copies of the contents of volume locations at the
// volume locations, unless we already have something there.
for _, volume := range builtinVolumes {
volumePath := filepath.Join(containerDir, "buildah-volumes", digest.Canonical.FromString(volume).Hex())
initializeVolume := false
// Make sure the volume exists in the rootfs.
createDirPerms := os.FileMode(0o755)
err := copier.Mkdir(mountPoint, filepath.Join(mountPoint, volume), copier.MkdirOptions{
ChownNew: &hostOwner,
ChmodNew: &createDirPerms,
})
if err != nil {
return nil, fmt.Errorf("ensuring volume path %q: %w", filepath.Join(mountPoint, volume), err)
}
// If we're not being asked to bind mount anonymous volumes
// onto the volume paths, we're done here.
if compatBuiltinVolumes != types.OptionalBoolTrue {
continue
}
// If we need to, create the directory that we'll use to hold
// the volume contents. If we do need to create it, then we'll
// need to populate it, too, so make a note of that.
volumePath := filepath.Join(containerDir, "buildah-volumes", digest.Canonical.FromString(volume).Hex())
initializeVolume := false
if err := fileutils.Exists(volumePath); err != nil {
if !errors.Is(err, fs.ErrNotExist) {
return nil, err
@ -1435,15 +1450,7 @@ func runSetupBuiltinVolumes(mountLabel, mountPoint, containerDir string, builtin
}
initializeVolume = true
}
// Make sure the volume exists in the rootfs and read its attributes.
createDirPerms := os.FileMode(0755)
err := copier.Mkdir(mountPoint, filepath.Join(mountPoint, volume), copier.MkdirOptions{
ChownNew: &hostOwner,
ChmodNew: &createDirPerms,
})
if err != nil {
return nil, fmt.Errorf("ensuring volume path %q: %w", filepath.Join(mountPoint, volume), err)
}
// Read the attributes of the volume's location in the rootfs.
srcPath, err := copier.Eval(mountPoint, filepath.Join(mountPoint, volume), copier.EvalOptions{})
if err != nil {
return nil, fmt.Errorf("evaluating path %q: %w", srcPath, err)

View File

@ -259,7 +259,7 @@ func (b *Builder) Run(command []string, options RunOptions) error {
SystemContext: options.SystemContext,
}
runArtifacts, err := b.setupMounts(mountPoint, spec, path, options.Mounts, bindFiles, volumes, b.CommonBuildOpts.Volumes, options.RunMounts, runMountInfo)
runArtifacts, err := b.setupMounts(mountPoint, spec, path, options.Mounts, bindFiles, volumes, options.CompatBuiltinVolumes, b.CommonBuildOpts.Volumes, options.RunMounts, runMountInfo)
if err != nil {
return fmt.Errorf("resolving mountpoints for container %q: %w", b.ContainerID, err)
}

View File

@ -475,7 +475,7 @@ rootless=%d
SystemContext: options.SystemContext,
}
runArtifacts, err := b.setupMounts(mountPoint, spec, path, options.Mounts, bindFiles, volumes, b.CommonBuildOpts.Volumes, options.RunMounts, runMountInfo)
runArtifacts, err := b.setupMounts(mountPoint, spec, path, options.Mounts, bindFiles, volumes, options.CompatBuiltinVolumes, b.CommonBuildOpts.Volumes, options.RunMounts, runMountInfo)
if err != nil {
return fmt.Errorf("resolving mountpoints for container %q: %w", b.ContainerID, err)
}

View File

@ -135,7 +135,7 @@ func (r *Runtime) layerTree(ctx context.Context, images []*Image) (*layerTree, e
// mistake. Users may not be able to recover, so we're now
// throwing a warning to guide them to resolve the issue and
// turn the errors non-fatal.
logrus.Warnf("Top layer %s of image %s not found in layer tree. The storage may be corrupted, consider running `podman system reset`.", topLayer, img.ID())
logrus.Warnf("Top layer %s of image %s not found in layer tree. The storage may be corrupted, consider running `podman system check`.", topLayer, img.ID())
continue
}
node.images = append(node.images, img)
@ -234,7 +234,7 @@ func (t *layerTree) children(ctx context.Context, parent *Image, all bool) ([]*I
// mistake. Users may not be able to recover, so we're now
// throwing a warning to guide them to resolve the issue and
// turn the errors non-fatal.
logrus.Warnf("Layer %s not found in layer tree. The storage may be corrupted, consider running `podman system reset`.", parent.TopLayer())
logrus.Warnf("Layer %s not found in layer tree. The storage may be corrupted, consider running `podman system check`.", parent.TopLayer())
return children, nil
}
@ -336,7 +336,7 @@ func (t *layerTree) parent(ctx context.Context, child *Image) (*Image, error) {
// mistake. Users may not be able to recover, so we're now
// throwing a warning to guide them to resolve the issue and
// turn the errors non-fatal.
logrus.Warnf("Layer %s not found in layer tree. The storage may be corrupted, consider running `podman system reset`.", child.TopLayer())
logrus.Warnf("Layer %s not found in layer tree. The storage may be corrupted, consider running `podman system check`.", child.TopLayer())
return nil, nil
}

View File

@ -1,4 +1,4 @@
package version
// Version is the version of the build.
const Version = "0.60.0-dev"
const Version = "0.60.0"

View File

@ -73,7 +73,7 @@ type bpCompressionStepData struct {
operation bpcOperation // What we are actually doing
uploadedOperation types.LayerCompression // Operation to use for updating the blob metadata (matching the end state, not necessarily what we do)
uploadedAlgorithm *compressiontypes.Algorithm // An algorithm parameter for the compressionOperation edits.
uploadedAnnotations map[string]string // Annotations that should be set on the uploaded blob. WARNING: This is only set after the srcStream.reader is fully consumed.
uploadedAnnotations map[string]string // Compression-related annotations that should be set on the uploaded blob. WARNING: This is only set after the srcStream.reader is fully consumed.
srcCompressorName string // Compressor name to record in the blob info cache for the source blob.
uploadedCompressorName string // Compressor name to record in the blob info cache for the uploaded blob.
closers []io.Closer // Objects to close after the upload is done, if any.
@ -323,7 +323,11 @@ func (d *bpCompressionStepData) recordValidatedDigestData(c *copier, uploadedInf
return fmt.Errorf("Internal error: Unexpected d.operation value %#v", d.operation)
}
}
if d.uploadedCompressorName != "" && d.uploadedCompressorName != internalblobinfocache.UnknownCompression {
if d.srcCompressorName == "" || d.uploadedCompressorName == "" {
return fmt.Errorf("internal error: missing compressor names (src: %q, uploaded: %q)",
d.srcCompressorName, d.uploadedCompressorName)
}
if d.uploadedCompressorName != internalblobinfocache.UnknownCompression {
if d.uploadedCompressorName != compressiontypes.ZstdChunkedAlgorithmName {
// HACK: Dont record zstd:chunked algorithms.
// There is already a similar hack in internal/imagedestination/impl/helpers.CandidateMatchesTryReusingBlobOptions,
@ -337,7 +341,7 @@ func (d *bpCompressionStepData) recordValidatedDigestData(c *copier, uploadedInf
}
}
if srcInfo.Digest != "" && srcInfo.Digest != uploadedInfo.Digest &&
d.srcCompressorName != "" && d.srcCompressorName != internalblobinfocache.UnknownCompression {
d.srcCompressorName != internalblobinfocache.UnknownCompression {
if d.srcCompressorName != compressiontypes.ZstdChunkedAlgorithmName {
// HACK: Dont record zstd:chunked algorithms, see above.
c.blobInfoCache.RecordDigestCompressorName(srcInfo.Digest, d.srcCompressorName)

View File

@ -361,8 +361,6 @@ func (d *dockerImageDestination) TryReusingBlobWithOptions(ctx context.Context,
logrus.Debugf("Error parsing BlobInfoCache location reference: %s", err)
continue
}
}
if !candidate.UnknownLocation {
if candidate.CompressionAlgorithm != nil {
logrus.Debugf("Trying to reuse blob with cached digest %s compressed with %s in destination repo %s", candidate.Digest.String(), candidate.CompressionAlgorithm.Name(), candidateRepo.Name())
} else {

View File

@ -27,7 +27,7 @@ type cache struct {
uncompressedDigests map[digest.Digest]digest.Digest
digestsByUncompressed map[digest.Digest]*set.Set[digest.Digest] // stores a set of digests for each uncompressed digest
knownLocations map[locationKey]map[types.BICLocationReference]time.Time // stores last known existence time for each location reference
compressors map[digest.Digest]string // stores a compressor name, or blobinfocache.Unknown (not blobinfocache.UnknownCompression), for each digest
compressors map[digest.Digest]string // stores a compressor name, or blobinfocache.Uncompressed (not blobinfocache.UnknownCompression), for each digest
}
// New returns a BlobInfoCache implementation which is in-memory only.

View File

@ -11,7 +11,7 @@ const (
VersionPatch = 0
// VersionDev indicates development branch. Releases will be empty string.
VersionDev = "-dev"
VersionDev = ""
)
// Version is the specification version that the package types support.

View File

@ -1 +1 @@
1.55.0-dev
1.55.0

View File

@ -401,7 +401,7 @@ type ExportImagesOptions struct {
//
// See https://goo.gl/N9XlDn for more details.
func (c *Client) ExportImages(opts ExportImagesOptions) error {
if opts.Names == nil || len(opts.Names) == 0 {
if len(opts.Names) == 0 {
return ErrMustSpecifyNames
}
// API < 1.25 allows multiple name values

View File

@ -14,8 +14,13 @@ before_install:
- yes | sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
- sudo apt-get update -q -y
- sudo apt-get -y -o Dpkg::Options::="--force-confnew" install docker-ce
- sudo systemctl enable --now docker.service && sudo systemctl enable --now docker.socket
- docker pull busybox
- docker pull centos:7
- docker pull alpine
- docker pull registry.fedoraproject.org/fedora-minimal
- docker pull registry.fedoraproject.org/fedora-minimal:41-x86_64
- docker pull registry.fedoraproject.org/fedora-minimal:41-aarch64
- chmod -R go-w ./dockerclient/testdata
script:

View File

@ -103,7 +103,11 @@ Example of usage from OpenShift's experimental `dockerbuild` [command with mount
```
docker rmi busybox; docker pull busybox
docker rmi alpine; docker pull alpine
docker rmi centos:7; docker pull centos:7
docker rmi registry.fedoraproject.org/fedora-minimal; docker pull registry.fedoraproject.org/fedora-minimal
docker rmi registry.fedoraproject.org/fedora-minimal:41-x86_64; docker pull registry.fedoraproject.org/fedora-minimal:41-x86_64
docker rmi registry.fedoraproject.org/fedora-minimal:41-aarch64; docker pull registry.fedoraproject.org/fedora-minimal:41-aarch64
chmod -R go-w ./dockerclient/testdata
go test ./dockerclient -tags conformance -timeout 30m
```

View File

@ -288,29 +288,38 @@ type Stage struct {
func NewStages(node *parser.Node, b *Builder) (Stages, error) {
var stages Stages
var allDeclaredArgs []string
for _, root := range SplitBy(node, command.Arg) {
argNode := root.Children[0]
if argNode.Value == command.Arg {
// extract declared variable
s := strings.SplitN(argNode.Original, " ", 2)
if len(s) == 2 && (strings.ToLower(s[0]) == command.Arg) {
allDeclaredArgs = append(allDeclaredArgs, s[1])
}
}
}
var headingArgs []string
if err := b.extractHeadingArgsFromNode(node); err != nil {
return stages, err
}
for k := range b.HeadingArgs {
headingArgs = append(headingArgs, k)
}
for i, root := range SplitBy(node, command.From) {
name, _ := extractNameFromNode(root.Children[0])
if len(name) == 0 {
name = strconv.Itoa(i)
}
filteredUserArgs := make(map[string]string)
for k, v := range b.UserArgs {
for _, a := range b.GlobalAllowedArgs {
if a == k {
filteredUserArgs[k] = v
}
}
}
userArgs := envMapAsSlice(filteredUserArgs)
userArgs = mergeEnv(envMapAsSlice(b.BuiltinArgDefaults), userArgs)
userArgs = mergeEnv(envMapAsSlice(builtinArgDefaults), userArgs)
userArgs = mergeEnv(envMapAsSlice(b.HeadingArgs), userArgs)
processedName, err := ProcessWord(name, userArgs)
if err != nil {
return nil, err
}
stages = append(stages, Stage{
Position: i,
Name: name,
Builder: b.builderForStage(allDeclaredArgs),
Name: processedName,
Builder: b.builderForStage(headingArgs),
Node: root,
})
}
@ -375,32 +384,41 @@ func extractNameFromNode(node *parser.Node) (string, bool) {
}
func (b *Builder) builderForStage(globalArgsList []string) *Builder {
stageBuilder := newBuilderWithGlobalAllowedArgs(b.UserArgs, globalArgsList)
for k, v := range b.HeadingArgs {
stageBuilder.HeadingArgs[k] = v
}
stageBuilder := newBuilderWithGlobalAllowedArgs(b.UserArgs, b.HeadingArgs, b.BuiltinArgDefaults, globalArgsList)
return stageBuilder
}
type Builder struct {
RunConfig docker.Config
Env []string
Args map[string]string
HeadingArgs map[string]string
UserArgs map[string]string
CmdSet bool
Author string
// Certain instructions like `FROM` will need to use
// `ARG` decalred before or not in this stage hence
// while processing instruction like `FROM ${SOME_ARG}`
// we will make sure to verify if they are declared any
// where in containerfile or not.
GlobalAllowedArgs []string
Env []string
// Args contains values originally given to NewBuilder() or set due to
// ARG instructions in a stage, either with a default value provided,
// or with a default inherited from an ARG instruction in the header
Args map[string]string
// HeadingArgs contains the values for ARG instructions in the
// Dockerfile which occurred before the first FROM instruction, either
// with a default value provided as part of the ARG instruction, or
// expecting a value to be supplied in UserArgs via NewBuilder().
HeadingArgs map[string]string
// UserArgs includes a copy of the values that were passed to
// NewBuilder(), unmodified.
UserArgs map[string]string
CmdSet bool
Author string
// GlobalAllowedArgs are args which should be resolvable in a FROM
// instruction, either built-in and always available, or introduced by
// an ARG instruction in the header.
GlobalAllowedArgs []string
// AllowedArgs are args which should be resolvable in this stage,
// having been introduced by a previous ARG instruction in this stage.
AllowedArgs map[string]bool
Volumes VolumeSet
Excludes []string
Volumes VolumeSet
Excludes []string
PendingVolumes VolumeSet
PendingRuns []Run
@ -410,13 +428,18 @@ type Builder struct {
// Raw platform string specified with `FROM --platform` of the stage
// It's up to the implementation or client to parse and use this field
Platform string
// Overrides for TARGET... and BUILD... values. TARGET... values are
// typically only necessary if the builder's target platform is not the
// same as the build platform.
BuiltinArgDefaults map[string]string
}
func NewBuilder(args map[string]string) *Builder {
return newBuilderWithGlobalAllowedArgs(args, []string{})
return newBuilderWithGlobalAllowedArgs(args, nil, nil, []string{})
}
func newBuilderWithGlobalAllowedArgs(args map[string]string, globalallowedargs []string) *Builder {
func newBuilderWithGlobalAllowedArgs(args, headingArgs, userBuiltinArgDefaults map[string]string, globalAllowedArgs []string) *Builder {
allowed := make(map[string]bool)
for k, v := range builtinAllowedBuildArgs {
allowed[k] = v
@ -427,12 +450,28 @@ func newBuilderWithGlobalAllowedArgs(args map[string]string, globalallowedargs [
userArgs[k] = v
initialArgs[k] = v
}
var copiedGlobalAllowedArgs []string
if len(globalAllowedArgs) > 0 {
copiedGlobalAllowedArgs = append([]string{}, globalAllowedArgs...)
}
copiedHeadingArgs := make(map[string]string)
for k, v := range headingArgs {
copiedHeadingArgs[k] = v
}
copiedBuiltinArgDefaults := make(map[string]string)
for k, v := range builtinArgDefaults {
copiedBuiltinArgDefaults[k] = v
}
for k, v := range userBuiltinArgDefaults {
copiedBuiltinArgDefaults[k] = v
}
return &Builder{
Args: initialArgs,
UserArgs: userArgs,
HeadingArgs: make(map[string]string),
AllowedArgs: allowed,
GlobalAllowedArgs: globalallowedargs,
Args: initialArgs,
UserArgs: userArgs,
HeadingArgs: copiedHeadingArgs,
AllowedArgs: allowed,
GlobalAllowedArgs: copiedGlobalAllowedArgs,
BuiltinArgDefaults: copiedBuiltinArgDefaults,
}
}

View File

@ -18,6 +18,7 @@ import (
docker "github.com/fsouza/go-dockerclient"
"github.com/containerd/containerd/errdefs"
"github.com/containerd/containerd/platforms"
"github.com/containers/storage/pkg/regexp"
"github.com/openshift/imagebuilder/signal"
@ -35,7 +36,7 @@ var (
var localspec = platforms.DefaultSpec()
// https://docs.docker.com/engine/reference/builder/#automatic-platform-args-in-the-global-scope
var builtinBuildArgs = map[string]string{
var builtinArgDefaults = map[string]string{
"TARGETPLATFORM": localspec.OS + "/" + localspec.Architecture,
"TARGETOS": localspec.OS,
"TARGETARCH": localspec.Architecture,
@ -48,8 +49,8 @@ var builtinBuildArgs = map[string]string{
func init() {
if localspec.Variant != "" {
builtinBuildArgs["TARGETPLATFORM"] = builtinBuildArgs["TARGETPLATFORM"] + "/" + localspec.Variant
builtinBuildArgs["BUILDPLATFORM"] = builtinBuildArgs["BUILDPLATFORM"] + "/" + localspec.Variant
builtinArgDefaults["TARGETPLATFORM"] = builtinArgDefaults["TARGETPLATFORM"] + "/" + localspec.Variant
builtinArgDefaults["BUILDPLATFORM"] = builtinArgDefaults["BUILDPLATFORM"] + "/" + localspec.Variant
}
}
@ -83,13 +84,12 @@ func env(b *Builder, args []string, attributes map[string]bool, flagArgs []strin
fmt.Printf("Str1:%v\n", flStr1)
*/
for j := 0; j < len(args); j++ {
for j := 0; j+1 < len(args); j += 2 {
// name ==> args[j]
// value ==> args[j+1]
newVar := []string{args[j] + "=" + args[j+1]}
b.RunConfig.Env = mergeEnv(b.RunConfig.Env, newVar)
b.Env = mergeEnv(b.Env, newVar)
j++
}
return nil
@ -254,7 +254,13 @@ func dispatchCopy(b *Builder, args []string, attributes map[string]bool, flagArg
var link bool
var parents bool
var excludes []string
userArgs := mergeEnv(envMapAsSlice(b.Args), b.Env)
filteredUserArgs := make(map[string]string)
for k, v := range b.Args {
if _, ok := b.AllowedArgs[k]; ok {
filteredUserArgs[k] = v
}
}
userArgs := mergeEnv(envMapAsSlice(filteredUserArgs), b.Env)
for _, a := range flagArgs {
arg, err := ProcessWord(a, userArgs)
if err != nil {
@ -323,17 +329,12 @@ func from(b *Builder, args []string, attributes map[string]bool, flagArgs []stri
case len(args) == 3 && len(args[0]) > 0 && strings.EqualFold(args[1], "as") && len(args[2]) > 0:
default:
return fmt.Errorf("FROM requires either one argument, or three: FROM <source> [as <name>]")
return fmt.Errorf("FROM requires either one argument, or three: FROM <source> [AS <name>]")
}
name := args[0]
// Support ARG before from
argStrs := []string{}
for n, v := range b.HeadingArgs {
argStrs = append(argStrs, n+"="+v)
}
defaultArgs := envMapAsSlice(builtinBuildArgs)
// Support ARG before FROM
filteredUserArgs := make(map[string]string)
for k, v := range b.UserArgs {
for _, a := range b.GlobalAllowedArgs {
@ -343,10 +344,11 @@ func from(b *Builder, args []string, attributes map[string]bool, flagArgs []stri
}
}
userArgs := mergeEnv(envMapAsSlice(filteredUserArgs), b.Env)
userArgs = mergeEnv(defaultArgs, userArgs)
nameArgs := mergeEnv(argStrs, userArgs)
userArgs = mergeEnv(envMapAsSlice(b.BuiltinArgDefaults), userArgs)
userArgs = mergeEnv(envMapAsSlice(builtinArgDefaults), userArgs)
userArgs = mergeEnv(envMapAsSlice(b.HeadingArgs), userArgs)
var err error
if name, err = ProcessWord(name, nameArgs); err != nil {
if name, err = ProcessWord(name, userArgs); err != nil {
return err
}
@ -357,7 +359,7 @@ func from(b *Builder, args []string, attributes map[string]bool, flagArgs []stri
}
}
for _, a := range flagArgs {
arg, err := ProcessWord(a, nameArgs)
arg, err := ProcessWord(a, userArgs)
if err != nil {
return err
}
@ -727,70 +729,64 @@ func healthcheck(b *Builder, args []string, attributes map[string]bool, flagArgs
return nil
}
var targetArgs = []string{"TARGETOS", "TARGETARCH", "TARGETVARIANT"}
// ARG name[=value]
//
// Adds the variable foo to the trusted list of variables that can be passed
// to builder using the --build-arg flag for expansion/subsitution or passing to 'run'.
// Dockerfile author may optionally set a default value of this variable.
func arg(b *Builder, args []string, attributes map[string]bool, flagArgs []string, original string, heredocs []buildkitparser.Heredoc) error {
var (
name string
value string
hasDefault bool
)
for _, argument := range args {
var (
name string
defaultValue string
haveDefault bool
)
arg := argument
// 'arg' can just be a name or name-value pair. Note that this is different
// from 'env' that handles the split of name and value at the parser level.
// The reason for doing it differently for 'arg' is that we support just
// defining an arg and not assign it a value (while 'env' always expects a
// defining an arg without assigning it a value (while 'env' always expects a
// name-value pair). If possible, it will be good to harmonize the two.
if strings.Contains(arg, "=") {
parts := strings.SplitN(arg, "=", 2)
name = parts[0]
value = parts[1]
hasDefault = true
if name == "TARGETPLATFORM" {
p, err := platforms.Parse(value)
if err != nil {
return fmt.Errorf("error parsing TARGETPLATFORM argument")
}
for _, val := range targetArgs {
b.AllowedArgs[val] = true
}
b.Args["TARGETPLATFORM"] = p.OS + "/" + p.Architecture
b.Args["TARGETOS"] = p.OS
b.Args["TARGETARCH"] = p.Architecture
b.Args["TARGETVARIANT"] = p.Variant
if p.Variant != "" {
b.Args["TARGETPLATFORM"] = b.Args["TARGETPLATFORM"] + "/" + p.Variant
}
}
} else if val, ok := builtinBuildArgs[arg]; ok {
name = arg
value = val
hasDefault = true
} else {
name = arg
hasDefault = false
}
name, defaultValue, haveDefault = strings.Cut(arg, "=")
// add the arg to allowed list of build-time args from this step on.
b.AllowedArgs[name] = true
// If there is still no default value, a value can be assigned from the heading args
if val, ok := b.HeadingArgs[name]; ok && !hasDefault {
b.Args[name] = val
// If the stage introduces one of the predefined args, add the
// predefined value to the list of values known in this stage
if value, defined := builtinArgDefaults[name]; defined {
if haveDefault && (name == "TARGETPLATFORM" || name == "BUILDPLATFORM") {
return fmt.Errorf("attempted to redefine %q: %w", name, errdefs.ErrInvalidArgument)
}
if b.BuiltinArgDefaults == nil {
b.BuiltinArgDefaults = make(map[string]string)
}
// N.B.: we're only consulting b.BuiltinArgDefaults for
// values that correspond to keys in
// builtinArgDefaults, which keeps the caller from
// using it to sneak in arbitrary ARG values
if _, setByUser := b.UserArgs[name]; !setByUser && defined {
if builderValue, builderDefined := b.BuiltinArgDefaults[name]; builderDefined {
b.Args[name] = builderValue
} else {
b.Args[name] = value
}
}
continue
}
// If there is a default value associated with this arg then add it to the
// b.buildArgs, later default values for the same arg override earlier ones.
// The args passed to builder (UserArgs) override the default value of 'arg'
// Don't add them here as they were already set in NewBuilder.
if _, ok := b.UserArgs[name]; !ok && hasDefault {
b.Args[name] = value
// If there is still no default value, check for a default value from the heading args
if !haveDefault {
defaultValue, haveDefault = b.HeadingArgs[name]
}
// If there is a default value provided for this arg, and the user didn't supply
// a value, then set the default value in b.Args. Later defaults given for the
// same arg override earlier ones. The args passed to the builder (UserArgs) override
// any default values of 'arg', so don't set them here as they were already set
// in NewBuilder().
if _, setByUser := b.UserArgs[name]; !setByUser && haveDefault {
b.Args[name] = defaultValue
}
}

View File

@ -12,7 +12,7 @@
#
%global golang_version 1.19
%{!?version: %global version 1.2.11}
%{!?version: %global version 1.2.14}
%{!?release: %global release 1}
%global package_name imagebuilder
%global product_name Container Image Builder

View File

@ -9,6 +9,7 @@ package imagebuilder
import (
"errors"
"fmt"
"path"
"strings"
"text/scanner"
"unicode"
@ -103,9 +104,14 @@ func (w *wordsStruct) getWords() []string {
return w.words
}
func (sw *shellWord) processStopOn(stopChar rune) (string, []string, error) {
_, result, words, err := sw.processStopOnAny([]rune{stopChar})
return result, words, err
}
// Process the word, starting at 'pos', and stop when we get to the
// end of the word or the 'stopChar' character
func (sw *shellWord) processStopOn(stopChar rune) (string, []string, error) {
func (sw *shellWord) processStopOnAny(stopChars []rune) (rune, string, []string, error) {
var result string
var words wordsStruct
@ -115,18 +121,26 @@ func (sw *shellWord) processStopOn(stopChar rune) (string, []string, error) {
'$': sw.processDollar,
}
sliceContains := func(slice []rune, value rune) bool {
for _, r := range slice {
if r == value {
return true
}
}
return false
}
for sw.scanner.Peek() != scanner.EOF {
ch := sw.scanner.Peek()
if stopChar != scanner.EOF && ch == stopChar {
sw.scanner.Next()
return result, words.getWords(), nil
if sliceContains(stopChars, ch) {
sw.scanner.Next() // skip over ch
return ch, result, words.getWords(), nil
}
if fn, ok := charFuncMapping[ch]; ok {
// Call special processing func for certain chars
tmp, err := fn()
if err != nil {
return "", []string{}, err
return ch, "", []string{}, err
}
result += tmp
@ -157,11 +171,11 @@ func (sw *shellWord) processStopOn(stopChar rune) (string, []string, error) {
}
}
if stopChar != scanner.EOF {
return "", []string{}, fmt.Errorf("unexpected end of statement while looking for matching %s", string(stopChar))
if !sliceContains(stopChars, scanner.EOF) {
return scanner.EOF, "", []string{}, fmt.Errorf("unexpected end of statement while looking for matching %s", string(stopChars))
}
return result, words.getWords(), nil
return scanner.EOF, result, words.getWords(), nil
}
func (sw *shellWord) processSingleQuote() (string, error) {
@ -281,7 +295,117 @@ func (sw *shellWord) processDollar() (string, error) {
return "", fmt.Errorf("Unsupported modifier (%c) in substitution: %s", modifier, sw.word)
}
}
return "", fmt.Errorf("Missing ':' in substitution: %s", sw.word)
if ch == '#' || ch == '%' { // strip a prefix or suffix
sw.scanner.Next() // skip over # or %
greedy := false
if sw.scanner.Peek() == ch {
sw.scanner.Next() // skip over second # or %
greedy = true
}
word, _, err := sw.processStopOn('}')
if err != nil {
return "", err
}
value := sw.getEnv(name)
switch ch {
case '#': // strip a prefix
if word == "" {
return "", fmt.Errorf("%s#: no prefix to remove", name)
}
if greedy {
for i := len(value) - 1; i >= 0; i-- {
if matches, err := path.Match(word, value[:i]); err == nil && matches {
return value[i:], nil
}
}
} else {
for i := 0; i < len(value)-1; i++ {
if matches, err := path.Match(word, value[:i]); err == nil && matches {
return value[i:], nil
}
}
}
return value, nil
case '%': // strip a suffix
if word == "" {
return "", fmt.Errorf("%s%%: no suffix to remove", name)
}
if greedy {
for i := 0; i < len(value)-1; i++ {
if matches, err := path.Match(word, value[i:]); err == nil && matches {
return value[:i], nil
}
}
} else {
for i := len(value) - 1; i >= 0; i-- {
if matches, err := path.Match(word, value[i:]); err == nil && matches {
return value[:i], nil
}
}
}
return value, nil
}
}
if ch == '/' { // perform substitution
sw.scanner.Next() // skip over /
all, begin, end := false, false, false
switch sw.scanner.Peek() {
case ch:
sw.scanner.Next() // skip over second /
all = true // replace all instances
case '#':
sw.scanner.Next() // skip over #
begin = true // replace only an prefix instance
case '%':
sw.scanner.Next() // skip over %
end = true // replace only a fuffix instance
}
// the '/', and the replacement pattern that follows
// it, can be omitted if the replacement pattern is "",
// so the pattern-to-replace can end at either a '/' or
// a '}'
ch, pattern, _, err := sw.processStopOnAny([]rune{'/', '}'})
if err != nil {
return "", err
}
if pattern == "" { // pattern to replace needs to not be empty
return "", fmt.Errorf("%s/: no pattern to replace", name)
}
var replacement string
if ch == '/' { // patter to replace it with was specified
replacement, _, err = sw.processStopOn('}')
if err != nil {
return "", err
}
}
value := sw.getEnv(name)
i := 0
for {
if i >= len(value) {
break
}
for j := len(value); j > i; j-- {
if begin && i != 0 {
continue
}
if end && j != len(value) {
continue
}
matches, err := path.Match(pattern, value[i:j])
if err == nil && matches {
value = value[:i] + replacement + value[j:]
if !all {
return value, nil
}
i += (len(replacement) - 1)
break
}
}
i++
}
return value, nil
}
return "", fmt.Errorf("Missing ':' or '#' or '%%' or '/' in substitution: %s", sw.word)
}
// $xxx case
name := sw.processName()

17
vendor/modules.txt vendored
View File

@ -109,6 +109,7 @@ github.com/chzyer/readline
github.com/containerd/cgroups/v3/cgroup1/stats
# github.com/containerd/containerd v1.7.18
## explicit; go 1.21
github.com/containerd/containerd/errdefs
github.com/containerd/containerd/pkg/userns
github.com/containerd/containerd/platforms
# github.com/containerd/errdefs v0.1.0
@ -124,7 +125,7 @@ github.com/containerd/stargz-snapshotter/estargz/errorutil
# github.com/containerd/typeurl/v2 v2.1.1
## explicit; go 1.13
github.com/containerd/typeurl/v2
# github.com/containernetworking/cni v1.2.2
# github.com/containernetworking/cni v1.2.3
## explicit; go 1.21
github.com/containernetworking/cni/libcni
github.com/containernetworking/cni/pkg/invoke
@ -139,7 +140,7 @@ github.com/containernetworking/cni/pkg/version
# github.com/containernetworking/plugins v1.5.1
## explicit; go 1.20
github.com/containernetworking/plugins/pkg/ns
# github.com/containers/buildah v1.36.1-0.20240715114330-4a82e0a3f382
# github.com/containers/buildah v1.37.0
## explicit; go 1.21.0
github.com/containers/buildah
github.com/containers/buildah/bind
@ -169,7 +170,7 @@ github.com/containers/buildah/pkg/sshagent
github.com/containers/buildah/pkg/util
github.com/containers/buildah/pkg/volumes
github.com/containers/buildah/util
# github.com/containers/common v0.59.1-0.20240717135212-fdbae3a180cb
# github.com/containers/common v0.60.0
## explicit; go 1.21.0
github.com/containers/common/internal
github.com/containers/common/internal/attributedstring
@ -242,7 +243,7 @@ github.com/containers/conmon/runner/config
# github.com/containers/gvisor-tap-vsock v0.7.4
## explicit; go 1.21
github.com/containers/gvisor-tap-vsock/pkg/types
# github.com/containers/image/v5 v5.31.1-0.20240711123249-1dbd8fbbe516
# github.com/containers/image/v5 v5.32.0
## explicit; go 1.21.0
github.com/containers/image/v5/copy
github.com/containers/image/v5/directory
@ -353,7 +354,7 @@ github.com/containers/psgo/internal/dev
github.com/containers/psgo/internal/host
github.com/containers/psgo/internal/proc
github.com/containers/psgo/internal/process
# github.com/containers/storage v1.54.1-0.20240724150347-86a0c425388b
# github.com/containers/storage v1.55.0
## explicit; go 1.21
github.com/containers/storage
github.com/containers/storage/drivers
@ -467,7 +468,7 @@ github.com/distribution/reference
github.com/docker/distribution/registry/api/errcode
github.com/docker/distribution/registry/api/v2
github.com/docker/distribution/registry/client/auth/challenge
# github.com/docker/docker v27.1.0+incompatible
# github.com/docker/docker v27.1.1+incompatible
## explicit
github.com/docker/docker/api
github.com/docker/docker/api/types
@ -526,7 +527,7 @@ github.com/felixge/httpsnoop
# github.com/fsnotify/fsnotify v1.7.0
## explicit; go 1.17
github.com/fsnotify/fsnotify
# github.com/fsouza/go-dockerclient v1.11.0
# github.com/fsouza/go-dockerclient v1.11.1
## explicit; go 1.21
github.com/fsouza/go-dockerclient
# github.com/gabriel-vasile/mimetype v1.4.3
@ -907,7 +908,7 @@ github.com/opencontainers/runtime-tools/validate/capabilities
github.com/opencontainers/selinux/go-selinux
github.com/opencontainers/selinux/go-selinux/label
github.com/opencontainers/selinux/pkg/pwalkdir
# github.com/openshift/imagebuilder v1.2.11
# github.com/openshift/imagebuilder v1.2.14
## explicit; go 1.19
github.com/openshift/imagebuilder
github.com/openshift/imagebuilder/dockerfile/command