Skip to content
40 changes: 40 additions & 0 deletions core/src/services/gcs/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,14 @@ pub struct GcsConfig {
pub predefined_acl: Option<String>,
/// The default storage class used by gcs.
pub default_storage_class: Option<String>,
/// Allow opendal to send requests without signing when credentials are not
/// loaded.
pub allow_anonymous: bool,
/// Disable attempting to load credentials from the GCE metadata server when
/// running within Google Cloud.
pub disable_vm_metadata: bool,
/// Disable loading configuration from the environment.
pub disable_config_load: bool,
}

impl Debug for GcsConfig {
Expand Down Expand Up @@ -205,6 +213,18 @@ impl GcsBuilder {
self
}

/// Disable attempting to load credentials from the GCE metadata server.
pub fn disable_vm_metadata(mut self) -> Self {
self.config.disable_vm_metadata = true;
self
}

/// Disable loading configuration from the environment.
pub fn disable_config_load(mut self) -> Self {
self.config.disable_config_load = true;
self
}

/// Set the predefined acl for GCS.
///
/// Available values are:
Expand Down Expand Up @@ -234,6 +254,15 @@ impl GcsBuilder {
};
self
}

/// Allow anonymous requests.
///
/// This is typically used for buckets which are open to the public or GCS
/// storage emulators.
pub fn allow_anonymous(mut self) -> Self {
self.config.allow_anonymous = true;
self
}
}

impl Builder for GcsBuilder {
Expand Down Expand Up @@ -287,6 +316,12 @@ impl Builder for GcsBuilder {
cred_loader = cred_loader.with_disable_well_known_location();
}

if self.config.disable_config_load {
cred_loader = cred_loader
.with_disable_env()
.with_disable_well_known_location();
}

let scope = if let Some(scope) = &self.config.scope {
scope
} else {
Expand All @@ -304,6 +339,10 @@ impl Builder for GcsBuilder {
token_loader = token_loader.with_customized_token_loader(loader)
}

if self.config.disable_vm_metadata {
token_loader = token_loader.with_disable_vm_metadata(true);
}

let signer = GoogleSigner::new("storage");

let backend = GcsBackend {
Expand All @@ -317,6 +356,7 @@ impl Builder for GcsBuilder {
credential_loader: cred_loader,
predefined_acl: self.config.predefined_acl.clone(),
default_storage_class: self.config.default_storage_class.clone(),
allow_anonymous: self.config.allow_anonymous,
}),
};

Expand Down
35 changes: 23 additions & 12 deletions core/src/services/gcs/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ pub struct GcsCore {

pub predefined_acl: Option<String>,
pub default_storage_class: Option<String>,

pub allow_anonymous: bool,
}

impl Debug for GcsCore {
Expand Down Expand Up @@ -89,23 +91,30 @@ impl GcsCore {
}
}

fn load_credential(&self) -> Result<GoogleCredential> {
fn load_credential(&self) -> Result<Option<GoogleCredential>> {
Comment thread
jdockerty marked this conversation as resolved.
let cred = self
.credential_loader
.load()
.map_err(new_request_credential_error)?;

if let Some(cred) = cred {
Ok(cred)
} else {
Err(Error::new(
ErrorKind::ConfigInvalid,
"no valid credential found",
))
return Ok(Some(cred));
}

if self.allow_anonymous {
return Ok(None);
}

Err(Error::new(
ErrorKind::ConfigInvalid,
"no valid credential found",
))
}

pub async fn sign<T>(&self, req: &mut Request<T>) -> Result<()> {
if self.allow_anonymous {
return Ok(());
}
let cred = self.load_token().await?;

self.signer
Expand All @@ -124,11 +133,13 @@ impl GcsCore {
}

pub async fn sign_query<T>(&self, req: &mut Request<T>, duration: Duration) -> Result<()> {
let cred = self.load_credential()?;

self.signer
.sign_query(req, duration, &cred)
.map_err(new_request_sign_error)?;
if let Some(cred) = self.load_credential()? {
self.signer
.sign_query(req, duration, &cred)
.map_err(new_request_sign_error)?;
} else {
return Ok(());
}

// Always remove host header, let users' client to set it based on HTTP
// version.
Expand Down