diff --git a/azurerm/internal/services/mariadb/client.go b/azurerm/internal/services/mariadb/client.go index a0d961df4cb6..628a2eda1f86 100644 --- a/azurerm/internal/services/mariadb/client.go +++ b/azurerm/internal/services/mariadb/client.go @@ -6,14 +6,18 @@ import ( ) type Client struct { - DatabasesClient mariadb.DatabasesClient - FirewallRulesClient mariadb.FirewallRulesClient - ServersClient mariadb.ServersClient + ConfigurationsClient mariadb.ConfigurationsClient + DatabasesClient mariadb.DatabasesClient + FirewallRulesClient mariadb.FirewallRulesClient + ServersClient mariadb.ServersClient } func BuildClient(o *common.ClientOptions) *Client { c := Client{} + c.ConfigurationsClient = mariadb.NewConfigurationsClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) + o.ConfigureClient(&c.ConfigurationsClient.Client, o.ResourceManagerAuthorizer) + c.DatabasesClient = mariadb.NewDatabasesClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) o.ConfigureClient(&c.DatabasesClient.Client, o.ResourceManagerAuthorizer) diff --git a/azurerm/provider.go b/azurerm/provider.go index 3a9ccc2d2281..e0fc3f00c3fc 100644 --- a/azurerm/provider.go +++ b/azurerm/provider.go @@ -277,6 +277,7 @@ func Provider() terraform.ResourceProvider { "azurerm_management_group": resourceArmManagementGroup(), "azurerm_management_lock": resourceArmManagementLock(), "azurerm_maps_account": resourceArmMapsAccount(), + "azurerm_mariadb_configuration": resourceArmMariaDbConfiguration(), "azurerm_mariadb_database": resourceArmMariaDbDatabase(), "azurerm_mariadb_firewall_rule": resourceArmMariaDBFirewallRule(), "azurerm_mariadb_server": resourceArmMariaDbServer(), diff --git a/azurerm/resource_arm_mariadb_configuration.go b/azurerm/resource_arm_mariadb_configuration.go new file mode 100644 index 000000000000..b2bf042332cf --- /dev/null +++ b/azurerm/resource_arm_mariadb_configuration.go @@ -0,0 +1,155 @@ +package azurerm + +import ( + "fmt" + "log" + "regexp" + + "github.com/Azure/azure-sdk-for-go/services/mariadb/mgmt/2018-06-01/mariadb" + "github.com/hashicorp/terraform/helper/schema" + "github.com/hashicorp/terraform/helper/validation" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" +) + +func resourceArmMariaDbConfiguration() *schema.Resource { + return &schema.Resource{ + Create: resourceArmMariaDbConfigurationCreateUpdate, + Read: resourceArmMariaDbConfigurationRead, + Delete: resourceArmMariaDbConfigurationDelete, + + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.NoZeroValues, + }, + + "resource_group_name": azure.SchemaResourceGroupName(), + + "server_name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringMatch( + regexp.MustCompile("^[-a-zA-Z0-9]{3,50}$"), + "server_name must be 3 - 50 characters long, and contain only letters, numbers and hyphens", + ), + }, + + "value": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + }, + } +} + +func resourceArmMariaDbConfigurationCreateUpdate(d *schema.ResourceData, meta interface{}) error { + client := meta.(*ArmClient).mariadb.ConfigurationsClient + ctx := meta.(*ArmClient).StopContext + + log.Printf("[INFO] preparing arguments for AzureRM MariaDb Configuration creation.") + + name := d.Get("name").(string) + resourceGroup := d.Get("resource_group_name").(string) + serverName := d.Get("server_name").(string) + value := d.Get("value").(string) + + properties := mariadb.Configuration{ + ConfigurationProperties: &mariadb.ConfigurationProperties{ + Value: utils.String(value), + }, + } + + future, err := client.CreateOrUpdate(ctx, resourceGroup, serverName, name, properties) + if err != nil { + return fmt.Errorf("Error issuing create/update request for MariaDb Configuration %s (resource group %s, server name %s): %v", name, resourceGroup, serverName, err) + } + + if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { + return fmt.Errorf("Error waiting for create/update of MariaDb Configuration %s (resource group %s, server name %s): %v", name, resourceGroup, serverName, err) + } + + read, err := client.Get(ctx, resourceGroup, serverName, name) + if err != nil { + return fmt.Errorf("Error issuing get request for MariaDb Configuration %s (resource group %s, server name %s): %v", name, resourceGroup, serverName, err) + } + if read.ID == nil { + return fmt.Errorf("Cannot read MariaDb Configuration %s (resource group %s, server name %s) ID", name, resourceGroup, serverName) + } + + d.SetId(*read.ID) + + return resourceArmMariaDbConfigurationRead(d, meta) +} + +func resourceArmMariaDbConfigurationRead(d *schema.ResourceData, meta interface{}) error { + client := meta.(*ArmClient).mariadb.ConfigurationsClient + ctx := meta.(*ArmClient).StopContext + + id, err := parseAzureResourceID(d.Id()) + if err != nil { + return err + } + resourceGroup := id.ResourceGroup + serverName := id.Path["servers"] + name := id.Path["configurations"] + + resp, err := client.Get(ctx, resourceGroup, serverName, name) + if err != nil { + if utils.ResponseWasNotFound(resp.Response) { + log.Printf("[WARN] MariaDb Configuration %q was not found (resource group %q)", name, resourceGroup) + d.SetId("") + return nil + } + + return fmt.Errorf("Error making Read request on Azure MariaDb Configuration %q (Resource Group %q): %+v", name, resourceGroup, err) + } + + d.Set("name", resp.Name) + d.Set("server_name", serverName) + d.Set("resource_group_name", resourceGroup) + d.Set("value", resp.ConfigurationProperties.Value) + + return nil +} + +func resourceArmMariaDbConfigurationDelete(d *schema.ResourceData, meta interface{}) error { + client := meta.(*ArmClient).mariadb.ConfigurationsClient + ctx := meta.(*ArmClient).StopContext + + id, err := parseAzureResourceID(d.Id()) + if err != nil { + return err + } + resourceGroup := id.ResourceGroup + serverName := id.Path["servers"] + name := id.Path["configurations"] + + // "delete" = resetting this to the default value + resp, err := client.Get(ctx, resourceGroup, serverName, name) + if err != nil { + return fmt.Errorf("Error retrieving MariaDb Configuration %q (Resource Group %q): %+v", name, resourceGroup, err) + } + + properties := mariadb.Configuration{ + ConfigurationProperties: &mariadb.ConfigurationProperties{ + // we can alternatively set `source: "system-default"` + Value: resp.DefaultValue, + }, + } + + future, err := client.CreateOrUpdate(ctx, resourceGroup, serverName, name, properties) + if err != nil { + return err + } + + return future.WaitForCompletionRef(ctx, client.Client) +} diff --git a/azurerm/resource_arm_mariadb_configuration_test.go b/azurerm/resource_arm_mariadb_configuration_test.go new file mode 100644 index 000000000000..1e6e131ef145 --- /dev/null +++ b/azurerm/resource_arm_mariadb_configuration_test.go @@ -0,0 +1,252 @@ +package azurerm + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/terraform" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/tf" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" +) + +func TestAccAzureRMMariaDbConfiguration_characterSetServer(t *testing.T) { + resourceName := "azurerm_mariadb_configuration.test" + ri := tf.AccRandTimeInt() + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMMariaDbConfigurationDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMMariaDbConfiguration_characterSetServer(ri, testLocation()), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMMariaDbConfigurationValue(resourceName, "hebrew"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccAzureRMMariaDbConfiguration_empty(ri, testLocation()), + Check: resource.ComposeTestCheckFunc( + // "delete" resets back to the default value + testCheckAzureRMMariaDbConfigurationValueReset(ri, "character_set_server"), + ), + }, + }, + }) +} + +func TestAccAzureRMMariaDbConfiguration_interactiveTimeout(t *testing.T) { + resourceName := "azurerm_mariadb_configuration.test" + ri := tf.AccRandTimeInt() + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMMariaDbConfigurationDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMMariaDbConfiguration_interactiveTimeout(ri, testLocation()), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMMariaDbConfigurationValue(resourceName, "30"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccAzureRMMariaDbConfiguration_empty(ri, testLocation()), + Check: resource.ComposeTestCheckFunc( + // "delete" resets back to the default value + testCheckAzureRMMariaDbConfigurationValueReset(ri, "interactive_timeout"), + ), + }, + }, + }) +} + +func TestAccAzureRMMariaDbConfiguration_logSlowAdminStatements(t *testing.T) { + resourceName := "azurerm_mariadb_configuration.test" + ri := tf.AccRandTimeInt() + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMMariaDbConfigurationDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMMariaDbConfiguration_logSlowAdminStatements(ri, testLocation()), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMMariaDbConfigurationValue(resourceName, "on"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccAzureRMMariaDbConfiguration_empty(ri, testLocation()), + Check: resource.ComposeTestCheckFunc( + // "delete" resets back to the default value + testCheckAzureRMMariaDbConfigurationValueReset(ri, "log_slow_admin_statements"), + ), + }, + }, + }) +} + +func testCheckAzureRMMariaDbConfigurationValue(resourceName string, value string) resource.TestCheckFunc { + return func(s *terraform.State) error { + // Ensure we have enough information in state to look up in API + rs, ok := s.RootModule().Resources[resourceName] + if !ok { + return fmt.Errorf("Not found: %s", resourceName) + } + + name := rs.Primary.Attributes["name"] + serverName := rs.Primary.Attributes["server_name"] + resourceGroup, hasResourceGroup := rs.Primary.Attributes["resource_group_name"] + if !hasResourceGroup { + return fmt.Errorf("Bad: no resource group found in state for MariaDb Configuration: %s", name) + } + + client := testAccProvider.Meta().(*ArmClient).mariadb.ConfigurationsClient + ctx := testAccProvider.Meta().(*ArmClient).StopContext + + resp, err := client.Get(ctx, resourceGroup, serverName, name) + if err != nil { + if utils.ResponseWasNotFound(resp.Response) { + return fmt.Errorf("Bad: MariaDb Configuration %q (server %q resource group: %q) does not exist", name, serverName, resourceGroup) + } + + return fmt.Errorf("Bad: Get on mariadbConfigurationsClient: %+v", err) + } + + if *resp.Value != value { + return fmt.Errorf("MariaDb Configuration wasn't set. Expected '%s' - got '%s': \n%+v", value, *resp.Value, resp) + } + + return nil + } +} + +func testCheckAzureRMMariaDbConfigurationValueReset(rInt int, configurationName string) resource.TestCheckFunc { + return func(s *terraform.State) error { + + resourceGroup := fmt.Sprintf("acctestRG-%d", rInt) + serverName := fmt.Sprintf("acctestmariadbsvr-%d", rInt) + + client := testAccProvider.Meta().(*ArmClient).mariadb.ConfigurationsClient + ctx := testAccProvider.Meta().(*ArmClient).StopContext + + resp, err := client.Get(ctx, resourceGroup, serverName, configurationName) + if err != nil { + if utils.ResponseWasNotFound(resp.Response) { + return fmt.Errorf("Bad: MariaDb Configuration %q (server %q resource group: %q) does not exist", configurationName, serverName, resourceGroup) + } + return fmt.Errorf("Bad: Get on mariadbConfigurationsClient: %+v", err) + } + + actualValue := *resp.Value + defaultValue := *resp.DefaultValue + + if defaultValue != actualValue { + return fmt.Errorf("MariaDb Configuration wasn't set to the default value. Expected '%s' - got '%s': \n%+v", defaultValue, actualValue, resp) + } + + return nil + } +} + +func testCheckAzureRMMariaDbConfigurationDestroy(s *terraform.State) error { + client := testAccProvider.Meta().(*ArmClient).mariadb.ConfigurationsClient + ctx := testAccProvider.Meta().(*ArmClient).StopContext + + for _, rs := range s.RootModule().Resources { + if rs.Type != "azurerm_mariadb_configuration" { + continue + } + + name := rs.Primary.Attributes["name"] + serverName := rs.Primary.Attributes["server_name"] + resourceGroup := rs.Primary.Attributes["resource_group_name"] + + resp, err := client.Get(ctx, resourceGroup, serverName, name) + + if err != nil { + if utils.ResponseWasNotFound(resp.Response) { + return nil + } + + return err + } + } + + return nil +} + +func testAccAzureRMMariaDbConfiguration_characterSetServer(rInt int, location string) string { + return testAccAzureRMMariaDbConfiguration_template(rInt, location, "character_set_server", "hebrew") +} + +func testAccAzureRMMariaDbConfiguration_interactiveTimeout(rInt int, location string) string { + return testAccAzureRMMariaDbConfiguration_template(rInt, location, "interactive_timeout", "30") +} + +func testAccAzureRMMariaDbConfiguration_logSlowAdminStatements(rInt int, location string) string { + return testAccAzureRMMariaDbConfiguration_template(rInt, location, "log_slow_admin_statements", "on") +} + +func testAccAzureRMMariaDbConfiguration_template(rInt int, location string, name string, value string) string { + server := testAccAzureRMMariaDbConfiguration_empty(rInt, location) + config := fmt.Sprintf(` +resource "azurerm_mariadb_configuration" "test" { + name = "%s" + resource_group_name = "${azurerm_resource_group.test.name}" + server_name = "${azurerm_mariadb_server.test.name}" + value = "%s" +} +`, name, value) + return server + config +} + +func testAccAzureRMMariaDbConfiguration_empty(rInt int, location string) string { + return fmt.Sprintf(` +resource "azurerm_resource_group" "test" { + name = "acctestRG-%d" + location = "%s" +} + +resource "azurerm_mariadb_server" "test" { + name = "acctestmariadbsvr-%d" + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" + + sku { + name = "GP_Gen5_2" + capacity = 2 + tier = "GeneralPurpose" + family = "Gen5" + } + + storage_profile { + storage_mb = 51200 + backup_retention_days = 7 + geo_redundant_backup = "Disabled" + } + + administrator_login = "acctestun" + administrator_login_password = "H@Sh1CoR3!" + version = "10.2" + ssl_enforcement = "Enabled" +} +`, rInt, location, rInt) +} diff --git a/website/docs/r/mariadb_configuration.html.markdown b/website/docs/r/mariadb_configuration.html.markdown new file mode 100644 index 000000000000..47067dddeec4 --- /dev/null +++ b/website/docs/r/mariadb_configuration.html.markdown @@ -0,0 +1,79 @@ +--- +layout: "azurerm" +page_title: "Azure Resource Manager: azurerm_mariadb_configuration" +sidebar_current: "docs-azurerm-resource-database-mariadb-configuration" +description: |- + Sets a MariaDB Configuration value on a MariaDB Server. +--- + +# azurerm_mariadb_configuration + +Sets a MariaDB Configuration value on a MariaDB Server. + +-> **NOTE** MariaDB Server is currently in Public Preview. You can find more information, including [how to register for the Public Preview here](https://azure.microsoft.com/en-us/updates/mariadb-public-preview/). + +## Example Usage + +```hcl +resource "azurerm_resource_group" "example" { + name = "api-rg-pro" + location = "West Europe" +} + +resource "azurerm_mariadb_server" "example" { + name = "mariadb-server-1" + location = "${azurerm_resource_group.example.location}" + resource_group_name = "${azurerm_resource_group.example.name}" + + sku { + name = "B_Gen5_2" + capacity = 2 + tier = "Basic" + family = "Gen5" + } + + storage_profile { + storage_mb = 5120 + backup_retention_days = 7 + geo_redundant_backup = "Disabled" + } + + administrator_login = "mariadbadmin" + administrator_login_password = "H@Sh1CoR3!" + version = "10.2" + ssl_enforcement = "Enabled" +} + +resource "azurerm_mariadb_configuration" "example" { + name = "interactive_timeout" + resource_group_name = "${azurerm_resource_group.example.name}" + server_name = "${azurerm_mariadb_server.example.name}" + value = "600" +} +``` + +## Argument Reference + +The following arguments are supported: + +* `name` - (Required) Specifies the name of the MariaDB Configuration, which needs [to be a valid MariaDB configuration name](https://mariadb.com/kb/en/library/server-system-variables/). Changing this forces a new resource to be created. + +* `server_name` - (Required) Specifies the name of the MariaDB Server. Changing this forces a new resource to be created. + +* `resource_group_name` - (Required) The name of the resource group in which the MariaDB Server exists. Changing this forces a new resource to be created. + +* `value` - (Required) Specifies the value of the MariaDB Configuration. See the MariaDB documentation for valid values. + +## Attributes Reference + +The following attributes are exported: + +* `id` - The ID of the MariaDB Configuration. + +## Import + +MariaDB Configurations can be imported using the `resource id`, e.g. + +```shell +terraform import azurerm_mariadb_configuration.interactive_timeout /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/mygroup1/providers/Microsoft.DBforMariaDB/servers/server1/configurations/interactive_timeout +```