188 lines
6.0 KiB
Go
188 lines
6.0 KiB
Go
/*
|
|
Copyright 2020 The Kubernetes Authors All rights reserved.
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
*/
|
|
|
|
package node
|
|
|
|
import (
|
|
"fmt"
|
|
"net"
|
|
"os"
|
|
"os/exec"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/docker/machine/libmachine"
|
|
"github.com/docker/machine/libmachine/host"
|
|
"github.com/golang/glog"
|
|
"github.com/spf13/viper"
|
|
"k8s.io/minikube/pkg/minikube/bootstrapper/images"
|
|
"k8s.io/minikube/pkg/minikube/command"
|
|
"k8s.io/minikube/pkg/minikube/config"
|
|
"k8s.io/minikube/pkg/minikube/driver"
|
|
"k8s.io/minikube/pkg/minikube/exit"
|
|
"k8s.io/minikube/pkg/minikube/machine"
|
|
"k8s.io/minikube/pkg/minikube/out"
|
|
"k8s.io/minikube/pkg/minikube/proxy"
|
|
"k8s.io/minikube/pkg/util/retry"
|
|
)
|
|
|
|
func startMachine(cfg *config.ClusterConfig, node *config.Node) (runner command.Runner, preExists bool, machineAPI libmachine.API, host *host.Host) {
|
|
m, err := machine.NewAPIClient()
|
|
if err != nil {
|
|
exit.WithError("Failed to get machine client", err)
|
|
}
|
|
host, preExists = startHost(m, *cfg)
|
|
runner, err = machine.CommandRunner(host)
|
|
if err != nil {
|
|
exit.WithError("Failed to get command runner", err)
|
|
}
|
|
|
|
ip := validateNetwork(host, runner)
|
|
|
|
// Bypass proxy for minikube's vm host ip
|
|
err = proxy.ExcludeIP(ip)
|
|
if err != nil {
|
|
out.ErrT(out.FailureType, "Failed to set NO_PROXY Env. Please use `export NO_PROXY=$NO_PROXY,{{.ip}}`.", out.V{"ip": ip})
|
|
}
|
|
// Save IP to configuration file for subsequent use
|
|
node.IP = ip
|
|
|
|
if err := Save(cfg, node); err != nil {
|
|
exit.WithError("Failed to save config", err)
|
|
}
|
|
|
|
return runner, preExists, m, host
|
|
}
|
|
|
|
// startHost starts a new minikube host using a VM or None
|
|
func startHost(api libmachine.API, mc config.ClusterConfig) (*host.Host, bool) {
|
|
exists, err := api.Exists(mc.Name)
|
|
if err != nil {
|
|
exit.WithError("Failed to check if machine exists", err)
|
|
}
|
|
|
|
host, err := machine.StartHost(api, mc)
|
|
if err != nil {
|
|
exit.WithError("Unable to start VM. Please investigate and run 'minikube delete' if possible", err)
|
|
}
|
|
return host, exists
|
|
}
|
|
|
|
// validateNetwork tries to catch network problems as soon as possible
|
|
func validateNetwork(h *host.Host, r command.Runner) string {
|
|
ip, err := h.Driver.GetIP()
|
|
if err != nil {
|
|
exit.WithError("Unable to get VM IP address", err)
|
|
}
|
|
|
|
optSeen := false
|
|
warnedOnce := false
|
|
for _, k := range proxy.EnvVars {
|
|
if v := os.Getenv(k); v != "" {
|
|
if !optSeen {
|
|
out.T(out.Internet, "Found network options:")
|
|
optSeen = true
|
|
}
|
|
out.T(out.Option, "{{.key}}={{.value}}", out.V{"key": k, "value": v})
|
|
ipExcluded := proxy.IsIPExcluded(ip) // Skip warning if minikube ip is already in NO_PROXY
|
|
k = strings.ToUpper(k) // for http_proxy & https_proxy
|
|
if (k == "HTTP_PROXY" || k == "HTTPS_PROXY") && !ipExcluded && !warnedOnce {
|
|
out.WarningT("You appear to be using a proxy, but your NO_PROXY environment does not include the minikube IP ({{.ip_address}}). Please see {{.documentation_url}} for more details", out.V{"ip_address": ip, "documentation_url": "https://minikube.sigs.k8s.io/docs/reference/networking/proxy/"})
|
|
warnedOnce = true
|
|
}
|
|
}
|
|
}
|
|
|
|
if !driver.BareMetal(h.Driver.DriverName()) && !driver.IsKIC(h.Driver.DriverName()) {
|
|
trySSH(h, ip)
|
|
}
|
|
|
|
tryLookup(r)
|
|
tryRegistry(r)
|
|
return ip
|
|
}
|
|
|
|
func trySSH(h *host.Host, ip string) {
|
|
if viper.GetBool("force") {
|
|
return
|
|
}
|
|
|
|
sshAddr := net.JoinHostPort(ip, "22")
|
|
|
|
dial := func() (err error) {
|
|
d := net.Dialer{Timeout: 3 * time.Second}
|
|
conn, err := d.Dial("tcp", sshAddr)
|
|
if err != nil {
|
|
out.WarningT("Unable to verify SSH connectivity: {{.error}}. Will retry...", out.V{"error": err})
|
|
return err
|
|
}
|
|
_ = conn.Close()
|
|
return nil
|
|
}
|
|
|
|
if err := retry.Expo(dial, time.Second, 13*time.Second); err != nil {
|
|
exit.WithCodeT(exit.IO, `minikube is unable to connect to the VM: {{.error}}
|
|
|
|
This is likely due to one of two reasons:
|
|
|
|
- VPN or firewall interference
|
|
- {{.hypervisor}} network configuration issue
|
|
|
|
Suggested workarounds:
|
|
|
|
- Disable your local VPN or firewall software
|
|
- Configure your local VPN or firewall to allow access to {{.ip}}
|
|
- Restart or reinstall {{.hypervisor}}
|
|
- Use an alternative --driver
|
|
- Use --force to override this connectivity check
|
|
`, out.V{"error": err, "hypervisor": h.Driver.DriverName(), "ip": ip})
|
|
}
|
|
}
|
|
|
|
func tryLookup(r command.Runner) {
|
|
// DNS check
|
|
if rr, err := r.RunCmd(exec.Command("nslookup", "-type=ns", "kubernetes.io")); err != nil {
|
|
glog.Infof("%s failed: %v which might be okay will retry nslookup without query type", rr.Args, err)
|
|
// will try with without query type for ISOs with different busybox versions.
|
|
if _, err = r.RunCmd(exec.Command("nslookup", "kubernetes.io")); err != nil {
|
|
glog.Warningf("nslookup failed: %v", err)
|
|
// try with the older "host" command, instead of the newer "nslookup"
|
|
if _, err = r.RunCmd(exec.Command("host", "kubernetes.io")); err != nil {
|
|
out.WarningT("Node may be unable to resolve external DNS records")
|
|
}
|
|
}
|
|
}
|
|
}
|
|
func tryRegistry(r command.Runner) {
|
|
// Try an HTTPS connection to the image repository
|
|
proxy := os.Getenv("HTTPS_PROXY")
|
|
opts := []string{"-sS"}
|
|
if proxy != "" && !strings.HasPrefix(proxy, "localhost") && !strings.HasPrefix(proxy, "127.0") {
|
|
opts = append([]string{"-x", proxy}, opts...)
|
|
}
|
|
|
|
repo := viper.GetString(imageRepository)
|
|
if repo == "" {
|
|
repo = images.DefaultKubernetesRepo
|
|
}
|
|
|
|
opts = append(opts, fmt.Sprintf("https://%s/", repo))
|
|
if rr, err := r.RunCmd(exec.Command("curl", opts...)); err != nil {
|
|
glog.Warningf("%s failed: %v", rr.Args, err)
|
|
out.WarningT("VM is unable to access {{.repository}}, you may need to configure a proxy or set --image-repository", out.V{"repository": repo})
|
|
}
|
|
}
|