Terraform
Migrating predefined attribute validators
This page explains how to migrate predefined attribute validators from SDKv2 to the framework. Refer to Migrating custom attribute validators to learn how to migrate custom validators.
Background
Attribute validators ensure that specific attributes do or do not contain specific values. You can use predefined validators for many use cases, or implement custom validators. Refer to Schemas - Validators in the framework documentation for details.
The following table describes the mapping between predefined validators in SDKv2 and the framework. You should use an attribute validator for per-attribute validation, or a data source validator, provider validator or resource validator for declaring validation at the level of the data source, provider or resource, respectively.
| SDK Attribute Field | Framework Attribute Validator | Framework Data Source Validator | Framework Provider Validator | Framework Resource Validator | 
|---|---|---|---|---|
| AtLeastOneOf | {TYPE}validator.AtLeastOneOf() | datasourcevalidator.AtLeastOneOf() | providervalidator.AtLeastOneOf() | resourcevalidator.AtLeastOneOf() | 
| ConflictsWith | {TYPE}validator.ConflictsWith() | datasourcevalidator.Conflicting() | providervalidator.Conflicting() | resourcevalidator.Conflicting() | 
| ExactlyOneOf | {TYPE}validator.ExactlyOneOf() | datasourcevalidator.ExactlyOneOf() | providervalidator.ExactlyOneOf() | resourcevalidator.ExactlyOneOf() | 
| RequiredWith | {TYPE}validator.AlsoRequires() | datasourcevalidator.RequiredTogether() | providervalidator.RequiredTogether() | resourcevalidator.RequiredTogether() | 
Migrate a predefined validator
In SDKv2, the ConflictsWith, ExactlyOneOf, AtLeastOneOf, and
RequiredWith fields on an attribute's schema.Schema struct perform
predefined validations on the list of attributes set for these fields.
In the framework, you implement either type of validation by setting the
Validators field on the schema.Attribute implementation. Validators that
perform the same checks as the predefined validators in SDKv2 are available for
the
framework.
If the predefined validators do not meet your needs, you must define custom
validators.
The following code block shows implementations of predefined attribute validators on a resource attribute with SDKv2.
SDKv2
func resourceExample() *schema.Resource {
    return &schema.Resource{
        /* ... */
        Schema: map[string]*schema.Schema{
            "attribute_example": {
                ConflictsWith:  []string{ /* ... */ },
                ExactlyOneOf:   []string{ /* ... */ },
                AtLeastOneOf:   []string{ /* ... */ },
                RequiredWith:   []string{ /* ... */ },
            /* ... */
The following shows the same section of provider code after the migration.
Framework
func (r *resourceExample) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
    resp.Schema = schema.Schema{
        /* ... */
        Attributes: map[string]schema.Attribute{
            "attribute_example": schema.StringAttribute{
                Validators: []validator.String{
                    stringvalidator.ConflictsWith( /* ... */ ),
                    /* ... */
Migration Notes
Remember the following details when migrating from SDKv2 to the framework.
- In SDKv2, ValidateDiagFuncis a field onschema.Schemathat you can use to define validation functions. In SDKv2, there are also built-in validations. For example,ConflictsWithis a field on theschema.Schemastruct in SDKv2. In the framework,Validatorsis a field on eachschema.Attributeimplementation.
- Validators replicating the behavior of ConflictsWith,ExactlyOneOf,AtLeastOneOf, andRequiredWithin SDKv2 are available for the framework in each of the type-specific packages of terraform-plugin-framework-validators.
- When the predefined validators do not meet your requirements, define custom validators
Examples
Migrating a ConflictsWith validator
When one attribute should not be configured in the same block as another attribute, use a ConflictsWith validator.
The following example shows the implementation of the ConflictsWith field on
the provider's example_block block's example_attribute_one attribute. This
validator checks that the provider does not use the example_attribute_one
attribute when the example_attribute_four is being used. The example also uses
the RequiredWith field to ensure that the example_attribute_two attribute is
configured when example_attribute_one is, and that the
example_attribute_three attribute is configured when example_attribute_two
is.
SDKv2
func New() (*schema.Provider, error) {
    return &schema.Provider{
        Schema: map[string]*schema.Schema{
            "example_block": {
                Elem: &schema.Resource{
                    Schema: map[string]*schema.Schema{
                        "example_attribute_one": {
                            ConflictsWith: []string{"example_block.0.example_attribute_four"},
                            /* ... */
                        },
                        "example_attribute_two": {
                            RequiredWith: []string{"example_block.0.example_attribute_one"},
                            /* ... */
                        },
                        "example_attribute_three": {
                            RequiredWith: []string{"example_block.0.example_attribute_two"},
                            /* ... */
                        },
                        "example_attribute_four": {
                            ConflictsWith: []string{
                                "example_block.0.example_attribute_one",
                                "example_block.0.example_attribute_two",
                                "example_block.0.example_attribute_three",
                            },
                            /* ... */
                        },
                    },
                },
            },
        },
    }, nil
}
The following shows the same section of provider code after the migration.
This code implements the ConflictsWith and AlsoRequires validators with the
framework. The validators are configured via the Validators field of the
provider's example_block block's attribute schema.
Framework
func (p *TlsProvider) Schema(_ context.Context, _ provider.SchemaRequest, resp *provider.SchemaResponse) {
    resp.Schema = schema.Schema{
        Blocks: map[string]schema.Block{
            "example_block": schema.ListNestedBlock{
                NestedObject: schema.NestedBlockObject{
                    Attributes: map[string]schema.Attribute{
                        "example_attribute_one": schema.StringAttribute{
                            Validators: []validator.String{
                                stringvalidator.ConflictsWith(path.MatchRelative().AtParent().AtName("example_attribute_four")),
                            },
                            /* ... */
                        },
                        "example_attribute_two": schema.StringAttribute{
                            Validators: []validator.String{
                                stringvalidator.AlsoRequires(path.MatchRelative().AtParent().AtName("example_attribute_one")),
                            },
                            /* ... */
                        },
                        "example_attribute_three": schema.StringAttribute{
                            Validators: []validator.String{
                                stringvalidator.AlsoRequires(path.MatchRelative().AtParent().AtName("example_attribute_two")),
                            },
                            /* ... */
                        },
                        "example_attribute_four": schema.BoolAttribute{
                            Validators: []validator.Bool{
                                boolvalidator.ConflictsWith(
                                    path.MatchRelative().AtParent().AtName("example_attribute_one"),
                                    path.MatchRelative().AtParent().AtName("example_attribute_two"),
                                    path.MatchRelative().AtParent().AtName("example_attribute_three"),
                                ),
                            },
                            /* ... */
                        },
                    },
                },
            },
    }
}