diff --git a/.changelog/2895.txt b/.changelog/2895.txt new file mode 100644 index 0000000000..09609d5520 --- /dev/null +++ b/.changelog/2895.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +resource/tencentcloud_nat_gateway: adapt to scenarios where `nat_product_version` is 2 +``` \ No newline at end of file diff --git a/tencentcloud/services/vpc/resource_tc_nat_gateway.go b/tencentcloud/services/vpc/resource_tc_nat_gateway.go index bcf3cdbc47..571e560bd5 100644 --- a/tencentcloud/services/vpc/resource_tc_nat_gateway.go +++ b/tencentcloud/services/vpc/resource_tc_nat_gateway.go @@ -43,15 +43,16 @@ func ResourceTencentCloudNatGateway() *schema.Resource { "max_concurrent": { Type: schema.TypeInt, Optional: true, - Default: 1000000, - ValidateFunc: tccommon.ValidateAllowedIntValue([]int{1000000, 3000000, 10000000}), - Description: "The upper limit of concurrent connection of NAT gateway. Valid values: `1000000`, `3000000`, `10000000`. Default is `1000000`.", + Computed: true, + ValidateFunc: tccommon.ValidateAllowedIntValue([]int{1000000, 3000000, 10000000, 2000000}), + Description: "The upper limit of concurrent connection of NAT gateway. Valid values: `1000000`, `3000000`, `10000000`. Default is `1000000`. When the value of parameter `nat_product_version` is 2, which is the standard NAT type, this parameter does not need to be filled in and defaults to `2000000`.", }, "bandwidth": { - Type: schema.TypeInt, - Optional: true, - Default: 100, - Description: "The maximum public network output bandwidth of NAT gateway (unit: Mbps). Valid values: `20`, `50`, `100`, `200`, `500`, `1000`, `2000`, `5000`. Default is 100.", + Type: schema.TypeInt, + Optional: true, + Computed: true, + ValidateFunc: tccommon.ValidateAllowedIntValue([]int{20, 50, 100, 200, 500, 1000, 2000, 5000}), + Description: "The maximum public network output bandwidth of NAT gateway (unit: Mbps). Valid values: `20`, `50`, `100`, `200`, `500`, `1000`, `2000`, `5000`. Default is `100`. When the value of parameter `nat_product_version` is 2, which is the standard NAT type, this parameter does not need to be filled in and defaults to `5000`.", }, "assigned_eip_set": { Type: schema.TypeSet, @@ -78,11 +79,12 @@ func ResourceTencentCloudNatGateway() *schema.Resource { Description: "Subnet of NAT.", }, "nat_product_version": { - Type: schema.TypeInt, - Optional: true, - Computed: true, - ForceNew: true, - Description: "1: traditional NAT, 2: standard NAT, default value is 1.", + Type: schema.TypeInt, + Optional: true, + Computed: true, + ForceNew: true, + ValidateFunc: tccommon.ValidateAllowedIntValue([]int{1, 2}), + Description: "1: traditional NAT, 2: standard NAT, default value is 1.", }, "tags": { Type: schema.TypeMap, @@ -102,20 +104,51 @@ func ResourceTencentCloudNatGateway() *schema.Resource { func resourceTencentCloudNatGatewayCreate(d *schema.ResourceData, meta interface{}) error { defer tccommon.LogElapsed("resource.tencentcloud_nat_gateway.create")() - logId := tccommon.GetLogId(tccommon.ContextNil) - request := vpc.NewCreateNatGatewayRequest() - vpcId := d.Get("vpc_id").(string) - natGatewayName := d.Get("name").(string) - request.VpcId = &vpcId - request.NatGatewayName = &natGatewayName - //test default value - bandwidth := uint64(d.Get("bandwidth").(int)) - request.InternetMaxBandwidthOut = &bandwidth - maxConcurrent := uint64(d.Get("max_concurrent").(int)) - request.MaxConcurrentConnection = &maxConcurrent + var ( + logId = tccommon.GetLogId(tccommon.ContextNil) + ctx = context.WithValue(context.TODO(), tccommon.LogIdKey, logId) + request = vpc.NewCreateNatGatewayRequest() + maxConcurrentConnection int + internetMaxBandwidthOut int + hasMaxConcurrentConnection bool + hasInternetMaxBandwidthOut bool + ) + + if v, ok := d.GetOkExists("max_concurrent"); ok { + maxConcurrentConnection = v.(int) + hasMaxConcurrentConnection = true + request.MaxConcurrentConnection = helper.IntUint64(maxConcurrentConnection) + } + + if v, ok := d.GetOkExists("bandwidth"); ok { + internetMaxBandwidthOut = v.(int) + hasInternetMaxBandwidthOut = true + request.InternetMaxBandwidthOut = helper.IntUint64(internetMaxBandwidthOut) + } + + if v, ok := d.GetOkExists("nat_product_version"); ok { + request.NatProductVersion = helper.IntUint64(v.(int)) + if v.(int) == 2 { + if hasMaxConcurrentConnection && maxConcurrentConnection != 2000000 { + return fmt.Errorf("If `nat_product_version` is 2, `max_concurrent` can only be set to `2000000` or not set at all.") + } + + if hasInternetMaxBandwidthOut && internetMaxBandwidthOut != 5000 { + return fmt.Errorf("If `nat_product_version` is 2, `bandwidth` can only be set to `5000` or not set at all.") + } + } + } + + if v, ok := d.GetOk("vpc_id"); ok { + request.VpcId = helper.String(v.(string)) + } + + if v, ok := d.GetOk("name"); ok { + request.NatGatewayName = helper.String(v.(string)) + } + if v, ok := d.GetOk("assigned_eip_set"); ok { eipSet := v.(*schema.Set).List() - //set request public ips for i := range eipSet { publicIp := eipSet[i].(string) request.PublicIpAddresses = append(request.PublicIpAddresses, &publicIp) @@ -130,16 +163,13 @@ func resourceTencentCloudNatGatewayCreate(d *schema.ResourceData, meta interface request.SubnetId = helper.String(v.(string)) } - if v, ok := d.GetOkExists("nat_product_version"); ok { - request.NatProductVersion = helper.IntUint64(v.(int)) - } - if v := helper.GetTags(d, "tags"); len(v) > 0 { for tagKey, tagValue := range v { tag := vpc.Tag{ Key: helper.String(tagKey), Value: helper.String(tagValue), } + request.Tags = append(request.Tags, &tag) } } @@ -152,33 +182,27 @@ func resourceTencentCloudNatGatewayCreate(d *schema.ResourceData, meta interface logId, request.GetAction(), request.ToJsonString(), e.Error()) return tccommon.RetryError(e) } + + if result == nil || result.Response == nil || len(result.Response.NatGatewaySet) < 1 { + e = fmt.Errorf("create NAT gateway failed.") + return resource.NonRetryableError(e) + } + response = result return nil }) + if err != nil { log.Printf("[CRITAL]%s create NAT gateway failed, reason:%s\n", logId, err.Error()) return err } - if len(response.Response.NatGatewaySet) < 1 { - return fmt.Errorf("NAT gateway ID is nil") - } - d.SetId(*response.Response.NatGatewaySet[0].NatGatewayId) - - //cs::vpc:ap-guangzhou:uin/12345:nat/nat-nxxx - ctx := context.WithValue(context.TODO(), tccommon.LogIdKey, logId) - if tags := helper.GetTags(d, "tags"); len(tags) > 0 { - tcClient := meta.(tccommon.ProviderMeta).GetAPIV3Conn() - tagService := svctag.NewTagService(tcClient) - resourceName := tccommon.BuildTagResourceName("vpc", "nat", tcClient.Region, d.Id()) - if err := tagService.ModifyTags(ctx, resourceName, tags, nil); err != nil { - return err - } - } + natGatewayId := *response.Response.NatGatewaySet[0].NatGatewayId + d.SetId(natGatewayId) // must wait for finishing creating NAT statRequest := vpc.NewDescribeNatGatewaysRequest() - statRequest.NatGatewayIds = []*string{response.Response.NatGatewaySet[0].NatGatewayId} + statRequest.NatGatewayIds = []*string{&natGatewayId} err = resource.Retry(tccommon.ReadRetryTimeout, func() *resource.RetryError { result, e := meta.(tccommon.ProviderMeta).GetAPIV3Conn().UseVpcClient().DescribeNatGateways(statRequest) if e != nil { @@ -190,20 +214,33 @@ func resourceTencentCloudNatGatewayCreate(d *schema.ResourceData, meta interface if len(result.Response.NatGatewaySet) != 1 { return resource.NonRetryableError(fmt.Errorf("creating error")) } + //else get stat nat := result.Response.NatGatewaySet[0] stat := *nat.State - if stat == "AVAILABLE" { return nil } + return resource.RetryableError(fmt.Errorf("creating not ready retry")) } }) + if err != nil { log.Printf("[CRITAL]%s create NAT gateway failed, reason:%s\n", logId, err.Error()) return err } + + //cs::vpc:ap-guangzhou:uin/12345:nat/nat-nxxx + if tags := helper.GetTags(d, "tags"); len(tags) > 0 { + tcClient := meta.(tccommon.ProviderMeta).GetAPIV3Conn() + tagService := svctag.NewTagService(tcClient) + resourceName := tccommon.BuildTagResourceName("vpc", "nat", tcClient.Region, d.Id()) + if err := tagService.ModifyTags(ctx, resourceName, tags, nil); err != nil { + return err + } + } + return resourceTencentCloudNatGatewayRead(d, meta) } @@ -269,12 +306,13 @@ func resourceTencentCloudNatGatewayRead(d *schema.ResourceData, meta interface{} func resourceTencentCloudNatGatewayUpdate(d *schema.ResourceData, meta interface{}) error { defer tccommon.LogElapsed("resource.tencentcloud_nat_gateway.update")() - logId := tccommon.GetLogId(tccommon.ContextNil) - ctx := context.WithValue(context.TODO(), tccommon.LogIdKey, logId) - vpcService := VpcService{client: meta.(tccommon.ProviderMeta).GetAPIV3Conn()} + var ( + logId = tccommon.GetLogId(tccommon.ContextNil) + ctx = context.WithValue(context.TODO(), tccommon.LogIdKey, logId) + vpcService = VpcService{client: meta.(tccommon.ProviderMeta).GetAPIV3Conn()} + ) immutableArgs := []string{"zone"} - for _, v := range immutableArgs { if d.HasChange(v) { return fmt.Errorf("argument `%s` cannot be changed", v) @@ -290,12 +328,19 @@ func resourceTencentCloudNatGatewayUpdate(d *schema.ResourceData, meta interface request.NatGatewayName = helper.String(d.Get("name").(string)) changed = true } + if d.HasChange("bandwidth") { bandwidth := d.Get("bandwidth").(int) bandwidth64 := uint64(bandwidth) + if v, ok := d.GetOkExists("nat_product_version"); ok { + if v.(int) == 2 && bandwidth64 != 5000 { + return fmt.Errorf("If `nat_product_version` is 2, `bandwidth` can only be set to `5000` or not set at all.") + } + } request.InternetMaxBandwidthOut = &bandwidth64 changed = true } + if changed { err := resource.Retry(tccommon.ReadRetryTimeout, func() *resource.RetryError { _, e := meta.(tccommon.ProviderMeta).GetAPIV3Conn().UseVpcClient().ModifyNatGatewayAttribute(request) @@ -304,19 +349,27 @@ func resourceTencentCloudNatGatewayUpdate(d *schema.ResourceData, meta interface logId, request.GetAction(), request.ToJsonString(), e.Error()) return tccommon.RetryError(e) } + return nil }) + if err != nil { log.Printf("[CRITAL]%s modify NAT gateway failed, reason:%s\n", logId, err.Error()) return err } } + //max concurrent if d.HasChange("max_concurrent") { concurrentReq := vpc.NewResetNatGatewayConnectionRequest() concurrentReq.NatGatewayId = &natGatewayId concurrent := d.Get("max_concurrent").(int) concurrent64 := uint64(concurrent) + if v, ok := d.GetOkExists("nat_product_version"); ok { + if v.(int) == 2 && concurrent64 != 2000000 { + return fmt.Errorf("If `nat_product_version` is 2, `max_concurrent` can only be set to `2000000` or not set at all.") + } + } concurrentReq.MaxConcurrentConnection = &concurrent64 err := resource.Retry(tccommon.ReadRetryTimeout, func() *resource.RetryError { _, e := meta.(tccommon.ProviderMeta).GetAPIV3Conn().UseVpcClient().ResetNatGatewayConnection(concurrentReq) @@ -327,6 +380,7 @@ func resourceTencentCloudNatGatewayUpdate(d *schema.ResourceData, meta interface } return nil }) + if err != nil { log.Printf("[CRITAL]%s modify NAT gateway concurrent failed, reason:%s\n", logId, err.Error()) return err @@ -334,13 +388,13 @@ func resourceTencentCloudNatGatewayUpdate(d *schema.ResourceData, meta interface } //eip - if d.HasChange("assigned_eip_set") { eipSetLength := 0 if v, ok := d.GetOk("assigned_eip_set"); ok { eipSet := v.(*schema.Set).List() eipSetLength = len(eipSet) } + if d.HasChange("assigned_eip_set") { o, n := d.GetChange("assigned_eip_set") os := o.(*schema.Set) @@ -365,6 +419,7 @@ func resourceTencentCloudNatGatewayUpdate(d *schema.ResourceData, meta interface isIn = true } } + if !isIn { if len(unassignedRequest.PublicIpAddresses)+1 == len(oldEipSet) { backUpOldIp = publicIp @@ -381,11 +436,14 @@ func resourceTencentCloudNatGatewayUpdate(d *schema.ResourceData, meta interface if e != nil { return tccommon.RetryError(e) } + if result != nil && result.Response != nil { response = result.Response } + return nil }) + if err != nil { log.Printf("[CRITAL]%s modify NAT gateway EIP failed, reason:%s\n", logId, err.Error()) return err @@ -414,6 +472,7 @@ func resourceTencentCloudNatGatewayUpdate(d *schema.ResourceData, meta interface isIn = true } } + if !isIn { if len(assignedRequest.PublicIpAddresses)+eipSetLength+1 == NAT_EIP_MAX_LIMIT { backUpNewIp = publicIp @@ -422,6 +481,7 @@ func resourceTencentCloudNatGatewayUpdate(d *schema.ResourceData, meta interface } } } + if len(assignedRequest.PublicIpAddresses) > 0 { var response *vpc.AssociateNatGatewayAddressResponseParams err := resource.Retry(tccommon.ReadRetryTimeout, func() *resource.RetryError { @@ -431,11 +491,14 @@ func resourceTencentCloudNatGatewayUpdate(d *schema.ResourceData, meta interface logId, assignedRequest.GetAction(), assignedRequest.ToJsonString(), e.Error()) return tccommon.RetryError(e) } + if result != nil && result.Response != nil { response = result.Response } + return nil }) + if err != nil { log.Printf("[CRITAL]%s modify NAT gateway EIP failed, reason:%s\n", logId, err.Error()) return err @@ -461,15 +524,19 @@ func resourceTencentCloudNatGatewayUpdate(d *schema.ResourceData, meta interface if e != nil { return tccommon.RetryError(e) } + if result != nil && result.Response != nil { response = result.Response } + return nil }) + if err != nil { log.Printf("[CRITAL]%s modify NAT gateway EIP failed, reason:%s\n", logId, err.Error()) return err } + if response != nil && response.RequestId != nil { err = vpcService.DescribeVpcTaskResult(ctx, response.RequestId) if err != nil { @@ -477,6 +544,7 @@ func resourceTencentCloudNatGatewayUpdate(d *schema.ResourceData, meta interface } } } + if backUpNewIp != "" { //associate one new ip var response *vpc.AssociateNatGatewayAddressResponseParams @@ -490,15 +558,19 @@ func resourceTencentCloudNatGatewayUpdate(d *schema.ResourceData, meta interface logId, assignedRequest.GetAction(), assignedRequest.ToJsonString(), e.Error()) return tccommon.RetryError(e) } + if result != nil && result.Response != nil { response = result.Response } + return nil }) + if err != nil { log.Printf("[CRITAL]%s modify NAT gateway EIP failed, reason:%s\n", logId, err.Error()) return err } + if response != nil && response.RequestId != nil { err = vpcService.DescribeVpcTaskResult(ctx, response.RequestId) if err != nil { @@ -507,14 +579,11 @@ func resourceTencentCloudNatGatewayUpdate(d *schema.ResourceData, meta interface } } } - } if d.HasChange("tags") { - oldValue, newValue := d.GetChange("tags") replaceTags, deleteTags := svctag.DiffTags(oldValue.(map[string]interface{}), newValue.(map[string]interface{})) - tcClient := meta.(tccommon.ProviderMeta).GetAPIV3Conn() tagService := svctag.NewTagService(tcClient) resourceName := tccommon.BuildTagResourceName("vpc", "nat", tcClient.Region, d.Id()) diff --git a/tencentcloud/services/vpc/resource_tc_nat_gateway.md b/tencentcloud/services/vpc/resource_tc_nat_gateway.md index 79f4cdf842..a3b81233f2 100644 --- a/tencentcloud/services/vpc/resource_tc_nat_gateway.md +++ b/tencentcloud/services/vpc/resource_tc_nat_gateway.md @@ -1,5 +1,7 @@ Provides a resource to create a NAT gateway. +~> **NOTE:** If `nat_product_version` is `1`, `max_concurrent` valid values is `1000000`, `3000000`, `10000000`. + Example Usage Create a traditional NAT gateway. @@ -19,16 +21,17 @@ resource "tencentcloud_eip" "eip_example2" { } resource "tencentcloud_nat_gateway" "example" { - name = "tf_example_nat_gateway" - vpc_id = tencentcloud_vpc.vpc.id - bandwidth = 100 - max_concurrent = 1000000 + name = "tf_example_nat_gateway" + vpc_id = tencentcloud_vpc.vpc.id + nat_product_version = 1 + bandwidth = 100 + max_concurrent = 1000000 assigned_eip_set = [ tencentcloud_eip.eip_example1.public_ip, tencentcloud_eip.eip_example2.public_ip, ] tags = { - tf_tag_key = "tf_tag_value" + createBy = "terraform" } } ``` @@ -50,22 +53,15 @@ resource "tencentcloud_eip" "eip_example2" { } resource "tencentcloud_nat_gateway" "example" { - name = "tf_example_nat_gateway" - vpc_id = tencentcloud_vpc.vpc.id + name = "tf_example_nat_gateway" + vpc_id = tencentcloud_vpc.vpc.id + nat_product_version = 2 assigned_eip_set = [ tencentcloud_eip.eip_example1.public_ip, tencentcloud_eip.eip_example2.public_ip, ] - nat_product_version = 2 - tags = { - tf_tag_key = "tf_tag_value" - } - lifecycle { - ignore_changes = [ - // standard nat will set default values for bandwidth and max_concurrent - bandwidth, - max_concurrent, - ] + tags = { + createBy = "terraform" } } ``` @@ -75,5 +71,5 @@ Import NAT gateway can be imported using the id, e.g. ``` -$ terraform import tencentcloud_nat_gateway.foo nat-1asg3t63 -``` \ No newline at end of file +$ terraform import tencentcloud_nat_gateway.example nat-1asg3t63 +``` diff --git a/website/docs/r/nat_gateway.html.markdown b/website/docs/r/nat_gateway.html.markdown index df75fdae4a..70af26c5c2 100644 --- a/website/docs/r/nat_gateway.html.markdown +++ b/website/docs/r/nat_gateway.html.markdown @@ -11,6 +11,8 @@ description: |- Provides a resource to create a NAT gateway. +~> **NOTE:** If `nat_product_version` is `1`, `max_concurrent` valid values is `1000000`, `3000000`, `10000000`. + ## Example Usage ### Create a traditional NAT gateway. @@ -30,16 +32,17 @@ resource "tencentcloud_eip" "eip_example2" { } resource "tencentcloud_nat_gateway" "example" { - name = "tf_example_nat_gateway" - vpc_id = tencentcloud_vpc.vpc.id - bandwidth = 100 - max_concurrent = 1000000 + name = "tf_example_nat_gateway" + vpc_id = tencentcloud_vpc.vpc.id + nat_product_version = 1 + bandwidth = 100 + max_concurrent = 1000000 assigned_eip_set = [ tencentcloud_eip.eip_example1.public_ip, tencentcloud_eip.eip_example2.public_ip, ] tags = { - tf_tag_key = "tf_tag_value" + createBy = "terraform" } } ``` @@ -61,22 +64,15 @@ resource "tencentcloud_eip" "eip_example2" { } resource "tencentcloud_nat_gateway" "example" { - name = "tf_example_nat_gateway" - vpc_id = tencentcloud_vpc.vpc.id + name = "tf_example_nat_gateway" + vpc_id = tencentcloud_vpc.vpc.id + nat_product_version = 2 assigned_eip_set = [ tencentcloud_eip.eip_example1.public_ip, tencentcloud_eip.eip_example2.public_ip, ] - nat_product_version = 2 tags = { - tf_tag_key = "tf_tag_value" - } - lifecycle { - ignore_changes = [ - // standard nat will set default values for bandwidth and max_concurrent - bandwidth, - max_concurrent, - ] + createBy = "terraform" } } ``` @@ -88,8 +84,8 @@ The following arguments are supported: * `assigned_eip_set` - (Required, Set: [`String`]) EIP IP address set bound to the gateway. The value of at least 1 and at most 10. * `name` - (Required, String) Name of the NAT gateway. * `vpc_id` - (Required, String, ForceNew) ID of the vpc. -* `bandwidth` - (Optional, Int) The maximum public network output bandwidth of NAT gateway (unit: Mbps). Valid values: `20`, `50`, `100`, `200`, `500`, `1000`, `2000`, `5000`. Default is 100. -* `max_concurrent` - (Optional, Int) The upper limit of concurrent connection of NAT gateway. Valid values: `1000000`, `3000000`, `10000000`. Default is `1000000`. +* `bandwidth` - (Optional, Int) The maximum public network output bandwidth of NAT gateway (unit: Mbps). Valid values: `20`, `50`, `100`, `200`, `500`, `1000`, `2000`, `5000`. Default is `100`. When the value of parameter `nat_product_version` is 2, which is the standard NAT type, this parameter does not need to be filled in and defaults to `5000`. +* `max_concurrent` - (Optional, Int) The upper limit of concurrent connection of NAT gateway. Valid values: `1000000`, `3000000`, `10000000`. Default is `1000000`. When the value of parameter `nat_product_version` is 2, which is the standard NAT type, this parameter does not need to be filled in and defaults to `2000000`. * `nat_product_version` - (Optional, Int, ForceNew) 1: traditional NAT, 2: standard NAT, default value is 1. * `subnet_id` - (Optional, String, ForceNew) Subnet of NAT. * `tags` - (Optional, Map) The available tags within this NAT gateway. @@ -108,6 +104,6 @@ In addition to all arguments above, the following attributes are exported: NAT gateway can be imported using the id, e.g. ``` -$ terraform import tencentcloud_nat_gateway.foo nat-1asg3t63 +$ terraform import tencentcloud_nat_gateway.example nat-1asg3t63 ```