Skip to content

Commit 55df8e2

Browse files
authored
Update eks version (#87)
* Fix: Increase start timeout to 60s for controlplane components in circleCI * Revert "Fix: Increase start timeout to 60s for controlplane components in circleCI" This reverts commit 8f58a54. * Add Support for Updating Nodegroup Versions * Update AMI Parameter name to reflect the aws eks sample yaml * Use AWS SSM instead of Hardcoding AMI ID * HouseKeeping for the nodegroup Controller * update ControlPlane Versions * Dont silently hide status update errors * moved to SSM removing hardcoded AMI's * Minor review comments - #87 * Set default Version back to 1.12 * Update Child account Sample role to include SSM permissions
1 parent d00e853 commit 55df8e2

File tree

8 files changed

+153
-108
lines changed

8 files changed

+153
-108
lines changed

config/setup/aws-eks-cluster-controller-management-role.yaml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,10 @@ Resources:
3434
"iam:*",
3535
"cloudformation:*",
3636
"eks:*",
37-
"sts:*"
37+
"sts:*",
38+
"ssm:GetParametersByPath",
39+
"ssm:GetParameters",
40+
"ssm:GetParameter"
3841
],
3942
"Resource": "*"
4043
}

pkg/apis/cluster/v1alpha1/versions.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ package v1alpha1
44
var SupportedVersions = []string{
55
"1.11",
66
"1.12",
7+
"1.13",
8+
"1.14",
79
}
810

911
// DefaultVersion is the version that is used if none is supplied

