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",
|
Short: "Access the kubernetes dashboard running within the minikube cluster",
|
||||||
Long: `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) {
|
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()
|
api, err := machine.NewAPIClient()
|
||||||
defer func() {
|
defer func() {
|
||||||
err := api.Close()
|
err := api.Close()
|
||||||
|
|
@ -81,7 +86,7 @@ var dashboardCmd = &cobra.Command{
|
||||||
}
|
}
|
||||||
|
|
||||||
console.ErrStyle("launch", "Launching proxy ...")
|
console.ErrStyle("launch", "Launching proxy ...")
|
||||||
p, hostPort, err := kubectlProxy()
|
p, hostPort, err := kubectlProxy(kubectl)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
exit.WithError("kubectl proxy", err)
|
exit.WithError("kubectl proxy", err)
|
||||||
}
|
}
|
||||||
|
|
@ -109,12 +114,7 @@ var dashboardCmd = &cobra.Command{
|
||||||
}
|
}
|
||||||
|
|
||||||
// kubectlProxy runs "kubectl proxy", returning host:port
|
// kubectlProxy runs "kubectl proxy", returning host:port
|
||||||
func kubectlProxy() (*exec.Cmd, string, error) {
|
func kubectlProxy(path string) (*exec.Cmd, string, error) {
|
||||||
path, err := exec.LookPath("kubectl")
|
|
||||||
if err != nil {
|
|
||||||
return nil, "", errors.Wrap(err, "kubectl not found in PATH")
|
|
||||||
}
|
|
||||||
|
|
||||||
// port=0 picks a random system port
|
// port=0 picks a random system port
|
||||||
// config.GetMachineName() respects the -p (profile) flag
|
// config.GetMachineName() respects the -p (profile) flag
|
||||||
cmd := exec.Command(path, "--context", config.GetMachineName(), "proxy", "--port=0")
|
cmd := exec.Command(path, "--context", config.GetMachineName(), "proxy", "--port=0")
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,6 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"runtime"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/docker/machine/libmachine"
|
"github.com/docker/machine/libmachine"
|
||||||
|
|
@ -32,7 +31,6 @@ import (
|
||||||
"github.com/spf13/pflag"
|
"github.com/spf13/pflag"
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
configCmd "k8s.io/minikube/cmd/minikube/cmd/config"
|
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"
|
||||||
"k8s.io/minikube/pkg/minikube/bootstrapper/kubeadm"
|
"k8s.io/minikube/pkg/minikube/bootstrapper/kubeadm"
|
||||||
"k8s.io/minikube/pkg/minikube/config"
|
"k8s.io/minikube/pkg/minikube/config"
|
||||||
|
|
@ -94,7 +92,6 @@ var RootCmd = &cobra.Command{
|
||||||
if enableUpdateNotification {
|
if enableUpdateNotification {
|
||||||
notify.MaybePrintUpdateTextFromGithub(os.Stderr)
|
notify.MaybePrintUpdateTextFromGithub(os.Stderr)
|
||||||
}
|
}
|
||||||
util.MaybePrintKubectlDownloadMsg(runtime.GOOS, os.Stderr)
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -211,6 +211,10 @@ func runStart(cmd *cobra.Command, args []string) {
|
||||||
} else {
|
} else {
|
||||||
console.OutStyle("kubectl", "kubectl is now configured to use %q", cfg.GetMachineName())
|
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!")
|
console.OutStyle("ready", "Done! Thank you for using minikube!")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -305,17 +309,21 @@ func prepareNone() {
|
||||||
if viper.GetBool(cfg.WantNoneDriverWarning) {
|
if viper.GetBool(cfg.WantNoneDriverWarning) {
|
||||||
console.OutLn("")
|
console.OutLn("")
|
||||||
console.Warning("The 'none' driver provides limited isolation and may reduce system security and reliability.")
|
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.OutStyle("url", "https://github.com/kubernetes/minikube/blob/master/docs/vmdriver-none.md")
|
||||||
console.OutLn("")
|
console.OutLn("")
|
||||||
}
|
}
|
||||||
|
|
||||||
if os.Getenv("CHANGE_MINIKUBE_NONE_USER") == "" {
|
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("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.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.OutLn("")
|
||||||
console.OutStyle("command", "sudo chown -R $USER %s/.kube %s/.minikube", os.Getenv("HOME"))
|
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")
|
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
|
package util
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/spf13/viper"
|
|
||||||
"k8s.io/minikube/pkg/minikube/config"
|
|
||||||
"k8s.io/minikube/pkg/minikube/constants"
|
"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
|
// Ask the kernel for a free open port that is ready to use
|
||||||
func GetPort() (string, error) {
|
func GetPort() (string, error) {
|
||||||
addr, err := net.ResolveTCPAddr("tcp", "localhost:0")
|
addr, err := net.ResolveTCPAddr("tcp", "localhost:0")
|
||||||
|
|
|
||||||
|
|
@ -17,108 +17,12 @@ limitations under the License.
|
||||||
package util
|
package util
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"fmt"
|
|
||||||
"net/http"
|
|
||||||
"net/http/httptest"
|
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
"github.com/spf13/viper"
|
|
||||||
"k8s.io/client-go/tools/clientcmd"
|
"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) {
|
func TestGetKubeConfigPath(t *testing.T) {
|
||||||
var tests = []struct {
|
var tests = []struct {
|
||||||
input string
|
input string
|
||||||
|
|
|
||||||
|
|
@ -255,7 +255,8 @@ func (k *KubeadmBootstrapper) DeleteCluster(k8s config.KubernetesConfig) error {
|
||||||
// PullImages downloads images that will be used by RestartCluster
|
// PullImages downloads images that will be used by RestartCluster
|
||||||
func (k *KubeadmBootstrapper) PullImages(k8s config.KubernetesConfig) error {
|
func (k *KubeadmBootstrapper) PullImages(k8s config.KubernetesConfig) error {
|
||||||
cmd := fmt.Sprintf("sudo kubeadm config images pull --config %s", constants.KubeadmConfigFile)
|
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 errors.Wrapf(err, "running cmd: %s", cmd)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|
|
||||||
|
|
@ -49,6 +49,7 @@ var styles = map[string]style{
|
||||||
"launch": {Prefix: "🚀 "},
|
"launch": {Prefix: "🚀 "},
|
||||||
"thumbs-up": {Prefix: "👍 "},
|
"thumbs-up": {Prefix: "👍 "},
|
||||||
"option": {Prefix: " ▪ "}, // Indented bullet
|
"option": {Prefix: " ▪ "}, // Indented bullet
|
||||||
|
"command": {Prefix: " ▪ "}, // Indented bullet
|
||||||
"log-entry": {Prefix: " "}, // Indent
|
"log-entry": {Prefix: " "}, // Indent
|
||||||
"crushed": {Prefix: "💔 "},
|
"crushed": {Prefix: "💔 "},
|
||||||
"running": {Prefix: "🏃 "},
|
"running": {Prefix: "🏃 "},
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue