Overhaul how we handle kubectl, as it isn't actually required except for the dashboard
parent
35449f685e
commit
71eafef5ce
|
|
@ -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")
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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: "🏃 "},
|
||||
|
|
|
|||
Loading…
Reference in New Issue