fs

package module
v0.5.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 24, 2026 License: Apache-2.0 Imports: 5 Imported by: 0

README

fs Go Reference codecov experimental

Simple S3-compatible storage server for development and testing.

Features

S3-Compatible Storage Server

A lightweight S3-compatible storage server for development and testing.

Quick Start:

# Install
go install github.com/go-faster/fs/cmd/fs@latest

# Start the server
fs s3

# Or with custom configuration
fs s3 --addr :9000 --root /data/s3

Features:

  • Bucket operations (create, delete, list)
  • Object operations (put, get, delete, list, copy, tagging, metadata)
  • Multipart uploads
  • File system-based storage
  • Compatible with AWS CLI, MinIO client, and other S3 clients
  • Health check endpoint

See COMPATIBILITY.md for the full compatibility statement (what's implemented, what returns NotImplemented, what's planned, and the durability & failure model). Compatibility is measured against the upstream ceph/s3-tests suite and real S3 clients — the machine-generated breakdown is in the S3 conformance report.

Example Usage:

# Using AWS CLI
export AWS_ENDPOINT_URL=http://localhost:8080
aws s3 mb s3://mybucket --endpoint-url $AWS_ENDPOINT_URL
aws s3 cp file.txt s3://mybucket/ --endpoint-url $AWS_ENDPOINT_URL

# Using cURL
curl -X PUT http://localhost:8080/mybucket
curl -X PUT -d "Hello!" http://localhost:8080/mybucket/hello.txt
curl http://localhost:8080/mybucket/hello.txt

Authentication & TLS

The binary authenticates requests with AWS Signature V4 by default. Provide a root credential and (optionally) TLS:

export FS_ROOT_ACCESS_KEY=AKIAEXAMPLE
export FS_ROOT_SECRET_KEY=exampleSecretKey
fs s3 --tls-cert cert.pem --tls-key key.pem

Additional keys, per-bucket grants (read/write/admin), and public-read buckets are configured under auth: in the config file. To run without any authentication (development only), pass --insecure-no-auth.

SigV4 header auth, presigned URLs (≤7-day expiry) and streaming uploads are all verified; TLS certificates hot-reload without dropping connections. As a library, enable it with server.WithAuth(store) / server.WithCORS(cfg) — the bare handler stays anonymous unless you opt in.

Admin API & access-key dashboard

Multiple access-key/secret credentials can be managed at runtime — without a restart — through a separate admin listener that also serves a small web dashboard. Config-defined keys stay read-only; keys created through the admin API are persisted (<root>/.access-keys.json, mode 0600) and survive restarts and SIGHUP reloads.

admin:
  enabled: true
  addr: "localhost:8090"   # keep bound to localhost or behind a proxy
  token: "change-me"       # or set FS_ADMIN_TOKEN

