@@ -223,7 +223,17 @@ type Schema struct {
223223 //
224224 // ValidateFunc is honored only when the schema's Type is set to TypeInt,
225225 // TypeFloat, TypeString, TypeBool, or TypeMap. It is ignored for all other types.
226- ValidateFunc SchemaValidateFunc
226+ //
227+ // Deprecated: please use ValidateDiagFunc
228+ ValidateFunc SchemaValidateFunc
229+
230+ // ValidateDiagFunc allows individual fields to define arbitrary validation
231+ // logic. It is yielded the provided config value as an interface{} that is
232+ // guaranteed to be of the proper Schema type, and it can yield diagnostics
233+ // based on inspection of that value.
234+ //
235+ // ValidateDiagFunc is honored only when the schema's Type is set to TypeInt,
236+ // TypeFloat, TypeString, TypeBool, or TypeMap. It is ignored for all other types.
227237 ValidateDiagFunc SchemaValidateDiagFunc
228238
229239 // Sensitive ensures that the attribute's value does not get displayed in
@@ -293,7 +303,12 @@ type SchemaStateFunc func(interface{}) string
293303
294304// SchemaValidateFunc is a function used to validate a single field in the
295305// schema.
306+ //
307+ // Deprecated: please use SchemaValidateDiagFunc
296308type SchemaValidateFunc func (interface {}, string ) ([]string , []error )
309+
310+ // SchemaValidateDiagFunc is a function used to validate a single field in the
311+ // schema and has Diagnostic support.
297312type SchemaValidateDiagFunc func (interface {}, string ) diag.Diagnostics
298313
299314func (s * Schema ) GoString () string {
@@ -842,6 +857,10 @@ func (m schemaMap) internalValidate(topSchemaMap schemaMap, attrsOnly bool) erro
842857 }
843858 }
844859
860+ if v .ValidateFunc != nil && v .ValidateDiagFunc != nil {
861+ return fmt .Errorf ("%s: ValidateFunc and ValidateDiagFunc cannot both be set" , k )
862+ }
863+
845864 if v .Deprecated == "" && v .Removed == "" {
846865 if ! isValidFieldName (k ) {
847866 return fmt .Errorf ("%s: Field name may only contain lowercase alphanumeric characters & underscores." , k )
@@ -1606,8 +1625,7 @@ func (m schemaMap) validateList(
16061625 raw interface {},
16071626 schema * Schema ,
16081627 c * terraform.ResourceConfig ,
1609- path cty.Path ,
1610- isTypeSet bool ) diag.Diagnostics {
1628+ path cty.Path ) diag.Diagnostics {
16111629
16121630 var diags diag.Diagnostics
16131631
@@ -1672,19 +1690,15 @@ func (m schemaMap) validateList(
16721690 for i , raw := range raws {
16731691 key := fmt .Sprintf ("%s.%d" , k , i )
16741692
1675- // TODO: figure out cty.Path for TypeSet
1676- // if isTypeSet {
1677- // } else {
1678- // }
1679- p := append (path .Copy (), cty.IndexStep {Key : cty .NumberIntVal (int64 (i ))})
1680-
16811693 // Reify the key value from the ResourceConfig.
16821694 // If the list was computed we have all raw values, but some of these
16831695 // may be known in the config, and aren't individually marked as Computed.
16841696 if r , ok := c .Get (key ); ok {
16851697 raw = r
16861698 }
16871699
1700+ p := append (path .Copy (), cty.IndexStep {Key : cty .NumberIntVal (int64 (i ))})
1701+
16881702 switch t := schema .Elem .(type ) {
16891703 case * Resource :
16901704 // This is a sub-resource
@@ -1899,7 +1913,7 @@ func (m schemaMap) validateObject(
18991913 if k != "" {
19001914 key = fmt .Sprintf ("%s.%s" , k , subK )
19011915 }
1902- diags = diags .Append (m .validate (key , s , c , append (path , cty.GetAttrStep {Name : subK })))
1916+ diags = diags .Append (m .validate (key , s , c , append (path . Copy () , cty.GetAttrStep {Name : subK })))
19031917 }
19041918
19051919 // Detect any extra/unknown keys and report those as errors.
@@ -1912,7 +1926,7 @@ func (m schemaMap) validateObject(
19121926 diags = diags .Append (& diag.Diagnostic {
19131927 Severity : diag .Error ,
19141928 Summary : "Invalid or unknown key" ,
1915- AttributePath : append (path , cty.GetAttrStep {Name : subk }),
1929+ AttributePath : append (path . Copy () , cty.GetAttrStep {Name : subk }),
19161930 })
19171931 }
19181932 }
@@ -2026,12 +2040,19 @@ func (m schemaMap) validateType(
20262040 path cty.Path ) diag.Diagnostics {
20272041
20282042 var diags diag.Diagnostics
2029-
20302043 switch schema .Type {
20312044 case TypeList :
2032- diags = m .validateList (k , raw , schema , c , path , false )
2045+ diags = m .validateList (k , raw , schema , c , path )
20332046 case TypeSet :
2034- diags = m .validateList (k , raw , schema , c , path , true )
2047+ // indexing into sets is not representable in the current protocol
2048+ // best we can do is associate the path up to this attribute
2049+ // we may be able to try and enhance the rendered text with the rest of
2050+ // the path ie "error in TypeSet element { 'foo' : 'bar' }",
2051+ // but it will not be a perfect UX
2052+ diags = m .validateList (k , raw , schema , c , path )
2053+ for _ , d := range diags {
2054+ d .AttributePath = path
2055+ }
20352056 case TypeMap :
20362057 diags = m .validateMap (k , raw , schema , c , path )
20372058 default :
0 commit comments