Skip to content

At Least One Multiple Attribute Validation (AtLeastOneOf / AtLeastOneAttribute) #16

@bflad

Description

@bflad

Terraform CLI and Framework Versions

Any Terraform CLI version; terraform-plugin-framework v0.8.0

Use Cases or Problem Statement

Provider developers should be able to generically validate that in a set of attributes, at least one of them contains a non-null configuration value.

Proposal

These are not necessarily mutually exclusive proposals -- both types of implementations have been requested in the past.

Proposal 1 (AttributeValidator Style)

This would be similar to the helper/schema.Schema.AtLeastOneOf field implementation.

Inside a multivalidator package, create a new unexported type that satisfies the tfsdk.AttributeValidator interface:

var _ atLeastOneOfValidator = tfsdk.AttributeValidator

type atLeastOneOfValidator struct {
  attributePaths []AttributePath
}

func (v atLeastOneOfValidator) Description(ctx context.Context) string {/*...*/}
func (v atLeastOneOfValidator) MarkdownDescription(ctx context.Context) string {/*...*/}
func (v atLeastOneOfValidator) Validate(ctx context.Context, req tfsdk.ValidateAttributeRequest, resp *tfsdk.ValidateAttributeResponse) {/*...*/}

Then, create an exported function that returns it:

func AtLeastOneOf(attributePaths AttributePath...) AttributeValidator {/*...*/}

This would allow provider developers to declare attributes such as:

tfsdk.Attribute{
  // ... other fields ...
  Type: types.String{},
  Validators: tfsdk.AttributeValidators{
    multivalidator.AtLeastOneOf(
      tftypes.NewAttributePath().WithAttributeName("other"), // until attribute paths/matchers are native
    ),
  },
},

Proposal 2 (ConfigValidator Style)

Rather than being part of the schema, this would enable provider developers to create it at the top level of a resource, etc.

Inside a configvalidator package, create a new unexported type that satisfies the tfsdk.ResourceConfigValidator interface (allowing a configuration validator across data sources, providers, and resources would require an upstream breaking change to those interfaces):

var _ atLeastOneAttributeValidator = tfsdk.ResourceConfigValidator

type atLeastOneAttributeValidator struct {
  attributePaths []AttributePath
}

func (v atLeastOneAttributeValidator) Description(ctx context.Context) string {/*...*/}
func (v atLeastOneAttributeValidator) MarkdownDescription(ctx context.Context) string {/*...*/}
func (v atLeastOneAttributeValidator) Validate(ctx context.Context, req tfsdk.ResourceConfigValidatorRequest, resp *tfsdk.ResourceConfigValidatorResponse) {/*...*/}

Then, create an exported function that returns it:

func AtLeastOneAttribute(attributePaths AttributePath...) AttributeValidator {/*...*/}

This would allow provider developers to declare resources such as:

var _ tfsdk.ResourceWithConfigValidators = exampleResource{}

func (r exampleResource) ConfigValidators(ctx context.Context) []tfsdk.ResourceConfigValidator {
  return []tfsdk.ResourceConfigValidator{
    configvalidator.AtLeastOneAttribute(
      // attribute path 1
      // attribute path 2
    ),
  },
}

Additional Information

No response

Code of Conduct

  • I agree to follow this project's Code of Conduct

Metadata

Metadata

Assignees

Labels

enhancementNew feature or requesttype/multiMultiple attribute validatorstype/schemaSchema validators

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions