Skip to content

Commit dba86fc

Browse files
authored
Merge pull request #4619 from AndiDog/machine-pool-bootstrap-config-ref-rotation
✨ Trigger machine pool instance refresh (node rollout) if bootstrap config reference changes
2 parents f1d1d05 + 7d2df5d commit dba86fc

13 files changed

+613
-160
lines changed

api/v1beta2/tags.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,11 @@ const (
190190

191191
// MachineNameTagKey is the key for machine name.
192192
MachineNameTagKey = "MachineName"
193+
194+
// LaunchTemplateBootstrapDataSecret is the tag we use to store the `<namespace>/<name>`
195+
// of the bootstrap secret that was used to create the user data for the latest launch
196+
// template version.
197+
LaunchTemplateBootstrapDataSecret = NameAWSProviderPrefix + "bootstrap-data-secret"
193198
)
194199

195200
// ClusterTagKey generates the key for resources associated with a cluster.

exp/controllers/awsmachinepool_controller.go

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ type AWSMachinePoolReconciler struct {
6161
WatchFilterValue string
6262
asgServiceFactory func(cloud.ClusterScoper) services.ASGInterface
6363
ec2ServiceFactory func(scope.EC2Scope) services.EC2Interface
64+
reconcileServiceFactory func(scope.EC2Scope) services.MachinePoolReconcileInterface
6465
TagUnmanagedNetworkResources bool
6566
}
6667

@@ -79,6 +80,14 @@ func (r *AWSMachinePoolReconciler) getEC2Service(scope scope.EC2Scope) services.
7980
return ec2.NewService(scope)
8081
}
8182

