diff --git a/azurerm/internal/services/appconfiguration/app_configuration_data_source.go b/azurerm/internal/services/appconfiguration/app_configuration_data_source.go new file mode 100644 index 000000000000..c4dd39a1c719 --- /dev/null +++ b/azurerm/internal/services/appconfiguration/app_configuration_data_source.go @@ -0,0 +1,191 @@ +package appconfiguration + +import ( + "fmt" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/clients" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/appconfiguration/validate" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/tags" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/timeouts" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" +) + +func dataSourceAppConfiguration() *schema.Resource { + return &schema.Resource{ + Read: dataSourceAppConfigurationRead, + + Timeouts: &schema.ResourceTimeout{ + Read: schema.DefaultTimeout(5 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validate.AppConfigurationName, + }, + + "resource_group_name": azure.SchemaResourceGroupNameForDataSource(), + + "location": azure.SchemaLocationForDataSource(), + + "sku": { + Type: schema.TypeString, + Computed: true, + }, + + "endpoint": { + Type: schema.TypeString, + Computed: true, + }, + + "primary_read_key": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Computed: true, + Sensitive: true, + }, + "secret": { + Type: schema.TypeString, + Computed: true, + Sensitive: true, + }, + "connection_string": { + Type: schema.TypeString, + Computed: true, + Sensitive: true, + }, + }, + }, + }, + + "secondary_read_key": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Computed: true, + Sensitive: true, + }, + "secret": { + Type: schema.TypeString, + Computed: true, + Sensitive: true, + }, + "connection_string": { + Type: schema.TypeString, + Computed: true, + Sensitive: true, + }, + }, + }, + }, + + "primary_write_key": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Computed: true, + Sensitive: true, + }, + "secret": { + Type: schema.TypeString, + Computed: true, + Sensitive: true, + }, + "connection_string": { + Type: schema.TypeString, + Computed: true, + Sensitive: true, + }, + }, + }, + }, + + "secondary_write_key": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Computed: true, + Sensitive: true, + }, + "secret": { + Type: schema.TypeString, + Computed: true, + Sensitive: true, + }, + "connection_string": { + Type: schema.TypeString, + Computed: true, + Sensitive: true, + }, + }, + }, + }, + + "tags": tags.SchemaDataSource(), + }, + } +} + +func dataSourceAppConfigurationRead(d *schema.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).AppConfiguration.AppConfigurationsClient + ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) + defer cancel() + + name := d.Get("name").(string) + resourceGroup := d.Get("resource_group_name").(string) + + resp, err := client.Get(ctx, resourceGroup, name) + if err != nil { + if utils.ResponseWasNotFound(resp.Response) { + return fmt.Errorf("App Configuration %q was not found in Resource Group %q", name, resourceGroup) + } + + return fmt.Errorf("Error retrieving App Configuration %q (Resource Group %q): %+v", name, resourceGroup, err) + } + + resultPage, err := client.ListKeys(ctx, resourceGroup, name, "") + if err != nil { + return fmt.Errorf("Failed to receive access keys for App Configuration %q (Resource Group %q): %+v", name, resourceGroup, err) + } + + d.SetId(*resp.ID) + + if location := resp.Location; location != nil { + d.Set("location", azure.NormalizeLocation(*location)) + } + + skuName := "" + if resp.Sku != nil && resp.Sku.Name != nil { + skuName = *resp.Sku.Name + } + d.Set("sku", skuName) + + if props := resp.ConfigurationStoreProperties; props != nil { + d.Set("endpoint", props.Endpoint) + } + + accessKeys := flattenAppConfigurationAccessKeys(resultPage.Values()) + d.Set("primary_read_key", accessKeys.primaryReadKey) + d.Set("primary_write_key", accessKeys.primaryWriteKey) + d.Set("secondary_read_key", accessKeys.secondaryReadKey) + d.Set("secondary_write_key", accessKeys.secondaryWriteKey) + + return tags.FlattenAndSet(d, resp.Tags) +} diff --git a/azurerm/internal/services/appconfiguration/resource_arm_app_configuration.go b/azurerm/internal/services/appconfiguration/app_configuration_resource.go similarity index 80% rename from azurerm/internal/services/appconfiguration/resource_arm_app_configuration.go rename to azurerm/internal/services/appconfiguration/app_configuration_resource.go index 02ca55004547..6d1f791871e2 100644 --- a/azurerm/internal/services/appconfiguration/resource_arm_app_configuration.go +++ b/azurerm/internal/services/appconfiguration/app_configuration_resource.go @@ -3,11 +3,10 @@ package appconfiguration import ( "fmt" "log" - "regexp" "strings" "time" - appconf "github.com/Azure/azure-sdk-for-go/services/appconfiguration/mgmt/2019-10-01/appconfiguration" + "github.com/Azure/azure-sdk-for-go/services/appconfiguration/mgmt/2019-10-01/appconfiguration" "github.com/hashicorp/go-azure-helpers/response" "github.com/hashicorp/terraform-plugin-sdk/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/helper/validation" @@ -16,6 +15,7 @@ import ( "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/clients" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/features" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/appconfiguration/parse" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/appconfiguration/validate" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/tags" azSchema "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/tf/schema" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/timeouts" @@ -46,7 +46,7 @@ func resourceArmAppConfiguration() *schema.Resource { Type: schema.TypeString, Required: true, ForceNew: true, - ValidateFunc: ValidateAppConfigurationName, + ValidateFunc: validate.AppConfigurationName, }, "location": azure.SchemaLocation(), @@ -194,9 +194,9 @@ func resourceArmAppConfigurationCreate(d *schema.ResourceData, meta interface{}) } } - parameters := appconf.ConfigurationStore{ + parameters := appconfiguration.ConfigurationStore{ Location: utils.String(azure.NormalizeLocation(d.Get("location").(string))), - Sku: &appconf.Sku{ + Sku: &appconfiguration.Sku{ Name: utils.String(d.Get("sku").(string)), }, Tags: tags.Expand(d.Get("tags").(map[string]interface{})), @@ -235,8 +235,8 @@ func resourceArmAppConfigurationUpdate(d *schema.ResourceData, meta interface{}) return err } - parameters := appconf.ConfigurationStoreUpdateParameters{ - Sku: &appconf.Sku{ + parameters := appconfiguration.ConfigurationStoreUpdateParameters{ + Sku: &appconfiguration.Sku{ Name: utils.String(d.Get("sku").(string)), }, Tags: tags.Expand(d.Get("tags").(map[string]interface{})), @@ -284,61 +284,32 @@ func resourceArmAppConfigurationRead(d *schema.ResourceData, meta interface{}) e return fmt.Errorf("Error making Read request on App Configuration %q (Resource Group %q): %+v", id.Name, id.ResourceGroup, err) } + resultPage, err := client.ListKeys(ctx, id.ResourceGroup, id.Name, "") + if err != nil { + return fmt.Errorf("Failed to receive access keys for App Configuration %q (Resource Group %q): %+v", id.Name, id.ResourceGroup, err) + } + d.Set("name", resp.Name) d.Set("resource_group_name", id.ResourceGroup) if location := resp.Location; location != nil { d.Set("location", azure.NormalizeLocation(*location)) } - if sku := resp.Sku; sku != nil { - d.Set("sku", sku.Name) + skuName := "" + if resp.Sku != nil && resp.Sku.Name != nil { + skuName = *resp.Sku.Name } + d.Set("sku", skuName) - if endpoint := resp.Endpoint; endpoint != nil { - d.Set("endpoint", resp.Endpoint) + if props := resp.ConfigurationStoreProperties; props != nil { + d.Set("endpoint", props.Endpoint) } - resultPage, err := client.ListKeys(ctx, id.ResourceGroup, id.Name, "") - if err != nil { - return fmt.Errorf("Failed to receive access keys for App Configuration %q (Resource Group %q): %+v", id.Name, id.ResourceGroup, err) - } - - values := resultPage.Values() - for _, value := range values { - accessKeyParams := map[string]string{} - if id := value.ID; id != nil { - accessKeyParams["id"] = *id - } - if value := value.Value; value != nil { - accessKeyParams["secret"] = *value - } - if connectionString := value.ConnectionString; connectionString != nil { - accessKeyParams["connection_string"] = *value.ConnectionString - } - - accessKey := []interface{}{accessKeyParams} - if n := value.Name; n != nil { - if strings.HasPrefix(*n, "Primary") { - if readOnly := value.ReadOnly; readOnly != nil { - if *readOnly { - d.Set("primary_read_key", accessKey) - } else { - d.Set("primary_write_key", accessKey) - } - } - } else if strings.HasPrefix(*n, "Secondary") { - if readOnly := value.ReadOnly; readOnly != nil { - if *readOnly { - d.Set("secondary_read_key", accessKey) - } else { - d.Set("secondary_write_key", accessKey) - } - } - } else { - log.Printf("[WARN] Received unknown App Configuration access key '%s', ignoring...", *n) - } - } - } + accessKeys := flattenAppConfigurationAccessKeys(resultPage.Values()) + d.Set("primary_read_key", accessKeys.primaryReadKey) + d.Set("primary_write_key", accessKeys.primaryWriteKey) + d.Set("secondary_read_key", accessKeys.secondaryReadKey) + d.Set("secondary_write_key", accessKeys.secondaryWriteKey) return tags.FlattenAndSet(d, resp.Tags) } @@ -371,11 +342,72 @@ func resourceArmAppConfigurationDelete(d *schema.ResourceData, meta interface{}) return nil } -func ValidateAppConfigurationName(v interface{}, k string) (warnings []string, errors []error) { - value := v.(string) - if matched := regexp.MustCompile(`^[a-zA-Z0-9-]{5,50}$`).Match([]byte(value)); !matched { - errors = append(errors, fmt.Errorf("%q may only contain alphanumeric characters and dashes and must be between 5-50 chars", k)) +type flattenedAccessKeys struct { + primaryReadKey []interface{} + primaryWriteKey []interface{} + secondaryReadKey []interface{} + secondaryWriteKey []interface{} +} + +func flattenAppConfigurationAccessKeys(values []appconfiguration.APIKey) flattenedAccessKeys { + result := flattenedAccessKeys{ + primaryReadKey: make([]interface{}, 0), + primaryWriteKey: make([]interface{}, 0), + secondaryReadKey: make([]interface{}, 0), + secondaryWriteKey: make([]interface{}, 0), } - return warnings, errors + for _, value := range values { + if value.Name == nil || value.ReadOnly == nil { + continue + } + + accessKey := flattenAppConfigurationAccessKey(value) + name := *value.Name + readOnly := *value.ReadOnly + + if strings.HasPrefix(strings.ToLower(name), "primary") { + if readOnly { + result.primaryReadKey = accessKey + } else { + result.primaryWriteKey = accessKey + } + } + + if strings.HasPrefix(strings.ToLower(name), "secondary") { + if readOnly { + result.secondaryReadKey = accessKey + } else { + result.secondaryWriteKey = accessKey + } + } + } + + return result +} + +func flattenAppConfigurationAccessKey(input appconfiguration.APIKey) []interface{} { + connectionString := "" + + if input.ConnectionString != nil { + connectionString = *input.ConnectionString + } + + id := "" + if input.ID != nil { + id = *input.ID + } + + secret := "" + if input.Value != nil { + secret = *input.Value + } + + return []interface{}{ + map[string]interface{}{ + "connection_string": connectionString, + "id": id, + "secret": secret, + }, + } } diff --git a/azurerm/internal/services/appconfiguration/registration.go b/azurerm/internal/services/appconfiguration/registration.go index dd8d1a92fe0d..2c6d8d31992d 100644 --- a/azurerm/internal/services/appconfiguration/registration.go +++ b/azurerm/internal/services/appconfiguration/registration.go @@ -20,7 +20,9 @@ func (r Registration) WebsiteCategories() []string { // SupportedDataSources returns the supported Data Sources supported by this Service func (r Registration) SupportedDataSources() map[string]*schema.Resource { - return map[string]*schema.Resource{} + return map[string]*schema.Resource{ + "azurerm_app_configuration": dataSourceAppConfiguration(), + } } // SupportedResources returns the supported Resources supported by this Service diff --git a/azurerm/internal/services/appconfiguration/tests/app_configuration_data_source_test.go b/azurerm/internal/services/appconfiguration/tests/app_configuration_data_source_test.go new file mode 100644 index 000000000000..5bf1e9d87942 --- /dev/null +++ b/azurerm/internal/services/appconfiguration/tests/app_configuration_data_source_test.go @@ -0,0 +1,57 @@ +package tests + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/acceptance" +) + +func TestAccAppConfigurationDataSource_basic(t *testing.T) { + data := acceptance.BuildTestData(t, "data.azurerm_app_configuration", "test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acceptance.PreCheck(t) }, + Providers: acceptance.SupportedProviders, + CheckDestroy: testCheckAppConfigurationDestroy, + Steps: []resource.TestStep{ + { + Config: testAppConfigurationResource_standard(data), + }, + { + Config: testAppConfigurationDataSource_basic(data), + Check: resource.ComposeTestCheckFunc( + testCheckAppConfigurationExists(data.ResourceName), + resource.TestCheckResourceAttrSet(data.ResourceName, "endpoint"), + resource.TestCheckResourceAttrSet(data.ResourceName, "location"), + resource.TestCheckResourceAttrSet(data.ResourceName, "sku"), + resource.TestCheckResourceAttrSet(data.ResourceName, "primary_read_key.0.connection_string"), + resource.TestCheckResourceAttrSet(data.ResourceName, "primary_read_key.0.id"), + resource.TestCheckResourceAttrSet(data.ResourceName, "primary_read_key.0.secret"), + resource.TestCheckResourceAttrSet(data.ResourceName, "primary_write_key.0.connection_string"), + resource.TestCheckResourceAttrSet(data.ResourceName, "primary_write_key.0.id"), + resource.TestCheckResourceAttrSet(data.ResourceName, "primary_write_key.0.secret"), + resource.TestCheckResourceAttrSet(data.ResourceName, "secondary_read_key.0.connection_string"), + resource.TestCheckResourceAttrSet(data.ResourceName, "secondary_read_key.0.id"), + resource.TestCheckResourceAttrSet(data.ResourceName, "secondary_read_key.0.secret"), + resource.TestCheckResourceAttrSet(data.ResourceName, "secondary_write_key.0.connection_string"), + resource.TestCheckResourceAttrSet(data.ResourceName, "secondary_write_key.0.id"), + resource.TestCheckResourceAttrSet(data.ResourceName, "secondary_write_key.0.secret"), + ), + }, + }, + }) +} + +func testAppConfigurationDataSource_basic(data acceptance.TestData) string { + template := testAppConfigurationResource_standard(data) + return fmt.Sprintf(` +%s + +data "azurerm_app_configuration" "test" { + name = azurerm_app_configuration.test.name + resource_group_name = azurerm_app_configuration.test.resource_group_name +} +`, template) +} diff --git a/azurerm/internal/services/appconfiguration/tests/resource_arm_app_configuration_test.go b/azurerm/internal/services/appconfiguration/tests/app_configuration_resource_test.go similarity index 65% rename from azurerm/internal/services/appconfiguration/tests/resource_arm_app_configuration_test.go rename to azurerm/internal/services/appconfiguration/tests/app_configuration_resource_test.go index 445ed626dc4b..ed04220e71b7 100644 --- a/azurerm/internal/services/appconfiguration/tests/resource_arm_app_configuration_test.go +++ b/azurerm/internal/services/appconfiguration/tests/app_configuration_resource_test.go @@ -5,85 +5,27 @@ import ( "net/http" "testing" - "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/appconfiguration" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/appconfiguration/parse" "github.com/hashicorp/terraform-plugin-sdk/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/terraform" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/acceptance" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/clients" - "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/features" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" ) -func TestAccAzureRMAppConfigurationName_validation(t *testing.T) { - cases := []struct { - Value string - ErrCount int - }{ - { - Value: "four", - ErrCount: 1, - }, - { - Value: "5five", - ErrCount: 0, - }, - { - Value: "hello-world", - ErrCount: 0, - }, - { - Value: "hello_world", - ErrCount: 1, - }, - { - Value: "helloWorld", - ErrCount: 0, - }, - { - Value: "helloworld12", - ErrCount: 0, - }, - { - Value: "hello@world", - ErrCount: 1, - }, - { - Value: "qfvbdsbvipqdbwsbddbdcwqffewsqwcdw21ddwqwd3324120", - ErrCount: 0, - }, - { - Value: "qfvbdsbvipqdbwsbddbdcwqffewsqwcdw21ddwqwd332412020", - ErrCount: 0, - }, - { - Value: "qfvbdsbvipqdbwsbddbdcwqfjjfewsqwcdw21ddwqwd33241201", - ErrCount: 1, - }, - } - - for _, tc := range cases { - _, errors := appconfiguration.ValidateAppConfigurationName(tc.Value, "azurerm_app_configuration") - - if len(errors) != tc.ErrCount { - t.Fatalf("Expected the Azure App Configuration Name to trigger a validation error: %v", tc) - } - } -} - -func TestAccAzureAppConfiguration_free(t *testing.T) { +func TestAccAppConfigurationResource_free(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_app_configuration", "test") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acceptance.PreCheck(t) }, Providers: acceptance.SupportedProviders, - CheckDestroy: testCheckAzureAppConfigurationDestroy, + CheckDestroy: testCheckAppConfigurationDestroy, Steps: []resource.TestStep{ { - Config: testAccAzureAppConfiguration_free(data), + Config: testAppConfigurationResource_free(data), Check: resource.ComposeTestCheckFunc( - testCheckAzureAppConfigurationExists(data.ResourceName), + testCheckAppConfigurationExists(data.ResourceName), ), }, data.ImportStep(), @@ -91,18 +33,18 @@ func TestAccAzureAppConfiguration_free(t *testing.T) { }) } -func TestAccAzureAppConfiguration_standard(t *testing.T) { +func TestAccAppConfigurationResource_standard(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_app_configuration", "test") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acceptance.PreCheck(t) }, Providers: acceptance.SupportedProviders, - CheckDestroy: testCheckAzureAppConfigurationDestroy, + CheckDestroy: testCheckAppConfigurationDestroy, Steps: []resource.TestStep{ { - Config: testAccAzureAppConfiguration_standard(data), + Config: testAppConfigurationResource_standard(data), Check: resource.ComposeTestCheckFunc( - testCheckAzureAppConfigurationExists(data.ResourceName), + testCheckAppConfigurationExists(data.ResourceName), ), }, data.ImportStep(), @@ -110,41 +52,37 @@ func TestAccAzureAppConfiguration_standard(t *testing.T) { }) } -func TestAccAzureAppConfiguration_requiresImport(t *testing.T) { - if !features.ShouldResourcesBeImported() { - t.Skip("Skipping since resources aren't required to be imported") - return - } +func TestAccAppConfigurationResource_requiresImport(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_app_configuration", "test") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acceptance.PreCheck(t) }, Providers: acceptance.SupportedProviders, - CheckDestroy: testCheckAzureAppConfigurationDestroy, + CheckDestroy: testCheckAppConfigurationDestroy, Steps: []resource.TestStep{ { - Config: testAccAzureAppConfiguration_free(data), + Config: testAppConfigurationResource_free(data), Check: resource.ComposeTestCheckFunc( - testCheckAzureAppConfigurationExists(data.ResourceName), + testCheckAppConfigurationExists(data.ResourceName), ), }, - data.RequiresImportErrorStep(testAccAzureAppConfiguration_requiresImport), + data.RequiresImportErrorStep(testAppConfigurationResource_requiresImport), }, }) } -func TestAccAzureAppConfiguration_complete(t *testing.T) { +func TestAccAppConfigurationResource_complete(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_app_configuration", "test") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acceptance.PreCheck(t) }, Providers: acceptance.SupportedProviders, - CheckDestroy: testCheckAzureAppConfigurationDestroy, + CheckDestroy: testCheckAppConfigurationDestroy, Steps: []resource.TestStep{ { - Config: testAccAzureAppConfiguration_complete(data), + Config: testAppConfigurationResource_complete(data), Check: resource.ComposeTestCheckFunc( - testCheckAzureAppConfigurationExists(data.ResourceName), + testCheckAppConfigurationExists(data.ResourceName), ), }, data.ImportStep(), @@ -152,31 +90,31 @@ func TestAccAzureAppConfiguration_complete(t *testing.T) { }) } -func TestAccAzureAppConfiguration_update(t *testing.T) { +func TestAccAppConfigurationResource_update(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_app_configuration", "test") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acceptance.PreCheck(t) }, Providers: acceptance.SupportedProviders, - CheckDestroy: testCheckAzureAppConfigurationDestroy, + CheckDestroy: testCheckAppConfigurationDestroy, Steps: []resource.TestStep{ { - Config: testAccAzureAppConfiguration_complete(data), + Config: testAppConfigurationResource_complete(data), Check: resource.ComposeTestCheckFunc( - testCheckAzureAppConfigurationExists(data.ResourceName), + testCheckAppConfigurationExists(data.ResourceName), ), }, { - Config: testAccAzureAppConfiguration_completeUpdated(data), + Config: testAppConfigurationResource_completeUpdated(data), Check: resource.ComposeTestCheckFunc( - testCheckAzureAppConfigurationExists(data.ResourceName), + testCheckAppConfigurationExists(data.ResourceName), ), }, }, }) } -func testCheckAzureAppConfigurationDestroy(s *terraform.State) error { +func testCheckAppConfigurationDestroy(s *terraform.State) error { conn := acceptance.AzureProvider.Meta().(*clients.Client).AppConfiguration.AppConfigurationsClient ctx := acceptance.AzureProvider.Meta().(*clients.Client).StopContext @@ -203,7 +141,7 @@ func testCheckAzureAppConfigurationDestroy(s *terraform.State) error { return nil } -func testCheckAzureAppConfigurationExists(resourceName string) resource.TestCheckFunc { +func testCheckAppConfigurationExists(resourceName string) resource.TestCheckFunc { return func(s *terraform.State) error { conn := acceptance.AzureProvider.Meta().(*clients.Client).AppConfiguration.AppConfigurationsClient ctx := acceptance.AzureProvider.Meta().(*clients.Client).StopContext @@ -232,7 +170,7 @@ func testCheckAzureAppConfigurationExists(resourceName string) resource.TestChec } } -func testAccAzureAppConfiguration_free(data acceptance.TestData) string { +func testAppConfigurationResource_free(data acceptance.TestData) string { return fmt.Sprintf(` provider "azurerm" { features {} @@ -252,7 +190,7 @@ resource "azurerm_app_configuration" "test" { `, data.RandomInteger, data.Locations.Primary, data.RandomInteger) } -func testAccAzureAppConfiguration_standard(data acceptance.TestData) string { +func testAppConfigurationResource_standard(data acceptance.TestData) string { return fmt.Sprintf(` provider "azurerm" { features {} @@ -272,8 +210,8 @@ resource "azurerm_app_configuration" "test" { `, data.RandomInteger, data.Locations.Primary, data.RandomInteger) } -func testAccAzureAppConfiguration_requiresImport(data acceptance.TestData) string { - template := testAccAzureAppConfiguration_free(data) +func testAppConfigurationResource_requiresImport(data acceptance.TestData) string { + template := testAppConfigurationResource_free(data) return fmt.Sprintf(` %s @@ -286,7 +224,7 @@ resource "azurerm_app_configuration" "import" { `, template) } -func testAccAzureAppConfiguration_complete(data acceptance.TestData) string { +func testAppConfigurationResource_complete(data acceptance.TestData) string { return fmt.Sprintf(` provider "azurerm" { features {} @@ -310,7 +248,7 @@ resource "azurerm_app_configuration" "test" { `, data.RandomInteger, data.Locations.Primary, data.RandomInteger) } -func testAccAzureAppConfiguration_completeUpdated(data acceptance.TestData) string { +func testAppConfigurationResource_completeUpdated(data acceptance.TestData) string { return fmt.Sprintf(` provider "azurerm" { features {} diff --git a/azurerm/internal/services/appconfiguration/validate/name.go b/azurerm/internal/services/appconfiguration/validate/name.go new file mode 100644 index 000000000000..8b3df0f8afcc --- /dev/null +++ b/azurerm/internal/services/appconfiguration/validate/name.go @@ -0,0 +1,15 @@ +package validate + +import ( + "fmt" + "regexp" +) + +func AppConfigurationName(v interface{}, k string) (warnings []string, errors []error) { + value := v.(string) + if matched := regexp.MustCompile(`^[a-zA-Z0-9-]{5,50}$`).Match([]byte(value)); !matched { + errors = append(errors, fmt.Errorf("%q may only contain alphanumeric characters and dashes and must be between 5-50 chars", k)) + } + + return warnings, errors +} diff --git a/azurerm/internal/services/appconfiguration/validate/name_test.go b/azurerm/internal/services/appconfiguration/validate/name_test.go new file mode 100644 index 000000000000..1c40161a2aab --- /dev/null +++ b/azurerm/internal/services/appconfiguration/validate/name_test.go @@ -0,0 +1,60 @@ +package validate + +import ( + "testing" +) + +func TestAppConfigurationName(t *testing.T) { + cases := []struct { + Value string + ErrCount int + }{ + { + Value: "four", + ErrCount: 1, + }, + { + Value: "5five", + ErrCount: 0, + }, + { + Value: "hello-world", + ErrCount: 0, + }, + { + Value: "hello_world", + ErrCount: 1, + }, + { + Value: "helloWorld", + ErrCount: 0, + }, + { + Value: "helloworld12", + ErrCount: 0, + }, + { + Value: "hello@world", + ErrCount: 1, + }, + { + Value: "qfvbdsbvipqdbwsbddbdcwqffewsqwcdw21ddwqwd3324120", + ErrCount: 0, + }, + { + Value: "qfvbdsbvipqdbwsbddbdcwqffewsqwcdw21ddwqwd332412020", + ErrCount: 0, + }, + { + Value: "qfvbdsbvipqdbwsbddbdcwqfjjfewsqwcdw21ddwqwd33241201", + ErrCount: 1, + }, + } + + for _, tc := range cases { + _, errors := AppConfigurationName(tc.Value, "azurerm_app_configuration") + if len(errors) != tc.ErrCount { + t.Fatalf("Expected the Azure App Configuration Name to trigger a validation error: %v", tc) + } + } +} diff --git a/website/azurerm.erb b/website/azurerm.erb index fe15a0396745..224d2313dc13 100644 --- a/website/azurerm.erb +++ b/website/azurerm.erb @@ -74,6 +74,10 @@ azurerm_api_management_user +
  • + azurerm_app_configuration +
  • +
  • azurerm_application_security_group
  • diff --git a/website/docs/d/app_configuration.html.markdown b/website/docs/d/app_configuration.html.markdown new file mode 100644 index 000000000000..95679fff1efe --- /dev/null +++ b/website/docs/d/app_configuration.html.markdown @@ -0,0 +1,100 @@ +--- +subcategory: "App Configuration" +layout: "azurerm" +page_title: "Azure Resource Manager: Data Source: azurerm_app_configuration" +description: |- + Gets information about an existing App Configuration. +--- + +# Data Source: azurerm_app_configuration + +Use this data source to access information about an existing App Configuration. + +## Example Usage + +```hcl +data "azurerm_app_configuration" "example" { + name = "existing" + resource_group_name = "existing" +} + +output "id" { + value = data.azurerm_app_configuration.example.id +} +``` + +## Arguments Reference + +The following arguments are supported: + +* `name` - (Required) The Name of this App Configuration. + +* `resource_group_name` - (Required) The name of the Resource Group where the App Configuration exists. + +## Attributes Reference + +In addition to the Arguments listed above - the following Attributes are exported: + +* `id` - The ID of the App Configuration. + +* `endpoint` - The Endpoint used to access this App Configuration. + +* `location` - The Azure Region where the App Configuration exists. + +* `primary_read_key` - A `primary_read_key` block as defined below containing the primary read access key. + +* `primary_write_key` - A `primary_write_key` block as defined below containing the primary write access key. + +* `secondary_read_key` - A `secondary_read_key` block as defined below containing the secondary read access key. + +* `secondary_write_key` - A `secondary_write_key` block as defined below containing the secondary write access key. + +* `sku` - The name of the SKU used for this App Configuration. + +* `tags` - A mapping of tags assigned to the App Configuration. + +--- + +A `primary_read_key` block exports the following: + +* `connection_string` - The Connection String for this Access Key - comprising of the Endpoint, ID and Secret. + +* `id` - The ID of the Access Key. + +* `secret` - The Secret of the Access Key. + +--- + +A `primary_write_key` block exports the following: + +* `connection_string` - The Connection String for this Access Key - comprising of the Endpoint, ID and Secret. + +* `id` - The ID of the Access Key. + +* `secret` - The Secret of the Access Key. + +--- + +A `secondary_read_key` block exports the following: + +* `connection_string` - The Connection String for this Access Key - comprising of the Endpoint, ID and Secret. + +* `id` - The ID of the Access Key. + +* `secret` - The Secret of the Access Key. + +--- + +A `secondary_write_key` block exports the following: + +* `connection_string` - The Connection String for this Access Key - comprising of the Endpoint, ID and Secret. + +* `id` - The ID of the Access Key. + +* `secret` - The Secret of the Access Key. + +## Timeouts + +The `timeouts` block allows you to specify [timeouts](https://www.terraform.io/docs/configuration/resources.html#timeouts) for certain actions: + +* `read` - (Defaults to 5 minutes) Used when retrieving the App Configuration. \ No newline at end of file diff --git a/website/docs/r/app_configuration.html.markdown b/website/docs/r/app_configuration.html.markdown index 61f8a18ea585..90ea0f6c33eb 100644 --- a/website/docs/r/app_configuration.html.markdown +++ b/website/docs/r/app_configuration.html.markdown @@ -51,23 +51,53 @@ The following attributes are exported: * `endpoint` - The URL of the App Configuration. -* `primary_write_key` - An `access_key` block as defined below containing the primary write access key. +* `primary_read_key` - A `primary_read_key` block as defined below containing the primary read access key. -* `secondary_write_key` - An `access_key` block as defined below containing the secondary write access key. +* `primary_write_key` - A `primary_write_key` block as defined below containing the primary write access key. -* `primary_read_key` - An `access_key` block as defined below containing the primary read access key. +* `secondary_read_key` - A `secondary_read_key` block as defined below containing the secondary read access key. -* `secondary_read_key` - An `access_key` block as defined below containing the secondary read access key. +* `secondary_write_key` - A `secondary_write_key` block as defined below containing the secondary write access key. --- -A `access_key` block exports the following: +A `primary_read_key` block exports the following: -* `id` - The ID of the access key. +* `connection_string` - The Connection String for this Access Key - comprising of the Endpoint, ID and Secret. -* `secret` - The secret of the access key. +* `id` - The ID of the Access Key. -* `connection_string` - The connection string including the endpoint, id and secret. +* `secret` - The Secret of the Access Key. + +--- + +A `primary_write_key` block exports the following: + +* `connection_string` - The Connection String for this Access Key - comprising of the Endpoint, ID and Secret. + +* `id` - The ID of the Access Key. + +* `secret` - The Secret of the Access Key. + +--- + +A `secondary_read_key` block exports the following: + +* `connection_string` - The Connection String for this Access Key - comprising of the Endpoint, ID and Secret. + +* `id` - The ID of the Access Key. + +* `secret` - The Secret of the Access Key. + +--- + +A `secondary_write_key` block exports the following: + +* `connection_string` - The Connection String for this Access Key - comprising of the Endpoint, ID and Secret. + +* `id` - The ID of the Access Key. + +* `secret` - The Secret of the Access Key. ## Timeouts