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 }