diff --git a/internal/services/search/search_service_data_source.go b/internal/services/search/search_service_data_source.go
index 8498bae1fef6e..b66909a84d385 100644
--- a/internal/services/search/search_service_data_source.go
+++ b/internal/services/search/search_service_data_source.go
@@ -2,8 +2,11 @@ package search
import (
"fmt"
+ "net/http"
+ "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/commonschema"
"github.com/hashicorp/go-azure-helpers/resourcemanager/identity"
@@ -13,6 +16,7 @@ import (
"github.com/hashicorp/terraform-provider-azurerm/internal/clients"
"github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk"
"github.com/hashicorp/terraform-provider-azurerm/internal/timeouts"
+ "github.com/hashicorp/terraform-provider-azurerm/utils"
)
func dataSourceSearchService() *pluginsdk.Resource {
@@ -29,7 +33,7 @@ func dataSourceSearchService() *pluginsdk.Resource {
Required: true,
},
- "resource_group_name": commonschema.ResourceGroupName(),
+ "resource_group_name": commonschema.ResourceGroupNameForDataSource(),
"replica_count": {
Type: pluginsdk.TypeInt,
@@ -102,9 +106,9 @@ func dataSourceSearchServiceRead(d *pluginsdk.ResourceData, meta interface{}) er
if model := resp.Model; model != nil {
if props := model.Properties; props != nil {
- partitionCount := 0
- replicaCount := 0
- publicNetworkAccess := false
+ partitionCount := 1
+ replicaCount := 1
+ publicNetworkAccess := true
if count := props.PartitionCount; count != nil {
partitionCount = int(*count)
@@ -115,7 +119,7 @@ func dataSourceSearchServiceRead(d *pluginsdk.ResourceData, meta interface{}) er
}
if props.PublicNetworkAccess != nil {
- publicNetworkAccess = *props.PublicNetworkAccess != "Disabled"
+ publicNetworkAccess = strings.EqualFold(string(pointer.From(props.PublicNetworkAccess)), string(services.PublicNetworkAccessEnabled))
}
d.Set("partition_count", partitionCount)
@@ -128,19 +132,23 @@ func dataSourceSearchServiceRead(d *pluginsdk.ResourceData, meta interface{}) er
}
}
+ primaryKey := ""
+ secondaryKey := ""
adminKeysClient := meta.(*clients.Client).Search.AdminKeysClient
adminKeysId, err := adminkeys.ParseSearchServiceID(d.Id())
if err != nil {
return err
}
-
adminKeysResp, err := adminKeysClient.Get(ctx, *adminKeysId, adminkeys.GetOperationOptions{})
- if err == nil {
- if model := adminKeysResp.Model; model != nil {
- d.Set("primary_key", model.PrimaryKey)
- d.Set("secondary_key", model.SecondaryKey)
- }
+ if err != nil && !response.WasStatusCode(adminKeysResp.HttpResponse, http.StatusForbidden) {
+ return fmt.Errorf("retrieving Admin Keys for %s: %+v", id, err)
+ }
+ if model := adminKeysResp.Model; model != nil {
+ primaryKey = utils.NormalizeNilableString(model.PrimaryKey)
+ secondaryKey = utils.NormalizeNilableString(model.SecondaryKey)
}
+ d.Set("primary_key", primaryKey)
+ d.Set("secondary_key", secondaryKey)
queryKeysClient := meta.(*clients.Client).Search.QueryKeysClient
queryKeysId, err := querykeys.ParseSearchServiceID(d.Id())
@@ -148,10 +156,11 @@ func dataSourceSearchServiceRead(d *pluginsdk.ResourceData, meta interface{}) er
return err
}
queryKeysResp, err := queryKeysClient.ListBySearchService(ctx, *queryKeysId, querykeys.ListBySearchServiceOperationOptions{})
- if err == nil {
- if model := queryKeysResp.Model; model != nil {
- d.Set("query_keys", flattenSearchQueryKeys(*model))
- }
+ if err != nil && !response.WasStatusCode(queryKeysResp.HttpResponse, http.StatusForbidden) {
+ return fmt.Errorf("retrieving Query Keys for %s: %+v", id, err)
+ }
+ if err := d.Set("query_keys", flattenSearchQueryKeys(queryKeysResp.Model)); err != nil {
+ return fmt.Errorf("setting `query_keys`: %+v", err)
}
return nil
diff --git a/internal/services/search/search_service_resource.go b/internal/services/search/search_service_resource.go
index 4c94ea2e6de47..1326780a708ae 100644
--- a/internal/services/search/search_service_resource.go
+++ b/internal/services/search/search_service_resource.go
@@ -15,7 +15,6 @@ import (
"github.com/hashicorp/go-azure-sdk/resource-manager/search/2022-09-01/adminkeys"
"github.com/hashicorp/go-azure-sdk/resource-manager/search/2022-09-01/querykeys"
"github.com/hashicorp/go-azure-sdk/resource-manager/search/2022-09-01/services"
- "github.com/hashicorp/terraform-provider-azurerm/helpers/azure"
"github.com/hashicorp/terraform-provider-azurerm/helpers/tf"
"github.com/hashicorp/terraform-provider-azurerm/helpers/validate"
"github.com/hashicorp/terraform-provider-azurerm/internal/clients"
@@ -91,10 +90,10 @@ func resourceSearchService() *pluginsdk.Resource {
}),
},
- "local_authentication_disabled": {
+ "local_authentication_enabled": {
Type: pluginsdk.TypeBool,
Optional: true,
- Default: false,
+ Default: true,
},
"authentication_failure_mode": {
@@ -110,7 +109,7 @@ func resourceSearchService() *pluginsdk.Resource {
Type: pluginsdk.TypeString,
Optional: true,
ForceNew: true,
- Default: services.HostingModeDefault,
+ Default: string(services.HostingModeDefault),
ValidateFunc: validation.StringInSlice([]string{
string(services.HostingModeDefault),
string(services.HostingModeHighDensity),
@@ -123,11 +122,6 @@ func resourceSearchService() *pluginsdk.Resource {
Default: false,
},
- "customer_managed_key_enforcement_compliance": {
- Type: pluginsdk.TypeString,
- Computed: true,
- },
-
"primary_key": {
Type: pluginsdk.TypeString,
Computed: true,
@@ -184,7 +178,7 @@ func resourceSearchService() *pluginsdk.Resource {
func resourceSearchServiceCreate(d *pluginsdk.ResourceData, meta interface{}) error {
client := meta.(*clients.Client).Search.ServicesClient
subscriptionId := meta.(*clients.Client).Account.SubscriptionId
- ctx, cancel := timeouts.ForCreateUpdate(meta.(*clients.Client).StopContext, d)
+ ctx, cancel := timeouts.ForCreate(meta.(*clients.Client).StopContext, d)
defer cancel()
id := services.NewSearchServiceID(subscriptionId, d.Get("resource_group_name").(string), d.Get("name").(string))
@@ -198,8 +192,6 @@ func resourceSearchServiceCreate(d *pluginsdk.ResourceData, meta interface{}) er
return tf.ImportAsExistsError("azurerm_search_service", id.ID())
}
- location := azure.NormalizeLocation(d.Get("location").(string))
-
publicNetworkAccess := services.PublicNetworkAccessEnabled
if enabled := d.Get("public_network_access_enabled").(bool); !enabled {
publicNetworkAccess = services.PublicNetworkAccessDisabled
@@ -210,7 +202,7 @@ func resourceSearchServiceCreate(d *pluginsdk.ResourceData, meta interface{}) er
ipRulesRaw := d.Get("allowed_ips").(*pluginsdk.Set).List()
hostingMode := services.HostingMode(d.Get("hosting_mode").(string))
cmkEnforcementEnabled := d.Get("customer_managed_key_enforcement_enabled").(bool)
- localAuthenticationDisabled := d.Get("local_authentication_disabled").(bool)
+ localAuthenticationEnabled := d.Get("local_authentication_enabled").(bool)
authenticationFailureMode := d.Get("authentication_failure_mode").(string)
cmkEnforcement := services.SearchEncryptionWithCmkDisabled
@@ -243,31 +235,31 @@ func resourceSearchServiceCreate(d *pluginsdk.ResourceData, meta interface{}) er
return err
}
- if localAuthenticationDisabled && authenticationFailureMode != "" {
+ if !localAuthenticationEnabled && authenticationFailureMode != "" {
return fmt.Errorf("'authentication_failure_mode' cannot be defined if 'local_authentication_disabled' has been set to 'true'")
}
- // API Only Mode (Defalut)(e.g. localAuthenticationDisabled = false)...
+ // API Only Mode (Default) (e.g. localAuthenticationEnabled = true)...
authenticationOptions := pointer.To(services.DataPlaneAuthOptions{
ApiKeyOnly: pointer.To(apiKeyOnly),
})
- if !localAuthenticationDisabled && authenticationFailureMode != "" {
+ if localAuthenticationEnabled && authenticationFailureMode != "" {
// API & RBAC Mode..
authenticationOptions = pointer.To(services.DataPlaneAuthOptions{
AadOrApiKey: pointer.To(services.DataPlaneAadOrApiKeyAuthOption{
- AadAuthFailureMode: (*services.AadAuthFailureMode)(pointer.To(authenticationFailureMode)),
+ AadAuthFailureMode: pointer.To(services.AadAuthFailureMode(authenticationFailureMode)),
}),
})
}
- if localAuthenticationDisabled {
+ if !localAuthenticationEnabled {
// RBAC Only Mode...
authenticationOptions = nil
}
- searchService := services.SearchService{
- Location: location,
+ payload := services.SearchService{
+ Location: location.Normalize(d.Get("location").(string)),
Sku: pointer.To(services.Sku{
Name: pointer.To(skuName),
}),
@@ -281,7 +273,7 @@ func resourceSearchServiceCreate(d *pluginsdk.ResourceData, meta interface{}) er
}),
HostingMode: pointer.To(hostingMode),
AuthOptions: authenticationOptions,
- DisableLocalAuth: pointer.To(localAuthenticationDisabled),
+ DisableLocalAuth: pointer.To(!localAuthenticationEnabled),
PartitionCount: pointer.To(partitionCount),
ReplicaCount: pointer.To(replicaCount),
},
@@ -297,10 +289,10 @@ func resourceSearchServiceCreate(d *pluginsdk.ResourceData, meta interface{}) er
// in the create call, only in the update call when 'identity' is removed from the
// configuration file...
if expandedIdentity.Type != identity.TypeNone {
- searchService.Identity = expandedIdentity
+ payload.Identity = expandedIdentity
}
- err = client.CreateOrUpdateThenPoll(ctx, id, searchService, services.CreateOrUpdateOperationOptions{})
+ err = client.CreateOrUpdateThenPoll(ctx, id, payload, services.CreateOrUpdateOperationOptions{})
if err != nil {
return fmt.Errorf("creating %s: %+v", id, err)
}
@@ -312,7 +304,7 @@ func resourceSearchServiceCreate(d *pluginsdk.ResourceData, meta interface{}) er
func resourceSearchServiceUpdate(d *pluginsdk.ResourceData, meta interface{}) error {
client := meta.(*clients.Client).Search.ServicesClient
- ctx, cancel := timeouts.ForCreateUpdate(meta.(*clients.Client).StopContext, d)
+ ctx, cancel := timeouts.ForUpdate(meta.(*clients.Client).StopContext, d)
defer cancel()
id, err := services.ParseSearchServiceID(d.Id())
@@ -324,120 +316,128 @@ func resourceSearchServiceUpdate(d *pluginsdk.ResourceData, meta interface{}) er
if err != nil {
return fmt.Errorf("retrieving %s: %+v", id, err)
}
+ if resp.Model == nil {
+ return fmt.Errorf("retrieving existing %s: %+v", id, err)
+ }
+ model := *resp.Model
+ if model.Properties == nil {
+ return fmt.Errorf("retrieving existing %s: `properties` was nil", id)
+ }
- if model := resp.Model; model != nil {
- if d.HasChange("public_network_access_enabled") {
- publicNetworkAccess := services.PublicNetworkAccessEnabled
- if enabled := d.Get("public_network_access_enabled").(bool); !enabled {
- publicNetworkAccess = services.PublicNetworkAccessDisabled
- }
-
- model.Properties.PublicNetworkAccess = pointer.To(publicNetworkAccess)
+ if d.HasChange("customer_managed_key_enforcement_enabled") {
+ cmkEnforcement := services.SearchEncryptionWithCmkDisabled
+ if enabled := d.Get("customer_managed_key_enforcement_enabled").(bool); enabled {
+ cmkEnforcement = services.SearchEncryptionWithCmkEnabled
+ }
+ model.Properties.EncryptionWithCmk = &services.EncryptionWithCmk{
+ Enforcement: pointer.To(cmkEnforcement),
}
+ }
- if d.HasChange("identity") {
- expandedIdentity, err := identity.ExpandSystemAssigned(d.Get("identity").([]interface{}))
- if err != nil {
- return fmt.Errorf("expanding `identity`: %+v", err)
- }
+ if d.HasChange("hosting_mode") {
+ hostingMode := services.HostingMode(d.Get("hosting_mode").(string))
+ if model.Sku == nil {
+ return fmt.Errorf("updating `hosting_mode` for %s: unable to validate the hosting_mode since `model.Sku` was nil", *id)
+ }
- model.Identity = expandedIdentity
+ if pointer.From(model.Sku.Name) != services.SkuNameStandardThree && hostingMode == services.HostingModeHighDensity {
+ return fmt.Errorf("'hosting_mode' can only be set to %q if the 'sku' is %q, got %q", services.HostingModeHighDensity, services.SkuNameStandardThree, pointer.From(model.Sku.Name))
}
- if d.HasChange("hosting_mode") {
- hostingMode := services.HostingMode(d.Get("hosting_mode").(string))
- if pointer.From(model.Sku.Name) != services.SkuNameStandardThree && hostingMode == services.HostingModeHighDensity {
- return fmt.Errorf("'hosting_mode' can only be set to %q if the 'sku' is %q, got %q", services.HostingModeHighDensity, services.SkuNameStandardThree, pointer.From(model.Sku.Name))
- }
+ model.Properties.HostingMode = pointer.To(hostingMode)
+ }
- model.Properties.HostingMode = pointer.To(hostingMode)
+ if d.HasChange("identity") {
+ expandedIdentity, err := identity.ExpandSystemAssigned(d.Get("identity").([]interface{}))
+ if err != nil {
+ return fmt.Errorf("expanding `identity`: %+v", err)
}
- if d.HasChange("customer_managed_key_enforcement_enabled") {
- cmkEnforcement := services.SearchEncryptionWithCmkDisabled
- if enabled := d.Get("customer_managed_key_enforcement_enabled").(bool); enabled {
- cmkEnforcement = services.SearchEncryptionWithCmkEnabled
- }
+ model.Identity = expandedIdentity
+ }
- model.Properties.EncryptionWithCmk.Enforcement = pointer.To(cmkEnforcement)
+ if d.HasChange("public_network_access_enabled") {
+ publicNetworkAccess := services.PublicNetworkAccessEnabled
+ if enabled := d.Get("public_network_access_enabled").(bool); !enabled {
+ publicNetworkAccess = services.PublicNetworkAccessDisabled
}
- if d.HasChange("local_authentication_disabled") || d.HasChange("authentication_failure_mode") {
- localAuthenticationDisabled := d.Get("local_authentication_disabled").(bool)
- authenticationFailureMode := d.Get("authentication_failure_mode").(string)
-
- if localAuthenticationDisabled && authenticationFailureMode != "" {
- return fmt.Errorf("'authentication_failure_mode' cannot be defined if 'local_authentication_disabled' has been set to 'true'")
- }
+ model.Properties.PublicNetworkAccess = pointer.To(publicNetworkAccess)
+ }
- var apiKeyOnly interface{} = make(map[string]interface{}, 0)
+ if d.HasChanges("authentication_failure_mode", "local_authentication_enabled") {
+ authenticationFailureMode := d.Get("authentication_failure_mode").(string)
+ localAuthenticationEnabled := d.Get("local_authentication_enabled").(bool)
+ if !localAuthenticationEnabled && authenticationFailureMode != "" {
+ return fmt.Errorf("'authentication_failure_mode' cannot be defined if 'local_authentication_enabled' has been set to 'false'")
+ }
- // API Only Mode (Defalut)...
- authenticationOptions := pointer.To(services.DataPlaneAuthOptions{
- ApiKeyOnly: pointer.To(apiKeyOnly),
- })
+ var apiKeyOnly interface{} = make(map[string]interface{}, 0)
- if !localAuthenticationDisabled && authenticationFailureMode != "" {
- // API & RBAC Mode..
- authenticationOptions = pointer.To(services.DataPlaneAuthOptions{
- AadOrApiKey: pointer.To(services.DataPlaneAadOrApiKeyAuthOption{
- AadAuthFailureMode: (*services.AadAuthFailureMode)(pointer.To(authenticationFailureMode)),
- }),
- })
- }
+ // API Only Mode (Default)...
+ authenticationOptions := pointer.To(services.DataPlaneAuthOptions{
+ ApiKeyOnly: pointer.To(apiKeyOnly),
+ })
- if localAuthenticationDisabled {
- // RBAC Only Mode...
- authenticationOptions = nil
- }
+ if localAuthenticationEnabled && authenticationFailureMode != "" {
+ // API & RBAC Mode..
+ authenticationOptions = pointer.To(services.DataPlaneAuthOptions{
+ AadOrApiKey: pointer.To(services.DataPlaneAadOrApiKeyAuthOption{
+ AadAuthFailureMode: (*services.AadAuthFailureMode)(pointer.To(authenticationFailureMode)),
+ }),
+ })
+ }
- model.Properties.DisableLocalAuth = pointer.To(localAuthenticationDisabled)
- model.Properties.AuthOptions = authenticationOptions
+ if !localAuthenticationEnabled {
+ // RBAC Only Mode...
+ authenticationOptions = nil
}
- if d.HasChange("replica_count") {
- replicaCount, err := validateSearchServiceReplicaCount(int64(d.Get("replica_count").(int)), pointer.From(model.Sku.Name))
- if err != nil {
- return err
- }
+ model.Properties.DisableLocalAuth = pointer.To(!localAuthenticationEnabled)
+ model.Properties.AuthOptions = authenticationOptions
+ }
- model.Properties.ReplicaCount = pointer.To(replicaCount)
+ if d.HasChange("replica_count") {
+ replicaCount, err := validateSearchServiceReplicaCount(int64(d.Get("replica_count").(int)), pointer.From(model.Sku.Name))
+ if err != nil {
+ return err
}
- if d.HasChange("partition_count") {
- partitionCount := int64(d.Get("partition_count").(int))
- // NOTE: 'partition_count' values greater than 1 are not valid for 'free' or 'basic' SKUs...
- if (pointer.From(model.Sku.Name) == services.SkuNameFree || pointer.From(model.Sku.Name) == services.SkuNameBasic) && partitionCount > 1 {
- return fmt.Errorf("'partition_count' values greater than 1 cannot be set for the %q SKU, got %d)", pointer.From(model.Sku.Name), partitionCount)
- }
-
- // NOTE: If SKU is 'standard3' and the 'hosting_mode' is set to 'highDensity' the maximum number of partitions allowed is 3
- // where if 'hosting_mode' is set to 'default' the maximum number of partitions is 12...
- if pointer.From(model.Sku.Name) == services.SkuNameStandardThree && partitionCount > 3 && pointer.From(model.Properties.HostingMode) == services.HostingModeHighDensity {
- return fmt.Errorf("%q SKUs in %q mode can have a maximum of 3 partitions, got %d", services.SkuNameStandardThree, services.HostingModeHighDensity, partitionCount)
- }
+ model.Properties.ReplicaCount = pointer.To(replicaCount)
+ }
- model.Properties.PartitionCount = pointer.To(partitionCount)
+ if d.HasChange("partition_count") {
+ partitionCount := int64(d.Get("partition_count").(int))
+ // NOTE: 'partition_count' values greater than 1 are not valid for 'free' or 'basic' SKUs...
+ if (pointer.From(model.Sku.Name) == services.SkuNameFree || pointer.From(model.Sku.Name) == services.SkuNameBasic) && partitionCount > 1 {
+ return fmt.Errorf("'partition_count' values greater than 1 cannot be set for the %q SKU, got %d)", pointer.From(model.Sku.Name), partitionCount)
}
- if d.HasChange("allowed_ips") {
- ipRulesRaw := d.Get("allowed_ips").(*pluginsdk.Set).List()
- model.Properties.NetworkRuleSet.IPRules = expandSearchServiceIPRules(ipRulesRaw)
+ // NOTE: If SKU is 'standard3' and the 'hosting_mode' is set to 'highDensity' the maximum number of partitions allowed is 3
+ // where if 'hosting_mode' is set to 'default' the maximum number of partitions is 12...
+ if pointer.From(model.Sku.Name) == services.SkuNameStandardThree && partitionCount > 3 && pointer.From(model.Properties.HostingMode) == services.HostingModeHighDensity {
+ return fmt.Errorf("%q SKUs in %q mode can have a maximum of 3 partitions, got %d", services.SkuNameStandardThree, services.HostingModeHighDensity, partitionCount)
}
- if d.HasChange("tags") {
- model.Tags = tags.Expand(d.Get("tags").(map[string]interface{}))
- }
+ model.Properties.PartitionCount = pointer.To(partitionCount)
+ }
- err = client.CreateOrUpdateThenPoll(ctx, pointer.From(id), pointer.From(model), services.CreateOrUpdateOperationOptions{})
- if err != nil {
- return fmt.Errorf("updating %s: %+v", id, err)
+ if d.HasChange("allowed_ips") {
+ ipRulesRaw := d.Get("allowed_ips").(*pluginsdk.Set).List()
+ model.Properties.NetworkRuleSet = &services.NetworkRuleSet{
+ IPRules: expandSearchServiceIPRules(ipRulesRaw),
}
+ }
- return resourceSearchServiceRead(d, meta)
+ if d.HasChange("tags") {
+ model.Tags = tags.Expand(d.Get("tags").(map[string]interface{}))
}
- return nil
+ if err = client.CreateOrUpdateThenPoll(ctx, *id, model, services.CreateOrUpdateOperationOptions{}); err != nil {
+ return fmt.Errorf("updating %s: %+v", id, err)
+ }
+
+ return resourceSearchServiceRead(d, meta)
}
func resourceSearchServiceRead(d *pluginsdk.ResourceData, meta interface{}) error {
@@ -479,7 +479,7 @@ func resourceSearchServiceRead(d *pluginsdk.ResourceData, meta interface{}) erro
publicNetworkAccess := true // publicNetworkAccess defaults to true...
cmkEnforcement := false // cmkEnforcment defaults to false...
hostingMode := services.HostingModeDefault
- localAuthDisabled := false
+ localAuthEnabled := true
authFailureMode := ""
if count := props.PartitionCount; count != nil {
@@ -500,16 +500,14 @@ func resourceSearchServiceRead(d *pluginsdk.ResourceData, meta interface{}) erro
hostingMode = *props.HostingMode
}
- var cmkCompliance string
if props.EncryptionWithCmk != nil {
cmkEnforcement = strings.EqualFold(string(pointer.From(props.EncryptionWithCmk.Enforcement)), string(services.SearchEncryptionWithCmkEnabled))
- cmkCompliance = string(pointer.From(props.EncryptionWithCmk.EncryptionComplianceStatus))
}
// I am using 'DisableLocalAuth' here because when you are in
// RBAC Only Mode, the 'props.AuthOptions' will be 'nil'...
if props.DisableLocalAuth != nil {
- localAuthDisabled = pointer.From(props.DisableLocalAuth)
+ localAuthEnabled = !pointer.From(props.DisableLocalAuth)
// if the AuthOptions are nil that means you are in RBAC Only Mode...
if props.AuthOptions != nil {
@@ -523,13 +521,12 @@ func resourceSearchServiceRead(d *pluginsdk.ResourceData, meta interface{}) erro
}
d.Set("authentication_failure_mode", authFailureMode)
- d.Set("local_authentication_disabled", localAuthDisabled)
+ d.Set("local_authentication_enabled", localAuthEnabled)
d.Set("partition_count", partitionCount)
d.Set("replica_count", replicaCount)
d.Set("public_network_access_enabled", publicNetworkAccess)
d.Set("hosting_mode", hostingMode)
d.Set("customer_managed_key_enforcement_enabled", cmkEnforcement)
- d.Set("customer_managed_key_enforcement_compliance", cmkCompliance)
d.Set("allowed_ips", flattenSearchServiceIPRules(props.NetworkRuleSet))
}
@@ -549,11 +546,12 @@ func resourceSearchServiceRead(d *pluginsdk.ResourceData, meta interface{}) erro
}
adminKeysResp, err := adminKeysClient.Get(ctx, *adminKeysId, adminkeys.GetOperationOptions{})
- if err == nil {
- if model := adminKeysResp.Model; model != nil {
- d.Set("primary_key", model.PrimaryKey)
- d.Set("secondary_key", model.SecondaryKey)
- }
+ if err != nil {
+ return fmt.Errorf("retrieving Admin Keys for %s: %+v", *id, err)
+ }
+ if model := adminKeysResp.Model; model != nil {
+ d.Set("primary_key", model.PrimaryKey)
+ d.Set("secondary_key", model.SecondaryKey)
}
queryKeysClient := meta.(*clients.Client).Search.QueryKeysClient
@@ -562,10 +560,11 @@ func resourceSearchServiceRead(d *pluginsdk.ResourceData, meta interface{}) erro
return err
}
queryKeysResp, err := queryKeysClient.ListBySearchService(ctx, *queryKeysId, querykeys.ListBySearchServiceOperationOptions{})
- if err == nil {
- if model := queryKeysResp.Model; model != nil {
- d.Set("query_keys", flattenSearchQueryKeys(*model))
- }
+ if err != nil {
+ return fmt.Errorf("retrieving Query Keys for %s: %+v", *id, err)
+ }
+ if err := d.Set("query_keys", flattenSearchQueryKeys(queryKeysResp.Model)); err != nil {
+ return fmt.Errorf("setting `query_keys`: %+v", err)
}
return nil
@@ -581,30 +580,23 @@ func resourceSearchServiceDelete(d *pluginsdk.ResourceData, meta interface{}) er
return err
}
- resp, err := client.Delete(ctx, *id, services.DeleteOperationOptions{})
- if err != nil {
- if response.WasNotFound(resp.HttpResponse) {
- return nil
- }
-
+ if _, err := client.Delete(ctx, *id, services.DeleteOperationOptions{}); err != nil {
return fmt.Errorf("deleting %s: %+v", *id, err)
}
return nil
}
-func flattenSearchQueryKeys(input []querykeys.QueryKey) []interface{} {
+func flattenSearchQueryKeys(input *[]querykeys.QueryKey) []interface{} {
results := make([]interface{}, 0)
- for _, v := range input {
- result := make(map[string]interface{})
-
- if v.Name != nil {
- result["name"] = *v.Name
+ if input != nil {
+ for _, v := range *input {
+ results = append(results, map[string]interface{}{
+ "name": utils.NormalizeNilableString(v.Name),
+ "key": utils.NormalizeNilableString(v.Key),
+ })
}
- result["key"] = *v.Key
-
- results = append(results, result)
}
return results
@@ -612,9 +604,6 @@ func flattenSearchQueryKeys(input []querykeys.QueryKey) []interface{} {
func expandSearchServiceIPRules(input []interface{}) *[]services.IPRule {
output := make([]services.IPRule, 0)
- if input == nil {
- return &output
- }
for _, rule := range input {
if rule != nil {
@@ -628,12 +617,11 @@ func expandSearchServiceIPRules(input []interface{}) *[]services.IPRule {
}
func flattenSearchServiceIPRules(input *services.NetworkRuleSet) []interface{} {
- if input == nil || *input.IPRules == nil || len(*input.IPRules) == 0 {
- return nil
- }
result := make([]interface{}, 0)
- for _, rule := range *input.IPRules {
- result = append(result, rule.Value)
+ if input != nil || input.IPRules != nil {
+ for _, rule := range *input.IPRules {
+ result = append(result, rule.Value)
+ }
}
return result
}
diff --git a/internal/services/search/search_service_resource_test.go b/internal/services/search/search_service_resource_test.go
index 5627985a5f14e..4bfdcbc82f1aa 100644
--- a/internal/services/search/search_service_resource_test.go
+++ b/internal/services/search/search_service_resource_test.go
@@ -16,13 +16,13 @@ import (
type SearchServiceResource struct{}
-func TestAccSearchService_basicStandard(t *testing.T) {
+func TestAccSearchService_basicSku(t *testing.T) {
data := acceptance.BuildTestData(t, "azurerm_search_service", "test")
r := SearchServiceResource{}
data.ResourceTest(t, r, []acceptance.TestStep{
{
- Config: r.basic(data, "standard"),
+ Config: r.basic(data, "basic"),
Check: acceptance.ComposeTestCheckFunc(
check.That(data.ResourceName).ExistsInAzure(r),
),
@@ -31,7 +31,7 @@ func TestAccSearchService_basicStandard(t *testing.T) {
})
}
-func TestAccSearchService_basicFree(t *testing.T) {
+func TestAccSearchService_freeSku(t *testing.T) {
// Regression test case for issue #10151
data := acceptance.BuildTestData(t, "azurerm_search_service", "test")
r := SearchServiceResource{}
@@ -47,13 +47,13 @@ func TestAccSearchService_basicFree(t *testing.T) {
})
}
-func TestAccSearchService_basicBasic(t *testing.T) {
+func TestAccSearchService_standardSku(t *testing.T) {
data := acceptance.BuildTestData(t, "azurerm_search_service", "test")
r := SearchServiceResource{}
data.ResourceTest(t, r, []acceptance.TestStep{
{
- Config: r.basic(data, "basic"),
+ Config: r.basic(data, "standard"),
Check: acceptance.ComposeTestCheckFunc(
check.That(data.ResourceName).ExistsInAzure(r),
),
@@ -309,8 +309,7 @@ func TestAccSearchService_apiAccessControlRbacError(t *testing.T) {
data.ResourceTest(t, r, []acceptance.TestStep{
{
- Config: r.apiAccessControlBoth(data, true, "http401WithBearerChallenge"),
- Check: acceptance.ComposeTestCheckFunc(),
+ Config: r.apiAccessControlBoth(data, false, "http401WithBearerChallenge"),
ExpectError: regexp.MustCompile("cannot be defined"),
},
})
@@ -329,28 +328,28 @@ func TestAccSearchService_apiAccessControlUpdate(t *testing.T) {
},
data.ImportStep(),
{
- Config: r.apiAccessControlApiKeysOrRBAC(data, false),
+ Config: r.apiAccessControlApiKeysOrRBAC(data, true),
Check: acceptance.ComposeTestCheckFunc(
check.That(data.ResourceName).ExistsInAzure(r),
),
},
data.ImportStep(),
{
- Config: r.apiAccessControlApiKeysOrRBAC(data, true),
+ Config: r.apiAccessControlApiKeysOrRBAC(data, false),
Check: acceptance.ComposeTestCheckFunc(
check.That(data.ResourceName).ExistsInAzure(r),
),
},
data.ImportStep(),
{
- Config: r.apiAccessControlBoth(data, false, "http401WithBearerChallenge"),
+ Config: r.apiAccessControlBoth(data, true, "http401WithBearerChallenge"),
Check: acceptance.ComposeTestCheckFunc(
check.That(data.ResourceName).ExistsInAzure(r),
),
},
data.ImportStep(),
{
- Config: r.apiAccessControlBoth(data, false, "http403"),
+ Config: r.apiAccessControlBoth(data, true, "http403"),
Check: acceptance.ComposeTestCheckFunc(
check.That(data.ResourceName).ExistsInAzure(r),
),
@@ -366,7 +365,7 @@ func TestAccSearchService_apiAccessControlUpdate(t *testing.T) {
})
}
-func (t SearchServiceResource) Exists(ctx context.Context, clients *clients.Client, state *pluginsdk.InstanceState) (*bool, error) {
+func (r SearchServiceResource) Exists(ctx context.Context, clients *clients.Client, state *pluginsdk.InstanceState) (*bool, error) {
id, err := services.ParseSearchServiceID(state.ID)
if err != nil {
return nil, err
@@ -403,10 +402,6 @@ resource "azurerm_search_service" "test" {
resource_group_name = azurerm_resource_group.test.name
location = azurerm_resource_group.test.location
sku = "%s"
-
- tags = {
- environment = "staging"
- }
}
`, template, data.RandomInteger, sku)
}
@@ -421,10 +416,6 @@ resource "azurerm_search_service" "import" {
resource_group_name = azurerm_search_service.test.resource_group_name
location = azurerm_search_service.test.location
sku = azurerm_search_service.test.sku
-
- tags = {
- environment = "staging"
- }
}
`, template)
}
@@ -471,12 +462,7 @@ resource "azurerm_search_service" "test" {
resource_group_name = azurerm_resource_group.test.name
location = azurerm_resource_group.test.location
sku = "standard"
-
- allowed_ips = ["168.1.5.65", "1.2.3.0/24"]
-
- tags = {
- environment = "staging"
- }
+ allowed_ips = ["168.1.5.65", "1.2.3.0/24"]
}
`, template, data.RandomInteger)
}
@@ -499,10 +485,6 @@ resource "azurerm_search_service" "test" {
identity {
type = "SystemAssigned"
}
-
- tags = {
- environment = "staging"
- }
}
`, template, data.RandomInteger)
}
@@ -522,10 +504,6 @@ resource "azurerm_search_service" "test" {
location = azurerm_resource_group.test.location
sku = "%s"
hosting_mode = "highDensity"
-
- tags = {
- environment = "staging"
- }
}
`, template, data.RandomInteger, sku)
}
@@ -584,15 +562,11 @@ resource "azurerm_search_service" "test" {
sku = "standard"
customer_managed_key_enforcement_enabled = %t
-
- tags = {
- environment = "staging"
- }
}
`, template, data.RandomInteger, enforceCustomerManagedKey)
}
-func (r SearchServiceResource) apiAccessControlApiKeysOrRBAC(data acceptance.TestData, localAuthenticationDisabled bool) string {
+func (r SearchServiceResource) apiAccessControlApiKeysOrRBAC(data acceptance.TestData, localAuthenticationEnabled bool) string {
template := r.template(data)
return fmt.Sprintf(`
provider "azurerm" {
@@ -607,16 +581,12 @@ resource "azurerm_search_service" "test" {
location = azurerm_resource_group.test.location
sku = "standard"
- local_authentication_disabled = %t
-
- tags = {
- environment = "staging"
- }
+ local_authentication_enabled = %t
}
-`, template, data.RandomInteger, localAuthenticationDisabled)
+`, template, data.RandomInteger, localAuthenticationEnabled)
}
-func (r SearchServiceResource) apiAccessControlBoth(data acceptance.TestData, localAuthenticationDisabled bool, authenticationFailureMode string) string {
+func (r SearchServiceResource) apiAccessControlBoth(data acceptance.TestData, localAuthenticationEnabled bool, authenticationFailureMode string) string {
template := r.template(data)
return fmt.Sprintf(`
provider "azurerm" {
@@ -631,12 +601,8 @@ resource "azurerm_search_service" "test" {
location = azurerm_resource_group.test.location
sku = "standard"
- local_authentication_disabled = %t
- authentication_failure_mode = "%s"
-
- tags = {
- environment = "staging"
- }
+ local_authentication_enabled = %t
+ authentication_failure_mode = "%s"
}
-`, template, data.RandomInteger, localAuthenticationDisabled, authenticationFailureMode)
+`, template, data.RandomInteger, localAuthenticationEnabled, authenticationFailureMode)
}
diff --git a/website/docs/r/search_service.html.markdown b/website/docs/r/search_service.html.markdown
index de47b1782f9d2..29b01303d6984 100644
--- a/website/docs/r/search_service.html.markdown
+++ b/website/docs/r/search_service.html.markdown
@@ -10,7 +10,7 @@ description: |-
Manages a Search Service.
-## Example Usage
+## Example Usage (supporting API Keys)
```hcl
resource "azurerm_resource_group" "example" {
@@ -26,6 +26,43 @@ resource "azurerm_search_service" "example" {
}
```
+## Example Usage (using both AzureAD and API Keys)
+
+```hcl
+resource "azurerm_resource_group" "example" {
+ name = "example-resources"
+ location = "West Europe"
+}
+
+resource "azurerm_search_service" "example" {
+ name = "example-resource"
+ resource_group_name = azurerm_resource_group.example.name
+ location = azurerm_resource_group.example.location
+ sku = "standard"
+
+ local_authentication_enabled = true
+ authentication_failure_mode = "http403"
+}
+```
+
+## Example Usage (supporting only AzureAD Authentication)
+
+```hcl
+resource "azurerm_resource_group" "example" {
+ name = "example-resources"
+ location = "West Europe"
+}
+
+resource "azurerm_search_service" "example" {
+ name = "example-resource"
+ resource_group_name = azurerm_resource_group.example.name
+ location = azurerm_resource_group.example.location
+ sku = "standard"
+
+ local_authentication_enabled = false
+}
+```
+
## Arguments Reference
The following arguments are supported:
@@ -44,37 +81,34 @@ The following arguments are supported:
---
-* `authentication_failure_mode` - (Optional) Describes what response the Search Service should return for requests that fail authentication. Possible values include `http401WithBearerChallenge` or `http403`.
-
-~> **NOTE:** The `authentication_failure_mode` field is only valid if the Search Service is in the `Role-based access control and API Key` mode. For more information on how to correctly configure the Search Services `API Access Control` settings, please see the `Setting API Access Control` section below.
+* `allowed_ips` - (Optional) Specifies a list of inbound IPv4 or CIDRs that are allowed to access the Search Service. If the incoming IP request is from an IP address which is not included in the `allowed_ips` it will be blocked by the Search Services firewall.
-* `customer_managed_key_enforcement_enabled` - (Optional) Should the Search Service enforce having non customer encrypted resources? Possible values include `true` or `false`. If `true` the Search Service will be marked as `non-compliant` if there are one or more non customer encrypted resources, if `false` no enforcement will be made and the Search Service can contain one or more non customer encrypted resources. Defaults to `false`.
+-> **NOTE:** The `allowed_ips` are only applied if the `public_network_access_enabled` field has been set to `true`, else all traffic over the public interface will be rejected, even if the `allowed_ips` field has been defined. When the `public_network_access_enabled` field has been set to `false` the private endpoint connections are the only allowed access point to the Search Service.
-* `hosting_mode` - (Optional) Enable high density partitions that allow for up to a 1000 indexes. Possible values are `highDensity` or `default`. Defaults to `default`. Changing this forces a new Search Service to be created.
+* `authentication_failure_mode` - (Optional) Specifies the response that the Search Service should return for requests that fail authentication. Possible values include `http401WithBearerChallenge` or `http403`.
--> **NOTE:** When the Search Service is in `highDensity` mode the maximum number of partitions allowed is `3`, to enable `hosting_mode` you must use a `standard3` SKU.
+-> **NOTE:** `authentication_failure_mode` can only be configured when using `local_authentication_enabled` is set to `true` - which when set together specifies that both API Keys and AzureAD Authentication should be supported.
-* `local_authentication_disabled` - (Optional) Should tha Search Service *not* be allowed to use API keys for authentication? Possible values include `true` or `false`. Defaults to `false`.
+* `customer_managed_key_enforcement_enabled` - (Optional) Specifies whether the Search Service should enforce that non-customer resources are encrypted. Defaults to `false`.
--> **NOTE:** For more information on how to correctly configure the Search Services `API Access Control` settings, please see the `Setting API Access Control` section below.
+* `hosting_mode` - (Optional) Specifies the Hosting Mode, which allows for High Density partitions (that allow for up to 1000 indexes) should be supported. Possible values are `highDensity` or `default`. Defaults to `default`. Changing this forces a new Search Service to be created.
-* `public_network_access_enabled` - (Optional) Whether or not public network access is allowed for this resource. Defaults to `true`.
+-> **NOTE:** `hosting_mode` can only be configured when `sku` is set to `standard3`.
-* `partition_count` - (Optional) The number of partitions which should be created. Possible values include `1`, `2`, `3`, `4`, `6`, or `12`. Defaults to `1`.
--> **NOTE:** `partition_count` cannot be configured when using a `free` or `basic` SKU. For more information please to the [product documentation](https://learn.microsoft.com/azure/search/search-sku-tier).
+* `identity` - (Optional) An `identity` block as defined below.
-* `replica_count` - (Optional) The number of replica's which should be created.
+* `local_authentication_enabled` - (Optional) Specifies whether the Search Service allows authenticating using API Keys? Defaults to `false`.
--> **NOTE:** `replica_count` cannot be configured when using a `free` SKU. For more information please to the [product documentation](https://learn.microsoft.com/azure/search/search-sku-tier).
+* `partition_count` - (Optional) Specifies the number of partitions which should be created. This field cannot be set when using a `free` or `basic` sku ([see the Microsoft documentation](https://learn.microsoft.com/azure/search/search-sku-tier)). Possible values include `1`, `2`, `3`, `4`, `6`, or `12`. Defaults to `1`.
-* `allowed_ips` - (Optional) A list of inbound IPv4 or CIDRs that are allowed to access the Search Service. If the incoming IP request is from an IP address which is not included in the `allowed_ips` it will be blocked by the Search Services firewall.
+-> **NOTE:** when `hosting_mode` is set to `highDensity` the maximum number of partitions allowed is `3`.
--> **NOTE:** The `allowed_ips` are only applied if the `public_network_access_enabled` field has been set to `true`, else all traffic over the public interface will be rejected, even if the `allowed_ips` field has been defined. When the `public_network_access_enabled` field has been set to `false` the private endpoint connections are the only allowed access point to the Search Service.
+* `public_network_access_enabled` - (Optional) Specifies whether Public Network Access is allowed for this resource. Defaults to `true`.
-* `identity` - (Optional) An `identity` block as defined below.
+* `replica_count` - (Optional) Specifies the number of Replica's which should be created for this Search Service. This field cannot be set when using a `free` sku ([see the Microsoft documentation](https://learn.microsoft.com/azure/search/search-sku-tier)).
-* `tags` - (Optional) A mapping of tags which should be assigned to the Search Service.
+* `tags` - (Optional) Specifies a mapping of tags which should be assigned to this Search Service.
---
@@ -90,8 +124,6 @@ In addition to the Arguments listed above - the following Attributes are exporte
* `id` - The ID of the Search Service.
-* `customer_managed_key_enforcement_compliance` - Describes whether the Search Service is `compliant` or not with respect to having non customer encrypted resources.
-
* `primary_key` - The Primary Key used for Search Service Administration.
* `query_keys` - A `query_keys` block as defined below.
@@ -116,20 +148,6 @@ An `identity` block exports the following:
---
-## Setting API Access Control:
-
-The values of the `local_authentication_disabled` and `authentication_failure_mode` fields will determin which `API Access Control` mode the Search Service will operate under. To correctly configure your Search Service to your desired `API Access Control` mode please configure your Search Service based on the field values in the below table.
-
-| Field Name | Value | API Access Control Mode |
-|------------------------------------------------------------------|:---------------------------------------------------------:|:----------------------------------------:|
-| `local_authentication_disabled`
`authentication_failure_mode` | `false`
`` | `API key` (`Default`) |
-| `local_authentication_disabled`
`authentication_failure_mode` | `false`
`authentication_failure_mode` as defined above | `Role-based access control and API Key` |
-| `local_authentication_disabled`
`authentication_failure_mode` | `true`
`` | `Role-based access control` |
-
--> **NOTE:** When the Search Service is in `Role-based access contol` (e.g. `local_authentication_disabled` is `true`) the `authentication_failure_mode` field *cannot* be defined.
-
----
-
## Timeouts
The `timeouts` block allows you to specify [timeouts](https://www.terraform.io/language/resources/syntax#operation-timeouts) for certain actions: