Merge pull request #55952 from rajansandeep/corednsupgrade

Automatic merge from submit-queue (batch tested with PRs 55952, 49112, 55450, 56178, 56151). If you want to cherry-pick this change to another branch, please follow the instructions <a href="https://github.com/kubernetes/community/blob/master/contributors/devel/cherry-picks.md">here</a>.

Add support to kubeadm upgrade for CoreDNS

**What this PR does / why we need it**:
This PR enables to get CoreDNS in the kubeadm upgrade and alpha phases addons via feature-gates.

**Which issue(s) this PR fixes** *(optional, in `fixes #<issue number>(, fixes #<issue_number>, ...)` format, will close the issue(s) when PR gets merged)*:
Fixes https://github.com/kubernetes/kubeadm/issues/446

**Special notes for your reviewer**:

**Release note**:

```release-note
kubeadm: Add CoreDNS support for kubeadm "upgrade" and "alpha phases addons".
```
pull/6/head
Kubernetes Submit Queue 2017-11-22 21:48:38 -08:00 committed by GitHub
commit 408f64062f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 96 additions and 22 deletions

View File

@ -17,6 +17,8 @@ limitations under the License.
package phases package phases
import ( import (
"strings"
"github.com/spf13/cobra" "github.com/spf13/cobra"
clientset "k8s.io/client-go/kubernetes" clientset "k8s.io/client-go/kubernetes"
@ -24,6 +26,7 @@ import (
kubeadmapiext "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1alpha1" kubeadmapiext "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1alpha1"
"k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/validation" "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/validation"
cmdutil "k8s.io/kubernetes/cmd/kubeadm/app/cmd/util" cmdutil "k8s.io/kubernetes/cmd/kubeadm/app/cmd/util"
"k8s.io/kubernetes/cmd/kubeadm/app/features"
dnsaddon "k8s.io/kubernetes/cmd/kubeadm/app/phases/addons/dns" dnsaddon "k8s.io/kubernetes/cmd/kubeadm/app/phases/addons/dns"
proxyaddon "k8s.io/kubernetes/cmd/kubeadm/app/phases/addons/proxy" proxyaddon "k8s.io/kubernetes/cmd/kubeadm/app/phases/addons/proxy"
kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util" kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util"
@ -93,7 +96,7 @@ func getAddonsSubCommands() []*cobra.Command {
// Default values for the cobra help text // Default values for the cobra help text
legacyscheme.Scheme.Default(cfg) legacyscheme.Scheme.Default(cfg)
var cfgPath, kubeConfigFile string var cfgPath, kubeConfigFile, featureGatesString string
var subCmds []*cobra.Command var subCmds []*cobra.Command
subCmdProperties := []struct { subCmdProperties := []struct {
@ -131,7 +134,7 @@ func getAddonsSubCommands() []*cobra.Command {
Short: properties.short, Short: properties.short,
Long: properties.long, Long: properties.long,
Example: properties.examples, Example: properties.examples,
Run: runAddonsCmdFunc(properties.cmdFunc, cfg, &kubeConfigFile, &cfgPath), Run: runAddonsCmdFunc(properties.cmdFunc, cfg, &kubeConfigFile, &cfgPath, &featureGatesString),
} }
// Add flags to the command // Add flags to the command
@ -149,6 +152,8 @@ func getAddonsSubCommands() []*cobra.Command {
if properties.use == "all" || properties.use == "kube-dns" { if properties.use == "all" || properties.use == "kube-dns" {
cmd.Flags().StringVar(&cfg.Networking.DNSDomain, "service-dns-domain", cfg.Networking.DNSDomain, `Alternative domain for services`) cmd.Flags().StringVar(&cfg.Networking.DNSDomain, "service-dns-domain", cfg.Networking.DNSDomain, `Alternative domain for services`)
cmd.Flags().StringVar(&cfg.Networking.ServiceSubnet, "service-cidr", cfg.Networking.ServiceSubnet, `The range of IP address used for service VIPs`) cmd.Flags().StringVar(&cfg.Networking.ServiceSubnet, "service-cidr", cfg.Networking.ServiceSubnet, `The range of IP address used for service VIPs`)
cmd.Flags().StringVar(&featureGatesString, "feature-gates", featureGatesString, "A set of key=value pairs that describe feature gates for various features."+
"Options are:\n"+strings.Join(features.KnownFeatures(&features.InitFeatureGates), "\n"))
} }
subCmds = append(subCmds, cmd) subCmds = append(subCmds, cmd)
} }
@ -157,7 +162,7 @@ func getAddonsSubCommands() []*cobra.Command {
} }
// runAddonsCmdFunc creates a cobra.Command Run function, by composing the call to the given cmdFunc with necessary additional steps (e.g preparation of input parameters) // runAddonsCmdFunc creates a cobra.Command Run function, by composing the call to the given cmdFunc with necessary additional steps (e.g preparation of input parameters)
func runAddonsCmdFunc(cmdFunc func(cfg *kubeadmapi.MasterConfiguration, client clientset.Interface) error, cfg *kubeadmapiext.MasterConfiguration, kubeConfigFile *string, cfgPath *string) func(cmd *cobra.Command, args []string) { func runAddonsCmdFunc(cmdFunc func(cfg *kubeadmapi.MasterConfiguration, client clientset.Interface) error, cfg *kubeadmapiext.MasterConfiguration, kubeConfigFile *string, cfgPath *string, featureGatesString *string) func(cmd *cobra.Command, args []string) {
// the following statement build a clousure that wraps a call to a cmdFunc, binding // the following statement build a clousure that wraps a call to a cmdFunc, binding
// the function itself with the specific parameters of each sub command. // the function itself with the specific parameters of each sub command.
@ -165,16 +170,24 @@ func runAddonsCmdFunc(cmdFunc func(cfg *kubeadmapi.MasterConfiguration, client c
// are shared between sub commands and gets access to current value e.g. flags value. // are shared between sub commands and gets access to current value e.g. flags value.
return func(cmd *cobra.Command, args []string) { return func(cmd *cobra.Command, args []string) {
var err error
if err := validation.ValidateMixedArguments(cmd.Flags()); err != nil { if err := validation.ValidateMixedArguments(cmd.Flags()); err != nil {
kubeadmutil.CheckErr(err) kubeadmutil.CheckErr(err)
} }
if cfg.FeatureGates, err = features.NewFeatureGate(&features.InitFeatureGates, *featureGatesString); err != nil {
kubeadmutil.CheckErr(err)
}
internalcfg := &kubeadmapi.MasterConfiguration{} internalcfg := &kubeadmapi.MasterConfiguration{}
legacyscheme.Scheme.Convert(cfg, internalcfg, nil) legacyscheme.Scheme.Convert(cfg, internalcfg, nil)
client, err := kubeconfigutil.ClientSetFromFile(*kubeConfigFile) client, err := kubeconfigutil.ClientSetFromFile(*kubeConfigFile)
kubeadmutil.CheckErr(err) kubeadmutil.CheckErr(err)
internalcfg, err = configutil.ConfigFileAndDefaultsToInternalConfig(*cfgPath, cfg) internalcfg, err = configutil.ConfigFileAndDefaultsToInternalConfig(*cfgPath, cfg)
kubeadmutil.CheckErr(err) kubeadmutil.CheckErr(err)
if err := features.ValidateVersion(features.InitFeatureGates, internalcfg.FeatureGates, internalcfg.KubernetesVersion); err != nil {
kubeadmutil.CheckErr(err)
}
// Execute the cmdFunc // Execute the cmdFunc
err = cmdFunc(internalcfg, client) err = cmdFunc(internalcfg, client)

View File

@ -16,6 +16,7 @@ go_library(
"//cmd/kubeadm/app/apis/kubeadm/validation:go_default_library", "//cmd/kubeadm/app/apis/kubeadm/validation:go_default_library",
"//cmd/kubeadm/app/cmd/util:go_default_library", "//cmd/kubeadm/app/cmd/util:go_default_library",
"//cmd/kubeadm/app/constants:go_default_library", "//cmd/kubeadm/app/constants:go_default_library",
"//cmd/kubeadm/app/features:go_default_library",
"//cmd/kubeadm/app/phases/controlplane:go_default_library", "//cmd/kubeadm/app/phases/controlplane:go_default_library",
"//cmd/kubeadm/app/phases/upgrade:go_default_library", "//cmd/kubeadm/app/phases/upgrade:go_default_library",
"//cmd/kubeadm/app/preflight:go_default_library", "//cmd/kubeadm/app/preflight:go_default_library",

View File

@ -119,7 +119,7 @@ func NewCmdApply(parentFlags *cmdUpgradeFlags) *cobra.Command {
func RunApply(flags *applyFlags) error { func RunApply(flags *applyFlags) error {
// Start with the basics, verify that the cluster is healthy and get the configuration from the cluster (using the ConfigMap) // Start with the basics, verify that the cluster is healthy and get the configuration from the cluster (using the ConfigMap)
upgradeVars, err := enforceRequirements(flags.parent.kubeConfigPath, flags.parent.cfgPath, flags.parent.printConfig, flags.dryRun) upgradeVars, err := enforceRequirements(flags.parent.featureGatesString, flags.parent.kubeConfigPath, flags.parent.cfgPath, flags.parent.printConfig, flags.dryRun)
if err != nil { if err != nil {
return err return err
} }

View File

@ -30,6 +30,7 @@ import (
fakediscovery "k8s.io/client-go/discovery/fake" fakediscovery "k8s.io/client-go/discovery/fake"
clientset "k8s.io/client-go/kubernetes" clientset "k8s.io/client-go/kubernetes"
kubeadmapiext "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1alpha1" kubeadmapiext "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1alpha1"
"k8s.io/kubernetes/cmd/kubeadm/app/features"
"k8s.io/kubernetes/cmd/kubeadm/app/phases/upgrade" "k8s.io/kubernetes/cmd/kubeadm/app/phases/upgrade"
"k8s.io/kubernetes/cmd/kubeadm/app/preflight" "k8s.io/kubernetes/cmd/kubeadm/app/preflight"
"k8s.io/kubernetes/cmd/kubeadm/app/util/apiclient" "k8s.io/kubernetes/cmd/kubeadm/app/util/apiclient"
@ -47,7 +48,7 @@ type upgradeVariables struct {
} }
// enforceRequirements verifies that it's okay to upgrade and then returns the variables needed for the rest of the procedure // enforceRequirements verifies that it's okay to upgrade and then returns the variables needed for the rest of the procedure
func enforceRequirements(kubeConfigPath, cfgPath string, printConfig, dryRun bool) (*upgradeVariables, error) { func enforceRequirements(featureGatesString, kubeConfigPath, cfgPath string, printConfig, dryRun bool) (*upgradeVariables, error) {
client, err := getClient(kubeConfigPath, dryRun) client, err := getClient(kubeConfigPath, dryRun)
if err != nil { if err != nil {
return nil, fmt.Errorf("couldn't create a Kubernetes client from file %q: %v", kubeConfigPath, err) return nil, fmt.Errorf("couldn't create a Kubernetes client from file %q: %v", kubeConfigPath, err)
@ -69,6 +70,14 @@ func enforceRequirements(kubeConfigPath, cfgPath string, printConfig, dryRun boo
printConfiguration(cfg, os.Stdout) printConfiguration(cfg, os.Stdout)
} }
cfg.FeatureGates, err = features.NewFeatureGate(&features.InitFeatureGates, featureGatesString)
if err != nil {
return nil, fmt.Errorf("[upgrade/config] FATAL: %v", err)
}
if err := features.ValidateVersion(features.InitFeatureGates, cfg.FeatureGates, cfg.KubernetesVersion); err != nil {
return nil, err
}
return &upgradeVariables{ return &upgradeVariables{
client: client, client: client,
cfg: cfg, cfg: cfg,

View File

@ -26,6 +26,7 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
"k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/validation" "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/validation"
"k8s.io/kubernetes/cmd/kubeadm/app/features"
"k8s.io/kubernetes/cmd/kubeadm/app/phases/upgrade" "k8s.io/kubernetes/cmd/kubeadm/app/phases/upgrade"
kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util" kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util"
) )
@ -53,29 +54,29 @@ func NewCmdPlan(parentFlags *cmdUpgradeFlags) *cobra.Command {
// RunPlan takes care of outputting available versions to upgrade to for the user // RunPlan takes care of outputting available versions to upgrade to for the user
func RunPlan(parentFlags *cmdUpgradeFlags) error { func RunPlan(parentFlags *cmdUpgradeFlags) error {
// Start with the basics, verify that the cluster is healthy, build a client and a versionGetter. Never set dry-run for plan. // Start with the basics, verify that the cluster is healthy, build a client and a versionGetter. Never set dry-run for plan.
upgradeVars, err := enforceRequirements(parentFlags.kubeConfigPath, parentFlags.cfgPath, parentFlags.printConfig, false) upgradeVars, err := enforceRequirements(parentFlags.featureGatesString, parentFlags.kubeConfigPath, parentFlags.cfgPath, parentFlags.printConfig, false)
if err != nil { if err != nil {
return err return err
} }
// Define Local Etcd cluster to be able to retrieve information // Define Local Etcd cluster to be able to retrieve information
etcdCluster := kubeadmutil.LocalEtcdCluster{} etcdCluster := kubeadmutil.LocalEtcdCluster{}
// Compute which upgrade possibilities there are // Compute which upgrade possibilities there are
availUpgrades, err := upgrade.GetAvailableUpgrades(upgradeVars.versionGetter, parentFlags.allowExperimentalUpgrades, parentFlags.allowRCUpgrades, etcdCluster) availUpgrades, err := upgrade.GetAvailableUpgrades(upgradeVars.versionGetter, parentFlags.allowExperimentalUpgrades, parentFlags.allowRCUpgrades, etcdCluster, upgradeVars.cfg.FeatureGates)
if err != nil { if err != nil {
return fmt.Errorf("[upgrade/versions] FATAL: %v", err) return fmt.Errorf("[upgrade/versions] FATAL: %v", err)
} }
// Tell the user which upgrades are available // Tell the user which upgrades are available
printAvailableUpgrades(availUpgrades, os.Stdout) printAvailableUpgrades(availUpgrades, os.Stdout, upgradeVars.cfg.FeatureGates)
return nil return nil
} }
// printAvailableUpgrades prints a UX-friendly overview of what versions are available to upgrade to // 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 // TODO look into columnize or some other formatter when time permits instead of using the tabwriter
func printAvailableUpgrades(upgrades []upgrade.Upgrade, w io.Writer) { func printAvailableUpgrades(upgrades []upgrade.Upgrade, w io.Writer, featureGates map[string]bool) {
// Return quickly if no upgrades can be made // Return quickly if no upgrades can be made
if len(upgrades) == 0 { if len(upgrades) == 0 {
@ -117,7 +118,11 @@ func printAvailableUpgrades(upgrades []upgrade.Upgrade, w io.Writer) {
fmt.Fprintf(tabw, "Controller Manager\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, "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) fmt.Fprintf(tabw, "Kube Proxy\t%s\t%s\n", upgrade.Before.KubeVersion, upgrade.After.KubeVersion)
fmt.Fprintf(tabw, "Kube DNS\t%s\t%s\n", upgrade.Before.DNSVersion, upgrade.After.DNSVersion) if features.Enabled(featureGates, features.CoreDNS) {
fmt.Fprintf(tabw, "CoreDNS\t%s\t%s\n", upgrade.Before.DNSVersion, upgrade.After.DNSVersion)
} else {
fmt.Fprintf(tabw, "Kube DNS\t%s\t%s\n", upgrade.Before.DNSVersion, upgrade.After.DNSVersion)
}
fmt.Fprintf(tabw, "Etcd\t%s\t%s\n", upgrade.Before.EtcdVersion, upgrade.After.EtcdVersion) 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. // 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.

View File

@ -60,6 +60,7 @@ func TestSortedSliceFromStringIntMap(t *testing.T) {
// TODO Think about modifying this test to be less verbose checking b/c it can be brittle. // TODO Think about modifying this test to be less verbose checking b/c it can be brittle.
func TestPrintAvailableUpgrades(t *testing.T) { func TestPrintAvailableUpgrades(t *testing.T) {
featureGates := make(map[string]bool)
var tests = []struct { var tests = []struct {
upgrades []upgrade.Upgrade upgrades []upgrade.Upgrade
buf *bytes.Buffer buf *bytes.Buffer
@ -334,7 +335,7 @@ _____________________________________________________________________
} }
for _, rt := range tests { for _, rt := range tests {
rt.buf = bytes.NewBufferString("") rt.buf = bytes.NewBufferString("")
printAvailableUpgrades(rt.upgrades, rt.buf) printAvailableUpgrades(rt.upgrades, rt.buf, featureGates)
actualBytes := rt.buf.Bytes() actualBytes := rt.buf.Bytes()
if !bytes.Equal(actualBytes, rt.expectedBytes) { if !bytes.Equal(actualBytes, rt.expectedBytes) {
t.Errorf( t.Errorf(

View File

@ -18,16 +18,19 @@ package upgrade
import ( import (
"io" "io"
"strings"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"k8s.io/apimachinery/pkg/util/sets" "k8s.io/apimachinery/pkg/util/sets"
cmdutil "k8s.io/kubernetes/cmd/kubeadm/app/cmd/util" cmdutil "k8s.io/kubernetes/cmd/kubeadm/app/cmd/util"
"k8s.io/kubernetes/cmd/kubeadm/app/features"
) )
// cmdUpgradeFlags holds the values for the common flags in `kubeadm upgrade` // cmdUpgradeFlags holds the values for the common flags in `kubeadm upgrade`
type cmdUpgradeFlags struct { type cmdUpgradeFlags struct {
kubeConfigPath string kubeConfigPath string
cfgPath string cfgPath string
featureGatesString string
allowExperimentalUpgrades bool allowExperimentalUpgrades bool
allowRCUpgrades bool allowRCUpgrades bool
printConfig bool printConfig bool
@ -41,6 +44,7 @@ func NewCmdUpgrade(out io.Writer) *cobra.Command {
flags := &cmdUpgradeFlags{ flags := &cmdUpgradeFlags{
kubeConfigPath: "/etc/kubernetes/admin.conf", kubeConfigPath: "/etc/kubernetes/admin.conf",
cfgPath: "", cfgPath: "",
featureGatesString: "",
allowExperimentalUpgrades: false, allowExperimentalUpgrades: false,
allowRCUpgrades: false, allowRCUpgrades: false,
printConfig: false, printConfig: false,
@ -62,6 +66,8 @@ func NewCmdUpgrade(out io.Writer) *cobra.Command {
cmd.PersistentFlags().StringSliceVar(&flags.ignoreChecksErrors, "ignore-checks-errors", flags.ignoreChecksErrors, "A list of checks whose errors will be shown as warnings. Example: 'IsPrivilegedUser,Swap'. Value 'all' ignores errors from all checks.") cmd.PersistentFlags().StringSliceVar(&flags.ignoreChecksErrors, "ignore-checks-errors", flags.ignoreChecksErrors, "A list of checks whose errors will be shown as warnings. Example: 'IsPrivilegedUser,Swap'. Value 'all' ignores errors from all checks.")
cmd.PersistentFlags().BoolVar(&flags.skipPreFlight, "skip-preflight-checks", flags.skipPreFlight, "Skip preflight checks that normally run before modifying the system.") cmd.PersistentFlags().BoolVar(&flags.skipPreFlight, "skip-preflight-checks", flags.skipPreFlight, "Skip preflight checks that normally run before modifying the system.")
cmd.PersistentFlags().MarkDeprecated("skip-preflight-checks", "it is now equivalent to --ignore-checks-errors=all") cmd.PersistentFlags().MarkDeprecated("skip-preflight-checks", "it is now equivalent to --ignore-checks-errors=all")
cmd.PersistentFlags().StringVar(&flags.featureGatesString, "feature-gates", flags.featureGatesString, "A set of key=value pairs that describe feature gates for various features."+
"Options are:\n"+strings.Join(features.KnownFeatures(&features.InitFeatureGates), "\n"))
cmd.AddCommand(NewCmdApply(flags)) cmd.AddCommand(NewCmdApply(flags))
cmd.AddCommand(NewCmdPlan(flags)) cmd.AddCommand(NewCmdPlan(flags))

View File

@ -196,7 +196,7 @@ const (
DefaultCIImageRepository = "gcr.io/kubernetes-ci-images" DefaultCIImageRepository = "gcr.io/kubernetes-ci-images"
// CoreDNS defines a variable used internally when referring to the CoreDNS addon for a cluster // CoreDNS defines a variable used internally when referring to the CoreDNS addon for a cluster
CoreDNS = "CoreDNS" CoreDNS = "coredns"
// KubeDNS defines a variable used internally when referring to the kube-dns addon for a cluster // KubeDNS defines a variable used internally when referring to the kube-dns addon for a cluster
KubeDNS = "kube-dns" KubeDNS = "kube-dns"
) )

View File

@ -21,6 +21,7 @@ go_library(
"//cmd/kubeadm/app/apis/kubeadm/v1alpha1:go_default_library", "//cmd/kubeadm/app/apis/kubeadm/v1alpha1:go_default_library",
"//cmd/kubeadm/app/apis/kubeadm/validation:go_default_library", "//cmd/kubeadm/app/apis/kubeadm/validation:go_default_library",
"//cmd/kubeadm/app/constants:go_default_library", "//cmd/kubeadm/app/constants:go_default_library",
"//cmd/kubeadm/app/features:go_default_library",
"//cmd/kubeadm/app/images:go_default_library", "//cmd/kubeadm/app/images:go_default_library",
"//cmd/kubeadm/app/phases/addons/dns:go_default_library", "//cmd/kubeadm/app/phases/addons/dns:go_default_library",
"//cmd/kubeadm/app/phases/addons/proxy:go_default_library", "//cmd/kubeadm/app/phases/addons/proxy:go_default_library",

View File

@ -21,6 +21,7 @@ import (
"strings" "strings"
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants" kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
"k8s.io/kubernetes/cmd/kubeadm/app/features"
"k8s.io/kubernetes/cmd/kubeadm/app/phases/addons/dns" "k8s.io/kubernetes/cmd/kubeadm/app/phases/addons/dns"
"k8s.io/kubernetes/cmd/kubeadm/app/util" "k8s.io/kubernetes/cmd/kubeadm/app/util"
"k8s.io/kubernetes/pkg/util/version" "k8s.io/kubernetes/pkg/util/version"
@ -49,6 +50,14 @@ func (u *Upgrade) CanUpgradeKubelets() bool {
return !sameVersionFound return !sameVersionFound
} }
// ActiveDNSAddon returns the version of CoreDNS or kube-dns
func ActiveDNSAddon(featureGates map[string]bool) string {
if features.Enabled(featureGates, features.CoreDNS) {
return kubeadmconstants.CoreDNS
}
return kubeadmconstants.KubeDNS
}
// ClusterState describes the state of certain versions for a cluster // ClusterState describes the state of certain versions for a cluster
type ClusterState struct { type ClusterState struct {
// KubeVersion describes the version of the Kubernetes API Server, Controller Manager, Scheduler and Proxy. // KubeVersion describes the version of the Kubernetes API Server, Controller Manager, Scheduler and Proxy.
@ -65,7 +74,7 @@ type ClusterState struct {
// GetAvailableUpgrades fetches all versions from the specified VersionGetter and computes which // GetAvailableUpgrades fetches all versions from the specified VersionGetter and computes which
// kinds of upgrades can be performed // kinds of upgrades can be performed
func GetAvailableUpgrades(versionGetterImpl VersionGetter, experimentalUpgradesAllowed, rcUpgradesAllowed bool, cluster util.EtcdCluster) ([]Upgrade, error) { func GetAvailableUpgrades(versionGetterImpl VersionGetter, experimentalUpgradesAllowed, rcUpgradesAllowed bool, cluster util.EtcdCluster, featureGates map[string]bool) ([]Upgrade, error) {
fmt.Println("[upgrade] Fetching available versions to upgrade to") fmt.Println("[upgrade] Fetching available versions to upgrade to")
// Collect the upgrades kubeadm can do in this list // Collect the upgrades kubeadm can do in this list
@ -104,10 +113,9 @@ func GetAvailableUpgrades(versionGetterImpl VersionGetter, experimentalUpgradesA
} }
// Construct a descriptor for the current state of the world // Construct a descriptor for the current state of the world
// TODO: Make CoreDNS available here.
beforeState := ClusterState{ beforeState := ClusterState{
KubeVersion: clusterVersionStr, KubeVersion: clusterVersionStr,
DNSVersion: dns.GetDNSVersion(clusterVersion, kubeadmconstants.KubeDNS), DNSVersion: dns.GetDNSVersion(clusterVersion, ActiveDNSAddon(featureGates)),
KubeadmVersion: kubeadmVersionStr, KubeadmVersion: kubeadmVersionStr,
KubeletVersions: kubeletVersions, KubeletVersions: kubeletVersions,
EtcdVersion: etcdStatus.Version, EtcdVersion: etcdStatus.Version,
@ -150,7 +158,7 @@ func GetAvailableUpgrades(versionGetterImpl VersionGetter, experimentalUpgradesA
Before: beforeState, Before: beforeState,
After: ClusterState{ After: ClusterState{
KubeVersion: patchVersionStr, KubeVersion: patchVersionStr,
DNSVersion: dns.GetDNSVersion(patchVersion, kubeadmconstants.KubeDNS), DNSVersion: dns.GetDNSVersion(patchVersion, ActiveDNSAddon(featureGates)),
KubeadmVersion: newKubeadmVer, KubeadmVersion: newKubeadmVer,
EtcdVersion: getSuggestedEtcdVersion(patchVersionStr), EtcdVersion: getSuggestedEtcdVersion(patchVersionStr),
// KubeletVersions is unset here as it is not used anywhere in .After // KubeletVersions is unset here as it is not used anywhere in .After
@ -166,7 +174,7 @@ func GetAvailableUpgrades(versionGetterImpl VersionGetter, experimentalUpgradesA
Before: beforeState, Before: beforeState,
After: ClusterState{ After: ClusterState{
KubeVersion: stableVersionStr, KubeVersion: stableVersionStr,
DNSVersion: dns.GetDNSVersion(stableVersion, kubeadmconstants.KubeDNS), DNSVersion: dns.GetDNSVersion(stableVersion, ActiveDNSAddon(featureGates)),
KubeadmVersion: stableVersionStr, KubeadmVersion: stableVersionStr,
EtcdVersion: getSuggestedEtcdVersion(stableVersionStr), EtcdVersion: getSuggestedEtcdVersion(stableVersionStr),
// KubeletVersions is unset here as it is not used anywhere in .After // KubeletVersions is unset here as it is not used anywhere in .After
@ -211,7 +219,7 @@ func GetAvailableUpgrades(versionGetterImpl VersionGetter, experimentalUpgradesA
Before: beforeState, Before: beforeState,
After: ClusterState{ After: ClusterState{
KubeVersion: previousBranchLatestVersionStr, KubeVersion: previousBranchLatestVersionStr,
DNSVersion: dns.GetDNSVersion(previousBranchLatestVersion, kubeadmconstants.KubeDNS), DNSVersion: dns.GetDNSVersion(previousBranchLatestVersion, ActiveDNSAddon(featureGates)),
KubeadmVersion: previousBranchLatestVersionStr, KubeadmVersion: previousBranchLatestVersionStr,
EtcdVersion: getSuggestedEtcdVersion(previousBranchLatestVersionStr), EtcdVersion: getSuggestedEtcdVersion(previousBranchLatestVersionStr),
// KubeletVersions is unset here as it is not used anywhere in .After // KubeletVersions is unset here as it is not used anywhere in .After
@ -224,12 +232,12 @@ func GetAvailableUpgrades(versionGetterImpl VersionGetter, experimentalUpgradesA
// Default to assume that the experimental version to show is the unstable one // Default to assume that the experimental version to show is the unstable one
unstableKubeVersion := latestVersionStr unstableKubeVersion := latestVersionStr
unstableKubeDNSVersion := dns.GetDNSVersion(latestVersion, kubeadmconstants.KubeDNS) unstableKubeDNSVersion := dns.GetDNSVersion(latestVersion, ActiveDNSAddon(featureGates))
// Ẃe should not display alpha.0. The previous branch's beta/rc versions are more relevant due how the kube branching process works. // Ẃe should not display alpha.0. The previous branch's beta/rc versions are more relevant due how the kube branching process works.
if latestVersion.PreRelease() == "alpha.0" { if latestVersion.PreRelease() == "alpha.0" {
unstableKubeVersion = previousBranchLatestVersionStr unstableKubeVersion = previousBranchLatestVersionStr
unstableKubeDNSVersion = dns.GetDNSVersion(previousBranchLatestVersion, kubeadmconstants.KubeDNS) unstableKubeDNSVersion = dns.GetDNSVersion(previousBranchLatestVersion, ActiveDNSAddon(featureGates))
} }
upgrades = append(upgrades, Upgrade{ upgrades = append(upgrades, Upgrade{

View File

@ -69,6 +69,7 @@ func (f fakeEtcdCluster) GetEtcdClusterStatus() (*clientv3.StatusResponse, error
} }
func TestGetAvailableUpgrades(t *testing.T) { func TestGetAvailableUpgrades(t *testing.T) {
featureGates := make(map[string]bool)
tests := []struct { tests := []struct {
vg *fakeVersionGetter vg *fakeVersionGetter
expectedUpgrades []Upgrade expectedUpgrades []Upgrade
@ -444,7 +445,7 @@ func TestGetAvailableUpgrades(t *testing.T) {
testCluster := fakeEtcdCluster{} testCluster := fakeEtcdCluster{}
for _, rt := range tests { for _, rt := range tests {
actualUpgrades, actualErr := GetAvailableUpgrades(rt.vg, rt.allowExperimental, rt.allowRCs, testCluster) actualUpgrades, actualErr := GetAvailableUpgrades(rt.vg, rt.allowExperimental, rt.allowRCs, testCluster, featureGates)
if !reflect.DeepEqual(actualUpgrades, rt.expectedUpgrades) { if !reflect.DeepEqual(actualUpgrades, rt.expectedUpgrades) {
t.Errorf("failed TestGetAvailableUpgrades\n\texpected upgrades: %v\n\tgot: %v", rt.expectedUpgrades, actualUpgrades) t.Errorf("failed TestGetAvailableUpgrades\n\texpected upgrades: %v\n\tgot: %v", rt.expectedUpgrades, actualUpgrades)
} }

View File

@ -19,16 +19,20 @@ package upgrade
import ( import (
"fmt" "fmt"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/errors" "k8s.io/apimachinery/pkg/util/errors"
clientset "k8s.io/client-go/kubernetes" clientset "k8s.io/client-go/kubernetes"
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm" kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
kubeadmapiext "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1alpha1" kubeadmapiext "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1alpha1"
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
"k8s.io/kubernetes/cmd/kubeadm/app/features"
"k8s.io/kubernetes/cmd/kubeadm/app/phases/addons/dns" "k8s.io/kubernetes/cmd/kubeadm/app/phases/addons/dns"
"k8s.io/kubernetes/cmd/kubeadm/app/phases/addons/proxy" "k8s.io/kubernetes/cmd/kubeadm/app/phases/addons/proxy"
"k8s.io/kubernetes/cmd/kubeadm/app/phases/bootstraptoken/clusterinfo" "k8s.io/kubernetes/cmd/kubeadm/app/phases/bootstraptoken/clusterinfo"
nodebootstraptoken "k8s.io/kubernetes/cmd/kubeadm/app/phases/bootstraptoken/node" nodebootstraptoken "k8s.io/kubernetes/cmd/kubeadm/app/phases/bootstraptoken/node"
certsphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/certs" certsphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/certs"
"k8s.io/kubernetes/cmd/kubeadm/app/phases/uploadconfig" "k8s.io/kubernetes/cmd/kubeadm/app/phases/uploadconfig"
"k8s.io/kubernetes/cmd/kubeadm/app/util/apiclient"
"k8s.io/kubernetes/pkg/util/version" "k8s.io/kubernetes/pkg/util/version"
) )
@ -88,8 +92,33 @@ func PerformPostUpgradeTasks(client clientset.Interface, cfg *kubeadmapi.MasterC
if err := dns.EnsureDNSAddon(cfg, client); err != nil { if err := dns.EnsureDNSAddon(cfg, client); err != nil {
errs = append(errs, err) errs = append(errs, err)
} }
if err := coreDNSDeployment(cfg, client); err != nil {
errs = append(errs, err)
}
if err := proxy.EnsureProxyAddon(cfg, client); err != nil { if err := proxy.EnsureProxyAddon(cfg, client); err != nil {
errs = append(errs, err) errs = append(errs, err)
} }
return errors.NewAggregate(errs) return errors.NewAggregate(errs)
} }
func coreDNSDeployment(cfg *kubeadmapi.MasterConfiguration, client clientset.Interface) error {
if features.Enabled(cfg.FeatureGates, features.CoreDNS) {
return apiclient.TryRunCommand(func() error {
getCoreDNS, err := client.AppsV1beta2().Deployments(metav1.NamespaceSystem).Get(kubeadmconstants.CoreDNS, metav1.GetOptions{})
if err != nil {
return err
}
if getCoreDNS.Status.ReadyReplicas == 0 {
return fmt.Errorf("the CodeDNS deployment isn't ready yet")
}
err = client.AppsV1beta2().Deployments(metav1.NamespaceSystem).Delete(kubeadmconstants.KubeDNS, nil)
if err != nil {
return err
}
return nil
}, 5)
}
return nil
}