pkg/api/components.go (291 lines of code) (raw):
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
package api
import (
"github.com/Azure/aks-engine-azurestack/pkg/api/common"
"github.com/Azure/aks-engine-azurestack/pkg/helpers/to"
)
func (cs *ContainerService) setComponentsConfig(isUpgrade bool) {
if cs == nil || cs.Properties == nil || cs.Properties.OrchestratorProfile == nil || cs.Properties.OrchestratorProfile.KubernetesConfig == nil {
return
}
kubernetesConfig := cs.Properties.OrchestratorProfile.KubernetesConfig
defaultSchedulerComponentConfig := KubernetesComponent{
Name: common.SchedulerComponentName,
Enabled: to.BoolPtr(true),
Containers: []KubernetesContainerSpec{
{
Name: common.SchedulerComponentName,
Image: getComponentDefaultContainerImage(common.SchedulerComponentName, cs),
},
},
Config: map[string]string{
"command": getSchedulerDefaultCommandString(cs),
},
}
defaultControllerManagerComponentConfig := KubernetesComponent{
Name: common.ControllerManagerComponentName,
Enabled: to.BoolPtr(true),
Containers: []KubernetesContainerSpec{
{
Name: common.ControllerManagerComponentName,
Image: getComponentDefaultContainerImage(common.ControllerManagerComponentName, cs),
},
},
Config: map[string]string{
"command": getControllerManagerDefaultCommandString(cs),
},
}
defaultCloudControllerManagerComponentConfig := KubernetesComponent{
Name: common.CloudControllerManagerComponentName,
Enabled: to.BoolPtr(to.Bool(kubernetesConfig.UseCloudControllerManager)),
Containers: []KubernetesContainerSpec{
{
Name: common.CloudControllerManagerComponentName,
Image: getComponentDefaultContainerImage(common.CloudControllerManagerComponentName, cs),
},
},
Config: map[string]string{
"command": "\"cloud-controller-manager\"",
},
}
defaultAPIServerComponentConfig := KubernetesComponent{
Name: common.APIServerComponentName,
Enabled: to.BoolPtr(true),
Containers: []KubernetesContainerSpec{
{
Name: common.APIServerComponentName,
Image: getComponentDefaultContainerImage(common.APIServerComponentName, cs),
},
},
Config: map[string]string{
"command": getAPIServerDefaultCommandString(cs),
},
}
defaultAddonManagerComponentConfig := KubernetesComponent{
Name: common.AddonManagerComponentName,
Enabled: to.BoolPtr(true),
Containers: []KubernetesContainerSpec{
{
Name: common.AddonManagerComponentName,
Image: getComponentDefaultContainerImage(common.AddonManagerComponentName, cs),
},
},
}
defaultAzureKMSProviderComponentConfig := KubernetesComponent{
Name: common.AzureKMSProviderComponentName,
Enabled: to.BoolPtr(to.Bool(kubernetesConfig.EnableEncryptionWithExternalKms)),
Containers: []KubernetesContainerSpec{
{
Name: common.AzureKMSProviderComponentName,
Image: getComponentDefaultContainerImage(common.AzureKMSProviderComponentName, cs),
},
},
Config: map[string]string{
"command": "\"k8s-azure-kms\"",
},
}
defaultComponents := []KubernetesComponent{
defaultSchedulerComponentConfig,
defaultControllerManagerComponentConfig,
defaultCloudControllerManagerComponentConfig,
defaultAPIServerComponentConfig,
defaultAddonManagerComponentConfig,
defaultAzureKMSProviderComponentConfig,
}
// Add default component specification, if no user-provided spec exists
if kubernetesConfig.Components == nil {
kubernetesConfig.Components = defaultComponents
} else {
for _, component := range defaultComponents {
kubernetesConfig.Components = appendComponentIfNotPresent(kubernetesConfig.Components, component)
}
}
// Honor custom{component}Image fields
useHyperkube := !common.IsKubernetesVersionGe(cs.Properties.OrchestratorProfile.OrchestratorVersion, "1.17.0")
for _, component := range defaultComponents {
if i := GetComponentsIndexByName(kubernetesConfig.Components, component.Name); i > -1 {
var customComponentImage string
switch component.Name {
case common.APIServerComponentName:
if useHyperkube {
customComponentImage = kubernetesConfig.CustomHyperkubeImage
} else {
customComponentImage = kubernetesConfig.CustomKubeAPIServerImage
}
case common.ControllerManagerComponentName:
if useHyperkube {
customComponentImage = kubernetesConfig.CustomHyperkubeImage
} else {
customComponentImage = kubernetesConfig.CustomKubeControllerManagerImage
}
case common.CloudControllerManagerComponentName:
customComponentImage = kubernetesConfig.CustomCcmImage
case common.SchedulerComponentName:
if useHyperkube {
customComponentImage = kubernetesConfig.CustomHyperkubeImage
} else {
customComponentImage = kubernetesConfig.CustomKubeSchedulerImage
}
}
if customComponentImage != "" {
// Since there is only one container for all Kubernetes components,
// it is safe to access index 0 of the component's containers
kubernetesConfig.Components[i].Containers[0].Image = customComponentImage
}
}
}
// Ensure cloud-controller-manager is enabled on appropriate upgrades for Azure Stack cloud
if isUpgrade &&
cs.Properties.IsAzureStackCloud() &&
to.Bool(cs.Properties.OrchestratorProfile.KubernetesConfig.UseCloudControllerManager) {
// Force enabling cloud-controller-manager
if i := GetComponentsIndexByName(kubernetesConfig.Components, common.CloudControllerManagerComponentName); i > -1 {
kubernetesConfig.Components[i] = defaultCloudControllerManagerComponentConfig
}
}
for _, component := range defaultComponents {
synthesizeComponentsConfig(kubernetesConfig.Components, component, isUpgrade)
}
}
func appendComponentIfNotPresent(components []KubernetesComponent, component KubernetesComponent) []KubernetesComponent {
if component.Name != "" {
i := GetComponentsIndexByName(components, component.Name)
if i < 0 {
return append(components, component)
}
}
return components
}
func GetComponentsIndexByName(components []KubernetesComponent, name string) int {
for i := range components {
if components[i].Name == name {
return i
}
}
return -1
}
// assignDefaultComponentVals will assign default values to component from defaults, for each property in component that has a zero value
func assignDefaultComponentVals(component, defaultComponent KubernetesComponent, isUpgrade bool) KubernetesComponent {
if component.Name == "" {
component.Name = defaultComponent.Name
}
if component.Enabled == nil {
component.Enabled = defaultComponent.Enabled
}
if !to.Bool(component.Enabled) {
return KubernetesComponent{
Name: component.Name,
Enabled: component.Enabled,
}
}
if component.Data != "" {
return KubernetesComponent{
Name: component.Name,
Enabled: component.Enabled,
Data: component.Data,
}
}
for i := range defaultComponent.Containers {
c := component.GetContainersIndexByName(defaultComponent.Containers[i].Name)
if c < 0 {
component.Containers = append(component.Containers, defaultComponent.Containers[i])
} else {
if component.Containers[c].Image == "" || isUpgrade {
component.Containers[c].Image = defaultComponent.Containers[i].Image
}
if component.Containers[c].CPURequests == "" {
component.Containers[c].CPURequests = defaultComponent.Containers[i].CPURequests
}
if component.Containers[c].MemoryRequests == "" {
component.Containers[c].MemoryRequests = defaultComponent.Containers[i].MemoryRequests
}
if component.Containers[c].CPULimits == "" {
component.Containers[c].CPULimits = defaultComponent.Containers[i].CPULimits
}
if component.Containers[c].MemoryLimits == "" {
component.Containers[c].MemoryLimits = defaultComponent.Containers[i].MemoryLimits
}
}
}
if component.Config == nil {
component.Config = make(map[string]string)
}
for key, val := range defaultComponent.Config {
if key == "command" && isUpgrade {
component.Config[key] = val
}
if v, ok := component.Config[key]; !ok || v == "" {
component.Config[key] = val
}
}
return component
}
func synthesizeComponentsConfig(components []KubernetesComponent, defaultComponent KubernetesComponent, isUpgrade bool) {
i := GetComponentsIndexByName(components, defaultComponent.Name)
if i >= 0 {
components[i] = assignDefaultComponentVals(components[i], defaultComponent, isUpgrade)
}
}
func getAPIServerDefaultCommandString(cs *ContainerService) string {
if common.IsKubernetesVersionGe(cs.Properties.OrchestratorProfile.OrchestratorVersion, "1.17.0") {
return "\"kube-apiserver\""
}
return "\"/hyperkube\", \"kube-apiserver\""
}
func getControllerManagerDefaultCommandString(cs *ContainerService) string {
if common.IsKubernetesVersionGe(cs.Properties.OrchestratorProfile.OrchestratorVersion, "1.17.0") {
return "\"kube-controller-manager\""
}
return "\"/hyperkube\", \"kube-controller-manager\""
}
func getSchedulerDefaultCommandString(cs *ContainerService) string {
if common.IsKubernetesVersionGe(cs.Properties.OrchestratorProfile.OrchestratorVersion, "1.17.0") {
return "\"kube-scheduler\""
}
return "\"/hyperkube\", \"kube-scheduler\""
}
func getComponentDefaultContainerImage(component string, cs *ContainerService) string {
if cs == nil || cs.Properties == nil || cs.Properties.OrchestratorProfile == nil || cs.Properties.OrchestratorProfile.KubernetesConfig == nil {
return ""
}
kubernetesConfig := cs.Properties.OrchestratorProfile.KubernetesConfig
cloudSpecConfig := cs.GetCloudSpecConfig()
specConfig := cloudSpecConfig.KubernetesSpecConfig
kubernetesImageBase := specConfig.MCRKubernetesImageBase
if kubernetesConfig.KubernetesImageBase != "" {
kubernetesImageBase = kubernetesConfig.KubernetesImageBase
}
k8sComponents := GetK8sComponentsByVersionMap(kubernetesConfig)[cs.Properties.OrchestratorProfile.OrchestratorVersion]
hyperkubeImageBase := kubernetesImageBase
hyperkubeImage := hyperkubeImageBase + k8sComponents[common.Hyperkube]
// For Azure Stack Hub clusters, no custom hyperkubeImage with "-azs" will be used for Kubernetes 1.21+
if cs.Properties.IsAzureStackCloud() && !common.IsKubernetesVersionGe(cs.Properties.OrchestratorProfile.OrchestratorVersion, "1.21.0") {
hyperkubeImage = hyperkubeImage + common.AzureStackSuffix
}
controllerManagerBase := kubernetesImageBase
if common.IsKubernetesVersionGe(cs.Properties.OrchestratorProfile.OrchestratorVersion, "1.16.0") {
controllerManagerBase = kubernetesConfig.MCRKubernetesImageBase
}
switch component {
case common.APIServerComponentName:
if common.IsKubernetesVersionGe(cs.Properties.OrchestratorProfile.OrchestratorVersion, "1.17.0") {
return kubernetesImageBase + k8sComponents[common.APIServerComponentName] + componentImageSuffix(*cs)
}
return hyperkubeImage
case common.ControllerManagerComponentName:
if common.IsKubernetesVersionGe(cs.Properties.OrchestratorProfile.OrchestratorVersion, "1.17.0") {
return kubernetesImageBase + k8sComponents[common.ControllerManagerComponentName] + componentImageSuffix(*cs)
}
return hyperkubeImage
case common.CloudControllerManagerComponentName:
return controllerManagerBase + k8sComponents[common.CloudControllerManagerComponentName] + componentImageSuffix(*cs)
case common.SchedulerComponentName:
if common.IsKubernetesVersionGe(cs.Properties.OrchestratorProfile.OrchestratorVersion, "1.17.0") {
return kubernetesImageBase + k8sComponents[common.SchedulerComponentName] + componentImageSuffix(*cs)
}
return hyperkubeImage
case common.AddonManagerComponentName:
return kubernetesImageBase + k8sComponents[common.AddonManagerComponentName]
case common.AzureKMSProviderComponentName:
return kubernetesImageBase + k8sComponents[common.AzureKMSProviderComponentName]
default:
return ""
}
}
// componentImageSuffix returns '-azs' if target cloud is Azure Stack. Otherwise, it returns empty string.
func componentImageSuffix(cs ContainerService) string {
if cs.Properties.IsAzureStackCloud() && !common.IsKubernetesVersionGe(cs.Properties.OrchestratorProfile.OrchestratorVersion, "1.21.0") {
return common.AzureStackSuffix
}
return ""
}