Documentation
¶
Overview ¶
Package objectstore is the production controlplane.ObjectStoreFactory: a small S3-compatible client for the ONE thing Burrow does with object storage, which is own the seam between a bucket and the backups written to it (ADR-0063).
Its surface is the whole of what ADR-0063 §2 permits and no more — create the bucket Burrow will own, write and delete a probe object, read the lifecycle configuration that must be reconciled against backup retention, and check a bucket is reachable. There is no cp, no sync, no listing of arbitrary prefixes, no presigned URL, and no policy/IAM/replication surface. That is not an omission to be filled in later: every vendor ships a capable CLI for those, and a capability enters here only when a Burrow feature requires it.
The client is a net/http client with an in-tree SigV4 signer (sigv4.go) rather than a vendor SDK, for the same reason the DNS adapters are: five API calls do not justify an SDK and its transitive module set (CLAUDE.md). Requests are PATH-STYLE (https://endpoint/bucket/key), which is what the S3-compatible vendors accept in common.
It lives under controlplane/ (not controlplane/internal) so cmd/burrowd and the managed module can wire it; it is licensed Apache-2.0.
Index ¶
- type Factory
- type Store
- func (s *Store) BucketExists(ctx context.Context, bucket string) (bool, error)
- func (s *Store) CreateBucket(ctx context.Context, bucket string) error
- func (s *Store) DeleteObject(ctx context.Context, bucket, key string) error
- func (s *Store) LifecycleRules(ctx context.Context, bucket string) ([]controlplane.LifecycleRule, error)
- func (s *Store) PutObject(ctx context.Context, bucket, key string, body []byte) error
- func (s *Store) PutObjectStream(ctx context.Context, bucket, key string, body io.Reader, size int64, ...) (bool, error)
- func (s *Store) StatObject(ctx context.Context, bucket, key string) (int64, error)
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Factory ¶
type Factory struct {
// contains filtered or unexported fields
}
Factory builds a Store for an endpoint and credential pair (ADR-0063 §1). The vendor is whoever answers the endpoint: there is no vendor list here, deliberately.
func NewFactory ¶
func NewFactory() *Factory
NewFactory returns a Factory bounding each object-store call by controlplane.ObjectStoreCallTimeout. The bound is declared there rather than here because registering a provider makes several of these calls in one API request, and the client waiting on that request sizes itself from the same constant (issue #404).
func (*Factory) ObjectStore ¶
func (f *Factory) ObjectStore(endpoint, region string, cred controlplane.ObjectStoreCredential) (controlplane.ObjectStore, error)
ObjectStore returns a client for the bucket-holding endpoint, signing with cred.
type Store ¶
type Store struct {
// contains filtered or unexported fields
}
Store is one endpoint's S3-compatible client, holding one credential pair.
func (*Store) BucketExists ¶
BucketExists reports whether the bucket is present AND reachable with this credential. A bucket that answers 403 is reported as absent: it may exist and belong to someone else, and either way Burrow can do nothing with it, so treating it as present would be the more dangerous answer.
func (*Store) CreateBucket ¶
CreateBucket creates the bucket under exactly the name it is given — the engine owns the name (ADR-0063 §4), and this adapter never derives, adopts, or falls back to another one.
func (*Store) DeleteObject ¶
DeleteObject removes key. S3 answers 204 whether or not the object was there, so deleting an absent object is a no-op rather than an error.
func (*Store) LifecycleRules ¶
func (s *Store) LifecycleRules(ctx context.Context, bucket string) ([]controlplane.LifecycleRule, error)
LifecycleRules returns the bucket's lifecycle rules, or an error wrapping ErrLifecycleUnknown where the answer cannot be had — the vendor does not serve the lifecycle API (501/405), or this credential is not permitted to read it (403). That distinction is load-bearing: ADR-0063 §3 wants an unreadable configuration reported as UNKNOWN, never as verified, and an adapter that quietly returned "no rules" for a 403 would report the second as the first.
func (*Store) PutObjectStream ¶
func (s *Store) PutObjectStream(ctx context.Context, bucket, key string, body io.Reader, size int64, sha256Hex string) (bool, error)
PutObjectStream writes size bytes read from body at key, streaming rather than buffering: the one payload Burrow puts here that is not small is a pg_dump, and a container that held a multi-gigabyte dump in memory to write it would be OOM-killed by the limit that protects the rest of the node.
sha256Hex is the hex SHA-256 of exactly those bytes, computed by the caller in a pass over the same file. It goes into x-amz-content-sha256, which the endpoint VALIDATES the body against and rejects on a mismatch — so a truncated or corrupted transfer is refused by the vendor rather than being stored as a backup that will not restore. That is the first of the two facts ADR-0063 §7 needs; the second is StatObject reading the object back afterwards.
refused distinguishes "the endpoint answered and said no" from "the write did not complete". Only the second is worth retrying. A 403, a 404 on the bucket, or a malformed request will answer the same way however many times it is asked, and spending the retry budget on it only delays the loud failure. A 429 or a 5xx is the endpoint asking to be asked again, so those are NOT refusals.
func (*Store) StatObject ¶
StatObject returns the size of the object at key, or ErrNotFound when it is not there.
This is the read-back that lets a Backup row claim the object is retrievable rather than merely accepted (ADR-0063 §7). It is a HEAD and not a full GET on purpose: the body's integrity is already established by the signed payload hash the write was validated against, so re-reading gigabytes would double the transfer and the egress bill to learn nothing the PUT did not already prove. What a HEAD adds — and the PUT cannot — is that the object is VISIBLE at the key Burrow recorded, with the length Burrow sent, to a subsequent request.