diff --git a/CHANGELOG.md b/CHANGELOG.md index 17db5b0f2c..6453c1b0c3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,10 @@ ## 1.22.1 (Unreleased) + +ENHANCEMENTS: + +* Resource: `tencentcloud_eip` add optional argument `tags`. +* Data Source: `tencentcloud_eips` add optional argument `tags`. + BUG FIXES: * Fixed docs of CAM diff --git a/examples/tencentcloud-eip/main.tf b/examples/tencentcloud-eip/main.tf index 9488e60ad0..a9e335987d 100644 --- a/examples/tencentcloud-eip/main.tf +++ b/examples/tencentcloud-eip/main.tf @@ -1,3 +1,11 @@ resource "tencentcloud_eip" "foo" { name = "awesome_eip_example" + + tags = { + "test" = "test" + } } + +data "tencentcloud_eips" "tags" { + tags = "${tencentcloud_eip.foo.tags}" +} \ No newline at end of file diff --git a/tencentcloud/data_source_tc_eips.go b/tencentcloud/data_source_tc_eips.go index a3728993d3..dd123a4d75 100644 --- a/tencentcloud/data_source_tc_eips.go +++ b/tencentcloud/data_source_tc_eips.go @@ -40,6 +40,11 @@ func dataSourceTencentCloudEips() *schema.Resource { Optional: true, Description: "The elastic ip address.", }, + "tags": { + Type: schema.TypeMap, + Optional: true, + Description: "The tags of eip.", + }, "result_output_file": { Type: schema.TypeString, Optional: true, @@ -92,6 +97,11 @@ func dataSourceTencentCloudEips() *schema.Resource { Computed: true, Description: "Creation time of the eip.", }, + "tags": { + Type: schema.TypeMap, + Computed: true, + Description: "Tags of the eip.", + }, }, }, }, @@ -103,9 +113,11 @@ func dataSourceTencentCloudEipsRead(d *schema.ResourceData, meta interface{}) er defer logElapsed("data_source.tencentcloud_eips.read")() logId := getLogId(contextNil) ctx := context.WithValue(context.TODO(), "logId", logId) - vpcService := VpcService{ - client: meta.(*TencentCloudClient).apiV3Conn, - } + + client := meta.(*TencentCloudClient).apiV3Conn + vpcService := VpcService{client: client} + tagService := TagService{client: client} + region := client.Region filter := make(map[string]string) if v, ok := d.GetOk("eip_id"); ok { @@ -118,6 +130,8 @@ func dataSourceTencentCloudEipsRead(d *schema.ResourceData, meta interface{}) er filter["public-ip"] = v.(string) } + tags := getTags(d, "tags") + var eips []*vpc.Address var errRet error err := resource.Retry(readRetryTimeout, func() *resource.RetryError { @@ -133,7 +147,21 @@ func dataSourceTencentCloudEipsRead(d *schema.ResourceData, meta interface{}) er eipList := make([]map[string]interface{}, 0, len(eips)) ids := make([]string, 0, len(eips)) + +EIP_LOOP: for _, eip := range eips { + respTags, err := tagService.DescribeResourceTags(ctx, VPC_SERVICE_TYPE, EIP_RESOURCE_TYPE, region, *eip.AddressId) + if err != nil { + log.Printf("[CRITAL]%s describe eip tags failed: %+v", logId, err) + return err + } + + for k, v := range tags { + if respTags[k] != v { + continue EIP_LOOP + } + } + mapping := map[string]interface{}{ "eip_id": eip.AddressId, "eip_name": eip.AddressName, @@ -143,7 +171,9 @@ func dataSourceTencentCloudEipsRead(d *schema.ResourceData, meta interface{}) er "instance_id": eip.InstanceId, "eni_id": eip.NetworkInterfaceId, "create_time": eip.CreatedTime, + "tags": respTags, } + eipList = append(eipList, mapping) ids = append(ids, *eip.AddressId) } diff --git a/tencentcloud/data_source_tc_eips_test.go b/tencentcloud/data_source_tc_eips_test.go index 5f73d4bd02..49c0f77184 100644 --- a/tencentcloud/data_source_tc_eips_test.go +++ b/tencentcloud/data_source_tc_eips_test.go @@ -15,7 +15,7 @@ func TestAccTencentCloudEipsDataSource(t *testing.T) { { Config: testAccEipsDataSource, Check: resource.ComposeTestCheckFunc( - testAccCheckEipExists("tencentcloud_eip.eip"), + testAccCheckTencentCloudDataSourceID("data.tencentcloud_eips.data_eips"), resource.TestCheckResourceAttr("data.tencentcloud_eips.data_eips", "eip_list.#", "1"), resource.TestCheckResourceAttrSet("data.tencentcloud_eips.data_eips", "eip_list.0.eip_id"), resource.TestCheckResourceAttr("data.tencentcloud_eips.data_eips", "eip_list.0.eip_name", "tf-test-eip"), @@ -23,6 +23,9 @@ func TestAccTencentCloudEipsDataSource(t *testing.T) { resource.TestCheckResourceAttrSet("data.tencentcloud_eips.data_eips", "eip_list.0.status"), resource.TestCheckResourceAttrSet("data.tencentcloud_eips.data_eips", "eip_list.0.public_ip"), resource.TestCheckResourceAttrSet("data.tencentcloud_eips.data_eips", "eip_list.0.create_time"), + + testAccCheckTencentCloudDataSourceID("data.tencentcloud_eips.tags"), + resource.TestCheckResourceAttr("data.tencentcloud_eips.tags", "eip_list.0.tags.test", "test"), ), }, }, @@ -31,10 +34,18 @@ func TestAccTencentCloudEipsDataSource(t *testing.T) { const testAccEipsDataSource = ` resource "tencentcloud_eip" "eip" { - name = "tf-test-eip" + name = "tf-test-eip" + + tags = { + "test" = "test" + } } data "tencentcloud_eips" "data_eips" { - eip_id = "${tencentcloud_eip.eip.id}" + eip_id = "${tencentcloud_eip.eip.id}" +} + +data "tencentcloud_eips" "tags" { + tags = "${tencentcloud_eip.eip.tags}" } ` diff --git a/tencentcloud/extension_vpc.go b/tencentcloud/extension_vpc.go index 8b2a8f0a6c..e780394e01 100644 --- a/tencentcloud/extension_vpc.go +++ b/tencentcloud/extension_vpc.go @@ -23,6 +23,8 @@ var ALL_GATE_WAY_TYPES = []string{GATE_WAY_TYPE_CVM, GATE_WAY_TYPE_CCN, } +const VPC_SERVICE_TYPE = "vpc" + /* EIP */ @@ -45,6 +47,8 @@ const ( EIP_INTERNET_PROVIDER_CMCC = "CMCC" EIP_INTERNET_PROVIDER_CTCC = "CTCC" EIP_INTERNET_PROVIDER_CUCC = "CUCC" + + EIP_RESOURCE_TYPE = "eip" ) var EIP_INTERNET_PROVIDER = []string{ diff --git a/tencentcloud/resource_tc_eip.go b/tencentcloud/resource_tc_eip.go index 8ff93ca0f2..f5daf91802 100644 --- a/tencentcloud/resource_tc_eip.go +++ b/tencentcloud/resource_tc_eip.go @@ -90,6 +90,11 @@ func resourceTencentCloudEip() *schema.Resource { ValidateFunc: validateIntegerInRange(1, 1000), Description: "The bandwidth limit of eip, unit is Mbps, and the range is 1-1000.", }, + "tags": { + Type: schema.TypeMap, + Optional: true, + Description: "The tags of eip.", + }, // computed "public_ip": { @@ -111,9 +116,11 @@ func resourceTencentCloudEipCreate(d *schema.ResourceData, meta interface{}) err logId := getLogId(contextNil) ctx := context.WithValue(context.TODO(), "logId", logId) - vpcService := VpcService{ - client: meta.(*TencentCloudClient).apiV3Conn, - } + + client := meta.(*TencentCloudClient).apiV3Conn + vpcService := VpcService{client: client} + tagService := TagService{client: client} + region := client.Region request := vpc.NewAllocateAddressesRequest() if v, ok := d.GetOk("type"); ok { @@ -139,7 +146,7 @@ func resourceTencentCloudEipCreate(d *schema.ResourceData, meta interface{}) err eipId := "" err := resource.Retry(writeRetryTimeout, func() *resource.RetryError { ratelimit.Check(request.GetAction()) - response, err := meta.(*TencentCloudClient).apiV3Conn.UseVpcClient().AllocateAddresses(request) + response, err := client.UseVpcClient().AllocateAddresses(request) if err != nil { log.Printf("[CRITAL]%s api[%s] fail, request body [%s], reason[%s]\n", logId, request.GetAction(), request.ToJsonString(), err.Error()) @@ -188,6 +195,14 @@ func resourceTencentCloudEipCreate(d *schema.ResourceData, meta interface{}) err } } + if tags := getTags(d, "tags"); len(tags) > 0 { + resourceName := BuildTagResourceName(VPC_SERVICE_TYPE, EIP_RESOURCE_TYPE, region, eipId) + if err := tagService.ModifyTags(ctx, resourceName, tags, nil); err != nil { + log.Printf("[CRITAL]%s set eip tags failed: %+v", logId, err) + return err + } + } + return resourceTencentCloudEipRead(d, meta) } @@ -196,9 +211,11 @@ func resourceTencentCloudEipRead(d *schema.ResourceData, meta interface{}) error logId := getLogId(contextNil) ctx := context.WithValue(context.TODO(), "logId", logId) - vpcService := VpcService{ - client: meta.(*TencentCloudClient).apiV3Conn, - } + + client := meta.(*TencentCloudClient).apiV3Conn + vpcService := VpcService{client: client} + tagService := TagService{client: client} + region := client.Region eipId := d.Id() var eip *vpc.Address @@ -218,10 +235,17 @@ func resourceTencentCloudEipRead(d *schema.ResourceData, meta interface{}) error return nil } + tags, err := tagService.DescribeResourceTags(ctx, VPC_SERVICE_TYPE, EIP_RESOURCE_TYPE, region, eipId) + if err != nil { + log.Printf("[CRITAL]%s describe eip tags failed: %+v", logId, err) + return err + } + d.Set("name", eip.AddressName) d.Set("type", eip.AddressType) d.Set("public_ip", eip.AddressIp) d.Set("status", eip.AddressStatus) + d.Set("tags", tags) return nil } @@ -230,18 +254,38 @@ func resourceTencentCloudEipUpdate(d *schema.ResourceData, meta interface{}) err logId := getLogId(contextNil) ctx := context.WithValue(context.TODO(), "logId", logId) - vpcService := VpcService{ - client: meta.(*TencentCloudClient).apiV3Conn, - } + + client := meta.(*TencentCloudClient).apiV3Conn + vpcService := VpcService{client: client} + tagService := TagService{client: client} + region := client.Region eipId := d.Id() + + d.Partial(true) + if d.HasChange("name") { name := d.Get("name").(string) err := vpcService.ModifyEipName(ctx, eipId, name) if err != nil { return err } + + d.SetPartial("name") } + + if d.HasChange("tags") { + oldTags, newTags := d.GetChange("tags") + replaceTags, deleteTags := diffTags(oldTags.(map[string]interface{}), newTags.(map[string]interface{})) + resourceName := BuildTagResourceName(VPC_SERVICE_TYPE, EIP_RESOURCE_TYPE, region, eipId) + + if err := tagService.ModifyTags(ctx, resourceName, replaceTags, deleteTags); err != nil { + log.Printf("[CRITAL]%s update eip tags failed: %+v", logId, err) + return err + } + d.SetPartial("tags") + } + return resourceTencentCloudEipRead(d, meta) } diff --git a/tencentcloud/resource_tc_eip_test.go b/tencentcloud/resource_tc_eip_test.go index bd32c67767..aec2246f47 100644 --- a/tencentcloud/resource_tc_eip_test.go +++ b/tencentcloud/resource_tc_eip_test.go @@ -33,6 +33,25 @@ func TestAccTencentCloudEip_basic(t *testing.T) { resource.TestCheckResourceAttrSet("tencentcloud_eip.foo", "public_ip"), ), }, + { + Config: testAccEipBasicWithTags, + Check: resource.ComposeTestCheckFunc( + testAccCheckEipExists("tencentcloud_eip.foo"), + resource.TestCheckResourceAttr("tencentcloud_eip.foo", "tags.test", "test"), + resource.TestCheckResourceAttr("tencentcloud_eip.foo", "status", "UNBIND"), + resource.TestCheckResourceAttrSet("tencentcloud_eip.foo", "public_ip"), + ), + }, + { + Config: testAccEipBasicWithNewTags, + Check: resource.ComposeTestCheckFunc( + testAccCheckEipExists("tencentcloud_eip.foo"), + resource.TestCheckNoResourceAttr("tencentcloud_eip.foo", "tags.test"), + resource.TestCheckResourceAttr("tencentcloud_eip.foo", "tags.abc", "abc"), + resource.TestCheckResourceAttr("tencentcloud_eip.foo", "status", "UNBIND"), + resource.TestCheckResourceAttrSet("tencentcloud_eip.foo", "public_ip"), + ), + }, { Config: testAccEipBasicWithoutName, Check: resource.ComposeTestCheckFunc( @@ -182,6 +201,26 @@ resource "tencentcloud_eip" "foo" { } ` +const testAccEipBasicWithTags = ` +resource "tencentcloud_eip" "foo" { + name = "new_name" + + tags = { + "test" = "test" + } +} +` + +const testAccEipBasicWithNewTags = ` +resource "tencentcloud_eip" "foo" { + name = "new_name" + + tags = { + "abc" = "abc" + } +} +` + const testAccEipBasicWithoutName = ` resource "tencentcloud_eip" "bar" { } diff --git a/website/docs/d/eips.html.markdown b/website/docs/d/eips.html.markdown index b480d8d9d3..428a982ee7 100644 --- a/website/docs/d/eips.html.markdown +++ b/website/docs/d/eips.html.markdown @@ -26,6 +26,7 @@ The following arguments are supported: * `eip_name` - (Optional) Name of the eip to be queried. * `public_ip` - (Optional) The elastic ip address. * `result_output_file` - (Optional) Used to save results. +* `tags` - (Optional) The tags of eip. ## Attributes Reference @@ -40,5 +41,6 @@ In addition to all arguments above, the following attributes are exported: * `instance_id` - The instance id to bind with the eip. * `public_ip` - The elastic ip address. * `status` - The eip current status. + * `tags` - Tags of the eip. diff --git a/website/docs/r/eip.html.markdown b/website/docs/r/eip.html.markdown index b08f6465a0..068c4757ce 100644 --- a/website/docs/r/eip.html.markdown +++ b/website/docs/r/eip.html.markdown @@ -28,6 +28,7 @@ The following arguments are supported: * `internet_max_bandwidth_out` - (Optional, ForceNew) The bandwidth limit of eip, unit is Mbps, and the range is 1-1000. * `internet_service_provider` - (Optional, ForceNew) Internet service provider of eip, and available values include `BGP`, `CMCC`, `CTCC` and `CUCC`. * `name` - (Optional) The name of eip. +* `tags` - (Optional) The tags of eip. * `type` - (Optional, ForceNew) The type of eip, and available values include `EIP` and `AnycastEIP`. Default is `EIP`. ## Attributes Reference