The dashboard (open http://localhost:8090/, paste the token) lists credentials and their grants, creates keys (generating the access key and secret, shown once), and deletes runtime keys. The same operations are available as a JSON API under /api/v1 (bearer-token protected), generated from _oas/admin.yml with ogen; the dashboard is a TypeScript/React SPA whose typed client is generated from the same spec with Orval:

# List credentials
curl -H "Authorization: Bearer $FS_ADMIN_TOKEN" localhost:8090/api/v1/access-keys

# Create a credential scoped to buckets matching "uploads-*"
curl -H "Authorization: Bearer $FS_ADMIN_TOKEN" -H "Content-Type: application/json" \
  -d '{"grants":[{"bucket":"uploads-*","permission":"write"}]}' \
  localhost:8090/api/v1/access-keys
Run as a systemd service

Generate a unit for fs s3 — a per-user service by default, or a hardened system service with --user=false:

# Install and enable a per-user service
fs systemd --install --config ~/fs.yaml
systemctl --user daemon-reload
systemctl --user enable --now fs
loginctl enable-linger "$USER"   # keep it running after logout

# Or emit a system unit
fs systemd --user=false --config /etc/fs/config.yaml | sudo tee /etc/systemd/system/fs.service

The unit wires ExecReload to SIGHUP, so systemctl --user reload fs performs the hot credential/TLS reload.

Operations

  • Durabilitystorage.fsync (none / file / file+dir, default file) controls fsync aggressiveness; writes are always crash-atomic (no torn object). A background scrubber (integrity.scrub_interval) detects bit-rot and can quarantine corrupt objects; integrity.verify_on_read checks each object before serving.
  • Health & readiness/health (liveness: the process is up) and /ready (readiness: storage is reachable, 503 otherwise). Prometheus /metrics and pprof are served on a separate listener (default localhost:9464, METRICS_ADDR to change).
  • Hot reload — send SIGHUP to reload credentials and the TLS certificate from disk without a restart.

Installation

go install github.com/go-faster/fs/cmd/fs@latest

Or build from source:

git clone https://github.com/go-faster/fs
cd fs
go build -o bin/fs ./cmd/fs

Usage

Quick Start
# Start S3 server with defaults
fs s3

# Show help
fs s3 --help
Configuration

The server supports both YAML configuration files and command-line flags:

# Using YAML configuration
fs s3 --config config.yaml

# Using command-line flags
fs s3 --addr :9000 --root /var/lib/s3data

# Mix both (flags override config file)
fs s3 --config config.yaml --addr :9000

# Generate example configuration
fs s3 --generate-config > my-config.yaml

Run fs s3 --generate-config to produce a fully commented configuration template, and fs s3 --help for the list of flags.

Example Configuration
server:
  addr: ":8080"
  read_timeout: 30s
  write_timeout: 30s
  idle_timeout: 120s
  health_path: "/health"

storage:
  root: ".s3data"
  type: "filesystem"

observability:
  service_name: "go-faster/fs"
  enable_request_logging: true
  enable_metrics: true
  enable_tracing: true

Use as a library

The S3 server is embeddable. Install the module and pick a storage backend — storagefs for the filesystem, storagemem for in-memory, or your own implementation of the fs.Storage interface:

go get github.com/go-faster/fs

The library core pulls in no observability stack — wrap the handler yourself (e.g. with otelhttp) via server.NewHandler or Config.WrapHandler.

Custom backends can verify themselves against the storage contract with the storagetest conformance suite:

func TestStorage(t *testing.T) {
	storagetest.Run(t, func(t testing.TB) fs.Storage {
		return mybackend.New(t.TempDir())
	})
}
Mount the handler into your own server

Use server.NewHandler when you already run an http.Server or mux and just want to expose the S3 API (optionally under a path prefix):

package main

import (
	"net/http"

	"github.com/go-faster/fs/server"
	"github.com/go-faster/fs/storagefs"
)

func main() {
	store, err := storagefs.New("/data")
	if err != nil {
		panic(err)
	}

	mux := http.NewServeMux()
	mux.Handle("/s3/", http.StripPrefix("/s3", server.NewHandler(store)))

	http.ListenAndServe(":8080", mux)
}
Run the turnkey server

Use server.New for a managed server with a health endpoint, request timeouts, optional bucket pre-creation and graceful shutdown driven by a context:

package main

import (
	"context"
	"os/signal"
	"syscall"

	"github.com/go-faster/fs/server"
	"github.com/go-faster/fs/storagemem"
)

func main() {
	ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM)
	defer stop()

	srv, err := server.New(server.Config{
		Storage: storagemem.New(),
		Addr:    ":9000",
		Buckets: []string{"uploads"}, // pre-created if absent
	})
	if err != nil {
		panic(err)
	}

	// Serves until ctx is canceled, then drains in-flight requests.
	if err := srv.ListenAndServe(ctx); err != nil {
		panic(err)
	}
}
server.Config
Field Default Description
Storage — (required) Backend serving S3 operations (fs.Storage).
Addr :8080 TCP address to listen on.
ReadTimeout / WriteTimeout / IdleTimeout 30s / 30s / 120s Underlying http.Server timeouts.
HealthPath /health Plaintext liveness endpoint; "-" disables it.
ReadyPath / Ready /ready / — Readiness endpoint and its probe; a non-nil probe error returns 503.
Buckets Buckets created (idempotently) before serving.
Auth / CORS / TLS SigV4 auth store, per-bucket CORS, and hot-reloadable TLS.
WrapHandler Wrap the handler with middleware/observability (e.g. otelhttp.NewHandler).

See the server package reference for the full API and runnable examples.

Development

# Run tests
go test ./...

# Build
go build ./cmd/fs

# Run with coverage
make coverage

License

Apache 2.0

Documentation

Overview

