OXYGENHUB

Coverage / crates/oxy-strata/src/gcp.rs 0.0%

0 of 57 lines run, 0 of 20 functions · run #271 on carry-identical · run missed

1
//! Google Cloud Storage: `gs://BUCKET/PREFIX`.
2
//!
3
//! Credentials, in Google's own order: a service account key file named
4
//! by `?credentials=PATH` or `GOOGLE_APPLICATION_CREDENTIALS` (which may
5
//! also hold application default credentials), the key or path in
6
//! `GOOGLE_SERVICE_ACCOUNT*`, then the application default credentials
7
//! `gcloud auth application-default login` wrote, then the instance's
8
//! service account. `?endpoint=URL` points at another endpoint.
9
10
use crate::StoreUrl;
11
use object_store::gcp::{GoogleCloudStorage, GoogleCloudStorageBuilder};
12
use oxy_core::strata::{Error, Result};
13
14
pub const HINT: &str = "run `gcloud auth application-default login`, or set GOOGLE_APPLICATION_CREDENTIALS (or add ?credentials=PATH to the remote URL) to a service account key file";
15
16
/// Whether a credentials file is a service account key, as opposed to
17
/// application default credentials.
180×
fn is_service_account_key(path: &str) -> bool {
190×
    std::fs::read_to_string(path)
200×
        .ok()
210×
        .and_then(|t| serde_json::from_str::<serde_json::Value>(&t).ok())
220×
        .and_then(|v| {
230×
            v.get("type")
240×
                .and_then(|t| t.as_str())
250×
                .map(|t| t == "service_account")
260×
        })
270×
        .unwrap_or(false)
280×
}
29
30
/// With `key` (a service account key's JSON) given, only it is used.
310×
pub fn open(url: &StoreUrl, key: Option<&str>) -> Result<GoogleCloudStorage> {
320×
    if let Some(key) = key {
330×
        let mut b = GoogleCloudStorageBuilder::new()
340×
            .with_bucket_name(&url.host)
350×
            .with_http_connector(crate::http::UreqConnector)
360×
            .with_service_account_key(key);
370×
        if let Some(endpoint) = url.param("endpoint") {
380×
            b = b.with_base_url(endpoint);
390×
        }
400×
        return b
410×
            .build()
420×
            .map_err(|e| Error::Backend(format!("{}: {e}", url.plain())));
430×
    }
440×
    let mut b = GoogleCloudStorageBuilder::from_env()
450×
        .with_bucket_name(&url.host)
460×
        .with_http_connector(crate::http::UreqConnector);
470×
    let file = url.param("credentials").map(str::to_string).or_else(|| {
480×
        std::env::var("GOOGLE_APPLICATION_CREDENTIALS")
490×
            .ok()
500×
            .filter(|v| !v.is_empty())
510×
    });
520×
    if let Some(path) = file {
530×
        if !std::path::Path::new(&path).is_file() {
540×
            return Err(Error::Backend(format!(
550×
                "{}: the credentials file {path} does not exist: {HINT}",
560×
                url.plain()
570×
            )));
580×
        }
590×
        b = if is_service_account_key(&path) {
600×
            b.with_service_account_path(path)
61
        } else {
620×
            b.with_application_credentials(path)
63
        };
640×
    }
650×
    if let Some(endpoint) = url.param("endpoint") {
660×
        b = b.with_base_url(endpoint);
670×
    }
680×
    b.build()
690×
        .map_err(|e| Error::Backend(format!("{}: {e}: {HINT}", url.plain())))
700×
}