mirror of https://github.com/kubernetes/kops.git
				
				
				
			Merge pull request #1790 from justinsb/k8s_version_per_kops_version
Recommend a k8s version based on each kops version
This commit is contained in:
		
						commit
						a909f38b9c
					
				| 
						 | 
				
			
			@ -20,8 +20,10 @@ spec:
 | 
			
		|||
    requiredVersion: 1.4.2
 | 
			
		||||
  kopsVersions:
 | 
			
		||||
  - range: ">=1.5.0-alpha1"
 | 
			
		||||
    recommendedVersion: 1.5.0-beta1
 | 
			
		||||
    #requiredVersion: 1.5.0-beta1
 | 
			
		||||
    recommendedVersion: 1.5.0-beta2
 | 
			
		||||
    #requiredVersion: 1.5.0-beta2
 | 
			
		||||
    kubernetesVersion: 1.5.2
 | 
			
		||||
  - range: "<1.5.0"
 | 
			
		||||
    recommendedVersion: 1.4.4
 | 
			
		||||
    #requiredVersion: 1.4.4
 | 
			
		||||
    kubernetesVersion: 1.4.8
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -96,12 +96,12 @@ func (c *ChannelVersion) Replaces(existing *ChannelVersion) bool {
 | 
			
		|||
		if c.Version == nil {
 | 
			
		||||
			return false
 | 
			
		||||
		}
 | 
			
		||||
		cVersion, err := semver.Parse(*c.Version)
 | 
			
		||||
		cVersion, err := semver.ParseTolerant(*c.Version)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			glog.Warningf("error parsing version %q; will ignore this version", *c.Version)
 | 
			
		||||
			return false
 | 
			
		||||
		}
 | 
			
		||||
		existingVersion, err := semver.Parse(*existing.Version)
 | 
			
		||||
		existingVersion, err := semver.ParseTolerant(*existing.Version)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			glog.Warningf("error parsing existing version %q", *existing.Version)
 | 
			
		||||
			return true
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -20,6 +20,7 @@ import (
 | 
			
		|||
	"fmt"
 | 
			
		||||
	"os"
 | 
			
		||||
 | 
			
		||||
	"github.com/blang/semver"
 | 
			
		||||
	"github.com/golang/glog"
 | 
			
		||||
	"github.com/spf13/cobra"
 | 
			
		||||
	api "k8s.io/kops/pkg/apis/kops"
 | 
			
		||||
| 
						 | 
				
			
			@ -129,26 +130,40 @@ func (c *UpgradeClusterCmd) Run(args []string) error {
 | 
			
		|||
		channelClusterSpec = &api.ClusterSpec{}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	//latestKubernetesVersion, err := api.FindLatestKubernetesVersion()
 | 
			
		||||
	//if err != nil {
 | 
			
		||||
	//	return err
 | 
			
		||||
	//}
 | 
			
		||||
	var currentKubernetesVersion *semver.Version
 | 
			
		||||
	{
 | 
			
		||||
		sv, err := util.ParseKubernetesVersion(cluster.Spec.KubernetesVersion)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			glog.Warningf("error parsing KubernetesVersion %q", cluster.Spec.KubernetesVersion)
 | 
			
		||||
		} else {
 | 
			
		||||
			currentKubernetesVersion = sv
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// So we can propose an image for the upgraded k8s version
 | 
			
		||||
	upgradedKubernetesVersion := cluster.Spec.KubernetesVersion
 | 
			
		||||
	proposedKubernetesVersion := api.RecommendedKubernetesVersion(channel)
 | 
			
		||||
 | 
			
		||||
	if channelClusterSpec.KubernetesVersion != "" && cluster.Spec.KubernetesVersion != channelClusterSpec.KubernetesVersion {
 | 
			
		||||
	// We won't propose a downgrade
 | 
			
		||||
	// TODO: What if a kubernetes version is bad?
 | 
			
		||||
	if currentKubernetesVersion != nil && proposedKubernetesVersion != nil && currentKubernetesVersion.GT(*proposedKubernetesVersion) {
 | 
			
		||||
		glog.Warningf("cluster version %q is greater than recommended version %q", *currentKubernetesVersion, *proposedKubernetesVersion)
 | 
			
		||||
		proposedKubernetesVersion = currentKubernetesVersion
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if proposedKubernetesVersion != nil && currentKubernetesVersion != nil && currentKubernetesVersion.NE(*proposedKubernetesVersion) {
 | 
			
		||||
		actions = append(actions, &upgradeAction{
 | 
			
		||||
			Item:     "Cluster",
 | 
			
		||||
			Property: "KubernetesVersion",
 | 
			
		||||
			Old:      cluster.Spec.KubernetesVersion,
 | 
			
		||||
			New:      channelClusterSpec.KubernetesVersion,
 | 
			
		||||
			New:      proposedKubernetesVersion.String(),
 | 
			
		||||
			apply: func() {
 | 
			
		||||
				cluster.Spec.KubernetesVersion = channelClusterSpec.KubernetesVersion
 | 
			
		||||
				cluster.Spec.KubernetesVersion = proposedKubernetesVersion.String()
 | 
			
		||||
			},
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
		upgradedKubernetesVersion = channelClusterSpec.KubernetesVersion
 | 
			
		||||
	// For further calculations, default to the current kubernetes version
 | 
			
		||||
	if proposedKubernetesVersion == nil {
 | 
			
		||||
		proposedKubernetesVersion = currentKubernetesVersion
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Prompt to upgrade addins?
 | 
			
		||||
| 
						 | 
				
			
			@ -179,13 +194,8 @@ func (c *UpgradeClusterCmd) Run(args []string) error {
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	// Prompt to upgrade image
 | 
			
		||||
	{
 | 
			
		||||
		sv, err := util.ParseKubernetesVersion(upgradedKubernetesVersion)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			// We could continue, but something has gone wrong here...
 | 
			
		||||
			return fmt.Errorf("unable to parse kubernetes version %q", upgradedKubernetesVersion)
 | 
			
		||||
		}
 | 
			
		||||
		image := channel.FindImage(cloud.ProviderID(), *sv)
 | 
			
		||||
	if proposedKubernetesVersion != nil {
 | 
			
		||||
		image := channel.FindImage(cloud.ProviderID(), *proposedKubernetesVersion)
 | 
			
		||||
 | 
			
		||||
		if image == nil {
 | 
			
		||||
			glog.Warningf("No matching images specified in channel; cannot prompt for upgrade")
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -272,7 +272,7 @@ func (b *DockerBuilder) Build(c *fi.ModelBuilderContext) error {
 | 
			
		|||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	dockerSemver, err := semver.Parse(dockerVersion)
 | 
			
		||||
	dockerSemver, err := semver.ParseTolerant(dockerVersion)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return fmt.Errorf("error parsing docker version %q as semver: %v", dockerVersion, err)
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -20,6 +20,8 @@ import (
 | 
			
		|||
	"fmt"
 | 
			
		||||
	"github.com/blang/semver"
 | 
			
		||||
	"github.com/golang/glog"
 | 
			
		||||
	"k8s.io/kops"
 | 
			
		||||
	"k8s.io/kops/pkg/apis/kops/util"
 | 
			
		||||
	"k8s.io/kops/upup/pkg/fi"
 | 
			
		||||
	"k8s.io/kops/util/pkg/vfs"
 | 
			
		||||
	"k8s.io/kubernetes/pkg/api"
 | 
			
		||||
| 
						 | 
				
			
			@ -44,13 +46,22 @@ type ChannelSpec struct {
 | 
			
		|||
	Cluster *ClusterSpec `json:"cluster,omitempty"`
 | 
			
		||||
 | 
			
		||||
	// KopsVersions allows us to recommend/require kops versions
 | 
			
		||||
	KopsVersions []VersionSpec `json:"kopsVersions,omitempty"`
 | 
			
		||||
	KopsVersions []KopsVersionSpec `json:"kopsVersions,omitempty"`
 | 
			
		||||
 | 
			
		||||
	// KubernetesVersions allows us to recommend/requires kubernetes versions
 | 
			
		||||
	KubernetesVersions []VersionSpec `json:"kubernetesVersions,omitempty"`
 | 
			
		||||
	KubernetesVersions []KubernetesVersionSpec `json:"kubernetesVersions,omitempty"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type VersionSpec struct {
 | 
			
		||||
type KopsVersionSpec struct {
 | 
			
		||||
	Range string `json:"range,omitempty"`
 | 
			
		||||
 | 
			
		||||
	RecommendedVersion string `json:"recommendedVersion,omitempty"`
 | 
			
		||||
	RequiredVersion    string `json:"requiredVersion,omitempty"`
 | 
			
		||||
 | 
			
		||||
	KubernetesVersion string `json:"kubernetesVersion,omitempty"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type KubernetesVersionSpec struct {
 | 
			
		||||
	Range string `json:"range,omitempty"`
 | 
			
		||||
 | 
			
		||||
	RecommendedVersion string `json:"recommendedVersion,omitempty"`
 | 
			
		||||
| 
						 | 
				
			
			@ -110,33 +121,53 @@ func ParseChannel(channelBytes []byte) (*Channel, error) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
// FindRecommendedUpgrade returns a string with a new version, if the current version is out of date
 | 
			
		||||
func FindRecommendedUpgrade(v *VersionSpec, version semver.Version) (string, error) {
 | 
			
		||||
func (v *KubernetesVersionSpec) FindRecommendedUpgrade(version semver.Version) (*semver.Version, error) {
 | 
			
		||||
	if v.RecommendedVersion == "" {
 | 
			
		||||
		glog.V(2).Infof("VersionRecommendationSpec does not specify RecommendedVersion")
 | 
			
		||||
		return "", nil
 | 
			
		||||
		return nil, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	recommendedVersion, err := semver.Parse(v.RecommendedVersion)
 | 
			
		||||
	recommendedVersion, err := util.ParseKubernetesVersion(v.RecommendedVersion)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "", fmt.Errorf("error parsing RecommendedVersion %q from channel", v.RecommendedVersion)
 | 
			
		||||
		return nil, fmt.Errorf("error parsing RecommendedVersion %q from channel", v.RecommendedVersion)
 | 
			
		||||
	}
 | 
			
		||||
	if recommendedVersion.GT(version) {
 | 
			
		||||
		glog.V(2).Infof("RecommendedVersion=%q, Have=%q.  Recommending upgrade", recommendedVersion, version)
 | 
			
		||||
		return v.RecommendedVersion, nil
 | 
			
		||||
		return recommendedVersion, nil
 | 
			
		||||
	} else {
 | 
			
		||||
		glog.V(4).Infof("RecommendedVersion=%q, Have=%q.  No upgrade needed.", recommendedVersion, version)
 | 
			
		||||
	}
 | 
			
		||||
	return "", nil
 | 
			
		||||
	return nil, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// FindRecommendedUpgrade returns a string with a new version, if the current version is out of date
 | 
			
		||||
func (v *KopsVersionSpec) FindRecommendedUpgrade(version semver.Version) (*semver.Version, error) {
 | 
			
		||||
	if v.RecommendedVersion == "" {
 | 
			
		||||
		glog.V(2).Infof("VersionRecommendationSpec does not specify RecommendedVersion")
 | 
			
		||||
		return nil, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	recommendedVersion, err := semver.ParseTolerant(v.RecommendedVersion)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, fmt.Errorf("error parsing RecommendedVersion %q from channel", v.RecommendedVersion)
 | 
			
		||||
	}
 | 
			
		||||
	if recommendedVersion.GT(version) {
 | 
			
		||||
		glog.V(2).Infof("RecommendedVersion=%q, Have=%q.  Recommending upgrade", recommendedVersion, version)
 | 
			
		||||
		return &recommendedVersion, nil
 | 
			
		||||
	} else {
 | 
			
		||||
		glog.V(4).Infof("RecommendedVersion=%q, Have=%q.  No upgrade needed.", recommendedVersion, version)
 | 
			
		||||
	}
 | 
			
		||||
	return nil, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IsUpgradeRequired returns true if the current version is not acceptable
 | 
			
		||||
func IsUpgradeRequired(v *VersionSpec, version semver.Version) (bool, error) {
 | 
			
		||||
func (v *KubernetesVersionSpec) IsUpgradeRequired(version semver.Version) (bool, error) {
 | 
			
		||||
	if v.RequiredVersion == "" {
 | 
			
		||||
		glog.V(2).Infof("VersionRecommendationSpec does not specify RequiredVersion")
 | 
			
		||||
		return false, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	requiredVersion, err := semver.Parse(v.RequiredVersion)
 | 
			
		||||
	requiredVersion, err := util.ParseKubernetesVersion(v.RequiredVersion)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return false, fmt.Errorf("error parsing RequiredVersion %q from channel", v.RequiredVersion)
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -149,8 +180,49 @@ func IsUpgradeRequired(v *VersionSpec, version semver.Version) (bool, error) {
 | 
			
		|||
	return false, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// FindVersionInfo returns a VersionSpec for the current version
 | 
			
		||||
func FindVersionInfo(versions []VersionSpec, version semver.Version) *VersionSpec {
 | 
			
		||||
// IsUpgradeRequired returns true if the current version is not acceptable
 | 
			
		||||
func (v *KopsVersionSpec) IsUpgradeRequired(version semver.Version) (bool, error) {
 | 
			
		||||
	if v.RequiredVersion == "" {
 | 
			
		||||
		glog.V(2).Infof("VersionRecommendationSpec does not specify RequiredVersion")
 | 
			
		||||
		return false, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	requiredVersion, err := semver.ParseTolerant(v.RequiredVersion)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return false, fmt.Errorf("error parsing RequiredVersion %q from channel", v.RequiredVersion)
 | 
			
		||||
	}
 | 
			
		||||
	if requiredVersion.GT(version) {
 | 
			
		||||
		glog.V(2).Infof("RequiredVersion=%q, Have=%q.  Requiring upgrade", requiredVersion, version)
 | 
			
		||||
		return true, nil
 | 
			
		||||
	} else {
 | 
			
		||||
		glog.V(4).Infof("RequiredVersion=%q, Have=%q.  No upgrade needed.", requiredVersion, version)
 | 
			
		||||
	}
 | 
			
		||||
	return false, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// FindKubernetesVersionSpec returns a KubernetesVersionSpec for the current version
 | 
			
		||||
func FindKubernetesVersionSpec(versions []KubernetesVersionSpec, version semver.Version) *KubernetesVersionSpec {
 | 
			
		||||
	for i := range versions {
 | 
			
		||||
		v := &versions[i]
 | 
			
		||||
		if v.Range != "" {
 | 
			
		||||
			versionRange, err := semver.ParseRange(v.Range)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				glog.Warningf("unable to parse range in channel version spec: %q", v.Range)
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
			if !versionRange(version) {
 | 
			
		||||
				glog.V(8).Infof("version range %q does not apply to version %q; skipping", v.Range, version)
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		return v
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// FindKopsVersionSpec returns a KopsVersionSpec for the current version
 | 
			
		||||
func FindKopsVersionSpec(versions []KopsVersionSpec, version semver.Version) *KopsVersionSpec {
 | 
			
		||||
	for i := range versions {
 | 
			
		||||
		v := &versions[i]
 | 
			
		||||
		if v.Range != "" {
 | 
			
		||||
| 
						 | 
				
			
			@ -203,3 +275,34 @@ func (c *Channel) FindImage(provider fi.CloudProviderID, kubernetesVersion semve
 | 
			
		|||
	}
 | 
			
		||||
	return matches[0]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func RecommendedKubernetesVersion(c *Channel) *semver.Version {
 | 
			
		||||
	kopsVersionString := kops.Version
 | 
			
		||||
	kopsVersion, err := semver.ParseTolerant(kopsVersionString)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		glog.Warningf("unable to parse kops version %q", kopsVersionString)
 | 
			
		||||
	} else {
 | 
			
		||||
		kopsVersionSpec := FindKopsVersionSpec(c.Spec.KopsVersions, kopsVersion)
 | 
			
		||||
		if kopsVersionSpec != nil {
 | 
			
		||||
			if kopsVersionSpec.KubernetesVersion != "" {
 | 
			
		||||
				sv, err := util.ParseKubernetesVersion(kopsVersionSpec.KubernetesVersion)
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					glog.Warningf("unable to parse kubernetes version %q", kopsVersionSpec.KubernetesVersion)
 | 
			
		||||
				} else {
 | 
			
		||||
					return sv
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if c.Spec.Cluster != nil {
 | 
			
		||||
		sv, err := util.ParseKubernetesVersion(c.Spec.Cluster.KubernetesVersion)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			glog.Warningf("unable to parse kubernetes version %q", c.Spec.Cluster.KubernetesVersion)
 | 
			
		||||
		} else {
 | 
			
		||||
			return sv
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -80,13 +80,13 @@ func TestKopsUpgrades(t *testing.T) {
 | 
			
		|||
	for _, g := range grid {
 | 
			
		||||
		kopsVersion := semver.MustParse(g.KopsVersion)
 | 
			
		||||
 | 
			
		||||
		versionInfo := kops.FindVersionInfo(channel.Spec.KopsVersions, kopsVersion)
 | 
			
		||||
		versionInfo := kops.FindKopsVersionSpec(channel.Spec.KopsVersions, kopsVersion)
 | 
			
		||||
		if versionInfo == nil {
 | 
			
		||||
			t.Errorf("unable to find version information for kops version %q in channel", kopsVersion)
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		actual, err := kops.FindRecommendedUpgrade(versionInfo, kopsVersion)
 | 
			
		||||
		actual, err := versionInfo.FindRecommendedUpgrade(kopsVersion)
 | 
			
		||||
		if g.ExpectedError {
 | 
			
		||||
			if err == nil {
 | 
			
		||||
				t.Errorf("expected error from FindRecommendedUpgrade(%q)", g.KopsVersion)
 | 
			
		||||
| 
						 | 
				
			
			@ -98,12 +98,12 @@ func TestKopsUpgrades(t *testing.T) {
 | 
			
		|||
				continue
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		if actual != g.ExpectedUpgrade {
 | 
			
		||||
		if semverString(actual) != g.ExpectedUpgrade {
 | 
			
		||||
			t.Errorf("unexpected result from IsUpgradeRequired(%q): expected=%q, actual=%q", g.KopsVersion, g.ExpectedUpgrade, actual)
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		required, err := kops.IsUpgradeRequired(versionInfo, kopsVersion)
 | 
			
		||||
		required, err := versionInfo.IsUpgradeRequired(kopsVersion)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			t.Errorf("unexpected error from IsUpgradeRequired(%q)", g.KopsVersion, err)
 | 
			
		||||
			continue
 | 
			
		||||
| 
						 | 
				
			
			@ -174,13 +174,13 @@ func TestKubernetesUpgrades(t *testing.T) {
 | 
			
		|||
	for _, g := range grid {
 | 
			
		||||
		kubernetesVersion := semver.MustParse(g.KubernetesVersion)
 | 
			
		||||
 | 
			
		||||
		versionInfo := kops.FindVersionInfo(channel.Spec.KubernetesVersions, kubernetesVersion)
 | 
			
		||||
		versionInfo := kops.FindKubernetesVersionSpec(channel.Spec.KubernetesVersions, kubernetesVersion)
 | 
			
		||||
		if versionInfo == nil {
 | 
			
		||||
			t.Errorf("unable to find version information for kubernetes version %q in channel", kubernetesVersion)
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		actual, err := kops.FindRecommendedUpgrade(versionInfo, kubernetesVersion)
 | 
			
		||||
		actual, err := versionInfo.FindRecommendedUpgrade(kubernetesVersion)
 | 
			
		||||
		if g.ExpectedError {
 | 
			
		||||
			if err == nil {
 | 
			
		||||
				t.Errorf("expected error from FindRecommendedUpgrade(%q)", g.KubernetesVersion)
 | 
			
		||||
| 
						 | 
				
			
			@ -192,12 +192,12 @@ func TestKubernetesUpgrades(t *testing.T) {
 | 
			
		|||
				continue
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		if actual != g.ExpectedUpgrade {
 | 
			
		||||
		if semverString(actual) != g.ExpectedUpgrade {
 | 
			
		||||
			t.Errorf("unexpected result from IsUpgradeRequired(%q): expected=%q, actual=%q", g.KubernetesVersion, g.ExpectedUpgrade, actual)
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		required, err := kops.IsUpgradeRequired(versionInfo, kubernetesVersion)
 | 
			
		||||
		required, err := versionInfo.IsUpgradeRequired(kubernetesVersion)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			t.Errorf("unexpected error from IsUpgradeRequired(%q)", g.KubernetesVersion, err)
 | 
			
		||||
			continue
 | 
			
		||||
| 
						 | 
				
			
			@ -249,3 +249,10 @@ func TestFindImage(t *testing.T) {
 | 
			
		|||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func semverString(sv *semver.Version) string {
 | 
			
		||||
	if sv == nil {
 | 
			
		||||
		return ""
 | 
			
		||||
	}
 | 
			
		||||
	return sv.String()
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -623,38 +623,38 @@ func (c *ApplyClusterCmd) upgradeSpecs() error {
 | 
			
		|||
 | 
			
		||||
// validateKopsVersion ensures that kops meet the version requirements / recommendations in the channel
 | 
			
		||||
func (c *ApplyClusterCmd) validateKopsVersion() error {
 | 
			
		||||
	kopsVersion, err := semver.Parse(kops.Version)
 | 
			
		||||
	kopsVersion, err := semver.ParseTolerant(kops.Version)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		glog.Warningf("unable to parse kops version %q", kops.Version)
 | 
			
		||||
		// Not a hard-error
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	versionInfo := api.FindVersionInfo(c.channel.Spec.KopsVersions, kopsVersion)
 | 
			
		||||
	versionInfo := api.FindKopsVersionSpec(c.channel.Spec.KopsVersions, kopsVersion)
 | 
			
		||||
	if versionInfo == nil {
 | 
			
		||||
		glog.Warningf("unable to find version information for kops version %q in channel", kopsVersion)
 | 
			
		||||
		// Not a hard-error
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	recommended, err := api.FindRecommendedUpgrade(versionInfo, kopsVersion)
 | 
			
		||||
	recommended, err := versionInfo.FindRecommendedUpgrade(kopsVersion)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		glog.Warningf("unable to parse version recommendation for kops version %q in channel", kopsVersion)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	required, err := api.IsUpgradeRequired(versionInfo, kopsVersion)
 | 
			
		||||
	required, err := versionInfo.IsUpgradeRequired(kopsVersion)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		glog.Warningf("unable to parse version requirement for kops version %q in channel", kopsVersion)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if recommended != "" && !required {
 | 
			
		||||
	if recommended != nil && !required {
 | 
			
		||||
		fmt.Printf("\n")
 | 
			
		||||
		fmt.Printf(starline)
 | 
			
		||||
		fmt.Printf("\n")
 | 
			
		||||
		fmt.Printf("A new kops version is available: %s\n", recommended)
 | 
			
		||||
		fmt.Printf("\n")
 | 
			
		||||
		fmt.Printf("Upgrading is recommended\n")
 | 
			
		||||
		fmt.Printf("More information: %s\n", buildPermalink("upgrade_kops", recommended))
 | 
			
		||||
		fmt.Printf("More information: %s\n", buildPermalink("upgrade_kops", recommended.String()))
 | 
			
		||||
		fmt.Printf("\n")
 | 
			
		||||
		fmt.Printf(starline)
 | 
			
		||||
		fmt.Printf("\n")
 | 
			
		||||
| 
						 | 
				
			
			@ -662,18 +662,17 @@ func (c *ApplyClusterCmd) validateKopsVersion() error {
 | 
			
		|||
		fmt.Printf("\n")
 | 
			
		||||
		fmt.Printf(starline)
 | 
			
		||||
		fmt.Printf("\n")
 | 
			
		||||
		if recommended != "" {
 | 
			
		||||
		if recommended != nil {
 | 
			
		||||
			fmt.Printf("A new kops version is available: %s\n", recommended)
 | 
			
		||||
		}
 | 
			
		||||
		fmt.Printf("\n")
 | 
			
		||||
		fmt.Printf("This version of kops is no longer supported; upgrading is required\n")
 | 
			
		||||
		fmt.Printf("(you can bypass this check by exporting KOPS_RUN_OBSOLETE_VERSION)\n")
 | 
			
		||||
		fmt.Printf("\n")
 | 
			
		||||
		fmt.Printf("More information: %s\n", buildPermalink("upgrade_kops", recommended))
 | 
			
		||||
		fmt.Printf("More information: %s\n", buildPermalink("upgrade_kops", recommended.String()))
 | 
			
		||||
		fmt.Printf("\n")
 | 
			
		||||
		fmt.Printf(starline)
 | 
			
		||||
		fmt.Printf("\n")
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if required {
 | 
			
		||||
| 
						 | 
				
			
			@ -697,31 +696,31 @@ func (c *ApplyClusterCmd) validateKubernetesVersion() error {
 | 
			
		|||
	// TODO: make util.ParseKubernetesVersion not return a pointer
 | 
			
		||||
	kubernetesVersion := *parsed
 | 
			
		||||
 | 
			
		||||
	versionInfo := api.FindVersionInfo(c.channel.Spec.KubernetesVersions, kubernetesVersion)
 | 
			
		||||
	versionInfo := api.FindKubernetesVersionSpec(c.channel.Spec.KubernetesVersions, kubernetesVersion)
 | 
			
		||||
	if versionInfo == nil {
 | 
			
		||||
		glog.Warningf("unable to find version information for kubernetes version %q in channel", kubernetesVersion)
 | 
			
		||||
		// Not a hard-error
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	recommended, err := api.FindRecommendedUpgrade(versionInfo, kubernetesVersion)
 | 
			
		||||
	recommended, err := versionInfo.FindRecommendedUpgrade(kubernetesVersion)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		glog.Warningf("unable to parse version recommendation for kubernetes version %q in channel", kubernetesVersion)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	required, err := api.IsUpgradeRequired(versionInfo, kubernetesVersion)
 | 
			
		||||
	required, err := versionInfo.IsUpgradeRequired(kubernetesVersion)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		glog.Warningf("unable to parse version requirement for kubernetes version %q in channel", kubernetesVersion)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if recommended != "" && !required {
 | 
			
		||||
	if recommended != nil && !required {
 | 
			
		||||
		fmt.Printf("\n")
 | 
			
		||||
		fmt.Printf(starline)
 | 
			
		||||
		fmt.Printf("\n")
 | 
			
		||||
		fmt.Printf("A new kubernetes version is available: %s\n", recommended)
 | 
			
		||||
		fmt.Printf("Upgrading is recommended (try kops upgrade cluster)\n")
 | 
			
		||||
		fmt.Printf("\n")
 | 
			
		||||
		fmt.Printf("More information: %s\n", buildPermalink("upgrade_k8s", recommended))
 | 
			
		||||
		fmt.Printf("More information: %s\n", buildPermalink("upgrade_k8s", recommended.String()))
 | 
			
		||||
		fmt.Printf("\n")
 | 
			
		||||
		fmt.Printf(starline)
 | 
			
		||||
		fmt.Printf("\n")
 | 
			
		||||
| 
						 | 
				
			
			@ -729,14 +728,14 @@ func (c *ApplyClusterCmd) validateKubernetesVersion() error {
 | 
			
		|||
		fmt.Printf("\n")
 | 
			
		||||
		fmt.Printf(starline)
 | 
			
		||||
		fmt.Printf("\n")
 | 
			
		||||
		if recommended != "" {
 | 
			
		||||
		if recommended != nil {
 | 
			
		||||
			fmt.Printf("A new kubernetes version is available: %s\n", recommended)
 | 
			
		||||
		}
 | 
			
		||||
		fmt.Printf("\n")
 | 
			
		||||
		fmt.Printf("This version of kubernetes is no longer supported; upgrading is required\n")
 | 
			
		||||
		fmt.Printf("(you can bypass this check by exporting KOPS_RUN_OBSOLETE_VERSION)\n")
 | 
			
		||||
		fmt.Printf("\n")
 | 
			
		||||
		fmt.Printf("More information: %s\n", buildPermalink("upgrade_k8s", recommended))
 | 
			
		||||
		fmt.Printf("More information: %s\n", buildPermalink("upgrade_k8s", recommended.String()))
 | 
			
		||||
		fmt.Printf("\n")
 | 
			
		||||
		fmt.Printf(starline)
 | 
			
		||||
		fmt.Printf("\n")
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -91,8 +91,9 @@ func ensureKubernetesVersion(c *kops.Cluster) error {
 | 
			
		|||
			if err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
			if channel.Spec.Cluster.KubernetesVersion != "" {
 | 
			
		||||
				c.Spec.KubernetesVersion = channel.Spec.Cluster.KubernetesVersion
 | 
			
		||||
			kubernetesVersion := kops.RecommendedKubernetesVersion(channel)
 | 
			
		||||
			if kubernetesVersion != nil {
 | 
			
		||||
				c.Spec.KubernetesVersion = kubernetesVersion.String()
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -86,8 +86,11 @@ func (x *ConvertKubeupCluster) Upgrade() error {
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	// Set KubernetesVersion from channel
 | 
			
		||||
	if x.Channel != nil && x.Channel.Spec.Cluster != nil && x.Channel.Spec.Cluster.KubernetesVersion != "" {
 | 
			
		||||
		cluster.Spec.KubernetesVersion = x.Channel.Spec.Cluster.KubernetesVersion
 | 
			
		||||
	if x.Channel != nil {
 | 
			
		||||
		kubernetesVersion := api.RecommendedKubernetesVersion(x.Channel)
 | 
			
		||||
		if kubernetesVersion != nil {
 | 
			
		||||
			cluster.Spec.KubernetesVersion = kubernetesVersion.String()
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err = cloudup.PerformAssignments(cluster)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue