Skip to content

Commit

Permalink
new automation private endpoint connection resource
Browse files Browse the repository at this point in the history
  • Loading branch information
wuxu92 committed Aug 31, 2022
1 parent 3ec69cf commit b512f22
Show file tree
Hide file tree
Showing 10 changed files with 781 additions and 0 deletions.
228 changes: 228 additions & 0 deletions internal/services/automation/automation_private_endpoint_connection.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,228 @@
package automation

import (
"context"
"fmt"
"time"

"github.com/Azure/azure-sdk-for-go/services/preview/automation/mgmt/2020-01-13-preview/automation"

"github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema"
"github.com/hashicorp/terraform-provider-azurerm/internal/sdk"
"github.com/hashicorp/terraform-provider-azurerm/internal/services/automation/parse"
"github.com/hashicorp/terraform-provider-azurerm/internal/services/automation/validate"
"github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk"
"github.com/hashicorp/terraform-provider-azurerm/internal/tf/validation"
"github.com/hashicorp/terraform-provider-azurerm/utils"
)

type PrivateEndpointConnectionModel struct {
ResourceGroupName string `tfschema:"resource_group_name"`
AutomationAccountName string `tfschema:"automation_account_name"`
Name string `tfschema:"name"`
LinkStatus string `tfschema:"link_status"`
LinkDescription string `tfschema:"link_description"`
LinkActionRequired string `tfschema:"link_action_required"`
PrivateEndpointID string `tfschema:"private_endpoint_id"`
GroupIds []string `tfschema:"group_ids"`
}

type PrivateEndpointConnectionResource struct{}

var _ sdk.Resource = (*PrivateEndpointConnectionResource)(nil)

func (m PrivateEndpointConnectionResource) Arguments() map[string]*pluginsdk.Schema {
return map[string]*pluginsdk.Schema{
"resource_group_name": commonschema.ResourceGroupName(),
"automation_account_name": {
Type: pluginsdk.TypeString,
Required: true,
ForceNew: true,
ValidateFunc: validation.StringIsNotEmpty,
},
"name": {
Type: pluginsdk.TypeString,
Required: true,
ForceNew: true,
ValidateFunc: validation.StringIsNotEmpty,
},
"link_status": {
Type: pluginsdk.TypeString,
Optional: true,
ValidateFunc: validation.StringIsNotEmpty,
},
"link_description": {
Type: pluginsdk.TypeString,
Optional: true,
ValidateFunc: validation.StringIsNotEmpty,
},
}
}

func (m PrivateEndpointConnectionResource) Attributes() map[string]*pluginsdk.Schema {
return map[string]*pluginsdk.Schema{
"group_ids": {
Type: pluginsdk.TypeList,
Computed: true,
Elem: &pluginsdk.Schema{
Type: pluginsdk.TypeString,
},
},
"link_action_required": {
Type: pluginsdk.TypeString,
Computed: true,
},
"private_endpoint_id": {
Type: pluginsdk.TypeString,
Computed: true,
},
}
}

func (m PrivateEndpointConnectionResource) ModelObject() interface{} {
return &PrivateEndpointConnectionModel{}
}

func (m PrivateEndpointConnectionResource) ResourceType() string {
return "azurerm_automation_private_endpoint_connection"
}

