From b512f229df922286118a8ccd8d1f47f968f33c7f Mon Sep 17 00:00:00 2001 From: xuwu1 Date: Wed, 13 Jul 2022 18:21:28 +0800 Subject: [PATCH] new automation private endpoint connection resource --- .../automation_private_endpoint_connection.go | 228 ++++++++++++++++++ ...mation_private_endpoint_connection_test.go | 164 +++++++++++++ internal/services/automation/client/client.go | 5 + .../parse/private_endpoint_connection.go | 75 ++++++ .../parse/private_endpoint_connection_test.go | 128 ++++++++++ internal/services/automation/registration.go | 1 + internal/services/automation/resourceids.go | 1 + .../private_endpoint_connection_id.go | 23 ++ .../private_endpoint_connection_id_test.go | 88 +++++++ ..._private_endpoint_connection.html.markdown | 68 ++++++ 10 files changed, 781 insertions(+) create mode 100644 internal/services/automation/automation_private_endpoint_connection.go create mode 100644 internal/services/automation/automation_private_endpoint_connection_test.go create mode 100644 internal/services/automation/parse/private_endpoint_connection.go create mode 100644 internal/services/automation/parse/private_endpoint_connection_test.go create mode 100644 internal/services/automation/validate/private_endpoint_connection_id.go create mode 100644 internal/services/automation/validate/private_endpoint_connection_id_test.go create mode 100644 website/docs/r/automation_private_endpoint_connection.html.markdown diff --git a/internal/services/automation/automation_private_endpoint_connection.go b/internal/services/automation/automation_private_endpoint_connection.go new file mode 100644 index 000000000000..edeff767f288 --- /dev/null +++ b/internal/services/automation/automation_private_endpoint_connection.go @@ -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 +} diff --git a/internal/services/automation/automation_private_endpoint_connection_test.go b/internal/services/automation/automation_private_endpoint_connection_test.go new file mode 100644 index 000000000000..70573dba255d --- /dev/null +++ b/internal/services/automation/automation_private_endpoint_connection_test.go @@ -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(), + }) +} diff --git a/internal/services/automation/client/client.go b/internal/services/automation/client/client.go index 689c2a94654e..58a04362216e 100644 --- a/internal/services/automation/client/client.go +++ b/internal/services/automation/client/client.go @@ -18,6 +18,7 @@ type Client struct { DscNodeConfigurationClient *automation.DscNodeConfigurationClient JobScheduleClient *automation.JobScheduleClient ModuleClient *automation.ModuleClient + PrivateEndpointClient *automation.PrivateEndpointConnectionsClient RunbookClient *automation.RunbookClient RunbookDraftClient *automation.RunbookDraftClient RunBookWgClient *hybridrunbookworkergroup.HybridRunbookWorkerGroupClient @@ -57,6 +58,9 @@ func NewClient(o *common.ClientOptions) *Client { moduleClient := automation.NewModuleClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) o.ConfigureClient(&moduleClient.Client, o.ResourceManagerAuthorizer) + privateEndpointClient := automation.NewPrivateEndpointConnectionsClient(o.SubscriptionId) + o.ConfigureClient(&privateEndpointClient.Client, o.ResourceManagerAuthorizer) + runbookClient := automation.NewRunbookClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) o.ConfigureClient(&runbookClient.Client, o.ResourceManagerAuthorizer) @@ -86,6 +90,7 @@ func NewClient(o *common.ClientOptions) *Client { DscNodeConfigurationClient: &dscNodeConfigurationClient, JobScheduleClient: &jobScheduleClient, ModuleClient: &moduleClient, + PrivateEndpointClient: &privateEndpointClient, RunbookClient: &runbookClient, RunbookDraftClient: &runbookDraftClient, RunBookWgClient: &runbookWgClient, diff --git a/internal/services/automation/parse/private_endpoint_connection.go b/internal/services/automation/parse/private_endpoint_connection.go new file mode 100644 index 000000000000..5f69cff5c5a4 --- /dev/null +++ b/internal/services/automation/parse/private_endpoint_connection.go @@ -0,0 +1,75 @@ +package parse + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import ( + "fmt" + "strings" + + "github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids" +) + +type PrivateEndpointConnectionId struct { + SubscriptionId string + ResourceGroup string + AutomationAccountName string + Name string +} + +func NewPrivateEndpointConnectionID(subscriptionId, resourceGroup, automationAccountName, name string) PrivateEndpointConnectionId { + return PrivateEndpointConnectionId{ + SubscriptionId: subscriptionId, + ResourceGroup: resourceGroup, + AutomationAccountName: automationAccountName, + Name: name, + } +} + +func (id PrivateEndpointConnectionId) String() string { + segments := []string{ + fmt.Sprintf("Name %q", id.Name), + fmt.Sprintf("Automation Account Name %q", id.AutomationAccountName), + fmt.Sprintf("Resource Group %q", id.ResourceGroup), + } + segmentsStr := strings.Join(segments, " / ") + return fmt.Sprintf("%s: (%s)", "Private Endpoint Connection", segmentsStr) +} + +func (id PrivateEndpointConnectionId) ID() string { + fmtString := "/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Automation/automationAccounts/%s/privateEndpointConnections/%s" + return fmt.Sprintf(fmtString, id.SubscriptionId, id.ResourceGroup, id.AutomationAccountName, id.Name) +} + +// PrivateEndpointConnectionID parses a PrivateEndpointConnection ID into an PrivateEndpointConnectionId struct +func PrivateEndpointConnectionID(input string) (*PrivateEndpointConnectionId, error) { + id, err := resourceids.ParseAzureResourceID(input) + if err != nil { + return nil, err + } + + resourceId := PrivateEndpointConnectionId{ + 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.AutomationAccountName, err = id.PopSegment("automationAccounts"); err != nil { + return nil, err + } + if resourceId.Name, err = id.PopSegment("privateEndpointConnections"); err != nil { + return nil, err + } + + if err := id.ValidateNoEmptySegments(input); err != nil { + return nil, err + } + + return &resourceId, nil +} diff --git a/internal/services/automation/parse/private_endpoint_connection_test.go b/internal/services/automation/parse/private_endpoint_connection_test.go new file mode 100644 index 000000000000..89059a658adb --- /dev/null +++ b/internal/services/automation/parse/private_endpoint_connection_test.go @@ -0,0 +1,128 @@ +package parse + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import ( + "testing" + + "github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids" +) + +var _ resourceids.Id = PrivateEndpointConnectionId{} + +func TestPrivateEndpointConnectionIDFormatter(t *testing.T) { + actual := NewPrivateEndpointConnectionID("12345678-1234-9876-4563-123456789012", "group1", "account1", "conn1").ID() + expected := "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.Automation/automationAccounts/account1/privateEndpointConnections/conn1" + if actual != expected { + t.Fatalf("Expected %q but got %q", expected, actual) + } +} + +func TestPrivateEndpointConnectionID(t *testing.T) { + testData := []struct { + Input string + Error bool + Expected *PrivateEndpointConnectionId + }{ + + { + // 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 AutomationAccountName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.Automation/", + Error: true, + }, + + { + // missing value for AutomationAccountName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.Automation/automationAccounts/", + Error: true, + }, + + { + // missing Name + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.Automation/automationAccounts/account1/", + Error: true, + }, + + { + // missing value for Name + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.Automation/automationAccounts/account1/privateEndpointConnections/", + Error: true, + }, + + { + // valid + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.Automation/automationAccounts/account1/privateEndpointConnections/conn1", + Expected: &PrivateEndpointConnectionId{ + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "group1", + AutomationAccountName: "account1", + Name: "conn1", + }, + }, + + { + // upper-cased + Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/GROUP1/PROVIDERS/MICROSOFT.AUTOMATION/AUTOMATIONACCOUNTS/ACCOUNT1/PRIVATEENDPOINTCONNECTIONS/CONN1", + Error: true, + }, + } + + for _, v := range testData { + t.Logf("[DEBUG] Testing %q", v.Input) + + actual, err := PrivateEndpointConnectionID(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.AutomationAccountName != v.Expected.AutomationAccountName { + t.Fatalf("Expected %q but got %q for AutomationAccountName", v.Expected.AutomationAccountName, actual.AutomationAccountName) + } + if actual.Name != v.Expected.Name { + t.Fatalf("Expected %q but got %q for Name", v.Expected.Name, actual.Name) + } + } +} diff --git a/internal/services/automation/registration.go b/internal/services/automation/registration.go index b3d3cc41487b..f582f8535a4c 100644 --- a/internal/services/automation/registration.go +++ b/internal/services/automation/registration.go @@ -18,6 +18,7 @@ func (r Registration) Resources() []sdk.Resource { return []sdk.Resource{ AutomationConnectionTypeResource{}, HybridRunbookWorkerGroupResource{}, + PrivateEndpointConnectionResource{}, } } diff --git a/internal/services/automation/resourceids.go b/internal/services/automation/resourceids.go index 55b7f0fdd235..884210a253b5 100644 --- a/internal/services/automation/resourceids.go +++ b/internal/services/automation/resourceids.go @@ -9,6 +9,7 @@ package automation //go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=Module -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.Automation/automationAccounts/account1/modules/module1 //go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=NodeConfiguration -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.Automation/automationAccounts/account1/nodeConfigurations/nodeconfig1 //go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=Runbook -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.Automation/automationAccounts/account1/runbooks/runbook1 +//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=PrivateEndpointConnection -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.Automation/automationAccounts/account1/privateEndpointConnections/conn1 //go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=Configuration -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.Automation/automationAccounts/account1/configurations/config1 //go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=JobSchedule -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.Automation/automationAccounts/account1/jobSchedules/schedule1 //go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=Variable -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.Automation/automationAccounts/account1/variables/variable1 diff --git a/internal/services/automation/validate/private_endpoint_connection_id.go b/internal/services/automation/validate/private_endpoint_connection_id.go new file mode 100644 index 000000000000..77db72e1fca7 --- /dev/null +++ b/internal/services/automation/validate/private_endpoint_connection_id.go @@ -0,0 +1,23 @@ +package validate + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import ( + "fmt" + + "github.com/hashicorp/terraform-provider-azurerm/internal/services/automation/parse" +) + +func PrivateEndpointConnectionID(input interface{}, key string) (warnings []string, errors []error) { + v, ok := input.(string) + if !ok { + errors = append(errors, fmt.Errorf("expected %q to be a string", key)) + return + } + + if _, err := parse.PrivateEndpointConnectionID(v); err != nil { + errors = append(errors, err) + } + + return +} diff --git a/internal/services/automation/validate/private_endpoint_connection_id_test.go b/internal/services/automation/validate/private_endpoint_connection_id_test.go new file mode 100644 index 000000000000..a8ae4c8025da --- /dev/null +++ b/internal/services/automation/validate/private_endpoint_connection_id_test.go @@ -0,0 +1,88 @@ +package validate + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import "testing" + +func TestPrivateEndpointConnectionID(t *testing.T) { + cases := []struct { + Input string + Valid bool + }{ + + { + // empty + Input: "", + Valid: false, + }, + + { + // missing SubscriptionId + Input: "/", + Valid: false, + }, + + { + // missing value for SubscriptionId + Input: "/subscriptions/", + Valid: false, + }, + + { + // missing ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", + Valid: false, + }, + + { + // missing value for ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", + Valid: false, + }, + + { + // missing AutomationAccountName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.Automation/", + Valid: false, + }, + + { + // missing value for AutomationAccountName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.Automation/automationAccounts/", + Valid: false, + }, + + { + // missing Name + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.Automation/automationAccounts/account1/", + Valid: false, + }, + + { + // missing value for Name + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.Automation/automationAccounts/account1/privateEndpointConnections/", + Valid: false, + }, + + { + // valid + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.Automation/automationAccounts/account1/privateEndpointConnections/conn1", + Valid: true, + }, + + { + // upper-cased + Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/GROUP1/PROVIDERS/MICROSOFT.AUTOMATION/AUTOMATIONACCOUNTS/ACCOUNT1/PRIVATEENDPOINTCONNECTIONS/CONN1", + Valid: false, + }, + } + for _, tc := range cases { + t.Logf("[DEBUG] Testing Value %s", tc.Input) + _, errors := PrivateEndpointConnectionID(tc.Input, "test") + valid := len(errors) == 0 + + if tc.Valid != valid { + t.Fatalf("Expected %t but got %t", tc.Valid, valid) + } + } +} diff --git a/website/docs/r/automation_private_endpoint_connection.html.markdown b/website/docs/r/automation_private_endpoint_connection.html.markdown new file mode 100644 index 000000000000..a98e87bfcb78 --- /dev/null +++ b/website/docs/r/automation_private_endpoint_connection.html.markdown @@ -0,0 +1,68 @@ +--- +subcategory: "Automation" +layout: "azurerm" +page_title: "Azure Resource Manager: azurerm_automation_private_endpoint_connection" +description: |- + Manages a Automation Private Endpoint Connection. +--- + +# azurerm_automation_private_endpoint_connection + +Manages a Automation Private Endpoint Connection. + +## Example Usage + +```hcl +resource "azurerm_automation_private_endpoint_connection" "example" { + 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" +} +``` + +## Arguments Reference + +The following arguments are supported: + +* `automation_account_name` - (Required) TODO. Changing this forces a new Automation to be created. + +* `name` - (Required) The name which should be used for this Automation Private Endpoint Connection. Changing this forces a new Automation to be created. + +* `resource_group_name` - (Required) The name of the Resource Group where the Automation should exist. Changing this forces a new Automation to be created. + +* `link_status` - (Required) The Operation on this connection, Possible values are `Aprroved` and `Rejected`. + +--- + +* `link_description` - (Optional) Description of this operation. + +## Attributes Reference + +In addition to the Arguments listed above - the following Attributes are exported: + +* `id` - The ID of the AutomationPrivate Endpoint Connection. + +* `group_ids` - A list of stirng of the type of sub-resource your private endpoint will be able to access. + +* `link_action_required` - Any action that is required beyond basic workflow (approve/ reject/ disconnect). + +* `private_endpoint_id` - The ID of the the Private Endpoint of this connection belongs to. + +## Timeouts + +The `timeouts` block allows you to specify [timeouts](https://www.terraform.io/docs/configuration/resources.html#timeouts) for certain actions: + +* `create` - (Defaults to 30 minutes) Used when creating the Automation. +* `read` - (Defaults to 5 minutes) Used when retrieving the Automation. +* `update` - (Defaults to 10 minutes) Used when updating the Automation. +* `delete` - (Defaults to 10 minutes) Used when deleting the Automation. + +## Import + +Automations can be imported using the `resource id`, e.g. + +```shell +terraform import azurerm_automation_private_endpoint_connection.example /subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.Automation/automationAccounts/account1/privateEndpointConnections/uuid +``` \ No newline at end of file