Skip to content

Commit 9ca0f6c

Browse files
committed
feat(awsmachinepool): add the ability to add lifecycle hooks
1 parent c23e955 commit 9ca0f6c

20 files changed

+839
-192
lines changed

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

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -791,6 +791,47 @@ spec:
791791
to become stable after it enters the InService state. If no value
792792
is supplied by user a default value of 300 seconds is set
793793
type: string
794+
lifecycleHooks:
795+
description: AWSLifecycleHooks specifies lifecycle hooks for the managed
796+
node group.
797+
items:
798+
description: AWSLifecycleHook describes an AWS lifecycle hook
799+
properties:
800+
defaultResult:
801+
description: The default result for the lifecycle hook. The
802+
possible values are CONTINUE and ABANDON. kubebuilder:validation:Enum=CONTINUE;ABANDON
803+
type: string
804+
heartbeatTimeout:
805+
description: The maximum time, in seconds, that an instance
806+
can remain in a Pending:Wait or Terminating:Wait state. The
807+
maximum is 172800 seconds (48 hours) or 100 times HeartbeatTimeout,
808+
whichever is smaller.
809+
format: int64
810+
type: integer
811+
lifecycleTransition:
812+
description: The state of the EC2 instance to which to attach
813+
the lifecycle hook.
814+
type: string
815+
name:
816+
description: The name of the lifecycle hook.
817+
type: string
818+
notificationMetadata:
819+
description: Contains additional metadata that will be passed
820+
to the notification target.
821+
type: string
822+
notificationTargetARN:
823+
description: The ARN of the notification target that Amazon
824+
EC2 Auto Scaling uses to notify you when an instance is in
825+
the transition state for the lifecycle hook.
826+
type: string
827+
roleARN:
828+
description: The ARN of the IAM role that allows the Auto Scaling
829+
group to publish to the specified notification target.
830+
type: string
831+
required:
832+
- lifecycleTransition
833+
type: object
834+
type: array
794835
maxSize:
795836
default: 1
796837
description: MaxSize defines the maximum size of the group.

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

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -790,6 +790,47 @@ spec:
790790
type: string
791791
description: Labels specifies labels for the Kubernetes node objects
792792
type: object
793+
lifecycleHooks:
794+
description: AWSLifecycleHooks specifies lifecycle hooks for the managed
795+
node group.
796+
items:
797+
description: AWSLifecycleHook describes an AWS lifecycle hook
798+
properties:
799+
defaultResult:
800+
description: The default result for the lifecycle hook. The
801+
possible values are CONTINUE and ABANDON. kubebuilder:validation:Enum=CONTINUE;ABANDON
802+
type: string
803+
heartbeatTimeout:
804+
description: The maximum time, in seconds, that an instance
805+
can remain in a Pending:Wait or Terminating:Wait state. The
806+
maximum is 172800 seconds (48 hours) or 100 times HeartbeatTimeout,
807+
whichever is smaller.
808+
format: int64
809+
type: integer
810+
lifecycleTransition:
811+
description: The state of the EC2 instance to which to attach
812+
the lifecycle hook.
813+
type: string
814+
name:
815+
description: The name of the lifecycle hook.
816+
type: string
817+
notificationMetadata:
818+
description: Contains additional metadata that will be passed
819+
to the notification target.
820+
type: string
821+
notificationTargetARN:
822+
description: The ARN of the notification target that Amazon
823+
EC2 Auto Scaling uses to notify you when an instance is in
824+
the transition state for the lifecycle hook.
825+
type: string
826+
roleARN:
827+
description: The ARN of the IAM role that allows the Auto Scaling
828+
group to publish to the specified notification target.
829+
type: string
830+
required:
831+
- lifecycleTransition
832+
type: object
833+
type: array
793834
providerIDList:
794835
description: ProviderIDList are the provider IDs of instances in the
795836
autoscaling group corresponding to the nodegroup represented by

exp/api/v1beta1/zz_generated.conversion.go

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

exp/api/v1beta2/awsmachinepool_types.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,10 @@ type AWSMachinePoolSpec struct {
101101
// SuspendProcesses defines a list of processes to suspend for the given ASG. This is constantly reconciled.
102102
// If a process is removed from this list it will automatically be resumed.
103103
SuspendProcesses *SuspendProcessesTypes `json:"suspendProcesses,omitempty"`
104+
105+
// AWSLifecycleHooks specifies lifecycle hooks for the managed node group.
106+
// +optional
107+
AWSLifecycleHooks []AWSLifecycleHook `json:"lifecycleHooks,omitempty"`
104108
}
105109

