diff --git a/pkg/drivers/qemu/qemu.go b/pkg/drivers/qemu/qemu.go index b5e758c76dd8..2919735d9c03 100644 --- a/pkg/drivers/qemu/qemu.go +++ b/pkg/drivers/qemu/qemu.go @@ -487,17 +487,17 @@ func (d *Driver) Stop() error { func (d *Driver) Remove() error { s, err := d.GetState() if err != nil { - return err + return errors.Wrap(err, "get state") } if s == state.Running { if err := d.Kill(); err != nil { - return err + return errors.Wrap(err, "kill") } } if s != state.Stopped { _, err = d.RunQMPCommand("quit") if err != nil { - return err + return errors.Wrap(err, "quit") } } return nil diff --git a/pkg/minikube/bootstrapper/kubeadm/kubeadm.go b/pkg/minikube/bootstrapper/kubeadm/kubeadm.go index 05c5ac1acfe3..65a51c8162d6 100644 --- a/pkg/minikube/bootstrapper/kubeadm/kubeadm.go +++ b/pkg/minikube/bootstrapper/kubeadm/kubeadm.go @@ -290,6 +290,10 @@ func (k *Bootstrapper) init(cfg config.ClusterConfig) error { }() wg.Wait() + // Tunnel apiserver to guest, if necessary + if cfg.APIServerPort != 0 { + k.tunnelToAPIServer(cfg) + } return nil } @@ -399,6 +403,10 @@ func (k *Bootstrapper) StartCluster(cfg config.ClusterConfig) error { } if err := bsutil.ExistingConfig(k.c); err == nil { + // If the guest already exists and was stopped, re-establish the apiserver tunnel so checks pass + if cfg.APIServerPort != 0 { + k.tunnelToAPIServer(cfg) + } klog.Infof("found existing configuration files, will attempt cluster restart") rerr := k.restartControlPlane(cfg) if rerr == nil { @@ -433,6 +441,22 @@ func (k *Bootstrapper) StartCluster(cfg config.ClusterConfig) error { return err } +func (k *Bootstrapper) tunnelToAPIServer(cfg config.ClusterConfig) { + m, err := machine.NewAPIClient() + if err != nil { + klog.Warningf("libmachine API failed: %v", err) + } + cp, err := config.PrimaryControlPlane(&cfg) + if err != nil { + klog.Warningf("finding control plane failed: %v", err) + } + args := []string{"-f", "-NTL", fmt.Sprintf("%d:localhost:8443", cfg.APIServerPort)} + err = machine.CreateSSHShell(m, cfg, cp, args, false) + if err != nil { + klog.Warningf("apiserver tunnel failed: %v", err) + } +} + // client sets and returns a Kubernetes client to use to speak to a kubeadm launched apiserver func (k *Bootstrapper) client(ip string, port int) (*kubernetes.Clientset, error) { if k.k8sClient != nil { @@ -569,6 +593,7 @@ func (k *Bootstrapper) needsReconfigure(conf string, hostname string, port int, klog.Infof("needs reconfigure: configs differ:\n%s", rr.Output()) return true } + // cruntime.Enable() may restart kube-apiserver but does not wait for it to return back apiStatusTimeout := 3000 * time.Millisecond st, err := kverify.WaitForAPIServerStatus(k.c, apiStatusTimeout, hostname, port) diff --git a/pkg/minikube/node/start.go b/pkg/minikube/node/start.go index b721f043617f..730bb6f03d7c 100644 --- a/pkg/minikube/node/start.go +++ b/pkg/minikube/node/start.go @@ -253,15 +253,6 @@ func handleAPIServer(starter Starter, cr cruntime.Manager, hostIP net.IP) (*kube return nil, bs, err } - // Tunnel apiserver to guest, if needed - if starter.Cfg.APIServerPort != 0 { - args := []string{"-f", "-NTL", fmt.Sprintf("%d:localhost:8443", starter.Cfg.APIServerPort)} - err := machine.CreateSSHShell(starter.MachineAPI, *starter.Cfg, *starter.Node, args, false) - if err != nil { - klog.Warningf("apiserver tunnel failed: %v", err) - } - } - // Write the kubeconfig to the file system after everything required (like certs) are created by the bootstrapper. if err := kubeconfig.Update(kcs); err != nil { return nil, bs, errors.Wrap(err, "Failed kubeconfig update")