diff --git a/.changelog/3246.txt b/.changelog/3246.txt new file mode 100644 index 0000000000..290f5fe7b5 --- /dev/null +++ b/.changelog/3246.txt @@ -0,0 +1,3 @@ +```release-note:new-resource +tencentcloud_address_extra_template +``` \ No newline at end of file diff --git a/tencentcloud/provider.go b/tencentcloud/provider.go index 4a2c6f0230..4fb2cd6730 100644 --- a/tencentcloud/provider.go +++ b/tencentcloud/provider.go @@ -1715,6 +1715,7 @@ func Provider() *schema.Provider { "tencentcloud_cos_bucket_generate_inventory_immediately_operation": cos.ResourceTencentCloudCosBucketGenerateInventoryImmediatelyOperation(), "tencentcloud_cos_object_download_operation": cos.ResourceTencentCloudCosObjectDownloadOperation(), "tencentcloud_address_template": vpc.ResourceTencentCloudAddressTemplate(), + "tencentcloud_address_extra_template": vpc.ResourceTencentCloudAddressExtraTemplate(), "tencentcloud_address_template_group": vpc.ResourceTencentCloudAddressTemplateGroup(), "tencentcloud_protocol_template": vpc.ResourceTencentCloudProtocolTemplate(), "tencentcloud_protocol_template_group": vpc.ResourceTencentCloudProtocolTemplateGroup(), diff --git a/tencentcloud/provider.md b/tencentcloud/provider.md index 1f7a0298cd..d2f8a3b175 100644 --- a/tencentcloud/provider.md +++ b/tencentcloud/provider.md @@ -1275,6 +1275,7 @@ tencentcloud_security_group tencentcloud_security_group_rule_set tencentcloud_security_group_lite_rule tencentcloud_address_template +tencentcloud_address_extra_template tencentcloud_address_template_group tencentcloud_protocol_template tencentcloud_protocol_template_group diff --git a/tencentcloud/services/vpc/resource_tc_address_extra_template.go b/tencentcloud/services/vpc/resource_tc_address_extra_template.go new file mode 100644 index 0000000000..eb96980b9a --- /dev/null +++ b/tencentcloud/services/vpc/resource_tc_address_extra_template.go @@ -0,0 +1,300 @@ +package vpc + +import ( + "context" + "fmt" + "log" + + "github.com/tencentcloudstack/terraform-provider-tencentcloud/tencentcloud/internal/helper" + svctag "github.com/tencentcloudstack/terraform-provider-tencentcloud/tencentcloud/services/tag" + + vpc "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/vpc/v20170312" + tccommon "github.com/tencentcloudstack/terraform-provider-tencentcloud/tencentcloud/common" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func ResourceTencentCloudAddressExtraTemplate() *schema.Resource { + return &schema.Resource{ + Create: resourceTencentCloudAddressExtraTemplateCreate, + Read: resourceTencentCloudAddressExtraTemplateRead, + Update: resourceTencentCloudAddressExtraTemplateUpdate, + Delete: resourceTencentCloudAddressExtraTemplateDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + Description: "IP address template name.", + }, + "addresses_extra": { + Required: true, + Type: schema.TypeSet, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "address": { + Type: schema.TypeString, + Required: true, + Description: "IP address.", + }, + "description": { + Type: schema.TypeString, + Optional: true, + Description: "Remarks.", + }, + "updated_time": { + Type: schema.TypeString, + Computed: true, + Description: "Update Time.", + }, + }, + }, + Description: "The address information can contain remarks and be presented by the IP, CIDR block or IP address range.", + }, + "tags": { + Type: schema.TypeMap, + Optional: true, + Description: "Tags of the Addresses.", + }, + }, + } +} + +func resourceTencentCloudAddressExtraTemplateCreate(d *schema.ResourceData, meta interface{}) error { + defer tccommon.LogElapsed("resource.tencentcloud_address_extra_template.create")() + + logId := tccommon.GetLogId(tccommon.ContextNil) + + var ( + request = vpc.NewCreateAddressTemplateRequest() + response *vpc.CreateAddressTemplateResponse + ) + + if v, ok := d.GetOk("name"); ok { + request.AddressTemplateName = helper.String(v.(string)) + } + + if v, ok := d.GetOk("addresses_extra"); ok { + addressInfos := make([]*vpc.AddressInfo, 0, 10) + for _, item := range v.(*schema.Set).List() { + dMap := item.(map[string]interface{}) + addressInfo := vpc.AddressInfo{} + if v, ok := dMap["address"]; ok { + addressInfo.Address = helper.String(v.(string)) + } + if v, ok := dMap["description"]; ok { + addressInfo.Description = helper.String(v.(string)) + } + addressInfos = append(addressInfos, &addressInfo) + } + request.AddressesExtra = addressInfos + } + + if v, ok := d.GetOk("tags"); ok { + tags := v.(map[string]interface{}) + request.Tags = make([]*vpc.Tag, 0, len(tags)) + for k, t := range tags { + key := k + value := t.(string) + tag := vpc.Tag{ + Key: &key, + Value: &value, + } + request.Tags = append(request.Tags, &tag) + } + } + + err := resource.Retry(tccommon.WriteRetryTimeout, func() *resource.RetryError { + result, e := meta.(tccommon.ProviderMeta).GetAPIV3Conn().UseVpcClient().CreateAddressTemplate(request) + if e != nil { + return tccommon.RetryError(e) + } else { + log.Printf("[DEBUG]%s api[%s] success, request body [%s], response body [%s]\n", + logId, request.GetAction(), request.ToJsonString(), result.ToJsonString()) + } + response = result + return nil + }) + + if err != nil { + log.Printf("[CRITAL]%s create vpc address template failed, reason:%+v", logId, err) + return err + } + + templateId := *response.Response.AddressTemplate.AddressTemplateId + d.SetId(templateId) + + return resourceTencentCloudAddressExtraTemplateRead(d, meta) +} + +func resourceTencentCloudAddressExtraTemplateRead(d *schema.ResourceData, meta interface{}) error { + defer tccommon.LogElapsed("resource.tencentcloud_address_extra_template.read")() + defer tccommon.InconsistentCheck(d, meta)() + + logId := tccommon.GetLogId(tccommon.ContextNil) + ctx := context.WithValue(context.TODO(), tccommon.LogIdKey, logId) + + templateId := d.Id() + var outErr, inErr error + vpcService := VpcService{client: meta.(tccommon.ProviderMeta).GetAPIV3Conn()} + template, has, outErr := vpcService.DescribeAddressTemplateById(ctx, templateId) + if outErr != nil { + outErr = resource.Retry(tccommon.ReadRetryTimeout, func() *resource.RetryError { + template, has, inErr = vpcService.DescribeAddressTemplateById(ctx, templateId) + if inErr != nil { + return tccommon.RetryError(inErr) + } + return nil + }) + } + if outErr != nil { + return outErr + } + if !has { + d.SetId("") + return nil + } + + _ = d.Set("name", template.AddressTemplateName) + + if len(template.AddressExtraSet) > 0 { + addressExtraSets := make([]map[string]interface{}, 0, len(template.AddressExtraSet)) + for _, v := range template.AddressExtraSet { + addressExtraSet := map[string]interface{}{} + if v.Address != nil { + addressExtraSet["address"] = *v.Address + } + if v.Description != nil { + addressExtraSet["description"] = *v.Description + } + if v.UpdatedTime != nil { + addressExtraSet["updated_time"] = *v.UpdatedTime + } + + addressExtraSets = append(addressExtraSets, addressExtraSet) + } + _ = d.Set("addresses_extra", addressExtraSets) + } + + if len(template.TagSet) > 0 { + tags := make(map[string]string) + for _, tag := range template.TagSet { + if tag.Key != nil && tag.Value != nil { + tags[*tag.Key] = *tag.Value + } + } + _ = d.Set("tags", tags) + } + return nil +} + +func resourceTencentCloudAddressExtraTemplateUpdate(d *schema.ResourceData, meta interface{}) error { + defer tccommon.LogElapsed("resource.tencentcloud_address_extra_template.update")() + + logId := tccommon.GetLogId(tccommon.ContextNil) + ctx := context.WithValue(context.TODO(), tccommon.LogIdKey, logId) + templateId := d.Id() + + if d.HasChange("name") || d.HasChange("addresses_extra") { + var ( + request = vpc.NewModifyAddressTemplateAttributeRequest() + ) + request.AddressTemplateId = helper.String(templateId) + + if v, ok := d.GetOk("name"); ok { + request.AddressTemplateName = helper.String(v.(string)) + } + + if v, ok := d.GetOk("addresses_extra"); ok { + addressInfos := make([]*vpc.AddressInfo, 0, 10) + for _, item := range v.(*schema.Set).List() { + dMap := item.(map[string]interface{}) + addressInfo := vpc.AddressInfo{} + if v, ok := dMap["address"]; ok { + addressInfo.Address = helper.String(v.(string)) + } + if v, ok := dMap["description"]; ok { + addressInfo.Description = helper.String(v.(string)) + } + addressInfos = append(addressInfos, &addressInfo) + } + request.AddressesExtra = addressInfos + } + + err := resource.Retry(tccommon.WriteRetryTimeout, func() *resource.RetryError { + result, e := meta.(tccommon.ProviderMeta).GetAPIV3Conn().UseVpcClient().ModifyAddressTemplateAttribute(request) + if e != nil { + return tccommon.RetryError(e) + } else { + log.Printf("[DEBUG]%s api[%s] success, request body [%s], response body [%s]\n", + logId, request.GetAction(), request.ToJsonString(), result.ToJsonString()) + } + return nil + }) + + if err != nil { + log.Printf("[CRITAL]%s modify vpc address template failed, reason:%+v", logId, err) + return err + } + } + + if d.HasChange("tags") { + client := meta.(tccommon.ProviderMeta).GetAPIV3Conn() + tagService := svctag.NewTagService(client) + oldValue, newValue := d.GetChange("tags") + replaceTags, deleteTags := svctag.DiffTags(oldValue.(map[string]interface{}), newValue.(map[string]interface{})) + region := client.Region + + resourceName := tccommon.BuildTagResourceName("vpc", "address", region, d.Id()) + err := tagService.ModifyTags(ctx, resourceName, replaceTags, deleteTags) + if err != nil { + return err + } + } + + return resourceTencentCloudAddressExtraTemplateRead(d, meta) +} + +func resourceTencentCloudAddressExtraTemplateDelete(d *schema.ResourceData, meta interface{}) error { + defer tccommon.LogElapsed("resource.tencentcloud_address_extra_template.delete")() + + logId := tccommon.GetLogId(tccommon.ContextNil) + ctx := context.WithValue(context.TODO(), tccommon.LogIdKey, logId) + templateId := d.Id() + vpcService := VpcService{client: meta.(tccommon.ProviderMeta).GetAPIV3Conn()} + var outErr, inErr error + + outErr = vpcService.DeleteAddressTemplate(ctx, templateId) + if outErr != nil { + outErr = resource.Retry(tccommon.WriteRetryTimeout, func() *resource.RetryError { + inErr = vpcService.DeleteAddressTemplate(ctx, templateId) + if inErr != nil { + return tccommon.RetryError(inErr, "UnsupportedOperation.MutexOperationTaskRunning") + } + return nil + }) + } + + if outErr != nil { + return outErr + } + + //check not exist + outErr = resource.Retry(tccommon.ReadRetryTimeout, func() *resource.RetryError { + _, has, inErr := vpcService.DescribeAddressTemplateById(ctx, templateId) + if inErr != nil { + return tccommon.RetryError(inErr) + } + if has { + return resource.RetryableError(fmt.Errorf("address template %s is still exists, retry...", templateId)) + } else { + return nil + } + }) + + return outErr +} diff --git a/tencentcloud/services/vpc/resource_tc_address_extra_template.md b/tencentcloud/services/vpc/resource_tc_address_extra_template.md new file mode 100644 index 0000000000..32a344287b --- /dev/null +++ b/tencentcloud/services/vpc/resource_tc_address_extra_template.md @@ -0,0 +1,41 @@ +Provides a resource to manage address extra template. + +~> **NOTE:** Compare to `tencentcloud_address_template`, It contains remarks. + + +Example Usage + +```hcl +resource "tencentcloud_address_extra_template" "foo" { + name = "demo" + + addresses_extra { + address = "10.0.0.1" + description = "create by terraform" + } + + addresses_extra { + address = "10.0.1.0/24" + description = "delete by terraform" + } + + addresses_extra { + address = "10.0.0.1-10.0.0.100" + description = "modify by terraform" + } + + tags = { + createBy = "terraform" + deleteBy = "terraform" + } + +} +``` + +Import + +Address template can be imported using the id, e.g. + +``` +$ terraform import tencentcloud_address_extra_template.foo ipm-makf7k9e +``` \ No newline at end of file diff --git a/tencentcloud/services/vpc/resource_tc_address_extra_template_test.go b/tencentcloud/services/vpc/resource_tc_address_extra_template_test.go new file mode 100644 index 0000000000..a513fd0cd8 --- /dev/null +++ b/tencentcloud/services/vpc/resource_tc_address_extra_template_test.go @@ -0,0 +1,115 @@ +package vpc_test + +import ( + "context" + "fmt" + "testing" + + tcacctest "github.com/tencentcloudstack/terraform-provider-tencentcloud/tencentcloud/acctest" + tccommon "github.com/tencentcloudstack/terraform-provider-tencentcloud/tencentcloud/common" + svcvpc "github.com/tencentcloudstack/terraform-provider-tencentcloud/tencentcloud/services/vpc" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +func TestAccTencentCloudAddressExtraTemplate_basic_and_update(t *testing.T) { + t.Parallel() + resource.Test(t, resource.TestCase{ + PreCheck: func() { tcacctest.AccPreCheck(t) }, + Providers: tcacctest.AccProviders, + CheckDestroy: testAccCheckAddressExtraTemplateDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAddressExtraTemplate_basic, + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("tencentcloud_address_extra_template.foo", "name", "demo"), + ), + }, + { + ResourceName: "tencentcloud_address_extra_template.foo", + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccAddressExtraTemplate_basic_update_name, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAddressTemplateExists("tencentcloud_address_extra_template.foo"), + resource.TestCheckResourceAttr("tencentcloud_address_extra_template.foo", "name", "hello"), + ), + }, + }, + }) +} + +func testAccCheckAddressExtraTemplateDestroy(s *terraform.State) error { + logId := tccommon.GetLogId(tccommon.ContextNil) + ctx := context.WithValue(context.TODO(), tccommon.LogIdKey, logId) + vpcService := svcvpc.NewVpcService(tcacctest.AccProvider.Meta().(tccommon.ProviderMeta).GetAPIV3Conn()) + for _, rs := range s.RootModule().Resources { + if rs.Type != "tencentcloud_address_template" { + continue + } + + _, has, err := vpcService.DescribeAddressTemplateById(ctx, rs.Primary.ID) + if has { + return fmt.Errorf("address template still exists") + } + if err != nil { + return err + } + } + return nil +} + +const testAccAddressExtraTemplate_basic = ` +resource "tencentcloud_address_extra_template" "foo" { + name = "demo" + + addresses_extra { + address = "10.0.0.1" + description = "create by terraform" + } + + addresses_extra { + address = "10.0.1.0/24" + description = "delete by terraform" + } + + addresses_extra { + address = "10.0.0.1-10.0.0.100" + description = "modify by terraform" + } + + tags = { + createBy = "terraform" + deleteBy = "terraform" + } + +}` + +const testAccAddressExtraTemplate_basic_update_name = ` +resource "tencentcloud_address_extra_template" "foo" { + name = "hello" + + addresses_extra { + address = "10.0.0.1" + description = "create by terraform" + } + + addresses_extra { + address = "10.0.1.0/24" + description = "delete by terraform" + } + + addresses_extra { + address = "10.0.0.1-10.0.0.100" + description = "modify by terraform" + } + + tags = { + createBy = "terraform" + deleteBy = "terraform" + } + +}` diff --git a/tencentcloud/services/vpc/resource_tc_address_template.md b/tencentcloud/services/vpc/resource_tc_address_template.md index a386036eb6..4e25f46282 100644 --- a/tencentcloud/services/vpc/resource_tc_address_template.md +++ b/tencentcloud/services/vpc/resource_tc_address_template.md @@ -1,11 +1,13 @@ Provides a resource to manage address template. +~> **NOTE:** It can be replaced by `tencentcloud_address_extra_template`. + Example Usage ```hcl resource "tencentcloud_address_template" "foo" { - name = "cam-user-test" - addresses = ["10.0.0.1","10.0.1.0/24","10.0.0.1-10.0.0.100"] + name = "cam-user-test" + addresses = ["10.0.0.1", "10.0.1.0/24", "10.0.0.1-10.0.0.100"] } ``` diff --git a/website/docs/r/address_extra_template.html.markdown b/website/docs/r/address_extra_template.html.markdown new file mode 100644 index 0000000000..4d07fcebab --- /dev/null +++ b/website/docs/r/address_extra_template.html.markdown @@ -0,0 +1,73 @@ +--- +subcategory: "Virtual Private Cloud(VPC)" +layout: "tencentcloud" +page_title: "TencentCloud: tencentcloud_address_extra_template" +sidebar_current: "docs-tencentcloud-resource-address_extra_template" +description: |- + Provides a resource to manage address extra template. +--- + +# tencentcloud_address_extra_template + +Provides a resource to manage address extra template. + +~> **NOTE:** Compare to `tencentcloud_address_template`, It contains remarks. + +## Example Usage + +```hcl +resource "tencentcloud_address_extra_template" "foo" { + name = "demo" + + addresses_extra { + address = "10.0.0.1" + description = "create by terraform" + } + + addresses_extra { + address = "10.0.1.0/24" + description = "delete by terraform" + } + + addresses_extra { + address = "10.0.0.1-10.0.0.100" + description = "modify by terraform" + } + + tags = { + createBy = "terraform" + deleteBy = "terraform" + } + +} +``` + +## Argument Reference + +The following arguments are supported: + +* `addresses_extra` - (Required, Set) The address information can contain remarks and be presented by the IP, CIDR block or IP address range. +* `name` - (Required, String) IP address template name. +* `tags` - (Optional, Map) Tags of the Addresses. + +The `addresses_extra` object supports the following: + +* `address` - (Required, String) IP address. +* `description` - (Optional, String) Remarks. + +## Attributes Reference + +In addition to all arguments above, the following attributes are exported: + +* `id` - ID of the resource. + + + +## Import + +Address template can be imported using the id, e.g. + +``` +$ terraform import tencentcloud_address_extra_template.foo ipm-makf7k9e +``` + diff --git a/website/docs/r/address_template.html.markdown b/website/docs/r/address_template.html.markdown index 7ef5f7712e..8a47862710 100644 --- a/website/docs/r/address_template.html.markdown +++ b/website/docs/r/address_template.html.markdown @@ -11,6 +11,8 @@ description: |- Provides a resource to manage address template. +~> **NOTE:** It can be replaced by `tencentcloud_address_extra_template`. + ## Example Usage ```hcl diff --git a/website/tencentcloud.erb b/website/tencentcloud.erb index 61010036c6..64a5bee178 100644 --- a/website/tencentcloud.erb +++ b/website/tencentcloud.erb @@ -6517,6 +6517,9 @@
  • Resources