Skip to content

Allow enabling versioning on buckets with a GCP location constraint - #6266

Draft
maeldonn wants to merge 3 commits into
development/9.4from
improvement/CLDSRV-984
Draft

Allow enabling versioning on buckets with a GCP location constraint#6266
maeldonn wants to merge 3 commits into
development/9.4from
improvement/CLDSRV-984

Conversation

@maeldonn

Copy link
Copy Markdown
Contributor

Not handled yet

Gap Impact What it would take
S3 has a suspended versioning state, with null version ids. GCS versioning is only on or off A GCP location cannot represent a suspended bucket Decide whether to reject the configuration or emulate the state
Object versioning on the GCS bucket is a hard requirement: without it, the delete issued behind a delete marker destroys the data instead of archiving it Silent data loss Block writes on a non-versioned bucket, instead of only reporting it in the healthcheck
GCS lifecycle rules on noncurrent versions (isLive: false, daysSinceNoncurrentTime, numNewerVersions) can reap generations that S3 still serves as current Deferred and silent data loss, with no error at write time Document the precondition, and consider detecting such rules at configuration time
GCS never promotes a noncurrent generation, so the backend state diverges from the S3 view after an undelete or a version delete Confusing during support, and the root cause of the lifecycle exposure above Optional: promote by copy, accepting the new generation, the non-atomicity and the storage class reset

@bert-e

bert-e commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

Hello maeldonn,

My role is to assist you with the merge of this
pull request. Please type @bert-e help to get information
on this process, or consult the user documentation.

Available options
name description privileged authored
/after_pull_request Wait for the given pull request id to be merged before continuing with the current one.
/bypass_author_approval Bypass the pull request author's approval
/bypass_build_status Bypass the build and test status
/bypass_commit_size Bypass the check on the size of the changeset TBA
/bypass_incompatible_branch Bypass the check on the source branch prefix
/bypass_jira_check Bypass the Jira issue check
/bypass_peer_approval Bypass the pull request peers' approval
/bypass_leader_approval Bypass the pull request leaders' approval
/bypass_source_branch_lineage Bypass the cross-branch contamination check
/approve Instruct Bert-E that the author has approved the pull request. ✍️
/create_pull_requests Allow the creation of integration pull requests.
/create_integration_branches Allow the creation of integration branches.
/no_octopus Prevent Wall-E from doing any octopus merge and use multiple consecutive merge instead
/unanimity Change review acceptance criteria from one reviewer at least to all reviewers
/wait Instruct Bert-E not to run until further notice.
Available commands
name description privileged
/help Print Bert-E's manual in the pull request.
/status Print Bert-E's current status in the pull request.
/clear Remove all comments from Bert-E from the history TBA
/retry Re-start a fresh build TBA
/build Re-start a fresh build TBA
/force_reset Delete integration branches & pull requests, and restart merge process from the beginning.
/reset Try to remove integration branches unless there are commits on them which do not appear on the source branch.

Status report is not available.

@bert-e

bert-e commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

Incorrect fix version

The Fix Version/s in issue CLDSRV-984 contains:

  • None

Considering where you are trying to merge, I ignored possible hotfix versions and I expected to find:

  • 9.4.3

Please check the Fix Version/s of CLDSRV-984, or the target
branch of this pull request.

Comment thread package.json
@codecov

codecov Bot commented Aug 31, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 89.65517% with 6 lines in your changes missing coverage. Please review.
✅ Project coverage is 86.50%. Comparing base (ff75a60) to head (5749a75).
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
lib/api/bucketPutVersioning.js 88.88% 6 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

Files with missing lines Coverage Δ
lib/api/apiUtils/object/createAndStoreObject.js 87.03% <100.00%> (+0.61%) ⬆️
lib/api/multiObjectDelete.js 83.69% <100.00%> (ø)
lib/api/objectCopy.js 89.74% <100.00%> (ø)
lib/api/bucketPutVersioning.js 90.00% <88.88%> (-0.11%) ⬇️

... and 1 file with indirect coverage changes

@@                 Coverage Diff                 @@
##           development/9.4    #6266      +/-   ##
===================================================
+ Coverage            86.45%   86.50%   +0.05%     
===================================================
  Files                  212      212              
  Lines                14578    14577       -1     
