helper/schema: can handle maps
This commit is contained in:
parent
66d7003e6f
commit
4c9271160e
|
@ -121,11 +121,74 @@ func (d *ResourceData) get(
|
||||||
switch schema.Type {
|
switch schema.Type {
|
||||||
case TypeList:
|
case TypeList:
|
||||||
return d.getList(k, parts, schema, source)
|
return d.getList(k, parts, schema, source)
|
||||||
|
case TypeMap:
|
||||||
|
return d.getMap(k, parts, schema, source)
|
||||||
default:
|
default:
|
||||||
return d.getPrimitive(k, parts, schema, source)
|
return d.getPrimitive(k, parts, schema, source)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *ResourceData) getMap(
|
||||||
|
k string,
|
||||||
|
parts []string,
|
||||||
|
schema *Schema,
|
||||||
|
source getSource) interface{} {
|
||||||
|
elemSchema := &Schema{Type: TypeString}
|
||||||
|
|
||||||
|
// Get the full map
|
||||||
|
var result map[string]interface{}
|
||||||
|
|
||||||
|
prefix := k + "."
|
||||||
|
|
||||||
|
// Try set first
|
||||||
|
if d.setMap != nil && source >= getSourceSet {
|
||||||
|
for k, _ := range d.setMap {
|
||||||
|
if !strings.HasPrefix(k, prefix) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
single := k[len(prefix):]
|
||||||
|
if result == nil {
|
||||||
|
result = make(map[string]interface{})
|
||||||
|
}
|
||||||
|
|
||||||
|
result[single] = d.getPrimitive(k, nil, elemSchema, source)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if result == nil && d.diff != nil && source >= getSourceDiff {
|
||||||
|
for k, _ := range d.diff.Attributes {
|
||||||
|
if !strings.HasPrefix(k, prefix) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
single := k[len(prefix):]
|
||||||
|
if result == nil {
|
||||||
|
result = make(map[string]interface{})
|
||||||
|
}
|
||||||
|
|
||||||
|
result[single] = d.getPrimitive(k, nil, elemSchema, source)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if result == nil && d.state != nil && source >= getSourceState {
|
||||||
|
for k, _ := range d.state.Attributes {
|
||||||
|
if !strings.HasPrefix(k, prefix) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
single := k[len(prefix):]
|
||||||
|
if result == nil {
|
||||||
|
result = make(map[string]interface{})
|
||||||
|
}
|
||||||
|
|
||||||
|
result[single] = d.getPrimitive(k, nil, elemSchema, source)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
func (d *ResourceData) getObject(
|
func (d *ResourceData) getObject(
|
||||||
k string,
|
k string,
|
||||||
parts []string,
|
parts []string,
|
||||||
|
@ -259,6 +322,8 @@ func (d *ResourceData) set(
|
||||||
switch schema.Type {
|
switch schema.Type {
|
||||||
case TypeList:
|
case TypeList:
|
||||||
return d.setList(k, parts, schema, value)
|
return d.setList(k, parts, schema, value)
|
||||||
|
case TypeMap:
|
||||||
|
return d.setMapValue(k, parts, schema, value)
|
||||||
default:
|
default:
|
||||||
return d.setPrimitive(k, schema, value)
|
return d.setPrimitive(k, schema, value)
|
||||||
}
|
}
|
||||||
|
@ -315,6 +380,27 @@ func (d *ResourceData) setList(
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *ResourceData) setMapValue(
|
||||||
|
k string,
|
||||||
|
parts []string,
|
||||||
|
schema *Schema,
|
||||||
|
value interface{}) error {
|
||||||
|
elemSchema := &Schema{Type: TypeString}
|
||||||
|
if len(parts) > 0 {
|
||||||
|
return fmt.Errorf("%s: full map must be set, no a single element", k)
|
||||||
|
}
|
||||||
|
|
||||||
|
vs := value.(map[string]interface{})
|
||||||
|
for subKey, v := range vs {
|
||||||
|
err := d.set(fmt.Sprintf("%s.%s", k, subKey), nil, elemSchema, v)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (d *ResourceData) setObject(
|
func (d *ResourceData) setObject(
|
||||||
k string,
|
k string,
|
||||||
parts []string,
|
parts []string,
|
||||||
|
@ -422,6 +508,26 @@ func (d *ResourceData) stateList(
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *ResourceData) stateMap(
|
||||||
|
prefix string,
|
||||||
|
schema *Schema) map[string]string {
|
||||||
|
v := d.getMap(prefix, nil, schema, getSourceSet)
|
||||||
|
if v == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
elemSchema := &Schema{Type: TypeString}
|
||||||
|
result := make(map[string]string)
|
||||||
|
for mk, _ := range v.(map[string]interface{}) {
|
||||||
|
mp := fmt.Sprintf("%s.%s", prefix, mk)
|
||||||
|
for k, v := range d.stateSingle(mp, elemSchema) {
|
||||||
|
result[k] = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
func (d *ResourceData) stateObject(
|
func (d *ResourceData) stateObject(
|
||||||
prefix string,
|
prefix string,
|
||||||
schema map[string]*Schema) map[string]string {
|
schema map[string]*Schema) map[string]string {
|
||||||
|
@ -469,6 +575,8 @@ func (d *ResourceData) stateSingle(
|
||||||
switch schema.Type {
|
switch schema.Type {
|
||||||
case TypeList:
|
case TypeList:
|
||||||
return d.stateList(prefix, schema)
|
return d.stateList(prefix, schema)
|
||||||
|
case TypeMap:
|
||||||
|
return d.stateMap(prefix, schema)
|
||||||
default:
|
default:
|
||||||
return d.statePrimitive(prefix, schema)
|
return d.statePrimitive(prefix, schema)
|
||||||
}
|
}
|
||||||
|
|
|
@ -300,6 +300,85 @@ func TestResourceDataGet(t *testing.T) {
|
||||||
"availability_zone": "foo",
|
"availability_zone": "foo",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// List of maps
|
||||||
|
{
|
||||||
|
Schema: map[string]*Schema{
|
||||||
|
"config_vars": &Schema{
|
||||||
|
Type: TypeList,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
Elem: &Schema{
|
||||||
|
Type: TypeMap,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
State: nil,
|
||||||
|
|
||||||
|
Diff: &terraform.ResourceDiff{
|
||||||
|
Attributes: map[string]*terraform.ResourceAttrDiff{
|
||||||
|
"config_vars.#": &terraform.ResourceAttrDiff{
|
||||||
|
Old: "0",
|
||||||
|
New: "2",
|
||||||
|
},
|
||||||
|
"config_vars.0.foo": &terraform.ResourceAttrDiff{
|
||||||
|
Old: "",
|
||||||
|
New: "bar",
|
||||||
|
},
|
||||||
|
"config_vars.1.bar": &terraform.ResourceAttrDiff{
|
||||||
|
Old: "",
|
||||||
|
New: "baz",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
Key: "config_vars",
|
||||||
|
|
||||||
|
Value: []interface{}{
|
||||||
|
map[string]interface{}{
|
||||||
|
"foo": "bar",
|
||||||
|
},
|
||||||
|
map[string]interface{}{
|
||||||
|
"bar": "baz",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
// List of maps in state
|
||||||
|
{
|
||||||
|
Schema: map[string]*Schema{
|
||||||
|
"config_vars": &Schema{
|
||||||
|
Type: TypeList,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
Elem: &Schema{
|
||||||
|
Type: TypeMap,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
State: &terraform.ResourceState{
|
||||||
|
Attributes: map[string]string{
|
||||||
|
"config_vars.#": "2",
|
||||||
|
"config_vars.0.foo": "baz",
|
||||||
|
"config_vars.1.bar": "bar",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
Diff: nil,
|
||||||
|
|
||||||
|
Key: "config_vars",
|
||||||
|
|
||||||
|
Value: []interface{}{
|
||||||
|
map[string]interface{}{
|
||||||
|
"foo": "baz",
|
||||||
|
},
|
||||||
|
map[string]interface{}{
|
||||||
|
"bar": "bar",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, tc := range cases {
|
for i, tc := range cases {
|
||||||
|
@ -762,6 +841,45 @@ func TestResourceDataSet(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// Set a list of maps
|
||||||
|
{
|
||||||
|
Schema: map[string]*Schema{
|
||||||
|
"config_vars": &Schema{
|
||||||
|
Type: TypeList,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
Elem: &Schema{
|
||||||
|
Type: TypeMap,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
State: nil,
|
||||||
|
|
||||||
|
Diff: nil,
|
||||||
|
|
||||||
|
Key: "config_vars",
|
||||||
|
Value: []interface{}{
|
||||||
|
map[string]interface{}{
|
||||||
|
"foo": "bar",
|
||||||
|
},
|
||||||
|
map[string]interface{}{
|
||||||
|
"bar": "baz",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Err: false,
|
||||||
|
|
||||||
|
GetKey: "config_vars",
|
||||||
|
GetValue: []interface{}{
|
||||||
|
map[string]interface{}{
|
||||||
|
"foo": "bar",
|
||||||
|
},
|
||||||
|
map[string]interface{}{
|
||||||
|
"bar": "baz",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, tc := range cases {
|
for i, tc := range cases {
|
||||||
|
@ -942,6 +1060,42 @@ func TestResourceDataState(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// List of maps
|
||||||
|
{
|
||||||
|
Schema: map[string]*Schema{
|
||||||
|
"config_vars": &Schema{
|
||||||
|
Type: TypeList,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
Elem: &Schema{
|
||||||
|
Type: TypeMap,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
State: &terraform.ResourceState{
|
||||||
|
Attributes: map[string]string{
|
||||||
|
"config_vars.#": "2",
|
||||||
|
"config_vars.0.foo": "bar",
|
||||||
|
"config_vars.1.bar": "baz",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
Set: map[string]interface{}{
|
||||||
|
"config_vars.1": map[string]interface{}{
|
||||||
|
"baz": "bang",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
Result: &terraform.ResourceState{
|
||||||
|
Attributes: map[string]string{
|
||||||
|
"config_vars.#": "2",
|
||||||
|
"config_vars.0.foo": "bar",
|
||||||
|
"config_vars.1.baz": "bang",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, tc := range cases {
|
for i, tc := range cases {
|
||||||
|
|
|
@ -17,6 +17,7 @@ const (
|
||||||
TypeInt
|
TypeInt
|
||||||
TypeString
|
TypeString
|
||||||
TypeList
|
TypeList
|
||||||
|
TypeMap
|
||||||
)
|
)
|
||||||
|
|
||||||
// Schema is used to describe the structure of a value.
|
// Schema is used to describe the structure of a value.
|
||||||
|
|
Loading…
Reference in New Issue