Lokasi ngalangkungan proxy:   [ UP ]  
[Ngawartoskeun bug]   [Panyetelan cookie]                
Skip to content

Commit 487a37b

Browse files
committed
helper/schema: PromoteSingle for legacy support of "maybe list" types
1 parent f29845e commit 487a37b

4 files changed

Lines changed: 144 additions & 3 deletions

File tree

builtin/provisioners/remote-exec/resource_provisioner.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ func Provisioner() terraform.ResourceProvisioner {
2323
"inline": &schema.Schema{
2424
Type: schema.TypeList,
2525
Elem: &schema.Schema{Type: schema.TypeString},
26+
PromoteSingle: true,
2627
Optional: true,
2728
ConflictsWith: []string{"script", "scripts"},
2829
},

helper/schema/field_reader_config.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,10 +79,35 @@ func (r *ConfigFieldReader) readField(
7979

8080
k := strings.Join(address, ".")
8181
schema := schemaList[len(schemaList)-1]
82+
83+
// If we're getting the single element of a promoted list, then
84+
// check to see if we have a single element we need to promote.
85+
if address[len(address)-1] == "0" && len(schemaList) > 1 {
86+
lastSchema := schemaList[len(schemaList)-2]
87+
if lastSchema.Type == TypeList && lastSchema.PromoteSingle {
88+
k := strings.Join(address[:len(address)-1], ".")
89+
result, err := r.readPrimitive(k, schema)
90+
if err == nil {
91+
return result, nil
92+
}
93+
}
94+
}
95+
8296
switch schema.Type {
8397
case TypeBool, TypeFloat, TypeInt, TypeString:
8498
return r.readPrimitive(k, schema)
8599
case TypeList:
100+
// If we support promotion then we first check if we have a lone
101+
// value that we must promote.
102+
// a value that is alone.
103+
if schema.PromoteSingle {
104+
result, err := r.readPrimitive(k, schema.Elem.(*Schema))
105+
if err == nil && result.Exists {
106+
result.Value = []interface{}{result.Value}
107+
return result, nil
108+
}
109+
}
110+
86111
return readListField(&nestedConfigFieldReader{r}, address, schema)
87112
case TypeMap:
88113
return r.readMap(k, schema)

helper/schema/schema.go

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -118,9 +118,16 @@ type Schema struct {
118118
// TypeSet or TypeList. Specific use cases would be if a TypeSet is being
119119
// used to wrap a complex structure, however less than one instance would
120120
// cause instability.
121-
Elem interface{}
122-
MaxItems int
123-
MinItems int
121+
//
122+
// PromoteSingle, if true, will allow single elements to be standalone
123+
// and promote them to a list. For example "foo" would be promoted to
124+
// ["foo"] automatically. This is primarily for legacy reasons and the
125+
// ambiguity is not recommended for new usage. Promotion is only allowed
126+
// for primitive element types.
127+
Elem interface{}
128+
MaxItems int
129+
MinItems int
130+
PromoteSingle bool
124131

125132
// The following fields are only valid for a TypeSet type.
126133
//
@@ -1140,6 +1147,14 @@ func (m schemaMap) validateList(
11401147
// We use reflection to verify the slice because you can't
11411148
// case to []interface{} unless the slice is exactly that type.
11421149
rawV := reflect.ValueOf(raw)
1150+
1151+
// If we support promotion and the raw value isn't a slice, wrap
1152+
// it in []interface{} and check again.
1153+
if schema.PromoteSingle && rawV.Kind() != reflect.Slice {
1154+
raw = []interface{}{raw}
1155+
rawV = reflect.ValueOf(raw)
1156+
}
1157+
11431158
if rawV.Kind() != reflect.Slice {
11441159
return nil, []error{fmt.Errorf(
11451160
"%s: should be a list", k)}

helper/schema/schema_test.go

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -582,6 +582,72 @@ func TestSchemaMap_Diff(t *testing.T) {
582582
Err: false,
583583
},
584584

585+
{
586+
Name: "List decode with promotion",
587+
Schema: map[string]*Schema{
588+
"ports": &Schema{
589+
Type: TypeList,
590+
Required: true,
591+
Elem: &Schema{Type: TypeInt},
592+
PromoteSingle: true,
593+
},
594+
},
595+
596+
State: nil,
597+
598+
Config: map[string]interface{}{
599+
"ports": "5",
600+
},
601+
602+
Diff: &terraform.InstanceDiff{
603+
Attributes: map[string]*terraform.ResourceAttrDiff{
604+
"ports.#": &terraform.ResourceAttrDiff{
605+
Old: "0",
606+
New: "1",
607+
},
608+
"ports.0": &terraform.ResourceAttrDiff{
609+
Old: "",
610+
New: "5",
611+
},
612+
},
613+
},
614+
615+
Err: false,
616+
},
617+
618+
{
619+
Name: "List decode with promotion with list",
620+
Schema: map[string]*Schema{
621+
"ports": &Schema{
622+
Type: TypeList,
623+
Required: true,
624+
Elem: &Schema{Type: TypeInt},
625+
PromoteSingle: true,
626+
},
627+
},
628+
629+
State: nil,
630+
631+
Config: map[string]interface{}{
632+
"ports": []interface{}{"5"},
633+
},
634+
635+
Diff: &terraform.InstanceDiff{
636+
Attributes: map[string]*terraform.ResourceAttrDiff{
637+
"ports.#": &terraform.ResourceAttrDiff{
638+
Old: "0",
639+
New: "1",
640+
},
641+
"ports.0": &terraform.ResourceAttrDiff{
642+
Old: "",
643+
New: "5",
644+
},
645+
},
646+
},
647+
648+
Err: false,
649+
},
650+
585651
{
586652
Schema: map[string]*Schema{
587653
"ports": &Schema{
@@ -3585,6 +3651,40 @@ func TestSchemaMap_Validate(t *testing.T) {
35853651
Err: true,
35863652
},
35873653

3654+
"List with promotion": {
3655+
Schema: map[string]*Schema{
3656+
"ingress": &Schema{
3657+
Type: TypeList,
3658+
Elem: &Schema{Type: TypeInt},
3659+
PromoteSingle: true,
3660+
Optional: true,
3661+
},
3662+
},
3663+
3664+
Config: map[string]interface{}{
3665+
"ingress": "5",
3666+
},
3667+
3668+
Err: false,
3669+
},
3670+
3671+
"List with promotion set as list": {
3672+
Schema: map[string]*Schema{
3673+
"ingress": &Schema{
3674+
Type: TypeList,
3675+
Elem: &Schema{Type: TypeInt},
3676+
PromoteSingle: true,
3677+
Optional: true,
3678+
},
3679+
},
3680+
3681+
Config: map[string]interface{}{
3682+
"ingress": []interface{}{"5"},
3683+
},
3684+
3685+
Err: false,
3686+
},
3687+
35883688
"Optional sub-resource": {
35893689
Schema: map[string]*Schema{
35903690
"ingress": &Schema{

0 commit comments

Comments
 (0)