Package fs is a S3-compatible storage server implementation.

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrBucketNotFound       = errors.New("bucket not found")
	ErrBucketAlreadyExists  = errors.New("bucket already exists")
	ErrBucketNotEmpty       = errors.New("bucket not empty")
	ErrObjectNotFound       = errors.New("object not found")
	ErrUploadNotFound       = errors.New("upload not found")
	ErrInvalidBucketName    = errors.New("invalid bucket name")
	ErrUnsupportedOperation = errors.New("unsupported operation")
	ErrPreconditionFailed   = errors.New("precondition failed")

	// ErrInvalidPart reports that a part referenced by CompleteMultipartUpload
	// was never uploaded or its ETag does not match.
	ErrInvalidPart = errors.New("invalid part")
	// ErrInvalidPartOrder reports that the CompleteMultipartUpload part list is
	// not in strictly ascending part-number order.
	ErrInvalidPartOrder = errors.New("invalid part order")
	// ErrInvalidPartNumber reports a part number outside the valid 1..10000 range.
	ErrInvalidPartNumber = errors.New("invalid part number")
	// ErrEntityTooSmall reports a non-last multipart part smaller than the 5 MiB
	// minimum.
	ErrEntityTooSmall = errors.New("entity too small")
	// ErrInvalidTag reports an object tag set violating the S3 limits
	// (at most 10 tags, unique keys, key ≤ 128 chars, value ≤ 256 chars).
	ErrInvalidTag = errors.New("invalid tag")

	// ErrIntegrity reports that an object's stored content does not match its
	// recorded checksum (bit-rot / corruption detected on read).
	ErrIntegrity = errors.New("object integrity check failed")
)

Functions

This section is empty.

Types

type ACL added in v0.5.0

type ACL string

ACL is a canned S3 access-control level applied to a bucket or object. Only the canned subset is modeled — full ACL grammar (arbitrary grantees, AccessControlPolicy XML) is out of scope; the `?acl` subresource is echo-only.

const (
	// ACLPrivate grants no anonymous access (the default).
	ACLPrivate ACL = "private"
	// ACLPublicRead allows anonymous reads.
	ACLPublicRead ACL = "public-read"
	// ACLPublicReadWrite allows anonymous reads and writes.
	ACLPublicReadWrite ACL = "public-read-write"
)

func ParseACL added in v0.5.0

func ParseACL(s string) ACL

ParseACL normalizes a canned ACL header value, defaulting empty or unrecognized values to ACLPrivate.

func (ACL) AllowsAnonRead added in v0.5.0

func (a ACL) AllowsAnonRead() bool

AllowsAnonRead reports whether the level permits anonymous reads.

func (ACL) AllowsAnonWrite added in v0.5.0

func (a ACL) AllowsAnonWrite() bool

AllowsAnonWrite reports whether the level permits anonymous writes.

type Bucket

type Bucket struct {
	Name         string
	CreationDate time.Time
}

Bucket represents an S3 bucket.

type CompleteMultipartUploadRequest added in v0.0.4

type CompleteMultipartUploadRequest struct {
	Bucket   string
	Key      string
	UploadID string
	Parts    []CompletedPart
}

CompleteMultipartUploadRequest represents a request to complete multipart upload.

type CompleteMultipartUploadResponse added in v0.0.4

type CompleteMultipartUploadResponse struct {
	Location string
	Bucket   string
	Key      string
	ETag     string
}

CompleteMultipartUploadResponse represents the response for completing multipart upload.

type CompletedPart added in v0.0.4

type CompletedPart struct {
	PartNumber int
	ETag       string
}

CompletedPart represents a completed part for completing multipart upload.

type CreateMultipartUploadRequest added in v0.4.0

type CreateMultipartUploadRequest struct {
	Bucket   string
	Key      string
	Metadata ObjectMetadata
	Tags     []Tag
	ACL      ACL
}

CreateMultipartUploadRequest represents a request to start a multipart upload. Metadata and tags are applied to the object at completion.

type GetObjectResponse

type GetObjectResponse struct {
	Reader       io.ReadCloser
	Size         int64
	LastModified time.Time
	ETag         string
	Metadata     ObjectMetadata
}

GetObjectResponse represents the response for GetObject operation.

type MultipartUpload added in v0.0.4

type MultipartUpload struct {
	UploadID  string
	Bucket    string
	Key       string
	Initiated time.Time
}

MultipartUpload represents an in-progress multipart upload.

type Object

type Object struct {
	Key          string
	Size         int64
	LastModified time.Time
	ETag         string
}

Object represents an S3 object.

type ObjectMetadata added in v0.4.0

type ObjectMetadata struct {
	ContentType        string
	CacheControl       string
	ContentDisposition string
	ContentEncoding    string
	// UserMetadata holds x-amz-meta-* pairs, keyed by the lowercase name
	// without the prefix (e.g. "color" for x-amz-meta-color).
	UserMetadata map[string]string
}

ObjectMetadata holds the user-controlled metadata stored with an object: the standard HTTP representation headers plus x-amz-meta-* pairs.

func (ObjectMetadata) IsZero added in v0.4.0

func (m ObjectMetadata) IsZero() bool

IsZero reports whether no metadata field is set.

