Skip to content

Commit

Permalink
new resource "azurerm_synapse_private_link_hub" (hashicorp#12495)
Browse files Browse the repository at this point in the history
* Add support for Synapse Private Link Hub resources

Signed-off-by: Owen Farrell <[email protected]>

* Apply suggestions from code review

Co-authored-by: Tom Bamford <[email protected]>

* Apply acceptance test suggestions from code review

Co-authored-by: Tom Bamford <[email protected]>

* Autogenerate Synapse Private Link Hub ID source

Signed-off-by: Owen Farrell <[email protected]>

* Test import of Synapse Private Link Hub

Signed-off-by: Owen Farrell <[email protected]>

Co-authored-by: Tom Bamford <[email protected]>
  • Loading branch information
2 people authored and yupwei68 committed Jul 26, 2021
1 parent fa4db99 commit 49c4281
Show file tree
Hide file tree
Showing 12 changed files with 740 additions and 0 deletions.
5 changes: 5 additions & 0 deletions azurerm/internal/services/synapse/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (

type Client struct {
FirewallRulesClient *synapse.IPFirewallRulesClient
PrivateLinkHubsClient *synapse.PrivateLinkHubsClient
SparkPoolClient *synapse.BigDataPoolsClient
SqlPoolClient *synapse.SQLPoolsClient
SqlPoolTransparentDataEncryptionClient *synapse.SQLPoolTransparentDataEncryptionsClient
Expand All @@ -26,6 +27,9 @@ func NewClient(o *common.ClientOptions) *Client {
firewallRuleClient := synapse.NewIPFirewallRulesClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId)
o.ConfigureClient(&firewallRuleClient.Client, o.ResourceManagerAuthorizer)

privateLinkHubsClient := synapse.NewPrivateLinkHubsClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId)
o.ConfigureClient(&privateLinkHubsClient.Client, o.ResourceManagerAuthorizer)

// the service team hopes to rename it to sparkPool, so rename the sdk here
sparkPoolClient := synapse.NewBigDataPoolsClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId)
o.ConfigureClient(&sparkPoolClient.Client, o.ResourceManagerAuthorizer)
Expand All @@ -47,6 +51,7 @@ func NewClient(o *common.ClientOptions) *Client {

return &Client{
FirewallRulesClient: &firewallRuleClient,
PrivateLinkHubsClient: &privateLinkHubsClient,
SparkPoolClient: &sparkPoolClient,
SqlPoolClient: &sqlPoolClient,
SqlPoolTransparentDataEncryptionClient: &sqlPoolTransparentDataEncryptionClient,
Expand Down
69 changes: 69 additions & 0 deletions azurerm/internal/services/synapse/parse/private_link_hub.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package parse

// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten

import (
"fmt"
"strings"

"github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure"
)

type PrivateLinkHubId struct {
SubscriptionId string
ResourceGroup string
Name string
}

func NewPrivateLinkHubID(subscriptionId, resourceGroup, name string) PrivateLinkHubId {
return PrivateLinkHubId{
SubscriptionId: subscriptionId,
ResourceGroup: resourceGroup,
Name: name,
}
}

func (id PrivateLinkHubId) String() string {
segments := []string{
fmt.Sprintf("Name %q", id.Name),
fmt.Sprintf("Resource Group %q", id.ResourceGroup),
}
segmentsStr := strings.Join(segments, " / ")
return fmt.Sprintf("%s: (%s)", "Private Link Hub", segmentsStr)
}

func (id PrivateLinkHubId) ID() string {
fmtString := "/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Synapse/privateLinkHubs/%s"
return fmt.Sprintf(fmtString, id.SubscriptionId, id.ResourceGroup, id.Name)
}

// PrivateLinkHubID parses a PrivateLinkHub ID into an PrivateLinkHubId struct
func PrivateLinkHubID(input string) (*PrivateLinkHubId, error) {
id, err := azure.ParseAzureResourceID(input)
if err != nil {
return nil, err
}

resourceId := PrivateLinkHubId{
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")
}

if resourceId.Name, err = id.PopSegment("privateLinkHubs"); err != nil {
return nil, err
}

if err := id.ValidateNoEmptySegments(input); err != nil {
return nil, err
}

return &resourceId, nil
}
112 changes: 112 additions & 0 deletions azurerm/internal/services/synapse/parse/private_link_hub_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
package parse

// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten

import (
"testing"

"github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/resourceid"
)

var _ resourceid.Formatter = PrivateLinkHubId{}

func TestPrivateLinkHubIDFormatter(t *testing.T) {
actual := NewPrivateLinkHubID("12345678-1234-9876-4563-123456789012", "resGroup1", "privateLinkHub1").ID()
expected := "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Synapse/privateLinkHubs/privateLinkHub1"
if actual != expected {
t.Fatalf("Expected %q but got %q", expected, actual)
}
}

func TestPrivateLinkHubID(t *testing.T) {
testData := []struct {
Input string
Error bool
Expected *PrivateLinkHubId
}{

{
// 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.Synapse/",
Error: true,
},

{
// missing value for Name
Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Synapse/privateLinkHubs/",
Error: true,
},

{
// valid
Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Synapse/privateLinkHubs/privateLinkHub1",
Expected: &PrivateLinkHubId{
SubscriptionId: "12345678-1234-9876-4563-123456789012",
ResourceGroup: "resGroup1",
Name: "privateLinkHub1",
},
},

{
// upper-cased
Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.SYNAPSE/PRIVATELINKHUBS/PRIVATELINKHUB1",
Error: true,
},
}

for _, v := range testData {
t.Logf("[DEBUG] Testing %q", v.Input)

actual, err := PrivateLinkHubID(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)
}
}
}
1 change: 1 addition & 0 deletions azurerm/internal/services/synapse/registration.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ func (r Registration) SupportedDataSources() map[string]*pluginsdk.Resource {
func (r Registration) SupportedResources() map[string]*pluginsdk.Resource {
return map[string]*pluginsdk.Resource{
"azurerm_synapse_firewall_rule": resourceSynapseFirewallRule(),
"azurerm_synapse_private_link_hub": resourceSynapsePrivateLinkHub(),
"azurerm_synapse_managed_private_endpoint": resourceSynapseManagedPrivateEndpoint(),
"azurerm_synapse_role_assignment": resourceSynapseRoleAssignment(),
"azurerm_synapse_spark_pool": resourceSynapseSparkPool(),
Expand Down
1 change: 1 addition & 0 deletions azurerm/internal/services/synapse/resourceids.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ package synapse
//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=SqlPool -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Synapse/workspaces/workspace1/sqlPools/sqlPool1
//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=Workspace -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Synapse/workspaces/workspace1
//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=ManagedPrivateEndpoint -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Synapse/workspaces/workspace1/managedVirtualNetworks/default/managedPrivateEndpoints/endpoint1
//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=PrivateLinkHub -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Synapse/privateLinkHubs/privateLinkHub1
165 changes: 165 additions & 0 deletions azurerm/internal/services/synapse/synapse_private_link_hub.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
package synapse

import (
"fmt"
"log"
"time"

"github.com/Azure/azure-sdk-for-go/services/synapse/mgmt/2021-03-01/synapse"
"github.com/hashicorp/go-azure-helpers/response"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/tf"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/clients"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/location"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/synapse/parse"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/synapse/validate"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/tags"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/tf/pluginsdk"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/timeouts"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils"
)

func resourceSynapsePrivateLinkHub() *pluginsdk.Resource {
return &pluginsdk.Resource{
Create: resourceSynapsePrivateLinkHubCreate,
Read: resourceSynapsePrivateLinkHubRead,
Update: resourceSynapsePrivateLinkHubUpdate,
Delete: resourceSynapsePrivateLinkHubDelete,

Timeouts: &pluginsdk.ResourceTimeout{
Create: pluginsdk.DefaultTimeout(30 * time.Minute),
Read: pluginsdk.DefaultTimeout(5 * time.Minute),
Update: pluginsdk.DefaultTimeout(30 * time.Minute),
Delete: pluginsdk.DefaultTimeout(30 * time.Minute),
},

Importer: pluginsdk.ImporterValidatingResourceId(func(id string) error {
_, err := parse.PrivateLinkHubID(id)
return err
}),

Schema: map[string]*pluginsdk.Schema{
"name": {
Type: pluginsdk.TypeString,
Required: true,
ForceNew: true,
ValidateFunc: validate.PrivateLinkHubName,
},

"resource_group_name": azure.SchemaResourceGroupName(),

"location": azure.SchemaLocation(),

"tags": tags.Schema(),
},
}
}

func resourceSynapsePrivateLinkHubCreate(d *pluginsdk.ResourceData, meta interface{}) error {
client := meta.(*clients.Client).Synapse.PrivateLinkHubsClient
ctx, cancel := timeouts.ForCreate(meta.(*clients.Client).StopContext, d)
defer cancel()

subscriptionId := meta.(*clients.Client).Account.SubscriptionId
id := parse.NewPrivateLinkHubID(subscriptionId, d.Get("resource_group_name").(string), d.Get("name").(string))

existing, err := client.Get(ctx, id.ResourceGroup, id.Name)
if err != nil {
if !utils.ResponseWasNotFound(existing.Response) {
return fmt.Errorf("checking for presence of %s: %+v", id, err)
}
}
if !utils.ResponseWasNotFound(existing.Response) {
return tf.ImportAsExistsError("azurerm_synapse_private_link_hub", id.ID())
}

privateLinkHubInfo := synapse.PrivateLinkHub{
Location: utils.String(location.Normalize(d.Get("location").(string))),
Tags: tags.Expand(d.Get("tags").(map[string]interface{})),
}

_, err = client.CreateOrUpdate(ctx, privateLinkHubInfo, id.ResourceGroup, id.Name)
if err != nil {
return fmt.Errorf("creating %s: %+v", id, err)
}

d.SetId(id.ID())

return resourceSynapsePrivateLinkHubRead(d, meta)
}

func resourceSynapsePrivateLinkHubRead(d *pluginsdk.ResourceData, meta interface{}) error {
client := meta.(*clients.Client).Synapse.PrivateLinkHubsClient
ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d)
defer cancel()

id, err := parse.PrivateLinkHubID(d.Id())
if err != nil {
return err
}

resp, err := client.Get(ctx, id.ResourceGroup, id.Name)
if err != nil {
if utils.ResponseWasNotFound(resp.Response) {
log.Printf("[INFO] synapse %q does not exist - removing from state", d.Id())
d.SetId("")
return nil
}
return fmt.Errorf("retrieving %s: %+v", id, err)
}

d.Set("name", id.Name)
d.Set("resource_group_name", id.ResourceGroup)
d.Set("location", location.NormalizeNilable(resp.Location))

return tags.FlattenAndSet(d, resp.Tags)
}

func resourceSynapsePrivateLinkHubUpdate(d *pluginsdk.ResourceData, meta interface{}) error {
client := meta.(*clients.Client).Synapse.PrivateLinkHubsClient
ctx, cancel := timeouts.ForUpdate(meta.(*clients.Client).StopContext, d)
defer cancel()

id, err := parse.PrivateLinkHubID(d.Id())
if err != nil {
return err
}

if d.HasChange("tags") {
privateLinkHubPatchInfo := synapse.PrivateLinkHubPatchInfo{
Tags: tags.Expand(d.Get("tags").(map[string]interface{})),
}

_, err := client.Update(ctx, privateLinkHubPatchInfo, id.ResourceGroup, id.Name)
if err != nil {
return fmt.Errorf("updating %s: %+v", id, err)
}
}

return resourceSynapsePrivateLinkHubRead(d, meta)
}

func resourceSynapsePrivateLinkHubDelete(d *pluginsdk.ResourceData, meta interface{}) error {
client := meta.(*clients.Client).Synapse.PrivateLinkHubsClient
ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d)
defer cancel()

id, err := parse.PrivateLinkHubID(d.Id())
if err != nil {
return err
}

future, err := client.Delete(ctx, id.ResourceGroup, id.Name)
if err != nil {
return fmt.Errorf("deleting %s: %+v", id, err)
}

// sometimes the waitForCompletion rest api will return 404
if err = future.WaitForCompletionRef(ctx, client.Client); err != nil {
if !response.WasNotFound(future.Response()) {
return fmt.Errorf("waiting for deletion of %s: %+v", id, err)
}
}

return nil
}
Loading

0 comments on commit 49c4281

Please sign in to comment.