From de4a98aa3ab04fe04335f4b1c16e9b36de09fafe Mon Sep 17 00:00:00 2001 From: Philipp Resch Date: Thu, 31 Oct 2019 20:18:54 +0100 Subject: [PATCH 01/17] added resource_arm_private_dns_srv_record --- azurerm/provider.go | 1 + .../resource_arm_private_dns_srv_record.go | 262 +++++++++++++ ...esource_arm_private_dns_srv_record_test.go | 365 ++++++++++++++++++ 3 files changed, 628 insertions(+) create mode 100644 azurerm/resource_arm_private_dns_srv_record.go create mode 100644 azurerm/resource_arm_private_dns_srv_record_test.go diff --git a/azurerm/provider.go b/azurerm/provider.go index 43c9ffb6e118..628a2a0f3ef5 100644 --- a/azurerm/provider.go +++ b/azurerm/provider.go @@ -380,6 +380,7 @@ func Provider() terraform.ResourceProvider { "azurerm_private_dns_a_record": resourceArmPrivateDnsARecord(), "azurerm_private_dns_cname_record": resourceArmPrivateDnsCNameRecord(), "azurerm_private_dns_ptr_record": resourceArmPrivateDnsPtrRecord(), + "azurerm_private_dns_srv_record": resourceArmPrivateDnsSrvRecord(), "azurerm_private_dns_zone_virtual_network_link": resourceArmPrivateDnsZoneVirtualNetworkLink(), "azurerm_proximity_placement_group": resourceArmProximityPlacementGroup(), "azurerm_public_ip": resourceArmPublicIp(), diff --git a/azurerm/resource_arm_private_dns_srv_record.go b/azurerm/resource_arm_private_dns_srv_record.go new file mode 100644 index 000000000000..c912d1a743c2 --- /dev/null +++ b/azurerm/resource_arm_private_dns_srv_record.go @@ -0,0 +1,262 @@ +package azurerm + +import ( + "bytes" + "fmt" + "time" + + "github.com/Azure/azure-sdk-for-go/services/privatedns/mgmt/2018-09-01/privatedns" + "github.com/hashicorp/terraform-plugin-sdk/helper/hashcode" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/helper/validation" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/tf" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/validate" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/features" + "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 resourceArmPrivateDnsSrvRecord() *schema.Resource { + return &schema.Resource{ + Create: resourceArmPrivateDnsSrvRecordCreateUpdate, + Read: resourceArmPrivateDnsSrvRecordRead, + Update: resourceArmPrivateDnsSrvRecordCreateUpdate, + Delete: resourceArmPrivateDnsSrvRecordDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(30 * time.Minute), + Read: schema.DefaultTimeout(5 * time.Minute), + Update: schema.DefaultTimeout(30 * time.Minute), + Delete: schema.DefaultTimeout(30 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.NoEmptyStrings, + }, + + // TODO: make this case sensitive once the API's fixed https://github.com/Azure/azure-rest-api-specs/issues/6641 + "resource_group_name": azure.SchemaResourceGroupNameDiffSuppress(), + + "zone_name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.NoEmptyStrings, + }, + + "record": { + Type: schema.TypeSet, + Required: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "priority": { + Type: schema.TypeInt, + Required: true, + ValidateFunc: validation.IntBetween(0, 65535), + }, + + "weight": { + Type: schema.TypeInt, + Required: true, + ValidateFunc: validation.IntBetween(0, 65535), + }, + + "port": { + Type: schema.TypeInt, + Required: true, + ValidateFunc: validation.IntBetween(1, 65535), + }, + + "target": { + Type: schema.TypeString, + Required: true, + }, + }, + }, + Set: resourceArmPrivateDnsSrvRecordHash, + }, + + "ttl": { + Type: schema.TypeInt, + Required: true, + ValidateFunc: validation.IntBetween(1, 2147483647), + }, + + "tags": tags.Schema(), + }, + } +} + +func resourceArmPrivateDnsSrvRecordCreateUpdate(d *schema.ResourceData, meta interface{}) error { + client := meta.(*ArmClient).PrivateDns.RecordSetsClient + ctx, cancel := timeouts.ForCreateUpdate(meta.(*ArmClient).StopContext, d) + defer cancel() + + name := d.Get("name").(string) + resGroup := d.Get("resource_group_name").(string) + zoneName := d.Get("zone_name").(string) + + if features.ShouldResourcesBeImported() && d.IsNewResource() { + existing, err := client.Get(ctx, resGroup, zoneName, privatedns.SRV, name) + if err != nil { + if !utils.ResponseWasNotFound(existing.Response) { + return fmt.Errorf("Error checking for presence of existing Private DNS SRV Record %q (Zone %q / Resource Group %q): %s", name, zoneName, resGroup, err) + } + } + + if existing.ID != nil && *existing.ID != "" { + return tf.ImportAsExistsError("azurerm_private_dns_srv_record", *existing.ID) + } + } + + ttl := int64(d.Get("ttl").(int)) + t := d.Get("tags").(map[string]interface{}) + + parameters := privatedns.RecordSet{ + Name: &name, + RecordSetProperties: &privatedns.RecordSetProperties{ + Metadata: tags.Expand(t), + TTL: &ttl, + SrvRecords: expandAzureRmPrivateDnsSrvRecords(d), + }, + } + + eTag := "" + ifNoneMatch := "" // set to empty to allow updates to records after creation + if _, err := client.CreateOrUpdate(ctx, resGroup, zoneName, privatedns.SRV, name, parameters, eTag, ifNoneMatch); err != nil { + return fmt.Errorf("Error creating/updating Private DNS SRV Record %q (Zone %q / Resource Group %q): %s", name, zoneName, resGroup, err) + } + + resp, err := client.Get(ctx, resGroup, zoneName, privatedns.SRV, name) + if err != nil { + return fmt.Errorf("Error retrieving Private DNS SRV Record %q (Zone %q / Resource Group %q): %s", name, zoneName, resGroup, err) + } + + if resp.ID == nil { + return fmt.Errorf("Cannot read Private DNS SRV Record %s (resource group %s) ID", name, resGroup) + } + + d.SetId(*resp.ID) + + return resourceArmPrivateDnsSrvRecordRead(d, meta) +} + +func resourceArmPrivateDnsSrvRecordRead(d *schema.ResourceData, meta interface{}) error { + dnsClient := meta.(*ArmClient).PrivateDns.RecordSetsClient + ctx, cancel := timeouts.ForRead(meta.(*ArmClient).StopContext, d) + defer cancel() + + id, err := azure.ParseAzureResourceID(d.Id()) + if err != nil { + return err + } + + resGroup := id.ResourceGroup + name := id.Path["SRV"] + zoneName := id.Path["privateDnsZones"] + + resp, err := dnsClient.Get(ctx, resGroup, zoneName, privatedns.SRV, name) + if err != nil { + if utils.ResponseWasNotFound(resp.Response) { + d.SetId("") + return nil + } + return fmt.Errorf("Error reading Private DNS SRV record %s: %+v", name, err) + } + + 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", flattenAzureRmPrivateDnsSrvRecords(resp.SrvRecords)); err != nil { + return err + } + + return tags.FlattenAndSet(d, resp.Metadata) +} + +func resourceArmPrivateDnsSrvRecordDelete(d *schema.ResourceData, meta interface{}) error { + dnsClient := meta.(*ArmClient).PrivateDns.RecordSetsClient + ctx, cancel := timeouts.ForDelete(meta.(*ArmClient).StopContext, d) + defer cancel() + + id, err := azure.ParseAzureResourceID(d.Id()) + if err != nil { + return err + } + + resGroup := id.ResourceGroup + name := id.Path["SRV"] + zoneName := id.Path["privateDnsZones"] + + _, err = dnsClient.Delete(ctx, resGroup, zoneName, privatedns.SRV, name, "") + if err != nil { + return fmt.Errorf("Error deleting Private DNS SRV Record %s: %+v", name, err) + } + + return nil +} + +func flattenAzureRmPrivateDnsSrvRecords(records *[]privatedns.SrvRecord) []map[string]interface{} { + results := make([]map[string]interface{}, 0) + + if records != nil { + for _, record := range *records { + results = append(results, map[string]interface{}{ + "priority": *record.Priority, + "weight": *record.Weight, + "port": *record.Port, + "target": *record.Target, + }) + } + } + + return results +} + +func expandAzureRmPrivateDnsSrvRecords(d *schema.ResourceData) *[]privatedns.SrvRecord { + recordStrings := d.Get("record").(*schema.Set).List() + records := make([]privatedns.SrvRecord, len(recordStrings)) + + for i, v := range recordStrings { + record := v.(map[string]interface{}) + priority := int32(record["priority"].(int)) + weight := int32(record["weight"].(int)) + port := int32(record["port"].(int)) + target := record["target"].(string) + + srvRecord := privatedns.SrvRecord{ + Priority: &priority, + Weight: &weight, + Port: &port, + Target: &target, + } + + records[i] = srvRecord + } + + return &records +} + +func resourceArmPrivateDnsSrvRecordHash(v interface{}) int { + var buf bytes.Buffer + + if m, ok := v.(map[string]interface{}); ok { + buf.WriteString(fmt.Sprintf("%d-", m["priority"].(int))) + buf.WriteString(fmt.Sprintf("%d-", m["weight"].(int))) + buf.WriteString(fmt.Sprintf("%d-", m["port"].(int))) + buf.WriteString(fmt.Sprintf("%s-", m["target"].(string))) + } + + return hashcode.String(buf.String()) +} diff --git a/azurerm/resource_arm_private_dns_srv_record_test.go b/azurerm/resource_arm_private_dns_srv_record_test.go new file mode 100644 index 000000000000..d63a517bb47b --- /dev/null +++ b/azurerm/resource_arm_private_dns_srv_record_test.go @@ -0,0 +1,365 @@ +package azurerm + +import ( + "fmt" + "net/http" + "testing" + + "github.com/Azure/azure-sdk-for-go/services/privatedns/mgmt/2018-09-01/privatedns" + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/terraform" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/tf" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/features" +) + +func TestAccAzureRMPrivateDnsSrvRecord_basic(t *testing.T) { + resourceName := "azurerm_private_dns_srv_record.test" + ri := tf.AccRandTimeInt() + config := testAccAzureRMPrivateDnsSrvRecord_basic(ri, testLocation()) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMPrivateDnsSrvRecordDestroy, + Steps: []resource.TestStep{ + { + Config: config, + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMPrivateDnsSrvRecordExists(resourceName), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccAzureRMPrivateDnsSrvRecord_requiresImport(t *testing.T) { + if !features.ShouldResourcesBeImported() { + t.Skip("Skipping since resources aren't required to be imported") + return + } + + resourceName := "azurerm_private_dns_srv_record.test" + ri := tf.AccRandTimeInt() + location := testLocation() + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMPrivateDnsSrvRecordDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMPrivateDnsSrvRecord_basic(ri, location), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMPrivateDnsSrvRecordExists(resourceName), + ), + }, + { + Config: testAccAzureRMPrivateDnsSrvRecord_requiresImport(ri, location), + ExpectError: testRequiresImportError("azurerm_private_dns_srv_record"), + }, + }, + }) +} + +func TestAccAzureRMPrivateDnsSrvRecord_updateRecords(t *testing.T) { + resourceName := "azurerm_private_dns_srv_record.test" + ri := tf.AccRandTimeInt() + location := testLocation() + preConfig := testAccAzureRMPrivateDnsSrvRecord_basic(ri, location) + postConfig := testAccAzureRMPrivateDnsSrvRecord_updateRecords(ri, location) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMPrivateDnsSrvRecordDestroy, + Steps: []resource.TestStep{ + { + Config: preConfig, + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMPrivateDnsSrvRecordExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "record.#", "2"), + ), + }, + { + Config: postConfig, + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMPrivateDnsSrvRecordExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "record.#", "3"), + ), + }, + }, + }) +} + +func TestAccAzureRMPrivateDnsSrvRecord_withTags(t *testing.T) { + resourceName := "azurerm_private_dns_srv_record.test" + ri := tf.AccRandTimeInt() + location := testLocation() + preConfig := testAccAzureRMPrivateDnsSrvRecord_withTags(ri, location) + postConfig := testAccAzureRMPrivateDnsSrvRecord_withTagsUpdate(ri, location) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMPrivateDnsSrvRecordDestroy, + Steps: []resource.TestStep{ + { + Config: preConfig, + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMPrivateDnsSrvRecordExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "tags.%", "2"), + ), + }, + { + Config: postConfig, + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMPrivateDnsSrvRecordExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testCheckAzureRMPrivateDnsSrvRecordExists(resourceName 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) + } + + srvName := 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 Private DNS SRV record: %s", srvName) + } + + conn := testAccProvider.Meta().(*ArmClient).PrivateDns.RecordSetsClient + ctx := testAccProvider.Meta().(*ArmClient).StopContext + resp, err := conn.Get(ctx, resourceGroup, zoneName, privatedns.SRV, srvName) + if err != nil { + return fmt.Errorf("Bad: Get SRV RecordSet: %+v", err) + } + + if resp.StatusCode == http.StatusNotFound { + return fmt.Errorf("Bad: Private DNS SRV record %s (resource group: %s) does not exist", srvName, resourceGroup) + } + + return nil + } +} + +func testCheckAzureRMPrivateDnsSrvRecordDestroy(s *terraform.State) error { + conn := testAccProvider.Meta().(*ArmClient).PrivateDns.RecordSetsClient + ctx := testAccProvider.Meta().(*ArmClient).StopContext + + for _, rs := range s.RootModule().Resources { + if rs.Type != "azurerm_private_dns_srv_record" { + continue + } + + srvName := rs.Primary.Attributes["name"] + zoneName := rs.Primary.Attributes["zone_name"] + resourceGroup := rs.Primary.Attributes["resource_group_name"] + + resp, err := conn.Get(ctx, resourceGroup, zoneName, privatedns.SRV, srvName) + + if err != nil { + if resp.StatusCode == http.StatusNotFound { + return nil + } + + return err + } + + return fmt.Errorf("Private DNS SRV record still exists:\n%#v", resp.RecordSetProperties) + } + + return nil +} + +func testAccAzureRMPrivateDnsSrvRecord_basic(rInt int, location string) string { + return fmt.Sprintf(` +resource "azurerm_resource_group" "test" { + name = "acctestRG-%d" + location = "%s" +} + +resource "azurerm_private_dns_zone" "test" { + name = "testzone%d.com" + resource_group_name = "${azurerm_resource_group.test.name}" +} + +resource "azurerm_private_dns_srv_record" "test" { + name = "test%d" + resource_group_name = "${azurerm_resource_group.test.name}" + zone_name = "${azurerm_private_dns_zone.test.name}" + ttl = 300 + record { + priority = 1 + weight = 5 + port = 8080 + target = "target1.contoso.com" + } + + record { + priority = 10 + weight = 10 + port = 8080 + target = "target2.contoso.com" + } +} +`, rInt, location, rInt, rInt) +} + +func testAccAzureRMPrivateDnsSrvRecord_requiresImport(rInt int, location string) string { + template := testAccAzureRMPrivateDnsSrvRecord_basic(rInt, location) + return fmt.Sprintf(` +%s + +resource "azurerm_private_dns_srv_record" "import" { + name = "${azurerm_private_dns_srv_record.test.name}" + resource_group_name = "${azurerm_private_dns_srv_record.test.resource_group_name}" + zone_name = "${azurerm_private_dns_srv_record.test.zone_name}" + ttl = 300 + record { + priority = 1 + weight = 5 + port = 8080 + target = "target1.contoso.com" + } + record { + priority = 10 + weight = 10 + port = 8080 + target = "target2.contoso.com" + } +} +`, template) +} + +func testAccAzureRMPrivateDnsSrvRecord_updateRecords(rInt int, location string) string { + return fmt.Sprintf(` +resource "azurerm_resource_group" "test" { + name = "acctestRG-%d" + location = "%s" +} + +resource "azurerm_private_dns_zone" "test" { + name = "testzone%d.com" + resource_group_name = "${azurerm_resource_group.test.name}" +} + +resource "azurerm_private_dns_srv_record" "test" { + name = "test%d" + resource_group_name = "${azurerm_resource_group.test.name}" + zone_name = "${azurerm_private_dns_zone.test.name}" + ttl = 300 + record { + priority = 1 + weight = 5 + port = 8080 + target = "target1.contoso.com" + } + record { + priority = 10 + weight = 10 + port = 8080 + target = "target2.contoso.com" + } + record { + priority = 20 + weight = 100 + port = 8080 + target = "target3.contoso.com" + } +} +`, rInt, location, rInt, rInt) +} + +func testAccAzureRMPrivateDnsSrvRecord_withTags(rInt int, location string) string { + return fmt.Sprintf(` +resource "azurerm_resource_group" "test" { + name = "acctestRG-%d" + location = "%s" +} + +resource "azurerm_private_dns_zone" "test" { + name = "testzone%d.com" + resource_group_name = "${azurerm_resource_group.test.name}" +} + +resource "azurerm_private_dns_srv_record" "test" { + name = "test%d" + resource_group_name = "${azurerm_resource_group.test.name}" + zone_name = "${azurerm_private_dns_zone.test.name}" + ttl = 300 + record { + priority = 1 + weight = 5 + port = 8080 + target = "target1.contoso.com" + } + record { + priority = 10 + weight = 10 + port = 8080 + target = "target2.contoso.com" + } + + tags = { + environment = "Production" + cost_center = "MSFT" + } +} +`, rInt, location, rInt, rInt) +} + +func testAccAzureRMPrivateDnsSrvRecord_withTagsUpdate(rInt int, location string) string { + return fmt.Sprintf(` +resource "azurerm_resource_group" "test" { + name = "acctestRG-%d" + location = "%s" +} + +resource "azurerm_private_dns_zone" "test" { + name = "testzone%d.com" + resource_group_name = "${azurerm_resource_group.test.name}" +} + +resource "azurerm_private_dns_srv_record" "test" { + name = "test%d" + resource_group_name = "${azurerm_resource_group.test.name}" + zone_name = "${azurerm_private_dns_zone.test.name}" + ttl = 300 + record { + priority = 1 + weight = 5 + port = 8080 + target = "target1.contoso.com" + } + record { + priority = 10 + weight = 10 + port = 8080 + target = "target2.contoso.com" + } + + tags = { + environment = "staging" + } +} +`, rInt, location, rInt, rInt) +} From 278eae8a7f7bb49353a1e08b01b7b21555c6bb74 Mon Sep 17 00:00:00 2001 From: Philipp Resch Date: Thu, 31 Oct 2019 20:25:58 +0100 Subject: [PATCH 02/17] Added documentation for private_dns_srv_record --- website/azurerm.erb | 3 + .../r/private_dns_srv_record.html.markdown | 88 +++++++++++++++++++ 2 files changed, 91 insertions(+) create mode 100644 website/docs/r/private_dns_srv_record.html.markdown diff --git a/website/azurerm.erb b/website/azurerm.erb index dce2bf913a38..5ea4a15f60f1 100644 --- a/website/azurerm.erb +++ b/website/azurerm.erb @@ -1660,6 +1660,9 @@
  • azurerm_private_dns_ptr_record
  • +
  • + azurerm_private_dns_srv_record +
  • azurerm_private_dns_zone
  • diff --git a/website/docs/r/private_dns_srv_record.html.markdown b/website/docs/r/private_dns_srv_record.html.markdown new file mode 100644 index 000000000000..8715ede87d03 --- /dev/null +++ b/website/docs/r/private_dns_srv_record.html.markdown @@ -0,0 +1,88 @@ +--- +layout: "azurerm" +page_title: "Azure Resource Manager: azurerm_private_dns_srv_record" +sidebar_current: "docs-azurerm-resource-private-dns-srv-record" +description: |- + Manages a Private DNS SRV Record. +--- + +# azurerm_private_dns_srv_record + +Enables you to manage DNS SRV Records within Azure Private DNS. + +## Example Usage + +```hcl +resource "azurerm_resource_group" "test" { + name = "acceptanceTestResourceGroup1" + location = "West US" +} + +resource "azurerm_private_dns_zone" "test" { + name = "contoso.com" + resource_group_name = "${azurerm_resource_group.test.name}" +} + +resource "azurerm_private_dns_srv_record" "test" { + name = "test" + resource_group_name = "${azurerm_resource_group.test.name}" + zone_name = "${azurerm_private_dns_zone.test.name}" + ttl = 300 + + record { + priority = 1 + weight = 5 + port = 8080 + target = "target1.contoso.com" + } + + record { + priority = 10 + weight = 10 + port = 8080 + target = "target2.contoso.com" + } + + tags = { + Environment = "Production" + } +} +``` + +## Argument Reference + +The following arguments are supported: + +* `name` - (Required) The name of the DNS SRV Record. Changing this forces a new resource to be created. + +* `resource_group_name` - (Required) Specifies the resource group where the resource exists. Changing this forces a new resource to be created. + +* `zone_name` - (Required) Specifies the Private DNS Zone where the resource exists. Changing this forces a new resource to be created. + +* `ttl ` - (Required) The Time To Live (TTL) of the DNS record in seconds. + +* `tags` - (Optional) A mapping of tags to assign to the resource. + +The `record` block supports: + +* `priority` - (Required) Priority of the SRV record. + +* `weight` - (Required) Weight of the SRV record. + +* `port` - (Required) Port the service is listening on. + +* `target` - (Required) FQDN of the service. + +## Attributes Reference + +The following attributes are exported: + +* `id` - The Private DNS PTR Record ID. + +## Import + +Private DNS SRV Records can be imported using the `resource id`, e.g. + +```shell +terraform import azurerm_private_dns_srv_record.test /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/mygroup1/providers/Microsoft.Network/privateDnsZones/contoso.com/SRV/test +``` From 90a7b0f6f22034489165d22396f7117a15a7d8e7 Mon Sep 17 00:00:00 2001 From: Philipp Resch Date: Sat, 2 Nov 2019 01:32:30 +0100 Subject: [PATCH 03/17] Update website/docs/r/private_dns_srv_record.html.markdown Co-Authored-By: kt --- website/docs/r/private_dns_srv_record.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/r/private_dns_srv_record.html.markdown b/website/docs/r/private_dns_srv_record.html.markdown index 8715ede87d03..716caca6ecb3 100644 --- a/website/docs/r/private_dns_srv_record.html.markdown +++ b/website/docs/r/private_dns_srv_record.html.markdown @@ -13,7 +13,7 @@ Enables you to manage DNS SRV Records within Azure Private DNS. ## Example Usage ```hcl -resource "azurerm_resource_group" "test" { +resource "azurerm_resource_group" "example" { name = "acceptanceTestResourceGroup1" location = "West US" } From 42dcc390a396fc8a21480d04e2375e38b251164a Mon Sep 17 00:00:00 2001 From: Philipp Resch Date: Sat, 2 Nov 2019 01:32:41 +0100 Subject: [PATCH 04/17] Update website/docs/r/private_dns_srv_record.html.markdown Co-Authored-By: kt --- website/docs/r/private_dns_srv_record.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/r/private_dns_srv_record.html.markdown b/website/docs/r/private_dns_srv_record.html.markdown index 716caca6ecb3..f70b2000a7af 100644 --- a/website/docs/r/private_dns_srv_record.html.markdown +++ b/website/docs/r/private_dns_srv_record.html.markdown @@ -71,7 +71,7 @@ The `record` block supports: * `port` - (Required) Port the service is listening on. -* `target` - (Required) FQDN of the service. +* `target` - (Required) The FQDN of the service. ## Attributes Reference From aa06f1e7963df42b2ff845021ab5de748a9d7cb0 Mon Sep 17 00:00:00 2001 From: Philipp Resch Date: Sat, 2 Nov 2019 01:32:50 +0100 Subject: [PATCH 05/17] Update website/docs/r/private_dns_srv_record.html.markdown Co-Authored-By: kt --- website/docs/r/private_dns_srv_record.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/r/private_dns_srv_record.html.markdown b/website/docs/r/private_dns_srv_record.html.markdown index f70b2000a7af..bc3b5917e5d7 100644 --- a/website/docs/r/private_dns_srv_record.html.markdown +++ b/website/docs/r/private_dns_srv_record.html.markdown @@ -69,7 +69,7 @@ The `record` block supports: * `weight` - (Required) Weight of the SRV record. -* `port` - (Required) Port the service is listening on. +* `port` - (Required) The Port the service is listening on. * `target` - (Required) The FQDN of the service. From cec6a11bbc34b12aca24ab1f18c082bafdc28b90 Mon Sep 17 00:00:00 2001 From: Philipp Resch Date: Sat, 2 Nov 2019 01:32:59 +0100 Subject: [PATCH 06/17] Update website/docs/r/private_dns_srv_record.html.markdown Co-Authored-By: kt --- website/docs/r/private_dns_srv_record.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/r/private_dns_srv_record.html.markdown b/website/docs/r/private_dns_srv_record.html.markdown index bc3b5917e5d7..9214c6ab4a9a 100644 --- a/website/docs/r/private_dns_srv_record.html.markdown +++ b/website/docs/r/private_dns_srv_record.html.markdown @@ -67,7 +67,7 @@ The `record` block supports: * `priority` - (Required) Priority of the SRV record. -* `weight` - (Required) Weight of the SRV record. +* `weight` - (Required) The Weight of the SRV record. * `port` - (Required) The Port the service is listening on. From 7dd02f8056295b531db94b778987f1a0576c1754 Mon Sep 17 00:00:00 2001 From: Philipp Resch Date: Sat, 2 Nov 2019 01:33:08 +0100 Subject: [PATCH 07/17] Update website/docs/r/private_dns_srv_record.html.markdown Co-Authored-By: kt --- website/docs/r/private_dns_srv_record.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/r/private_dns_srv_record.html.markdown b/website/docs/r/private_dns_srv_record.html.markdown index 9214c6ab4a9a..a00e295f71b1 100644 --- a/website/docs/r/private_dns_srv_record.html.markdown +++ b/website/docs/r/private_dns_srv_record.html.markdown @@ -65,7 +65,7 @@ The following arguments are supported: The `record` block supports: -* `priority` - (Required) Priority of the SRV record. +* `priority` - (Required) The priority of the SRV record. * `weight` - (Required) The Weight of the SRV record. From be1faf3e0fa91d80cbf6c2448babbb9e3ac40ff3 Mon Sep 17 00:00:00 2001 From: Philipp Resch Date: Fri, 8 Nov 2019 12:53:59 +0100 Subject: [PATCH 08/17] Inline variables --- azurerm/resource_arm_private_dns_srv_record.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/azurerm/resource_arm_private_dns_srv_record.go b/azurerm/resource_arm_private_dns_srv_record.go index c912d1a743c2..8737cd7f8542 100644 --- a/azurerm/resource_arm_private_dns_srv_record.go +++ b/azurerm/resource_arm_private_dns_srv_record.go @@ -130,9 +130,7 @@ func resourceArmPrivateDnsSrvRecordCreateUpdate(d *schema.ResourceData, meta int }, } - eTag := "" - ifNoneMatch := "" // set to empty to allow updates to records after creation - if _, err := client.CreateOrUpdate(ctx, resGroup, zoneName, privatedns.SRV, name, parameters, eTag, ifNoneMatch); err != nil { + if _, err := client.CreateOrUpdate(ctx, resGroup, zoneName, privatedns.SRV, name, parameters, "", ""); err != nil { return fmt.Errorf("Error creating/updating Private DNS SRV Record %q (Zone %q / Resource Group %q): %s", name, zoneName, resGroup, err) } From 39912fc66bf202def3e8ed44fea867e16de502fe Mon Sep 17 00:00:00 2001 From: Philipp Resch Date: Fri, 8 Nov 2019 12:56:49 +0100 Subject: [PATCH 09/17] Validation of "record.target" to not be empty --- azurerm/resource_arm_private_dns_srv_record.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/azurerm/resource_arm_private_dns_srv_record.go b/azurerm/resource_arm_private_dns_srv_record.go index 8737cd7f8542..5a46237f103a 100644 --- a/azurerm/resource_arm_private_dns_srv_record.go +++ b/azurerm/resource_arm_private_dns_srv_record.go @@ -77,8 +77,9 @@ func resourceArmPrivateDnsSrvRecord() *schema.Resource { }, "target": { - Type: schema.TypeString, - Required: true, + Type: schema.TypeString, + Required: true, + ValidateFunc: validate.NoEmptyStrings, }, }, }, From 1fe8fd599b0407cc6f9e84e80a40b1a50fdb1700 Mon Sep 17 00:00:00 2001 From: Philipp Resch Date: Fri, 8 Nov 2019 13:07:09 +0100 Subject: [PATCH 10/17] Removed custom hashing of record --- azurerm/resource_arm_private_dns_srv_record.go | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/azurerm/resource_arm_private_dns_srv_record.go b/azurerm/resource_arm_private_dns_srv_record.go index 5a46237f103a..abf1c2a27f32 100644 --- a/azurerm/resource_arm_private_dns_srv_record.go +++ b/azurerm/resource_arm_private_dns_srv_record.go @@ -1,12 +1,10 @@ package azurerm import ( - "bytes" "fmt" "time" "github.com/Azure/azure-sdk-for-go/services/privatedns/mgmt/2018-09-01/privatedns" - "github.com/hashicorp/terraform-plugin-sdk/helper/hashcode" "github.com/hashicorp/terraform-plugin-sdk/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/helper/validation" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure" @@ -83,7 +81,6 @@ func resourceArmPrivateDnsSrvRecord() *schema.Resource { }, }, }, - Set: resourceArmPrivateDnsSrvRecordHash, }, "ttl": { @@ -246,16 +243,3 @@ func expandAzureRmPrivateDnsSrvRecords(d *schema.ResourceData) *[]privatedns.Srv return &records } - -func resourceArmPrivateDnsSrvRecordHash(v interface{}) int { - var buf bytes.Buffer - - if m, ok := v.(map[string]interface{}); ok { - buf.WriteString(fmt.Sprintf("%d-", m["priority"].(int))) - buf.WriteString(fmt.Sprintf("%d-", m["weight"].(int))) - buf.WriteString(fmt.Sprintf("%d-", m["port"].(int))) - buf.WriteString(fmt.Sprintf("%s-", m["target"].(string))) - } - - return hashcode.String(buf.String()) -} From 1570f1bcf2c12032dca37bb17684fbabbaf1c38d Mon Sep 17 00:00:00 2001 From: Philipp Resch Date: Fri, 8 Nov 2019 13:22:29 +0100 Subject: [PATCH 11/17] minor changes to acceptance test --- azurerm/resource_arm_private_dns_srv_record_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/azurerm/resource_arm_private_dns_srv_record_test.go b/azurerm/resource_arm_private_dns_srv_record_test.go index d63a517bb47b..6e82eca0df32 100644 --- a/azurerm/resource_arm_private_dns_srv_record_test.go +++ b/azurerm/resource_arm_private_dns_srv_record_test.go @@ -193,7 +193,7 @@ func testCheckAzureRMPrivateDnsSrvRecordDestroy(s *terraform.State) error { func testAccAzureRMPrivateDnsSrvRecord_basic(rInt int, location string) string { return fmt.Sprintf(` resource "azurerm_resource_group" "test" { - name = "acctestRG-%d" + name = "acctestRG-prvdns-%d" location = "%s" } @@ -203,7 +203,7 @@ resource "azurerm_private_dns_zone" "test" { } resource "azurerm_private_dns_srv_record" "test" { - name = "test%d" + name = "testaccSRV%d" resource_group_name = "${azurerm_resource_group.test.name}" zone_name = "${azurerm_private_dns_zone.test.name}" ttl = 300 From ac29c41868aa3d94cfa64f9e40a8a2449ca56eac Mon Sep 17 00:00:00 2001 From: Philipp Resch Date: Fri, 8 Nov 2019 15:22:51 +0100 Subject: [PATCH 12/17] Added subcategory --- website/docs/r/private_dns_srv_record.html.markdown | 1 + 1 file changed, 1 insertion(+) diff --git a/website/docs/r/private_dns_srv_record.html.markdown b/website/docs/r/private_dns_srv_record.html.markdown index a00e295f71b1..6e4e115d7cc0 100644 --- a/website/docs/r/private_dns_srv_record.html.markdown +++ b/website/docs/r/private_dns_srv_record.html.markdown @@ -1,4 +1,5 @@ --- +subcategory: "Private DNS" layout: "azurerm" page_title: "Azure Resource Manager: azurerm_private_dns_srv_record" sidebar_current: "docs-azurerm-resource-private-dns-srv-record" From d7ec631da6d3042f72b168d099b17e5d85670416 Mon Sep 17 00:00:00 2001 From: Philipp Resch Date: Fri, 8 Nov 2019 15:37:53 +0100 Subject: [PATCH 13/17] Added dereference nil checks --- azurerm/resource_arm_private_dns_srv_record.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/azurerm/resource_arm_private_dns_srv_record.go b/azurerm/resource_arm_private_dns_srv_record.go index abf1c2a27f32..797a0c540b25 100644 --- a/azurerm/resource_arm_private_dns_srv_record.go +++ b/azurerm/resource_arm_private_dns_srv_record.go @@ -208,6 +208,13 @@ func flattenAzureRmPrivateDnsSrvRecords(records *[]privatedns.SrvRecord) []map[s if records != nil { for _, record := range *records { + if record.Priority == nil || + record.Weight == nil || + record.Port == nil || + record.Target == nil { + continue + } + results = append(results, map[string]interface{}{ "priority": *record.Priority, "weight": *record.Weight, From 987c26edb82e54ea724d116a76226d3fd93dab67 Mon Sep 17 00:00:00 2001 From: Philipp Resch Date: Mon, 11 Nov 2019 16:28:35 +0100 Subject: [PATCH 14/17] Update website/docs/r/private_dns_srv_record.html.markdown Co-Authored-By: Tom Harvey --- website/docs/r/private_dns_srv_record.html.markdown | 2 ++ 1 file changed, 2 insertions(+) diff --git a/website/docs/r/private_dns_srv_record.html.markdown b/website/docs/r/private_dns_srv_record.html.markdown index 6e4e115d7cc0..c05e83f18501 100644 --- a/website/docs/r/private_dns_srv_record.html.markdown +++ b/website/docs/r/private_dns_srv_record.html.markdown @@ -60,6 +60,8 @@ The following arguments are supported: * `zone_name` - (Required) Specifies the Private DNS Zone where the resource exists. Changing this forces a new resource to be created. +* `record` - (Required) One or more `record` blocks as defined below. + * `ttl ` - (Required) The Time To Live (TTL) of the DNS record in seconds. * `tags` - (Optional) A mapping of tags to assign to the resource. From d8377ca02842618ea6a2ab80790cd23adbbf2d10 Mon Sep 17 00:00:00 2001 From: Philipp Resch Date: Mon, 11 Nov 2019 16:28:49 +0100 Subject: [PATCH 15/17] Update website/docs/r/private_dns_srv_record.html.markdown Co-Authored-By: Tom Harvey --- website/docs/r/private_dns_srv_record.html.markdown | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/website/docs/r/private_dns_srv_record.html.markdown b/website/docs/r/private_dns_srv_record.html.markdown index c05e83f18501..708348730e47 100644 --- a/website/docs/r/private_dns_srv_record.html.markdown +++ b/website/docs/r/private_dns_srv_record.html.markdown @@ -66,7 +66,9 @@ The following arguments are supported: * `tags` - (Optional) A mapping of tags to assign to the resource. -The `record` block supports: +--- + +A `record` block supports the following: * `priority` - (Required) The priority of the SRV record. From 206108d081386393a10f946460d1cefb8f119673 Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Sun, 17 Nov 2019 14:55:03 +0200 Subject: [PATCH 16/17] r/private_dns: validating that the name field is lower-cased --- azurerm/helpers/validate/strings.go | 22 ++++++ azurerm/helpers/validate/strings_test.go | 69 +++++++++++++++++++ azurerm/resource_arm_private_dns_a_record.go | 3 + .../resource_arm_private_dns_cname_record.go | 9 +-- .../resource_arm_private_dns_ptr_record.go | 9 +-- .../resource_arm_private_dns_srv_record.go | 9 +-- 6 files changed, 109 insertions(+), 12 deletions(-) diff --git a/azurerm/helpers/validate/strings.go b/azurerm/helpers/validate/strings.go index 1dec1bd2e07f..0fe84690cc02 100644 --- a/azurerm/helpers/validate/strings.go +++ b/azurerm/helpers/validate/strings.go @@ -5,6 +5,28 @@ import ( "strings" ) +// LowerCasedString validates that the string is lower-cased +func LowerCasedString(i interface{}, k string) ([]string, []error) { + v, ok := i.(string) + if !ok { + return nil, []error{fmt.Errorf("expected type of %q to be string", k)} + } + + if strings.TrimSpace(v) == "" { + return nil, []error{fmt.Errorf("%q must not be empty", k)} + } + + if strings.ToLower(v) != v { + return nil, []error{fmt.Errorf("%q must be a lower-cased string", k)} + } + + if strings.ContainsAny(v, " ") { + return nil, []error{fmt.Errorf("%q cannot contain whitespace", k)} + } + + return nil, nil +} + // NoEmptyStrings validates that the string is not just whitespace characters (equal to [\r\n\t\f\v ]) func NoEmptyStrings(i interface{}, k string) ([]string, []error) { v, ok := i.(string) diff --git a/azurerm/helpers/validate/strings_test.go b/azurerm/helpers/validate/strings_test.go index 8d00a222bc60..3ece86328604 100644 --- a/azurerm/helpers/validate/strings_test.go +++ b/azurerm/helpers/validate/strings_test.go @@ -4,6 +4,75 @@ import ( "testing" ) +func TestLowerCasedStrings(t *testing.T) { + cases := []struct { + Value string + TestName string + ErrCount int + }{ + { + Value: "", + TestName: "Empty", + ErrCount: 1, + }, + { + Value: " ", + TestName: "Whitespace", + ErrCount: 1, + }, + { + Value: "Hello", + TestName: "TitleCaseSingleWord", + ErrCount: 1, + }, + { + Value: "HELLO", + TestName: "TitleCaseSingleWord", + ErrCount: 1, + }, + { + Value: "hello", + TestName: "LowerCaseSingleWord", + ErrCount: 0, + }, + { + Value: "hello-there.com", + TestName: "LowerCaseMultipleWords", + ErrCount: 0, + }, + { + Value: "hello there.com", + TestName: "LowerCaseMultipleWordsWhitespace", + ErrCount: 1, + }, + { + Value: "Hello There.com", + TestName: "TitleCaseMultipleWordsWhitespace", + ErrCount: 1, + }, + { + Value: "Hello-There.com", + TestName: "TitleCaseMultipleWordsDash", + ErrCount: 1, + }, + { + Value: "HELLO-THERE.COM", + TestName: "UpperCaseMultipleWordsDash", + ErrCount: 1, + }, + } + + for _, tc := range cases { + t.Run(tc.TestName, func(t *testing.T) { + _, errors := LowerCasedString(tc.Value, tc.TestName) + + if len(errors) != tc.ErrCount { + t.Fatalf("Expected NoEmptyStrings to have %d not %d errors for %q", tc.ErrCount, len(errors), tc.TestName) + } + }) + } +} + func TestNoEmptyStrings(t *testing.T) { cases := []struct { Value string diff --git a/azurerm/resource_arm_private_dns_a_record.go b/azurerm/resource_arm_private_dns_a_record.go index b3e082a9bdaa..ab2eddb08730 100644 --- a/azurerm/resource_arm_private_dns_a_record.go +++ b/azurerm/resource_arm_private_dns_a_record.go @@ -9,6 +9,7 @@ import ( "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/helpers/tf" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/validate" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/features" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/tags" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/timeouts" @@ -37,6 +38,8 @@ func resourceArmPrivateDnsARecord() *schema.Resource { Type: schema.TypeString, Required: true, ForceNew: true, + // lower-cased due to the broken API https://github.com/Azure/azure-rest-api-specs/issues/6641 + ValidateFunc: validate.LowerCasedString, }, // TODO: make this case sensitive once the API's fixed https://github.com/Azure/azure-rest-api-specs/issues/6641 diff --git a/azurerm/resource_arm_private_dns_cname_record.go b/azurerm/resource_arm_private_dns_cname_record.go index aac341157517..98586f1d10ff 100644 --- a/azurerm/resource_arm_private_dns_cname_record.go +++ b/azurerm/resource_arm_private_dns_cname_record.go @@ -35,10 +35,11 @@ func resourceArmPrivateDnsCNameRecord() *schema.Resource { Schema: map[string]*schema.Schema{ "name": { - Type: schema.TypeString, - Required: true, - ForceNew: true, - ValidateFunc: validate.NoEmptyStrings, + Type: schema.TypeString, + Required: true, + ForceNew: true, + // lower-cased due to the broken API https://github.com/Azure/azure-rest-api-specs/issues/6641 + ValidateFunc: validate.LowerCasedString, }, // TODO: make this case sensitive once the API's fixed https://github.com/Azure/azure-rest-api-specs/issues/6641 diff --git a/azurerm/resource_arm_private_dns_ptr_record.go b/azurerm/resource_arm_private_dns_ptr_record.go index f2d0ad2534a4..5334c4e10327 100644 --- a/azurerm/resource_arm_private_dns_ptr_record.go +++ b/azurerm/resource_arm_private_dns_ptr_record.go @@ -35,10 +35,11 @@ func resourceArmPrivateDnsPtrRecord() *schema.Resource { Schema: map[string]*schema.Schema{ "name": { - Type: schema.TypeString, - Required: true, - ForceNew: true, - ValidateFunc: validate.NoEmptyStrings, + Type: schema.TypeString, + Required: true, + ForceNew: true, + // lower-cased due to the broken API https://github.com/Azure/azure-rest-api-specs/issues/6641 + ValidateFunc: validate.LowerCasedString, }, // TODO: make this case sensitive once the API's fixed https://github.com/Azure/azure-rest-api-specs/issues/6641 diff --git a/azurerm/resource_arm_private_dns_srv_record.go b/azurerm/resource_arm_private_dns_srv_record.go index 797a0c540b25..d5b62ec38d69 100644 --- a/azurerm/resource_arm_private_dns_srv_record.go +++ b/azurerm/resource_arm_private_dns_srv_record.go @@ -35,10 +35,11 @@ func resourceArmPrivateDnsSrvRecord() *schema.Resource { Schema: map[string]*schema.Schema{ "name": { - Type: schema.TypeString, - Required: true, - ForceNew: true, - ValidateFunc: validate.NoEmptyStrings, + Type: schema.TypeString, + Required: true, + ForceNew: true, + // lower-cased due to the broken API https://github.com/Azure/azure-rest-api-specs/issues/6641 + ValidateFunc: validate.LowerCasedString, }, // TODO: make this case sensitive once the API's fixed https://github.com/Azure/azure-rest-api-specs/issues/6641 From 4bb7e7d328da1835f7ed2e3024f80d5229edc892 Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Sun, 17 Nov 2019 14:55:43 +0200 Subject: [PATCH 17/17] r/privtae_dns_srv_record: updating the test name to be lower-cased --- azurerm/resource_arm_private_dns_srv_record_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azurerm/resource_arm_private_dns_srv_record_test.go b/azurerm/resource_arm_private_dns_srv_record_test.go index 6e82eca0df32..1be4f08e3d2a 100644 --- a/azurerm/resource_arm_private_dns_srv_record_test.go +++ b/azurerm/resource_arm_private_dns_srv_record_test.go @@ -203,7 +203,7 @@ resource "azurerm_private_dns_zone" "test" { } resource "azurerm_private_dns_srv_record" "test" { - name = "testaccSRV%d" + name = "testaccsrv%d" resource_group_name = "${azurerm_resource_group.test.name}" zone_name = "${azurerm_private_dns_zone.test.name}" ttl = 300