From d9e111e03bdefe35b86d6262fe2e83e9ac70c949 Mon Sep 17 00:00:00 2001 From: N3uR0TiCV0iD Date: Sun, 6 Aug 2023 18:11:35 +0200 Subject: [PATCH 1/2] Fix parsing of names & vhosts containing "@" symbols. --- rabbitmq/data_source_exchange.go | 3 +- rabbitmq/resource_exchange.go | 6 ++-- rabbitmq/resource_federation_upstream.go | 8 +++--- rabbitmq/resource_operator_policy.go | 9 +++--- rabbitmq/resource_permissions.go | 8 +++--- rabbitmq/resource_policy.go | 8 +++--- rabbitmq/resource_queue.go | 6 ++-- rabbitmq/resource_shovel.go | 17 ++++++------ rabbitmq/resource_topic_permissions.go | 8 +++--- rabbitmq/util.go | 35 +++++++++++++++++++----- 10 files changed, 64 insertions(+), 44 deletions(-) diff --git a/rabbitmq/data_source_exchange.go b/rabbitmq/data_source_exchange.go index c3a9005f..17ee53f6 100644 --- a/rabbitmq/data_source_exchange.go +++ b/rabbitmq/data_source_exchange.go @@ -2,7 +2,6 @@ package rabbitmq import ( "context" - "fmt" "log" rabbithole "github.com/michaelklishin/rabbit-hole/v2" @@ -68,7 +67,7 @@ func dataSourcesReadExchange(ctx context.Context, d *schema.ResourceData, meta i name := d.Get("name").(string) vhost := d.Get("vhost").(string) - id := fmt.Sprintf("%s@%s", name, vhost) + id := buildVHostResourceId(name, vhost) exchangeSettings, err := rmqc.GetExchange(vhost, name) if err != nil { diff --git a/rabbitmq/resource_exchange.go b/rabbitmq/resource_exchange.go index 6ff4f16d..0265dd9c 100644 --- a/rabbitmq/resource_exchange.go +++ b/rabbitmq/resource_exchange.go @@ -83,7 +83,7 @@ func CreateExchange(d *schema.ResourceData, meta interface{}) error { return err } - id := fmt.Sprintf("%s@%s", name, vhost) + id := buildVHostResourceId(name, vhost) d.SetId(id) return ReadExchange(d, meta) @@ -92,7 +92,7 @@ func CreateExchange(d *schema.ResourceData, meta interface{}) error { func ReadExchange(d *schema.ResourceData, meta interface{}) error { rmqc := meta.(*rabbithole.Client) - name, vhost, err := parseResourceId(d) + name, vhost, err := parseVHostResourceId(d) if err != nil { return err } @@ -122,7 +122,7 @@ func ReadExchange(d *schema.ResourceData, meta interface{}) error { func DeleteExchange(d *schema.ResourceData, meta interface{}) error { rmqc := meta.(*rabbithole.Client) - name, vhost, err := parseResourceId(d) + name, vhost, err := parseVHostResourceId(d) if err != nil { return err } diff --git a/rabbitmq/resource_federation_upstream.go b/rabbitmq/resource_federation_upstream.go index 8a42feec..d8a26dd2 100644 --- a/rabbitmq/resource_federation_upstream.go +++ b/rabbitmq/resource_federation_upstream.go @@ -128,7 +128,7 @@ func CreateFederationUpstream(d *schema.ResourceData, meta interface{}) error { return err } - id := fmt.Sprintf("%s@%s", name, vhost) + id := buildVHostResourceId(name, vhost) d.SetId(id) return ReadFederationUpstream(d, meta) @@ -137,7 +137,7 @@ func CreateFederationUpstream(d *schema.ResourceData, meta interface{}) error { func ReadFederationUpstream(d *schema.ResourceData, meta interface{}) error { rmqc := meta.(*rabbithole.Client) - name, vhost, err := parseResourceId(d) + name, vhost, err := parseVHostResourceId(d) if err != nil { return err } @@ -179,7 +179,7 @@ func ReadFederationUpstream(d *schema.ResourceData, meta interface{}) error { func UpdateFederationUpstream(d *schema.ResourceData, meta interface{}) error { rmqc := meta.(*rabbithole.Client) - name, vhost, err := parseResourceId(d) + name, vhost, err := parseVHostResourceId(d) if err != nil { return err } @@ -204,7 +204,7 @@ func UpdateFederationUpstream(d *schema.ResourceData, meta interface{}) error { func DeleteFederationUpstream(d *schema.ResourceData, meta interface{}) error { rmqc := meta.(*rabbithole.Client) - name, vhost, err := parseResourceId(d) + name, vhost, err := parseVHostResourceId(d) if err != nil { return err } diff --git a/rabbitmq/resource_operator_policy.go b/rabbitmq/resource_operator_policy.go index 60b1785c..b7ef7473 100644 --- a/rabbitmq/resource_operator_policy.go +++ b/rabbitmq/resource_operator_policy.go @@ -82,7 +82,8 @@ func CreateOperatorPolicy(d *schema.ResourceData, meta interface{}) error { return err } - d.SetId(fmt.Sprintf("%s@%s", name, vhost)) + id := buildVHostResourceId(name, vhost) + d.SetId(id) return ReadOperatorPolicy(d, meta) } @@ -90,7 +91,7 @@ func CreateOperatorPolicy(d *schema.ResourceData, meta interface{}) error { func ReadOperatorPolicy(d *schema.ResourceData, meta interface{}) error { rmqc := meta.(*rabbithole.Client) - name, vhost, err := parseResourceId(d) + name, vhost, err := parseVHostResourceId(d) if err != nil { return err } @@ -138,7 +139,7 @@ func ReadOperatorPolicy(d *schema.ResourceData, meta interface{}) error { func UpdateOperatorPolicy(d *schema.ResourceData, meta interface{}) error { rmqc := meta.(*rabbithole.Client) - name, vhost, err := parseResourceId(d) + name, vhost, err := parseVHostResourceId(d) if err != nil { return err } @@ -163,7 +164,7 @@ func UpdateOperatorPolicy(d *schema.ResourceData, meta interface{}) error { func DeleteOperatorPolicy(d *schema.ResourceData, meta interface{}) error { rmqc := meta.(*rabbithole.Client) - name, vhost, err := parseResourceId(d) + name, vhost, err := parseVHostResourceId(d) if err != nil { return err } diff --git a/rabbitmq/resource_permissions.go b/rabbitmq/resource_permissions.go index 6b2800d6..f3771a8f 100644 --- a/rabbitmq/resource_permissions.go +++ b/rabbitmq/resource_permissions.go @@ -76,7 +76,7 @@ func CreatePermissions(d *schema.ResourceData, meta interface{}) error { return err } - id := fmt.Sprintf("%s@%s", user, vhost) + id := buildVHostResourceId(user, vhost) d.SetId(id) return ReadPermissions(d, meta) @@ -85,7 +85,7 @@ func CreatePermissions(d *schema.ResourceData, meta interface{}) error { func ReadPermissions(d *schema.ResourceData, meta interface{}) error { rmqc := meta.(*rabbithole.Client) - user, vhost, err := parseResourceId(d) + user, vhost, err := parseVHostResourceId(d) if err != nil { return err } @@ -114,7 +114,7 @@ func ReadPermissions(d *schema.ResourceData, meta interface{}) error { func UpdatePermissions(d *schema.ResourceData, meta interface{}) error { rmqc := meta.(*rabbithole.Client) - user, vhost, err := parseResourceId(d) + user, vhost, err := parseVHostResourceId(d) if err != nil { return err } @@ -139,7 +139,7 @@ func UpdatePermissions(d *schema.ResourceData, meta interface{}) error { func DeletePermissions(d *schema.ResourceData, meta interface{}) error { rmqc := meta.(*rabbithole.Client) - user, vhost, err := parseResourceId(d) + user, vhost, err := parseVHostResourceId(d) if err != nil { return err } diff --git a/rabbitmq/resource_policy.go b/rabbitmq/resource_policy.go index 208106c1..6294d56e 100644 --- a/rabbitmq/resource_policy.go +++ b/rabbitmq/resource_policy.go @@ -82,7 +82,7 @@ func CreatePolicy(d *schema.ResourceData, meta interface{}) error { return err } - id := fmt.Sprintf("%s@%s", name, vhost) + id := buildVHostResourceId(name, vhost) d.SetId(id) return ReadPolicy(d, meta) @@ -91,7 +91,7 @@ func CreatePolicy(d *schema.ResourceData, meta interface{}) error { func ReadPolicy(d *schema.ResourceData, meta interface{}) error { rmqc := meta.(*rabbithole.Client) - name, vhost, err := parseResourceId(d) + name, vhost, err := parseVHostResourceId(d) if err != nil { return err } @@ -139,7 +139,7 @@ func ReadPolicy(d *schema.ResourceData, meta interface{}) error { func UpdatePolicy(d *schema.ResourceData, meta interface{}) error { rmqc := meta.(*rabbithole.Client) - name, vhost, err := parseResourceId(d) + name, vhost, err := parseVHostResourceId(d) if err != nil { return err } @@ -164,7 +164,7 @@ func UpdatePolicy(d *schema.ResourceData, meta interface{}) error { func DeletePolicy(d *schema.ResourceData, meta interface{}) error { rmqc := meta.(*rabbithole.Client) - name, vhost, err := parseResourceId(d) + name, vhost, err := parseVHostResourceId(d) if err != nil { return err } diff --git a/rabbitmq/resource_queue.go b/rabbitmq/resource_queue.go index 86bfcc63..3e39ee77 100644 --- a/rabbitmq/resource_queue.go +++ b/rabbitmq/resource_queue.go @@ -106,7 +106,7 @@ func CreateQueue(d *schema.ResourceData, meta interface{}) error { return err } - id := fmt.Sprintf("%s@%s", name, vhost) + id := buildVHostResourceId(name, vhost) d.SetId(id) return ReadQueue(d, meta) @@ -115,7 +115,7 @@ func CreateQueue(d *schema.ResourceData, meta interface{}) error { func ReadQueue(d *schema.ResourceData, meta interface{}) error { rmqc := meta.(*rabbithole.Client) - name, vhost, err := parseResourceId(d) + name, vhost, err := parseVHostResourceId(d) if err != nil { return err } @@ -161,7 +161,7 @@ func ReadQueue(d *schema.ResourceData, meta interface{}) error { func DeleteQueue(d *schema.ResourceData, meta interface{}) error { rmqc := meta.(*rabbithole.Client) - name, vhost, err := parseResourceId(d) + name, vhost, err := parseVHostResourceId(d) if err != nil { return err } diff --git a/rabbitmq/resource_shovel.go b/rabbitmq/resource_shovel.go index 59297b30..658dbeb2 100644 --- a/rabbitmq/resource_shovel.go +++ b/rabbitmq/resource_shovel.go @@ -203,8 +203,8 @@ func resourceShovel() *schema.Resource { func CreateShovel(d *schema.ResourceData, meta interface{}) error { rmqc := meta.(*rabbithole.Client) + name := d.Get("name").(string) vhost := d.Get("vhost").(string) - shovelName := d.Get("name").(string) shovelInfo := d.Get("info").([]interface{}) shovelMap, ok := shovelInfo[0].(map[string]interface{}) @@ -214,16 +214,15 @@ func CreateShovel(d *schema.ResourceData, meta interface{}) error { shovelDefinition := setShovelDefinition(shovelMap).(rabbithole.ShovelDefinition) - log.Printf("[DEBUG] RabbitMQ: Attempting to declare shovel %s in vhost %s", shovelName, vhost) - resp, err := rmqc.DeclareShovel(vhost, shovelName, shovelDefinition) + log.Printf("[DEBUG] RabbitMQ: Attempting to declare shovel %s in vhost %s", name, vhost) + resp, err := rmqc.DeclareShovel(vhost, name, shovelDefinition) log.Printf("[DEBUG] RabbitMQ: shovel declartion response: %#v", resp) if err != nil { return err } - shovelId := fmt.Sprintf("%s@%s", shovelName, vhost) - - d.SetId(shovelId) + id := buildVHostResourceId(name, vhost) + d.SetId(id) return ReadShovel(d, meta) } @@ -231,7 +230,7 @@ func CreateShovel(d *schema.ResourceData, meta interface{}) error { func ReadShovel(d *schema.ResourceData, meta interface{}) error { rmqc := meta.(*rabbithole.Client) - name, vhost, err := parseResourceId(d) + name, vhost, err := parseVHostResourceId(d) if err != nil { return err } @@ -283,7 +282,7 @@ func ReadShovel(d *schema.ResourceData, meta interface{}) error { func UpdateShovel(d *schema.ResourceData, meta interface{}) error { rmqc := meta.(*rabbithole.Client) - name, vhost, err := parseResourceId(d) + name, vhost, err := parseVHostResourceId(d) if err != nil { return err } @@ -312,7 +311,7 @@ func UpdateShovel(d *schema.ResourceData, meta interface{}) error { func DeleteShovel(d *schema.ResourceData, meta interface{}) error { rmqc := meta.(*rabbithole.Client) - name, vhost, err := parseResourceId(d) + name, vhost, err := parseVHostResourceId(d) if err != nil { return err } diff --git a/rabbitmq/resource_topic_permissions.go b/rabbitmq/resource_topic_permissions.go index 7da80f0c..2ce97198 100644 --- a/rabbitmq/resource_topic_permissions.go +++ b/rabbitmq/resource_topic_permissions.go @@ -80,7 +80,7 @@ func CreateTopicPermissions(d *schema.ResourceData, meta interface{}) error { } } - id := fmt.Sprintf("%s@%s", user, vhost) + id := buildVHostResourceId(user, vhost) d.SetId(id) return ReadTopicPermissions(d, meta) @@ -90,7 +90,7 @@ func CreateTopicPermissions(d *schema.ResourceData, meta interface{}) error { func ReadTopicPermissions(d *schema.ResourceData, meta interface{}) error { rmqc := meta.(*rabbithole.Client) - user, vhost, err := parseResourceId(d) + user, vhost, err := parseVHostResourceId(d) if err != nil { return err } @@ -122,7 +122,7 @@ func ReadTopicPermissions(d *schema.ResourceData, meta interface{}) error { func UpdateTopicPermissions(d *schema.ResourceData, meta interface{}) error { rmqc := meta.(*rabbithole.Client) - user, vhost, err := parseResourceId(d) + user, vhost, err := parseVHostResourceId(d) if err != nil { return err } @@ -153,7 +153,7 @@ func UpdateTopicPermissions(d *schema.ResourceData, meta interface{}) error { func DeleteTopicPermissions(d *schema.ResourceData, meta interface{}) error { rmqc := meta.(*rabbithole.Client) - user, vhost, err := parseResourceId(d) + user, vhost, err := parseVHostResourceId(d) if err != nil { return err } diff --git a/rabbitmq/util.go b/rabbitmq/util.go index 8006c5de..eab46fc0 100644 --- a/rabbitmq/util.go +++ b/rabbitmq/util.go @@ -35,19 +35,40 @@ func percentDecodeSlashes(s string) string { return strings.Replace(strings.Replace(s, "%2F", "/", -1), "%25", "%", -1) } -// get the id of the resource from the ResourceData -func parseResourceId(d *schema.ResourceData) (name, vhost string, err error) { - return parseId(d.Id()) +// Builds a combined resource id using a percent encoded name and vhost. +func buildVHostResourceId(name, vhost string) string { + id := fmt.Sprintf("%s@%s", percentEncodeAtSymbols(name), percentEncodeAtSymbols(vhost)) + return id } -// get the resource name and rabbitmq vhost from the resource id -func parseId(resourceId string) (name, vhost string, err error) { +// Get the resource name and rabbitmq vhost from the ResourceData. +func parseVHostResourceId(d *schema.ResourceData) (name, vhost string, err error) { + return parseVHostResourceIdString(d.Id()) +} + +// Get the resource name and rabbitmq vhost from the resource id. +func parseVHostResourceIdString(resourceId string) (name, vhost string, err error) { parts := strings.Split(resourceId, "@") if len(parts) != 2 { err = fmt.Errorf("Unable to parse resource id: %s", resourceId) return } - name = parts[0] - vhost = parts[1] + name = percentDecodeAtSymbols(parts[0]) + vhost = percentDecodeAtSymbols(parts[1]) return } + +// Because the @ symbol is used to separate the name & vhost components when building a "vhost resource id", +// we need a way to ensure that any @ symbol within the components can survive the round trip. +// Percent-encoding is a straightforward way of doing so. +// (reference: https://developer.mozilla.org/en-US/docs/Glossary/percent-encoding) + +func percentEncodeAtSymbols(s string) string { + // Encode any percent signs, then encode any @ symbols. + return strings.Replace(strings.Replace(s, "%", "%25", -1), "@", "%40", -1) +} + +func percentDecodeAtSymbols(s string) string { + // Decode any @ symbols, then decode any percent signs. + return strings.Replace(strings.Replace(s, "%40", "@", -1), "%25", "%", -1) +} From b481b71b3299f2b212f1fdac2d80267e2f6504b3 Mon Sep 17 00:00:00 2001 From: N3uR0TiCV0iD Date: Sun, 6 Aug 2023 18:11:49 +0200 Subject: [PATCH 2/2] Extend tests for names & vhosts containing "@" symbols. --- rabbitmq/resource_exchange_test.go | 51 +++++++++++++++++-- rabbitmq/resource_federation_upstream_test.go | 5 +- rabbitmq/resource_operator_policy_test.go | 5 +- rabbitmq/resource_permissions_test.go | 47 +++++++++++++++-- rabbitmq/resource_policy_test.go | 5 +- rabbitmq/resource_queue_test.go | 47 +++++++++++++++-- rabbitmq/resource_shovel_test.go | 5 +- rabbitmq/resource_topic_permissions_test.go | 5 +- rabbitmq/util_test.go | 9 ++-- 9 files changed, 147 insertions(+), 32 deletions(-) diff --git a/rabbitmq/resource_exchange_test.go b/rabbitmq/resource_exchange_test.go index 6b3a6a90..0c4fa1c3 100644 --- a/rabbitmq/resource_exchange_test.go +++ b/rabbitmq/resource_exchange_test.go @@ -2,7 +2,6 @@ package rabbitmq import ( "fmt" - "strings" "testing" rabbithole "github.com/michaelklishin/rabbit-hole/v2" @@ -11,7 +10,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" ) -func TestAccExchange(t *testing.T) { +func TestAccExchange_basic(t *testing.T) { var exchangeInfo rabbithole.ExchangeInfo resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -28,6 +27,23 @@ func TestAccExchange(t *testing.T) { }) } +func TestAccExchange_atSymbolEscaping(t *testing.T) { + var exchangeInfo rabbithole.ExchangeInfo + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccExchangeCheckDestroy(&exchangeInfo), + Steps: []resource.TestStep{ + { + Config: testAccExchangeConfig_atSymbolsAreOk, + Check: testAccExchangeCheck( + "rabbitmq_exchange.test", &exchangeInfo, + ), + }, + }, + }) +} + func testAccExchangeCheck(rn string, exchangeInfo *rabbithole.ExchangeInfo) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[rn] @@ -40,15 +56,15 @@ func testAccExchangeCheck(rn string, exchangeInfo *rabbithole.ExchangeInfo) reso } rmqc := testAccProvider.Meta().(*rabbithole.Client) - exchParts := strings.Split(rs.Primary.ID, "@") + name, vhost, err := parseVHostResourceIdString(rs.Primary.ID) - exchanges, err := rmqc.ListExchangesIn(exchParts[1]) + exchanges, err := rmqc.ListExchangesIn(vhost) if err != nil { return fmt.Errorf("Error retrieving exchange: %s", err) } for _, exchange := range exchanges { - if exchange.Name == exchParts[0] && exchange.Vhost == exchParts[1] { + if exchange.Name == name && exchange.Vhost == vhost { exchangeInfo = &exchange return nil } @@ -101,3 +117,28 @@ resource "rabbitmq_exchange" "test" { auto_delete = true } }` + +const testAccExchangeConfig_atSymbolsAreOk = ` +resource "rabbitmq_vhost" "test" { + name = "foo@test" +} + +resource "rabbitmq_permissions" "guest" { + user = "guest" + vhost = "${rabbitmq_vhost.test.name}" + permissions { + configure = ".*" + write = ".*" + read = ".*" + } +} + +resource "rabbitmq_exchange" "test" { + name = "bar@exchange" + vhost = "${rabbitmq_permissions.guest.vhost}" + settings { + type = "fanout" + durable = false + auto_delete = true + } +}` diff --git a/rabbitmq/resource_federation_upstream_test.go b/rabbitmq/resource_federation_upstream_test.go index a2e7bdd2..7204158d 100644 --- a/rabbitmq/resource_federation_upstream_test.go +++ b/rabbitmq/resource_federation_upstream_test.go @@ -3,7 +3,6 @@ package rabbitmq import ( "fmt" "regexp" - "strings" "testing" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" @@ -123,9 +122,7 @@ func testAccFederationUpstreamCheck(rn string, upstream *rabbithole.FederationUp return fmt.Errorf("federation upstream id not set") } - id := strings.Split(rs.Primary.ID, "@") - name := id[0] - vhost := id[1] + name, vhost, err := parseVHostResourceIdString(rs.Primary.ID) rmqc := testAccProvider.Meta().(*rabbithole.Client) upstreams, err := rmqc.ListFederationUpstreamsIn(vhost) diff --git a/rabbitmq/resource_operator_policy_test.go b/rabbitmq/resource_operator_policy_test.go index cc8dfbdd..5da86cc2 100644 --- a/rabbitmq/resource_operator_policy_test.go +++ b/rabbitmq/resource_operator_policy_test.go @@ -2,7 +2,6 @@ package rabbitmq import ( "fmt" - "strings" "testing" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" @@ -57,7 +56,7 @@ func testAccOperatorPolicyCheck(rn string, operatorPolicy *rabbithole.OperatorPo } rmqc := testAccProvider.Meta().(*rabbithole.Client) - operatorPolicyParts := strings.Split(rs.Primary.ID, "@") + name, vhost, err := parseVHostResourceIdString(rs.Primary.ID) operatorPolicies, err := rmqc.ListOperatorPolicies() if err != nil { @@ -65,7 +64,7 @@ func testAccOperatorPolicyCheck(rn string, operatorPolicy *rabbithole.OperatorPo } for _, p := range operatorPolicies { - if p.Name == operatorPolicyParts[0] && p.Vhost == operatorPolicyParts[1] { + if p.Name == name && p.Vhost == vhost { operatorPolicy = &p return nil } diff --git a/rabbitmq/resource_permissions_test.go b/rabbitmq/resource_permissions_test.go index d87285d6..7b7d2220 100644 --- a/rabbitmq/resource_permissions_test.go +++ b/rabbitmq/resource_permissions_test.go @@ -2,7 +2,6 @@ package rabbitmq import ( "fmt" - "strings" "testing" rabbithole "github.com/michaelklishin/rabbit-hole/v2" @@ -11,7 +10,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" ) -func TestAccPermissions(t *testing.T) { +func TestAccPermissions_basic(t *testing.T) { var permissionInfo rabbithole.PermissionInfo resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -34,7 +33,24 @@ func TestAccPermissions(t *testing.T) { }) } -func TestAccPermissions_Empty(t *testing.T) { +func TestAccPermissions_atSymbolEscaping(t *testing.T) { + var permissionInfo rabbithole.PermissionInfo + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccPermissionsCheckDestroy(&permissionInfo), + Steps: []resource.TestStep{ + { + Config: testAccPermissionsConfig_atSymbolsAreOk, + Check: testAccPermissionsCheck( + "rabbitmq_permissions.test", &permissionInfo, + ), + }, + }, + }) +} + +func TestAccPermissions_empty(t *testing.T) { configCreate := ` resource "rabbitmq_vhost" "test" { @@ -88,9 +104,9 @@ func testAccPermissionsCheck(rn string, permissionInfo *rabbithole.PermissionInf return fmt.Errorf("Error retrieving permissions: %s", err) } - userParts := strings.Split(rs.Primary.ID, "@") + name, vhost, err := parseVHostResourceIdString(rs.Primary.ID) for _, perm := range perms { - if perm.User == userParts[0] && perm.Vhost == userParts[1] { + if perm.User == name && perm.Vhost == vhost { permissionInfo = &perm return nil } @@ -159,3 +175,24 @@ resource "rabbitmq_permissions" "test" { read = "" } }` + +const testAccPermissionsConfig_atSymbolsAreOk = ` +resource "rabbitmq_vhost" "test" { + name = "test" +} + +resource "rabbitmq_user" "test" { + name = "someone@test" + password = "foobar" + tags = ["administrator"] +} + +resource "rabbitmq_permissions" "test" { + user = "${rabbitmq_user.test.name}" + vhost = "${rabbitmq_vhost.test.name}" + permissions { + configure = ".*" + write = ".*" + read = ".*" + } +}` diff --git a/rabbitmq/resource_policy_test.go b/rabbitmq/resource_policy_test.go index c46db112..02a6870d 100644 --- a/rabbitmq/resource_policy_test.go +++ b/rabbitmq/resource_policy_test.go @@ -2,7 +2,6 @@ package rabbitmq import ( "fmt" - "strings" "testing" rabbithole "github.com/michaelklishin/rabbit-hole/v2" @@ -46,7 +45,7 @@ func testAccPolicyCheck(rn string, policy *rabbithole.Policy) resource.TestCheck } rmqc := testAccProvider.Meta().(*rabbithole.Client) - policyParts := strings.Split(rs.Primary.ID, "@") + name, vhost, err := parseVHostResourceIdString(rs.Primary.ID) policies, err := rmqc.ListPolicies() if err != nil { @@ -54,7 +53,7 @@ func testAccPolicyCheck(rn string, policy *rabbithole.Policy) resource.TestCheck } for _, p := range policies { - if p.Name == policyParts[0] && p.Vhost == policyParts[1] { + if p.Name == name && p.Vhost == vhost { policy = &p return nil } diff --git a/rabbitmq/resource_queue_test.go b/rabbitmq/resource_queue_test.go index c910bc54..6836b5bf 100644 --- a/rabbitmq/resource_queue_test.go +++ b/rabbitmq/resource_queue_test.go @@ -54,6 +54,23 @@ func TestAccQueue_jsonArguments(t *testing.T) { }) } +func TestAccQueue_atSymbolEscaping(t *testing.T) { + var queueInfo rabbithole.QueueInfo + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccQueueCheckDestroy(&queueInfo), + Steps: []resource.TestStep{ + { + Config: testAccQueueConfig_atSymbolsAreOk, + Check: testAccQueueCheck( + "rabbitmq_queue.test", &queueInfo, + ), + }, + }, + }) +} + func testAccQueueCheck(rn string, queueInfo *rabbithole.QueueInfo) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[rn] @@ -66,15 +83,15 @@ func testAccQueueCheck(rn string, queueInfo *rabbithole.QueueInfo) resource.Test } rmqc := testAccProvider.Meta().(*rabbithole.Client) - queueParts := strings.Split(rs.Primary.ID, "@") + name, vhost, err := parseVHostResourceIdString(rs.Primary.ID) - queues, err := rmqc.ListQueuesIn(queueParts[1]) + queues, err := rmqc.ListQueuesIn(vhost) if err != nil { return fmt.Errorf("Error retrieving queue: %s", err) } for _, queue := range queues { - if queue.Name == queueParts[0] && queue.Vhost == queueParts[1] { + if queue.Name == name && queue.Vhost == vhost { *queueInfo = queue return nil } @@ -209,3 +226,27 @@ resource "rabbitmq_queue" "test" { } }`, j) } + +const testAccQueueConfig_atSymbolsAreOk = ` +resource "rabbitmq_vhost" "test" { + name = "test" +} + +resource "rabbitmq_permissions" "guest" { + user = "guest" + vhost = "${rabbitmq_vhost.test.name}" + permissions { + configure = ".*" + write = ".*" + read = ".*" + } +} + +resource "rabbitmq_queue" "test" { + name = "queue@test" + vhost = "${rabbitmq_permissions.guest.vhost}" + settings { + durable = false + auto_delete = true + } +}` diff --git a/rabbitmq/resource_shovel_test.go b/rabbitmq/resource_shovel_test.go index 0765639c..eacab7f1 100644 --- a/rabbitmq/resource_shovel_test.go +++ b/rabbitmq/resource_shovel_test.go @@ -2,7 +2,6 @@ package rabbitmq import ( "fmt" - "strings" "testing" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" @@ -46,7 +45,7 @@ func testAccShovelCheck(rn string, shovelInfo *rabbithole.ShovelInfo) resource.T } rmqc := testAccProvider.Meta().(*rabbithole.Client) - shovelParts := strings.Split(rs.Primary.ID, "@") + name, vhost, err := parseVHostResourceIdString(rs.Primary.ID) shovelInfos, err := rmqc.ListShovels() if err != nil { @@ -54,7 +53,7 @@ func testAccShovelCheck(rn string, shovelInfo *rabbithole.ShovelInfo) resource.T } for _, info := range shovelInfos { - if info.Name == shovelParts[0] && info.Vhost == shovelParts[1] { + if info.Name == name && info.Vhost == vhost { expectedSourceExchange := rs.Primary.Attributes["info.0.source_exchange"] expectedSourceExchangeKey := rs.Primary.Attributes["info.0.source_exchange_key"] expectedSourceUri := rs.Primary.Attributes["info.0.source_uri"] diff --git a/rabbitmq/resource_topic_permissions_test.go b/rabbitmq/resource_topic_permissions_test.go index 439ae306..56cadde1 100644 --- a/rabbitmq/resource_topic_permissions_test.go +++ b/rabbitmq/resource_topic_permissions_test.go @@ -4,7 +4,6 @@ import ( "fmt" "os" "regexp" - "strings" "testing" rabbithole "github.com/michaelklishin/rabbit-hole/v2" @@ -61,9 +60,9 @@ func testAccTopicPermissionsCheck(rn string, topicPermissionInfo *rabbithole.Top return fmt.Errorf("Error retrieving topic permissions: %s", err) } - userParts := strings.Split(rs.Primary.ID, "@") + name, vhost, err := parseVHostResourceIdString(rs.Primary.ID) for _, perm := range perms { - if perm.User == userParts[0] && perm.Vhost == userParts[1] { + if perm.User == name && perm.Vhost == vhost { topicPermissionInfo = &perm return nil } diff --git a/rabbitmq/util_test.go b/rabbitmq/util_test.go index 81c269f2..38368214 100644 --- a/rabbitmq/util_test.go +++ b/rabbitmq/util_test.go @@ -2,7 +2,7 @@ package rabbitmq import "testing" -func TestParseId(t *testing.T) { +func TestParseVHostResourceIdString(t *testing.T) { var badInputs = []string{ "", "foo/test", @@ -11,7 +11,7 @@ func TestParseId(t *testing.T) { } for _, input := range badInputs { - _, _, err := parseId(input) + _, _, err := parseVHostResourceIdString(input) if err == nil { t.Errorf("parseId failed for: %s.", input) } @@ -25,10 +25,13 @@ func TestParseId(t *testing.T) { {"foo@test", "foo", "test"}, {"foo@/", "foo", "/"}, {"foo/bar/baz@/", "foo/bar/baz", "/"}, + {"foo%40bar@test", "foo@bar", "test"}, + {"foo@bar%40test", "foo", "bar@test"}, + {"foo%40bar@my%40test", "foo@bar", "my@test"}, } for _, test := range goodInputs { - name, vhost, err := parseId(test.input) + name, vhost, err := parseVHostResourceIdString(test.input) if err != nil || name != test.name || vhost != test.vhost { t.Errorf("parseId failed for: %s.", test.input) }