Skip to content

Commit

Permalink
Add support for enum values validation in terraform
Browse files Browse the repository at this point in the history
  • Loading branch information
kklimonda-cl committed Oct 23, 2024
1 parent 197afe3 commit 73bffab
Show file tree
Hide file tree
Showing 4 changed files with 160 additions and 31 deletions.
19 changes: 14 additions & 5 deletions pkg/properties/normalized.go
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ type SpecParam struct {
Required bool `json:"required" yaml:"required"`
Sensitive bool `json:"sensitive" yaml:"sensitive"`
Length *SpecParamLength `json:"length" yaml:"length,omitempty"`
EnumValues map[string]*string `json:"enum_values" yaml:"enum_values,omitempty"`
Count *SpecParamCount `json:"count" yaml:"count,omitempty"`
Hashing *SpecParamHashing `json:"hashing" yaml:"hashing,omitempty"`
Items *SpecParamItems `json:"items" yaml:"items,omitempty"`
Expand Down Expand Up @@ -698,25 +699,33 @@ func schemaToSpec(object object.Object) (*Normalization, error) {
if err != nil {
return nil, err
}

enumValues := make(map[string]*string)
switch spec := param.Spec.(type) {
case *parameter.EnumSpec:
constValues := make(map[string]*ConstValue)
for _, elt := range spec.Values {
var constValue *string
if elt.Const == "" {
continue
constValue = nil
} else {
constValue = &elt.Const
}
constValues[elt.Const] = &ConstValue{
Value: elt.Value,

enumValues[elt.Value] = constValue

if constValue != nil {
constValues[*constValue] = &ConstValue{
Value: elt.Value,
}
}
}
if len(constValues) > 0 {
consts[param.Name] = &Const{
Values: constValues,
}
}

}
specParam.EnumValues = enumValues
spec.Spec.Params[param.Name] = specParam
}

Expand Down
161 changes: 137 additions & 24 deletions pkg/translate/terraform_provider/funcs.go
Original file line number Diff line number Diff line change
Expand Up @@ -741,8 +741,10 @@ type modifierCtx struct {
}

type validatorFunctionCtx struct {
Type string
Function string
Expressions []string
Values []string
}

type validatorCtx struct {
Expand Down Expand Up @@ -959,6 +961,43 @@ func createSchemaSpecForParameter(schemaTyp schemaType, manager *imports.Manager
})
}

for _, elt := range param.Spec.Params {
if elt.IsPrivateParameter() {
continue
}

var functions []validatorFunctionCtx
if len(elt.EnumValues) > 0 && schemaTyp == schemaResource {
var values []string
for value := range elt.EnumValues {
values = append(values, value)
}

functions = append(functions, validatorFunctionCtx{
Type: "Values",
Function: "OneOf",
Values: values,
})
}

var validators *validatorCtx
if len(functions) > 0 {
typ := elt.ValidatorType()
validatorImport := fmt.Sprintf("github.com/hashicorp/terraform-plugin-framework-validators/%svalidator", typ)
manager.AddHashicorpImport(validatorImport, "")
validators = &validatorCtx{
ListType: pascalCase(typ),
Package: fmt.Sprintf("%svalidator", typ),
Functions: functions,
}
}

attributes = append(attributes, createSchemaAttributeForParameter(schemaTyp, manager, packageName, elt, validators))
}

// Generating schema validation for variants. By default, ExactlyOneOf validation
// is performed, unless XML API allows for no variant to be provided, in which case
// validation is performed by ConflictsWith.
validatorFn := "ExactlyOneOf"
var expressions []string
for _, elt := range param.Spec.OneOf {
Expand All @@ -973,33 +1012,31 @@ func createSchemaSpecForParameter(schemaTyp schemaType, manager *imports.Manager
expressions = append(expressions, fmt.Sprintf(`path.MatchRelative().AtParent().AtName("%s")`, elt.Name.Underscore))
}

for _, elt := range param.Spec.Params {
if elt.IsPrivateParameter() {
continue
}
attributes = append(attributes, createSchemaAttributeForParameter(schemaTyp, manager, packageName, elt, nil))
var variantFns []validatorFunctionCtx
if len(expressions) > 0 {
variantFns = append(variantFns, validatorFunctionCtx{
Type: "Expressions",
Function: validatorFn,
Expressions: expressions,
})
}

functions := []validatorFunctionCtx{{
Function: validatorFn,
Expressions: expressions,
}}

var idx int
for _, elt := range param.Spec.OneOf {
if elt.IsPrivateParameter() {
continue
}

var validators *validatorCtx
if idx == 0 {
if idx == 0 && schemaTyp == schemaResource && len(variantFns) > 0 {
log.Printf("variantFns: %v, Name: %s", variantFns, elt.Name)
typ := elt.ValidatorType()
validatorImport := fmt.Sprintf("github.com/hashicorp/terraform-plugin-framework-validators/%svalidator", typ)
manager.AddHashicorpImport(validatorImport, "")
validators = &validatorCtx{
ListType: pascalCase(typ),
Package: fmt.Sprintf("%svalidator", typ),
Functions: functions,
Functions: variantFns,
}
}
attributes = append(attributes, createSchemaAttributeForParameter(schemaTyp, manager, packageName, elt, validators))
Expand Down Expand Up @@ -1043,8 +1080,34 @@ func createSchemaSpecForParameter(schemaTyp schemaType, manager *imports.Manager
continue
}

var functions []validatorFunctionCtx
if len(elt.EnumValues) > 0 && schemaTyp == schemaResource {
var values []string
for value := range elt.EnumValues {
values = append(values, value)
}

functions = append(functions, validatorFunctionCtx{
Type: "Values",
Function: "OneOf",
Values: values,
})
}

var validators *validatorCtx
if len(functions) > 0 {
typ := elt.ValidatorType()
validatorImport := fmt.Sprintf("github.com/hashicorp/terraform-plugin-framework-validators/%svalidator", typ)
manager.AddHashicorpImport(validatorImport, "")
validators = &validatorCtx{
ListType: pascalCase(typ),
Package: fmt.Sprintf("%svalidator", typ),
Functions: functions,
}
}

if elt.Type == "" || (elt.Type == "list" && elt.Items.Type == "entry") {
schemas = append(schemas, createSchemaSpecForParameter(schemaTyp, manager, structName, packageName, elt, nil)...)
schemas = append(schemas, createSchemaSpecForParameter(schemaTyp, manager, structName, packageName, elt, validators)...)
}
}

Expand All @@ -1059,7 +1122,7 @@ func createSchemaSpecForParameter(schemaTyp schemaType, manager *imports.Manager
validators := &validatorCtx{
ListType: "Object",
Package: "objectvalidator",
Functions: functions,
Functions: variantFns,
}
schemas = append(schemas, createSchemaSpecForParameter(schemaTyp, manager, structName, packageName, elt, validators)...)
}
Expand Down Expand Up @@ -1422,7 +1485,34 @@ func createSchemaSpecForNormalization(resourceTyp properties.ResourceType, schem
if elt.IsPrivateParameter() {
continue
}
attributes = append(attributes, createSchemaAttributeForParameter(schemaTyp, manager, packageName, elt, nil))

var functions []validatorFunctionCtx
if len(elt.EnumValues) > 0 && schemaTyp == schemaResource {
var values []string
for value := range elt.EnumValues {
values = append(values, value)
}

functions = append(functions, validatorFunctionCtx{
Type: "Values",
Function: "OneOf",
Values: values,
})
}

var validators *validatorCtx
if len(functions) > 0 {
typ := elt.ValidatorType()
validatorImport := fmt.Sprintf("github.com/hashicorp/terraform-plugin-framework-validators/%svalidator", typ)
manager.AddHashicorpImport(validatorImport, "")
validators = &validatorCtx{
ListType: pascalCase(typ),
Package: fmt.Sprintf("%svalidator", typ),
Functions: functions,
}
}

attributes = append(attributes, createSchemaAttributeForParameter(schemaTyp, manager, packageName, elt, validators))
schemas = append(schemas, createSchemaSpecForParameter(schemaTyp, manager, structName, packageName, elt, nil)...)
}

Expand All @@ -1439,18 +1529,24 @@ func createSchemaSpecForNormalization(resourceTyp properties.ResourceType, schem
expressions = append(expressions, fmt.Sprintf(`path.MatchRelative().AtParent().AtName("%s")`, elt.Name.Underscore))
}

functions := []validatorFunctionCtx{{
Function: validatorFn,
Expressions: expressions,
}}
var functions []validatorFunctionCtx

if len(expressions) > 0 {
functions = append(functions, validatorFunctionCtx{
Type: "Expressions",
Function: validatorFn,
Expressions: expressions,
})
}

var idx int
for _, elt := range spec.Spec.OneOf {
if elt.IsPrivateParameter() {
continue
}

var validators *validatorCtx
if idx == 0 {
if idx == 0 && schemaTyp == schemaResource && len(functions) > 0 {
typ := elt.ValidatorType()
validatorImport := fmt.Sprintf("github.com/hashicorp/terraform-plugin-framework-validators/%svalidator", typ)
manager.AddHashicorpImport(validatorImport, "")
Expand Down Expand Up @@ -1483,11 +1579,20 @@ const renderSchemaTemplate = `
{{ $package := .Package }}
Validators: []validator.{{ .ListType }}{
{{- range .Functions }}
{{- if eq .Type "Expressions" }}
{{ $package }}.{{ .Function }}(path.Expressions{
{{- range .Expressions }}
{{- range .Expressions }}
{{ . }},
{{- end }}
{{- end }}
}...),
{{- else if eq .Type "Values" }}
{{ $package }}.{{ .Function }}([]string{
{{- range .Values }}
{{ . }},
{{- end }}
}...),
{{- end }}
{{- end }}
},
{{- end }}
Expand Down Expand Up @@ -1557,11 +1662,19 @@ const renderSchemaTemplate = `
{{ $package := .Package }}
Validators: []validator.{{ .ListType }}{
{{- range .Functions }}
{{- if eq .Type "Expressions" }}
{{ $package }}.{{ .Function }}(path.Expressions{
{{- range .Expressions }}
{{- range .Expressions }}
{{ . }},
{{- end }}
{{- end }}
}...),
{{- else if eq .Type "Values" }}
{{ $package }}.{{ .Function }}([]string{
{{- range .Values }}
"{{ . }}",
{{- end }}
}...),
{{- end }}
{{- end }}
},
{{- end }}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,6 @@ func (g *GenerateTerraformProvider) updateProviderFile(renderedTemplate *strings
case "ProviderFile":
terraformProvider.Code = renderedTemplate
default:
log.Printf("updateProviderFile() renderedTemplate: %d", renderedTemplate.Len())
if _, err := terraformProvider.Code.WriteString(renderedTemplate.String()); err != nil {
return fmt.Errorf("error writing %s template: %v", resourceType, err)
}
Expand Down
10 changes: 9 additions & 1 deletion specs/objects/custom-url-category.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -137,9 +137,17 @@ spec:
items:
type: string
- name: type
type: string
type: enum
profiles:
- xpath: ["type"]
validators:
- type: values
spec:
values: ["URL List", "Category Match"]
spec:
values:
- value: URL List
- value: Category Match
- name: disable-override
type: bool
profiles:
Expand Down

0 comments on commit 73bffab

Please sign in to comment.