Skip to content

Commit b56e852

Browse files
committed
fix: Dont expunge all attached data volumes on machine destroy
If csMachine.Spec.DiskOffering is nil, skip looking up data volumes attached to VM for expunging If csMachine.Spec.DiskOffering is not nil, only add data volumes for expunging that are named 'DATA-<something>'
1 parent 116b93c commit b56e852

File tree

2 files changed

+54
-6
lines changed

2 files changed

+54
-6
lines changed

pkg/cloud/instance.go

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -427,12 +427,15 @@ func findVirtualMachine(
427427
func (c *client) DestroyVMInstance(csMachine *infrav1.CloudStackMachine) error {
428428
// Attempt deletion regardless of machine state.
429429
p := c.csAsync.VirtualMachine.NewDestroyVirtualMachineParams(*csMachine.Spec.InstanceID)
430-
volIDs, err := c.listVMInstanceDatadiskVolumeIDs(*csMachine.Spec.InstanceID)
431-
if err != nil {
432-
return err
430+
// If an additional data disk was requested on creation of this machine, find it and expunge it as well.
431+
if csMachine.Spec.DiskOffering != nil {
432+
volIDs, err := c.listVMInstanceDatadiskVolumeIDs(*csMachine.Spec.InstanceID)
433+
if err != nil {
434+
return err
435+
}
436+
setArrayIfNotEmpty(volIDs, p.SetVolumeids)
433437
}
434438
p.SetExpunge(true)
435-
setArrayIfNotEmpty(volIDs, p.SetVolumeids)
436439
if _, err := c.csAsync.VirtualMachine.DestroyVirtualMachine(p); err != nil &&
437440
strings.Contains(strings.ToLower(err.Error()), "unable to find uuid for id") {
438441
// VM doesn't exist. Success...
@@ -462,6 +465,17 @@ func (c *client) listVMInstanceDatadiskVolumeIDs(instanceID string) ([]string, e
462465
p.SetVirtualmachineid(instanceID)
463466
// VM root volumes are destroyed automatically, no need to explicitly include
464467
p.SetType("DATADISK")
468+
// This makes extra sure that data disks created/attached by something other than CloudStack itself
469+
// are not expunged. Right now this is the only way to sort of distinguish a data volume automatically
470+
// created on deployVirtualMachine (by passing diskoffering ID or name) from a volume attached at a later
471+
// stage (assuming those aren't called 'DATA-<something>').
472+
//
473+
// This f.e. prevents data volumes backing PVC's from the CloudStack CSI driver from being expunged.
474+
//
475+
// See:
476+
// - https://github.com/apache/cloudstack/blob/b69cc0272d48f0aea7353627d760c27c284dad84/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java#L524
477+
// - https://github.com/kubernetes-sigs/cluster-api-provider-cloudstack/issues/389
478+
p.SetKeyword("DATA-")
465479

466480
listVOLResp, err := c.csAsync.Volume.ListVolumes(p)
467481
if err != nil {

pkg/cloud/instance_test.go

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,9 @@ package cloud_test
1919
import (
2020
"encoding/base64"
2121
"fmt"
22-
2322
"github.com/apache/cloudstack-go/v2/cloudstack"
2423
"github.com/golang/mock/gomock"
2524
. "github.com/onsi/ginkgo/v2"
26-
2725
infrav1 "sigs.k8s.io/cluster-api-provider-cloudstack/api/v1beta3"
2826
"sigs.k8s.io/cluster-api-provider-cloudstack/pkg/cloud"
2927
dummies "sigs.k8s.io/cluster-api-provider-cloudstack/test/dummies/v1beta3"
@@ -750,6 +748,7 @@ var _ = Describe("Instance", func() {
750748
It("calls destroy and finds VM doesn't exist, then returns nil", func() {
751749
listVolumesParams.SetVirtualmachineid(*dummies.CSMachine1.Spec.InstanceID)
752750
listVolumesParams.SetType("DATADISK")
751+
listVolumesParams.SetKeyword("DATA-")
753752
vms.EXPECT().NewDestroyVirtualMachineParams(*dummies.CSMachine1.Spec.InstanceID).
754753
Return(expungeDestroyParams)
755754
vms.EXPECT().DestroyVirtualMachine(expungeDestroyParams).Return(nil, fmt.Errorf("unable to find uuid for id"))
@@ -762,6 +761,7 @@ var _ = Describe("Instance", func() {
762761
It("calls destroy and returns unexpected error", func() {
763762
listVolumesParams.SetVirtualmachineid(*dummies.CSMachine1.Spec.InstanceID)
764763
listVolumesParams.SetType("DATADISK")
764+
listVolumesParams.SetKeyword("DATA-")
765765
vms.EXPECT().NewDestroyVirtualMachineParams(*dummies.CSMachine1.Spec.InstanceID).
766766
Return(expungeDestroyParams)
767767
vms.EXPECT().DestroyVirtualMachine(expungeDestroyParams).Return(nil, fmt.Errorf("new error"))
@@ -773,6 +773,7 @@ var _ = Describe("Instance", func() {
773773
It("calls destroy without error but cannot resolve VM after", func() {
774774
listVolumesParams.SetVirtualmachineid(*dummies.CSMachine1.Spec.InstanceID)
775775
listVolumesParams.SetType("DATADISK")
776+
listVolumesParams.SetKeyword("DATA-")
776777
vms.EXPECT().NewDestroyVirtualMachineParams(*dummies.CSMachine1.Spec.InstanceID).
777778
Return(expungeDestroyParams)
778779
vms.EXPECT().DestroyVirtualMachine(expungeDestroyParams).Return(nil, nil)
@@ -787,6 +788,7 @@ var _ = Describe("Instance", func() {
787788
It("calls destroy without error and identifies it as expunging", func() {
788789
listVolumesParams.SetVirtualmachineid(*dummies.CSMachine1.Spec.InstanceID)
789790
listVolumesParams.SetType("DATADISK")
791+
listVolumesParams.SetKeyword("DATA-")
790792
vms.EXPECT().NewDestroyVirtualMachineParams(*dummies.CSMachine1.Spec.InstanceID).
791793
Return(expungeDestroyParams)
792794
vms.EXPECT().DestroyVirtualMachine(expungeDestroyParams).Return(nil, nil)
@@ -803,6 +805,7 @@ var _ = Describe("Instance", func() {
803805
It("calls destroy without error and identifies it as expunged", func() {
804806
listVolumesParams.SetVirtualmachineid(*dummies.CSMachine1.Spec.InstanceID)
805807
listVolumesParams.SetType("DATADISK")
808+
listVolumesParams.SetKeyword("DATA-")
806809
vms.EXPECT().NewDestroyVirtualMachineParams(*dummies.CSMachine1.Spec.InstanceID).
807810
Return(expungeDestroyParams)
808811
vms.EXPECT().DestroyVirtualMachine(expungeDestroyParams).Return(nil, nil)
@@ -819,6 +822,7 @@ var _ = Describe("Instance", func() {
819822
It("calls destroy without error and identifies it as stopping", func() {
820823
listVolumesParams.SetVirtualmachineid(*dummies.CSMachine1.Spec.InstanceID)
821824
listVolumesParams.SetType("DATADISK")
825+
listVolumesParams.SetKeyword("DATA-")
822826
vms.EXPECT().NewDestroyVirtualMachineParams(*dummies.CSMachine1.Spec.InstanceID).
823827
Return(expungeDestroyParams)
824828
vms.EXPECT().DestroyVirtualMachine(expungeDestroyParams).Return(nil, nil)
@@ -830,5 +834,35 @@ var _ = Describe("Instance", func() {
830834
}, 1, nil)
831835
Ω(client.DestroyVMInstance(dummies.CSMachine1)).Should(MatchError("VM deletion in progress"))
832836
})
837+
838+
It("calls destroy without error on a VM without additional diskoffering and does not search for data disks", func() {
839+
dummies.CSMachine1.Spec.DiskOffering = nil
840+
expungeDestroyParams := &cloudstack.DestroyVirtualMachineParams{}
841+
expungeDestroyParams.SetExpunge(true)
842+
843+
vms.EXPECT().NewDestroyVirtualMachineParams(*dummies.CSMachine1.Spec.InstanceID).
844+
Return(expungeDestroyParams)
845+
vms.EXPECT().DestroyVirtualMachine(gomock.Any()).DoAndReturn(
846+
func(p *cloudstack.DestroyVirtualMachineParams) (*cloudstack.DestroyVirtualMachineResponse, error) {
847+
value, ok := p.GetExpunge()
848+
Ω(value).To(BeTrue())
849+
Ω(ok).To(BeTrue())
850+
851+
ids, ok := p.GetVolumeids()
852+
Ω(len(ids)).To(Equal(0))
853+
Ω(ok).To(BeFalse())
854+
855+
return nil, nil
856+
})
857+
vs.EXPECT().NewListVolumesParams().Times(0)
858+
vs.EXPECT().ListVolumes(gomock.Any()).Times(0)
859+
vms.EXPECT().GetVirtualMachinesMetricByID(*dummies.CSMachine1.Spec.InstanceID).
860+
Return(&cloudstack.VirtualMachinesMetric{
861+
State: "Expunged",
862+
}, 1, nil)
863+
Ω(dummies.CSMachine1.Spec.DiskOffering).Should(BeNil())
864+
Ω(client.DestroyVMInstance(dummies.CSMachine1)).
865+
Should(Succeed())
866+
})
833867
})
834868
})

0 commit comments

Comments
 (0)