106110
// SuspendProcessesTypes contains user friendly auto-completable values for suspended process names.

exp/api/v1beta2/awsmanagedmachinepool_types.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,10 @@ type AWSManagedMachinePoolSpec struct {
155155
// are prohibited (https://docs.aws.amazon.com/eks/latest/userguide/launch-templates.html).
156156
// +optional
157157
AWSLaunchTemplate *AWSLaunchTemplate `json:"awsLaunchTemplate,omitempty"`
158+
159+
// AWSLifecycleHooks specifies lifecycle hooks for the managed node group.
160+
// +optional
161+
AWSLifecycleHooks []AWSLifecycleHook `json:"lifecycleHooks,omitempty"`
158162
}
159163

160164
// ManagedMachinePoolScaling specifies scaling options.

exp/api/v1beta2/conditions_consts.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,17 @@ const (
5454
InstanceRefreshNotReadyReason = "InstanceRefreshNotReady"
5555
// InstanceRefreshFailedReason used to report when there instance refresh is not initiated.
5656
InstanceRefreshFailedReason = "InstanceRefreshFailed"
57+
58+
// LifecycleHookReadyCondition reports on the status of the lifecycle hook.
59+
LifecycleHookReadyCondition clusterv1.ConditionType = "LifecycleHookReady"
60+
// LifecycleHookNotFoundReason used when the lifecycle hook couldn't be retrieved.
61+
LifecycleHookNotFoundReason = "LifecycleHookNotFound"
62+
// LifecycleHookExistsCondition reports on the existence of the lifecycle hook.
63+
LifecycleHookExistsCondition clusterv1.ConditionType = "LifecycleHookExists"
64+
// LifecycleHookCreationFailedReason used for failures during lifecycle hook creation.
65+
LifecycleHookCreationFailedReason = "LifecycleHookCreationFailed"
66+
// LifecycleHookUpdateFailedReason used for failures during lifecycle hook update.
67+
LifecycleHookUpdateFailedReason = "LifecycleHookUpdateFailed"
5768
)
5869

