Skip to content

Commit db16e3c

Browse files
AndiDogcnmcavoy
andcommitted
Add AWSMachines to back the EC2 instances in AWSMachinePools and AWSManagedMachinePools
Co-authored-by: Cameron McAvoy <[email protected]>
1 parent b99a49c commit db16e3c

16 files changed

+554
-80
lines changed

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

+4
Original file line numberDiff line numberDiff line change
@@ -1159,6 +1159,10 @@ spec:
11591159
can be added as events to the Machine object and/or logged in the
11601160
controller's output.
11611161
type: string
1162+
infrastructureMachineKind:
1163+
description: InfrastructureMachineKind is the kind of the infrastructure
1164+
resources behind MachinePool Machines.
1165+
type: string
11621166
instances:
11631167
description: Instances contains the status for each instance in the
11641168
pool

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

+4
Original file line numberDiff line numberDiff line change
@@ -1087,6 +1087,10 @@ spec:
10871087
can be added as events to the MachinePool object and/or logged in the
10881088
controller's output.
10891089
type: string
1090+
infrastructureMachineKind:
1091+
description: InfrastructureMachineKind is the kind of the infrastructure
1092+
resources behind MachinePool Machines.
1093+
type: string
10901094
launchTemplateID:
10911095
description: The ID of the launch template
10921096
type: string

config/rbac/role.yaml

+9
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,14 @@ rules:
126126
- cluster.x-k8s.io
127127
resources:
128128
- machines
129+
verbs:
130+
- delete
131+
- get
132+
- list
133+
- watch
134+
- apiGroups:
135+
- cluster.x-k8s.io
136+
resources:
129137
- machines/status
130138
verbs:
131139
- get
@@ -310,6 +318,7 @@ rules:
310318
resources:
311319
- awsmachines
312320
verbs:
321+
- create
313322
- delete
314323
- get
315324
- list

controllers/awsmachine_controller.go

+42-17
Original file line numberDiff line numberDiff line change
@@ -143,10 +143,11 @@ func (r *AWSMachineReconciler) getObjectStoreService(scope scope.S3Scope) servic
143143
return s3.NewService(scope)
144144
}
145145

146-
// +kubebuilder:rbac:groups=infrastructure.cluster.x-k8s.io,resources=awsmachines,verbs=get;list;watch;update;patch;delete
147-
// +kubebuilder:rbac:groups=infrastructure.cluster.x-k8s.io,resources=awsmachines/status,verbs=get;update;patch
148146
// +kubebuilder:rbac:groups=controlplane.cluster.x-k8s.io,resources=*,verbs=get;list;watch
149-
// +kubebuilder:rbac:groups=cluster.x-k8s.io,resources=machines;machines/status,verbs=get;list;watch
147+
// +kubebuilder:rbac:groups=infrastructure.cluster.x-k8s.io,resources=awsmachines,verbs=create;get;list;watch;update;patch;delete
148+
// +kubebuilder:rbac:groups=infrastructure.cluster.x-k8s.io,resources=awsmachines/status,verbs=get;update;patch
149+
// +kubebuilder:rbac:groups=cluster.x-k8s.io,resources=machines,verbs=get;list;watch;delete
150+
// +kubebuilder:rbac:groups=cluster.x-k8s.io,resources=machines/status,verbs=get;list;watch
150151
// +kubebuilder:rbac:groups="",resources=secrets;,verbs=get;list;watch
151152
// +kubebuilder:rbac:groups="",resources=namespaces,verbs=get;list;watch
152153
// +kubebuilder:rbac:groups="",resources=events,verbs=get;list;watch;create;update;patch
@@ -459,6 +460,7 @@ func (r *AWSMachineReconciler) findInstance(machineScope *scope.MachineScope, ec
459460
return instance, nil
460461
}
461462

