1use 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_PATH: &str = "gcs.service.path";
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)]
57pub struct GcsConfig {
58 #[builder(default, setter(strip_option, into))]
60 pub project_id: Option<String>,
61 #[builder(default, setter(strip_option, into))]
63 pub endpoint: Option<String>,
64 #[builder(default, setter(strip_option, into))]
66 pub user_project: Option<String>,
67 #[builder(default, setter(strip_option, into))]
69 pub credential: Option<String>,
70 #[builder(default, setter(strip_option, into))]
72 pub token: Option<String>,
73 #[builder(default)]
75 pub allow_anonymous: bool,
76 #[builder(default)]
78 pub disable_vm_metadata: bool,
79 #[builder(default)]
81 pub disable_config_load: bool,
82}
83
84impl TryFrom<&StorageConfig> for GcsConfig {
85 type Error = crate::Error;
86
87 fn try_from(config: &StorageConfig) -> Result<Self> {
88 let props = config.props();
89
90 let mut cfg = GcsConfig::default();
91
92 if let Some(project_id) = props.get(GCS_PROJECT_ID) {
93 cfg.project_id = Some(project_id.clone());
94 }
95 if let Some(endpoint) = props.get(GCS_SERVICE_PATH) {
96 cfg.endpoint = Some(endpoint.clone());
97 }
98 if let Some(user_project) = props.get(GCS_USER_PROJECT) {
99 cfg.user_project = Some(user_project.clone());
100 }
101 if let Some(credential) = props.get(GCS_CREDENTIALS_JSON) {
102 cfg.credential = Some(credential.clone());
103 }
104 if let Some(token) = props.get(GCS_TOKEN) {
105 cfg.token = Some(token.clone());
106 }
107
108 if props.get(GCS_NO_AUTH).is_some() {
110 cfg.allow_anonymous = true;
111 cfg.disable_vm_metadata = true;
112 cfg.disable_config_load = true;
113 }
114
115 if let Some(allow_anonymous) = props.get(GCS_ALLOW_ANONYMOUS)
116 && is_truthy(allow_anonymous.to_lowercase().as_str())
117 {
118 cfg.allow_anonymous = true;
119 }
120 if let Some(disable_vm_metadata) = props.get(GCS_DISABLE_VM_METADATA)
121 && is_truthy(disable_vm_metadata.to_lowercase().as_str())
122 {
123 cfg.disable_vm_metadata = true;
124 }
125 if let Some(disable_config_load) = props.get(GCS_DISABLE_CONFIG_LOAD)
126 && is_truthy(disable_config_load.to_lowercase().as_str())
127 {
128 cfg.disable_config_load = true;
129 }
130
131 Ok(cfg)
132 }
133}
134
135#[cfg(test)]
136mod tests {
137 use super::*;
138
139 #[test]
140 fn test_gcs_config_builder() {
141 let config = GcsConfig::builder()
142 .project_id("my-project")
143 .credential("base64-creds")
144 .endpoint("http://localhost:4443")
145 .build();
146
147 assert_eq!(config.project_id.as_deref(), Some("my-project"));
148 assert_eq!(config.credential.as_deref(), Some("base64-creds"));
149 assert_eq!(config.endpoint.as_deref(), Some("http://localhost:4443"));
150 }
151
152 #[test]
153 fn test_gcs_config_from_storage_config() {
154 let storage_config = StorageConfig::new()
155 .with_prop(GCS_PROJECT_ID, "my-project")
156 .with_prop(GCS_CREDENTIALS_JSON, "base64-creds")
157 .with_prop(GCS_SERVICE_PATH, "http://localhost:4443");
158
159 let gcs_config = GcsConfig::try_from(&storage_config).unwrap();
160
161 assert_eq!(gcs_config.project_id.as_deref(), Some("my-project"));
162 assert_eq!(gcs_config.credential.as_deref(), Some("base64-creds"));
163 assert_eq!(
164 gcs_config.endpoint.as_deref(),
165 Some("http://localhost:4443")
166 );
167 }
168
169 #[test]
170 fn test_gcs_config_no_auth() {
171 let storage_config = StorageConfig::new().with_prop(GCS_NO_AUTH, "true");
172
173 let gcs_config = GcsConfig::try_from(&storage_config).unwrap();
174
175 assert!(gcs_config.allow_anonymous);
176 assert!(gcs_config.disable_vm_metadata);
177 assert!(gcs_config.disable_config_load);
178 }
179
180 #[test]
181 fn test_gcs_config_allow_anonymous() {
182 let storage_config = StorageConfig::new().with_prop(GCS_ALLOW_ANONYMOUS, "true");
183
184 let gcs_config = GcsConfig::try_from(&storage_config).unwrap();
185
186 assert!(gcs_config.allow_anonymous);
187 assert!(!gcs_config.disable_vm_metadata);
188 }
189}