package cluster import ( "context" "fmt" "github.com/rancher/rke/k8s" "github.com/rancher/rke/log" "github.com/rancher/rke/services" "github.com/rancher/types/apis/management.cattle.io/v3" ) const ( DefaultServiceClusterIPRange = "10.43.0.0/16" DefaultNodePortRange = "30000-32767" DefaultClusterCIDR = "10.42.0.0/16" DefaultClusterDNSService = "10.43.0.10" DefaultClusterDomain = "cluster.local" DefaultClusterName = "local" DefaultClusterSSHKeyPath = "~/.ssh/id_rsa" DefaultK8sVersion = v3.DefaultK8s DefaultSSHPort = "22" DefaultDockerSockPath = "/var/run/docker.sock" DefaultAuthStrategy = "x509" DefaultAuthorizationMode = "rbac" DefaultNetworkPlugin = "canal" DefaultNetworkCloudProvider = "none" DefaultIngressController = "nginx" DefaultEtcdBackupCreationPeriod = "12h" DefaultEtcdBackupRetentionPeriod = "3d" DefaultEtcdSnapshot = true DefaultMonitoringProvider = "metrics-server" DefaultEtcdHeartbeatIntervalName = "heartbeat-interval" DefaultEtcdHeartbeatIntervalValue = "500" DefaultEtcdElectionTimeoutName = "election-timeout" DefaultEtcdElectionTimeoutValue = "5000" ) func setDefaultIfEmptyMapValue(configMap map[string]string, key string, value string) { if _, ok := configMap[key]; !ok { configMap[key] = value } } func setDefaultIfEmpty(varName *string, defaultValue string) { if len(*varName) == 0 { *varName = defaultValue } } func (c *Cluster) setClusterDefaults(ctx context.Context) { if len(c.SSHKeyPath) == 0 { c.SSHKeyPath = DefaultClusterSSHKeyPath } // Default Path prefix if len(c.PrefixPath) == 0 { c.PrefixPath = "/" } // Set bastion/jump host defaults if len(c.BastionHost.Address) > 0 { if len(c.BastionHost.Port) == 0 { c.BastionHost.Port = DefaultSSHPort } if len(c.BastionHost.SSHKeyPath) == 0 { c.BastionHost.SSHKeyPath = c.SSHKeyPath } c.BastionHost.SSHAgentAuth = c.SSHAgentAuth } for i, host := range c.Nodes { if len(host.InternalAddress) == 0 { c.Nodes[i].InternalAddress = c.Nodes[i].Address } if len(host.HostnameOverride) == 0 { // This is a temporary modification c.Nodes[i].HostnameOverride = c.Nodes[i].Address } if len(host.SSHKeyPath) == 0 { c.Nodes[i].SSHKeyPath = c.SSHKeyPath } if len(host.Port) == 0 { c.Nodes[i].Port = DefaultSSHPort } // For now, you can set at the global level only. c.Nodes[i].SSHAgentAuth = c.SSHAgentAuth } if len(c.Authorization.Mode) == 0 { c.Authorization.Mode = DefaultAuthorizationMode } if c.Services.KubeAPI.PodSecurityPolicy && c.Authorization.Mode != services.RBACAuthorizationMode { log.Warnf(ctx, "PodSecurityPolicy can't be enabled with RBAC support disabled") c.Services.KubeAPI.PodSecurityPolicy = false } if len(c.Ingress.Provider) == 0 { c.Ingress.Provider = DefaultIngressController } if len(c.ClusterName) == 0 { c.ClusterName = DefaultClusterName } if len(c.Version) == 0 { c.Version = DefaultK8sVersion } if c.AddonJobTimeout == 0 { c.AddonJobTimeout = k8s.DefaultTimeout } if len(c.Monitoring.Provider) == 0 { c.Monitoring.Provider = DefaultMonitoringProvider } c.setClusterImageDefaults() c.setClusterServicesDefaults() c.setClusterNetworkDefaults() } func (c *Cluster) setClusterServicesDefaults() { // We don't accept per service images anymore. c.Services.KubeAPI.Image = c.SystemImages.Kubernetes c.Services.Scheduler.Image = c.SystemImages.Kubernetes c.Services.KubeController.Image = c.SystemImages.Kubernetes c.Services.Kubelet.Image = c.SystemImages.Kubernetes c.Services.Kubeproxy.Image = c.SystemImages.Kubernetes c.Services.Etcd.Image = c.SystemImages.Etcd // enable etcd snapshots by default if c.Services.Etcd.Snapshot == nil { defaultSnapshot := DefaultEtcdSnapshot c.Services.Etcd.Snapshot = &defaultSnapshot } serviceConfigDefaultsMap := map[*string]string{ &c.Services.KubeAPI.ServiceClusterIPRange: DefaultServiceClusterIPRange, &c.Services.KubeAPI.ServiceNodePortRange: DefaultNodePortRange, &c.Services.KubeController.ServiceClusterIPRange: DefaultServiceClusterIPRange, &c.Services.KubeController.ClusterCIDR: DefaultClusterCIDR, &c.Services.Kubelet.ClusterDNSServer: DefaultClusterDNSService, &c.Services.Kubelet.ClusterDomain: DefaultClusterDomain, &c.Services.Kubelet.InfraContainerImage: c.SystemImages.PodInfraContainer, &c.Authentication.Strategy: DefaultAuthStrategy, &c.Services.Etcd.Creation: DefaultEtcdBackupCreationPeriod, &c.Services.Etcd.Retention: DefaultEtcdBackupRetentionPeriod, } for k, v := range serviceConfigDefaultsMap { setDefaultIfEmpty(k, v) } // Add etcd timeouts if c.Services.Etcd.ExtraArgs == nil { c.Services.Etcd.ExtraArgs = make(map[string]string) } if _, ok := c.Services.Etcd.ExtraArgs[DefaultEtcdElectionTimeoutName]; !ok { c.Services.Etcd.ExtraArgs[DefaultEtcdElectionTimeoutName] = DefaultEtcdElectionTimeoutValue } if _, ok := c.Services.Etcd.ExtraArgs[DefaultEtcdHeartbeatIntervalName]; !ok { c.Services.Etcd.ExtraArgs[DefaultEtcdHeartbeatIntervalName] = DefaultEtcdHeartbeatIntervalValue } } func (c *Cluster) setClusterImageDefaults() { var privRegURL string imageDefaults, ok := v3.K8sVersionToRKESystemImages[c.Version] if !ok { imageDefaults = v3.K8sVersionToRKESystemImages[DefaultK8sVersion] } for _, privReg := range c.PrivateRegistries { if privReg.IsDefault { privRegURL = privReg.URL break } } systemImagesDefaultsMap := map[*string]string{ &c.SystemImages.Alpine: d(imageDefaults.Alpine, privRegURL), &c.SystemImages.NginxProxy: d(imageDefaults.NginxProxy, privRegURL), &c.SystemImages.CertDownloader: d(imageDefaults.CertDownloader, privRegURL), &c.SystemImages.KubeDNS: d(imageDefaults.KubeDNS, privRegURL), &c.SystemImages.KubeDNSSidecar: d(imageDefaults.KubeDNSSidecar, privRegURL), &c.SystemImages.DNSmasq: d(imageDefaults.DNSmasq, privRegURL), &c.SystemImages.KubeDNSAutoscaler: d(imageDefaults.KubeDNSAutoscaler, privRegURL), &c.SystemImages.KubernetesServicesSidecar: d(imageDefaults.KubernetesServicesSidecar, privRegURL), &c.SystemImages.Etcd: d(imageDefaults.Etcd, privRegURL), &c.SystemImages.Kubernetes: d(imageDefaults.Kubernetes, privRegURL), &c.SystemImages.PodInfraContainer: d(imageDefaults.PodInfraContainer, privRegURL), &c.SystemImages.Flannel: d(imageDefaults.Flannel, privRegURL), &c.SystemImages.FlannelCNI: d(imageDefaults.FlannelCNI, privRegURL), &c.SystemImages.CalicoNode: d(imageDefaults.CalicoNode, privRegURL), &c.SystemImages.CalicoCNI: d(imageDefaults.CalicoCNI, privRegURL), &c.SystemImages.CalicoCtl: d(imageDefaults.CalicoCtl, privRegURL), &c.SystemImages.CanalNode: d(imageDefaults.CanalNode, privRegURL), &c.SystemImages.CanalCNI: d(imageDefaults.CanalCNI, privRegURL), &c.SystemImages.CanalFlannel: d(imageDefaults.CanalFlannel, privRegURL), &c.SystemImages.WeaveNode: d(imageDefaults.WeaveNode, privRegURL), &c.SystemImages.WeaveCNI: d(imageDefaults.WeaveCNI, privRegURL), &c.SystemImages.Ingress: d(imageDefaults.Ingress, privRegURL), &c.SystemImages.IngressBackend: d(imageDefaults.IngressBackend, privRegURL), &c.SystemImages.MetricsServer: d(imageDefaults.MetricsServer, privRegURL), } for k, v := range systemImagesDefaultsMap { setDefaultIfEmpty(k, v) } } func (c *Cluster) setClusterNetworkDefaults() { setDefaultIfEmpty(&c.Network.Plugin, DefaultNetworkPlugin) if c.Network.Options == nil { // don't break if the user didn't define options c.Network.Options = make(map[string]string) } networkPluginConfigDefaultsMap := make(map[string]string) // This is still needed because RKE doesn't use c.Network.*NetworkProvider, that's a rancher type switch c.Network.Plugin { case CalicoNetworkPlugin: networkPluginConfigDefaultsMap = map[string]string{ CalicoCloudProvider: DefaultNetworkCloudProvider, } case FlannelNetworkPlugin: networkPluginConfigDefaultsMap = map[string]string{ FlannelBackendType: "vxlan", } case CanalNetworkPlugin: networkPluginConfigDefaultsMap = map[string]string{ CanalFlannelBackendType: "vxlan", } } if c.Network.CalicoNetworkProvider != nil { setDefaultIfEmpty(&c.Network.CalicoNetworkProvider.CloudProvider, DefaultNetworkCloudProvider) networkPluginConfigDefaultsMap[CalicoCloudProvider] = c.Network.CalicoNetworkProvider.CloudProvider } if c.Network.FlannelNetworkProvider != nil { networkPluginConfigDefaultsMap[FlannelIface] = c.Network.FlannelNetworkProvider.Iface } if c.Network.CanalNetworkProvider != nil { networkPluginConfigDefaultsMap[CanalIface] = c.Network.CanalNetworkProvider.Iface } for k, v := range networkPluginConfigDefaultsMap { setDefaultIfEmptyMapValue(c.Network.Options, k, v) } } func d(image, defaultRegistryURL string) string { if len(defaultRegistryURL) == 0 { return image } return fmt.Sprintf("%s/%s", defaultRegistryURL, image) }