pkg/agent/datamodel/versions.go (456 lines of code) (raw):

// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. package datamodel import ( "fmt" "sort" "strings" "github.com/blang/semver" "github.com/pkg/errors" ) // AllKubernetesSupportedVersions is a whitelist map of all supported Kubernetes version strings. // The bool value indicates if creating new clusters with this version is allowed. // //nolint:gochecknoglobals var AllKubernetesSupportedVersions = map[string]bool{ "1.6.6": false, "1.6.9": true, // need to keep 1.6.9 version support for v20160930. "1.6.11": false, "1.6.12": false, "1.6.13": false, "1.7.0": false, "1.7.1": false, "1.7.2": false, "1.7.4": false, "1.7.5": false, "1.7.7": false, "1.7.9": false, "1.7.10": false, "1.7.12": false, "1.7.13": false, "1.7.14": false, "1.7.15": false, "1.7.16": false, "1.8.0": false, "1.8.1": false, "1.8.2": false, "1.8.4": false, "1.8.6": false, "1.8.7": false, "1.8.8": false, "1.8.9": false, "1.8.10": false, "1.8.11": false, "1.8.12": false, "1.8.13": false, "1.8.14": false, "1.8.15": false, "1.9.0": false, "1.9.1": false, "1.9.2": false, "1.9.3": false, "1.9.4": false, "1.9.5": false, "1.9.6": false, "1.9.7": false, "1.9.8": false, "1.9.9": false, "1.9.10": false, "1.9.11": false, "1.10.0-beta.2": false, "1.10.0-beta.4": false, "1.10.0-rc.1": false, "1.10.0": false, "1.10.1": false, "1.10.2": false, "1.10.3": false, "1.10.4": false, "1.10.5": false, "1.10.6": false, "1.10.7": false, "1.10.8": false, "1.10.9": false, "1.10.12": false, "1.10.13": false, "1.11.0-alpha.1": false, "1.11.0-alpha.2": false, "1.11.0-beta.1": false, "1.11.0-beta.2": false, "1.11.0-rc.1": false, "1.11.0-rc.2": false, "1.11.0-rc.3": false, "1.11.0": false, "1.11.1": false, "1.11.2": false, "1.11.3": false, "1.11.4": false, "1.11.5": false, "1.11.6": false, "1.11.7": false, "1.11.8": false, "1.11.9": false, "1.11.10": false, "1.12.0-alpha.1": false, "1.12.0-beta.0": false, "1.12.0-beta.1": false, "1.12.0-rc.1": false, "1.12.0-rc.2": false, "1.12.0": false, "1.12.1": false, "1.12.2": false, "1.12.4": false, "1.12.5": false, "1.12.6": false, "1.12.7": false, "1.12.8": false, "1.12.9": false, // disabled because of https://github.com/Azure/aks-engine/issues/1421. "1.13.0-alpha.1": false, "1.13.0-alpha.2": false, "1.13.1": false, "1.13.2": false, "1.13.3": false, "1.13.4": false, "1.13.5": false, "1.13.6": false, // disabled because of https://github.com/kubernetes/kubernetes/issues/78308. "1.13.7": false, "1.13.8": false, "1.13.9": false, "1.13.10": false, "1.13.11": true, "1.13.12": true, // disabled because of https://github.com/Azure/aks-engine/issues/2312, enabled for aks with v1.13.12_f0.0.2 "1.14.0-alpha.1": false, "1.14.0-alpha.2": false, "1.14.0-beta.1": false, "1.14.0-beta.2": false, "1.14.0-rc.1": false, "1.14.0": false, "1.14.1": false, "1.14.2": false, // disabled because of https://github.com/kubernetes/kubernetes/issues/78308. "1.14.3": false, "1.14.4": false, "1.14.5": false, "1.14.6": false, "1.14.7": true, "1.14.8": true, // disabled because of https://github.com/Azure/aks-engine/issues/2312, enabled for aks with v1.14.8_f0.0.4 "1.14.10": false, // disabled because of https://github.com/Azure/aks-engine/issues/2312. "1.15.0-alpha.1": false, "1.15.0-alpha.2": false, "1.15.0-alpha.3": false, "1.15.0-beta.1": false, "1.15.0-beta.2": false, "1.15.0-rc.1": false, "1.15.0": false, "1.15.1": false, "1.15.2": false, "1.15.3": false, "1.15.4": false, "1.15.5": false, // disabled because of https://github.com/Azure/aks-engine/issues/2312. "1.15.7": true, // enabled for aks with v1.15.7_f0.0.2. "1.15.8": false, // disabled because of https://github.com/kubernetes/release/issues/1020. "1.15.9": true, "1.15.10": true, "1.15.11": true, "1.15.12": true, "1.16.0-alpha.1": false, "1.16.0-alpha.2": false, "1.16.0-alpha.3": false, "1.16.0-beta.1": false, "1.16.0-beta.2": false, "1.16.0-rc.1": false, "1.16.0": false, "1.16.1": false, "1.16.2": false, // disabled because of https://github.com/Azure/aks-engine/issues/2312. "1.16.4": false, "1.16.5": false, // disabled because of https://github.com/kubernetes/release/issues/1020. "1.16.6": true, "1.16.7": true, "1.16.8": false, "1.16.9": true, "1.16.10": true, "1.16.13": true, "1.16.15": true, "1.17.0-alpha.1": false, "1.17.0-alpha.2": false, "1.17.0-alpha.3": false, "1.17.0-beta.1": false, "1.17.0-beta.2": false, "1.17.0-rc.1": false, "1.17.0-rc.2": false, "1.17.0": false, "1.17.1": false, "1.17.2": true, "1.17.3": true, "1.17.4": true, "1.17.5": true, "1.17.6": false, "1.17.7": true, "1.17.9": true, "1.17.11": true, "1.18.0": false, "1.18.1": true, "1.18.2": true, "1.18.3": false, "1.18.4": true, "1.18.6": true, "1.19.0": true, } /* GetDefaultKubernetesVersion returns the default Kubernetes version, that is the latest patch of the default release. */ func GetDefaultKubernetesVersion(hasWindows bool) string { defaultRelease := KubernetesDefaultRelease if hasWindows { defaultRelease = KubernetesDefaultReleaseWindows } return GetLatestPatchVersion(defaultRelease, GetAllSupportedKubernetesVersions(false, hasWindows)) } /* GetSupportedKubernetesVersion verifies that a passed-in version string is supported, or returns a default version string if not. */ func GetSupportedKubernetesVersion(version string, hasWindows bool) string { k8sVersion := GetDefaultKubernetesVersion(hasWindows) allKubernetesWindowsSupportedVersions := getAllKubernetesWindowsSupportedVersionsMap() if hasWindows { if allKubernetesWindowsSupportedVersions[version] { k8sVersion = version } } else { if AllKubernetesSupportedVersions[version] { k8sVersion = version } } return k8sVersion } // GetAllSupportedKubernetesVersions returns a slice of all supported Kubernetes versions. func GetAllSupportedKubernetesVersions(isUpdate, hasWindows bool) []string { var versions []string allSupportedVersions := AllKubernetesSupportedVersions allKubernetesWindowsSupportedVersions := getAllKubernetesWindowsSupportedVersionsMap() if hasWindows { allSupportedVersions = allKubernetesWindowsSupportedVersions } for ver, supported := range allSupportedVersions { if isUpdate || supported { versions = append(versions, ver) } } sort.Slice(versions, func(i, j int) bool { return IsKubernetesVersionGe(versions[j], versions[i]) }) return versions } /* GetVersionsGt returns a list of versions greater than a semver string given a list of versions inclusive=true means that we test for equality as well preReleases=true means that we include pre-release versions in the list. */ func GetVersionsGt(versions []string, version string, inclusive, preReleases bool) []string { // Try to get latest version matching the release. var ret []string minVersion, _ := semver.Make(version) for _, v := range versions { sv, _ := semver.Make(v) if !preReleases && len(sv.Pre) != 0 { continue } if (inclusive && sv.GTE(minVersion)) || (!inclusive && sv.GT(minVersion)) { ret = append(ret, v) } } return ret } /* GetVersionsLt returns a list of versions less than than a semver string given a list of versions inclusive=true means that we test for equality as well preReleases=true means that we include pre-release versions in the list. */ func GetVersionsLt(versions []string, version string, inclusive, preReleases bool) []string { // Try to get latest version matching the release. var ret []string minVersion, _ := semver.Make(version) for _, v := range versions { sv, _ := semver.Make(v) if !preReleases && len(sv.Pre) != 0 { continue } if (inclusive && sv.LTE(minVersion)) || (!inclusive && sv.LT(minVersion)) { ret = append(ret, v) } } return ret } /* GetVersionsBetween returns a list of versions between a min and max inclusive=true means that we test for equality on both bounds preReleases=true means that we include pre-release versions in the list. */ func GetVersionsBetween(versions []string, versionMin, versionMax string, inclusive, preReleases bool) []string { var ret []string if minV, _ := semver.Make(versionMin); len(minV.Pre) != 0 { preReleases = true } greaterThan := GetVersionsGt(versions, versionMin, inclusive, preReleases) lessThan := GetVersionsLt(versions, versionMax, inclusive, preReleases) for _, lv := range lessThan { for _, gv := range greaterThan { if lv == gv { ret = append(ret, lv) } } } return ret } // GetMinVersion gets the lowest semver version. // preRelease=true means accept a pre-release version as a min value. func GetMinVersion(versions []string, preRelease bool) string { if len(versions) < 1 { return "" } semverVersions := getSortedSemverVersions(versions, preRelease) return semverVersions[0].String() } // GetMaxVersion gets the highest semver version. // preRelease=true means accept a pre-release version as a max value. func GetMaxVersion(versions []string, preRelease bool) string { if len(versions) < 1 { return "" } semverVersions := getSortedSemverVersions(versions, preRelease) return semverVersions[len(semverVersions)-1].String() } func getSortedSemverVersions(versions []string, preRelease bool) []semver.Version { var semverVersions []semver.Version for _, v := range versions { sv, _ := semver.Make(v) if len(sv.Pre) == 0 || preRelease { semverVersions = append(semverVersions, sv) } } semver.Sort(semverVersions) return semverVersions } func getAllKubernetesWindowsSupportedVersionsMap() map[string]bool { ret := make(map[string]bool) for k, v := range AllKubernetesSupportedVersions { ret[k] = v } for _, version := range []string{ "1.6.6", "1.6.9", "1.6.11", "1.6.12", "1.6.13", "1.7.0", "1.7.1", "1.8.13", "1.8.14", "1.8.15", "1.10.0-beta.2", "1.10.0-beta.4", "1.10.0-rc.1", "1.11.0-alpha.1", "1.11.0-alpha.2"} { delete(ret, version) } // 1.8.12 is the latest supported patch for Windows ret["1.8.12"] = true return ret } // GetSupportedVersions get supported version list for a certain orchestrator. func GetSupportedVersions(orchType string, isUpdate, hasWindows bool) ([]string, string) { if orchType == Kubernetes { return GetAllSupportedKubernetesVersions(isUpdate, hasWindows), GetDefaultKubernetesVersion(hasWindows) } return nil, "" } // GetValidPatchVersion gets the current valid patch version for the minor version of the passed in version. func GetValidPatchVersion(orchType, orchVer string, isUpdate, hasWindows bool) string { if orchVer == "" { return RationalizeReleaseAndVersion( orchType, "", "", isUpdate, hasWindows) } /* check if the current version is valid, this allows us to have multiple supported patch versions in the future if we need it. */ version := RationalizeReleaseAndVersion( orchType, "", orchVer, isUpdate, hasWindows) if version == "" { sv, err := semver.Make(orchVer) if err != nil { return "" } sr := fmt.Sprintf("%d.%d", sv.Major, sv.Minor) version = RationalizeReleaseAndVersion( orchType, sr, "", isUpdate, hasWindows) } return version } // RationalizeReleaseAndVersion return a version when it can be rationalized from the input, otherwise "". func RationalizeReleaseAndVersion(orchType, orchRel, orchVer string, isUpdate, hasWindows bool) string { /* ignore "v" prefix in orchestrator version and release: "v1.8.0" is equivalent to "1.8.0", "v1.9" is equivalent to "1.9". */ var version string orchVer = strings.TrimPrefix(orchVer, "v") orchRel = strings.TrimPrefix(orchRel, "v") supportedVersions, defaultVersion := GetSupportedVersions(orchType, isUpdate, hasWindows) if supportedVersions == nil { return "" } if orchRel == "" && orchVer == "" { return defaultVersion } if orchVer == "" { // Try to get latest version matching the release. version = GetLatestPatchVersion(orchRel, supportedVersions) return version } else if orchRel == "" { // Try to get version the same with orchVer. version = "" for _, ver := range supportedVersions { if ver == orchVer { version = ver break } } return version } // Try to get latest version matching the release. version = "" for _, ver := range supportedVersions { sv, _ := semver.Make(ver) sr := fmt.Sprintf("%d.%d", sv.Major, sv.Minor) if sr == orchRel && ver == orchVer { version = ver break } } return version } func IsValidMinVersion(orchType, orchRelease, orchVersion, minVersion string) (bool, error) { version := RationalizeReleaseAndVersion( orchType, orchRelease, orchVersion, false, false) if version == "" { return false, errors.Errorf("the following user supplied OrchestratorProfile configuration is not supported: "+ "OrchestratorType: %s, OrchestratorRelease: %s, OrchestratorVersion: %s. Please check supported Release or Version for this build"+ " of aks-engine", orchType, orchRelease, orchVersion) } sv, err := semver.Make(version) if err != nil { return false, errors.Errorf("could not validate version %s", version) } m, err := semver.Make(minVersion) if err != nil { return false, errors.New("could not validate version") } if sv.LT(m) { return false, nil } return true, nil } // IsKubernetesVersionGe returns true if actualVersion is greater than or equal to version. func IsKubernetesVersionGe(actualVersion, version string) bool { v1, _ := semver.Make(actualVersion) v2, _ := semver.Make(version) return v1.GE(v2) } /* GetLatestPatchVersion gets the most recent patch version from a list of semver versions given a major.minor string. */ func GetLatestPatchVersion(majorMinor string, versionsList []string) string { // Try to get latest version matching the release. var version string for _, ver := range versionsList { sv, err := semver.Make(ver) if err != nil { return "" } sr := fmt.Sprintf("%d.%d", sv.Major, sv.Minor) if sr == majorMinor { if version == "" { version = ver } else { current, _ := semver.Make(version) if sv.GT(current) { version = ver } } } } return version } // IsSupportedKubernetesVersion return true if the provided Kubernetes version is supported. func IsSupportedKubernetesVersion(version string, isUpdate, hasWindows bool) bool { for _, ver := range GetAllSupportedKubernetesVersions(isUpdate, hasWindows) { if ver == version { return true } } return false }