helper/schema: Adding of MinItems as a validation to Lists and Maps
This is required for the times when the configuration cannot have an empty configuration. An example would be in AzureRM, when you create a LoadBalancer with a configuration, you can delete *all* but 1 of these configurations
This commit is contained in:
parent
a879323d23
commit
5a537cdbf9
|
@ -113,8 +113,14 @@ type Schema struct {
|
||||||
// TypeSet or TypeList. Specific use cases would be if a TypeSet is being
|
// TypeSet or TypeList. Specific use cases would be if a TypeSet is being
|
||||||
// used to wrap a complex structure, however more than one instance would
|
// used to wrap a complex structure, however more than one instance would
|
||||||
// cause instability.
|
// cause instability.
|
||||||
|
//
|
||||||
|
// MinItems defines a minimum amount of items that can exist within a
|
||||||
|
// TypeSet or TypeList. Specific use cases would be if a TypeSet is being
|
||||||
|
// used to wrap a complex structure, however less than one instance would
|
||||||
|
// cause instability.
|
||||||
Elem interface{}
|
Elem interface{}
|
||||||
MaxItems int
|
MaxItems int
|
||||||
|
MinItems int
|
||||||
|
|
||||||
// The following fields are only valid for a TypeSet type.
|
// The following fields are only valid for a TypeSet type.
|
||||||
//
|
//
|
||||||
|
@ -597,8 +603,8 @@ func (m schemaMap) InternalValidate(topSchemaMap schemaMap) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if v.MaxItems > 0 {
|
if v.MaxItems > 0 || v.MinItems > 0 {
|
||||||
return fmt.Errorf("%s: MaxItems is only supported on lists or sets", k)
|
return fmt.Errorf("%s: MaxItems and MinItems are only supported on lists or sets", k)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1128,6 +1134,11 @@ func (m schemaMap) validateList(
|
||||||
"%s: attribute supports %d item maximum, config has %d declared", k, schema.MaxItems, rawV.Len())}
|
"%s: attribute supports %d item maximum, config has %d declared", k, schema.MaxItems, rawV.Len())}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if schema.MinItems > 0 && rawV.Len() < schema.MinItems {
|
||||||
|
return nil, []error{fmt.Errorf(
|
||||||
|
"%s: attribute supports %d item as a minimum, config has %d declared", k, schema.MinItems, rawV.Len())}
|
||||||
|
}
|
||||||
|
|
||||||
// Now build the []interface{}
|
// Now build the []interface{}
|
||||||
raws := make([]interface{}, rawV.Len())
|
raws := make([]interface{}, rawV.Len())
|
||||||
for i, _ := range raws {
|
for i, _ := range raws {
|
||||||
|
|
|
@ -3895,3 +3895,94 @@ func TestSchemaSet_ValidateMaxItems(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSchemaSet_ValidateMinItems(t *testing.T) {
|
||||||
|
cases := map[string]struct {
|
||||||
|
Schema map[string]*Schema
|
||||||
|
State *terraform.InstanceState
|
||||||
|
Config map[string]interface{}
|
||||||
|
ConfigVariables map[string]string
|
||||||
|
Diff *terraform.InstanceDiff
|
||||||
|
Err bool
|
||||||
|
Errors []error
|
||||||
|
}{
|
||||||
|
"#0": {
|
||||||
|
Schema: map[string]*Schema{
|
||||||
|
"aliases": &Schema{
|
||||||
|
Type: TypeSet,
|
||||||
|
Optional: true,
|
||||||
|
MinItems: 2,
|
||||||
|
Elem: &Schema{Type: TypeString},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
State: nil,
|
||||||
|
Config: map[string]interface{}{
|
||||||
|
"aliases": []interface{}{"foo", "bar"},
|
||||||
|
},
|
||||||
|
Diff: nil,
|
||||||
|
Err: false,
|
||||||
|
Errors: nil,
|
||||||
|
},
|
||||||
|
"#1": {
|
||||||
|
Schema: map[string]*Schema{
|
||||||
|
"aliases": &Schema{
|
||||||
|
Type: TypeSet,
|
||||||
|
Optional: true,
|
||||||
|
Elem: &Schema{Type: TypeString},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
State: nil,
|
||||||
|
Config: map[string]interface{}{
|
||||||
|
"aliases": []interface{}{"foo", "bar"},
|
||||||
|
},
|
||||||
|
Diff: nil,
|
||||||
|
Err: false,
|
||||||
|
Errors: nil,
|
||||||
|
},
|
||||||
|
"#2": {
|
||||||
|
Schema: map[string]*Schema{
|
||||||
|
"aliases": &Schema{
|
||||||
|
Type: TypeSet,
|
||||||
|
Optional: true,
|
||||||
|
MinItems: 2,
|
||||||
|
Elem: &Schema{Type: TypeString},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
State: nil,
|
||||||
|
Config: map[string]interface{}{
|
||||||
|
"aliases": []interface{}{"foo"},
|
||||||
|
},
|
||||||
|
Diff: nil,
|
||||||
|
Err: true,
|
||||||
|
Errors: []error{
|
||||||
|
fmt.Errorf("aliases: attribute supports 2 item as a minimum, config has 1 declared"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for tn, tc := range cases {
|
||||||
|
c, err := config.NewRawConfig(tc.Config)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("%q: err: %s", tn, err)
|
||||||
|
}
|
||||||
|
_, es := schemaMap(tc.Schema).Validate(terraform.NewResourceConfig(c))
|
||||||
|
|
||||||
|
if len(es) > 0 != tc.Err {
|
||||||
|
if len(es) == 0 {
|
||||||
|
t.Errorf("%q: no errors", tn)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, e := range es {
|
||||||
|
t.Errorf("%q: err: %s", tn, e)
|
||||||
|
}
|
||||||
|
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
|
||||||
|
if tc.Errors != nil {
|
||||||
|
if !reflect.DeepEqual(es, tc.Errors) {
|
||||||
|
t.Fatalf("%q: expected: %q\ngot: %q", tn, tc.Errors, es)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue