Add schema.ConflictsWith[]
- this will allow defining logically conflicting attributes
This commit is contained in:
parent
1c0f2f136c
commit
e0df74c863
|
@ -114,6 +114,9 @@ type Schema struct {
|
|||
// NOTE: This currently does not work.
|
||||
ComputedWhen []string
|
||||
|
||||
// ConflictsWith is a set of schema keys that conflict with this schema
|
||||
ConflictsWith []string
|
||||
|
||||
// When Deprecated is set, this attribute is deprecated.
|
||||
//
|
||||
// A deprecated field still works, but will probably stop working in near
|
||||
|
@ -436,6 +439,22 @@ func (m schemaMap) InternalValidate() error {
|
|||
return fmt.Errorf("%s: ComputedWhen can only be set with Computed", k)
|
||||
}
|
||||
|
||||
if len(v.ConflictsWith) > 0 && v.Required {
|
||||
return fmt.Errorf("%s: ConflictsWith cannot be set with Required", k)
|
||||
}
|
||||
|
||||
if len(v.ConflictsWith) > 0 {
|
||||
for _, key := range v.ConflictsWith {
|
||||
if m[key].Required {
|
||||
return fmt.Errorf("%s: ConflictsWith cannot contain Required attribute (%s)", k, key)
|
||||
}
|
||||
|
||||
if m[key].Computed || len(m[key].ComputedWhen) > 0 {
|
||||
return fmt.Errorf("%s: ConflictsWith cannot contain Computed(When) attribute (%s)", k, key)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if v.Type == TypeList || v.Type == TypeSet {
|
||||
if v.Elem == nil {
|
||||
return fmt.Errorf("%s: Elem must be set for lists", k)
|
||||
|
@ -913,9 +932,33 @@ func (m schemaMap) validate(
|
|||
"%q: this field cannot be set", k)}
|
||||
}
|
||||
|
||||
err := m.validateConflictingAttributes(k, schema, c)
|
||||
if err != nil {
|
||||
return nil, []error{err}
|
||||
}
|
||||
|
||||
return m.validateType(k, raw, schema, c)
|
||||
}
|
||||
|
||||
func (m schemaMap) validateConflictingAttributes(
|
||||
k string,
|
||||
schema *Schema,
|
||||
c *terraform.ResourceConfig) error {
|
||||
|
||||
if len(schema.ConflictsWith) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
for _, conflicting_key := range schema.ConflictsWith {
|
||||
if value, ok := c.Get(conflicting_key); ok {
|
||||
return fmt.Errorf(
|
||||
"%q: conflicts with %s (%#v)", k, conflicting_key, value)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m schemaMap) validateList(
|
||||
k string,
|
||||
raw interface{},
|
||||
|
|
|
@ -2555,6 +2555,66 @@ func TestSchemaMap_InternalValidate(t *testing.T) {
|
|||
true,
|
||||
},
|
||||
|
||||
// Conflicting attributes cannot be required
|
||||
{
|
||||
map[string]*Schema{
|
||||
"blacklist": &Schema{
|
||||
Type: TypeBool,
|
||||
Required: true,
|
||||
},
|
||||
"whitelist": &Schema{
|
||||
Type: TypeBool,
|
||||
Optional: true,
|
||||
ConflictsWith: []string{"blacklist"},
|
||||
},
|
||||
},
|
||||
true,
|
||||
},
|
||||
|
||||
// Attribute with conflicts cannot be required
|
||||
{
|
||||
map[string]*Schema{
|
||||
"whitelist": &Schema{
|
||||
Type: TypeBool,
|
||||
Required: true,
|
||||
ConflictsWith: []string{"blacklist"},
|
||||
},
|
||||
},
|
||||
true,
|
||||
},
|
||||
|
||||
// ConflictsWith cannot be used w/ Computed
|
||||
{
|
||||
map[string]*Schema{
|
||||
"blacklist": &Schema{
|
||||
Type: TypeBool,
|
||||
Computed: true,
|
||||
},
|
||||
"whitelist": &Schema{
|
||||
Type: TypeBool,
|
||||
Optional: true,
|
||||
ConflictsWith: []string{"blacklist"},
|
||||
},
|
||||
},
|
||||
true,
|
||||
},
|
||||
|
||||
// ConflictsWith cannot be used w/ ComputedWhen
|
||||
{
|
||||
map[string]*Schema{
|
||||
"blacklist": &Schema{
|
||||
Type: TypeBool,
|
||||
ComputedWhen: []string{"foor"},
|
||||
},
|
||||
"whitelist": &Schema{
|
||||
Type: TypeBool,
|
||||
Required: true,
|
||||
ConflictsWith: []string{"blacklist"},
|
||||
},
|
||||
},
|
||||
true,
|
||||
},
|
||||
|
||||
// Sub-resource invalid
|
||||
{
|
||||
map[string]*Schema{
|
||||
|
@ -2594,7 +2654,10 @@ func TestSchemaMap_InternalValidate(t *testing.T) {
|
|||
for i, tc := range cases {
|
||||
err := schemaMap(tc.In).InternalValidate()
|
||||
if (err != nil) != tc.Err {
|
||||
t.Fatalf("%d: bad: %s\n\n%#v", i, err, tc.In)
|
||||
if tc.Err {
|
||||
t.Fatalf("%d: Expected error did not occur:\n\n%#v", i, tc.In)
|
||||
}
|
||||
t.Fatalf("%d: Unexpected error occured:\n\n%#v", i, tc.In)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3103,6 +3166,74 @@ func TestSchemaMap_Validate(t *testing.T) {
|
|||
|
||||
Err: false,
|
||||
},
|
||||
|
||||
"Conflicting attributes generate error": {
|
||||
Schema: map[string]*Schema{
|
||||
"whitelist": &Schema{
|
||||
Type: TypeString,
|
||||
Optional: true,
|
||||
},
|
||||
"blacklist": &Schema{
|
||||
Type: TypeString,
|
||||
Optional: true,
|
||||
ConflictsWith: []string{"whitelist"},
|
||||
},
|
||||
},
|
||||
|
||||
Config: map[string]interface{}{
|
||||
"whitelist": "white-val",
|
||||
"blacklist": "black-val",
|
||||
},
|
||||
|
||||
Err: true,
|
||||
Errors: []error{
|
||||
fmt.Errorf("\"blacklist\": conflicts with whitelist (\"white-val\")"),
|
||||
},
|
||||
},
|
||||
|
||||
"Required attribute & undefined conflicting optional are good": {
|
||||
Schema: map[string]*Schema{
|
||||
"required_att": &Schema{
|
||||
Type: TypeString,
|
||||
Required: true,
|
||||
},
|
||||
"optional_att": &Schema{
|
||||
Type: TypeString,
|
||||
Optional: true,
|
||||
ConflictsWith: []string{"required_att"},
|
||||
},
|
||||
},
|
||||
|
||||
Config: map[string]interface{}{
|
||||
"required_att": "required-val",
|
||||
},
|
||||
|
||||
Err: false,
|
||||
},
|
||||
|
||||
"Required conflicting attribute & defined optional generate error": {
|
||||
Schema: map[string]*Schema{
|
||||
"required_att": &Schema{
|
||||
Type: TypeString,
|
||||
Required: true,
|
||||
},
|
||||
"optional_att": &Schema{
|
||||
Type: TypeString,
|
||||
Optional: true,
|
||||
ConflictsWith: []string{"required_att"},
|
||||
},
|
||||
},
|
||||
|
||||
Config: map[string]interface{}{
|
||||
"required_att": "required-val",
|
||||
"optional_att": "optional-val",
|
||||
},
|
||||
|
||||
Err: true,
|
||||
Errors: []error{
|
||||
fmt.Errorf("\"optional_att\": conflicts with required_att (\"required-val\")"),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for tn, tc := range cases {
|
||||
|
|
Loading…
Reference in New Issue