@@ -8,6 +8,9 @@ use tracing::{debug, error, warn};
8
8
9
9
use crate :: role_utils:: { CommonConfiguration , Role } ;
10
10
11
+ pub const CONFIG_OVERRIDE_FILE_HEADER_KEY : & str = "EXPERIMENTAL_FILE_HEADER" ;
12
+ pub const CONFIG_OVERRIDE_FILE_FOOTER_KEY : & str = "EXPERIMENTAL_FILE_FOOTER" ;
13
+
11
14
type Result < T , E = Error > = std:: result:: Result < T , E > ;
12
15
13
16
#[ derive( Debug , PartialEq , Snafu ) ]
@@ -345,7 +348,7 @@ fn process_validation_result(
345
348
/// with the highest priority. The merge priority chain looks like this where '->' means
346
349
/// "overwrites if existing or adds":
347
350
///
348
- /// group overrides -> group config -> role overrides -> role config (TODO: -> common_config)
351
+ /// group overrides -> role overrides -> group config -> role config (TODO: -> common_config)
349
352
///
350
353
/// The output is a map where the [`crate::role_utils::RoleGroup] name points to another map of
351
354
/// [`product_config::types::PropertyValidationResult`] that points to the mapped configuration
@@ -368,24 +371,42 @@ where
368
371
{
369
372
let mut result = HashMap :: new ( ) ;
370
373
374
+ // Properties from the role have the lowest priority, so they are computed first...
371
375
let role_properties = parse_role_config ( resource, role_name, & role. config , property_kinds) ?;
376
+ let role_overrides = parse_role_overrides ( & role. config , property_kinds) ?;
372
377
373
378
// for each role group ...
374
379
for ( role_group_name, role_group) in & role. role_groups {
375
- // ... compute the group properties ...
380
+ let mut role_group_properties_merged = role_properties. clone ( ) ;
381
+
382
+ // ... compute the group properties and merge them into role properties.
376
383
let role_group_properties =
377
384
parse_role_config ( resource, role_name, & role_group. config , property_kinds) ?;
378
-
379
- // ... and merge them with the role properties.
380
- let mut role_properties_copy = role_properties. clone ( ) ;
381
385
for ( property_kind, properties) in role_group_properties {
382
- role_properties_copy
386
+ role_group_properties_merged
383
387
. entry ( property_kind)
384
388
. or_default ( )
385
389
. extend ( properties) ;
386
390
}
387
391
388
- result. insert ( role_group_name. clone ( ) , role_properties_copy) ;
392
+ // ... copy role overrides and merge them into `role_group_properties_merged`.
393
+ for ( property_kind, property_overrides) in role_overrides. clone ( ) {
394
+ role_group_properties_merged
395
+ . entry ( property_kind)
396
+ . or_default ( )
397
+ . extend ( property_overrides) ;
398
+ }
399
+
400
+ // ... compute the role group overrides and merge them into `role_group_properties_merged`.
401
+ let role_group_overrides = parse_role_overrides ( & role_group. config , property_kinds) ?;
402
+ for ( property_kind, property_overrides) in role_group_overrides {
403
+ role_group_properties_merged
404
+ . entry ( property_kind)
405
+ . or_default ( )
406
+ . extend ( property_overrides) ;
407
+ }
408
+
409
+ result. insert ( role_group_name. clone ( ) , role_group_properties_merged) ;
389
410
}
390
411
391
412
Ok ( result)
@@ -411,86 +432,80 @@ where
411
432
T : Configuration ,
412
433
{
413
434
let mut result = HashMap :: new ( ) ;
414
-
415
435
for property_kind in property_kinds {
416
436
match property_kind {
417
437
PropertyNameKind :: File ( file) => result. insert (
418
438
property_kind. clone ( ) ,
419
- parse_file_properties ( resource, role_name, config , file) ?,
439
+ config . config . compute_files ( resource, role_name, file) ?,
420
440
) ,
421
441
PropertyNameKind :: Env => result. insert (
422
442
property_kind. clone ( ) ,
423
- parse_env_properties ( resource, role_name, config ) ?,
443
+ config . config . compute_env ( resource, role_name) ?,
424
444
) ,
425
445
PropertyNameKind :: Cli => result. insert (
426
446
property_kind. clone ( ) ,
427
- parse_cli_properties ( resource, role_name, config ) ?,
447
+ config . config . compute_cli ( resource, role_name) ?,
428
448
) ,
429
449
} ;
430
450
}
431
451
432
452
Ok ( result)
433
453
}
434
454
435
- fn parse_cli_properties < T > (
436
- resource : & <T as Configuration >:: Configurable ,
437
- role_name : & str ,
438
- config : & CommonConfiguration < T > ,
439
- ) -> Result < BTreeMap < String , Option < String > > >
440
- where
441
- T : Configuration ,
442
- {
443
- // Properties from the role have the lowest priority, so they are computed and added first...
444
- let mut final_properties = config. config . compute_cli ( resource, role_name) ?;
445
-
446
- // ...followed by config_overrides from the role
447
- for ( key, value) in & config. cli_overrides {
448
- final_properties. insert ( key. clone ( ) , Some ( value. clone ( ) ) ) ;
449
- }
450
-
451
- Ok ( final_properties)
452
- }
453
-
454
- fn parse_env_properties < T > (
455
- resource : & <T as Configuration >:: Configurable ,
456
- role_name : & str ,
455
+ fn parse_role_overrides < T > (
457
456
config : & CommonConfiguration < T > ,
458
- ) -> Result < BTreeMap < String , Option < String > > >
457
+ property_kinds : & [ PropertyNameKind ] ,
458
+ ) -> Result < HashMap < PropertyNameKind , BTreeMap < String , Option < String > > > >
459
459
where
460
460
T : Configuration ,
461
461
{
462
- // Properties from the role have the lowest priority, so they are computed and added first...
463
- let mut final_properties = config. config . compute_env ( resource, role_name) ?;
464
-
465
- // ...followed by config_overrides from the role
466
- for ( key, value) in & config. env_overrides {
467
- final_properties. insert ( key. clone ( ) , Some ( value. clone ( ) ) ) ;
462
+ let mut result = HashMap :: new ( ) ;
463
+ for property_kind in property_kinds {
464
+ match property_kind {
465
+ PropertyNameKind :: File ( file) => {
466
+ result. insert ( property_kind. clone ( ) , parse_file_overrides ( config, file) ?)
467
+ }
468
+ PropertyNameKind :: Env => result. insert (
469
+ property_kind. clone ( ) ,
470
+ config
471
+ . env_overrides
472
+ . clone ( )
473
+ . into_iter ( )
474
+ . map ( |( k, v) | ( k, Some ( v) ) )
475
+ . collect ( ) ,
476
+ ) ,
477
+ PropertyNameKind :: Cli => result. insert (
478
+ property_kind. clone ( ) ,
479
+ config
480
+ . cli_overrides
481
+ . clone ( )
482
+ . into_iter ( )
483
+ . map ( |( k, v) | ( k, Some ( v) ) )
484
+ . collect ( ) ,
485
+ ) ,
486
+ } ;
468
487
}
469
488
470
- Ok ( final_properties )
489
+ Ok ( result )
471
490
}
472
491
473
- fn parse_file_properties < T > (
474
- resource : & <T as Configuration >:: Configurable ,
475
- role_name : & str ,
492
+ fn parse_file_overrides < T > (
476
493
config : & CommonConfiguration < T > ,
477
494
file : & str ,
478
495
) -> Result < BTreeMap < String , Option < String > > >
479
496
where
480
497
T : Configuration ,
481
498
{
482
- // Properties from the role have the lowest priority, so they are computed and added first...
483
- let mut final_properties = config. config . compute_files ( resource, role_name, file) ?;
499
+ let mut final_overrides: BTreeMap < String , Option < String > > = BTreeMap :: new ( ) ;
484
500
485
- // ...followed by config_overrides from the role
486
501
// For Conf files only process overrides that match our file name
487
502
if let Some ( config) = config. config_overrides . get ( file) {
488
503
for ( key, value) in config {
489
- final_properties . insert ( key. clone ( ) , Some ( value. clone ( ) ) ) ;
504
+ final_overrides . insert ( key. clone ( ) , Some ( value. clone ( ) ) ) ;
490
505
}
491
506
}
492
507
493
- Ok ( final_properties )
508
+ Ok ( final_overrides )
494
509
}
495
510
496
511
#[ cfg( test) ]
@@ -1046,6 +1061,136 @@ mod tests {
1046
1061
assert_eq ! ( config, expected) ;
1047
1062
}
1048
1063
1064
+ #[ rstest]
1065
+ #[ case(
1066
+ HashMap :: from( [
1067
+ ( "env" . to_string( ) , ROLE_ENV_OVERRIDE . to_string( ) ) ,
1068
+ ] ) ,
1069
+ HashMap :: from( [
1070
+ ( "env" . to_string( ) , GROUP_ENV_OVERRIDE . to_string( ) ) ,
1071
+ ] ) ,
1072
+ BTreeMap :: from( [
1073
+ ( "cli" . to_string( ) , ROLE_CLI_OVERRIDE . to_string( ) ) ,
1074
+ ] ) ,
1075
+ BTreeMap :: from( [
1076
+ ( "cli" . to_string( ) , GROUP_CLI_OVERRIDE . to_string( ) ) ,
1077
+ ] ) ,
1078
+ HashMap :: from( [
1079
+ ( "file" . to_string( ) , HashMap :: from( [
1080
+ ( "file" . to_string( ) , ROLE_CONF_OVERRIDE . to_string( ) )
1081
+ ] ) )
1082
+ ] ) ,
1083
+ HashMap :: from( [
1084
+ ( "file" . to_string( ) , HashMap :: from( [
1085
+ ( "file" . to_string( ) , GROUP_CONF_OVERRIDE . to_string( ) )
1086
+ ] ) )
1087
+ ] ) ,
1088
+ collection ! {
1089
+ ROLE_GROUP . to_string( ) => collection ! {
1090
+ PropertyNameKind :: Env => collection ! {
1091
+ "env" . to_string( ) => Some ( GROUP_ENV_OVERRIDE . to_string( ) ) ,
1092
+ } ,
1093
+ PropertyNameKind :: Cli => collection ! {
1094
+ "cli" . to_string( ) => Some ( GROUP_CLI_OVERRIDE . to_string( ) ) ,
1095
+ } ,
1096
+ PropertyNameKind :: File ( "file" . to_string( ) ) => collection ! {
1097
+ "file" . to_string( ) => Some ( GROUP_CONF_OVERRIDE . to_string( ) ) ,
1098
+ }
1099
+ }
1100
+ }
1101
+ ) ]
1102
+ #[ case(
1103
+ HashMap :: from( [
1104
+ ( "env" . to_string( ) , ROLE_ENV_OVERRIDE . to_string( ) ) ,
1105
+ ] ) ,
1106
+ HashMap :: from( [ ] ) ,
1107
+ BTreeMap :: from( [
1108
+ ( "cli" . to_string( ) , ROLE_CLI_OVERRIDE . to_string( ) ) ,
1109
+ ] ) ,
1110
+ BTreeMap :: from( [ ] ) ,
1111
+ HashMap :: from( [
1112
+ ( "file" . to_string( ) , HashMap :: from( [
1113
+ ( "file" . to_string( ) , ROLE_CONF_OVERRIDE . to_string( ) )
1114
+ ] ) )
1115
+ ] ) ,
1116
+ HashMap :: from( [ ] ) ,
1117
+ collection ! {
1118
+ ROLE_GROUP . to_string( ) => collection ! {
1119
+ PropertyNameKind :: Env => collection ! {
1120
+ "env" . to_string( ) => Some ( ROLE_ENV_OVERRIDE . to_string( ) ) ,
1121
+ } ,
1122
+ PropertyNameKind :: Cli => collection ! {
1123
+ "cli" . to_string( ) => Some ( ROLE_CLI_OVERRIDE . to_string( ) ) ,
1124
+ } ,
1125
+ PropertyNameKind :: File ( "file" . to_string( ) ) => collection ! {
1126
+ "file" . to_string( ) => Some ( ROLE_CONF_OVERRIDE . to_string( ) ) ,
1127
+ }
1128
+ }
1129
+ }
1130
+ ) ]
1131
+ #[ case(
1132
+ HashMap :: from( [ ] ) ,
1133
+ HashMap :: from( [ ] ) ,
1134
+ BTreeMap :: from( [ ] ) ,
1135
+ BTreeMap :: from( [ ] ) ,
1136
+ HashMap :: from( [ ] ) ,
1137
+ HashMap :: from( [ ] ) ,
1138
+ collection ! {
1139
+ ROLE_GROUP . to_string( ) => collection ! {
1140
+ PropertyNameKind :: Env => collection ! {
1141
+ "env" . to_string( ) => Some ( GROUP_ENV . to_string( ) ) ,
1142
+ } ,
1143
+ PropertyNameKind :: Cli => collection ! {
1144
+ "cli" . to_string( ) => Some ( GROUP_CLI . to_string( ) ) ,
1145
+ } ,
1146
+ PropertyNameKind :: File ( "file" . to_string( ) ) => collection ! {
1147
+ "file" . to_string( ) => Some ( GROUP_CONFIG . to_string( ) ) ,
1148
+ }
1149
+ }
1150
+ }
1151
+ ) ]
1152
+ fn test_order_in_transform_role_to_config (
1153
+ #[ case] role_env_override : HashMap < String , String > ,
1154
+ #[ case] group_env_override : HashMap < String , String > ,
1155
+ #[ case] role_cli_override : BTreeMap < String , String > ,
1156
+ #[ case] group_cli_override : BTreeMap < String , String > ,
1157
+ #[ case] role_conf_override : HashMap < String , HashMap < String , String > > ,
1158
+ #[ case] group_conf_override : HashMap < String , HashMap < String , String > > ,
1159
+ #[ case] expected : HashMap <
1160
+ String ,
1161
+ HashMap < PropertyNameKind , BTreeMap < String , Option < String > > > ,
1162
+ > ,
1163
+ ) {
1164
+ let role: Role < Box < TestConfig > , TestRoleConfig > = Role {
1165
+ config : build_common_config (
1166
+ build_test_config ( ROLE_CONFIG , ROLE_ENV , ROLE_CLI ) ,
1167
+ Some ( role_conf_override) ,
1168
+ Some ( role_env_override) ,
1169
+ Some ( role_cli_override) ,
1170
+ ) ,
1171
+ role_config : Default :: default ( ) ,
1172
+ role_groups : collection ! { "role_group" . to_string( ) => RoleGroup {
1173
+ replicas: Some ( 1 ) ,
1174
+ config: build_common_config(
1175
+ build_test_config( GROUP_CONFIG , GROUP_ENV , GROUP_CLI ) ,
1176
+ Some ( group_conf_override) ,
1177
+ Some ( group_env_override) ,
1178
+ Some ( group_cli_override) ) ,
1179
+ } } ,
1180
+ } ;
1181
+
1182
+ let property_kinds = vec ! [
1183
+ PropertyNameKind :: Env ,
1184
+ PropertyNameKind :: Cli ,
1185
+ PropertyNameKind :: File ( "file" . to_string( ) ) ,
1186
+ ] ;
1187
+
1188
+ let config =
1189
+ transform_role_to_config ( & String :: new ( ) , ROLE_GROUP , & role, & property_kinds) . unwrap ( ) ;
1190
+
1191
+ assert_eq ! ( config, expected) ;
1192
+ }
1193
+
1049
1194
#[ test]
1050
1195
fn test_transform_role_to_config_overrides ( ) {
1051
1196
let role_group = "role_group" ;
@@ -1085,7 +1230,7 @@ mod tests {
1085
1230
) ,
1086
1231
PropertyNameKind :: Cli =>
1087
1232
collection!(
1088
- "cli" . to_string( ) => Some ( GROUP_CLI . to_string( ) ) ,
1233
+ "cli" . to_string( ) => Some ( "cli" . to_string( ) ) ,
1089
1234
) ,
1090
1235
}
1091
1236
} ;
0 commit comments