From 7b4feec57898bd15611da1e380ded71741ce11b7 Mon Sep 17 00:00:00 2001 From: aahel Date: Mon, 25 Sep 2023 16:56:48 +0530 Subject: [PATCH 1/9] added cas support for consul_keys resource --- consul/key_client.go | 13 +++++++++++++ consul/resource_consul_keys.go | 19 ++++++++++++++++--- 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/consul/key_client.go b/consul/key_client.go index 5817627d..b95f3705 100644 --- a/consul/key_client.go +++ b/consul/key_client.go @@ -75,6 +75,19 @@ func (c *keyClient) Put(path, value string, flags int) error { return nil } +func (c *keyClient) Cas(path, value string, flags int, cas int) (bool, error) { + log.Printf( + "[DEBUG] Setting key '%s' to '%v' with cas %d in %s", + path, value, cas, c.wOpts.Datacenter, + ) + pair := consulapi.KVPair{Key: path, Value: []byte(value), Flags: uint64(flags), ModifyIndex: uint64(cas)} + written, _, err := c.client.CAS(&pair, c.wOpts) + if err != nil { + return false, fmt.Errorf("failed to write Consul key '%s': %s", path, err) + } + return written, nil +} + func (c *keyClient) Delete(path string) error { log.Printf( "[DEBUG] Deleting key '%s' in %s", diff --git a/consul/resource_consul_keys.go b/consul/resource_consul_keys.go index 08ad1824..4a173471 100644 --- a/consul/resource_consul_keys.go +++ b/consul/resource_consul_keys.go @@ -70,7 +70,11 @@ func resourceConsulKeys() *schema.Resource { Optional: true, Default: 0, }, - + "cas": { + Type: schema.TypeInt, + Optional: true, + Default: -1, + }, "default": { Type: schema.TypeString, Optional: true, @@ -111,7 +115,6 @@ func resourceConsulKeys() *schema.Resource { func resourceConsulKeysCreateUpdate(d *schema.ResourceData, meta interface{}) error { keyClient := newKeyClient(d, meta) - if d.HasChange("key") { o, n := d.GetChange("key") if o == nil { @@ -154,7 +157,17 @@ func resourceConsulKeysCreateUpdate(d *schema.ResourceData, meta interface{}) er } flags := sub["flags"].(int) - + cas := sub["cas"].(int) + if cas != -1 { + written, err := keyClient.Cas(path, value, flags, cas) + if err != nil { + return err + } + if written { + addedPaths[path] = true + } + continue + } if err := keyClient.Put(path, value, flags); err != nil { return err } From d0ebad4eb6f94a22c00bd5fee6a8e4e3b0a9babd Mon Sep 17 00:00:00 2001 From: aahel Date: Tue, 26 Sep 2023 10:40:21 +0530 Subject: [PATCH 2/9] added cas test --- consul/resource_consul_keys_test.go | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/consul/resource_consul_keys_test.go b/consul/resource_consul_keys_test.go index 432c5cd1..e07404ab 100644 --- a/consul/resource_consul_keys_test.go +++ b/consul/resource_consul_keys_test.go @@ -26,7 +26,7 @@ func TestAccConsulKeys_basic(t *testing.T) { testAccCheckConsulKeysValue("consul_keys.app", "enabled", "true"), testAccCheckConsulKeysValue("consul_keys.app", "set", "acceptance"), testAccCheckConsulKeysValue("consul_keys.app", "remove_one", "hello"), - resource.TestCheckResourceAttr("consul_keys.app", "key.4258512057.flags", "0"), + resource.TestCheckResourceAttr("consul_keys.app", "key.3606807749.flags", "0"), ), }, { @@ -42,6 +42,20 @@ func TestAccConsulKeys_basic(t *testing.T) { }) } +func TestTestAccConsulKeys_Cas(t *testing.T) { + providers, _ := startTestServer(t) + + resource.Test(t, resource.TestCase{ + Providers: providers, + Steps: []resource.TestStep{ + { + Config: testAccConsulKeysConfig_Cas, + Check: resource.TestCheckResourceAttr("consul_keys.app", "key.2637474718.cas", "0"), + }, + }, + }) +} + func TestAccConsulKeys_EmptyValue(t *testing.T) { providers, client := startTestServer(t) @@ -286,3 +300,14 @@ resource "consul_keys" "dc2" { } } ` + +const testAccConsulKeysConfig_Cas = ` +resource "consul_keys" "app" { + datacenter = "dc1" + key { + path = "test/testKey" + value = "testVal" + cas = 0 + } +} +` From 18505f18867bd756db10f7f60ace951e0792085e Mon Sep 17 00:00:00 2001 From: aahel Date: Tue, 26 Sep 2023 10:43:55 +0530 Subject: [PATCH 3/9] fix typo --- consul/resource_consul_keys_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/consul/resource_consul_keys_test.go b/consul/resource_consul_keys_test.go index e07404ab..c87158a7 100644 --- a/consul/resource_consul_keys_test.go +++ b/consul/resource_consul_keys_test.go @@ -42,7 +42,7 @@ func TestAccConsulKeys_basic(t *testing.T) { }) } -func TestTestAccConsulKeys_Cas(t *testing.T) { +func TestAccConsulKeys_Cas(t *testing.T) { providers, _ := startTestServer(t) resource.Test(t, resource.TestCase{ From 593f7d6c4e54b8a90b0e11f4ad65587f615fd2fc Mon Sep 17 00:00:00 2001 From: aahel Date: Tue, 26 Sep 2023 12:18:43 +0530 Subject: [PATCH 4/9] fix test --- consul/resource_consul_keys_migrate_test.go | 24 +++++++++++---------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/consul/resource_consul_keys_migrate_test.go b/consul/resource_consul_keys_migrate_test.go index 4500c0d5..aad976e6 100644 --- a/consul/resource_consul_keys_migrate_test.go +++ b/consul/resource_consul_keys_migrate_test.go @@ -35,17 +35,19 @@ func TestConsulKeysMigrateState(t *testing.T) { }, Expected: map[string]string{ "key.#": "2", - "key.3630941097.default": "", - "key.3630941097.delete": "true", - "key.3630941097.name": "temp", - "key.3630941097.path": "foo/foo", - "key.3630941097.value": "", - "key.3975462262.path": "foo/bar", - "key.3975462262.default": "", - "key.3975462262.delete": "false", - "key.3975462262.name": "hello", - "key.3975462262.value": "world", - "key.3975462262.flags": "0", + "key.1529757638.default": "", + "key.1529757638.delete": "true", + "key.3609964659.name": "hello", + "key.1529757638.path": "foo/foo", + "key.1529757638.value": "", + "key.1529757638.flags": "0", + "key.1529757638.cas": "0", + "key.3609964659.path": "foo/bar", + "key.3609964659.default": "", + "key.3609964659.delete": "false", + "key.1529757638.name": "temp", + "key.3609964659.value": "world", + "key.3609964659.cas": "0", }, }, } From da5ab9634f9e7040c528213dd8b6cd8ff14e94fb Mon Sep 17 00:00:00 2001 From: aahel Date: Tue, 26 Sep 2023 12:23:48 +0530 Subject: [PATCH 5/9] added check value and path in cas test --- consul/resource_consul_keys_test.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/consul/resource_consul_keys_test.go b/consul/resource_consul_keys_test.go index c87158a7..277d22e9 100644 --- a/consul/resource_consul_keys_test.go +++ b/consul/resource_consul_keys_test.go @@ -50,7 +50,11 @@ func TestAccConsulKeys_Cas(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccConsulKeysConfig_Cas, - Check: resource.TestCheckResourceAttr("consul_keys.app", "key.2637474718.cas", "0"), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("consul_keys.app", "key.2637474718.value", "testVal"), + resource.TestCheckResourceAttr("consul_keys.app", "key.2637474718.path", "test/testKey"), + resource.TestCheckResourceAttr("consul_keys.app", "key.2637474718.cas", "0"), + ), }, }, }) From 89d56049b067dada422677425c52be523a966498 Mon Sep 17 00:00:00 2001 From: aahel Date: Tue, 26 Sep 2023 12:34:21 +0530 Subject: [PATCH 6/9] removed written check in cas --- consul/resource_consul_keys.go | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/consul/resource_consul_keys.go b/consul/resource_consul_keys.go index 4a173471..9506075e 100644 --- a/consul/resource_consul_keys.go +++ b/consul/resource_consul_keys.go @@ -159,13 +159,11 @@ func resourceConsulKeysCreateUpdate(d *schema.ResourceData, meta interface{}) er flags := sub["flags"].(int) cas := sub["cas"].(int) if cas != -1 { - written, err := keyClient.Cas(path, value, flags, cas) + _, err := keyClient.Cas(path, value, flags, cas) if err != nil { return err } - if written { - addedPaths[path] = true - } + addedPaths[path] = true continue } if err := keyClient.Put(path, value, flags); err != nil { From c32de386ed77aef31df75bbfcba5d070ef97d2d7 Mon Sep 17 00:00:00 2001 From: aahel Date: Tue, 26 Sep 2023 12:54:47 +0530 Subject: [PATCH 7/9] added cas for delete --- consul/key_client.go | 13 +++++++++++++ consul/resource_consul_keys.go | 11 +++++++++-- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/consul/key_client.go b/consul/key_client.go index b95f3705..22254f3e 100644 --- a/consul/key_client.go +++ b/consul/key_client.go @@ -88,6 +88,19 @@ func (c *keyClient) Cas(path, value string, flags int, cas int) (bool, error) { return written, nil } +func (c *keyClient) DeleteCas(path string, cas int) (bool, error) { + log.Printf( + "[DEBUG] Deleting key '%s' in %s with cas %d", + path, c.wOpts.Datacenter, cas, + ) + pair := consulapi.KVPair{Key: path, ModifyIndex: uint64(cas)} + written, _, err := c.client.DeleteCAS(&pair, c.wOpts) + if err != nil { + return false, fmt.Errorf("failed to delete Consul key '%s': %s", path, err) + } + return written, nil +} + func (c *keyClient) Delete(path string) error { log.Printf( "[DEBUG] Deleting key '%s' in %s", diff --git a/consul/resource_consul_keys.go b/consul/resource_consul_keys.go index 9506075e..7e984141 100644 --- a/consul/resource_consul_keys.go +++ b/consul/resource_consul_keys.go @@ -158,7 +158,7 @@ func resourceConsulKeysCreateUpdate(d *schema.ResourceData, meta interface{}) er flags := sub["flags"].(int) cas := sub["cas"].(int) - if cas != -1 { + if cas >= 0 { _, err := keyClient.Cas(path, value, flags, cas) if err != nil { return err @@ -273,7 +273,14 @@ func resourceConsulKeysDelete(d *schema.ResourceData, meta interface{}) error { if !ok || !shouldDelete { continue } - + cas := sub["cas"].(int) + if cas > 0 { + _, err := keyClient.DeleteCas(path, cas) + if err != nil { + return err + } + continue + } if err := keyClient.Delete(path); err != nil { return err } From a967c8a3cb2839f55f7a152724efa43cd0cfeccf Mon Sep 17 00:00:00 2001 From: aahel Date: Tue, 26 Sep 2023 14:14:57 +0530 Subject: [PATCH 8/9] removed caas from delete --- consul/key_client.go | 13 ------------- consul/resource_consul_keys.go | 8 -------- 2 files changed, 21 deletions(-) diff --git a/consul/key_client.go b/consul/key_client.go index 22254f3e..b95f3705 100644 --- a/consul/key_client.go +++ b/consul/key_client.go @@ -88,19 +88,6 @@ func (c *keyClient) Cas(path, value string, flags int, cas int) (bool, error) { return written, nil } -func (c *keyClient) DeleteCas(path string, cas int) (bool, error) { - log.Printf( - "[DEBUG] Deleting key '%s' in %s with cas %d", - path, c.wOpts.Datacenter, cas, - ) - pair := consulapi.KVPair{Key: path, ModifyIndex: uint64(cas)} - written, _, err := c.client.DeleteCAS(&pair, c.wOpts) - if err != nil { - return false, fmt.Errorf("failed to delete Consul key '%s': %s", path, err) - } - return written, nil -} - func (c *keyClient) Delete(path string) error { log.Printf( "[DEBUG] Deleting key '%s' in %s", diff --git a/consul/resource_consul_keys.go b/consul/resource_consul_keys.go index 7e984141..c3be47f9 100644 --- a/consul/resource_consul_keys.go +++ b/consul/resource_consul_keys.go @@ -273,14 +273,6 @@ func resourceConsulKeysDelete(d *schema.ResourceData, meta interface{}) error { if !ok || !shouldDelete { continue } - cas := sub["cas"].(int) - if cas > 0 { - _, err := keyClient.DeleteCas(path, cas) - if err != nil { - return err - } - continue - } if err := keyClient.Delete(path); err != nil { return err } From ad5356576f24c945cb0117721595d527cf983c43 Mon Sep 17 00:00:00 2001 From: aahel Date: Wed, 27 Sep 2023 15:33:09 +0530 Subject: [PATCH 9/9] exporting modify index from data source and added delete support for resource --- consul/data_source_consul_key_prefix.go | 2 +- consul/data_source_consul_keys.go | 6 ++++-- consul/key_client.go | 23 ++++++++++++++++++++--- consul/resource_consul_keys.go | 21 ++++++++++++++++++++- 4 files changed, 45 insertions(+), 7 deletions(-) diff --git a/consul/data_source_consul_key_prefix.go b/consul/data_source_consul_key_prefix.go index 670ca8ea..3ee4efe5 100644 --- a/consul/data_source_consul_key_prefix.go +++ b/consul/data_source_consul_key_prefix.go @@ -97,7 +97,7 @@ func dataSourceConsulKeyPrefixRead(d *schema.ResourceData, meta interface{}) err } fullPath := pathPrefix + path - value, _, err := keyClient.Get(fullPath) + value, _, _, err := keyClient.Get(fullPath) if err != nil { return err } diff --git a/consul/data_source_consul_keys.go b/consul/data_source_consul_keys.go index 56b29cb9..ec00ef5b 100644 --- a/consul/data_source_consul_keys.go +++ b/consul/data_source_consul_keys.go @@ -4,6 +4,8 @@ package consul import ( + "fmt" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" ) @@ -81,11 +83,11 @@ func dataSourceConsulKeysRead(d *schema.ResourceData, meta interface{}) error { return err } - value, _, err := keyClient.Get(path) + value, _, modifyInd, err := keyClient.Get(path) if err != nil { return err } - + vars[key+"_modifyindex"] = fmt.Sprint(modifyInd) value = attributeValue(sub, value) vars[key] = value } diff --git a/consul/key_client.go b/consul/key_client.go index b95f3705..23bf6189 100644 --- a/consul/key_client.go +++ b/consul/key_client.go @@ -29,14 +29,14 @@ func newKeyClient(d *schema.ResourceData, meta interface{}) *keyClient { } } -func (c *keyClient) Get(path string) (string, int, error) { +func (c *keyClient) Get(path string) (string, int, int, error) { log.Printf( "[DEBUG] Reading key '%s' in %s", path, c.qOpts.Datacenter, ) pair, _, err := c.client.Get(path, c.qOpts) if err != nil { - return "", 0, fmt.Errorf("failed to read Consul key '%s': %s", path, err) + return "", 0, 0, fmt.Errorf("failed to read Consul key '%s': %s", path, err) } value := "" if pair != nil { @@ -46,7 +46,11 @@ func (c *keyClient) Get(path string) (string, int, error) { if pair != nil { flags = int(pair.Flags) } - return value, flags, nil + modifyInd := 0 + if pair != nil { + modifyInd = int(pair.ModifyIndex) + } + return value, flags, modifyInd, nil } func (c *keyClient) GetUnderPrefix(pathPrefix string) (consulapi.KVPairs, error) { @@ -88,6 +92,19 @@ func (c *keyClient) Cas(path, value string, flags int, cas int) (bool, error) { return written, nil } +func (c *keyClient) DeleteCas(path string, cas int) (bool, error) { + log.Printf( + "[DEBUG] Deleting key '%s' in %s with cas %d", + path, c.wOpts.Datacenter, cas, + ) + pair := consulapi.KVPair{Key: path, ModifyIndex: uint64(cas)} + written, _, err := c.client.DeleteCAS(&pair, c.wOpts) + if err != nil { + return false, fmt.Errorf("failed to delete Consul key '%s': %s", path, err) + } + return written, nil +} + func (c *keyClient) Delete(path string) error { log.Printf( "[DEBUG] Deleting key '%s' in %s", diff --git a/consul/resource_consul_keys.go b/consul/resource_consul_keys.go index c3be47f9..247a6c9a 100644 --- a/consul/resource_consul_keys.go +++ b/consul/resource_consul_keys.go @@ -189,6 +189,15 @@ func resourceConsulKeysCreateUpdate(d *schema.ResourceData, meta interface{}) er continue } + cas := sub["cas"].(int) + if cas >= 0 { + _, err := keyClient.DeleteCas(path, cas) + if err != nil { + return err + } + continue + } + if err := keyClient.Delete(path); err != nil { return err } @@ -219,7 +228,7 @@ func resourceConsulKeysRead(d *schema.ResourceData, meta interface{}) error { return err } - value, flags, err := keyClient.Get(path) + value, flags, _, err := keyClient.Get(path) if err != nil { return err } @@ -273,6 +282,16 @@ func resourceConsulKeysDelete(d *schema.ResourceData, meta interface{}) error { if !ok || !shouldDelete { continue } + + cas := sub["cas"].(int) + if cas >= 0 { + _, err := keyClient.DeleteCas(path, cas) + if err != nil { + return err + } + continue + } + if err := keyClient.Delete(path); err != nil { return err }