pkg/providers/nutanix/template.go (546 lines of code) (raw):

package nutanix import ( "encoding/base64" "encoding/json" "fmt" "net" "strings" capxv1beta1 "github.com/nutanix-cloud-native/cluster-api-provider-nutanix/api/v1beta1" "github.com/nutanix-cloud-native/prism-go-client/environment/credentials" "sigs.k8s.io/yaml" "github.com/aws/eks-anywhere/pkg/api/v1alpha1" "github.com/aws/eks-anywhere/pkg/cluster" "github.com/aws/eks-anywhere/pkg/clusterapi" "github.com/aws/eks-anywhere/pkg/config" "github.com/aws/eks-anywhere/pkg/constants" "github.com/aws/eks-anywhere/pkg/crypto" "github.com/aws/eks-anywhere/pkg/providers" "github.com/aws/eks-anywhere/pkg/providers/common" "github.com/aws/eks-anywhere/pkg/registrymirror" "github.com/aws/eks-anywhere/pkg/registrymirror/containerd" "github.com/aws/eks-anywhere/pkg/templater" "github.com/aws/eks-anywhere/pkg/types" ) var jsonMarshal = json.Marshal // TemplateBuilder builds templates for nutanix. type TemplateBuilder struct { datacenterSpec *v1alpha1.NutanixDatacenterConfigSpec controlPlaneMachineSpec *v1alpha1.NutanixMachineConfigSpec etcdMachineSpec *v1alpha1.NutanixMachineConfigSpec workerNodeGroupMachineSpecs map[string]v1alpha1.NutanixMachineConfigSpec creds credentials.BasicAuthCredential now types.NowFunc } var _ providers.TemplateBuilder = &TemplateBuilder{} func NewNutanixTemplateBuilder( datacenterSpec *v1alpha1.NutanixDatacenterConfigSpec, controlPlaneMachineSpec, etcdMachineSpec *v1alpha1.NutanixMachineConfigSpec, workerNodeGroupMachineSpecs map[string]v1alpha1.NutanixMachineConfigSpec, creds credentials.BasicAuthCredential, now types.NowFunc, ) *TemplateBuilder { return &TemplateBuilder{ datacenterSpec: datacenterSpec, controlPlaneMachineSpec: controlPlaneMachineSpec, etcdMachineSpec: etcdMachineSpec, workerNodeGroupMachineSpecs: workerNodeGroupMachineSpecs, creds: creds, now: now, } } func (ntb *TemplateBuilder) GenerateCAPISpecControlPlane(clusterSpec *cluster.Spec, buildOptions ...providers.BuildMapOption) (content []byte, err error) { var etcdMachineSpec v1alpha1.NutanixMachineConfigSpec if clusterSpec.Cluster.Spec.ExternalEtcdConfiguration != nil { etcdMachineSpec = *ntb.etcdMachineSpec } values, err := buildTemplateMapCP(ntb.datacenterSpec, clusterSpec, *ntb.controlPlaneMachineSpec, etcdMachineSpec, ntb.creds) if err != nil { return nil, err } for _, buildOption := range buildOptions { buildOption(values) } bytes, err := templater.Execute(defaultCAPIConfigCP, values) if err != nil { return nil, err } return bytes, nil } func (ntb *TemplateBuilder) GenerateCAPISpecWorkers(clusterSpec *cluster.Spec, workloadTemplateNames, kubeadmconfigTemplateNames map[string]string) (content []byte, err error) { workerSpecs := make([][]byte, 0, len(clusterSpec.Cluster.Spec.WorkerNodeGroupConfigurations)) for _, workerNodeGroupConfiguration := range clusterSpec.Cluster.Spec.WorkerNodeGroupConfigurations { values, err := buildTemplateMapMD(clusterSpec, ntb.workerNodeGroupMachineSpecs[workerNodeGroupConfiguration.MachineGroupRef.Name], workerNodeGroupConfiguration) if err != nil { return nil, err } values["workloadTemplateName"] = workloadTemplateNames[workerNodeGroupConfiguration.Name] values["workloadkubeadmconfigTemplateName"] = kubeadmconfigTemplateNames[workerNodeGroupConfiguration.Name] values["autoscalingConfig"] = workerNodeGroupConfiguration.AutoScalingConfiguration if workerNodeGroupConfiguration.UpgradeRolloutStrategy != nil { values["upgradeRolloutStrategy"] = true values["maxSurge"] = workerNodeGroupConfiguration.UpgradeRolloutStrategy.RollingUpdate.MaxSurge values["maxUnavailable"] = workerNodeGroupConfiguration.UpgradeRolloutStrategy.RollingUpdate.MaxUnavailable } bytes, err := templater.Execute(defaultClusterConfigMD, values) if err != nil { return nil, err } workerSpecs = append(workerSpecs, bytes) } return templater.AppendYamlResources(workerSpecs...), nil } // GenerateCAPISpecSecret generates the secret containing the credentials for the nutanix prism central and is used by the // CAPX controller. The secret is named after the cluster name. func (ntb *TemplateBuilder) GenerateCAPISpecSecret(clusterSpec *cluster.Spec, buildOptions ...providers.BuildMapOption) (content []byte, err error) { return ntb.generateSpecSecret(clusterSpec, CAPXSecretName(clusterSpec), ntb.creds, buildOptions...) } // CAPXSecretName returns the name of the secret containing the credentials for the nutanix prism central and is used by the // CAPX controller. func CAPXSecretName(spec *cluster.Spec) string { return fmt.Sprintf("capx-%s", spec.Cluster.Name) } // GenerateEKSASpecSecret generates the secret containing the credentials for the nutanix prism central and is used by the // EKS-A controller. The secret is named nutanix-credentials. func (ntb *TemplateBuilder) GenerateEKSASpecSecret(clusterSpec *cluster.Spec, buildOptions ...providers.BuildMapOption) (content []byte, err error) { return ntb.generateSpecSecret(clusterSpec, EKSASecretName(clusterSpec), ntb.creds, buildOptions...) } // EKSASecretName returns the name of the secret containing the credentials for the nutanix prism central and is used by the // EKS-Anywhere controller. func EKSASecretName(spec *cluster.Spec) string { if spec.NutanixDatacenter.Spec.CredentialRef != nil { return spec.NutanixDatacenter.Spec.CredentialRef.Name } return constants.NutanixCredentialsName } func (ntb *TemplateBuilder) generateSpecSecret(clusterSpec *cluster.Spec, secretName string, creds credentials.BasicAuthCredential, buildOptions ...providers.BuildMapOption) ([]byte, error) { values, err := buildTemplateMapSecret(clusterSpec, secretName, creds) if err != nil { return nil, err } for _, buildOption := range buildOptions { buildOption(values) } bytes, err := templater.Execute(secretTemplate, values) if err != nil { return nil, err } return bytes, nil } func machineDeploymentName(clusterName, nodeGroupName string) string { return fmt.Sprintf("%s-%s", clusterName, nodeGroupName) } func buildTemplateMapCP( datacenterSpec *v1alpha1.NutanixDatacenterConfigSpec, clusterSpec *cluster.Spec, controlPlaneMachineSpec v1alpha1.NutanixMachineConfigSpec, etcdMachineSpec v1alpha1.NutanixMachineConfigSpec, creds credentials.BasicAuthCredential, ) (map[string]interface{}, error) { versionsBundle := clusterSpec.RootVersionsBundle() format := "cloud-config" apiServerExtraArgs := clusterapi.OIDCToExtraArgs(clusterSpec.OIDCConfig). Append(clusterapi.AwsIamAuthExtraArgs(clusterSpec.AWSIamConfig)). Append(clusterapi.APIServerExtraArgs(clusterSpec.Cluster.Spec.ControlPlaneConfiguration.APIServerExtraArgs)). Append(clusterapi.EtcdEncryptionExtraArgs(clusterSpec.Cluster.Spec.EtcdEncryption)) clusterapi.SetPodIAMAuthExtraArgs(clusterSpec.Cluster.Spec.PodIAMConfig, apiServerExtraArgs) auditPolicy, err := common.GetAuditPolicy(clusterSpec.Cluster.Spec.KubernetesVersion) if err != nil { return nil, err } failureDomains := generateNutanixFailureDomains(datacenterSpec.FailureDomains) ccmIgnoredNodeIPs := generateCcmIgnoredNodeIPsList(clusterSpec) values := map[string]interface{}{ "auditPolicy": auditPolicy, "apiServerExtraArgs": apiServerExtraArgs.ToPartialYaml(), "ccmIgnoredNodeIPs": ccmIgnoredNodeIPs, "cloudProviderImage": versionsBundle.Nutanix.CloudProvider.VersionedImage(), "clusterName": clusterSpec.Cluster.Name, "controlPlaneEndpointIp": clusterSpec.Cluster.Spec.ControlPlaneConfiguration.Endpoint.Host, "controlPlaneReplicas": clusterSpec.Cluster.Spec.ControlPlaneConfiguration.Count, "controlPlaneSshAuthorizedKey": controlPlaneMachineSpec.Users[0].SshAuthorizedKeys[0], "controlPlaneSshUsername": controlPlaneMachineSpec.Users[0].Name, "controlPlaneTaints": clusterSpec.Cluster.Spec.ControlPlaneConfiguration.Taints, "eksaSystemNamespace": constants.EksaSystemNamespace, "format": format, "failureDomains": failureDomains, "podCidrs": clusterSpec.Cluster.Spec.ClusterNetwork.Pods.CidrBlocks, "serviceCidrs": clusterSpec.Cluster.Spec.ClusterNetwork.Services.CidrBlocks, "kubernetesVersion": versionsBundle.KubeDistro.Kubernetes.Tag, "kubernetesRepository": versionsBundle.KubeDistro.Kubernetes.Repository, "corednsRepository": versionsBundle.KubeDistro.CoreDNS.Repository, "corednsVersion": versionsBundle.KubeDistro.CoreDNS.Tag, "etcdRepository": versionsBundle.KubeDistro.Etcd.Repository, "etcdImageTag": versionsBundle.KubeDistro.Etcd.Tag, "kubeVipImage": versionsBundle.Nutanix.KubeVip.VersionedImage(), "kubeVipSvcEnable": false, "kubeVipLBEnable": false, "externalEtcdVersion": versionsBundle.KubeDistro.EtcdVersion, "etcdCipherSuites": crypto.SecureCipherSuitesString(), "nutanixEndpoint": datacenterSpec.Endpoint, "nutanixPort": datacenterSpec.Port, "nutanixAdditionalTrustBundle": datacenterSpec.AdditionalTrustBundle, "nutanixInsecure": datacenterSpec.Insecure, "vcpusPerSocket": controlPlaneMachineSpec.VCPUsPerSocket, "vcpuSockets": controlPlaneMachineSpec.VCPUSockets, "memorySize": controlPlaneMachineSpec.MemorySize.String(), "systemDiskSize": controlPlaneMachineSpec.SystemDiskSize.String(), "imageIDType": controlPlaneMachineSpec.Image.Type, "imageName": controlPlaneMachineSpec.Image.Name, "imageUUID": controlPlaneMachineSpec.Image.UUID, "nutanixPEClusterIDType": controlPlaneMachineSpec.Cluster.Type, "nutanixPEClusterName": controlPlaneMachineSpec.Cluster.Name, "nutanixPEClusterUUID": controlPlaneMachineSpec.Cluster.UUID, "secretName": CAPXSecretName(clusterSpec), "subnetIDType": controlPlaneMachineSpec.Subnet.Type, "subnetName": controlPlaneMachineSpec.Subnet.Name, "subnetUUID": controlPlaneMachineSpec.Subnet.UUID, "apiServerCertSANs": clusterSpec.Cluster.Spec.ControlPlaneConfiguration.CertSANs, "nutanixPCUsername": creds.PrismCentral.BasicAuth.Username, "nutanixPCPassword": creds.PrismCentral.BasicAuth.Password, } if controlPlaneMachineSpec.Project != nil { values["projectIDType"] = controlPlaneMachineSpec.Project.Type values["projectName"] = controlPlaneMachineSpec.Project.Name values["projectUUID"] = controlPlaneMachineSpec.Project.UUID } if len(controlPlaneMachineSpec.AdditionalCategories) > 0 { values["additionalCategories"] = controlPlaneMachineSpec.AdditionalCategories } if clusterSpec.Cluster.Spec.RegistryMirrorConfiguration != nil { registryMirror := registrymirror.FromCluster(clusterSpec.Cluster) values["registryMirrorMap"] = containerd.ToAPIEndpoints(registryMirror.NamespacedRegistryMap) values["mirrorBase"] = registryMirror.BaseRegistry values["publicMirror"] = containerd.ToAPIEndpoint(registryMirror.CoreEKSAMirror()) values["insecureSkip"] = registryMirror.InsecureSkipVerify if len(registryMirror.CACertContent) > 0 { values["registryCACert"] = registryMirror.CACertContent } if registryMirror.Auth { values["registryAuth"] = registryMirror.Auth username, password, err := config.ReadCredentials() if err != nil { return values, err } values["registryUsername"] = username values["registryPassword"] = password } } if clusterSpec.Cluster.Spec.ExternalEtcdConfiguration != nil { values["externalEtcd"] = true values["externalEtcdReplicas"] = clusterSpec.Cluster.Spec.ExternalEtcdConfiguration.Count values["etcdSshUsername"] = etcdMachineSpec.Users[0].Name values["etcdSshAuthorizedKey"] = etcdMachineSpec.Users[0].SshAuthorizedKeys[0] values["etcdVCPUsPerSocket"] = etcdMachineSpec.VCPUsPerSocket values["etcdVcpuSockets"] = etcdMachineSpec.VCPUSockets values["etcdMemorySize"] = etcdMachineSpec.MemorySize.String() values["etcdSystemDiskSize"] = etcdMachineSpec.SystemDiskSize.String() values["etcdImageIDType"] = etcdMachineSpec.Image.Type values["etcdImageName"] = etcdMachineSpec.Image.Name values["etcdImageUUID"] = etcdMachineSpec.Image.UUID values["etcdSubnetIDType"] = etcdMachineSpec.Subnet.Type values["etcdSubnetName"] = etcdMachineSpec.Subnet.Name values["etcdSubnetUUID"] = etcdMachineSpec.Subnet.UUID values["etcdNutanixPEClusterIDType"] = etcdMachineSpec.Cluster.Type values["etcdNutanixPEClusterName"] = etcdMachineSpec.Cluster.Name values["etcdNutanixPEClusterUUID"] = etcdMachineSpec.Cluster.UUID if etcdMachineSpec.Project != nil { values["etcdProjectIDType"] = etcdMachineSpec.Project.Type values["etcdProjectName"] = etcdMachineSpec.Project.Name values["etcdProjectUUID"] = etcdMachineSpec.Project.UUID } if len(etcdMachineSpec.AdditionalCategories) > 0 { values["etcdAdditionalCategories"] = etcdMachineSpec.AdditionalCategories } } if clusterSpec.AWSIamConfig != nil { values["awsIamAuth"] = true } if clusterSpec.Cluster.Spec.ProxyConfiguration != nil { values["proxyConfig"] = true values["httpProxy"] = clusterSpec.Cluster.Spec.ProxyConfiguration.HttpProxy values["httpsProxy"] = clusterSpec.Cluster.Spec.ProxyConfiguration.HttpsProxy values["noProxy"] = generateNoProxyList(clusterSpec) } if clusterSpec.Cluster.Spec.ControlPlaneConfiguration.UpgradeRolloutStrategy != nil { values["upgradeRolloutStrategy"] = true values["maxSurge"] = clusterSpec.Cluster.Spec.ControlPlaneConfiguration.UpgradeRolloutStrategy.RollingUpdate.MaxSurge } etcdURL, _ := common.GetExternalEtcdReleaseURL(clusterSpec.Cluster.Spec.EksaVersion, versionsBundle) if etcdURL != "" { values["externalEtcdReleaseUrl"] = etcdURL } if clusterSpec.Cluster.Spec.EtcdEncryption != nil && len(*clusterSpec.Cluster.Spec.EtcdEncryption) != 0 { conf, err := common.GenerateKMSEncryptionConfiguration(clusterSpec.Cluster.Spec.EtcdEncryption) if err != nil { return nil, err } values["encryptionProviderConfig"] = conf } if clusterSpec.Cluster.Spec.ControlPlaneConfiguration.KubeletConfiguration != nil { cpKubeletConfig := clusterSpec.Cluster.Spec.ControlPlaneConfiguration.KubeletConfiguration.Object if _, ok := cpKubeletConfig["tlsCipherSuites"]; !ok { cpKubeletConfig["tlsCipherSuites"] = crypto.SecureCipherSuiteNames() } if _, ok := cpKubeletConfig["resolvConf"]; !ok { if clusterSpec.Cluster.Spec.ClusterNetwork.DNS.ResolvConf != nil { cpKubeletConfig["resolvConf"] = clusterSpec.Cluster.Spec.ClusterNetwork.DNS.ResolvConf.Path } } kcString, err := yaml.Marshal(cpKubeletConfig) if err != nil { return nil, fmt.Errorf("error marshaling %v", err) } values["kubeletConfiguration"] = string(kcString) } else { kubeletExtraArgs := clusterapi.SecureTlsCipherSuitesExtraArgs(). Append(clusterapi.ResolvConfExtraArgs(clusterSpec.Cluster.Spec.ClusterNetwork.DNS.ResolvConf)) values["kubeletExtraArgs"] = kubeletExtraArgs.ToPartialYaml() } nodeLabelArgs := clusterapi.ControlPlaneNodeLabelsExtraArgs(clusterSpec.Cluster.Spec.ControlPlaneConfiguration) if len(nodeLabelArgs) != 0 { values["nodeLabelArgs"] = nodeLabelArgs.ToPartialYaml() } return values, nil } func calcFailureDomainReplicas(workerNodeGroupConfiguration v1alpha1.WorkerNodeGroupConfiguration, failureDomains []v1alpha1.NutanixDatacenterFailureDomain) map[string]int { replicasPerFailureDomain := make(map[string]int) failureDomainCount := len(failureDomains) if workerNodeGroupConfiguration.AutoScalingConfiguration != nil { return replicasPerFailureDomain } if failureDomainCount == 0 { return replicasPerFailureDomain } workerNodeGroupCount := failureDomainCount if workerNodeGroupConfiguration.Count != nil { workerNodeGroupCount = int(*workerNodeGroupConfiguration.Count) } minCount := int(workerNodeGroupCount / failureDomainCount) for i := 0; i < len(failureDomains); i++ { replicasPerFailureDomain[failureDomains[i].Name] = minCount } replicasPerFailureDomain[failureDomains[0].Name] = workerNodeGroupCount - (failureDomainCount-1)*minCount return replicasPerFailureDomain } func getFailureDomainsForWorkerNodeGroup(allFailureDomains []v1alpha1.NutanixDatacenterFailureDomain, workerNodeGroupConfigurationName string) []v1alpha1.NutanixDatacenterFailureDomain { result := make([]v1alpha1.NutanixDatacenterFailureDomain, 0) for _, fd := range allFailureDomains { for _, workerMachineGroup := range fd.WorkerMachineGroups { if workerMachineGroup == workerNodeGroupConfigurationName { result = append(result, fd) } } } return result } func buildTemplateMapMD(clusterSpec *cluster.Spec, workerNodeGroupMachineSpec v1alpha1.NutanixMachineConfigSpec, workerNodeGroupConfiguration v1alpha1.WorkerNodeGroupConfiguration) (map[string]interface{}, error) { versionsBundle := clusterSpec.WorkerNodeGroupVersionsBundle(workerNodeGroupConfiguration) format := "cloud-config" failureDomainsForWorkerNodeGroup := getFailureDomainsForWorkerNodeGroup(clusterSpec.NutanixDatacenter.Spec.FailureDomains, workerNodeGroupConfiguration.Name) replicasPerFailureDomain := calcFailureDomainReplicas(workerNodeGroupConfiguration, failureDomainsForWorkerNodeGroup) values := map[string]interface{}{ "clusterName": clusterSpec.Cluster.Name, "eksaSystemNamespace": constants.EksaSystemNamespace, "format": format, "kubernetesVersion": versionsBundle.KubeDistro.Kubernetes.Tag, "workerReplicas": *workerNodeGroupConfiguration.Count, "workerPoolName": "md-0", "workerSshAuthorizedKey": workerNodeGroupMachineSpec.Users[0].SshAuthorizedKeys[0], "workerSshUsername": workerNodeGroupMachineSpec.Users[0].Name, "vcpusPerSocket": workerNodeGroupMachineSpec.VCPUsPerSocket, "vcpuSockets": workerNodeGroupMachineSpec.VCPUSockets, "memorySize": workerNodeGroupMachineSpec.MemorySize.String(), "systemDiskSize": workerNodeGroupMachineSpec.SystemDiskSize.String(), "imageIDType": workerNodeGroupMachineSpec.Image.Type, "imageName": workerNodeGroupMachineSpec.Image.Name, "imageUUID": workerNodeGroupMachineSpec.Image.UUID, "nutanixPEClusterIDType": workerNodeGroupMachineSpec.Cluster.Type, "nutanixPEClusterName": workerNodeGroupMachineSpec.Cluster.Name, "nutanixPEClusterUUID": workerNodeGroupMachineSpec.Cluster.UUID, "subnetIDType": workerNodeGroupMachineSpec.Subnet.Type, "subnetName": workerNodeGroupMachineSpec.Subnet.Name, "subnetUUID": workerNodeGroupMachineSpec.Subnet.UUID, "workerNodeGroupName": fmt.Sprintf("%s-%s", clusterSpec.Cluster.Name, workerNodeGroupConfiguration.Name), "workerNodeGroupTaints": workerNodeGroupConfiguration.Taints, "failureDomains": failureDomainsForWorkerNodeGroup, "failureDomainsReplicas": replicasPerFailureDomain, } if clusterSpec.Cluster.Spec.RegistryMirrorConfiguration != nil { registryMirror := registrymirror.FromCluster(clusterSpec.Cluster) values["registryMirrorMap"] = containerd.ToAPIEndpoints(registryMirror.NamespacedRegistryMap) values["mirrorBase"] = registryMirror.BaseRegistry values["publicMirror"] = containerd.ToAPIEndpoint(registryMirror.CoreEKSAMirror()) values["insecureSkip"] = registryMirror.InsecureSkipVerify if len(registryMirror.CACertContent) > 0 { values["registryCACert"] = registryMirror.CACertContent } if registryMirror.Auth { values["registryAuth"] = registryMirror.Auth username, password, err := config.ReadCredentials() if err != nil { return values, err } values["registryUsername"] = username values["registryPassword"] = password } } if workerNodeGroupMachineSpec.Project != nil { values["projectIDType"] = workerNodeGroupMachineSpec.Project.Type values["projectName"] = workerNodeGroupMachineSpec.Project.Name values["projectUUID"] = workerNodeGroupMachineSpec.Project.UUID } if clusterSpec.Cluster.Spec.ProxyConfiguration != nil { values["proxyConfig"] = true values["httpProxy"] = clusterSpec.Cluster.Spec.ProxyConfiguration.HttpProxy values["httpsProxy"] = clusterSpec.Cluster.Spec.ProxyConfiguration.HttpsProxy values["noProxy"] = generateNoProxyList(clusterSpec) } if len(workerNodeGroupMachineSpec.AdditionalCategories) > 0 { values["additionalCategories"] = workerNodeGroupMachineSpec.AdditionalCategories } if len(workerNodeGroupMachineSpec.GPUs) > 0 { values["GPUs"] = workerNodeGroupMachineSpec.GPUs } if workerNodeGroupConfiguration.KubeletConfiguration != nil { wnKubeletConfig := workerNodeGroupConfiguration.KubeletConfiguration.Object if _, ok := wnKubeletConfig["tlsCipherSuites"]; !ok { wnKubeletConfig["tlsCipherSuites"] = crypto.SecureCipherSuiteNames() } if _, ok := wnKubeletConfig["resolvConf"]; !ok { if clusterSpec.Cluster.Spec.ClusterNetwork.DNS.ResolvConf != nil { wnKubeletConfig["resolvConf"] = clusterSpec.Cluster.Spec.ClusterNetwork.DNS.ResolvConf.Path } } kcString, err := yaml.Marshal(wnKubeletConfig) if err != nil { return nil, fmt.Errorf("error marshaling %v", err) } values["kubeletConfiguration"] = string(kcString) } else { kubeletExtraArgs := clusterapi.SecureTlsCipherSuitesExtraArgs(). Append(clusterapi.ResolvConfExtraArgs(clusterSpec.Cluster.Spec.ClusterNetwork.DNS.ResolvConf)) values["kubeletExtraArgs"] = kubeletExtraArgs.ToPartialYaml() } nodeLabelArgs := clusterapi.WorkerNodeLabelsExtraArgs(workerNodeGroupConfiguration) if len(nodeLabelArgs) != 0 { values["nodeLabelArgs"] = nodeLabelArgs.ToPartialYaml() } return values, nil } func buildTemplateMapSecret(clusterSpec *cluster.Spec, secretName string, creds credentials.BasicAuthCredential) (map[string]interface{}, error) { encodedCreds, err := jsonMarshal(creds) if err != nil { return nil, err } nutanixCreds := []credentials.Credential{{ Type: credentials.BasicAuthCredentialType, Data: encodedCreds, }} credsJSON, err := jsonMarshal(nutanixCreds) if err != nil { return nil, err } values := map[string]interface{}{ "clusterName": clusterSpec.Cluster.Name, "secretName": secretName, "eksaSystemNamespace": constants.EksaSystemNamespace, "base64EncodedCredentials": base64.StdEncoding.EncodeToString(credsJSON), "nutanixPCUsername": creds.PrismCentral.BasicAuth.Username, "nutanixPCPassword": creds.PrismCentral.BasicAuth.Password, } return values, nil } func generateNoProxyList(clusterSpec *cluster.Spec) []string { capacity := len(clusterSpec.Cluster.Spec.ClusterNetwork.Pods.CidrBlocks) + len(clusterSpec.Cluster.Spec.ClusterNetwork.Services.CidrBlocks) + len(clusterSpec.Cluster.Spec.ProxyConfiguration.NoProxy) + 4 noProxyList := make([]string, 0, capacity) noProxyList = append(noProxyList, clusterSpec.Cluster.Spec.ClusterNetwork.Pods.CidrBlocks...) noProxyList = append(noProxyList, clusterSpec.Cluster.Spec.ClusterNetwork.Services.CidrBlocks...) noProxyList = append(noProxyList, clusterSpec.Cluster.Spec.ProxyConfiguration.NoProxy...) // Add no-proxy defaults noProxyList = append(noProxyList, clusterapi.NoProxyDefaults()...) noProxyList = append(noProxyList, clusterSpec.Config.NutanixDatacenter.Spec.Endpoint, clusterSpec.Cluster.Spec.ControlPlaneConfiguration.Endpoint.Host, ) return noProxyList } func generateNutanixFailureDomains(eksNutanixFailureDomains []v1alpha1.NutanixDatacenterFailureDomain) []capxv1beta1.NutanixFailureDomain { var failureDomains []capxv1beta1.NutanixFailureDomain for _, fd := range eksNutanixFailureDomains { subnets := []capxv1beta1.NutanixResourceIdentifier{} for _, subnet := range fd.Subnets { subnets = append(subnets, capxv1beta1.NutanixResourceIdentifier{ Type: capxv1beta1.NutanixIdentifierType(subnet.Type), Name: subnet.Name, UUID: subnet.UUID, }) } failureDomains = append(failureDomains, capxv1beta1.NutanixFailureDomain{ Name: fd.Name, Cluster: capxv1beta1.NutanixResourceIdentifier{ Type: capxv1beta1.NutanixIdentifierType(fd.Cluster.Type), Name: fd.Cluster.Name, UUID: fd.Cluster.UUID, }, Subnets: subnets, ControlPlane: true, }) } return failureDomains } func incrementIP(ip net.IP) { for i := len(ip) - 1; i >= 0; i-- { ip[i]++ if ip[i] > 0 { break } } } func compareIP(ip1, ip2 net.IP) (int, error) { if len(ip1) != len(ip2) { return -1, fmt.Errorf("IP addresses are not the same protocol") } for i := 0; i < len(ip1); i++ { if ip1[i] < ip2[i] { return -1, nil } if ip1[i] > ip2[i] { return 1, nil } } return 0, nil } func addCIDRToIgnoredNodeIPsList(cidr string, result []string) []string { ip, ipNet, _ := net.ParseCIDR(cidr) // Add all ip addresses in the range to the list for ip := ip.Mask(ipNet.Mask); ipNet.Contains(ip); incrementIP(ip) { if ip != nil { result = append(result, ip.String()) } } return result } func addIPRangeToIgnoredNodeIPsList(ipRangeStr string, result []string) []string { // Parse the range ipRange := strings.Split(ipRangeStr, "-") // Parse the start and end of the range start := net.ParseIP(strings.TrimSpace(ipRange[0])) end := net.ParseIP(strings.TrimSpace(ipRange[1])) cmp, _ := compareIP(start, end) if cmp >= 0 { // swap start and end if start is greater than end start, end = end, start } // Add all ip addresses in the range to the list for ip := start; !ip.Equal(end); incrementIP(ip) { result = append(result, ip.String()) } result = append(result, end.String()) return result } func addIPAddressToIgnoredNodeIPsList(ipAddrStr string, result []string) []string { result = append(result, ipAddrStr) return result } func generateCcmIgnoredNodeIPsList(clusterSpec *cluster.Spec) []string { // Add the kube-vip IP address to the list result := []string{clusterSpec.Cluster.Spec.ControlPlaneConfiguration.Endpoint.Host} for _, IPAddrOrRange := range clusterSpec.NutanixDatacenter.Spec.CcmExcludeNodeIPs { addrOrRange := strings.TrimSpace(IPAddrOrRange) if strings.Contains(addrOrRange, "/") { result = addCIDRToIgnoredNodeIPsList(addrOrRange, result) } else if strings.Contains(addrOrRange, "-") { result = addIPRangeToIgnoredNodeIPsList(addrOrRange, result) } else { result = addIPAddressToIgnoredNodeIPsList(addrOrRange, result) } } return result }