Skip to content

no-jira: cluster-api: use zstd for compression#10450

Open
patrickdillon wants to merge 1 commit intoopenshift:mainfrom
patrickdillon:capi-zstd
Open

no-jira: cluster-api: use zstd for compression#10450
patrickdillon wants to merge 1 commit intoopenshift:mainfrom
patrickdillon:capi-zstd

Conversation

@patrickdillon
Copy link
Copy Markdown
Contributor

Prior to this commit, the installer built all capi providers and zipped them with no compression. This updates that approach to use zstd to compress (and decompress the providers). It decreases the installer binary size from 618M -> 533M (roughly 14%).

Prior to this commit, the installer built all capi providers and
zipped them with no compression. This updates that approach to use
zstd to compress (and decompress the providers). It decreases the
installer binary size from 618M -> 533M (roughly 14%).
@openshift-ci-robot openshift-ci-robot added the jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. label Mar 31, 2026
@openshift-ci-robot
Copy link
Copy Markdown
Contributor

@patrickdillon: This pull request explicitly references no jira issue.

Details

In response to this:

Prior to this commit, the installer built all capi providers and zipped them with no compression. This updates that approach to use zstd to compress (and decompress the providers). It decreases the installer binary size from 618M -> 533M (roughly 14%).

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

@openshift-ci openshift-ci bot requested review from bfournie and jhixson74 March 31, 2026 17:36
@openshift-ci
Copy link
Copy Markdown
Contributor

openshift-ci bot commented Mar 31, 2026

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by:
Once this PR has been reviewed and has the lgtm label, please assign dtantsur for approval. For more information see the Code Review Process.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@patrickdillon
Copy link
Copy Markdown
Contributor Author

/cc @dlom

@openshift-ci openshift-ci bot requested a review from dlom March 31, 2026 17:36
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 31, 2026

Walkthrough

The pull request transitions the binary packaging and extraction strategy from ZIP archives to Zstandard (zstd) compression format. The build script now generates a shared compression dictionary and produces individual .zst files per binary. The extraction code is refactored to load the embedded dictionary and decompress zstd-compressed provider files instead of handling zip archives.

Changes

Cohort / File(s) Summary
Dependency Management
go.mod
Mark github.com/klauspost/compress as a direct dependency by removing the // indirect comment.
Build System
hack/build-cluster-api.sh
Replace zip packaging with zstd compression: remove prior .zst and dict artifacts, train a shared dictionary from all binaries, and create individual .zst files per binary compressed with that dictionary.
Extraction Logic
pkg/clusterapi/providers.go
Refactor Provider.Extract to load embedded zstd dictionary and decompress individual provider .zst files instead of extracting from a single zip archive. Add decompressFile function for zstd decompression with dictionary context and remove prior zip handling and helper functions (unpackFile, sanitizeArchivePath).

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 golangci-lint (2.11.4)

Error: can't load config: unsupported version of the configuration: "" See https://golangci-lint.run/docs/product/migration-guide for migration instructions
The command is terminated due to an error: can't load config: unsupported version of the configuration: "" See https://golangci-lint.run/docs/product/migration-guide for migration instructions


Comment @coderabbitai help to get the list of available commands and usage tips.

@patrickdillon
Copy link
Copy Markdown
Contributor Author

