From 1c8150428f0a39bacd54925399049ba95708e65a Mon Sep 17 00:00:00 2001 From: Martin Atkins Date: Tue, 12 Mar 2019 11:29:23 -0700 Subject: [PATCH] helper/schema: Schema.AsSingle flag This setting indicates that an attribute defined as TypeList or TypeSet should be presented to Terraform Core as a single value instead when running in Terraform v0.12 or later. It has no effect for Terraform v0.10 or v0.11. This commit just introduces the setting without any associated behavior, so it can be included in both the v0.12 and v0.11 branches. A subsequent commit only to the v0.12 branch will introduce the behavior as part of the protocol version 5 shims. --- helper/schema/schema.go | 22 +++++++++++++ helper/schema/schema_test.go | 62 ++++++++++++++++++++++++++++++++++++ 2 files changed, 84 insertions(+) diff --git a/helper/schema/schema.go b/helper/schema/schema.go index dd3f01352..90f517363 100644 --- a/helper/schema/schema.go +++ b/helper/schema/schema.go @@ -187,8 +187,21 @@ type Schema struct { // // If the field Optional is set to true then MinItems is ignored and thus // effectively zero. + // + // If MaxItems is 1, you may optionally also set AsSingle in order to have + // Terraform v0.12 or later treat a TypeList or TypeSet as if it were a + // single value. It will remain a list or set in Terraform v0.10 and v0.11. + // Enabling this for an existing attribute after you've made at least one + // v0.12-compatible provider release is a breaking change. AsSingle is + // likely to misbehave when used with deeply-nested set structures due to + // the imprecision of set diffs, so be sure to test it thoroughly, + // including updates that change the set members at all levels. AsSingle + // exists primarily to be used in conjunction with ConfigMode when forcing + // a nested resource to be treated as an attribute, so it can be considered + // an attribute of object type rather than of list/set of object. MaxItems int MinItems int + AsSingle bool // PromoteSingle originally allowed for a single element to be assigned // where a primitive list was expected, but this no longer works from @@ -811,6 +824,15 @@ func (m schemaMap) internalValidate(topSchemaMap schemaMap, attrsOnly bool) erro } } + if v.AsSingle { + if v.MaxItems != 1 { + return fmt.Errorf("%s: MaxItems must be 1 when AsSingle is set", k) + } + if v.Type != TypeList && v.Type != TypeSet { + return fmt.Errorf("%s: AsSingle can be used only with TypeList and TypeSet schemas", k) + } + } + // Computed-only field if v.Computed && !v.Optional { if v.ValidateFunc != nil { diff --git a/helper/schema/schema_test.go b/helper/schema/schema_test.go index 4f8d9dd61..327a4e343 100644 --- a/helper/schema/schema_test.go +++ b/helper/schema/schema_test.go @@ -3924,6 +3924,68 @@ func TestSchemaMap_InternalValidate(t *testing.T) { }, true, // in *schema.Resource with ConfigMode of attribute, so must also have ConfigMode of attribute }, + + "AsSingle okay": { + map[string]*Schema{ + "block": &Schema{ + Type: TypeList, + Optional: true, + MaxItems: 1, + AsSingle: true, + Elem: &Resource{ + Schema: map[string]*Schema{ + "sub": &Schema{ + Type: TypeList, + Optional: true, + Elem: &Resource{}, + }, + }, + }, + }, + }, + false, + }, + + "AsSingle without MaxItems": { + map[string]*Schema{ + "block": &Schema{ + Type: TypeList, + Optional: true, + AsSingle: true, + Elem: &Resource{ + Schema: map[string]*Schema{ + "sub": &Schema{ + Type: TypeList, + Optional: true, + Elem: &Resource{}, + }, + }, + }, + }, + }, + true, // MaxItems must be 1 when AsSingle is set + }, + + "AsSingle on primitive type": { + map[string]*Schema{ + "block": &Schema{ + Type: TypeString, + Optional: true, + MaxItems: 1, + AsSingle: true, + Elem: &Resource{ + Schema: map[string]*Schema{ + "sub": &Schema{ + Type: TypeList, + Optional: true, + Elem: &Resource{}, + }, + }, + }, + }, + }, + true, // Unexpected error occurred: block: MaxItems and MinItems are only supported on lists or sets + }, } for tn, tc := range cases {