463+
//nolint:gocyclo
462464
func (r *AWSMachineReconciler) reconcileNormal(_ context.Context, machineScope *scope.MachineScope, clusterScope cloud.ClusterScoper, ec2Scope scope.EC2Scope, elbScope scope.ELBScope, objectStoreScope scope.S3Scope) (ctrl.Result, error) {
463465
machineScope.Trace("Reconciling AWSMachine")
464466

@@ -482,7 +484,7 @@ func (r *AWSMachineReconciler) reconcileNormal(_ context.Context, machineScope *
482484
}
483485

484486
// Make sure bootstrap data is available and populated.
485-
if machineScope.Machine.Spec.Bootstrap.DataSecretName == nil {
487+
if !machineScope.IsMachinePoolMachine() && machineScope.Machine.Spec.Bootstrap.DataSecretName == nil {
486488
machineScope.Info("Bootstrap data secret reference is not yet available")
487489
conditions.MarkFalse(machineScope.AWSMachine, infrav1.InstanceReadyCondition, infrav1.WaitingForBootstrapDataReason, clusterv1.ConditionSeverityInfo, "")
488490
return ctrl.Result{}, nil
@@ -497,6 +499,12 @@ func (r *AWSMachineReconciler) reconcileNormal(_ context.Context, machineScope *
497499
conditions.MarkUnknown(machineScope.AWSMachine, infrav1.InstanceReadyCondition, infrav1.InstanceNotFoundReason, err.Error())
498500
return ctrl.Result{}, err
499501
}
502+
if instance == nil && machineScope.IsMachinePoolMachine() {
503+
err = errors.New("no instance found for machine pool")
504+
machineScope.Error(err, "unable to find instance")
505+
conditions.MarkUnknown(machineScope.AWSMachine, infrav1.InstanceReadyCondition, infrav1.InstanceNotFoundReason, err.Error())
506+
return ctrl.Result{}, err
507+
}
500508

501509
// If the AWSMachine doesn't have our finalizer, add it.
502510
if controllerutil.AddFinalizer(machineScope.AWSMachine, infrav1.MachineFinalizer) {
@@ -586,9 +594,18 @@ func (r *AWSMachineReconciler) reconcileNormal(_ context.Context, machineScope *
586594
conditions.MarkTrue(machineScope.AWSMachine, infrav1.InstanceReadyCondition)
587595
case infrav1.InstanceStateShuttingDown, infrav1.InstanceStateTerminated:
588596
machineScope.SetNotReady()
589-
machineScope.Info("Unexpected EC2 instance termination", "state", instance.State, "instance-id", *machineScope.GetInstanceID())
590-
r.Recorder.Eventf(machineScope.AWSMachine, corev1.EventTypeWarning, "InstanceUnexpectedTermination", "Unexpected EC2 instance termination")
591-
conditions.MarkFalse(machineScope.AWSMachine, infrav1.InstanceReadyCondition, infrav1.InstanceTerminatedReason, clusterv1.ConditionSeverityError, "")
597+
598+
if machineScope.IsMachinePoolMachine() {
599+
// In an auto-scaling group, instance termination is perfectly normal on scale-down
600+
// and therefore should not be reported as error.
601+
machineScope.Info("EC2 instance of machine pool was terminated", "state", instance.State, "instance-id", *machineScope.GetInstanceID())
602+
r.Recorder.Eventf(machineScope.AWSMachine, corev1.EventTypeNormal, infrav1.InstanceTerminatedReason, "EC2 instance termination")
603+
conditions.MarkFalse(machineScope.AWSMachine, infrav1.InstanceReadyCondition, infrav1.InstanceTerminatedReason, clusterv1.ConditionSeverityInfo, "")
604+
} else {
605+
machineScope.Info("Unexpected EC2 instance termination", "state", instance.State, "instance-id", *machineScope.GetInstanceID())
606+
r.Recorder.Eventf(machineScope.AWSMachine, corev1.EventTypeWarning, "InstanceUnexpectedTermination", "Unexpected EC2 instance termination")
607+
conditions.MarkFalse(machineScope.AWSMachine, infrav1.InstanceReadyCondition, infrav1.InstanceTerminatedReason, clusterv1.ConditionSeverityError, "")
608+
}
592609
default:
593610
machineScope.SetNotReady()
594611
machineScope.Info("EC2 instance state is undefined", "state", instance.State, "instance-id", *machineScope.GetInstanceID())
@@ -599,14 +616,18 @@ func (r *AWSMachineReconciler) reconcileNormal(_ context.Context, machineScope *
599616
}
600617

601618
// reconcile the deletion of the bootstrap data secret now that we have updated instance state
602-
if deleteSecretErr := r.deleteBootstrapData(machineScope, clusterScope, objectStoreScope); deleteSecretErr != nil {
603-
r.Log.Error(deleteSecretErr, "unable to delete secrets")
604-
return ctrl.Result{}, deleteSecretErr
605-
}
619+
if !machineScope.IsMachinePoolMachine() {
620+
if deleteSecretErr := r.deleteBootstrapData(machineScope, clusterScope, objectStoreScope); deleteSecretErr != nil {
621+
r.Log.Error(deleteSecretErr, "unable to delete secrets")
622+
return ctrl.Result{}, deleteSecretErr
623+
}
606624

607-
if instance.State == infrav1.InstanceStateTerminated {
608-
machineScope.SetFailureReason(capierrors.UpdateMachineError)
609-
machineScope.SetFailureMessage(errors.Errorf("EC2 instance state %q is unexpected", instance.State))
625+
// For machine pool machines, it is expected that the ASG terminates instances at any time,
626+
// so no error is logged for those.
627+
if instance.State == infrav1.InstanceStateTerminated {
628+
machineScope.SetFailureReason(capierrors.UpdateMachineError)
629+
machineScope.SetFailureMessage(errors.Errorf("EC2 instance state %q is unexpected", instance.State))
630+
}
610631
}
611632

612633
// tasks that can take place during all known instance states
@@ -876,9 +897,13 @@ func getIgnitionVersion(scope *scope.MachineScope) string {
876897
}
877898

878899
func (r *AWSMachineReconciler) deleteBootstrapData(machineScope *scope.MachineScope, clusterScope cloud.ClusterScoper, objectStoreScope scope.S3Scope) error {
879-
_, userDataFormat, err := machineScope.GetRawBootstrapDataWithFormat()
880-
if client.IgnoreNotFound(err) != nil {
881-
return errors.Wrap(err, "failed to get raw userdata")
900+
var userDataFormat string
901+
var err error
902+
if machineScope.Machine.Spec.Bootstrap.DataSecretName != nil {
903+
_, userDataFormat, err = machineScope.GetRawBootstrapDataWithFormat()
904+
if client.IgnoreNotFound(err) != nil {
905+
return errors.Wrap(err, "failed to get raw userdata")
906+
}
882907
}
883908

884909
if machineScope.UseSecretsManager(userDataFormat) {

exp/api/v1beta1/conversion.go

+11-1
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ func (src *AWSMachinePool) ConvertTo(dstRaw conversion.Hub) error {
5252
if restored.Spec.AvailabilityZoneSubnetType != nil {
5353
dst.Spec.AvailabilityZoneSubnetType = restored.Spec.AvailabilityZoneSubnetType
5454
}
55+
dst.Status.InfrastructureMachineKind = restored.Status.InfrastructureMachineKind
5556

5657
if restored.Spec.AWSLaunchTemplate.PrivateDNSName != nil {
5758
dst.Spec.AWSLaunchTemplate.PrivateDNSName = restored.Spec.AWSLaunchTemplate.PrivateDNSName
@@ -83,7 +84,6 @@ func (src *AWSMachinePoolList) ConvertTo(dstRaw conversion.Hub) error {
8384
// ConvertFrom converts the v1beta2 AWSMachinePoolList receiver to v1beta1 AWSMachinePoolList.
8485
func (r *AWSMachinePoolList) ConvertFrom(srcRaw conversion.Hub) error {
8586
src := srcRaw.(*infrav1exp.AWSMachinePoolList)
86-
8787
return Convert_v1beta2_AWSMachinePoolList_To_v1beta1_AWSMachinePoolList(src, r, nil)
8888
}
8989

@@ -114,6 +114,8 @@ func (src *AWSManagedMachinePool) ConvertTo(dstRaw conversion.Hub) error {
114114
dst.Spec.AvailabilityZoneSubnetType = restored.Spec.AvailabilityZoneSubnetType
115115
}
116116

117+
dst.Status.InfrastructureMachineKind = restored.Status.InfrastructureMachineKind
118+
117119
return nil
118120
}
119121

@@ -133,6 +135,14 @@ func Convert_v1beta2_AWSManagedMachinePoolSpec_To_v1beta1_AWSManagedMachinePoolS
133135
return autoConvert_v1beta2_AWSManagedMachinePoolSpec_To_v1beta1_AWSManagedMachinePoolSpec(in, out, s)
134136
}
135137

138+
func Convert_v1beta2_AWSMachinePoolStatus_To_v1beta1_AWSMachinePoolStatus(in *infrav1exp.AWSMachinePoolStatus, out *AWSMachinePoolStatus, s apiconversion.Scope) error {
139+
return autoConvert_v1beta2_AWSMachinePoolStatus_To_v1beta1_AWSMachinePoolStatus(in, out, s)
140+
}
141+
142+
func Convert_v1beta2_AWSManagedMachinePoolStatus_To_v1beta1_AWSManagedMachinePoolStatus(in *infrav1exp.AWSManagedMachinePoolStatus, out *AWSManagedMachinePoolStatus, s apiconversion.Scope) error {
143+
return autoConvert_v1beta2_AWSManagedMachinePoolStatus_To_v1beta1_AWSManagedMachinePoolStatus(in, out, s)
144+
}
145+
136146
// ConvertTo converts the v1beta1 AWSManagedMachinePoolList receiver to a v1beta2 AWSManagedMachinePoolList.
137147
func (src *AWSManagedMachinePoolList) ConvertTo(dstRaw conversion.Hub) error {
138148
dst := dstRaw.(*infrav1exp.AWSManagedMachinePoolList)

exp/api/v1beta1/zz_generated.conversion.go

+12-20
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

exp/api/v1beta2/awsmachinepool_types.go

+4
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,10 @@ type AWSMachinePoolStatus struct {
210210
// +optional
211211
LaunchTemplateVersion *string `json:"launchTemplateVersion,omitempty"`
212212

213+
// InfrastructureMachineKind is the kind of the infrastructure resources behind MachinePool Machines.
214+
// +optional
215+
InfrastructureMachineKind string `json:"infrastructureMachineKind,omitempty"`
216+
213217
// FailureReason will be set in the event that there is a terminal problem
214218
// reconciling the Machine and will contain a succinct value suitable
215219
// for machine interpretation.

exp/api/v1beta2/awsmanagedmachinepool_types.go

+4
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,10 @@ type AWSManagedMachinePoolStatus struct {
199199
// +optional
200200
LaunchTemplateVersion *string `json:"launchTemplateVersion,omitempty"`
201201

202+
// InfrastructureMachineKind is the kind of the infrastructure resources behind MachinePool Machines.
203+
// +optional
204+
InfrastructureMachineKind string `json:"infrastructureMachineKind,omitempty"`
205+
202206
// FailureReason will be set in the event that there is a terminal problem
203207
// reconciling the MachinePool and will contain a succinct value suitable
204208
// for machine interpretation.

exp/api/v1beta2/conditions_consts.go

+5
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,11 @@ const (
5454
InstanceRefreshNotReadyReason = "InstanceRefreshNotReady"
5555
// InstanceRefreshFailedReason used to report when there instance refresh is not initiated.
5656
InstanceRefreshFailedReason = "InstanceRefreshFailed"
57+
58+
// AWSMachineCreationFailed reports if creating AWSMachines to represent ASG (machine pool) machines failed.
59+
AWSMachineCreationFailed = "AWSMachineCreationFailed"
60+
// AWSMachineDeletionFailed reports if deleting AWSMachines failed.
61+
AWSMachineDeletionFailed = "AWSMachineDeletionFailed"
5762
)
5863

5964
const (

exp/api/v1beta2/types.go

+5
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,11 @@ import (
2222
infrav1 "sigs.k8s.io/cluster-api-provider-aws/v2/api/v1beta2"
2323
)
2424

25+
const (
26+
// KindMachinePool is a MachinePool resource Kind
27+
KindMachinePool string = "MachinePool"
28+
)
29+
2530
// EBS can be used to automatically set up EBS volumes when an instance is launched.
2631
type EBS struct {
2732
// Encrypted is whether the volume should be encrypted or not.

0 commit comments

Comments
 (0)