Skip to content

Commit d1e5113

Browse files
feat: support overriding default scaling configuration (#385)
* make launchtemplates default Signed-off-by: sbadiger <[email protected]> * remove additional new lint Signed-off-by: sbadiger <[email protected]> * indentation Signed-off-by: sbadiger <[email protected]> * update default config type Signed-off-by: sbadiger <[email protected]> * update spec Signed-off-by: sbadiger <[email protected]> * refactor the default scaling config code Signed-off-by: sbadiger <[email protected]> * add unit tests Signed-off-by: sbadiger <[email protected]> * fix unit tests Signed-off-by: sbadiger <[email protected]> * indent Signed-off-by: sbadiger <[email protected]> * update defaultScalingConfiguration flag description Signed-off-by: sbadiger <[email protected]> --------- Signed-off-by: sbadiger <[email protected]>
1 parent 7c2bf62 commit d1e5113

File tree

7 files changed

+174
-42
lines changed

7 files changed

+174
-42
lines changed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ all: check-go test clean manager
3838
# Run tests
3939
.PHONY: test
4040
test: generate fmt vet manifests
41-
go test -v ./controllers/... ./api/... -coverprofile coverage.txt
41+
go test ./controllers/... ./api/... -coverprofile coverage.txt
4242

4343
.PHONY: bdd
4444
bdd:

api/v1alpha1/instancegroup_types.go

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -368,6 +368,15 @@ type InstanceGroupStatus struct {
368368

369369
type InstanceGroupConditionType string
370370

371+
type ValidationOverrides struct {
372+
scalingConfigurationOverride *ScalingConfigurationType
373+
}
374+
375+
func NewValidationOverrides(defaultScalingConfiguration *ScalingConfigurationType) *ValidationOverrides {
376+
return &ValidationOverrides{
377+
scalingConfigurationOverride: defaultScalingConfiguration,
378+
}
379+
}
371380
func NewInstanceGroupCondition(cType InstanceGroupConditionType, status corev1.ConditionStatus) InstanceGroupCondition {
372381
return InstanceGroupCondition{
373382
Type: cType,
@@ -409,7 +418,7 @@ func (ig *InstanceGroup) Locked() bool {
409418
return false
410419
}
411420

412-
func (s *EKSSpec) Validate() error {
421+
func (s *EKSSpec) Validate(overrides *ValidationOverrides) error {
413422
var (
414423
configuration = s.EKSConfiguration
415424
configType = s.Type
@@ -419,7 +428,10 @@ func (s *EKSSpec) Validate() error {
419428
}
420429

421430
if s.Type != LaunchConfiguration && s.Type != LaunchTemplate {
422-
s.Type = LaunchConfiguration
431+
s.Type = LaunchTemplate
432+
if overrides.scalingConfigurationOverride != nil {
433+
s.Type = *overrides.scalingConfigurationOverride
434+
}
423435
}
424436

425437
if s.Type == LaunchConfiguration {
@@ -700,7 +712,7 @@ func (m *MixedInstancesPolicySpec) Validate() error {
700712
return nil
701713
}
702714

703-
func (ig *InstanceGroup) Validate() error {
715+
func (ig *InstanceGroup) Validate(overrides *ValidationOverrides) error {
704716
s := ig.Spec
705717

706718
if !common.ContainsEqualFold(Provisioners, s.Provisioner) {
@@ -735,7 +747,7 @@ func (ig *InstanceGroup) Validate() error {
735747
config := ig.GetEKSConfiguration()
736748
spec := ig.GetEKSSpec()
737749

738-
if err := spec.Validate(); err != nil {
750+
if err := spec.Validate(overrides); err != nil {
739751
return err
740752
}
741753

api/v1alpha1/instancegroup_types_test.go

Lines changed: 93 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,11 @@ import (
2222

2323
type EksUnitTest struct {
2424
InstanceGroup *InstanceGroup
25+
Overrides *ValidationOverrides
2526
}
2627

2728
func (u *EksUnitTest) Run(t *testing.T) string {
28-
err := u.InstanceGroup.Validate()
29+
err := u.InstanceGroup.Validate(u.Overrides)
2930
if err == nil {
3031
return aws.StringValue(nil)
3132
} else {
@@ -34,12 +35,15 @@ func (u *EksUnitTest) Run(t *testing.T) string {
3435
}
3536

3637
func TestInstanceGroupSpecValidate(t *testing.T) {
38+
launchconfiguration := LaunchConfiguration
3739
type args struct {
3840
instancegroup *InstanceGroup
41+
overrides *ValidationOverrides
3942
}
4043
testFunction := func(t *testing.T, args args) string {
4144
testCase := EksUnitTest{
4245
InstanceGroup: args.instancegroup,
46+
Overrides: args.overrides,
4347
}
4448
return testCase.Run(t)
4549
}
@@ -432,6 +436,16 @@ func TestInstanceGroupSpecValidate(t *testing.T) {
432436
},
433437
want: "validation failed, HostResourceGroupArn must be a valid dedicated HostResourceGroup ARN",
434438
},
439+
{
440+
name: "default to launch config instead of launch template",
441+
args: args{
442+
instancegroup: MockInstanceGroup("eks-fargate", "managed", nil, nil, basicFargateSpec()),
443+
overrides: &ValidationOverrides{
444+
scalingConfigurationOverride: &launchconfiguration,
445+
},
446+
},
447+
want: "",
448+
},
435449
}
436450
for _, tt := range tests {
437451
t.Run(tt.name, func(t *testing.T) {
@@ -444,6 +458,70 @@ func TestInstanceGroupSpecValidate(t *testing.T) {
444458
}
445459
}
446460

461+
func TestScalingConfigOverride(t *testing.T) {
462+
launchconfiguration := LaunchConfiguration
463+
launchtemplate := LaunchTemplate
464+
type args struct {
465+
instancegroup *InstanceGroup
466+
overrides *ValidationOverrides
467+
}
468+
testFunction := func(t *testing.T, args args) string {
469+
testCase := EksUnitTest{
470+
InstanceGroup: args.instancegroup,
471+
Overrides: args.overrides,
472+
}
473+
return testCase.Run(t)
474+
}
475+
tests := []struct {
476+
name string
477+
args args
478+
want ScalingConfigurationType
479+
}{
480+
{
481+
name: "override default to launchconfig instead of launchtemplate",
482+
args: args{
483+
instancegroup: MockInstanceGroup("eks", "managed", MockEKSSpec(), nil, basicFargateSpec()),
484+
overrides: &ValidationOverrides{
485+
scalingConfigurationOverride: &launchconfiguration,
486+
},
487+
},
488+
want: LaunchConfiguration,
489+
},
490+
{
491+
name: "no default overrides",
492+
args: args{
493+
instancegroup: MockInstanceGroup("eks", "managed", MockEKSSpec(), nil, basicFargateSpec()),
494+
overrides: &ValidationOverrides{},
495+
},
496+
want: LaunchTemplate,
497+
},
498+
{
499+
name: "override default to launchtemplate",
500+
args: args{
501+
instancegroup: MockInstanceGroup("eks", "managed", MockEKSSpec(), nil, basicFargateSpec()),
502+
overrides: &ValidationOverrides{
503+
scalingConfigurationOverride: &launchtemplate,
504+
},
505+
},
506+
want: LaunchTemplate,
507+
},
508+
}
509+
for _, tt := range tests {
510+
t.Run(tt.name, func(t *testing.T) {
511+
err := testFunction(t, tt.args)
512+
if err != "" {
513+
t.Errorf("error:%v", err)
514+
}
515+
got := tt.args.instancegroup.Spec.EKSSpec.Type
516+
if got != tt.want {
517+
t.Errorf("%v: got %v, want %v", tt.name, got, tt.want)
518+
}
519+
520+
})
521+
522+
}
523+
}
524+
447525
func TestLockedAnnotation(t *testing.T) {
448526
tests := []struct {
449527
name string
@@ -507,3 +585,17 @@ func MockInstanceGroup(provisioner, strategy string, eksSpec *EKSSpec, eksManage
507585
}
508586

509587
}
588+
589+
func MockEKSSpec() *EKSSpec {
590+
return &EKSSpec{
591+
Type: "invalid-scaling-config",
592+
EKSConfiguration: &EKSConfiguration{
593+
EksClusterName: "sample-cluster",
594+
Subnets: []string{"subnet-1111111", "subnet-222222"},
595+
NodeSecurityGroups: []string{"sg-sample-1", "sg-sample-2"},
596+
Image: "sample-ami",
597+
InstanceType: "sample-instance",
598+
KeyPairName: "sample-key-pair",
599+
},
600+
}
601+
}

api/v1alpha1/zz_generated.deepcopy.go

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

controllers/instancegroup_controller.go

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -43,18 +43,19 @@ import (
4343
// InstanceGroupReconciler reconciles an InstanceGroup object
4444
type InstanceGroupReconciler struct {
4545
client.Client
46-
SpotRecommendationTime float64
47-
ConfigNamespace string
48-
NodeRelabel bool
49-
Log logr.Logger
50-
MaxParallel int
51-
Auth *InstanceGroupAuthenticator
52-
ConfigMap *corev1.ConfigMap
53-
Namespaces map[string]corev1.Namespace
54-
NamespacesLock *sync.RWMutex
55-
ConfigRetention int
56-
Metrics *common.MetricsCollector
57-
DisableWinClusterInjection bool
46+
SpotRecommendationTime float64
47+
ConfigNamespace string
48+
NodeRelabel bool
49+
Log logr.Logger
50+
MaxParallel int
51+
Auth *InstanceGroupAuthenticator
52+
ConfigMap *corev1.ConfigMap
53+
Namespaces map[string]corev1.Namespace
54+
NamespacesLock *sync.RWMutex
55+
ConfigRetention int
56+
Metrics *common.MetricsCollector
57+
DisableWinClusterInjection bool
58+
DefaultScalingConfiguration *v1alpha1.ScalingConfigurationType
5859
}
5960

6061
type InstanceGroupAuthenticator struct {
@@ -194,7 +195,10 @@ func (r *InstanceGroupReconciler) Reconcile(ctxt context.Context, req ctrl.Reque
194195
ctx = eksfargate.New(input)
195196
}
196197

197-
if err = input.InstanceGroup.Validate(); err != nil {
198+
// for igs without any config type mentioned, allow overriding the default.
199+
overrides := v1alpha1.NewValidationOverrides(r.DefaultScalingConfiguration)
200+
201+
if err = input.InstanceGroup.Validate(overrides); err != nil {
198202
ctx.SetState(v1alpha1.ReconcileErr)
199203
r.PatchStatus(input.InstanceGroup, statusPatch)
200204
r.Metrics.IncFail(instanceGroup.NamespacedName(), ErrorReasonValidationFailed)

controllers/provisioners/eks/upgrade_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ func TestUpgradeCRDStrategyValidation(t *testing.T) {
9696
t.Logf("#%v - %+v", i, tc.input)
9797
var errOccured bool
9898
ig.SetUpgradeStrategy(tc.input)
99-
err := ig.Validate()
99+
err := ig.Validate(&v1alpha1.ValidationOverrides{})
100100
if err != nil {
101101
t.Log(err)
102102
errOccured = true

main.go

Lines changed: 26 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -65,16 +65,17 @@ func main() {
6565
printVersion()
6666

6767
var (
68-
metricsAddr string
69-
configNamespace string
70-
spotRecommendationTime float64
71-
enableLeaderElection bool
72-
nodeRelabel bool
73-
disableWinClusterInjection bool
74-
maxParallel int
75-
maxAPIRetries int
76-
configRetention int
77-
err error
68+
metricsAddr string
69+
configNamespace string
70+
spotRecommendationTime float64
71+
enableLeaderElection bool
72+
nodeRelabel bool
73+
disableWinClusterInjection bool
74+
maxParallel int
75+
maxAPIRetries int
76+
configRetention int
77+
err error
78+
defaultScalingConfiguration string
7879
)
7980

8081
flag.IntVar(&maxParallel, "max-workers", 5, "The number of maximum parallel reconciles")
@@ -87,6 +88,7 @@ func main() {
8788
"Enable leader election for controller manager. Enabling this will ensure there is only one active controller manager.")
8889
flag.BoolVar(&nodeRelabel, "node-relabel", true, "relabel nodes as they join with kubernetes.io/role label via controller")
8990
flag.BoolVar(&disableWinClusterInjection, "disable-windows-cluster-ca-injection", false, "Setting this to true will cause the ClusterCA and Endpoint to not be injected for Windows nodes")
91+
flag.StringVar(&defaultScalingConfiguration, "", string(instancemgrv1alpha1.LaunchTemplate), "By default ASGs will have LaunchTemplate. Set this string to either 'LaunchConfiguration' or 'LaunchTemplate' to enforce defaults.")
9092

9193
flag.Parse()
9294
ctrl.SetLogger(zap.New(zap.UseDevMode(true)))
@@ -149,19 +151,21 @@ func main() {
149151
setupLog.Info("instance-manager configmap does not exist, will not load defaults/boundaries")
150152
}
151153

154+
defaultScalingConfigurationType := instancemgrv1alpha1.ScalingConfigurationType(defaultScalingConfiguration)
152155
err = (&controllers.InstanceGroupReconciler{
153-
Metrics: controllerCollector,
154-
ConfigMap: cm,
155-
ConfigRetention: configRetention,
156-
SpotRecommendationTime: spotRecommendationTime,
157-
ConfigNamespace: configNamespace,
158-
Namespaces: make(map[string]corev1.Namespace),
159-
NamespacesLock: &sync.RWMutex{},
160-
NodeRelabel: nodeRelabel,
161-
DisableWinClusterInjection: disableWinClusterInjection,
162-
Client: mgr.GetClient(),
163-
Log: ctrl.Log.WithName("controllers").WithName("instancegroup"),
164-
MaxParallel: maxParallel,
156+
Metrics: controllerCollector,
157+
ConfigMap: cm,
158+
ConfigRetention: configRetention,
159+
SpotRecommendationTime: spotRecommendationTime,
160+
ConfigNamespace: configNamespace,
161+
Namespaces: make(map[string]corev1.Namespace),
162+
NamespacesLock: &sync.RWMutex{},
163+
NodeRelabel: nodeRelabel,
164+
DisableWinClusterInjection: disableWinClusterInjection,
165+
Client: mgr.GetClient(),
166+
Log: ctrl.Log.WithName("controllers").WithName("instancegroup"),
167+
MaxParallel: maxParallel,
168+
DefaultScalingConfiguration: &defaultScalingConfigurationType,
165169
Auth: &controllers.InstanceGroupAuthenticator{
166170
Aws: awsWorker,
167171
Kubernetes: kube,

0 commit comments

Comments
 (0)