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  }