@@ -18,10 +18,12 @@ package controllers
18
18
19
19
import (
20
20
"context"
21
+ "encoding/json"
21
22
"fmt"
22
23
"reflect"
23
24
24
25
"github.com/aws/aws-sdk-go/aws"
26
+ ignTypes "github.com/flatcar-linux/ignition/config/v2_3/types"
25
27
"github.com/go-logr/logr"
26
28
"github.com/pkg/errors"
27
29
corev1 "k8s.io/api/core/v1"
@@ -46,6 +48,7 @@ import (
46
48
"sigs.k8s.io/cluster-api-provider-aws/pkg/cloud/services/ec2"
47
49
"sigs.k8s.io/cluster-api-provider-aws/pkg/cloud/services/elb"
48
50
"sigs.k8s.io/cluster-api-provider-aws/pkg/cloud/services/instancestate"
51
+ "sigs.k8s.io/cluster-api-provider-aws/pkg/cloud/services/s3"
49
52
"sigs.k8s.io/cluster-api-provider-aws/pkg/cloud/services/secretsmanager"
50
53
"sigs.k8s.io/cluster-api-provider-aws/pkg/cloud/services/ssm"
51
54
"sigs.k8s.io/cluster-api-provider-aws/pkg/cloud/services/userdata"
@@ -70,6 +73,7 @@ type AWSMachineReconciler struct {
70
73
elbServiceFactory func (scope.ELBScope ) services.ELBInterface
71
74
secretsManagerServiceFactory func (cloud.ClusterScoper ) services.SecretInterface
72
75
SSMServiceFactory func (cloud.ClusterScoper ) services.SecretInterface
76
+ objectStoreServiceFactory func (cloud.ClusterScoper ) services.ObjectStoreInterface
73
77
Endpoints []scope.ServiceEndpoint
74
78
WatchFilterValue string
75
79
}
@@ -119,6 +123,14 @@ func (r *AWSMachineReconciler) getELBService(elbScope scope.ELBScope) services.E
119
123
return elb .NewService (elbScope )
120
124
}
121
125
126
+ func (r * AWSMachineReconciler ) getObjectStoreService (scope scope.S3Scope ) services.ObjectStoreInterface {
127
+ if r .objectStoreServiceFactory != nil {
128
+ return r .objectStoreServiceFactory (scope )
129
+ }
130
+
131
+ return s3 .NewService (scope )
132
+ }
133
+
122
134
// +kubebuilder:rbac:groups=infrastructure.cluster.x-k8s.io,resources=awsmachines,verbs=get;list;watch;create;update;patch;delete
123
135
// +kubebuilder:rbac:groups=infrastructure.cluster.x-k8s.io,resources=awsmachines/status,verbs=get;update;patch
124
136
// +kubebuilder:rbac:groups=cluster.x-k8s.io,resources=machines;machines/status,verbs=get;list;watch
@@ -197,16 +209,16 @@ func (r *AWSMachineReconciler) Reconcile(ctx context.Context, req ctrl.Request)
197
209
switch infraScope := infraCluster .(type ) {
198
210
case * scope.ManagedControlPlaneScope :
199
211
if ! awsMachine .ObjectMeta .DeletionTimestamp .IsZero () {
200
- return r .reconcileDelete (machineScope , infraScope , infraScope , nil )
212
+ return r .reconcileDelete (machineScope , infraScope , infraScope , nil , nil )
201
213
}
202
214
203
- return r .reconcileNormal (ctx , machineScope , infraScope , infraScope , nil )
215
+ return r .reconcileNormal (ctx , machineScope , infraScope , infraScope , nil , nil )
204
216
case * scope.ClusterScope :
205
217
if ! awsMachine .ObjectMeta .DeletionTimestamp .IsZero () {
206
- return r .reconcileDelete (machineScope , infraScope , infraScope , infraScope )
218
+ return r .reconcileDelete (machineScope , infraScope , infraScope , infraScope , infraScope )
207
219
}
208
220
209
- return r .reconcileNormal (ctx , machineScope , infraScope , infraScope , infraScope )
221
+ return r .reconcileNormal (ctx , machineScope , infraScope , infraScope , infraScope , infraScope )
210
222
default :
211
223
return ctrl.Result {}, errors .New ("infraCluster has unknown type" )
212
224
}
@@ -271,16 +283,14 @@ func (r *AWSMachineReconciler) SetupWithManager(ctx context.Context, mgr ctrl.Ma
271
283
)
272
284
}
273
285
274
- func (r * AWSMachineReconciler ) reconcileDelete (machineScope * scope.MachineScope , clusterScope cloud.ClusterScoper , ec2Scope scope.EC2Scope , elbScope scope.ELBScope ) (ctrl.Result , error ) {
286
+ func (r * AWSMachineReconciler ) reconcileDelete (machineScope * scope.MachineScope , clusterScope cloud.ClusterScoper , ec2Scope scope.EC2Scope , elbScope scope.ELBScope , objectStoreScope scope. S3Scope ) (ctrl.Result , error ) {
275
287
machineScope .Info ("Handling deleted AWSMachine" )
276
288
277
289
ec2Service := r .getEC2Service (ec2Scope )
278
290
279
- if machineScope .UseSecretsManager () {
280
- if err := r .deleteEncryptedBootstrapDataSecret (machineScope , clusterScope ); err != nil {
281
- machineScope .Error (err , "unable to delete machine" )
282
- return ctrl.Result {}, err
283
- }
291
+ if err := r .deleteBootstrapData (machineScope , clusterScope , objectStoreScope ); err != nil {
292
+ machineScope .Error (err , "unable to delete machine" )
293
+ return ctrl.Result {}, err
284
294
}
285
295
286
296
instance , err := r .findInstance (machineScope , ec2Service )
@@ -418,19 +428,17 @@ func (r *AWSMachineReconciler) findInstance(scope *scope.MachineScope, ec2svc se
418
428
return instance , nil
419
429
}
420
430
421
- func (r * AWSMachineReconciler ) reconcileNormal (_ context.Context , machineScope * scope.MachineScope , clusterScope cloud.ClusterScoper , ec2Scope scope.EC2Scope , elbScope scope.ELBScope ) (ctrl.Result , error ) {
431
+ func (r * AWSMachineReconciler ) reconcileNormal (_ context.Context , machineScope * scope.MachineScope , clusterScope cloud.ClusterScoper , ec2Scope scope.EC2Scope , elbScope scope.ELBScope , objectStoreScope scope. S3Scope ) (ctrl.Result , error ) {
422
432
machineScope .Info ("Reconciling AWSMachine" )
423
433
424
434
// If the AWSMachine is in an error state, return early.
425
435
if machineScope .HasFailed () {
426
436
machineScope .Info ("Error state detected, skipping reconciliation" )
427
437
428
- if machineScope .UseSecretsManager () {
429
- // If we are in a failed state, delete the secret regardless of instance state
430
- if err := r .deleteEncryptedBootstrapDataSecret (machineScope , clusterScope ); err != nil {
431
- machineScope .Error (err , "unable to reconcile machine" )
432
- return ctrl.Result {}, err
433
- }
438
+ // If we are in a failed state, delete the secret regardless of instance state.
439
+ if err := r .deleteBootstrapData (machineScope , clusterScope , objectStoreScope ); err != nil {
440
+ machineScope .Error (err , "unable to reconcile machine" )
441
+ return ctrl.Result {}, err
434
442
}
435
443
436
444
return ctrl.Result {}, nil
@@ -477,7 +485,14 @@ func (r *AWSMachineReconciler) reconcileNormal(_ context.Context, machineScope *
477
485
return ctrl.Result {}, patchErr
478
486
}
479
487
}
480
- instance , err = r .createInstance (ec2svc , machineScope , clusterScope )
488
+
489
+ var objectStoreSvc services.ObjectStoreInterface
490
+
491
+ if objectStoreScope != nil {
492
+ objectStoreSvc = r .getObjectStoreService (objectStoreScope )
493
+ }
494
+
495
+ instance , err = r .createInstance (ec2svc , machineScope , clusterScope , objectStoreSvc )
481
496
if err != nil {
482
497
machineScope .Error (err , "unable to create instance" )
483
498
conditions .MarkFalse (machineScope .AWSMachine , infrav1 .InstanceReadyCondition , infrav1 .InstanceProvisionFailedReason , clusterv1 .ConditionSeverityError , err .Error ())
@@ -533,7 +548,7 @@ func (r *AWSMachineReconciler) reconcileNormal(_ context.Context, machineScope *
533
548
}
534
549
535
550
// reconcile the deletion of the bootstrap data secret now that we have updated instance state
536
- if deleteSecretErr := r .deleteEncryptedBootstrapDataSecret (machineScope , clusterScope ); deleteSecretErr != nil {
551
+ if deleteSecretErr := r .deleteBootstrapData (machineScope , clusterScope , objectStoreScope ); deleteSecretErr != nil {
537
552
r .Log .Error (deleteSecretErr , "unable to delete secrets" )
538
553
return ctrl.Result {}, deleteSecretErr
539
554
}
@@ -585,10 +600,6 @@ func (r *AWSMachineReconciler) reconcileNormal(_ context.Context, machineScope *
585
600
}
586
601
587
602
func (r * AWSMachineReconciler ) deleteEncryptedBootstrapDataSecret (machineScope * scope.MachineScope , clusterScope cloud.ClusterScoper ) error {
588
- if ! machineScope .UseSecretsManager () {
589
- return nil
590
- }
591
-
592
603
secretSvc , secretBackendErr := r .getSecretService (machineScope , clusterScope )
593
604
if secretBackendErr != nil {
594
605
machineScope .Error (secretBackendErr , "unable to get secret service backend" )
@@ -621,33 +632,41 @@ func (r *AWSMachineReconciler) deleteEncryptedBootstrapDataSecret(machineScope *
621
632
return nil
622
633
}
623
634
624
- func (r * AWSMachineReconciler ) createInstance (ec2svc services.EC2Interface , machineScope * scope.MachineScope , clusterScope cloud.ClusterScoper ) (* infrav1.Instance , error ) {
635
+ func (r * AWSMachineReconciler ) createInstance (ec2svc services.EC2Interface , machineScope * scope.MachineScope , clusterScope cloud.ClusterScoper , objectStoreSvc services. ObjectStoreInterface ) (* infrav1.Instance , error ) {
625
636
machineScope .Info ("Creating EC2 instance" )
626
637
627
- userData , userDataErr := r .resolveUserData (machineScope , clusterScope )
638
+ userData , userDataFormat , userDataErr := r .resolveUserData (machineScope , clusterScope , objectStoreSvc )
628
639
if userDataErr != nil {
629
640
return nil , errors .Wrapf (userDataErr , "failed to resolve userdata" )
630
641
}
631
642
632
- instance , err := ec2svc .CreateInstance (machineScope , userData )
643
+ instance , err := ec2svc .CreateInstance (machineScope , userData , userDataFormat )
633
644
if err != nil {
634
645
return nil , errors .Wrapf (err , "failed to create AWSMachine instance" )
635
646
}
636
647
637
648
return instance , nil
638
649
}
639
650
640
- func (r * AWSMachineReconciler ) resolveUserData (machineScope * scope.MachineScope , clusterScope cloud.ClusterScoper ) ([]byte , error ) {
641
- userData , err := machineScope .GetRawBootstrapData ()
651
+ func (r * AWSMachineReconciler ) resolveUserData (machineScope * scope.MachineScope , clusterScope cloud.ClusterScoper , objectStoreSvc services. ObjectStoreInterface ) ([]byte , string , error ) {
652
+ userData , userDataFormat , err := machineScope .GetRawBootstrapDataWithFormat ()
642
653
if err != nil {
643
654
r .Recorder .Eventf (machineScope .AWSMachine , corev1 .EventTypeWarning , "FailedGetBootstrapData" , err .Error ())
644
- return nil , err
655
+ return nil , "" , err
656
+ }
657
+
658
+ if machineScope .UseSecretsManager (userDataFormat ) {
659
+ userData , err = r .cloudInitUserData (machineScope , clusterScope , userData )
645
660
}
646
661
647
- if ! machineScope .UseSecretsManager ( ) {
648
- return userData , nil
662
+ if machineScope .UseIgnition ( userDataFormat ) {
663
+ userData , err = r . ignitionUserData ( machineScope , objectStoreSvc , userData )
649
664
}
650
665
666
+ return userData , userDataFormat , err
667
+ }
668
+
669
+ func (r * AWSMachineReconciler ) cloudInitUserData (machineScope * scope.MachineScope , clusterScope cloud.ClusterScoper , userData []byte ) ([]byte , error ) {
651
670
secretSvc , secretBackendErr := r .getSecretService (machineScope , clusterScope )
652
671
if secretBackendErr != nil {
653
672
machineScope .Error (secretBackendErr , "unable to reconcile machine" )
@@ -681,6 +700,83 @@ func (r *AWSMachineReconciler) resolveUserData(machineScope *scope.MachineScope,
681
700
return encryptedCloudInit , nil
682
701
}
683
702
703
+ func (r * AWSMachineReconciler ) ignitionUserData (scope * scope.MachineScope , objectStoreSvc services.ObjectStoreInterface , userData []byte ) ([]byte , error ) {
704
+ if objectStoreSvc == nil {
705
+ return nil , errors .New ("object store service not available" )
706
+ }
707
+
708
+ objectURL , err := objectStoreSvc .Create (scope , userData )
709
+ if err != nil {
710
+ return nil , errors .Wrap (err , "creating userdata object" )
711
+ }
712
+
713
+ ignData := & ignTypes.Config {
714
+ Ignition : ignTypes.Ignition {
715
+ Version : "2.3.0" ,
716
+ Config : ignTypes.IgnitionConfig {
717
+ Append : []ignTypes.ConfigReference {
718
+ {
719
+ Source : objectURL ,
720
+ },
721
+ },
722
+ },
723
+ },
724
+ }
725
+
726
+ ignitionUserData , err := json .Marshal (ignData )
727
+ if err != nil {
728
+ r .Recorder .Eventf (scope .AWSMachine , corev1 .EventTypeWarning , "FailedGenerateIgnition" , err .Error ())
729
+ return nil , errors .Wrap (err , "serializing generated data" )
730
+ }
731
+
732
+ return ignitionUserData , nil
733
+ }
734
+
735
+ func (r * AWSMachineReconciler ) deleteBootstrapData (machineScope * scope.MachineScope , clusterScope cloud.ClusterScoper , objectStoreScope scope.S3Scope ) error {
736
+ if err := r .deleteEncryptedBootstrapDataSecret (machineScope , clusterScope ); err != nil {
737
+ return err
738
+ }
739
+
740
+ if objectStoreScope != nil {
741
+ // Bootstrap data will be removed from S3 if it is already populated.
742
+ if err := r .deleteIgnitionBootstrapDataFromS3 (machineScope , r .getObjectStoreService (objectStoreScope )); err != nil {
743
+ return err
744
+ }
745
+ }
746
+
747
+ return nil
748
+ }
749
+
750
+ func (r * AWSMachineReconciler ) deleteIgnitionBootstrapDataFromS3 (machineScope * scope.MachineScope , objectStoreSvc services.ObjectStoreInterface ) error {
751
+ // Do nothing if the AWSMachine is not in a failed state, and is operational from an EC2 perspective, but does not have a node reference
752
+ if ! machineScope .HasFailed () && machineScope .InstanceIsOperational () && machineScope .Machine .Status .NodeRef == nil && ! machineScope .AWSMachineIsDeleted () {
753
+ return nil
754
+ }
755
+
756
+ // If bootstrap data has not been populated yet, we cannot determine it's format, so there is probably nothing to do.
757
+ if machineScope .Machine .Spec .Bootstrap .DataSecretName == nil {
758
+ return nil
759
+ }
760
+
761
+ machineScope .Info ("Deleting unneeded entry from AWS S3" , "secretPrefix" , machineScope .GetSecretPrefix ())
762
+
763
+ _ , userDataFormat , err := machineScope .GetRawBootstrapDataWithFormat ()
764
+ if err != nil {
765
+ r .Recorder .Eventf (machineScope .AWSMachine , corev1 .EventTypeWarning , "FailedGetBootstrapData" , err .Error ())
766
+ return err
767
+ }
768
+
769
+ if ! machineScope .UseIgnition (userDataFormat ) {
770
+ return nil
771
+ }
772
+
773
+ if err := objectStoreSvc .Delete (machineScope ); err != nil {
774
+ return errors .Wrap (err , "deleting bootstrap data object" )
775
+ }
776
+
777
+ return nil
778
+ }
779
+
684
780
func (r * AWSMachineReconciler ) reconcileLBAttachment (machineScope * scope.MachineScope , elbScope scope.ELBScope , i * infrav1.Instance ) error {
685
781
if ! machineScope .IsControlPlane () {
686
782
return nil
0 commit comments