Skip to main content

alien_core/bindings/
storage.rs

1//! Service-type based storage binding definitions
2
3use super::BindingValue;
4use serde::{Deserialize, Serialize};
5
6/// S3 storage binding configuration.
7///
8/// Targets AWS S3 by default. Setting `endpoint` targets any S3-compatible
9/// store instead (MinIO, Ceph RGW, NetApp StorageGRID, Cloudflare R2, ...),
10/// which is how Kubernetes deployments outside a cloud account attach the
11/// customer's existing object storage.
12#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
13#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
14#[cfg_attr(feature = "jsonschema", derive(schemars::JsonSchema))]
15#[serde(rename_all = "camelCase")]
16pub struct S3StorageBinding {
17    /// The name of the S3 bucket
18    pub bucket_name: BindingValue<String>,
19    /// Endpoint of an S3-compatible store, e.g. `https://minio.internal:9000`.
20    /// Unset means AWS S3.
21    #[serde(default, skip_serializing_if = "Option::is_none")]
22    pub endpoint: Option<BindingValue<String>>,
23    /// Region to sign requests for. Defaults to the ambient AWS region, or
24    /// `us-east-1` for S3-compatible endpoints.
25    #[serde(default, skip_serializing_if = "Option::is_none")]
26    pub region: Option<BindingValue<String>>,
27    /// Use path-style URLs (`endpoint/bucket/key`) instead of virtual-hosted
28    /// ones (`bucket.endpoint/key`). Defaults to `true` when `endpoint` is
29    /// set, since most S3-compatible stores require it.
30    #[serde(default, skip_serializing_if = "Option::is_none")]
31    pub force_path_style: Option<bool>,
32    /// Static access key ID. Unset means the ambient AWS credential chain.
33    #[serde(default, skip_serializing_if = "Option::is_none")]
34    pub access_key_id: Option<BindingValue<String>>,
35    /// Static secret access key; required when `accessKeyId` is set.
36    #[serde(default, skip_serializing_if = "Option::is_none")]
37    pub secret_access_key: Option<BindingValue<String>>,
38}
39
40impl S3StorageBinding {
41    /// AWS S3 bucket using the ambient credential chain.
42    pub fn bucket(bucket_name: impl Into<BindingValue<String>>) -> Self {
43        Self {
44            bucket_name: bucket_name.into(),
45            endpoint: None,
46            region: None,
47            force_path_style: None,
48            access_key_id: None,
49            secret_access_key: None,
50        }
51    }
52}
53
54/// Azure Blob Storage binding configuration
55#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
56#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
57#[cfg_attr(feature = "jsonschema", derive(schemars::JsonSchema))]
58#[serde(rename_all = "camelCase")]
59pub struct BlobStorageBinding {
60    /// The name of the storage account
61    pub account_name: BindingValue<String>,
62    /// The name of the container
63    pub container_name: BindingValue<String>,
64}
65
66/// Google Cloud Storage binding configuration
67#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
68#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
69#[cfg_attr(feature = "jsonschema", derive(schemars::JsonSchema))]
70#[serde(rename_all = "camelCase")]
71pub struct GcsStorageBinding {
72    /// The name of the GCS bucket
73    pub bucket_name: BindingValue<String>,
74}
75
76/// Local filesystem storage binding configuration
77#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
78#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
79#[cfg_attr(feature = "jsonschema", derive(schemars::JsonSchema))]
80#[serde(rename_all = "camelCase")]
81pub struct LocalStorageBinding {
82    /// The storage directory path (file:// URL or absolute path)
83    pub storage_path: BindingValue<String>,
84}
85
86/// Service-type based storage binding that supports multiple storage providers
87#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
88#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
89#[cfg_attr(feature = "jsonschema", derive(schemars::JsonSchema))]
90#[serde(tag = "service", rename_all = "lowercase")]
91pub enum StorageBinding {
92    /// AWS S3
93    S3(S3StorageBinding),
94    /// Azure Blob Storage
95    Blob(BlobStorageBinding),
96    /// Google Cloud Storage
97    Gcs(GcsStorageBinding),
98    /// Local filesystem storage
99    #[serde(rename = "local-storage")]
100    Local(LocalStorageBinding),
101}
102
103impl StorageBinding {
104    /// Creates an S3 storage binding
105    pub fn s3(bucket_name: impl Into<BindingValue<String>>) -> Self {
106        Self::S3(S3StorageBinding::bucket(bucket_name))
107    }
108
109    /// Creates an Azure Blob storage binding
110    pub fn blob(
111        account_name: impl Into<BindingValue<String>>,
112        container_name: impl Into<BindingValue<String>>,
113    ) -> Self {
114        Self::Blob(BlobStorageBinding {
115            account_name: account_name.into(),
116            container_name: container_name.into(),
117        })
118    }
119
120    /// Creates a GCS storage binding
121    pub fn gcs(bucket_name: impl Into<BindingValue<String>>) -> Self {
122        Self::Gcs(GcsStorageBinding {
123            bucket_name: bucket_name.into(),
124        })
125    }
126
127    /// Creates a local storage binding
128    pub fn local(storage_path: impl Into<BindingValue<String>>) -> Self {
129        Self::Local(LocalStorageBinding {
130            storage_path: storage_path.into(),
131        })
132    }
133}