Skip to content

Commit

Permalink
New Resource azurerm_resource_management_private_link_association (#…
Browse files Browse the repository at this point in the history
…23546)

* new resource private_link_association

* new resource azurerm_resource_management_private_link_association

* fix

* fix

* change name as required

* change to optional
  • Loading branch information
teowa authored Oct 24, 2023
1 parent 61192ff commit d492898
Show file tree
Hide file tree
Showing 20 changed files with 1,006 additions and 0 deletions.
9 changes: 9 additions & 0 deletions internal/services/resource/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"github.com/Azure/azure-sdk-for-go/services/preview/resources/mgmt/2019-06-01-preview/templatespecs" // nolint: staticcheck
"github.com/Azure/azure-sdk-for-go/services/resources/mgmt/2020-06-01/resources" // nolint: staticcheck
"github.com/hashicorp/go-azure-sdk/resource-manager/resources/2020-05-01/managementlocks"
"github.com/hashicorp/go-azure-sdk/resource-manager/resources/2020-05-01/privatelinkassociation"
"github.com/hashicorp/go-azure-sdk/resource-manager/resources/2020-05-01/resourcemanagementprivatelink"
"github.com/hashicorp/go-azure-sdk/resource-manager/resources/2020-10-01/deploymentscripts"
"github.com/hashicorp/go-azure-sdk/resource-manager/resources/2021-07-01/features"
Expand All @@ -22,6 +23,7 @@ type Client struct {
FeaturesClient *features.FeaturesClient
GroupsClient *resources.GroupsClient
LocksClient *managementlocks.ManagementLocksClient
PrivateLinkAssociationClient *privatelinkassociation.PrivateLinkAssociationClient
ResourceManagementPrivateLinkClient *resourcemanagementprivatelink.ResourceManagementPrivateLinkClient
ResourceProvidersClient *providers.ProvidersClient
ResourcesClient *resources.Client
Expand Down Expand Up @@ -56,6 +58,12 @@ func NewClient(o *common.ClientOptions) (*Client, error) {
}
o.Configure(locksClient.Client, o.Authorizers.ResourceManager)

privateLinkAssociationClient, err := privatelinkassociation.NewPrivateLinkAssociationClientWithBaseURI(o.Environment.ResourceManager)
if err != nil {
return nil, fmt.Errorf("building PrivateLinkAssociation client: %+v", err)
}
o.Configure(privateLinkAssociationClient.Client, o.Authorizers.ResourceManager)

resourceManagementPrivateLinkClient, err := resourcemanagementprivatelink.NewResourceManagementPrivateLinkClientWithBaseURI(o.Environment.ResourceManager)
if err != nil {
return nil, fmt.Errorf("building ResourceManagementPrivateLink client: %+v", err)
Expand Down Expand Up @@ -83,6 +91,7 @@ func NewClient(o *common.ClientOptions) (*Client, error) {
DeploymentScriptsClient: deploymentScriptsClient,
FeaturesClient: featuresClient,
LocksClient: locksClient,
PrivateLinkAssociationClient: privateLinkAssociationClient,
ResourceManagementPrivateLinkClient: resourceManagementPrivateLinkClient,
ResourceProvidersClient: resourceProvidersClient,
ResourcesClient: &resourcesClient,
Expand Down
1 change: 1 addition & 0 deletions internal/services/resource/registration.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ func (r Registration) DataSources() []sdk.DataSource {
// Resources returns a list of Resources supported by this Service
func (r Registration) Resources() []sdk.Resource {
return []sdk.Resource{
ResourceManagementPrivateLinkAssociationResource{},
ResourceProviderRegistrationResource{},
ResourceManagementPrivateLinkResource{},
ResourceDeploymentScriptAzurePowerShellResource{},
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
package resource

import (
"context"
"fmt"
"time"

"github.com/google/uuid"
"github.com/hashicorp/go-azure-helpers/lang/pointer"
"github.com/hashicorp/go-azure-helpers/lang/response"
"github.com/hashicorp/go-azure-helpers/resourcemanager/commonids"
"github.com/hashicorp/go-azure-sdk/resource-manager/resources/2020-05-01/privatelinkassociation"
"github.com/hashicorp/go-azure-sdk/resource-manager/resources/2020-05-01/resourcemanagementprivatelink"
"github.com/hashicorp/terraform-provider-azurerm/internal/sdk"
"github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk"
"github.com/hashicorp/terraform-provider-azurerm/internal/tf/validation"
)

var _ sdk.Resource = ResourceManagementPrivateLinkAssociationResource{}

type ResourceManagementPrivateLinkAssociationResource struct{}

func (r ResourceManagementPrivateLinkAssociationResource) ModelObject() interface{} {
return &ResourceManagementPrivateLinkAssociationResourceSchema{}
}

type ResourceManagementPrivateLinkAssociationResourceSchema struct {
ManagementGroupId string `tfschema:"management_group_id"`
Name string `tfschema:"name"`
ResourceManagementPrivateLinkId string `tfschema:"resource_management_private_link_id"`
PublicNetworkAccessEnabled bool `tfschema:"public_network_access_enabled"`
TenantID string `tfschema:"tenant_id"`
}

func (r ResourceManagementPrivateLinkAssociationResource) IDValidationFunc() pluginsdk.SchemaValidateFunc {
return privatelinkassociation.ValidatePrivateLinkAssociationID
}

func (r ResourceManagementPrivateLinkAssociationResource) ResourceType() string {
return "azurerm_resource_management_private_link_association"
}

func (r ResourceManagementPrivateLinkAssociationResource) Arguments() map[string]*pluginsdk.Schema {
return map[string]*pluginsdk.Schema{
"name": {
ForceNew: true,
Optional: true,
Type: pluginsdk.TypeString,
ValidateFunc: validation.IsUUID,
},
"management_group_id": {
ForceNew: true,
Required: true,
Type: pluginsdk.TypeString,
ValidateFunc: commonids.ValidateManagementGroupID,
},
"resource_management_private_link_id": {
ForceNew: true,
Required: true,
Type: pluginsdk.TypeString,
ValidateFunc: resourcemanagementprivatelink.ValidateResourceManagementPrivateLinkID,
},
"public_network_access_enabled": {
ForceNew: true,
Required: true,
Type: pluginsdk.TypeBool,
},
}
}

func (r ResourceManagementPrivateLinkAssociationResource) Attributes() map[string]*pluginsdk.Schema {
return map[string]*pluginsdk.Schema{
"tenant_id": {
Computed: true,
Type: pluginsdk.TypeString,
},
}
}

func (r ResourceManagementPrivateLinkAssociationResource) Create() sdk.ResourceFunc {
return sdk.ResourceFunc{
Timeout: 30 * time.Minute,
Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error {
client := metadata.Client.Resource.PrivateLinkAssociationClient

var config ResourceManagementPrivateLinkAssociationResourceSchema
if err := metadata.Decode(&config); err != nil {
return fmt.Errorf("decoding: %+v", err)
}

managementGroupId, err := commonids.ParseManagementGroupID(config.ManagementGroupId)
if err != nil {
return err
}

var name string
if config.Name != "" {
name = config.Name
}

if name == "" {
name = uuid.New().String()
}

id := privatelinkassociation.NewPrivateLinkAssociationID(managementGroupId.GroupId, name)

existing, err := client.Get(ctx, id)
if err != nil {
if !response.WasNotFound(existing.HttpResponse) {
return fmt.Errorf("checking for the presence of an existing %s: %+v", id, err)
}
}
if !response.WasNotFound(existing.HttpResponse) {
return metadata.ResourceRequiresImport(r.ResourceType(), id)
}

payload := privatelinkassociation.PrivateLinkAssociationObject{
Properties: &privatelinkassociation.PrivateLinkAssociationProperties{
PrivateLink: pointer.To(config.ResourceManagementPrivateLinkId),
PublicNetworkAccess: r.expandPublicNetworkAccess(config.PublicNetworkAccessEnabled),
},
}

if _, err := client.Put(ctx, id, payload); err != nil {
return fmt.Errorf("creating %s: %+v", id, err)
}

metadata.SetID(id)
return nil
},
}
}

func (r ResourceManagementPrivateLinkAssociationResource) Read() sdk.ResourceFunc {
return sdk.ResourceFunc{
Timeout: 5 * time.Minute,
Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error {
client := metadata.Client.Resource.PrivateLinkAssociationClient
schema := ResourceManagementPrivateLinkAssociationResourceSchema{}

id, err := privatelinkassociation.ParsePrivateLinkAssociationID(metadata.ResourceData.Id())
if err != nil {
return err
}

resp, err := client.Get(ctx, *id)
if err != nil {
if response.WasNotFound(resp.HttpResponse) {
return metadata.MarkAsGone(*id)
}
return fmt.Errorf("retrieving %s: %+v", *id, err)
}

schema.ManagementGroupId = commonids.NewManagementGroupID(id.GroupId).ID()
schema.Name = id.PlaId

if model := resp.Model; model != nil {
if prop := model.Properties; prop != nil {
schema.PublicNetworkAccessEnabled = r.flattenPublicNetworkAccess(prop.PublicNetworkAccess)
schema.TenantID = pointer.From(prop.TenantID)
schema.ResourceManagementPrivateLinkId = pointer.From(prop.PrivateLink)
}
}

return metadata.Encode(&schema)
},
}
}

func (r ResourceManagementPrivateLinkAssociationResource) Delete() sdk.ResourceFunc {
return sdk.ResourceFunc{
Timeout: 30 * time.Minute,
Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error {
client := metadata.Client.Resource.PrivateLinkAssociationClient

id, err := privatelinkassociation.ParsePrivateLinkAssociationID(metadata.ResourceData.Id())
if err != nil {
return err
}

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

return nil
},
}
}

func (r ResourceManagementPrivateLinkAssociationResource) expandPublicNetworkAccess(input bool) *privatelinkassociation.PublicNetworkAccessOptions {
output := privatelinkassociation.PublicNetworkAccessOptionsEnabled
if !input {
output = privatelinkassociation.PublicNetworkAccessOptionsDisabled
}

return &output
}

func (r ResourceManagementPrivateLinkAssociationResource) flattenPublicNetworkAccess(input *privatelinkassociation.PublicNetworkAccessOptions) bool {
if input == nil || *input == privatelinkassociation.PublicNetworkAccessOptionsEnabled {
return true
}

return false
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
package resource_test

import (
"context"
"fmt"
"testing"

"github.com/hashicorp/go-azure-sdk/resource-manager/resources/2020-05-01/privatelinkassociation"
"github.com/hashicorp/go-uuid"
"github.com/hashicorp/terraform-provider-azurerm/internal/acceptance"
"github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check"
"github.com/hashicorp/terraform-provider-azurerm/internal/clients"
"github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk"
"github.com/hashicorp/terraform-provider-azurerm/utils"
)

type ResourceManagementPrivateLinkAssociationTestResource struct{}

func TestAccResourceManagementPrivateLinkAssociation_basic(t *testing.T) {
data := acceptance.BuildTestData(t, "azurerm_resource_management_private_link_association", "test")
r := ResourceManagementPrivateLinkAssociationTestResource{}

data.ResourceTest(t, r, []acceptance.TestStep{
{
Config: r.basic(data),
Check: acceptance.ComposeTestCheckFunc(
check.That(data.ResourceName).ExistsInAzure(r),
),
},
data.ImportStep(),
})
}

func TestAccResourceManagementPrivateLinkAssociation_requiresImport(t *testing.T) {
data := acceptance.BuildTestData(t, "azurerm_resource_management_private_link_association", "test")
r := ResourceManagementPrivateLinkAssociationTestResource{}

data.ResourceTest(t, r, []acceptance.TestStep{
{
Config: r.basic(data),
Check: acceptance.ComposeTestCheckFunc(
check.That(data.ResourceName).ExistsInAzure(r),
),
},
data.RequiresImportErrorStep(r.requiresImport),
})
}

func TestAccResourceManagementPrivateLinkAssociation_generateName(t *testing.T) {
data := acceptance.BuildTestData(t, "azurerm_resource_management_private_link_association", "test")
r := ResourceManagementPrivateLinkAssociationTestResource{}

data.ResourceTest(t, r, []acceptance.TestStep{
{
Config: r.generateName(data),
Check: acceptance.ComposeTestCheckFunc(
check.That(data.ResourceName).ExistsInAzure(r),
),
},
data.ImportStep(),
})
}

func (r ResourceManagementPrivateLinkAssociationTestResource) Exists(ctx context.Context, clients *clients.Client, state *pluginsdk.InstanceState) (*bool, error) {
id, err := privatelinkassociation.ParsePrivateLinkAssociationID(state.ID)
if err != nil {
return nil, err
}

resp, err := clients.Resource.PrivateLinkAssociationClient.Get(ctx, *id)
if err != nil {
return nil, fmt.Errorf("reading %s: %+v", *id, err)
}

return utils.Bool(resp.Model != nil), nil
}

func (r ResourceManagementPrivateLinkAssociationTestResource) basic(data acceptance.TestData) string {
randomUUID, _ := uuid.GenerateUUID()
return fmt.Sprintf(`
provider "azurerm" {
features {}
}
%s
resource "azurerm_resource_management_private_link_association" "test" {
name = "%s"
management_group_id = data.azurerm_management_group.test.id
resource_management_private_link_id = azurerm_resource_management_private_link.test.id
public_network_access_enabled = true
}
`, r.template(data), randomUUID)
}

func (r ResourceManagementPrivateLinkAssociationTestResource) generateName(data acceptance.TestData) string {
return fmt.Sprintf(`
provider "azurerm" {
features {}
}
%s
resource "azurerm_resource_management_private_link_association" "test" {
management_group_id = data.azurerm_management_group.test.id
resource_management_private_link_id = azurerm_resource_management_private_link.test.id
public_network_access_enabled = true
lifecycle {
ignore_changes = [name]
}
}
`, r.template(data))
}

func (r ResourceManagementPrivateLinkAssociationTestResource) requiresImport(data acceptance.TestData) string {
return fmt.Sprintf(`
%s
resource "azurerm_resource_management_private_link_association" "import" {
name = azurerm_resource_management_private_link_association.test.name
management_group_id = azurerm_resource_management_private_link_association.test.management_group_id
resource_management_private_link_id = azurerm_resource_management_private_link_association.test.resource_management_private_link_id
public_network_access_enabled = azurerm_resource_management_private_link_association.test.public_network_access_enabled
}
`, r.basic(data))
}

func (r ResourceManagementPrivateLinkAssociationTestResource) template(data acceptance.TestData) string {
return fmt.Sprintf(`
data "azurerm_client_config" "test" {}
data "azurerm_management_group" "test" {
name = data.azurerm_client_config.test.tenant_id
}
resource "azurerm_resource_group" "test" {
name = "acctestrg-%d"
location = "%s"
}
resource "azurerm_resource_management_private_link" "test" {
location = azurerm_resource_group.test.location
name = "acctestrmpl-%[1]d"
resource_group_name = azurerm_resource_group.test.name
}
`, data.RandomInteger, data.Locations.Primary)
}
Loading

0 comments on commit d492898

Please sign in to comment.