1
1
// Builders for the various client structs for Docker/Kube etc.
2
2
3
+ use std:: sync:: OnceLock ;
4
+
3
5
use anyhow:: { anyhow, bail, Context , Error , Result } ;
4
6
use bollard;
5
7
use futures:: TryFutureExt ;
@@ -17,16 +19,27 @@ use crate::configparser::config;
17
19
//
18
20
// Docker stuff
19
21
//
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?)" ) ) ?;
28
22
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
+ }
30
43
}
31
44
32
45
#[ derive( Debug ) ]
@@ -54,27 +67,38 @@ pub async fn engine_type() -> EngineType {
54
67
// S3 stuff
55
68
//
56
69
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
+ }
75
98
}
76
99
77
100
/// 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
78
102
pub fn bucket_client_anonymous ( config : & config:: S3Config ) -> Result < Box < s3:: Bucket > > {
79
103
trace ! ( "creating anon bucket client" ) ;
80
104
// 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
92
116
// Kubernetes stuff
93
117
//
94
118
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
+
95
123
/// Returns Kubernetes Client for selected profile
96
124
pub async fn kube_client ( profile : & config:: ProfileConfig ) -> Result < kube:: Client > {
97
125
debug ! ( "building kube client" ) ;
0 commit comments