sigs.k8s.io/cluster-api-provider-aws@v1.5.5/pkg/cloud/scope/managednodegroup.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  
    23  	awsclient "github.com/aws/aws-sdk-go/aws/client"
    24  	"github.com/go-logr/logr"
    25  	"github.com/pkg/errors"
    26  	"k8s.io/klog/v2/klogr"
    27  	"sigs.k8s.io/controller-runtime/pkg/client"
    28  
    29  	infrav1 "sigs.k8s.io/cluster-api-provider-aws/api/v1beta1"
    30  	ekscontrolplanev1 "sigs.k8s.io/cluster-api-provider-aws/controlplane/eks/api/v1beta1"
    31  	expinfrav1 "sigs.k8s.io/cluster-api-provider-aws/exp/api/v1beta1"
    32  	"sigs.k8s.io/cluster-api-provider-aws/pkg/cloud"
    33  	"sigs.k8s.io/cluster-api-provider-aws/pkg/cloud/throttle"
    34  	clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
    35  	expclusterv1 "sigs.k8s.io/cluster-api/exp/api/v1beta1"
    36  	"sigs.k8s.io/cluster-api/util/conditions"
    37  	"sigs.k8s.io/cluster-api/util/patch"
    38  )
    39  
    40  // ManagedMachinePoolScopeParams defines the input parameters used to create a new Scope.
    41  type ManagedMachinePoolScopeParams struct {
    42  	Client             client.Client
    43  	Logger             *logr.Logger
    44  	Cluster            *clusterv1.Cluster
    45  	ControlPlane       *ekscontrolplanev1.AWSManagedControlPlane
    46  	ManagedMachinePool *expinfrav1.AWSManagedMachinePool
    47  	MachinePool        *expclusterv1.MachinePool
    48  	ControllerName     string
    49  	Endpoints          []ServiceEndpoint
    50  	Session            awsclient.ConfigProvider
    51  
    52  	EnableIAM            bool
    53  	AllowAdditionalRoles bool
    54  }
    55  
    56  // NewManagedMachinePoolScope creates a new Scope from the supplied parameters.
    57  // This is meant to be called for each reconcile iteration.
    58  func NewManagedMachinePoolScope(params ManagedMachinePoolScopeParams) (*ManagedMachinePoolScope, error) {
    59  	if params.ControlPlane == nil {
    60  		return nil, errors.New("failed to generate new scope from nil AWSManagedMachinePool")
    61  	}
    62  	if params.MachinePool == nil {
    63  		return nil, errors.New("failed to generate new scope from nil MachinePool")
    64  	}
    65  	if params.ManagedMachinePool == nil {
    66  		return nil, errors.New("failed to generate new scope from nil ManagedMachinePool")
    67  	}
    68  	if params.Logger == nil {
    69  		log := klogr.New()
    70  		params.Logger = &log
    71  	}
    72  
    73  	managedScope := &ManagedControlPlaneScope{
    74  		Logger:         *params.Logger,
    75  		Client:         params.Client,
    76  		Cluster:        params.Cluster,
    77  		ControlPlane:   params.ControlPlane,
    78  		controllerName: params.ControllerName,
    79  	}
    80  	session, serviceLimiters, err := sessionForClusterWithRegion(params.Client, managedScope, params.ControlPlane.Spec.Region, params.Endpoints, *params.Logger)
    81  	if err != nil {
    82  		return nil, errors.Errorf("failed to create aws session: %v", err)
    83  	}
    84  
    85  	helper, err := patch.NewHelper(params.ManagedMachinePool, params.Client)
    86  	if err != nil {
    87  		return nil, errors.Wrap(err, "failed to init patch helper")
    88  	}
    89  
    90  	return &ManagedMachinePoolScope{
    91  		Logger:               *params.Logger,
    92  		Client:               params.Client,
    93  		Cluster:              params.Cluster,
    94  		ControlPlane:         params.ControlPlane,
    95  		ManagedMachinePool:   params.ManagedMachinePool,
    96  		MachinePool:          params.MachinePool,
    97  		patchHelper:          helper,
    98  		session:              session,
    99  		serviceLimiters:      serviceLimiters,
   100  		controllerName:       params.ControllerName,
   101  		enableIAM:            params.EnableIAM,
   102  		allowAdditionalRoles: params.AllowAdditionalRoles,
   103  	}, nil
   104  }
   105  
   106  // ManagedMachinePoolScope defines the basic context for an actuator to operate upon.
   107  type ManagedMachinePoolScope struct {
   108  	logr.Logger
   109  	Client      client.Client
   110  	patchHelper *patch.Helper
   111  
   112  	Cluster            *clusterv1.Cluster
   113  	ControlPlane       *ekscontrolplanev1.AWSManagedControlPlane
   114  	ManagedMachinePool *expinfrav1.AWSManagedMachinePool
   115  	MachinePool        *expclusterv1.MachinePool
   116  
   117  	session         awsclient.ConfigProvider
   118  	serviceLimiters throttle.ServiceLimiters
   119  	controllerName  string
   120  
   121  	enableIAM            bool
   122  	allowAdditionalRoles bool
   123  }
   124  
   125  // ManagedPoolName returns the managed machine pool name.
   126  func (s *ManagedMachinePoolScope) ManagedPoolName() string {
   127  	return s.ManagedMachinePool.Name
   128  }
   129  
   130  // ServiceLimiter returns the AWS SDK session. Used for creating clients.
   131  func (s *ManagedMachinePoolScope) ServiceLimiter(service string) *throttle.ServiceLimiter {
   132  	if sl, ok := s.serviceLimiters[service]; ok {
   133  		return sl
   134  	}
   135  	return nil
   136  }
   137  
   138  // ClusterName returns the cluster name.
   139  func (s *ManagedMachinePoolScope) ClusterName() string {
   140  	return s.ControlPlane.Spec.EKSClusterName
   141  }
   142  
   143  // EnableIAM indicates that reconciliation should create IAM roles.
   144  func (s *ManagedMachinePoolScope) EnableIAM() bool {
   145  	return s.enableIAM
   146  }
   147  
   148  // AllowAdditionalRoles indicates if additional roles can be added to the created IAM roles.
   149  func (s *ManagedMachinePoolScope) AllowAdditionalRoles() bool {
   150  	return s.allowAdditionalRoles
   151  }
   152  
   153  // IdentityRef returns the cluster identityRef.
   154  func (s *ManagedMachinePoolScope) IdentityRef() *infrav1.AWSIdentityReference {
   155  	return s.ControlPlane.Spec.IdentityRef
   156  }
   157  
   158  // AdditionalTags returns AdditionalTags from the scope's ManagedMachinePool
   159  // The returned value will never be nil.
   160  func (s *ManagedMachinePoolScope) AdditionalTags() infrav1.Tags {
   161  	if s.ManagedMachinePool.Spec.AdditionalTags == nil {
   162  		s.ManagedMachinePool.Spec.AdditionalTags = infrav1.Tags{}
   163  	}
   164  
   165  	return s.ManagedMachinePool.Spec.AdditionalTags.DeepCopy()
   166  }
   167  
   168  // RoleName returns the node group role name.
   169  func (s *ManagedMachinePoolScope) RoleName() string {
   170  	return s.ManagedMachinePool.Spec.RoleName
   171  }
   172  
   173  // Version returns the nodegroup Kubernetes version.
   174  func (s *ManagedMachinePoolScope) Version() *string {
   175  	return s.MachinePool.Spec.Template.Spec.Version
   176  }
   177  
   178  // ControlPlaneSubnets returns the control plane subnets.
   179  func (s *ManagedMachinePoolScope) ControlPlaneSubnets() infrav1.Subnets {
   180  	return s.ControlPlane.Spec.NetworkSpec.Subnets
   181  }
   182  
   183  // SubnetIDs returns the machine pool subnet IDs.
   184  func (s *ManagedMachinePoolScope) SubnetIDs() ([]string, error) {
   185  	strategy, err := newDefaultSubnetPlacementStrategy(&s.Logger)
   186  	if err != nil {
   187  		return []string{}, fmt.Errorf("getting subnet placement strategy: %w", err)
   188  	}
   189  
   190  	return strategy.Place(&placementInput{
   191  		SpecSubnetIDs:           s.ManagedMachinePool.Spec.SubnetIDs,
   192  		SpecAvailabilityZones:   s.ManagedMachinePool.Spec.AvailabilityZones,
   193  		ParentAvailabilityZones: s.MachinePool.Spec.FailureDomains,
   194  		ControlplaneSubnets:     s.ControlPlaneSubnets(),
   195  	})
   196  }
   197  
   198  // NodegroupReadyFalse marks the ready condition false using warning if error isn't
   199  // empty.
   200  func (s *ManagedMachinePoolScope) NodegroupReadyFalse(reason string, err string) error {
   201  	severity := clusterv1.ConditionSeverityWarning
   202  	if err == "" {
   203  		severity = clusterv1.ConditionSeverityInfo
   204  	}
   205  	conditions.MarkFalse(
   206  		s.ManagedMachinePool,
   207  		expinfrav1.EKSNodegroupReadyCondition,
   208  		reason,
   209  		severity,
   210  		err,
   211  	)
   212  	if err := s.PatchObject(); err != nil {
   213  		return errors.Wrap(err, "failed to mark nodegroup not ready")
   214  	}
   215  	return nil
   216  }
   217  
   218  // IAMReadyFalse marks the ready condition false using warning if error isn't
   219  // empty.
   220  func (s *ManagedMachinePoolScope) IAMReadyFalse(reason string, err string) error {
   221  	severity := clusterv1.ConditionSeverityWarning
   222  	if err == "" {
   223  		severity = clusterv1.ConditionSeverityInfo
   224  	}
   225  	conditions.MarkFalse(
   226  		s.ManagedMachinePool,
   227  		expinfrav1.IAMNodegroupRolesReadyCondition,
   228  		reason,
   229  		severity,
   230  		err,
   231  	)
   232  	if err := s.PatchObject(); err != nil {
   233  		return errors.Wrap(err, "failed to mark nodegroup role not ready")
   234  	}
   235  	return nil
   236  }
   237  
   238  // PatchObject persists the control plane configuration and status.
   239  func (s *ManagedMachinePoolScope) PatchObject() error {
   240  	return s.patchHelper.Patch(
   241  		context.TODO(),
   242  		s.ManagedMachinePool,
   243  		patch.WithOwnedConditions{Conditions: []clusterv1.ConditionType{
   244  			expinfrav1.EKSNodegroupReadyCondition,
   245  			expinfrav1.IAMNodegroupRolesReadyCondition,
   246  		}})
   247  }
   248  
   249  // Close closes the current scope persisting the control plane configuration and status.
   250  func (s *ManagedMachinePoolScope) Close() error {
   251  	return s.PatchObject()
   252  }
   253  
   254  // InfraCluster returns the AWS infrastructure cluster or control plane object.
   255  func (s *ManagedMachinePoolScope) InfraCluster() cloud.ClusterObject {
   256  	return s.ControlPlane
   257  }
   258  
   259  // ClusterObj returns the cluster object.
   260  func (s *ManagedMachinePoolScope) ClusterObj() cloud.ClusterObject {
   261  	return s.Cluster
   262  }
   263  
   264  // Session returns the AWS SDK session. Used for creating clients.
   265  func (s *ManagedMachinePoolScope) Session() awsclient.ConfigProvider {
   266  	return s.session
   267  }
   268  
   269  // ControllerName returns the name of the controller that
   270  // created the ManagedMachinePool.
   271  func (s *ManagedMachinePoolScope) ControllerName() string {
   272  	return s.controllerName
   273  }
   274  
   275  // KubernetesClusterName is the name of the EKS cluster name.
   276  func (s *ManagedMachinePoolScope) KubernetesClusterName() string {
   277  	return s.ControlPlane.Spec.EKSClusterName
   278  }
   279  
   280  // NodegroupName is the name of the EKS nodegroup.
   281  func (s *ManagedMachinePoolScope) NodegroupName() string {
   282  	return s.ManagedMachinePool.Spec.EKSNodegroupName
   283  }