From 8b1e46170b56dbcd5d169472603decfff75ee1ce Mon Sep 17 00:00:00 2001 From: Tom Sweeney Date: Thu, 28 May 2026 13:34:11 -0400 Subject: [PATCH] Adjust API calls for compression Add the various compression API calls as created by @nalind in #28807 Signed-off-by: Tom Sweeney --- cmd/podman/common/build.go | 48 +++++++++++++++++++++++-- pkg/api/handlers/compat/images_build.go | 19 ++++++++-- pkg/api/server/register_images.go | 12 +++++++ pkg/bindings/images/build.go | 11 ++++++ test/buildah-bud/apply-podman-deltas | 3 ++ 5 files changed, 88 insertions(+), 5 deletions(-) diff --git a/cmd/podman/common/build.go b/cmd/podman/common/build.go index 94b75f996b..d1aa3a8f0b 100644 --- a/cmd/podman/common/build.go +++ b/cmd/podman/common/build.go @@ -26,6 +26,7 @@ import ( "go.podman.io/common/pkg/completion" "go.podman.io/common/pkg/config" "go.podman.io/image/v5/docker/reference" + "go.podman.io/image/v5/pkg/compression" "go.podman.io/image/v5/types" "go.podman.io/podman/v6/cmd/podman/registry" "go.podman.io/podman/v6/cmd/podman/utils" @@ -425,9 +426,9 @@ func buildFlagsWrapperToOptions(c *cobra.Command, contextDir string, flags *Buil return nil, err } - compression := buildahDefine.Gzip + compressionIntent := buildahDefine.Gzip if flags.DisableCompression { - compression = buildahDefine.Uncompressed + compressionIntent = buildahDefine.Uncompressed } isolation := buildahDefine.IsolationDefault @@ -562,6 +563,44 @@ func buildFlagsWrapperToOptions(c *cobra.Command, contextDir string, flags *Buil sbomScanOptions = append(sbomScanOptions, *sbomScanOption) } + if c.Flag("disable-compression").Changed && flags.DisableCompression { + if c.Flag("compression-format").Changed { + return nil, errors.New("--disable-compression and --compression-format cannot be used together") + } + if c.Flag("force-compression").Changed { + return nil, errors.New("--disable-compression and --force-compression cannot be used together") + } + } + var compressionLevel *int + if c.Flag("compression-level").Changed { + compressionLevel = &flags.CompressionLevel + } else { + compressionLevel = podmanConfig.ContainersConfDefaultsRO.Engine.CompressionLevel + } + var compressionFormat *compression.Algorithm + forceCompressionFormat := flags.ForceCompressionFormat + if c.Flag("compression-format").Changed { + algo, err := compression.AlgorithmByName(flags.CompressionFormat) + if err != nil { + return nil, fmt.Errorf("unable to parse value provided %q as --compression-format: %w", flags.CompressionFormat, err) + } + compressionFormat = &algo + if !c.Flag("disable-compression").Changed { + compressionIntent = buildahDefine.Gzip + } + } else { + algo, err := compression.AlgorithmByName(podmanConfig.ContainersConfDefaultsRO.Engine.CompressionFormat) + if err != nil { + return nil, fmt.Errorf("parsing compression_format from containers.conf: %w", err) + } + compressionFormat = &algo + if !c.Flag("force-compression").Changed { + forceCompressionFormat = true + } + if !c.Flag("disable-compression").Changed { + compressionIntent = buildahDefine.Gzip + } + } opts := buildahDefine.BuildOptions{ AddCapabilities: flags.CapAdd, AdditionalTags: tags, @@ -576,7 +615,9 @@ func buildFlagsWrapperToOptions(c *cobra.Command, contextDir string, flags *Buil CacheTTL: cacheTTL, ConfidentialWorkload: confidentialWorkloadOptions, CommonBuildOpts: commonOpts, - Compression: compression, + Compression: compressionIntent, + CompressionFormat: compressionFormat, + CompressionLevel: compressionLevel, ConfigureNetwork: networkPolicy, ContextDirectory: contextDir, CPPFlags: flags.CPPFlags, @@ -585,6 +626,7 @@ func buildFlagsWrapperToOptions(c *cobra.Command, contextDir string, flags *Buil DropCapabilities: flags.CapDrop, Envs: buildahCLI.LookupEnvVarReferences(flags.Envs, os.Environ()), Err: stderr, + ForceCompressionFormat: forceCompressionFormat, ForceRmIntermediateCtrs: flags.ForceRm, From: flags.From, GroupAdd: flags.GroupAdd, diff --git a/pkg/api/handlers/compat/images_build.go b/pkg/api/handlers/compat/images_build.go index 2724200bf0..59828539e3 100644 --- a/pkg/api/handlers/compat/images_build.go +++ b/pkg/api/handlers/compat/images_build.go @@ -25,6 +25,7 @@ import ( "go.podman.io/buildah/pkg/parse" "go.podman.io/common/pkg/config" "go.podman.io/image/v5/docker/reference" + "go.podman.io/image/v5/pkg/compression" "go.podman.io/image/v5/types" "go.podman.io/podman/v6/internal/localapi" "go.podman.io/podman/v6/libpod" @@ -57,6 +58,8 @@ type BuildQuery struct { CgroupParent string `schema:"cgroupparent"` CompatVolumes bool `schema:"compatvolumes"` Compression uint64 `schema:"compression"` + CompressionFormat string `schema:"compressionFormat"` + CompressionLevel *int `schema:"compressionLevel"` ConfigureNetwork string `schema:"networkmode"` CPPFlags string `schema:"cppflags"` CpuPeriod uint64 `schema:"cpuperiod"` @@ -74,6 +77,7 @@ type BuildQuery struct { Envs []string `schema:"setenv"` Excludes string `schema:"excludes"` ForceRm bool `schema:"forcerm"` + ForceCompressionFormat bool `schema:"forceCompressionFormat"` From string `schema:"from"` GroupAdd []string `schema:"groupadd"` HTTPProxy bool `schema:"httpproxy"` @@ -385,7 +389,7 @@ func createBuildOptions(query *BuildQuery, buildCtx *BuildContext, queryValues u compatVolumes, _ := utils.ParseOptionalBool(query.CompatVolumes, "compatvolumes", queryValues) - compression := archive.Compression(query.Compression) + compressionIntent := archive.Compression(query.Compression) if query.StageLabels && !query.SaveStages { return nil, nil, utils.GetGenericBadRequestError(errors.New("stage-labels requires save-stages be set as well")) @@ -694,6 +698,15 @@ func createBuildOptions(query *BuildQuery, buildCtx *BuildContext, queryValues u sbomScanOptions = append(sbomScanOptions, *sbomScanOption) } + var compressionFormat *compression.Algorithm + if query.CompressionFormat != "" { + algo, err := compression.AlgorithmByName(query.CompressionFormat) + if err != nil { + return nil, cleanup, utils.GetBadRequestError("compressionFormat", query.CompressionFormat, err) + } + compressionFormat = &algo + } + // Create build options buildOptions := &buildahDefine.BuildOptions{ AddCapabilities: addCaps, @@ -732,8 +745,10 @@ func createBuildOptions(query *BuildQuery, buildCtx *BuildContext, queryValues u Volumes: query.Volumes, }, CompatVolumes: compatVolumes, + CompressionFormat: compressionFormat, + CompressionLevel: query.CompressionLevel, CreatedAnnotation: query.CreatedAnnotation, - Compression: compression, + Compression: compressionIntent, ConfigureNetwork: parseNetworkConfigurationPolicy(query.ConfigureNetwork), ContextDirectory: buildCtx.ContextDirectory, Devices: devices, diff --git a/pkg/api/server/register_images.go b/pkg/api/server/register_images.go index 148ec70382..2c41e149a1 100644 --- a/pkg/api/server/register_images.go +++ b/pkg/api/server/register_images.go @@ -289,6 +289,18 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error { // type: boolean // description: Use compression on image. // - in: query + // name: compressionFormat + // type: string + // description: The type of compression to apply to layer blobs pushed to build caches in registries. + // - in: query + // name: compressionLevel + // type: integer + // description: The level of compression to apply to layer blobs pushed to build caches in registries. The range of acceptable values varies based on the compression format. + // - in: query + // name: forceCompressionFormat + // type: boolean + // description: Use the specified compression format for layer blobs, even when pushing to a location where an equivalent blob which differs only in how it's compressed could be reused. + // - in: query // name: destination // type: string // description: Allows for pushing the image to a different destination than the image refers to. diff --git a/pkg/bindings/images/build.go b/pkg/bindings/images/build.go index 500c205dc6..a0bda74530 100644 --- a/pkg/bindings/images/build.go +++ b/pkg/bindings/images/build.go @@ -175,6 +175,17 @@ func prepareParams(options types.BuildOptions) (url.Values, error) { } params.Set("idmappingoptions", string(idmappingsOptions)) } + if options.CompressionFormat != nil { + params.Set("compressionFormat", options.CompressionFormat.Name()) + } + if options.CompressionLevel != nil { + params.Set("compressionLevel", strconv.Itoa(*options.CompressionLevel)) + } + if options.ForceCompressionFormat { + params.Set("forceCompressionFormat", "1") + } else { + params.Set("forceCompressionFormat", "0") + } if buildArgs := options.Args; len(buildArgs) > 0 { bArgs, err := jsoniter.MarshalToString(buildArgs) if err != nil { diff --git a/test/buildah-bud/apply-podman-deltas b/test/buildah-bud/apply-podman-deltas index bfd8776576..7d0e8dc883 100755 --- a/test/buildah-bud/apply-podman-deltas +++ b/test/buildah-bud/apply-podman-deltas @@ -349,6 +349,9 @@ skip "Requires bit-identical tar outputs when using process substitution" \ "use-secret-to-env-variable" \ "use-secret-to-env-variable-and-file-path" +skip_if_remote "remote builds only commit to local storage, and this test isn't worth working around that" \ + "build --compression-format zstd to dir and oci-archive" + # END temporary workarounds that must be reevaluated periodically ###############################################################################