5970
const (

exp/api/v1beta2/types.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,40 @@ type AutoScalingGroup struct {
217217
CurrentlySuspendProcesses []string `json:"currentlySuspendProcesses,omitempty"`
218218
}
219219

220+
// AWSLifecycleHook describes an AWS lifecycle hook
221+
type AWSLifecycleHook struct {
222+
// The name of the lifecycle hook.
223+
Name string `json:"name,omitempty"`
224+
225+
// The ARN of the notification target that Amazon EC2 Auto Scaling uses to
226+
// notify you when an instance is in the transition state for the lifecycle hook.
227+
// +optional
228+
NotificationTargetARN *string `json:"notificationTargetARN,omitempty"`
229+
230+
// The ARN of the IAM role that allows the Auto Scaling group to publish to the
231+
// specified notification target.
232+
// +optional
233+
RoleARN *string `json:"roleARN,omitempty"`
234+
235+
// The state of the EC2 instance to which to attach the lifecycle hook.
236+
LifecycleTransition string `json:"lifecycleTransition"`
237+
238+
// The maximum time, in seconds, that an instance can remain in a Pending:Wait or
239+
// Terminating:Wait state. The maximum is 172800 seconds (48 hours) or 100 times
240+
// HeartbeatTimeout, whichever is smaller.
241+
// +optional
242+
HeartbeatTimeout *int64 `json:"heartbeatTimeout,omitempty"`
243+
244+
// The default result for the lifecycle hook. The possible values are CONTINUE and ABANDON.
245+
// kubebuilder:validation:Enum=CONTINUE;ABANDON
246+
// +optional
247+
DefaultResult *string `json:"defaultResult,omitempty"`
248+
249+
// Contains additional metadata that will be passed to the notification target.
250+
// +optional
251+
NotificationMetadata *string `json:"notificationMetadata,omitempty"`
252+
}
253+
220254
// ASGStatus is a status string returned by the autoscaling API.
221255
type ASGStatus string
222256

exp/api/v1beta2/zz_generated.deepcopy.go

Lines changed: 54 additions & 0 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: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ import (
4646
"sigs.k8s.io/cluster-api-provider-aws/v2/pkg/cloud/services"
4747
asg "sigs.k8s.io/cluster-api-provider-aws/v2/pkg/cloud/services/autoscaling"
4848
"sigs.k8s.io/cluster-api-provider-aws/v2/pkg/cloud/services/ec2"
49+
"sigs.k8s.io/cluster-api-provider-aws/v2/pkg/cloud/services/machinepool"
4950
"sigs.k8s.io/cluster-api-provider-aws/v2/pkg/logger"
5051
clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
5152
expclusterv1 "sigs.k8s.io/cluster-api/exp/api/v1beta1"
@@ -62,7 +63,7 @@ type AWSMachinePoolReconciler struct {
6263
WatchFilterValue string
6364
asgServiceFactory func(cloud.ClusterScoper) services.ASGInterface
6465
ec2ServiceFactory func(scope.EC2Scope) services.EC2Interface
65-
reconcileServiceFactory func(scope.EC2Scope) services.MachinePoolReconcileInterface
66+
reconcileServiceFactory func(EC2Interface services.EC2Interface, ASGInterface services.ASGInterface) services.MachinePoolReconcileInterface
6667
TagUnmanagedNetworkResources bool
6768
}
6869

@@ -81,12 +82,12 @@ func (r *AWSMachinePoolReconciler) getEC2Service(scope scope.EC2Scope) services.
8182
return ec2.NewService(scope)
8283
}
8384

84-
func (r *AWSMachinePoolReconciler) getReconcileService(scope scope.EC2Scope) services.MachinePoolReconcileInterface {
85+
func (r *AWSMachinePoolReconciler) getReconcileService(EC2Interface services.EC2Interface, ASGInterface services.ASGInterface) services.MachinePoolReconcileInterface {
8586
if r.reconcileServiceFactory != nil {
86-
return r.reconcileServiceFactory(scope)
87+
return r.reconcileServiceFactory(EC2Interface, ASGInterface)
8788
}
8889

89-
return ec2.NewService(scope)
90+
return machinepool.NewService(EC2Interface, ASGInterface)
9091
}
9192

9293
// +kubebuilder:rbac:groups=infrastructure.cluster.x-k8s.io,resources=awsmachinepools,verbs=get;list;watch;update;patch;delete
@@ -237,7 +238,7 @@ func (r *AWSMachinePoolReconciler) reconcileNormal(ctx context.Context, machineP
237238

238239
ec2Svc := r.getEC2Service(ec2Scope)
239240
asgsvc := r.getASGService(clusterScope)
240-
reconSvc := r.getReconcileService(ec2Scope)
241+
reconSvc := r.getReconcileService(ec2Svc, asgsvc)
241242

242243
// Find existing ASG
243244
asg, err := r.findASG(machinePoolScope, asgsvc)
@@ -298,6 +299,11 @@ func (r *AWSMachinePoolReconciler) reconcileNormal(ctx context.Context, machineP
298299
return nil
299300
}
300301

302+
if err := reconSvc.ReconcileLifecycleHooks(machinePoolScope); err != nil {
303+
r.Recorder.Eventf(machinePoolScope.AWSMachinePool, corev1.EventTypeWarning, "FaileLifecycleHooksReconcile", "Failed to reconcile lifecycle hooks: %v", err)
304+
return errors.Wrap(err, "failed to reconcile lifecycle hooks")
305+
}
306+
301307
if annotations.ReplicasManagedByExternalAutoscaler(machinePoolScope.MachinePool) {
302308
// Set MachinePool replicas to the ASG DesiredCapacity
303309
if *machinePoolScope.MachinePool.Spec.Replicas != *asg.DesiredCapacity {

exp/controllers/awsmachinepool_controller_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ func TestAWSMachinePoolReconciler(t *testing.T) {
169169
asgServiceFactory: func(cloud.ClusterScoper) services.ASGInterface {
170170
return asgSvc
171171
},
172-
reconcileServiceFactory: func(scope.EC2Scope) services.MachinePoolReconcileInterface {
172+
reconcileServiceFactory: func(services.EC2Interface, services.ASGInterface) services.MachinePoolReconcileInterface {
173173
return reconSvc
174174
},
175175
Recorder: recorder,

0 commit comments

Comments
 (0)