@@ -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
370392func 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+
624867func 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 ())
0 commit comments