===================================================
+ Hits                 12603    12610       +7     
+ Misses                1975     1967       -8     
Flag Coverage Δ
checksums-disabled-tests 35.30% <13.79%> (+<0.01%) ⬆️
file-ft-tests 70.00% <84.48%> (-0.01%) ⬇️
file-ft-tests-null-compat 70.52% <84.48%> (+0.04%) ⬆️
kmip-ft-tests 28.07% <13.79%> (+<0.01%) ⬆️
mongo-v0-ft-tests 71.13% <84.48%> (+0.04%) ⬆️
mongo-v1-ft-tests 71.08% <84.48%> (-0.01%) ⬇️
multiple-backend 36.07% <65.51%> (-0.01%) ⬇️
s3c-ft-tests-v0 65.01% <84.48%> (-0.01%) ⬇️
s3c-ft-tests-v0-null-compat 65.06% <84.48%> (-0.01%) ⬇️
s3c-ft-tests-v1 65.00% <84.48%> (+0.01%) ⬆️
sur-tests 36.61% <65.51%> (-0.01%) ⬇️
sur-tests-inflights 39.43% <65.51%> (-0.01%) ⬇️
unit 74.18% <82.75%> (+<0.01%) ⬆️
utapi-v2-tests 35.28% <67.24%> (-0.01%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@bert-e

bert-e commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

Waiting for approval

The following approvals are needed before I can proceed with the merge:

  • the author

  • 2 peers

Arsenal now supports versioning on the GCP backend, so drop gcp from
versioningNotImplBackends and stop naming it in the error messages.

Issue: CLDSRV-984
@maeldonn
maeldonn force-pushed the improvement/CLDSRV-984 branch from 860728b to 9c78d85 Compare August 31, 2026 14:22
Comment thread lib/api/bucketPutVersioning.js Dismissed
Comment thread lib/api/bucketPutVersioning.js Dismissed
Comment thread lib/api/bucketPutVersioning.js Dismissed
Comment thread lib/api/bucketPutVersioning.js Dismissed
A delete marker has no body, but createAndStoreObject took its checksum
from the request headers, which on a multi-object delete cover the request
XML. On an external location the mismatch failed the put, and the rollback
error then hit an unguarded result.versionId in multiObjectDelete, killing
the worker with a 502. Skip the header checksum for delete markers, and
guard the result so any later error is returned as a proper S3 error.

Issue: CLDSRV-984
@maeldonn
maeldonn force-pushed the improvement/CLDSRV-984 branch from 9c78d85 to 5749a75 Compare August 31, 2026 14:29

@francoisferrand francoisferrand left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

S3 has a suspended versioning state, with nullversion ids. GCS versioning is only on or off

Suspended versioning is really just a name : in our implementation it differs (so in particular performance may not be the same), but functionally suspended is about the same as off?
i.e. is suspended not just a different name for no versioning (no versioning → versioning ←→ suspended versioning), so we could map both no & suspended versioning on GCP's disabled versioning?

Object versioning on the GCS bucket is a hard requirement: without it, the delete issued behind a delete marker destroys the data instead of archiving it

  • not sure what you mean, there is no "archiving" in S3...
  • if using GCP versioning is not practical, another option would be to "flatten" the versions: i.e. store each version side-by-side, as <objKey>.<scalVersionId>

Block writes on a non-versioned bucket, instead of only reporting it in the healthcheck

If there a GCP "extension" to make the putObject/deleteObject conditional on versioning? Otherwise this may be very costly....

GCS lifecycle rules on noncurrent versions (isLive: false, daysSinceNoncurrentTime, numNewerVersions) can reap generations that S3 still serves as current

  • Should be part of the documentation, and may be verified when creating location and/or enabling versioning (though none of these are foolproof, and we still risk a data loss)
  • Or a reason to switch to "emulating" versions by flattening them....

GCS never promotes a noncurrent generation, so the backend state diverges from the S3 view after an undelete or a version delete

That is not really a problem for us, right: The issue is more about what the user would see in GCP's bucket?

All in all, I don't think we should merge this -and esp. in 9.4- but take the time to make a (short) design in Citadel : so we can align on the requirements and limits of the solution (i.e. do we want to keep the same "view" on GCP, or is this really just data storage, accessed only through the product ? what to do with GCP-side lifecycle rules ? ...)

// A delete marker has no body: an x-amz-checksum-* header
// describes the request payload (e.g. a multi-object delete XML).
const headerChecksum =
isDeleteMarker || !areChecksumsEnabled() ? null : getChecksumDataFromHeaders(request.headers);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Is this not an issue for other data locations as well? Ie a separate bugfix for integrity check feature?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

no change here AFAICS, only removal of " or GCP" in the externalVersioningErrorMessage const?

const missingVerIdInternalError = errorInstances.InternalError.customizeDescription(
'Invalid state. Please ensure versioning is enabled ' +
'in AWS for the location constraint and try again.'
'Invalid state. Please ensure versioning is enabled ' + 'in AWS for the location constraint and try again.',

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
'Invalid state. Please ensure versioning is enabled ' + 'in AWS for the location constraint and try again.',
'Invalid state. Please ensure versioning is enabled in AWS for the location constraint and try again.',

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

same for a few below

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

  • the GPC removal should not go in 9.4, but 9.5
  • I wonder if we should build the strings, instead of having the source of truth in 2 constants (one in arsenal + one in cloudserver) AND having manually duplicated that info in multiple error strings...

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants