terraform: InstanceState.Meta is value type interface{}
This changes the type of values in Meta for InstanceState to `interface{}`. They were `string` before. This will allow richer structures to be persisted to this without flatmapping them (down with flatmap!). The documentation clearly states that only primitives/collections are allowed here. The only thing using this was helper/schema for schema versioning. Appropriate type checking was added to make this change safe. The timeout work @catsby is doing will use this for a richer structure.
This commit is contained in:
parent
9379ec9c60
commit
3342aa580c
|
@ -353,7 +353,7 @@ func (r *Resource) Data(s *terraform.InstanceState) *ResourceData {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the schema version to latest by default
|
// Set the schema version to latest by default
|
||||||
result.meta = map[string]string{
|
result.meta = map[string]interface{}{
|
||||||
"schema_version": strconv.Itoa(r.SchemaVersion),
|
"schema_version": strconv.Itoa(r.SchemaVersion),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -378,7 +378,22 @@ func (r *Resource) isTopLevel() bool {
|
||||||
// Determines if a given InstanceState needs to be migrated by checking the
|
// Determines if a given InstanceState needs to be migrated by checking the
|
||||||
// stored version number with the current SchemaVersion
|
// stored version number with the current SchemaVersion
|
||||||
func (r *Resource) checkSchemaVersion(is *terraform.InstanceState) (bool, int) {
|
func (r *Resource) checkSchemaVersion(is *terraform.InstanceState) (bool, int) {
|
||||||
stateSchemaVersion, _ := strconv.Atoi(is.Meta["schema_version"])
|
// Get the raw interface{} value for the schema version. If it doesn't
|
||||||
|
// exist or is nil then set it to zero.
|
||||||
|
raw := is.Meta["schema_version"]
|
||||||
|
if raw == nil {
|
||||||
|
raw = "0"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to convert it to a string. If it isn't a string then we pretend
|
||||||
|
// that it isn't set at all. It should never not be a string unless it
|
||||||
|
// was manually tampered with.
|
||||||
|
rawString, ok := raw.(string)
|
||||||
|
if !ok {
|
||||||
|
rawString = "0"
|
||||||
|
}
|
||||||
|
|
||||||
|
stateSchemaVersion, _ := strconv.Atoi(rawString)
|
||||||
return stateSchemaVersion < r.SchemaVersion, stateSchemaVersion
|
return stateSchemaVersion < r.SchemaVersion, stateSchemaVersion
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -386,7 +401,7 @@ func (r *Resource) recordCurrentSchemaVersion(
|
||||||
state *terraform.InstanceState) *terraform.InstanceState {
|
state *terraform.InstanceState) *terraform.InstanceState {
|
||||||
if state != nil && r.SchemaVersion > 0 {
|
if state != nil && r.SchemaVersion > 0 {
|
||||||
if state.Meta == nil {
|
if state.Meta == nil {
|
||||||
state.Meta = make(map[string]string)
|
state.Meta = make(map[string]interface{})
|
||||||
}
|
}
|
||||||
state.Meta["schema_version"] = strconv.Itoa(r.SchemaVersion)
|
state.Meta["schema_version"] = strconv.Itoa(r.SchemaVersion)
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,7 @@ type ResourceData struct {
|
||||||
config *terraform.ResourceConfig
|
config *terraform.ResourceConfig
|
||||||
state *terraform.InstanceState
|
state *terraform.InstanceState
|
||||||
diff *terraform.InstanceDiff
|
diff *terraform.InstanceDiff
|
||||||
meta map[string]string
|
meta map[string]interface{}
|
||||||
|
|
||||||
// Don't set
|
// Don't set
|
||||||
multiReader *MultiLevelFieldReader
|
multiReader *MultiLevelFieldReader
|
||||||
|
|
|
@ -52,7 +52,7 @@ func TestResourceApply_create(t *testing.T) {
|
||||||
"id": "foo",
|
"id": "foo",
|
||||||
"foo": "42",
|
"foo": "42",
|
||||||
},
|
},
|
||||||
Meta: map[string]string{
|
Meta: map[string]interface{}{
|
||||||
"schema_version": "2",
|
"schema_version": "2",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -210,7 +210,7 @@ func TestResourceApply_destroyPartial(t *testing.T) {
|
||||||
"id": "bar",
|
"id": "bar",
|
||||||
"foo": "42",
|
"foo": "42",
|
||||||
},
|
},
|
||||||
Meta: map[string]string{
|
Meta: map[string]interface{}{
|
||||||
"schema_version": "3",
|
"schema_version": "3",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -558,7 +558,7 @@ func TestResourceRefresh(t *testing.T) {
|
||||||
"id": "bar",
|
"id": "bar",
|
||||||
"foo": "13",
|
"foo": "13",
|
||||||
},
|
},
|
||||||
Meta: map[string]string{
|
Meta: map[string]interface{}{
|
||||||
"schema_version": "2",
|
"schema_version": "2",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -749,7 +749,7 @@ func TestResourceRefresh_needsMigration(t *testing.T) {
|
||||||
Attributes: map[string]string{
|
Attributes: map[string]string{
|
||||||
"oldfoo": "1.2",
|
"oldfoo": "1.2",
|
||||||
},
|
},
|
||||||
Meta: map[string]string{
|
Meta: map[string]interface{}{
|
||||||
"schema_version": "1",
|
"schema_version": "1",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -765,7 +765,7 @@ func TestResourceRefresh_needsMigration(t *testing.T) {
|
||||||
"id": "bar",
|
"id": "bar",
|
||||||
"newfoo": "13",
|
"newfoo": "13",
|
||||||
},
|
},
|
||||||
Meta: map[string]string{
|
Meta: map[string]interface{}{
|
||||||
"schema_version": "2",
|
"schema_version": "2",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -803,7 +803,7 @@ func TestResourceRefresh_noMigrationNeeded(t *testing.T) {
|
||||||
Attributes: map[string]string{
|
Attributes: map[string]string{
|
||||||
"newfoo": "12",
|
"newfoo": "12",
|
||||||
},
|
},
|
||||||
Meta: map[string]string{
|
Meta: map[string]interface{}{
|
||||||
"schema_version": "2",
|
"schema_version": "2",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -819,7 +819,7 @@ func TestResourceRefresh_noMigrationNeeded(t *testing.T) {
|
||||||
"id": "bar",
|
"id": "bar",
|
||||||
"newfoo": "13",
|
"newfoo": "13",
|
||||||
},
|
},
|
||||||
Meta: map[string]string{
|
Meta: map[string]interface{}{
|
||||||
"schema_version": "2",
|
"schema_version": "2",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -871,7 +871,7 @@ func TestResourceRefresh_stateSchemaVersionUnset(t *testing.T) {
|
||||||
"id": "bar",
|
"id": "bar",
|
||||||
"newfoo": "13",
|
"newfoo": "13",
|
||||||
},
|
},
|
||||||
Meta: map[string]string{
|
Meta: map[string]interface{}{
|
||||||
"schema_version": "1",
|
"schema_version": "1",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -945,7 +945,7 @@ func TestResourceData(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set expectations
|
// Set expectations
|
||||||
state.Meta = map[string]string{
|
state.Meta = map[string]interface{}{
|
||||||
"schema_version": "2",
|
"schema_version": "2",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1541,8 +1541,9 @@ type InstanceState struct {
|
||||||
|
|
||||||
// Meta is a simple K/V map that is persisted to the State but otherwise
|
// Meta is a simple K/V map that is persisted to the State but otherwise
|
||||||
// ignored by Terraform core. It's meant to be used for accounting by
|
// ignored by Terraform core. It's meant to be used for accounting by
|
||||||
// external client code.
|
// external client code. The value here must only contain Go primitives
|
||||||
Meta map[string]string `json:"meta"`
|
// and collections.
|
||||||
|
Meta map[string]interface{} `json:"meta"`
|
||||||
|
|
||||||
// Tainted is used to mark a resource for recreation.
|
// Tainted is used to mark a resource for recreation.
|
||||||
Tainted bool `json:"tainted"`
|
Tainted bool `json:"tainted"`
|
||||||
|
@ -1561,7 +1562,7 @@ func (s *InstanceState) init() {
|
||||||
s.Attributes = make(map[string]string)
|
s.Attributes = make(map[string]string)
|
||||||
}
|
}
|
||||||
if s.Meta == nil {
|
if s.Meta == nil {
|
||||||
s.Meta = make(map[string]string)
|
s.Meta = make(map[string]interface{})
|
||||||
}
|
}
|
||||||
s.Ephemeral.init()
|
s.Ephemeral.init()
|
||||||
}
|
}
|
||||||
|
|
|
@ -278,7 +278,7 @@ func TestStateDeepCopy(t *testing.T) {
|
||||||
Resources: map[string]*ResourceState{
|
Resources: map[string]*ResourceState{
|
||||||
"test_instance.foo": &ResourceState{
|
"test_instance.foo": &ResourceState{
|
||||||
Primary: &InstanceState{
|
Primary: &InstanceState{
|
||||||
Meta: map[string]string{},
|
Meta: map[string]interface{}{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -298,7 +298,7 @@ func TestStateDeepCopy(t *testing.T) {
|
||||||
Resources: map[string]*ResourceState{
|
Resources: map[string]*ResourceState{
|
||||||
"test_instance.foo": &ResourceState{
|
"test_instance.foo": &ResourceState{
|
||||||
Primary: &InstanceState{
|
Primary: &InstanceState{
|
||||||
Meta: map[string]string{},
|
Meta: map[string]interface{}{},
|
||||||
},
|
},
|
||||||
Deposed: []*InstanceState{
|
Deposed: []*InstanceState{
|
||||||
{ID: "test"},
|
{ID: "test"},
|
||||||
|
@ -389,7 +389,7 @@ func TestStateEqual(t *testing.T) {
|
||||||
Resources: map[string]*ResourceState{
|
Resources: map[string]*ResourceState{
|
||||||
"test_instance.foo": &ResourceState{
|
"test_instance.foo": &ResourceState{
|
||||||
Primary: &InstanceState{
|
Primary: &InstanceState{
|
||||||
Meta: map[string]string{
|
Meta: map[string]interface{}{
|
||||||
"schema_version": "1",
|
"schema_version": "1",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -405,7 +405,7 @@ func TestStateEqual(t *testing.T) {
|
||||||
Resources: map[string]*ResourceState{
|
Resources: map[string]*ResourceState{
|
||||||
"test_instance.foo": &ResourceState{
|
"test_instance.foo": &ResourceState{
|
||||||
Primary: &InstanceState{
|
Primary: &InstanceState{
|
||||||
Meta: map[string]string{
|
Meta: map[string]interface{}{
|
||||||
"schema_version": "2",
|
"schema_version": "2",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -610,7 +610,7 @@ func TestStateIncrementSerialMaybe(t *testing.T) {
|
||||||
Resources: map[string]*ResourceState{
|
Resources: map[string]*ResourceState{
|
||||||
"test_instance.foo": &ResourceState{
|
"test_instance.foo": &ResourceState{
|
||||||
Primary: &InstanceState{
|
Primary: &InstanceState{
|
||||||
Meta: map[string]string{},
|
Meta: map[string]interface{}{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -625,7 +625,7 @@ func TestStateIncrementSerialMaybe(t *testing.T) {
|
||||||
Resources: map[string]*ResourceState{
|
Resources: map[string]*ResourceState{
|
||||||
"test_instance.foo": &ResourceState{
|
"test_instance.foo": &ResourceState{
|
||||||
Primary: &InstanceState{
|
Primary: &InstanceState{
|
||||||
Meta: map[string]string{
|
Meta: map[string]interface{}{
|
||||||
"schema_version": "1",
|
"schema_version": "1",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -150,16 +150,22 @@ func (old *instanceStateV1) upgradeToV2() (*InstanceState, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("Error upgrading InstanceState V1: %v", err)
|
return nil, fmt.Errorf("Error upgrading InstanceState V1: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
meta, err := copystructure.Copy(old.Meta)
|
meta, err := copystructure.Copy(old.Meta)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("Error upgrading InstanceState V1: %v", err)
|
return nil, fmt.Errorf("Error upgrading InstanceState V1: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
newMeta := make(map[string]interface{})
|
||||||
|
for k, v := range meta.(map[string]string) {
|
||||||
|
newMeta[k] = v
|
||||||
|
}
|
||||||
|
|
||||||
return &InstanceState{
|
return &InstanceState{
|
||||||
ID: old.ID,
|
ID: old.ID,
|
||||||
Attributes: attributes.(map[string]string),
|
Attributes: attributes.(map[string]string),
|
||||||
Ephemeral: *ephemeral,
|
Ephemeral: *ephemeral,
|
||||||
Meta: meta.(map[string]string),
|
Meta: newMeta,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue