Overhaul how we handle kubectl, as it isn't actually required except for the dashboard

pull/3680/head
Thomas Stromberg 2019-02-14 17:10:03 -08:00
parent 35449f685e
commit 71eafef5ce
7 changed files with 21 additions and 164 deletions

View File

@ -52,6 +52,11 @@ var dashboardCmd = &cobra.Command{
Short: "Access the kubernetes dashboard running within the minikube cluster",
Long: `Access the kubernetes dashboard running within the minikube cluster`,
Run: func(cmd *cobra.Command, args []string) {
kubectl, err := exec.LookPath("kubectl")
if err != nil {
exit.WithCode(exit.NoInput, "kubectl not found in PATH, but is required for the dashboard. Installation guide: https://kubernetes.io/docs/tasks/tools/install-kubectl/")
}
api, err := machine.NewAPIClient()
defer func() {
err := api.Close()
@ -81,7 +86,7 @@ var dashboardCmd = &cobra.Command{
}
console.ErrStyle("launch", "Launching proxy ...")
p, hostPort, err := kubectlProxy()
p, hostPort, err := kubectlProxy(kubectl)
if err != nil {
exit.WithError("kubectl proxy", err)
}
@ -109,12 +114,7 @@ var dashboardCmd = &cobra.Command{
}
// kubectlProxy runs "kubectl proxy", returning host:port
func kubectlProxy() (*exec.Cmd, string, error) {
path, err := exec.LookPath("kubectl")
if err != nil {
return nil, "", errors.Wrap(err, "kubectl not found in PATH")
}
func kubectlProxy(path string) (*exec.Cmd, string, error) {
// port=0 picks a random system port
// config.GetMachineName() respects the -p (profile) flag
cmd := exec.Command(path, "--context", config.GetMachineName(), "proxy", "--port=0")

View File

@ -21,7 +21,6 @@ import (
"fmt"
"io/ioutil"
"os"
"runtime"
"strings"
"github.com/docker/machine/libmachine"
@ -32,7 +31,6 @@ import (
"github.com/spf13/pflag"
"github.com/spf13/viper"
configCmd "k8s.io/minikube/cmd/minikube/cmd/config"
"k8s.io/minikube/cmd/util"
"k8s.io/minikube/pkg/minikube/bootstrapper"
"k8s.io/minikube/pkg/minikube/bootstrapper/kubeadm"
"k8s.io/minikube/pkg/minikube/config"
@ -94,7 +92,6 @@ var RootCmd = &cobra.Command{
if enableUpdateNotification {
notify.MaybePrintUpdateTextFromGithub(os.Stderr)
}
util.MaybePrintKubectlDownloadMsg(runtime.GOOS, os.Stderr)
},
}

View File

@ -211,6 +211,10 @@ func runStart(cmd *cobra.Command, args []string) {
} else {
console.OutStyle("kubectl", "kubectl is now configured to use %q", cfg.GetMachineName())
}
_, err = exec.LookPath("kubectl")
if err != nil {
console.OutStyle("tip", "For best results, install kubectl: https://kubernetes.io/docs/tasks/tools/install-kubectl/")
}
console.OutStyle("ready", "Done! Thank you for using minikube!")
}
@ -305,17 +309,21 @@ func prepareNone() {
if viper.GetBool(cfg.WantNoneDriverWarning) {
console.OutLn("")
console.Warning("The 'none' driver provides limited isolation and may reduce system security and reliability.")
console.Warning("For more information, see:")
console.OutStyle("url", "https://github.com/kubernetes/minikube/blob/master/docs/vmdriver-none.md")
console.OutLn("")
}
if os.Getenv("CHANGE_MINIKUBE_NONE_USER") == "" {
console.Warning("kubectl and minikube configuration will be stored in %s", os.Getenv("HOME"))
home := os.Getenv("HOME")
console.Warning("kubectl and minikube configuration will be stored in %s", home)
console.Warning("To use kubectl or minikube commands as your own user, you may")
console.Warning("need to relocate them. For example, to overwrite your own settings:")
console.OutStyle("command", "sudo mv %s/.kube %s/.minikube $HOME", os.Getenv("HOME"))
console.OutStyle("command", "sudo chown -R $USER %s/.kube %s/.minikube", os.Getenv("HOME"))
console.OutLn("")
console.OutStyle("command", "sudo mv %s/.kube %s/.minikube $HOME", home, home)
console.OutStyle("command", "sudo chown -R $USER %s/.kube %s/.minikube", home, home)
console.OutLn("")
console.OutStyle("tip", "This can also be done automatically by setting the env var CHANGE_MINIKUBE_NONE_USER=true")
}

View File

@ -18,70 +18,16 @@ limitations under the License.
package util
import (
"fmt"
"io"
"io/ioutil"
"net"
"os"
"os/exec"
"path/filepath"
"runtime"
"strconv"
"github.com/pkg/errors"
"github.com/spf13/viper"
"k8s.io/minikube/pkg/minikube/config"
"k8s.io/minikube/pkg/minikube/constants"
)
type ServiceContext struct {
Service string `json:"service"`
Version string `json:"version"`
}
type LookPath func(filename string) (string, error)
var lookPath LookPath
func init() {
lookPath = exec.LookPath
}
func MaybePrintKubectlDownloadMsg(goos string, out io.Writer) {
if !viper.GetBool(config.WantKubectlDownloadMsg) {
return
}
verb := "run"
installInstructions := "curl -Lo kubectl https://storage.googleapis.com/kubernetes-release/release/%s/bin/%s/%s/kubectl && chmod +x kubectl && sudo cp kubectl /usr/local/bin/ && rm kubectl"
if goos == "windows" {
verb = "do"
installInstructions = `download kubectl from:
https://storage.googleapis.com/kubernetes-release/release/%s/bin/%s/%s/kubectl.exe
Add kubectl to your system PATH`
}
_, err := lookPath("kubectl")
if err != nil && goos == "windows" {
_, err = lookPath("kubectl.exe")
}
if err != nil {
fmt.Fprintf(out,
`========================================
kubectl could not be found on your path. kubectl is a requirement for using minikube
To install kubectl, please %s the following:
%s
To disable this message, run the following:
minikube config set WantKubectlDownloadMsg false
========================================
`,
verb, fmt.Sprintf(installInstructions, constants.DefaultKubernetesVersion, goos, runtime.GOARCH))
}
}
// Ask the kernel for a free open port that is ready to use
func GetPort() (string, error) {
addr, err := net.ResolveTCPAddr("tcp", "localhost:0")

View File

@ -17,108 +17,12 @@ limitations under the License.
package util
import (
"bytes"
"fmt"
"net/http"
"net/http/httptest"
"os"
"strings"
"testing"
"github.com/pkg/errors"
"github.com/spf13/viper"
"k8s.io/client-go/tools/clientcmd"
"k8s.io/minikube/pkg/minikube/config"
)
func startTestHTTPServer(returnError bool, response string) *httptest.Server {
return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if returnError {
http.Error(w, response, 400)
} else {
fmt.Fprintf(w, response)
}
}))
}
func revertLookPath(l LookPath) {
lookPath = l
}
func fakeLookPathFound(string) (string, error) { return "/usr/local/bin/kubectl", nil }
func fakeLookPathError(string) (string, error) { return "", errors.New("") }
func TestKubectlDownloadMsg(t *testing.T) {
var tests = []struct {
description string
lp LookPath
goos string
matches string
noOutput bool
warningEnabled bool
}{
{
description: "No output when binary is found windows",
goos: "windows",
lp: fakeLookPathFound,
noOutput: true,
warningEnabled: true,
},
{
description: "No output when binary is found darwin",
goos: "darwin",
lp: fakeLookPathFound,
noOutput: true,
warningEnabled: true,
},
{
description: "windows kubectl not found, has .exe in output",
goos: "windows",
lp: fakeLookPathError,
matches: ".exe",
warningEnabled: true,
},
{
description: "linux kubectl not found",
goos: "linux",
lp: fakeLookPathError,
matches: "WantKubectlDownloadMsg",
warningEnabled: true,
},
{
description: "warning disabled",
goos: "linux",
lp: fakeLookPathError,
noOutput: true,
warningEnabled: false,
},
}
for _, test := range tests {
test := test
t.Run(test.description, func(t *testing.T) {
defer revertLookPath(lookPath)
// Remember the original config value and revert to it.
origConfig := viper.GetBool(config.WantKubectlDownloadMsg)
defer func() {
viper.Set(config.WantKubectlDownloadMsg, origConfig)
}()
viper.Set(config.WantKubectlDownloadMsg, test.warningEnabled)
lookPath = test.lp
var b bytes.Buffer
MaybePrintKubectlDownloadMsg(test.goos, &b)
actual := b.String()
if actual != "" && test.noOutput {
t.Errorf("Got output, but kubectl binary was found")
}
if !strings.Contains(actual, test.matches) {
t.Errorf("Output did not contain substring expected got output %s", actual)
}
})
}
}
func TestGetKubeConfigPath(t *testing.T) {
var tests = []struct {
input string

View File

@ -255,7 +255,8 @@ func (k *KubeadmBootstrapper) DeleteCluster(k8s config.KubernetesConfig) error {
// PullImages downloads images that will be used by RestartCluster
func (k *KubeadmBootstrapper) PullImages(k8s config.KubernetesConfig) error {
cmd := fmt.Sprintf("sudo kubeadm config images pull --config %s", constants.KubeadmConfigFile)
if err := k.c.Run(cmd); err != nil {
// Use CombinedOutput instead of Run to avoid spamming stdout/stderr
if _, err := k.c.CombinedOutput(cmd); err != nil {
return errors.Wrapf(err, "running cmd: %s", cmd)
}
return nil

View File

@ -49,6 +49,7 @@ var styles = map[string]style{
"launch": {Prefix: "🚀 "},
"thumbs-up": {Prefix: "👍 "},
"option": {Prefix: " ▪ "}, // Indented bullet
"command": {Prefix: " ▪ "}, // Indented bullet
"log-entry": {Prefix: " "}, // Indent
"crushed": {Prefix: "💔 "},
"running": {Prefix: "🏃 "},