/test e2e-gcp-ovn e2e-azure-ovn e2e-openstack-ovn e2e-nutanix-ovn e2e-vsphere-ovn

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@pkg/clusterapi/providers.go`:
- Around line 119-127: The decompressed file at destPath is left with
unpredictable mode bits and Close errors are ignored; after writing with
os.OpenFile (destPath, ...), ensure you explicitly set the final executable mode
(e.g., os.Chmod(destPath, 0o755) or a properly restrictive mode) once io.Copy to
dest completes, and surface any errors from dest.Close() and os.Chmod by
returning/wrapping them; reference destPath, dest (the *os.File returned by
os.OpenFile), decoder and the io.Copy/Close sequence when making the change.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 56146467-c2ca-4ad0-89e6-9903a8f8775b

📥 Commits

Reviewing files that changed from the base of the PR and between 3fa9ca0 and 2fc5609.

📒 Files selected for processing (3)
  • go.mod
  • hack/build-cluster-api.sh
  • pkg/clusterapi/providers.go

Comment on lines +119 to 127
dest, err := os.OpenFile(destPath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0o777)
if err != nil {
return err
}
defer destFile.Close()
if _, err := io.CopyN(destFile, src, f.FileInfo().Size()); err != nil {
return err
}
return nil
}
defer dest.Close()

func sanitizeArchivePath(d, t string) (v string, err error) {
v = filepath.Join(d, t)
if strings.HasPrefix(v, filepath.Clean(d)) {
return v, nil
if _, err := io.Copy(dest, decoder); err != nil {
return fmt.Errorf("failed to decompress: %w", err)
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Restore executable permissions explicitly after decompression.

Raw .zst payloads no longer carry the mode bits the zip path used to preserve. OpenFile(..., 0o777) only affects brand-new files and relies on umask, so reruns can leave a stale non-executable mode in place and first-time extracts can be overly permissive. Since these files are executed later, set the final mode explicitly and surface Close errors.

Possible hardening
-	dest, err := os.OpenFile(destPath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0o777)
+	dest, err := os.OpenFile(destPath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0o600)
 	if err != nil {
 		return err
 	}
-	defer dest.Close()
 
 	if _, err := io.Copy(dest, decoder); err != nil {
-		return fmt.Errorf("failed to decompress: %w", err)
+		dest.Close()
+		return fmt.Errorf("failed to decompress %s: %w", destPath, err)
 	}
+	if err := dest.Close(); err != nil {
+		return fmt.Errorf("failed to close %s: %w", destPath, err)
+	}
+	if err := os.Chmod(destPath, 0o755); err != nil {
+		return fmt.Errorf("failed to chmod %s: %w", destPath, err)
+	}
 	return nil
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
dest, err := os.OpenFile(destPath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0o777)
if err != nil {
return err
}
defer destFile.Close()
if _, err := io.CopyN(destFile, src, f.FileInfo().Size()); err != nil {
return err
}
return nil
}
defer dest.Close()
func sanitizeArchivePath(d, t string) (v string, err error) {
v = filepath.Join(d, t)
if strings.HasPrefix(v, filepath.Clean(d)) {
return v, nil
if _, err := io.Copy(dest, decoder); err != nil {
return fmt.Errorf("failed to decompress: %w", err)
}
dest, err := os.OpenFile(destPath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0o600)
if err != nil {
return err
}
if _, err := io.Copy(dest, decoder); err != nil {
dest.Close()
return fmt.Errorf("failed to decompress %s: %w", destPath, err)
}
if err := dest.Close(); err != nil {
return fmt.Errorf("failed to close %s: %w", destPath, err)
}
if err := os.Chmod(destPath, 0o755); err != nil {
return fmt.Errorf("failed to chmod %s: %w", destPath, err)
}
return nil
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/clusterapi/providers.go` around lines 119 - 127, The decompressed file at
destPath is left with unpredictable mode bits and Close errors are ignored;
after writing with os.OpenFile (destPath, ...), ensure you explicitly set the
final executable mode (e.g., os.Chmod(destPath, 0o755) or a properly restrictive
mode) once io.Copy to dest completes, and surface any errors from dest.Close()
and os.Chmod by returning/wrapping them; reference destPath, dest (the *os.File
returned by os.OpenFile), decoder and the io.Copy/Close sequence when making the
change.

@patrickdillon
Copy link
Copy Markdown
Contributor Author

hack/build-cluster-api.sh: line 24: zstd: command not found

well, that would be a problem

@patrickdillon
Copy link
Copy Markdown
Contributor Author

/close

@openshift-ci openshift-ci bot closed this Mar 31, 2026
@openshift-ci
Copy link
Copy Markdown
Contributor

openshift-ci bot commented Mar 31, 2026

@patrickdillon: Closed this PR.

Details

In response to this:

/close

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository.

@patrickdillon
Copy link
Copy Markdown
Contributor Author

following up with art about getting zstd in builder images

@patrickdillon
Copy link
Copy Markdown
Contributor Author

/open
/hold
zstd is now only in the ci builder image, not in osbs, yet. Let's test the effect on build time

@openshift-ci openshift-ci bot added the do-not-merge/hold Indicates that a PR should not merge because someone has issued a /hold command. label Mar 31, 2026
@patrickdillon patrickdillon reopened this Mar 31, 2026
@patrickdillon
Copy link
Copy Markdown
Contributor Author

/retest

@patrickdillon
Copy link
Copy Markdown
Contributor Author

Depends on openshift-eng/ocp-build-data#9740

@patrickdillon
Copy link
Copy Markdown
Contributor Author

patrickdillon commented Mar 31, 2026

zstd is now only in the ci builder image, not in osbs, yet. Let's test the effect on build time

Correction: zstd is being added to the builder image, should be available by tomorrow

@patrickdillon
Copy link
Copy Markdown
Contributor Author

/retest

@openshift-ci
Copy link
Copy Markdown
Contributor

openshift-ci bot commented Apr 1, 2026

@patrickdillon: The following tests failed, say /retest to rerun all failed tests or /retest-required to rerun all mandatory failed tests:

Test name Commit Details Required Rerun command
ci/prow/e2e-vsphere-ovn 2fc5609 link true /test e2e-vsphere-ovn
ci/prow/okd-scos-images 2fc5609 link true /test okd-scos-images
ci/prow/e2e-nutanix-ovn 2fc5609 link false /test e2e-nutanix-ovn
ci/prow/images 2fc5609 link true /test images
ci/prow/e2e-openstack-ovn 2fc5609 link true /test e2e-openstack-ovn
ci/prow/e2e-azure-ovn 2fc5609 link true /test e2e-azure-ovn
ci/prow/artifacts-images 2fc5609 link true /test artifacts-images
ci/prow/e2e-aws-ovn 2fc5609 link true /test e2e-aws-ovn
ci/prow/e2e-gcp-ovn 2fc5609 link true /test e2e-gcp-ovn

Full PR test history. Your PR dashboard.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. I understand the commands that are listed here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

do-not-merge/hold Indicates that a PR should not merge because someone has issued a /hold command. jira/valid-reference Indicates that this PR references a valid Jira ticket of any type.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants