@@ -23,6 +23,7 @@ import (
2323 "fmt"
2424 "log"
2525 "strings"
26+ "time"
2627
2728 "github.com/apache/cloudstack-go/v2/cloudstack"
2829 "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
@@ -93,6 +94,27 @@ func resourceCloudStackAutoScaleVMGroup() *schema.Resource {
9394 Optional : true ,
9495 Description : "an optional field, whether to the display the group to the end user or not" ,
9596 },
97+
98+ "state" : {
99+ Type : schema .TypeString ,
100+ Optional : true ,
101+ Default : "enable" ,
102+ Description : "the state of the autoscale vm group (enable or disable)" ,
103+ ValidateFunc : func (v interface {}, k string ) (ws []string , errors []error ) {
104+ value := v .(string )
105+ if value != "enable" && value != "disable" {
106+ errors = append (errors , fmt .Errorf ("state must be either 'enable' or 'disable'" ))
107+ }
108+ return
109+ },
110+ },
111+
112+ "cleanup" : {
113+ Type : schema .TypeBool ,
114+ Optional : true ,
115+ Default : false ,
116+ Description : "true if all the members of autoscale vm group has to be cleaned up, false otherwise" ,
117+ },
96118 },
97119 }
98120}
@@ -144,6 +166,16 @@ func resourceCloudStackAutoScaleVMGroupCreate(d *schema.ResourceData, meta inter
144166 d .SetId (resp .Id )
145167 log .Printf ("[DEBUG] Autoscale VM group created with ID: %s" , resp .Id )
146168
169+ requestedState := d .Get ("state" ).(string )
170+ if requestedState == "disable" {
171+ log .Printf ("[DEBUG] Disabling autoscale VM group as requested: %s" , resp .Id )
172+ disableParams := cs .AutoScale .NewDisableAutoScaleVmGroupParams (resp .Id )
173+ _ , err = cs .AutoScale .DisableAutoScaleVmGroup (disableParams )
174+ if err != nil {
175+ return fmt .Errorf ("Error disabling autoscale VM group after creation: %s" , err )
176+ }
177+ }
178+
147179 if v , ok := d .GetOk ("name" ); ok {
148180 d .Set ("name" , v .(string ))
149181 }
@@ -170,6 +202,8 @@ func resourceCloudStackAutoScaleVMGroupCreate(d *schema.ResourceData, meta inter
170202 }
171203 d .Set ("scaledown_policy_ids" , scaleDownSet )
172204
205+ d .Set ("state" , requestedState )
206+
173207 return nil
174208}
175209
@@ -199,18 +233,35 @@ func resourceCloudStackAutoScaleVMGroupRead(d *schema.ResourceData, meta interfa
199233 d .Set ("vm_profile_id" , group .Vmprofileid )
200234 d .Set ("display" , group .Fordisplay )
201235
236+ terraformState := "enable"
237+ if strings .ToLower (group .State ) == "disabled" {
238+ terraformState = "disable"
239+ }
240+
241+ currentConfigState := d .Get ("state" ).(string )
242+ log .Printf ("[DEBUG] CloudStack API state: %s, mapped to Terraform state: %s" , group .State , terraformState )
243+ log .Printf ("[DEBUG] Current config state: %s, will set state to: %s" , currentConfigState , terraformState )
244+
245+ d .Set ("state" , terraformState )
246+
202247 scaleUpPolicyIds := schema .NewSet (schema .HashString , []interface {}{})
203248 if group .Scaleuppolicies != nil {
204- for _ , policyId := range group .Scaleuppolicies {
205- scaleUpPolicyIds .Add (policyId )
249+ for _ , policy := range group .Scaleuppolicies {
250+ // Extract the ID from the AutoScalePolicy object
251+ if policy != nil {
252+ scaleUpPolicyIds .Add (policy .Id )
253+ }
206254 }
207255 }
208256 d .Set ("scaleup_policy_ids" , scaleUpPolicyIds )
209257
210258 scaleDownPolicyIds := schema .NewSet (schema .HashString , []interface {}{})
211259 if group .Scaledownpolicies != nil {
212- for _ , policyId := range group .Scaledownpolicies {
213- scaleDownPolicyIds .Add (policyId )
260+ for _ , policy := range group .Scaledownpolicies {
261+ // Extract the ID from the AutoScalePolicy object
262+ if policy != nil {
263+ scaleDownPolicyIds .Add (policy .Id )
264+ }
214265 }
215266 }
216267 d .Set ("scaledown_policy_ids" , scaleDownPolicyIds )
@@ -221,67 +272,137 @@ func resourceCloudStackAutoScaleVMGroupRead(d *schema.ResourceData, meta interfa
221272func resourceCloudStackAutoScaleVMGroupUpdate (d * schema.ResourceData , meta interface {}) error {
222273 cs := meta .(* cloudstack.CloudStackClient )
223274
275+ oldState , newState := d .GetChange ("state" )
276+ log .Printf ("[DEBUG] State in terraform config: %s" , d .Get ("state" ).(string ))
277+ log .Printf ("[DEBUG] Old state: %s, New state: %s" , oldState .(string ), newState .(string ))
278+
279+ changes := []string {}
280+ if d .HasChange ("name" ) {
281+ changes = append (changes , "name" )
282+ }
283+ if d .HasChange ("min_members" ) {
284+ changes = append (changes , "min_members" )
285+ }
286+ if d .HasChange ("max_members" ) {
287+ changes = append (changes , "max_members" )
288+ }
289+ if d .HasChange ("interval" ) {
290+ changes = append (changes , "interval" )
291+ }
292+ if d .HasChange ("scaleup_policy_ids" ) {
293+ changes = append (changes , "scaleup_policy_ids" )
294+ }
295+ if d .HasChange ("scaledown_policy_ids" ) {
296+ changes = append (changes , "scaledown_policy_ids" )
297+ }
298+ if d .HasChange ("display" ) {
299+ changes = append (changes , "display" )
300+ }
301+ if d .HasChange ("state" ) {
302+ changes = append (changes , "state" )
303+ }
304+ log .Printf ("[DEBUG] Detected changes in autoscale VM group: %v" , changes )
305+
224306 if d .HasChange ("name" ) || d .HasChange ("min_members" ) || d .HasChange ("max_members" ) ||
225307 d .HasChange ("interval" ) || d .HasChange ("scaleup_policy_ids" ) ||
226- d .HasChange ("scaledown_policy_ids" ) || d .HasChange ("display" ) {
308+ d .HasChange ("scaledown_policy_ids" ) || d .HasChange ("display" ) || d . HasChange ( "state" ) {
227309
228310 log .Printf ("[DEBUG] Updating autoscale VM group: %s" , d .Id ())
229311
230- p := cs .AutoScale .NewUpdateAutoScaleVmGroupParams (d .Id ())
312+ // Check current state to determine operation order
313+ currentState := "enable"
314+ if oldState , newState := d .GetChange ("state" ); d .HasChange ("state" ) {
315+ currentState = oldState .(string )
316+ log .Printf ("[DEBUG] State change detected: %s -> %s" , currentState , newState .(string ))
317+ }
231318
232- if d .HasChange ("name" ) {
233- if v , ok := d .GetOk ("name" ); ok {
234- p .SetName (v .(string ))
319+ if d .HasChange ("state" ) {
320+ newState := d .Get ("state" ).(string )
321+ if newState == "disable" && currentState == "enable" {
322+ log .Printf ("[DEBUG] Disabling autoscale VM group before other updates: %s" , d .Id ())
323+ disableParams := cs .AutoScale .NewDisableAutoScaleVmGroupParams (d .Id ())
324+ _ , err := cs .AutoScale .DisableAutoScaleVmGroup (disableParams )
325+ if err != nil {
326+ return fmt .Errorf ("Error disabling autoscale VM group: %s" , err )
327+ }
328+ // Wait a moment for disable to take effect
329+ time .Sleep (1 * time .Second )
235330 }
236331 }
237332
238- if d .HasChange ("min_members" ) {
239- minmembers := d .Get ("min_members" ).(int )
240- p .SetMinmembers (minmembers )
241- }
333+ if d .HasChange ("name" ) || d .HasChange ("min_members" ) || d .HasChange ("max_members" ) ||
334+ d .HasChange ("interval" ) || d .HasChange ("scaleup_policy_ids" ) ||
335+ d .HasChange ("scaledown_policy_ids" ) || d .HasChange ("display" ) {
242336
243- if d .HasChange ("max_members" ) {
244- maxmembers := d .Get ("max_members" ).(int )
245- p .SetMaxmembers (maxmembers )
246- }
337+ p := cs .AutoScale .NewUpdateAutoScaleVmGroupParams (d .Id ())
247338
248- if d .HasChange ("interval" ) {
249- if v , ok := d .GetOk ("interval" ); ok {
250- p .SetInterval (v .(int ))
339+ if d .HasChange ("name" ) {
340+ if v , ok := d .GetOk ("name" ); ok {
341+ p .SetName (v .(string ))
342+ }
251343 }
252- }
253344
254- if d .HasChange ("scaleup_policy_ids" ) {
255- scaleUpPolicyIds := []string {}
256- if v , ok := d .GetOk ("scaleup_policy_ids" ); ok {
257- scaleUpSet := v .(* schema.Set )
258- for _ , id := range scaleUpSet .List () {
259- scaleUpPolicyIds = append (scaleUpPolicyIds , id .(string ))
345+ if d .HasChange ("min_members" ) {
346+ minmembers := d .Get ("min_members" ).(int )
347+ p .SetMinmembers (minmembers )
348+ }
349+
350+ if d .HasChange ("max_members" ) {
351+ maxmembers := d .Get ("max_members" ).(int )
352+ p .SetMaxmembers (maxmembers )
353+ }
354+
355+ if d .HasChange ("interval" ) {
356+ if v , ok := d .GetOk ("interval" ); ok {
357+ p .SetInterval (v .(int ))
260358 }
261359 }
262- p .SetScaleuppolicyids (scaleUpPolicyIds )
263- }
264360
265- if d .HasChange ("scaledown_policy_ids" ) {
266- scaleDownPolicyIds := []string {}
267- if v , ok := d .GetOk ("scaledown_policy_ids" ); ok {
268- scaleDownSet := v .(* schema.Set )
269- for _ , id := range scaleDownSet .List () {
270- scaleDownPolicyIds = append (scaleDownPolicyIds , id .(string ))
361+ if d .HasChange ("scaleup_policy_ids" ) {
362+ scaleUpPolicyIds := []string {}
363+ if v , ok := d .GetOk ("scaleup_policy_ids" ); ok {
364+ scaleUpSet := v .(* schema.Set )
365+ for _ , id := range scaleUpSet .List () {
366+ scaleUpPolicyIds = append (scaleUpPolicyIds , id .(string ))
367+ }
271368 }
369+ p .SetScaleuppolicyids (scaleUpPolicyIds )
370+ }
371+
372+ if d .HasChange ("scaledown_policy_ids" ) {
373+ scaleDownPolicyIds := []string {}
374+ if v , ok := d .GetOk ("scaledown_policy_ids" ); ok {
375+ scaleDownSet := v .(* schema.Set )
376+ for _ , id := range scaleDownSet .List () {
377+ scaleDownPolicyIds = append (scaleDownPolicyIds , id .(string ))
378+ }
379+ }
380+ p .SetScaledownpolicyids (scaleDownPolicyIds )
272381 }
273- p .SetScaledownpolicyids (scaleDownPolicyIds )
274- }
275382
276- if d .HasChange ("display" ) {
277- if v , ok := d .GetOk ("display" ); ok {
278- p .SetFordisplay (v .(bool ))
383+ if d .HasChange ("display" ) {
384+ if v , ok := d .GetOk ("display" ); ok {
385+ p .SetFordisplay (v .(bool ))
386+ }
387+ }
388+
389+ log .Printf ("[DEBUG] Applying parameter updates to autoscale VM group: %s" , d .Id ())
390+ _ , err := cs .AutoScale .UpdateAutoScaleVmGroup (p )
391+ if err != nil {
392+ return fmt .Errorf ("Error updating autoscale VM group parameters: %s" , err )
279393 }
280394 }
281395
282- _ , err := cs .AutoScale .UpdateAutoScaleVmGroup (p )
283- if err != nil {
284- return fmt .Errorf ("Error updating autoscale VM group: %s" , err )
396+ if d .HasChange ("state" ) {
397+ newState := d .Get ("state" ).(string )
398+ if newState == "enable" {
399+ log .Printf ("[DEBUG] Enabling autoscale VM group after updates: %s" , d .Id ())
400+ enableParams := cs .AutoScale .NewEnableAutoScaleVmGroupParams (d .Id ())
401+ _ , err := cs .AutoScale .EnableAutoScaleVmGroup (enableParams )
402+ if err != nil {
403+ return fmt .Errorf ("Error enabling autoscale VM group: %s" , err )
404+ }
405+ }
285406 }
286407
287408 log .Printf ("[DEBUG] Autoscale VM group updated successfully: %s" , d .Id ())
@@ -295,8 +416,27 @@ func resourceCloudStackAutoScaleVMGroupDelete(d *schema.ResourceData, meta inter
295416
296417 p := cs .AutoScale .NewDeleteAutoScaleVmGroupParams (d .Id ())
297418
419+ cleanup := d .Get ("cleanup" ).(bool )
420+ p .SetCleanup (cleanup )
421+ log .Printf ("[DEBUG] Deleting autoscale VM group with cleanup=%t" , cleanup )
422+ log .Printf ("[DEBUG] This deletion was triggered by Terraform - check if this should be an update instead" )
423+
424+ log .Printf ("[DEBUG] Disabling autoscale VM group before deletion: %s" , d .Id ())
425+ disableParams := cs .AutoScale .NewDisableAutoScaleVmGroupParams (d .Id ())
426+ _ , err := cs .AutoScale .DisableAutoScaleVmGroup (disableParams )
427+ if err != nil {
428+ if ! strings .Contains (err .Error (), "Invalid parameter id value" ) &&
429+ ! strings .Contains (err .Error (), "entity does not exist" ) &&
430+ ! strings .Contains (err .Error (), "already disabled" ) {
431+ return fmt .Errorf ("Error disabling autoscale VM group: %s" , err )
432+ }
433+ }
434+
435+ time .Sleep (2 * time .Second )
436+ log .Printf ("[DEBUG] Autoscale VM group disabled, proceeding with deletion: %s" , d .Id ())
437+
298438 log .Printf ("[DEBUG] Deleting autoscale VM group: %s" , d .Id ())
299- _ , err : = cs .AutoScale .DeleteAutoScaleVmGroup (p )
439+ _ , err = cs .AutoScale .DeleteAutoScaleVmGroup (p )
300440 if err != nil {
301441 // This is a very poor way to be told the ID does no longer exist :(
302442 if strings .Contains (err .Error (), fmt .Sprintf (
0 commit comments