Skip to content

Commit 6811f71

Browse files
committed
Switching to using preconfigured values
1 parent 59f8000 commit 6811f71

File tree

7 files changed

+160
-23
lines changed

7 files changed

+160
-23
lines changed

config/crd/bases/infrastructure.cluster.x-k8s.io_awsmachinepools.yaml

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -850,9 +850,28 @@ spec:
850850
description: SuspendProcesses defines a list of processes to suspend
851851
for the given ASG. This is constantly reconciled. If a process is
852852
removed from this list it will automatically be resumed.
853-
items:
854-
type: string
855-
type: array
853+
properties:
854+
addToLoadBalancer:
855+
type: boolean
856+
alarmNotification:
857+
type: boolean
858+
all:
859+
type: boolean
860+
azRebalance:
861+
type: boolean
862+
healthCheck:
863+
type: boolean
864+
instanceRefresh:
865+
type: boolean
866+
launch:
867+
type: boolean
868+
replaceUnhealthy:
869+
type: boolean
870+
scheduledActions:
871+
type: boolean
872+
terminate:
873+
type: boolean
874+
type: object
856875
required:
857876
- awsLaunchTemplate
858877
- maxSize

docs/book/src/topics/suspend-asg-processes.md

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,9 @@ spec:
2626
instanceType: "${AWS_CONTROL_PLANE_MACHINE_TYPE}"
2727
sshKeyName: "${AWS_SSH_KEY_NAME}"
2828
suspendProcesses:
29-
- Launch
30-
- AlarmNotification
31-
- AZRebalance
29+
launch: true
30+
alarmNotification: true
31+
azRebalance: true
3232
---
3333
```
3434

@@ -52,9 +52,31 @@ spec:
5252
instanceType: "${AWS_CONTROL_PLANE_MACHINE_TYPE}"
5353
sshKeyName: "${AWS_SSH_KEY_NAME}"
5454
suspendProcesses:
55-
- Launch
55+
launch: true
5656
---
5757
```
5858

5959
_Note_ that now `AlarmNotification` and `AZRebalance` will be resumed, but the reconciler will not try to suspend
6060
`Launch` again. So it doesn't incur additional expensive, redundant API calls.
61+
62+
## Optional `All`
63+
64+
An option is also provided to suspend all processes without having to set each of them to `true`. Simply use `all` like
65+
this:
66+
67+
```yaml
68+
apiVersion: infrastructure.cluster.x-k8s.io/v1beta2
69+
kind: AWSMachinePool
70+
metadata:
71+
name: capa-mp-0
72+
spec:
73+
minSize: 1
74+
maxSize: 10
75+
availabilityZones:
76+
- "${AWS_AVAILABILITY_ZONE}"
77+
awsLaunchTemplate:
78+
instanceType: "${AWS_CONTROL_PLANE_MACHINE_TYPE}"
79+
sshKeyName: "${AWS_SSH_KEY_NAME}"
80+
suspendProcesses:
81+
all: true
82+
```

exp/api/v1beta1/conversion.go

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,7 @@ func (src *AWSMachinePool) ConvertTo(dstRaw conversion.Hub) error {
3939
}
4040

4141
if restored.Spec.SuspendProcesses != nil {
42-
restoredProcesses := make([]string, len(restored.Spec.SuspendProcesses))
43-
copy(restoredProcesses, restored.Spec.SuspendProcesses)
44-
dst.Spec.SuspendProcesses = restoredProcesses
42+
dst.Spec.SuspendProcesses = restored.Spec.SuspendProcesses
4543
}
4644

4745
return nil

exp/api/v1beta2/awsmachinepool_types.go

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ limitations under the License.
1717
package v1beta2
1818

