sigs.k8s.io/cluster-api-provider-aws@v1.5.5/pkg/cloud/services/network/gateways.go (about)

     1  /*
     2  Copyright 2018 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8  	http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package network
    18  
    19  import (
    20  	"fmt"
    21  
    22  	"github.com/aws/aws-sdk-go/aws"
    23  	"github.com/aws/aws-sdk-go/service/ec2"
    24  	"github.com/pkg/errors"
    25  
    26  	infrav1 "sigs.k8s.io/cluster-api-provider-aws/api/v1beta1"
    27  	"sigs.k8s.io/cluster-api-provider-aws/pkg/cloud/awserrors"
    28  	"sigs.k8s.io/cluster-api-provider-aws/pkg/cloud/converters"
    29  	"sigs.k8s.io/cluster-api-provider-aws/pkg/cloud/filter"
    30  	"sigs.k8s.io/cluster-api-provider-aws/pkg/cloud/services"
    31  	"sigs.k8s.io/cluster-api-provider-aws/pkg/cloud/services/wait"
    32  	"sigs.k8s.io/cluster-api-provider-aws/pkg/cloud/tags"
    33  	"sigs.k8s.io/cluster-api-provider-aws/pkg/record"
    34  	"sigs.k8s.io/cluster-api/util/conditions"
    35  )
    36  
    37  func (s *Service) reconcileInternetGateways() error {
    38  	if s.scope.VPC().IsUnmanaged(s.scope.Name()) {
    39  		s.scope.V(4).Info("Skipping internet gateways reconcile in unmanaged mode")
    40  		return nil
    41  	}
    42  
    43  	s.scope.V(2).Info("Reconciling internet gateways")
    44  
    45  	igs, err := s.describeVpcInternetGateways()
    46  	if awserrors.IsNotFound(err) {
    47  		if s.scope.VPC().IsUnmanaged(s.scope.Name()) {
    48  			return errors.Errorf("failed to validate network: no internet gateways found in VPC %q", s.scope.VPC().ID)
    49  		}
    50  
    51  		ig, err := s.createInternetGateway()
    52  		if err != nil {
    53  			return err
    54  		}
    55  		igs = []*ec2.InternetGateway{ig}
    56  	} else if err != nil {
    57  		return err
    58  	}
    59  
    60  	gateway := igs[0]
    61  	s.scope.VPC().InternetGatewayID = gateway.InternetGatewayId
    62  
    63  	// Make sure tags are up to date.
    64  	if err := wait.WaitForWithRetryable(wait.NewBackoff(), func() (bool, error) {
    65  		buildParams := s.getGatewayTagParams(*gateway.InternetGatewayId)
    66  		tagsBuilder := tags.New(&buildParams, tags.WithEC2(s.EC2Client))
    67  		if err := tagsBuilder.Ensure(converters.TagsToMap(gateway.Tags)); err != nil {
    68  			return false, err
    69  		}
    70  		return true, nil
    71  	}, awserrors.InternetGatewayNotFound); err != nil {
    72  		record.Warnf(s.scope.InfraCluster(), "FailedTagInternetGateway", "Failed to tag managed Internet Gateway %q: %v", gateway.InternetGatewayId, err)
    73  		return errors.Wrapf(err, "failed to tag internet gateway %q", *gateway.InternetGatewayId)
    74  	}
    75  	conditions.MarkTrue(s.scope.InfraCluster(), infrav1.InternetGatewayReadyCondition)
    76  	return nil
    77  }
    78  
    79  func (s *Service) deleteInternetGateways() error {
    80  	if s.scope.VPC().IsUnmanaged(s.scope.Name()) {
    81  		s.scope.V(4).Info("Skipping internet gateway deletion in unmanaged mode")
    82  		return nil
    83  	}
    84  
    85  	igs, err := s.describeVpcInternetGateways()
    86  	if awserrors.IsNotFound(err) {
    87  		return nil
    88  	} else if err != nil {
    89  		return err
    90  	}
    91  
    92  	for _, ig := range igs {
    93  		detachReq := &ec2.DetachInternetGatewayInput{
    94  			InternetGatewayId: ig.InternetGatewayId,
    95  			VpcId:             aws.String(s.scope.VPC().ID),
    96  		}
    97  
    98  		if _, err := s.EC2Client.DetachInternetGateway(detachReq); err != nil {
    99  			record.Warnf(s.scope.InfraCluster(), "FailedDetachInternetGateway", "Failed to detach Internet Gateway %q from VPC %q: %v", *ig.InternetGatewayId, s.scope.VPC().ID, err)
   100  			return errors.Wrapf(err, "failed to detach internet gateway %q", *ig.InternetGatewayId)
   101  		}
   102  
   103  		record.Eventf(s.scope.InfraCluster(), "SuccessfulDetachInternetGateway", "Detached Internet Gateway %q from VPC %q", *ig.InternetGatewayId, s.scope.VPC().ID)
   104  		s.scope.V(2).Info("Detached internet gateway from VPC", "internet-gateway-id", *ig.InternetGatewayId, "vpc-id", s.scope.VPC().ID)
   105  
   106  		deleteReq := &ec2.DeleteInternetGatewayInput{
   107  			InternetGatewayId: ig.InternetGatewayId,
   108  		}
   109  
   110  		if _, err = s.EC2Client.DeleteInternetGateway(deleteReq); err != nil {
   111  			record.Warnf(s.scope.InfraCluster(), "FailedDeleteInternetGateway", "Failed to delete Internet Gateway %q previously attached to VPC %q: %v", *ig.InternetGatewayId, s.scope.VPC().ID, err)
   112  			return errors.Wrapf(err, "failed to delete internet gateway %q", *ig.InternetGatewayId)
   113  		}
   114  
   115  		record.Eventf(s.scope.InfraCluster(), "SuccessfulDeleteInternetGateway", "Deleted Internet Gateway %q previously attached to VPC %q", *ig.InternetGatewayId, s.scope.VPC().ID)
   116  		s.scope.Info("Deleted Internet gateway in VPC", "internet-gateway-id", *ig.InternetGatewayId, "vpc-id", s.scope.VPC().ID)
   117  	}
   118  
   119  	return nil
   120  }
   121  
   122  func (s *Service) createInternetGateway() (*ec2.InternetGateway, error) {
   123  	ig, err := s.EC2Client.CreateInternetGateway(&ec2.CreateInternetGatewayInput{
   124  		TagSpecifications: []*ec2.TagSpecification{
   125  			tags.BuildParamsToTagSpecification(ec2.ResourceTypeInternetGateway, s.getGatewayTagParams(services.TemporaryResourceID)),
   126  		},
   127  	})
   128  	if err != nil {
   129  		record.Warnf(s.scope.InfraCluster(), "FailedCreateInternetGateway", "Failed to create new managed Internet Gateway: %v", err)
   130  		return nil, errors.Wrap(err, "failed to create internet gateway")
   131  	}
   132  	record.Eventf(s.scope.InfraCluster(), "SuccessfulCreateInternetGateway", "Created new managed Internet Gateway %q", *ig.InternetGateway.InternetGatewayId)
   133  	s.scope.Info("Created Internet gateway for VPC", "internet-gateway-id", *ig.InternetGateway.InternetGatewayId, "vpc-id", s.scope.VPC().ID)
   134  
   135  	if err := wait.WaitForWithRetryable(wait.NewBackoff(), func() (bool, error) {
   136  		if _, err := s.EC2Client.AttachInternetGateway(&ec2.AttachInternetGatewayInput{
   137  			InternetGatewayId: ig.InternetGateway.InternetGatewayId,
   138  			VpcId:             aws.String(s.scope.VPC().ID),
   139  		}); err != nil {
   140  			return false, err
   141  		}
   142  		return true, nil
   143  	}, awserrors.InternetGatewayNotFound); err != nil {
   144  		record.Warnf(s.scope.InfraCluster(), "FailedAttachInternetGateway", "Failed to attach managed Internet Gateway %q to vpc %q: %v", *ig.InternetGateway.InternetGatewayId, s.scope.VPC().ID, err)
   145  		return nil, errors.Wrapf(err, "failed to attach internet gateway %q to vpc %q", *ig.InternetGateway.InternetGatewayId, s.scope.VPC().ID)
   146  	}
   147  	record.Eventf(s.scope.InfraCluster(), "SuccessfulAttachInternetGateway", "Internet Gateway %q attached to VPC %q", *ig.InternetGateway.InternetGatewayId, s.scope.VPC().ID)
   148  	s.scope.V(2).Info("attached internet gateway to VPC", "internet-gateway-id", *ig.InternetGateway.InternetGatewayId, "vpc-id", s.scope.VPC().ID)
   149  
   150  	return ig.InternetGateway, nil
   151  }
   152  
   153  func (s *Service) describeVpcInternetGateways() ([]*ec2.InternetGateway, error) {
   154  	out, err := s.EC2Client.DescribeInternetGateways(&ec2.DescribeInternetGatewaysInput{
   155  		Filters: []*ec2.Filter{
   156  			filter.EC2.VPCAttachment(s.scope.VPC().ID),
   157  		},
   158  	})
   159  	if err != nil {
   160  		record.Eventf(s.scope.InfraCluster(), "FailedDescribeInternetGateway", "Failed to describe internet gateways in vpc %q: %v", s.scope.VPC().ID, err)
   161  		return nil, errors.Wrapf(err, "failed to describe internet gateways in vpc %q", s.scope.VPC().ID)
   162  	}
   163  
   164  	if len(out.InternetGateways) == 0 {
   165  		return nil, awserrors.NewNotFound(fmt.Sprintf("no internet gateways found in vpc %q", s.scope.VPC().ID))
   166  	}
   167  
   168  	return out.InternetGateways, nil
   169  }
   170  
   171  func (s *Service) getGatewayTagParams(id string) infrav1.BuildParams {
   172  	name := fmt.Sprintf("%s-igw", s.scope.Name())
   173  
   174  	return infrav1.BuildParams{
   175  		ClusterName: s.scope.Name(),
   176  		ResourceID:  id,
   177  		Lifecycle:   infrav1.ResourceLifecycleOwned,
   178  		Name:        aws.String(name),
   179  		Role:        aws.String(infrav1.CommonRoleTagValue),
   180  		Additional:  s.scope.AdditionalTags(),
   181  	}
   182  }