type Part added in v0.0.4

type Part struct {
	PartNumber   int
	ETag         string
	Size         int64
	LastModified time.Time
}

Part represents a part of a multipart upload.

type PutObjectRequest

type PutObjectRequest struct {
	Reader   io.Reader
	Bucket   string
	Key      string
	Size     int64
	Metadata ObjectMetadata
	Tags     []Tag
	// ACL is the canned access-control level for the object (default
	// ACLPrivate). Governs anonymous access only.
	ACL ACL

	// IfNoneMatch and IfMatch carry the raw conditional-write header values
	// (e.g. "*" or a quoted ETag list). When set, the storage backend must
	// evaluate them atomically with the write — see PreconditionFailed — so
	// concurrent conditional PUTs resolve to a single winner. Empty means no
	// condition.
	IfNoneMatch string
	IfMatch     string
}

func (*PutObjectRequest) PreconditionFailed added in v0.4.0

func (r *PutObjectRequest) PreconditionFailed(exists bool, currentETag string) bool

PreconditionFailed reports whether the request's If-None-Match / If-Match conditions fail against the current object state, where exists reports whether the target object is present and currentETag is its ETag (quoted or bare; only meaningful when exists is true). A true result means the write must be rejected with ErrPreconditionFailed.

Storage backends MUST call this while holding the lock that serializes writes to the key, so the evaluation is atomic with the write. Evaluating the condition in a separate step before the write (check-then-act) races: several concurrent If-None-Match: * writers can all observe "absent" and all succeed.

Semantics (matching S3):

  • If-None-Match: * fail if the object exists.
  • If-None-Match: "<etag>" fail if it exists and the ETag matches.
  • If-Match: * fail if the object does not exist.
  • If-Match: "<etag>" fail if it is missing or the ETag differs.

type PutObjectResponse added in v0.4.0

type PutObjectResponse struct {
	ETag string
}

PutObjectResponse reports the stored object's ETag.

type Storage

type Storage interface {
	ListBuckets(ctx context.Context) ([]Bucket, error)
	CreateBucket(ctx context.Context, bucket string) error
	DeleteBucket(ctx context.Context, bucket string) error
	BucketExists(ctx context.Context, bucket string) (bool, error)
	ListObjects(ctx context.Context, bucket, prefix string) ([]Object, error)
	PutObject(ctx context.Context, req *PutObjectRequest) (*PutObjectResponse, error)
	GetObject(ctx context.Context, bucket, key string) (*GetObjectResponse, error)
	DeleteObject(ctx context.Context, bucket, key string) error

	// GetObjectTagging returns the object's tag set (empty when untagged).
	GetObjectTagging(ctx context.Context, bucket, key string) ([]Tag, error)
	// PutObjectTagging replaces the object's tag set.
	PutObjectTagging(ctx context.Context, bucket, key string, tags []Tag) error
	// DeleteObjectTagging removes the object's tag set.
	DeleteObjectTagging(ctx context.Context, bucket, key string) error

	// SetBucketACL records the bucket's canned ACL.
	SetBucketACL(ctx context.Context, bucket string, acl ACL) error
	// BucketACL returns the bucket's canned ACL (ACLPrivate default);
	// ErrBucketNotFound when the bucket is absent.
	BucketACL(ctx context.Context, bucket string) (ACL, error)
	// ObjectACL returns the object's canned ACL (ACLPrivate default);
	// ErrBucketNotFound/ErrObjectNotFound when absent.
	ObjectACL(ctx context.Context, bucket, key string) (ACL, error)

	CreateMultipartUpload(ctx context.Context, req *CreateMultipartUploadRequest) (*MultipartUpload, error)
	UploadPart(ctx context.Context, req *UploadPartRequest) (*Part, error)
	// ListParts returns the parts uploaded so far for an in-progress multipart
	// upload, sorted by ascending part number.
	ListParts(ctx context.Context, bucket, key, uploadID string) ([]Part, error)
	// ListMultipartUploads returns the in-progress multipart uploads for a
	// bucket, sorted by object key (then upload ID for equal keys).
	ListMultipartUploads(ctx context.Context, bucket string) ([]MultipartUpload, error)
	CompleteMultipartUpload(ctx context.Context, req *CompleteMultipartUploadRequest) (*CompleteMultipartUploadResponse, error)
	AbortMultipartUpload(ctx context.Context, bucket, key, uploadID string) error
}

Storage defines the interface for S3-compatible storage operations.

type Tag added in v0.4.0

type Tag struct {
	Key   string
	Value string
}

Tag is a single object tag.

