5
5
//! used in the get_signed_certificates_json.sh script.
6
6
//!
7
7
//! ## Note
8
- //!
9
8
//! This module is not intended to be used directly, but through the `Properties` struct. It will
10
- //! always be used when getting a `Properties` struct vja dsh::Properties::get().
11
- //!
12
- //! If this module returns an error, it defaults to the local_datastreams.json file, so it can be used
13
- //! in a local environment. (when feature `local` is enabled)
9
+ //! always be used when getting a `Properties` struct via dsh::Properties::get().
14
10
//!
15
- //! ## Example
16
- //! ```
17
- //! use dsh_sdk::Properties;
18
- //!
19
- //! let dsh_properties = Properties::get();
20
- //! ```
11
+ //! If this module returns an error, it defaults to the local_datastreams.json file or the
12
+ //! default properties. This means it can be used in you local development environment without
13
+ //! the need to connect to DSH.
21
14
22
- use log:: { debug , info, warn} ;
15
+ use log:: { info, warn} ;
23
16
use reqwest:: blocking:: Client ;
24
17
25
- use std:: env;
26
-
27
18
use crate :: error:: DshError ;
28
19
29
- use super :: { certificates:: Cert , datastream:: Datastream , Properties } ;
20
+ use super :: {
21
+ certificates:: Cert , datastream:: Datastream , utils, VAR_DSH_CA_CERTIFICATE ,
22
+ VAR_DSH_SECRET_TOKEN , VAR_DSH_SECRET_TOKEN_PATH , VAR_KAFKA_CONFIG_HOST ,
23
+ } ;
30
24
31
- impl Properties {
32
- /// Connect to DSH and retrieve the certificates and datastreams.json to create the properties struct
33
- pub ( crate ) fn new_dsh ( ) -> Result < Self , DshError > {
34
- let dsh_config = DshConfig :: new ( ) ?;
35
- let client = Properties :: reqwest_client ( dsh_config. dsh_ca_certificate . as_bytes ( ) ) ?;
36
- let dn = DshCall :: Dn ( & dsh_config) . perform_call ( & client) ?;
37
- let dn = Dn :: parse_string ( & dn) ?;
38
- let certificates = Cert :: new ( dn, & dsh_config, & client) ?;
39
- let client_with_cert = certificates. reqwest_blocking_client_config ( ) ?. build ( ) ?;
40
- let datastreams_string =
41
- DshCall :: Datastream ( & dsh_config) . perform_call ( & client_with_cert) ?;
42
- let datastream: Datastream = serde_json:: from_str ( & datastreams_string) ?;
43
- Ok ( Self {
44
- client_id : dsh_config. task_id . to_string ( ) ,
45
- tenant_name : dsh_config. tenant_name . to_string ( ) ,
46
- task_id : dsh_config. task_id . to_string ( ) ,
47
- datastream,
48
- certificates : Some ( certificates) ,
49
- } )
50
- }
25
+ /// Connect to DSH and retrieve the certificates and datastreams.json to create the properties struct
26
+ pub ( crate ) fn bootstrap ( tenant_name : & str , task_id : & str ) -> Result < ( Cert , Datastream ) , DshError > {
27
+ let dsh_config = DshConfig :: new ( tenant_name, task_id) ?;
28
+ let client = reqwest_ca_client ( dsh_config. dsh_ca_certificate . as_bytes ( ) ) ?;
29
+ let dn = DshCall :: Dn ( & dsh_config) . perform_call ( & client) ?;
30
+ let dn = Dn :: parse_string ( & dn) ?;
31
+ let certificates = Cert :: bootstrap ( dn, & dsh_config, & client) ?;
32
+ let client_with_cert = certificates. reqwest_blocking_client_config ( ) ?. build ( ) ?;
33
+ let datastreams_string = DshCall :: Datastream ( & dsh_config) . perform_call ( & client_with_cert) ?;
34
+ let datastream: Datastream = serde_json:: from_str ( & datastreams_string) ?;
35
+ Ok ( ( certificates, datastream) )
36
+ }
51
37
52
- /// Build a request client with the DSH CA certificate.
53
- fn reqwest_client ( dsh_ca_certificate : & [ u8 ] ) -> Result < Client , reqwest:: Error > {
54
- let reqwest_cert = reqwest:: tls:: Certificate :: from_pem ( dsh_ca_certificate) ?;
55
- let client = Client :: builder ( )
56
- . add_root_certificate ( reqwest_cert)
57
- . build ( ) ?;
58
- Ok ( client)
59
- }
38
+ /// Build a request client with the DSH CA certificate.
39
+ fn reqwest_ca_client ( dsh_ca_certificate : & [ u8 ] ) -> Result < Client , reqwest:: Error > {
40
+ let reqwest_cert = reqwest:: tls:: Certificate :: from_pem ( dsh_ca_certificate) ?;
41
+ let client = Client :: builder ( )
42
+ . add_root_certificate ( reqwest_cert)
43
+ . build ( ) ?;
44
+ Ok ( client)
60
45
}
61
46
62
47
#[ derive( Debug ) ]
63
- pub ( crate ) struct DshConfig {
48
+ pub ( crate ) struct DshConfig < ' a > {
64
49
config_host : String ,
65
- tenant_name : String ,
66
- task_id : String ,
50
+ tenant_name : & ' a str ,
51
+ task_id : & ' a str ,
67
52
dsh_secret_token : String ,
68
53
dsh_ca_certificate : String ,
69
54
}
70
55
71
56
/// Helper struct to store the config needed for bootstrapping to DSH
72
- impl DshConfig {
73
- fn new ( ) -> Result < Self , DshError > {
74
- let config_host = Self :: get_env_var ( "KAFKA_CONFIG_HOST" )
57
+ impl < ' a > DshConfig < ' a > {
58
+ fn new ( tenant_name : & ' a str , task_id : & ' a str ) -> Result < Self , DshError > {
59
+ let config_host = utils :: get_env_var ( VAR_KAFKA_CONFIG_HOST )
75
60
. map ( |host| format ! ( "https://{}" , host) )
76
61
. unwrap_or_else ( |_| {
77
- let default = "https://pikachu.dsh.marathon.mesos:4443" . to_string ( ) ;
62
+ let default = "https://pikachu.dsh.marathon.mesos:4443" ;
78
63
warn ! (
79
- "KAFKA_CONFIG_HOST is not set, using default value {}" ,
80
- default
64
+ "{} is not set, using default value {}" ,
65
+ VAR_KAFKA_CONFIG_HOST , default
81
66
) ;
82
- default
67
+ default. to_string ( )
83
68
} ) ;
84
-
85
- let task_id = Self :: get_env_var ( "MESOS_TASK_ID" ) ?;
86
- let app_id = Self :: get_env_var ( "MARATHON_APP_ID" ) ?;
87
- let dsh_secret_token = match Self :: get_env_var ( "DSH_SECRET_TOKEN" ) {
69
+ let dsh_secret_token = match utils:: get_env_var ( VAR_DSH_SECRET_TOKEN ) {
88
70
Ok ( token) => token,
89
71
Err ( _) => {
90
72
// if DSH_SECRET_TOKEN is not set, try to read it from a file (for system space applications)
91
73
info ! ( "trying to read DSH_SECRET_TOKEN from file" ) ;
92
- let secret_token_path = Self :: get_env_var ( "DSH_SECRET_TOKEN_PATH" ) ?;
74
+ let secret_token_path = utils :: get_env_var ( VAR_DSH_SECRET_TOKEN_PATH ) ?;
93
75
let path = std:: path:: PathBuf :: from ( secret_token_path) ;
94
76
std:: fs:: read_to_string ( path) ?
95
77
}
96
78
} ;
97
- let dsh_ca_certificate = Self :: get_env_var ( "DSH_CA_CERTIFICATE" ) ?;
98
- let tenant_name = DshConfig :: tenant_name ( & app_id) ;
79
+ let dsh_ca_certificate = utils:: get_env_var ( VAR_DSH_CA_CERTIFICATE ) ?;
99
80
Ok ( DshConfig {
100
81
config_host,
101
82
task_id,
102
- tenant_name : tenant_name . to_string ( ) ,
83
+ tenant_name,
103
84
dsh_secret_token,
104
85
dsh_ca_certificate,
105
86
} )
@@ -108,41 +89,18 @@ impl DshConfig {
108
89
pub ( crate ) fn dsh_ca_certificate ( & self ) -> & str {
109
90
& self . dsh_ca_certificate
110
91
}
111
-
112
- /// Derive the tenant name from the app id.
113
- fn tenant_name ( app_id : & str ) -> & str {
114
- let tenant_name = app_id. split ( '/' ) . nth ( 1 ) ;
115
- match tenant_name {
116
- Some ( tenant_name) => tenant_name,
117
- None => {
118
- warn ! (
119
- "MARATHON_APP_ID is not as expected, missing expected slashes, using \" {}\" as tenant name" ,
120
- app_id
121
- ) ;
122
- app_id
123
- }
124
- }
125
- }
126
-
127
- fn get_env_var ( var_name : & str ) -> Result < String , DshError > {
128
- debug ! ( "Reading {} from environment variable" , var_name) ;
129
- match env:: var ( var_name) {
130
- Ok ( value) => Ok ( value) ,
131
- Err ( e) => {
132
- warn ! ( "{} is not set" , var_name) ;
133
- Err ( e. into ( ) )
134
- }
135
- }
136
- }
137
92
}
138
93
139
94
pub ( crate ) enum DshCall < ' a > {
140
95
/// Call to retreive distinguished name.
141
- Dn ( & ' a DshConfig ) ,
96
+ Dn ( & ' a DshConfig < ' a > ) ,
142
97
/// Call to retreive datastreams.json.
143
- Datastream ( & ' a DshConfig ) ,
98
+ Datastream ( & ' a DshConfig < ' a > ) ,
144
99
/// Call to post the certificate signing request.
145
- CertificateSignRequest { config : & ' a DshConfig , csr : & ' a str } ,
100
+ CertificateSignRequest {
101
+ config : & ' a DshConfig < ' a > ,
102
+ csr : & ' a str ,
103
+ } ,
146
104
}
147
105
148
106
impl DshCall < ' _ > {
@@ -248,35 +206,17 @@ impl Dn {
248
206
249
207
#[ cfg( test) ]
250
208
mod tests {
251
- use std:: str:: from_utf8;
252
-
253
209
use super :: * ;
254
-
255
- #[ test]
256
- fn test_dsh_config_tenant_name ( ) {
257
- let app_id = "/greenbox-dev/app-name" ;
258
- let result = DshConfig :: tenant_name ( app_id) ;
259
- assert_eq ! (
260
- result,
261
- "greenbox-dev" . to_string( ) ,
262
- "{} is not parsed correctly" ,
263
- app_id
264
- ) ;
265
- let app_id = "greenbox-dev" ;
266
- let result = DshConfig :: tenant_name ( app_id) ;
267
- assert_eq ! (
268
- result, app_id,
269
- "{} is not parsed correctly, should be the same" ,
270
- app_id
271
- ) ;
272
- }
210
+ use serial_test:: serial;
211
+ use std:: env;
212
+ use std:: str:: from_utf8;
273
213
274
214
#[ test]
275
215
fn test_dsh_call_request_builder ( ) {
276
216
let dsh_config = DshConfig {
277
217
config_host : "https://test_host" . to_string ( ) ,
278
- tenant_name : "test_tenant_name" . to_string ( ) ,
279
- task_id : "test_task_id" . to_string ( ) ,
218
+ tenant_name : "test_tenant_name" ,
219
+ task_id : "test_task_id" ,
280
220
dsh_secret_token : "test_token" . to_string ( ) ,
281
221
dsh_ca_certificate : "test_ca_certificate" . to_string ( ) ,
282
222
} ;
@@ -324,8 +264,8 @@ mod tests {
324
264
// create a DshConfig struct
325
265
let dsh_config = DshConfig {
326
266
config_host : dsh. url ( ) ,
327
- tenant_name : "tenant" . to_string ( ) ,
328
- task_id : "test_task_id" . to_string ( ) ,
267
+ tenant_name : "tenant" ,
268
+ task_id : "test_task_id" ,
329
269
dsh_secret_token : "test_token" . to_string ( ) ,
330
270
dsh_ca_certificate : "test_ca_certificate" . to_string ( ) ,
331
271
} ;
@@ -344,41 +284,39 @@ mod tests {
344
284
}
345
285
346
286
#[ test]
347
- fn test_get_env_var ( ) {
348
- env:: set_var ( "TEST_ENV_VAR" , "test_value" ) ;
349
- let result = DshConfig :: get_env_var ( "TEST_ENV_VAR" ) . unwrap ( ) ;
350
- assert_eq ! ( result, "test_value" ) ;
351
- }
352
-
353
- #[ test]
287
+ #[ serial( env_depencency) ]
354
288
fn test_dsh_config_new ( ) {
355
289
// normal situation where DSH variables are set
356
- env:: set_var ( "KAFKA_CONFIG_HOST" , "test_host" ) ;
357
- env:: set_var ( "MESOS_TASK_ID" , "test_task_id " ) ;
358
- env:: set_var ( "MARATHON_APP_ID" , "/test_tenant/test_app " ) ;
359
- env :: set_var ( "DSH_SECRET_TOKEN" , "test_token" ) ;
360
- env :: set_var ( "DSH_CA_CERTIFICATE" , "test_ca_certificate" ) ;
361
- let dsh_config = DshConfig :: new ( ) . unwrap ( ) ;
290
+ env:: set_var ( VAR_KAFKA_CONFIG_HOST , "test_host" ) ;
291
+ env:: set_var ( VAR_DSH_SECRET_TOKEN , "test_token " ) ;
292
+ env:: set_var ( VAR_DSH_CA_CERTIFICATE , "test_ca_certificate " ) ;
293
+ let tenant_name = "test_tenant" ;
294
+ let task_id = "test_task_id" ;
295
+ let dsh_config = DshConfig :: new ( tenant_name , task_id ) . unwrap ( ) ;
362
296
assert_eq ! ( dsh_config. config_host, "https://test_host" ) ;
363
297
assert_eq ! ( dsh_config. task_id, "test_task_id" ) ;
364
298
assert_eq ! ( dsh_config. tenant_name, "test_tenant" ) ;
365
299
assert_eq ! ( dsh_config. dsh_secret_token, "test_token" ) ;
366
300
assert_eq ! ( dsh_config. dsh_ca_certificate, "test_ca_certificate" ) ;
367
301
// DSH_SECRET_TOKEN is not set, but DSH_SECRET_TOKEN_PATH is set
368
- env:: remove_var ( "DSH_SECRET_TOKEN" ) ;
302
+ env:: remove_var ( VAR_DSH_SECRET_TOKEN ) ;
369
303
let test_token_dir = "test_files" ;
370
304
std:: fs:: create_dir_all ( test_token_dir) . unwrap ( ) ;
371
305
let test_token_dir = format ! ( "{}/test_token" , test_token_dir) ;
372
306
let _ = std:: fs:: remove_file ( & test_token_dir) ;
373
- env:: set_var ( "DSH_SECRET_TOKEN_PATH" , & test_token_dir) ;
374
- let result = DshConfig :: new ( ) ;
307
+ env:: set_var ( VAR_DSH_SECRET_TOKEN_PATH , & test_token_dir) ;
308
+ let result = DshConfig :: new ( tenant_name , task_id ) ;
375
309
assert ! ( result. is_err( ) ) ;
376
310
std:: fs:: write ( test_token_dir. as_str ( ) , "test_token_from_file" ) . unwrap ( ) ;
377
- let dsh_config = DshConfig :: new ( ) . unwrap ( ) ;
311
+ let dsh_config = DshConfig :: new ( tenant_name , task_id ) . unwrap ( ) ;
378
312
assert_eq ! ( dsh_config. dsh_secret_token, "test_token_from_file" ) ;
379
313
// fail if DSH_CA_CERTIFICATE is not set
380
- env:: remove_var ( "DSH_CA_CERTIFICATE" ) ;
381
- let result = DshConfig :: new ( ) ;
314
+ env:: remove_var ( VAR_DSH_CA_CERTIFICATE ) ;
315
+ let result = DshConfig :: new ( tenant_name , task_id ) ;
382
316
assert ! ( result. is_err( ) ) ;
317
+ env:: remove_var ( VAR_KAFKA_CONFIG_HOST ) ;
318
+ env:: remove_var ( VAR_DSH_SECRET_TOKEN ) ;
319
+ env:: remove_var ( VAR_DSH_CA_CERTIFICATE ) ;
320
+ env:: remove_var ( VAR_DSH_SECRET_TOKEN_PATH ) ;
383
321
}
384
322
}
0 commit comments