From ecd9c2b9d412e96455bd23b0f2ee725b2975b9d1 Mon Sep 17 00:00:00 2001 From: Felipe Rezende Date: Tue, 28 Jan 2025 13:12:47 -0300 Subject: [PATCH] `azurerm_cognitive_account`: allows `bypass` property for `network_acls` (#28221) * feature: adding bypass property * test: unit testing for bypass * doc: adding information about bypass property * test: added one more validation step * fix: test networkacls * fix: support for the kind of OpenAI only * chore: executed terrafmt fmt command * fix: bypass for the kind OpenAI default value * fix: PR adjustments * Fix formatting in cognitive_account documentation --- .../cognitive/cognitive_account_resource.go | 36 ++++- .../cognitive_account_resource_test.go | 149 +++++++++++++++++- .../docs/r/cognitive_account.html.markdown | 4 + 3 files changed, 183 insertions(+), 6 deletions(-) diff --git a/internal/services/cognitive/cognitive_account_resource.go b/internal/services/cognitive/cognitive_account_resource.go index 822ac9e597d9..36ee4c3684e1 100644 --- a/internal/services/cognitive/cognitive_account_resource.go +++ b/internal/services/cognitive/cognitive_account_resource.go @@ -241,6 +241,15 @@ func resourceCognitiveAccount() *pluginsdk.Resource { }, }, }, + + "bypass": { + Type: pluginsdk.TypeString, + Optional: true, + ValidateFunc: validation.StringInSlice( + cognitiveservicesaccounts.PossibleValuesForByPassSelection(), + false, + ), + }, }, }, }, @@ -343,7 +352,10 @@ func resourceCognitiveAccountCreate(d *pluginsdk.ResourceData, meta interface{}) Name: d.Get("sku_name").(string), } - networkAcls, subnetIds := expandCognitiveAccountNetworkAcls(d) + networkAcls, subnetIds, err := expandCognitiveAccountNetworkAcls(d) + if err != nil { + return err + } // also lock on the Virtual Network ID's since modifications in the networking stack are exclusive virtualNetworkNames := make([]string, 0) @@ -429,7 +441,10 @@ func resourceCognitiveAccountUpdate(d *pluginsdk.ResourceData, meta interface{}) Name: d.Get("sku_name").(string), } - networkAcls, subnetIds := expandCognitiveAccountNetworkAcls(d) + networkAcls, subnetIds, err := expandCognitiveAccountNetworkAcls(d) + if err != nil { + return err + } // also lock on the Virtual Network ID's since modifications in the networking stack are exclusive virtualNetworkNames := make([]string, 0) @@ -662,11 +677,11 @@ func cognitiveAccountStateRefreshFunc(ctx context.Context, client *cognitiveserv } } -func expandCognitiveAccountNetworkAcls(d *pluginsdk.ResourceData) (*cognitiveservicesaccounts.NetworkRuleSet, []string) { +func expandCognitiveAccountNetworkAcls(d *pluginsdk.ResourceData) (*cognitiveservicesaccounts.NetworkRuleSet, []string, error) { input := d.Get("network_acls").([]interface{}) subnetIds := make([]string, 0) if len(input) == 0 || input[0] == nil { - return nil, subnetIds + return nil, subnetIds, nil } v := input[0].(map[string]interface{}) @@ -701,7 +716,17 @@ func expandCognitiveAccountNetworkAcls(d *pluginsdk.ResourceData) (*cognitiveser IPRules: &ipRules, VirtualNetworkRules: &networkRules, } - return &ruleSet, subnetIds + + if b, ok := d.GetOk("network_acls.0.bypass"); ok && b != "" { + kind := d.Get("kind").(string) + if kind != "OpenAI" { + return nil, nil, fmt.Errorf("the `network_acls.bypass` does not support Trusted Services for the kind %q", kind) + } + bypasss := cognitiveservicesaccounts.ByPassSelection(v["bypass"].(string)) + ruleSet.Bypass = &bypasss + } + + return &ruleSet, subnetIds, nil } func expandCognitiveAccountStorage(input []interface{}) *[]cognitiveservicesaccounts.UserOwnedStorage { @@ -803,6 +828,7 @@ func flattenCognitiveAccountNetworkAcls(input *cognitiveservicesaccounts.Network } return []interface{}{map[string]interface{}{ + "bypass": input.Bypass, "default_action": input.DefaultAction, "ip_rules": pluginsdk.NewSet(pluginsdk.HashString, ipRules), "virtual_network_rules": virtualNetworkRules, diff --git a/internal/services/cognitive/cognitive_account_resource_test.go b/internal/services/cognitive/cognitive_account_resource_test.go index 96a8ac43715d..83b4db6da5cd 100644 --- a/internal/services/cognitive/cognitive_account_resource_test.go +++ b/internal/services/cognitive/cognitive_account_resource_test.go @@ -291,6 +291,47 @@ func TestAccCognitiveAccount_networkAclsVirtualNetworkRules(t *testing.T) { }) } +func TestAccCognitiveAccount_networkAclsVirtualNetworkRulesWithBypass(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_cognitive_account", "test") + r := CognitiveAccountResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.networkAclsVirtualNetworkRulesWithBypassDefault(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + { + Config: r.networkAclsVirtualNetworkRulesWithBypass(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + { + Config: r.networkAclsVirtualNetworkRulesWithBypassUpdated(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + +func TestAccCognitiveAccount_networkAclsVirtualNetworkRulesWithBypassKindNotSupported(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_cognitive_account", "test") + r := CognitiveAccountResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.networkAclsVirtualNetworkRulesWithBypassKindNotSupported(data), + ExpectError: regexp.MustCompile("the `network_acls.bypass` does not support Trusted Services for the kind \"Face\""), + }, + }) +} + func TestAccCognitiveAccount_networkAcls(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_cognitive_account", "test") r := CognitiveAccountResource{} @@ -952,7 +993,6 @@ resource "azurerm_cognitive_account" "test" { subnet_id = azurerm_subnet.test_b.id ignore_missing_vnet_service_endpoint = true } - } } `, r.networkAclsTemplate(data), data.RandomInteger, data.RandomInteger) @@ -981,6 +1021,113 @@ resource "azurerm_cognitive_account" "test" { `, r.networkAclsTemplate(data), data.RandomInteger, data.RandomInteger) } +func (r CognitiveAccountResource) networkAclsVirtualNetworkRulesWithBypassDefault(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +resource "azurerm_cognitive_account" "test" { + name = "acctestcogacc-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + kind = "OpenAI" + sku_name = "S0" + custom_subdomain_name = "acctestcogacc-%d" + + network_acls { + default_action = "Deny" + virtual_network_rules { + subnet_id = azurerm_subnet.test_a.id + } + virtual_network_rules { + subnet_id = azurerm_subnet.test_b.id + ignore_missing_vnet_service_endpoint = true + } + } +} +`, r.networkAclsTemplate(data), data.RandomInteger, data.RandomInteger) +} + +func (r CognitiveAccountResource) networkAclsVirtualNetworkRulesWithBypass(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +resource "azurerm_cognitive_account" "test" { + name = "acctestcogacc-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + kind = "OpenAI" + sku_name = "S0" + custom_subdomain_name = "acctestcogacc-%d" + + network_acls { + bypass = "AzureServices" + default_action = "Allow" + virtual_network_rules { + subnet_id = azurerm_subnet.test_a.id + } + virtual_network_rules { + subnet_id = azurerm_subnet.test_b.id + ignore_missing_vnet_service_endpoint = true + } + } +} +`, r.networkAclsTemplate(data), data.RandomInteger, data.RandomInteger) +} + +func (r CognitiveAccountResource) networkAclsVirtualNetworkRulesWithBypassUpdated(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +resource "azurerm_cognitive_account" "test" { + name = "acctestcogacc-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + kind = "OpenAI" + sku_name = "S0" + custom_subdomain_name = "acctestcogacc-%d" + + network_acls { + bypass = "None" + default_action = "Allow" + virtual_network_rules { + subnet_id = azurerm_subnet.test_a.id + } + virtual_network_rules { + subnet_id = azurerm_subnet.test_b.id + ignore_missing_vnet_service_endpoint = true + } + } +} +`, r.networkAclsTemplate(data), data.RandomInteger, data.RandomInteger) +} + +func (r CognitiveAccountResource) networkAclsVirtualNetworkRulesWithBypassKindNotSupported(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +resource "azurerm_cognitive_account" "test" { + name = "acctestcogacc-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + kind = "Face" + sku_name = "S0" + custom_subdomain_name = "acctestcogacc-%d" + + network_acls { + bypass = "AzureServices" + default_action = "Deny" + virtual_network_rules { + subnet_id = azurerm_subnet.test_a.id + } + virtual_network_rules { + subnet_id = azurerm_subnet.test_b.id + ignore_missing_vnet_service_endpoint = true + } + } +} +`, r.networkAclsTemplate(data), data.RandomInteger, data.RandomInteger) +} + func (CognitiveAccountResource) networkAclsTemplate(data acceptance.TestData) string { return fmt.Sprintf(` provider "azurerm" { diff --git a/website/docs/r/cognitive_account.html.markdown b/website/docs/r/cognitive_account.html.markdown index 67bbcec3f894..618d90f02f94 100644 --- a/website/docs/r/cognitive_account.html.markdown +++ b/website/docs/r/cognitive_account.html.markdown @@ -98,6 +98,10 @@ The following arguments are supported: A `network_acls` block supports the following: +* `bypass` - (Optional) Whether to allow trusted Azure Services to access the service. Possible values are `None` and `AzureServices`. + +-> **NOTE:** `bypass` can only be set when `kind` is set to `OpenAI` + * `default_action` - (Required) The Default Action to use when no rules match from `ip_rules` / `virtual_network_rules`. Possible values are `Allow` and `Deny`. * `ip_rules` - (Optional) One or more IP Addresses, or CIDR Blocks which should be able to access the Cognitive Account.