sigs.k8s.io/cluster-api-provider-aws@v1.5.5/pkg/eks/addons/procedures.go (about) 1 /* 2 Copyright 2021 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 addons 18 19 import ( 20 "context" 21 "errors" 22 "fmt" 23 24 "github.com/aws/aws-sdk-go/aws" 25 "github.com/aws/aws-sdk-go/service/eks" 26 27 "sigs.k8s.io/cluster-api-provider-aws/pkg/cloud/services/wait" 28 ) 29 30 var ( 31 // ErrNilAddon defines an error for when a nil addon is returned. 32 ErrNilAddon = errors.New("nil addon returned from create") 33 // ErrAddonNotFound defines an error for when an addon is not found. 34 ErrAddonNotFound = errors.New("addon not found") 35 // ErrAddonAlreadyExists defines an error for when an addon already exists. 36 ErrAddonAlreadyExists = errors.New("addon already exists") 37 ) 38 39 // DeleteAddonProcedure is a procedure that will delete an EKS addon. 40 type DeleteAddonProcedure struct { 41 plan *plan 42 name string 43 } 44 45 // Do implements the logic for the procedure. 46 func (p *DeleteAddonProcedure) Do(ctx context.Context) error { 47 input := &eks.DeleteAddonInput{ 48 AddonName: aws.String(p.name), 49 ClusterName: aws.String(p.plan.clusterName), 50 } 51 52 if _, err := p.plan.eksClient.DeleteAddon(input); err != nil { 53 return fmt.Errorf("deleting eks addon %s: %w", p.name, err) 54 } 55 56 return nil 57 } 58 59 // Name is the name of the procedure. 60 func (p *DeleteAddonProcedure) Name() string { 61 return "addon_delete" 62 } 63 64 // UpdateAddonProcedure is a procedure that will update an EKS addon. 65 type UpdateAddonProcedure struct { 66 plan *plan 67 name string 68 } 69 70 // Do implements the logic for the procedure. 71 func (p *UpdateAddonProcedure) Do(ctx context.Context) error { 72 desired := p.plan.getDesired(p.name) 73 74 if desired == nil { 75 return fmt.Errorf("getting desired addon %s: %w", p.name, ErrAddonNotFound) 76 } 77 78 input := &eks.UpdateAddonInput{ 79 AddonName: desired.Name, 80 AddonVersion: desired.Version, 81 ClusterName: &p.plan.clusterName, 82 ResolveConflicts: desired.ResolveConflict, 83 ServiceAccountRoleArn: desired.ServiceAccountRoleARN, 84 } 85 86 if _, err := p.plan.eksClient.UpdateAddon(input); err != nil { 87 return fmt.Errorf("updating eks addon %s: %w", p.name, err) 88 } 89 90 return nil 91 } 92 93 // Name is the name of the procedure. 94 func (p *UpdateAddonProcedure) Name() string { 95 return "addon_update" 96 } 97 98 // UpdateAddonTagsProcedure is a procedure that will update an EKS addon tags. 99 type UpdateAddonTagsProcedure struct { 100 plan *plan 101 name string 102 } 103 104 // Do implements the logic for the procedure. 105 func (p *UpdateAddonTagsProcedure) Do(ctx context.Context) error { 106 desired := p.plan.getDesired(p.name) 107 installed := p.plan.getInstalled(p.name) 108 109 if desired == nil { 110 return fmt.Errorf("getting desired addon %s: %w", p.name, ErrAddonNotFound) 111 } 112 if installed == nil { 113 return fmt.Errorf("getting installed addon %s: %w", p.name, ErrAddonNotFound) 114 } 115 116 input := &eks.TagResourceInput{ 117 ResourceArn: installed.ARN, 118 Tags: convertTags(desired.Tags), 119 } 120 121 if _, err := p.plan.eksClient.TagResource(input); err != nil { 122 return fmt.Errorf("updating eks addon tags %s: %w", p.name, err) 123 } 124 125 return nil 126 } 127 128 // Name is the name of the procedure. 129 func (p *UpdateAddonTagsProcedure) Name() string { 130 return "addon_tags_update" 131 } 132 133 // CreateAddonProcedure is a procedure that will create an EKS addon for a cluster. 134 type CreateAddonProcedure struct { 135 plan *plan 136 name string 137 } 138 139 // Do implements the logic for the procedure. 140 func (p *CreateAddonProcedure) Do(ctx context.Context) error { 141 desired := p.plan.getDesired(p.name) 142 if desired == nil { 143 return fmt.Errorf("getting desired addon %s: %w", p.name, ErrAddonNotFound) 144 } 145 146 input := &eks.CreateAddonInput{ 147 AddonName: desired.Name, 148 AddonVersion: desired.Version, 149 ClusterName: &p.plan.clusterName, 150 ServiceAccountRoleArn: desired.ServiceAccountRoleARN, 151 ResolveConflicts: desired.ResolveConflict, 152 Tags: convertTags(desired.Tags), 153 } 154 155 output, err := p.plan.eksClient.CreateAddon(input) 156 if err != nil { 157 return fmt.Errorf("creating eks addon %s: %w", p.name, err) 158 } 159 160 if output.Addon == nil { 161 return ErrNilAddon 162 } 163 164 return nil 165 } 166 167 // Name is the name of the procedure. 168 func (p *CreateAddonProcedure) Name() string { 169 return "addon_create" 170 } 171 172 // WaitAddonActiveProcedure is a procedure that will wait for an EKS addon 173 // to be active in a cluster. Abd optionally include the degraded state. 174 // Note: addons may be degraded until there are worker nodes. 175 type WaitAddonActiveProcedure struct { 176 plan *plan 177 name string 178 includeDegraded bool 179 } 180 181 // Do implements the logic for the procedure. 182 func (p *WaitAddonActiveProcedure) Do(ctx context.Context) error { 183 input := &eks.DescribeAddonInput{ 184 AddonName: aws.String(p.name), 185 ClusterName: aws.String(p.plan.clusterName), 186 } 187 188 if err := wait.WaitForWithRetryable(wait.NewBackoff(), func() (bool, error) { 189 out, describeErr := p.plan.eksClient.DescribeAddon(input) 190 if describeErr != nil { 191 return false, describeErr 192 } 193 194 if *out.Addon.Status == eks.AddonStatusActive { 195 return true, nil 196 } 197 198 if p.includeDegraded && *out.Addon.Status == eks.AddonStatusDegraded { 199 return true, nil 200 } 201 202 return false, nil 203 }); err != nil { 204 return fmt.Errorf("failed waiting for addon %s to be ready: %w", p.name, err) 205 } 206 207 return nil 208 } 209 210 // Name is the name of the procedure. 211 func (p *WaitAddonActiveProcedure) Name() string { 212 return "addon_wait_active" 213 } 214 215 // WaitAddonDeleteProcedure is a procedure that will wait for an EKS addon 216 // to be deleted from a cluster. 217 type WaitAddonDeleteProcedure struct { 218 plan *plan 219 name string 220 } 221 222 // Do implements the logic for the procedure. 223 func (p *WaitAddonDeleteProcedure) Do(ctx context.Context) error { 224 input := &eks.DescribeAddonInput{ 225 AddonName: aws.String(p.name), 226 ClusterName: aws.String(p.plan.clusterName), 227 } 228 229 if err := p.plan.eksClient.WaitUntilAddonDeleted(input); err != nil { 230 return fmt.Errorf("waiting for addon %s to be deleted: %w", p.name, err) 231 } 232 233 return nil 234 } 235 236 // Name is the name of the procedure. 237 func (p *WaitAddonDeleteProcedure) Name() string { 238 return "addon_wait_delete" 239 }