From 9cf8f4823998bc346e94a14af49ad2d9a6bb0e38 Mon Sep 17 00:00:00 2001 From: James Bardin Date: Wed, 30 Jan 2019 16:10:17 -0500 Subject: [PATCH] decode legacy timeouts The new decoder is more precise, and unpacks the timeout block into a single map, which ResourceTimeout.ConfigDecode was updated to handle. We however still need to work with legacy versions of terraform, with the old decoder. --- helper/schema/provider_test.go | 44 +++++++++++++++++++++++++- helper/schema/resource_timeout.go | 30 ++++++++++++------ helper/schema/resource_timeout_test.go | 39 +++++++++++++++++++++++ 3 files changed, 103 insertions(+), 10 deletions(-) diff --git a/helper/schema/provider_test.go b/helper/schema/provider_test.go index bebe1f19b7..9c0d92bf32 100644 --- a/helper/schema/provider_test.go +++ b/helper/schema/provider_test.go @@ -278,7 +278,7 @@ func TestProviderValidate(t *testing.T) { } } -func TestProviderDiff_timeoutInvalidType(t *testing.T) { +func TestProviderDiff_legacyTimeoutType(t *testing.T) { p := &Provider{ ResourcesMap: map[string]*Resource{ "blah": &Resource{ @@ -308,6 +308,48 @@ func TestProviderDiff_timeoutInvalidType(t *testing.T) { t.Fatalf("err: %s", err) } + _, err = p.Diff( + &terraform.InstanceInfo{ + Type: "blah", + }, + nil, + terraform.NewResourceConfig(ic), + ) + if err != nil { + t.Fatal(err) + } +} + +func TestProviderDiff_invalidTimeoutType(t *testing.T) { + p := &Provider{ + ResourcesMap: map[string]*Resource{ + "blah": &Resource{ + Schema: map[string]*Schema{ + "foo": { + Type: TypeInt, + Optional: true, + }, + }, + Timeouts: &ResourceTimeout{ + Create: DefaultTimeout(10 * time.Minute), + }, + }, + }, + } + + invalidCfg := map[string]interface{}{ + "foo": 42, + "timeouts": []interface{}{ + map[string]interface{}{ + "create": "40m", + }, + }, + } + ic, err := config.NewRawConfig(invalidCfg) + if err != nil { + t.Fatalf("err: %s", err) + } + _, err = p.Diff( &terraform.InstanceInfo{ Type: "blah", diff --git a/helper/schema/resource_timeout.go b/helper/schema/resource_timeout.go index b7d63fafa5..9e422c1a6f 100644 --- a/helper/schema/resource_timeout.go +++ b/helper/schema/resource_timeout.go @@ -63,7 +63,27 @@ func (t *ResourceTimeout) ConfigDecode(s *Resource, c *terraform.ResourceConfig) } if raw, ok := c.Config[TimeoutsConfigKey]; ok { - if timeoutValues, ok := raw.(map[string]interface{}); ok { + var rawTimeouts []map[string]interface{} + switch raw := raw.(type) { + case map[string]interface{}: + rawTimeouts = append(rawTimeouts, raw) + case []map[string]interface{}: + rawTimeouts = raw + case string: + if raw == config.UnknownVariableValue { + // Timeout is not defined in the config + // Defaults will be used instead + return nil + } else { + log.Printf("[ERROR] Invalid timeout value: %q", raw) + return fmt.Errorf("Invalid Timeout value found") + } + default: + log.Printf("[ERROR] Invalid timeout structure: %#v", raw) + return fmt.Errorf("Invalid Timeout structure found") + } + + for _, timeoutValues := range rawTimeouts { for timeKey, timeValue := range timeoutValues { // validate that we're dealing with the normal CRUD actions var found bool @@ -108,14 +128,6 @@ func (t *ResourceTimeout) ConfigDecode(s *Resource, c *terraform.ResourceConfig) } return nil } - if v, ok := raw.(string); ok && v == config.UnknownVariableValue { - // Timeout is not defined in the config - // Defaults will be used instead - return nil - } - - log.Printf("[ERROR] Invalid timeout structure: %T", raw) - return fmt.Errorf("Invalid Timeout structure found") } return nil diff --git a/helper/schema/resource_timeout_test.go b/helper/schema/resource_timeout_test.go index f48ba883be..605cf327d5 100644 --- a/helper/schema/resource_timeout_test.go +++ b/helper/schema/resource_timeout_test.go @@ -129,6 +129,45 @@ func TestResourceTimeout_ConfigDecode(t *testing.T) { } } +func TestResourceTimeout_legacyConfigDecode(t *testing.T) { + r := &Resource{ + Timeouts: &ResourceTimeout{ + Create: DefaultTimeout(10 * time.Minute), + Update: DefaultTimeout(5 * time.Minute), + }, + } + + raw, err := config.NewRawConfig( + map[string]interface{}{ + "foo": "bar", + TimeoutsConfigKey: []map[string]interface{}{ + { + "create": "2m", + "update": "1m", + }, + }, + }) + if err != nil { + t.Fatalf("err: %s", err) + } + c := terraform.NewResourceConfig(raw) + + timeout := &ResourceTimeout{} + err = timeout.ConfigDecode(r, c) + if err != nil { + t.Fatalf("Expected good timeout returned:, %s", err) + } + + expected := &ResourceTimeout{ + Create: DefaultTimeout(2 * time.Minute), + Update: DefaultTimeout(1 * time.Minute), + } + + if !reflect.DeepEqual(timeout, expected) { + t.Fatalf("bad timeout decode.\nExpected:\n%#v\nGot:\n%#v\n", expected, timeout) + } +} + func TestResourceTimeout_DiffEncode_basic(t *testing.T) { cases := []struct { Timeout *ResourceTimeout