83+
func (r *AWSMachinePoolReconciler) getReconcileService(scope scope.EC2Scope) services.MachinePoolReconcileInterface {
84+
if r.reconcileServiceFactory != nil {
85+
return r.reconcileServiceFactory(scope)
86+
}
87+
88+
return ec2.NewService(scope)
89+
}
90+
8291
// +kubebuilder:rbac:groups=infrastructure.cluster.x-k8s.io,resources=awsmachinepools,verbs=get;list;watch;update;patch;delete
8392
// +kubebuilder:rbac:groups=infrastructure.cluster.x-k8s.io,resources=awsmachinepools/status,verbs=get;update;patch
8493
// +kubebuilder:rbac:groups=cluster.x-k8s.io,resources=machinepools;machinepools/status,verbs=get;list;watch;patch
@@ -227,6 +236,7 @@ func (r *AWSMachinePoolReconciler) reconcileNormal(ctx context.Context, machineP
227236

228237
ec2Svc := r.getEC2Service(ec2Scope)
229238
asgsvc := r.getASGService(clusterScope)
239+
reconSvc := r.getReconcileService(ec2Scope)
230240

231241
// Find existing ASG
232242
asg, err := r.findASG(machinePoolScope, asgsvc)
@@ -269,7 +279,7 @@ func (r *AWSMachinePoolReconciler) reconcileNormal(ctx context.Context, machineP
269279
machinePoolScope.Info("starting instance refresh", "number of instances", machinePoolScope.MachinePool.Spec.Replicas)
270280
return asgsvc.StartASGInstanceRefresh(machinePoolScope)
271281
}
272-
if err := ec2Svc.ReconcileLaunchTemplate(machinePoolScope, canUpdateLaunchTemplate, runPostLaunchTemplateUpdateOperation); err != nil {
282+
if err := reconSvc.ReconcileLaunchTemplate(machinePoolScope, ec2Svc, canUpdateLaunchTemplate, runPostLaunchTemplateUpdateOperation); err != nil {
273283
r.Recorder.Eventf(machinePoolScope.AWSMachinePool, corev1.EventTypeWarning, "FailedLaunchTemplateReconcile", "Failed to reconcile launch template: %v", err)
274284
machinePoolScope.Error(err, "failed to reconcile launch template")
275285
return err
@@ -317,7 +327,7 @@ func (r *AWSMachinePoolReconciler) reconcileNormal(ctx context.Context, machineP
317327
ResourceService: asgsvc,
318328
},
319329
}
320-
err = ec2Svc.ReconcileTags(machinePoolScope, resourceServiceToUpdate)
330+
err = reconSvc.ReconcileTags(machinePoolScope, resourceServiceToUpdate)
321331
if err != nil {
322332
return errors.Wrap(err, "error updating tags")
323333
}
@@ -378,7 +388,7 @@ func (r *AWSMachinePoolReconciler) reconcileDelete(machinePoolScope *scope.Machi
378388
}
379389

380390
launchTemplateID := machinePoolScope.AWSMachinePool.Status.LaunchTemplateID
381-
launchTemplate, _, err := ec2Svc.GetLaunchTemplate(machinePoolScope.LaunchTemplateName())
391+
launchTemplate, _, _, err := ec2Svc.GetLaunchTemplate(machinePoolScope.LaunchTemplateName())
382392
if err != nil {
383393
return err
384394
}
@@ -422,7 +432,7 @@ func (r *AWSMachinePoolReconciler) updatePool(machinePoolScope *scope.MachinePoo
422432

423433
asgDiff := diffASG(machinePoolScope, existingASG)
424434
if asgDiff != "" {
425-
machinePoolScope.Debug("asg diff detected", "diff", subnetDiff)
435+
machinePoolScope.Debug("asg diff detected", "asgDiff", asgDiff, "subnetDiff", subnetDiff)
426436
}
427437
if asgDiff != "" || subnetDiff != "" {
428438
machinePoolScope.Info("updating AutoScalingGroup")

exp/controllers/awsmachinepool_controller_test.go

Lines changed: 284 additions & 36 deletions
Large diffs are not rendered by default.

exp/controllers/awsmanagedmachinepool_controller.go

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,7 @@ func (r *AWSManagedMachinePoolReconciler) reconcileNormal(
207207

208208
ekssvc := eks.NewNodegroupService(machinePoolScope)
209209
ec2svc := r.getEC2Service(ec2Scope)
210+
reconSvc := r.getReconcileService(ec2Scope)
210211

211212
if machinePoolScope.ManagedMachinePool.Spec.AWSLaunchTemplate != nil {
212213
canUpdateLaunchTemplate := func() (bool, error) {
@@ -215,7 +216,7 @@ func (r *AWSManagedMachinePoolReconciler) reconcileNormal(
215216
runPostLaunchTemplateUpdateOperation := func() error {
216217
return nil
217218
}
218-
if err := ec2svc.ReconcileLaunchTemplate(machinePoolScope, canUpdateLaunchTemplate, runPostLaunchTemplateUpdateOperation); err != nil {
219+
if err := reconSvc.ReconcileLaunchTemplate(machinePoolScope, ec2svc, canUpdateLaunchTemplate, runPostLaunchTemplateUpdateOperation); err != nil {
219220
r.Recorder.Eventf(machinePoolScope.ManagedMachinePool, corev1.EventTypeWarning, "FailedLaunchTemplateReconcile", "Failed to reconcile launch template: %v", err)
220221
machinePoolScope.Error(err, "failed to reconcile launch template")
221222
conditions.MarkFalse(machinePoolScope.ManagedMachinePool, expinfrav1.LaunchTemplateReadyCondition, expinfrav1.LaunchTemplateReconcileFailedReason, clusterv1.ConditionSeverityError, "")
@@ -227,7 +228,7 @@ func (r *AWSManagedMachinePoolReconciler) reconcileNormal(
227228
ResourceID: &launchTemplateID,
228229
ResourceService: ec2svc,
229230
}}
230-
if err := ec2svc.ReconcileTags(machinePoolScope, resourceServiceToUpdate); err != nil {
231+
if err := reconSvc.ReconcileTags(machinePoolScope, resourceServiceToUpdate); err != nil {
231232
return errors.Wrap(err, "error updating tags")
232233
}
233234

@@ -258,7 +259,7 @@ func (r *AWSManagedMachinePoolReconciler) reconcileDelete(
258259

259260
if machinePoolScope.ManagedMachinePool.Spec.AWSLaunchTemplate != nil {
260261
launchTemplateID := machinePoolScope.ManagedMachinePool.Status.LaunchTemplateID
261-
launchTemplate, _, err := ec2Svc.GetLaunchTemplate(machinePoolScope.LaunchTemplateName())
262+
launchTemplate, _, _, err := ec2Svc.GetLaunchTemplate(machinePoolScope.LaunchTemplateName())
262263
if err != nil {
263264
return err
264265
}
@@ -347,3 +348,7 @@ func managedControlPlaneToManagedMachinePoolMapFunc(c client.Client, gvk schema.
347348
func (r *AWSManagedMachinePoolReconciler) getEC2Service(scope scope.EC2Scope) services.EC2Interface {
348349
return ec2.NewService(scope)
349350
}
351+
352+
func (r *AWSManagedMachinePoolReconciler) getReconcileService(scope scope.EC2Scope) services.MachinePoolReconcileInterface {
353+
return ec2.NewService(scope)
354+
}

pkg/cloud/scope/launchtemplate.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package scope
1818

1919
import (
2020
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
21+
"k8s.io/apimachinery/pkg/types"
2122
"sigs.k8s.io/controller-runtime/pkg/client"
2223

2324
infrav1 "sigs.k8s.io/cluster-api-provider-aws/v2/api/v1beta2"
@@ -36,7 +37,7 @@ type LaunchTemplateScope interface {
3637
SetLaunchTemplateIDStatus(id string)
3738
GetLaunchTemplateLatestVersionStatus() string
3839
SetLaunchTemplateLatestVersionStatus(version string)
39-
GetRawBootstrapData() ([]byte, error)
40+
GetRawBootstrapData() ([]byte, *types.NamespacedName, error)
4041

4142
IsEKSManaged() bool
4243
AdditionalTags() infrav1.Tags

pkg/cloud/scope/machinepool.go

Lines changed: 10 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -131,36 +131,32 @@ func (m *MachinePoolScope) Namespace() string {
131131
return m.AWSMachinePool.Namespace
132132
}
133133

134-
// GetRawBootstrapData returns the bootstrap data from the secret in the Machine's bootstrap.dataSecretName.
135-
// todo(rudoi): stolen from MachinePool - any way to reuse?
136-
func (m *MachinePoolScope) GetRawBootstrapData() ([]byte, error) {
137-
data, _, err := m.getBootstrapData()
134+
// GetRawBootstrapData returns the bootstrap data from the secret in the Machine's bootstrap.dataSecretName,
135+
// including the secret's namespaced name.
136+
func (m *MachinePoolScope) GetRawBootstrapData() ([]byte, *types.NamespacedName, error) {
137+
data, _, bootstrapDataSecretKey, err := m.getBootstrapData()
138138

139-
return data, err
139+
return data, bootstrapDataSecretKey, err
140140
}
141141

142-
func (m *MachinePoolScope) GetRawBootstrapDataWithFormat() ([]byte, string, error) {
143-
return m.getBootstrapData()
144-
}
145-
146-
func (m *MachinePoolScope) getBootstrapData() ([]byte, string, error) {
142+
func (m *MachinePoolScope) getBootstrapData() ([]byte, string, *types.NamespacedName, error) {
147143
if m.MachinePool.Spec.Template.Spec.Bootstrap.DataSecretName == nil {
148-
return nil, "", errors.New("error retrieving bootstrap data: linked Machine's bootstrap.dataSecretName is nil")
144+
return nil, "", nil, errors.New("error retrieving bootstrap data: linked Machine's bootstrap.dataSecretName is nil")
149145
}
150146

151147
secret := &corev1.Secret{}
152148
key := types.NamespacedName{Namespace: m.Namespace(), Name: *m.MachinePool.Spec.Template.Spec.Bootstrap.DataSecretName}
153149

154150
if err := m.Client.Get(context.TODO(), key, secret); err != nil {
155-
return nil, "", errors.Wrapf(err, "failed to retrieve bootstrap data secret %s for AWSMachine %s/%s", key.Name, m.Namespace(), m.Name())
151+
return nil, "", nil, errors.Wrapf(err, "failed to retrieve bootstrap data secret %s for AWSMachinePool %s/%s", key.Name, m.Namespace(), m.Name())
156152
}
157153

158154
value, ok := secret.Data["value"]
159155
if !ok {
160-
return nil, "", errors.New("error retrieving bootstrap data: secret value key is missing")
156+
return nil, "", nil, errors.New("error retrieving bootstrap data: secret value key is missing")
161157
}
162158

163-
return value, string(secret.Data["format"]), nil
159+
return value, string(secret.Data["format"]), &key, nil
164160
}
165161

166162
// AdditionalTags merges AdditionalTags from the scope's AWSCluster and AWSMachinePool. If the same key is present in both,

pkg/cloud/scope/managednodegroup.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -323,24 +323,24 @@ func (s *ManagedMachinePoolScope) Namespace() string {
323323
return s.ManagedMachinePool.Namespace
324324
}
325325

326-
func (s *ManagedMachinePoolScope) GetRawBootstrapData() ([]byte, error) {
326+
func (s *ManagedMachinePoolScope) GetRawBootstrapData() ([]byte, *types.NamespacedName, error) {
327327
if s.MachinePool.Spec.Template.Spec.Bootstrap.DataSecretName == nil {
328-
return nil, errors.New("error retrieving bootstrap data: linked Machine's bootstrap.dataSecretName is nil")
328+
return nil, nil, errors.New("error retrieving bootstrap data: linked Machine's bootstrap.dataSecretName is nil")
329329
}
330330

331331
secret := &corev1.Secret{}
332332
key := types.NamespacedName{Namespace: s.Namespace(), Name: *s.MachinePool.Spec.Template.Spec.Bootstrap.DataSecretName}
333333

334334
if err := s.Client.Get(context.TODO(), key, secret); err != nil {
335-
return nil, errors.Wrapf(err, "failed to retrieve bootstrap data secret for AWSManagedMachinePool %s/%s", s.Namespace(), s.Name())
335+
return nil, nil, errors.Wrapf(err, "failed to retrieve bootstrap data secret for AWSManagedMachinePool %s/%s", s.Namespace(), s.Name())
336336
}
337337

338338
value, ok := secret.Data["value"]
339339
if !ok {
340-
return nil, errors.New("error retrieving bootstrap data: secret value key is missing")
340+
return nil, nil, errors.New("error retrieving bootstrap data: secret value key is missing")
341341
}
342342

343-
return value, nil
343+
return value, &key, nil
344344
}
345345

346346
func (s *ManagedMachinePoolScope) GetObjectMeta() *metav1.ObjectMeta {

0 commit comments

Comments
 (0)