Skip to content

bartvanbenthem/cn-objectstore

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

6 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Cloud Native ObjectStore

A reusable, provider agnostic object store client library for Cloud Native applications and Kubernetes operators.

Wraps object_store with a simpler, higher-level API covering CRUD, prefix listing, latest-file retrieval, and background change detection — all driven by environment variables so the same operator binary works against Azure Blob Storage, AWS S3, MinIO, Cloudian, or any S3-compatible vendor with no code changes.


Features

  • Azure Blob Storage and S3-compatible backends (AWS S3, MinIO, Cloudian, …)
  • Environment-variable-driven config — no credentials in code
  • Typed error enum — pattern-match on NotFound, StoreBuildError, etc.
  • Convenience methods: exists, copy, rename, delete_prefix, write_if_absent, read_latest
  • Background prefix watcher with configurable poll interval
  • Clone-able client backed by Arc<dyn ObjectStore> — share freely across tasks
  • Fully testable via ObjectStoreClient::from_store with object_store::memory::InMemory

Installation

Add to your Cargo.toml:

[dependencies]
kube-objstore = { path = "../kube-objstore" }   # local
# or once published:
# kube-objstore = "0.1.0"

Environment variables

Variable Required Description
CLOUD_PROVIDER Yes azure or s3
OBJECT_STORAGE_BUCKET Yes Bucket (S3) or container name (Azure)
OBJECT_STORAGE_ACCOUNT Yes Storage account name (Azure) or access key ID (S3)
OBJECT_STORAGE_SECRET Yes Storage access key (Azure) or secret access key (S3)
S3_ENDPOINT_URL No Custom S3 endpoint for MinIO / Cloudian / other vendors

For AWS S3 the region is sourced from the standard AWS_DEFAULT_REGION environment variable or the AWS SDK default chain.


Quick start

use kube_objstore::{ObjectStoreClient, ObjectStoreConfig};

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    let config = ObjectStoreConfig::from_env()?;
    let client = ObjectStoreClient::new(config).await?;

    // Write
    client.write("snapshots/v1.bin", b"my data").await?;

    // Read
    if let Some(bytes) = client.read("snapshots/v1.bin").await? {
        println!("Read {} bytes", bytes.len());
    }

    // Read the most recently modified object under a prefix
    if let Some(bytes) = client.read_latest("snapshots/").await? {
        println!("Latest snapshot: {} bytes", bytes.len());
    }

    Ok(())
}

API reference

ObjectStoreClient

Method Description
new(config) Build a client from ObjectStoreConfig
from_store(store, bucket) Wrap any ObjectStore (useful in tests)
inner() Access the underlying Arc<dyn ObjectStore>
CRUD
write(path, data) Write bytes, overwriting any existing object. Returns ObjectMeta.
read(path) Read bytes. Returns None if not found.
read_required(path) Read bytes. Returns Err(NotFound) if not found.
delete(path) Delete an object. Returns false if it did not exist.
metadata(path) HEAD request — returns ObjectMeta or None.
exists(path) true if the object exists, no content downloaded.
Listing
list(prefix) All objects under a prefix.
latest(prefix) Metadata of the most recently modified object under a prefix.
read_latest(prefix) Content of the most recently modified object under a prefix.
Batch / convenience
copy(src, dst) Copy an object within the same store.
rename(src, dst) Copy then delete source.
delete_prefix(prefix) Delete all objects under a prefix. Returns count deleted.
write_if_absent(path, data) Write only if the object does not already exist.

ObjectStoreWatcher

Polls a prefix on a configurable interval and sends a () signal on a Tokio mpsc channel whenever objects are added or removed. The first poll establishes a baseline without firing. The background task shuts down automatically when all receivers are dropped.

use kube_objstore::{ObjectStoreClient, ObjectStoreConfig, ObjectStoreWatcher};
use tokio::sync::mpsc;
use std::time::Duration;

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    let config = ObjectStoreConfig::from_env()?;
    let client = ObjectStoreClient::new(config).await?;

    let (tx, mut rx) = mpsc::channel(8);

    let _handle = ObjectStoreWatcher::new(client, "configs/")
        .with_interval(Duration::from_secs(15))
        .spawn(tx);

    while let Some(()) = rx.recv().await {
        println!("Prefix changed — trigger reconcile");
    }

    Ok(())
}

ObjectStoreConfig

Build from environment variables:

let config = ObjectStoreConfig::from_env()?;

Or programmatically with the builder:

use kube_objstore::config::{ObjectStoreConfigBuilder, Provider};
use std::time::Duration;

let config = ObjectStoreConfigBuilder::default()
    .provider(Provider::S3 { endpoint_url: Some("http://minio:9000".into()) })
    .bucket("my-bucket")
    .account("minioadmin")
    .secret("minioadmin")
    .poll_interval(Duration::from_secs(60))
    .build()?;

Error handling

All methods return Result<T, ObjectStoreClientError>. The error enum covers:

pub enum ObjectStoreClientError {
    MissingEnvVar(String),
    UnsupportedProvider(String),
    StoreBuildError(String),
    NotFound(String),
    StoreError(object_store::Error),
    Io(std::io::Error),
    Other(anyhow::Error),
}

Testing

Tests use object_store::memory::InMemory — no cloud credentials or network needed:

cargo test

Enable log output:

RUST_LOG=debug cargo test -- --nocapture

To write your own tests against the library:

use std::sync::Arc;
use object_store::memory::InMemory;
use kube_objstore::ObjectStoreClient;

fn test_client() -> ObjectStoreClient {
    ObjectStoreClient::from_store(Arc::new(InMemory::new()), "test-bucket")
}

Provider examples

Azure Blob Storage

export CLOUD_PROVIDER=azure
export OBJECT_STORAGE_BUCKET=my-container
export OBJECT_STORAGE_ACCOUNT=mystorageaccount
export OBJECT_STORAGE_SECRET=base64accesskey==

AWS S3

export CLOUD_PROVIDER=s3
export OBJECT_STORAGE_BUCKET=my-bucket
export OBJECT_STORAGE_ACCOUNT=AKIAIOSFODNN7EXAMPLE
export OBJECT_STORAGE_SECRET=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
export AWS_DEFAULT_REGION=eu-west-1

S3-compatible

export CLOUD_PROVIDER=s3
export OBJECT_STORAGE_BUCKET=my-bucket
export OBJECT_STORAGE_ACCOUNT=minioadmin
export OBJECT_STORAGE_SECRET=minioadmin
export S3_ENDPOINT_URL=http://minio.minio-ns.svc.cluster.local:9000

Logging

The library uses tracing. Add a subscriber in your operator's main.rs to see structured logs from the library:

tracing_subscriber::fmt()
    .with_env_filter(tracing_subscriber::EnvFilter::from_default_env())
    .init();

Then set RUST_LOG=kube_objstore=debug for verbose output.


License

MIT

About

Provider agnostic object store client for Cloud Native applications. Supports AWS S3, Azure Blob Storage and other S3 compatible backends.

Resources

Stars

2 stars

Watchers

0 watching

Forks

Packages

 
 
 

Contributors

Languages