Skip to content

Commit 3235431

Browse files
authored
Merge pull request vmware-tanzu#916 from bryanv/bryanv/classless-vm-resize
🐛 Handle resize for VMs that were classless
2 parents abbd863 + 1a7296d commit 3235431

File tree

4 files changed

+128
-1
lines changed

4 files changed

+128
-1
lines changed

pkg/providers/vsphere/vmprovider_vm_resize_test.go

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,31 @@ func vmResizeTests() {
212212
})
213213
})
214214

215+
It("Resizes VM that was classless", func() {
216+
newCS := configSpec
217+
newCS.NumCPUs = 42
218+
newCS.MemoryMB = 8192
219+
newVMClass := createVMClass(newCS)
220+
vm.Spec.ClassName = newVMClass.Name
221+
222+
// Simulate what the VM mutation webhook would do by setting the LRA to an empty class name.
223+
delete(vm.Annotations, vmopv1util.LastResizedAnnotationKey)
224+
Expect(vmopv1util.SetLastResizedAnnotationClassName(vm, "")).To(Succeed())
225+
Expect(vm.Annotations).To(HaveKey(vmopv1util.LastResizedAnnotationKey))
226+
227+
vcVM, err := createOrUpdateAndGetVcVM(ctx, vmProvider, vm)
228+
Expect(err).ToNot(HaveOccurred())
229+
230+
var o mo.VirtualMachine
231+
Expect(vcVM.Properties(ctx, vcVM.Reference(), nil, &o)).To(Succeed())
232+
Expect(o.Summary.Runtime.PowerState).To(Equal(vimtypes.VirtualMachinePowerStatePoweredOff))
233+
Expect(o.Config.Hardware.NumCPU).To(BeEquivalentTo(newCS.NumCPUs))
234+
Expect(o.Config.Hardware.MemoryMB).To(BeEquivalentTo(newCS.MemoryMB))
235+
assertExpectedNoReservationFields(o)
236+
237+
assertExpectedResizedClassFields(vm, newVMClass)
238+
})
239+
215240
Context("CPU/Memory Reservations", func() {
216241

217242
Context("No reservations", func() {
@@ -402,6 +427,32 @@ func vmResizeTests() {
402427

403428
assertExpectedResizedClassFields(vm, newVMClass)
404429
})
430+
431+
It("Resizes VM that was classless", func() {
432+
newCS := configSpec
433+
newCS.NumCPUs = 42
434+
newCS.MemoryMB = 8192
435+
newVMClass := createVMClass(newCS)
436+
vm.Spec.ClassName = newVMClass.Name
437+
438+
// Simulate what the VM mutation webhook would do by setting the LRA to an emtpy class name.
439+
delete(vm.Annotations, vmopv1util.LastResizedAnnotationKey)
440+
Expect(vmopv1util.SetLastResizedAnnotationClassName(vm, "")).To(Succeed())
441+
Expect(vm.Annotations).To(HaveKey(vmopv1util.LastResizedAnnotationKey))
442+
443+
vm.Spec.PowerState = vmopv1.VirtualMachinePowerStateOn
444+
vcVM, err := createOrUpdateAndGetVcVM(ctx, vmProvider, vm)
445+
Expect(err).ToNot(HaveOccurred())
446+
447+
var o mo.VirtualMachine
448+
Expect(vcVM.Properties(ctx, vcVM.Reference(), nil, &o)).To(Succeed())
449+
Expect(o.Summary.Runtime.PowerState).To(Equal(vimtypes.VirtualMachinePowerStatePoweredOn))
450+
Expect(o.Config.Hardware.NumCPU).To(BeEquivalentTo(newCS.NumCPUs))
451+
Expect(o.Config.Hardware.MemoryMB).To(BeEquivalentTo(newCS.MemoryMB))
452+
assertExpectedNoReservationFields(o)
453+
454+
assertExpectedResizedClassFields(vm, newVMClass)
455+
})
405456
})
406457

407458
Context("Without Same Class Resize Annotation", func() {

pkg/util/vmopv1/resize.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,9 @@ func MustSetLastResizedAnnotation(
5858
}
5959

6060
// SetLastResizedAnnotationClassName sets the resize annotation to just of the class name.
61+
// This is called from the VM mutation wehbook to record the prior class name of a VM
62+
// that does not already have the annotation (so that ResizeNeeded() will return true).
63+
// Note className may be empty if the VM was classless.
6164
func SetLastResizedAnnotationClassName(
6265
vm *vmopv1.VirtualMachine,
6366
className string) error {
@@ -107,7 +110,7 @@ func ResizeNeeded(
107110
vmClass vmopv1.VirtualMachineClass) bool {
108111

109112
lra, exists := getLastResizeAnnotation(vm)
110-
if !exists || lra.Name == "" {
113+
if !exists {
111114
// The VM does not have the last resized annotation. Most likely this is an existing VM
112115
// and the VM Spec.ClassName hasn't been changed (because the mutation webhook sets the
113116
// annotation when it changes). However, if the same class opt-in annotation is set, do

pkg/util/vmopv1/resize_test.go

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,24 @@ var _ = Describe("SetLastResizedAnnotationClassName", func() {
5454
vmClass.Generation = 42
5555
})
5656

57+
When("Classless", func() {
58+
It("Sets expected annotation", func() {
59+
err := vmopv1util.SetLastResizedAnnotationClassName(vm, "")
60+
Expect(err).ToNot(HaveOccurred())
61+
val, ok := vm.Annotations[vmopv1util.LastResizedAnnotationKey]
62+
Expect(ok).To(BeTrue())
63+
Expect(val).To(MatchJSON(`{"name":""}`))
64+
65+
By("GetLastResizedAnnotation also returns expected values", func() {
66+
className, uid, generation, ok := vmopv1util.GetLastResizedAnnotation(*vm)
67+
Expect(ok).To(BeTrue())
68+
Expect(className).To(BeEmpty())
69+
Expect(uid).To(BeEmpty())
70+
Expect(generation).To(BeZero())
71+
})
72+
})
73+
})
74+
5775
It("Sets expected annotation", func() {
5876
err := vmopv1util.SetLastResizedAnnotationClassName(vm, vmClass.Name)
5977
Expect(err).ToNot(HaveOccurred())
@@ -96,6 +114,20 @@ var _ = Describe("GetLastResizedAnnotation", func() {
96114
})
97115
})
98116

117+
When("Resize annotation is present from classless VM", func() {
118+
BeforeEach(func() {
119+
Expect(vmopv1util.SetLastResizedAnnotationClassName(vm, ""))
120+
})
121+
122+
It("Returns expected values", func() {
123+
className, uid, generation, ok := vmopv1util.GetLastResizedAnnotation(*vm)
124+
Expect(ok).To(BeTrue())
125+
Expect(className).To(BeEmpty())
126+
Expect(uid).To(BeEmpty())
127+
Expect(generation).To(BeZero())
128+
})
129+
})
130+
99131
When("Resize annotation is present", func() {
100132
BeforeEach(func() {
101133
Expect(vmopv1util.SetLastResizedAnnotation(vm, vmClass)).To(Succeed())
@@ -144,6 +176,30 @@ var _ = Describe("ResizeNeeded", func() {
144176
})
145177
})
146178

179+
Context("Resize annotation with just ClassName is set", func() {
180+
Context("Resize annotation is present via non-classless VM", func() {
181+
BeforeEach(func() {
182+
Expect(vmopv1util.SetLastResizedAnnotationClassName(&vm, "my-old-class")).To(Succeed())
183+
vm.Spec.ClassName = "my-new-class"
184+
})
185+
186+
It("returns true", func() {
187+
Expect(vmopv1util.ResizeNeeded(vm, vmClass)).To(BeTrue())
188+
})
189+
})
190+
191+
Context("Resize annotation is present via classless VM", func() {
192+
BeforeEach(func() {
193+
Expect(vmopv1util.SetLastResizedAnnotationClassName(&vm, "")).To(Succeed())
194+
vm.Spec.ClassName = "my-new-class"
195+
})
196+
197+
It("returns true", func() {
198+
Expect(vmopv1util.ResizeNeeded(vm, vmClass)).To(BeTrue())
199+
})
200+
})
201+
})
202+
147203
Context("Resize annotation is present", func() {
148204
BeforeEach(func() {
149205
Expect(vmopv1util.SetLastResizedAnnotation(&vm, vmClass)).To(Succeed())

webhooks/virtualmachine/mutation/virtualmachine_mutator_unit_test.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1148,6 +1148,23 @@ func unitTestsMutating() {
11481148
})
11491149
})
11501150

1151+
When("existing vm is classless", func() {
1152+
It("set last-resize annotation", func() {
1153+
oldVM.Spec.ClassName = ""
1154+
ctx.vm.Spec.ClassName = newClassName
1155+
1156+
updated, err := mutation.SetLastResizeAnnotation(&ctx.WebhookRequestContext, ctx.vm, oldVM)
1157+
Expect(err).ToNot(HaveOccurred())
1158+
Expect(updated).To(BeTrue())
1159+
1160+
className, uid, gen, exists := vmopv1util.GetLastResizedAnnotation(*ctx.vm)
1161+
Expect(exists).To(BeTrue())
1162+
Expect(className).To(Equal(oldVM.Spec.ClassName))
1163+
Expect(uid).To(BeEmpty())
1164+
Expect(gen).To(BeZero())
1165+
})
1166+
})
1167+
11511168
When("vm already has last-resize annotation", func() {
11521169
It("annotation is not changed", func() {
11531170
vmClass := builder.DummyVirtualMachineClass("my-class")

0 commit comments

Comments
 (0)