Conversation
a69e251 to
93b80d1
Compare
230cd5a to
cc66878
Compare
4e7c568 to
9a45943
Compare
stephanme
left a comment
There was a problem hiding this comment.
storage_client.go is huge and includes lots of logic. But it has no unit tests, i.e. it is only covered by the integration tests.
The old implementation had tests for the commands.
| - Partitioned paths: `ab/cd/my-blob-id` | ||
| - Nested paths: `folder/subfolder/my-blob-id` | ||
|
|
||
| All are stored exactly as specified. If your use case requires a specific directory layout (e.g., partitioning by hash prefix), implement this in the caller before invoking storage-cli. |
There was a problem hiding this comment.
We should mention this in the release notes because it is an surprising / incompatible change for bosh. Bosh needs to add the 1 byte checksum prefix to the object id before calling storage-cli when using dav. If I got it right, this prefix was only 'invented' for dav but not for s3, gcs, azurebs, alioss.
There was a problem hiding this comment.
Yes, this needs to be in the release notes as a breaking change for BOSH. You are right.
You're right that the old cmd/ structure had unit tests. However, looking at the other providers (S3, Azure, GCS, AliOSS), they follow this pattern:
|
| } | ||
| } | ||
|
|
||
| // Check if we should fallback to GET+PUT or return the error |
There was a problem hiding this comment.
Do we really need this fallback? If it's not supported it will fail
There was a problem hiding this comment.
For nginx (used in CAPI and BOSH not). Will remove it.
| // @todo should a logger now be passed in to this client? | ||
| duration := time.Duration(0) | ||
| // Retry with 1 second delay between attempts | ||
| duration := time.Duration(1) * time.Second |
There was a problem hiding this comment.
Should we make this retry duration configurable with 1 second default?
| RetryAttempts uint | ||
| TLS TLS | ||
| Secret string | ||
| SigningMethod string `json:"signing_method"` // "sha256" (default) or "md5" |
There was a problem hiding this comment.
We should rename field to signed_url_format (or similar) to make it clear that this not only the hash method but also changes the format of the URLs.
We should make clear in the documentation that this is given by the webdav sever and that one could/should not switch around.
Supported values: hmac-sha256 (default), secure-link-md5
| blobID, | ||
| method, | ||
| time.Now(), | ||
| 15*time.Minute, |
There was a problem hiding this comment.
Should make this configurable with 15 min default
| Expect(signedPutURL).To(ContainSubstring("ts=")) | ||
| Expect(signedPutURL).To(ContainSubstring("e=")) | ||
|
|
||
| // Verify PUT URL contains /signed/ path prefix for BOSH compatibility |
There was a problem hiding this comment.
Should not mention bosh here rather hmac-sha256
| if err != nil { | ||
| return err | ||
| } | ||
| defer content.Close() //nolint:errcheck |
There was a problem hiding this comment.
defer should be moved up before validateBlobID(path) to ensure it's closed when an error occurs
| time.RFC1123Z, // "Mon, 02 Jan 2006 15:04:05 -0700" | ||
| time.RFC850, // "Monday, 02-Jan-06 15:04:05 MST" | ||
| time.ANSIC, // "Mon Jan _2 15:04:05 2006" | ||
| } |
There was a problem hiding this comment.
The multiple date formats (RFC1123, RFC1123Z, RFC850, ANSIC) are unnecessary. nginx always sends Last-Modified in RFC 1123 format. Since we only target CAPI/BOSH nginx blobstores, simplify to only parse time.RFC1123.
| // When using signed URLs, skip this step because MKCOL operations are not supported | ||
| // with nginx signed URLs - the nginx blobstore handles directory creation automatically. | ||
| if c.signer == nil { | ||
| if err := c.ensureObjectParentsExist(path); err != nil { |
There was a problem hiding this comment.
Both bosh and capi blobstores are based on nginx - so this might not be needed
|
|
||
| // Create parent collections for destination (skip for signed URLs - nginx handles it) | ||
| if c.signer == nil { | ||
| if err := c.ensureObjectParentsExist(dstBlob); err != nil { |
There was a problem hiding this comment.
Might be handled by nginx automatically
| @@ -0,0 +1,19 @@ | |||
| FROM httpd:2.4 | |||
There was a problem hiding this comment.
Maybe we should use a nginx based webdav server for testing as this is what is used for bosh and capi?
| All are stored exactly as specified. If your use case requires a specific directory layout (e.g., partitioning by hash prefix), implement this in the caller before invoking storage-cli. | ||
|
|
||
| ## BOSH Impact/Breaking Changes | ||
| The WebDAV client previously applied automatic path partitioning using SHA1 hash prefixes (e.g., `blob-id` → stored as `ab/blob-id` where `ab` is the first byte of SHA1). This behavior has been removed. |
There was a problem hiding this comment.
Should specify the storage-cli versions for this applies (everything after v0.0.6)
1. Added Missing Operations:**
- COPY - Server-side blob copying via WebDAV COPY method
- PROPERTIES - Retrieve blob metadata (ContentLength, ETag, LastModified)
- ENSURE-STORAGE-EXISTS - Initialize WebDAV directory structure
- SIGN - Generate pre-signed URLs with HMAC-SHA256
- DELETE-RECURSIVE - Delete all blobs matching a prefix
2. Architecture Refactoring:
- Two-layer architecture matching S3/Azure/GCS/AliOSS
- client.go - High-level DavBlobstore wrapper (implements Storager interface)
- storage_client.go - Low-level StorageClient (HTTP/WebDAV operations)
- Centralized path building and validation
3. Configuration:
- Added retry_delay (optional, default: 1s)
- Added signed_url_format (optional, default: "hmac-sha256", supports "secure-link-md5")
- Added signed_url_expiration (optional, default: 15 minutes)
- Renamed config key: signing_method → signed_url_format
4. Improvements:
- Exists now returns (bool, error) matching other providers
- List returns full canonical object names, handles non-existent prefix (returns empty list)
- Error messages include response body for better debugging
- Fixed resource leaks in HTTP clients
5. Testing:
- Comprehensive integration tests with nginx WebDAV server
- Multi-stage Docker build with ngx_http_dav_ext_module
- Tests for both signed URL formats (BOSH HMAC-SHA256 and CAPI secure-link-md5)
BREAKING CHANGE:
Automatic SHA1 path partitioning removed. Callers must now provide complete object paths including any directory structure (e.g., ab/cd/blob-id instead
of blob-id). This aligns DAV behavior with S3/GCS/Azure/AliOSS.
Migration for BOSH:
BOSH deployments must include the hash prefix in object IDs when calling storage-cli:
- Before: Pass blob-id → stored as {sha1_prefix}/blob-id
- After: Pass {sha1_prefix}/blob-id → stored as {sha1_prefix}/blob-id
d6ccb40 to
484e0a1
Compare
Added Missing Operations:
Structural Changes:
Configuration:
Configurable Retry Delay
Made the retry delay between HTTP request attempts configurable through the
retry_delayconfiguration field (in seconds).Backward Compatibility
retry_delaycontinue to work with the 1-second defaultUsage Examples