Merge pull request #88854 from bart0sh/PR0088-kubeadm-redesign-printAvailableUpgrades

kubeadm: redesign printAvailableUpgrades function
This commit is contained in:
Kubernetes Prow Robot 2020-03-27 05:14:23 -07:00 committed by GitHub
commit c1fc466cdd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 434 additions and 216 deletions

View File

@ -48,6 +48,7 @@ func addKnownTypes(scheme *runtime.Scheme) error {
scheme.AddKnownTypes(SchemeGroupVersion,
&BootstrapToken{},
&Images{},
&UpgradePlan{},
)
return nil
}

View File

@ -40,3 +40,20 @@ type Images struct {
Images []string
}
// ComponentUpgradePlan represents information about upgrade plan for one component
type ComponentUpgradePlan struct {
Name string
CurrentVersion string
NewVersion string
}
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// UpgradePlan represents information about upgrade plan for the output
// produced by 'kubeadm upgrade plan'
type UpgradePlan struct {
metav1.TypeMeta
Components []ComponentUpgradePlan
}

View File

@ -60,6 +60,7 @@ func addKnownTypes(scheme *runtime.Scheme) error {
scheme.AddKnownTypes(SchemeGroupVersion,
&BootstrapToken{},
&Images{},
&UpgradePlan{},
)
metav1.AddToGroupVersion(scheme, SchemeGroupVersion)
return nil

View File

@ -40,3 +40,20 @@ type Images struct {
Images []string `json:"images"`
}
// ComponentUpgradePlan represents information about upgrade plan for one component
type ComponentUpgradePlan struct {
Name string `json:"name"`
CurrentVersion string `json:"currentVersion"`
NewVersion string `json:"newVersion"`
}
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// UpgradePlan represents information about upgrade plan for the output
// produced by 'kubeadm upgrade plan'
type UpgradePlan struct {
metav1.TypeMeta
Components []ComponentUpgradePlan `json:"components"`
}

View File

@ -45,6 +45,16 @@ func RegisterConversions(s *runtime.Scheme) error {
}); err != nil {
return err
}
if err := s.AddGeneratedConversionFunc((*ComponentUpgradePlan)(nil), (*output.ComponentUpgradePlan)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_v1alpha1_ComponentUpgradePlan_To_output_ComponentUpgradePlan(a.(*ComponentUpgradePlan), b.(*output.ComponentUpgradePlan), scope)
}); err != nil {
return err
}
if err := s.AddGeneratedConversionFunc((*output.ComponentUpgradePlan)(nil), (*ComponentUpgradePlan)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_output_ComponentUpgradePlan_To_v1alpha1_ComponentUpgradePlan(a.(*output.ComponentUpgradePlan), b.(*ComponentUpgradePlan), scope)
}); err != nil {
return err
}
if err := s.AddGeneratedConversionFunc((*Images)(nil), (*output.Images)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_v1alpha1_Images_To_output_Images(a.(*Images), b.(*output.Images), scope)
}); err != nil {
@ -55,6 +65,16 @@ func RegisterConversions(s *runtime.Scheme) error {
}); err != nil {
return err
}
if err := s.AddGeneratedConversionFunc((*UpgradePlan)(nil), (*output.UpgradePlan)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_v1alpha1_UpgradePlan_To_output_UpgradePlan(a.(*UpgradePlan), b.(*output.UpgradePlan), scope)
}); err != nil {
return err
}
if err := s.AddGeneratedConversionFunc((*output.UpgradePlan)(nil), (*UpgradePlan)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_output_UpgradePlan_To_v1alpha1_UpgradePlan(a.(*output.UpgradePlan), b.(*UpgradePlan), scope)
}); err != nil {
return err
}
return nil
}
@ -78,6 +98,30 @@ func Convert_output_BootstrapToken_To_v1alpha1_BootstrapToken(in *output.Bootstr
return autoConvert_output_BootstrapToken_To_v1alpha1_BootstrapToken(in, out, s)
}
func autoConvert_v1alpha1_ComponentUpgradePlan_To_output_ComponentUpgradePlan(in *ComponentUpgradePlan, out *output.ComponentUpgradePlan, s conversion.Scope) error {
out.Name = in.Name
out.CurrentVersion = in.CurrentVersion
out.NewVersion = in.NewVersion
return nil
}
// Convert_v1alpha1_ComponentUpgradePlan_To_output_ComponentUpgradePlan is an autogenerated conversion function.
func Convert_v1alpha1_ComponentUpgradePlan_To_output_ComponentUpgradePlan(in *ComponentUpgradePlan, out *output.ComponentUpgradePlan, s conversion.Scope) error {
return autoConvert_v1alpha1_ComponentUpgradePlan_To_output_ComponentUpgradePlan(in, out, s)
}
func autoConvert_output_ComponentUpgradePlan_To_v1alpha1_ComponentUpgradePlan(in *output.ComponentUpgradePlan, out *ComponentUpgradePlan, s conversion.Scope) error {
out.Name = in.Name
out.CurrentVersion = in.CurrentVersion
out.NewVersion = in.NewVersion
return nil
}
// Convert_output_ComponentUpgradePlan_To_v1alpha1_ComponentUpgradePlan is an autogenerated conversion function.
func Convert_output_ComponentUpgradePlan_To_v1alpha1_ComponentUpgradePlan(in *output.ComponentUpgradePlan, out *ComponentUpgradePlan, s conversion.Scope) error {
return autoConvert_output_ComponentUpgradePlan_To_v1alpha1_ComponentUpgradePlan(in, out, s)
}
func autoConvert_v1alpha1_Images_To_output_Images(in *Images, out *output.Images, s conversion.Scope) error {
out.Images = *(*[]string)(unsafe.Pointer(&in.Images))
return nil
@ -97,3 +141,23 @@ func autoConvert_output_Images_To_v1alpha1_Images(in *output.Images, out *Images
func Convert_output_Images_To_v1alpha1_Images(in *output.Images, out *Images, s conversion.Scope) error {
return autoConvert_output_Images_To_v1alpha1_Images(in, out, s)
}
func autoConvert_v1alpha1_UpgradePlan_To_output_UpgradePlan(in *UpgradePlan, out *output.UpgradePlan, s conversion.Scope) error {
out.Components = *(*[]output.ComponentUpgradePlan)(unsafe.Pointer(&in.Components))
return nil
}
// Convert_v1alpha1_UpgradePlan_To_output_UpgradePlan is an autogenerated conversion function.
func Convert_v1alpha1_UpgradePlan_To_output_UpgradePlan(in *UpgradePlan, out *output.UpgradePlan, s conversion.Scope) error {
return autoConvert_v1alpha1_UpgradePlan_To_output_UpgradePlan(in, out, s)
}
func autoConvert_output_UpgradePlan_To_v1alpha1_UpgradePlan(in *output.UpgradePlan, out *UpgradePlan, s conversion.Scope) error {
out.Components = *(*[]ComponentUpgradePlan)(unsafe.Pointer(&in.Components))
return nil
}
// Convert_output_UpgradePlan_To_v1alpha1_UpgradePlan is an autogenerated conversion function.
func Convert_output_UpgradePlan_To_v1alpha1_UpgradePlan(in *output.UpgradePlan, out *UpgradePlan, s conversion.Scope) error {
return autoConvert_output_UpgradePlan_To_v1alpha1_UpgradePlan(in, out, s)
}

View File

@ -50,6 +50,22 @@ func (in *BootstrapToken) DeepCopyObject() runtime.Object {
return nil
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ComponentUpgradePlan) DeepCopyInto(out *ComponentUpgradePlan) {
*out = *in
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ComponentUpgradePlan.
func (in *ComponentUpgradePlan) DeepCopy() *ComponentUpgradePlan {
if in == nil {
return nil
}
out := new(ComponentUpgradePlan)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Images) DeepCopyInto(out *Images) {
*out = *in
@ -79,3 +95,33 @@ func (in *Images) DeepCopyObject() runtime.Object {
}
return nil
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *UpgradePlan) DeepCopyInto(out *UpgradePlan) {
*out = *in
out.TypeMeta = in.TypeMeta
if in.Components != nil {
in, out := &in.Components, &out.Components
*out = make([]ComponentUpgradePlan, len(*in))
copy(*out, *in)
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new UpgradePlan.
func (in *UpgradePlan) DeepCopy() *UpgradePlan {
if in == nil {
return nil
}
out := new(UpgradePlan)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *UpgradePlan) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil {
return c
}
return nil
}

View File

@ -50,6 +50,22 @@ func (in *BootstrapToken) DeepCopyObject() runtime.Object {
return nil
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ComponentUpgradePlan) DeepCopyInto(out *ComponentUpgradePlan) {
*out = *in
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ComponentUpgradePlan.
func (in *ComponentUpgradePlan) DeepCopy() *ComponentUpgradePlan {
if in == nil {
return nil
}
out := new(ComponentUpgradePlan)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Images) DeepCopyInto(out *Images) {
*out = *in
@ -79,3 +95,33 @@ func (in *Images) DeepCopyObject() runtime.Object {
}
return nil
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *UpgradePlan) DeepCopyInto(out *UpgradePlan) {
*out = *in
out.TypeMeta = in.TypeMeta
if in.Components != nil {
in, out := &in.Components, &out.Components
*out = make([]ComponentUpgradePlan, len(*in))
copy(*out, *in)
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new UpgradePlan.
func (in *UpgradePlan) DeepCopy() *UpgradePlan {
if in == nil {
return nil
}
out := new(UpgradePlan)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *UpgradePlan) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil {
return c
}
return nil
}

View File

@ -15,6 +15,7 @@ go_library(
deps = [
"//cmd/kubeadm/app/apis/kubeadm:go_default_library",
"//cmd/kubeadm/app/apis/kubeadm/validation:go_default_library",
"//cmd/kubeadm/app/apis/output/v1alpha1:go_default_library",
"//cmd/kubeadm/app/cmd/options:go_default_library",
"//cmd/kubeadm/app/cmd/phases/upgrade/node:go_default_library",
"//cmd/kubeadm/app/cmd/phases/workflow:go_default_library",

View File

@ -29,6 +29,8 @@ import (
"k8s.io/apimachinery/pkg/util/version"
"k8s.io/klog"
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
outputapiv1alpha1 "k8s.io/kubernetes/cmd/kubeadm/app/apis/output/v1alpha1"
"k8s.io/kubernetes/cmd/kubeadm/app/constants"
"k8s.io/kubernetes/cmd/kubeadm/app/phases/upgrade"
etcdutil "k8s.io/kubernetes/cmd/kubeadm/app/util/etcd"
)
@ -97,131 +99,154 @@ func runPlan(flags *planFlags, userVersion string) error {
return errors.Wrap(err, "[upgrade/versions] FATAL")
}
// Tell the user which upgrades are available
printAvailableUpgrades(availUpgrades, os.Stdout, isExternalEtcd)
// No upgrades available
if len(availUpgrades) == 0 {
klog.V(1).Infoln("[upgrade/plan] Awesome, you're up-to-date! Enjoy!")
return nil
}
// Generate and print upgrade plans
for _, up := range availUpgrades {
plan, unstableVersionFlag, err := genUpgradePlan(&up, isExternalEtcd)
if err != nil {
return err
}
printUpgradePlan(&up, plan, unstableVersionFlag, isExternalEtcd, os.Stdout)
}
return nil
}
// printAvailableUpgrades prints a UX-friendly overview of what versions are available to upgrade to
// TODO look into columnize or some other formatter when time permits instead of using the tabwriter
func printAvailableUpgrades(upgrades []upgrade.Upgrade, w io.Writer, isExternalEtcd bool) {
// Return quickly if no upgrades can be made
if len(upgrades) == 0 {
fmt.Fprintln(w, "Awesome, you're up-to-date! Enjoy!")
return
// newComponentUpgradePlan helper creates outputapiv1alpha1.ComponentUpgradePlan object
func newComponentUpgradePlan(name, currentVersion, newVersion string) outputapiv1alpha1.ComponentUpgradePlan {
return outputapiv1alpha1.ComponentUpgradePlan{
Name: name,
CurrentVersion: currentVersion,
NewVersion: newVersion,
}
}
// TODO There is currently no way to cleanly output upgrades that involve adding, removing, or changing components
// https://github.com/kubernetes/kubeadm/issues/810 was created to track addressing this.
func appendDNSComponent(components []outputapiv1alpha1.ComponentUpgradePlan, up *upgrade.Upgrade, DNSType kubeadmapi.DNSAddOnType, name string) []outputapiv1alpha1.ComponentUpgradePlan {
beforeVersion, afterVersion := "", ""
if up.Before.DNSType == DNSType {
beforeVersion = up.Before.DNSVersion
}
if up.After.DNSType == DNSType {
afterVersion = up.After.DNSVersion
}
if beforeVersion != "" || afterVersion != "" {
components = append(components, newComponentUpgradePlan(name, beforeVersion, afterVersion))
}
return components
}
// genUpgradePlan generates output-friendly upgrade plan out of upgrade.Upgrade structure
func genUpgradePlan(up *upgrade.Upgrade, isExternalEtcd bool) (*outputapiv1alpha1.UpgradePlan, string, error) {
newK8sVersion, err := version.ParseSemantic(up.After.KubeVersion)
if err != nil {
return nil, "", errors.Wrapf(err, "Unable to parse normalized version %q as a semantic version", up.After.KubeVersion)
}
unstableVersionFlag := ""
if len(newK8sVersion.PreRelease()) != 0 {
if strings.HasPrefix(newK8sVersion.PreRelease(), "rc") {
unstableVersionFlag = " --allow-release-candidate-upgrades"
} else {
unstableVersionFlag = " --allow-experimental-upgrades"
}
}
components := []outputapiv1alpha1.ComponentUpgradePlan{}
if isExternalEtcd && up.CanUpgradeEtcd() {
components = append(components, newComponentUpgradePlan(constants.Etcd, up.Before.EtcdVersion, up.After.EtcdVersion))
}
if up.CanUpgradeKubelets() {
// The map is of the form <old-version>:<node-count>. Here all the keys are put into a slice and sorted
// in order to always get the right order. Then the map value is extracted separately
for _, oldVersion := range sortedSliceFromStringIntMap(up.Before.KubeletVersions) {
nodeCount := up.Before.KubeletVersions[oldVersion]
components = append(components, newComponentUpgradePlan(constants.Kubelet, fmt.Sprintf("%d x %s", nodeCount, oldVersion), up.After.KubeVersion))
}
}
components = append(components, newComponentUpgradePlan(constants.KubeAPIServer, up.Before.KubeVersion, up.After.KubeVersion))
components = append(components, newComponentUpgradePlan(constants.KubeControllerManager, up.Before.KubeVersion, up.After.KubeVersion))
components = append(components, newComponentUpgradePlan(constants.KubeScheduler, up.Before.KubeVersion, up.After.KubeVersion))
components = append(components, newComponentUpgradePlan(constants.KubeProxy, up.Before.KubeVersion, up.After.KubeVersion))
components = appendDNSComponent(components, up, kubeadmapi.CoreDNS, constants.CoreDNS)
components = appendDNSComponent(components, up, kubeadmapi.KubeDNS, constants.KubeDNS)
if !isExternalEtcd {
components = append(components, newComponentUpgradePlan(constants.Etcd, up.Before.EtcdVersion, up.After.EtcdVersion))
}
return &outputapiv1alpha1.UpgradePlan{Components: components}, unstableVersionFlag, nil
}
// printUpgradePlan prints a UX-friendly overview of what versions are available to upgrade to
func printUpgradePlan(up *upgrade.Upgrade, plan *outputapiv1alpha1.UpgradePlan, unstableVersionFlag string, isExternalEtcd bool, w io.Writer) {
// The tab writer writes to the "real" writer w
tabw := tabwriter.NewWriter(w, 10, 4, 3, ' ', 0)
// Loop through the upgrade possibilities and output text to the command line
for _, upgrade := range upgrades {
newK8sVersion, err := version.ParseSemantic(upgrade.After.KubeVersion)
if err != nil {
fmt.Fprintf(w, "Unable to parse normalized version %q as a semantic version\n", upgrade.After.KubeVersion)
continue
}
UnstableVersionFlag := ""
if len(newK8sVersion.PreRelease()) != 0 {
if strings.HasPrefix(newK8sVersion.PreRelease(), "rc") {
UnstableVersionFlag = " --allow-release-candidate-upgrades"
} else {
UnstableVersionFlag = " --allow-experimental-upgrades"
}
}
if isExternalEtcd && upgrade.CanUpgradeEtcd() {
fmt.Fprintln(w, "External components that should be upgraded manually before you upgrade the control plane with 'kubeadm upgrade apply':")
fmt.Fprintln(tabw, "COMPONENT\tCURRENT\tAVAILABLE")
fmt.Fprintf(tabw, "Etcd\t%s\t%s\n", upgrade.Before.EtcdVersion, upgrade.After.EtcdVersion)
// We should flush the writer here at this stage; as the columns will now be of the right size, adjusted to the above content
tabw.Flush()
fmt.Fprintln(w, "")
}
if upgrade.CanUpgradeKubelets() {
fmt.Fprintln(w, "Components that must be upgraded manually after you have upgraded the control plane with 'kubeadm upgrade apply':")
fmt.Fprintln(tabw, "COMPONENT\tCURRENT\tAVAILABLE")
firstPrinted := false
// The map is of the form <old-version>:<node-count>. Here all the keys are put into a slice and sorted
// in order to always get the right order. Then the map value is extracted separately
for _, oldVersion := range sortedSliceFromStringIntMap(upgrade.Before.KubeletVersions) {
nodeCount := upgrade.Before.KubeletVersions[oldVersion]
if !firstPrinted {
// Output the Kubelet header only on the first version pair
fmt.Fprintf(tabw, "Kubelet\t%d x %s\t%s\n", nodeCount, oldVersion, upgrade.After.KubeVersion)
firstPrinted = true
continue
}
fmt.Fprintf(tabw, "\t%d x %s\t%s\n", nodeCount, oldVersion, upgrade.After.KubeVersion)
}
// We should flush the writer here at this stage; as the columns will now be of the right size, adjusted to the above content
tabw.Flush()
fmt.Fprintln(w, "")
}
fmt.Fprintf(w, "Upgrade to the latest %s:\n", upgrade.Description)
fmt.Fprintln(w, "")
fmt.Fprintln(tabw, "COMPONENT\tCURRENT\tAVAILABLE")
fmt.Fprintf(tabw, "API Server\t%s\t%s\n", upgrade.Before.KubeVersion, upgrade.After.KubeVersion)
fmt.Fprintf(tabw, "Controller Manager\t%s\t%s\n", upgrade.Before.KubeVersion, upgrade.After.KubeVersion)
fmt.Fprintf(tabw, "Scheduler\t%s\t%s\n", upgrade.Before.KubeVersion, upgrade.After.KubeVersion)
fmt.Fprintf(tabw, "Kube Proxy\t%s\t%s\n", upgrade.Before.KubeVersion, upgrade.After.KubeVersion)
// TODO There is currently no way to cleanly output upgrades that involve adding, removing, or changing components
// https://github.com/kubernetes/kubeadm/issues/810 was created to track addressing this.
printCoreDNS, printKubeDNS := false, false
coreDNSBeforeVersion, coreDNSAfterVersion, kubeDNSBeforeVersion, kubeDNSAfterVersion := "", "", "", ""
switch upgrade.Before.DNSType {
case kubeadmapi.CoreDNS:
printCoreDNS = true
coreDNSBeforeVersion = upgrade.Before.DNSVersion
case kubeadmapi.KubeDNS:
printKubeDNS = true
kubeDNSBeforeVersion = upgrade.Before.DNSVersion
}
switch upgrade.After.DNSType {
case kubeadmapi.CoreDNS:
printCoreDNS = true
coreDNSAfterVersion = upgrade.After.DNSVersion
case kubeadmapi.KubeDNS:
printKubeDNS = true
kubeDNSAfterVersion = upgrade.After.DNSVersion
}
if printCoreDNS {
fmt.Fprintf(tabw, "CoreDNS\t%s\t%s\n", coreDNSBeforeVersion, coreDNSAfterVersion)
}
if printKubeDNS {
fmt.Fprintf(tabw, "Kube DNS\t%s\t%s\n", kubeDNSBeforeVersion, kubeDNSAfterVersion)
}
if !isExternalEtcd {
fmt.Fprintf(tabw, "Etcd\t%s\t%s\n", upgrade.Before.EtcdVersion, upgrade.After.EtcdVersion)
}
// The tabwriter should be flushed at this stage as we have now put in all the required content for this time. This is required for the tabs' size to be correct.
// endOfTable helper function flashes table writer
endOfTable := func() {
tabw.Flush()
fmt.Fprintln(w, "")
fmt.Fprintln(w, "You can now apply the upgrade by executing the following command:")
fmt.Fprintln(w, "")
fmt.Fprintf(w, "\tkubeadm upgrade apply %s%s\n", upgrade.After.KubeVersion, UnstableVersionFlag)
fmt.Fprintln(w, "")
}
if upgrade.Before.KubeadmVersion != upgrade.After.KubeadmVersion {
fmt.Fprintf(w, "Note: Before you can perform this upgrade, you have to update kubeadm to %s.\n", upgrade.After.KubeadmVersion)
fmt.Fprintln(w, "")
printHeader := true
printManualUpgradeHeader := true
for _, component := range plan.Components {
if isExternalEtcd && component.Name == constants.Etcd {
fmt.Fprintln(w, "External components that should be upgraded manually before you upgrade the control plane with 'kubeadm upgrade apply':")
fmt.Fprintln(tabw, "COMPONENT\tCURRENT\tAVAILABLE")
fmt.Fprintf(tabw, "%s\t%s\t%s\n", component.Name, component.CurrentVersion, component.NewVersion)
// end of external components table
endOfTable()
} else if component.Name == constants.Kubelet {
if printManualUpgradeHeader {
fmt.Fprintln(w, "Components that must be upgraded manually after you have upgraded the control plane with 'kubeadm upgrade apply':")
fmt.Fprintln(tabw, "COMPONENT\tCURRENT\tAVAILABLE")
fmt.Fprintf(tabw, "%s\t%s\t%s\n", component.Name, component.CurrentVersion, component.NewVersion)
printManualUpgradeHeader = false
} else {
fmt.Fprintf(tabw, "%s\t%s\t%s\n", "", component.CurrentVersion, component.NewVersion)
}
} else {
if printHeader {
// End of manual upgrades table
endOfTable()
fmt.Fprintf(w, "Upgrade to the latest %s:\n", up.Description)
fmt.Fprintln(w, "")
fmt.Fprintln(tabw, "COMPONENT\tCURRENT\tAVAILABLE")
printHeader = false
}
fmt.Fprintf(tabw, "%s\t%s\t%s\n", component.Name, component.CurrentVersion, component.NewVersion)
}
}
// End of control plane table
endOfTable()
fmt.Fprintln(w, "_____________________________________________________________________")
//fmt.Fprintln(w, "")
fmt.Fprintln(w, "You can now apply the upgrade by executing the following command:")
fmt.Fprintln(w, "")
fmt.Fprintf(w, "\tkubeadm upgrade apply %s%s\n", up.After.KubeVersion, unstableVersionFlag)
fmt.Fprintln(w, "")
if up.Before.KubeadmVersion != up.After.KubeadmVersion {
fmt.Fprintf(w, "Note: Before you can perform this upgrade, you have to update kubeadm to %s.\n", up.After.KubeadmVersion)
fmt.Fprintln(w, "")
}
fmt.Fprintln(w, "_____________________________________________________________________")
fmt.Fprintln(w, "")
}
// sortedSliceFromStringIntMap returns a slice of the keys in the map sorted alphabetically

View File

@ -75,19 +75,6 @@ func TestPrintAvailableUpgrades(t *testing.T) {
expectedBytes []byte
externalEtcd bool
}{
{
name: "Up to date",
upgrades: []upgrade.Upgrade{},
expectedBytes: []byte(`Awesome, you're up-to-date! Enjoy!
`),
},
{
name: "Up to date external etcd",
externalEtcd: true,
upgrades: []upgrade.Upgrade{},
expectedBytes: []byte(`Awesome, you're up-to-date! Enjoy!
`),
},
{
name: "Patch version available",
upgrades: []upgrade.Upgrade{
@ -114,17 +101,17 @@ func TestPrintAvailableUpgrades(t *testing.T) {
},
expectedBytes: []byte(`Components that must be upgraded manually after you have upgraded the control plane with 'kubeadm upgrade apply':
COMPONENT CURRENT AVAILABLE
Kubelet 1 x v1.8.1 v1.8.3
kubelet 1 x v1.8.1 v1.8.3
Upgrade to the latest version in the v1.8 series:
COMPONENT CURRENT AVAILABLE
API Server v1.8.1 v1.8.3
Controller Manager v1.8.1 v1.8.3
Scheduler v1.8.1 v1.8.3
Kube Proxy v1.8.1 v1.8.3
Kube DNS 1.14.5 1.14.5
Etcd 3.0.17 3.0.17
COMPONENT CURRENT AVAILABLE
kube-apiserver v1.8.1 v1.8.3
kube-controller-manager v1.8.1 v1.8.3
kube-scheduler v1.8.1 v1.8.3
kube-proxy v1.8.1 v1.8.3
kube-dns 1.14.5 1.14.5
etcd 3.0.17 3.0.17
You can now apply the upgrade by executing the following command:
@ -162,17 +149,17 @@ _____________________________________________________________________
},
expectedBytes: []byte(`Components that must be upgraded manually after you have upgraded the control plane with 'kubeadm upgrade apply':
COMPONENT CURRENT AVAILABLE
Kubelet 1 x v1.8.3 v1.9.0
kubelet 1 x v1.8.3 v1.9.0
Upgrade to the latest stable version:
COMPONENT CURRENT AVAILABLE
API Server v1.8.3 v1.9.0
Controller Manager v1.8.3 v1.9.0
Scheduler v1.8.3 v1.9.0
Kube Proxy v1.8.3 v1.9.0
Kube DNS 1.14.5 1.14.13
Etcd 3.0.17 3.1.12
COMPONENT CURRENT AVAILABLE
kube-apiserver v1.8.3 v1.9.0
kube-controller-manager v1.8.3 v1.9.0
kube-scheduler v1.8.3 v1.9.0
kube-proxy v1.8.3 v1.9.0
kube-dns 1.14.5 1.14.13
etcd 3.0.17 3.1.12
You can now apply the upgrade by executing the following command:
@ -228,17 +215,17 @@ _____________________________________________________________________
},
expectedBytes: []byte(`Components that must be upgraded manually after you have upgraded the control plane with 'kubeadm upgrade apply':
COMPONENT CURRENT AVAILABLE
Kubelet 1 x v1.8.3 v1.8.5
kubelet 1 x v1.8.3 v1.8.5
Upgrade to the latest version in the v1.8 series:
COMPONENT CURRENT AVAILABLE
API Server v1.8.3 v1.8.5
Controller Manager v1.8.3 v1.8.5
Scheduler v1.8.3 v1.8.5
Kube Proxy v1.8.3 v1.8.5
Kube DNS 1.14.5 1.14.5
Etcd 3.0.17 3.0.17
COMPONENT CURRENT AVAILABLE
kube-apiserver v1.8.3 v1.8.5
kube-controller-manager v1.8.3 v1.8.5
kube-scheduler v1.8.3 v1.8.5
kube-proxy v1.8.3 v1.8.5
kube-dns 1.14.5 1.14.5
etcd 3.0.17 3.0.17
You can now apply the upgrade by executing the following command:
@ -248,17 +235,17 @@ _____________________________________________________________________
Components that must be upgraded manually after you have upgraded the control plane with 'kubeadm upgrade apply':
COMPONENT CURRENT AVAILABLE
Kubelet 1 x v1.8.3 v1.9.0
kubelet 1 x v1.8.3 v1.9.0
Upgrade to the latest stable version:
COMPONENT CURRENT AVAILABLE
API Server v1.8.3 v1.9.0
Controller Manager v1.8.3 v1.9.0
Scheduler v1.8.3 v1.9.0
Kube Proxy v1.8.3 v1.9.0
Kube DNS 1.14.5 1.14.13
Etcd 3.0.17 3.1.12
COMPONENT CURRENT AVAILABLE
kube-apiserver v1.8.3 v1.9.0
kube-controller-manager v1.8.3 v1.9.0
kube-scheduler v1.8.3 v1.9.0
kube-proxy v1.8.3 v1.9.0
kube-dns 1.14.5 1.14.13
etcd 3.0.17 3.1.12
You can now apply the upgrade by executing the following command:
@ -296,17 +283,17 @@ _____________________________________________________________________
},
expectedBytes: []byte(`Components that must be upgraded manually after you have upgraded the control plane with 'kubeadm upgrade apply':
COMPONENT CURRENT AVAILABLE
Kubelet 1 x v1.8.5 v1.9.0-beta.1
kubelet 1 x v1.8.5 v1.9.0-beta.1
Upgrade to the latest experimental version:
COMPONENT CURRENT AVAILABLE
API Server v1.8.5 v1.9.0-beta.1
Controller Manager v1.8.5 v1.9.0-beta.1
Scheduler v1.8.5 v1.9.0-beta.1
Kube Proxy v1.8.5 v1.9.0-beta.1
Kube DNS 1.14.5 1.14.13
Etcd 3.0.17 3.1.12
COMPONENT CURRENT AVAILABLE
kube-apiserver v1.8.5 v1.9.0-beta.1
kube-controller-manager v1.8.5 v1.9.0-beta.1
kube-scheduler v1.8.5 v1.9.0-beta.1
kube-proxy v1.8.5 v1.9.0-beta.1
kube-dns 1.14.5 1.14.13
etcd 3.0.17 3.1.12
You can now apply the upgrade by executing the following command:
@ -344,17 +331,17 @@ _____________________________________________________________________
},
expectedBytes: []byte(`Components that must be upgraded manually after you have upgraded the control plane with 'kubeadm upgrade apply':
COMPONENT CURRENT AVAILABLE
Kubelet 1 x v1.8.5 v1.9.0-rc.1
kubelet 1 x v1.8.5 v1.9.0-rc.1
Upgrade to the latest release candidate version:
COMPONENT CURRENT AVAILABLE
API Server v1.8.5 v1.9.0-rc.1
Controller Manager v1.8.5 v1.9.0-rc.1
Scheduler v1.8.5 v1.9.0-rc.1
Kube Proxy v1.8.5 v1.9.0-rc.1
Kube DNS 1.14.5 1.14.13
Etcd 3.0.17 3.1.12
COMPONENT CURRENT AVAILABLE
kube-apiserver v1.8.5 v1.9.0-rc.1
kube-controller-manager v1.8.5 v1.9.0-rc.1
kube-scheduler v1.8.5 v1.9.0-rc.1
kube-proxy v1.8.5 v1.9.0-rc.1
kube-dns 1.14.5 1.14.13
etcd 3.0.17 3.1.12
You can now apply the upgrade by executing the following command:
@ -393,18 +380,18 @@ _____________________________________________________________________
},
expectedBytes: []byte(`Components that must be upgraded manually after you have upgraded the control plane with 'kubeadm upgrade apply':
COMPONENT CURRENT AVAILABLE
Kubelet 1 x v1.9.2 v1.9.3
kubelet 1 x v1.9.2 v1.9.3
2 x v1.9.3 v1.9.3
Upgrade to the latest version in the v1.9 series:
COMPONENT CURRENT AVAILABLE
API Server v1.9.2 v1.9.3
Controller Manager v1.9.2 v1.9.3
Scheduler v1.9.2 v1.9.3
Kube Proxy v1.9.2 v1.9.3
Kube DNS 1.14.5 1.14.8
Etcd 3.0.17 3.1.12
COMPONENT CURRENT AVAILABLE
kube-apiserver v1.9.2 v1.9.3
kube-controller-manager v1.9.2 v1.9.3
kube-scheduler v1.9.2 v1.9.3
kube-proxy v1.9.2 v1.9.3
kube-dns 1.14.5 1.14.8
etcd 3.0.17 3.1.12
You can now apply the upgrade by executing the following command:
@ -444,20 +431,20 @@ _____________________________________________________________________
externalEtcd: true,
expectedBytes: []byte(`External components that should be upgraded manually before you upgrade the control plane with 'kubeadm upgrade apply':
COMPONENT CURRENT AVAILABLE
Etcd 3.0.17 3.1.12
etcd 3.0.17 3.1.12
Components that must be upgraded manually after you have upgraded the control plane with 'kubeadm upgrade apply':
COMPONENT CURRENT AVAILABLE
Kubelet 1 x v1.9.2 v1.9.3
kubelet 1 x v1.9.2 v1.9.3
Upgrade to the latest version in the v1.9 series:
COMPONENT CURRENT AVAILABLE
API Server v1.9.2 v1.9.3
Controller Manager v1.9.2 v1.9.3
Scheduler v1.9.2 v1.9.3
Kube Proxy v1.9.2 v1.9.3
Kube DNS 1.14.5 1.14.8
COMPONENT CURRENT AVAILABLE
kube-apiserver v1.9.2 v1.9.3
kube-controller-manager v1.9.2 v1.9.3
kube-scheduler v1.9.2 v1.9.3
kube-proxy v1.9.2 v1.9.3
kube-dns 1.14.5 1.14.8
You can now apply the upgrade by executing the following command:
@ -495,18 +482,18 @@ _____________________________________________________________________
},
expectedBytes: []byte(`Components that must be upgraded manually after you have upgraded the control plane with 'kubeadm upgrade apply':
COMPONENT CURRENT AVAILABLE
Kubelet 1 x v1.10.2 v1.11.0
kubelet 1 x v1.10.2 v1.11.0
Upgrade to the latest kubedns to coredns:
COMPONENT CURRENT AVAILABLE
API Server v1.10.2 v1.11.0
Controller Manager v1.10.2 v1.11.0
Scheduler v1.10.2 v1.11.0
Kube Proxy v1.10.2 v1.11.0
CoreDNS 1.0.6
Kube DNS 1.14.7
Etcd 3.1.11 3.2.18
COMPONENT CURRENT AVAILABLE
kube-apiserver v1.10.2 v1.11.0
kube-controller-manager v1.10.2 v1.11.0
kube-scheduler v1.10.2 v1.11.0
kube-proxy v1.10.2 v1.11.0
CoreDNS 1.0.6
kube-dns 1.14.7
etcd 3.1.11 3.2.18
You can now apply the upgrade by executing the following command:
@ -542,17 +529,17 @@ _____________________________________________________________________
},
expectedBytes: []byte(`Components that must be upgraded manually after you have upgraded the control plane with 'kubeadm upgrade apply':
COMPONENT CURRENT AVAILABLE
Kubelet 1 x v1.10.2 v1.11.0
kubelet 1 x v1.10.2 v1.11.0
Upgrade to the latest coredns:
COMPONENT CURRENT AVAILABLE
API Server v1.10.2 v1.11.0
Controller Manager v1.10.2 v1.11.0
Scheduler v1.10.2 v1.11.0
Kube Proxy v1.10.2 v1.11.0
CoreDNS 1.0.5 1.0.6
Etcd 3.1.11 3.2.18
COMPONENT CURRENT AVAILABLE
kube-apiserver v1.10.2 v1.11.0
kube-controller-manager v1.10.2 v1.11.0
kube-scheduler v1.10.2 v1.11.0
kube-proxy v1.10.2 v1.11.0
CoreDNS 1.0.5 1.0.6
etcd 3.1.11 3.2.18
You can now apply the upgrade by executing the following command:
@ -588,18 +575,18 @@ _____________________________________________________________________
},
expectedBytes: []byte(`Components that must be upgraded manually after you have upgraded the control plane with 'kubeadm upgrade apply':
COMPONENT CURRENT AVAILABLE
Kubelet 1 x v1.10.2 v1.11.0
kubelet 1 x v1.10.2 v1.11.0
Upgrade to the latest coredns to kubedns:
COMPONENT CURRENT AVAILABLE
API Server v1.10.2 v1.11.0
Controller Manager v1.10.2 v1.11.0
Scheduler v1.10.2 v1.11.0
Kube Proxy v1.10.2 v1.11.0
CoreDNS 1.0.6
Kube DNS 1.14.9
Etcd 3.1.11 3.2.18
COMPONENT CURRENT AVAILABLE
kube-apiserver v1.10.2 v1.11.0
kube-controller-manager v1.10.2 v1.11.0
kube-scheduler v1.10.2 v1.11.0
kube-proxy v1.10.2 v1.11.0
CoreDNS 1.0.6
kube-dns 1.14.9
etcd 3.1.11 3.2.18
You can now apply the upgrade by executing the following command:
@ -613,11 +600,18 @@ _____________________________________________________________________
for _, rt := range tests {
t.Run(rt.name, func(t *testing.T) {
rt.buf = bytes.NewBufferString("")
printAvailableUpgrades(rt.upgrades, rt.buf, rt.externalEtcd)
// Generate and print upgrade plans
for _, up := range rt.upgrades {
plan, unstableVersionFlag, err := genUpgradePlan(&up, rt.externalEtcd)
if err != nil {
t.Errorf("failed genUpgradePlan, err: %+v", err)
}
printUpgradePlan(&up, plan, unstableVersionFlag, rt.externalEtcd, rt.buf)
}
actualBytes := rt.buf.Bytes()
if !bytes.Equal(actualBytes, rt.expectedBytes) {
t.Errorf(
"failed PrintAvailableUpgrades:\n\texpected: %q\n\t actual: %q",
"failed PrintAvailableUpgrades:\n\texpected: %q\n\n\tactual : %q",
string(rt.expectedBytes),
string(actualBytes),
)

View File

@ -279,6 +279,12 @@ const (
KubeProxy = "kube-proxy"
// HyperKube defines variable used internally when referring to the hyperkube image
HyperKube = "hyperkube"
// CoreDNS defines variable used internally when referring to the CoreDNS component
CoreDNS = "CoreDNS"
// KubeDNS defines variable used internally when referring to the KubeDNS component
KubeDNS = "kube-dns"
// Kubelet defines variable used internally when referring to the Kubelet
Kubelet = "kubelet"
// SelfHostingPrefix describes the prefix workloads that are self-hosted by kubeadm has
SelfHostingPrefix = "self-hosted-"