internal/pkg/api/cluster.go (345 lines of code) (raw):

package api import ( "fmt" "strings" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" anywherev1 "github.com/aws/eks-anywhere/pkg/api/v1alpha1" "github.com/aws/eks-anywhere/pkg/cluster" "github.com/aws/eks-anywhere/pkg/logger" "github.com/aws/eks-anywhere/pkg/providers" "github.com/aws/eks-anywhere/pkg/utils/ptr" ) type ClusterFiller func(c *anywherev1.Cluster) // ClusterToConfigFiller updates the Cluster in the cluster.Config by applying all the fillers. func ClusterToConfigFiller(fillers ...ClusterFiller) ClusterConfigFiller { return func(c *cluster.Config) { for _, f := range fillers { f(c.Cluster) } } } // JoinClusterConfigFillers creates one single ClusterConfigFiller from a collection of fillers. func JoinClusterConfigFillers(fillers ...ClusterConfigFiller) ClusterConfigFiller { return func(c *cluster.Config) { for _, f := range fillers { f(c) } } } func WithKubernetesVersion(v anywherev1.KubernetesVersion) ClusterFiller { return func(c *anywherev1.Cluster) { c.Spec.KubernetesVersion = v } } // WithLicenseToken sets LicenseToken with the provided token value to use. func WithLicenseToken(licenseToken string) ClusterFiller { return func(c *anywherev1.Cluster) { c.Spec.LicenseToken = licenseToken } } // WithBundlesRef sets BundlesRef with the provided name to use. func WithBundlesRef(name string, namespace string, apiVersion string) ClusterFiller { return func(c *anywherev1.Cluster) { c.Spec.BundlesRef = &anywherev1.BundlesRef{Name: name, Namespace: namespace, APIVersion: apiVersion} } } // WithEksaVersion sets EksaVersion with the provided name to use. func WithEksaVersion(eksaVersion *anywherev1.EksaVersion) ClusterFiller { return func(c *anywherev1.Cluster) { c.Spec.EksaVersion = eksaVersion } } func WithCiliumPolicyEnforcementMode(mode anywherev1.CiliumPolicyEnforcementMode) ClusterFiller { return func(c *anywherev1.Cluster) { if c.Spec.ClusterNetwork.CNIConfig == nil { c.Spec.ClusterNetwork.CNIConfig = &anywherev1.CNIConfig{Cilium: &anywherev1.CiliumConfig{}} } c.Spec.ClusterNetwork.CNIConfig.Cilium.PolicyEnforcementMode = mode } } // WithCiliumEgressMasqueradeInterfaces sets the egressMasqueradeInterfaces with the provided interface option to use. func WithCiliumEgressMasqueradeInterfaces(interfaceName string) ClusterFiller { return func(c *anywherev1.Cluster) { if c.Spec.ClusterNetwork.CNIConfig == nil { c.Spec.ClusterNetwork.CNIConfig = &anywherev1.CNIConfig{Cilium: &anywherev1.CiliumConfig{}} } c.Spec.ClusterNetwork.CNIConfig.Cilium.EgressMasqueradeInterfaces = interfaceName } } // WithCiliumSkipUpgrade enables skip upgrade for EKSA Cilium installations. func WithCiliumSkipUpgrade() ClusterFiller { return func(c *anywherev1.Cluster) { network := c.Spec.ClusterNetwork if network.CNIConfig != nil && network.CNIConfig.Cilium != nil { fmt.Println("Enable ciliun skip upgrade") network.CNIConfig.Cilium.SkipUpgrade = ptr.Bool(true) } } } // WithCiliumRoutingMode sets the tunnel mode with the provided mode option to use. func WithCiliumRoutingMode(mode anywherev1.CiliumRoutingMode) ClusterFiller { return func(c *anywherev1.Cluster) { if c.Spec.ClusterNetwork.CNIConfig == nil { c.Spec.ClusterNetwork.CNIConfig = &anywherev1.CNIConfig{Cilium: &anywherev1.CiliumConfig{}} } c.Spec.ClusterNetwork.CNIConfig.Cilium.RoutingMode = mode } } func WithClusterNamespace(ns string) ClusterFiller { return func(c *anywherev1.Cluster) { c.Namespace = ns } } func WithControlPlaneCount(r int) ClusterFiller { return func(c *anywherev1.Cluster) { c.Spec.ControlPlaneConfiguration.Count = r } } func WithControlPlaneEndpointIP(value string) ClusterFiller { return func(c *anywherev1.Cluster) { c.Spec.ControlPlaneConfiguration.Endpoint.Host = value } } func WithControlPlaneTaints(taints []corev1.Taint) ClusterFiller { return func(c *anywherev1.Cluster) { c.Spec.ControlPlaneConfiguration.Taints = taints } } func WithControlPlaneLabel(key string, val string) ClusterFiller { return func(c *anywherev1.Cluster) { if c.Spec.ControlPlaneConfiguration.Labels == nil { c.Spec.ControlPlaneConfiguration.Labels = map[string]string{} } c.Spec.ControlPlaneConfiguration.Labels[key] = val } } // WithControlPlaneAPIServerExtraArgs adds the APIServerExtraArgs to the cluster spec. func WithControlPlaneAPIServerExtraArgs() ClusterFiller { return func(c *anywherev1.Cluster) { if c.Spec.ControlPlaneConfiguration.APIServerExtraArgs == nil { c.Spec.ControlPlaneConfiguration.APIServerExtraArgs = map[string]string{} } issuerURL := "https://" + c.Spec.ControlPlaneConfiguration.Endpoint.Host c.Spec.ControlPlaneConfiguration.APIServerExtraArgs["service-account-jwks-uri"] = issuerURL + "/openid/v1/jwks" } } // WithControlPlaneKubeletConfig adds the Kubelet config to the control plane in cluster spec. func WithControlPlaneKubeletConfig(kc *unstructured.Unstructured) ClusterFiller { return func(c *anywherev1.Cluster) { c.Spec.ControlPlaneConfiguration.KubeletConfiguration = kc } } // RemoveAllAPIServerExtraArgs removes all the API server flags from the cluster spec. func RemoveAllAPIServerExtraArgs() ClusterFiller { return func(c *anywherev1.Cluster) { for k := range c.Spec.ControlPlaneConfiguration.APIServerExtraArgs { delete(c.Spec.ControlPlaneConfiguration.APIServerExtraArgs, k) } } } // WithPodCidr sets an explicit pod CIDR, overriding the provider's default. func WithPodCidr(podCidr string) ClusterFiller { return func(c *anywherev1.Cluster) { c.Spec.ClusterNetwork.Pods.CidrBlocks = strings.Split(podCidr, ",") } } func WithServiceCidr(svcCidr string) ClusterFiller { return func(c *anywherev1.Cluster) { c.Spec.ClusterNetwork.Services.CidrBlocks = []string{svcCidr} } } // WithWorkerKubernetesVersion sets the kubernetes version field for the given worker group. func WithWorkerKubernetesVersion(name string, version *anywherev1.KubernetesVersion) ClusterFiller { return func(c *anywherev1.Cluster) { pos := -1 for i, wng := range c.Spec.WorkerNodeGroupConfigurations { if wng.Name == name { wng.KubernetesVersion = version pos = i c.Spec.WorkerNodeGroupConfigurations[pos] = wng break } } // Append the worker node group if not already found in existing configuration if pos == -1 { c.Spec.WorkerNodeGroupConfigurations = append(c.Spec.WorkerNodeGroupConfigurations, workerNodeWithKubernetesVersion(name, version)) } } } func workerNodeWithKubernetesVersion(name string, version *anywherev1.KubernetesVersion) anywherev1.WorkerNodeGroupConfiguration { return anywherev1.WorkerNodeGroupConfiguration{ Name: name, Count: ptr.Int(1), KubernetesVersion: version, } } // WithWorkerNodeKubeletConfig adds the Kubelet config to the worker node groups in cluster spec. func WithWorkerNodeKubeletConfig(kc *unstructured.Unstructured) ClusterFiller { return func(c *anywherev1.Cluster) { if len(c.Spec.WorkerNodeGroupConfigurations) == 0 { c.Spec.WorkerNodeGroupConfigurations = []anywherev1.WorkerNodeGroupConfiguration{{}} } c.Spec.WorkerNodeGroupConfigurations[0].KubeletConfiguration = kc } } func WithWorkerNodeCount(r int) ClusterFiller { return func(c *anywherev1.Cluster) { if len(c.Spec.WorkerNodeGroupConfigurations) == 0 { c.Spec.WorkerNodeGroupConfigurations = []anywherev1.WorkerNodeGroupConfiguration{{Count: ptr.Int(0)}} } c.Spec.WorkerNodeGroupConfigurations[0].Count = &r } } // WithWorkerNodeAutoScalingConfig adds an autoscaling configuration with a given min and max count. func WithWorkerNodeAutoScalingConfig(min int, max int) ClusterFiller { return func(c *anywherev1.Cluster) { if len(c.Spec.WorkerNodeGroupConfigurations) == 0 { c.Spec.WorkerNodeGroupConfigurations = []anywherev1.WorkerNodeGroupConfiguration{{Count: ptr.Int(min)}} } c.Spec.WorkerNodeGroupConfigurations[0].AutoScalingConfiguration = &anywherev1.AutoScalingConfiguration{ MinCount: min, MaxCount: max, } } } func WithOIDCIdentityProviderRef(name string) ClusterFiller { return func(c *anywherev1.Cluster) { c.Spec.IdentityProviderRefs = append(c.Spec.IdentityProviderRefs, anywherev1.Ref{Name: name, Kind: anywherev1.OIDCConfigKind}) } } func WithGitOpsRef(name, kind string) ClusterFiller { return func(c *anywherev1.Cluster) { c.Spec.GitOpsRef = &anywherev1.Ref{Name: name, Kind: kind} } } func WithExternalEtcdTopology(count int) ClusterFiller { return func(c *anywherev1.Cluster) { if c.Spec.ExternalEtcdConfiguration == nil { c.Spec.ExternalEtcdConfiguration = &anywherev1.ExternalEtcdConfiguration{} } c.Spec.ExternalEtcdConfiguration.Count = count } } func WithEtcdCountIfExternal(count int) ClusterFiller { return func(c *anywherev1.Cluster) { if c.Spec.ExternalEtcdConfiguration != nil { c.Spec.ExternalEtcdConfiguration.Count = count } } } func WithExternalEtcdMachineRef(kind string) ClusterFiller { return func(c *anywherev1.Cluster) { if c.Spec.ExternalEtcdConfiguration == nil { c.Spec.ExternalEtcdConfiguration = &anywherev1.ExternalEtcdConfiguration{} c.Spec.ExternalEtcdConfiguration.Count = 1 } if c.Spec.ExternalEtcdConfiguration.MachineGroupRef == nil { c.Spec.ExternalEtcdConfiguration.MachineGroupRef = &anywherev1.Ref{} } c.Spec.ExternalEtcdConfiguration.MachineGroupRef.Kind = kind c.Spec.ExternalEtcdConfiguration.MachineGroupRef.Name = providers.GetEtcdNodeName(c.Name) } } func WithStackedEtcdTopology() ClusterFiller { return func(c *anywherev1.Cluster) { c.Spec.ExternalEtcdConfiguration = nil } } func WithProxyConfig(httpProxy, httpsProxy string, noProxy []string) ClusterFiller { return func(c *anywherev1.Cluster) { if c.Spec.ProxyConfiguration == nil { c.Spec.ProxyConfiguration = &anywherev1.ProxyConfiguration{} } c.Spec.ProxyConfiguration.HttpProxy = httpProxy c.Spec.ProxyConfiguration.HttpsProxy = httpProxy c.Spec.ProxyConfiguration.NoProxy = noProxy } } // WithRegistryMirror adds a registry mirror configuration. func WithRegistryMirror(endpoint, port string, caCert string, authenticate bool, insecureSkipVerify bool, ociNamespaces ...anywherev1.OCINamespace) ClusterFiller { return func(c *anywherev1.Cluster) { if c.Spec.RegistryMirrorConfiguration == nil { c.Spec.RegistryMirrorConfiguration = &anywherev1.RegistryMirrorConfiguration{} } c.Spec.RegistryMirrorConfiguration.Endpoint = endpoint c.Spec.RegistryMirrorConfiguration.Port = port c.Spec.RegistryMirrorConfiguration.CACertContent = caCert c.Spec.RegistryMirrorConfiguration.Authenticate = authenticate c.Spec.RegistryMirrorConfiguration.InsecureSkipVerify = insecureSkipVerify if len(ociNamespaces) != 0 { c.Spec.RegistryMirrorConfiguration.OCINamespaces = ociNamespaces } } } func WithManagementCluster(name string) ClusterFiller { return func(c *anywherev1.Cluster) { c.Spec.ManagementCluster.Name = name } } func WithAWSIamIdentityProviderRef(name string) ClusterFiller { return func(c *anywherev1.Cluster) { c.Spec.IdentityProviderRefs = append(c.Spec.IdentityProviderRefs, anywherev1.Ref{Name: name, Kind: anywherev1.AWSIamConfigKind}) } } func RemoveAllWorkerNodeGroups() ClusterFiller { return func(c *anywherev1.Cluster) { c.Spec.WorkerNodeGroupConfigurations = make([]anywherev1.WorkerNodeGroupConfiguration, 0) } } func RemoveWorkerNodeGroup(name string) ClusterFiller { logger.Info("removing", "name", name) return func(c *anywherev1.Cluster) { logger.Info("before deleting", "w", c.Spec.WorkerNodeGroupConfigurations) for i, w := range c.Spec.WorkerNodeGroupConfigurations { if w.Name == name { copy(c.Spec.WorkerNodeGroupConfigurations[i:], c.Spec.WorkerNodeGroupConfigurations[i+1:]) c.Spec.WorkerNodeGroupConfigurations[len(c.Spec.WorkerNodeGroupConfigurations)-1] = anywherev1.WorkerNodeGroupConfiguration{} c.Spec.WorkerNodeGroupConfigurations = c.Spec.WorkerNodeGroupConfigurations[:len(c.Spec.WorkerNodeGroupConfigurations)-1] logger.Info("after deleting", "w", c.Spec.WorkerNodeGroupConfigurations) return } } } } func WithWorkerNodeGroup(name string, fillers ...WorkerNodeGroupFiller) ClusterFiller { return func(c *anywherev1.Cluster) { var nodeGroup *anywherev1.WorkerNodeGroupConfiguration position := -1 for i, w := range c.Spec.WorkerNodeGroupConfigurations { if w.Name == name { logger.Info("Updating worker node group", "name", name) nodeGroup = &w position = i break } } if nodeGroup == nil { logger.Info("Adding worker node group", "name", name) nodeGroup = &anywherev1.WorkerNodeGroupConfiguration{Name: name} c.Spec.WorkerNodeGroupConfigurations = append(c.Spec.WorkerNodeGroupConfigurations, *nodeGroup) position = len(c.Spec.WorkerNodeGroupConfigurations) - 1 } FillWorkerNodeGroup(nodeGroup, fillers...) c.Spec.WorkerNodeGroupConfigurations[position] = *nodeGroup } } // WithPodIamFiller configures pod IAM config to enable IRSA. func WithPodIamFiller(issuerURL string) ClusterFiller { return func(c *anywherev1.Cluster) { c.Spec.PodIAMConfig = &anywherev1.PodIAMConfig{ ServiceAccountIssuer: issuerURL, } } } // WithEtcdEncryptionFiller configures EtcdEncyption on the cluster. func WithEtcdEncryptionFiller(kms *anywherev1.KMS, resources []string) ClusterFiller { return func(c *anywherev1.Cluster) { c.Spec.EtcdEncryption = &[]anywherev1.EtcdEncryption{ { Providers: []anywherev1.EtcdEncryptionProvider{ { KMS: kms, }, }, Resources: resources, }, } } } // WithInPlaceUpgradeStrategy configures the UpgradeStrategy on Control-plane and Worker node groups to InPlace. func WithInPlaceUpgradeStrategy() ClusterFiller { return func(c *anywherev1.Cluster) { c.Spec.ControlPlaneConfiguration.UpgradeRolloutStrategy = &anywherev1.ControlPlaneUpgradeRolloutStrategy{ Type: anywherev1.InPlaceStrategyType, } for idx, wng := range c.Spec.WorkerNodeGroupConfigurations { wng.UpgradeRolloutStrategy = &anywherev1.WorkerNodesUpgradeRolloutStrategy{ Type: anywherev1.InPlaceStrategyType, } c.Spec.WorkerNodeGroupConfigurations[idx] = wng } } }