pkg/providers/vsphere/template.go (549 lines of code) (raw):
package vsphere
import (
"fmt"
vspherev1 "sigs.k8s.io/cluster-api-provider-vsphere/apis/v1beta1"
bootstrapv1 "sigs.k8s.io/cluster-api/bootstrap/kubeadm/api/v1beta1"
"sigs.k8s.io/yaml"
anywherev1 "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/semver"
"github.com/aws/eks-anywhere/pkg/templater"
"github.com/aws/eks-anywhere/pkg/types"
)
func NewVsphereTemplateBuilder(
now types.NowFunc,
) *VsphereTemplateBuilder {
return &VsphereTemplateBuilder{
now: now,
}
}
type VsphereTemplateBuilder struct {
now types.NowFunc
}
func (vs *VsphereTemplateBuilder) GenerateCAPISpecControlPlane(
clusterSpec *cluster.Spec,
buildOptions ...providers.BuildMapOption,
) (content []byte, err error) {
var etcdMachineSpec anywherev1.VSphereMachineConfigSpec
if clusterSpec.Cluster.Spec.ExternalEtcdConfiguration != nil {
etcdMachineSpec = etcdMachineConfig(clusterSpec).Spec
}
values, err := buildTemplateMapCP(
clusterSpec,
clusterSpec.VSphereDatacenter.Spec,
controlPlaneMachineConfig(clusterSpec).Spec,
etcdMachineSpec,
)
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 (vs *VsphereTemplateBuilder) isCgroupDriverSystemd(clusterSpec *cluster.Spec, worker anywherev1.WorkerNodeGroupConfiguration) (bool, error) {
bundle := clusterSpec.WorkerNodeGroupVersionsBundle(worker)
k8sVersion, err := semver.New(bundle.KubeDistro.Kubernetes.Tag)
if err != nil {
return false, fmt.Errorf("parsing kubernetes version %v: %v", bundle.KubeDistro.Kubernetes.Tag, err)
}
if k8sVersion.Major == 1 && k8sVersion.Minor == 21 {
return true, nil
}
return false, nil
}
// CAPIWorkersSpecWithInitialNames generates a yaml spec with the CAPI objects representing the worker
// nodes for a particular eks-a cluster. It uses default initial names (ended in '-1') for the vsphere
// machine templates and kubeadm config templates.
func (vs *VsphereTemplateBuilder) CAPIWorkersSpecWithInitialNames(spec *cluster.Spec) (content []byte, err error) {
machineTemplateNames, kubeadmConfigTemplateNames := clusterapi.InitialTemplateNamesForWorkers(spec)
return vs.GenerateCAPISpecWorkers(spec, machineTemplateNames, kubeadmConfigTemplateNames)
}
func (vs *VsphereTemplateBuilder) 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 {
// pin cgroupDriver to systemd for k8s >= 1.21 when generating template in controller
// remove this check once the controller supports order upgrade.
// i.e. control plane, etcd upgrade before worker nodes.
cgroupDriverSystemd, err := vs.isCgroupDriverSystemd(clusterSpec, workerNodeGroupConfiguration)
if err != nil {
return nil, err
}
values, err := buildTemplateMapMD(
clusterSpec,
clusterSpec.VSphereDatacenter.Spec,
workerMachineConfig(clusterSpec, workerNodeGroupConfiguration).Spec,
workerNodeGroupConfiguration,
)
if err != nil {
return nil, err
}
values["workloadTemplateName"] = workloadTemplateNames[workerNodeGroupConfiguration.Name]
values["workloadkubeadmconfigTemplateName"] = kubeadmconfigTemplateNames[workerNodeGroupConfiguration.Name]
values["cgroupDriverSystemd"] = cgroupDriverSystemd
if len(workerNodeGroupConfiguration.FailureDomains) > 0 {
workerNodeGroupFailureDomain := workerNodeGroupConfiguration.FailureDomains[0]
values["failureDomain"] = FailureDomainTemplateName(clusterSpec, workerNodeGroupFailureDomain)
}
if workerNodeGroupConfiguration.UpgradeRolloutStrategy != nil {
values["upgradeRolloutStrategy"] = true
if workerNodeGroupConfiguration.UpgradeRolloutStrategy.Type == anywherev1.InPlaceStrategyType {
values["upgradeRolloutStrategyType"] = workerNodeGroupConfiguration.UpgradeRolloutStrategy.Type
} else {
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
}
// GenerateVsphereFailureDomainsSpec generates a yaml spec with the Vsphere failure domains objects.
// It uses the provided template names for the VsphereFailureDomain and VsphereDeploymentZone.
func (vs *VsphereTemplateBuilder) GenerateVsphereFailureDomainsSpec(spec *cluster.Spec, templateNames map[string]string) (content []byte, err error) {
failureDomainSpecs := make([][]byte, 0, len(spec.VSphereDatacenter.Spec.FailureDomains))
for _, failureDomain := range spec.VSphereDatacenter.Spec.FailureDomains {
if _, exists := templateNames[failureDomain.Name]; !exists {
continue
}
values := buildTemplateMapFailureDomain(spec, failureDomain)
values["failureDomainTemplateName"] = templateNames[failureDomain.Name]
bytes, err := templater.Execute(defaultFailureDomainConfig, values)
if err != nil {
return nil, err
}
failureDomainSpecs = append(failureDomainSpecs, bytes)
}
return templater.AppendYamlResources(failureDomainSpecs...), nil
}
func buildTemplateMapCP(
clusterSpec *cluster.Spec,
datacenterSpec anywherev1.VSphereDatacenterConfigSpec,
controlPlaneMachineSpec, etcdMachineSpec anywherev1.VSphereMachineConfigSpec,
) (map[string]interface{}, error) {
versionsBundle := clusterSpec.RootVersionsBundle()
format := "cloud-config"
etcdExtraArgs := clusterapi.SecureEtcdTlsCipherSuitesExtraArgs()
sharedExtraArgs := clusterapi.SecureTlsCipherSuitesExtraArgs()
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)).
Append(sharedExtraArgs)
clusterapi.SetPodIAMAuthExtraArgs(clusterSpec.Cluster.Spec.PodIAMConfig, apiServerExtraArgs)
controllerManagerExtraArgs := clusterapi.SecureTlsCipherSuitesExtraArgs().
Append(clusterapi.NodeCIDRMaskExtraArgs(&clusterSpec.Cluster.Spec.ClusterNetwork))
vuc := config.NewVsphereUserConfig()
firstControlPlaneMachinesUser := controlPlaneMachineSpec.Users[0]
controlPlaneSSHKey, err := common.StripSshAuthorizedKeyComment(firstControlPlaneMachinesUser.SshAuthorizedKeys[0])
if err != nil {
return nil, fmt.Errorf("formatting ssh key for vsphere control plane template: %v", err)
}
values := map[string]interface{}{
"clusterName": clusterSpec.Cluster.Name,
"controlPlaneEndpointIp": clusterSpec.Cluster.Spec.ControlPlaneConfiguration.Endpoint.Host,
"controlPlaneReplicas": clusterSpec.Cluster.Spec.ControlPlaneConfiguration.Count,
"apiServerCertSANs": clusterSpec.Cluster.Spec.ControlPlaneConfiguration.CertSANs,
"kubernetesRepository": versionsBundle.KubeDistro.Kubernetes.Repository,
"kubernetesVersion": versionsBundle.KubeDistro.Kubernetes.Tag,
"etcdRepository": versionsBundle.KubeDistro.Etcd.Repository,
"etcdImageTag": versionsBundle.KubeDistro.Etcd.Tag,
"corednsRepository": versionsBundle.KubeDistro.CoreDNS.Repository,
"corednsVersion": versionsBundle.KubeDistro.CoreDNS.Tag,
"nodeDriverRegistrarImage": versionsBundle.KubeDistro.NodeDriverRegistrar.VersionedImage(),
"livenessProbeImage": versionsBundle.KubeDistro.LivenessProbe.VersionedImage(),
"externalAttacherImage": versionsBundle.KubeDistro.ExternalAttacher.VersionedImage(),
"externalProvisionerImage": versionsBundle.KubeDistro.ExternalProvisioner.VersionedImage(),
"thumbprint": datacenterSpec.Thumbprint,
"vsphereDatacenter": datacenterSpec.Datacenter,
"controlPlaneVsphereDatastore": controlPlaneMachineSpec.Datastore,
"controlPlaneVsphereFolder": controlPlaneMachineSpec.Folder,
"managerImage": versionsBundle.VSphere.Manager.VersionedImage(),
"kubeVipImage": versionsBundle.VSphere.KubeVip.VersionedImage(),
"insecure": datacenterSpec.Insecure,
"vsphereNetwork": datacenterSpec.Network,
"controlPlaneVsphereResourcePool": controlPlaneMachineSpec.ResourcePool,
"vsphereServer": datacenterSpec.Server,
"controlPlaneVsphereStoragePolicyName": controlPlaneMachineSpec.StoragePolicyName,
"controlPlaneTemplate": controlPlaneMachineSpec.Template,
"etcdTemplate": etcdMachineSpec.Template,
"controlPlaneVMsMemoryMiB": controlPlaneMachineSpec.MemoryMiB,
"controlPlaneVMsNumCPUs": controlPlaneMachineSpec.NumCPUs,
"controlPlaneDiskGiB": controlPlaneMachineSpec.DiskGiB,
"controlPlaneTagIDs": controlPlaneMachineSpec.TagIDs,
"etcdTagIDs": etcdMachineSpec.TagIDs,
"controlPlaneSshUsername": firstControlPlaneMachinesUser.Name,
"vsphereControlPlaneSshAuthorizedKey": controlPlaneSSHKey,
"podCidrs": clusterSpec.Cluster.Spec.ClusterNetwork.Pods.CidrBlocks,
"serviceCidrs": clusterSpec.Cluster.Spec.ClusterNetwork.Services.CidrBlocks,
"etcdExtraArgs": etcdExtraArgs.ToPartialYaml(),
"etcdCipherSuites": crypto.SecureCipherSuitesString(),
"apiserverExtraArgs": apiServerExtraArgs.ToPartialYaml(),
"controllerManagerExtraArgs": controllerManagerExtraArgs.ToPartialYaml(),
"schedulerExtraArgs": sharedExtraArgs.ToPartialYaml(),
"format": format,
"externalEtcdVersion": versionsBundle.KubeDistro.EtcdVersion,
"etcdImage": versionsBundle.KubeDistro.EtcdImage.VersionedImage(),
"eksaSystemNamespace": constants.EksaSystemNamespace,
"cpiResourceSetName": cpiResourceSetName(clusterSpec),
"eksaVsphereUsername": vuc.EksaVsphereUsername,
"eksaVspherePassword": vuc.EksaVspherePassword,
"eksaCloudProviderUsername": vuc.EksaVsphereCPUsername,
"eksaCloudProviderPassword": vuc.EksaVsphereCPPassword,
"controlPlaneCloneMode": controlPlaneMachineSpec.CloneMode,
"etcdCloneMode": etcdMachineSpec.CloneMode,
}
auditPolicy, err := common.GetAuditPolicy(clusterSpec.Cluster.Spec.KubernetesVersion)
if err != nil {
return nil, err
}
values["auditPolicy"] = auditPolicy
if clusterSpec.Cluster.Spec.RegistryMirrorConfiguration != nil {
registryMirror := registrymirror.FromCluster(clusterSpec.Cluster)
values["registryMirrorMap"] = containerd.ToAPIEndpoints(registryMirror.NamespacedRegistryMap)
values["mirrorBase"] = registryMirror.BaseRegistry
values["insecureSkip"] = registryMirror.InsecureSkipVerify
values["publicMirror"] = containerd.ToAPIEndpoint(registryMirror.CoreEKSAMirror())
if len(registryMirror.CACertContent) > 0 {
values["registryCACert"] = registryMirror.CACertContent
}
if controlPlaneMachineSpec.OSFamily == anywherev1.Bottlerocket &&
len(registryMirror.NamespacedRegistryMap) == 1 &&
registryMirror.CoreEKSAMirror() != "" {
values["publicECRMirror"] = containerd.ToAPIEndpoint(registryMirror.CoreEKSAMirror())
}
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.ProxyConfiguration != nil {
values["proxyConfig"] = true
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,
datacenterSpec.Server,
clusterSpec.Cluster.Spec.ControlPlaneConfiguration.Endpoint.Host,
)
values["httpProxy"] = clusterSpec.Cluster.Spec.ProxyConfiguration.HttpProxy
values["httpsProxy"] = clusterSpec.Cluster.Spec.ProxyConfiguration.HttpsProxy
values["noProxy"] = noProxyList
}
if clusterSpec.Cluster.Spec.ExternalEtcdConfiguration != nil {
firstEtcdMachinesUser := etcdMachineSpec.Users[0]
etcdSSHKey, err := common.StripSshAuthorizedKeyComment(firstEtcdMachinesUser.SshAuthorizedKeys[0])
if err != nil {
return nil, fmt.Errorf("formatting ssh key for vsphere etcd template: %v", err)
}
values["externalEtcd"] = true
values["externalEtcdReplicas"] = clusterSpec.Cluster.Spec.ExternalEtcdConfiguration.Count
values["etcdVsphereDatastore"] = etcdMachineSpec.Datastore
values["etcdVsphereFolder"] = etcdMachineSpec.Folder
values["etcdDiskGiB"] = etcdMachineSpec.DiskGiB
values["etcdVMsMemoryMiB"] = etcdMachineSpec.MemoryMiB
values["etcdVMsNumCPUs"] = etcdMachineSpec.NumCPUs
values["etcdVsphereResourcePool"] = etcdMachineSpec.ResourcePool
values["etcdVsphereStoragePolicyName"] = etcdMachineSpec.StoragePolicyName
values["etcdSshUsername"] = firstEtcdMachinesUser.Name
values["vsphereEtcdSshAuthorizedKey"] = etcdSSHKey
if etcdMachineSpec.HostOSConfiguration != nil {
if etcdMachineSpec.HostOSConfiguration.NTPConfiguration != nil {
values["etcdNtpServers"] = etcdMachineSpec.HostOSConfiguration.NTPConfiguration.Servers
}
if etcdMachineSpec.HostOSConfiguration.CertBundles != nil {
values["etcdCertBundles"] = etcdMachineSpec.HostOSConfiguration.CertBundles
}
if etcdMachineSpec.HostOSConfiguration.BottlerocketConfiguration != nil {
if etcdMachineSpec.HostOSConfiguration.BottlerocketConfiguration.Kernel != nil &&
etcdMachineSpec.HostOSConfiguration.BottlerocketConfiguration.Kernel.SysctlSettings != nil {
values["etcdKernelSettings"] = etcdMachineSpec.HostOSConfiguration.BottlerocketConfiguration.Kernel.SysctlSettings
}
if etcdMachineSpec.HostOSConfiguration.BottlerocketConfiguration.Boot != nil &&
etcdMachineSpec.HostOSConfiguration.BottlerocketConfiguration.Boot.BootKernelParameters != nil {
values["etcdBootParameters"] = etcdMachineSpec.HostOSConfiguration.BottlerocketConfiguration.Boot.BootKernelParameters
}
}
}
etcdURL, _ := common.GetExternalEtcdReleaseURL(clusterSpec.Cluster.Spec.EksaVersion, versionsBundle)
if etcdURL != "" {
values["externalEtcdReleaseUrl"] = etcdURL
}
}
var bottlerocketKubernetesSettings *bootstrapv1.BottlerocketKubernetesSettings
if controlPlaneMachineSpec.OSFamily == anywherev1.Bottlerocket {
values["format"] = string(anywherev1.Bottlerocket)
values["pauseRepository"] = versionsBundle.KubeDistro.Pause.Image()
values["pauseVersion"] = versionsBundle.KubeDistro.Pause.Tag()
values["bottlerocketBootstrapRepository"] = versionsBundle.BottleRocketHostContainers.KubeadmBootstrap.Image()
values["bottlerocketBootstrapVersion"] = versionsBundle.BottleRocketHostContainers.KubeadmBootstrap.Tag()
if clusterSpec.Cluster.Spec.ControlPlaneConfiguration.KubeletConfiguration != nil {
br, err := common.ConvertToBottlerocketKubernetesSettings(clusterSpec.Cluster.Spec.ControlPlaneConfiguration.KubeletConfiguration)
if err != nil {
return nil, err
}
bottlerocketKubernetesSettings = br
}
}
if len(clusterSpec.Cluster.Spec.ControlPlaneConfiguration.Taints) > 0 {
values["controlPlaneTaints"] = clusterSpec.Cluster.Spec.ControlPlaneConfiguration.Taints
}
if clusterSpec.AWSIamConfig != nil {
values["awsIamAuth"] = true
}
if controlPlaneMachineSpec.HostOSConfiguration != nil {
if controlPlaneMachineSpec.HostOSConfiguration.NTPConfiguration != nil {
values["cpNtpServers"] = controlPlaneMachineSpec.HostOSConfiguration.NTPConfiguration.Servers
}
if controlPlaneMachineSpec.HostOSConfiguration.CertBundles != nil {
values["certBundles"] = controlPlaneMachineSpec.HostOSConfiguration.CertBundles
}
if bottlerocketKubernetesSettings == nil && controlPlaneMachineSpec.HostOSConfiguration.BottlerocketConfiguration != nil {
bottlerocketKubernetesSettings = controlPlaneMachineSpec.HostOSConfiguration.BottlerocketConfiguration.Kubernetes
}
}
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 bottlerocketKubernetesSettings != nil || controlPlaneMachineSpec.HostOSConfiguration != nil {
brSettings, err := common.GetCAPIBottlerocketSettingsConfig(controlPlaneMachineSpec.HostOSConfiguration, bottlerocketKubernetesSettings)
if err != nil {
return nil, err
}
if len(brSettings) != 0 {
values["bottlerocketSettings"] = brSettings
}
}
if clusterSpec.Cluster.Spec.ControlPlaneConfiguration.KubeletConfiguration != nil && controlPlaneMachineSpec.OSFamily != anywherev1.Bottlerocket {
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()
}
if clusterSpec.Cluster.Spec.ControlPlaneConfiguration.UpgradeRolloutStrategy != nil {
values["upgradeRolloutStrategy"] = true
if clusterSpec.Cluster.Spec.ControlPlaneConfiguration.UpgradeRolloutStrategy.Type == anywherev1.InPlaceStrategyType {
values["upgradeRolloutStrategyType"] = clusterSpec.Cluster.Spec.ControlPlaneConfiguration.UpgradeRolloutStrategy.Type
} else {
values["maxSurge"] = clusterSpec.Cluster.Spec.ControlPlaneConfiguration.UpgradeRolloutStrategy.RollingUpdate.MaxSurge
}
}
return values, nil
}
func buildTemplateMapMD(
clusterSpec *cluster.Spec,
datacenterSpec anywherev1.VSphereDatacenterConfigSpec,
workerNodeGroupMachineSpec anywherev1.VSphereMachineConfigSpec,
workerNodeGroupConfiguration anywherev1.WorkerNodeGroupConfiguration,
) (map[string]interface{}, error) {
bundle := clusterSpec.WorkerNodeGroupVersionsBundle(workerNodeGroupConfiguration)
if bundle == nil {
return nil, fmt.Errorf("could not find VersionsBundle")
}
format := "cloud-config"
firstUser := workerNodeGroupMachineSpec.Users[0]
sshKey, err := common.StripSshAuthorizedKeyComment(firstUser.SshAuthorizedKeys[0])
if err != nil {
return nil, fmt.Errorf("formatting ssh key for vsphere workers template: %v", err)
}
values := map[string]interface{}{
"clusterName": clusterSpec.Cluster.Name,
"kubernetesVersion": bundle.KubeDistro.Kubernetes.Tag,
"thumbprint": datacenterSpec.Thumbprint,
"vsphereDatacenter": datacenterSpec.Datacenter,
"workerVsphereDatastore": workerNodeGroupMachineSpec.Datastore,
"workerVsphereFolder": workerNodeGroupMachineSpec.Folder,
"vsphereNetwork": datacenterSpec.Network,
"workerVsphereResourcePool": workerNodeGroupMachineSpec.ResourcePool,
"vsphereServer": datacenterSpec.Server,
"workerVsphereStoragePolicyName": workerNodeGroupMachineSpec.StoragePolicyName,
"workerTemplate": workerNodeGroupMachineSpec.Template,
"workloadVMsMemoryMiB": workerNodeGroupMachineSpec.MemoryMiB,
"workloadVMsNumCPUs": workerNodeGroupMachineSpec.NumCPUs,
"workloadDiskGiB": workerNodeGroupMachineSpec.DiskGiB,
"workerTagIDs": workerNodeGroupMachineSpec.TagIDs,
"workerSshUsername": firstUser.Name,
"vsphereWorkerSshAuthorizedKey": sshKey,
"format": format,
"eksaSystemNamespace": constants.EksaSystemNamespace,
"workerReplicas": *workerNodeGroupConfiguration.Count,
"workerNodeGroupName": fmt.Sprintf("%s-%s", clusterSpec.Cluster.Name, workerNodeGroupConfiguration.Name),
"workerNodeGroupTaints": workerNodeGroupConfiguration.Taints,
"autoscalingConfig": workerNodeGroupConfiguration.AutoScalingConfiguration,
"workerCloneMode": workerNodeGroupMachineSpec.CloneMode,
}
if clusterSpec.Cluster.Spec.RegistryMirrorConfiguration != nil {
registryMirror := registrymirror.FromCluster(clusterSpec.Cluster)
values["registryMirrorMap"] = containerd.ToAPIEndpoints(registryMirror.NamespacedRegistryMap)
values["mirrorBase"] = registryMirror.BaseRegistry
values["insecureSkip"] = registryMirror.InsecureSkipVerify
values["publicMirror"] = containerd.ToAPIEndpoint(registryMirror.CoreEKSAMirror())
if len(registryMirror.CACertContent) > 0 {
values["registryCACert"] = registryMirror.CACertContent
}
if workerNodeGroupMachineSpec.OSFamily == anywherev1.Bottlerocket &&
len(registryMirror.NamespacedRegistryMap) == 1 &&
registryMirror.CoreEKSAMirror() != "" {
values["publicECRMirror"] = containerd.ToAPIEndpoint(registryMirror.CoreEKSAMirror())
}
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.ProxyConfiguration != nil {
values["proxyConfig"] = true
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,
datacenterSpec.Server,
clusterSpec.Cluster.Spec.ControlPlaneConfiguration.Endpoint.Host,
)
values["httpProxy"] = clusterSpec.Cluster.Spec.ProxyConfiguration.HttpProxy
values["httpsProxy"] = clusterSpec.Cluster.Spec.ProxyConfiguration.HttpsProxy
values["noProxy"] = noProxyList
}
var bottlerocketKubernetesSettings *bootstrapv1.BottlerocketKubernetesSettings
if workerNodeGroupMachineSpec.OSFamily == anywherev1.Bottlerocket {
values["format"] = string(anywherev1.Bottlerocket)
values["pauseRepository"] = bundle.KubeDistro.Pause.Image()
values["pauseVersion"] = bundle.KubeDistro.Pause.Tag()
values["bottlerocketBootstrapRepository"] = bundle.BottleRocketHostContainers.KubeadmBootstrap.Image()
values["bottlerocketBootstrapVersion"] = bundle.BottleRocketHostContainers.KubeadmBootstrap.Tag()
if workerNodeGroupConfiguration.KubeletConfiguration != nil {
br, err := common.ConvertToBottlerocketKubernetesSettings(workerNodeGroupConfiguration.KubeletConfiguration)
if err != nil {
return nil, err
}
bottlerocketKubernetesSettings = br
}
}
if workerNodeGroupMachineSpec.HostOSConfiguration != nil {
if workerNodeGroupMachineSpec.HostOSConfiguration.NTPConfiguration != nil {
values["ntpServers"] = workerNodeGroupMachineSpec.HostOSConfiguration.NTPConfiguration.Servers
}
if workerNodeGroupMachineSpec.HostOSConfiguration.CertBundles != nil {
values["certBundles"] = workerNodeGroupMachineSpec.HostOSConfiguration.CertBundles
}
if bottlerocketKubernetesSettings == nil && workerNodeGroupMachineSpec.HostOSConfiguration.BottlerocketConfiguration != nil {
bottlerocketKubernetesSettings = workerNodeGroupMachineSpec.HostOSConfiguration.BottlerocketConfiguration.Kubernetes
}
}
if bottlerocketKubernetesSettings != nil || workerNodeGroupMachineSpec.HostOSConfiguration != nil {
brSettings, err := common.GetCAPIBottlerocketSettingsConfig(workerNodeGroupMachineSpec.HostOSConfiguration, bottlerocketKubernetesSettings)
if err != nil {
return nil, err
}
values["bottlerocketSettings"] = brSettings
}
if workerNodeGroupConfiguration.KubeletConfiguration != nil && workerNodeGroupMachineSpec.OSFamily != anywherev1.Bottlerocket {
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 buildTemplateMapFailureDomain(
clusterSpec *cluster.Spec,
failureDomain anywherev1.FailureDomain,
) map[string]interface{} {
regionType, regionName := getFailureDomainRegionTypeAndName(clusterSpec.VSphereDatacenter.Spec)
zoneType, zoneName := getFailureDomainZoneTypeAndName(failureDomain)
values := map[string]interface{}{
"server": clusterSpec.VSphereDatacenter.Spec.Server,
"datacenter": clusterSpec.VSphereDatacenter.Spec.Datacenter,
"computeCluster": failureDomain.ComputeCluster,
"resourcePool": failureDomain.ResourcePool,
"datastore": failureDomain.Datastore,
"folder": failureDomain.Folder,
"network": failureDomain.Network,
"clusterName": clusterSpec.Cluster.Name,
"vsphereDataCenterConfigName": clusterSpec.VSphereDatacenter.Name,
"regionType": regionType,
"regionName": regionName,
"zoneType": zoneType,
"zoneName": zoneName,
}
return values
}
// Currently, we only support compute cluster topology in failure domain
// In future, when we add supports for other topologies, update this get region type and name based on topology type.
// For example, if topology type is host group, region will be one level above host group i.e ComputeCluster.
func getFailureDomainRegionTypeAndName(datacenterSpec anywherev1.VSphereDatacenterConfigSpec) (string, string) {
return string(vspherev1.DatacenterFailureDomain), datacenterSpec.Datacenter
}
// Currently, we only support compute cluster topology in failure domain
// In future, when we add supports for other topologies, update this get zone type and name based on topology type.
// For example, if topology type is host group, zone type = HostGroup and name = host group name.
func getFailureDomainZoneTypeAndName(failureDomain anywherev1.FailureDomain) (string, string) {
return string(vspherev1.ComputeClusterFailureDomain), failureDomain.ComputeCluster
}