sigs.k8s.io/cluster-api-provider-aws@v1.5.5/pkg/cloud/scope/managedcontrolplane.go (about) 1 /* 2 Copyright 2020 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 scope 18 19 import ( 20 "context" 21 "fmt" 22 "time" 23 24 amazoncni "github.com/aws/amazon-vpc-cni-k8s/pkg/apis/crd/v1alpha1" 25 awsclient "github.com/aws/aws-sdk-go/aws/client" 26 "github.com/go-logr/logr" 27 "github.com/pkg/errors" 28 appsv1 "k8s.io/api/apps/v1" 29 corev1 "k8s.io/api/core/v1" 30 "k8s.io/apimachinery/pkg/runtime" 31 "k8s.io/klog/v2/klogr" 32 "sigs.k8s.io/controller-runtime/pkg/client" 33 34 infrav1 "sigs.k8s.io/cluster-api-provider-aws/api/v1beta1" 35 ekscontrolplanev1 "sigs.k8s.io/cluster-api-provider-aws/controlplane/eks/api/v1beta1" 36 "sigs.k8s.io/cluster-api-provider-aws/pkg/cloud" 37 "sigs.k8s.io/cluster-api-provider-aws/pkg/cloud/throttle" 38 clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" 39 "sigs.k8s.io/cluster-api/controllers/remote" 40 "sigs.k8s.io/cluster-api/util/patch" 41 ) 42 43 var ( 44 scheme = runtime.NewScheme() 45 ) 46 47 func init() { 48 _ = amazoncni.AddToScheme(scheme) 49 _ = appsv1.AddToScheme(scheme) 50 _ = corev1.AddToScheme(scheme) 51 } 52 53 // ManagedControlPlaneScopeParams defines the input parameters used to create a new Scope. 54 type ManagedControlPlaneScopeParams struct { 55 Client client.Client 56 Logger *logr.Logger 57 Cluster *clusterv1.Cluster 58 ControlPlane *ekscontrolplanev1.AWSManagedControlPlane 59 ControllerName string 60 Endpoints []ServiceEndpoint 61 Session awsclient.ConfigProvider 62 63 EnableIAM bool 64 AllowAdditionalRoles bool 65 } 66 67 // NewManagedControlPlaneScope creates a new Scope from the supplied parameters. 68 // This is meant to be called for each reconcile iteration. 69 func NewManagedControlPlaneScope(params ManagedControlPlaneScopeParams) (*ManagedControlPlaneScope, error) { 70 if params.Cluster == nil { 71 return nil, errors.New("failed to generate new scope from nil Cluster") 72 } 73 if params.ControlPlane == nil { 74 return nil, errors.New("failed to generate new scope from nil AWSManagedControlPlane") 75 } 76 if params.Logger == nil { 77 log := klogr.New() 78 params.Logger = &log 79 } 80 81 managedScope := &ManagedControlPlaneScope{ 82 Logger: *params.Logger, 83 Client: params.Client, 84 Cluster: params.Cluster, 85 ControlPlane: params.ControlPlane, 86 patchHelper: nil, 87 session: nil, 88 serviceLimiters: nil, 89 controllerName: params.ControllerName, 90 allowAdditionalRoles: params.AllowAdditionalRoles, 91 enableIAM: params.EnableIAM, 92 } 93 session, serviceLimiters, err := sessionForClusterWithRegion(params.Client, managedScope, params.ControlPlane.Spec.Region, params.Endpoints, *params.Logger) 94 if err != nil { 95 return nil, errors.Errorf("failed to create aws session: %v", err) 96 } 97 98 managedScope.session = session 99 managedScope.serviceLimiters = serviceLimiters 100 101 helper, err := patch.NewHelper(params.ControlPlane, params.Client) 102 if err != nil { 103 return nil, errors.Wrap(err, "failed to init patch helper") 104 } 105 106 managedScope.patchHelper = helper 107 return managedScope, nil 108 } 109 110 // ManagedControlPlaneScope defines the basic context for an actuator to operate upon. 111 type ManagedControlPlaneScope struct { 112 logr.Logger 113 Client client.Client 114 patchHelper *patch.Helper 115 116 Cluster *clusterv1.Cluster 117 ControlPlane *ekscontrolplanev1.AWSManagedControlPlane 118 119 session awsclient.ConfigProvider 120 serviceLimiters throttle.ServiceLimiters 121 controllerName string 122 123 enableIAM bool 124 allowAdditionalRoles bool 125 } 126 127 // RemoteClient returns the Kubernetes client for connecting to the workload cluster. 128 func (s *ManagedControlPlaneScope) RemoteClient() (client.Client, error) { 129 clusterKey := client.ObjectKey{ 130 Name: s.Name(), 131 Namespace: s.Namespace(), 132 } 133 134 restConfig, err := remote.RESTConfig(context.Background(), s.ControlPlane.Name, s.Client, clusterKey) 135 if err != nil { 136 return nil, fmt.Errorf("getting remote rest config for %s/%s: %w", s.Namespace(), s.Name(), err) 137 } 138 restConfig.Timeout = 1 * time.Minute 139 140 return client.New(restConfig, client.Options{Scheme: scheme}) 141 } 142 143 // Network returns the control plane network object. 144 func (s *ManagedControlPlaneScope) Network() *infrav1.NetworkStatus { 145 return &s.ControlPlane.Status.Network 146 } 147 148 // VPC returns the control plane VPC. 149 func (s *ManagedControlPlaneScope) VPC() *infrav1.VPCSpec { 150 return &s.ControlPlane.Spec.NetworkSpec.VPC 151 } 152 153 // ServiceLimiter returns the AWS SDK session. Used for creating clients. 154 func (s *ManagedControlPlaneScope) ServiceLimiter(service string) *throttle.ServiceLimiter { 155 if sl, ok := s.serviceLimiters[service]; ok { 156 return sl 157 } 158 return nil 159 } 160 161 // Subnets returns the control plane subnets. 162 func (s *ManagedControlPlaneScope) Subnets() infrav1.Subnets { 163 return s.ControlPlane.Spec.NetworkSpec.Subnets 164 } 165 166 // IdentityRef returns the cluster identityRef. 167 func (s *ManagedControlPlaneScope) IdentityRef() *infrav1.AWSIdentityReference { 168 return s.ControlPlane.Spec.IdentityRef 169 } 170 171 // SetSubnets updates the control planes subnets. 172 func (s *ManagedControlPlaneScope) SetSubnets(subnets infrav1.Subnets) { 173 s.ControlPlane.Spec.NetworkSpec.Subnets = subnets 174 } 175 176 // CNIIngressRules returns the CNI spec ingress rules. 177 func (s *ManagedControlPlaneScope) CNIIngressRules() infrav1.CNIIngressRules { 178 if s.ControlPlane.Spec.NetworkSpec.CNI != nil { 179 return s.ControlPlane.Spec.NetworkSpec.CNI.CNIIngressRules 180 } 181 return infrav1.CNIIngressRules{} 182 } 183 184 // SecurityGroups returns the control plane security groups as a map, it creates the map if empty. 185 func (s *ManagedControlPlaneScope) SecurityGroups() map[infrav1.SecurityGroupRole]infrav1.SecurityGroup { 186 return s.ControlPlane.Status.Network.SecurityGroups 187 } 188 189 // SecondaryCidrBlock returns the SecondaryCidrBlock of the control plane. 190 func (s *ManagedControlPlaneScope) SecondaryCidrBlock() *string { 191 return s.ControlPlane.Spec.SecondaryCidrBlock 192 } 193 194 // SecurityGroupOverrides returns the the security groups that are overridden in the ControlPlane spec. 195 func (s *ManagedControlPlaneScope) SecurityGroupOverrides() map[infrav1.SecurityGroupRole]string { 196 return s.ControlPlane.Spec.NetworkSpec.SecurityGroupOverrides 197 } 198 199 // Name returns the CAPI cluster name. 200 func (s *ManagedControlPlaneScope) Name() string { 201 return s.Cluster.Name 202 } 203 204 // InfraClusterName returns the AWS cluster name. 205 func (s *ManagedControlPlaneScope) InfraClusterName() string { 206 return s.ControlPlane.Name 207 } 208 209 // Namespace returns the cluster namespace. 210 func (s *ManagedControlPlaneScope) Namespace() string { 211 return s.Cluster.Namespace 212 } 213 214 // Region returns the cluster region. 215 func (s *ManagedControlPlaneScope) Region() string { 216 return s.ControlPlane.Spec.Region 217 } 218 219 // ListOptionsLabelSelector returns a ListOptions with a label selector for clusterName. 220 func (s *ManagedControlPlaneScope) ListOptionsLabelSelector() client.ListOption { 221 return client.MatchingLabels(map[string]string{ 222 clusterv1.ClusterLabelName: s.Cluster.Name, 223 }) 224 } 225 226 // PatchObject persists the control plane configuration and status. 227 func (s *ManagedControlPlaneScope) PatchObject() error { 228 return s.patchHelper.Patch( 229 context.TODO(), 230 s.ControlPlane, 231 patch.WithOwnedConditions{Conditions: []clusterv1.ConditionType{ 232 infrav1.VpcReadyCondition, 233 infrav1.SubnetsReadyCondition, 234 infrav1.ClusterSecurityGroupsReadyCondition, 235 infrav1.InternetGatewayReadyCondition, 236 infrav1.NatGatewaysReadyCondition, 237 infrav1.RouteTablesReadyCondition, 238 infrav1.BastionHostReadyCondition, 239 ekscontrolplanev1.EKSControlPlaneCreatingCondition, 240 ekscontrolplanev1.EKSControlPlaneReadyCondition, 241 ekscontrolplanev1.EKSControlPlaneUpdatingCondition, 242 ekscontrolplanev1.IAMControlPlaneRolesReadyCondition, 243 }}) 244 } 245 246 // Close closes the current scope persisting the control plane configuration and status. 247 func (s *ManagedControlPlaneScope) Close() error { 248 return s.PatchObject() 249 } 250 251 // AdditionalTags returns AdditionalTags from the scope's EksControlPlane. The returned value will never be nil. 252 func (s *ManagedControlPlaneScope) AdditionalTags() infrav1.Tags { 253 if s.ControlPlane.Spec.AdditionalTags == nil { 254 s.ControlPlane.Spec.AdditionalTags = infrav1.Tags{} 255 } 256 257 return s.ControlPlane.Spec.AdditionalTags.DeepCopy() 258 } 259 260 // APIServerPort returns the port to use when communicating with the API server. 261 func (s *ManagedControlPlaneScope) APIServerPort() int32 { 262 return 443 263 } 264 265 // SetFailureDomain sets the infrastructure provider failure domain key to the spec given as input. 266 func (s *ManagedControlPlaneScope) SetFailureDomain(id string, spec clusterv1.FailureDomainSpec) { 267 if s.ControlPlane.Status.FailureDomains == nil { 268 s.ControlPlane.Status.FailureDomains = make(clusterv1.FailureDomains) 269 } 270 s.ControlPlane.Status.FailureDomains[id] = spec 271 } 272 273 // InfraCluster returns the AWS infrastructure cluster or control plane object. 274 func (s *ManagedControlPlaneScope) InfraCluster() cloud.ClusterObject { 275 return s.ControlPlane 276 } 277 278 // ClusterObj returns the cluster object. 279 func (s *ManagedControlPlaneScope) ClusterObj() cloud.ClusterObject { 280 return s.Cluster 281 } 282 283 // Session returns the AWS SDK session. Used for creating clients. 284 func (s *ManagedControlPlaneScope) Session() awsclient.ConfigProvider { 285 return s.session 286 } 287 288 // Bastion returns the bastion details. 289 func (s *ManagedControlPlaneScope) Bastion() *infrav1.Bastion { 290 return &s.ControlPlane.Spec.Bastion 291 } 292 293 // SetBastionInstance sets the bastion instance in the status of the cluster. 294 func (s *ManagedControlPlaneScope) SetBastionInstance(instance *infrav1.Instance) { 295 s.ControlPlane.Status.Bastion = instance 296 } 297 298 // SSHKeyName returns the SSH key name to use for instances. 299 func (s *ManagedControlPlaneScope) SSHKeyName() *string { 300 return s.ControlPlane.Spec.SSHKeyName 301 } 302 303 // ControllerName returns the name of the controller that 304 // created the ManagedControlPlane. 305 func (s *ManagedControlPlaneScope) ControllerName() string { 306 return s.controllerName 307 } 308 309 // TokenMethod returns the token method to use in the kubeconfig. 310 func (s *ManagedControlPlaneScope) TokenMethod() ekscontrolplanev1.EKSTokenMethod { 311 if s.ControlPlane.Spec.TokenMethod != nil { 312 return *s.ControlPlane.Spec.TokenMethod 313 } 314 315 return ekscontrolplanev1.EKSTokenMethodIAMAuthenticator 316 } 317 318 // KubernetesClusterName is the name of the Kubernetes cluster. For the managed 319 // scope this is the different to the CAPI cluster name and is the EKS cluster name. 320 func (s *ManagedControlPlaneScope) KubernetesClusterName() string { 321 return s.ControlPlane.Spec.EKSClusterName 322 } 323 324 // EnableIAM indicates that reconciliation should create IAM roles. 325 func (s *ManagedControlPlaneScope) EnableIAM() bool { 326 return s.enableIAM 327 } 328 329 // AllowAdditionalRoles indicates if additional roles can be added to the created IAM roles. 330 func (s *ManagedControlPlaneScope) AllowAdditionalRoles() bool { 331 return s.allowAdditionalRoles 332 } 333 334 // ImageLookupFormat returns the format string to use when looking up AMIs. 335 func (s *ManagedControlPlaneScope) ImageLookupFormat() string { 336 return s.ControlPlane.Spec.ImageLookupFormat 337 } 338 339 // ImageLookupOrg returns the organization name to use when looking up AMIs. 340 func (s *ManagedControlPlaneScope) ImageLookupOrg() string { 341 return s.ControlPlane.Spec.ImageLookupOrg 342 } 343 344 // ImageLookupBaseOS returns the base operating system name to use when looking up AMIs. 345 func (s *ManagedControlPlaneScope) ImageLookupBaseOS() string { 346 return s.ControlPlane.Spec.ImageLookupBaseOS 347 } 348 349 // IAMAuthConfig returns the IAM authenticator config. The returned value will never be nil. 350 func (s *ManagedControlPlaneScope) IAMAuthConfig() *ekscontrolplanev1.IAMAuthenticatorConfig { 351 if s.ControlPlane.Spec.IAMAuthenticatorConfig == nil { 352 s.ControlPlane.Spec.IAMAuthenticatorConfig = &ekscontrolplanev1.IAMAuthenticatorConfig{} 353 } 354 return s.ControlPlane.Spec.IAMAuthenticatorConfig 355 } 356 357 // Addons returns the list of addons for a EKS cluster. 358 func (s *ManagedControlPlaneScope) Addons() []ekscontrolplanev1.Addon { 359 if s.ControlPlane.Spec.Addons == nil { 360 return []ekscontrolplanev1.Addon{} 361 } 362 return *s.ControlPlane.Spec.Addons 363 } 364 365 // DisableKubeProxy returns whether kube-proxy should be disabled. 366 func (s *ManagedControlPlaneScope) DisableKubeProxy() bool { 367 return s.ControlPlane.Spec.KubeProxy.Disable 368 } 369 370 // DisableVPCCNI returns whether the AWS VPC CNI should be disabled. 371 func (s *ManagedControlPlaneScope) DisableVPCCNI() bool { 372 return s.ControlPlane.Spec.DisableVPCCNI 373 } 374 375 func (s *ManagedControlPlaneScope) OIDCIdentityProviderConfig() *ekscontrolplanev1.OIDCIdentityProviderConfig { 376 return s.ControlPlane.Spec.OIDCIdentityProviderConfig 377 } 378 379 // ServiceCidrs returns the CIDR blocks used for services. 380 func (s *ManagedControlPlaneScope) ServiceCidrs() *clusterv1.NetworkRanges { 381 if s.Cluster.Spec.ClusterNetwork != nil { 382 if s.Cluster.Spec.ClusterNetwork.Services != nil { 383 if len(s.Cluster.Spec.ClusterNetwork.Services.CIDRBlocks) > 0 { 384 return s.Cluster.Spec.ClusterNetwork.Services 385 } 386 } 387 } 388 389 return nil 390 }