From 9d85116568f64111fd96de0593283a1149b683f4 Mon Sep 17 00:00:00 2001 From: galal-hussein Date: Fri, 1 Mar 2019 20:09:45 +0200 Subject: [PATCH] Modify kubernetes version check to allow upgrade --- cluster/cluster.go | 2 +- cluster/defaults.go | 10 +-- cluster/validation.go | 169 +++++++++++++++++++++++++++++++++++++++++- cmd/config.go | 19 ++--- util/util.go | 44 ----------- 5 files changed, 179 insertions(+), 65 deletions(-) diff --git a/cluster/cluster.go b/cluster/cluster.go index 5bc243ee..b4bf14cc 100644 --- a/cluster/cluster.go +++ b/cluster/cluster.go @@ -184,7 +184,7 @@ func InitClusterObject(ctx context.Context, rkeConfig *v3.RancherKubernetesEngin return nil, fmt.Errorf("Failed to classify hosts from config file: %v", err) } // validate cluster configuration - if err := c.ValidateCluster(); err != nil { + if err := c.ValidateCluster(ctx); err != nil { return nil, fmt.Errorf("Failed to validate cluster: %v", err) } return c, nil diff --git a/cluster/defaults.go b/cluster/defaults.go index 7090e670..58a5fe6c 100644 --- a/cluster/defaults.go +++ b/cluster/defaults.go @@ -11,7 +11,6 @@ import ( "github.com/rancher/rke/log" "github.com/rancher/rke/services" "github.com/rancher/rke/templates" - "github.com/rancher/rke/util" "github.com/rancher/types/apis/management.cattle.io/v3" ) @@ -215,14 +214,11 @@ func (c *Cluster) setClusterServicesDefaults() { func (c *Cluster) setClusterImageDefaults() error { var privRegURL string - // Version Check - err := util.ValidateVersion(c.Version) - if err != nil { - return err + imageDefaults, ok := v3.AllK8sVersions[c.Version] + if !ok { + return nil } - imageDefaults := v3.AllK8sVersions[c.Version] - for _, privReg := range c.PrivateRegistries { if privReg.IsDefault { privRegURL = privReg.URL diff --git a/cluster/validation.go b/cluster/validation.go index d6a1743c..09d2da5e 100644 --- a/cluster/validation.go +++ b/cluster/validation.go @@ -1,14 +1,24 @@ package cluster import ( + "context" "fmt" "strings" + "github.com/rancher/rke/log" "github.com/rancher/rke/services" + "github.com/rancher/rke/util" + "github.com/rancher/types/apis/management.cattle.io/v3" "k8s.io/apimachinery/pkg/util/validation" ) -func (c *Cluster) ValidateCluster() error { +func (c *Cluster) ValidateCluster(ctx context.Context) error { + // validate kubernetes version + // Version Check + if err := validateVersion(ctx, c); err != nil { + return err + } + // validate duplicate nodes if err := validateDuplicateNodes(c); err != nil { return err @@ -183,3 +193,160 @@ func validateDuplicateNodes(c *Cluster) error { } return nil } + +func validateVersion(ctx context.Context, c *Cluster) error { + _, err := util.StrToSemVer(c.Version) + if err != nil { + return fmt.Errorf("%s is not valid semver", c.Version) + } + _, ok := v3.AllK8sVersions[c.Version] + if !ok { + if err := validateSystemImages(c); err != nil { + return fmt.Errorf("%s is an unsupported Kubernetes version and system images are not populated: %v", c.Version, err) + } + return nil + } + + if _, ok := v3.K8sBadVersions[c.Version]; ok { + log.Warnf(ctx, "%s version exists but its recommended to install this version - see 'rke config --system-images --all' for versions supported with this release", c.Version) + return nil + } + + return nil +} + +func validateSystemImages(c *Cluster) error { + if err := validateKubernetesImages(c); err != nil { + return err + } + if err := validateNetworkImages(c); err != nil { + return err + } + if err := validateDNSImages(c); err != nil { + return err + } + if err := validateMetricsImages(c); err != nil { + return err + } + if err := validateIngressImages(c); err != nil { + return err + } + return nil +} + +func validateKubernetesImages(c *Cluster) error { + if len(c.SystemImages.Etcd) == 0 { + return fmt.Errorf("etcd image is not populated") + } + if len(c.SystemImages.Kubernetes) == 0 { + return fmt.Errorf("kubernetes image is not populated") + } + if len(c.SystemImages.PodInfraContainer) == 0 { + return fmt.Errorf("pod infrastructure container image is not populated") + } + if len(c.SystemImages.Alpine) == 0 { + return fmt.Errorf("alpine image is not populated") + } + if len(c.SystemImages.NginxProxy) == 0 { + return fmt.Errorf("nginx proxy image is not populated") + } + if len(c.SystemImages.CertDownloader) == 0 { + return fmt.Errorf("certificate downloader image is not populated") + } + if len(c.SystemImages.KubernetesServicesSidecar) == 0 { + return fmt.Errorf("kubernetes sidecar image is not populated") + } + return nil +} + +func validateNetworkImages(c *Cluster) error { + // check network provider images + if c.Network.Plugin == FlannelNetworkPlugin { + if len(c.SystemImages.Flannel) == 0 { + return fmt.Errorf("flannel image is not populated") + } + if len(c.SystemImages.FlannelCNI) == 0 { + return fmt.Errorf("flannel cni image is not populated") + } + } else if c.Network.Plugin == CanalNetworkPlugin { + if len(c.SystemImages.CanalNode) == 0 { + return fmt.Errorf("canal image is not populated") + } + if len(c.SystemImages.CanalCNI) == 0 { + return fmt.Errorf("canal cni image is not populated") + } + if len(c.SystemImages.CanalFlannel) == 0 { + return fmt.Errorf("flannel image is not populated") + } + } else if c.Network.Plugin == CalicoNetworkPlugin { + if len(c.SystemImages.CalicoCNI) == 0 { + return fmt.Errorf("calico cni image is not populated") + } + if len(c.SystemImages.CalicoCtl) == 0 { + return fmt.Errorf("calico ctl image is not populated") + } + if len(c.SystemImages.CalicoNode) == 0 { + return fmt.Errorf("calico image is not populated") + } + if len(c.SystemImages.CalicoControllers) == 0 { + return fmt.Errorf("calico controllers image is not populated") + } + } else if c.Network.Plugin == WeaveNetworkPlugin { + if len(c.SystemImages.WeaveCNI) == 0 { + return fmt.Errorf("weave cni image is not populated") + } + if len(c.SystemImages.WeaveNode) == 0 { + return fmt.Errorf("weave image is not populated") + } + } + return nil +} + +func validateDNSImages(c *Cluster) error { + // check dns provider images + if c.DNS.Provider == "kube-dns" { + if len(c.SystemImages.KubeDNS) == 0 { + return fmt.Errorf("kubedns image is not populated") + } + if len(c.SystemImages.DNSmasq) == 0 { + return fmt.Errorf("dnsmasq image is not populated") + } + if len(c.SystemImages.KubeDNSSidecar) == 0 { + return fmt.Errorf("kubedns sidecar image is not populated") + } + if len(c.SystemImages.KubeDNSAutoscaler) == 0 { + return fmt.Errorf("kubedns autoscaler image is not populated") + } + } else if c.DNS.Provider == "coredns" { + if len(c.SystemImages.CoreDNS) == 0 { + return fmt.Errorf("coredns image is not populated") + } + if len(c.SystemImages.CoreDNSAutoscaler) == 0 { + return fmt.Errorf("coredns autoscaler image is not populated") + } + } + return nil +} + +func validateMetricsImages(c *Cluster) error { + // checl metrics server image + if c.Monitoring.Provider != "none" { + if len(c.SystemImages.MetricsServer) == 0 { + return fmt.Errorf("metrics server images is not populated") + } + } + return nil +} + +func validateIngressImages(c *Cluster) error { + // check ingress images + if c.Ingress.Provider != "none" { + if len(c.SystemImages.Ingress) == 0 { + return fmt.Errorf("ingress image is not populated") + } + if len(c.SystemImages.IngressBackend) == 0 { + return fmt.Errorf("ingress backend image is not populated") + } + } + return nil +} diff --git a/cmd/config.go b/cmd/config.go index 1d95f8fc..c52d4b3b 100644 --- a/cmd/config.go +++ b/cmd/config.go @@ -12,7 +12,6 @@ import ( "github.com/rancher/rke/cluster" "github.com/rancher/rke/pki" "github.com/rancher/rke/services" - "github.com/rancher/rke/util" "github.com/rancher/types/apis/management.cattle.io/v3" "github.com/sirupsen/logrus" "github.com/urfave/cli" @@ -404,21 +403,14 @@ func getAddonManifests(reader *bufio.Reader) ([]string, error) { func generateSystemImagesList(version string, all bool) error { allVersions := []string{} currentVersionImages := make(map[string]v3.RKESystemImages) - for version := range v3.AllK8sVersions { - err := util.ValidateVersion(version) - if err != nil { - continue + for _, version := range v3.K8sVersionsCurrent { + if _, ok := v3.K8sBadVersions[version]; !ok { + allVersions = append(allVersions, version) + currentVersionImages[version] = v3.AllK8sVersions[version] } - allVersions = append(allVersions, version) - currentVersionImages[version] = v3.AllK8sVersions[version] } if all { for version, rkeSystemImages := range currentVersionImages { - err := util.ValidateVersion(version) - if err != nil { - continue - } - logrus.Infof("Generating images list for version [%s]:", version) uniqueImages := getUniqueSystemImageList(rkeSystemImages) for _, image := range uniqueImages { @@ -434,6 +426,9 @@ func generateSystemImagesList(version string, all bool) error { version = v3.DefaultK8s } rkeSystemImages := v3.AllK8sVersions[version] + if _, ok := v3.K8sBadVersions[version]; ok { + return fmt.Errorf("k8s version is not recommended, supported versions are: %v", allVersions) + } if rkeSystemImages == (v3.RKESystemImages{}) { return fmt.Errorf("k8s version is not supported, supported versions are: %v", allVersions) } diff --git a/util/util.go b/util/util.go index be54f6f1..fcd21e7e 100644 --- a/util/util.go +++ b/util/util.go @@ -68,50 +68,6 @@ func IsSymlink(file string) (bool, error) { return false, nil } -// ValidateVersion - Return error if version is not valid -// Is version major.minor >= oldest major.minor supported -// Is version in the AllK8sVersions list -// Is version not in the "bad" list -func ValidateVersion(version string) error { - // Create target version and current versions list - targetVersion, err := StrToSemVer(version) - if err != nil { - return fmt.Errorf("%s is not valid semver", version) - } - currentVersionsList := []*semver.Version{} - for _, ver := range v3.K8sVersionsCurrent { - v, err := StrToSemVer(ver) - if err != nil { - return fmt.Errorf("%s in Current Versions list is not valid semver", ver) - } - - currentVersionsList = append(currentVersionsList, v) - } - - // Make sure Target version is greater than or equal to oldest major.minor supported. - semver.Sort(currentVersionsList) - if targetVersion.Major < currentVersionsList[0].Major { - return fmt.Errorf("%s is an unsupported Kubernetes version - see 'rke config --system-images --all' for versions supported with this release", version) - } - if targetVersion.Major == currentVersionsList[0].Major { - if targetVersion.Minor < currentVersionsList[0].Minor { - return fmt.Errorf("%s is an unsupported Kubernetes version - see 'rke config --system-images --all' for versions supported with this release", version) - } - } - // Make sure Target version is in the AllK8sVersions list. - _, ok := v3.AllK8sVersions[version] - if !ok { - return fmt.Errorf("%s is an unsupported Kubernetes version - see 'rke config --system-images --all' for versions supported with this release", version) - } - // Make sure Target version is not "bad". - _, ok = v3.K8sBadVersions[version] - if ok { - return fmt.Errorf("%s is an unsupported Kubernetes version - see 'rke config --system-images --all' for versions supported with this release", version) - } - - return nil -} - func GetDefaultRKETools() string { return v3.AllK8sVersions[v3.DefaultK8s].Alpine }