From 8fe2db90215aa8a64dfe969540bcd5bcf07c1f7b Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Tue, 5 Sep 2017 10:18:21 +0100 Subject: [PATCH 01/27] Adding a Sweeper for CosmosDB Accounts --- .../resource_arm_cosmos_db_account_test.go | 52 ++++++++++++++++++- 1 file changed, 51 insertions(+), 1 deletion(-) diff --git a/azurerm/resource_arm_cosmos_db_account_test.go b/azurerm/resource_arm_cosmos_db_account_test.go index 46d17a3bc6d3..a4b3a902bd82 100644 --- a/azurerm/resource_arm_cosmos_db_account_test.go +++ b/azurerm/resource_arm_cosmos_db_account_test.go @@ -2,14 +2,64 @@ package azurerm import ( "fmt" + "log" "net/http" "testing" "github.com/hashicorp/terraform/helper/acctest" "github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/terraform" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" ) +func init() { + resource.AddTestSweepers("azurerm_cosmosdb_account", &resource.Sweeper{ + Name: "azurerm_cosmosdb_account", + F: testSweepCosmosDBAccount, + }) +} + +func testSweepCosmosDBAccount(region string) error { + armClient, err := buildConfigForSweepers() + if err != nil { + return err + } + + client := (*armClient).cosmosDBClient + + log.Printf("Retrieving the CosmosDB Accounts..") + results, err := client.List() + if err != nil { + return fmt.Errorf("Error Listing on CosmosDB Accounts: %+v", err) + } + + for _, account := range *results.Value { + if !shouldSweepAcceptanceTestResource(*account.Name, *account.Location, region) { + continue + } + + resourceId, err := parseAzureResourceID(*account.ID) + if err != nil { + return err + } + + resourceGroup := resourceId.ResourceGroup + name := resourceId.Path["databaseAccounts"] + + log.Printf("Deleting CosmosDB Account '%s' in Resource Group '%s'", name, resourceGroup) + deleteResp, deleteErr := client.Delete(resourceGroup, name, make(chan struct{})) + resp := <-deleteResp + err = <-deleteErr + if err != nil { + if !utils.ResponseWasNotFound(resp) { + return err + } + } + } + + return nil +} + func TestAccAzureRMCosmosDBAccountName_validation(t *testing.T) { str := acctest.RandString(50) cases := []struct { @@ -194,7 +244,7 @@ func testCheckAzureRMCosmosDBAccountDestroy(s *terraform.State) error { conn := testAccProvider.Meta().(*ArmClient).cosmosDBClient for _, rs := range s.RootModule().Resources { - if rs.Type != "azurerm_cosmos_db" { + if rs.Type != "azurerm_cosmosdb_account" { continue } From d8c142d303a82370534e50393c07f737e9867500 Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Sun, 9 Jul 2017 14:22:02 -0700 Subject: [PATCH 02/27] Adding support for PostgreSQL Servers --- azurerm/config.go | 9 + azurerm/import_arm_postgresql_server_test.go | 34 ++ azurerm/provider.go | 34 +- azurerm/resource_arm_postgresql_server.go | 305 ++++++++++++++++++ .../resource_arm_postgresql_server_test.go | 110 +++++++ website/azurerm.erb | 13 + .../docs/r/postgresql_server.html.markdown | 88 +++++ 7 files changed, 577 insertions(+), 16 deletions(-) create mode 100644 azurerm/import_arm_postgresql_server_test.go create mode 100644 azurerm/resource_arm_postgresql_server.go create mode 100644 azurerm/resource_arm_postgresql_server_test.go create mode 100644 website/docs/r/postgresql_server.html.markdown diff --git a/azurerm/config.go b/azurerm/config.go index d6eef74e042f..169608c3c81b 100644 --- a/azurerm/config.go +++ b/azurerm/config.go @@ -20,6 +20,7 @@ import ( "github.com/Azure/azure-sdk-for-go/arm/graphrbac" "github.com/Azure/azure-sdk-for-go/arm/keyvault" "github.com/Azure/azure-sdk-for-go/arm/network" + "github.com/Azure/azure-sdk-for-go/arm/postgresql" "github.com/Azure/azure-sdk-for-go/arm/redis" "github.com/Azure/azure-sdk-for-go/arm/resources/resources" "github.com/Azure/azure-sdk-for-go/arm/resources/subscriptions" @@ -90,6 +91,8 @@ type ArmClient struct { eventHubConsumerGroupClient eventhub.ConsumerGroupsClient eventHubNamespacesClient eventhub.NamespacesClient + postgresqlServersClient postgresql.ServersClient + providers resources.ProvidersClient resourceGroupClient resources.GroupsClient tagsClient resources.TagsClient @@ -401,6 +404,12 @@ func (c *Config) getArmClient() (*ArmClient, error) { vnpc.Sender = autorest.CreateSender(withRequestLogging()) client.vnetPeeringsClient = vnpc + psc := postgresql.NewServersClientWithBaseURI(endpoint, c.SubscriptionID) + setUserAgent(&psc.Client) + psc.Authorizer = auth + psc.Sender = autorest.CreateSender(withRequestLogging()) + client.postgresqlServersClient = psc + rtc := network.NewRouteTablesClientWithBaseURI(endpoint, c.SubscriptionID) setUserAgent(&rtc.Client) rtc.Authorizer = auth diff --git a/azurerm/import_arm_postgresql_server_test.go b/azurerm/import_arm_postgresql_server_test.go new file mode 100644 index 000000000000..da8da9aa5d20 --- /dev/null +++ b/azurerm/import_arm_postgresql_server_test.go @@ -0,0 +1,34 @@ +package azurerm + +import ( + "testing" + + "github.com/hashicorp/terraform/helper/acctest" + "github.com/hashicorp/terraform/helper/resource" +) + +func TestAccAzureRMPostgreSQLServer_importBasic(t *testing.T) { + resourceName := "azurerm_postgresql_server.test" + + ri := acctest.RandInt() + config := testAccAzureRMPostgreSQLServer_basic(ri) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMPostgreSQLServerDestroy, + Steps: []resource.TestStep{ + { + Config: config, + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "administrator_login_password", // not returned as sensitive + }, + }, + }, + }) +} diff --git a/azurerm/provider.go b/azurerm/provider.go index 3fa362c062a0..54536838ef8d 100644 --- a/azurerm/provider.go +++ b/azurerm/provider.go @@ -104,6 +104,7 @@ func Provider() terraform.ResourceProvider { "azurerm_network_interface": resourceArmNetworkInterface(), "azurerm_network_security_group": resourceArmNetworkSecurityGroup(), "azurerm_network_security_rule": resourceArmNetworkSecurityRule(), + "azurerm_postgresql_server": resourceArmPostgreSQLServer(), "azurerm_public_ip": resourceArmPublicIp(), "azurerm_redis_cache": resourceArmRedisCache(), "azurerm_resource_group": resourceArmResourceGroup(), @@ -239,22 +240,23 @@ var providerRegistrationOnce sync.Once func determineAzureResourceProvidersToRegister(providerList []resources.Provider) map[string]struct{} { providers := map[string]struct{}{ - "Microsoft.Cache": struct{}{}, - "Microsoft.Cdn": struct{}{}, - "Microsoft.Compute": struct{}{}, - "Microsoft.ContainerRegistry": struct{}{}, - "Microsoft.ContainerService": struct{}{}, - "Microsoft.DocumentDB": struct{}{}, - "Microsoft.EventGrid": struct{}{}, - "Microsoft.EventHub": struct{}{}, - "Microsoft.KeyVault": struct{}{}, - "microsoft.insights": struct{}{}, - "Microsoft.Network": struct{}{}, - "Microsoft.Resources": struct{}{}, - "Microsoft.Search": struct{}{}, - "Microsoft.ServiceBus": struct{}{}, - "Microsoft.Sql": struct{}{}, - "Microsoft.Storage": struct{}{}, + "Microsoft.Cache": {}, + "Microsoft.Cdn": {}, + "Microsoft.Compute": {}, + "Microsoft.ContainerRegistry": {}, + "Microsoft.ContainerService": {}, + "Microsoft.DBforPostgreSQL": {}, + "Microsoft.DocumentDB": {}, + "Microsoft.EventGrid": {}, + "Microsoft.EventHub": {}, + "Microsoft.KeyVault": {}, + "microsoft.insights": {}, + "Microsoft.Network": {}, + "Microsoft.Resources": {}, + "Microsoft.Search": {}, + "Microsoft.ServiceBus": {}, + "Microsoft.Sql": {}, + "Microsoft.Storage": {}, } // filter out any providers already registered diff --git a/azurerm/resource_arm_postgresql_server.go b/azurerm/resource_arm_postgresql_server.go new file mode 100644 index 000000000000..261e909959b4 --- /dev/null +++ b/azurerm/resource_arm_postgresql_server.go @@ -0,0 +1,305 @@ +package azurerm + +import ( + "fmt" + "log" + "net/http" + "strconv" + + "github.com/Azure/azure-sdk-for-go/arm/postgresql" + "github.com/hashicorp/terraform/helper/schema" + "github.com/hashicorp/terraform/helper/validation" + "github.com/jen20/riviera/azure" +) + +func resourceArmPostgreSQLServer() *schema.Resource { + return &schema.Resource{ + Create: resourceArmPostgreSQLServerCreate, + Read: resourceArmPostgreSQLServerRead, + Update: resourceArmPostgreSQLServerUpdate, + Delete: resourceArmPostgreSQLServerDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + + "location": locationSchema(), + + "resource_group_name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + + "sku": { + Type: schema.TypeSet, + Required: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice([]string{ + "PGSQLB50", + "PGSQLB100", + }, true), + DiffSuppressFunc: ignoreCaseDiffSuppressFunc, + }, + + "capacity": { + Type: schema.TypeInt, + Required: true, + ValidateFunc: validation.IntInSlice([]int{ + 50, + 100, + }), + }, + + "tier": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice([]string{ + string(postgresql.Basic), + }, true), + DiffSuppressFunc: ignoreCaseDiffSuppressFunc, + }, + }, + }, + }, + + "administrator_login": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + + "administrator_login_password": { + Type: schema.TypeString, + Required: true, + Sensitive: true, + }, + + "version": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice([]string{ + string(postgresql.NineFullStopFive), + string(postgresql.NineFullStopSix), + }, true), + DiffSuppressFunc: ignoreCaseDiffSuppressFunc, + ForceNew: true, + }, + + "storage_mb": { + Type: schema.TypeInt, + Required: true, + ForceNew: true, + ValidateFunc: validation.IntInSlice([]int{ + 51200, + 102400, + }), + }, + + "ssl_enforcement": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice([]string{ + string(postgresql.SslEnforcementEnumDisabled), + string(postgresql.SslEnforcementEnumEnabled), + }, true), + DiffSuppressFunc: ignoreCaseDiffSuppressFunc, + }, + + "fqdn": { + Type: schema.TypeString, + Computed: true, + }, + + "tags": tagsSchema(), + }, + } +} + +func resourceArmPostgreSQLServerCreate(d *schema.ResourceData, meta interface{}) error { + client := meta.(*ArmClient).postgresqlServersClient + + log.Printf("[INFO] preparing arguments for AzureRM PostgreSQL Server creation.") + + name := d.Get("name").(string) + location := d.Get("location").(string) + resGroup := d.Get("resource_group_name").(string) + + adminLogin := d.Get("administrator_login").(string) + adminLoginPassword := d.Get("administrator_login_password").(string) + sslEnforcement := d.Get("ssl_enforcement").(string) + version := d.Get("version").(string) + storageMB := d.Get("storage_mb").(int) + + tags := d.Get("tags").(map[string]interface{}) + + sku := expandAzureRmPostgreSQLServerSku(d, storageMB) + + properties := postgresql.ServerForCreate{ + Location: &location, + Sku: sku, + Properties: &postgresql.ServerPropertiesForCreate{ + Version: postgresql.ServerVersion(version), + StorageMB: azure.Int64(int64(storageMB)), + SslEnforcement: postgresql.SslEnforcementEnum(sslEnforcement), + AdministratorLogin: azure.String(adminLogin), + AdministratorLoginPassword: azure.String(adminLoginPassword), + }, + Tags: expandTags(tags), + } + + _, error := client.Create(resGroup, name, properties, make(chan struct{})) + err := <-error + if err != nil { + return err + } + + read, err := client.Get(resGroup, name) + if err != nil { + return err + } + if read.ID == nil { + return fmt.Errorf("Cannot read PostgreSQL Server %s (resource group %s) ID", name, resGroup) + } + + d.SetId(*read.ID) + + return resourceArmPostgreSQLServerRead(d, meta) +} + +func resourceArmPostgreSQLServerUpdate(d *schema.ResourceData, meta interface{}) error { + client := meta.(*ArmClient).postgresqlServersClient + + log.Printf("[INFO] preparing arguments for AzureRM PostgreSQL Server update.") + + name := d.Get("name").(string) + resGroup := d.Get("resource_group_name").(string) + + adminLoginPassword := d.Get("administrator_login_password").(string) + sslEnforcement := d.Get("ssl_enforcement").(string) + version := d.Get("version").(string) + storageMB := d.Get("storage_mb").(int) + sku := expandAzureRmPostgreSQLServerSku(d, storageMB) + + tags := d.Get("tags").(map[string]interface{}) + + properties := postgresql.ServerUpdateParameters{ + Sku: sku, + ServerUpdateParametersProperties: &postgresql.ServerUpdateParametersProperties{ + SslEnforcement: postgresql.SslEnforcementEnum(sslEnforcement), + StorageMB: azure.Int64(int64(storageMB)), + Version: postgresql.ServerVersion(version), + AdministratorLoginPassword: azure.String(adminLoginPassword), + }, + Tags: expandTags(tags), + } + + _, error := client.Update(resGroup, name, properties, make(chan struct{})) + err := <-error + if err != nil { + return err + } + + read, err := client.Get(resGroup, name) + if err != nil { + return err + } + if read.ID == nil { + return fmt.Errorf("Cannot read PostgreSQL Server %s (resource group %s) ID", name, resGroup) + } + + d.SetId(*read.ID) + + return resourceArmPostgreSQLServerRead(d, meta) +} + +func resourceArmPostgreSQLServerRead(d *schema.ResourceData, meta interface{}) error { + client := meta.(*ArmClient).postgresqlServersClient + + id, err := parseAzureResourceID(d.Id()) + if err != nil { + return err + } + resGroup := id.ResourceGroup + name := id.Path["servers"] + + resp, err := client.Get(resGroup, name) + if err != nil { + if resp.StatusCode == http.StatusNotFound { + d.SetId("") + return nil + } + return fmt.Errorf("Error making Read request on Azure PostgreSQL Server %s: %+v", name, err) + } + + d.Set("name", resp.Name) + d.Set("resource_group_name", resGroup) + d.Set("location", azureRMNormalizeLocation(*resp.Location)) + + d.Set("administrator_login", resp.AdministratorLogin) + d.Set("version", string(resp.Version)) + d.Set("storage_mb", int(*resp.StorageMB)) + d.Set("ssl_enforcement", string(resp.SslEnforcement)) + + flattenAndSetAzureRmPostgreSQLServerSku(d, resp.Sku) + flattenAndSetTags(d, resp.Tags) + + // Computed + d.Set("fqdn", resp.FullyQualifiedDomainName) + + return nil +} + +func resourceArmPostgreSQLServerDelete(d *schema.ResourceData, meta interface{}) error { + client := meta.(*ArmClient).postgresqlServersClient + + id, err := parseAzureResourceID(d.Id()) + if err != nil { + return err + } + resGroup := id.ResourceGroup + name := id.Path["servers"] + + _, error := client.Delete(resGroup, name, make(chan struct{})) + err = <-error + + return err +} + +func expandAzureRmPostgreSQLServerSku(d *schema.ResourceData, storageMB int) *postgresql.Sku { + skus := d.Get("sku").(*schema.Set).List() + sku := skus[0].(map[string]interface{}) + + name := sku["name"].(string) + capacity := sku["capacity"].(int) + tier := sku["tier"].(string) + + return &postgresql.Sku{ + Name: azure.String(name), + Capacity: azure.Int32(int32(capacity)), + Tier: postgresql.SkuTier(tier), + Size: azure.String(strconv.Itoa(storageMB)), + } +} + +func flattenAndSetAzureRmPostgreSQLServerSku(d *schema.ResourceData, resp *postgresql.Sku) { + values := map[string]interface{}{} + + values["name"] = *resp.Name + values["capacity"] = int(*resp.Capacity) + values["tier"] = string(resp.Tier) + + sku := []interface{}{values} + d.Set("sku", sku) +} diff --git a/azurerm/resource_arm_postgresql_server_test.go b/azurerm/resource_arm_postgresql_server_test.go new file mode 100644 index 000000000000..eed1dc25a072 --- /dev/null +++ b/azurerm/resource_arm_postgresql_server_test.go @@ -0,0 +1,110 @@ +package azurerm + +import ( + "fmt" + "net/http" + "testing" + + "github.com/hashicorp/terraform/helper/acctest" + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/terraform" +) + +func TestAccAzureRMPostgreSQLServer_basic(t *testing.T) { + ri := acctest.RandInt() + config := testAccAzureRMPostgreSQLServer_basic(ri) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMPostgreSQLServerDestroy, + Steps: []resource.TestStep{ + { + Config: config, + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMPostgreSQLServerExists("azurerm_postgresql_server.test"), + ), + }, + }, + }) +} + +func testCheckAzureRMPostgreSQLServerExists(name 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[name] + if !ok { + return fmt.Errorf("Not found: %s", name) + } + + name := rs.Primary.Attributes["name"] + resourceGroup, hasResourceGroup := rs.Primary.Attributes["resource_group_name"] + if !hasResourceGroup { + return fmt.Errorf("Bad: no resource group found in state for PostgreSQL Server: %s", name) + } + + client := testAccProvider.Meta().(*ArmClient).postgresqlServersClient + + resp, err := client.Get(resourceGroup, name) + if err != nil { + return fmt.Errorf("Bad: Get on postgresqlServersClient: %s", err) + } + + if resp.StatusCode == http.StatusNotFound { + return fmt.Errorf("Bad: PostgreSQL Server %q (resource group: %q) does not exist", name, resourceGroup) + } + + return nil + } +} + +func testCheckAzureRMPostgreSQLServerDestroy(s *terraform.State) error { + client := testAccProvider.Meta().(*ArmClient).postgresqlServersClient + + for _, rs := range s.RootModule().Resources { + if rs.Type != "azurerm_postgresql_server" { + continue + } + + name := rs.Primary.Attributes["name"] + resourceGroup := rs.Primary.Attributes["resource_group_name"] + + resp, err := client.Get(resourceGroup, name) + + if err != nil { + return nil + } + + if resp.StatusCode != http.StatusNotFound { + return fmt.Errorf("PostgreSQL Server still exists:\n%#v", resp) + } + } + + return nil +} + +func testAccAzureRMPostgreSQLServer_basic(rInt int) string { + return fmt.Sprintf(` +resource "azurerm_resource_group" "test" { + name = "acctestRG-%d" + location = "West US" +} +resource "azurerm_postgresql_server" "test" { + name = "acctestpsqlsvr-%d" + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" + + sku { + name = "PGSQLB50" + capacity = 50 + tier = "Basic" + } + + administrator_login = "acctestun" + administrator_login_password = "H@Sh1CoR3!" + version = "9.5" + storage_mb = 51200 + ssl_enforcement = "Enabled" +} +`, rInt, rInt) +} diff --git a/website/azurerm.erb b/website/azurerm.erb index 0c5f79ef7612..33c1063705b6 100644 --- a/website/azurerm.erb +++ b/website/azurerm.erb @@ -109,6 +109,19 @@ + > + Database Resources + + + > DNS Resources