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