From 187c9c2517bcbb006ed37841ce1f8b8a921d09a0 Mon Sep 17 00:00:00 2001 From: Yichun Ma Date: Tue, 14 Feb 2023 16:13:41 +0800 Subject: [PATCH 1/2] `azurerm_private_endpoint` - read private endpoint connection insensitively --- internal/services/mysql/parse/server.go | 44 ++++++++++ internal/services/mysql/resourceids.go | 2 +- .../network/private_endpoint_resource.go | 80 ++++++++----------- 3 files changed, 79 insertions(+), 47 deletions(-) diff --git a/internal/services/mysql/parse/server.go b/internal/services/mysql/parse/server.go index d05075b10ec5..d2eb1c0edccd 100644 --- a/internal/services/mysql/parse/server.go +++ b/internal/services/mysql/parse/server.go @@ -67,3 +67,47 @@ func ServerID(input string) (*ServerId, error) { return &resourceId, nil } + +// ServerIDInsensitively parses a Server ID into an ServerId struct, insensitively +// This should only be used to parse an ID for rewriting, the ServerID +// method should be used instead for validation etc. +// +// Whilst this may seem strange, this enables Terraform have consistent casing +// which works around issues in Core, whilst handling broken API responses. +func ServerIDInsensitively(input string) (*ServerId, error) { + id, err := resourceids.ParseAzureResourceID(input) + if err != nil { + return nil, err + } + + resourceId := ServerId{ + SubscriptionId: id.SubscriptionID, + ResourceGroup: id.ResourceGroup, + } + + if resourceId.SubscriptionId == "" { + return nil, fmt.Errorf("ID was missing the 'subscriptions' element") + } + + if resourceId.ResourceGroup == "" { + return nil, fmt.Errorf("ID was missing the 'resourceGroups' element") + } + + // find the correct casing for the 'servers' segment + serversKey := "servers" + for key := range id.Path { + if strings.EqualFold(key, serversKey) { + serversKey = key + break + } + } + if resourceId.Name, err = id.PopSegment(serversKey); err != nil { + return nil, err + } + + if err := id.ValidateNoEmptySegments(input); err != nil { + return nil, err + } + + return &resourceId, nil +} diff --git a/internal/services/mysql/resourceids.go b/internal/services/mysql/resourceids.go index 0bd4776667b6..3eadc9988b1e 100644 --- a/internal/services/mysql/resourceids.go +++ b/internal/services/mysql/resourceids.go @@ -9,5 +9,5 @@ package mysql //go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=FlexibleServerConfiguration -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforMySQL/flexibleServers/flexibleServer1/configurations/config1 //go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=FlexibleServerFirewallRule -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforMySQL/flexibleServers/flexibleServer1/firewallRules/firewallRule1 //go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=Key -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforMySQL/servers/server1/keys/key1 -//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=Server -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforMySQL/servers/server1 +//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=Server -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforMySQL/servers/server1 -rewrite=true //go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=VirtualNetworkRule -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforMySQL/servers/server1/virtualNetworkRules/virtualNetworkRule1 diff --git a/internal/services/network/private_endpoint_resource.go b/internal/services/network/private_endpoint_resource.go index 5f2099145a9b..3620a9e14bbe 100644 --- a/internal/services/network/private_endpoint_resource.go +++ b/internal/services/network/private_endpoint_resource.go @@ -11,8 +11,8 @@ import ( "github.com/hashicorp/go-azure-helpers/lang/response" "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" "github.com/hashicorp/go-azure-helpers/resourcemanager/location" - mariaDB "github.com/hashicorp/go-azure-sdk/resource-manager/mariadb/2018-06-01/servers" - "github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/servers" + mariadbServers "github.com/hashicorp/go-azure-sdk/resource-manager/mariadb/2018-06-01/servers" + postgresqlServers "github.com/hashicorp/go-azure-sdk/resource-manager/postgresql/2017-12-01/servers" "github.com/hashicorp/go-azure-sdk/resource-manager/privatedns/2018-09-01/privatezones" "github.com/hashicorp/go-azure-sdk/resource-manager/redis/2021-06-01/redis" "github.com/hashicorp/go-azure-sdk/resource-manager/signalr/2022-02-01/signalr" @@ -857,33 +857,7 @@ func flattenPrivateLinkEndpointServiceConnection(serviceConnections *[]network.P if strings.HasSuffix(privateConnectionId, ".azure.privatelinkservice") { attrs["private_connection_resource_alias"] = privateConnectionId } else { - // There is a bug from service, the PE created from portal could be with the connection id for postgresql server "Microsoft.DBForPostgreSQL" instead of "Microsoft.DBforPostgreSQL" - // and for Mysql and MariaDB - if strings.Contains(strings.ToLower(privateConnectionId), "microsoft.dbforpostgresql") { - if serverId, err := servers.ParseServerID(privateConnectionId); err == nil { - privateConnectionId = serverId.ID() - } - } - if strings.Contains(strings.ToLower(privateConnectionId), "microsoft.dbformysql") { - if serverId, err := mysqlParse.ServerID(privateConnectionId); err == nil { - privateConnectionId = serverId.ID() - } - } - if strings.Contains(strings.ToLower(privateConnectionId), "microsoft.dbformariadb") { - if serverId, err := mariaDB.ParseServerID(privateConnectionId); err == nil { - privateConnectionId = serverId.ID() - } - } - if strings.Contains(strings.ToLower(privateConnectionId), "microsoft.redis") { - if cacheId, err := redis.ParseRediIDInsensitively(privateConnectionId); err == nil { - privateConnectionId = cacheId.ID() - } - } - if strings.Contains(strings.ToLower(privateConnectionId), "microsoft.signalrservice") { - if serviceId, err := signalr.ParseSignalRIDInsensitively(privateConnectionId); err == nil { - privateConnectionId = serviceId.ID() - } - } + privateConnectionId = normalizePrivateConnectionId(privateConnectionId) attrs["private_connection_resource_id"] = privateConnectionId } @@ -924,23 +898,7 @@ func flattenPrivateLinkEndpointServiceConnection(serviceConnections *[]network.P if strings.HasSuffix(privateConnectionId, ".azure.privatelinkservice") { attrs["private_connection_resource_alias"] = privateConnectionId } else { - // There is a bug from service, the PE created from portal could be with the connection id for postgresql server "Microsoft.DBForPostgreSQL" instead of "Microsoft.DBforPostgreSQL" - // and for Mysql and MariaDB - if strings.Contains(strings.ToLower(privateConnectionId), "microsoft.dbforpostgresql") { - if serverId, err := servers.ParseServerID(privateConnectionId); err == nil { - privateConnectionId = serverId.ID() - } - } - if strings.Contains(strings.ToLower(privateConnectionId), "microsoft.dbformysql") { - if serverId, err := mysqlParse.ServerID(privateConnectionId); err == nil { - privateConnectionId = serverId.ID() - } - } - if strings.Contains(strings.ToLower(privateConnectionId), "microsoft.dbformariadb") { - if serverId, err := mariaDB.ParseServerID(privateConnectionId); err == nil { - privateConnectionId = serverId.ID() - } - } + privateConnectionId = normalizePrivateConnectionId(privateConnectionId) attrs["private_connection_resource_id"] = privateConnectionId } @@ -1171,3 +1129,33 @@ func validatePrivateEndpointSettings(d *pluginsdk.ResourceData) error { return nil } + +// normalize the PrivateConnectionId due to the casing change at service side +func normalizePrivateConnectionId(privateConnectionId string) string { + if strings.Contains(strings.ToLower(privateConnectionId), "microsoft.dbforpostgresql") { + if serverId, err := postgresqlServers.ParseServerIDInsensitively(privateConnectionId); err == nil { + privateConnectionId = serverId.ID() + } + } + if strings.Contains(strings.ToLower(privateConnectionId), "microsoft.dbformysql") { + if serverId, err := mysqlParse.ServerIDInsensitively(privateConnectionId); err == nil { + privateConnectionId = serverId.ID() + } + } + if strings.Contains(strings.ToLower(privateConnectionId), "microsoft.dbformariadb") { + if serverId, err := mariadbServers.ParseServerIDInsensitively(privateConnectionId); err == nil { + privateConnectionId = serverId.ID() + } + } + if strings.Contains(strings.ToLower(privateConnectionId), "microsoft.redis") { + if cacheId, err := redis.ParseRediIDInsensitively(privateConnectionId); err == nil { + privateConnectionId = cacheId.ID() + } + } + if strings.Contains(strings.ToLower(privateConnectionId), "microsoft.signalrservice") { + if serviceId, err := signalr.ParseSignalRIDInsensitively(privateConnectionId); err == nil { + privateConnectionId = serviceId.ID() + } + } + return privateConnectionId +} From c153f18be8f115b02dba89df730a31575116465c Mon Sep 17 00:00:00 2001 From: Yichun Ma Date: Tue, 14 Feb 2023 20:44:10 +0800 Subject: [PATCH 2/2] Fix generate --- internal/services/mysql/parse/server.go | 2 +- internal/services/mysql/parse/server_test.go | 117 +++++++++++++++++++ 2 files changed, 118 insertions(+), 1 deletion(-) diff --git a/internal/services/mysql/parse/server.go b/internal/services/mysql/parse/server.go index d2eb1c0edccd..1d1083de8d73 100644 --- a/internal/services/mysql/parse/server.go +++ b/internal/services/mysql/parse/server.go @@ -68,7 +68,7 @@ func ServerID(input string) (*ServerId, error) { return &resourceId, nil } -// ServerIDInsensitively parses a Server ID into an ServerId struct, insensitively +// ServerIDInsensitively parses an Server ID into an ServerId struct, insensitively // This should only be used to parse an ID for rewriting, the ServerID // method should be used instead for validation etc. // diff --git a/internal/services/mysql/parse/server_test.go b/internal/services/mysql/parse/server_test.go index 5eaeb4609f84..dd32612bb8f2 100644 --- a/internal/services/mysql/parse/server_test.go +++ b/internal/services/mysql/parse/server_test.go @@ -110,3 +110,120 @@ func TestServerID(t *testing.T) { } } } + +func TestServerIDInsensitively(t *testing.T) { + testData := []struct { + Input string + Error bool + Expected *ServerId + }{ + + { + // empty + Input: "", + Error: true, + }, + + { + // missing SubscriptionId + Input: "/", + Error: true, + }, + + { + // missing value for SubscriptionId + Input: "/subscriptions/", + Error: true, + }, + + { + // missing ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", + Error: true, + }, + + { + // missing value for ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", + Error: true, + }, + + { + // missing Name + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforMySQL/", + Error: true, + }, + + { + // missing value for Name + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforMySQL/servers/", + Error: true, + }, + + { + // valid + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforMySQL/servers/server1", + Expected: &ServerId{ + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "resGroup1", + Name: "server1", + }, + }, + + { + // lower-cased segment names + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforMySQL/servers/server1", + Expected: &ServerId{ + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "resGroup1", + Name: "server1", + }, + }, + + { + // upper-cased segment names + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforMySQL/SERVERS/server1", + Expected: &ServerId{ + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "resGroup1", + Name: "server1", + }, + }, + + { + // mixed-cased segment names + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.DBforMySQL/SeRvErS/server1", + Expected: &ServerId{ + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "resGroup1", + Name: "server1", + }, + }, + } + + for _, v := range testData { + t.Logf("[DEBUG] Testing %q", v.Input) + + actual, err := ServerIDInsensitively(v.Input) + if err != nil { + if v.Error { + continue + } + + t.Fatalf("Expect a value but got an error: %s", err) + } + if v.Error { + t.Fatal("Expect an error but didn't get one") + } + + if actual.SubscriptionId != v.Expected.SubscriptionId { + t.Fatalf("Expected %q but got %q for SubscriptionId", v.Expected.SubscriptionId, actual.SubscriptionId) + } + if actual.ResourceGroup != v.Expected.ResourceGroup { + t.Fatalf("Expected %q but got %q for ResourceGroup", v.Expected.ResourceGroup, actual.ResourceGroup) + } + if actual.Name != v.Expected.Name { + t.Fatalf("Expected %q but got %q for Name", v.Expected.Name, actual.Name) + } + } +}