8000 #8183: Add S3 provider for Hetzner object storage by spiffytech · Pull Request #8551 · rclone/rclone · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

#8183: Add S3 provider for Hetzner object storage #8551

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

spiffytech
Copy link
@spiffytech spiffytech commented May 12, 2025

What is the purpose of this change?

This PR closes issue #8183: adding an S3 provider for Hetzner Object Storage.

Was the change discussed in an issue or in the forum before?

#8183

Notes

Hetzner test performance

Hetzner only offers European regions for their object storage.

When I ran the integration tests from my home in North Carolina, or my VPS in Virginia, they blew past the 10-minute test timeout (especially the chunk tests).

When I used a Hetzner VPS in Finland, they ran well under the limit.

Yay, trans-Atlantic latency!

Hetzner useAlreadyExists behavior

The existing integration tests appear to assume that if a bucket is being asynchronously deleted, and you request creating a new bucket with the same name, the provider honor the bucket create command (cancelling the deletion?).

Hetzner doesn't do this. You'll get a create error (which the S3 fs code swallows), then the bucket still gets deleted, and then all the tests error out because they try to use a bucket that doesn't exist.

I considered waiting until the API reported the bucket name is available for reuse, but we can't count on every provider doing that swiftly. Hetzner, at least, is slow to report that the name is free. If we were recreating the bucket into a different region, AWS is known to take over an hour.

Instead, I altered the tests to use a new bucket name each time they request a bucket. With this change, the tests pass under Hetzner and AWS. I don't know if this breaks any assumptions.

Please let me know if this isn't the right way to handle this!

I considered extracting the fs.NewFS() + f.mkDir() + error handling into a reusable function, but it wasn't clear that there was a unified abstraction across the tests. That pattern appeared in several places, some others seemed to want manual control over those steps, and others used operations.MkDir() instead of f.MkDir(). I tried to keep the change small and concrete until I get feedback otherwise.

rclone-s3 (2)

rclone-hetzner

Checklist

  • I have read the contribution guidelines.
  • I have added tests for all changes in this PR if appropriate.
  • I have added documentation for the changes if appropriate.
  • All commit messages are in house style.
  • I'm done, this Pull Request is ready for review :-)

@ncw
Copy link
Member
ncw commented May 15, 2025

The existing integration tests appear to assume that if a bucket is being asynchronously deleted, and you request creating a new bucket with the same name, the provider honor the bucket create command (cancelling the deletion?).

I'm not particularly happy about altering the integration tests just for one provider.

The azureblob backend has a similar problem too and what it does is check the create error (hopefully it is speci 8000 fic enough) and sleep and retry. Could we use that technique here too?

@spiffytech
Copy link
Author
spiffytech commented May 15, 2025

Very understandable.

Note that this PR creates a new S3 provider, not a separate backend like azureblob. The proposal to retry would require changing the behavior for all S3 providers, or special-casing Hetzner Object Storage. Or maybe a new quirk? Are any of these choices acceptable, or do we need to look at a different approach?

Hetzner returns BucketAlreadyExists for buckets pending deletion. s3.go makeBucket explicitly swallows that error if quirk useAlreadyExists is false (which it is for Hetzner). Is it appropriate for all S3 providers to stop swallowing the error and switch to retry?

// Current code
case "BucketAlreadyExists", "BucketNameUnavailable":
    if f.opt.UseAlreadyExists.Value {
        // We can trust BucketAlreadyExists to mean not owned by us, so make it non retriable
        err = fserrors.NoRetryError(err)
    } else {
        // We can't trust BucketAlreadyExists to mean not owned by us, so ignore it
        err = nil
    }
}

I've implemented the retry logic by mimicking azureblob makeContainer. It's not perfect: S3's Pacer only does 2 retries. That's enough to get the tests passing today, but who knows how fast or slow any given delete will be.

With this change, all tests pass except one:

Test FsListRootedSubdir fails. I think it assumes BucketCreate is idempotent, and relies on the current error-swallowing behavior. The test calls testPut ➜ ... PutTestContentsMetadata ➜ ... NewFs against a bucket that already exists and is not pending deletion. So the tests just keep retrying, waiting for CreateBucket to stop returning BucketAlreadyExists.

I cannot see a way for Hetzner Object Storage to handle CreateBucket idempotently. The error for a permanent bucket is the same as for one that'll disappear any second. And we can't just ask "does this bucket exist" because we can't tell whether it's pending deletion.

Next steps
I need input to proceed with this PR:

  1. How should s3.go know to apply Hetzner-specific behavior?
    • A new quirk seems the least intrusive. Is this an appropriate use of quirks?
  2. How can we preserve CreateBucket idempotence with Hetzner?
  3. Can we have makeBucket use more retries than S3 Pacer's default?

@spiffytech
Copy link
Author

I've pushed an update backing out the changes to the integration tests, and adding a retry for CreateBucket. This is WIP and isn't ready to merge, as noted above.

@ncw
Copy link
Member
ncw commented May 16, 2025
  • How should s3.go know to apply Hetzner-specific behavior?

    • A new quirk seems the least intrusive. Is this an appropriate use of quirks?

Absolutely. That is what quirks are for. Make sure you name it for what it does, not fixHetzner.

  • How can we preserve CreateBucket idempotence with Hetzner?

Good question!

We could just decide that one test failure is ok. Does it work if you just run that test with the -run flag? If so the integration tester would run tes tests, get one failure, and retry that test.

  • Can we have makeBucket use more retries than S3 Pacer's default?

The AWS SDK reties 10 times for most things anyway which is why we only use 2 by default.

You could just have a bit of manual logic, or make a new pacer, whichever you fancy. I think if the tests pass today it probably isn't worth worrying about too much though.

@spiffytech
Copy link
Author

Does it work if you just run that test with the -run flag?

Nope: because an Fs is initialized at the top of the test suite, running just FsListRootedSubdir still fails to create the bucket.

I think if the tests pass today it probably isn't worth worrying about too much though.

Sounds good. YAGNI!


I've pushed an update that adds the quirk. Given we're willing to accept one test failure, I think this is ready for review!

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.

2 participants
0