1919
import (
20+
"reflect"
21+
2022
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2123
"k8s.io/apimachinery/pkg/runtime/schema"
2224

@@ -86,7 +88,43 @@ type AWSMachinePoolSpec struct {
8688

8789
// SuspendProcesses defines a list of processes to suspend for the given ASG. This is constantly reconciled.
8890
// If a process is removed from this list it will automatically be resumed.
89-
SuspendProcesses []string `json:"suspendProcesses,omitempty"`
91+
SuspendProcesses *SuspendProcessesTypes `json:"suspendProcesses,omitempty"`
92+
}
93+
94+
// SuspendProcessesTypes contains user friendly auto-completable values for suspended process names.
95+
type SuspendProcessesTypes struct {
96+
All bool `json:"all,omitempty"`
97+
Launch bool `json:"launch,omitempty"`
98+
Terminate bool `json:"terminate,omitempty"`
99+
AddToLoadBalancer bool `json:"addToLoadBalancer,omitempty"`
100+
AlarmNotification bool `json:"alarmNotification,omitempty"`
101+
AZRebalance bool `json:"azRebalance,omitempty"`
102+
HealthCheck bool `json:"healthCheck,omitempty"`
103+
InstanceRefresh bool `json:"instanceRefresh,omitempty"`
104+
ReplaceUnhealthy bool `json:"replaceUnhealthy,omitempty"`
105+
ScheduledActions bool `json:"scheduledActions,omitempty"`
106+
}
107+
108+
// ConvertSetValuesToStringSlice converts all the values that are set into a string slice for further processing.
109+
func (s *SuspendProcessesTypes) ConvertSetValuesToStringSlice() []string {
110+
if s == nil {
111+
return nil
112+
}
113+
e := reflect.ValueOf(s).Elem()
114+
115+
var result []string
116+
for i := 0; i < e.NumField(); i++ {
117+
if s.All {
118+
if e.Type().Field(i).Name == "All" {
119+
continue
120+
}
121+
result = append(result, e.Type().Field(i).Name)
122+
} else if e.Field(i).Bool() {
123+
result = append(result, e.Type().Field(i).Name)
124+
}
125+
}
126+
127+
return result
90128
}
91129

92130
// RefreshPreferences defines the specs for instance refreshing.

exp/api/v1beta2/zz_generated.deepcopy.go

Lines changed: 17 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

exp/controllers/awsmachinepool_controller.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -384,7 +384,8 @@ func (r *AWSMachinePoolReconciler) updatePool(machinePoolScope *scope.MachinePoo
384384
}
385385
}
386386

