diff --git a/internal/services/machinelearning/machine_learning_workspace_network_outbound_rule_private_endpoint_resource.go b/internal/services/machinelearning/machine_learning_workspace_network_outbound_rule_private_endpoint_resource.go new file mode 100644 index 000000000000..36e9eabbd9b4 --- /dev/null +++ b/internal/services/machinelearning/machine_learning_workspace_network_outbound_rule_private_endpoint_resource.go @@ -0,0 +1,251 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package machinelearning + +import ( + "context" + "fmt" + "strings" + "time" + + "github.com/hashicorp/go-azure-helpers/lang/pointer" + "github.com/hashicorp/go-azure-helpers/lang/response" + "github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids" + "github.com/hashicorp/go-azure-sdk/resource-manager/machinelearningservices/2024-04-01/managednetwork" + "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" + "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 resourceTypeSupportSubResType = map[string][]string{ + "Microsoft.KeyVault": {"vault"}, + "Microsoft.Cache": {"redisCache"}, + "Microsoft.MachineLearningServices": {"amlworkspace"}, + "Microsoft.Storage": {"blob", "table", "queue", "file", "web", "dfs"}, +} + +type machineLearningWorkspaceOutboundRulePrivateEndpointModel struct { + Name string `tfschema:"name"` + WorkspaceId string `tfschema:"workspace_id"` + ServiceResourceId string `tfschema:"service_resource_id"` + SubresourceTarget string `tfschema:"sub_resource_target"` + SparkEnabled bool `tfschema:"spark_enabled"` +} + +type WorkspaceNetworkOutboundRulePrivateEndpoint struct{} + +var _ sdk.Resource = WorkspaceNetworkOutboundRulePrivateEndpoint{} + +func (r WorkspaceNetworkOutboundRulePrivateEndpoint) ResourceType() string { + return "azurerm_machine_learning_workspace_network_outbound_rule_private_endpoint" +} + +func (r WorkspaceNetworkOutboundRulePrivateEndpoint) ModelObject() interface{} { + return &machineLearningWorkspaceOutboundRulePrivateEndpointModel{} +} + +func (r WorkspaceNetworkOutboundRulePrivateEndpoint) IDValidationFunc() pluginsdk.SchemaValidateFunc { + return managednetwork.ValidateOutboundRuleID +} + +func (r WorkspaceNetworkOutboundRulePrivateEndpoint) Arguments() map[string]*pluginsdk.Schema { + arguments := map[string]*pluginsdk.Schema{ + "name": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringIsNotEmpty, + }, + + "workspace_id": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: managednetwork.ValidateWorkspaceID, + }, + + "service_resource_id": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringIsNotEmpty, + }, + + "sub_resource_target": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringInSlice([]string{ + "vault", + "amlworkspace", + "blob", + "table", + "queue", + "file", + "web", + "dfs", + "redisCache", + }, false), + }, + + "spark_enabled": { + Type: pluginsdk.TypeBool, + Optional: true, + Default: false, + ForceNew: true, + }, + } + return arguments +} + +func (r WorkspaceNetworkOutboundRulePrivateEndpoint) Attributes() map[string]*pluginsdk.Schema { + return map[string]*pluginsdk.Schema{} +} + +func (r WorkspaceNetworkOutboundRulePrivateEndpoint) Create() sdk.ResourceFunc { + return sdk.ResourceFunc{ + Timeout: 30 * time.Minute, + Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error { + var model machineLearningWorkspaceOutboundRulePrivateEndpointModel + if err := metadata.Decode(&model); err != nil { + return fmt.Errorf("decoding: %+v", err) + } + + client := metadata.Client.MachineLearning.ManagedNetwork + subscriptionId := metadata.Client.Account.SubscriptionId + + workspaceId, err := managednetwork.ParseWorkspaceID(model.WorkspaceId) + if err != nil { + return err + } + id := managednetwork.NewOutboundRuleID(subscriptionId, workspaceId.ResourceGroupName, workspaceId.WorkspaceName, model.Name) + existing, err := client.SettingsRuleGet(ctx, id) + if err != nil { + if !response.WasNotFound(existing.HttpResponse) { + return fmt.Errorf("checking for presence of existing %s: %+v", id, err) + } + } + if !response.WasNotFound(existing.HttpResponse) { + return tf.ImportAsExistsError("azurerm_machine_learning_workspace_network_outbound_rule_private_endpoint", id.ID()) + } + + resId, err := resourceids.ParseAzureResourceID(model.ServiceResourceId) + if err != nil { + return fmt.Errorf(" parsing resource ID: %+v", err) + } + + supportType := false + if subTypes, ok := resourceTypeSupportSubResType[resId.Provider]; ok { + for _, typ := range subTypes { + if strings.EqualFold(typ, model.SubresourceTarget) { + supportType = true + break + } + } + } + + if !supportType { + return fmt.Errorf(" unsupported resource type: %s. Sub resource type supported by Service Resource ID: %s is %s ", + model.SubresourceTarget, model.ServiceResourceId, + strings.Join(resourceTypeSupportSubResType[resId.Provider], ", ")) + } + + outboundRule := managednetwork.OutboundRuleBasicResource{ + Name: pointer.To(model.Name), + Type: pointer.To(string(managednetwork.RuleTypePrivateEndpoint)), + Properties: managednetwork.PrivateEndpointOutboundRule{ + Category: pointer.To(managednetwork.RuleCategoryUserDefined), + Destination: &managednetwork.PrivateEndpointDestination{ + ServiceResourceId: pointer.To(model.ServiceResourceId), + SubresourceTarget: pointer.To(model.SubresourceTarget), + SparkEnabled: pointer.To(model.SparkEnabled), + }, + }, + } + + if err = client.SettingsRuleCreateOrUpdateThenPoll(ctx, id, outboundRule); err != nil { + return fmt.Errorf("creating %s: %+v", id, err) + } + + metadata.SetID(id) + return nil + }, + } +} + +func (r WorkspaceNetworkOutboundRulePrivateEndpoint) Read() sdk.ResourceFunc { + return sdk.ResourceFunc{ + Timeout: 5 * time.Minute, + Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error { + client := metadata.Client.MachineLearning.ManagedNetwork + + id, err := managednetwork.ParseOutboundRuleID(metadata.ResourceData.Id()) + if err != nil { + return err + } + + resp, err := client.SettingsRuleGet(ctx, *id) + if err != nil { + if response.WasNotFound(resp.HttpResponse) { + return metadata.MarkAsGone(id) + } + + return fmt.Errorf("retrieving %s: %+v", *id, err) + } + + model := resp.Model + if model == nil { + return fmt.Errorf("retrieving %s: model was nil", id) + } + + state := machineLearningWorkspaceOutboundRulePrivateEndpointModel{ + Name: id.OutboundRuleName, + } + + if props := model.Properties; props != nil { + if prop, ok := props.(managednetwork.PrivateEndpointOutboundRule); ok && prop.Destination != nil { + if prop.Destination.SparkEnabled != nil { + state.SparkEnabled = *prop.Destination.SparkEnabled + } + + if prop.Destination.SubresourceTarget != nil { + state.SubresourceTarget = *prop.Destination.SubresourceTarget + } + + if prop.Destination.ServiceResourceId != nil { + state.ServiceResourceId = *prop.Destination.ServiceResourceId + } + } + } + state.WorkspaceId = managednetwork.NewWorkspaceID(id.SubscriptionId, id.ResourceGroupName, id.WorkspaceName).ID() + return metadata.Encode(&state) + }, + } +} + +func (r WorkspaceNetworkOutboundRulePrivateEndpoint) Delete() sdk.ResourceFunc { + return sdk.ResourceFunc{ + Timeout: 30 * time.Minute, + Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error { + client := metadata.Client.MachineLearning.ManagedNetwork + + id, err := managednetwork.ParseOutboundRuleID(metadata.ResourceData.Id()) + if err != nil { + return err + } + + future, err := client.SettingsRuleDelete(ctx, *id) + if err != nil { + return fmt.Errorf("deleting Machine Learning Workspace Private Endpoint Network Outbound Rule %q (Resource Group %q, Workspace %q): %+v", id.OutboundRuleName, id.ResourceGroupName, id.WorkspaceName, err) + } + + if err = future.Poller.PollUntilDone(ctx); err != nil { + return fmt.Errorf("waiting for deletion of Machine Learning Workspace Private Endpoint Network Outbound Rule %q (Resource Group %q, Workspace %q): %+v", id.OutboundRuleName, id.ResourceGroupName, id.WorkspaceName, err) + } + + return nil + }, + } +} diff --git a/internal/services/machinelearning/machine_learning_workspace_network_outbound_rule_private_endpoint_resource_test.go b/internal/services/machinelearning/machine_learning_workspace_network_outbound_rule_private_endpoint_resource_test.go new file mode 100644 index 000000000000..9aa5598947a8 --- /dev/null +++ b/internal/services/machinelearning/machine_learning_workspace_network_outbound_rule_private_endpoint_resource_test.go @@ -0,0 +1,475 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package machinelearning_test + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/go-azure-helpers/lang/pointer" + "github.com/hashicorp/go-azure-helpers/lang/response" + "github.com/hashicorp/go-azure-sdk/resource-manager/machinelearningservices/2024-04-01/managednetwork" + "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" +) + +type WorkspaceNetworkOutboundPrivateEndpointResource struct{} + +func TestAccMachineLearningWorkspaceNetworkOutboundRulePrivateEndpoint_onlyApprovedOutbound(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_machine_learning_workspace_network_outbound_rule_private_endpoint", "test") + r := WorkspaceNetworkOutboundPrivateEndpointResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.onlyApprovedOutbound(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("service_resource_id").Exists(), + ), + }, + data.ImportStep(), + }) +} + +func TestAccMachineLearningWorkspaceNetworkOutboundRulePrivateEndpoint_internetOutbound(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_machine_learning_workspace_network_outbound_rule_private_endpoint", "test") + r := WorkspaceNetworkOutboundPrivateEndpointResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.internetOutbound(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("service_resource_id").Exists(), + ), + }, + data.ImportStep(), + }) +} + +func TestAccMachineLearningWorkspaceNetworkOutboundRulePrivateEndpoint_keyVault(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_machine_learning_workspace_network_outbound_rule_private_endpoint", "test") + r := WorkspaceNetworkOutboundPrivateEndpointResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.withKeyVault(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("service_resource_id").Exists(), + ), + }, + data.ImportStep(), + }) +} + +func TestAccMachineLearningWorkspaceNetworkOutboundRulePrivateEndpoint_workspace(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_machine_learning_workspace_network_outbound_rule_private_endpoint", "test") + r := WorkspaceNetworkOutboundPrivateEndpointResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.withWorkspace(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("service_resource_id").Exists(), + ), + }, + data.ImportStep(), + }) +} + +func TestAccMachineLearningWorkspaceNetworkOutboundRulePrivateEndpoint_redis(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_machine_learning_workspace_network_outbound_rule_private_endpoint", "test") + r := WorkspaceNetworkOutboundPrivateEndpointResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.withRedis(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("service_resource_id").Exists(), + ), + }, + data.ImportStep(), + }) +} + +func TestAccMachineLearningWorkspaceNetworkOutboundRulePrivateEndpoint_requiresImport(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_machine_learning_workspace_network_outbound_rule_private_endpoint", "test") + r := WorkspaceNetworkOutboundPrivateEndpointResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.onlyApprovedOutbound(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.RequiresImportErrorStep(r.requiresImport), + }) +} + +func (r WorkspaceNetworkOutboundPrivateEndpointResource) Exists(ctx context.Context, client *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { + maangedNetworkClient := client.MachineLearning.ManagedNetwork + id, err := managednetwork.ParseOutboundRuleID(state.ID) + if err != nil { + return nil, err + } + + resp, err := maangedNetworkClient.SettingsRuleGet(ctx, *id) + if err != nil { + if response.WasNotFound(resp.HttpResponse) { + return pointer.To(false), nil + } + return nil, fmt.Errorf("retrieving Machine Learning Workspace Outbound Rule Private Endpoint %q: %+v", state.ID, err) + } + + return pointer.To(resp.Model.Properties != nil), nil +} + +func (r WorkspaceNetworkOutboundPrivateEndpointResource) template(data acceptance.TestData) string { + return fmt.Sprintf(` +data "azurerm_client_config" "current" {} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-ml-%[1]d" + location = "%[2]s" +} + +resource "azurerm_application_insights" "test" { + name = "acctestai-%[1]d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + application_type = "web" +} + +resource "azurerm_key_vault" "test" { + name = "acctestvault%[3]s" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + tenant_id = data.azurerm_client_config.current.tenant_id + + sku_name = "standard" + + purge_protection_enabled = true +} + +resource "azurerm_key_vault_access_policy" "test" { + key_vault_id = azurerm_key_vault.test.id + tenant_id = data.azurerm_client_config.current.tenant_id + object_id = data.azurerm_client_config.current.object_id + + key_permissions = [ + "Create", + "Get", + "Delete", + "Purge", + "GetRotationPolicy", + ] +} + +resource "azurerm_storage_account" "test" { + name = "acctestsa%[4]d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + account_tier = "Standard" + account_replication_type = "LRS" +}`, data.RandomInteger, data.Locations.Primary, data.RandomString, data.RandomIntOfLength(10)) +} + +func (r WorkspaceNetworkOutboundPrivateEndpointResource) onlyApprovedOutbound(data acceptance.TestData) string { + template := r.template(data) + return fmt.Sprintf(` +provider "azurerm" { + features { + key_vault { + purge_soft_delete_on_destroy = false + purge_soft_deleted_keys_on_destroy = false + } + resource_group { + prevent_deletion_if_contains_resources = false + } + } +} + +%[1]s + +resource "azurerm_machine_learning_workspace" "test" { + name = "acctest-MLW-%[2]d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + application_insights_id = azurerm_application_insights.test.id + key_vault_id = azurerm_key_vault.test.id + storage_account_id = azurerm_storage_account.test.id + + managed_network { + isolation_mode = "AllowOnlyApprovedOutbound" + } + identity { + type = "SystemAssigned" + } +} + +resource "azurerm_storage_account" "test2" { + name = "acctestsa%[3]s" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + account_tier = "Standard" + account_replication_type = "LRS" +} + +resource "azurerm_machine_learning_workspace_network_outbound_rule_private_endpoint" "test" { + name = "acctest-MLW-outboundrule-%[3]s" + workspace_id = azurerm_machine_learning_workspace.test.id + service_resource_id = azurerm_storage_account.test2.id + sub_resource_target = "blob" +} +`, template, data.RandomInteger, data.RandomString) +} + +func (r WorkspaceNetworkOutboundPrivateEndpointResource) internetOutbound(data acceptance.TestData) string { + template := r.template(data) + return fmt.Sprintf(` +provider "azurerm" { + features { + key_vault { + purge_soft_delete_on_destroy = false + purge_soft_deleted_keys_on_destroy = false + } + resource_group { + prevent_deletion_if_contains_resources = false + } + } +} + +%[1]s + +resource "azurerm_machine_learning_workspace" "test" { + name = "acctest-MLW-%[2]d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + application_insights_id = azurerm_application_insights.test.id + key_vault_id = azurerm_key_vault.test.id + storage_account_id = azurerm_storage_account.test.id + + managed_network { + isolation_mode = "AllowInternetOutbound" + } + identity { + type = "SystemAssigned" + } +} + +resource "azurerm_storage_account" "test2" { + name = "acctestsa%[3]s" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + account_tier = "Standard" + account_replication_type = "LRS" +} + +resource "azurerm_machine_learning_workspace_network_outbound_rule_private_endpoint" "test" { + name = "acctest-MLW-outboundrule-%[3]s" + workspace_id = azurerm_machine_learning_workspace.test.id + service_resource_id = azurerm_storage_account.test2.id + sub_resource_target = "blob" +} +`, template, data.RandomInteger, data.RandomStringOfLength(6)) +} + +func (r WorkspaceNetworkOutboundPrivateEndpointResource) withKeyVault(data acceptance.TestData) string { + template := r.template(data) + return fmt.Sprintf(` +provider "azurerm" { + features { + key_vault { + purge_soft_delete_on_destroy = false + purge_soft_deleted_keys_on_destroy = false + } + resource_group { + prevent_deletion_if_contains_resources = false + } + } +} + +%[1]s + +resource "azurerm_machine_learning_workspace" "test" { + name = "acctest-MLW-%[2]d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + application_insights_id = azurerm_application_insights.test.id + key_vault_id = azurerm_key_vault.test.id + storage_account_id = azurerm_storage_account.test.id + + managed_network { + isolation_mode = "AllowOnlyApprovedOutbound" + } + identity { + type = "SystemAssigned" + } +} + +resource "azurerm_key_vault" "test2" { + name = "acctestvault%[3]s" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + tenant_id = data.azurerm_client_config.current.tenant_id + + sku_name = "standard" + + purge_protection_enabled = true +} + +resource "azurerm_key_vault_access_policy" "test2" { + key_vault_id = azurerm_key_vault.test2.id + tenant_id = data.azurerm_client_config.current.tenant_id + object_id = data.azurerm_client_config.current.object_id + + key_permissions = [ + "Create", + "Get", + "Delete", + "Purge", + "GetRotationPolicy", + ] +} + +resource "azurerm_machine_learning_workspace_network_outbound_rule_private_endpoint" "test" { + name = "acctest-MLW-outboundrule-%[3]s" + workspace_id = azurerm_machine_learning_workspace.test.id + service_resource_id = azurerm_key_vault.test2.id + sub_resource_target = "vault" +} +`, template, data.RandomInteger, data.RandomStringOfLength(6)) +} + +func (r WorkspaceNetworkOutboundPrivateEndpointResource) withWorkspace(data acceptance.TestData) string { + template := r.template(data) + return fmt.Sprintf(` +provider "azurerm" { + features { + key_vault { + purge_soft_delete_on_destroy = false + purge_soft_deleted_keys_on_destroy = false + } + resource_group { + prevent_deletion_if_contains_resources = false + } + } +} + +%[1]s + +resource "azurerm_machine_learning_workspace" "test" { + name = "acctest-MLW-%[2]d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + application_insights_id = azurerm_application_insights.test.id + key_vault_id = azurerm_key_vault.test.id + storage_account_id = azurerm_storage_account.test.id + + managed_network { + isolation_mode = "AllowOnlyApprovedOutbound" + } + identity { + type = "SystemAssigned" + } +} + +resource "azurerm_machine_learning_workspace" "test2" { + name = "acctest-MLW2-%[2]d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + application_insights_id = azurerm_application_insights.test.id + key_vault_id = azurerm_key_vault.test.id + storage_account_id = azurerm_storage_account.test.id + + identity { + type = "SystemAssigned" + } +} + +resource "azurerm_machine_learning_workspace_network_outbound_rule_private_endpoint" "test" { + name = "acctest-MLW-outboundrule-%[3]s" + workspace_id = azurerm_machine_learning_workspace.test.id + service_resource_id = azurerm_machine_learning_workspace.test2.id + sub_resource_target = "amlworkspace" +} +`, template, data.RandomInteger, data.RandomStringOfLength(6)) +} + +func (r WorkspaceNetworkOutboundPrivateEndpointResource) withRedis(data acceptance.TestData) string { + template := r.template(data) + return fmt.Sprintf(` +provider "azurerm" { + features { + key_vault { + purge_soft_delete_on_destroy = false + purge_soft_deleted_keys_on_destroy = false + } + resource_group { + prevent_deletion_if_contains_resources = false + } + } +} + +%[1]s + +resource "azurerm_machine_learning_workspace" "test" { + name = "acctest-MLW-%[2]d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + application_insights_id = azurerm_application_insights.test.id + key_vault_id = azurerm_key_vault.test.id + storage_account_id = azurerm_storage_account.test.id + + managed_network { + isolation_mode = "AllowOnlyApprovedOutbound" + } + identity { + type = "SystemAssigned" + } +} + +resource "azurerm_redis_cache" "test" { + name = "acctest-mlwcache-%[3]s" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + capacity = 2 + family = "C" + sku_name = "Standard" + non_ssl_port_enabled = false + minimum_tls_version = "1.2" + + redis_configuration { + } +} + +resource "azurerm_machine_learning_workspace_network_outbound_rule_private_endpoint" "test" { + name = "acctest-MLW-outboundrule-%[3]s" + workspace_id = azurerm_machine_learning_workspace.test.id + service_resource_id = azurerm_redis_cache.test.id + sub_resource_target = "redisCache" +} +`, template, data.RandomInteger, data.RandomStringOfLength(6)) +} + +func (r WorkspaceNetworkOutboundPrivateEndpointResource) requiresImport(data acceptance.TestData) string { + template := r.onlyApprovedOutbound(data) + return fmt.Sprintf(` +%s + +resource "azurerm_machine_learning_workspace_network_outbound_rule_private_endpoint" "import" { + name = azurerm_machine_learning_workspace_network_outbound_rule_private_endpoint.test.name + workspace_id = azurerm_machine_learning_workspace_network_outbound_rule_private_endpoint.test.workspace_id + service_resource_id = azurerm_machine_learning_workspace_network_outbound_rule_private_endpoint.test.service_resource_id + sub_resource_target = azurerm_machine_learning_workspace_network_outbound_rule_private_endpoint.test.sub_resource_target +} +`, template) +} diff --git a/internal/services/machinelearning/registration.go b/internal/services/machinelearning/registration.go index ffcb53b87cf5..040f014d7765 100644 --- a/internal/services/machinelearning/registration.go +++ b/internal/services/machinelearning/registration.go @@ -58,5 +58,6 @@ func (r Registration) Resources() []sdk.Resource { MachineLearningDataStoreDataLakeGen2{}, MachineLearningDataStoreFileShare{}, WorkspaceNetworkOutboundRuleFqdn{}, + WorkspaceNetworkOutboundRulePrivateEndpoint{}, } } diff --git a/website/docs/r/machine_learning_workspace_network_outbound_rule_private_endpoint.html.markdown b/website/docs/r/machine_learning_workspace_network_outbound_rule_private_endpoint.html.markdown new file mode 100644 index 000000000000..19afda5235df --- /dev/null +++ b/website/docs/r/machine_learning_workspace_network_outbound_rule_private_endpoint.html.markdown @@ -0,0 +1,128 @@ +--- +subcategory: "Machine Learning" +layout: "azurerm" +page_title: "Azure Resource Manager: azurerm_machine_learning_workspace_network_outbound_rule_private_endpoint" +description: |- + Manages an Azure Machine Learning Workspace Private Endpoint Network Outbound Rule . +--- + +# azurerm_machine_learning_workspace_network_outbound_rule_private_endpoint + +Manages an Azure Machine Learning Workspace Private Endpoint Network Outbound Rule . + +## Example Usage + +```hcl +provider "azurerm" { + features {} +} + +data "azurerm_client_config" "current" {} + +resource "azurerm_resource_group" "example" { + name = "example-resources" + location = "West Europe" +} + +resource "azurerm_application_insights" "example" { + name = "workspace-example-ai" + location = azurerm_resource_group.example.location + resource_group_name = azurerm_resource_group.example.name + application_type = "web" +} + +resource "azurerm_key_vault" "example" { + name = "workspaceexamplekeyvault" + location = azurerm_resource_group.example.location + resource_group_name = azurerm_resource_group.example.name + tenant_id = data.azurerm_client_config.current.tenant_id + sku_name = "premium" +} + +resource "azurerm_storage_account" "example" { + name = "workspacestorageaccount" + location = azurerm_resource_group.example.location + resource_group_name = azurerm_resource_group.example.name + account_tier = "Standard" + account_replication_type = "GRS" +} + +resource "azurerm_machine_learning_workspace" "example" { + name = "example-workspace" + location = azurerm_resource_group.example.location + resource_group_name = azurerm_resource_group.example.name + application_insights_id = azurerm_application_insights.example.id + key_vault_id = azurerm_key_vault.example.id + storage_account_id = azurerm_storage_account.example.id + + managed_network { + isolation_mode = "AllowOnlyApprovedOutbound" + } + + identity { + type = "SystemAssigned" + } +} + +resource "azurerm_storage_account" "example2" { + name = "example-sa" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + account_tier = "Standard" + account_replication_type = "LRS" +} + +resource "azurerm_machine_learning_workspace_network_outbound_rule_private_endpoint" "example" { + name = "example-outboundrule" + workspace_id = azurerm_machine_learning_workspace.example.id + service_resource_id = azurerm_storage_account.example2.id + sub_resource_target = "blob" +} +``` + +## Argument Reference + +The following arguments are supported: + +* `name` - (Required) Specifies the name of the Machine Learning Workspace Private Endpoint Network Outbound Rule. Changing this forces a new resource to be created. + +* `workspace_id` - (Required) Specifies the ID of the Machine Learning Workspace. Changing this forces a new resource to be created. + +* `service_resource_id` - (Required) Specifies the Service Resource ID to connect. Changing this forces a new resource to be created. + +~> **Note** Supported service resources: **Key Vault**, **Storage Account**, **Machine Learning Workspace**, **Redis**. + +* `sub_resource_target` - (Required) Specifies the Sub Resource of the service resource to connect to. Possible values are `vault`,`amlworkspace`,`blob`,`table`,`queue`,`file`,`web`,`dfs`, `redisCache`. Changing this forces a new resource to be created. + + | Service | Sub Resource Type | + |----------------------------|-------------------------------------------| + | Machine Learning Workspace | `amlworkspace` | + | Redis | `redisCache` | + | Storage Account | `blob`,`table`,`queue`,`file`,`web`,`dfs` | + | Key Vault | `vault` | + +* `spark_enabled` - (Optional) Whether to enable an additional private endpoint to be used by jobs running on Spark. Changing this forces a new resource to be created. + +## Attributes Reference + +In addition to the Arguments listed above - the following Attributes are exported: + +* `id` - The ID of the Machine Learning Workspace Private Endpoint Network Outbound rule. + +### Timeouts + +The `timeouts` block allows you to +specify [timeouts](https://www.terraform.io/language/resources/syntax#operation-timeouts) for certain actions: + +* `create` - (Defaults to 30 minutes) Used when creating the Machine Learning Workspace Private Endpoint Network Outbound Rule. +* `update` - (Defaults to 30 minutes) Used when updating the Machine Learning Workspace Private Endpoint Network Outbound Rule. +* `read` - (Defaults to 5 minutes) Used when retrieving the Machine Learning Workspace Private Endpoint Network Outbound Rule. +* `delete` - (Defaults to 30 minutes) Used when deleting the Machine Learning Workspace Private Endpoint Network Outbound Rule. + +## Import + +Machine Learning Workspace Private Endpoint Network Outbound Rule can be imported using the `resource id`, e.g. + +```shell +terraform import azurerm_machine_learning_workspace_network_outbound_rule_private_endpoint.example /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/group1/providers/Microsoft.MachineLearningServices/workspaces/workspace1/outboundRules/rule1 +```