@@ -4,18 +4,22 @@ import (
44 "context"
55 "errors"
66 "fmt"
7+ "strings"
8+ "time"
79
810 "github.com/aws/aws-sdk-go/aws"
911 "github.com/aws/aws-sdk-go/aws/awserr"
1012 "github.com/aws/aws-sdk-go/aws/session"
1113 "github.com/aws/aws-sdk-go/service/ec2"
1214 "github.com/aws/aws-sdk-go/service/elbv2"
1315 "github.com/sirupsen/logrus"
16+ "k8s.io/apimachinery/pkg/util/wait"
1417 "k8s.io/utils/ptr"
1518 capa "sigs.k8s.io/cluster-api-provider-aws/v2/api/v1beta2"
1619 k8sClient "sigs.k8s.io/controller-runtime/pkg/client"
1720
1821 awsconfig "github.com/openshift/installer/pkg/asset/installconfig/aws"
22+ awsmanifest "github.com/openshift/installer/pkg/asset/manifests/aws"
1923 "github.com/openshift/installer/pkg/asset/manifests/capiutils"
2024 "github.com/openshift/installer/pkg/infrastructure/clusterapi"
2125 awstypes "github.com/openshift/installer/pkg/types/aws"
@@ -192,3 +196,77 @@ func getHostedZoneIDForNLB(ctx context.Context, awsSession *session.Session, reg
192196
193197 return "" , errNotFound
194198}
199+
200+ // DestroyBootstrap removes aws bootstrap resources not handled
201+ // by the deletion of the bootstrap machine by the capi controllers.
202+ func (* Provider ) DestroyBootstrap (ctx context.Context , in clusterapi.BootstrapDestroyInput ) error {
203+ if err := removeSSHRule (ctx , in .Client , in .Metadata .InfraID ); err != nil {
204+ return fmt .Errorf ("failed to remove bootstrap SSH rule: %w" , err )
205+ }
206+ return nil
207+ }
208+
209+ // removeSSHRule removes the SSH rule for accessing the bootstrap node
210+ // by removing the rule from the cluster spec and updating the object.
211+ func removeSSHRule (ctx context.Context , cl k8sClient.Client , infraID string ) error {
212+ awsCluster := & capa.AWSCluster {}
213+ key := k8sClient.ObjectKey {
214+ Name : infraID ,
215+ Namespace : capiutils .Namespace ,
216+ }
217+ if err := cl .Get (ctx , key , awsCluster ); err != nil {
218+ return fmt .Errorf ("failed to get AWSCluster: %w" , err )
219+ }
220+
221+ postBootstrapRules := []capa.IngressRule {}
222+ for _ , rule := range awsCluster .Spec .NetworkSpec .AdditionalControlPlaneIngressRules {
223+ if strings .EqualFold (rule .Description , awsmanifest .BootstrapSSHDescription ) {
224+ continue
225+ }
226+ postBootstrapRules = append (postBootstrapRules , rule )
227+ }
228+
229+ awsCluster .Spec .NetworkSpec .AdditionalControlPlaneIngressRules = postBootstrapRules
230+
231+ if err := cl .Update (ctx , awsCluster ); err != nil {
232+ return fmt .Errorf ("failed to update AWSCluster during bootstrap destroy: %w" , err )
233+ }
234+ logrus .Debug ("Updated AWSCluster to remove bootstrap SSH rule" )
235+
236+ timeout := 5 * time .Minute
237+ untilTime := time .Now ().Add (timeout )
238+ timezone , _ := untilTime .Zone ()
239+ logrus .Infof ("Waiting up to %v (until %v %s) for bootstrap SSH rule to be destroyed..." , timeout , untilTime .Format (time .Kitchen ), timezone )
240+ if err := wait .ExponentialBackoffWithContext (ctx , wait.Backoff {
241+ Duration : time .Second * 10 ,
242+ Factor : float64 (1.5 ),
243+ Steps : 32 ,
244+ Cap : timeout ,
245+ }, func (ctx context.Context ) (bool , error ) {
246+ c := & capa.AWSCluster {}
247+ if err := cl .Get (ctx , key , c ); err != nil {
248+ return false , err
249+ }
250+ if sg , ok := c .Status .Network .SecurityGroups [capa .SecurityGroupControlPlane ]; ok {
251+ for _ , r := range sg .IngressRules {
252+ if r .Description == awsmanifest .BootstrapSSHDescription {
253+ return false , nil
254+ }
255+ }
256+ return true , nil
257+ }
258+ // This shouldn't happen, but if control plane SG is not found, return an error.
259+ keys := make ([]capa.SecurityGroupRole , 0 , len (c .Status .Network .SecurityGroups ))
260+ for sgr := range c .Status .Network .SecurityGroups {
261+ keys = append (keys , sgr )
262+ }
263+ return false , fmt .Errorf ("controlplane not found in cluster security groups: %v" , keys )
264+ }); err != nil {
265+ if wait .Interrupted (err ) {
266+ return fmt .Errorf ("bootstrap ssh rule was not removed within %v: %w" , timeout , err )
267+ }
268+ return fmt .Errorf ("unable to remove bootstrap ssh rule: %w" , err )
269+ }
270+
271+ return nil
272+ }
0 commit comments