type UploadPartRequest added in v0.0.4

type UploadPartRequest struct {
	Bucket     string
	Key        string
	UploadID   string
	PartNumber int
	Reader     io.Reader
	Size       int64
}

UploadPartRequest represents a request to upload a part.

Directories

Path Synopsis
Package auth provides credential storage and a small grant-based authorization model for the S3 server.
Package auth provides credential storage and a small grant-based authorization model for the S3 server.
Package clusterstore is the replicating storage layer for go-faster/fs cluster mode (DESIGN.md §4, ROADMAP.md M3 Phase 7).
Package clusterstore is the replicating storage layer for go-faster/fs cluster mode (DESIGN.md §4, ROADMAP.md M3 Phase 7).
cmd
fs command
Package cors provides per-bucket CORS configuration for the S3 server: which cross-origin requests are allowed and what preflight responses to return.
Package cors provides per-bucket CORS configuration for the S3 server: which cross-origin requests are allowed and what preflight responses to return.
Package internal contains go:generate annotations.
Package internal contains go:generate annotations.
adminhandler
Package adminhandler implements the go-faster/fs admin API: instance info and runtime access-key management, backed by an auth.Manager.
Package adminhandler implements the go-faster/fs admin API: instance info and runtime access-key management, backed by an auth.Manager.
cluster
Package cluster holds the shared domain types for go-faster/fs cluster mode: the failure-domain topology (rack → server → disk) that the etcd control plane publishes and the placement function consumes.
Package cluster holds the shared domain types for go-faster/fs cluster mode: the failure-domain topology (rack → server → disk) that the etcd control plane publishes and the placement function consumes.
cluster/diskstore
Package diskstore is the filesystem-backed fragment store for go-faster/fs cluster mode: the durable transport.Store a production node serves its fragments from, one root directory per disk.
Package diskstore is the filesystem-backed fragment store for go-faster/fs cluster mode: the durable transport.Store a production node serves its fragments from, one root directory per disk.
cluster/etcd
Package etcd is the go-faster/fs cluster control plane: the only component that talks to etcd.
Package etcd is the go-faster/fs cluster control plane: the only component that talks to etcd.
cluster/fragment
Package fragment is the connective layer between placement and the erasure schemes: it encodes an object into the per-target fragments a scheme stores, and reconstructs the object from whatever fragments survive.
Package fragment is the connective layer between placement and the erasure schemes: it encodes an object into the per-target fragments a scheme stores, and reconstructs the object from whatever fragments survive.
cluster/placement
Package placement is the pure, failure-domain-aware placement function for go-faster/fs cluster mode (DESIGN.md FR-16).
Package placement is the pure, failure-domain-aware placement function for go-faster/fs cluster mode (DESIGN.md FR-16).
cluster/scheme
Package scheme models the go-faster/fs replication and erasure schemes (DESIGN.md FR-17) and implements the pure codecs they need.
Package scheme models the go-faster/fs replication and erasure schemes (DESIGN.md FR-17) and implements the pure codecs they need.
cluster/transport
Package transport is the peer replication transport for go-faster/fs cluster mode: the internal HTTP API nodes use to store, fetch and delete object fragments on each other (the payloads produced by internal/cluster/fragment).
Package transport is the peer replication transport for go-faster/fs cluster mode: the internal HTTP API nodes use to store, fetch and delete object fragments on each other (the payloads produced by internal/cluster/fragment).
s3err
Package s3err renders S3-compatible error responses.
Package s3err renders S3-compatible error responses.
sigv4
Package sigv4 verifies AWS Signature Version 4 on incoming S3 requests: Authorization-header auth, presigned-URL (query) auth, and the seed signature for streaming (aws-chunked) uploads.
Package sigv4 verifies AWS Signature Version 4 on incoming S3 requests: Authorization-header auth, presigned-URL (query) auth, and the seed signature for streaming (aws-chunked) uploads.
scripts
gencompat command
Command gencompat generates docs/CONFORMANCE.md from the ceph/s3-tests allow-list, grouping the passing tests by feature area.
Command gencompat generates docs/CONFORMANCE.md from the ceph/s3-tests allow-list, grouping the passing tests by feature area.
Package server provides an embeddable S3-compatible HTTP server.
Package server provides an embeddable S3-compatible HTTP server.
Package storagefs implements fs.Storage.
Package storagefs implements fs.Storage.
Package storagemem implements fs.Storage using in-memory storage.
Package storagemem implements fs.Storage using in-memory storage.
Package storagetest provides a conformance test suite for fs.Storage implementations.
Package storagetest provides a conformance test suite for fs.Storage implementations.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL