diff --git a/azurerm/import_arm_dns_mx_record_test.go b/azurerm/import_arm_dns_mx_record_test.go index ef87fffd1338..95e448dae335 100644 --- a/azurerm/import_arm_dns_mx_record_test.go +++ b/azurerm/import_arm_dns_mx_record_test.go @@ -1,7 +1,6 @@ package azurerm import ( - "fmt" "testing" "github.com/hashicorp/terraform/helper/acctest" @@ -12,18 +11,42 @@ func TestAccAzureRMDnsMxRecord_importBasic(t *testing.T) { resourceName := "azurerm_dns_mx_record.test" ri := acctest.RandInt() - config := fmt.Sprintf(testAccAzureRMDnsMxRecord_basic, ri, ri, ri) + config := testAccAzureRMDnsMxRecord_basic(ri) resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, CheckDestroy: testCheckAzureRMDnsMxRecordDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: config, }, - resource.TestStep{ + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccAzureRMDnsMxRecord_importWithTags(t *testing.T) { + resourceName := "azurerm_dns_mx_record.test" + + ri := acctest.RandInt() + config := testAccAzureRMDnsMxRecord_withTags(ri) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMDnsMxRecordDestroy, + Steps: []resource.TestStep{ + { + Config: config, + }, + + { ResourceName: resourceName, ImportState: true, ImportStateVerify: true, diff --git a/azurerm/resource_arm_dns_mx_record.go b/azurerm/resource_arm_dns_mx_record.go index d4881c5f5149..ec7b0b1e67fd 100644 --- a/azurerm/resource_arm_dns_mx_record.go +++ b/azurerm/resource_arm_dns_mx_record.go @@ -3,52 +3,54 @@ package azurerm import ( "bytes" "fmt" - "log" + "net/http" + "strconv" + "github.com/Azure/azure-sdk-for-go/arm/dns" "github.com/hashicorp/terraform/helper/hashcode" "github.com/hashicorp/terraform/helper/schema" - "github.com/jen20/riviera/dns" ) func resourceArmDnsMxRecord() *schema.Resource { return &schema.Resource{ - Create: resourceArmDnsMxRecordCreate, + Create: resourceArmDnsMxRecordCreateOrUpdate, Read: resourceArmDnsMxRecordRead, - Update: resourceArmDnsMxRecordCreate, + Update: resourceArmDnsMxRecordCreateOrUpdate, Delete: resourceArmDnsMxRecordDelete, Importer: &schema.ResourceImporter{ State: schema.ImportStatePassthrough, }, Schema: map[string]*schema.Schema{ - "name": &schema.Schema{ + "name": { Type: schema.TypeString, Required: true, ForceNew: true, }, - "resource_group_name": &schema.Schema{ + "resource_group_name": { Type: schema.TypeString, Required: true, ForceNew: true, }, - "zone_name": &schema.Schema{ + "zone_name": { Type: schema.TypeString, Required: true, }, - "record": &schema.Schema{ + "record": { Type: schema.TypeSet, Required: true, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "preference": &schema.Schema{ + "preference": { + // TODO: this should become an Int Type: schema.TypeString, Required: true, }, - "exchange": &schema.Schema{ + "exchange": { Type: schema.TypeString, Required: true, }, @@ -57,7 +59,7 @@ func resourceArmDnsMxRecord() *schema.Resource { Set: resourceArmDnsMxRecordHash, }, - "ttl": &schema.Schema{ + "ttl": { Type: schema.TypeInt, Required: true, }, @@ -67,155 +69,145 @@ func resourceArmDnsMxRecord() *schema.Resource { } } -func resourceArmDnsMxRecordCreate(d *schema.ResourceData, meta interface{}) error { - client := meta.(*ArmClient) - rivieraClient := client.rivieraClient +func resourceArmDnsMxRecordCreateOrUpdate(d *schema.ResourceData, meta interface{}) error { + client := meta.(*ArmClient).dnsClient + name := d.Get("name").(string) + resGroup := d.Get("resource_group_name").(string) + zoneName := d.Get("zone_name").(string) + ttl := int64(d.Get("ttl").(int)) tags := d.Get("tags").(map[string]interface{}) - expandedTags := expandTags(tags) - - createCommand := &dns.CreateMXRecordSet{ - Name: d.Get("name").(string), - Location: "global", - ResourceGroupName: d.Get("resource_group_name").(string), - ZoneName: d.Get("zone_name").(string), - TTL: d.Get("ttl").(int), - Tags: *expandedTags, - } - - mxRecords, recordErr := expandAzureRmDnsMxRecord(d) - if recordErr != nil { - return fmt.Errorf("Error Building Azure RM MX Record: %s", recordErr) - } - createCommand.MXRecords = mxRecords - - createRequest := rivieraClient.NewRequest() - createRequest.Command = createCommand - - createResponse, err := createRequest.Execute() + records, err := expandAzureRmDnsMxRecords(d) if err != nil { - return fmt.Errorf("Error creating DNS MX Record: %s", err) - } - if !createResponse.IsSuccessful() { - return fmt.Errorf("Error creating DNS MX Record: %s", createResponse.Error) + return err } - readRequest := rivieraClient.NewRequest() - readRequest.Command = &dns.GetMXRecordSet{ - Name: d.Get("name").(string), - ResourceGroupName: d.Get("resource_group_name").(string), - ZoneName: d.Get("zone_name").(string), + parameters := dns.RecordSet{ + Name: &name, + RecordSetProperties: &dns.RecordSetProperties{ + Metadata: expandTags(tags), + TTL: &ttl, + MxRecords: &records, + }, } - readResponse, err := readRequest.Execute() + eTag := "" + ifNoneMatch := "" // set to empty to allow updates to records after creation + resp, err := client.CreateOrUpdate(resGroup, zoneName, name, dns.MX, parameters, eTag, ifNoneMatch) if err != nil { - return fmt.Errorf("Error reading DNS MX Record: %s", err) + return err } - if !readResponse.IsSuccessful() { - return fmt.Errorf("Error reading DNS MX Record: %s", readResponse.Error) + + if resp.ID == nil { + return fmt.Errorf("Cannot read DNS MX Record %s (resource group %s) ID", name, resGroup) } - resp := readResponse.Parsed.(*dns.GetMXRecordSetResponse) - d.SetId(resp.ID) + d.SetId(*resp.ID) return resourceArmDnsMxRecordRead(d, meta) } func resourceArmDnsMxRecordRead(d *schema.ResourceData, meta interface{}) error { - client := meta.(*ArmClient) - rivieraClient := client.rivieraClient + client := meta.(*ArmClient).dnsClient id, err := parseAzureResourceID(d.Id()) if err != nil { return err } - readRequest := rivieraClient.NewRequestForURI(d.Id()) - readRequest.Command = &dns.GetMXRecordSet{} + resGroup := id.ResourceGroup + name := id.Path["MX"] + zoneName := id.Path["dnszones"] - readResponse, err := readRequest.Execute() + resp, err := client.Get(resGroup, zoneName, name, dns.MX) if err != nil { - return fmt.Errorf("Error reading DNS MX Record: %s", err) + return fmt.Errorf("Error reading DNS MX record %s: %v", name, err) } - if !readResponse.IsSuccessful() { - log.Printf("[INFO] Error reading DNS MX Record %q - removing from state", d.Id()) + if resp.StatusCode == http.StatusNotFound { d.SetId("") - return fmt.Errorf("Error reading DNS MX Record: %s", readResponse.Error) + return nil } - resp := readResponse.Parsed.(*dns.GetMXRecordSetResponse) - - d.Set("name", resp.Name) - d.Set("resource_group_name", id.ResourceGroup) - d.Set("zone_name", id.Path["dnszones"]) + d.Set("name", name) + d.Set("resource_group_name", resGroup) + d.Set("zone_name", zoneName) d.Set("ttl", resp.TTL) - if err := d.Set("record", flattenAzureRmDnsMxRecord(resp.MXRecords)); err != nil { - log.Printf("[INFO] Error setting the Azure RM MX Record State: %s", err) + if err := d.Set("record", flattenAzureRmDnsMxRecords(resp.MxRecords)); err != nil { return err } - - flattenAndSetTags(d, &resp.Tags) + flattenAndSetTags(d, resp.Metadata) return nil } func resourceArmDnsMxRecordDelete(d *schema.ResourceData, meta interface{}) error { - client := meta.(*ArmClient) - rivieraClient := client.rivieraClient - - deleteRequest := rivieraClient.NewRequestForURI(d.Id()) - deleteRequest.Command = &dns.DeleteRecordSet{ - RecordSetType: "MX", - } + client := meta.(*ArmClient).dnsClient - deleteResponse, err := deleteRequest.Execute() + id, err := parseAzureResourceID(d.Id()) if err != nil { - return fmt.Errorf("Error deleting DNS MX Record: %s", err) + return err } - if !deleteResponse.IsSuccessful() { - return fmt.Errorf("Error deleting DNS MX Record: %s", deleteResponse.Error) + + resGroup := id.ResourceGroup + name := id.Path["MX"] + zoneName := id.Path["dnszones"] + + resp, error := client.Delete(resGroup, zoneName, name, dns.MX, "") + if resp.StatusCode != http.StatusOK { + return fmt.Errorf("Error deleting DNS MX Record %s: %+v", name, error) } return nil } -func expandAzureRmDnsMxRecord(d *schema.ResourceData) ([]dns.MXRecord, error) { - config := d.Get("record").(*schema.Set).List() - records := make([]dns.MXRecord, 0, len(config)) - - for _, pRaw := range config { - data := pRaw.(map[string]interface{}) - - mxrecord := dns.MXRecord{ - Preference: data["preference"].(string), - Exchange: data["exchange"].(string), +// flatten creates an array of map where preference is a string to suit +// the expectations of the ResourceData schema, so that this data can be +// managed by Terradata state. +func flattenAzureRmDnsMxRecords(records *[]dns.MxRecord) []map[string]interface{} { + results := make([]map[string]interface{}, 0, len(*records)) + + if records != nil { + for _, record := range *records { + preferenceI32 := *record.Preference + preference := strconv.Itoa(int(preferenceI32)) + results = append(results, map[string]interface{}{ + "preference": preference, + "exchange": *record.Exchange, + }) } - - records = append(records, mxrecord) - } - return records, nil - + return results } -func flattenAzureRmDnsMxRecord(records []dns.MXRecord) []map[string]interface{} { - - result := make([]map[string]interface{}, 0, len(records)) - for _, record := range records { - result = append(result, map[string]interface{}{ - "preference": record.Preference, - "exchange": record.Exchange, - }) +// expand creates an array of dns.MxRecord, that is, the array needed +// by azure-sdk-for-go to manipulate azure resources, hence Preference +// is an int32 +func expandAzureRmDnsMxRecords(d *schema.ResourceData) ([]dns.MxRecord, error) { + recordStrings := d.Get("record").(*schema.Set).List() + records := make([]dns.MxRecord, len(recordStrings)) + + for i, v := range recordStrings { + mxrecord := v.(map[string]interface{}) + preference := mxrecord["preference"].(string) + i64, _ := strconv.ParseInt(preference, 10, 32) + i32 := int32(i64) + exchange := mxrecord["exchange"].(string) + + records[i] = dns.MxRecord{ + Preference: &i32, + Exchange: &exchange, + } } - return result + return records, nil } func resourceArmDnsMxRecordHash(v interface{}) int { var buf bytes.Buffer m := v.(map[string]interface{}) + buf.WriteString(fmt.Sprintf("%s-", m["preference"].(string))) buf.WriteString(fmt.Sprintf("%s-", m["exchange"].(string))) diff --git a/azurerm/resource_arm_dns_mx_record_test.go b/azurerm/resource_arm_dns_mx_record_test.go index e3ef8b836f1b..8a6c614a5ca7 100644 --- a/azurerm/resource_arm_dns_mx_record_test.go +++ b/azurerm/resource_arm_dns_mx_record_test.go @@ -2,27 +2,29 @@ package azurerm import ( "fmt" + "net/http" "testing" + "github.com/Azure/azure-sdk-for-go/arm/dns" "github.com/hashicorp/terraform/helper/acctest" "github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/terraform" - "github.com/jen20/riviera/dns" ) func TestAccAzureRMDnsMxRecord_basic(t *testing.T) { + resourceName := "azurerm_dns_mx_record.test" ri := acctest.RandInt() - config := fmt.Sprintf(testAccAzureRMDnsMxRecord_basic, ri, ri, ri) + config := testAccAzureRMDnsMxRecord_basic(ri) resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, CheckDestroy: testCheckAzureRMDnsMxRecordDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: config, Check: resource.ComposeTestCheckFunc( - testCheckAzureRMDnsMxRecordExists("azurerm_dns_mx_record.test"), + testCheckAzureRMDnsMxRecordExists(resourceName), ), }, }, @@ -30,30 +32,28 @@ func TestAccAzureRMDnsMxRecord_basic(t *testing.T) { } func TestAccAzureRMDnsMxRecord_updateRecords(t *testing.T) { + resourceName := "azurerm_dns_mx_record.test" ri := acctest.RandInt() - preConfig := fmt.Sprintf(testAccAzureRMDnsMxRecord_basic, ri, ri, ri) - postConfig := fmt.Sprintf(testAccAzureRMDnsMxRecord_updateRecords, ri, ri, ri) + preConfig := testAccAzureRMDnsMxRecord_basic(ri) + postConfig := testAccAzureRMDnsMxRecord_updateRecords(ri) resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, CheckDestroy: testCheckAzureRMDnsMxRecordDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: preConfig, Check: resource.ComposeTestCheckFunc( - testCheckAzureRMDnsMxRecordExists("azurerm_dns_mx_record.test"), - resource.TestCheckResourceAttr( - "azurerm_dns_mx_record.test", "record.#", "2"), + testCheckAzureRMDnsMxRecordExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "record.#", "2"), ), }, - - resource.TestStep{ + { Config: postConfig, Check: resource.ComposeTestCheckFunc( - testCheckAzureRMDnsMxRecordExists("azurerm_dns_mx_record.test"), - resource.TestCheckResourceAttr( - "azurerm_dns_mx_record.test", "record.#", "3"), + testCheckAzureRMDnsMxRecordExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "record.#", "3"), ), }, }, @@ -61,30 +61,28 @@ func TestAccAzureRMDnsMxRecord_updateRecords(t *testing.T) { } func TestAccAzureRMDnsMxRecord_withTags(t *testing.T) { + resourceName := "azurerm_dns_mx_record.test" ri := acctest.RandInt() - preConfig := fmt.Sprintf(testAccAzureRMDnsMxRecord_withTags, ri, ri, ri) - postConfig := fmt.Sprintf(testAccAzureRMDnsMxRecord_withTagsUpdate, ri, ri, ri) + preConfig := testAccAzureRMDnsMxRecord_withTags(ri) + postConfig := testAccAzureRMDnsMxRecord_withTagsUpdate(ri) resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, CheckDestroy: testCheckAzureRMDnsMxRecordDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: preConfig, Check: resource.ComposeTestCheckFunc( - testCheckAzureRMDnsMxRecordExists("azurerm_dns_mx_record.test"), - resource.TestCheckResourceAttr( - "azurerm_dns_mx_record.test", "tags.%", "2"), + testCheckAzureRMDnsMxRecordExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "tags.%", "2"), ), }, - - resource.TestStep{ + { Config: postConfig, Check: resource.ComposeTestCheckFunc( - testCheckAzureRMDnsMxRecordExists("azurerm_dns_mx_record.test"), - resource.TestCheckResourceAttr( - "azurerm_dns_mx_record.test", "tags.%", "1"), + testCheckAzureRMDnsMxRecordExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), ), }, }, @@ -99,17 +97,21 @@ func testCheckAzureRMDnsMxRecordExists(name string) resource.TestCheckFunc { return fmt.Errorf("Not found: %s", name) } - conn := testAccProvider.Meta().(*ArmClient).rivieraClient - - readRequest := conn.NewRequestForURI(rs.Primary.ID) - readRequest.Command = &dns.GetMXRecordSet{} + mxName := rs.Primary.Attributes["name"] + zoneName := rs.Primary.Attributes["zone_name"] + resourceGroup, hasResourceGroup := rs.Primary.Attributes["resource_group_name"] + if !hasResourceGroup { + return fmt.Errorf("Bad: no resource group found in state for DNS MX record: %s", mxName) + } - readResponse, err := readRequest.Execute() + conn := testAccProvider.Meta().(*ArmClient).dnsClient + resp, err := conn.Get(resourceGroup, zoneName, mxName, dns.MX) if err != nil { - return fmt.Errorf("Bad: GetMXRecordSet: %s", err) + return fmt.Errorf("Bad: Get MX RecordSet: %+v", err) } - if !readResponse.IsSuccessful() { - return fmt.Errorf("Bad: GetMXRecordSet: %s", readResponse.Error) + + if resp.StatusCode == http.StatusNotFound { + return fmt.Errorf("Bad: DNS MX record %s (resource group: %s) does not exist", mxName, resourceGroup) } return nil @@ -117,34 +119,40 @@ func testCheckAzureRMDnsMxRecordExists(name string) resource.TestCheckFunc { } func testCheckAzureRMDnsMxRecordDestroy(s *terraform.State) error { - conn := testAccProvider.Meta().(*ArmClient).rivieraClient + conn := testAccProvider.Meta().(*ArmClient).dnsClient for _, rs := range s.RootModule().Resources { if rs.Type != "azurerm_dns_mx_record" { continue } - readRequest := conn.NewRequestForURI(rs.Primary.ID) - readRequest.Command = &dns.GetMXRecordSet{} + mxName := rs.Primary.Attributes["name"] + zoneName := rs.Primary.Attributes["zone_name"] + resourceGroup := rs.Primary.Attributes["resource_group_name"] + + resp, err := conn.Get(resourceGroup, zoneName, mxName, dns.MX) - readResponse, err := readRequest.Execute() if err != nil { - return fmt.Errorf("Bad: GetMXRecordSet: %s", err) - } + if resp.StatusCode == http.StatusNotFound { + return nil + } - if readResponse.IsSuccessful() { - return fmt.Errorf("Bad: DNS MX Record still exists: %s", readResponse.Error) + return err } + + return fmt.Errorf("DNS MX record still exists:\n%#v", resp.RecordSetProperties) } return nil } -var testAccAzureRMDnsMxRecord_basic = ` +func testAccAzureRMDnsMxRecord_basic(rInt int) string { + return fmt.Sprintf(` resource "azurerm_resource_group" "test" { name = "acctestRG_%d" location = "West US" } + resource "azurerm_dns_zone" "test" { name = "acctestzone%d.com" resource_group_name = "${azurerm_resource_group.test.name}" @@ -166,13 +174,16 @@ resource "azurerm_dns_mx_record" "test" { exchange = "mail2.contoso.com" } } -` +`, rInt, rInt, rInt) +} -var testAccAzureRMDnsMxRecord_updateRecords = ` +func testAccAzureRMDnsMxRecord_updateRecords(rInt int) string { + return fmt.Sprintf(` resource "azurerm_resource_group" "test" { name = "acctestRG_%d" location = "West US" } + resource "azurerm_dns_zone" "test" { name = "acctestzone%d.com" resource_group_name = "${azurerm_resource_group.test.name}" @@ -199,13 +210,16 @@ resource "azurerm_dns_mx_record" "test" { exchange = "mail3.contoso.com" } } -` +`, rInt, rInt, rInt) +} -var testAccAzureRMDnsMxRecord_withTags = ` +func testAccAzureRMDnsMxRecord_withTags(rInt int) string { + return fmt.Sprintf(` resource "azurerm_resource_group" "test" { name = "acctestRG_%d" location = "West US" } + resource "azurerm_dns_zone" "test" { name = "acctestzone%d.com" resource_group_name = "${azurerm_resource_group.test.name}" @@ -232,13 +246,16 @@ resource "azurerm_dns_mx_record" "test" { cost_center = "MSFT" } } -` +`, rInt, rInt, rInt) +} -var testAccAzureRMDnsMxRecord_withTagsUpdate = ` +func testAccAzureRMDnsMxRecord_withTagsUpdate(rInt int) string { + return fmt.Sprintf(` resource "azurerm_resource_group" "test" { name = "acctestRG_%d" location = "West US" } + resource "azurerm_dns_zone" "test" { name = "acctestzone%d.com" resource_group_name = "${azurerm_resource_group.test.name}" @@ -264,4 +281,5 @@ resource "azurerm_dns_mx_record" "test" { environment = "staging" } } -` +`, rInt, rInt, rInt) +}