func()

in pkg/api/vlabs/validate.go [675:849]


func (a *Properties) validateAddons(isUpdate bool) error {
	if a.OrchestratorProfile.KubernetesConfig != nil && a.OrchestratorProfile.KubernetesConfig.Addons != nil {
		var isAvailabilitySets bool
		var kubeDNSEnabled bool
		var corednsEnabled bool

		for _, agentPool := range a.AgentPoolProfiles {
			if agentPool.IsAvailabilitySets() {
				isAvailabilitySets = true
			}
		}
		for _, addon := range a.OrchestratorProfile.KubernetesConfig.Addons {
			if addon.Data != "" {
				if len(addon.Config) > 0 || len(addon.Containers) > 0 {
					return errors.New("Config and containers should be empty when addon.Data is specified")
				}
				if _, err := base64.StdEncoding.DecodeString(addon.Data); err != nil {
					return errors.Errorf("Addon %s's data should be base64 encoded", addon.Name)
				}
			}

			if addon.Mode != "" {
				if addon.Mode != AddonModeEnsureExists && addon.Mode != AddonModeReconcile {
					return errors.Errorf("addon %s has a mode configuration '%s', must be either %s or %s", addon.Name, addon.Mode, AddonModeEnsureExists, AddonModeReconcile)
				}
			}

			// Validation for addons if they are enabled
			if to.Bool(addon.Enabled) {
				switch addon.Name {
				case "cluster-autoscaler":
					if isAvailabilitySets {
						return errors.Errorf("cluster-autoscaler addon can only be used with VirtualMachineScaleSets. Please specify \"availabilityProfile\": \"%s\"", VirtualMachineScaleSets)
					}
					for _, pool := range addon.Pools {
						if pool.Name == "" {
							return errors.Errorf("cluster-autoscaler addon pools configuration must have a 'name' property that correlates with a pool name in the agentPoolProfiles array")
						}
						if a.GetAgentPoolByName(pool.Name) == nil {
							return errors.Errorf("cluster-autoscaler addon pool 'name' %s does not match any agentPoolProfiles nodepool name", pool.Name)
						}
						if pool.Config != nil {
							var min, max int
							var err error
							if pool.Config["min-nodes"] != "" {
								min, err = strconv.Atoi(pool.Config["min-nodes"])
								if err != nil {
									return errors.Errorf("cluster-autoscaler addon pool 'name' %s has invalid 'min-nodes' config, must be a string int, got %s", pool.Name, pool.Config["min-nodes"])
								}
							}
							if pool.Config["max-nodes"] != "" {
								max, err = strconv.Atoi(pool.Config["max-nodes"])
								if err != nil {
									return errors.Errorf("cluster-autoscaler addon pool 'name' %s has invalid 'max-nodes' config, must be a string int, got %s", pool.Name, pool.Config["max-nodes"])
								}
							}
							if min > max {
								return errors.Errorf("cluster-autoscaler addon pool 'name' %s has invalid config, 'max-nodes' %d must be greater than or equal to 'min-nodes' %d", pool.Name, max, min)
							}
						}
					}
				case "aad":
					if !a.HasAADAdminGroupID() {
						return errors.New("aad addon can't be enabled without a valid aadProfile w/ adminGroupID")
					}
				case "appgw-ingress":
					if (a.ServicePrincipalProfile == nil || len(a.ServicePrincipalProfile.ObjectID) == 0) &&
						!to.Bool(a.OrchestratorProfile.KubernetesConfig.UseManagedIdentity) {
						return errors.New("appgw-ingress add-ons requires 'objectID' to be specified or UseManagedIdentity to be true")
					}

					if a.OrchestratorProfile.KubernetesConfig.NetworkPlugin != "azure" {
						return errors.New("appgw-ingress add-ons can only be used with Network Plugin as 'azure'")
					}

					if len(addon.Config["appgw-subnet"]) == 0 {
						return errors.New("appgw-ingress add-ons requires 'appgw-subnet' in the Config. It is used to provision the subnet for Application Gateway in the vnet")
					}
				case "cloud-node-manager":
					if !to.Bool(a.OrchestratorProfile.KubernetesConfig.UseCloudControllerManager) {
						return errors.Errorf("%s add-on requires useCloudControllerManager to be true", addon.Name)
					}
					if !a.ShouldEnableAzureCloudAddon(addon.Name) {
						minVersion := "1.16.0"
						if a.HasWindows() {
							minVersion = "1.18.0"
						}
						return errors.Errorf("%s add-on can only be used Kubernetes %s or above", addon.Name, minVersion)
					}
				case common.CiliumAddonName:
					if !common.IsKubernetesVersionGe(a.OrchestratorProfile.OrchestratorVersion, "1.16.0") {
						if a.OrchestratorProfile.KubernetesConfig.NetworkPolicy != NetworkPolicyCilium {
							return errors.Errorf("%s addon may only be enabled if the networkPolicy=%s", common.CiliumAddonName, NetworkPolicyCilium)
						}
					} else {
						return errors.Errorf("%s addon is not supported on Kubernetes v1.16.0 or greater", common.CiliumAddonName)
					}
				case common.AntreaAddonName:
					if a.OrchestratorProfile.KubernetesConfig.NetworkPolicy != NetworkPolicyAntrea {
						return errors.Errorf("%s addon may only be enabled if the networkPolicy=%s", common.AntreaAddonName, NetworkPolicyAntrea)
					}
				case common.FlannelAddonName:
					if isUpdate {
						if a.OrchestratorProfile.KubernetesConfig.NetworkPolicy != "" {
							return errors.Errorf("%s addon does not support NetworkPolicy, replace %s with \"\"", common.FlannelAddonName, a.OrchestratorProfile.KubernetesConfig.NetworkPolicy)
						}
						networkPlugin := a.OrchestratorProfile.KubernetesConfig.NetworkPlugin
						if networkPlugin != "" {
							if networkPlugin != NetworkPluginFlannel {
								return errors.Errorf("%s addon is not supported with networkPlugin=%s, please use networkPlugin=%s", common.FlannelAddonName, networkPlugin, NetworkPluginFlannel)
							}
						}
						if a.OrchestratorProfile.KubernetesConfig.ContainerRuntime != Containerd {
							return errors.Errorf("%s addon is only supported with containerRuntime=%s", common.FlannelAddonName, Containerd)
						}
					} else {
						return errors.Errorf("%s addon is deprecated for new clusters", common.FlannelAddonName)
					}
				case common.KubeDNSAddonName:
					kubeDNSEnabled = true
				case common.CoreDNSAddonName:
					corednsEnabled = true
				case common.SecretsStoreCSIDriverAddonName:
					if !common.IsKubernetesVersionGe(a.OrchestratorProfile.OrchestratorVersion, "1.16.0") {
						return errors.Errorf("%s add-on can only be used in 1.16+", addon.Name)
					}
				case common.PodSecurityPolicyAddonName:
					if common.ShouldDisablePodSecurityPolicyAddon(a.OrchestratorProfile.OrchestratorVersion) {
						log.Warn("The PodSecurityPolicy admission was removed in Kubernetes v1.25+. " +
							"The pod security standards will be enforced by the built-in PodSecurity admission controller instead. " +
							"See https://github.com/Azure/aks-engine-azurestack/blob/master/docs/topics/pod-security.md")
					}
				case common.AzureArcOnboardingAddonName:
					if err := addon.validateArcAddonConfig(); err != nil {
						return err
					}
				case common.ReschedulerAddonName:
					if isUpdate {
						log.Warnf("The rescheduler addon has been deprecated and disabled, it will be removed during this update")
					}
					return errors.Errorf("The rescheduler addon has been deprecated and disabled, please remove it from your cluster configuration before creating a new cluster")
				case common.ContainerMonitoringAddonName:
					if isUpdate {
						log.Warnf("The container monitoring addon has been deprecated and disabled, it will be removed during this update")
					}
					return errors.Errorf("The container monitoring addon has been deprecated and disabled, please remove it from your cluster configuration before creating a new cluster")
				case common.DashboardAddonName:
					log.Warnf("The kube-dashboard addon is deprecated, we recommend you install the dashboard yourself, see https://github.com/kubernetes/dashboard")
				case common.AzureCNINetworkMonitorAddonName:
					if isUpdate {
						log.Warnf("The Azure CNI networkmonitor addon has been deprecated, it will be marked as disabled")
					}
				}
			} else {
				// Validation for addons if they are disabled
				switch addon.Name {
				case "cloud-node-manager":
					if a.ShouldEnableAzureCloudAddon(addon.Name) && !a.IsAzureStackCloud() {
						minVersion := "1.16.0"
						if a.HasWindows() {
							minVersion = "1.18.0"
						}
						return errors.Errorf("%s add-on is required when useCloudControllerManager is true in Kubernetes %s or above", addon.Name, minVersion)
					}
				case common.AzureCloudProviderAddonName:
					return errors.Errorf("%s add-on is required, it cannot be disabled", addon.Name)
				}
			}
		}
		if kubeDNSEnabled && corednsEnabled {
			return errors.New("Both kube-dns and coredns addons are enabled, only one of these may be enabled on a cluster")
		}
	}
	return nil
}