Skip to content

Commit 95ee83c

Browse files
authored
add exclude (#1138)
1 parent 0b4010d commit 95ee83c

File tree

2 files changed

+259
-10
lines changed

2 files changed

+259
-10
lines changed

tencentcloud/resource_tc_instance_set.go

Lines changed: 257 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ func resourceTencentCloudInstanceSet() *schema.Resource {
9191
Timeouts: &schema.ResourceTimeout{
9292
Create: schema.DefaultTimeout(600 * time.Second),
9393
Read: schema.DefaultTimeout(600 * time.Second),
94+
Update: schema.DefaultTimeout(600 * time.Second),
9495
Delete: schema.DefaultTimeout(600 * time.Second),
9596
},
9697

@@ -110,9 +111,16 @@ func resourceTencentCloudInstanceSet() *schema.Resource {
110111
"instance_count": {
111112
Type: schema.TypeInt,
112113
Optional: true,
113-
ForceNew: true,
114114
Description: "The number of instances to be purchased. Value range:[1,100]; default value: 1.",
115115
},
116+
"exclude_instance_ids": {
117+
Type: schema.TypeSet,
118+
Optional: true,
119+
Elem: &schema.Schema{
120+
Type: schema.TypeString,
121+
},
122+
Description: "instance ids list to exclude.",
123+
},
116124
"instance_name": {
117125
Type: schema.TypeString,
118126
Optional: true,
@@ -361,10 +369,24 @@ func resourceTencentCloudInstanceSetRead(d *schema.ResourceData, meta interface{
361369
}
362370
}
363371

364-
func resourceTencentCloudInstanceSetUpdate(d *schema.ResourceData, meta interface{}) (err error) {
365-
defer logElapsed("resource.tencentcloud_instance_set.update")()
372+
func resourceTencentCloudInstanceSetUpdate(d *schema.ResourceData, meta interface{}) error {
373+
doneChan := make(chan struct{}, 1)
374+
rspChan := make(chan error, 1)
375+
376+
timeout := d.Timeout(schema.TimeoutUpdate)
377+
378+
go func(d *schema.ResourceData, meta interface{}) {
379+
e := doResourceTencentCloudInstanceSetUpdate(d, meta)
380+
doneChan <- struct{}{}
381+
rspChan <- e
382+
}(d, meta)
366383

367-
return fmt.Errorf("`resource_instance_set` do not support change now.")
384+
select {
385+
case <-doneChan:
386+
return <-rspChan
387+
case <-time.After(timeout):
388+
return fmt.Errorf("Do cvm instance set update action timeout, current timeout :[%.3f]s", timeout.Seconds())
389+
}
368390
}
369391

370392
func resourceTencentCloudInstanceSetDelete(d *schema.ResourceData, meta interface{}) error {
@@ -559,15 +581,18 @@ func doResourceTencentCloudInstanceSetRead(d *schema.ResourceData, meta interfac
559581
logId := getLogId(contextNil)
560582
ctx := context.WithValue(context.TODO(), logIdKey, logId)
561583

562-
instanceId := d.Id()
584+
var instanceSetIds []*string
585+
if v, ok := d.GetOk("instance_ids"); ok {
586+
instanceSetIds = helper.InterfacesStringsPoint(v.([]interface{}))
587+
}
563588

564589
client := meta.(*TencentCloudClient).apiV3Conn
565590
cvmService := CvmService{
566591
client: client,
567592
}
568593
var instanceSet []*cvm.Instance
569594
var errRet error
570-
instanceSet, errRet = cvmService.DescribeInstanceSetByIds(ctx, instanceId)
595+
instanceSet, errRet = cvmService.DescribeInstanceSetByIds(ctx, helper.StrListToStr(instanceSetIds))
571596
if errRet != nil {
572597
return errRet
573598
}
@@ -579,7 +604,6 @@ func doResourceTencentCloudInstanceSetRead(d *schema.ResourceData, meta interfac
579604

580605
instance := instanceSet[0]
581606

582-
_ = d.Set("instance_count", len(instanceSet))
583607
_ = d.Set("image_id", instance.ImageId)
584608
_ = d.Set("availability_zone", instance.Placement.Zone)
585609
_ = d.Set("instance_name", d.Get("instance_name"))
@@ -621,21 +645,245 @@ func doResourceTencentCloudInstanceSetRead(d *schema.ResourceData, meta interfac
621645
return nil
622646
}
623647

648+
func doResourceTencentCloudInstanceSetUpdate(d *schema.ResourceData, meta interface{}) (err error) {
649+
defer logElapsed("resource.tencentcloud_instance_set.update")()
650+
651+
logId := getLogId(contextNil)
652+
ctx := context.WithValue(context.TODO(), logIdKey, logId)
653+
654+
cvmService := CvmService{
655+
client: meta.(*TencentCloudClient).apiV3Conn,
656+
}
657+
658+
if d.HasChange("exclude_instance_ids") {
659+
old, new := d.GetChange("exclude_instance_ids")
660+
olds := old.(*schema.Set)
661+
news := new.(*schema.Set)
662+
needExclude := news.Difference(olds).List()
663+
needCreate := olds.Difference(news).List()
664+
665+
// need delete instance
666+
if len(needExclude) > 0 {
667+
instanceSetIds := helper.StrListToStr(helper.InterfacesStringsPoint(needExclude))
668+
err := resource.Retry(writeRetryTimeout, func() *resource.RetryError {
669+
errRet := cvmService.DeleteInstanceSetByIds(ctx, instanceSetIds)
670+
if errRet != nil {
671+
log.Printf("[CRITAL][first delete]%s api[%s] fail, reason[%s]\n",
672+
logId, "delete", errRet.Error())
673+
e, ok := errRet.(*sdkErrors.TencentCloudSDKError)
674+
if ok && IsContains(CVM_RETRYABLE_ERROR, e.Code) {
675+
time.Sleep(1 * time.Second) // 需要重试的话,等待1s进行重试
676+
return resource.RetryableError(fmt.Errorf("[first delete]cvm delete error: %s, retrying", e.Error()))
677+
}
678+
return resource.NonRetryableError(errRet)
679+
}
680+
return nil
681+
})
682+
if err != nil {
683+
return err
684+
}
685+
}
686+
687+
createInstanceIds := make([]*string, 0)
688+
// need create instance
689+
if len(needCreate) > 0 {
690+
instanceCount := len(needCreate)
691+
request := cvm.NewRunInstancesRequest()
692+
request.ImageId = helper.String(d.Get("image_id").(string))
693+
request.InstanceCount = helper.Int64(int64(instanceCount))
694+
request.Placement = &cvm.Placement{
695+
Zone: helper.String(d.Get("availability_zone").(string)),
696+
}
697+
if v, ok := d.GetOk("project_id"); ok {
698+
projectId := int64(v.(int))
699+
request.Placement.ProjectId = &projectId
700+
}
701+
if v, ok := d.GetOk("instance_name"); ok {
702+
request.InstanceName = helper.String(v.(string))
703+
}
704+
705+
if v, ok := d.GetOk("instance_type"); ok {
706+
request.InstanceType = helper.String(v.(string))
707+
}
708+
if v, ok := d.GetOk("hostname"); ok {
709+
request.HostName = helper.String(v.(string))
710+
}
711+
if v, ok := d.GetOk("cam_role_name"); ok {
712+
request.CamRoleName = helper.String(v.(string))
713+
}
714+
715+
if v, ok := d.GetOk("instance_charge_type"); ok {
716+
instanceChargeType := v.(string)
717+
request.InstanceChargeType = &instanceChargeType
718+
}
719+
if v, ok := d.GetOk("placement_group_id"); ok {
720+
request.DisasterRecoverGroupIds = []*string{helper.String(v.(string))}
721+
}
722+
723+
// network
724+
request.InternetAccessible = &cvm.InternetAccessible{}
725+
if v, ok := d.GetOk("internet_charge_type"); ok {
726+
request.InternetAccessible.InternetChargeType = helper.String(v.(string))
727+
}
728+
if v, ok := d.GetOk("internet_max_bandwidth_out"); ok {
729+
maxBandwidthOut := int64(v.(int))
730+
request.InternetAccessible.InternetMaxBandwidthOut = &maxBandwidthOut
731+
}
732+
if v, ok := d.GetOk("bandwidth_package_id"); ok {
733+
request.InternetAccessible.BandwidthPackageId = helper.String(v.(string))
734+
}
735+
if v, ok := d.GetOkExists("allocate_public_ip"); ok {
736+
allocatePublicIp := v.(bool)
737+
request.InternetAccessible.PublicIpAssigned = &allocatePublicIp
738+
}
739+
740+
// vpc
741+
if v, ok := d.GetOk("vpc_id"); ok {
742+
request.VirtualPrivateCloud = &cvm.VirtualPrivateCloud{}
743+
request.VirtualPrivateCloud.VpcId = helper.String(v.(string))
744+
745+
if v, ok = d.GetOk("subnet_id"); ok {
746+
request.VirtualPrivateCloud.SubnetId = helper.String(v.(string))
747+
}
748+
}
749+
750+
if v, ok := d.GetOk("security_groups"); ok {
751+
securityGroups := v.(*schema.Set).List()
752+
request.SecurityGroupIds = make([]*string, 0, len(securityGroups))
753+
for _, securityGroup := range securityGroups {
754+
request.SecurityGroupIds = append(request.SecurityGroupIds, helper.String(securityGroup.(string)))
755+
}
756+
}
757+
758+
// storage
759+
request.SystemDisk = &cvm.SystemDisk{}
760+
if v, ok := d.GetOk("system_disk_type"); ok {
761+
request.SystemDisk.DiskType = helper.String(v.(string))
762+
}
763+
if v, ok := d.GetOk("system_disk_size"); ok {
764+
diskSize := int64(v.(int))
765+
request.SystemDisk.DiskSize = &diskSize
766+
}
767+
768+
// enhanced service
769+
request.EnhancedService = &cvm.EnhancedService{}
770+
if v, ok := d.GetOkExists("disable_security_service"); ok {
771+
securityService := !(v.(bool))
772+
request.EnhancedService.SecurityService = &cvm.RunSecurityServiceEnabled{
773+
Enabled: &securityService,
774+
}
775+
}
776+
if v, ok := d.GetOkExists("disable_monitor_service"); ok {
777+
monitorService := !(v.(bool))
778+
request.EnhancedService.MonitorService = &cvm.RunMonitorServiceEnabled{
779+
Enabled: &monitorService,
780+
}
781+
}
782+
783+
// login
784+
request.LoginSettings = &cvm.LoginSettings{}
785+
if v, ok := d.GetOk("key_name"); ok {
786+
request.LoginSettings.KeyIds = []*string{helper.String(v.(string))}
787+
}
788+
if v, ok := d.GetOk("password"); ok {
789+
request.LoginSettings.Password = helper.String(v.(string))
790+
}
791+
v := d.Get("keep_image_login").(bool)
792+
if v {
793+
request.LoginSettings.KeepImageLogin = helper.String(CVM_IMAGE_LOGIN)
794+
} else {
795+
request.LoginSettings.KeepImageLogin = helper.String(CVM_IMAGE_LOGIN_NOT)
796+
}
797+
798+
if v, ok := d.GetOk("user_data"); ok {
799+
request.UserData = helper.String(v.(string))
800+
}
801+
if v, ok := d.GetOk("user_data_raw"); ok {
802+
userData := base64.StdEncoding.EncodeToString([]byte(v.(string)))
803+
request.UserData = &userData
804+
}
805+
806+
err := resource.Retry(writeRetryTimeout, func() *resource.RetryError {
807+
ratelimit.Check("create")
808+
response, err := meta.(*TencentCloudClient).apiV3Conn.UseCvmClient().RunInstances(request)
809+
if err != nil {
810+
log.Printf("[CRITAL]%s api[%s] fail, request body [%s], reason[%s]\n",
811+
logId, request.GetAction(), request.ToJsonString(), err.Error())
812+
e, ok := err.(*sdkErrors.TencentCloudSDKError)
813+
if ok && IsContains(CVM_RETRYABLE_ERROR, e.Code) {
814+
time.Sleep(1 * time.Second) // 需要重试的话,等待1s进行重试
815+
return resource.RetryableError(fmt.Errorf("cvm create error: %s, retrying", e.Error()))
816+
}
817+
return resource.NonRetryableError(err)
818+
}
819+
log.Printf("[DEBUG]%s api[%s] success, request body [%s], response body [%s]\n",
820+
logId, request.GetAction(), request.ToJsonString(), response.ToJsonString())
821+
if len(response.Response.InstanceIdSet) < instanceCount {
822+
err = fmt.Errorf("number of instances is less than %s", strconv.Itoa(instanceCount))
823+
return resource.NonRetryableError(err)
824+
}
825+
createInstanceIds = response.Response.InstanceIdSet
826+
827+
return nil
828+
})
829+
if err != nil {
830+
return err
831+
}
832+
833+
}
834+
835+
var instanceSetIds []*string
836+
if v, ok := d.GetOk("instance_ids"); ok {
837+
instanceSetIds = helper.InterfacesStringsPoint(v.([]interface{}))
838+
}
839+
840+
var newInstanceSetIds []*string
841+
for _, v := range instanceSetIds {
842+
ins := v
843+
noEqual := true
844+
for _, u := range needExclude {
845+
if *ins == u.(string) {
846+
noEqual = false
847+
}
848+
}
849+
if noEqual {
850+
newInstanceSetIds = append(newInstanceSetIds, ins)
851+
}
852+
}
853+
854+
if len(needCreate) > 0 {
855+
for _, v := range createInstanceIds {
856+
ins := v
857+
newInstanceSetIds = append(newInstanceSetIds, ins)
858+
}
859+
}
860+
_ = d.Set("instance_ids", newInstanceSetIds)
861+
862+
}
863+
864+
return nil
865+
}
866+
624867
func doResourceTencentCloudInstanceSetDelete(d *schema.ResourceData, meta interface{}) error {
625868
defer logElapsed("resource.tencentcloud_instance_set.delete")()
626869

627870
logId := getLogId(contextNil)
628871
ctx := context.WithValue(context.TODO(), logIdKey, logId)
629872

630-
instanceSetIds := d.Id()
873+
//instanceSetIds := d.Id()
631874

632875
cvmService := CvmService{
633876
client: meta.(*TencentCloudClient).apiV3Conn,
634877
}
635878

879+
var instanceSetIds []*string
880+
if v, ok := d.GetOk("instance_ids"); ok {
881+
instanceSetIds = helper.InterfacesStringsPoint(v.([]interface{}))
882+
}
883+
636884
// delete
637885
err := resource.Retry(writeRetryTimeout, func() *resource.RetryError {
638-
errRet := cvmService.DeleteInstanceSetByIds(ctx, instanceSetIds)
886+
errRet := cvmService.DeleteInstanceSetByIds(ctx, helper.StrListToStr(instanceSetIds))
639887
if errRet != nil {
640888
log.Printf("[CRITAL][first delete]%s api[%s] fail, reason[%s]\n",
641889
logId, "delete", errRet.Error())

website/docs/r/instance_set.html.markdown

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,9 +84,10 @@ The following arguments are supported:
8484
* `cam_role_name` - (Optional, ForceNew) CAM role name authorized to access.
8585
* `disable_monitor_service` - (Optional) Disable enhance service for monitor, it is enabled by default. When this options is set, monitor agent won't be installed. Modifying will cause the instance reset.
8686
* `disable_security_service` - (Optional) Disable enhance service for security, it is enabled by default. When this options is set, security agent won't be installed. Modifying will cause the instance reset.
87+
* `exclude_instance_ids` - (Optional) instance ids list to exclude.
8788
* `hostname` - (Optional) The hostname of the instance. Windows instance: The name should be a combination of 2 to 15 characters comprised of letters (case insensitive), numbers, and hyphens (-). Period (.) is not supported, and the name cannot be a string of pure numbers. Other types (such as Linux) of instances: The name should be a combination of 2 to 60 characters, supporting multiple periods (.). The piece between two periods is composed of letters (case insensitive), numbers, and hyphens (-). Modifying will cause the instance reset.
8889
* `instance_charge_type` - (Optional) The charge type of instance. Only support `POSTPAID_BY_HOUR`.
89-
* `instance_count` - (Optional, ForceNew) The number of instances to be purchased. Value range:[1,100]; default value: 1.
90+
* `instance_count` - (Optional) The number of instances to be purchased. Value range:[1,100]; default value: 1.
9091
* `instance_name` - (Optional) The name of the instance. The max length of instance_name is 60, and default value is `Terraform-CVM-Instance`.
9192
* `instance_type` - (Optional) The type of the instance.
9293
* `internet_charge_type` - (Optional, ForceNew) Internet charge type of the instance, Valid values are `BANDWIDTH_PREPAID`, `TRAFFIC_POSTPAID_BY_HOUR`, `BANDWIDTH_POSTPAID_BY_HOUR` and `BANDWIDTH_PACKAGE`. This value does not need to be set when `allocate_public_ip` is false.

0 commit comments

Comments
 (0)