kubeadm: improve some grammar issues and add some unit test cases

This commit is contained in:
SataQiu 2024-08-15 18:05:38 +08:00
parent 595482d264
commit a2f8d31c65
9 changed files with 185 additions and 102 deletions

View File

@ -18,32 +18,27 @@ limitations under the License.
package apply
import (
"context"
"fmt"
"io"
"github.com/pkg/errors"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
clientset "k8s.io/client-go/kubernetes"
"k8s.io/klog/v2"
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
"k8s.io/kubernetes/cmd/kubeadm/app/cmd/options"
"k8s.io/kubernetes/cmd/kubeadm/app/cmd/phases/workflow"
cmdutil "k8s.io/kubernetes/cmd/kubeadm/app/cmd/util"
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
dnsaddon "k8s.io/kubernetes/cmd/kubeadm/app/phases/addons/dns"
proxyaddon "k8s.io/kubernetes/cmd/kubeadm/app/phases/addons/proxy"
"k8s.io/kubernetes/cmd/kubeadm/app/phases/upgrade"
)
// NewAddonPhase returns the addon Cobra command
// NewAddonPhase returns a new addon phase.
func NewAddonPhase() workflow.Phase {
return workflow.Phase{
Name: "addon",
Short: "Install required addons for passing conformance tests",
Short: "Install the default kubeadm addons",
Long: cmdutil.MacroCommandLongDescription,
Phases: []workflow.Phase{
{
@ -54,13 +49,13 @@ func NewAddonPhase() workflow.Phase {
},
{
Name: "coredns",
Short: "Install the CoreDNS addon to a Kubernetes cluster",
Short: "Install the CoreDNS addon",
InheritFlags: getAddonPhaseFlags("coredns"),
Run: runCoreDNSAddon,
},
{
Name: "kube-proxy",
Short: "Install the kube-proxy addon to a Kubernetes cluster",
Short: "Install the kube-proxy addon",
InheritFlags: getAddonPhaseFlags("kube-proxy"),
Run: runKubeProxyAddon,
},
@ -74,10 +69,9 @@ func shouldUpgradeAddons(client clientset.Interface, cfg *kubeadmapi.InitConfigu
return false, errors.Wrapf(err, "failed to determine whether all the control plane instances have been upgraded")
}
if len(unupgradedControlPlanes) > 0 {
fmt.Fprintf(out, "[upgrade/addons] skip upgrade addons because control plane instances %v have not been upgraded\n", unupgradedControlPlanes)
fmt.Fprintf(out, "[upgrade/addons] Skipping upgrade of addons because control plane instances %v have not been upgraded\n", unupgradedControlPlanes)
return false, nil
}
return true, nil
}
@ -89,7 +83,7 @@ func getInitData(c workflow.RunData) (*kubeadmapi.InitConfiguration, clientset.I
return data.InitCfg(), data.Client(), data.PatchesDir(), data.OutputWriter(), data.DryRun(), nil
}
// runCoreDNSAddon installs CoreDNS addon to a Kubernetes cluster
// runCoreDNSAddon installs the CoreDNS addon.
func runCoreDNSAddon(c workflow.RunData) error {
cfg, client, patchesDir, out, dryRun, err := getInitData(c)
if err != nil {
@ -104,25 +98,6 @@ func runCoreDNSAddon(c workflow.RunData) error {
return nil
}
// If the coredns ConfigMap is missing, show a warning and assume that the
// DNS addon was skipped during "kubeadm init", and that its redeployment on upgrade is not desired.
//
// TODO: remove this once "kubeadm upgrade apply" phases are supported:
// https://github.com/kubernetes/kubeadm/issues/1318
if _, err := client.CoreV1().ConfigMaps(metav1.NamespaceSystem).Get(
context.TODO(),
kubeadmconstants.CoreDNSConfigMap,
metav1.GetOptions{},
); err != nil && apierrors.IsNotFound(err) {
klog.Warningf("the ConfigMaps %q in the namespace %q were not found. "+
"Assuming that a DNS server was not deployed for this cluster. "+
"Note that once 'kubeadm upgrade apply' supports phases you "+
"will have to skip the DNS upgrade manually",
kubeadmconstants.CoreDNSConfigMap,
metav1.NamespaceSystem)
return nil
}
// Upgrade CoreDNS
if err := dnsaddon.EnsureDNSAddon(&cfg.ClusterConfiguration, client, patchesDir, out, dryRun); err != nil {
return err
@ -131,7 +106,7 @@ func runCoreDNSAddon(c workflow.RunData) error {
return nil
}
// runKubeProxyAddon installs KubeProxy addon to a Kubernetes cluster
// runKubeProxyAddon installs the KubeProxy addon.
func runKubeProxyAddon(c workflow.RunData) error {
cfg, client, _, out, dryRun, err := getInitData(c)
if err != nil {
@ -146,25 +121,6 @@ func runKubeProxyAddon(c workflow.RunData) error {
return nil
}
// If the kube-proxy ConfigMap is missing, show a warning and assume that kube-proxy
// was skipped during "kubeadm init", and that its redeployment on upgrade is not desired.
//
// TODO: remove this once "kubeadm upgrade apply" phases are supported:
// https://github.com/kubernetes/kubeadm/issues/1318
if _, err := client.CoreV1().ConfigMaps(metav1.NamespaceSystem).Get(
context.TODO(),
kubeadmconstants.KubeProxyConfigMap,
metav1.GetOptions{},
); err != nil && apierrors.IsNotFound(err) {
klog.Warningf("the ConfigMap %q in the namespace %q was not found. "+
"Assuming that kube-proxy was not deployed for this cluster. "+
"Note that once 'kubeadm upgrade apply' supports phases you "+
"will have to skip the kube-proxy upgrade manually",
kubeadmconstants.KubeProxyConfigMap,
metav1.NamespaceSystem)
return nil
}
// Upgrade kube-proxy
if err := proxyaddon.EnsureProxyAddon(&cfg.ClusterConfiguration, &cfg.LocalAPIEndpoint, client, out, dryRun); err != nil {
return err

View File

@ -30,12 +30,11 @@ import (
nodebootstraptoken "k8s.io/kubernetes/cmd/kubeadm/app/phases/bootstraptoken/node"
)
// NewBootstrapTokenPhase returns the phase to bootstrapToken
// NewBootstrapTokenPhase returns a new bootstrap-token phase.
func NewBootstrapTokenPhase() workflow.Phase {
return workflow.Phase{
Name: "bootstrap-token",
Aliases: []string{"bootstraptoken"},
Short: "Generates bootstrap tokens used to join a node to a cluster",
Name: "bootstrap-token",
Short: "Configures bootstrap token and cluster-info RBAC rules",
InheritFlags: []string{
options.CfgPath,
options.KubeconfigPath,
@ -56,7 +55,7 @@ func runBootstrapToken(c workflow.RunData) error {
return nil
}
fmt.Println("[bootstrap-token] Configuring cluster-info ConfigMap, RBAC Roles")
fmt.Println("[bootstrap-token] Configuring the cluster-info ConfigMap and RBAC roles")
client := data.Client()

View File

@ -29,7 +29,7 @@ import (
"k8s.io/kubernetes/cmd/kubeadm/app/util/apiclient"
)
// NewControlPlanePhase creates a kubeadm workflow phase that implements handling of control-plane upgrade.
// NewControlPlanePhase returns a new control-plane phase.
func NewControlPlanePhase() workflow.Phase {
phase := workflow.Phase{
Name: "control-plane",

View File

@ -28,7 +28,7 @@ import (
"k8s.io/kubernetes/cmd/kubeadm/app/phases/upgrade"
)
// NewKubeconfigPhase creates a kubeadm workflow phase that implements handling of kubeconfig upgrade.
// NewKubeconfigPhase returns a new kubeconfig phase.
func NewKubeconfigPhase() workflow.Phase {
phase := workflow.Phase{
Name: "kubeconfig",
@ -59,7 +59,7 @@ func runKubeconfig() func(c workflow.RunData) error {
}
}
fmt.Println("[upgrade] The kubeconfig for this node was successfully updated!")
fmt.Println("[upgrade] The kubeconfig files for this node were successfully updated!")
return nil
}

View File

@ -34,7 +34,7 @@ var (
`)
)
// NewKubeletConfigPhase creates a kubeadm workflow phase that implements handling of kubelet-config upgrade.
// NewKubeletConfigPhase returns a new kubelet-config phase.
func NewKubeletConfigPhase() workflow.Phase {
phase := workflow.Phase{
Name: "kubelet-config",
@ -59,15 +59,14 @@ func runKubeletConfigPhase(c workflow.RunData) error {
initCfg, dryRun := data.InitCfg(), data.DryRun()
// Write the configuration for the kubelet down to disk and print the generated manifests instead if dry-running.
// Write the configuration for the kubelet down to disk and print the generated manifests instead of dry-running.
// If not dry-running, the kubelet config file will be backed up to /etc/kubernetes/tmp/ dir, so that it could be
// recovered if there is anything goes wrong.
// recovered if anything goes wrong.
err := upgrade.WriteKubeletConfigFiles(initCfg, data.PatchesDir(), dryRun, data.OutputWriter())
if err != nil {
return err
}
fmt.Println("[upgrade] The configuration for this node was successfully updated!")
fmt.Println("[upgrade] Now you should go ahead and upgrade the kubelet package using your package manager.")
fmt.Println("[upgrade] The kubelet configuration for this node was successfully updated!")
return nil
}

View File

@ -38,12 +38,12 @@ import (
"k8s.io/kubernetes/cmd/kubeadm/app/util/output"
)
// NewPreflightPhase creates a kubeadm workflow phase that implements preflight checks for kubeadm upgrade apply.
// NewPreflightPhase returns a new prefight phase.
func NewPreflightPhase() workflow.Phase {
return workflow.Phase{
Name: "preflight",
Short: "Run upgrade apply pre-flight checks",
Long: "Run pre-flight checks for kubeadm upgrade apply.",
Short: "Run upgrade apply preflight checks",
Long: "Run preflight checks for kubeadm upgrade apply.",
Run: runPreflight,
InheritFlags: []string{
options.CfgPath,
@ -58,13 +58,12 @@ func NewPreflightPhase() workflow.Phase {
}
}
// runPreflight executes preflight checks logic.
func runPreflight(c workflow.RunData) error {
data, ok := c.(Data)
if !ok {
return errors.New("preflight phase invoked with an invalid data struct")
}
fmt.Println("[preflight] Running pre-flight checks")
fmt.Println("[preflight] Running preflight checks")
printer := &output.TextPrinter{}
@ -81,7 +80,7 @@ func runPreflight(c workflow.RunData) error {
}
// Run healthchecks against the cluster
klog.V(1).Infoln("[upgrade/apply] verifying health of cluster")
klog.V(1).Infoln("[upgrade/apply] Verifying the cluster health")
if err := upgrade.CheckClusterHealth(client, &initCfg.ClusterConfiguration, ignorePreflightErrors, printer); err != nil {
return err
}
@ -94,7 +93,7 @@ func runPreflight(c workflow.RunData) error {
}
// Validate requested and validate actual version
klog.V(1).Infoln("[upgrade/apply] validating requested and actual version")
klog.V(1).Infoln("[upgrade/apply] Validating requested and actual version")
if err := configutil.NormalizeKubernetesVersion(&initCfg.ClusterConfiguration); err != nil {
return err
}
@ -110,7 +109,7 @@ func runPreflight(c workflow.RunData) error {
}
versionGetter := upgrade.NewOfflineVersionGetter(upgrade.NewKubeVersionGetter(client), initCfg.KubernetesVersion)
if err := EnforceVersionPolicies(initCfg.KubernetesVersion, upgradeVersion, data.AllowExperimentalUpgrades(), data.AllowRCUpgrades(), data.ForceUpgrade(), versionGetter); err != nil {
if err := enforceVersionPolicies(initCfg.KubernetesVersion, upgradeVersion, data.AllowExperimentalUpgrades(), data.AllowRCUpgrades(), data.ForceUpgrade(), versionGetter); err != nil {
return err
}
@ -134,23 +133,23 @@ func runPreflight(c workflow.RunData) error {
return nil
}
// EnforceVersionPolicies makes sure that the version the user specified is valid to upgrade to
// enforceVersionPolicies makes sure that the version the user specified is valid to upgrade to
// There are both fatal and skippable (with --force) errors
func EnforceVersionPolicies(newK8sVersionStr string, newK8sVersion *version.Version, allowExperimentalUpgrades, allowRCUpgrades, force bool, versionGetter upgrade.VersionGetter) error {
fmt.Printf("[upgrade/version] You have chosen to change the cluster version to %q\n", newK8sVersionStr)
func enforceVersionPolicies(newK8sVersionStr string, newK8sVersion *version.Version, allowExperimentalUpgrades, allowRCUpgrades, force bool, versionGetter upgrade.VersionGetter) error {
fmt.Printf("[upgrade/version] You have chosen to upgrade the cluster version to %q\n", newK8sVersionStr)
versionSkewErrs := upgrade.EnforceVersionPolicies(versionGetter, newK8sVersionStr, newK8sVersion, allowExperimentalUpgrades, allowRCUpgrades)
if versionSkewErrs != nil {
if len(versionSkewErrs.Mandatory) > 0 {
return errors.Errorf("the --version argument is invalid due to these fatal errors:\n\n%v\nPlease fix the misalignments highlighted above and try upgrading again",
return errors.Errorf("the version argument is invalid due to these fatal errors:\n\n%v\nPlease fix the misalignments highlighted above and try upgrading again",
kubeadmutil.FormatErrMsg(versionSkewErrs.Mandatory))
}
if len(versionSkewErrs.Skippable) > 0 {
// Return the error if the user hasn't specified the --force flag
if !force {
return errors.Errorf("the --version argument is invalid due to these errors:\n\n%v\nCan be bypassed if you pass the --force flag",
return errors.Errorf("the version argument is invalid due to these errors:\n\n%v\nCan be bypassed if you pass the --force flag",
kubeadmutil.FormatErrMsg(versionSkewErrs.Skippable))
}
// Soft errors found, but --force was specified

View File

@ -39,12 +39,12 @@ func NewUploadConfigPhase() workflow.Phase {
return workflow.Phase{
Name: "upload-config",
Aliases: []string{"uploadconfig"},
Short: "Upload the kubeadm and kubelet configuration to a ConfigMap",
Short: "Upload the kubeadm and kubelet configurations to a ConfigMaps",
Long: cmdutil.MacroCommandLongDescription,
Phases: []workflow.Phase{
{
Name: "all",
Short: "Upload all configuration to a config map",
Short: "Upload all the configurations to ConfigMaps",
RunAllSiblings: true,
InheritFlags: getUploadConfigPhaseFlags(),
},
@ -56,7 +56,7 @@ func NewUploadConfigPhase() workflow.Phase {
},
{
Name: "kubelet",
Short: "Upload the kubelet component config to a ConfigMap",
Short: "Upload the kubelet configuration config to a ConfigMap",
Run: runUploadKubeletConfig,
InheritFlags: getUploadConfigPhaseFlags(),
},
@ -99,19 +99,19 @@ func runUploadKubeletConfig(c workflow.RunData) error {
}
if dryRun {
fmt.Println("[dryrun] Would upload the kubelet component config to a ConfigMap")
fmt.Println("[dryrun] Would upload the kubelet configuration to a ConfigMap")
fmt.Println("[dryrun] Would write the CRISocket annotation for the control-plane node")
return nil
}
klog.V(1).Infoln("[upload-config] Uploading the kubelet component config to a ConfigMap")
klog.V(1).Infoln("[upload-config] Uploading the kubelet configuration to a ConfigMap")
if err = kubeletphase.CreateConfigMap(&cfg.ClusterConfiguration, client); err != nil {
return errors.Wrap(err, "error creating kubelet configuration ConfigMap")
}
klog.V(1).Infoln("[upload-config] Preserving the CRISocket information for the control-plane node")
if err := patchnodephase.AnnotateCRISocket(client, cfg.NodeRegistration.Name, cfg.NodeRegistration.CRISocket); err != nil {
return errors.Wrap(err, "Error writing Crisocket information for the control-plane node")
return errors.Wrap(err, "error writing Crisocket information for the control-plane node")
}
return nil

View File

@ -99,25 +99,21 @@ func newCmdApply(apf *applyPlanFlags) *cobra.Command {
if err != nil {
return err
}
applyData, ok := data.(*applyData)
if !ok {
return errors.New("invalid data struct")
}
if err := applyRunner.Run(args); err != nil {
return err
}
if flags.dryRun {
fmt.Println("[upgrade/successful] Finished dryrunning successfully!")
return nil
}
fmt.Println("")
fmt.Printf("[upgrade/successful] SUCCESS! Your cluster was upgraded to %q. Enjoy!\n", applyData.InitCfg().KubernetesVersion)
fmt.Println("")
fmt.Println("[upgrade/kubelet] Now that your control plane is upgraded, please proceed with upgrading your kubelets if you haven't already done so.")
fmt.Printf("[upgrade/successful] SUCCESS! A control plane node of your cluster was upgraded to %q.\n\n", applyData.InitCfg().KubernetesVersion)
fmt.Println("[upgrade/kubelet] Now please proceed with upgrading the rest of the nodes by following the right order.")
return nil
},
@ -133,7 +129,7 @@ func newCmdApply(apf *applyPlanFlags) *cobra.Command {
cmd.Flags().BoolVar(&flags.renewCerts, options.CertificateRenewal, flags.renewCerts, "Perform the renewal of certificates used by component changed during upgrades.")
options.AddPatchesFlag(cmd.Flags(), &flags.patchesDir)
// initialize the workflow runner with the list of phases
// Initialize the workflow runner with the list of phases
applyRunner.AppendPhase(phases.NewPreflightPhase())
applyRunner.AppendPhase(phases.NewControlPlanePhase())
applyRunner.AppendPhase(phases.NewUploadConfigPhase())
@ -142,7 +138,7 @@ func newCmdApply(apf *applyPlanFlags) *cobra.Command {
applyRunner.AppendPhase(phases.NewBootstrapTokenPhase())
applyRunner.AppendPhase(phases.NewAddonPhase())
// sets the data builder function, that will be used by the runner
// Sets the data builder function, that will be used by the runner
// both when running the entire workflow or single phases
applyRunner.SetDataInitializer(func(cmd *cobra.Command, args []string) (workflow.RunData, error) {
data, err := newApplyData(cmd, args, flags)
@ -156,7 +152,7 @@ func newCmdApply(apf *applyPlanFlags) *cobra.Command {
return data, nil
})
// binds the Runner to kubeadm upgrade apply command by altering
// Binds the Runner to kubeadm upgrade apply command by altering
// command help, adding --skip-phases flag and by adding phases subcommands
applyRunner.BindToCommand(cmd)
@ -173,18 +169,23 @@ func newApplyData(cmd *cobra.Command, args []string, applyFlags *applyFlags) (*a
}
upgradeVersion := upgradeCfg.Apply.KubernetesVersion
// The version arg is mandatory, during upgrade apply, unless it's specified in the config file
// The version arg is mandatory, unless it's specified in the config file
if upgradeVersion == "" {
if err := cmdutil.ValidateExactArgNumber(args, []string{"version"}); err != nil {
return nil, err
}
}
// If option was specified in both args and config file, args will overwrite the config file.
// If the version was specified in both the arg and config file, the arg will overwrite the config file.
if len(args) == 1 {
upgradeVersion = args[0]
}
ignorePreflightErrorsSet, err := validation.ValidateIgnorePreflightErrors(applyFlags.ignorePreflightErrors, upgradeCfg.Apply.IgnorePreflightErrors)
if err != nil {
return nil, err
}
force, ok := cmdutil.ValueFromFlagsOrConfig(cmd.Flags(), "force", upgradeCfg.Apply.ForceUpgrade, &applyFlags.force).(*bool)
if !ok {
return nil, cmdutil.TypeMismatchErr("forceUpgrade", "bool")
@ -239,10 +240,6 @@ func newApplyData(cmd *cobra.Command, args []string, applyFlags *applyFlags) (*a
return nil, errors.Wrap(err, "[upgrade/init config] FATAL")
}
ignorePreflightErrorsSet, err := validation.ValidateIgnorePreflightErrors(applyFlags.ignorePreflightErrors, upgradeCfg.Apply.IgnorePreflightErrors)
if err != nil {
return nil, err
}
// Also set the union of pre-flight errors to InitConfiguration, to provide a consistent view of the runtime configuration:
initCfg.NodeRegistration.IgnorePreflightErrors = sets.List(ignorePreflightErrorsSet)
@ -303,7 +300,7 @@ func (d *applyData) RenewCerts() bool {
return d.renewCerts
}
// Cfg returns upgradeConfiguration.
// Cfg returns the UpgradeConfiguration.
func (d *applyData) Cfg() *kubeadmapi.UpgradeConfiguration {
return d.cfg
}
@ -338,17 +335,17 @@ func (d *applyData) SessionIsInteractive() bool {
return !(d.nonInteractiveMode || d.dryRun || d.force)
}
// AllowExperimentalUpgrades returns true if allow upgrading to an alpha/beta/release candidate version of Kubernetes.
// AllowExperimentalUpgrades returns true if upgrading to an alpha/beta/release candidate version of Kubernetes is allowed.
func (d *applyData) AllowExperimentalUpgrades() bool {
return d.allowExperimentalUpgrades
}
// AllowRCUpgrades returns true if allow upgrading to a release candidate version of Kubernetes.
// AllowRCUpgrades returns true if upgrading to a release candidate version of Kubernetes is allowed.
func (d *applyData) AllowRCUpgrades() bool {
return d.allowRCUpgrades
}
// ForceUpgrade returns true if force upgrading although some requirements might not be met.
// ForceUpgrade returns true if force-upgrading is enabled.
func (d *applyData) ForceUpgrade() bool {
return d.force
}

View File

@ -17,7 +17,15 @@ limitations under the License.
package upgrade
import (
"fmt"
"os"
"path/filepath"
"strings"
"testing"
kubeadmapiv1 "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1beta4"
"k8s.io/kubernetes/cmd/kubeadm/app/cmd/options"
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
)
func TestSessionIsInteractive(t *testing.T) {
@ -61,3 +69,128 @@ func TestSessionIsInteractive(t *testing.T) {
})
}
}
var testApplyConfig = fmt.Sprintf(`---
apiVersion: %s
apply:
certificateRenewal: true
etcdUpgrade: true
imagePullPolicy: IfNotPresent
imagePullSerial: true
diff: {}
kind: UpgradeConfiguration
node:
certificateRenewal: true
etcdUpgrade: true
imagePullPolicy: IfNotPresent
imagePullSerial: true
plan: {}
timeouts:
controlPlaneComponentHealthCheck: 4m0s
discovery: 5m0s
etcdAPICall: 2m0s
kubeletHealthCheck: 4m0s
kubernetesAPICall: 1m0s
tlsBootstrap: 5m0s
upgradeManifests: 5m0s
`, kubeadmapiv1.SchemeGroupVersion.String())
func TestNewApplyData(t *testing.T) {
// create temp directory
tmpDir, err := os.MkdirTemp("", "kubeadm-upgrade-apply-test")
if err != nil {
t.Errorf("Unable to create temporary directory: %v", err)
}
defer func() {
_ = os.RemoveAll(tmpDir)
}()
// create config file
configFilePath := filepath.Join(tmpDir, "test-config-file")
cfgFile, err := os.Create(configFilePath)
if err != nil {
t.Errorf("Unable to create file %q: %v", configFilePath, err)
}
defer func() {
_ = cfgFile.Close()
}()
if _, err = cfgFile.WriteString(testApplyConfig); err != nil {
t.Fatalf("Unable to write file %q: %v", configFilePath, err)
}
testCases := []struct {
name string
args []string
flags map[string]string
validate func(*testing.T, *applyData)
expectedError string
}{
{
name: "fails if no upgrade version set",
flags: map[string]string{
options.CfgPath: configFilePath,
},
expectedError: "missing one or more required arguments. Required arguments: [version]",
},
{
name: "fails if invalid preflight checks are provided",
args: []string{"v1.1.0"},
flags: map[string]string{
options.IgnorePreflightErrors: "all,something-else",
},
expectedError: "ignore-preflight-errors: Invalid value",
},
{
name: "fails if kubeconfig file doesn't exists",
args: []string{"v1.1.0"},
flags: map[string]string{
options.CfgPath: configFilePath,
options.KubeconfigPath: "invalid-kubeconfig-path",
},
expectedError: "couldn't create a Kubernetes client from file",
},
// TODO: add more test cases here when the fake client for `kubeadm upgrade apply` can be injected
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
// initialize an external apply flags and inject it to the apply cmd
apf := &applyPlanFlags{
kubeConfigPath: kubeadmconstants.GetAdminKubeConfigPath(),
cfgPath: "",
featureGatesString: "",
allowExperimentalUpgrades: false,
allowRCUpgrades: false,
printConfig: false,
out: os.Stdout,
}
cmd := newCmdApply(apf)
// sets cmd flags (that will be reflected on the init options)
for f, v := range tc.flags {
_ = cmd.Flags().Set(f, v)
}
flags := &applyFlags{
applyPlanFlags: apf,
etcdUpgrade: true,
renewCerts: true,
}
// test newApplyData method
data, err := newApplyData(cmd, tc.args, flags)
if err == nil && len(tc.expectedError) != 0 {
t.Error("Expected error, but got success")
}
if err != nil && (len(tc.expectedError) == 0 || !strings.Contains(err.Error(), tc.expectedError)) {
t.Fatalf("newApplyData returned unexpected error, expected: %s, got %v", tc.expectedError, err)
}
// exec additional validation on the returned value
if tc.validate != nil {
tc.validate(t, data)
}
})
}
}