pkg/controller/controlplane/cfn_template.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@ var controlplaneCFNTemplate = `
55
AWSTemplateFormatVersion: '2010-09-09'
66
Description: 'Amazon EKS Networking + Control Plane [managed by aws-eks-cluster-controller]'
77
8+
Parameters:
9+
EKSVersion:
10+
Type: String
11+
Description: EKS Version this control plane should run on
12+
Default: {{ .Version }}
13+
814
Resources:
915
VPC:
1016
Type: AWS::EC2::VPC
@@ -147,7 +153,7 @@ Resources:
147153
- !Ref 'Subnet03'
148154
RoleArn:
149155
!GetAtt ServiceRole.Arn
150-
Version: '{{.Version}}'
156+
Version: !Ref EKSVersion
151157
Outputs:
152158
153159
SubnetIds:

pkg/controller/controlplane/controlplane_controller.go

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import (
2828
var (
2929
StatusCreateComplete = "Complete"
3030
StatusCreating = "Creating"
31+
StatusUpdating = "Updating"
3132
StatusFailed = "Failed"
3233
StatusError = "Error"
3334
)
@@ -198,6 +199,8 @@ func (r *ReconcileControlPlane) Reconcile(request reconcile.Request) (reconcile.
198199
return reconcile.Result{}, nil
199200
}
200201

202+
crdParameters := parseCFNParametersFromCRD(instance)
203+
201204
if err != nil && awsHelper.IsStackDoesNotExist(err) {
202205
logger.Info("creating stack")
203206

@@ -220,6 +223,26 @@ func (r *ReconcileControlPlane) Reconcile(request reconcile.Request) (reconcile.
220223
return reconcile.Result{}, err
221224
}
222225

226+
cfnParameters, err := getCFNParametersFromCFNStack(cfnSvc, stackName)
227+
if err != nil {
228+
r.fail(instance, "error trying to read the CFN Parameters", err, logger)
229+
return reconcile.Result{}, err
230+
}
231+
232+
if shouldUpdate(crdParameters, cfnParameters) {
233+
logger.Info("Updating the control Plane")
234+
235+
err := r.updateControlPlaneStack(cfnSvc, stackName, instance)
236+
if err != nil {
237+
r.fail(instance, "error updating the controlplane cloudformation stack", err, logger)
238+
return reconcile.Result{}, err
239+
}
240+
241+
instance.Status.Status = StatusUpdating
242+
243+
return reconcile.Result{Requeue: true}, r.Update(context.TODO(), instance)
244+
}
245+
223246
if awsHelper.IsPending(*stack.StackStatus) {
224247
logger.Info("waiting for stack to complete", zap.String("StackStatus", *stack.StackStatus))
225248
return reconcile.Result{RequeueAfter: 5 * time.Second}, nil
@@ -282,3 +305,77 @@ func (r *ReconcileControlPlane) createControlPlaneStack(cfnSvc cloudformationifa
282305
return err
283306

284307
}
308+
309+
func (r *ReconcileControlPlane) updateControlPlaneStack(cfnSvc cloudformationiface.CloudFormationAPI, stackName string, instance *clusterv1alpha1.ControlPlane) error {
310+
network, err := instance.GetNetwork()
311+
if err != nil {
312+
return err
313+
}
314+
315+
body, err := awsHelper.GetCFNTemplateBody(controlplaneCFNTemplate, controlPlaneTemplateInput{
316+
ClusterName: instance.Spec.ClusterName,
317+
Version: instance.GetVersion(),
318+
Network: network,
319+
})
320+
if err != nil {
321+
return err
322+
}
323+
324+
_, err = cfnSvc.UpdateStack(&cloudformation.UpdateStackInput{
325+
TemplateBody: aws.String(body),
326+
StackName: aws.String(stackName),
327+
Capabilities: []*string{aws.String("CAPABILITY_IAM")},
328+
Tags: []*cloudformation.Tag{
329+
{
330+
Key: aws.String("ClusterName"),
331+
Value: aws.String(instance.Spec.ClusterName),
332+
},
333+
},
334+
})
335+
return err
336+
337+
}
338+
339+
func parseCFNParametersFromCRD(cp *clusterv1alpha1.ControlPlane) []*cloudformation.Parameter {
340+
var params []*cloudformation.Parameter
341+
342+
if cp.Spec.Version != nil {
343+
params = append(params, &cloudformation.Parameter{
344+
ParameterKey: aws.String("EKSVersion"),
345+
ParameterValue: aws.String(cp.GetVersion()),
346+
})
347+
}
348+
349+
return params
350+
}
351+
352+
func getCFNParametersFromCFNStack(cfnSvc cloudformationiface.CloudFormationAPI, stackName string) ([]*cloudformation.Parameter, error) {
353+
354+
output, err := cfnSvc.DescribeStacks(&cloudformation.DescribeStacksInput{
355+
StackName: aws.String(stackName),
356+
})
357+
358+
if err != nil {
359+
return nil, err
360+
}
361+
362+
if len(output.Stacks) != 1 {
363+
return nil, fmt.Errorf("Error while describing the stacks, got %d stacks for the name : %s", len(output.Stacks), stackName)
364+
}
365+
366+
return output.Stacks[0].Parameters, nil
367+
}
368+
369+
func shouldUpdate(crdParams []*cloudformation.Parameter, cfnParams []*cloudformation.Parameter) bool {
370+
cfnParamMap := make(map[string]string)
371+
for _, param := range cfnParams {
372+
cfnParamMap[*param.ParameterKey] = *param.ParameterValue
373+
}
374+
375+
for _, param := range crdParams {
376+
if cfnParamMap[*param.ParameterKey] != *param.ParameterValue {
377+
return true
378+
}
379+
}
380+
return false
381+
}

pkg/controller/nodegroup/ami.go

Lines changed: 0 additions & 44 deletions
This file was deleted.

pkg/controller/nodegroup/ami_test.go

Lines changed: 0 additions & 34 deletions
This file was deleted.

pkg/controller/nodegroup/cfn_template.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,11 @@ Parameters:
9999
Type: String
100100
Default: {{ .NodeInstanceName }}
101101
102+
NodeImageIdSSMParam:
103+
Type: "AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>"
104+
Default: {{ .NodeImageIdSSMParam }}
105+
Description: AWS Systems Manager Parameter Store parameter of the AMI ID for the worker node instances.
106+
102107
Resources:
103108
104109
NodeInstanceProfile:
@@ -237,7 +242,7 @@ Resources:
237242
Properties:
238243
AssociatePublicIpAddress: 'true'
239244
IamInstanceProfile: !Ref NodeInstanceProfile
240-
ImageId: {{ .AMI }}
245+
ImageId: !Ref NodeImageIdSSMParam
241246
InstanceType: !Ref NodeInstanceType
242247
# KeyName: !Ref KeyName
243248
SecurityGroups:

pkg/controller/nodegroup/nodegroup_controller.go

Lines changed: 37 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"context"
55
"fmt"
66
"strconv"
7+
"strings"
78
"time"
89

910
clusterv1alpha1 "github.com/awslabs/aws-eks-cluster-controller/pkg/apis/cluster/v1alpha1"
@@ -198,7 +199,7 @@ func (r *ReconcileNodeGroup) Reconcile(request reconcile.Request) (reconcile.Res
198199
}
199200
}
200201

201-
crdParameters := parseCFNParameterFromCRD(instance.Spec)
202+
crdParameters := parseCFNParametersFromCRD(instance)
202203

203204
stack, err := awsHelper.DescribeStack(cfnSvc, stackName)
204205
if err != nil && awsHelper.IsStackDoesNotExist(err) {
@@ -237,11 +238,8 @@ func (r *ReconcileNodeGroup) Reconcile(request reconcile.Request) (reconcile.Res
237238
return reconcile.Result{}, err
238239
}
239240
instance.Status.Status = StatusUpdating
240-
err = r.Update(context.TODO(), instance)
241-
if err != nil {
242-
return reconcile.Result{}, err
243-
}
244-
return reconcile.Result{Requeue: true}, nil
241+
242+
return reconcile.Result{Requeue: true}, r.Update(context.TODO(), instance)
245243
}
246244

247245
logger.Info("Found Stack", zap.String("StackStatus", *stack.StackStatus))
@@ -276,7 +274,7 @@ func (r *ReconcileNodeGroup) fail(instance *clusterv1alpha1.NodeGroup, msg strin
276274
type nodeGroupTemplateInput struct {
277275
ClusterName string
278276
ControlPlaneStackName string
279-
AMI string
277+
NodeImageIdSSMParam string
280278
NodeInstanceName string
281279
IAMPolicies []clusterv1alpha1.Policy
282280
}
@@ -286,7 +284,7 @@ func (r *ReconcileNodeGroup) createNodeGroupStack(cfnSvc cloudformationiface.Clo
286284
templateBody, err := awsHelper.GetCFNTemplateBody(nodeGroupCFNTemplate, nodeGroupTemplateInput{
287285
ClusterName: eks.Spec.ControlPlane.ClusterName,
288286
ControlPlaneStackName: eks.GetControlPlaneStackName(),
289-
AMI: GetAMI(nodegroup.GetVersion(), eks.Spec.Region),
287+
NodeImageIdSSMParam: getSSMParamKey(nodegroup.GetVersion()),
290288
NodeInstanceName: nodegroup.Name,
291289
IAMPolicies: nodegroup.Spec.IAMPolicies,
292290
})
@@ -316,7 +314,7 @@ func (r *ReconcileNodeGroup) updateNodeGroupStack(cfnSvc cloudformationiface.Clo
316314
templateBody, err := awsHelper.GetCFNTemplateBody(nodeGroupCFNTemplate, nodeGroupTemplateInput{
317315
ClusterName: eks.Spec.ControlPlane.ClusterName,
318316
ControlPlaneStackName: eks.GetControlPlaneStackName(),
319-
AMI: GetAMI(nodegroup.GetVersion(), eks.Spec.Region),
317+
NodeImageIdSSMParam: getSSMParamKey(nodegroup.GetVersion()),
320318
NodeInstanceName: nodegroup.Name,
321319
IAMPolicies: nodegroup.Spec.IAMPolicies,
322320
})
@@ -341,31 +339,37 @@ func (r *ReconcileNodeGroup) updateNodeGroupStack(cfnSvc cloudformationiface.Clo
341339
return err
342340
}
343341

344-
func parseCFNParameterFromCRD(ngSpec clusterv1alpha1.NodeGroupSpec) []*cloudformation.Parameter {
345-
if ngSpec.Instance == nil {
346-
return nil
347-
}
342+
func parseCFNParametersFromCRD(ng *clusterv1alpha1.NodeGroup) []*cloudformation.Parameter {
348343

349344
var parameter []*cloudformation.Parameter
350345

351-
if ngSpec.Instance.InstanceType != nil {
352-
parameter = append(parameter, &cloudformation.Parameter{
353-
ParameterKey: aws.String("NodeInstanceType"),
354-
ParameterValue: ngSpec.Instance.InstanceType,
355-
})
356-
}
346+
if ng.Spec.Instance != nil {
347+
if ng.Spec.Instance.InstanceType != nil {
348+
parameter = append(parameter, &cloudformation.Parameter{
349+
ParameterKey: aws.String("NodeInstanceType"),
350+
ParameterValue: ng.Spec.Instance.InstanceType,
351+
})
352+
}
357353

358-
if ngSpec.Instance.MaxInstanceCount != nil {
359-
parameter = append(parameter, &cloudformation.Parameter{
360-
ParameterKey: aws.String("NodeAutoScalingGroupMaxSize"),
361-
ParameterValue: aws.String(strconv.Itoa(*ngSpec.Instance.MaxInstanceCount)),
362-
})
354+
if ng.Spec.Instance.MaxInstanceCount != nil {
355+
parameter = append(parameter, &cloudformation.Parameter{
356+
ParameterKey: aws.String("NodeAutoScalingGroupMaxSize"),
357+
ParameterValue: aws.String(strconv.Itoa(*ng.Spec.Instance.MaxInstanceCount)),
358+
})
359+
}
360+
361+
if ng.Spec.Instance.EBSVolumeSize != nil {
362+
parameter = append(parameter, &cloudformation.Parameter{
363+
ParameterKey: aws.String("NodeVolumeSize"),
364+
ParameterValue: aws.String(strconv.Itoa(*ng.Spec.Instance.EBSVolumeSize)),
365+
})
366+
}
363367
}
364368

365-
if ngSpec.Instance.EBSVolumeSize != nil {
369+
if ng.Spec.Version != nil {
366370
parameter = append(parameter, &cloudformation.Parameter{
367-
ParameterKey: aws.String("NodeVolumeSize"),
368-
ParameterValue: aws.String(strconv.Itoa(*ngSpec.Instance.EBSVolumeSize)),
371+
ParameterKey: aws.String("NodeImageIdSSMParam"),
372+
ParameterValue: aws.String(getSSMParamKey(ng.GetVersion())),
369373
})
370374
}
371375

@@ -402,3 +406,9 @@ func shouldUpdate(crdParams []*cloudformation.Parameter, cfnParams []*cloudforma
402406
}
403407
return false
404408
}
409+
410+
func getSSMParamKey(version string) string {
411+
eksOptimizedAMIKey := "/aws/service/eks/optimized-ami/<EKS_VERSION>/amazon-linux-2/recommended/image_id"
412+
413+
return strings.Replace(eksOptimizedAMIKey, "<EKS_VERSION>", version, -1)
414+
}

0 commit comments

Comments
 (0)