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 {
|
||||
case TypeList:
|
||||
return d.getList(k, parts, schema, source)
|
||||
case TypeMap:
|
||||
return d.getMap(k, parts, schema, source)
|
||||
default:
|
||||
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(
|
||||
k string,
|
||||
parts []string,
|
||||
|
@ -259,6 +322,8 @@ func (d *ResourceData) set(
|
|||
switch schema.Type {
|
||||
case TypeList:
|
||||
return d.setList(k, parts, schema, value)
|
||||
case TypeMap:
|
||||
return d.setMapValue(k, parts, schema, value)
|
||||
default:
|
||||
return d.setPrimitive(k, schema, value)
|
||||
}
|
||||
|
@ -315,6 +380,27 @@ func (d *ResourceData) setList(
|
|||
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(
|
||||
k string,
|
||||
parts []string,
|
||||
|
@ -422,6 +508,26 @@ func (d *ResourceData) stateList(
|
|||
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(
|
||||
prefix string,
|
||||
schema map[string]*Schema) map[string]string {
|
||||
|
@ -469,6 +575,8 @@ func (d *ResourceData) stateSingle(
|
|||
switch schema.Type {
|
||||
case TypeList:
|
||||
return d.stateList(prefix, schema)
|
||||
case TypeMap:
|
||||
return d.stateMap(prefix, schema)
|
||||
default:
|
||||
return d.statePrimitive(prefix, schema)
|
||||
}
|
||||
|
|
|
@ -300,6 +300,85 @@ func TestResourceDataGet(t *testing.T) {
|
|||
"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 {
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
|
|
@ -17,6 +17,7 @@ const (
|
|||
TypeInt
|
||||
TypeString
|
||||
TypeList
|
||||
TypeMap
|
||||
)
|
||||
|
||||
// Schema is used to describe the structure of a value.
|
||||
|
|
Loading…
Reference in New Issue