1
1
// Copyright (c) Microsoft Corporation.
2
2
// Licensed under the MIT License.
3
3
4
- use crate :: configure:: config_doc:: { ExecutionKind , Metadata , Resource } ;
4
+ use crate :: configure:: config_doc:: { ExecutionKind , Metadata , Resource , Parameter } ;
5
5
use crate :: configure:: context:: { Context , ProcessMode } ;
6
6
use crate :: configure:: { config_doc:: RestartRequired , parameters:: Input } ;
7
7
use crate :: discovery:: discovery_trait:: DiscoveryFilter ;
@@ -767,7 +767,6 @@ impl Configurator {
767
767
}
768
768
769
769
fn set_parameters ( & mut self , parameters_input : Option < & Value > , config : & Configuration ) -> Result < ( ) , DscError > {
770
- // set default parameters first
771
770
let Some ( parameters) = & config. parameters else {
772
771
if parameters_input. is_none ( ) {
773
772
info ! ( "{}" , t!( "configure.mod.noParameters" ) ) ;
@@ -776,66 +775,87 @@ impl Configurator {
776
775
return Err ( DscError :: Validation ( t ! ( "configure.mod.noParametersDefined" ) . to_string ( ) ) ) ;
777
776
} ;
778
777
779
- for ( name, parameter) in parameters {
780
- debug ! ( "{}" , t!( "configure.mod.processingParameter" , name = name) ) ;
781
- if let Some ( default_value) = & parameter. default_value {
782
- debug ! ( "{}" , t!( "configure.mod.setDefaultParameter" , name = name) ) ;
783
- // default values can be expressions
784
- let value = if default_value. is_string ( ) {
785
- if let Some ( value) = default_value. as_str ( ) {
786
- self . context . process_mode = ProcessMode :: ParametersDefault ;
787
- let result = self . statement_parser . parse_and_execute ( value, & self . context ) ?;
788
- self . context . process_mode = ProcessMode :: Normal ;
789
- result
778
+ // process input parameters first
779
+ if let Some ( parameters_input) = parameters_input {
780
+ trace ! ( "parameters_input: {parameters_input}" ) ;
781
+ let input_parameters: HashMap < String , Value > = serde_json:: from_value :: < Input > ( parameters_input. clone ( ) ) ?. parameters ;
782
+
783
+ for ( name, value) in input_parameters {
784
+ if let Some ( constraint) = parameters. get ( & name) {
785
+ debug ! ( "Validating parameter '{name}'" ) ;
786
+ check_length ( & name, & value, constraint) ?;
787
+ check_allowed_values ( & name, & value, constraint) ?;
788
+ check_number_limits ( & name, & value, constraint) ?;
789
+ // TODO: additional array constraints
790
+ // TODO: object constraints
791
+
792
+ validate_parameter_type ( & name, & value, & constraint. parameter_type ) ?;
793
+ if constraint. parameter_type == DataType :: SecureString || constraint. parameter_type == DataType :: SecureObject {
794
+ info ! ( "{}" , t!( "configure.mod.setSecureParameter" , name = name) ) ;
790
795
} else {
791
- return Err ( DscError :: Parser ( t ! ( "configure.mod.defaultStringNotDefined" ) . to_string ( ) ) ) ;
796
+ info ! ( "{}" , t!( "configure.mod.setParameter" , name = name , value = value ) ) ;
792
797
}
793
- } else {
794
- default_value. clone ( )
795
- } ;
796
- validate_parameter_type ( name, & value, & parameter. parameter_type ) ?;
797
- self . context . parameters . insert ( name. clone ( ) , ( value, parameter. parameter_type . clone ( ) ) ) ;
798
+
799
+ self . context . parameters . insert ( name. clone ( ) , ( value. clone ( ) , constraint. parameter_type . clone ( ) ) ) ;
800
+ if let Some ( parameters) = & mut self . config . parameters {
801
+ if let Some ( parameter) = parameters. get_mut ( & name) {
802
+ parameter. default_value = Some ( value) ;
803
+ }
804
+ }
805
+ }
806
+ else {
807
+ return Err ( DscError :: Validation ( t ! ( "configure.mod.parameterNotDefined" , name = name) . to_string ( ) ) ) ;
808
+ }
798
809
}
799
810
}
800
811
801
- let Some ( parameters_input) = parameters_input else {
802
- debug ! ( "{}" , t!( "configure.mod.noParametersInput" ) ) ;
803
- return Ok ( ( ) ) ;
804
- } ;
812
+ // Now process default values for parameters that weren't provided in input
813
+ let mut unresolved_parameters: HashMap < String , & Parameter > = parameters
814
+ . iter ( )
815
+ . filter ( |( name, _) | !self . context . parameters . contains_key ( * name) )
816
+ . map ( |( k, v) | ( k. clone ( ) , v) )
817
+ . collect ( ) ;
818
+
819
+ while !unresolved_parameters. is_empty ( ) {
820
+ let mut resolved_in_this_pass = Vec :: new ( ) ;
821
+
822
+ for ( name, parameter) in & unresolved_parameters {
823
+ debug ! ( "{}" , t!( "configure.mod.processingParameter" , name = name) ) ;
824
+ if let Some ( default_value) = & parameter. default_value {
825
+ debug ! ( "{}" , t!( "configure.mod.setDefaultParameter" , name = name) ) ;
826
+ let value_result = if default_value. is_string ( ) {
827
+ if let Some ( value) = default_value. as_str ( ) {
828
+ self . context . process_mode = ProcessMode :: ParametersDefault ;
829
+ let result = self . statement_parser . parse_and_execute ( value, & self . context ) ;
830
+ self . context . process_mode = ProcessMode :: Normal ;
831
+ result
832
+ } else {
833
+ return Err ( DscError :: Parser ( t ! ( "configure.mod.defaultStringNotDefined" ) . to_string ( ) ) ) ;
834
+ }
835
+ } else {
836
+ Ok ( default_value. clone ( ) )
837
+ } ;
805
838
806
- trace ! ( "parameters_input: {parameters_input}" ) ;
807
- let parameters: HashMap < String , Value > = serde_json:: from_value :: < Input > ( parameters_input. clone ( ) ) ?. parameters ;
808
- let Some ( parameters_constraints) = & config. parameters else {
809
- return Err ( DscError :: Validation ( t ! ( "configure.mod.noParametersDefined" ) . to_string ( ) ) ) ;
810
- } ;
811
- for ( name, value) in parameters {
812
- if let Some ( constraint) = parameters_constraints. get ( & name) {
813
- debug ! ( "Validating parameter '{name}'" ) ;
814
- check_length ( & name, & value, constraint) ?;
815
- check_allowed_values ( & name, & value, constraint) ?;
816
- check_number_limits ( & name, & value, constraint) ?;
817
- // TODO: additional array constraints
818
- // TODO: object constraints
819
-
820
- validate_parameter_type ( & name, & value, & constraint. parameter_type ) ?;
821
- if constraint. parameter_type == DataType :: SecureString || constraint. parameter_type == DataType :: SecureObject {
822
- info ! ( "{}" , t!( "configure.mod.setSecureParameter" , name = name) ) ;
839
+ if let Ok ( value) = value_result {
840
+ validate_parameter_type ( name, & value, & parameter. parameter_type ) ?;
841
+ self . context . parameters . insert ( name. to_string ( ) , ( value, parameter. parameter_type . clone ( ) ) ) ;
842
+ resolved_in_this_pass. push ( name. clone ( ) ) ;
843
+ }
823
844
} else {
824
- info ! ( "{}" , t! ( "configure.mod.setParameter" , name = name , value = value ) ) ;
845
+ resolved_in_this_pass . push ( name. clone ( ) ) ;
825
846
}
847
+ }
826
848
827
- self . context . parameters . insert ( name. clone ( ) , ( value. clone ( ) , constraint. parameter_type . clone ( ) ) ) ;
828
- // also update the configuration with the parameter value
829
- if let Some ( parameters) = & mut self . config . parameters {
830
- if let Some ( parameter) = parameters. get_mut ( & name) {
831
- parameter. default_value = Some ( value) ;
832
- }
833
- }
849
+ if resolved_in_this_pass. is_empty ( ) {
850
+ let unresolved_names: Vec < _ > = unresolved_parameters. keys ( ) . map ( std:: string:: String :: as_str) . collect ( ) ;
851
+ return Err ( DscError :: Validation ( t ! ( "configure.mod.circularDependency" , parameters = unresolved_names. join( ", " ) ) . to_string ( ) ) ) ;
834
852
}
835
- else {
836
- return Err ( DscError :: Validation ( t ! ( "configure.mod.parameterNotDefined" , name = name) . to_string ( ) ) ) ;
853
+
854
+ for name in & resolved_in_this_pass {
855
+ unresolved_parameters. remove ( name) ;
837
856
}
838
857
}
858
+
839
859
Ok ( ( ) )
840
860
}
841
861
0 commit comments