387-
if !cmp.Equal(existingASG.CurrentlySuspendProcesses, machinePoolScope.AWSMachinePool.Spec.SuspendProcesses) {
387+
suspendedProcessesSlice := machinePoolScope.AWSMachinePool.Spec.SuspendProcesses.ConvertSetValuesToStringSlice()
388+
if !cmp.Equal(existingASG.CurrentlySuspendProcesses, suspendedProcessesSlice) {
388389
var (
389390
toBeSuspended []string
390391
toBeResumed []string
@@ -398,7 +399,7 @@ func (r *AWSMachinePoolReconciler) updatePool(machinePoolScope *scope.MachinePoo
398399
currentlySuspended[p] = struct{}{}
399400
}
400401

401-
for _, p := range machinePoolScope.AWSMachinePool.Spec.SuspendProcesses {
402+
for _, p := range suspendedProcessesSlice {
402403
desiredSuspended[p] = struct{}{}
403404
}
404405

@@ -445,7 +446,8 @@ func (r *AWSMachinePoolReconciler) createPool(machinePoolScope *scope.MachinePoo
445446
if err != nil {
446447
return nil, errors.Wrapf(err, "failed to create AWSMachinePool")
447448
}
448-
if err := asgsvc.SuspendProcesses(asg.Name, machinePoolScope.AWSMachinePool.Spec.SuspendProcesses); err != nil {
449+
suspendedProcessesSlice := machinePoolScope.AWSMachinePool.Spec.SuspendProcesses.ConvertSetValuesToStringSlice()
450+
if err := asgsvc.SuspendProcesses(asg.Name, suspendedProcessesSlice); err != nil {
449451
return nil, errors.Wrapf(err, "failed to suspend processes while trying to create Pool")
450452
}
451453
return asg, nil

exp/controllers/awsmachinepool_controller_test.go

Lines changed: 50 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,10 @@ func TestAWSMachinePoolReconciler(t *testing.T) {
252252
t.Run("there's suspended processes provided during ASG creation", func(t *testing.T) {
253253
setSuspendedProcesses := func(t *testing.T, g *WithT) {
254254
t.Helper()
255-
ms.AWSMachinePool.Spec.SuspendProcesses = []string{"process1", "process2"}
255+
ms.AWSMachinePool.Spec.SuspendProcesses = &expinfrav1.SuspendProcessesTypes{
256+
Launch: true,
257+
Terminate: true,
258+
}
256259
}
257260
t.Run("it should suspend these processes", func(t *testing.T) {
258261
g := NewWithT(t)
@@ -265,7 +268,41 @@ func TestAWSMachinePoolReconciler(t *testing.T) {
265268
asgSvc.EXPECT().CreateASG(gomock.Any()).Return(&expinfrav1.AutoScalingGroup{
266269
Name: "name",
267270
}, nil)
268-
asgSvc.EXPECT().SuspendProcesses("name", []string{"process1", "process2"}).Return(nil).AnyTimes()
271+
asgSvc.EXPECT().SuspendProcesses("name", []string{"Launch", "Terminate"}).Return(nil).AnyTimes()
272+
273+
_, err := reconciler.reconcileNormal(context.Background(), ms, cs, cs)
274+
g.Expect(err).To(Succeed())
275+
})
276+
})
277+
t.Run("all processes are suspended", func(t *testing.T) {
278+
setSuspendedProcesses := func(t *testing.T, g *WithT) {
279+
t.Helper()
280+
ms.AWSMachinePool.Spec.SuspendProcesses = &expinfrav1.SuspendProcessesTypes{
281+
All: true,
282+
}
283+
}
284+
t.Run("it should result in all processes being included except the value all", func(t *testing.T) {
285+
g := NewWithT(t)
286+
setup(t, g)
287+
defer teardown(t, g)
288+
setSuspendedProcesses(t, g)
289+
290+
ec2Svc.EXPECT().ReconcileLaunchTemplate(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil)
291+
asgSvc.EXPECT().GetASGByName(gomock.Any()).Return(nil, nil)
292+
asgSvc.EXPECT().CreateASG(gomock.Any()).Return(&expinfrav1.AutoScalingGroup{
293+
Name: "name",
294+
}, nil)
295+
asgSvc.EXPECT().SuspendProcesses("name", []string{
296+
"Launch",
297+
"Terminate",
298+
"AddToLoadBalancer",
299+
"AlarmNotification",
300+
"AZRebalance",
301+
"HealthCheck",
302+
"InstanceRefresh",
303+
"ReplaceUnhealthy",
304+
"ScheduledActions",
305+
}).Return(nil).AnyTimes()
269306

270307
_, err := reconciler.reconcileNormal(context.Background(), ms, cs, cs)
271308
g.Expect(err).To(Succeed())
@@ -275,7 +312,10 @@ func TestAWSMachinePoolReconciler(t *testing.T) {
275312
setSuspendedProcesses := func(t *testing.T, g *WithT) {
276313
t.Helper()
277314

278-
ms.AWSMachinePool.Spec.SuspendProcesses = []string{"process1", "process2"}
315+
ms.AWSMachinePool.Spec.SuspendProcesses = &expinfrav1.SuspendProcessesTypes{
316+
Launch: true,
317+
Terminate: true,
318+
}
279319
}
280320
t.Run("it should suspend and resume processes that are desired to be suspended and desired to be resumed", func(t *testing.T) {
281321
g := NewWithT(t)
@@ -287,10 +327,10 @@ func TestAWSMachinePoolReconciler(t *testing.T) {
287327
ec2Svc.EXPECT().ReconcileTags(gomock.Any(), gomock.Any()).Return(nil)
288328
asgSvc.EXPECT().GetASGByName(gomock.Any()).Return(&expinfrav1.AutoScalingGroup{
289329
Name: "name",
290-
CurrentlySuspendProcesses: []string{"process1", "process3"},
330+
CurrentlySuspendProcesses: []string{"Launch", "process3"},
291331
}, nil)
292332
asgSvc.EXPECT().UpdateASG(gomock.Any()).Return(nil).AnyTimes()
293-
asgSvc.EXPECT().SuspendProcesses("name", []string{"process2"}).Return(nil).AnyTimes()
333+
asgSvc.EXPECT().SuspendProcesses("name", []string{"Terminate"}).Return(nil).AnyTimes()
294334
asgSvc.EXPECT().ResumeProcesses("name", []string{"process3"}).Return(nil).AnyTimes()
295335

296336
_, err := reconciler.reconcileNormal(context.Background(), ms, cs, cs)
@@ -583,7 +623,10 @@ func TestASGNeedsUpdates(t *testing.T) {
583623
},
584624
Overrides: nil,
585625
},
586-
SuspendProcesses: []string{"process1", "process2"},
626+
SuspendProcesses: &expinfrav1.SuspendProcessesTypes{
627+
Launch: true,
628+
Terminate: true,
629+
},
587630
},
588631
},
589632
Logger: logr.Discard(),
@@ -594,7 +637,7 @@ func TestASGNeedsUpdates(t *testing.T) {
594637
MinSize: 0,
595638
CapacityRebalance: true,
596639
MixedInstancesPolicy: &expinfrav1.MixedInstancesPolicy{},
597-
CurrentlySuspendProcesses: []string{"process1", "process3"},
640+
CurrentlySuspendProcesses: []string{"Launch", "Terminate"},
598641
},
599642
},
600643
want: true,

0 commit comments

Comments
 (0)