iceberg/io/storage/config/
gcs.rs1use serde::{Deserialize, Serialize};
24use typed_builder::TypedBuilder;
25
26use super::StorageConfig;
27use crate::Result;
28use crate::io::is_truthy;
29
30pub const GCS_PROJECT_ID: &str = "gcs.project-id";
32pub const GCS_SERVICE_HOST: &str = "gcs.service.host";
34pub const GCS_USER_PROJECT: &str = "gcs.user-project";
36pub const GCS_NO_AUTH: &str = "gcs.no-auth";
38pub const GCS_CREDENTIALS_JSON: &str = "gcs.credentials-json";
42pub const GCS_TOKEN: &str = "gcs.oauth2.token";
44pub const GCS_ALLOW_ANONYMOUS: &str = "gcs.allow-anonymous";
46pub const GCS_DISABLE_VM_METADATA: &str = "gcs.disable-vm-metadata";
48pub const GCS_DISABLE_CONFIG_LOAD: &str = "gcs.disable-config-load";
50
51#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize, TypedBuilder)]
56pub struct GcsConfig {
57 #[builder(default, setter(strip_option, into))]
59 pub project_id: Option<String>,
60 #[builder(default, setter(strip_option, into))]
62 pub endpoint: Option<String>,
63 #[builder(default, setter(strip_option, into))]
65 pub user_project: Option<String>,
66 #[builder(default, setter(strip_option, into))]
68 pub credential: Option<String>,
69 #[builder(default, setter(strip_option, into))]
71 pub token: Option<String>,
72 #[builder(default)]
74 pub allow_anonymous: bool,
75 #[builder(default)]
77 pub disable_vm_metadata: bool,
78 #[builder(default)]
80 pub disable_config_load: bool,
81}
82
83impl TryFrom<&StorageConfig> for GcsConfig {
84 type Error = crate::Error;
85
86 fn try_from(config: &StorageConfig) -> Result<Self> {
87 let props = config.props();
88
89 let mut cfg = GcsConfig::default();
90
91 if let Some(project_id) = props.get(GCS_PROJECT_ID) {
92 cfg.project_id = Some(project_id.clone());
93 }
94 if let Some(endpoint) = props.get(GCS_SERVICE_HOST) {
95 cfg.endpoint = Some(endpoint.clone());
96 }
97 if let Some(user_project) = props.get(GCS_USER_PROJECT) {
98 cfg.user_project = Some(user_project.clone());
99 }
100 if let Some(credential) = props.get(GCS_CREDENTIALS_JSON) {
101 cfg.credential = Some(credential.clone());
102 }
103 if let Some(token) = props.get(GCS_TOKEN) {
104 cfg.token = Some(token.clone());
105 }
106
107 if props.get(GCS_NO_AUTH).is_some() {
109 cfg.allow_anonymous = true;
110 cfg.disable_vm_metadata = true;
111 cfg.disable_config_load = true;
112 }
113
114 if let Some(allow_anonymous) = props.get(GCS_ALLOW_ANONYMOUS)
115 && is_truthy(allow_anonymous.to_lowercase().as_str())
116 {
117 cfg.allow_anonymous = true;
118 }
119 if let Some(disable_vm_metadata) = props.get(GCS_DISABLE_VM_METADATA)
120 && is_truthy(disable_vm_metadata.to_lowercase().as_str())
121 {
122 cfg.disable_vm_metadata = true;
123 }
124 if let Some(disable_config_load) = props.get(GCS_DISABLE_CONFIG_LOAD)
125 && is_truthy(disable_config_load.to_lowercase().as_str())
126 {
127 cfg.disable_config_load = true;
128 }
129
130 Ok(cfg)
131 }
132}
133
134#[cfg(test)]
135mod tests {
136 use super::*;
137
138 #[test]
139 fn test_gcs_config_builder() {
140 let config = GcsConfig::builder()
141 .project_id("my-project")
142 .credential("base64-creds")
143 .endpoint("http://localhost:4443")
144 .build();
145
146 assert_eq!(config.project_id.as_deref(), Some("my-project"));
147 assert_eq!(config.credential.as_deref(), Some("base64-creds"));
148 assert_eq!(config.endpoint.as_deref(), Some("http://localhost:4443"));
149 }
150
151 #[test]
152 fn test_gcs_config_from_storage_config() {
153 let storage_config = StorageConfig::new()
154 .with_prop(GCS_PROJECT_ID, "my-project")
155 .with_prop(GCS_CREDENTIALS_JSON, "base64-creds")
156 .with_prop(GCS_SERVICE_HOST, "http://localhost:4443");
157
158 let gcs_config = GcsConfig::try_from(&storage_config).unwrap();
159
160 assert_eq!(gcs_config.project_id.as_deref(), Some("my-project"));
161 assert_eq!(gcs_config.credential.as_deref(), Some("base64-creds"));
162 assert_eq!(
163 gcs_config.endpoint.as_deref(),
164 Some("http://localhost:4443")
165 );
166 }
167
168 #[test]
169 fn test_gcs_config_no_auth() {
170 let storage_config = StorageConfig::new().with_prop(GCS_NO_AUTH, "true");
171
172 let gcs_config = GcsConfig::try_from(&storage_config).unwrap();
173
174 assert!(gcs_config.allow_anonymous);
175 assert!(gcs_config.disable_vm_metadata);
176 assert!(gcs_config.disable_config_load);
177 }
178
179 #[test]
180 fn test_gcs_config_allow_anonymous() {
181 let storage_config = StorageConfig::new().with_prop(GCS_ALLOW_ANONYMOUS, "true");
182
183 let gcs_config = GcsConfig::try_from(&storage_config).unwrap();
184
185 assert!(gcs_config.allow_anonymous);
186 assert!(!gcs_config.disable_vm_metadata);
187 }
188}