gcloud_artifact_registry/
client.rs1use crate::grpc::apiv1::artifact_registry_client::Client as ArtifactRegistryGrpcClient;
2use google_cloud_gax::conn::{ConnectionManager, ConnectionOptions, Environment, Error};
3use std::ops::{Deref, DerefMut};
4use std::time::Duration;
5use token_source::{NoopTokenSourceProvider, TokenSourceProvider};
6
7use crate::grpc::apiv1::{ARTIFACT_REGISTRY, AUDIENCE, SCOPES};
8
9use google_cloud_googleapis::devtools::artifact_registry::v1::artifact_registry_client::ArtifactRegistryClient;
10use google_cloud_longrunning::autogen::operations_client::OperationsClient;
11
12#[derive(Debug)]
13pub struct ClientConfig {
14 pub artifact_registry_endpoint: String,
15 pub token_source_provider: Box<dyn TokenSourceProvider>,
16 pub timeout: Option<Duration>,
17 pub connect_timeout: Option<Duration>,
18 pub http2_keep_alive_interval: Option<Duration>,
19 pub keep_alive_timeout: Option<Duration>,
20 pub keep_alive_while_idle: Option<bool>,
21}
22
23#[cfg(feature = "auth")]
24pub use google_cloud_auth;
25
26#[cfg(feature = "auth")]
27impl ClientConfig {
28 pub async fn with_auth(self) -> Result<Self, google_cloud_auth::error::Error> {
29 let ts = google_cloud_auth::token::DefaultTokenSourceProvider::new(Self::auth_config()).await?;
30 Ok(self.with_token_source(ts).await)
31 }
32
33 pub async fn with_credentials(
34 self,
35 credentials: google_cloud_auth::credentials::CredentialsFile,
36 ) -> Result<Self, google_cloud_auth::error::Error> {
37 let ts = google_cloud_auth::token::DefaultTokenSourceProvider::new_with_credentials(
38 Self::auth_config(),
39 Box::new(credentials),
40 )
41 .await?;
42 Ok(self.with_token_source(ts).await)
43 }
44
45 async fn with_token_source(mut self, ts: google_cloud_auth::token::DefaultTokenSourceProvider) -> Self {
46 self.token_source_provider = Box::new(ts);
47 self
48 }
49
50 fn auth_config() -> google_cloud_auth::project::Config<'static> {
51 google_cloud_auth::project::Config::default().with_scopes(&SCOPES)
52 }
53}
54
55impl Default for ClientConfig {
56 fn default() -> Self {
57 Self {
58 artifact_registry_endpoint: ARTIFACT_REGISTRY.to_string(),
59 token_source_provider: Box::new(NoopTokenSourceProvider {}),
60 timeout: Some(Duration::from_secs(30)),
61 connect_timeout: Some(Duration::from_secs(30)),
62 http2_keep_alive_interval: None,
63 keep_alive_timeout: None,
64 keep_alive_while_idle: None,
65 }
66 }
67}
68
69#[derive(Clone)]
70pub struct Client {
71 artifact_registry_client: ArtifactRegistryGrpcClient,
72}
73
74impl Client {
75 pub async fn new(config: ClientConfig) -> Result<Self, Error> {
76 let conn_options = ConnectionOptions {
77 timeout: config.timeout,
78 connect_timeout: config.connect_timeout,
79 http2_keep_alive_interval: config.http2_keep_alive_interval,
80 keep_alive_timeout: config.keep_alive_timeout,
81 keep_alive_while_idle: config.keep_alive_while_idle,
82 };
83 let conn_pool = ConnectionManager::new(
84 1,
85 config.artifact_registry_endpoint,
86 AUDIENCE,
87 &Environment::GoogleCloud(config.token_source_provider),
88 &conn_options,
89 )
90 .await?;
91 let conn = conn_pool.conn();
92 let lro_client = OperationsClient::new(conn_pool.conn()).await.unwrap();
93
94 Ok(Self {
95 artifact_registry_client: ArtifactRegistryGrpcClient::new(ArtifactRegistryClient::new(conn), lro_client),
96 })
97 }
98}
99
100impl Deref for Client {
101 type Target = ArtifactRegistryGrpcClient;
102
103 fn deref(&self) -> &Self::Target {
104 &self.artifact_registry_client
105 }
106}
107
108impl DerefMut for Client {
109 fn deref_mut(&mut self) -> &mut Self::Target {
110 &mut self.artifact_registry_client
111 }
112}
113
114#[cfg(test)]
115mod tests {
116 use crate::client::{Client, ClientConfig};
117
118 use google_cloud_googleapis::devtools::artifact_registry::v1::repository::Format;
119 use google_cloud_googleapis::devtools::artifact_registry::v1::{
120 CreateRepositoryRequest, DeleteRepositoryRequest, GetRepositoryRequest, ListRepositoriesRequest, Repository,
121 UpdateRepositoryRequest,
122 };
123 use prost_types::FieldMask;
124 use serial_test::serial;
125 use std::time::{SystemTime, UNIX_EPOCH};
126
127 async fn new_client() -> (Client, String) {
128 let cred = google_cloud_auth::credentials::CredentialsFile::new().await.unwrap();
129 let project = cred.project_id.clone().unwrap();
130 let config = ClientConfig::default().with_credentials(cred).await.unwrap();
131 (Client::new(config).await.unwrap(), project)
132 }
133
134 #[ctor::ctor]
135 fn init() {
136 let _ = tracing_subscriber::fmt().try_init();
137 }
138
139 #[tokio::test]
140 #[serial]
141 async fn test_crud_repository() {
142 let (mut client, project) = new_client().await;
143 let now = SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs();
144 let repository_id = format!("gcrar{now}");
145
146 let create_request = CreateRepositoryRequest {
148 parent: format!("projects/{project}/locations/us-central1"),
149 repository_id,
150 repository: Some(Repository {
151 name: "".to_string(),
152 format: Format::Docker as i32,
153 description: "test repository".to_string(),
154 labels: Default::default(),
155 create_time: None,
156 update_time: None,
157 kms_key_name: "".to_string(),
158 mode: 0,
159 cleanup_policies: Default::default(),
160 size_bytes: 0,
161 satisfies_pzs: false,
162 cleanup_policy_dry_run: false,
163 format_config: None,
164 mode_config: None,
165 vulnerability_scanning_config: None,
166 disallow_unspecified_mode: false,
167 satisfies_pzi: false,
168 registry_uri: "".to_string(),
169 }),
170 };
171 let mut created_repository = client.create_repository(create_request.clone(), None).await.unwrap();
172 let result = created_repository.wait(None).await.unwrap().unwrap();
173 assert_eq!(
174 format!("{}/repositories/{}", create_request.parent, create_request.repository_id),
175 result.name
176 );
177
178 let get_request = GetRepositoryRequest {
180 name: result.name.to_string(),
181 };
182 let get_repository = client.get_repository(get_request.clone(), None).await.unwrap();
183 assert_eq!(get_repository.name, get_request.name);
184
185 let update_request = UpdateRepositoryRequest {
187 repository: Some(Repository {
188 description: "update test".to_string(),
189 ..get_repository.clone()
190 }),
191 update_mask: Some(FieldMask {
192 paths: vec!["description".to_string()],
193 }),
194 };
195 let update_repository = client.update_repository(update_request.clone(), None).await.unwrap();
196 assert_eq!(update_repository.description, update_request.repository.unwrap().description);
197
198 let list_request = ListRepositoriesRequest {
200 parent: create_request.parent.to_string(),
201 page_size: 0,
202 page_token: "".to_string(),
203 order_by: "".to_string(),
204 filter: "".to_string(),
205 };
206 let list_result = client.list_repositories(list_request, None).await.unwrap();
207 assert!(!list_result.repositories.is_empty());
208
209 let delete_request = DeleteRepositoryRequest {
211 name: get_repository.name.to_string(),
212 };
213 client.delete_repository(delete_request, None).await.unwrap();
214 }
215}