From 4e33f9617360c69a47a9db8c379594c51fa5e55b Mon Sep 17 00:00:00 2001 From: Steven Powell Date: Wed, 1 Mar 2023 13:07:46 -0800 Subject: [PATCH] add timeout and force to kubectl command --- pkg/addons/addons.go | 9 ++++++++- pkg/addons/kubectl.go | 8 ++++++-- pkg/addons/kubectl_test.go | 21 +++++++++++++++++++-- 3 files changed, 33 insertions(+), 5 deletions(-) diff --git a/pkg/addons/addons.go b/pkg/addons/addons.go index 0fd2d0cb1c..497cbe2708 100644 --- a/pkg/addons/addons.go +++ b/pkg/addons/addons.go @@ -17,6 +17,7 @@ limitations under the License. package addons import ( + "context" "fmt" "os/exec" "path" @@ -433,11 +434,17 @@ func enableOrDisableAddonInternal(cc *config.ClusterConfig, addon *assets.Addon, } } + // on the first attempt try without force, but on subsuquent attempts use force + force := false + // Retry, because sometimes we race against an apiserver restart apply := func() error { - _, err := runner.RunCmd(kubectlCommand(cc, deployFiles, enable)) + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + _, err := runner.RunCmd(kubectlCommand(ctx, cc, deployFiles, enable, force)) if err != nil { klog.Warningf("apply failed, will retry: %v", err) + force = true } return err } diff --git a/pkg/addons/kubectl.go b/pkg/addons/kubectl.go index 60ccc2c239..46aeb8071a 100644 --- a/pkg/addons/kubectl.go +++ b/pkg/addons/kubectl.go @@ -17,6 +17,7 @@ limitations under the License. package addons import ( + "context" "fmt" "os/exec" "path" @@ -27,7 +28,7 @@ import ( "k8s.io/minikube/pkg/minikube/vmpath" ) -func kubectlCommand(cc *config.ClusterConfig, files []string, enable bool) *exec.Cmd { +func kubectlCommand(ctx context.Context, cc *config.ClusterConfig, files []string, enable, force bool) *exec.Cmd { v := constants.DefaultKubernetesVersion if cc != nil { v = cc.KubernetesConfig.KubernetesVersion @@ -41,6 +42,9 @@ func kubectlCommand(cc *config.ClusterConfig, files []string, enable bool) *exec } args := []string{fmt.Sprintf("KUBECONFIG=%s", path.Join(vmpath.GuestPersistentDir, "kubeconfig")), kubectlBinary, kubectlAction} + if force { + args = append(args, "--force") + } if !enable { // --ignore-not-found just ignores when we try to delete a resource that is already gone, // like a completed job with a ttlSecondsAfterFinished @@ -50,5 +54,5 @@ func kubectlCommand(cc *config.ClusterConfig, files []string, enable bool) *exec args = append(args, []string{"-f", f}...) } - return exec.Command("sudo", args...) + return exec.CommandContext(ctx, "sudo", args...) } diff --git a/pkg/addons/kubectl_test.go b/pkg/addons/kubectl_test.go index 69eddce133..b460f22d3d 100644 --- a/pkg/addons/kubectl_test.go +++ b/pkg/addons/kubectl_test.go @@ -17,6 +17,7 @@ limitations under the License. package addons import ( + "context" "strings" "testing" @@ -28,6 +29,7 @@ func TestKubectlCommand(t *testing.T) { description string files []string enable bool + force bool expected string }{ { @@ -35,12 +37,27 @@ func TestKubectlCommand(t *testing.T) { files: []string{"a", "b"}, enable: true, expected: "sudo KUBECONFIG=/var/lib/minikube/kubeconfig /var/lib/minikube/binaries/v1.17.0/kubectl apply -f a -f b", - }, { + }, + { description: "disable an addon", files: []string{"a", "b"}, enable: false, expected: "sudo KUBECONFIG=/var/lib/minikube/kubeconfig /var/lib/minikube/binaries/v1.17.0/kubectl delete --ignore-not-found -f a -f b", }, + { + description: "enable an addon", + files: []string{"a", "b"}, + enable: true, + force: true, + expected: "sudo KUBECONFIG=/var/lib/minikube/kubeconfig /var/lib/minikube/binaries/v1.17.0/kubectl apply --force -f a -f b", + }, + { + description: "disable an addon", + files: []string{"a", "b"}, + enable: false, + force: true, + expected: "sudo KUBECONFIG=/var/lib/minikube/kubeconfig /var/lib/minikube/binaries/v1.17.0/kubectl delete --force --ignore-not-found -f a -f b", + }, } cc := &config.ClusterConfig{ @@ -51,7 +68,7 @@ func TestKubectlCommand(t *testing.T) { for _, test := range tests { t.Run(test.description, func(t *testing.T) { - command := kubectlCommand(cc, test.files, test.enable) + command := kubectlCommand(context.Background(), cc, test.files, test.enable, test.force) actual := strings.Join(command.Args, " ") if actual != test.expected {