diff --git a/go.sum b/go.sum index 691acd153f..39381f259c 100644 --- a/go.sum +++ b/go.sum @@ -494,6 +494,7 @@ github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.351/go.mod github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.353 h1:rFkcKuLFxt2xolSWbyeznetTBw9Cyhe1ycILmEkE1Pk= github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.353/go.mod h1:7sCQWVkxcsR38nffDW057DRGk8mUjK1Ing/EFOK8s8Y= github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.357/go.mod h1:7sCQWVkxcsR38nffDW057DRGk8mUjK1Ing/EFOK8s8Y= +github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.358/go.mod h1:7sCQWVkxcsR38nffDW057DRGk8mUjK1Ing/EFOK8s8Y= github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.359 h1:m7Ga+AAWcngpWVIU6TjtyJ2MZupZvyY4soTNKDYQVVs= github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.359/go.mod h1:7sCQWVkxcsR38nffDW057DRGk8mUjK1Ing/EFOK8s8Y= github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cvm v1.0.199 h1:ajgJogYSIQ5u1PIbiV5nsvr5K0fYpm1/T7Dy+mxEM6U= diff --git a/tencentcloud/provider.go b/tencentcloud/provider.go index a1ab5bdc9f..cd18cd1ab6 100644 --- a/tencentcloud/provider.go +++ b/tencentcloud/provider.go @@ -586,6 +586,7 @@ EMR DNSPOD Resource tencentcloud_dnspod_domain_instance + tencentcloud_dnspod_record PrivateDNS Resource @@ -621,10 +622,13 @@ const ( ACCOUNT_TYPE_INTERNATION = "INTERNATION" ACCOUNT_TYPE_PREPAY = "PREPAY" ACCOUNT_TYPE_COMMON = "COMMON" + ACCOUNT_TYPE_PRIVATE = "PRIVATE" INTERNATION_PROVIDER_SECRET_ID = "TENCENTCLOUD_SECRET_ID_INTERNATION" INTERNATION_PROVIDER_SECRET_KEY = "TENCENTCLOUD_SECRET_KEY_INTERNATION" PREPAY_PROVIDER_SECRET_ID = "TENCENTCLOUD_SECRET_ID_PREPAY" PREPAY_PROVIDER_SECRET_KEY = "TENCENTCLOUD_SECRET_KEY_PREPAY" + PRIVATE_PROVIDER_SECRET_ID = "TENCENTCLOUD_SECRET_ID_PRIVATE" + PRIVATE_PROVIDER_SECRET_KEY = "TENCENTCLOUD_SECRET_KEY_PRIVATE" ) type TencentCloudClient struct { @@ -1063,6 +1067,7 @@ func Provider() terraform.ResourceProvider { "tencentcloud_ssm_secret_version": resourceTencentCloudSsmSecretVersion(), "tencentcloud_cdh_instance": resourceTencentCloudCdhInstance(), "tencentcloud_dnspod_domain_instance": resourceTencentCloudDnspodDomainInstance(), + "tencentcloud_dnspod_record": resourceTencentCloudDnspodRecord(), "tencentcloud_private_dns_zone": resourceTencentCloudPrivateDnsZone(), "tencentcloud_private_dns_record": resourceTencentCloudPrivateDnsRecord(), }, diff --git a/tencentcloud/provider_test.go b/tencentcloud/provider_test.go index 66812d9d4c..368a056a4f 100644 --- a/tencentcloud/provider_test.go +++ b/tencentcloud/provider_test.go @@ -66,6 +66,14 @@ func testAccPreCheckCommon(t *testing.T, accountType string) { } os.Setenv(PROVIDER_SECRET_ID, secretId) os.Setenv(PROVIDER_SECRET_KEY, secretKey) + case accountType == ACCOUNT_TYPE_PRIVATE: + secretId := os.Getenv(PRIVATE_PROVIDER_SECRET_ID) + secretKey := os.Getenv(PRIVATE_PROVIDER_SECRET_KEY) + if secretId == "" || secretKey == "" { + t.Fatalf("%v and %v must be set for acceptance tests\n", PRIVATE_PROVIDER_SECRET_ID, PRIVATE_PROVIDER_SECRET_KEY) + } + os.Setenv(PROVIDER_SECRET_ID, secretId) + os.Setenv(PROVIDER_SECRET_KEY, secretKey) default: if v := os.Getenv(PROVIDER_SECRET_ID); v == "" { t.Fatalf("%v must be set for acceptance tests\n", PROVIDER_SECRET_ID) diff --git a/tencentcloud/resource_tc_dnspod_record.go b/tencentcloud/resource_tc_dnspod_record.go new file mode 100644 index 0000000000..387a5e4d9e --- /dev/null +++ b/tencentcloud/resource_tc_dnspod_record.go @@ -0,0 +1,286 @@ +/* +Provide a resource to create a DnsPod record. + +Example Usage + +```hcl +resource "tencentcloud_dnspod_record" "demo" { + domain="mikatong.com" + record_type="A" + record_line="默认" + value="1.2.3.9" + sub_domain="demo" +} +``` +*/ +package tencentcloud + +import ( + "fmt" + "log" + "strconv" + "strings" + + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + dnspod "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod/v20210323" + "github.com/tencentcloudstack/terraform-provider-tencentcloud/tencentcloud/internal/helper" +) + +func resourceTencentCloudDnspodRecord() *schema.Resource { + return &schema.Resource{ + Create: resourceTencentCloudDnspodRecordCreate, + Read: resourceTencentCloudDnspodRecordRead, + Update: resourceTencentCloudDnspodRecordUpdate, + Delete: resourceTencentCloudDnspodRecordDelete, + + Schema: map[string]*schema.Schema{ + "domain": { + Type: schema.TypeString, + Required: true, + Description: "The Domain.", + }, + "record_type": { + Type: schema.TypeString, + Required: true, + Description: "The record type.", + }, + "record_line": { + Type: schema.TypeString, + Required: true, + Description: "The record line.", + }, + "value": { + Type: schema.TypeString, + Required: true, + Description: "The record value.", + }, + "sub_domain": { + Type: schema.TypeString, + Optional: true, + Default: "@", + Description: "The host records, default value is `@`.", + }, + "mx": { + Type: schema.TypeInt, + Optional: true, + Description: "MX priority, valid when the record type is MX, range 1-20. Note: must set when record type equal MX.", + }, + "ttl": { + Type: schema.TypeInt, + Optional: true, + Default: 600, + Description: "TTL, the range is 1-604800, and the minimum value of different levels of domain names is different. Default is 600.", + }, + "weight": { + Type: schema.TypeInt, + Optional: true, + Default: 0, + Description: "Weight information. An integer from 0 to 100. Only enterprise VIP domain names are available, 0 means off, does not pass this parameter, means that the weight information is not set. Default is 0.", + }, + "status": { + Type: schema.TypeString, + Optional: true, + Default: "ENABLE", + Description: "Records the initial state, with values ranging from ENABLE and DISABLE. The default is ENABLE, and if DISABLE is passed in, resolution will not take effect and the limits of load balancing will not be verified.", + }, + "monitor_status": { + Type: schema.TypeString, + Computed: true, + Description: "The D monitoring status of the record.", + }, + }, + } +} + +func resourceTencentCloudDnspodRecordCreate(d *schema.ResourceData, meta interface{}) error { + defer logElapsed("resource.tencentcloud_dnspod_record.create")() + logId := getLogId(contextNil) + request := dnspod.NewCreateRecordRequest() + + domain := d.Get("domain").(string) + recordType := d.Get("record_type").(string) + recordLine := d.Get("record_line").(string) + value := d.Get("value").(string) + subDomain := d.Get("sub_domain").(string) + ttl := d.Get("ttl").(int) + status := d.Get("status").(string) + request.Domain = &domain + request.RecordType = &recordType + request.RecordLine = &recordLine + request.Value = &value + request.SubDomain = &subDomain + if v, ok := d.GetOk("mx"); ok { + request.MX = helper.IntUint64(v.(int)) + } + request.TTL = helper.IntUint64(ttl) + if v, ok := d.GetOk("weight"); ok { + request.Weight = helper.IntUint64(v.(int)) + } + request.Status = &status + + err := resource.Retry(readRetryTimeout, func() *resource.RetryError { + response, e := meta.(*TencentCloudClient).apiV3Conn.UseDnsPodClient().CreateRecord(request) + if e != nil { + return retryError(e) + } + recordId := *response.Response.RecordId + + d.SetId(domain + FILED_SP + fmt.Sprint(recordId)) + + return nil + }) + if err != nil { + log.Printf("[CRITAL]%s create DnsPod record failed, reason:%s\n", logId, err.Error()) + return err + } + + return resourceTencentCloudDnspodRecordRead(d, meta) +} + +func resourceTencentCloudDnspodRecordRead(d *schema.ResourceData, meta interface{}) error { + defer logElapsed("resource.tencentcloud_dnspod_record.read")() + defer inconsistentCheck(d, meta)() + + logId := getLogId(contextNil) + + id := d.Id() + items := strings.Split(id, FILED_SP) + if len(items) < 2 { + return nil + } + request := dnspod.NewDescribeRecordRequest() + request.Domain = helper.String(items[0]) + recordId, err := strconv.Atoi(items[1]) + if err != nil { + return err + } + request.RecordId = helper.IntUint64(recordId) + + err = resource.Retry(readRetryTimeout, func() *resource.RetryError { + response, e := meta.(*TencentCloudClient).apiV3Conn.UseDnsPodClient().DescribeRecord(request) + if e != nil { + return retryError(e) + } + + recordInfo := response.Response.RecordInfo + + _ = d.Set("sub_domain", recordInfo.SubDomain) + _ = d.Set("mx", recordInfo.MX) + _ = d.Set("ttl", recordInfo.TTL) + _ = d.Set("monitor_status", recordInfo.MonitorStatus) + _ = d.Set("weight", recordInfo.Weight) + if *recordInfo.Enabled == uint64(0) { + _ = d.Set("status", "DISABLE") + } else { + _ = d.Set("status", "ENABLE") + } + + return nil + }) + if err != nil { + log.Printf("[CRITAL]%s read DnsPod record failed, reason:%s\n", logId, err.Error()) + return err + } + return nil +} + +func resourceTencentCloudDnspodRecordUpdate(d *schema.ResourceData, meta interface{}) error { + defer logElapsed("resource.tencentcloud_dnspod_record.update")() + + id := d.Id() + items := strings.Split(id, FILED_SP) + if len(items) < 2 { + return nil + } + domain := items[0] + recordId, err := strconv.Atoi(items[1]) + if err != nil { + return err + } + request := dnspod.NewModifyRecordRequest() + request.Domain = &domain + request.RecordId = helper.IntUint64(recordId) + recordType := d.Get("record_type").(string) + recordLine := d.Get("record_line").(string) + value := d.Get("value").(string) + subDomain := d.Get("sub_domain").(string) + request.RecordType = &recordType + request.RecordLine = &recordLine + request.Value = &value + request.SubDomain = &subDomain + + d.SetPartial("record_type") + d.SetPartial("record_line") + d.SetPartial("value") + d.SetPartial("sub_domain") + + if d.HasChange("status") { + status := d.Get("status").(string) + request.Status = &status + d.SetPartial("status") + } + if d.HasChange("mx") { + if v, ok := d.GetOk("mx"); ok { + request.MX = helper.IntUint64(v.(int)) + d.SetPartial("mx") + } + } + if d.HasChange("ttl") { + ttl := d.Get("ttl").(int) + request.TTL = helper.IntUint64(ttl) + d.SetPartial("ttl") + } + if d.HasChange("weight") { + weight := d.Get("weight").(int) + request.TTL = helper.IntUint64(weight) + d.SetPartial("weight") + + } + d.Partial(true) + err = resource.Retry(readRetryTimeout, func() *resource.RetryError { + _, e := meta.(*TencentCloudClient).apiV3Conn.UseDnsPodClient().ModifyRecord(request) + if e != nil { + return retryError(e) + } + return nil + }) + + if err != nil { + return err + } + d.Partial(false) + return resourceTencentCloudDnspodRecordRead(d, meta) +} + +func resourceTencentCloudDnspodRecordDelete(d *schema.ResourceData, meta interface{}) error { + defer logElapsed("resource.tencentcloud_dnspod_record.delete")() + + logId := getLogId(contextNil) + id := d.Id() + items := strings.Split(id, FILED_SP) + if len(items) < 2 { + return nil + } + domain := items[0] + recordId, err := strconv.Atoi(items[1]) + if err != nil { + return err + } + request := dnspod.NewDeleteRecordRequest() + request.Domain = helper.String(domain) + request.RecordId = helper.IntUint64(recordId) + + err = resource.Retry(writeRetryTimeout, func() *resource.RetryError { + _, e := meta.(*TencentCloudClient).apiV3Conn.UseDnsPodClient().DeleteRecord(request) + if e != nil { + return retryError(e) + } + return nil + }) + if err != nil { + log.Printf("[CRITAL]%s delete DnsPod record failed, reason:%s\n", logId, err.Error()) + return err + } + return nil +} diff --git a/tencentcloud/resource_tc_dnspod_record_test.go b/tencentcloud/resource_tc_dnspod_record_test.go new file mode 100644 index 0000000000..ff18a40c94 --- /dev/null +++ b/tencentcloud/resource_tc_dnspod_record_test.go @@ -0,0 +1,124 @@ +package tencentcloud + +import ( + "fmt" + "strconv" + "strings" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/terraform" + sdkErrors "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/errors" + dnspod "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod/v20210323" + "github.com/tencentcloudstack/terraform-provider-tencentcloud/tencentcloud/internal/helper" +) + +func TestAccTencentCloudDnspodRecord(t *testing.T) { + t.Parallel() + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheckCommon(t, ACCOUNT_TYPE_PRIVATE) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckDnspodRecordDestroy, + Steps: []resource.TestStep{ + { + Config: testAccTencentCloudDnspodRecord, + Check: resource.ComposeTestCheckFunc( + testAccCheckDnspodRecordExists("tencentcloud_dnspod_record.demo"), + resource.TestCheckResourceAttr("tencentcloud_dnspod_record.demo", "domain", "mikatong.com"), + resource.TestCheckResourceAttr("tencentcloud_dnspod_record.demo", "value", "1.2.3.9"), + resource.TestCheckResourceAttr("tencentcloud_dnspod_record.demo", "sub_domain", "demo"), + resource.TestCheckResourceAttr("tencentcloud_dnspod_record.demo", "status", "ENABLE"), + resource.TestCheckResourceAttr("tencentcloud_dnspod_record.demo", "record_type", "A"), + resource.TestCheckResourceAttr("tencentcloud_dnspod_record.demo", "record_line", "默认"), + ), + }, + }, + }) +} + +func testAccCheckDnspodRecordExists(n string) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("dnspod record %s is not found", n) + } + if rs.Primary.ID == "" { + return fmt.Errorf("dnspod record id is not set") + } + items := strings.Split(rs.Primary.ID, FILED_SP) + if len(items) < 2 { + return nil + } + request := dnspod.NewDescribeRecordRequest() + request.Domain = helper.String(items[0]) + recordId, err := strconv.Atoi(items[1]) + if err != nil { + return err + } + request.RecordId = helper.IntUint64(recordId) + + err = resource.Retry(readRetryTimeout, func() *resource.RetryError { + response, e := testAccProvider.Meta().(*TencentCloudClient).apiV3Conn.UseDnsPodClient().DescribeRecord(request) + if e != nil { + return retryError(e) + } + + if response.Response.RecordInfo != nil { + return nil + } + return retryError(fmt.Errorf("Dnspod record is null!")) + }) + if err != nil { + return err + } + return nil + } +} + +func testAccCheckDnspodRecordDestroy(s *terraform.State) error { + for _, rs := range s.RootModule().Resources { + if rs.Type != "tencentcloud_dnspod_record" { + continue + } + + items := strings.Split(rs.Primary.ID, FILED_SP) + if len(items) < 2 { + return nil + } + request := dnspod.NewDescribeRecordRequest() + request.Domain = helper.String(items[0]) + recordId, err := strconv.Atoi(items[1]) + if err != nil { + return err + } + request.RecordId = helper.IntUint64(recordId) + + err = resource.Retry(readRetryTimeout, func() *resource.RetryError { + response, e := testAccProvider.Meta().(*TencentCloudClient).apiV3Conn.UseDnsPodClient().DescribeRecord(request) + if sdkError, ok := e.(*sdkErrors.TencentCloudSDKError); ok { + if sdkError.Code == "InvalidParameter.RecordIdInvalid" { + return nil + } + return retryError(e) + } + if response.Response.RecordInfo == nil { + return nil + } + return retryError(fmt.Errorf("Dnspod record still exist!")) + }) + if err != nil { + return err + } + } + return nil +} + +const testAccTencentCloudDnspodRecord = ` +resource "tencentcloud_dnspod_record" "demo" { + domain="mikatong.com" + record_type="A" + record_line="默认" + value="1.2.3.9" + sub_domain="demo" +} +` diff --git a/website/docs/r/dnspod_record.html.markdown b/website/docs/r/dnspod_record.html.markdown new file mode 100644 index 0000000000..6645ac66ab --- /dev/null +++ b/website/docs/r/dnspod_record.html.markdown @@ -0,0 +1,47 @@ +--- +subcategory: "DNSPOD" +layout: "tencentcloud" +page_title: "TencentCloud: tencentcloud_dnspod_record" +sidebar_current: "docs-tencentcloud-resource-dnspod_record" +description: |- + Provide a resource to create a DnsPod record. +--- + +# tencentcloud_dnspod_record + +Provide a resource to create a DnsPod record. + +## Example Usage + +```hcl +resource "tencentcloud_dnspod_record" "demo" { + domain = "mikatong.com" + record_type = "A" + record_line = "默认" + value = "1.2.3.9" + sub_domain = "demo" +} +``` + +## Argument Reference + +The following arguments are supported: + +* `domain` - (Required) The Domain. +* `record_line` - (Required) The record line. +* `record_type` - (Required) The record type. +* `value` - (Required) The record value. +* `mx` - (Optional) MX priority, valid when the record type is MX, range 1-20. Note: must set when record type equal MX. +* `status` - (Optional) Records the initial state, with values ranging from ENABLE and DISABLE. The default is ENABLE, and if DISABLE is passed in, resolution will not take effect and the limits of load balancing will not be verified. +* `sub_domain` - (Optional) The host records, default value is `@`. +* `ttl` - (Optional) TTL, the range is 1-604800, and the minimum value of different levels of domain names is different. Default is 600. +* `weight` - (Optional) Weight information. An integer from 0 to 100. Only enterprise VIP domain names are available, 0 means off, does not pass this parameter, means that the weight information is not set. Default is 0. + +## Attributes Reference + +In addition to all arguments above, the following attributes are exported: + +* `id` - ID of the resource. +* `monitor_status` - The D monitoring status of the record. + + diff --git a/website/tencentcloud.erb b/website/tencentcloud.erb index 620f21d70f..8bf41ecf94 100644 --- a/website/tencentcloud.erb +++ b/website/tencentcloud.erb @@ -748,6 +748,9 @@
  • tencentcloud_dnspod_domain_instance
  • +
  • + tencentcloud_dnspod_record +