helper/schema: Set object
This commit is contained in:
parent
2d74a3cadd
commit
06d30a559a
|
@ -14,7 +14,7 @@ type ResourceData struct {
|
||||||
schema map[string]*Schema
|
schema map[string]*Schema
|
||||||
state *terraform.ResourceState
|
state *terraform.ResourceState
|
||||||
diff *terraform.ResourceDiff
|
diff *terraform.ResourceDiff
|
||||||
set map[string]string
|
setMap map[string]string
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get returns the data for the given key, or nil if the key doesn't exist.
|
// Get returns the data for the given key, or nil if the key doesn't exist.
|
||||||
|
@ -36,8 +36,8 @@ func (d *ResourceData) Get(key string) interface{} {
|
||||||
// If the key is invalid or the value is not a correct type, an error
|
// If the key is invalid or the value is not a correct type, an error
|
||||||
// will be returned.
|
// will be returned.
|
||||||
func (d *ResourceData) Set(key string, value interface{}) error {
|
func (d *ResourceData) Set(key string, value interface{}) error {
|
||||||
if d.set == nil {
|
if d.setMap == nil {
|
||||||
d.set = make(map[string]string)
|
d.setMap = make(map[string]string)
|
||||||
}
|
}
|
||||||
|
|
||||||
parts := strings.Split(key, ".")
|
parts := strings.Split(key, ".")
|
||||||
|
@ -145,8 +145,8 @@ func (d *ResourceData) getPrimitive(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if d.set != nil {
|
if d.setMap != nil {
|
||||||
if v, ok := d.set[k]; ok {
|
if v, ok := d.setMap[k]; ok {
|
||||||
result = v
|
result = v
|
||||||
resultSet = true
|
resultSet = true
|
||||||
}
|
}
|
||||||
|
@ -176,6 +176,70 @@ func (d *ResourceData) getPrimitive(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *ResourceData) set(
|
||||||
|
k string,
|
||||||
|
parts []string,
|
||||||
|
schema *Schema,
|
||||||
|
value interface{}) error {
|
||||||
|
switch schema.Type {
|
||||||
|
case TypeList:
|
||||||
|
return d.setList(k, parts, schema, value)
|
||||||
|
default:
|
||||||
|
return d.setPrimitive(k, schema, value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *ResourceData) setList(
|
||||||
|
k string,
|
||||||
|
parts []string,
|
||||||
|
schema *Schema,
|
||||||
|
value interface{}) error {
|
||||||
|
if len(parts) > 0 {
|
||||||
|
// We're setting a specific element
|
||||||
|
idx := parts[0]
|
||||||
|
parts = parts[1:]
|
||||||
|
|
||||||
|
// Special case if we're accessing the count of the list
|
||||||
|
if idx == "#" {
|
||||||
|
return fmt.Errorf("%s: can't set count of list", k)
|
||||||
|
}
|
||||||
|
|
||||||
|
key := fmt.Sprintf("%s.%s", k, idx)
|
||||||
|
switch t := schema.Elem.(type) {
|
||||||
|
case *Resource:
|
||||||
|
return d.setObject(key, parts, t.Schema, value)
|
||||||
|
case *Schema:
|
||||||
|
return d.set(key, parts, t, value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var vs []interface{}
|
||||||
|
if err := mapstructure.Decode(value, &vs); err != nil {
|
||||||
|
return fmt.Errorf("%s: %s", k, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the entire list.
|
||||||
|
var err error
|
||||||
|
for i, elem := range vs {
|
||||||
|
is := strconv.FormatInt(int64(i), 10)
|
||||||
|
err = d.setList(k, []string{is}, schema, elem)
|
||||||
|
if err != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
for i, _ := range vs {
|
||||||
|
is := strconv.FormatInt(int64(i), 10)
|
||||||
|
d.setList(k, []string{is}, schema, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
d.setMap[k+".#"] = strconv.FormatInt(int64(len(vs)), 10)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (d *ResourceData) setObject(
|
func (d *ResourceData) setObject(
|
||||||
k string,
|
k string,
|
||||||
parts []string,
|
parts []string,
|
||||||
|
@ -197,16 +261,41 @@ func (d *ResourceData) setObject(
|
||||||
key = fmt.Sprintf("%s.%s", k, key)
|
key = fmt.Sprintf("%s.%s", k, key)
|
||||||
}
|
}
|
||||||
|
|
||||||
return d.setPrimitive(key, s, value)
|
return d.set(key, parts, s, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
panic("can't set full object yet")
|
// Set the entire object. First decode into a proper structure
|
||||||
|
var v map[string]interface{}
|
||||||
|
if err := mapstructure.Decode(value, &v); err != nil {
|
||||||
|
return fmt.Errorf("%s: %s", k, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set each element in turn
|
||||||
|
var err error
|
||||||
|
for k1, v1 := range v {
|
||||||
|
err = d.setObject(k, []string{k1}, schema, v1)
|
||||||
|
if err != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
for k1, _ := range v {
|
||||||
|
d.setObject(k, []string{k1}, schema, nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *ResourceData) setPrimitive(
|
func (d *ResourceData) setPrimitive(
|
||||||
k string,
|
k string,
|
||||||
schema *Schema,
|
schema *Schema,
|
||||||
v interface{}) error {
|
v interface{}) error {
|
||||||
|
if v == nil {
|
||||||
|
delete(d.setMap, k)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
var set string
|
var set string
|
||||||
switch schema.Type {
|
switch schema.Type {
|
||||||
case TypeString:
|
case TypeString:
|
||||||
|
@ -224,6 +313,6 @@ func (d *ResourceData) setPrimitive(
|
||||||
return fmt.Errorf("Unknown type: %s", schema.Type)
|
return fmt.Errorf("Unknown type: %s", schema.Type)
|
||||||
}
|
}
|
||||||
|
|
||||||
d.set[k] = set
|
d.setMap[k] = set
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -392,6 +392,210 @@ func TestResourceDataSet(t *testing.T) {
|
||||||
GetKey: "availability_zone",
|
GetKey: "availability_zone",
|
||||||
GetValue: nil,
|
GetValue: nil,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// List of primitives, set element
|
||||||
|
{
|
||||||
|
Schema: map[string]*Schema{
|
||||||
|
"ports": &Schema{
|
||||||
|
Type: TypeList,
|
||||||
|
Computed: true,
|
||||||
|
Elem: &Schema{Type: TypeInt},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
State: &terraform.ResourceState{
|
||||||
|
Attributes: map[string]string{
|
||||||
|
"ports.#": "3",
|
||||||
|
"ports.0": "1",
|
||||||
|
"ports.1": "2",
|
||||||
|
"ports.2": "5",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
Diff: nil,
|
||||||
|
|
||||||
|
Key: "ports.1",
|
||||||
|
Value: 3,
|
||||||
|
|
||||||
|
GetKey: "ports",
|
||||||
|
GetValue: []interface{}{1, 3, 5},
|
||||||
|
},
|
||||||
|
|
||||||
|
// List of primitives, set list
|
||||||
|
{
|
||||||
|
Schema: map[string]*Schema{
|
||||||
|
"ports": &Schema{
|
||||||
|
Type: TypeList,
|
||||||
|
Computed: true,
|
||||||
|
Elem: &Schema{Type: TypeInt},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
State: nil,
|
||||||
|
|
||||||
|
Diff: nil,
|
||||||
|
|
||||||
|
Key: "ports",
|
||||||
|
Value: []int{1, 2, 5},
|
||||||
|
|
||||||
|
GetKey: "ports",
|
||||||
|
GetValue: []interface{}{1, 2, 5},
|
||||||
|
},
|
||||||
|
|
||||||
|
// List of primitives, set list with error
|
||||||
|
{
|
||||||
|
Schema: map[string]*Schema{
|
||||||
|
"ports": &Schema{
|
||||||
|
Type: TypeList,
|
||||||
|
Computed: true,
|
||||||
|
Elem: &Schema{Type: TypeInt},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
State: nil,
|
||||||
|
|
||||||
|
Diff: nil,
|
||||||
|
|
||||||
|
Key: "ports",
|
||||||
|
Value: []interface{}{1, "NOPE", 5},
|
||||||
|
Err: true,
|
||||||
|
|
||||||
|
GetKey: "ports",
|
||||||
|
GetValue: []interface{}{},
|
||||||
|
},
|
||||||
|
|
||||||
|
// List of resource, set element
|
||||||
|
{
|
||||||
|
Schema: map[string]*Schema{
|
||||||
|
"ingress": &Schema{
|
||||||
|
Type: TypeList,
|
||||||
|
Computed: true,
|
||||||
|
Elem: &Resource{
|
||||||
|
Schema: map[string]*Schema{
|
||||||
|
"from": &Schema{
|
||||||
|
Type: TypeInt,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
State: &terraform.ResourceState{
|
||||||
|
Attributes: map[string]string{
|
||||||
|
"ingress.#": "2",
|
||||||
|
"ingress.0.from": "80",
|
||||||
|
"ingress.1.from": "8080",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
Diff: nil,
|
||||||
|
|
||||||
|
Key: "ingress.1.from",
|
||||||
|
Value: 9000,
|
||||||
|
|
||||||
|
GetKey: "ingress",
|
||||||
|
GetValue: []interface{}{
|
||||||
|
map[string]interface{}{
|
||||||
|
"from": 80,
|
||||||
|
},
|
||||||
|
map[string]interface{}{
|
||||||
|
"from": 9000,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
// List of resource, set full resource element
|
||||||
|
{
|
||||||
|
Schema: map[string]*Schema{
|
||||||
|
"ingress": &Schema{
|
||||||
|
Type: TypeList,
|
||||||
|
Computed: true,
|
||||||
|
Elem: &Resource{
|
||||||
|
Schema: map[string]*Schema{
|
||||||
|
"from": &Schema{
|
||||||
|
Type: TypeInt,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
State: &terraform.ResourceState{
|
||||||
|
Attributes: map[string]string{
|
||||||
|
"ingress.#": "2",
|
||||||
|
"ingress.0.from": "80",
|
||||||
|
"ingress.1.from": "8080",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
Diff: nil,
|
||||||
|
|
||||||
|
Key: "ingress.1",
|
||||||
|
Value: map[string]interface{}{
|
||||||
|
"from": 9000,
|
||||||
|
},
|
||||||
|
|
||||||
|
GetKey: "ingress",
|
||||||
|
GetValue: []interface{}{
|
||||||
|
map[string]interface{}{
|
||||||
|
"from": 80,
|
||||||
|
},
|
||||||
|
map[string]interface{}{
|
||||||
|
"from": 9000,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
// List of resource, set full resource element, with error
|
||||||
|
{
|
||||||
|
Schema: map[string]*Schema{
|
||||||
|
"ingress": &Schema{
|
||||||
|
Type: TypeList,
|
||||||
|
Computed: true,
|
||||||
|
Elem: &Resource{
|
||||||
|
Schema: map[string]*Schema{
|
||||||
|
"from": &Schema{
|
||||||
|
Type: TypeInt,
|
||||||
|
},
|
||||||
|
"to": &Schema{
|
||||||
|
Type: TypeInt,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
State: &terraform.ResourceState{
|
||||||
|
Attributes: map[string]string{
|
||||||
|
"ingress.#": "2",
|
||||||
|
"ingress.0.from": "80",
|
||||||
|
"ingress.0.to": "10",
|
||||||
|
"ingress.1.from": "8080",
|
||||||
|
"ingress.1.to": "8080",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
Diff: nil,
|
||||||
|
|
||||||
|
Key: "ingress.1",
|
||||||
|
Value: map[string]interface{}{
|
||||||
|
"from": 9000,
|
||||||
|
"to": "bar",
|
||||||
|
},
|
||||||
|
Err: true,
|
||||||
|
|
||||||
|
GetKey: "ingress",
|
||||||
|
GetValue: []interface{}{
|
||||||
|
map[string]interface{}{
|
||||||
|
"from": 80,
|
||||||
|
"to": 10,
|
||||||
|
},
|
||||||
|
map[string]interface{}{
|
||||||
|
"from": 8080,
|
||||||
|
"to": 8080,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, tc := range cases {
|
for i, tc := range cases {
|
||||||
|
|
Loading…
Reference in New Issue