From 8dddd767595fa5ee0ef66bef467018b732eb3306 Mon Sep 17 00:00:00 2001 From: Naohiro Yoshida Date: Sat, 1 Jul 2023 16:42:27 +0900 Subject: [PATCH] Move `with_auth` method for `ClientConfig` into each component's features (#172) --- .github/workflows/ci.yaml | 5 - Cargo.toml | 1 - bigquery/Cargo.toml | 7 +- bigquery/README.md | 6 +- bigquery/src/client.rs | 73 ++++++--- bigquery/src/lib.rs | 15 +- default/Cargo.toml | 38 ----- default/README.md | 19 --- default/src/lib.rs | 287 ----------------------------------- pubsub/Cargo.toml | 7 +- pubsub/README.md | 7 +- pubsub/src/client.rs | 50 +++++- pubsub/src/lib.rs | 9 +- spanner/Cargo.toml | 7 +- spanner/README.md | 4 +- spanner/src/client.rs | 37 +++++ spanner/src/lib.rs | 19 +-- spanner/tests/client_test.rs | 9 ++ storage/Cargo.toml | 8 +- storage/README.md | 8 +- storage/src/client.rs | 73 ++++++--- storage/src/lib.rs | 10 +- 22 files changed, 243 insertions(+), 456 deletions(-) delete mode 100644 default/Cargo.toml delete mode 100644 default/README.md delete mode 100644 default/src/lib.rs diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 30969fb5..92fa0074 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -55,11 +55,6 @@ jobs: with: command: test args: --release --all-features --manifest-path foundation/gax/Cargo.toml - - uses: actions-rs/cargo@v1 - name: default-test - with: - command: test - args: --release --all-features --manifest-path default/Cargo.toml - name: cargo-deny uses: EmbarkStudios/cargo-deny-action@v1 with: diff --git a/Cargo.toml b/Cargo.toml index 7995e436..517348ce 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,5 +11,4 @@ members = [ "storage", "bigquery", "spanner-derive", - "default", ] diff --git a/bigquery/Cargo.toml b/bigquery/Cargo.toml index d4bbd7eb..62ea4e23 100644 --- a/bigquery/Cargo.toml +++ b/bigquery/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "google-cloud-bigquery" -version = "0.1.1" +version = "0.2.0" edition = "2021" authors = ["yoshidan "] repository = "https://github.com/yoshidan/google-cloud-rust/tree/main/bigquery" @@ -28,6 +28,8 @@ bigdecimal = { version="0.3", features=["serde"] } num-bigint = "0.4" backon = "0.4" +google-cloud-auth = { optional = true, version = "0.11", path="../foundation/auth", default-features=false } + [dev-dependencies] tokio = { version="1.20", features=["rt-multi-thread"] } serial_test = "0.9" @@ -38,7 +40,8 @@ google-cloud-auth = { path = "../foundation/auth", default-features=false } base64-serde = "0.7" [features] -default = ["default-tls"] +default = ["default-tls", "auth"] default-tls = ["reqwest/default-tls"] rustls-tls = ["reqwest/rustls-tls"] trace = [] +auth = ["google-cloud-auth"] diff --git a/bigquery/README.md b/bigquery/README.md index 8b0992cb..505622de 100644 --- a/bigquery/README.md +++ b/bigquery/README.md @@ -8,8 +8,7 @@ Google Cloud Platform BigQuery Client library. ```toml [dependencies] -google-cloud-bigquery = -google-cloud-default = { version = , features = ["bigquery"] } +google-cloud-bigquery = version ``` ## Quick Start @@ -23,7 +22,6 @@ This is also described in [google-cloud-auth](https://github.com/yoshidan/google ```rust use google_cloud_pubsub::client::{ClientConfig, Client}; -use google_cloud_default::biqquery::CreateAuthExt; async fn run() { let (config, project_id) = ClientConfig::new_with_auth().await.unwrap(); @@ -36,8 +34,8 @@ you can parse your own version of the 'credentials-file' and use it like that: ```rust use google_cloud_auth::credentials::CredentialsFile; +// or google_cloud_bigquery::client::google_cloud_auth::credentials::CredentialsFile use google_cloud_bigquery::client::{ClientConfig, Client}; -use google_cloud_default::biqquery::CreateAuthExt; async fn run(cred: CredentialsFile) { let (config, project_id) = ClientConfig::new_with_credentials(cred).await.unwrap(); diff --git a/bigquery/src/client.rs b/bigquery/src/client.rs index d1b8aa45..d8666df1 100644 --- a/bigquery/src/client.rs +++ b/bigquery/src/client.rs @@ -90,6 +90,56 @@ impl ClientConfig { } } +#[cfg(feature = "auth")] +pub use google_cloud_auth; + +#[cfg(feature = "auth")] +impl ClientConfig { + pub async fn new_with_auth() -> Result<(Self, Option), google_cloud_auth::error::Error> { + let ts_http = + google_cloud_auth::token::DefaultTokenSourceProvider::new(Self::bigquery_http_auth_config()).await?; + let ts_grpc = + google_cloud_auth::token::DefaultTokenSourceProvider::new(Self::bigquery_grpc_auth_config()).await?; + let project_id = ts_grpc.project_id.clone(); + let config = Self::new(Box::new(ts_http), Box::new(ts_grpc)); + Ok((config, project_id)) + } + + pub async fn new_with_credentials( + credentials: google_cloud_auth::credentials::CredentialsFile, + ) -> Result<(Self, Option), google_cloud_auth::error::Error> { + let ts_http = google_cloud_auth::token::DefaultTokenSourceProvider::new_with_credentials( + Self::bigquery_http_auth_config(), + Box::new(credentials.clone()), + ) + .await?; + let ts_grpc = google_cloud_auth::token::DefaultTokenSourceProvider::new_with_credentials( + Self::bigquery_grpc_auth_config(), + Box::new(credentials), + ) + .await?; + let project_id = ts_grpc.project_id.clone(); + let config = Self::new(Box::new(ts_http), Box::new(ts_grpc)); + Ok((config, project_id)) + } + + fn bigquery_http_auth_config() -> google_cloud_auth::project::Config<'static> { + google_cloud_auth::project::Config { + audience: None, + scopes: Some(&crate::http::bigquery_client::SCOPES), + sub: None, + } + } + + fn bigquery_grpc_auth_config() -> google_cloud_auth::project::Config<'static> { + google_cloud_auth::project::Config { + audience: Some(crate::grpc::apiv1::conn_pool::AUDIENCE), + scopes: Some(&crate::grpc::apiv1::conn_pool::SCOPES), + sub: None, + } + } +} + #[derive(Clone)] pub struct Client { dataset_client: BigqueryDatasetClient, @@ -399,14 +449,10 @@ mod tests { use time::macros::datetime; use time::{Date, OffsetDateTime, Time}; - use google_cloud_auth::project::Config; - use google_cloud_auth::token::DefaultTokenSourceProvider; use google_cloud_googleapis::cloud::bigquery::storage::v1::read_session::TableReadOptions; use crate::client::{Client, ClientConfig, ReadTableOption}; - use crate::grpc::apiv1; use crate::http::bigquery_client::test::TestData; - use crate::http::bigquery_client::SCOPES; use crate::http::job::query::QueryRequest; use crate::http::table::TableReference; use crate::query; @@ -418,23 +464,8 @@ mod tests { } async fn create_client() -> (Client, String) { - let http_tsp = DefaultTokenSourceProvider::new(Config { - audience: None, - scopes: Some(&SCOPES), - sub: None, - }) - .await - .unwrap(); - let grpc_tsp = DefaultTokenSourceProvider::new(Config { - audience: Some(apiv1::conn_pool::AUDIENCE), - scopes: Some(&apiv1::conn_pool::SCOPES), - sub: None, - }) - .await - .unwrap(); - let project_id = http_tsp.source_credentials.clone().unwrap().project_id.unwrap(); - let client_config = ClientConfig::new(Box::new(http_tsp), Box::new(grpc_tsp)).with_debug(false); - (Client::new(client_config).await.unwrap(), project_id) + let (client_config, project_id) = ClientConfig::new_with_auth().await.unwrap(); + (Client::new(client_config).await.unwrap(), project_id.unwrap()) } #[tokio::test] diff --git a/bigquery/src/lib.rs b/bigquery/src/lib.rs index aebbbe71..90b0153d 100644 --- a/bigquery/src/lib.rs +++ b/bigquery/src/lib.rs @@ -2,14 +2,6 @@ //! //! Google Cloud Platform BigQuery Client library. //! -//! ## Installation -//! -//! ```toml -//! [dependencies] -//! google-cloud-bigquery = -//! google-cloud-default = { version = , features = ["bigquery"] } -//! ``` -//! //! ## Quick Start //! //! ### CreateClient @@ -19,9 +11,8 @@ //! //! This is also described in [google-cloud-auth](https://github.com/yoshidan/google-cloud-rust/blob/main/foundation/auth/README.md) //! -//! ```ignore +//! ```rust //! use google_cloud_bigquery::client::{ClientConfig, Client}; -//! use google_cloud_default::biqquery::CreateAuthExt; //! //! async fn run() { //! let (config, project_id) = ClientConfig::new_with_auth().await.unwrap(); @@ -32,10 +23,10 @@ //! When you can't use the `gcloud` authentication but you have a different way to get your credentials (e.g a different environment variable) //! you can parse your own version of the 'credentials-file' and use it like that: //! -//! ```ignore +//! ```rust //! use google_cloud_auth::credentials::CredentialsFile; +//! // or google_cloud_bigquery::client::google_cloud_auth::credentials::CredentialsFile //! use google_cloud_bigquery::client::{ClientConfig, Client}; -//! use google_cloud_default::biqquery::CreateAuthExt; //! //! async fn run(cred: CredentialsFile) { //! let (config, project_id) = ClientConfig::new_with_credentials(cred).await.unwrap(); diff --git a/default/Cargo.toml b/default/Cargo.toml deleted file mode 100644 index 73862831..00000000 --- a/default/Cargo.toml +++ /dev/null @@ -1,38 +0,0 @@ -[package] -name = "google-cloud-default" -version = "0.4.0" -authors = ["yoshidan "] -edition = "2021" -repository = "https://github.com/yoshidan/google-cloud-rust/tree/main/foundation/auth" -keywords = ["gcp","googleapis","google-cloud-rust"] -license = "MIT" -readme = "README.md" -description = "Google Cloud Platform default config." - -[dependencies] -async-trait = "0.1" - -google-cloud-auth = { version = "0.11", path = "../foundation/auth", default-features = false } - -# optional -google-cloud-metadata = { version = "0.3", path = "../foundation/metadata", optional = true } -google-cloud-gax = { version = "0.15", path = "../foundation/gax", optional = true } - -# components -google-cloud-pubsub = { version = "0.16", path = "../pubsub", optional = true } -google-cloud-spanner = { version = "0.20", path = "../spanner", optional = true } -google-cloud-storage = { version = "0.11", path = "../storage", default-features=false, optional = true } -google-cloud-bigquery = { version = "0.1", path = "../bigquery", default-features=false, optional = true } - -[dev-dependencies] -tokio = "1.20" -serial_test = "0.9" - -[features] -default = ["default-tls"] -default-tls = ["google-cloud-auth/default-tls"] -rustls-tls = ["google-cloud-auth/rustls-tls"] -spanner = ["google-cloud-spanner", "google-cloud-gax"] -pubsub = ["google-cloud-pubsub", "google-cloud-gax"] -storage = ["google-cloud-storage", "google-cloud-metadata"] -bigquery = ["google-cloud-bigquery", "google-cloud-gax"] diff --git a/default/README.md b/default/README.md deleted file mode 100644 index 483b4ff0..00000000 --- a/default/README.md +++ /dev/null @@ -1,19 +0,0 @@ -# google-cloud-default - -Google Cloud Platform default configuration for google-cloud-rust. - -[![crates.io](https://img.shields.io/crates/v/google-cloud-default.svg)](https://crates.io/crates/google-cloud-default) - -## Installation - -```toml -[dependencies] -google-cloud-default = -``` - -## Quick Start - -* [pubsub](https://github.com/yoshidan/google-cloud-rust/tree/main/pubsub) -* [spanner](https://github.com/yoshidan/google-cloud-rust/tree/main/spanner) -* [storage](https://github.com/yoshidan/google-cloud-rust/tree/main/storage) -* [bigquery](https://github.com/yoshidan/google-cloud-rust/tree/main/bigquery) diff --git a/default/src/lib.rs b/default/src/lib.rs deleted file mode 100644 index d45f1da0..00000000 --- a/default/src/lib.rs +++ /dev/null @@ -1,287 +0,0 @@ -//! # google-cloud-default -//! -//! Google Cloud Platform default configuration for google-cloud-rust. -//! -//! ## Quick Start -//! -//! * [pubsub](https://github.com/yoshidan/google-cloud-rust/tree/main/pubsub) -//! * [spanner](https://github.com/yoshidan/google-cloud-rust/tree/main/spanner) -//! * [storage](https://github.com/yoshidan/google-cloud-rust/tree/main/storage) -//! * [bigquery](https://github.com/yoshidan/google-cloud-rust/tree/main/bigquery) -//! -use async_trait::async_trait; - -use google_cloud_auth::error::Error; - -#[async_trait] -pub trait WithAuthExt { - async fn with_auth(mut self) -> Result - where - Self: Sized; - - async fn with_credentials( - self, - credentials: google_cloud_auth::credentials::CredentialsFile, - ) -> Result - where - Self: Sized; -} - -#[cfg(feature = "pubsub")] -#[async_trait] -impl WithAuthExt for google_cloud_pubsub::client::ClientConfig { - async fn with_auth(mut self) -> Result { - if let google_cloud_gax::conn::Environment::GoogleCloud(_) = self.environment { - let ts = google_cloud_auth::token::DefaultTokenSourceProvider::new(google_cloud_auth::project::Config { - audience: Some(google_cloud_pubsub::apiv1::conn_pool::AUDIENCE), - scopes: Some(&google_cloud_pubsub::apiv1::conn_pool::SCOPES), - sub: None, - }) - .await?; - self.project_id = ts.project_id.clone(); - self.environment = google_cloud_gax::conn::Environment::GoogleCloud(Box::new(ts)) - } - Ok(self) - } - - async fn with_credentials( - mut self, - credentials: google_cloud_auth::credentials::CredentialsFile, - ) -> Result { - if let google_cloud_gax::conn::Environment::GoogleCloud(_) = self.environment { - let ts = google_cloud_auth::token::DefaultTokenSourceProvider::new_with_credentials( - google_cloud_auth::project::Config { - audience: Some(google_cloud_pubsub::apiv1::conn_pool::AUDIENCE), - scopes: Some(&google_cloud_pubsub::apiv1::conn_pool::SCOPES), - sub: None, - }, - Box::new(credentials), - ) - .await?; - self.project_id = ts.project_id.clone(); - self.environment = google_cloud_gax::conn::Environment::GoogleCloud(Box::new(ts)) - } - - Ok(self) - } -} - -#[cfg(feature = "spanner")] -#[async_trait] -impl WithAuthExt for google_cloud_spanner::client::ClientConfig { - async fn with_auth(mut self) -> Result { - if let google_cloud_gax::conn::Environment::GoogleCloud(_) = self.environment { - let ts = google_cloud_auth::token::DefaultTokenSourceProvider::new(google_cloud_auth::project::Config { - audience: Some(google_cloud_spanner::apiv1::conn_pool::AUDIENCE), - scopes: Some(&google_cloud_spanner::apiv1::conn_pool::SCOPES), - sub: None, - }) - .await?; - self.environment = google_cloud_gax::conn::Environment::GoogleCloud(Box::new(ts)) - } - Ok(self) - } - - async fn with_credentials( - mut self, - credentials: google_cloud_auth::credentials::CredentialsFile, - ) -> Result { - if let google_cloud_gax::conn::Environment::GoogleCloud(_) = self.environment { - let ts = google_cloud_auth::token::DefaultTokenSourceProvider::new_with_credentials( - google_cloud_auth::project::Config { - audience: Some(google_cloud_spanner::apiv1::conn_pool::AUDIENCE), - scopes: Some(&google_cloud_spanner::apiv1::conn_pool::SCOPES), - sub: None, - }, - Box::new(credentials), - ) - .await?; - self.environment = google_cloud_gax::conn::Environment::GoogleCloud(Box::new(ts)) - } - Ok(self) - } -} - -#[cfg(feature = "storage")] -#[async_trait] -impl WithAuthExt for google_cloud_storage::client::ClientConfig { - async fn with_auth(mut self) -> Result { - let ts = google_cloud_auth::token::DefaultTokenSourceProvider::new(google_cloud_auth::project::Config { - audience: None, - scopes: Some(&google_cloud_storage::http::storage_client::SCOPES), - sub: None, - }) - .await?; - - match &ts.source_credentials { - // Credential file is used. - Some(cred) => { - self.project_id = cred.project_id.clone(); - if let Some(pk) = &cred.private_key { - self.default_sign_by = - Some(google_cloud_storage::sign::SignBy::PrivateKey(pk.clone().into_bytes())); - } - self.default_google_access_id = cred.client_email.clone(); - } - // On Google Cloud - None => { - self.project_id = Some(google_cloud_metadata::project_id().await); - self.default_sign_by = Some(google_cloud_storage::sign::SignBy::SignBytes); - self.default_google_access_id = google_cloud_metadata::email("default").await.ok(); - } - } - - self.token_source_provider = Box::new(ts); - Ok(self) - } - - async fn with_credentials( - mut self, - credentials: google_cloud_auth::credentials::CredentialsFile, - ) -> Result { - let ts = google_cloud_auth::token::DefaultTokenSourceProvider::new_with_credentials( - google_cloud_auth::project::Config { - audience: None, - scopes: Some(&google_cloud_storage::http::storage_client::SCOPES), - sub: None, - }, - Box::new(credentials), - ) - .await?; - - match &ts.source_credentials { - // Credential file is used. - Some(cred) => { - self.project_id = cred.project_id.clone(); - if let Some(pk) = &cred.private_key { - self.default_sign_by = - Some(google_cloud_storage::sign::SignBy::PrivateKey(pk.clone().into_bytes())); - } - self.default_google_access_id = cred.client_email.clone(); - } - // On Google Cloud - None => { - self.project_id = Some(google_cloud_metadata::project_id().await); - self.default_sign_by = Some(google_cloud_storage::sign::SignBy::SignBytes); - self.default_google_access_id = google_cloud_metadata::email("default").await.ok(); - } - } - - self.token_source_provider = Box::new(ts); - Ok(self) - } -} - -#[cfg(feature = "bigquery")] -pub mod bigquery { - use async_trait::async_trait; - use google_cloud_auth::credentials::CredentialsFile; - use google_cloud_auth::error::Error; - use google_cloud_auth::project::Config; - use google_cloud_auth::token::DefaultTokenSourceProvider; - use google_cloud_bigquery::client::ClientConfig; - - #[async_trait] - pub trait CreateAuthExt { - async fn new_with_auth() -> Result<(Self, Option), Error> - where - Self: Sized; - - async fn new_with_credentials(credentials: CredentialsFile) -> Result<(Self, Option), Error> - where - Self: Sized; - } - - #[async_trait] - impl CreateAuthExt for ClientConfig { - async fn new_with_auth() -> Result<(Self, Option), Error> { - let ts_http = DefaultTokenSourceProvider::new(bigquery_http_auth_config()).await?; - let ts_grpc = DefaultTokenSourceProvider::new(bigquery_grpc_auth_config()).await?; - let project_id = ts_grpc.project_id.clone(); - let config = Self::new(Box::new(ts_http), Box::new(ts_grpc)); - Ok((config, project_id)) - } - async fn new_with_credentials(credentials: CredentialsFile) -> Result<(Self, Option), Error> - where - Self: Sized, - { - let ts_http = DefaultTokenSourceProvider::new_with_credentials( - bigquery_http_auth_config(), - Box::new(credentials.clone()), - ) - .await?; - let ts_grpc = - DefaultTokenSourceProvider::new_with_credentials(bigquery_grpc_auth_config(), Box::new(credentials)) - .await?; - let project_id = ts_grpc.project_id.clone(); - let config = Self::new(Box::new(ts_http), Box::new(ts_grpc)); - Ok((config, project_id)) - } - } - - #[cfg(feature = "bigquery")] - fn bigquery_http_auth_config() -> Config<'static> { - Config { - audience: None, - scopes: Some(&google_cloud_bigquery::http::bigquery_client::SCOPES), - sub: None, - } - } - - #[cfg(feature = "bigquery")] - fn bigquery_grpc_auth_config() -> Config<'static> { - Config { - audience: Some(google_cloud_bigquery::grpc::apiv1::conn_pool::AUDIENCE), - scopes: Some(&google_cloud_bigquery::grpc::apiv1::conn_pool::SCOPES), - sub: None, - } - } -} - -#[cfg(test)] -mod test { - use google_cloud_gax::conn::Environment; - - use crate::WithAuthExt; - - #[tokio::test] - async fn test_spanner() { - let config = google_cloud_spanner::client::ClientConfig::default() - .with_auth() - .await - .unwrap(); - if let Environment::Emulator(_) = config.environment { - unreachable!() - } - } - - #[tokio::test] - async fn test_pubsub() { - let config = google_cloud_pubsub::client::ClientConfig::default() - .with_auth() - .await - .unwrap(); - if let Environment::Emulator(_) = config.environment { - unreachable!() - } - } - - #[tokio::test] - async fn test_storage() { - let config = google_cloud_storage::client::ClientConfig::default() - .with_auth() - .await - .unwrap(); - assert!(config.default_google_access_id.is_some()); - assert!(config.default_sign_by.is_some()); - } - - #[tokio::test] - async fn test_bigquery() { - use crate::bigquery::CreateAuthExt; - let (_config, project_id) = google_cloud_bigquery::client::ClientConfig::new_with_auth() - .await - .unwrap(); - assert!(project_id.is_some()) - } -} diff --git a/pubsub/Cargo.toml b/pubsub/Cargo.toml index bc458ee8..47b96072 100644 --- a/pubsub/Cargo.toml +++ b/pubsub/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "google-cloud-pubsub" -version = "0.16.0" +version = "0.17.0" authors = ["yoshidan "] edition = "2021" repository = "https://github.com/yoshidan/google-cloud-rust/tree/main/pubsub" @@ -23,6 +23,8 @@ google-cloud-token = { version = "0.1.1", path = "../foundation/token" } google-cloud-gax = { version = "0.15.0", path = "../foundation/gax" } google-cloud-googleapis = { version = "0.10.0", path = "../googleapis", features = ["pubsub"]} +google-cloud-auth = { optional = true, version = "0.11", path="../foundation/auth", default-features=false } + [dev-dependencies] tokio = { version="1.20", features=["rt-multi-thread"] } rand = "0.8.5" @@ -33,6 +35,7 @@ ctor = "0.1.21" futures-util = "0.3" [features] -default = [] +default = ["auth"] trace = [] bytes = ["google-cloud-googleapis/bytes"] +auth = ["google-cloud-auth"] diff --git a/pubsub/README.md b/pubsub/README.md index fabdd066..43c8c151 100644 --- a/pubsub/README.md +++ b/pubsub/README.md @@ -12,15 +12,13 @@ Google Cloud Platform pub/sub library. ```toml [dependencies] -google-cloud-pubsub = -google-cloud-default = { version = , features = ["pubsub"] } +google-cloud-pubsub = "version" ``` ## Quickstart ### Authentication There are two ways to create a client that is authenticated against the google cloud. -The crate [google-cloud-default](https://crates.io/crates/google-cloud-default) provides two methods that help to implement those. #### Automatically @@ -31,7 +29,6 @@ This is also described in [google-cloud-auth](https://github.com/yoshidan/google ```rust use google_cloud_pubsub::client::{ClientConfig, Client}; -use google_cloud_default::WithAuthExt; async fn run() { let config = ClientConfig::default().with_auth().await.unwrap(); @@ -46,8 +43,8 @@ you can parse your own version of the 'credentials-file' and use it like that: ```rust use google_cloud_auth::credentials::CredentialsFile; +// or google_cloud_pubsub::client::google_cloud_auth::credentials::CredentialsFile use google_cloud_pubsub::client::{ClientConfig, Client}; -use google_cloud_default::WithAuthExt; async fn run(cred: CredentialsFile) { let config = ClientConfig::default().with_credentials(cred).await.unwrap(); diff --git a/pubsub/src/client.rs b/pubsub/src/client.rs index ecdbc6e9..6ac5b759 100644 --- a/pubsub/src/client.rs +++ b/pubsub/src/client.rs @@ -43,6 +43,45 @@ impl Default for ClientConfig { } } +#[cfg(feature = "auth")] +pub use google_cloud_auth; + +#[cfg(feature = "auth")] +impl ClientConfig { + pub async fn with_auth(mut self) -> Result { + if let Environment::GoogleCloud(_) = self.environment { + let ts = google_cloud_auth::token::DefaultTokenSourceProvider::new(Self::auth_config()).await?; + self.project_id = ts.project_id.clone(); + self.environment = Environment::GoogleCloud(Box::new(ts)) + } + Ok(self) + } + + pub async fn with_credentials( + mut self, + credentials: google_cloud_auth::credentials::CredentialsFile, + ) -> Result { + if let Environment::GoogleCloud(_) = self.environment { + let ts = google_cloud_auth::token::DefaultTokenSourceProvider::new_with_credentials( + Self::auth_config(), + Box::new(credentials), + ) + .await?; + self.project_id = ts.project_id.clone(); + self.environment = Environment::GoogleCloud(Box::new(ts)) + } + Ok(self) + } + + fn auth_config() -> google_cloud_auth::project::Config<'static> { + google_cloud_auth::project::Config { + audience: Some(crate::apiv1::conn_pool::AUDIENCE), + scopes: Some(&crate::apiv1::conn_pool::SCOPES), + sub: None, + } + } +} + #[derive(thiserror::Error, Debug)] pub enum Error { #[error(transparent)] @@ -238,13 +277,14 @@ mod tests { use std::thread; use std::time::Duration; + use google_cloud_gax::conn::Environment; use serial_test::serial; use tokio_util::sync::CancellationToken; use uuid::Uuid; use google_cloud_googleapis::pubsub::v1::PubsubMessage; - use crate::client::Client; + use crate::client::{Client, ClientConfig}; use crate::subscriber::SubscriberConfig; use crate::subscription::{ReceiveConfig, SubscriptionConfig}; @@ -411,4 +451,12 @@ mod tests { assert_eq!(1, subs_after.len() - subs.len()); assert_eq!(1, snapshots_after.len() - snapshots.len()); } + + #[tokio::test] + async fn test_with_auth() { + let config = ClientConfig::default().with_auth().await.unwrap(); + if let Environment::GoogleCloud(_) = config.environment { + unreachable!() + } + } } diff --git a/pubsub/src/lib.rs b/pubsub/src/lib.rs index a6492d6b..23ca124b 100644 --- a/pubsub/src/lib.rs +++ b/pubsub/src/lib.rs @@ -10,8 +10,6 @@ //! ### Authentication //! There are two ways to create a client that is authenticated against the google cloud. //! -//! The crate [google-cloud-default](https://crates.io/crates/google-cloud-default) provides two methods that help to implement those. -//! //! #### Automatically //! //! The function `with_auth()` will try and read the credentials from a file specified in the environment variable `GOOGLE_APPLICATION_CREDENTIALS`, `GOOGLE_APPLICATION_CREDENTIALS_JSON` or @@ -19,9 +17,8 @@ //! //! This is also described in [google-cloud-auth](https://github.com/yoshidan/google-cloud-rust/blob/main/foundation/auth/README.md) //! -//! ```ignore +//! ```rust //! use google_cloud_pubsub::client::{ClientConfig, Client}; -//! use google_cloud_default::WithAuthExt; //! //! async fn run() { //! let config = ClientConfig::default().with_auth().await.unwrap(); @@ -34,10 +31,10 @@ //! When you cant use the `gcloud` authentication but you have a different way to get your credentials (e.g a different environment variable) //! you can parse your own version of the 'credentials-file' and use it like that: //! -//! ```ignore +//! ```rust //! use google_cloud_auth::credentials::CredentialsFile; +//! // or google_cloud_pubsub::client::google_cloud_auth::credentials::CredentialsFile //! use google_cloud_pubsub::client::{ClientConfig, Client}; -//! use google_cloud_default::WithAuthExt; //! //! async fn run(cred: CredentialsFile) { //! let config = ClientConfig::default().with_credentials(cred).await.unwrap(); diff --git a/spanner/Cargo.toml b/spanner/Cargo.toml index f7c95a0a..e537097b 100644 --- a/spanner/Cargo.toml +++ b/spanner/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "google-cloud-spanner" -version = "0.20.0" +version = "0.21.0" authors = ["yoshidan "] edition = "2021" repository = "https://github.com/yoshidan/google-cloud-rust/tree/main/spanner" @@ -27,6 +27,8 @@ google-cloud-longrunning= { version = "0.15.0", path = "../foundation/longrunnin google-cloud-gax = { version = "0.15.0", path = "../foundation/gax" } google-cloud-googleapis = { version = "0.10.0", path = "../googleapis", features = ["spanner"]} +google-cloud-auth = { optional = true, version = "0.11", path="../foundation/auth", default-features=false } + [dev-dependencies] tokio = { version="1.20", features=["rt-multi-thread"] } tracing-subscriber = { version="0.3", features=["env-filter"] } @@ -35,5 +37,6 @@ ctor = "0.1" google-cloud-auth = { path="../foundation/auth", default-features=false, features=["rustls-tls"]} [features] -default = ["serde"] +default = ["serde", "auth"] trace = [] +auth = ["google-cloud-auth"] diff --git a/spanner/README.md b/spanner/README.md index 113c3c91..9c1c8d0d 100644 --- a/spanner/README.md +++ b/spanner/README.md @@ -12,8 +12,7 @@ Google Cloud Platform spanner library. ```toml [dependencies] -google-cloud-spanner = -google-cloud-default = { version = , features = ["spanner"] } +google-cloud-spanner = "version" ``` ## Quickstart @@ -27,7 +26,6 @@ Create `Client` and call transaction API same as [Google Cloud Go](https://githu use google_cloud_spanner::reader::AsyncIterator; use google_cloud_spanner::value::CommitTimestamp; use google_cloud_spanner::client::Error; - use google_cloud_default::WithAuthExt; #[tokio::main] async fn main() -> Result<(), Error> { diff --git a/spanner/src/client.rs b/spanner/src/client.rs index 2ac40f1b..3af1f9eb 100644 --- a/spanner/src/client.rs +++ b/spanner/src/client.rs @@ -95,6 +95,43 @@ impl Default for ClientConfig { } } +#[cfg(feature = "auth")] +pub use google_cloud_auth; + +#[cfg(feature = "auth")] +impl ClientConfig { + pub async fn with_auth(mut self) -> Result { + if let Environment::GoogleCloud(_) = self.environment { + let ts = google_cloud_auth::token::DefaultTokenSourceProvider::new(Self::auth_config()).await?; + self.environment = Environment::GoogleCloud(Box::new(ts)) + } + Ok(self) + } + + pub async fn with_credentials( + mut self, + credentials: google_cloud_auth::credentials::CredentialsFile, + ) -> Result { + if let Environment::GoogleCloud(_) = self.environment { + let ts = google_cloud_auth::token::DefaultTokenSourceProvider::new_with_credentials( + Self::auth_config(), + Box::new(credentials), + ) + .await?; + self.environment = Environment::GoogleCloud(Box::new(ts)) + } + Ok(self) + } + + fn auth_config() -> google_cloud_auth::project::Config<'static> { + google_cloud_auth::project::Config { + audience: Some(crate::apiv1::conn_pool::AUDIENCE), + scopes: Some(&crate::apiv1::conn_pool::SCOPES), + sub: None, + } + } +} + #[derive(thiserror::Error, Debug)] pub enum Error { #[error(transparent)] diff --git a/spanner/src/lib.rs b/spanner/src/lib.rs index 77b337cb..6ccbb70a 100644 --- a/spanner/src/lib.rs +++ b/spanner/src/lib.rs @@ -7,8 +7,6 @@ //! * [Rust client Documentation](#Documentation) //! //! ## Quickstart -//! You can use [google-cloud-default](https://crates.io/crates/google-cloud-default) to create `ClientConfig` -//! //! Create `Client` and call transaction API same as [Google Cloud Go](https://github.com/googleapis/google-cloud-go/tree/main/spanner). //! //! ``` @@ -78,13 +76,11 @@ //! //! To start working with this package, create a client that refers to the database of interest: //! -//! ```ignore +//! ``` //! use google_cloud_spanner::client::Client; //! use google_cloud_spanner::client::ClientConfig; -//! use google_cloud_default::WithAuthExt; //! -//! #[tokio::main] -//! async fn main() { +//! async fn run() { //! const DATABASE: &str = "projects/local-project/instances/test-instance/databases/local-database"; //! //! // google_cloud_default provides default ClientConfig with credentials source @@ -92,7 +88,6 @@ //! let mut client = Client::new(DATABASE, config).await.unwrap(); //! //! client.close().await; -//! Ok(()) //! } //! ``` //! @@ -121,9 +116,6 @@ //! //! There are two ways to create a client that is authenticated against the google cloud. //! -//! The crate [google-cloud-default](https://crates.io/crates/google-cloud-default) provides two -//! methods that help implementing those. -//! //! #### Automatically //! //! The function `with_auth()` will try and read the credentials from a file specified in the environment variable `GOOGLE_APPLICATION_CREDENTIALS`, `GOOGLE_APPLICATION_CREDENTIALS_JSON` or @@ -131,9 +123,8 @@ //! //! This is also described in [google-cloud-auth](https://github.com/yoshidan/google-cloud-rust/blob/main/foundation/auth/README.md) //! -//! ```ignore +//! ``` //! use google_cloud_spanner::client::{ClientConfig, Client}; -//! use google_cloud_default::WithAuthExt; //! //! async fn run() { //! let config = ClientConfig::default().with_auth().await.unwrap(); @@ -146,10 +137,10 @@ //! When you can't use the `gcloud` authentication but you have a different way to get your credentials (e.g a different environment variable) //! you can parse your own version of the 'credentials-file' and use it like that: //! -//! ```ignore +//! ``` //! use google_cloud_auth::credentials::CredentialsFile; +//! // or google_cloud_spanner::client::google_cloud_auth::credentials::CredentialsFile //! use google_cloud_spanner::client::{ClientConfig, Client}; -//! use google_cloud_default::WithAuthExt; //! //! async fn run(cred: CredentialsFile) { //! let config = ClientConfig::default().with_credentials(cred).await.unwrap(); diff --git a/spanner/tests/client_test.rs b/spanner/tests/client_test.rs index 87b98dfc..10c3e61e 100644 --- a/spanner/tests/client_test.rs +++ b/spanner/tests/client_test.rs @@ -2,6 +2,7 @@ use serial_test::serial; use time::OffsetDateTime; use common::*; +use google_cloud_gax::conn::Environment; use google_cloud_gax::grpc::{Code, Status}; use google_cloud_gax::retry::TryAs; use google_cloud_spanner::client::{Client, ClientConfig, Error}; @@ -232,3 +233,11 @@ async fn test_begin_read_write_transaction_retry() { } assert_eq!(retry_count, 5); } + +#[tokio::test] +async fn test_with_auth() { + let config = ClientConfig::default().with_auth().await.unwrap(); + if let Environment::GoogleCloud(_) = config.environment { + unreachable!() + } +} diff --git a/storage/Cargo.toml b/storage/Cargo.toml index 04553c39..d7be4bd8 100644 --- a/storage/Cargo.toml +++ b/storage/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "google-cloud-storage" -version = "0.11.1" +version = "0.12.0" edition = "2021" authors = ["yoshidan "] repository = "https://github.com/yoshidan/google-cloud-rust/tree/main/storage" @@ -32,6 +32,9 @@ percent-encoding = "2.1" futures-util = "0.3" bytes = "1.2" +google-cloud-metadata = { optional = true, version = "0.3", path = "../foundation/metadata" } +google-cloud-auth = { optional = true, version = "0.11", path="../foundation/auth", default-features=false } + [dev-dependencies] tokio = { version="1.20", features=["rt-multi-thread"] } serial_test = "0.9" @@ -41,7 +44,8 @@ tokio-util = {version ="0.7", features = ["codec"] } google-cloud-auth = { path = "../foundation/auth", default-features=false } [features] -default = ["default-tls"] +default = ["default-tls", "auth"] default-tls = ["reqwest/default-tls"] rustls-tls = ["reqwest/rustls-tls"] trace = [] +auth = ["google-cloud-auth", "google-cloud-metadata"] diff --git a/storage/README.md b/storage/README.md index c7d6c7d1..6fe82d88 100644 --- a/storage/README.md +++ b/storage/README.md @@ -11,8 +11,7 @@ Google Cloud Platform Storage Client library. ```toml [dependencies] -google-cloud-storage = -google-cloud-default = { version = , features = ["storage"] } +google-cloud-storage = "version" ``` ## Quickstart @@ -20,8 +19,6 @@ google-cloud-default = { version = , features = ["storage"] } ### Authentication There are two ways to create a client that is authenticated against the google cloud. -The crate [google-cloud-default](https://crates.io/crates/google-cloud-default) provides two methods that help to implement those. - #### Automatically The function `with_auth()` will try and read the credentials from a file specified in the environment variable `GOOGLE_APPLICATION_CREDENTIALS`, `GOOGLE_APPLICATION_CREDENTIALS_JSON` or @@ -31,7 +28,6 @@ This is also described in [google-cloud-auth](https://github.com/yoshidan/google ```rust use google_cloud_storage::client::{ClientConfig, Client}; -use google_cloud_default::WithAuthExt; async fn run() { let config = ClientConfig::default().with_auth().await.unwrap(); @@ -46,8 +42,8 @@ you can parse your own version of the 'credentials-file' and use it like that: ```rust use google_cloud_auth::credentials::CredentialsFile; +// or google_cloud_storage::client::google_cloud_auth::credentials::CredentialsFile use google_cloud_storage::client::{ClientConfig, Client}; -use google_cloud_default::WithAuthExt; async fn run(cred: CredentialsFile) { let config = ClientConfig::default().with_credentials(cred).await.unwrap(); diff --git a/storage/src/client.rs b/storage/src/client.rs index 5349c05b..8faadb5f 100644 --- a/storage/src/client.rs +++ b/storage/src/client.rs @@ -35,6 +35,58 @@ impl Default for ClientConfig { } } +#[cfg(feature = "auth")] +pub use google_cloud_auth; + +#[cfg(feature = "auth")] +impl ClientConfig { + pub async fn with_auth(self) -> Result { + let ts = google_cloud_auth::token::DefaultTokenSourceProvider::new(Self::auth_config()).await?; + Ok(self.with_token_source(ts).await) + } + + pub async fn with_credentials( + self, + credentials: google_cloud_auth::credentials::CredentialsFile, + ) -> Result { + let ts = google_cloud_auth::token::DefaultTokenSourceProvider::new_with_credentials( + Self::auth_config(), + Box::new(credentials), + ) + .await?; + Ok(self.with_token_source(ts).await) + } + + async fn with_token_source(mut self, ts: google_cloud_auth::token::DefaultTokenSourceProvider) -> Self { + match &ts.source_credentials { + // Credential file is used. + Some(cred) => { + self.project_id = cred.project_id.clone(); + if let Some(pk) = &cred.private_key { + self.default_sign_by = Some(PrivateKey(pk.clone().into_bytes())); + } + self.default_google_access_id = cred.client_email.clone(); + } + // On Google Cloud + None => { + self.project_id = Some(google_cloud_metadata::project_id().await); + self.default_sign_by = Some(SignBy::SignBytes); + self.default_google_access_id = google_cloud_metadata::email("default").await.ok(); + } + } + self.token_source_provider = Box::new(ts); + self + } + + fn auth_config() -> google_cloud_auth::project::Config<'static> { + google_cloud_auth::project::Config { + audience: None, + scopes: Some(&crate::http::storage_client::SCOPES), + sub: None, + } + } +} + #[derive(Clone)] pub struct Client { default_google_access_id: Option, @@ -198,9 +250,6 @@ mod test { use serial_test::serial; use time::OffsetDateTime; - use google_cloud_auth::project::Config; - use google_cloud_auth::token::DefaultTokenSourceProvider; - use crate::client::{Client, ClientConfig}; use crate::http::buckets::delete::DeleteBucketRequest; use crate::http::buckets::iam_configuration::{PublicAccessPrevention, UniformBucketLevelAccess}; @@ -209,8 +258,7 @@ mod test { }; use crate::http::buckets::list::ListBucketsRequest; use crate::http::buckets::{lifecycle, Billing, Cors, IamConfiguration, Lifecycle, Website}; - use crate::http::storage_client::SCOPES; - use crate::sign::{SignBy, SignedURLMethod, SignedURLOptions}; + use crate::sign::{SignedURLMethod, SignedURLOptions}; #[ctor::ctor] fn init() { @@ -218,20 +266,7 @@ mod test { } async fn create_client() -> (Client, String) { - let mut config = ClientConfig::default(); - let ts = DefaultTokenSourceProvider::new(Config { - audience: None, - scopes: Some(&SCOPES), - sub: None, - }) - .await - .unwrap(); - - let cred = &ts.source_credentials.clone().unwrap(); - config.project_id = cred.project_id.clone(); - config.token_source_provider = Box::new(ts); - config.default_google_access_id = cred.client_email.clone(); - config.default_sign_by = Some(SignBy::PrivateKey(cred.private_key.clone().unwrap().into_bytes())); + let config = ClientConfig::default().with_auth().await.unwrap(); let project_id = config.project_id.clone(); (Client::new(config), project_id.unwrap()) } diff --git a/storage/src/lib.rs b/storage/src/lib.rs index ffed258c..468ecc3d 100644 --- a/storage/src/lib.rs +++ b/storage/src/lib.rs @@ -10,9 +10,6 @@ //! ### Authentication //! There are two ways to create a client that is authenticated against the google cloud. //! -//! The crate [google-cloud-default](https://crates.io/crates/google-cloud-default) provides two -//! methods that help to implement those. -//! //! #### Automatically //! //! The function `with_auth()` will try and read the credentials from a file specified in the environment variable `GOOGLE_APPLICATION_CREDENTIALS`, `GOOGLE_APPLICATION_CREDENTIALS_JSON` or @@ -20,9 +17,8 @@ //! //! This is also described in [google-cloud-auth](https://github.com/yoshidan/google-cloud-rust/blob/main/foundation/auth/README.md) //! -//! ```ignore +//! ``` //! use google_cloud_storage::client::{ClientConfig, Client}; -//! use google_cloud_default::WithAuthExt; //! //! async fn run() { //! let config = ClientConfig::default().with_auth().await.unwrap(); @@ -35,10 +31,10 @@ //! When you cant use the `gcloud` authentication but you have a different way to get your credentials (e.g a different environment variable) //! you can parse your own version of the 'credentials-file' and use it like that: //! -//! ```ignore +//! ``` //! use google_cloud_auth::credentials::CredentialsFile; +//! // or google_cloud_storage::client::google_cloud_auth::credentials::CredentialsFile //! use google_cloud_storage::client::{ClientConfig, Client}; -//! use google_cloud_default::WithAuthExt; //! //! async fn run(cred: CredentialsFile) { //! let config = ClientConfig::default().with_credentials(cred).await.unwrap();