func (m PrivateEndpointConnectionResource) Create() sdk.ResourceFunc {
return sdk.ResourceFunc{
Timeout: 30 * time.Minute,
Func: func(ctx context.Context, meta sdk.ResourceMetaData) error {
client := meta.Client.Automation.PrivateEndpointClient

var model PrivateEndpointConnectionModel
if err := meta.Decode(&model); err != nil {
return err
}

subscriptionID := meta.Client.Account.SubscriptionId
id := parse.NewPrivateEndpointConnectionID(subscriptionID, model.ResourceGroupName,
model.AutomationAccountName, model.Name)
existing, err := client.Get(ctx, id.ResourceGroup, id.AutomationAccountName, id.Name)
if err != nil {
return fmt.Errorf("retreiving %s: %v", id, err)
}
if utils.ResponseWasNotFound(existing.Response) {
return fmt.Errorf("no such private endpoint connection: %v", id)
}

var params automation.PrivateEndpointConnection
params.PrivateEndpointConnectionProperties = &automation.PrivateEndpointConnectionProperties{
PrivateLinkServiceConnectionState: &automation.PrivateLinkServiceConnectionStateProperty{},
}
if model.LinkStatus != "" {
params.PrivateLinkServiceConnectionState.Status = utils.String(model.LinkStatus)
}
if model.LinkDescription != "" {
params.PrivateLinkServiceConnectionState.Description = utils.String(model.LinkDescription)
}
future, err := client.CreateOrUpdate(ctx, id.ResourceGroup, id.AutomationAccountName, id.Name, params)
if err != nil {
return fmt.Errorf("creating %s: %v", id, err)
}
// TODO may not need wait, delete lines below
if err := future.WaitForCompletionRef(ctx, client.Client); err != nil {
return fmt.Errorf("waiting for creation of %s: %v", id, err)
}

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

func (m PrivateEndpointConnectionResource) Read() sdk.ResourceFunc {
return sdk.ResourceFunc{
Timeout: 5 * time.Minute,
Func: func(ctx context.Context, meta sdk.ResourceMetaData) error {
id, err := parse.PrivateEndpointConnectionID(meta.ResourceData.Id())
if err != nil {
return err
}
client := meta.Client.Automation.PrivateEndpointClient
result, err := client.Get(ctx, id.ResourceGroup, id.AutomationAccountName, id.Name)
if err != nil {
return err
}

var output PrivateEndpointConnectionModel
output.Name = id.Name
output.ResourceGroupName = id.ResourceGroup
output.AutomationAccountName = id.AutomationAccountName
if result.PrivateEndpoint != nil {
output.PrivateEndpointID = utils.NormalizeNilableString(result.PrivateEndpoint.ID)
}
if prop := result.PrivateEndpointConnectionProperties; prop != nil {
if state := prop.PrivateLinkServiceConnectionState; state != nil {
output.LinkStatus = utils.NormalizeNilableString(state.Status)
output.LinkDescription = utils.NormalizeNilableString(state.Description)
output.LinkActionRequired = utils.NormalizeNilableString(state.ActionsRequired)
}
if point := prop.PrivateEndpoint; point != nil {
output.PrivateEndpointID = utils.NormalizeNilableString(point.ID)
}
// no group id in definition
}
return meta.Encode(&output)
},
}
}

func (m PrivateEndpointConnectionResource) Update() sdk.ResourceFunc {
return sdk.ResourceFunc{
Timeout: 10 * time.Minute,
Func: func(ctx context.Context, meta sdk.ResourceMetaData) (err error) {
client := meta.Client.Automation.PrivateEndpointClient

id, err := parse.PrivateEndpointConnectionID(meta.ResourceData.Id())
if err != nil {
return err
}

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

var upd automation.PrivateEndpointConnection
upd.PrivateEndpointConnectionProperties = &automation.PrivateEndpointConnectionProperties{}
upd.PrivateEndpointConnectionProperties.PrivateLinkServiceConnectionState = &automation.PrivateLinkServiceConnectionStateProperty{}
if meta.ResourceData.HasChange("link_status") {
upd.PrivateLinkServiceConnectionState.Status = utils.String(model.LinkStatus)
}
if meta.ResourceData.HasChange("link_description") {
upd.PrivateLinkServiceConnectionState.Description = utils.String(model.LinkDescription)
}
if _, err = client.CreateOrUpdate(ctx, id.ResourceGroup, id.AutomationAccountName, id.Name, upd); err != nil {
return fmt.Errorf("updating %s: %v", id, err)
}

return nil
},
}
}

func (m PrivateEndpointConnectionResource) Delete() sdk.ResourceFunc {
return sdk.ResourceFunc{
Timeout: 10 * time.Minute,
Func: func(ctx context.Context, meta sdk.ResourceMetaData) error {
id, err := parse.PrivateEndpointConnectionID(meta.ResourceData.Id())
if err != nil {
return err
}
meta.Logger.Infof("deleting %s", id)
client := meta.Client.Automation.PrivateEndpointClient
if _, err = client.Delete(ctx, id.ResourceGroup, id.AutomationAccountName, id.Name); err != nil {
return fmt.Errorf("deleting %s: %v", id, err)
}
return nil
},
}
}

func (m PrivateEndpointConnectionResource) IDValidationFunc() pluginsdk.SchemaValidateFunc {
return validate.PrivateEndpointConnectionID
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
package automation_test

import (
"context"
"fmt"
"testing"

"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/services/automation"
"github.com/hashicorp/terraform-provider-azurerm/internal/services/automation/parse"
"github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk"
"github.com/hashicorp/terraform-provider-azurerm/utils"
)

type PrivateEndpointConnectionResource struct{}

func (a PrivateEndpointConnectionResource) Exists(ctx context.Context, client *clients.Client, state *pluginsdk.InstanceState) (*bool, error) {
id, err := parse.PrivateEndpointConnectionID(state.ID)
if err != nil {
return nil, err
}
resp, err := client.Automation.PrivateEndpointClient.Get(ctx, id.ResourceGroup, id.AutomationAccountName, id.Name)
if err != nil {
return nil, fmt.Errorf("retrieving Type %s: %+v", id, err)
}
return utils.Bool(resp.PrivateEndpointConnectionProperties != nil), nil
}

func (a PrivateEndpointConnectionResource) template(data acceptance.TestData) string {
return fmt.Sprintf(`
provider "azurerm" {
features {}
}
data "azurerm_subscription" "current" {}
resource "azurerm_resource_group" "test" {
name = "acctestRG-auto-%[1]d"
location = "%[2]s"
}
resource "azurerm_virtual_network" "test" {
name = "acctestvnet-%[1]d"
resource_group_name = azurerm_resource_group.test.name
location = azurerm_resource_group.test.location
address_space = ["10.5.0.0/16"]
}
resource "azurerm_subnet" "endpoint" {
name = "acctestsnetendpoint-%[1]d"
resource_group_name = azurerm_resource_group.test.name
virtual_network_name = azurerm_virtual_network.test.name
address_prefixes = ["10.5.2.0/24"]
enforce_private_link_endpoint_network_policies = true
}
resource "azurerm_private_endpoint" "test" {
name = "acctest-pe-%[1]d"
resource_group_name = azurerm_resource_group.test.name
location = azurerm_resource_group.test.location
subnet_id = azurerm_subnet.endpoint.id
private_service_connection {
name = azurerm_automation_account.test.name
is_manual_connection = true
private_connection_resource_id = azurerm_automation_account.test.id
subresource_names = ["Webhook"]
request_message = "abc"
}
}
resource "azurerm_automation_account" "test" {
name = "acctestAA-%[1]d"
location = azurerm_resource_group.test.location
resource_group_name = azurerm_resource_group.test.name
sku_name = "Basic"
}
`, data.RandomInteger, data.Locations.Primary)
}

func (a PrivateEndpointConnectionResource) basic(data acceptance.TestData) string {
return fmt.Sprintf(`
%s
data "azurerm_automation_account" "test" {
name = azurerm_automation_account.test.name
resource_group_name = azurerm_resource_group.test.name
depends_on = [azurerm_private_endpoint.test]
}
resource "azurerm_automation_private_endpoint_connection" "test" {
name = data.azurerm_automation_account.test.private_endpoint_connection[0].name
resource_group_name = azurerm_resource_group.test.name
automation_account_name = azurerm_automation_account.test.name
link_status = "Approved"
link_description = "test description"
depends_on = [azurerm_private_endpoint.test]
}
`, a.template(data))
}

func (a PrivateEndpointConnectionResource) update(data acceptance.TestData) string {
return fmt.Sprintf(`
%s
data "azurerm_automation_account" "test" {
name = azurerm_automation_account.test.name
resource_group_name = azurerm_resource_group.test.name
}
resource "azurerm_automation_private_endpoint_connection" "test" {
name = azurerm_automation_account.test.private_endpoint_connection[0].name
resource_group_name = azurerm_resource_group.test.name
automation_account_name = azurerm_automation_account.test.name
link_status = "Rejected"
link_description = "approved 2"
}
`, a.template(data))
}

func TestAccPrivateEndpointConnection_basic(t *testing.T) {
data := acceptance.BuildTestData(t, automation.PrivateEndpointConnectionResource{}.ResourceType(), "test")
r := PrivateEndpointConnectionResource{}
data.ResourceTest(t, r, []acceptance.TestStep{
{
Config: r.basic(data),
Check: acceptance.ComposeTestCheckFunc(
check.That(data.ResourceName).ExistsInAzure(r),
),
},
data.ImportStep(),
})
}

func TestAccPrivateEndpointConnection_update(t *testing.T) {
data := acceptance.BuildTestData(t, automation.PrivateEndpointConnectionResource{}.ResourceType(), "test")
r := PrivateEndpointConnectionResource{}
data.ResourceTest(t, r, []acceptance.TestStep{
{
Config: r.basic(data),
Check: acceptance.ComposeTestCheckFunc(
check.That(data.ResourceName).ExistsInAzure(r),
),
},
data.ImportStep(),
{
Config: r.update(data),
Check: acceptance.ComposeTestCheckFunc(
check.That(data.ResourceName).ExistsInAzure(r),
),
},
data.ImportStep(),
})
}
Loading

0 comments on commit b512f22

Please sign in to comment.