11// Builders for the various client structs for Docker/Kube etc.
22
3+ use std:: sync:: OnceLock ;
4+
35use anyhow:: { anyhow, bail, Context , Error , Result } ;
46use bollard;
57use futures:: TryFutureExt ;
@@ -17,16 +19,27 @@ use crate::configparser::config;
1719//
1820// Docker stuff
1921//
20- pub async fn docker ( ) -> Result < bollard:: Docker > {
21- debug ! ( "connecting to docker..." ) ;
22- let client = bollard:: Docker :: connect_with_defaults ( ) ?;
23- client
24- . ping ( )
25- . await
26- // truncate error chain with new error (returned error is way too verbose)
27- . map_err ( |_| anyhow ! ( "could not talk to Docker daemon (is DOCKER_HOST correct?)" ) ) ?;
2822
29- Ok ( client)
23+ static DOCKER_CLIENT : OnceLock < bollard:: Docker > = OnceLock :: new ( ) ;
24+
25+ /// Return existing or create new Docker client
26+ pub async fn docker ( ) -> Result < & ' static bollard:: Docker > {
27+ match DOCKER_CLIENT . get ( ) {
28+ Some ( d) => Ok ( d) ,
29+ None => {
30+ debug ! ( "connecting to docker..." ) ;
31+ let client = bollard:: Docker :: connect_with_defaults ( ) ?;
32+ client
33+ . ping ( )
34+ . await
35+ // truncate error chain with new error (returned error is way too verbose)
36+ . map_err ( |_| {
37+ anyhow ! ( "could not talk to Docker daemon (is DOCKER_HOST correct?)" )
38+ } ) ?;
39+
40+ Ok ( DOCKER_CLIENT . get_or_init ( || client) )
41+ }
42+ }
3043}
3144
3245#[ derive( Debug ) ]
@@ -54,27 +67,38 @@ pub async fn engine_type() -> EngineType {
5467// S3 stuff
5568//
5669
57- /// create bucket client for passed profile config
58- pub fn bucket_client ( config : & config:: S3Config ) -> Result < Box < s3:: Bucket > > {
59- trace ! ( "creating bucket client" ) ;
60- // TODO: once_cell this so it reuses the same bucket?
61- let region = s3:: Region :: Custom {
62- region : config. region . clone ( ) ,
63- endpoint : config. endpoint . clone ( ) ,
64- } ;
65- let creds = s3:: creds:: Credentials :: new (
66- Some ( & config. access_key ) ,
67- Some ( & config. secret_key ) ,
68- None ,
69- None ,
70- None ,
71- ) ?;
72- let bucket = s3:: Bucket :: new ( & config. bucket_name , region, creds) ?. with_path_style ( ) ;
73-
74- Ok ( bucket)
70+ // this does need to be a OnceLock instead of a LazyLock, even though how this
71+ // is used is more inline with a LazyLock. Lazy does not allow for passing
72+ // anything into the init function, and this needs a parameter to know what
73+ // profile to fetch creds for.
74+ static BUCKET_CLIENT : OnceLock < Box < s3:: Bucket > > = OnceLock :: new ( ) ;
75+
76+ /// return existing or create new bucket client for passed profile config
77+ pub fn bucket_client ( config : & config:: S3Config ) -> Result < & s3:: Bucket > {
78+ match BUCKET_CLIENT . get ( ) {
79+ Some ( b) => Ok ( b) ,
80+ None => {
81+ trace ! ( "creating bucket client" ) ;
82+ let region = s3:: Region :: Custom {
83+ region : config. region . clone ( ) ,
84+ endpoint : config. endpoint . clone ( ) ,
85+ } ;
86+ let creds = s3:: creds:: Credentials :: new (
87+ Some ( & config. access_key ) ,
88+ Some ( & config. secret_key ) ,
89+ None ,
90+ None ,
91+ None ,
92+ ) ?;
93+ let bucket = s3:: Bucket :: new ( & config. bucket_name , region, creds) ?. with_path_style ( ) ;
94+
95+ Ok ( BUCKET_CLIENT . get_or_init ( || bucket) )
96+ }
97+ }
7598}
7699
77100/// create public/anonymous bucket client for passed profile config
101+ // this does not need a oncelock and can be created on-demand, as this is not used in very many places
78102pub fn bucket_client_anonymous ( config : & config:: S3Config ) -> Result < Box < s3:: Bucket > > {
79103 trace ! ( "creating anon bucket client" ) ;
80104 // TODO: once_cell this so it reuses the same bucket?
@@ -92,6 +116,10 @@ pub fn bucket_client_anonymous(config: &config::S3Config) -> Result<Box<s3::Buck
92116// Kubernetes stuff
93117//
94118
119+ // no OnceLock caching for K8S client. Some operations with the client require
120+ // their own owned `kube::Client`, so always returning a borrowed client from
121+ // the OnceLock would not work.
122+
95123/// Returns Kubernetes Client for selected profile
96124pub async fn kube_client ( profile : & config:: ProfileConfig ) -> Result < kube:: Client > {
97125 debug ! ( "building kube client" ) ;
0 commit comments